diff options
Diffstat (limited to 'kviewshell/plugins/djvu/libdjvu/ByteStream.cpp')
-rw-r--r-- | kviewshell/plugins/djvu/libdjvu/ByteStream.cpp | 1445 |
1 files changed, 1445 insertions, 0 deletions
diff --git a/kviewshell/plugins/djvu/libdjvu/ByteStream.cpp b/kviewshell/plugins/djvu/libdjvu/ByteStream.cpp new file mode 100644 index 00000000..011b348d --- /dev/null +++ b/kviewshell/plugins/djvu/libdjvu/ByteStream.cpp @@ -0,0 +1,1445 @@ +//C- -*- C++ -*- +//C- ------------------------------------------------------------------- +//C- DjVuLibre-3.5 +//C- Copyright (c) 2002 Leon Bottou and Yann Le Cun. +//C- Copyright (c) 2001 AT&T +//C- +//C- This software is subject to, and may be distributed under, the +//C- GNU General Public License, Version 2. The license should have +//C- accompanied the software or you may obtain a copy of the license +//C- from the Free Software Foundation at http://www.fsf.org . +//C- +//C- This program is distributed in the hope that it will be useful, +//C- but WITHOUT ANY WARRANTY; without even the implied warranty of +//C- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +//C- GNU General Public License for more details. +//C- +//C- DjVuLibre-3.5 is derived from the DjVu(r) Reference Library +//C- distributed by Lizardtech Software. On July 19th 2002, Lizardtech +//C- Software authorized us to replace the original DjVu(r) Reference +//C- Library notice by the following text (see doc/lizard2002.djvu): +//C- +//C- ------------------------------------------------------------------ +//C- | DjVu (r) Reference Library (v. 3.5) +//C- | Copyright (c) 1999-2001 LizardTech, Inc. All Rights Reserved. +//C- | The DjVu Reference Library is protected by U.S. Pat. No. +//C- | 6,058,214 and patents pending. +//C- | +//C- | This software is subject to, and may be distributed under, the +//C- | GNU General Public License, Version 2. The license should have +//C- | accompanied the software or you may obtain a copy of the license +//C- | from the Free Software Foundation at http://www.fsf.org . +//C- | +//C- | The computer code originally released by LizardTech under this +//C- | license and unmodified by other parties is deemed "the LIZARDTECH +//C- | ORIGINAL CODE." Subject to any third party intellectual property +//C- | claims, LizardTech grants recipient a worldwide, royalty-free, +//C- | non-exclusive license to make, use, sell, or otherwise dispose of +//C- | the LIZARDTECH ORIGINAL CODE or of programs derived from the +//C- | LIZARDTECH ORIGINAL CODE in compliance with the terms of the GNU +//C- | General Public License. This grant only confers the right to +//C- | infringe patent claims underlying the LIZARDTECH ORIGINAL CODE to +//C- | the extent such infringement is reasonably necessary to enable +//C- | recipient to make, have made, practice, sell, or otherwise dispose +//C- | of the LIZARDTECH ORIGINAL CODE (or portions thereof) and not to +//C- | any greater extent that may be necessary to utilize further +//C- | modifications or combinations. +//C- | +//C- | The LIZARDTECH ORIGINAL CODE is provided "AS IS" WITHOUT WARRANTY +//C- | OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +//C- | TO ANY WARRANTY OF NON-INFRINGEMENT, OR ANY IMPLIED WARRANTY OF +//C- | MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. +//C- +------------------------------------------------------------------ +// +// $Id: ByteStream.cpp,v 1.18 2004/08/06 14:50:05 leonb Exp $ +// $Name: release_3_5_15 $ + +// From: Leon Bottou, 1/31/2002 +// This file has very little to do with my initial implementation. +// It has been practically rewritten by Lizardtech for i18n changes. +// Our original implementation consisted of multiple classes. +// <http://prdownloads.sourceforge.net/djvu/DjVu2_2b-src.tgz>. + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif +#if NEED_GNUG_PRAGMAS +# pragma implementation +#endif + +// - Author: Leon Bottou, 04/1997 + +#include "DjVuGlobal.h" +#include "ByteStream.h" +#include "GOS.h" +#include "GURL.h" +#include "DjVuMessage.h" +#include <fcntl.h> +#if defined(WIN32) || defined(__CYGWIN32__) +# include <io.h> +#endif + +#ifdef UNIX +# ifndef HAS_MEMMAP +# define HAS_MEMMAP 1 +# endif +#endif + +#if defined(UNIX) +# include <sys/types.h> +# include <sys/stat.h> +# include <unistd.h> +# include <errno.h> +# ifdef HAS_MEMMAP +# include <sys/mman.h> +# endif +#elif defined(macintosh) +# include <unistd.h> +_MSL_IMP_EXP_C int _dup(int); +_MSL_IMP_EXP_C int _dup2(int,int); +_MSL_IMP_EXP_C int _close(int); +__inline int dup(int _a ) { return _dup(_a);} +__inline int dup2(int _a, int _b ) { return _dup2(_a, _b);} +#endif + +#ifdef HAVE_NAMESPACES +namespace DJVU { +# ifdef NOT_DEFINED // Just to fool emacs c++ mode +} +#endif +#endif + +const char *ByteStream::EndOfFile=ERR_MSG("EOF"); + +/** ByteStream interface for stdio files. + The virtual member functions #read#, #write#, #tell# and #seek# are mapped + to the well known stdio functions #fread#, #fwrite#, #ftell# and #fseek#. + @see Unix man page fopen(3), fread(3), fwrite(3), ftell(3), fseek(3) */ + +class ByteStream::Stdio : public ByteStream { +public: + Stdio(void); + + /** Constructs a ByteStream for accessing the file named #url#. + Arguments #url# and #mode# are similar to the arguments of the well + known stdio function #fopen#. In addition a url of #-# will be + interpreted as the standard output or the standard input according to + #mode#. This constructor will open a stdio file and construct a + ByteStream object accessing this file. Destroying the ByteStream object + will flush and close the associated stdio file. Returns an error code + if the stdio file cannot be opened. */ + GUTF8String init(const GURL &url, const char * const mode); + + /** Constructs a ByteStream for accessing the stdio file #f#. + Argument #mode# indicates the type of the stdio file, as in the + well known stdio function #fopen#. Destroying the ByteStream + object will not close the stdio file #f# unless closeme is true. */ + GUTF8String init(FILE * const f, const char * const mode="rb", const bool closeme=false); + + /** Initializes from stdio */ + GUTF8String init(const char mode[]); + + // Virtual functions + ~Stdio(); + virtual size_t read(void *buffer, size_t size); + virtual size_t write(const void *buffer, size_t size); + virtual void flush(void); + virtual int seek(long offset, int whence = SEEK_SET, bool nothrow=false); + virtual long tell(void) const; +private: + // Cancel C++ default stuff + Stdio(const Stdio &); + Stdio & operator=(const Stdio &); +private: + // Implementation + bool can_read; + bool can_write; + bool must_close; +protected: + FILE *fp; + long pos; +}; + +inline GUTF8String +ByteStream::Stdio::init(FILE * const f,const char mode[],const bool closeme) +{ + fp=f; + must_close=closeme; + return init(mode); +} + + +/** ByteStream interface managing a memory buffer. + Class #ByteStream::Memory# manages a dynamically resizable buffer from + which data can be read or written. The buffer itself is organized as an + array of blocks of 4096 bytes. */ + +class ByteStream::Memory : public ByteStream +{ +public: + /** Constructs an empty ByteStream::Memory. + The buffer is initially empty. You must first use function #write# + to store data into the buffer, use function #seek# to rewind the + current position, and function #read# to read the data back. */ + Memory(); + /** Constructs a Memory by copying initial data. The + Memory buffer is initialized with #size# bytes copied from the + memory area pointed to by #buffer#. */ + GUTF8String init(const void * const buffer, const size_t size); + // Virtual functions + ~Memory(); + virtual size_t read(void *buffer, size_t size); + virtual size_t write(const void *buffer, size_t size); + virtual int seek(long offset, int whence=SEEK_SET, bool nothrow=false); + virtual long tell(void) const; + /** Erases everything in the Memory. + The current location is reset to zero. */ + void empty(); + /** Returns the total number of bytes contained in the buffer. Valid + offsets for function #seek# range from 0 to the value returned by this + function. */ + virtual int size(void) const; + /** Returns a reference to the byte at offset #n#. This reference can be + used to read (as in #mbs[n]#) or modify (as in #mbs[n]=c#) the contents + of the buffer. */ + char &operator[] (int n); + /** Copies all internal data into \Ref{TArray} and returns it */ +private: + // Cancel C++ default stuff + Memory(const Memory &); + Memory & operator=(const Memory &); + // Current position + int where; +protected: + /** Reads data from a random position. This function reads at most #sz# + bytes at position #pos# into #buffer# and returns the actual number of + bytes read. The current position is unchanged. */ + virtual size_t readat(void *buffer, size_t sz, int pos); + /** Number of bytes in internal buffer. */ + int bsize; + /** Number of 4096 bytes blocks. */ + int nblocks; + /** Pointers (possibly null) to 4096 bytes blocks. */ + char **blocks; + /** Pointers (possibly null) to 4096 bytes blocks. */ + GPBuffer<char *> gblocks; +}; + + + +inline int +ByteStream::Memory::size(void) const +{ + return bsize; +} + +inline char & +ByteStream::Memory::operator[] (int n) +{ + return blocks[n>>12][n&0xfff]; +} + + + +/** Read-only ByteStream interface to a memory area. + Class #ByteStream::Static# implements a read-only ByteStream interface for a + memory area specified by the user at construction time. Calls to function + #read# directly access this memory area. The user must therefore make + sure that its content remain valid long enough. */ + +class ByteStream::Static : public ByteStream +{ +public: + class Allocate; + class Duplicate; + friend class Duplicate; + + /** Creates a Static object for allocating the memory area of + length #sz# starting at address #buffer#. */ + Static(const void * const buffer, const size_t sz); + ~Static(); + // Virtual functions + virtual size_t read(void *buffer, size_t sz); + virtual int seek(long offset, int whence = SEEK_SET, bool nothrow=false); + virtual long tell(void) const; + /** Returns the total number of bytes contained in the buffer, file, etc. + Valid offsets for function #seek# range from 0 to the value returned + by this function. */ + virtual int size(void) const; + virtual GP<ByteStream> duplicate(const size_t xsize) const; + /// Returns false, unless a subclass of ByteStream::Static + virtual bool is_static(void) const { return true; } +protected: + const char *data; + int bsize; +private: + int where; +}; + +ByteStream::Static::~Static() {} + +class ByteStream::Static::Allocate : public ByteStream::Static +{ +public: + friend class ByteStream; +protected: + char *buf; + GPBuffer<char> gbuf; +public: + Allocate(const size_t size) : Static(0,size), gbuf(buf,size) { data=buf; } + virtual ~Allocate(); +}; + +ByteStream::Static::Allocate::~Allocate() {} + +inline int +ByteStream::Static::size(void) const +{ + return bsize; +} + +class ByteStream::Static::Duplicate : public ByteStream::Static +{ +protected: + GP<ByteStream> gbs; +public: + Duplicate(const ByteStream::Static &bs, const size_t size); +}; + +ByteStream::Static::Duplicate::Duplicate( + const ByteStream::Static &bs, const size_t xsize) +: ByteStream::Static(0,0) +{ + if(xsize&&(bs.bsize<bs.where)) + { + const size_t bssize=(size_t)bs.bsize-(size_t)bs.where; + bsize=(size_t)((xsize>bssize)?bssize:xsize); + gbs=const_cast<ByteStream::Static *>(&bs); + data=bs.data+bs.where; + } +} + +GP<ByteStream> +ByteStream::Static::duplicate(const size_t xsize) const +{ + return new ByteStream::Static::Duplicate(*this,xsize); +} + +#if HAS_MEMMAP +/** Read-only ByteStream interface to a memmap area. + Class #MemoryMapByteStream# implements a read-only ByteStream interface + for a memory map to a file. */ + +class MemoryMapByteStream : public ByteStream::Static +{ +public: + MemoryMapByteStream(void); + virtual ~MemoryMapByteStream(); +private: + GUTF8String init(const int fd, const bool closeme); + GUTF8String init(FILE *const f,const bool closeme); + friend class ByteStream; +}; +#endif + +//// CLASS BYTESTREAM + + +ByteStream::~ByteStream() +{ +} + +int +ByteStream::scanf(const char *fmt, ...) +{ + G_THROW( ERR_MSG("ByteStream.not_implemented") ); // This is a place holder function. + return 0; +} + +size_t +ByteStream::read(void *buffer, size_t sz) +{ + G_THROW( ERR_MSG("ByteStream.cant_read") ); // Cannot read from a ByteStream created for writing + return 0; +} + +size_t +ByteStream::write(const void *buffer, size_t sz) +{ + G_THROW( ERR_MSG("ByteStream.cant_write") ); // Cannot write from a ByteStream created for reading + return 0; +} + +void +ByteStream::flush() +{ +} + +int +ByteStream::seek(long offset, int whence, bool nothrow) +{ + int nwhere = 0; + int ncurrent = tell(); + switch (whence) + { + case SEEK_SET: + nwhere=0; break; + case SEEK_CUR: + nwhere=ncurrent; break; + case SEEK_END: + { + if(offset) + { + if (nothrow) + return -1; + G_THROW( ERR_MSG("ByteStream.backward") ); + } + char buffer[1024]; + int bytes; + while((bytes=read(buffer, sizeof(buffer)))) + EMPTY_LOOP; + return 0; + } + default: + G_THROW( ERR_MSG("ByteStream.bad_arg") ); // Illegal argument in seek + } + nwhere += offset; + if (nwhere < ncurrent) + { + // Seeking backwards is not supported by this ByteStream + if (nothrow) + return -1; + G_THROW( ERR_MSG("ByteStream.backward") ); + } + while (nwhere>ncurrent) + { + char buffer[1024]; + const int xbytes=(ncurrent+(int)sizeof(buffer)>nwhere) + ?(nwhere - ncurrent):(int)sizeof(buffer); + const int bytes = read(buffer, xbytes); + ncurrent += bytes; + if (!bytes) + G_THROW( ByteStream::EndOfFile ); + // Seeking works funny on this ByteStream (ftell() acts strange) + if (ncurrent!=tell()) + G_THROW( ERR_MSG("ByteStream.seek") ); + } + return 0; +} + +size_t +ByteStream::readall(void *buffer, size_t size) +{ + size_t total = 0; + while (size > 0) + { + int nitems = read(buffer, size); + // Replaced perror() below with G_THROW(). It still makes little sense + // as there is no guarantee, that errno is right. Still, throwing + // exception instead of continuing to loop is better. + // - eaf + if(nitems < 0) + G_THROW(strerror(errno)); // (No error in the DjVuMessageFile) + if (nitems == 0) + break; + total += nitems; + size -= nitems; + buffer = (void*)((char*)buffer + nitems); + } + return total; +} + +size_t +ByteStream::format(const char *fmt, ... ) +{ + va_list args; + va_start(args, fmt); + const GUTF8String message(fmt,args); + return writestring(message); +} + +size_t +ByteStream::writestring(const GNativeString &s) +{ + int retval; + if(cp != UTF8) + { + retval=writall((const char *)s,s.length()); + if(cp == AUTO) + cp=NATIVE; // Avoid mixing string types. + }else + { + const GUTF8String msg(s.getNative2UTF8()); + retval=writall((const char *)msg,msg.length()); + } + return retval; +} + +size_t +ByteStream::writestring(const GUTF8String &s) +{ + int retval; + if(cp != NATIVE) + { + retval=writall((const char *)s,s.length()); + if(cp == AUTO) + cp=UTF8; // Avoid mixing string types. + }else + { + const GNativeString msg(s.getUTF82Native()); + retval=writall((const char *)msg,msg.length()); + } + return retval; +} + +size_t +ByteStream::writall(const void *buffer, size_t size) +{ + size_t total = 0; + while (size > 0) + { + size_t nitems = write(buffer, size); + if (nitems == 0) + G_THROW( ERR_MSG("ByteStream.write_error") ); // Unknown error in write + total += nitems; + size -= nitems; + buffer = (void*)((char*)buffer + nitems); + } + return total; +} + +size_t +ByteStream::copy(ByteStream &bsfrom, size_t size) +{ + size_t total = 0; + const size_t max_buffer_size=200*1024; + const size_t buffer_size=(size>0 && size<max_buffer_size) + ?size:max_buffer_size; + char *buffer; + GPBuffer<char> gbuf(buffer,buffer_size); + for(;;) + { + size_t bytes = buffer_size; + if (size>0 && bytes+total>size) + bytes = size - total; + if (bytes == 0) + break; + bytes = bsfrom.read((void*)buffer, bytes); + if (bytes == 0) + break; + writall((void*)buffer, bytes); + total += bytes; + } + return total; +} + + +void +ByteStream::write8 (unsigned int card) +{ + unsigned char c[1]; + c[0] = (card) & 0xff; + if (write((void*)c, sizeof(c)) != sizeof(c)) + G_THROW(strerror(errno)); // (No error in the DjVuMessageFile) +} + +void +ByteStream::write16(unsigned int card) +{ + unsigned char c[2]; + c[0] = (card>>8) & 0xff; + c[1] = (card) & 0xff; + if (writall((void*)c, sizeof(c)) != sizeof(c)) + G_THROW(strerror(errno)); // (No error in the DjVuMessageFile) +} + +void +ByteStream::write24(unsigned int card) +{ + unsigned char c[3]; + c[0] = (card>>16) & 0xff; + c[1] = (card>>8) & 0xff; + c[2] = (card) & 0xff; + if (writall((void*)c, sizeof(c)) != sizeof(c)) + G_THROW(strerror(errno)); // (No error in the DjVuMessageFile) +} + +void +ByteStream::write32(unsigned int card) +{ + unsigned char c[4]; + c[0] = (card>>24) & 0xff; + c[1] = (card>>16) & 0xff; + c[2] = (card>>8) & 0xff; + c[3] = (card) & 0xff; + if (writall((void*)c, sizeof(c)) != sizeof(c)) + G_THROW(strerror(errno)); // (No error in the DjVuMessageFile) +} + +unsigned int +ByteStream::read8 () +{ + unsigned char c[1]; + if (readall((void*)c, sizeof(c)) != sizeof(c)) + G_THROW( ByteStream::EndOfFile ); + return c[0]; +} + +unsigned int +ByteStream::read16() +{ + unsigned char c[2]; + if (readall((void*)c, sizeof(c)) != sizeof(c)) + G_THROW( ByteStream::EndOfFile ); + return (c[0]<<8)+c[1]; +} + +unsigned int +ByteStream::read24() +{ + unsigned char c[3]; + if (readall((void*)c, sizeof(c)) != sizeof(c)) + G_THROW( ByteStream::EndOfFile ); + return (((c[0]<<8)+c[1])<<8)+c[2]; +} + +unsigned int +ByteStream::read32() +{ + unsigned char c[4]; + if (readall((void*)c, sizeof(c)) != sizeof(c)) + G_THROW( ByteStream::EndOfFile ); + return (((((c[0]<<8)+c[1])<<8)+c[2])<<8)+c[3]; +} + + + +//// CLASS ByteStream::Stdio + +ByteStream::Stdio::Stdio(void) +: can_read(false),can_write(false),must_close(true),fp(0),pos(0) +{} + +ByteStream::Stdio::~Stdio() +{ + if (fp && must_close) + fclose(fp); +} + +GUTF8String +ByteStream::Stdio::init(const char mode[]) +{ + char const *mesg=0; + bool binary=false; + if(!fp) + must_close=false; + for (const char *s=mode; s && *s; s++) + { + switch(*s) + { + case 'r': + can_read=true; + if(!fp) fp=stdin; + break; + case 'w': + case 'a': + can_write=true; + if(!fp) fp=stdout; + break; + case '+': + can_read=can_write=true; + break; + case 'b': + binary=true; + break; + default: + mesg= ERR_MSG("ByteStream.bad_mode"); // Illegal mode in Stdio + } + } + if(binary && fp) { +#if defined(__CYGWIN32__) + setmode(fileno(fp), O_BINARY); +#elif defined(WIN32) + _setmode(_fileno(fp), _O_BINARY); +#endif + } + GUTF8String retval; + if(!mesg) + { + tell(); + }else + { + retval=mesg; + } + if(mesg &&(fp && must_close)) + { + fclose(fp); + fp=0; + must_close=false; + } + return retval; +} + +static FILE * +urlfopen(const GURL &url,const char mode[]) +{ +#ifdef WIN32 + FILE *retval=0; + const GUTF8String filename(url.UTF8Filename()); + wchar_t *wfilename; + const size_t wfilename_size=filename.length()+1; + GPBuffer<wchar_t> gwfilename(wfilename,wfilename_size); + if(filename.ncopy(wfilename,wfilename_size) > 0) + { + const GUTF8String gmode(mode); + wchar_t *wmode; + const size_t wmode_size=gmode.length()+1; + GPBuffer<wchar_t> gwmode(wmode,wmode_size); + if(gmode.ncopy(wmode,wmode_size) > 0) + { + retval=_wfopen(wfilename,wmode); + } + } + return retval?retval:fopen((const char *)url.NativeFilename(),mode); +#else + return fopen((const char *)url.NativeFilename(),mode); +#endif +} + +#ifdef UNIX +static int +urlopen(const GURL &url, const int mode, const int perm) +{ + return open((const char *)url.NativeFilename(),mode,perm); +} +#endif /* UNIX */ + +GUTF8String +ByteStream::Stdio::init(const GURL &url, const char mode[]) +{ + GUTF8String retval; + if (url.fname() != "-") + { + fp = urlfopen(url,mode); + if (!fp) + { + // Failed to open '%s': %s + G_THROW( ERR_MSG("ByteStream.open_fail") "\t" + url.name() + +"\t"+GNativeString(strerror(errno)).getNative2UTF8()); + } + } + return retval.length()?retval:init(mode); +} + +size_t +ByteStream::Stdio::read(void *buffer, size_t size) +{ + if (!can_read) + G_THROW( ERR_MSG("ByteStream.no_read") ); // Stdio not opened for reading + size_t nitems; + do + { + clearerr(fp); + nitems = fread(buffer, 1, size, fp); + if (nitems<=0 && ferror(fp)) + { +#ifdef EINTR + if (errno!=EINTR) +#endif + G_THROW(strerror(errno)); // (No error in the DjVuMessageFile) + } + else + break; + } while(true); + pos += nitems; + return nitems; +} + +size_t +ByteStream::Stdio::write(const void *buffer, size_t size) +{ + if (!can_write) + G_THROW( ERR_MSG("ByteStream.no_write") ); // Stdio not opened for writing + size_t nitems; + do + { + clearerr(fp); + nitems = fwrite(buffer, 1, size, fp); + if (nitems<=0 && ferror(fp)) + { +#ifdef EINTR + if (errno!=EINTR) +#endif + G_THROW(strerror(errno)); // (No error in the DjVuMessageFile) + } + else + break; + } while(true); + pos += nitems; + return nitems; +} + +void +ByteStream::Stdio::flush() +{ + if (fflush(fp) < 0) + G_THROW(strerror(errno)); // (No error in the DjVuMessageFile) +} + +long +ByteStream::Stdio::tell(void) const +{ + long x = ftell(fp); + if (x >= 0) + { + Stdio *sbs=const_cast<Stdio *>(this); + (sbs->pos) = x; + }else + { + x=pos; + } + return x; +} + +int +ByteStream::Stdio::seek(long offset, int whence, bool nothrow) +{ + if (whence==SEEK_SET && offset>=0 && offset==ftell(fp)) + return 0; + clearerr(fp); + if (fseek(fp, offset, whence)) + { + if (nothrow) + return -1; + G_THROW(strerror(errno)); // (No error in the DjVuMessageFile) + } + return tell(); +} + + + + +///////// ByteStream::Memory + +ByteStream::Memory::Memory() + : where(0), bsize(0), nblocks(0), gblocks(blocks,0) +{ +} + +GUTF8String +ByteStream::Memory::init(void const * const buffer, const size_t sz) +{ + GUTF8String retval; + G_TRY + { + writall(buffer, sz); + where = 0; + } + G_CATCH(ex) // The only error that should be thrown is out of memory... + { + retval=ex.get_cause(); + } + G_ENDCATCH; + return retval; +} + +void +ByteStream::Memory::empty() +{ + for (int b=0; b<nblocks; b++) + { + delete [] blocks[b]; + blocks[b]=0; + } + bsize = 0; + where = 0; + nblocks = 0; +} + +ByteStream::Memory::~Memory() +{ + empty(); +} + +size_t +ByteStream::Memory::write(const void *buffer, size_t sz) +{ + int nsz = (int)sz; + if (nsz <= 0) + return 0; + // check memory + if ( (where+nsz) > ((bsize+0xfff)&~0xfff) ) + { + // reallocate pointer array + if ( (where+nsz) > (nblocks<<12) ) + { + const int old_nblocks=nblocks; + nblocks = (((where+nsz)+0xffff)&~0xffff) >> 12; + gblocks.resize(nblocks); + char const ** eblocks=(char const **)(blocks+old_nblocks); + for(char const * const * const new_eblocks=blocks+nblocks; + eblocks <new_eblocks; eblocks++) + { + *eblocks = 0; + } + } + // allocate blocks + for (int b=(where>>12); (b<<12)<(where+nsz); b++) + { + if (! blocks[b]) + blocks[b] = new char[0x1000]; + } + } + // write data to buffer + while (nsz > 0) + { + int n = (where|0xfff) + 1 - where; + n = ((nsz < n) ? nsz : n); + memcpy( (void*)&blocks[where>>12][where&0xfff], buffer, n); + buffer = (void*) ((char*)buffer + n); + where += n; + nsz -= n; + } + // adjust size + if (where > bsize) + bsize = where; + return sz; +} + +size_t +ByteStream::Memory::readat(void *buffer, size_t sz, int pos) +{ + if ((int) sz > bsize - pos) + sz = bsize - pos; + int nsz = (int)sz; + if (nsz <= 0) + return 0; + // read data from buffer + while (nsz > 0) + { + int n = (pos|0xfff) + 1 - pos; + n = ((nsz < n) ? nsz : n); + memcpy(buffer, (void*)&blocks[pos>>12][pos&0xfff], n); + buffer = (void*) ((char*)buffer + n); + pos += n; + nsz -= n; + } + return sz; +} + +size_t +ByteStream::Memory::read(void *buffer, size_t sz) +{ + sz = readat(buffer,sz,where); + where += sz; + return sz; +} + +long +ByteStream::Memory::tell(void) const +{ + return where; +} + +int +ByteStream::Memory::seek(long offset, int whence, bool nothrow) +{ + int nwhere = 0; + switch (whence) + { + case SEEK_SET: nwhere = 0; break; + case SEEK_CUR: nwhere = where; break; + case SEEK_END: nwhere = bsize; break; + default: G_THROW( ERR_MSG("bad_arg") "\tByteStream::Memory::seek()"); // Illegal argument in ByteStream::Memory::seek() + } + nwhere += offset; + if (nwhere<0) + G_THROW( ERR_MSG("ByteStream.seek_error2") ); // Attempt to seek before the beginning of the file + where = nwhere; + return 0; +} + + + +/** This function has been moved into Arrays.cpp + In order to avoid dependencies from ByteStream.o + to Arrays.o */ +#ifdef DO_NOT_MOVE_GET_DATA_TO_ARRAYS_CPP +TArray<char> +ByteStream::get_data(void) +{ + TArray<char> data(0, size()-1); + readat((char*)data, size(), 0); + return data; +} +#endif + + +///////// ByteStream::Static + +ByteStream::Static::Static(const void * const buffer, const size_t sz) + : data((const char *)buffer), bsize(sz), where(0) +{ +} + +size_t +ByteStream::Static::read(void *buffer, size_t sz) +{ + int nsz = (int)sz; + if (nsz > bsize - where) + nsz = bsize - where; + if (nsz <= 0) + return 0; + memcpy(buffer, data+where, nsz); + where += nsz; + return nsz; +} + +int +ByteStream::Static::seek(long offset, int whence, bool nothrow) +{ + int nwhere = 0; + switch (whence) + { + case SEEK_SET: nwhere = 0; break; + case SEEK_CUR: nwhere = where; break; + case SEEK_END: nwhere = bsize; break; + default: G_THROW("bad_arg\tByteStream::Static::seek()"); // Illegal argument to ByteStream::Static::seek() + } + nwhere += offset; + if (nwhere<0) + G_THROW( ERR_MSG("ByteStream.seek_error2") ); // Attempt to seek before the beginning of the file + where = nwhere; + return 0; +} + +long +ByteStream::Static::tell(void) const +{ + return where; +} + +GP<ByteStream> +ByteStream::create(void) +{ + return new Memory(); +} + +GP<ByteStream> +ByteStream::create(void const * const buffer, const size_t size) +{ + Memory *mbs=new Memory(); + GP<ByteStream> retval=mbs; + mbs->init(buffer,size); + return retval; +} + +GP<ByteStream> +ByteStream::create(const GURL &url,char const * const xmode) +{ + GP<ByteStream> retval; + const char *mode = ((xmode) ? xmode : "rb"); +#ifdef UNIX + if (!strcmp(mode,"rb")) + { + int fd = urlopen(url,O_RDONLY,0777); + if (fd >= 0) + { +#if HAS_MEMMAP && defined(S_IFREG) + struct stat buf; + if ( (fstat(fd, &buf) >= 0) && (buf.st_mode & S_IFREG) ) + { + MemoryMapByteStream *rb = new MemoryMapByteStream(); + retval = rb; + GUTF8String errmessage = rb->init(fd,true); + if(errmessage.length()) + retval=0; + } +#endif + if (! retval) + { + FILE *f = fdopen(fd, mode); + if (f) + { + Stdio *sbs=new Stdio(); + retval=sbs; + GUTF8String errmessage=sbs->init(f, mode, true); + if(errmessage.length()) + retval=0; + } + } + if (! retval) + close(fd); + } + } +#endif + if (! retval) + { + Stdio *sbs=new Stdio(); + retval=sbs; + GUTF8String errmessage=sbs->init(url, mode); + if(errmessage.length()) + G_THROW(errmessage); + } + return retval; +} + +GP<ByteStream> +ByteStream::create(char const * const mode) +{ + GP<ByteStream> retval; + Stdio *sbs=new Stdio(); + retval=sbs; + GUTF8String errmessage=sbs->init(mode?mode:"rb"); + if(errmessage.length()) + { + G_THROW(errmessage); + } + return retval; +} + +GP<ByteStream> +ByteStream::create(const int fd,char const * const mode,const bool closeme) +{ + GP<ByteStream> retval; + const char *default_mode="rb"; +#if HAS_MEMMAP + if ( (!mode&&(fd!=0)&&(fd!=1)&&(fd!=2)) + || (mode&&(GUTF8String("rb") == mode))) + { + MemoryMapByteStream *rb=new MemoryMapByteStream(); + retval=rb; + GUTF8String errmessage=rb->init(fd,closeme); + if(errmessage.length()) + { + retval=0; + } + } + if(!retval) +#endif + { + int fd2 = fd; + FILE *f = 0; + if (fd == 0 && !closeme + && (!mode || mode[0]=='r') ) + { + f=stdin; + default_mode = "r"; + fd2=(-1); + } + else if (fd == 1 && !closeme + && (!mode || mode[0]=='a' || mode[0]=='w') ) + { + default_mode = "a"; + f=stdout; + fd2 = -1; + } + else if (fd == 2 && !closeme + && (!mode || mode[0]=='a' || mode[0]=='w') ) + { + default_mode = "a"; + f=stderr; + fd2 = -1; + } + else + { + if (! closeme) + fd2 = dup(fd); + f = fdopen(fd2,(char*)(mode?mode:default_mode)); + } + + if(!f) + { + if ( fd2 >= 0) + close(fd2); + G_THROW( ERR_MSG("ByteStream.open_fail2") ); + } + Stdio *sbs=new Stdio(); + retval=sbs; + GUTF8String errmessage=sbs->init(f,mode?mode:default_mode,(fd2>=0)); + if(errmessage.length()) + G_THROW(errmessage); + } + return retval; +} + +GP<ByteStream> +ByteStream::create(FILE * const f,char const * const mode,const bool closeme) +{ + GP<ByteStream> retval; +#if HAS_MEMMAP + if (!mode || (GUTF8String("rb") == mode)) + { + MemoryMapByteStream *rb=new MemoryMapByteStream(); + retval=rb; + GUTF8String errmessage=rb->init(fileno(f),false); + if(errmessage.length()) + { + retval=0; + }else + { + fclose(f); + } + } + if(!retval) +#endif + { + Stdio *sbs=new Stdio(); + retval=sbs; + GUTF8String errmessage=sbs->init(f,mode?mode:"rb",closeme); + if(errmessage.length()) + { + G_THROW(errmessage); + } + } + return retval; +} + +GP<ByteStream> +ByteStream::create_static(const void * const buffer, size_t sz) +{ + return new Static(buffer, sz); +} + +GP<ByteStream> +ByteStream::duplicate(const size_t xsize) const +{ + GP<ByteStream> retval; + const long int pos=tell(); + const int tsize=size(); + ByteStream &self=*(const_cast<ByteStream *>(this)); + if(tsize < 0 || pos < 0 || (unsigned int)tsize < 1+(unsigned int)pos) + { + retval=ByteStream::create(); + retval->copy(self,xsize); + retval->seek(0L); + }else + { + const size_t s=(size_t)tsize-(size_t)pos; + const int size=(!xsize||(s<xsize))?s:xsize; + ByteStream::Static::Allocate *bs=new ByteStream::Static::Allocate(size); + retval=bs; + self.readall(bs->buf,size); + } + self.seek(pos,SEEK_SET,true); + return retval; +} + + +#if HAS_MEMMAP +MemoryMapByteStream::MemoryMapByteStream(void) +: ByteStream::Static(0,0) +{} + +GUTF8String +MemoryMapByteStream::init(FILE *const f,const bool closeme) +{ + GUTF8String retval; + retval=init(fileno(f),false); + if(closeme) + { + fclose(f); + } + return retval; +} + +GUTF8String +MemoryMapByteStream::init(const int fd,const bool closeme) +{ + GUTF8String retval; +#if defined(PROT_READ) && defined(MAP_SHARED) + struct stat statbuf; + if(!fstat(fd,&statbuf)) + { + if(statbuf.st_size) + { + bsize=statbuf.st_size; + data=(char *)mmap(0,statbuf.st_size,PROT_READ,MAP_SHARED,fd,0); + } + }else + { + if(closeme) + { + close(fd); + } + retval= ERR_MSG("ByteStream.open_fail2"); + } +#else + retval= ERR_MSG("ByteStream.open_fail2"); +#endif + if(closeme) + { + close(fd); + } + return retval; +} + +MemoryMapByteStream::~MemoryMapByteStream() +{ + if(data) + { + munmap(const_cast<char *>(data),bsize); + } +} + +#endif + +ByteStream::Wrapper::~Wrapper() {} + + +GP<ByteStream> +ByteStream::get_stdin(char const * const mode) +{ + static GP<ByteStream> gp = ByteStream::create(0,mode,false); + return gp; +} + +GP<ByteStream> +ByteStream::get_stdout(char const * const mode) +{ + static GP<ByteStream> gp = ByteStream::create(1,mode,false); + return gp; +} + +GP<ByteStream> +ByteStream::get_stderr(char const * const mode) +{ + static GP<ByteStream> gp = ByteStream::create(2,mode,false); + return gp; +} + + +/** Looks up the message and writes it to the specified stream. */ +void ByteStream::formatmessage( const char *fmt, ... ) +{ + va_list args; + va_start(args, fmt); + const GUTF8String message(fmt,args); + writemessage( message ); +} + +/** Looks up the message and writes it to the specified stream. */ +void ByteStream::writemessage( const char *message ) +{ + writestring( DjVuMessage::LookUpUTF8( message ) ); +} + +static void +read_file(ByteStream &bs,char *&buffer,GPBuffer<char> &gbuffer) +{ + const int size=bs.size(); + int pos=0; + if(size>0) + { + size_t readsize=size+1; + gbuffer.resize(readsize); + for(int i;readsize&&(i=bs.read(buffer+pos,readsize))>0;pos+=i,readsize-=i) + EMPTY_LOOP; + }else + { + const size_t readsize=32768; + gbuffer.resize(readsize); + for(int i;((i=bs.read(buffer+pos,readsize))>0); + gbuffer.resize((pos+=i)+readsize)) + EMPTY_LOOP; + } + buffer[pos]=0; +} + +GNativeString +ByteStream::getAsNative(void) +{ + char *buffer; + GPBuffer<char> gbuffer(buffer); + read_file(*this,buffer,gbuffer); + return GNativeString(buffer); +} + +GUTF8String +ByteStream::getAsUTF8(void) +{ + char *buffer; + GPBuffer<char> gbuffer(buffer); + read_file(*this,buffer,gbuffer); + return GUTF8String(buffer); +} + + +#ifdef HAVE_NAMESPACES +} +# ifndef NOT_USING_DJVU_NAMESPACE +using namespace DJVU; +# endif +#endif + +void +DjVuPrintErrorUTF8(const char *fmt, ... ) +{ + G_TRY { + GP<ByteStream> errout = ByteStream::get_stderr(); + if (errout) + { + errout->cp=ByteStream::NATIVE; + va_list args; + va_start(args, fmt); + const GUTF8String message(fmt,args); + errout->writestring(message); + } + // Need to catch all exceptions because these might be + // called from an outer exception handler (with prejudice) + } G_CATCH_ALL { } G_ENDCATCH; +} + +void +DjVuPrintErrorNative(const char *fmt, ... ) +{ + G_TRY { + GP<ByteStream> errout = ByteStream::get_stderr(); + if (errout) + { + errout->cp=ByteStream::NATIVE; + va_list args; + va_start(args, fmt); + const GNativeString message(fmt,args); + errout->writestring(message); + } + // Need to catch all exceptions because these might be + // called from an outer exception handler (with prejudice) + } G_CATCH_ALL { } G_ENDCATCH; +} + +void +DjVuPrintMessageUTF8(const char *fmt, ... ) +{ + G_TRY { + GP<ByteStream> strout = ByteStream::get_stdout(); + if (strout) + { + strout->cp=ByteStream::NATIVE; + va_list args; + va_start(args, fmt); + const GUTF8String message(fmt,args); + strout->writestring(message); + } + // Need to catch all exceptions because these might be + // called from an outer exception handler (with prejudice) + } G_CATCH_ALL { } G_ENDCATCH; +} + +void +DjVuPrintMessageNative(const char *fmt, ... ) +{ + G_TRY { + GP<ByteStream> strout = ByteStream::get_stdout(); + if (strout) + { + strout->cp=ByteStream::NATIVE; + va_list args; + va_start(args, fmt); + const GNativeString message(fmt,args); + strout->writestring(message); + } + // Need to catch all exceptions because these might be + // called from an outer exception handler (with prejudice) + } G_CATCH_ALL { } G_ENDCATCH; +} |