00001
00002
00003
00004
00005
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_DEFAULT_COMPRESSION);
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
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*)"";
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
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
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