ソースを参照

fix zstream inflate

David Rose 23 年 前
コミット
cdb5139a10

+ 95 - 7
panda/src/express/test_zstream.cxx

@@ -20,8 +20,10 @@
 #include "zStream.h"
 #include "filename.h"
 
+#include "zlib.h"
+
 void
-decompress(istream &source) {
+stream_decompress(istream &source) {
   IDecompressStream zstream(&source, false);
 
   int ch = zstream.get();
@@ -32,7 +34,7 @@ decompress(istream &source) {
 }
 
 void
-compress(istream &source) {
+stream_compress(istream &source) {
   OCompressStream zstream(&cout, false);
 
   int ch = source.get();
@@ -42,12 +44,89 @@ compress(istream &source) {
   }
 }
 
+void
+zlib_decompress(istream &source) {
+  // First, read the entire contents into a buffer.
+  string data;
+
+  int ch = source.get();
+  while (!source.eof() && !source.fail()) {
+    data += (char)ch;
+    ch = source.get();
+  }
+
+  // Now call zlib to decompress the buffer directly.
+  size_t source_len = data.length();
+  // Take a stab on the appropriate size of the output buffer.
+  size_t dest_len = source_len * 4;
+  char *dest = new char[dest_len];
+
+  uLongf actual_dest_len = dest_len;
+  int result = uncompress((Bytef *)dest, &actual_dest_len, 
+                          (const Bytef *)data.data(), source_len);
+  if (result != Z_OK) {
+    cerr << "compress result == " << result << "\n";
+  }
+
+  while (result == Z_BUF_ERROR) {
+    dest_len *= 2;
+    cerr << "Increasing buffer size to " << dest_len << "\n";
+    delete[] dest;
+    dest = new char[dest_len];
+
+    actual_dest_len = dest_len;
+    result = uncompress((Bytef *)dest, &actual_dest_len, 
+                        (const Bytef *)data.data(), source_len);
+    if (result != Z_OK) {
+      cerr << "compress result == " << result << "\n";
+    }
+  }
+
+  cout.write(dest, actual_dest_len);
+}
+
+void
+zlib_compress(istream &source) {
+  // First, read the entire contents into a buffer.
+  string data;
+
+  int ch = source.get();
+  while (!source.eof() && !source.fail()) {
+    data += (char)ch;
+    ch = source.get();
+  }
+
+  // Now call zlib to compress the buffer directly.
+  size_t source_len = data.length();
+  size_t dest_len = (size_t)(source_len * 1.1) + 12;
+  char *dest = new char[dest_len];
+
+  uLongf actual_dest_len = dest_len;
+  int result = compress((Bytef *)dest, &actual_dest_len, 
+                        (const Bytef *)data.data(), source_len);
+
+  if (result != Z_OK) {
+    cerr << "compress result == " << result << "\n";
+  }
+
+  cout.write(dest, actual_dest_len);
+}
+
 int
 main(int argc, char *argv[]) {
+  bool zlib_direct = false;
+
+  if (argc >= 2 && strcmp(argv[1], "-z") == 0) {
+    zlib_direct = true;
+    argc--;
+    argv++;
+  }
+    
   if (argc != 2) {
-    cerr << "test_zstream file\n"
+    cerr << "test_zstream [-z] file\n"
          << "compresses file to standard output, or decompresses it if the\n"
-         << "filename ends in .pz.\n";
+         << "filename ends in .pz.\n\n"
+         << "With -z, calls zlib directly instead of using the zstream interface.\n";
     return (1);
   }
 
@@ -60,10 +139,19 @@ main(int argc, char *argv[]) {
     cerr << "Unable to open source " << source_filename << ".\n";
     return (1);
   }
-  if (source_filename.get_extension() == "pz") {
-    decompress(source);
+
+  if (zlib_direct) {
+    if (source_filename.get_extension() == "pz") {
+      zlib_decompress(source);
+    } else {
+      zlib_compress(source);
+    }
   } else {
-    compress(source);
+    if (source_filename.get_extension() == "pz") {
+      stream_decompress(source);
+    } else {
+      stream_compress(source);
+    }
   }
 
   return (0);

+ 4 - 10
panda/src/express/zStreamBuf.cxx

@@ -243,27 +243,21 @@ underflow() {
 ////////////////////////////////////////////////////////////////////
 size_t ZStreamBuf::
 read_chars(char *start, size_t length) {
-  static const size_t decompress_buffer_size = 4096;
-  char decompress_buffer[decompress_buffer_size];
-
   _z_source.next_out = (Bytef *)start;
   _z_source.avail_out = length;
 
-  int flush = (_source->eof() || _source->fail()) ? Z_FINISH : 0;
+  bool eof = (_source->eof() || _source->fail());
 
   while (_z_source.avail_out > 0) {
-    if (_z_source.avail_in == 0 && flush == 0) {
+    if (_z_source.avail_in == 0 && !eof) {
       _source->read(decompress_buffer, decompress_buffer_size);
       size_t read_count = _source->gcount();
-      if (read_count == 0 || _source->eof() || _source->fail()) {
-        // End of input; tell zlib to expect to stop.
-        flush = Z_FINISH;
-      }
+      eof = (read_count == 0 || _source->eof() || _source->fail());
         
       _z_source.next_in = (Bytef *)decompress_buffer;
       _z_source.avail_in = read_count;
     }
-    int result = inflate(&_z_source, flush);
+    int result = inflate(&_z_source, 0);
     size_t bytes_read = length - _z_source.avail_out;
 
     if (result == Z_STREAM_END) {

+ 14 - 0
panda/src/express/zStreamBuf.h

@@ -61,6 +61,20 @@ private:
 
   z_stream _z_source;
   z_stream _z_dest;
+
+  // We need to store the decompression buffer on the class object,
+  // because zlib might not consume all of the input characters at
+  // each call to inflate().  This isn't a problem on output because
+  // in that case we can afford to wait until it does consume all of
+  // the characters we give it.
+  enum {
+    // It's not clear how large or small this buffer ought to be.  It
+    // doesn't seem to matter much, especially since this is just a
+    // temporary holding area before getting copied into zlib's own
+    // internal buffers.
+    decompress_buffer_size = 128
+  };
+  char decompress_buffer[decompress_buffer_size];
 };
 
 #endif  // HAVE_ZLIB