4 #include "zlibcompressed.h"
11 zlib_error::zlib_error(const 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):
43 mode = below.get_mode()&M_RDWR;
44 if(mode!=M_READ && mode!=M_WRITE)
45 throw invalid_access(mode);
50 ZlibCompressed::ZlibCompressed(Base &b, Mode m, unsigned level):
53 mode = m&below.get_mode()&M_RDWR;
54 if(mode!=M_READ && mode!=M_WRITE)
55 throw invalid_access(m);
60 void ZlibCompressed::init(unsigned level)
71 int ret = deflateInit(&priv->stream, level);
73 throw zlib_error("deflateInit", ret);
77 int ret = inflateInit(&priv->stream);
79 throw zlib_error("inflateInit", ret);
82 in_buffer = new unsigned char[buffer_size];
83 out_buffer = new unsigned char[buffer_size];
85 priv->stream.next_in = in_buffer;
86 priv->stream.avail_in = 0;
87 priv->stream.next_out = out_buffer;
88 priv->stream.avail_out = buffer_size;
90 below.signal_flush_required.connect(sigc::mem_fun(this, &ZlibCompressed::flush));
95 throw zlib_error("unsupported", -1);
99 ZlibCompressed::~ZlibCompressed()
104 while(compress_data(Z_FINISH)) ;
105 deflateEnd(&priv->stream);
108 inflateEnd(&priv->stream);
116 void ZlibCompressed::set_block(bool)
118 throw logic_error("ZlibCompressed::set_block");
121 void ZlibCompressed::set_inherit(bool)
123 throw logic_error("ZlibCompressed::set_inherit");
126 void ZlibCompressed::flush()
133 if(!compress_data(Z_SYNC_FLUSH))
136 // The flush is done when all input data has been consumed
137 if(!priv->stream.avail_in)
144 size_t ZlibCompressed::do_write(const char *data, size_t size)
146 check_access(M_WRITE);
148 size_t processed = 0;
150 while(processed<size)
152 size_t free_in = (in_buffer+buffer_size-priv->stream.next_in);
153 if(free_in<size && priv->stream.next_in>in_buffer)
155 // Not all of the data fits in the buffer, so make some more room
156 copy(priv->stream.next_in, priv->stream.next_in+priv->stream.avail_in, in_buffer);
157 priv->stream.next_in = in_buffer;
158 free_in = buffer_size-priv->stream.avail_in;
163 // Copy as much data into the input buffer as possible
164 size_t len = min(free_in, size-processed);
165 copy(data+processed, data+processed+len, priv->stream.next_in+priv->stream.avail_in);
166 priv->stream.avail_in += len;
170 bool stalled = false;
171 while(priv->stream.avail_in && !stalled)
172 stalled = !compress_data(Z_NO_FLUSH);
184 bool ZlibCompressed::compress_data(int flush_mode)
187 bool can_deflate = ((priv->stream.avail_in || flush_mode) && priv->stream.avail_out);
188 bool finished = false;
191 int ret = deflate(&priv->stream, flush_mode);
192 if(flush_mode==Z_FINISH && ret==Z_STREAM_END)
195 throw zlib_error("deflate", ret);
198 // Write compressed data into the underlying object
200 if(priv->stream.next_out>out_buffer)
201 len = below.write(reinterpret_cast<char *>(out_buffer), priv->stream.next_out-out_buffer);
204 if(len<static_cast<size_t>(priv->stream.next_out-out_buffer))
205 copy(out_buffer+len, priv->stream.next_out, out_buffer);
206 priv->stream.avail_out += len;
207 priv->stream.next_out -= len;
209 else if(!can_deflate)
210 // We weren't able to do anything
220 size_t ZlibCompressed::do_read(char *data, size_t size)
222 check_access(M_READ);
224 size_t processed = 0;
226 while(processed<size)
228 if(priv->stream.next_out>out_buffer)
230 // We have some pending output, give it out first
231 size_t len = min<size_t>(priv->stream.next_out-out_buffer, size-processed);
233 copy(out_buffer, out_buffer+len, data+processed);
236 if(len<static_cast<size_t>(priv->stream.next_out-out_buffer))
237 copy(out_buffer+len, priv->stream.next_out, out_buffer);
238 priv->stream.next_out -= len;
239 priv->stream.avail_out += len;
244 bool need_more_input = !priv->stream.avail_in;
245 if(priv->stream.avail_in)
247 int ret = inflate(&priv->stream, Z_NO_FLUSH);
248 if(ret==Z_STREAM_END)
251 throw zlib_error("inflate", ret);
252 need_more_input = (priv->stream.next_out==out_buffer);
260 if(priv->stream.next_in>in_buffer)
261 copy(priv->stream.next_in, priv->stream.next_in+priv->stream.avail_in, in_buffer);
262 priv->stream.next_in = in_buffer;
264 size_t len = below.read(reinterpret_cast<char *>(priv->stream.next_in), in_buffer+buffer_size-priv->stream.next_in);
265 priv->stream.avail_in += len;
266 if(!len && below.eof())
271 if(size>0 && processed==0 && stream_end)
281 const Handle &ZlibCompressed::get_handle(Mode)
283 throw logic_error("ZlibCompressed::get_handle");