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 "DataPool.h"
00065 #include "IFFByteStream.h"
00066 #include "GString.h"
00067 #include "GOS.h"
00068 #include "GURL.h"
00069 #include "debug.h"
00070
00071 #ifndef macintosh
00072 # include <sys/types.h>
00073 #endif
00074
00075 #ifdef HAVE_NAMESPACES
00076 namespace DJVU {
00077 # ifdef NOT_DEFINED // Just to fool emacs c++ mode
00078 }
00079 #endif
00080 #endif
00081
00082 const char * DataPool::Stop = ERR_MSG("STOP");
00083
00084 static void
00085
00086 call_callback(void (* callback)(void *), void *cl_data)
00087 {
00088 G_TRY
00089 {
00090 if (callback)
00091 callback(cl_data);
00092 } G_CATCH_ALL {} G_ENDCATCH;
00093 }
00094
00095
00096
00097
00098
00099
00100 #define MAX_OPEN_FILES 15
00101
00111 class DataPool::OpenFiles_File : public GPEnabled
00112 {
00113 public:
00114 GURL url;
00115 GP<ByteStream> stream;
00116 GCriticalSection stream_lock;
00117 GPList<DataPool> pools_list;
00118 GCriticalSection pools_lock;
00119 unsigned long open_time;
00120
00121 int add_pool(GP<DataPool> &pool);
00122 int del_pool(GP<DataPool> &pool);
00123
00124 OpenFiles_File(const GURL &url, GP<DataPool> &pool);
00125 virtual ~OpenFiles_File(void);
00126 void clear_stream(void);
00127 };
00128
00129 class DataPool::OpenFiles : public GPEnabled
00130 {
00131 private:
00132 static OpenFiles * global_ptr;
00133
00134 GPList<DataPool::OpenFiles_File> files_list;
00135 GCriticalSection files_lock;
00136 public:
00137 static OpenFiles * get(void);
00138
00139
00140
00141
00142
00143
00144 GP<DataPool::OpenFiles_File> request_stream(const GURL &url, GP<DataPool> pool);
00145
00146 void prune(void);
00147
00148
00149
00150 void stream_released(GP<ByteStream> &stream, GP<DataPool> pool);
00151
00152 void close_all(void);
00153 };
00154
00155 DataPool::OpenFiles * DataPool::OpenFiles::global_ptr;
00156
00157 DataPool::OpenFiles_File::OpenFiles_File(const GURL &xurl, GP<DataPool> &pool) : url(xurl)
00158 {
00159 DEBUG_MSG("DataPool::OpenFiles_File::OpenFiles_File(): Opening file '" << url << "'\n");
00160 DEBUG_MAKE_INDENT(3);
00161
00162 open_time=GOS::ticks();
00163 stream=ByteStream::create(url,"rb");
00164 add_pool(pool);
00165 }
00166
00167 DataPool::OpenFiles_File::~OpenFiles_File(void)
00168 {
00169 DEBUG_MSG("DataPool::OpenFiles_File::~OpenFiles_File(): Closing file '" << url << "'\n");
00170 DEBUG_MAKE_INDENT(3);
00171 clear_stream();
00172 }
00173
00174 void
00175 DataPool::OpenFiles_File::clear_stream(void)
00176 {
00177 GCriticalSectionLock lock(&pools_lock);
00178 for(GPosition pos=pools_list;pos;++pos)
00179 if(pools_list[pos])
00180 pools_list[pos]->clear_stream(false);
00181 pools_list.empty();
00182 }
00183
00184 int
00185 DataPool::OpenFiles_File::add_pool(GP<DataPool> &pool)
00186 {
00187 DEBUG_MSG("DataPool::OpenFiles_File::add_pool: pool=" << (void *) pool << "\n");
00188 DEBUG_MAKE_INDENT(3);
00189 GCriticalSectionLock lock(&pools_lock);
00190 if (!pools_list.contains(pool))
00191 pools_list.append(pool);
00192 return pools_list.size();
00193 }
00194
00195 int
00196 DataPool::OpenFiles_File::del_pool(GP<DataPool> &pool)
00197 {
00198 DEBUG_MSG("DataPool::OpenFiles_File::del_pool: pool=" << (void *) pool << "\n");
00199 DEBUG_MAKE_INDENT(3);
00200 GCriticalSectionLock lock(&pools_lock);
00201 GPosition pos;
00202 if (pools_list.search(pool, pos))
00203 pools_list.del(pos);
00204 return pools_list.size();
00205 }
00206
00207 inline DataPool::OpenFiles *
00208 DataPool::OpenFiles::get(void)
00209 {
00210 DEBUG_MSG("DataPool::OpenFiles::get()\n");
00211 DEBUG_MAKE_INDENT(3);
00212 if (!global_ptr)
00213 global_ptr=new OpenFiles();
00214 return global_ptr;
00215 }
00216
00217 void
00218 DataPool::OpenFiles::prune(void)
00219 {
00220 DEBUG_MSG("DataPool::OpenFiles::prune(void): "<<files_list.size()<< "\n");
00221 DEBUG_MAKE_INDENT(3);
00222 while(files_list.size()>MAX_OPEN_FILES)
00223 {
00224
00225 unsigned long oldest_time=GOS::ticks();
00226 GPosition oldest_pos=files_list;
00227 for(GPosition pos=files_list;pos;++pos)
00228 {
00229 if (files_list[pos]->open_time<oldest_time)
00230 {
00231 oldest_time=files_list[pos]->open_time;
00232 oldest_pos=pos;
00233 }
00234 }
00235 files_list[oldest_pos]->clear_stream();
00236 files_list.del(oldest_pos);
00237 }
00238 }
00239
00240
00241
00242 GP<DataPool::OpenFiles_File>
00243 DataPool::OpenFiles::request_stream(const GURL &url, GP<DataPool> pool)
00244 {
00245 DEBUG_MSG("DataPool::OpenFiles::request_stream(): url='" << url << "'\n");
00246 DEBUG_MAKE_INDENT(3);
00247
00248 GP<DataPool::OpenFiles_File> file;
00249
00250
00251
00252 GCriticalSectionLock lock(&files_lock);
00253 for(GPosition pos=files_list;pos;++pos)
00254 {
00255 if (files_list[pos]->url==url)
00256 {
00257 DEBUG_MSG("found existing stream\n");
00258 file=files_list[pos];
00259 break;
00260 }
00261 }
00262
00263
00264
00265 if (!file)
00266 {
00267 file=new DataPool::OpenFiles_File(url, pool);
00268 files_list.append(file);
00269 prune();
00270 }
00271
00272 file->add_pool(pool);
00273 return file;
00274 }
00275
00276 void
00277 DataPool::OpenFiles::stream_released(GP<ByteStream> &stream, GP<DataPool> pool)
00278 {
00279 DEBUG_MSG("DataPool::OpenFiles::stream_release: stream="
00280 << (void *)stream << " pool=" << (void *)pool << "\n");
00281 DEBUG_MAKE_INDENT(3);
00282 GCriticalSectionLock lock(&files_lock);
00283 for(GPosition pos=files_list;pos;)
00284 {
00285 GPosition dpos = pos;
00286 ++pos;
00287 GP<DataPool::OpenFiles_File> f=files_list[dpos];
00288 if ((ByteStream *)(f->stream) == (ByteStream *)stream)
00289 if (f->del_pool(pool)==0)
00290 files_list.del(dpos);
00291 }
00292 }
00293
00294
00295
00296
00297
00298 void
00299 DataPool::OpenFiles::close_all(void)
00300 {
00301 DEBUG_MSG("DataPool::OpenFiles::close_all\n");
00302 DEBUG_MAKE_INDENT(3);
00303 GCriticalSectionLock lock(&files_lock);
00304 files_list.empty();
00305 }
00306
00307
00308
00309
00310
00317 class FCPools
00318 {
00319 private:
00320 GMap<GURL, GPList<DataPool> > map;
00321 GCriticalSection map_lock;
00322
00323 static FCPools * global_ptr;
00324 public:
00325 static FCPools * get(void);
00326
00327 void add_pool(const GURL &furl, GP<DataPool> pool);
00328
00329 void del_pool(const GURL &furl, GP<DataPool> pool);
00330
00331
00332 void load_file(const GURL &url);
00333
00334 GP<DataPool> get_pool(const GURL &url, int start, int length);
00335 void clean(void);
00336 };
00337
00338 void
00339 FCPools::clean(void)
00340 {
00341 GCriticalSectionLock lock(&map_lock);
00342 static int count=0;
00343 if(! count++)
00344 {
00345 bool restart = true;
00346 while (restart)
00347 {
00348 restart = false;
00349 for (GPosition posmap = map; posmap; ++posmap)
00350 {
00351 GPList<DataPool> *lst;
00352 lst = & map[posmap];
00353 if (lst->isempty())
00354 {
00355 map.del(posmap);
00356 restart = true;
00357 break;
00358 }
00359 for (GPosition poslst = *lst; poslst; ++poslst)
00360 if ((*lst)[poslst]->get_count() < 2)
00361 {
00362 lst->del(poslst);
00363 restart = true;
00364 break;
00365 }
00366 if (restart)
00367 break;
00368 }
00369 }
00370 }
00371 --count;
00372 }
00373
00374 void
00375 FCPools::add_pool(const GURL &url, GP<DataPool> pool)
00376 {
00377 DEBUG_MSG("FCPools::add_pool: url='" << url << "' pool=" << (void *)pool << "\n");
00378 DEBUG_MAKE_INDENT(3);
00379 GCriticalSectionLock lock(&map_lock);
00380
00381 if (url.is_local_file_url())
00382 {
00383 GPList<DataPool> list;
00384 GPosition pos(map.contains(url));
00385 if (! pos)
00386 {
00387 map[url]=list;
00388 pos=map.contains(url);
00389 }
00390 GPList<DataPool> &plist=map[pos];
00391 if (!plist.contains(pool))
00392 plist.append(pool);
00393 }
00394 clean();
00395 }
00396
00397 GP<DataPool>
00398 FCPools::get_pool(const GURL &url, int start, int length)
00399 {
00400 DEBUG_MSG("FCPools::get_pool: url='" << url << "\n");
00401 DEBUG_MAKE_INDENT(3);
00402 GP<DataPool> retval;
00403 if (url.is_local_file_url())
00404 {
00405 GCriticalSectionLock lock(&map_lock);
00406 GPosition pos(map.contains(url));
00407 if (pos)
00408 {
00409 GPList<DataPool> &plist=map[pos];
00410 for(pos=plist;pos;++pos)
00411 {
00412 DataPool &pool=*plist[pos];
00413 if(start == pool.start && (length < 0 || (length == pool.length)))
00414 {
00415 retval=plist[pos];
00416 break;
00417 }
00418 }
00419 }
00420 clean();
00421 }
00422 return retval;
00423 }
00424
00425 void
00426 FCPools::del_pool(const GURL &url, GP<DataPool> pool)
00427 {
00428 DEBUG_MSG("FCPools::del_pool: url='" << url << "' pool=" << (void *)pool << "\n");
00429 DEBUG_MAKE_INDENT(3);
00430 GCriticalSectionLock lock(&map_lock);
00431
00432 clean();
00433 if (url.is_local_file_url())
00434 {
00435 GPosition pos;
00436 if (map.contains(url, pos))
00437 {
00438 GPList<DataPool> &list=map[pos];
00439 GPosition list_pos;
00440 while(list.search(pool, list_pos))
00441 list.del(list_pos);
00442 if (list.isempty())
00443 {
00444 map.del(pos);
00445 }
00446 }
00447 }
00448 }
00449
00450 void
00451 FCPools::load_file(const GURL &url)
00452 {
00453 DEBUG_MSG("FCPools::load_file: url='" << url << "'\n");
00454 DEBUG_MAKE_INDENT(3);
00455 GCriticalSectionLock lock(&map_lock);
00456
00457 clean();
00458 if (url.is_local_file_url())
00459 {
00460 GPosition pos;
00461 if (map.contains(url, pos))
00462 {
00463
00464
00465 GPList<DataPool> list=map[pos];
00466 for(GPosition list_pos=list;list_pos;++list_pos)
00467 list[list_pos]->load_file();
00468 }
00469 }
00470 }
00471
00472 FCPools * FCPools::global_ptr;
00473
00474 inline FCPools *
00475 FCPools::get(void)
00476 {
00477 if (!global_ptr)
00478 global_ptr=new FCPools();
00479 return global_ptr;
00480 }
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493 class DataPool::BlockList
00494 {
00495
00496 private:
00497 GCriticalSection lock;
00498 GList<int> list;
00499 public:
00500 BlockList() {};
00501 void clear(void);
00502 void add_range(int start, int length);
00503 int get_bytes(int start, int length) const;
00504 int get_range(int start, int length) const;
00505 friend class DataPool;
00506 };
00507
00508 void
00509 DataPool::BlockList::clear(void)
00510 {
00511 DEBUG_MSG("DataPool::BlockList::clear()\n");
00512 DEBUG_MAKE_INDENT(3);
00513 GCriticalSectionLock lk(&lock);
00514 list.empty();
00515 }
00516
00517 void
00518 DataPool::BlockList::add_range(int start, int length)
00519
00520 {
00521 DEBUG_MSG("DataPool::BlockList::add_range: start=" << start << " length=" << length << "\n");
00522 DEBUG_MAKE_INDENT(3);
00523 if (start<0)
00524 G_THROW( ERR_MSG("DataPool.neg_start") );
00525 if (length<=0)
00526 G_THROW( ERR_MSG("DataPool.bad_length") );
00527 if (length>0)
00528 {
00529 GCriticalSectionLock lk(&lock);
00530
00531
00532
00533 GPosition pos=list;
00534 int block_start=0, block_end=0;
00535 while(pos && block_start<start+length)
00536 {
00537 int size=list[pos];
00538 block_end=block_start+abs(size);
00539 if (size<0)
00540 if (block_start<start)
00541 {
00542 if (block_end>start && block_end<=start+length)
00543 {
00544 list[pos]=-(start-block_start);
00545 list.insert_after(pos, block_end-start);
00546 ++pos;
00547 block_start=start;
00548 } else if (block_end>start+length)
00549 {
00550 list[pos]=-(start-block_start);
00551 list.insert_after(pos, length);
00552 ++pos;
00553 list.insert_after(pos, -(block_end-(start+length)));
00554 ++pos;
00555 block_start=start+length;
00556 }
00557 } else if (block_start>=start && block_start<start+length)
00558 {
00559 if (block_end<=start+length) list[pos]=abs(size);
00560 else
00561 {
00562 list[pos]=start+length-block_start;
00563 list.insert_after(pos, -(block_end-(start+length)));
00564 ++pos;
00565 block_start=start+length;
00566 }
00567 }
00568 block_start=block_end;
00569 ++pos;
00570 }
00571 if (block_end<start)
00572 {
00573 list.append(-(start-block_end));
00574 list.append(length);
00575 } else if (block_end<start+length) list.append(start+length-block_end);
00576
00577
00578 pos=list;
00579 while(pos)
00580 {
00581 GPosition pos1=pos; ++pos1;
00582 while(pos1)
00583 {
00584 if (list[pos]<0 && list[pos1]>0 ||
00585 list[pos]>0 && list[pos1]<0)
00586 break;
00587 list[pos]+=list[pos1];
00588 GPosition this_pos=pos1;
00589 ++pos1;
00590 list.del(this_pos);
00591 }
00592 pos=pos1;
00593 }
00594 }
00595 }
00596
00597 int
00598 DataPool::BlockList::get_bytes(int start, int length) const
00599
00600
00601 {
00602 DEBUG_MSG("DataPool::BlockList::get_bytes: start=" << start << " length=" << length << "\n");
00603 DEBUG_MAKE_INDENT(3);
00604
00605 if (length<0)
00606 G_THROW( ERR_MSG("DataPool.bad_length") );
00607
00608 GCriticalSectionLock lk((GCriticalSection *) &lock);
00609 int bytes=0;
00610 int block_start=0, block_end=0;
00611 for(GPosition pos=list;pos && block_start<start+length;++pos)
00612 {
00613 int size=list[pos];
00614 block_end=block_start+abs(size);
00615 if (size>0)
00616 if (block_start<start)
00617 {
00618 if (block_end>=start && block_end<start+length)
00619 bytes+=block_end-start;
00620 else if (block_end>=start+length)
00621 bytes+=length;
00622 } else
00623 {
00624 if (block_end<=start+length)
00625 bytes+=block_end-block_start;
00626 else bytes+=start+length-block_start;
00627 }
00628 block_start=block_end;
00629 }
00630 return bytes;
00631 }
00632
00633 int
00634 DataPool::BlockList::get_range(int start, int length) const
00635
00636
00637
00638 {
00639 DEBUG_MSG("DataPool::BlockList::get_range: start=" << start << " length=" << length << "\n");
00640 DEBUG_MAKE_INDENT(3);
00641 if (start<0)
00642 G_THROW( ERR_MSG("DataPool.neg_start") );
00643 if (length<=0)
00644 G_THROW( ERR_MSG("DataPool.bad_length") );
00645
00646 GCriticalSectionLock lk((GCriticalSection *) &lock);
00647 int block_start=0, block_end=0;
00648 for(GPosition pos=list;pos && block_start<start+length;++pos)
00649 {
00650 int size=list[pos];
00651 block_end=block_start+abs(size);
00652 if (block_start<=start && block_end>start)
00653 if (size<0) return -1;
00654 else
00655 if (block_end>start+length) return length;
00656 else return block_end-start;
00657 block_start=block_end;
00658 }
00659 return 0;
00660 }
00661
00662
00663
00664
00665
00666 class DataPool::Reader : public GPEnabled
00667 {
00668 public:
00669 GEvent event;
00670 bool reenter_flag;
00671 int offset;
00672 int size;
00673 Reader() : reenter_flag(false), offset(0), size(-1){};
00674 Reader(int offset_in, int size_in=-1) :
00675 reenter_flag(false), offset(offset_in), size(size_in) {};
00676 virtual ~Reader() {};
00677 };
00678
00679 class DataPool::Trigger : public GPEnabled
00680 {
00681 public:
00682 GSafeFlags disabled;
00683 int start, length;
00684
00685 void (* callback)(void *);
00686
00687 void *cl_data;
00688
00689 Trigger() : start(0), length(-1), callback(0), cl_data(0) {};
00690 Trigger(int xstart, int xlength,
00691
00692 void (* xcallback)(void *), void *xcl_data) :
00693 start(xstart), length(xlength), callback(xcallback), cl_data(xcl_data) {};
00694 virtual ~Trigger() {};
00695 };
00696
00697 class DataPool::Counter
00698 {
00699 private:
00700 int counter;
00701 GCriticalSection lock;
00702 public:
00703 Counter() : counter(0) {};
00704 operator int(void) const;
00705 void inc(void);
00706 void dec(void);
00707 };
00708
00709 #define DATAPOOL_INIT eof_flag(false),stop_flag(false), \
00710 stop_blocked_flag(false), \
00711 add_at(0),start(0),length(-1)
00712
00713 void
00714 DataPool::init(void)
00715 {
00716 DEBUG_MSG("DataPool::init(): Initializing\n");
00717 DEBUG_MAKE_INDENT(3);
00718 start=0; length=-1; add_at=0;
00719 eof_flag=false;
00720 stop_flag=false;
00721 stop_blocked_flag=false;
00722
00723 active_readers=new Counter;
00724 block_list=0;
00725 G_TRY
00726 {
00727 block_list=new BlockList;
00728 data=ByteStream::create();
00729 }
00730 G_CATCH_ALL
00731 {
00732 delete block_list;
00733 block_list=0;
00734 delete active_readers;
00735 active_readers=0;
00736 G_RETHROW;
00737 }
00738 G_ENDCATCH;
00739 }
00740
00741 DataPool::DataPool(void) : DATAPOOL_INIT {}
00742
00743 GP<DataPool>
00744 DataPool::create(void)
00745 {
00746 DEBUG_MSG("DataPool::DataPool()\n");
00747 DEBUG_MAKE_INDENT(3);
00748 DataPool *pool=new DataPool();
00749
00750 GP<DataPool> retval=pool;
00751 pool->init();
00752
00753
00754
00755 pool->add_trigger(0, 32, static_trigger_cb, pool);
00756 return retval;
00757 }
00758
00759 GP<DataPool>
00760 DataPool::create(const GP<ByteStream> &gstr)
00761 {
00762 DEBUG_MSG("DataPool::create: str="<<(ByteStream *)gstr<<"\n");
00763 DEBUG_MAKE_INDENT(3);
00764 DataPool *pool=new DataPool();
00765 GP<DataPool> retval=pool;
00766 pool->init();
00767
00768
00769 pool->add_trigger(0, 32, static_trigger_cb, pool);
00770
00771 pool->data=gstr->duplicate();
00772 pool->added_data(0,pool->data->size());
00773
00774
00775
00776
00777 pool->set_eof();
00778 return retval;
00779 }
00780
00781 GP<DataPool>
00782 DataPool::create(const GP<DataPool> & pool, int start, int length)
00783 {
00784 DEBUG_MSG("DataPool::DataPool: pool=" << (void *)((DataPool *)pool) << " start=" << start << " length= " << length << "\n");
00785 DEBUG_MAKE_INDENT(3);
00786
00787 DataPool *xpool=new DataPool();
00788 GP<DataPool> retval=xpool;
00789 xpool->init();
00790 xpool->connect(pool, start, length);
00791 return retval;
00792 }
00793
00794 GP<DataPool>
00795 DataPool::create(const GURL &furl, int start, int length)
00796 {
00797 DEBUG_MSG("DataPool::DataPool: furl='" << furl << "' start=" << start << " length= " << length << "\n");
00798 DEBUG_MAKE_INDENT(3);
00799
00800 GP<DataPool> retval=FCPools::get()->get_pool(furl,start,length);
00801 if(! retval)
00802 {
00803 DataPool *pool=new DataPool();
00804 retval=pool;
00805 pool->init();
00806 pool->connect(furl, start, length);
00807 }
00808 return retval;
00809 }
00810
00811 void
00812 DataPool::clear_stream(const bool release)
00813 {
00814 DEBUG_MSG("DataPool::clear_stream()\n");
00815 DEBUG_MAKE_INDENT(3);
00816 if(fstream)
00817 {
00818 GCriticalSectionLock lock1(&class_stream_lock);
00819 GP<OpenFiles_File> f=fstream;
00820 if(f)
00821 {
00822 GCriticalSectionLock lock2(&(f->stream_lock));
00823 fstream=0;
00824 if(release)
00825 OpenFiles::get()->stream_released(f->stream, this);
00826 }
00827 }
00828 }
00829
00830 DataPool::~DataPool(void)
00831 {
00832 DEBUG_MSG("DataPool::~DataPool()\n");
00833 DEBUG_MAKE_INDENT(3);
00834
00835 clear_stream(true);
00836 if (furl.is_local_file_url())
00837 {
00838 FCPools::get()->del_pool(furl, this);
00839 }
00840
00841 {
00842
00843 GCriticalSectionLock lock(&trigger_lock);
00844 if (pool)
00845 pool->del_trigger(static_trigger_cb, this);
00846 del_trigger(static_trigger_cb, this);
00847 }
00848
00849 if (pool)
00850 {
00851 GCriticalSectionLock lock(&triggers_lock);
00852 for(GPosition pos=triggers_list;pos;++pos)
00853 {
00854 GP<Trigger> trigger=triggers_list[pos];
00855 pool->del_trigger(trigger->callback, trigger->cl_data);
00856 }
00857 }
00858 delete block_list;
00859 delete active_readers;
00860 }
00861
00862 void
00863 DataPool::connect(const GP<DataPool> & pool_in, int start_in, int length_in)
00864 {
00865 DEBUG_MSG("DataPool::connect(): connecting to another DataPool\n");
00866 DEBUG_MAKE_INDENT(3);
00867
00868 if (pool) G_THROW( ERR_MSG("DataPool.connected1") );
00869 if (furl.is_local_file_url()) G_THROW( ERR_MSG("DataPool.connected2") );
00870 if (start_in<0) G_THROW( ERR_MSG("DataPool.neg_start") );
00871
00872 pool=pool_in;
00873 start=start_in;
00874 length=length_in;
00875
00876
00877 if (pool->has_data(start, length))
00878 eof_flag=true;
00879 else
00880 pool->add_trigger(start, length, static_trigger_cb, this);
00881
00882 data=0;
00883
00884 wake_up_all_readers();
00885
00886
00887 GCriticalSectionLock lock(&triggers_lock);
00888 for(GPosition pos=triggers_list;pos;++pos)
00889 {
00890 GP<Trigger> t=triggers_list[pos];
00891 int tlength=t->length;
00892 if (tlength<0 && length>0)
00893 tlength=length-t->start;
00894 pool->add_trigger(start+t->start, tlength, t->callback, t->cl_data);
00895 }
00896 }
00897
00898 void
00899 DataPool::connect(const GURL &furl_in, int start_in, int length_in)
00900 {
00901 DEBUG_MSG("DataPool::connect(): connecting to a file\n");
00902 DEBUG_MAKE_INDENT(3);
00903
00904 if (pool)
00905 G_THROW( ERR_MSG("DataPool.connected1") );
00906 if (furl.is_local_file_url())
00907 G_THROW( ERR_MSG("DataPool.connected2") );
00908 if (start_in<0)
00909 G_THROW( ERR_MSG("DataPool.neg_start") );
00910
00911
00912 if (furl_in.name() == "-")
00913 {
00914 DEBUG_MSG("This is stdin => just read the data...\n");
00915 DEBUG_MAKE_INDENT(3);
00916 char buffer[1024];
00917 int length;
00918 GP<ByteStream> gstr=ByteStream::create(furl_in, "rb");
00919 ByteStream &str=*gstr;
00920 while((length=str.read(buffer, 1024)))
00921 add_data(buffer, length);
00922 set_eof();
00923 } else if(furl_in.is_local_file_url())
00924 {
00925
00926
00927
00928 GP<ByteStream> str=ByteStream::create(furl_in,"rb");
00929 str->seek(0, SEEK_END);
00930 int file_size=str->tell();
00931
00932 furl=furl_in;
00933 start=start_in;
00934 length=length_in;
00935 if (start>=file_size)
00936 length=0;
00937 else if (length<0 || start+length>=file_size)
00938 length=file_size-start;
00939
00940 eof_flag=true;
00941
00942 if(str->is_static())
00943 {
00944 data=str;
00945 added_data(0,length);
00946 }else
00947 {
00948 data=0;
00949 }
00950
00951 FCPools::get()->add_pool(furl, this);
00952
00953 wake_up_all_readers();
00954
00955
00956 GCriticalSectionLock lock(&triggers_lock);
00957 for(GPosition pos=triggers_list;pos;++pos)
00958 {
00959 GP<Trigger> t=triggers_list[pos];
00960 call_callback(t->callback, t->cl_data);
00961 }
00962 triggers_list.empty();
00963 }
00964 }
00965
00966 int
00967 DataPool::get_length(void) const
00968 {
00969
00970
00971
00972 int retval=(-1);
00973 if (length>=0)
00974 {
00975 retval=length;
00976 }else if (pool)
00977 {
00978 int plength=pool->get_length();
00979 if (plength>=0)
00980 retval=plength-start;
00981 }
00982 return retval;
00983 }
00984
00985 int
00986 DataPool::get_size(int dstart, int dlength) const
00987 {
00988 if (dlength<0 && length>0)
00989 {
00990 dlength=length-dstart;
00991 if (dlength<0) return 0;
00992 }
00993
00994 if (pool) return pool->get_size(start+dstart, dlength);
00995 else if (furl.is_local_file_url())
00996 {
00997 if (start+dstart+dlength>length) return length-(start+dstart);
00998 else return dlength;
00999 } else
01000 {
01001 if (dlength<0)
01002 {
01003 GCriticalSectionLock lock((GCriticalSection *) &data_lock);
01004 dlength=data->size()-dstart;
01005 }
01006 return (dlength<0)?0:(block_list->get_bytes(dstart, dlength));
01007 }
01008 }
01009
01010 void
01011 DataPool::add_data(const void * buffer, int size)
01012
01013 {
01014 DEBUG_MSG("DataPool::add_data(): adding " << size << " bytes of data...\n");
01015 DEBUG_MAKE_INDENT(3);
01016
01017 add_data(buffer, add_at, size);
01018 add_at+=size;
01019 }
01020
01021 void
01022 DataPool::add_data(const void * buffer, int offset, int size)
01023 {
01024 DEBUG_MSG("DataPool::add_data(): adding " << size << " bytes at pos=" <<
01025 offset << "...\n");
01026 DEBUG_MAKE_INDENT(3);
01027
01028 if (furl.is_local_file_url() || pool)
01029 G_THROW( ERR_MSG("DataPool.add_data") );
01030
01031
01032 {
01033 GCriticalSectionLock lock(&data_lock);
01034 if (offset>data->size())
01035 {
01036 char ch=0;
01037 data->seek(0, SEEK_END);
01038 for(int i=data->size();i<offset;i++)
01039 data->write(&ch, 1);
01040 } else
01041 {
01042 data->seek(offset, SEEK_SET);
01043 data->writall(buffer, size);
01044 }
01045 }
01046
01047 added_data(offset, size);
01048 }
01049
01050 void
01051 DataPool::added_data(const int offset, const int size)
01052 {
01053
01054 block_list->add_range(offset, size);
01055
01056
01057 {
01058 GCriticalSectionLock lock(&readers_lock);
01059 for(GPosition pos=readers_list;pos;++pos)
01060 {
01061 GP<Reader> reader=readers_list[pos];
01062 if (block_list->get_bytes(reader->offset, 1))
01063 {
01064 DEBUG_MSG("waking up reader: offset=" << reader->offset <<
01065 ", size=" << reader->size << "\n");
01066 DEBUG_MAKE_INDENT(3);
01067 reader->event.set();
01068 }
01069 }
01070 }
01071
01072
01073 check_triggers();
01074
01075
01076
01077
01078
01079
01080
01081 GCriticalSectionLock lock(&data_lock);
01082 if (length>=0 && data->size()>=length)
01083 set_eof();
01084 }
01085
01086 bool
01087 DataPool::has_data(int dstart, int dlength)
01088 {
01089 if (dlength<0 && length>0)
01090 dlength=length-dstart;
01091 return (pool?(pool->has_data(start+dstart, dlength))
01092 :((furl.is_local_file_url())?(start+dstart+dlength<=length)
01093 :((dlength<0)?is_eof()
01094 :(block_list->get_bytes(dstart, dlength)==dlength))));
01095 }
01096
01097 int
01098 DataPool::get_data(void * buffer, int offset, int sz)
01099 {
01100 return get_data(buffer, offset, sz, 0);
01101 }
01102
01103 class DataPool::Incrementor
01104 {
01105 private:
01106 Counter & counter;
01107 public:
01108 Incrementor(Counter & xcounter) : counter(xcounter) {counter.inc();}
01109 ~Incrementor() {counter.dec();}
01110 };
01111
01112 int
01113 DataPool::get_data(void * buffer, int offset, int sz, int level)
01114 {
01115 DEBUG_MSG("DataPool::get_data()\n");
01116 DEBUG_MAKE_INDENT(3);
01117 Incrementor inc(*active_readers);
01118
01119 if (stop_flag)
01120 G_THROW( DataPool::Stop );
01121 if (stop_blocked_flag && !is_eof() &&
01122 !has_data(offset, sz))
01123 G_THROW( DataPool::Stop );
01124
01125 if (sz < 0)
01126 G_THROW( ERR_MSG("DataPool.bad_size") );
01127
01128 if (! sz)
01129 return 0;
01130
01131 if (pool)
01132 {
01133 DEBUG_MSG("DataPool::get_data(): from pool\n");
01134 DEBUG_MAKE_INDENT(3);
01135 int retval=0;
01136 if (length>0 && offset+sz>length)
01137 sz=length-offset;
01138 if (sz<0)
01139 sz=0;
01140 for(;;)
01141 {
01142
01143
01144
01145
01146
01147
01148
01149 G_TRY
01150 {
01151 if(stop_flag||stop_blocked_flag&&!is_eof()&&!has_data(offset, sz))
01152 G_THROW( DataPool::Stop );
01153 retval=pool->get_data(buffer, start+offset, sz, level+1);
01154 }
01155 G_CATCH(exc)
01156 {
01157 pool->clear_stream(true);
01158 if ((exc.get_cause() != GUTF8String( ERR_MSG("DataPool.reenter") ) ) || level)
01159 G_RETHROW;
01160 } G_ENDCATCH;
01161 pool->clear_stream(true);
01162 return retval;
01163 }
01164 }
01165 else if(data && data->is_static() && eof_flag)
01166 {
01167 DEBUG_MSG("DataPool::get_data(): static\n");
01168 DEBUG_MAKE_INDENT(3);
01169
01170 int size=block_list->get_range(offset, sz);
01171 if (size>0)
01172 {
01173
01174 GCriticalSectionLock lock(&data_lock);
01175 data->seek(offset, SEEK_SET);
01176 return data->readall(buffer, size);
01177 }
01178 return 0;
01179 }
01180 else if (furl.is_local_file_url())
01181 {
01182 DEBUG_MSG("DataPool::get_data(): from file\n");
01183 DEBUG_MAKE_INDENT(3);
01184 if (length>0 && offset+sz>length)
01185 sz=length-offset;
01186 if (sz<0)
01187 sz=0;
01188
01189 GP<OpenFiles_File> f=fstream;
01190 if (!f)
01191 {
01192 GCriticalSectionLock lock(&class_stream_lock);
01193 f=fstream;
01194 if(!f)
01195 {
01196 fstream=f=OpenFiles::get()->request_stream(furl, this);
01197 }
01198 }
01199 GCriticalSectionLock lock2(&(f->stream_lock));
01200 f->stream->seek(start+offset, SEEK_SET);
01201 return f->stream->readall(buffer, sz);
01202 }
01203 else
01204 {
01205 DEBUG_MSG("DataPool::get_data(): direct\n");
01206 DEBUG_MAKE_INDENT(3);
01207
01208 int size=block_list->get_range(offset, sz);
01209 if (size>0)
01210 {
01211
01212 GCriticalSectionLock lock(&data_lock);
01213 data->seek(offset, SEEK_SET);
01214 return data->readall(buffer, size);
01215 }
01216
01217
01218
01219
01220
01221
01222
01223
01224
01225
01226
01227
01228 if (eof_flag)
01229 {
01230 if (length>0 && offset<length)
01231 {
01232 G_THROW( ByteStream::EndOfFile );
01233 }
01234 else
01235 {
01236 return 0;
01237 }
01238 }
01239
01240
01241 DEBUG_MSG("DataPool::get_data(): There is no data in the pool.\n");
01242 DEBUG_MSG("offset=" << offset << ", size=" << sz <<
01243 ", data_size=" << data->size() << "\n");
01244 GP<Reader> reader=new Reader(offset, sz);
01245 G_TRY
01246 {
01247 {
01248 GCriticalSectionLock slock(&readers_lock);
01249 readers_list.append(reader);
01250 }
01251 wait_for_data(reader);
01252 }
01253 G_CATCH_ALL
01254 {
01255 {
01256 GCriticalSectionLock slock(&readers_lock);
01257 GPosition pos;
01258 if (readers_list.search(reader, pos)) readers_list.del(pos);
01259 }
01260 G_RETHROW;
01261 }
01262 G_ENDCATCH;
01263
01264 {
01265 GCriticalSectionLock slock(&readers_lock);
01266 GPosition pos;
01267 if (readers_list.search(reader, pos)) readers_list.del(pos);
01268 }
01269
01270
01271
01272
01273 return get_data(buffer, reader->offset, reader->size, level);
01274 }
01275 return 0;
01276 }
01277
01278 void
01279 DataPool::wait_for_data(const GP<Reader> & reader)
01280
01281
01282 {
01283 DEBUG_MSG("DataPool::wait_for_data(): waiting for data at offset=" << reader->offset <<
01284 ", length=" << reader->size << "\n");
01285 DEBUG_MAKE_INDENT(3);
01286
01287 #if THREADMODEL==NOTHREADS
01288 G_THROW( ERR_MSG("DataPool.no_threadless") );
01289 #else
01290 for(;;)
01291 {
01292 if (stop_flag)
01293 G_THROW( DataPool::Stop );
01294 if (reader->reenter_flag)
01295 G_THROW( ERR_MSG("DataPool.reenter") );
01296 if (eof_flag || block_list->get_bytes(reader->offset, 1))
01297 return;
01298 if (pool || furl.is_local_file_url())
01299 return;
01300
01301 if (stop_blocked_flag)
01302 G_THROW( DataPool::Stop );
01303
01304 DEBUG_MSG("calling event.wait()...\n");
01305 reader->event.wait();
01306 }
01307 #endif
01308
01309 DEBUG_MSG("Got some data to read\n");
01310 }
01311
01312 void
01313 DataPool::wake_up_all_readers(void)
01314 {
01315 DEBUG_MSG("DataPool::wake_up_all_readers(): waking up all readers\n");
01316 DEBUG_MAKE_INDENT(3);
01317
01318 GCriticalSectionLock lock(&readers_lock);
01319 for(GPosition pos=readers_list;pos;++pos)
01320 readers_list[pos]->event.set();
01321 }
01322
01323 void
01324 DataPool::set_eof(void)
01325
01326 {
01327 if (!furl.is_local_file_url() && !pool)
01328 {
01329 eof_flag=true;
01330
01331
01332 if (length<0)
01333 {
01334 GCriticalSectionLock lock(&data_lock);
01335 length=data->size();
01336 }
01337
01338
01339 wake_up_all_readers();
01340
01341
01342 check_triggers();
01343 }
01344 }
01345
01346 void
01347 DataPool::stop(bool only_blocked)
01348 {
01349 DEBUG_MSG("DataPool::stop(): Stopping this and dependent DataPools, only_blocked="
01350 << only_blocked << "\n");
01351 DEBUG_MAKE_INDENT(3);
01352
01353 if (only_blocked) stop_blocked_flag=true;
01354 else stop_flag=true;
01355
01356
01357 wake_up_all_readers();
01358
01359
01360
01361
01362
01363
01364 if (pool)
01365 {
01366
01367
01368
01369
01370
01371
01372 while(*active_readers)
01373 {
01374 #if (THREADMODEL==COTHREADS) || (THREADMODEL==MACTHREADS)
01375 GThread::yield();
01376 #endif
01377 pool->restart_readers();
01378 }
01379 }
01380 }
01381
01382 void
01383 DataPool::restart_readers(void)
01384 {
01385 DEBUG_MSG("DataPool::restart_readers(): telling all readers to reenter\n");
01386 DEBUG_MAKE_INDENT(3);
01387
01388 GCriticalSectionLock slock(&readers_lock);
01389 for(GPosition pos=readers_list;pos;++pos)
01390 {
01391 GP<Reader> reader=readers_list[pos];
01392 reader->reenter_flag=true;
01393 reader->event.set();
01394 }
01395
01396 if (pool)
01397 pool->restart_readers();
01398 }
01399
01400 void
01401 DataPool::load_file(void)
01402 {
01403 DEBUG_MSG("DataPool::load_file() called\n");
01404 DEBUG_MAKE_INDENT(3);
01405
01406 if (pool)
01407 {
01408 DEBUG_MSG("passing the request down.\n");
01409 pool->load_file();
01410 } else if (furl.is_local_file_url())
01411 {
01412 DEBUG_MSG("loading the data from \""<<(const char *)furl<<"\".\n");
01413
01414 GCriticalSectionLock lock1(&class_stream_lock);
01415 GP<OpenFiles_File> f=fstream;
01416 if (!f)
01417 {
01418 fstream=f=OpenFiles::get()->request_stream(furl, this);
01419 }
01420 {
01421 GCriticalSectionLock lock2(&(f->stream_lock));
01422
01423 data=ByteStream::create();
01424 block_list->clear();
01425 FCPools::get()->del_pool(furl, this);
01426 furl=GURL();
01427
01428 const GP<ByteStream> gbs=f->stream;
01429 gbs->seek(0, SEEK_SET);
01430 data=gbs->duplicate();
01431 added_data(0,data->size());
01432 set_eof();
01433
01434
01435
01436
01437
01438 OpenFiles::get()->stream_released(f->stream, this);
01439 }
01440 fstream=0;
01441 } else { DEBUG_MSG("Not connected\n"); }
01442 }
01443
01444 void
01445 DataPool::load_file(const GURL &url )
01446 {
01447 FCPools::get()->load_file(url);
01448 }
01449
01450 void
01451 DataPool::check_triggers(void)
01452
01453 {
01454 DEBUG_MSG("DataPool::check_triggers(): calling activated trigger callbacks.\n");
01455 DEBUG_MAKE_INDENT(3);
01456
01457 if (!pool && !furl.is_local_file_url())
01458 while(true)
01459 {
01460 GP<Trigger> trigger;
01461
01462
01463
01464
01465 {
01466 GCriticalSectionLock list_lock(&triggers_lock);
01467 for(GPosition pos=triggers_list;pos;++pos)
01468 {
01469 GP<Trigger> t=triggers_list[pos];
01470 if (is_eof() || t->length>=0 &&
01471 block_list->get_bytes(t->start, t->length)==t->length)
01472 {
01473 trigger=t;
01474 break;
01475 }
01476 }
01477 }
01478
01479 if (trigger)
01480 {
01481
01482
01483
01484
01485
01486 {
01487 GMonitorLock lock(&trigger->disabled);
01488 if (!trigger->disabled)
01489 call_callback(trigger->callback, trigger->cl_data);
01490 }
01491
01492
01493 GCriticalSectionLock list_lock(&triggers_lock);
01494 for(GPosition pos=triggers_list;pos;++pos)
01495 if (triggers_list[pos]==trigger)
01496 {
01497 triggers_list.del(pos);
01498 break;
01499 }
01500 } else break;
01501 }
01502 }
01503
01504 void
01505
01506 DataPool::add_trigger(int thresh, void (* callback)(void *), void * cl_data)
01507 {
01508 if (thresh>=0)
01509 add_trigger(0, thresh+1, callback, cl_data);
01510 else
01511 add_trigger(0, -1, callback, cl_data);
01512 }
01513
01514 void
01515 DataPool::add_trigger(int tstart, int tlength,
01516
01517 void (* callback)(void *), void * cl_data)
01518 {
01519 DEBUG_MSG("DataPool::add_trigger(): start=" << tstart <<
01520 ", length=" << tlength << ", func=" << (void *) callback << "\n");
01521 DEBUG_MAKE_INDENT(3);
01522
01523 if (callback)
01524 {
01525 if (is_eof())
01526 {
01527 call_callback(callback, cl_data);
01528 }else
01529 {
01530 if (pool)
01531 {
01532
01533
01534 if (tlength<0 && length>0) tlength=length-tstart;
01535 GP<Trigger> trigger=new Trigger(tstart, tlength, callback, cl_data);
01536 pool->add_trigger(start+tstart, tlength, callback, cl_data);
01537 GCriticalSectionLock lock(&triggers_lock);
01538 triggers_list.append(trigger);
01539 } else if (!furl.is_local_file_url())
01540 {
01541
01542 if (tlength>=0 && block_list->get_bytes(tstart, tlength)==tlength)
01543 call_callback(callback, cl_data);
01544 else
01545 {
01546 GCriticalSectionLock lock(&triggers_lock);
01547 triggers_list.append(new Trigger(tstart, tlength, callback, cl_data));
01548 }
01549 }
01550 }
01551 }
01552 }
01553
01554 void
01555
01556 DataPool::del_trigger(void (* callback)(void *), void * cl_data)
01557 {
01558 DEBUG_MSG("DataPool::del_trigger(): func=" << (void *) callback << "\n");
01559 DEBUG_MAKE_INDENT(3);
01560
01561 for(;;)
01562 {
01563 GP<Trigger> trigger;
01564 {
01565 GCriticalSectionLock lock(&triggers_lock);
01566 for(GPosition pos=triggers_list;pos;)
01567 {
01568 GP<Trigger> t=triggers_list[pos];
01569 if (t->callback==callback && t->cl_data==cl_data)
01570 {
01571 trigger=t;
01572 GPosition this_pos=pos;
01573 ++pos;
01574 triggers_list.del(this_pos);
01575 break;
01576 } else
01577 ++pos;
01578 }
01579 }
01580
01581
01582
01583
01584
01585
01586
01587 if (trigger)
01588 trigger->disabled=1;
01589 else
01590 break;
01591 }
01592
01593 if (pool)
01594 pool->del_trigger(callback, cl_data);
01595 }
01596
01597 void
01598
01599 DataPool::static_trigger_cb(void *cl_data)
01600 {
01601
01602 GP<DataPool> d=(DataPool *)cl_data;
01603 d->trigger_cb();
01604 }
01605
01606 void
01607 DataPool::trigger_cb(void)
01608
01609
01610 {
01611
01612
01613 GCriticalSectionLock lock(&trigger_lock);
01614
01615 DEBUG_MSG("DataPool::trigger_cb() called\n");
01616 DEBUG_MAKE_INDENT(3);
01617
01618 if (pool)
01619 {
01620
01621
01622
01623 if (pool->is_eof() || pool->has_data(start, length)) eof_flag=true;
01624 } else if (!furl.is_local_file_url())
01625 {
01626
01627 if (length<0) analyze_iff();
01628
01629
01630 if (length<0 && is_eof())
01631 {
01632 GCriticalSectionLock lock(&data_lock);
01633 length=data->size();
01634 }
01635 }
01636 }
01637
01638 void
01639 DataPool::analyze_iff(void)
01640
01641
01642
01643
01644
01645 {
01646 DEBUG_MSG("DataPool::analyze_iff(): Trying to decode IFF structure of " << furl << ".\n");
01647 DEBUG_MSG("in order to predict the DataPool's size\n");
01648 DEBUG_MAKE_INDENT(3);
01649
01650 GP<ByteStream> str=get_stream();
01651
01652 GP<IFFByteStream> giff=IFFByteStream::create(str);
01653 IFFByteStream &iff=*giff;
01654 GUTF8String chkid;
01655 int size;
01656 if ((size=iff.get_chunk(chkid)) && size>=0)
01657 {
01658 length=size+iff.tell()-4;
01659 DEBUG_MSG("Got size=" << size << ", length=" << length << "\n");
01660 }
01661 }
01662
01663
01664
01665
01666
01667
01668
01669
01670
01671
01672 class PoolByteStream : public ByteStream
01673 {
01674 public:
01675 PoolByteStream(GP<DataPool> data_pool);
01676 virtual ~PoolByteStream() {};
01677
01678 virtual size_t read(void *buffer, size_t size);
01679 virtual size_t write(const void *buffer, size_t size);
01680 virtual long tell(void) const ;
01681 virtual int seek(long offset, int whence = SEEK_SET, bool nothrow=false);
01682 private:
01683
01684
01685
01686
01687 DataPool * data_pool;
01688 GP<DataPool> data_pool_lock;
01689 long position;
01690
01691 char buffer[512];
01692 size_t buffer_size;
01693 size_t buffer_pos;
01694
01695
01696 PoolByteStream & operator=(const PoolByteStream &);
01697 };
01698
01699 inline
01700 PoolByteStream::PoolByteStream(GP<DataPool> xdata_pool) :
01701 data_pool(xdata_pool), position(0), buffer_size(0), buffer_pos(0)
01702 {
01703 if (!data_pool)
01704 G_THROW( ERR_MSG("DataPool.zero_DataPool") );
01705
01706
01707
01708 if (data_pool->get_count()) data_pool_lock=data_pool;
01709 }
01710
01711 size_t
01712 PoolByteStream::read(void *data, size_t size)
01713 {
01714 if (buffer_pos >= buffer_size) {
01715 if (size >= sizeof(buffer)) {
01716
01717 size = data_pool->get_data(data, position, size);
01718 position += size;
01719 return size;
01720 } else {
01721
01722 buffer_size = data_pool->get_data(buffer, position, sizeof(buffer));
01723 buffer_pos=0;
01724 }
01725 }
01726 if (buffer_pos + size >= buffer_size)
01727 size = buffer_size - buffer_pos;
01728 memcpy(data, buffer+buffer_pos, size);
01729 buffer_pos += size;
01730 position += size;
01731 return size;
01732 }
01733
01734 size_t
01735 PoolByteStream::write(const void *buffer, size_t size)
01736 {
01737 G_THROW( ERR_MSG("not_implemented_n") "\tPoolByteStream::write()");
01738 return 0;
01739 }
01740
01741 long
01742 PoolByteStream::tell(void) const
01743 {
01744 return position;
01745 }
01746
01747 int
01748 PoolByteStream::seek(long offset, int whence, bool nothrow)
01749 {
01750 int retval=(-1);
01751 switch(whence)
01752 {
01753 case SEEK_CUR:
01754 offset+=position;
01755
01756 case SEEK_SET:
01757 if(offset<position)
01758 {
01759 if((int)(offset+buffer_pos)>=(int)position)
01760 {
01761 buffer_pos-=position-offset;
01762 }else
01763 {
01764 buffer_size=0;
01765 }
01766 position=offset;
01767 }else if(offset>position)
01768 {
01769 buffer_pos+=(offset-position)-1;
01770 position=offset-1;
01771 unsigned char c;
01772 if(read(&c,1)<1)
01773 {
01774 G_THROW( ByteStream::EndOfFile );
01775 }
01776 }
01777 retval=0;
01778 break;
01779 case SEEK_END:
01780 if(! nothrow)
01781 G_THROW( ERR_MSG("DataPool.seek_backward") );
01782 break;
01783 }
01784 return retval;
01785 }
01786
01787 void
01788 DataPool::close_all(void)
01789 {
01790 OpenFiles::get()->close_all();
01791 }
01792
01793
01794 GP<ByteStream>
01795 DataPool::get_stream(void)
01796 {
01797 if(data && data->is_static())
01798 {
01799 GCriticalSectionLock lock(&data_lock);
01800 data->seek(0, SEEK_SET);
01801 return data->duplicate(length);
01802 }else
01803 {
01804 return new PoolByteStream(this);
01805 }
01806 }
01807
01808
01809 inline
01810 DataPool::Counter::operator int(void) const
01811 {
01812 GCriticalSectionLock lk((GCriticalSection *) &lock);
01813 int cnt=counter;
01814 return cnt;
01815 }
01816
01817 inline void
01818 DataPool::Counter::inc(void)
01819 {
01820 GCriticalSectionLock lk(&lock);
01821 counter++;
01822 }
01823
01824 inline void
01825 DataPool::Counter::dec(void)
01826 {
01827 GCriticalSectionLock lk(&lock);
01828 counter--;
01829 }
01830
01831
01832 #ifdef HAVE_NAMESPACES
01833 }
01834 # ifndef NOT_USING_DJVU_NAMESPACE
01835 using namespace DJVU;
01836 # endif
01837 #endif