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 
00058 
00059 
00060 
00061 
00062 
00063 #ifdef HAVE_CONFIG_H
00064 # include "config.h"
00065 #endif
00066 #if NEED_GNUG_PRAGMAS
00067 # pragma implementation
00068 #endif
00069 
00070 
00071 
00072 #include "DjVuGlobal.h"
00073 #include "ByteStream.h"
00074 #include "GOS.h"
00075 #include "GURL.h"
00076 #include "DjVuMessage.h"
00077 #include <fcntl.h>
00078 #if defined(WIN32) || defined(__CYGWIN32__)
00079 # include <io.h>
00080 #endif
00081 
00082 #ifdef UNIX
00083 # ifndef HAS_MEMMAP
00084 #  define HAS_MEMMAP 1
00085 # endif
00086 #endif
00087 
00088 #if defined(UNIX)
00089 # include <sys/types.h>
00090 # include <sys/stat.h>
00091 # include <unistd.h>
00092 # include <errno.h>
00093 # ifdef HAS_MEMMAP
00094 #  include <sys/mman.h>
00095 # endif
00096 #elif defined(macintosh)
00097 # include <unistd.h>
00098 _MSL_IMP_EXP_C int _dup(int);
00099 _MSL_IMP_EXP_C int _dup2(int,int);
00100 _MSL_IMP_EXP_C int _close(int);
00101 __inline int dup(int _a ) { return _dup(_a);}
00102 __inline int dup2(int _a, int _b ) { return _dup2(_a, _b);}
00103 #endif
00104 
00105 #ifdef HAVE_NAMESPACES
00106 namespace DJVU {
00107 # ifdef NOT_DEFINED // Just to fool emacs c++ mode
00108 }
00109 #endif
00110 #endif
00111 
00112 const char *ByteStream::EndOfFile=ERR_MSG("EOF");
00113 
00119 class ByteStream::Stdio : public ByteStream {
00120 public:
00121   Stdio(void);
00122 
00131   GUTF8String init(const GURL &url, const char * const mode);
00132 
00137   GUTF8String init(FILE * const f, const char * const mode="rb", const bool closeme=false);
00138 
00140   GUTF8String init(const char mode[]);
00141 
00142   
00143   ~Stdio();
00144   virtual size_t read(void *buffer, size_t size);
00145   virtual size_t write(const void *buffer, size_t size);
00146   virtual void flush(void);
00147   virtual int seek(long offset, int whence = SEEK_SET, bool nothrow=false);
00148   virtual long tell(void) const;
00149 private:
00150   
00151   Stdio(const Stdio &);
00152   Stdio & operator=(const Stdio &);
00153 private:
00154   
00155   bool can_read;
00156   bool can_write;
00157   bool must_close;
00158 protected:
00159   FILE *fp;
00160   long pos;
00161 };
00162 
00163 inline GUTF8String
00164 ByteStream::Stdio::init(FILE * const f,const char mode[],const bool closeme)
00165 {
00166   fp=f;
00167   must_close=closeme;
00168   return init(mode);
00169 }
00170 
00171 
00177 class ByteStream::Memory : public ByteStream
00178 {
00179 public:
00184   Memory();
00188   GUTF8String init(const void * const buffer, const size_t size);
00189   
00190   ~Memory();
00191   virtual size_t read(void *buffer, size_t size);
00192   virtual size_t write(const void *buffer, size_t size);
00193   virtual int    seek(long offset, int whence=SEEK_SET, bool nothrow=false);
00194   virtual long   tell(void) const;
00197   void empty();
00201   virtual int size(void) const;
00205   char &operator[] (int n);
00207 private:
00208   
00209   Memory(const Memory &);
00210   Memory & operator=(const Memory &);
00211   
00212   int where;
00213 protected:
00217   virtual size_t readat(void *buffer, size_t sz, int pos);
00219   int bsize;
00221   int nblocks;
00223   char **blocks;
00225   GPBuffer<char *> gblocks;
00226 };
00227 
00228 
00229 
00230 inline int
00231 ByteStream::Memory::size(void) const
00232 {
00233   return bsize;
00234 }
00235 
00236 inline char &
00237 ByteStream::Memory::operator[] (int n)
00238 {
00239   return blocks[n>>12][n&0xfff];
00240 }
00241 
00242 
00243 
00250 class ByteStream::Static : public ByteStream
00251 {
00252 public:
00253   class Allocate;
00254   class Duplicate;
00255   friend class Duplicate;
00256 
00259   Static(const void * const buffer, const size_t sz);
00260   ~Static();
00261   
00262   virtual size_t read(void *buffer, size_t sz);
00263   virtual int    seek(long offset, int whence = SEEK_SET, bool nothrow=false);
00264   virtual long tell(void) const;
00268   virtual int size(void) const;
00269   virtual GP<ByteStream> duplicate(const size_t xsize) const;
00271   virtual bool is_static(void) const { return true; }
00272 protected:
00273   const char *data;
00274   int bsize;
00275 private:
00276   int where;
00277 };
00278 
00279 ByteStream::Static::~Static() {}
00280 
00281 class ByteStream::Static::Allocate : public ByteStream::Static
00282 {
00283 public:
00284   friend class ByteStream;
00285 protected:
00286   char *buf;
00287   GPBuffer<char> gbuf;
00288 public:
00289   Allocate(const size_t size) : Static(0,size), gbuf(buf,size) { data=buf; }
00290   virtual ~Allocate();
00291 };
00292 
00293 ByteStream::Static::Allocate::~Allocate() {}
00294 
00295 inline int
00296 ByteStream::Static::size(void) const
00297 {
00298   return bsize;
00299 }
00300 
00301 class ByteStream::Static::Duplicate : public ByteStream::Static
00302 {
00303 protected:
00304   GP<ByteStream> gbs;
00305 public:
00306   Duplicate(const ByteStream::Static &bs, const size_t size);
00307 };
00308 
00309 ByteStream::Static::Duplicate::Duplicate(
00310   const ByteStream::Static &bs, const size_t xsize)
00311 : ByteStream::Static(0,0)
00312 {
00313   if(xsize&&(bs.bsize<bs.where))
00314   {
00315     const size_t bssize=(size_t)bs.bsize-(size_t)bs.where;
00316     bsize=(size_t)((xsize>bssize)?bssize:xsize);
00317     gbs=const_cast<ByteStream::Static *>(&bs);
00318     data=bs.data+bs.where;
00319   }
00320 }
00321 
00322 GP<ByteStream>
00323 ByteStream::Static::duplicate(const size_t xsize) const
00324 {
00325   return new ByteStream::Static::Duplicate(*this,xsize);
00326 }
00327 
00328 #if HAS_MEMMAP
00329 
00333 class MemoryMapByteStream : public ByteStream::Static
00334 {
00335 public:
00336   MemoryMapByteStream(void);
00337   virtual ~MemoryMapByteStream();  
00338 private:
00339   GUTF8String init(const int fd, const bool closeme);
00340   GUTF8String init(FILE *const f,const bool closeme);
00341   friend class ByteStream;
00342 };
00343 #endif
00344 
00346 
00347 
00348 ByteStream::~ByteStream()
00349 {
00350 }
00351 
00352 int 
00353 ByteStream::scanf(const char *fmt, ...)
00354 {
00355   G_THROW( ERR_MSG("ByteStream.not_implemented") ); 
00356   return 0;
00357 }
00358 
00359 size_t 
00360 ByteStream::read(void *buffer, size_t sz)
00361 {
00362   G_THROW( ERR_MSG("ByteStream.cant_read") );      
00363   return 0;
00364 }
00365 
00366 size_t 
00367 ByteStream::write(const void *buffer, size_t sz)
00368 {
00369   G_THROW( ERR_MSG("ByteStream.cant_write") );      
00370   return 0;
00371 }
00372 
00373 void
00374 ByteStream::flush()
00375 {
00376 }
00377 
00378 int
00379 ByteStream::seek(long offset, int whence, bool nothrow)
00380 {
00381   int nwhere = 0;
00382   int ncurrent = tell();
00383   switch (whence)
00384     {
00385     case SEEK_SET:
00386       nwhere=0; break;
00387     case SEEK_CUR:
00388       nwhere=ncurrent; break;
00389     case SEEK_END: 
00390     {
00391       if(offset)
00392       {
00393         if (nothrow)
00394           return -1;
00395         G_THROW( ERR_MSG("ByteStream.backward") );
00396       }
00397       char buffer[1024];
00398       int bytes;
00399       while((bytes=read(buffer, sizeof(buffer))))
00400         EMPTY_LOOP;
00401       return 0;
00402     }
00403     default:
00404       G_THROW( ERR_MSG("ByteStream.bad_arg") );       
00405     }
00406   nwhere += offset;
00407   if (nwhere < ncurrent) 
00408   {
00409     
00410     if (nothrow)
00411       return -1;
00412     G_THROW( ERR_MSG("ByteStream.backward") );
00413   }
00414   while (nwhere>ncurrent)
00415   {
00416     char buffer[1024];
00417     const int xbytes=(ncurrent+(int)sizeof(buffer)>nwhere)
00418       ?(nwhere - ncurrent):(int)sizeof(buffer);
00419     const int bytes = read(buffer, xbytes);
00420     ncurrent += bytes;
00421     if (!bytes)
00422       G_THROW( ByteStream::EndOfFile );
00423     
00424     if (ncurrent!=tell())
00425       G_THROW( ERR_MSG("ByteStream.seek") );
00426   }
00427   return 0;
00428 }
00429 
00430 size_t 
00431 ByteStream::readall(void *buffer, size_t size)
00432 {
00433   size_t total = 0;
00434     while (size > 0)
00435     {
00436       int nitems = read(buffer, size);
00437       
00438       
00439       
00440       
00441       if(nitems < 0) 
00442         G_THROW(strerror(errno));               
00443       if (nitems == 0)
00444         break;
00445       total += nitems;
00446       size -= nitems; 
00447       buffer = (void*)((char*)buffer + nitems);
00448     }
00449   return total;
00450 }
00451 
00452 size_t
00453 ByteStream::format(const char *fmt, ... )
00454 {
00455   va_list args;
00456   va_start(args, fmt); 
00457   const GUTF8String message(fmt,args);
00458   return writestring(message);
00459 }
00460 
00461 size_t
00462 ByteStream::writestring(const GNativeString &s)
00463 {
00464   int retval;
00465   if(cp != UTF8)
00466   {
00467     retval=writall((const char *)s,s.length());
00468     if(cp == AUTO)
00469       cp=NATIVE; 
00470   }else
00471   { 
00472     const GUTF8String msg(s.getNative2UTF8());
00473     retval=writall((const char *)msg,msg.length());
00474   }
00475   return retval;
00476 }
00477 
00478 size_t
00479 ByteStream::writestring(const GUTF8String &s)
00480 {
00481   int retval;
00482   if(cp != NATIVE)
00483   {
00484     retval=writall((const char *)s,s.length());
00485     if(cp == AUTO)
00486       cp=UTF8; 
00487   }else
00488   { 
00489     const GNativeString msg(s.getUTF82Native());
00490     retval=writall((const char *)msg,msg.length());
00491   }
00492   return retval;
00493 }
00494 
00495 size_t 
00496 ByteStream::writall(const void *buffer, size_t size)
00497 {
00498   size_t total = 0;
00499   while (size > 0)
00500     {
00501       size_t nitems = write(buffer, size);
00502       if (nitems == 0)
00503         G_THROW( ERR_MSG("ByteStream.write_error") );      
00504       total += nitems;
00505       size -= nitems; 
00506       buffer = (void*)((char*)buffer + nitems);
00507     }
00508   return total;
00509 }
00510 
00511 size_t 
00512 ByteStream::copy(ByteStream &bsfrom, size_t size)
00513 {
00514   size_t total = 0;
00515   const size_t max_buffer_size=200*1024;
00516   const size_t buffer_size=(size>0 && size<max_buffer_size)
00517     ?size:max_buffer_size;
00518   char *buffer;
00519   GPBuffer<char> gbuf(buffer,buffer_size);
00520   for(;;)
00521     {
00522       size_t bytes = buffer_size;
00523       if (size>0 && bytes+total>size)
00524         bytes = size - total;
00525       if (bytes == 0)
00526         break;
00527       bytes = bsfrom.read((void*)buffer, bytes);
00528       if (bytes == 0)
00529         break;
00530       writall((void*)buffer, bytes);
00531       total += bytes;
00532     }
00533   return total;
00534 }
00535 
00536 
00537 void 
00538 ByteStream::write8 (unsigned int card)
00539 {
00540   unsigned char c[1];
00541   c[0] = (card) & 0xff;
00542   if (write((void*)c, sizeof(c)) != sizeof(c))
00543     G_THROW(strerror(errno));   
00544 }
00545 
00546 void 
00547 ByteStream::write16(unsigned int card)
00548 {
00549   unsigned char c[2];
00550   c[0] = (card>>8) & 0xff;
00551   c[1] = (card) & 0xff;
00552   if (writall((void*)c, sizeof(c)) != sizeof(c))
00553     G_THROW(strerror(errno));   
00554 }
00555 
00556 void 
00557 ByteStream::write24(unsigned int card)
00558 {
00559   unsigned char c[3];
00560   c[0] = (card>>16) & 0xff;
00561   c[1] = (card>>8) & 0xff;
00562   c[2] = (card) & 0xff;
00563   if (writall((void*)c, sizeof(c)) != sizeof(c))
00564     G_THROW(strerror(errno));   
00565 }
00566 
00567 void 
00568 ByteStream::write32(unsigned int card)
00569 {
00570   unsigned char c[4];
00571   c[0] = (card>>24) & 0xff;
00572   c[1] = (card>>16) & 0xff;
00573   c[2] = (card>>8) & 0xff;
00574   c[3] = (card) & 0xff;
00575   if (writall((void*)c, sizeof(c)) != sizeof(c))
00576     G_THROW(strerror(errno));   
00577 }
00578 
00579 unsigned int 
00580 ByteStream::read8 ()
00581 {
00582   unsigned char c[1];
00583   if (readall((void*)c, sizeof(c)) != sizeof(c))
00584     G_THROW( ByteStream::EndOfFile );
00585   return c[0];
00586 }
00587 
00588 unsigned int 
00589 ByteStream::read16()
00590 {
00591   unsigned char c[2];
00592   if (readall((void*)c, sizeof(c)) != sizeof(c))
00593     G_THROW( ByteStream::EndOfFile );
00594   return (c[0]<<8)+c[1];
00595 }
00596 
00597 unsigned int 
00598 ByteStream::read24()
00599 {
00600   unsigned char c[3];
00601   if (readall((void*)c, sizeof(c)) != sizeof(c))
00602     G_THROW( ByteStream::EndOfFile );
00603   return (((c[0]<<8)+c[1])<<8)+c[2];
00604 }
00605 
00606 unsigned int 
00607 ByteStream::read32()
00608 {
00609   unsigned char c[4];
00610   if (readall((void*)c, sizeof(c)) != sizeof(c))
00611     G_THROW( ByteStream::EndOfFile );
00612   return (((((c[0]<<8)+c[1])<<8)+c[2])<<8)+c[3];
00613 }
00614 
00615 
00616 
00618 
00619 ByteStream::Stdio::Stdio(void)
00620 : can_read(false),can_write(false),must_close(true),fp(0),pos(0)
00621 {}
00622 
00623 ByteStream::Stdio::~Stdio()
00624 {
00625   if (fp && must_close)
00626     fclose(fp);
00627 }
00628 
00629 GUTF8String
00630 ByteStream::Stdio::init(const char mode[])
00631 {
00632   char const *mesg=0;
00633   bool binary=false;
00634   if(!fp)
00635     must_close=false;
00636   for (const char *s=mode; s && *s; s++)
00637   {
00638     switch(*s) 
00639     {
00640       case 'r':
00641         can_read=true;
00642         if(!fp) fp=stdin;
00643         break;
00644       case 'w': 
00645       case 'a':
00646         can_write=true;
00647         if(!fp) fp=stdout;
00648         break;
00649       case '+':
00650         can_read=can_write=true;
00651         break;
00652       case 'b':
00653         binary=true;
00654         break;
00655       default:
00656         mesg= ERR_MSG("ByteStream.bad_mode"); 
00657     }
00658   }
00659   if(binary && fp) {
00660 #if defined(__CYGWIN32__)
00661     setmode(fileno(fp), O_BINARY);
00662 #elif defined(WIN32)
00663     _setmode(_fileno(fp), _O_BINARY);
00664 #endif
00665   }
00666   GUTF8String retval;
00667   if(!mesg)
00668   {
00669     tell();
00670   }else
00671   {
00672     retval=mesg;
00673   }
00674   if(mesg &&(fp && must_close))
00675   {
00676     fclose(fp);
00677     fp=0;
00678     must_close=false;
00679   }
00680   return retval;
00681 }
00682 
00683 static FILE *
00684 urlfopen(const GURL &url,const char mode[])
00685 {
00686 #ifdef WIN32
00687   FILE *retval=0;
00688   const GUTF8String filename(url.UTF8Filename());
00689   wchar_t *wfilename;
00690   const size_t wfilename_size=filename.length()+1;
00691   GPBuffer<wchar_t> gwfilename(wfilename,wfilename_size);
00692   if(filename.ncopy(wfilename,wfilename_size) > 0)
00693   {
00694     const GUTF8String gmode(mode);
00695     wchar_t *wmode;
00696     const size_t wmode_size=gmode.length()+1;
00697     GPBuffer<wchar_t> gwmode(wmode,wmode_size);
00698     if(gmode.ncopy(wmode,wmode_size) > 0)
00699     {
00700       retval=_wfopen(wfilename,wmode);
00701     }
00702   }
00703   return retval?retval:fopen((const char *)url.NativeFilename(),mode);
00704 #else
00705   return fopen((const char *)url.NativeFilename(),mode);
00706 #endif
00707 }
00708 
00709 #ifdef UNIX
00710 static int
00711 urlopen(const GURL &url, const int mode, const int perm)
00712 {
00713   return open((const char *)url.NativeFilename(),mode,perm);
00714 }
00715 #endif 
00716 
00717 GUTF8String
00718 ByteStream::Stdio::init(const GURL &url, const char mode[])
00719 {
00720   GUTF8String retval;
00721   if (url.fname() != "-")
00722   {
00723     fp = urlfopen(url,mode);
00724     if (!fp)
00725     {
00726       
00727       G_THROW( ERR_MSG("ByteStream.open_fail") "\t" + url.name()
00728                +"\t"+GNativeString(strerror(errno)).getNative2UTF8());
00729     }
00730   }
00731   return retval.length()?retval:init(mode);
00732 }
00733 
00734 size_t 
00735 ByteStream::Stdio::read(void *buffer, size_t size)
00736 {
00737   if (!can_read)
00738     G_THROW( ERR_MSG("ByteStream.no_read") ); 
00739   size_t nitems;
00740   do
00741   {
00742     clearerr(fp);
00743     nitems = fread(buffer, 1, size, fp); 
00744     if (nitems<=0 && ferror(fp))
00745     {
00746 #ifdef EINTR
00747       if (errno!=EINTR)
00748 #endif
00749         G_THROW(strerror(errno)); 
00750     }
00751     else
00752       break;
00753   } while(true);
00754   pos += nitems;
00755   return nitems;
00756 }
00757 
00758 size_t 
00759 ByteStream::Stdio::write(const void *buffer, size_t size)
00760 {
00761   if (!can_write)
00762     G_THROW( ERR_MSG("ByteStream.no_write") ); 
00763   size_t nitems;
00764   do
00765   {
00766     clearerr(fp);
00767     nitems = fwrite(buffer, 1, size, fp);
00768     if (nitems<=0 && ferror(fp))
00769     {
00770 #ifdef EINTR
00771       if (errno!=EINTR)
00772 #endif
00773         G_THROW(strerror(errno)); 
00774     }
00775     else
00776       break;
00777   } while(true);
00778   pos += nitems;
00779   return nitems;
00780 }
00781 
00782 void
00783 ByteStream::Stdio::flush()
00784 {
00785   if (fflush(fp) < 0)
00786     G_THROW(strerror(errno)); 
00787 }
00788 
00789 long 
00790 ByteStream::Stdio::tell(void) const
00791 {
00792   long x = ftell(fp);
00793   if (x >= 0)
00794   {
00795     Stdio *sbs=const_cast<Stdio *>(this);
00796     (sbs->pos) = x;
00797   }else
00798   {
00799     x=pos;
00800   }
00801   return x;
00802 }
00803 
00804 int
00805 ByteStream::Stdio::seek(long offset, int whence, bool nothrow)
00806 {
00807   if (whence==SEEK_SET && offset>=0 && offset==ftell(fp))
00808     return 0;
00809   clearerr(fp);
00810   if (fseek(fp, offset, whence)) 
00811     {
00812       if (nothrow) 
00813         return -1;
00814       G_THROW(strerror(errno)); 
00815     }
00816   return tell();
00817 }
00818 
00819 
00820 
00821 
00823 
00824 ByteStream::Memory::Memory()
00825   : where(0), bsize(0), nblocks(0), gblocks(blocks,0)
00826 {
00827 }
00828 
00829 GUTF8String
00830 ByteStream::Memory::init(void const * const buffer, const size_t sz)
00831 {
00832   GUTF8String retval;
00833   G_TRY
00834   {
00835     writall(buffer, sz);
00836     where = 0;
00837   }
00838   G_CATCH(ex) 
00839   {
00840     retval=ex.get_cause();
00841   }
00842   G_ENDCATCH;
00843   return retval;
00844 }
00845 
00846 void 
00847 ByteStream::Memory::empty()
00848 {
00849   for (int b=0; b<nblocks; b++)
00850   {
00851     delete [] blocks[b];
00852     blocks[b]=0;
00853   }
00854   bsize = 0;
00855   where = 0;
00856   nblocks = 0;
00857 }
00858 
00859 ByteStream::Memory::~Memory()
00860 {
00861   empty();
00862 }
00863 
00864 size_t 
00865 ByteStream::Memory::write(const void *buffer, size_t sz)
00866 {
00867   int nsz = (int)sz;
00868   if (nsz <= 0)
00869     return 0;
00870   
00871   if ( (where+nsz) > ((bsize+0xfff)&~0xfff) )
00872     {
00873       
00874       if ( (where+nsz) > (nblocks<<12) )
00875         {
00876           const int old_nblocks=nblocks;
00877           nblocks = (((where+nsz)+0xffff)&~0xffff) >> 12;
00878           gblocks.resize(nblocks);
00879           char const ** eblocks=(char const **)(blocks+old_nblocks);
00880           for(char const * const * const new_eblocks=blocks+nblocks;
00881             eblocks <new_eblocks; eblocks++) 
00882           {
00883             *eblocks = 0;
00884           }
00885         }
00886       
00887       for (int b=(where>>12); (b<<12)<(where+nsz); b++)
00888       {
00889         if (! blocks[b])
00890           blocks[b] = new char[0x1000];
00891       }
00892     }
00893   
00894   while (nsz > 0)
00895     {
00896       int n = (where|0xfff) + 1 - where;
00897       n = ((nsz < n) ? nsz : n);
00898       memcpy( (void*)&blocks[where>>12][where&0xfff], buffer, n);
00899       buffer = (void*) ((char*)buffer + n);
00900       where += n;
00901       nsz -= n;
00902     }
00903   
00904   if (where > bsize)
00905     bsize = where;
00906   return sz;
00907 }
00908 
00909 size_t 
00910 ByteStream::Memory::readat(void *buffer, size_t sz, int pos)
00911 {
00912   if ((int) sz > bsize - pos)
00913     sz = bsize - pos;
00914   int nsz = (int)sz;
00915   if (nsz <= 0)
00916     return 0;
00917   
00918   while (nsz > 0)
00919     {
00920       int n = (pos|0xfff) + 1 - pos;
00921       n = ((nsz < n) ? nsz : n);
00922       memcpy(buffer, (void*)&blocks[pos>>12][pos&0xfff], n);
00923       buffer = (void*) ((char*)buffer + n);
00924       pos += n;
00925       nsz -= n;
00926     }
00927   return sz;
00928 }
00929 
00930 size_t 
00931 ByteStream::Memory::read(void *buffer, size_t sz)
00932 {
00933   sz = readat(buffer,sz,where);
00934   where += sz;
00935   return sz;
00936 }
00937 
00938 long 
00939 ByteStream::Memory::tell(void) const
00940 {
00941   return where;
00942 }
00943 
00944 int
00945 ByteStream::Memory::seek(long offset, int whence, bool nothrow)
00946 {
00947   int nwhere = 0;
00948   switch (whence)
00949     {
00950     case SEEK_SET: nwhere = 0; break;
00951     case SEEK_CUR: nwhere = where; break;
00952     case SEEK_END: nwhere = bsize; break;
00953     default: G_THROW( ERR_MSG("bad_arg") "\tByteStream::Memory::seek()");      
00954     }
00955   nwhere += offset;
00956   if (nwhere<0)
00957     G_THROW( ERR_MSG("ByteStream.seek_error2") );                          
00958   where = nwhere;
00959   return 0;
00960 }
00961 
00962 
00963 
00967 #ifdef DO_NOT_MOVE_GET_DATA_TO_ARRAYS_CPP
00968 TArray<char>
00969 ByteStream::get_data(void)
00970 {
00971    TArray<char> data(0, size()-1);
00972    readat((char*)data, size(), 0);
00973    return data;
00974 }
00975 #endif
00976 
00977 
00979 
00980 ByteStream::Static::Static(const void * const buffer, const size_t sz)
00981   : data((const char *)buffer), bsize(sz), where(0)
00982 {
00983 }
00984 
00985 size_t 
00986 ByteStream::Static::read(void *buffer, size_t sz)
00987 {
00988   int nsz = (int)sz;
00989   if (nsz > bsize - where)
00990     nsz = bsize - where;
00991   if (nsz <= 0)
00992     return 0;
00993   memcpy(buffer, data+where, nsz);
00994   where += nsz;
00995   return nsz;
00996 }
00997 
00998 int
00999 ByteStream::Static::seek(long offset, int whence, bool nothrow)
01000 {
01001   int nwhere = 0;
01002   switch (whence)
01003     {
01004     case SEEK_SET: nwhere = 0; break;
01005     case SEEK_CUR: nwhere = where; break;
01006     case SEEK_END: nwhere = bsize; break;
01007     default: G_THROW("bad_arg\tByteStream::Static::seek()");      
01008     }
01009   nwhere += offset;
01010   if (nwhere<0)
01011     G_THROW( ERR_MSG("ByteStream.seek_error2") );                          
01012   where = nwhere;
01013   return 0;
01014 }
01015 
01016 long 
01017 ByteStream::Static::tell(void) const
01018 {
01019   return where;
01020 }
01021 
01022 GP<ByteStream>
01023 ByteStream::create(void)
01024 {
01025   return new Memory();
01026 }
01027 
01028 GP<ByteStream>
01029 ByteStream::create(void const * const buffer, const size_t size)
01030 {
01031   Memory *mbs=new Memory();
01032   GP<ByteStream> retval=mbs;
01033   mbs->init(buffer,size);
01034   return retval;
01035 }
01036 
01037 GP<ByteStream>
01038 ByteStream::create(const GURL &url,char const * const xmode)
01039 {
01040   GP<ByteStream> retval;
01041   const char *mode = ((xmode) ? xmode : "rb");
01042 #ifdef UNIX
01043   if (!strcmp(mode,"rb")) 
01044     {
01045       int fd = urlopen(url,O_RDONLY,0777);
01046       if (fd >= 0)
01047         {
01048 #if HAS_MEMMAP && defined(S_IFREG)
01049           struct stat buf;
01050           if ( (fstat(fd, &buf) >= 0) && (buf.st_mode & S_IFREG) )
01051             {
01052               MemoryMapByteStream *rb = new MemoryMapByteStream();
01053               retval = rb;
01054               GUTF8String errmessage = rb->init(fd,true);
01055               if(errmessage.length())
01056                 retval=0;
01057             }
01058 #endif
01059           if (! retval)
01060             {
01061               FILE *f = fdopen(fd, mode);
01062               if (f) 
01063                 {
01064                   Stdio *sbs=new Stdio();
01065                   retval=sbs;
01066                   GUTF8String errmessage=sbs->init(f, mode, true);
01067                   if(errmessage.length())
01068                     retval=0;
01069                 }
01070             }
01071           if (! retval)
01072             close(fd);
01073         }     
01074     }
01075 #endif
01076   if (! retval)
01077     {
01078       Stdio *sbs=new Stdio();
01079       retval=sbs;
01080       GUTF8String errmessage=sbs->init(url, mode);
01081       if(errmessage.length())
01082         G_THROW(errmessage);
01083     }
01084   return retval;
01085 }
01086 
01087 GP<ByteStream>
01088 ByteStream::create(char const * const mode)
01089 {
01090   GP<ByteStream> retval;
01091   Stdio *sbs=new Stdio();
01092   retval=sbs;
01093   GUTF8String errmessage=sbs->init(mode?mode:"rb");
01094   if(errmessage.length())
01095   {
01096     G_THROW(errmessage);
01097   }
01098   return retval;
01099 }
01100 
01101 GP<ByteStream>
01102 ByteStream::create(const int fd,char const * const mode,const bool closeme)
01103 {
01104   GP<ByteStream> retval;
01105   const char *default_mode="rb";
01106 #if HAS_MEMMAP
01107   if (   (!mode&&(fd!=0)&&(fd!=1)&&(fd!=2)) 
01108       || (mode&&(GUTF8String("rb") == mode)))
01109   {
01110     MemoryMapByteStream *rb=new MemoryMapByteStream();
01111     retval=rb;
01112     GUTF8String errmessage=rb->init(fd,closeme);
01113     if(errmessage.length())
01114     {
01115       retval=0;
01116     }
01117   }
01118   if(!retval)
01119 #endif
01120   {
01121     int fd2 = fd;
01122     FILE *f = 0;
01123     if (fd == 0 && !closeme 
01124         && (!mode || mode[0]=='r') )
01125       {
01126         f=stdin;
01127         default_mode = "r";
01128         fd2=(-1);
01129       }
01130     else if (fd == 1 && !closeme 
01131              && (!mode || mode[0]=='a' || mode[0]=='w') )
01132       {
01133         default_mode = "a";
01134         f=stdout;
01135         fd2 = -1;
01136       }
01137     else if (fd == 2 && !closeme
01138              && (!mode || mode[0]=='a' || mode[0]=='w') )
01139       {
01140         default_mode = "a";
01141         f=stderr;
01142         fd2 = -1;
01143       }
01144     else
01145       {
01146         if (! closeme)
01147           fd2 = dup(fd);
01148         f = fdopen(fd2,(char*)(mode?mode:default_mode));
01149       }
01150 
01151     if(!f)
01152       {
01153         if ( fd2 >= 0)
01154           close(fd2);
01155         G_THROW( ERR_MSG("ByteStream.open_fail2") );
01156       }
01157     Stdio *sbs=new Stdio();
01158     retval=sbs;
01159     GUTF8String errmessage=sbs->init(f,mode?mode:default_mode,(fd2>=0));
01160     if(errmessage.length())
01161       G_THROW(errmessage);
01162   }
01163   return retval;
01164 }
01165 
01166 GP<ByteStream>
01167 ByteStream::create(FILE * const f,char const * const mode,const bool closeme)
01168 {
01169   GP<ByteStream> retval;
01170 #if HAS_MEMMAP
01171   if (!mode || (GUTF8String("rb") == mode))
01172   {
01173     MemoryMapByteStream *rb=new MemoryMapByteStream();
01174     retval=rb;
01175     GUTF8String errmessage=rb->init(fileno(f),false);
01176     if(errmessage.length())
01177     {
01178       retval=0;
01179     }else
01180     {
01181       fclose(f);
01182     }
01183   }
01184   if(!retval)
01185 #endif
01186   {
01187     Stdio *sbs=new Stdio();
01188     retval=sbs;
01189     GUTF8String errmessage=sbs->init(f,mode?mode:"rb",closeme);
01190     if(errmessage.length())
01191     {
01192       G_THROW(errmessage);
01193     }
01194   }
01195   return retval;
01196 }
01197 
01198 GP<ByteStream>
01199 ByteStream::create_static(const void * const buffer, size_t sz)
01200 {
01201   return new Static(buffer, sz);
01202 }
01203 
01204 GP<ByteStream>
01205 ByteStream::duplicate(const size_t xsize) const
01206 {
01207   GP<ByteStream> retval;
01208   const long int pos=tell();
01209   const int tsize=size();
01210   ByteStream &self=*(const_cast<ByteStream *>(this));
01211   if(tsize < 0 || pos < 0 || (unsigned int)tsize < 1+(unsigned int)pos)
01212   {
01213     retval=ByteStream::create();
01214     retval->copy(self,xsize);
01215     retval->seek(0L);
01216   }else
01217   {
01218     const size_t s=(size_t)tsize-(size_t)pos;
01219     const int size=(!xsize||(s<xsize))?s:xsize;
01220     ByteStream::Static::Allocate *bs=new ByteStream::Static::Allocate(size);
01221     retval=bs;
01222     self.readall(bs->buf,size);
01223   }
01224   self.seek(pos,SEEK_SET,true);
01225   return retval;
01226 }
01227 
01228 
01229 #if HAS_MEMMAP
01230 MemoryMapByteStream::MemoryMapByteStream(void)
01231 : ByteStream::Static(0,0)
01232 {}
01233 
01234 GUTF8String
01235 MemoryMapByteStream::init(FILE *const f,const bool closeme)
01236 {
01237   GUTF8String retval;
01238   retval=init(fileno(f),false);
01239   if(closeme)
01240   {
01241     fclose(f);
01242   }
01243   return retval;
01244 }
01245 
01246 GUTF8String
01247 MemoryMapByteStream::init(const int fd,const bool closeme)
01248 {
01249   GUTF8String retval;
01250 #if defined(PROT_READ) && defined(MAP_SHARED)
01251   struct stat statbuf;
01252   if(!fstat(fd,&statbuf))
01253   {
01254     if(statbuf.st_size)
01255     {
01256       bsize=statbuf.st_size;
01257       data=(char *)mmap(0,statbuf.st_size,PROT_READ,MAP_SHARED,fd,0);
01258     }
01259   }else
01260   {
01261     if(closeme)
01262     {
01263       close(fd);
01264     }
01265     retval= ERR_MSG("ByteStream.open_fail2");
01266   }
01267 #else
01268   retval= ERR_MSG("ByteStream.open_fail2");
01269 #endif
01270   if(closeme)
01271   {
01272     close(fd);
01273   }
01274   return retval;
01275 }
01276 
01277 MemoryMapByteStream::~MemoryMapByteStream()
01278 {
01279   if(data)
01280   {
01281     munmap(const_cast<char *>(data),bsize);
01282   }
01283 }
01284 
01285 #endif
01286 
01287 ByteStream::Wrapper::~Wrapper() {}
01288 
01289 
01290 GP<ByteStream> 
01291 ByteStream::get_stdin(char const * const mode)
01292 {
01293   static GP<ByteStream> gp = ByteStream::create(0,mode,false);
01294   return gp;
01295 }
01296 
01297 GP<ByteStream> 
01298 ByteStream::get_stdout(char const * const mode)
01299 {
01300   static GP<ByteStream> gp = ByteStream::create(1,mode,false);
01301   return gp;
01302 }
01303 
01304 GP<ByteStream> 
01305 ByteStream::get_stderr(char const * const mode)
01306 {
01307   static GP<ByteStream> gp = ByteStream::create(2,mode,false);
01308   return gp;
01309 }
01310 
01311 
01313 void ByteStream::formatmessage( const char *fmt, ... )
01314 {
01315   va_list args;
01316   va_start(args, fmt);
01317   const GUTF8String message(fmt,args);
01318   writemessage( message );
01319 }
01320 
01322 void ByteStream::writemessage( const char *message )
01323 {
01324   writestring( DjVuMessage::LookUpUTF8( message ) );
01325 }
01326 
01327 static void 
01328 read_file(ByteStream &bs,char *&buffer,GPBuffer<char> &gbuffer)
01329 {
01330   const int size=bs.size();
01331   int pos=0;
01332   if(size>0)
01333   {
01334     size_t readsize=size+1;
01335     gbuffer.resize(readsize);
01336     for(int i;readsize&&(i=bs.read(buffer+pos,readsize))>0;pos+=i,readsize-=i)
01337       EMPTY_LOOP;
01338   }else
01339   {
01340     const size_t readsize=32768;
01341     gbuffer.resize(readsize);
01342     for(int i;((i=bs.read(buffer+pos,readsize))>0);
01343       gbuffer.resize((pos+=i)+readsize))
01344       EMPTY_LOOP;
01345   }
01346   buffer[pos]=0;
01347 }
01348 
01349 GNativeString
01350 ByteStream::getAsNative(void)
01351 {
01352   char *buffer;
01353   GPBuffer<char> gbuffer(buffer);
01354   read_file(*this,buffer,gbuffer);
01355   return GNativeString(buffer);
01356 }
01357 
01358 GUTF8String
01359 ByteStream::getAsUTF8(void)
01360 {
01361   char *buffer;
01362   GPBuffer<char> gbuffer(buffer);
01363   read_file(*this,buffer,gbuffer);
01364   return GUTF8String(buffer);
01365 }
01366 
01367 
01368 #ifdef HAVE_NAMESPACES
01369 }
01370 # ifndef NOT_USING_DJVU_NAMESPACE
01371 using namespace DJVU;
01372 # endif
01373 #endif
01374 
01375 void
01376 DjVuPrintErrorUTF8(const char *fmt, ... )
01377 {
01378   G_TRY {
01379     GP<ByteStream> errout = ByteStream::get_stderr();
01380     if (errout)
01381       {
01382         errout->cp=ByteStream::NATIVE;
01383         va_list args;
01384         va_start(args, fmt); 
01385         const GUTF8String message(fmt,args);
01386         errout->writestring(message);
01387       }
01388     
01389     
01390   } G_CATCH_ALL { } G_ENDCATCH;
01391 }
01392 
01393 void
01394 DjVuPrintErrorNative(const char *fmt, ... )
01395 {
01396   G_TRY {
01397     GP<ByteStream> errout = ByteStream::get_stderr();
01398     if (errout)
01399       {
01400         errout->cp=ByteStream::NATIVE;
01401         va_list args;
01402         va_start(args, fmt); 
01403         const GNativeString message(fmt,args);
01404         errout->writestring(message);
01405       }
01406     
01407     
01408   } G_CATCH_ALL { } G_ENDCATCH;
01409 }
01410 
01411 void
01412 DjVuPrintMessageUTF8(const char *fmt, ... )
01413 {
01414   G_TRY {
01415     GP<ByteStream> strout = ByteStream::get_stdout();
01416     if (strout)
01417       {
01418         strout->cp=ByteStream::NATIVE;
01419         va_list args;
01420         va_start(args, fmt);
01421         const GUTF8String message(fmt,args);
01422         strout->writestring(message);
01423       }
01424     
01425     
01426   } G_CATCH_ALL { } G_ENDCATCH;
01427 }
01428 
01429 void
01430 DjVuPrintMessageNative(const char *fmt, ... )
01431 {
01432   G_TRY {
01433     GP<ByteStream> strout = ByteStream::get_stdout();
01434     if (strout)
01435       {
01436         strout->cp=ByteStream::NATIVE;
01437         va_list args;
01438         va_start(args, fmt);
01439         const GNativeString message(fmt,args);
01440         strout->writestring(message);
01441       }
01442     
01443     
01444   } G_CATCH_ALL { } G_ENDCATCH;
01445 }