00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057 #ifdef HAVE_CONFIG_H
00058 # include "config.h"
00059 #endif
00060 #if NEED_GNUG_PRAGMAS
00061 # pragma implementation
00062 #endif
00063
00064 #include "DjVuPort.h"
00065 #include "GOS.h"
00066 #include "DjVuImage.h"
00067 #include "DjVuDocument.h"
00068 #include "DjVuFile.h"
00069 #include "DjVuMessageLite.h"
00070 #include "DataPool.h"
00071
00072
00073 #ifdef HAVE_NAMESPACES
00074 namespace DJVU {
00075 # ifdef NOT_DEFINED // Just to fool emacs c++ mode
00076 }
00077 #endif
00078 #endif
00079
00080
00081
00082
00083
00084
00085 static DjVuPortcaster *pcaster;
00086
00087 DjVuPortcaster *
00088 DjVuPort::get_portcaster(void)
00089 {
00090 if (!pcaster) pcaster = new DjVuPortcaster();
00091 return pcaster;
00092 }
00093
00094 class DjVuPort::DjVuPortCorpse
00095 {
00096 public:
00097 DjVuPort * port;
00098 DjVuPortCorpse * next;
00099
00100 DjVuPortCorpse(DjVuPort * _port) : port(_port), next(0) {}
00101 };
00102
00103
00104
00105
00106
00107 #define MAX_CORPSE_NUM 128
00108
00109
00110
00111
00112
00113
00114
00115 GCriticalSection * DjVuPort::corpse_lock;
00116 DjVuPort::DjVuPortCorpse * DjVuPort::corpse_head;
00117 DjVuPort::DjVuPortCorpse * DjVuPort::corpse_tail;
00118 int DjVuPort::corpse_num;
00119
00120 void *
00121 DjVuPort::operator new (size_t sz)
00122 {
00123 if (!corpse_lock) corpse_lock=new GCriticalSection();
00124
00125
00126
00127
00128
00129 void * addr=0;
00130 {
00131 GCriticalSectionLock lock(corpse_lock);
00132
00133
00134
00135 int addr_num=0;
00136 static void * addr_arr[MAX_CORPSE_NUM];
00137
00138
00139
00140
00141
00142
00143 for(int attempt=0;attempt<MAX_CORPSE_NUM;attempt++)
00144 {
00145 void * test_addr=::operator new (sz);
00146 addr_arr[addr_num++]=test_addr;
00147
00148
00149 DjVuPortCorpse * corpse;
00150 for(corpse=corpse_head;corpse;corpse=corpse->next)
00151 if (test_addr==corpse->port) break;
00152 if (!corpse)
00153 {
00154 addr=test_addr;
00155 addr_num--;
00156 break;
00157 }
00158 }
00159
00160
00161
00162 if (!addr) addr=::operator new(sz);
00163
00164
00165
00166
00167 addr_num--;
00168 while(addr_num>=0) ::operator delete(addr_arr[addr_num--]);
00169 }
00170
00171 DjVuPortcaster * pcaster=get_portcaster();
00172 GCriticalSectionLock lock(&pcaster->map_lock);
00173 pcaster->cont_map[addr]=0;
00174 return addr;
00175 }
00176
00177 void
00178 DjVuPort::operator delete(void * addr)
00179 {
00180 if (corpse_lock)
00181 {
00182 GCriticalSectionLock lock(corpse_lock);
00183
00184
00185 if (corpse_tail)
00186 {
00187 corpse_tail->next=new DjVuPortCorpse((DjVuPort *) addr);
00188 corpse_tail=corpse_tail->next;
00189 corpse_tail->next=0;
00190 } else
00191 {
00192 corpse_head=corpse_tail=new DjVuPortCorpse((DjVuPort *) addr);
00193 corpse_tail->next=0;
00194 }
00195 corpse_num++;
00196 if (corpse_num>=MAX_CORPSE_NUM)
00197 {
00198 DjVuPortCorpse * corpse=corpse_head;
00199 corpse_head=corpse_head->next;
00200 delete corpse;
00201 corpse_num--;
00202 }
00203 }
00204 ::operator delete(addr);
00205 }
00206
00207 DjVuPort::DjVuPort()
00208 {
00209 DjVuPortcaster *pcaster = get_portcaster();
00210 GCriticalSectionLock lock(& pcaster->map_lock );
00211 GPosition p = pcaster->cont_map.contains(this);
00212 if (!p) G_THROW( ERR_MSG("DjVuPort.not_alloc") );
00213 pcaster->cont_map[p] = (void*)this;
00214 }
00215
00216 DjVuPort::DjVuPort(const DjVuPort & port)
00217 {
00218 DjVuPortcaster *pcaster = get_portcaster();
00219 GCriticalSectionLock lock(& pcaster->map_lock );
00220 GPosition p = pcaster->cont_map.contains(this);
00221 if (!p) G_THROW( ERR_MSG("DjVuPort.not_alloc") );
00222 pcaster->cont_map[p] = (void*)this;
00223 pcaster->copy_routes(this, &port);
00224 }
00225
00226 DjVuPort &
00227 DjVuPort::operator=(const DjVuPort & port)
00228 {
00229 if (this != &port)
00230 get_portcaster()->copy_routes(this, &port);
00231 return *this;
00232 }
00233
00234 DjVuPort::~DjVuPort(void)
00235 {
00236 get_portcaster()->del_port(this);
00237 }
00238
00239
00240
00241
00242
00243
00244
00245
00246 DjVuPortcaster::DjVuPortcaster(void)
00247 {
00248 }
00249
00250 DjVuPortcaster::~DjVuPortcaster(void)
00251 {
00252 GCriticalSectionLock lock(&map_lock);
00253 for(GPosition pos=route_map;pos;++pos)
00254 delete (GList<void *> *) route_map[pos];
00255 }
00256
00257 GP<DjVuPort>
00258 DjVuPortcaster::is_port_alive(DjVuPort *port)
00259 {
00260 GP<DjVuPort> gp_port;
00261 GCriticalSectionLock lock(&map_lock);
00262 GPosition pos=cont_map.contains(port);
00263 if (pos && cont_map[pos] && ((DjVuPort *) port)->get_count()>0)
00264 gp_port=port;
00265 return gp_port;
00266 }
00267
00268 void
00269 DjVuPortcaster::add_alias(const DjVuPort * port, const GUTF8String &alias)
00270 {
00271 GCriticalSectionLock lock(&map_lock);
00272 a2p_map[alias]=port;
00273 }
00274
00275 void
00276 DjVuPortcaster::clear_all_aliases(void)
00277 {
00278 DjVuPortcaster *p=get_portcaster();
00279 GCriticalSectionLock lock(&(p->map_lock));
00280 GPosition pos;
00281 while((pos=p->a2p_map))
00282 {
00283 p->a2p_map.del(pos);
00284 }
00285 }
00286
00287 void
00288 DjVuPortcaster::clear_aliases(const DjVuPort * port)
00289 {
00290 GCriticalSectionLock lock(&map_lock);
00291 for(GPosition pos=a2p_map;pos;)
00292 if (a2p_map[pos]==port)
00293 {
00294 GPosition this_pos=pos;
00295 ++pos;
00296 a2p_map.del(this_pos);
00297 } else ++pos;
00298 }
00299
00300 GP<DjVuPort>
00301 DjVuPortcaster::alias_to_port(const GUTF8String &alias)
00302 {
00303 GCriticalSectionLock lock(&map_lock);
00304 GPosition pos;
00305 if (a2p_map.contains(alias, pos))
00306 {
00307 DjVuPort * port=(DjVuPort *) a2p_map[pos];
00308 GP<DjVuPort> gp_port=is_port_alive(port);
00309 if (gp_port) return gp_port;
00310 else a2p_map.del(pos);
00311 }
00312 return 0;
00313 }
00314
00315 GPList<DjVuPort>
00316 DjVuPortcaster::prefix_to_ports(const GUTF8String &prefix)
00317 {
00318 GPList<DjVuPort> list;
00319 {
00320 int length=prefix.length();
00321 if (length)
00322 {
00323 GCriticalSectionLock lock(&map_lock);
00324 for(GPosition pos=a2p_map;pos;++pos)
00325 if (!prefix.cmp(a2p_map.key(pos), length))
00326 {
00327 DjVuPort * port=(DjVuPort *) a2p_map[pos];
00328 GP<DjVuPort> gp_port=is_port_alive(port);
00329 if (gp_port) list.append(gp_port);
00330 }
00331 }
00332 }
00333 return list;
00334 }
00335
00336 void
00337 DjVuPortcaster::del_port(const DjVuPort * port)
00338 {
00339 GCriticalSectionLock lock(&map_lock);
00340
00341 GPosition pos;
00342
00343
00344 clear_aliases(port);
00345
00346
00347 if (cont_map.contains(port, pos)) cont_map.del(pos);
00348
00349
00350 if (route_map.contains(port, pos))
00351 {
00352 delete (GList<void *> *) route_map[pos];
00353 route_map.del(pos);
00354 }
00355 for(pos=route_map;pos;)
00356 {
00357 GList<void *> & list=*(GList<void *> *) route_map[pos];
00358 GPosition list_pos;
00359 if (list.search((void *) port, list_pos)) list.del(list_pos);
00360 if (!list.size())
00361 {
00362 delete &list;
00363 GPosition tmp_pos=pos;
00364 ++pos;
00365 route_map.del(tmp_pos);
00366 } else ++pos;
00367 }
00368 }
00369
00370 void
00371 DjVuPortcaster::add_route(const DjVuPort * src, DjVuPort * dst)
00372
00373 {
00374 GCriticalSectionLock lock(&map_lock);
00375 if (cont_map.contains(src) && src->get_count()>0 &&
00376 cont_map.contains(dst) && dst->get_count()>0)
00377 {
00378 if (!route_map.contains(src)) route_map[src]=new GList<void *>();
00379 GList<void *> & list=*(GList<void *> *) route_map[src];
00380 if (!list.contains(dst)) list.append(dst);
00381 }
00382 }
00383
00384 void
00385 DjVuPortcaster::del_route(const DjVuPort * src, DjVuPort * dst)
00386
00387 {
00388 GCriticalSectionLock lock(&map_lock);
00389
00390 if (route_map.contains(src))
00391 {
00392 GList<void *> & list=*(GList<void *> *) route_map[src];
00393 GPosition pos;
00394 if (list.search(dst, pos)) list.del(pos);
00395 if (!list.size())
00396 {
00397 delete &list;
00398 route_map.del(src);
00399 }
00400 }
00401 }
00402
00403 void
00404 DjVuPortcaster::copy_routes(DjVuPort * dst, const DjVuPort * src)
00405
00406
00407
00408 {
00409 GCriticalSectionLock lock(&map_lock);
00410
00411 if (!cont_map.contains(src) || src->get_count()<=0 ||
00412 !cont_map.contains(dst) || dst->get_count()<=0) return;
00413
00414 for(GPosition pos=route_map;pos;++pos)
00415 {
00416 GList<void *> & list=*(GList<void *> *) route_map[pos];
00417 if (route_map.key(pos) == src)
00418 for(GPosition pos=list;pos;++pos)
00419 add_route(dst, (DjVuPort *) list[pos]);
00420 for(GPosition pos=list;pos;++pos)
00421 if ((DjVuPort*)(list[pos]) == src)
00422 add_route((DjVuPort *) route_map.key(pos), dst);
00423 }
00424 }
00425
00426 void
00427 DjVuPortcaster::add_to_closure(GMap<const void *, void *> & set,
00428 const DjVuPort * dst, int distance)
00429 {
00430
00431
00432 set[dst]= (void*) (unsigned long) distance;
00433 if (route_map.contains(dst))
00434 {
00435 GList<void *> & list=*(GList<void *> *) route_map[dst];
00436 for(GPosition pos=list;pos;++pos)
00437 {
00438 DjVuPort * new_dst=(DjVuPort *) list[pos];
00439 if (!set.contains(new_dst))
00440 add_to_closure(set, new_dst, distance+1);
00441 }
00442 }
00443 }
00444
00445 void
00446 DjVuPortcaster::compute_closure(const DjVuPort * src, GPList<DjVuPort> &list, bool sorted)
00447 {
00448 GCriticalSectionLock lock(&map_lock);
00449 GMap<const void*, void*> set;
00450 if (route_map.contains(src))
00451 {
00452 GList<void *> & list=*(GList<void *> *) route_map[src];
00453 for(GPosition pos=list;pos;++pos)
00454 {
00455 DjVuPort * dst=(DjVuPort *) list[pos];
00456 if (dst==src) add_to_closure(set, src, 0);
00457 else add_to_closure(set, dst, 1);
00458 }
00459 }
00460
00461
00462 GPosition pos;
00463 if (sorted)
00464 {
00465
00466 int max_dist=0;
00467 for(pos=set;pos;++pos)
00468 if (max_dist < (int)(long)set[pos])
00469 max_dist = (int)(long)set[pos];
00470 GArray<GList<const void*> > lists(0,max_dist);
00471 for(pos=set;pos;++pos)
00472 lists[(int)(long)set[pos]].append(set.key(pos));
00473 for(int dist=0;dist<=max_dist;dist++)
00474 for(pos=lists[dist];pos;++pos)
00475 {
00476 GP<DjVuPort> p = is_port_alive((DjVuPort*) lists[dist][pos]);
00477 if (p) list.append(p);
00478 }
00479 }
00480 else
00481 {
00482
00483 for(pos=set;pos;++pos)
00484 {
00485 GP<DjVuPort> p = is_port_alive((DjVuPort*) set.key(pos));
00486 if (p) list.append(p);
00487 }
00488 }
00489 }
00490
00491 GURL
00492 DjVuPortcaster::id_to_url(const DjVuPort * source, const GUTF8String &id)
00493 {
00494 GPList<DjVuPort> list;
00495 compute_closure(source, list, true);
00496 GURL url;
00497 for(GPosition pos=list;pos;++pos)
00498 {
00499 url=list[pos]->id_to_url(source, id);
00500 if (!url.is_empty()) break;
00501 }
00502 return url;
00503 }
00504
00505 GP<DjVuFile>
00506 DjVuPortcaster::id_to_file(const DjVuPort * source, const GUTF8String &id)
00507 {
00508 GPList<DjVuPort> list;
00509 compute_closure(source, list, true);
00510 GP<DjVuFile> file;
00511 for(GPosition pos=list;pos;++pos)
00512 if ((file=list[pos]->id_to_file(source, id))) break;
00513 return file;
00514 }
00515
00516 GP<DataPool>
00517 DjVuPortcaster::request_data(const DjVuPort * source, const GURL & url)
00518 {
00519 GPList<DjVuPort> list;
00520 compute_closure(source, list, true);
00521 GP<DataPool> data;
00522 for(GPosition pos=list;pos;++pos)
00523 if ((data = list[pos]->request_data(source, url)))
00524 break;
00525 return data;
00526 }
00527
00528 bool
00529 DjVuPortcaster::notify_error(const DjVuPort * source, const GUTF8String &msg)
00530 {
00531 GPList<DjVuPort> list;
00532 compute_closure(source, list, true);
00533 for(GPosition pos=list;pos;++pos)
00534 if (list[pos]->notify_error(source, msg))
00535 return 1;
00536 return 0;
00537 }
00538
00539 bool
00540 DjVuPortcaster::notify_status(const DjVuPort * source, const GUTF8String &msg)
00541 {
00542 GPList<DjVuPort> list;
00543 compute_closure(source, list, true);
00544 for(GPosition pos=list;pos;++pos)
00545 if (list[pos]->notify_status(source, msg))
00546 return 1;
00547 return 0;
00548 }
00549
00550 void
00551 DjVuPortcaster::notify_redisplay(const DjVuImage * source)
00552 {
00553 GPList<DjVuPort> list;
00554 compute_closure(source, list);
00555 for(GPosition pos=list; pos; ++pos)
00556 list[pos]->notify_redisplay(source);
00557 }
00558
00559 void
00560 DjVuPortcaster::notify_relayout(const DjVuImage * source)
00561 {
00562 GPList<DjVuPort> list;
00563 compute_closure(source, list);
00564 for(GPosition pos=list; pos; ++pos)
00565 list[pos]->notify_relayout(source);
00566 }
00567
00568 void
00569 DjVuPortcaster::notify_chunk_done(const DjVuPort * source, const GUTF8String &name)
00570 {
00571 GPList<DjVuPort> list;
00572 compute_closure(source, list);
00573 for(GPosition pos=list; pos; ++pos)
00574 list[pos]->notify_chunk_done(source, name);
00575 }
00576
00577 void
00578 DjVuPortcaster::notify_file_flags_changed(const DjVuFile * source,
00579 long set_mask, long clr_mask)
00580 {
00581 GPList<DjVuPort> list;
00582 compute_closure(source, list);
00583 for(GPosition pos=list; pos; ++pos)
00584 list[pos]->notify_file_flags_changed(source, set_mask, clr_mask);
00585 }
00586
00587 void
00588 DjVuPortcaster::notify_doc_flags_changed(const DjVuDocument * source,
00589 long set_mask, long clr_mask)
00590 {
00591 GPList<DjVuPort> list;
00592 compute_closure(source, list);
00593 for(GPosition pos=list; pos; ++pos)
00594 list[pos]->notify_doc_flags_changed(source, set_mask, clr_mask);
00595 }
00596
00597 void
00598 DjVuPortcaster::notify_decode_progress(const DjVuPort * source, float done)
00599 {
00600 GPList<DjVuPort> list;
00601 compute_closure(source, list);
00602 for(GPosition pos=list; pos; ++pos)
00603 list[pos]->notify_decode_progress(source, done);
00604 }
00605
00606
00607
00608
00609
00610 GURL
00611 DjVuPort::id_to_url(const DjVuPort *, const GUTF8String &) { return GURL(); }
00612
00613 GP<DjVuFile>
00614 DjVuPort::id_to_file(const DjVuPort *, const GUTF8String &) { return 0; }
00615
00616 GP<DataPool>
00617 DjVuPort::request_data(const DjVuPort *, const GURL &) { return 0; }
00618
00619 bool
00620 DjVuPort::notify_error(const DjVuPort *, const GUTF8String &) { return 0; }
00621
00622 bool
00623 DjVuPort::notify_status(const DjVuPort *, const GUTF8String &) { return 0; }
00624
00625 void
00626 DjVuPort::notify_redisplay(const DjVuImage *) {}
00627
00628 void
00629 DjVuPort::notify_relayout(const DjVuImage *) {}
00630
00631 void
00632 DjVuPort::notify_chunk_done(const DjVuPort *, const GUTF8String &) {}
00633
00634 void
00635 DjVuPort::notify_file_flags_changed(const DjVuFile *, long, long) {}
00636
00637 void
00638 DjVuPort::notify_doc_flags_changed(const DjVuDocument *, long, long) {}
00639
00640 void
00641 DjVuPort::notify_decode_progress(const DjVuPort *, float) {}
00642
00643
00644
00645
00646
00647 GP<DataPool>
00648 DjVuSimplePort::request_data(const DjVuPort * source, const GURL & url)
00649 {
00650 G_TRY {
00651 if (url.is_local_file_url())
00652 {
00653
00654
00655 return DataPool::create(url);
00656 }
00657 } G_CATCH_ALL {} G_ENDCATCH;
00658 return 0;
00659 }
00660
00661 bool
00662 DjVuSimplePort::notify_error(const DjVuPort * source, const GUTF8String &msg)
00663 {
00664 DjVuMessageLite::perror(msg);
00665 return 1;
00666 }
00667
00668 bool
00669 DjVuSimplePort::notify_status(const DjVuPort * source, const GUTF8String &msg)
00670 {
00671 DjVuMessageLite::perror(msg);
00672 return 1;
00673 }
00674
00675
00676
00677
00678
00679
00680
00681
00682
00683
00684
00685 GP<DataPool>
00686 DjVuMemoryPort::request_data(const DjVuPort * source, const GURL & url)
00687 {
00688 GCriticalSectionLock lk(&lock);
00689 GP<DataPool> pool;
00690 GPosition pos;
00691 if (map.contains(url, pos))
00692 pool=map[pos];
00693 return pool;
00694 }
00695
00696 void
00697 DjVuMemoryPort::add_data(const GURL & url, const GP<DataPool> & pool)
00698 {
00699 GCriticalSectionLock lk(&lock);
00700 map[url]=pool;
00701 }
00702
00703
00704 #ifdef HAVE_NAMESPACES
00705 }
00706 # ifndef NOT_USING_DJVU_NAMESPACE
00707 using namespace DJVU;
00708 # endif
00709 #endif
00710