4 #include "zlibcompressed.h"
11 zlib_error::zlib_error(const std::string &w, int c):
13 runtime_error(w+": "+zError(c)),
21 struct ZlibCompressed::Private
30 ZlibCompressed::Private::Private()
40 ZlibCompressed::ZlibCompressed(Base &b, unsigned level):
49 mode = below.get_mode()&M_RDWR;
50 if(mode!=M_READ && mode!=M_WRITE)
51 throw invalid_access(mode);
57 int ret = deflateInit(&priv->stream, level);
59 throw zlib_error("deflateInit", ret);
63 int ret = inflateInit(&priv->stream);
65 throw zlib_error("inflateInit", ret);
68 in_buffer = new unsigned char[buffer_size];
69 out_buffer = new unsigned char[buffer_size];
71 priv->stream.next_in = in_buffer;
72 priv->stream.avail_in = 0;
73 priv->stream.next_out = out_buffer;
74 priv->stream.avail_out = buffer_size;
76 below.signal_flush_required.connect(sigc::mem_fun(this, &ZlibCompressed::flush));
79 throw zlib_error("unsupported", -1);
83 ZlibCompressed::~ZlibCompressed()
88 while(compress_data(Z_FINISH)) ;
89 deflateEnd(&priv->stream);
92 inflateEnd(&priv->stream);
100 void ZlibCompressed::flush()
107 if(!compress_data(Z_SYNC_FLUSH))
110 // The flush is done when all input data has been consumed
111 if(!priv->stream.avail_in)
118 unsigned ZlibCompressed::do_write(const char *data, unsigned size)
120 check_access(M_WRITE);
122 unsigned processed = 0;
124 while(processed<size)
126 unsigned free_in = (in_buffer+buffer_size-priv->stream.next_in);
127 if(free_in<size && priv->stream.next_in>in_buffer)
129 // Not all of the data fits in the buffer, so make some more room
130 copy(priv->stream.next_in, priv->stream.next_in+priv->stream.avail_in, in_buffer);
131 priv->stream.next_in = in_buffer;
132 free_in = buffer_size-priv->stream.avail_in;
137 // Copy as much data into the input buffer as possible
138 unsigned len = min(free_in, size-processed);
139 copy(data+processed, data+processed+len, priv->stream.next_in+priv->stream.avail_in);
140 priv->stream.avail_in += len;
144 bool stalled = false;
145 while(priv->stream.avail_in && !stalled)
146 stalled = !compress_data(Z_NO_FLUSH);
158 bool ZlibCompressed::compress_data(int flush_mode)
161 bool can_deflate = ((priv->stream.avail_in || flush_mode) && priv->stream.avail_out);
162 bool finished = false;
165 int ret = deflate(&priv->stream, flush_mode);
166 if(flush_mode==Z_FINISH && ret==Z_STREAM_END)
169 throw zlib_error("deflate", ret);
172 // Write compressed data into the underlying object
174 if(priv->stream.next_out>out_buffer)
175 len = below.write(reinterpret_cast<char *>(out_buffer), priv->stream.next_out-out_buffer);
178 if(len<static_cast<unsigned>(priv->stream.next_out-out_buffer))
179 copy(out_buffer+len, priv->stream.next_out, out_buffer);
180 priv->stream.avail_out += len;
181 priv->stream.next_out -= len;
183 else if(!can_deflate)
184 // We weren't able to do anything
194 unsigned ZlibCompressed::do_read(char *data, unsigned size)
196 check_access(M_READ);
198 unsigned processed = 0;
200 while(processed<size)
202 if(priv->stream.next_out>out_buffer)
204 // We have some pending output, give it out first
205 unsigned len = min<unsigned>(priv->stream.next_out-out_buffer, size-processed);
207 copy(out_buffer, out_buffer+len, data+processed);
210 if(len<static_cast<unsigned>(priv->stream.next_out-out_buffer))
211 copy(out_buffer+len, priv->stream.next_out, out_buffer);
212 priv->stream.next_out -= len;
213 priv->stream.avail_out += len;
218 bool need_more_input = !priv->stream.avail_in;
219 if(priv->stream.avail_in)
221 int ret = inflate(&priv->stream, Z_NO_FLUSH);
222 if(ret==Z_STREAM_END)
225 throw zlib_error("inflate", ret);
226 need_more_input = (priv->stream.next_out==out_buffer);
234 if(priv->stream.next_in>in_buffer)
235 copy(priv->stream.next_in, priv->stream.next_in+priv->stream.avail_in, in_buffer);
236 priv->stream.next_in = in_buffer;
238 unsigned len = below.read(reinterpret_cast<char *>(priv->stream.next_in), in_buffer+buffer_size-priv->stream.next_in);
239 priv->stream.avail_in += len;
240 if(!len && below.eof())
245 if(size>0 && processed==0 && stream_end)