4 #include <msp/core/except.h>
5 #include "zlibcompressed.h"
12 zlib_error::zlib_error(const string &w, int c):
14 runtime_error(w+": "+zError(c)),
22 struct ZlibCompressed::Private
31 ZlibCompressed::Private::Private()
34 stream.zalloc = nullptr;
35 stream.zfree = nullptr;
36 stream.opaque = nullptr;
41 ZlibCompressed::ZlibCompressed(Base &b, Mode m, unsigned level):
44 mode = m&below.get_mode()&M_RDWR;
45 if(mode!=M_READ && mode!=M_WRITE)
46 throw invalid_access(m);
53 int ret = deflateInit(&priv->stream, level);
55 throw zlib_error("deflateInit", ret);
59 int ret = inflateInit(&priv->stream);
61 throw zlib_error("inflateInit", ret);
64 in_buffer = new unsigned char[buffer_size];
65 out_buffer = new unsigned char[buffer_size];
67 priv->stream.next_in = in_buffer;
68 priv->stream.avail_in = 0;
69 priv->stream.next_out = out_buffer;
70 priv->stream.avail_out = buffer_size;
72 below.signal_flush_required.connect(sigc::mem_fun(this, &ZlibCompressed::flush));
77 throw unsupported("ZlibCompressed");
81 ZlibCompressed::~ZlibCompressed()
86 while(compress_data(Z_FINISH)) ;
87 deflateEnd(&priv->stream);
90 inflateEnd(&priv->stream);
98 void ZlibCompressed::set_block(bool)
100 throw unsupported("ZlibCompressed::set_block");
103 void ZlibCompressed::set_inherit(bool)
105 throw unsupported("ZlibCompressed::set_inherit");
108 void ZlibCompressed::flush()
115 if(!compress_data(Z_SYNC_FLUSH))
118 // The flush is done when all input data has been consumed
119 if(!priv->stream.avail_in)
126 size_t ZlibCompressed::do_write(const char *data, size_t size)
128 check_access(M_WRITE);
130 size_t processed = 0;
132 while(processed<size)
134 size_t free_in = (in_buffer+buffer_size-priv->stream.next_in);
135 if(free_in<size && priv->stream.next_in>in_buffer)
137 // Not all of the data fits in the buffer, so make some more room
138 copy(priv->stream.next_in, priv->stream.next_in+priv->stream.avail_in, in_buffer);
139 priv->stream.next_in = in_buffer;
140 free_in = buffer_size-priv->stream.avail_in;
145 // Copy as much data into the input buffer as possible
146 size_t len = min(free_in, size-processed);
147 copy(data+processed, data+processed+len, priv->stream.next_in+priv->stream.avail_in);
148 priv->stream.avail_in += len;
152 bool stalled = false;
153 while(priv->stream.avail_in && !stalled)
154 stalled = !compress_data(Z_NO_FLUSH);
166 bool ZlibCompressed::compress_data(int flush_mode)
169 bool can_deflate = ((priv->stream.avail_in || flush_mode) && priv->stream.avail_out);
170 bool finished = false;
173 int ret = deflate(&priv->stream, flush_mode);
174 if(flush_mode==Z_FINISH && ret==Z_STREAM_END)
177 throw zlib_error("deflate", ret);
180 // Write compressed data into the underlying object
182 if(priv->stream.next_out>out_buffer)
183 len = below.write(reinterpret_cast<char *>(out_buffer), priv->stream.next_out-out_buffer);
186 if(len<static_cast<size_t>(priv->stream.next_out-out_buffer))
187 copy(out_buffer+len, priv->stream.next_out, out_buffer);
188 priv->stream.avail_out += len;
189 priv->stream.next_out -= len;
191 else if(!can_deflate)
192 // We weren't able to do anything
202 size_t ZlibCompressed::do_read(char *data, size_t size)
204 check_access(M_READ);
206 size_t processed = 0;
208 while(processed<size)
210 if(priv->stream.next_out>out_buffer)
212 // We have some pending output, give it out first
213 size_t len = min<size_t>(priv->stream.next_out-out_buffer, size-processed);
215 copy(out_buffer, out_buffer+len, data+processed);
218 if(len<static_cast<size_t>(priv->stream.next_out-out_buffer))
219 copy(out_buffer+len, priv->stream.next_out, out_buffer);
220 priv->stream.next_out -= len;
221 priv->stream.avail_out += len;
226 bool need_more_input = !priv->stream.avail_in;
227 if(priv->stream.avail_in)
229 int ret = inflate(&priv->stream, Z_NO_FLUSH);
230 if(ret==Z_STREAM_END)
233 throw zlib_error("inflate", ret);
234 need_more_input = (priv->stream.next_out==out_buffer);
242 if(priv->stream.next_in>in_buffer)
243 copy(priv->stream.next_in, priv->stream.next_in+priv->stream.avail_in, in_buffer);
244 priv->stream.next_in = in_buffer;
246 size_t len = below.read(reinterpret_cast<char *>(priv->stream.next_in), in_buffer+buffer_size-priv->stream.next_in);
247 priv->stream.avail_in += len;
248 if(!len && below.eof())
253 if(size>0 && processed==0 && stream_end)
263 const Handle &ZlibCompressed::get_handle(Mode)
265 throw unsupported("ZlibCompressed::get_handle");