From cdb5139a1008c653edda1cfff1ee550ba4a4fcea Mon Sep 17 00:00:00 2001 From: David Rose Date: Wed, 7 Aug 2002 19:09:53 +0000 Subject: [PATCH] fix zstream inflate --- panda/src/express/test_zstream.cxx | 102 +++++++++++++++++++++++++++-- panda/src/express/zStreamBuf.cxx | 14 ++-- panda/src/express/zStreamBuf.h | 14 ++++ 3 files changed, 113 insertions(+), 17 deletions(-) diff --git a/panda/src/express/test_zstream.cxx b/panda/src/express/test_zstream.cxx index 69d1f86a13..b5b83b58fb 100644 --- a/panda/src/express/test_zstream.cxx +++ b/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); diff --git a/panda/src/express/zStreamBuf.cxx b/panda/src/express/zStreamBuf.cxx index 444eed4789..c01c2fa931 100644 --- a/panda/src/express/zStreamBuf.cxx +++ b/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) { diff --git a/panda/src/express/zStreamBuf.h b/panda/src/express/zStreamBuf.h index d495dfcc29..7e5810ec52 100644 --- a/panda/src/express/zStreamBuf.h +++ b/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