WvStreams
|
00001 /* 00002 * Worldvisions Weaver Software: 00003 * Copyright (C) 1997-2002 Net Integration Technologies, Inc. 00004 * 00005 * Gzip encoder/decoder based on zlib. 00006 */ 00007 #include "wvgzip.h" 00008 #include <zlib.h> 00009 #include <assert.h> 00010 00011 #define ZBUFSIZE 10240 00012 00013 00014 WvGzipEncoder::WvGzipEncoder(Mode _mode, size_t _out_limit) : 00015 out_limit(_out_limit), tmpbuf(ZBUFSIZE), mode(_mode) 00016 { 00017 ignore_decompression_errors = false; 00018 full_flush = false; 00019 init(); 00020 } 00021 00022 00023 WvGzipEncoder::~WvGzipEncoder() 00024 { 00025 close(); 00026 } 00027 00028 00029 void WvGzipEncoder::init() 00030 { 00031 zstr = new z_stream; 00032 memset(zstr, 0, sizeof(*zstr)); 00033 zstr->zalloc = Z_NULL; 00034 zstr->zfree = Z_NULL; 00035 zstr->opaque = NULL; 00036 zstr->msg = NULL; 00037 00038 int retval; 00039 if (mode == Deflate) 00040 retval = deflateInit(zstr, Z_BEST_SPEED); 00041 else 00042 retval = inflateInit(zstr); 00043 00044 if (retval != Z_OK) 00045 { 00046 seterror("error %s initializing gzip %s: %s", retval, 00047 mode == Deflate ? "compressor" : "decompressor", 00048 zstr->msg ? zstr->msg : "unknown"); 00049 return; 00050 } 00051 zstr->next_in = zstr->next_out = NULL; 00052 zstr->avail_in = zstr->avail_out = 0; 00053 } 00054 00055 void WvGzipEncoder::close() 00056 { 00057 if (mode == Deflate) 00058 deflateEnd(zstr); 00059 else 00060 inflateEnd(zstr); 00061 00062 delete zstr; 00063 00064 } 00065 00066 bool WvGzipEncoder::_encode(WvBuf &inbuf, WvBuf &outbuf, bool flush) 00067 { 00068 bool success; 00069 output = 0; 00070 for (;;) 00071 { 00072 size_t starting_size = inbuf.used(); 00073 prepare(& inbuf); 00074 bool alldata = inbuf.used() == 0; 00075 success = process(outbuf, flush && alldata, false); 00076 if (zstr->avail_in != 0) 00077 { 00078 // unget unused data 00079 inbuf.unget(zstr->avail_in); 00080 zstr->avail_in = 0; 00081 } 00082 if (! success) 00083 return false; 00084 if (alldata || (starting_size == inbuf.used()) || 00085 (out_limit && (output >= out_limit))) 00086 return true; 00087 } 00088 } 00089 00090 00091 bool WvGzipEncoder::_finish(WvBuf &outbuf) 00092 { 00093 prepare(NULL); 00094 return process(outbuf, false, true); 00095 } 00096 00097 00098 bool WvGzipEncoder::_reset() 00099 { 00100 close(); 00101 init(); 00102 return true; 00103 } 00104 00105 00106 void WvGzipEncoder::prepare(WvBuf *inbuf) 00107 { 00108 assert(zstr->avail_in == 0); 00109 if (inbuf && inbuf->used() != 0) 00110 { 00111 size_t avail = inbuf->optgettable(); 00112 zstr->avail_in = avail; 00113 zstr->next_in = const_cast<Bytef*>( 00114 (const Bytef*)inbuf->get(avail)); 00115 } 00116 else 00117 { 00118 zstr->avail_in = 0; 00119 zstr->next_in = (Bytef*)""; // so it's not NULL 00120 } 00121 } 00122 00123 00124 bool WvGzipEncoder::process(WvBuf &outbuf, bool flush, bool finish) 00125 { 00126 int flushmode = finish ? Z_FINISH : 00127 flush ? (full_flush ? Z_FULL_FLUSH : Z_SYNC_FLUSH) : Z_NO_FLUSH; 00128 int retval; 00129 do 00130 { 00131 // process the next chunk 00132 tmpbuf.zap(); 00133 size_t avail_out = tmpbuf.free(); 00134 if (out_limit) 00135 avail_out = tmpbuf.free() < (out_limit - output) ? tmpbuf.free() 00136 : (out_limit - output); 00137 00138 zstr->avail_out = avail_out; 00139 zstr->next_out = tmpbuf.alloc(avail_out); 00140 if (mode == Deflate) 00141 retval = deflate(zstr, flushmode); 00142 else 00143 retval = inflate(zstr, flushmode); 00144 tmpbuf.unalloc(zstr->avail_out); 00145 00146 output += avail_out - zstr->avail_out; 00147 00148 // consume pending output 00149 outbuf.merge(tmpbuf); 00150 00151 if (retval == Z_DATA_ERROR && mode == Inflate 00152 && ignore_decompression_errors) 00153 retval = inflateSync(zstr); 00154 } while (retval == Z_OK && (!out_limit || (out_limit > output))); 00155 00156 if (retval == Z_STREAM_END) 00157 setfinished(); 00158 else if (retval != Z_OK && retval != Z_BUF_ERROR && 00159 !(retval == Z_DATA_ERROR && mode == Inflate 00160 && ignore_decompression_errors)) 00161 { 00162 seterror("error %s during gzip %s: %s", retval, 00163 mode == Deflate ? "compression" : "decompression", 00164 zstr->msg ? zstr->msg : "unknown"); 00165 return false; 00166 } 00167 00168 return true; 00169 } 00170