WvStreams
wvgzip.cc
1/*
2 * Worldvisions Weaver Software:
3 * Copyright (C) 1997-2002 Net Integration Technologies, Inc.
4 *
5 * Gzip encoder/decoder based on zlib.
6 */
7#include "wvgzip.h"
8#include <zlib.h>
9#include <assert.h>
10
11#define ZBUFSIZE 10240
12
13
14WvGzipEncoder::WvGzipEncoder(Mode _mode, size_t _out_limit) :
15 out_limit(_out_limit), tmpbuf(ZBUFSIZE), mode(_mode)
16{
18 full_flush = false;
19 init();
20}
21
22
23WvGzipEncoder::~WvGzipEncoder()
24{
25 close();
26}
27
28
29void WvGzipEncoder::init()
30{
31 zstr = new z_stream;
32 memset(zstr, 0, sizeof(*zstr));
33 zstr->zalloc = Z_NULL;
34 zstr->zfree = Z_NULL;
35 zstr->opaque = NULL;
36 zstr->msg = NULL;
37
38 int retval;
39 if (mode == Deflate)
40 retval = deflateInit(zstr, Z_BEST_SPEED);
41 else
42 retval = inflateInit(zstr);
43
44 if (retval != Z_OK)
45 {
46 seterror("error %s initializing gzip %s: %s", retval,
47 mode == Deflate ? "compressor" : "decompressor",
48 zstr->msg ? zstr->msg : "unknown");
49 return;
50 }
51 zstr->next_in = zstr->next_out = NULL;
52 zstr->avail_in = zstr->avail_out = 0;
53}
54
55void WvGzipEncoder::close()
56{
57 if (mode == Deflate)
58 deflateEnd(zstr);
59 else
60 inflateEnd(zstr);
61
62 delete zstr;
63
64}
65
66bool WvGzipEncoder::_encode(WvBuf &inbuf, WvBuf &outbuf, bool flush)
67{
68 bool success;
69 output = 0;
70 for (;;)
71 {
72 size_t starting_size = inbuf.used();
73 prepare(& inbuf);
74 bool alldata = inbuf.used() == 0;
75 success = process(outbuf, flush && alldata, false);
76 if (zstr->avail_in != 0)
77 {
78 // unget unused data
79 inbuf.unget(zstr->avail_in);
80 zstr->avail_in = 0;
81 }
82 if (! success)
83 return false;
84 if (alldata || (starting_size == inbuf.used()) ||
85 (out_limit && (output >= out_limit)))
86 return true;
87 }
88}
89
90
92{
93 prepare(NULL);
94 return process(outbuf, false, true);
95}
96
97
99{
100 close();
101 init();
102 return true;
103}
104
105
106void WvGzipEncoder::prepare(WvBuf *inbuf)
107{
108 assert(zstr->avail_in == 0);
109 if (inbuf && inbuf->used() != 0)
110 {
111 size_t avail = inbuf->optgettable();
112 zstr->avail_in = avail;
113 zstr->next_in = const_cast<Bytef*>(
114 (const Bytef*)inbuf->get(avail));
115 }
116 else
117 {
118 zstr->avail_in = 0;
119 zstr->next_in = (Bytef*)""; // so it's not NULL
120 }
121}
122
123
124bool WvGzipEncoder::process(WvBuf &outbuf, bool flush, bool finish)
125{
126 int flushmode = finish ? Z_FINISH :
127 flush ? (full_flush ? Z_FULL_FLUSH : Z_SYNC_FLUSH) : Z_NO_FLUSH;
128 int retval;
129 do
130 {
131 // process the next chunk
132 tmpbuf.zap();
133 size_t avail_out = tmpbuf.free();
134 if (out_limit)
135 avail_out = tmpbuf.free() < (out_limit - output) ? tmpbuf.free()
136 : (out_limit - output);
137
138 zstr->avail_out = avail_out;
139 zstr->next_out = tmpbuf.alloc(avail_out);
140 if (mode == Deflate)
141 retval = deflate(zstr, flushmode);
142 else
143 retval = inflate(zstr, flushmode);
144 tmpbuf.unalloc(zstr->avail_out);
145
146 output += avail_out - zstr->avail_out;
147
148 // consume pending output
149 outbuf.merge(tmpbuf);
150
151 if (retval == Z_DATA_ERROR && mode == Inflate
153 retval = inflateSync(zstr);
154 } while (retval == Z_OK && (!out_limit || (out_limit > output)));
155
156 if (retval == Z_STREAM_END)
157 setfinished();
158 else if (retval != Z_OK && retval != Z_BUF_ERROR &&
159 !(retval == Z_DATA_ERROR && mode == Inflate
161 {
162 seterror("error %s during gzip %s: %s", retval,
163 mode == Deflate ? "compression" : "decompression",
164 zstr->msg ? zstr->msg : "unknown");
165 return false;
166 }
167
168 return true;
169}
170
void merge(Buffer &inbuf, size_t count)
Efficiently moves count bytes from the specified buffer into this one.
Definition: wvbufbase.h:558
size_t optgettable() const
Returns the optimal maximum number of elements in the buffer currently available for reading without ...
Definition: wvbufbase.h:154
const T * get(size_t count)
Reads exactly the specified number of elements and returns a pointer to a storage location owned by t...
Definition: wvbufbase.h:114
void unget(size_t count)
Ungets exactly the specified number of elements by returning them to the buffer for subsequent reads.
Definition: wvbufbase.h:177
void unalloc(size_t count)
Unallocates exactly the specified number of elements by removing them from the buffer and releasing t...
Definition: wvbufbase.h:421
size_t free() const
Returns the number of elements that the buffer can currently accept for writing.
Definition: wvbufbase.h:353
T * alloc(size_t count)
Allocates exactly the specified number of elements and returns a pointer to an UNINITIALIZED storage ...
Definition: wvbufbase.h:379
void zap()
Clears the buffer.
Definition: wvbufbase.h:257
size_t used() const
Returns the number of elements in the buffer currently available for reading.
Definition: wvbufbase.h:92
Specialization of WvBufBase for unsigned char type buffers intended for use with raw memory buffers.
Definition: wvbuf.h:24
bool finish(WvBuf &outbuf)
Tells the encoder that NO MORE DATA will ever be encoded.
Definition: wvencoder.cc:49
void seterror(WvStringParm message)
Sets an error condition, then setnotok().
Definition: wvencoder.h:375
bool flush(WvBuf &inbuf, WvBuf &outbuf, bool finish=false)
Flushes the encoder and optionally finishes it.
Definition: wvencoder.h:163
void setfinished()
Sets 'finished' to true explicitly.
Definition: wvencoder.h:383
size_t out_limit
Limit the amount of output produced in one call to encode().
Definition: wvgzip.h:55
WvGzipEncoder(Mode mode, size_t _out_limit=0)
Creates a Gzip encoder.
Definition: wvgzip.cc:14
bool ignore_decompression_errors
Continue decompression if errors are found.
Definition: wvgzip.h:66
virtual bool _reset()
Template method implementation of reset().
Definition: wvgzip.cc:98
bool full_flush
Do full flushes.
Definition: wvgzip.h:75
virtual bool _finish(WvBuf &outbuf)
Template method implementation of finish().
Definition: wvgzip.cc:91
virtual bool _encode(WvBuf &inbuf, WvBuf &outbuf, bool flush)
Template method implementation of encode().
Definition: wvgzip.cc:66