Panda3D
 All Classes Functions Variables Enumerations
zStreamBuf.cxx
00001 // Filename: zStreamBuf.cxx
00002 // Created by:  drose (05Aug02)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 #include "zStreamBuf.h"
00016 
00017 #ifdef HAVE_ZLIB
00018 
00019 #include "pnotify.h"
00020 #include "config_express.h"
00021 
00022 #if !defined(USE_MEMORY_NOWRAPPERS)
00023 // Define functions that hook zlib into panda's memory allocation system.
00024 static void *
00025 do_zlib_alloc(voidpf opaque, uInt items, uInt size) {
00026   return PANDA_MALLOC_ARRAY(items * size);
00027 }
00028 static void 
00029 do_zlib_free(voidpf opaque, voidpf address) {
00030   PANDA_FREE_ARRAY(address);
00031 }
00032 #endif  //  !USE_MEMORY_NOWRAPPERS
00033 
00034 ////////////////////////////////////////////////////////////////////
00035 //     Function: ZStreamBuf::Constructor
00036 //       Access: Public
00037 //  Description:
00038 ////////////////////////////////////////////////////////////////////
00039 ZStreamBuf::
00040 ZStreamBuf() {
00041   _source = (istream *)NULL;
00042   _owns_source = false;
00043   _dest = (ostream *)NULL;
00044   _owns_dest = false;
00045 
00046 #ifdef PHAVE_IOSTREAM
00047   _buffer = (char *)PANDA_MALLOC_ARRAY(4096);
00048   char *ebuf = _buffer + 4096;
00049   setg(_buffer, ebuf, ebuf);
00050   setp(_buffer, ebuf);
00051 
00052 #else
00053   allocate();
00054   setg(base(), ebuf(), ebuf());
00055   setp(base(), ebuf());
00056 #endif
00057 }
00058 
00059 ////////////////////////////////////////////////////////////////////
00060 //     Function: ZStreamBuf::Destructor
00061 //       Access: Public, Virtual
00062 //  Description:
00063 ////////////////////////////////////////////////////////////////////
00064 ZStreamBuf::
00065 ~ZStreamBuf() {
00066   close_read();
00067   close_write();
00068 #ifdef PHAVE_IOSTREAM
00069   PANDA_FREE_ARRAY(_buffer);
00070 #endif
00071 }
00072 
00073 ////////////////////////////////////////////////////////////////////
00074 //     Function: ZStreamBuf::open_read
00075 //       Access: Public
00076 //  Description:
00077 ////////////////////////////////////////////////////////////////////
00078 void ZStreamBuf::
00079 open_read(istream *source, bool owns_source) {
00080   _source = source;
00081   _owns_source = owns_source;
00082 
00083   _z_source.next_in = Z_NULL;
00084   _z_source.avail_in = 0;
00085   _z_source.next_out = Z_NULL;
00086   _z_source.avail_out = 0;
00087 #ifdef USE_MEMORY_NOWRAPPERS
00088   _z_source.zalloc = Z_NULL;
00089   _z_source.zfree = Z_NULL;
00090 #else
00091   _z_source.zalloc = (alloc_func)&do_zlib_alloc;
00092   _z_source.zfree = (free_func)&do_zlib_free;
00093 #endif
00094   _z_source.opaque = Z_NULL;
00095   _z_source.msg = (char *)"no error message";
00096 
00097   int result = inflateInit(&_z_source);
00098   if (result < 0) {
00099     show_zlib_error("inflateInit", result, _z_source);
00100     close_read();
00101   }
00102   thread_consider_yield();
00103 }
00104 
00105 ////////////////////////////////////////////////////////////////////
00106 //     Function: ZStreamBuf::close_read
00107 //       Access: Public
00108 //  Description:
00109 ////////////////////////////////////////////////////////////////////
00110 void ZStreamBuf::
00111 close_read() {
00112   if (_source != (istream *)NULL) {
00113 
00114     int result = inflateEnd(&_z_source);
00115     if (result < 0) {
00116       show_zlib_error("inflateEnd", result, _z_source);
00117     }
00118     thread_consider_yield();
00119 
00120     if (_owns_source) {
00121       delete _source;
00122       _owns_source = false;
00123     }
00124     _source = (istream *)NULL;
00125   }
00126 }
00127 
00128 ////////////////////////////////////////////////////////////////////
00129 //     Function: ZStreamBuf::open_write
00130 //       Access: Public
00131 //  Description:
00132 ////////////////////////////////////////////////////////////////////
00133 void ZStreamBuf::
00134 open_write(ostream *dest, bool owns_dest, int compression_level) {
00135   _dest = dest;
00136   _owns_dest = owns_dest;
00137 
00138   _z_dest.next_in = Z_NULL;
00139   _z_dest.avail_in = 0;
00140   _z_dest.next_out = Z_NULL;
00141   _z_dest.avail_out = 0;
00142 #ifdef USE_MEMORY_NOWRAPPERS
00143   _z_dest.zalloc = Z_NULL;
00144   _z_dest.zfree = Z_NULL;
00145 #else
00146   _z_dest.zalloc = (alloc_func)&do_zlib_alloc;
00147   _z_dest.zfree = (free_func)&do_zlib_free;
00148 #endif
00149   _z_dest.opaque = Z_NULL;
00150   _z_dest.msg = (char *)"no error message";
00151 
00152   int result = deflateInit(&_z_dest, compression_level);
00153   if (result < 0) {
00154     show_zlib_error("deflateInit", result, _z_dest);
00155     close_write();
00156   }
00157   thread_consider_yield();
00158 }
00159 
00160 ////////////////////////////////////////////////////////////////////
00161 //     Function: ZStreamBuf::close_write
00162 //       Access: Public
00163 //  Description:
00164 ////////////////////////////////////////////////////////////////////
00165 void ZStreamBuf::
00166 close_write() {
00167   if (_dest != (ostream *)NULL) {
00168     size_t n = pptr() - pbase();
00169     write_chars(pbase(), n, Z_FINISH);
00170     pbump(-(int)n);
00171 
00172     int result = deflateEnd(&_z_dest);
00173     if (result < 0) {
00174       show_zlib_error("deflateEnd", result, _z_dest);
00175     }
00176     thread_consider_yield();
00177 
00178     if (_owns_dest) {
00179       delete _dest;
00180       _owns_dest = false;
00181     }
00182     _dest = (ostream *)NULL;
00183   }
00184 }
00185 
00186 ////////////////////////////////////////////////////////////////////
00187 //     Function: ZStreamBuf::overflow
00188 //       Access: Protected, Virtual
00189 //  Description: Called by the system ostream implementation when its
00190 //               internal buffer is filled, plus one character.
00191 ////////////////////////////////////////////////////////////////////
00192 int ZStreamBuf::
00193 overflow(int ch) {
00194   size_t n = pptr() - pbase();
00195   if (n != 0) {
00196     write_chars(pbase(), n, 0);
00197     pbump(-(int)n);
00198   }
00199 
00200   if (ch != EOF) {
00201     // Write one more character.
00202     char c = ch;
00203     write_chars(&c, 1, 0);
00204   }
00205 
00206   return 0;
00207 }
00208 
00209 ////////////////////////////////////////////////////////////////////
00210 //     Function: ZStreamBuf::sync
00211 //       Access: Protected, Virtual
00212 //  Description: Called by the system iostream implementation to
00213 //               implement a flush operation.
00214 ////////////////////////////////////////////////////////////////////
00215 int ZStreamBuf::
00216 sync() {
00217   if (_source != (istream *)NULL) {
00218     size_t n = egptr() - gptr();
00219     gbump(n);
00220   }
00221 
00222   if (_dest != (ostream *)NULL) {
00223     size_t n = pptr() - pbase();
00224     write_chars(pbase(), n, Z_SYNC_FLUSH);
00225     pbump(-(int)n);
00226   }
00227 
00228   _dest->flush();
00229   return 0;
00230 }
00231 
00232 ////////////////////////////////////////////////////////////////////
00233 //     Function: ZStreamBuf::underflow
00234 //       Access: Protected, Virtual
00235 //  Description: Called by the system istream implementation when its
00236 //               internal buffer needs more characters.
00237 ////////////////////////////////////////////////////////////////////
00238 int ZStreamBuf::
00239 underflow() {
00240   // Sometimes underflow() is called even if the buffer is not empty.
00241   if (gptr() >= egptr()) {
00242     size_t buffer_size = egptr() - eback();
00243     gbump(-(int)buffer_size);
00244 
00245     size_t num_bytes = buffer_size;
00246     size_t read_count = read_chars(gptr(), buffer_size);
00247 
00248     if (read_count != num_bytes) {
00249       // Oops, we didn't read what we thought we would.
00250       if (read_count == 0) {
00251         gbump(num_bytes);
00252         return EOF;
00253       }
00254 
00255       // Slide what we did read to the top of the buffer.
00256       nassertr(read_count < num_bytes, EOF);
00257       size_t delta = num_bytes - read_count;
00258       memmove(gptr() + delta, gptr(), read_count);
00259       gbump(delta);
00260     }
00261   }
00262 
00263   return (unsigned char)*gptr();
00264 }
00265 
00266 
00267 ////////////////////////////////////////////////////////////////////
00268 //     Function: ZStreamBuf::read_chars
00269 //       Access: Private
00270 //  Description: Gets some characters from the source stream.
00271 ////////////////////////////////////////////////////////////////////
00272 size_t ZStreamBuf::
00273 read_chars(char *start, size_t length) {
00274   _z_source.next_out = (Bytef *)start;
00275   _z_source.avail_out = length;
00276 
00277   bool eof = (_source->eof() || _source->fail());
00278   int flush = 0;
00279 
00280   while (_z_source.avail_out > 0) {
00281     if (_z_source.avail_in == 0 && !eof) {
00282       _source->read(decompress_buffer, decompress_buffer_size);
00283       size_t read_count = _source->gcount();
00284       eof = (read_count == 0 || _source->eof() || _source->fail());
00285         
00286       _z_source.next_in = (Bytef *)decompress_buffer;
00287       _z_source.avail_in = read_count;
00288     }
00289     int result = inflate(&_z_source, flush);
00290     thread_consider_yield();
00291     size_t bytes_read = length - _z_source.avail_out;
00292 
00293     if (result == Z_STREAM_END) {
00294       // Here's the end of the file.
00295       return bytes_read;
00296 
00297     } else if (result == Z_BUF_ERROR && flush == 0) {
00298       // We might get this if no progress is possible, for instance if
00299       // the input stream is truncated.  In this case, tell zlib to
00300       // dump everything it's got.
00301       flush = Z_FINISH;
00302 
00303     } else if (result < 0) {
00304       show_zlib_error("inflate", result, _z_source);
00305       return bytes_read;
00306     }
00307   }
00308 
00309   return length;
00310 }
00311 
00312 ////////////////////////////////////////////////////////////////////
00313 //     Function: ZStreamBuf::write_chars
00314 //       Access: Private
00315 //  Description: Sends some characters to the dest stream.  The flush
00316 //               parameter is passed to deflate().
00317 ////////////////////////////////////////////////////////////////////
00318 void ZStreamBuf::
00319 write_chars(const char *start, size_t length, int flush) {
00320   static const size_t compress_buffer_size = 4096;
00321   char compress_buffer[compress_buffer_size];
00322 
00323   _z_dest.next_in = (Bytef *)(char *)start;
00324   _z_dest.avail_in = length;
00325 
00326   _z_dest.next_out = (Bytef *)compress_buffer;
00327   _z_dest.avail_out = compress_buffer_size;
00328 
00329   int result = deflate(&_z_dest, flush);
00330   if (result < 0 && result != Z_BUF_ERROR) {
00331     show_zlib_error("deflate", result, _z_dest);
00332   }
00333   thread_consider_yield();
00334 
00335   while (_z_dest.avail_in != 0) {
00336     if (_z_dest.avail_out != compress_buffer_size) {
00337       _dest->write(compress_buffer, compress_buffer_size - _z_dest.avail_out);
00338       _z_dest.next_out = (Bytef *)compress_buffer;
00339       _z_dest.avail_out = compress_buffer_size;
00340     }
00341     result = deflate(&_z_dest, flush);
00342     if (result < 0) {
00343       show_zlib_error("deflate", result, _z_dest);
00344     }
00345     thread_consider_yield();
00346   }
00347 
00348   while (_z_dest.avail_out != compress_buffer_size) {
00349     _dest->write(compress_buffer, compress_buffer_size - _z_dest.avail_out);
00350     _z_dest.next_out = (Bytef *)compress_buffer;
00351     _z_dest.avail_out = compress_buffer_size;
00352     result = deflate(&_z_dest, flush);
00353     if (result < 0 && result != Z_BUF_ERROR) {
00354       show_zlib_error("deflate", result, _z_dest);
00355     }
00356     thread_consider_yield();
00357   }
00358 }
00359 
00360 ////////////////////////////////////////////////////////////////////
00361 //     Function: ZStreamBuf::show_zlib_error
00362 //       Access: Private
00363 //  Description: Reports a recent error code returned by zlib.
00364 ////////////////////////////////////////////////////////////////////
00365 void ZStreamBuf::
00366 show_zlib_error(const char *function, int error_code, z_stream &z) {
00367   stringstream error_line;
00368 
00369   error_line
00370     << "zlib error in " << function << ": ";
00371   switch (error_code) {
00372   case Z_OK:
00373     error_line << "Z_OK";
00374     break;
00375   case Z_STREAM_END:
00376     error_line << "Z_STREAM_END";
00377     break;
00378   case Z_NEED_DICT:
00379     error_line << "Z_NEED_DICT";
00380     break;
00381   case Z_ERRNO:
00382     error_line << "Z_ERRNO";
00383     break;
00384   case Z_STREAM_ERROR:
00385     error_line << "Z_STREAM_ERROR";
00386     break;
00387   case Z_DATA_ERROR:
00388     error_line << "Z_DATA_ERROR";
00389     break;
00390   case Z_MEM_ERROR:
00391     error_line << "Z_MEM_ERROR";
00392     break;
00393   case Z_BUF_ERROR:
00394     error_line << "Z_BUF_ERROR";
00395     break;
00396   case Z_VERSION_ERROR:
00397     error_line << "Z_VERSION_ERROR";
00398     break;
00399   default:
00400     error_line << error_code;
00401   }
00402   if (z.msg != (char *)NULL) {
00403     error_line
00404       << " = " << z.msg;
00405   }
00406 
00407   express_cat.warning() << error_line.str() << "\n";
00408 }
00409 
00410 #endif  // HAVE_ZLIB
 All Classes Functions Variables Enumerations