source: trunk/libdjvu/ByteStream.cpp @ 280

Last change on this file since 280 was 280, checked in by rbri, 11 years ago

DJVU plugin: djvulibre updated to version 3.5.22

File size: 32.9 KB
Line 
1//C-  -*- C++ -*-
2//C- -------------------------------------------------------------------
3//C- DjVuLibre-3.5
4//C- Copyright (c) 2002  Leon Bottou and Yann Le Cun.
5//C- Copyright (c) 2001  AT&T
6//C-
7//C- This software is subject to, and may be distributed under, the
8//C- GNU General Public License, either Version 2 of the license,
9//C- or (at your option) any later version. The license should have
10//C- accompanied the software or you may obtain a copy of the license
11//C- from the Free Software Foundation at http://www.fsf.org .
12//C-
13//C- This program is distributed in the hope that it will be useful,
14//C- but WITHOUT ANY WARRANTY; without even the implied warranty of
15//C- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16//C- GNU General Public License for more details.
17//C-
18//C- DjVuLibre-3.5 is derived from the DjVu(r) Reference Library from
19//C- Lizardtech Software.  Lizardtech Software has authorized us to
20//C- replace the original DjVu(r) Reference Library notice by the following
21//C- text (see doc/lizard2002.djvu and doc/lizardtech2007.djvu):
22//C-
23//C-  ------------------------------------------------------------------
24//C- | DjVu (r) Reference Library (v. 3.5)
25//C- | Copyright (c) 1999-2001 LizardTech, Inc. All Rights Reserved.
26//C- | The DjVu Reference Library is protected by U.S. Pat. No.
27//C- | 6,058,214 and patents pending.
28//C- |
29//C- | This software is subject to, and may be distributed under, the
30//C- | GNU General Public License, either Version 2 of the license,
31//C- | or (at your option) any later version. The license should have
32//C- | accompanied the software or you may obtain a copy of the license
33//C- | from the Free Software Foundation at http://www.fsf.org .
34//C- |
35//C- | The computer code originally released by LizardTech under this
36//C- | license and unmodified by other parties is deemed "the LIZARDTECH
37//C- | ORIGINAL CODE."  Subject to any third party intellectual property
38//C- | claims, LizardTech grants recipient a worldwide, royalty-free,
39//C- | non-exclusive license to make, use, sell, or otherwise dispose of
40//C- | the LIZARDTECH ORIGINAL CODE or of programs derived from the
41//C- | LIZARDTECH ORIGINAL CODE in compliance with the terms of the GNU
42//C- | General Public License.   This grant only confers the right to
43//C- | infringe patent claims underlying the LIZARDTECH ORIGINAL CODE to
44//C- | the extent such infringement is reasonably necessary to enable
45//C- | recipient to make, have made, practice, sell, or otherwise dispose
46//C- | of the LIZARDTECH ORIGINAL CODE (or portions thereof) and not to
47//C- | any greater extent that may be necessary to utilize further
48//C- | modifications or combinations.
49//C- |
50//C- | The LIZARDTECH ORIGINAL CODE is provided "AS IS" WITHOUT WARRANTY
51//C- | OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
52//C- | TO ANY WARRANTY OF NON-INFRINGEMENT, OR ANY IMPLIED WARRANTY OF
53//C- | MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
54//C- +------------------------------------------------------------------
55//
56// $Id: ByteStream.cpp,v 1.24 2007/07/14 01:21:56 leonb Exp $
57// $Name: release_3_5_22 $
58
59// From: Leon Bottou, 1/31/2002
60// This file has very little to do with my initial implementation.
61// It has been practically rewritten by Lizardtech for i18n changes.
62// Our original implementation consisted of multiple classes.
63// <http://prdownloads.sourceforge.net/djvu/DjVu2_2b-src.tgz>.
64
65#ifdef HAVE_CONFIG_H
66# include "config.h"
67#endif
68#if NEED_GNUG_PRAGMAS
69# pragma implementation
70#endif
71
72// - Author: Leon Bottou, 04/1997
73
74#include "DjVuGlobal.h"
75#include "ByteStream.h"
76#include "GOS.h"
77#include "GURL.h"
78#include "DjVuMessage.h"
79#include <fcntl.h>
80/* Lucide */
81#if defined(WIN32) || defined(__CYGWIN32__) || defined(OS2)
82# include <io.h>
83#endif
84
85#ifdef UNIX
86# ifndef HAS_MEMMAP
87#  define HAS_MEMMAP 1
88# endif
89#endif
90
91#ifdef UNIX
92# include <sys/types.h>
93# include <sys/stat.h>
94# include <unistd.h>
95# include <errno.h>
96# ifdef HAS_MEMMAP
97#  include <sys/mman.h>
98# endif
99#endif
100
101#ifdef macintosh
102# ifndef UNIX
103#  include <unistd.h>
104_MSL_IMP_EXP_C int _dup(int);
105_MSL_IMP_EXP_C int _dup2(int,int);
106_MSL_IMP_EXP_C int _close(int);
107__inline int dup(int _a ) { return _dup(_a);}
108__inline int dup2(int _a, int _b ) { return _dup2(_a, _b);}
109# endif
110#endif
111
112#ifdef WIN32
113# if !defined(__MINGW32__) && !defined(__CYGWIN32__)
114#  define close _close
115#  define fdopen _fdopen
116#  define dup _dup
117# endif
118#endif
119
120#ifdef HAVE_NAMESPACES
121namespace DJVU {
122# ifdef NOT_DEFINED // Just to fool emacs c++ mode
123}
124#endif
125#endif
126
127const char *ByteStream::EndOfFile=ERR_MSG("EOF");
128
129/** ByteStream interface for stdio files.
130    The virtual member functions #read#, #write#, #tell# and #seek# are mapped
131    to the well known stdio functions #fread#, #fwrite#, #ftell# and #fseek#.
132    @see Unix man page fopen(3), fread(3), fwrite(3), ftell(3), fseek(3) */
133
134class ByteStream::Stdio : public ByteStream {
135public:
136  Stdio(void);
137
138  /** Constructs a ByteStream for accessing the file named #url#.
139      Arguments #url# and #mode# are similar to the arguments of the well
140      known stdio function #fopen#. In addition a url of #-# will be
141      interpreted as the standard output or the standard input according to
142      #mode#.  This constructor will open a stdio file and construct a
143      ByteStream object accessing this file. Destroying the ByteStream object
144      will flush and close the associated stdio file.  Returns an error code
145      if the stdio file cannot be opened. */
146  GUTF8String init(const GURL &url, const char * const mode);
147
148  /** Constructs a ByteStream for accessing the stdio file #f#.
149      Argument #mode# indicates the type of the stdio file, as in the
150      well known stdio function #fopen#.  Destroying the ByteStream
151      object will not close the stdio file #f# unless closeme is true. */
152  GUTF8String init(FILE * const f, const char * const mode="rb", const bool closeme=false);
153
154  /** Initializes from stdio */
155  GUTF8String init(const char mode[]);
156
157  // Virtual functions
158  ~Stdio();
159  virtual size_t read(void *buffer, size_t size);
160  virtual size_t write(const void *buffer, size_t size);
161  virtual void flush(void);
162  virtual int seek(long offset, int whence = SEEK_SET, bool nothrow=false);
163  virtual long tell(void) const;
164private:
165  // Cancel C++ default stuff
166  Stdio(const Stdio &);
167  Stdio & operator=(const Stdio &);
168private:
169  // Implementation
170  bool can_read;
171  bool can_write;
172  bool must_close;
173protected:
174  FILE *fp;
175  long pos;
176};
177
178inline GUTF8String
179ByteStream::Stdio::init(FILE * const f,const char mode[],const bool closeme)
180{
181  fp=f;
182  must_close=closeme;
183  return init(mode);
184}
185
186
187/** ByteStream interface managing a memory buffer. 
188    Class #ByteStream::Memory# manages a dynamically resizable buffer from
189    which data can be read or written.  The buffer itself is organized as an
190    array of blocks of 4096 bytes.  */
191
192class ByteStream::Memory : public ByteStream
193{
194public:
195  /** Constructs an empty ByteStream::Memory.
196      The buffer is initially empty. You must first use function #write#
197      to store data into the buffer, use function #seek# to rewind the
198      current position, and function #read# to read the data back. */
199  Memory();
200  /** Constructs a Memory by copying initial data.  The
201      Memory buffer is initialized with #size# bytes copied from the
202      memory area pointed to by #buffer#. */
203  GUTF8String init(const void * const buffer, const size_t size);
204  // Virtual functions
205  ~Memory();
206  virtual size_t read(void *buffer, size_t size);
207  virtual size_t write(const void *buffer, size_t size);
208  virtual int    seek(long offset, int whence=SEEK_SET, bool nothrow=false);
209  virtual long   tell(void) const;
210  /** Erases everything in the Memory.
211      The current location is reset to zero. */
212  void empty();
213  /** Returns the total number of bytes contained in the buffer.  Valid
214      offsets for function #seek# range from 0 to the value returned by this
215      function. */
216  virtual int size(void) const;
217  /** Returns a reference to the byte at offset #n#. This reference can be
218      used to read (as in #mbs[n]#) or modify (as in #mbs[n]=c#) the contents
219      of the buffer. */
220  char &operator[] (int n);
221  /** Copies all internal data into \Ref{TArray} and returns it */
222private:
223  // Cancel C++ default stuff
224  Memory(const Memory &);
225  Memory & operator=(const Memory &);
226  // Current position
227  int where;
228protected:
229  /** Reads data from a random position. This function reads at most #sz#
230      bytes at position #pos# into #buffer# and returns the actual number of
231      bytes read.  The current position is unchanged. */
232  virtual size_t readat(void *buffer, size_t sz, int pos);
233  /** Number of bytes in internal buffer. */
234  int bsize;
235  /** Number of 4096 bytes blocks. */
236  int nblocks;
237  /** Pointers (possibly null) to 4096 bytes blocks. */
238  char **blocks;
239  /** Pointers (possibly null) to 4096 bytes blocks. */
240  GPBuffer<char *> gblocks;
241};
242
243
244
245inline int
246ByteStream::Memory::size(void) const
247{
248  return bsize;
249}
250
251inline char &
252ByteStream::Memory::operator[] (int n)
253{
254  return blocks[n>>12][n&0xfff];
255}
256
257
258
259/** Read-only ByteStream interface to a memory area. 
260    Class #ByteStream::Static# implements a read-only ByteStream interface for a
261    memory area specified by the user at construction time. Calls to function
262    #read# directly access this memory area.  The user must therefore make
263    sure that its content remain valid long enough.  */
264
265class ByteStream::Static : public ByteStream
266{
267public:
268
269  /** Creates a Static object for allocating the memory area of
270      length #sz# starting at address #buffer#. */
271  Static(const void * const buffer, const size_t sz);
272  ~Static();
273  // Virtual functions
274  virtual size_t read(void *buffer, size_t sz);
275  virtual int    seek(long offset, int whence = SEEK_SET, bool nothrow=false);
276  virtual long tell(void) const;
277  /** Returns the total number of bytes contained in the buffer, file, etc.
278      Valid offsets for function #seek# range from 0 to the value returned
279      by this function. */
280  virtual int size(void) const;
281protected:
282  const char *data;
283  int bsize;
284private:
285  int where;
286};
287
288ByteStream::Static::~Static() {}
289
290inline int
291ByteStream::Static::size(void) const
292{
293  return bsize;
294}
295
296#if HAS_MEMMAP
297/** Read-only ByteStream interface to a memmap area.
298    Class #MemoryMapByteStream# implements a read-only ByteStream interface
299    for a memory map to a file. */
300
301class MemoryMapByteStream : public ByteStream::Static
302{
303public:
304  MemoryMapByteStream(void);
305  virtual ~MemoryMapByteStream(); 
306private:
307  GUTF8String init(const int fd, const bool closeme);
308  GUTF8String init(FILE *const f,const bool closeme);
309  friend class ByteStream;
310};
311#endif
312
313//// CLASS BYTESTREAM
314
315
316ByteStream::~ByteStream()
317{
318}
319
320int 
321ByteStream::scanf(const char *fmt, ...)
322{
323  G_THROW( ERR_MSG("ByteStream.not_implemented") ); // This is a place holder function.
324  return 0;
325}
326
327size_t 
328ByteStream::read(void *buffer, size_t sz)
329{
330  G_THROW( ERR_MSG("ByteStream.cant_read") );      //  Cannot read from a ByteStream created for writing
331  return 0;
332}
333
334size_t 
335ByteStream::write(const void *buffer, size_t sz)
336{
337  G_THROW( ERR_MSG("ByteStream.cant_write") );      //  Cannot write from a ByteStream created for reading
338  return 0;
339}
340
341void
342ByteStream::flush()
343{
344}
345
346int
347ByteStream::seek(long offset, int whence, bool nothrow)
348{
349  int nwhere = 0;
350  int ncurrent = tell();
351  switch (whence)
352    {
353    case SEEK_SET:
354      nwhere=0; break;
355    case SEEK_CUR:
356      nwhere=ncurrent; break;
357    case SEEK_END: 
358    {
359      if(offset)
360      {
361        if (nothrow)
362          return -1;
363        G_THROW( ERR_MSG("ByteStream.backward") );
364      }
365      char buffer[1024];
366      int bytes;
367      while((bytes=read(buffer, sizeof(buffer))))
368        EMPTY_LOOP;
369      return 0;
370    }
371    default:
372      G_THROW( ERR_MSG("ByteStream.bad_arg") );       //  Illegal argument in seek
373    }
374  nwhere += offset;
375  if (nwhere < ncurrent) 
376  {
377    //  Seeking backwards is not supported by this ByteStream
378    if (nothrow)
379      return -1;
380    G_THROW( ERR_MSG("ByteStream.backward") );
381  }
382  while (nwhere>ncurrent)
383  {
384    char buffer[1024];
385    const int xbytes=(ncurrent+(int)sizeof(buffer)>nwhere)
386      ?(nwhere - ncurrent):(int)sizeof(buffer);
387    const int bytes = read(buffer, xbytes);
388    ncurrent += bytes;
389    if (!bytes)
390      G_THROW( ByteStream::EndOfFile );
391    //  Seeking works funny on this ByteStream (ftell() acts strange)
392    if (ncurrent!=tell())
393      G_THROW( ERR_MSG("ByteStream.seek") );
394  }
395  return 0;
396}
397
398size_t 
399ByteStream::readall(void *buffer, size_t size)
400{
401  size_t total = 0;
402    while (size > 0)
403    {
404      int nitems = read(buffer, size);
405      // Replaced perror() below with G_THROW(). It still makes little sense
406      // as there is no guarantee, that errno is right. Still, throwing
407      // exception instead of continuing to loop is better.
408      // - eaf
409      if(nitems < 0) 
410        G_THROW(strerror(errno));               //  (No error in the DjVuMessageFile)
411      if (nitems == 0)
412        break;
413      total += nitems;
414      size -= nitems; 
415      buffer = (void*)((char*)buffer + nitems);
416    }
417  return total;
418}
419
420size_t
421ByteStream::format(const char *fmt, ... )
422{
423  va_list args;
424  va_start(args, fmt); 
425  const GUTF8String message(fmt,args);
426  return writestring(message);
427}
428
429size_t
430ByteStream::writestring(const GNativeString &s)
431{
432  int retval;
433  if(cp != UTF8)
434  {
435    retval=writall((const char *)s,s.length());
436    if(cp == AUTO)
437      cp=NATIVE; // Avoid mixing string types.
438  }else
439  { 
440    const GUTF8String msg(s.getNative2UTF8());
441    retval=writall((const char *)msg,msg.length());
442  }
443  return retval;
444}
445
446size_t
447ByteStream::writestring(const GUTF8String &s)
448{
449  int retval;
450  if(cp != NATIVE)
451  {
452    retval=writall((const char *)s,s.length());
453    if(cp == AUTO)
454      cp=UTF8; // Avoid mixing string types.
455  }else
456  { 
457    const GNativeString msg(s.getUTF82Native());
458    retval=writall((const char *)msg,msg.length());
459  }
460  return retval;
461}
462
463size_t 
464ByteStream::writall(const void *buffer, size_t size)
465{
466  size_t total = 0;
467  while (size > 0)
468    {
469      size_t nitems = write(buffer, size);
470      if (nitems == 0)
471        G_THROW( ERR_MSG("ByteStream.write_error") );      //  Unknown error in write
472      total += nitems;
473      size -= nitems; 
474      buffer = (void*)((char*)buffer + nitems);
475    }
476  return total;
477}
478
479size_t 
480ByteStream::copy(ByteStream &bsfrom, size_t size)
481{
482  size_t total = 0;
483  const size_t max_buffer_size=200*1024;
484  const size_t buffer_size=(size>0 && size<max_buffer_size)
485    ?size:max_buffer_size;
486  char *buffer;
487  GPBuffer<char> gbuf(buffer,buffer_size);
488  for(;;)
489    {
490      size_t bytes = buffer_size;
491      if (size>0 && bytes+total>size)
492        bytes = size - total;
493      if (bytes == 0)
494        break;
495      bytes = bsfrom.read((void*)buffer, bytes);
496      if (bytes == 0)
497        break;
498      writall((void*)buffer, bytes);
499      total += bytes;
500    }
501  return total;
502}
503
504
505void 
506ByteStream::write8 (unsigned int card)
507{
508  unsigned char c[1];
509  c[0] = (card) & 0xff;
510  if (write((void*)c, sizeof(c)) != sizeof(c))
511    G_THROW(strerror(errno));   //  (No error in the DjVuMessageFile)
512}
513
514void 
515ByteStream::write16(unsigned int card)
516{
517  unsigned char c[2];
518  c[0] = (card>>8) & 0xff;
519  c[1] = (card) & 0xff;
520  if (writall((void*)c, sizeof(c)) != sizeof(c))
521    G_THROW(strerror(errno));   //  (No error in the DjVuMessageFile)
522}
523
524void 
525ByteStream::write24(unsigned int card)
526{
527  unsigned char c[3];
528  c[0] = (card>>16) & 0xff;
529  c[1] = (card>>8) & 0xff;
530  c[2] = (card) & 0xff;
531  if (writall((void*)c, sizeof(c)) != sizeof(c))
532    G_THROW(strerror(errno));   //  (No error in the DjVuMessageFile)
533}
534
535void 
536ByteStream::write32(unsigned int card)
537{
538  unsigned char c[4];
539  c[0] = (card>>24) & 0xff;
540  c[1] = (card>>16) & 0xff;
541  c[2] = (card>>8) & 0xff;
542  c[3] = (card) & 0xff;
543  if (writall((void*)c, sizeof(c)) != sizeof(c))
544    G_THROW(strerror(errno));   //  (No error in the DjVuMessageFile)
545}
546
547unsigned int 
548ByteStream::read8 ()
549{
550  unsigned char c[1];
551  if (readall((void*)c, sizeof(c)) != sizeof(c))
552    G_THROW( ByteStream::EndOfFile );
553  return c[0];
554}
555
556unsigned int 
557ByteStream::read16()
558{
559  unsigned char c[2];
560  if (readall((void*)c, sizeof(c)) != sizeof(c))
561    G_THROW( ByteStream::EndOfFile );
562  return (c[0]<<8)+c[1];
563}
564
565unsigned int 
566ByteStream::read24()
567{
568  unsigned char c[3];
569  if (readall((void*)c, sizeof(c)) != sizeof(c))
570    G_THROW( ByteStream::EndOfFile );
571  return (((c[0]<<8)+c[1])<<8)+c[2];
572}
573
574unsigned int 
575ByteStream::read32()
576{
577  unsigned char c[4];
578  if (readall((void*)c, sizeof(c)) != sizeof(c))
579    G_THROW( ByteStream::EndOfFile );
580  return (((((c[0]<<8)+c[1])<<8)+c[2])<<8)+c[3];
581}
582
583
584
585//// CLASS ByteStream::Stdio
586
587ByteStream::Stdio::Stdio(void)
588: can_read(false),can_write(false),must_close(true),fp(0),pos(0)
589{}
590
591ByteStream::Stdio::~Stdio()
592{
593  if (fp && must_close)
594    fclose(fp);
595}
596
597GUTF8String
598ByteStream::Stdio::init(const char mode[])
599{
600  char const *mesg=0;
601  bool binary=false;
602  if(!fp)
603    must_close=false;
604  for (const char *s=mode; s && *s; s++)
605  {
606    switch(*s) 
607    {
608      case 'r':
609        can_read=true;
610        if(!fp) fp=stdin;
611        break;
612      case 'w': 
613      case 'a':
614        can_write=true;
615        if(!fp) fp=stdout;
616        break;
617      case '+':
618        can_read=can_write=true;
619        break;
620      case 'b':
621        binary=true;
622        break;
623      default:
624        mesg= ERR_MSG("ByteStream.bad_mode"); //  Illegal mode in Stdio
625    }
626  }
627  if(binary && fp) {
628#if defined(__CYGWIN32__)
629    setmode(fileno(fp), O_BINARY);
630#elif defined(WIN32)
631    _setmode(_fileno(fp), _O_BINARY);
632#endif
633  }
634  GUTF8String retval;
635  if(!mesg)
636  {
637    tell();
638  }else
639  {
640    retval=mesg;
641  }
642  if(mesg &&(fp && must_close))
643  {
644    fclose(fp);
645    fp=0;
646    must_close=false;
647  }
648  return retval;
649}
650
651static FILE *
652urlfopen(const GURL &url,const char mode[])
653{
654#ifdef WIN32
655  FILE *retval=0;
656  const GUTF8String filename(url.UTF8Filename());
657  wchar_t *wfilename;
658  const size_t wfilename_size=filename.length()+1;
659  GPBuffer<wchar_t> gwfilename(wfilename,wfilename_size);
660  if(filename.ncopy(wfilename,wfilename_size) > 0)
661  {
662    const GUTF8String gmode(mode);
663    wchar_t *wmode;
664    const size_t wmode_size=gmode.length()+1;
665    GPBuffer<wchar_t> gwmode(wmode,wmode_size);
666        if(gmode.ncopy(wmode,wmode_size) > 0)
667        {
668          retval=_wfopen(wfilename,wmode);
669        }
670  }
671  return retval?retval:fopen((const char *)url.NativeFilename(),mode);
672#else
673  return fopen((const char *)url.NativeFilename(),mode);
674#endif
675}
676
677#ifdef UNIX
678static int
679urlopen(const GURL &url, const int mode, const int perm)
680{
681  return open((const char *)url.NativeFilename(),mode,perm);
682}
683#endif /* UNIX */
684
685GUTF8String
686ByteStream::Stdio::init(const GURL &url, const char mode[])
687{
688  GUTF8String retval;
689  if (url.fname() != "-")
690  {
691    fp = urlfopen(url,mode);
692    if (!fp)
693    {
694      //  Failed to open '%s': %s
695      G_THROW( ERR_MSG("ByteStream.open_fail") "\t" + url.name()
696               +"\t"+GNativeString(strerror(errno)).getNative2UTF8());
697    }
698  }
699  return retval.length()?retval:init(mode);
700}
701
702size_t 
703ByteStream::Stdio::read(void *buffer, size_t size)
704{
705  if (!can_read)
706    G_THROW( ERR_MSG("ByteStream.no_read") ); //  Stdio not opened for reading
707  size_t nitems;
708  do
709  {
710    clearerr(fp);
711    nitems = fread(buffer, 1, size, fp); 
712    if (nitems<=0 && ferror(fp))
713    {
714#ifdef EINTR
715      if (errno!=EINTR)
716#endif
717        G_THROW(strerror(errno)); //  (No error in the DjVuMessageFile)
718    }
719    else
720      break;
721  } while(true);
722  pos += nitems;
723  return nitems;
724}
725
726size_t 
727ByteStream::Stdio::write(const void *buffer, size_t size)
728{
729  if (!can_write)
730    G_THROW( ERR_MSG("ByteStream.no_write") ); //  Stdio not opened for writing
731  size_t nitems;
732  do
733  {
734    clearerr(fp);
735    nitems = fwrite(buffer, 1, size, fp);
736    if (nitems<=0 && ferror(fp))
737    {
738#ifdef EINTR
739      if (errno!=EINTR)
740#endif
741        G_THROW(strerror(errno)); //  (No error in the DjVuMessageFile)
742    }
743    else
744      break;
745  } while(true);
746  pos += nitems;
747  return nitems;
748}
749
750void
751ByteStream::Stdio::flush()
752{
753  if (fflush(fp) < 0)
754    G_THROW(strerror(errno)); //  (No error in the DjVuMessageFile)
755}
756
757long 
758ByteStream::Stdio::tell(void) const
759{
760  long x = ftell(fp);
761  if (x >= 0)
762  {
763    Stdio *sbs=const_cast<Stdio *>(this);
764    (sbs->pos) = x;
765  }else
766  {
767    x=pos;
768  }
769  return x;
770}
771
772int
773ByteStream::Stdio::seek(long offset, int whence, bool nothrow)
774{
775  if (whence==SEEK_SET && offset>=0 && offset==ftell(fp))
776    return 0;
777  clearerr(fp);
778  if (fseek(fp, offset, whence)) 
779    {
780      if (nothrow) 
781        return -1;
782      G_THROW(strerror(errno)); //  (No error in the DjVuMessageFile)
783    }
784  return tell();
785}
786
787
788
789
790///////// ByteStream::Memory
791
792ByteStream::Memory::Memory()
793  : where(0), bsize(0), nblocks(0), gblocks(blocks,0)
794{
795}
796
797GUTF8String
798ByteStream::Memory::init(void const * const buffer, const size_t sz)
799{
800  GUTF8String retval;
801  G_TRY
802  {
803    writall(buffer, sz);
804    where = 0;
805  }
806  G_CATCH(ex) // The only error that should be thrown is out of memory...
807  {
808    retval=ex.get_cause();
809  }
810  G_ENDCATCH;
811  return retval;
812}
813
814void 
815ByteStream::Memory::empty()
816{
817  for (int b=0; b<nblocks; b++)
818  {
819    delete [] blocks[b];
820    blocks[b]=0;
821  }
822  bsize = 0;
823  where = 0;
824  nblocks = 0;
825}
826
827ByteStream::Memory::~Memory()
828{
829  empty();
830}
831
832size_t 
833ByteStream::Memory::write(const void *buffer, size_t sz)
834{
835  int nsz = (int)sz;
836  if (nsz <= 0)
837    return 0;
838  // check memory
839  if ( (where+nsz) > ((bsize+0xfff)&~0xfff) )
840    {
841      // reallocate pointer array
842      if ( (where+nsz) > (nblocks<<12) )
843        {
844          const int old_nblocks=nblocks;
845          nblocks = (((where+nsz)+0xffff)&~0xffff) >> 12;
846          gblocks.resize(nblocks);
847          char const ** eblocks=(char const **)(blocks+old_nblocks);
848          for(char const * const * const new_eblocks=blocks+nblocks;
849            eblocks <new_eblocks; eblocks++) 
850          {
851            *eblocks = 0;
852          }
853        }
854      // allocate blocks
855      for (int b=(where>>12); (b<<12)<(where+nsz); b++)
856      {
857        if (! blocks[b])
858          blocks[b] = new char[0x1000];
859      }
860    }
861  // write data to buffer
862  while (nsz > 0)
863    {
864      int n = (where|0xfff) + 1 - where;
865      n = ((nsz < n) ? nsz : n);
866      memcpy( (void*)&blocks[where>>12][where&0xfff], buffer, n);
867      buffer = (void*) ((char*)buffer + n);
868      where += n;
869      nsz -= n;
870    }
871  // adjust size
872  if (where > bsize)
873    bsize = where;
874  return sz;
875}
876
877size_t 
878ByteStream::Memory::readat(void *buffer, size_t sz, int pos)
879{
880  if ((int) sz > bsize - pos)
881    sz = bsize - pos;
882  int nsz = (int)sz;
883  if (nsz <= 0)
884    return 0;
885  // read data from buffer
886  while (nsz > 0)
887    {
888      int n = (pos|0xfff) + 1 - pos;
889      n = ((nsz < n) ? nsz : n);
890      memcpy(buffer, (void*)&blocks[pos>>12][pos&0xfff], n);
891      buffer = (void*) ((char*)buffer + n);
892      pos += n;
893      nsz -= n;
894    }
895  return sz;
896}
897
898size_t 
899ByteStream::Memory::read(void *buffer, size_t sz)
900{
901  sz = readat(buffer,sz,where);
902  where += sz;
903  return sz;
904}
905
906long 
907ByteStream::Memory::tell(void) const
908{
909  return where;
910}
911
912int
913ByteStream::Memory::seek(long offset, int whence, bool nothrow)
914{
915  int nwhere = 0;
916  switch (whence)
917    {
918    case SEEK_SET: nwhere = 0; break;
919    case SEEK_CUR: nwhere = where; break;
920    case SEEK_END: nwhere = bsize; break;
921    default: G_THROW( ERR_MSG("bad_arg") "\tByteStream::Memory::seek()");      // Illegal argument in ByteStream::Memory::seek()
922    }
923  nwhere += offset;
924  if (nwhere<0)
925    G_THROW( ERR_MSG("ByteStream.seek_error2") );                          //  Attempt to seek before the beginning of the file
926  where = nwhere;
927  return 0;
928}
929
930
931
932/** This function has been moved into Arrays.cpp
933    In order to avoid dependencies from ByteStream.o
934    to Arrays.o */
935#ifdef DO_NOT_MOVE_GET_DATA_TO_ARRAYS_CPP
936TArray<char>
937ByteStream::get_data(void)
938{
939   TArray<char> data(0, size()-1);
940   readat((char*)data, size(), 0);
941   return data;
942}
943#endif
944
945
946///////// ByteStream::Static
947
948ByteStream::Static::Static(const void * const buffer, const size_t sz)
949  : data((const char *)buffer), bsize(sz), where(0)
950{
951}
952
953size_t 
954ByteStream::Static::read(void *buffer, size_t sz)
955{
956  int nsz = (int)sz;
957  if (nsz > bsize - where)
958    nsz = bsize - where;
959  if (nsz <= 0)
960    return 0;
961  memcpy(buffer, data+where, nsz);
962  where += nsz;
963  return nsz;
964}
965
966int
967ByteStream::Static::seek(long offset, int whence, bool nothrow)
968{
969  int nwhere = 0;
970  switch (whence)
971    {
972    case SEEK_SET: nwhere = 0; break;
973    case SEEK_CUR: nwhere = where; break;
974    case SEEK_END: nwhere = bsize; break;
975    default: G_THROW("bad_arg\tByteStream::Static::seek()");      //  Illegal argument to ByteStream::Static::seek()
976    }
977  nwhere += offset;
978  if (nwhere<0)
979    G_THROW( ERR_MSG("ByteStream.seek_error2") );                          //  Attempt to seek before the beginning of the file
980  where = nwhere;
981  return 0;
982}
983
984long 
985ByteStream::Static::tell(void) const
986{
987  return where;
988}
989
990GP<ByteStream>
991ByteStream::create(void)
992{
993  return new Memory();
994}
995
996GP<ByteStream>
997ByteStream::create(void const * const buffer, const size_t size)
998{
999  Memory *mbs=new Memory();
1000  GP<ByteStream> retval=mbs;
1001  mbs->init(buffer,size);
1002  return retval;
1003}
1004
1005GP<ByteStream>
1006ByteStream::create(const GURL &url,char const * const xmode)
1007{
1008  GP<ByteStream> retval;
1009  const char *mode = ((xmode) ? xmode : "rb");
1010#ifdef UNIX
1011  if (!strcmp(mode,"rb")) 
1012    {
1013      int fd = urlopen(url,O_RDONLY,0777);
1014      if (fd >= 0)
1015        {
1016#if HAS_MEMMAP && defined(S_IFREG)
1017          struct stat buf;
1018          if ( (fstat(fd, &buf) >= 0) && (buf.st_mode & S_IFREG) )
1019            {
1020              MemoryMapByteStream *rb = new MemoryMapByteStream();
1021              retval = rb;
1022              GUTF8String errmessage = rb->init(fd,true);
1023              if(errmessage.length())
1024                retval=0;
1025            }
1026#endif
1027          if (! retval)
1028            {
1029              FILE *f = fdopen(fd, mode);
1030              if (f) 
1031                {
1032                  Stdio *sbs=new Stdio();
1033                  retval=sbs;
1034                  GUTF8String errmessage=sbs->init(f, mode, true);
1035                  if(errmessage.length())
1036                    retval=0;
1037                }
1038            }
1039          if (! retval)
1040            close(fd);
1041        }     
1042    }
1043#endif
1044  if (! retval)
1045    {
1046      Stdio *sbs=new Stdio();
1047      retval=sbs;
1048      GUTF8String errmessage=sbs->init(url, mode);
1049      if(errmessage.length())
1050        G_THROW(errmessage);
1051    }
1052  return retval;
1053}
1054
1055GP<ByteStream>
1056ByteStream::create(char const * const mode)
1057{
1058  GP<ByteStream> retval;
1059  Stdio *sbs=new Stdio();
1060  retval=sbs;
1061  GUTF8String errmessage=sbs->init(mode?mode:"rb");
1062  if(errmessage.length())
1063  {
1064    G_THROW(errmessage);
1065  }
1066  return retval;
1067}
1068
1069GP<ByteStream>
1070ByteStream::create(const int fd,char const * const mode,const bool closeme)
1071{
1072  GP<ByteStream> retval;
1073  const char *default_mode="rb";
1074#if HAS_MEMMAP
1075  if (   (!mode&&(fd!=0)&&(fd!=1)&&(fd!=2)) 
1076      || (mode&&(GUTF8String("rb") == mode)))
1077  {
1078    MemoryMapByteStream *rb=new MemoryMapByteStream();
1079    retval=rb;
1080    GUTF8String errmessage=rb->init(fd,closeme);
1081    if(errmessage.length())
1082    {
1083      retval=0;
1084    }
1085  }
1086  if(!retval)
1087#endif
1088  {
1089    int fd2 = fd;
1090    FILE *f = 0;
1091    if (fd == 0 && !closeme
1092        && (!mode || mode[0]=='r') )
1093      {
1094        f=stdin;
1095        default_mode = "r";
1096        fd2=(-1);
1097      }
1098    else if (fd == 1 && !closeme
1099             && (!mode || mode[0]=='a' || mode[0]=='w') )
1100      {
1101        default_mode = "a";
1102        f=stdout;
1103        fd2 = -1;
1104      }
1105    else if (fd == 2 && !closeme
1106             && (!mode || mode[0]=='a' || mode[0]=='w') )
1107      {
1108        default_mode = "a";
1109        f=stderr;
1110        fd2 = -1;
1111      }
1112    else
1113      {
1114        if (! closeme)
1115          fd2 = dup(fd);
1116        f = fdopen(fd2,(char*)(mode?mode:default_mode));
1117      }
1118
1119    if(!f)
1120      {
1121        if ( fd2 >= 0)
1122          close(fd2);
1123        G_THROW( ERR_MSG("ByteStream.open_fail2") );
1124      }
1125    Stdio *sbs=new Stdio();
1126    retval=sbs;
1127    GUTF8String errmessage=sbs->init(f,mode?mode:default_mode,(fd2>=0));
1128    if(errmessage.length())
1129      G_THROW(errmessage);
1130  }
1131  return retval;
1132}
1133
1134GP<ByteStream>
1135ByteStream::create(FILE * const f,char const * const mode,const bool closeme)
1136{
1137  GP<ByteStream> retval;
1138#if HAS_MEMMAP
1139  if (!mode || (GUTF8String("rb") == mode))
1140  {
1141    MemoryMapByteStream *rb=new MemoryMapByteStream();
1142    retval=rb;
1143    GUTF8String errmessage=rb->init(fileno(f),false);
1144    if(errmessage.length())
1145    {
1146      retval=0;
1147    }else
1148    {
1149      fclose(f);
1150    }
1151  }
1152  if(!retval)
1153#endif
1154  {
1155    Stdio *sbs=new Stdio();
1156    retval=sbs;
1157    GUTF8String errmessage=sbs->init(f,mode?mode:"rb",closeme);
1158    if(errmessage.length())
1159    {
1160      G_THROW(errmessage);
1161    }
1162  }
1163  return retval;
1164}
1165
1166GP<ByteStream>
1167ByteStream::create_static(const void * buffer, size_t sz)
1168{
1169  return new Static(buffer, sz);
1170}
1171
1172#if HAS_MEMMAP
1173MemoryMapByteStream::MemoryMapByteStream(void)
1174: ByteStream::Static(0,0)
1175{}
1176
1177GUTF8String
1178MemoryMapByteStream::init(FILE *const f,const bool closeme)
1179{
1180  GUTF8String retval;
1181  retval=init(fileno(f),false);
1182  if(closeme)
1183  {
1184    fclose(f);
1185  }
1186  return retval;
1187}
1188
1189GUTF8String
1190MemoryMapByteStream::init(const int fd,const bool closeme)
1191{
1192  GUTF8String retval;
1193  data = (char*)(-1);
1194#if defined(PROT_READ) && defined(MAP_SHARED)
1195  struct stat statbuf;
1196  if(!fstat(fd,&statbuf) && statbuf.st_size)
1197    {
1198      bsize=statbuf.st_size;
1199      data=(char *)mmap(0,statbuf.st_size,PROT_READ,MAP_SHARED,fd,0);
1200    }
1201#endif
1202  if(data == (char *)(-1))
1203    retval = ERR_MSG("ByteStream.open_fail2");
1204  if(closeme)
1205    close(fd);
1206  return retval;
1207}
1208
1209MemoryMapByteStream::~MemoryMapByteStream()
1210{
1211  if(data)
1212  {
1213    munmap(const_cast<char *>(data),bsize);
1214  }
1215}
1216
1217#endif
1218
1219ByteStream::Wrapper::~Wrapper() {}
1220
1221
1222GP<ByteStream> 
1223ByteStream::get_stdin(char const *mode)
1224{
1225  static GP<ByteStream> gp = ByteStream::create(0,mode,false);
1226  return gp;
1227}
1228
1229GP<ByteStream> 
1230ByteStream::get_stdout(char const *mode)
1231{
1232  static GP<ByteStream> gp = ByteStream::create(1,mode,false);
1233  return gp;
1234}
1235
1236GP<ByteStream> 
1237ByteStream::get_stderr(char const *mode)
1238{
1239  static GP<ByteStream> gp = ByteStream::create(2,mode,false);
1240  return gp;
1241}
1242
1243
1244/** Looks up the message and writes it to the specified stream. */
1245void ByteStream::formatmessage( const char *fmt, ... )
1246{
1247  va_list args;
1248  va_start(args, fmt);
1249  const GUTF8String message(fmt,args);
1250  writemessage( message );
1251}
1252
1253/** Looks up the message and writes it to the specified stream. */
1254void ByteStream::writemessage( const char *message )
1255{
1256  writestring( DjVuMessage::LookUpUTF8( message ) );
1257}
1258
1259static void 
1260read_file(ByteStream &bs,char *&buffer,GPBuffer<char> &gbuffer)
1261{
1262  const int size=bs.size();
1263  int pos=0;
1264  if(size>0)
1265  {
1266    size_t readsize=size+1;
1267    gbuffer.resize(readsize);
1268    for(int i;readsize&&(i=bs.read(buffer+pos,readsize))>0;pos+=i,readsize-=i)
1269      EMPTY_LOOP;
1270  }else
1271  {
1272    const size_t readsize=32768;
1273    gbuffer.resize(readsize);
1274    for(int i;((i=bs.read(buffer+pos,readsize))>0);
1275      gbuffer.resize((pos+=i)+readsize))
1276      EMPTY_LOOP;
1277  }
1278  buffer[pos]=0;
1279}
1280
1281GNativeString
1282ByteStream::getAsNative(void)
1283{
1284  char *buffer;
1285  GPBuffer<char> gbuffer(buffer);
1286  read_file(*this,buffer,gbuffer);
1287  return GNativeString(buffer);
1288}
1289
1290GUTF8String
1291ByteStream::getAsUTF8(void)
1292{
1293  char *buffer;
1294  GPBuffer<char> gbuffer(buffer);
1295  read_file(*this,buffer,gbuffer);
1296  return GUTF8String(buffer);
1297}
1298
1299
1300#ifdef HAVE_NAMESPACES
1301}
1302# ifndef NOT_USING_DJVU_NAMESPACE
1303using namespace DJVU;
1304# endif
1305#endif
1306
1307void
1308DjVuPrintErrorUTF8(const char *fmt, ... )
1309{
1310  G_TRY {
1311    GP<ByteStream> errout = ByteStream::get_stderr();
1312    if (errout)
1313      {
1314        errout->cp=ByteStream::NATIVE;
1315        va_list args;
1316        va_start(args, fmt); 
1317        const GUTF8String message(fmt,args);
1318        errout->writestring(message);
1319      }
1320    // Need to catch all exceptions because these might be
1321    // called from an outer exception handler (with prejudice)
1322  } G_CATCH_ALL { } G_ENDCATCH;
1323}
1324
1325void
1326DjVuPrintErrorNative(const char *fmt, ... )
1327{
1328  G_TRY {
1329    GP<ByteStream> errout = ByteStream::get_stderr();
1330    if (errout)
1331      {
1332        errout->cp=ByteStream::NATIVE;
1333        va_list args;
1334        va_start(args, fmt); 
1335        const GNativeString message(fmt,args);
1336        errout->writestring(message);
1337      }
1338    // Need to catch all exceptions because these might be
1339    // called from an outer exception handler (with prejudice)
1340  } G_CATCH_ALL { } G_ENDCATCH;
1341}
1342
1343void
1344DjVuPrintMessageUTF8(const char *fmt, ... )
1345{
1346  G_TRY {
1347    GP<ByteStream> strout = ByteStream::get_stdout();
1348    if (strout)
1349      {
1350        strout->cp=ByteStream::NATIVE;
1351        va_list args;
1352        va_start(args, fmt);
1353        const GUTF8String message(fmt,args);
1354        strout->writestring(message);
1355      }
1356    // Need to catch all exceptions because these might be
1357    // called from an outer exception handler (with prejudice)
1358  } G_CATCH_ALL { } G_ENDCATCH;
1359}
1360
1361void
1362DjVuPrintMessageNative(const char *fmt, ... )
1363{
1364  G_TRY {
1365    GP<ByteStream> strout = ByteStream::get_stdout();
1366    if (strout)
1367      {
1368        strout->cp=ByteStream::NATIVE;
1369        va_list args;
1370        va_start(args, fmt);
1371        const GNativeString message(fmt,args);
1372        strout->writestring(message);
1373      }
1374    // Need to catch all exceptions because these might be
1375    // called from an outer exception handler (with prejudice)
1376  } G_CATCH_ALL { } G_ENDCATCH;
1377}
Note: See TracBrowser for help on using the repository browser.