source: trunk/libdjvu/ByteStream.cpp @ 15

Last change on this file since 15 was 15, checked in by Eugene Romanenko, 15 years ago

needed libs update

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