]> git.tdb.fi Git - libs/core.git/blob - source/io/zlibcompressed.cpp
Remove unnecessary std:: qualifiers
[libs/core.git] / source / io / zlibcompressed.cpp
1 #ifdef WITH_ZLIB
2 #include <zlib.h>
3 #endif
4 #include "zlibcompressed.h"
5
6 using namespace std;
7
8 namespace Msp {
9 namespace IO {
10
11 zlib_error::zlib_error(const string &w, int c):
12 #ifdef WITH_ZLIB
13         runtime_error(w+": "+zError(c)),
14 #else
15         runtime_error(w),
16 #endif
17         code_(c)
18 { }
19
20
21 struct ZlibCompressed::Private
22 {
23 #ifdef WITH_ZLIB
24         z_stream stream;
25 #endif
26
27         Private();
28 };
29
30 ZlibCompressed::Private::Private()
31 {
32 #ifdef WITH_ZLIB
33         stream.zalloc = 0;
34         stream.zfree = 0;
35         stream.opaque = 0;
36 #endif
37 }
38
39
40 ZlibCompressed::ZlibCompressed(Base &b, unsigned level):
41         below(b)
42 {
43         mode = below.get_mode()&M_RDWR;
44         if(mode!=M_READ && mode!=M_WRITE)
45                 throw invalid_access(mode);
46
47         init(level);
48 }
49
50 ZlibCompressed::ZlibCompressed(Base &b, Mode m, unsigned level):
51         below(b)
52 {
53         mode = m&below.get_mode()&M_RDWR;
54         if(mode!=M_READ && mode!=M_WRITE)
55                 throw invalid_access(m);
56
57         init(level);
58 }
59
60 void ZlibCompressed::init(unsigned level)
61 {
62 #ifdef WITH_ZLIB
63         buffer_size = 1024;
64         in_buffer = 0;
65         out_buffer = 0;
66         stream_end = false;
67         priv = new Private;
68
69         if(mode==M_WRITE)
70         {
71                 int ret = deflateInit(&priv->stream, level);
72                 if(ret!=Z_OK)
73                         throw zlib_error("deflateInit", ret);
74         }
75         else
76         {
77                 int ret = inflateInit(&priv->stream);
78                 if(ret!=Z_OK)
79                         throw zlib_error("inflateInit", ret);
80         }
81
82         in_buffer = new unsigned char[buffer_size];
83         out_buffer = new unsigned char[buffer_size];
84
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;
89
90         below.signal_flush_required.connect(sigc::mem_fun(this, &ZlibCompressed::flush));
91 #else
92         (void)buffer_size;
93         (void)stream_end;
94         (void)level;
95         throw zlib_error("unsupported", -1);
96 #endif
97 }
98
99 ZlibCompressed::~ZlibCompressed()
100 {
101 #ifdef WITH_ZLIB
102         if(mode==M_WRITE)
103         {
104                 while(compress_data(Z_FINISH)) ;
105                 deflateEnd(&priv->stream);
106         }
107         else
108                 inflateEnd(&priv->stream);
109 #endif
110
111         delete[] in_buffer;
112         delete[] out_buffer;
113         delete priv;
114 }
115
116 void ZlibCompressed::set_block(bool)
117 {
118         throw logic_error("ZlibCompressed::set_block");
119 }
120
121 void ZlibCompressed::set_inherit(bool)
122 {
123         throw logic_error("ZlibCompressed::set_inherit");
124 }
125
126 void ZlibCompressed::flush()
127 {
128 #ifdef WITH_ZLIB
129         if(mode==M_WRITE)
130         {
131                 while(1)
132                 {
133                         if(!compress_data(Z_SYNC_FLUSH))
134                                 break;
135
136                         // The flush is done when all input data has been consumed
137                         if(!priv->stream.avail_in)
138                                 break;
139                 }
140         }
141 #endif
142 }
143
144 size_t ZlibCompressed::do_write(const char *data, size_t size)
145 {
146         check_access(M_WRITE);
147
148         size_t processed = 0;
149 #ifdef WITH_ZLIB
150         while(processed<size)
151         {
152                 size_t free_in = (in_buffer+buffer_size-priv->stream.next_in);
153                 if(free_in<size && priv->stream.next_in>in_buffer)
154                 {
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;
159                 }
160
161                 if(free_in)
162                 {
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;
167                         processed += len;
168                 }
169
170                 bool stalled = false;
171                 while(priv->stream.avail_in && !stalled)
172                         stalled = !compress_data(Z_NO_FLUSH);
173                 if(stalled)
174                         break;
175         }
176 #else
177         (void)data;
178         (void)size;
179 #endif
180
181         return processed;
182 }
183
184 bool ZlibCompressed::compress_data(int flush_mode)
185 {
186 #ifdef WITH_ZLIB
187         bool can_deflate = ((priv->stream.avail_in || flush_mode) && priv->stream.avail_out);
188         bool finished = false;
189         if(can_deflate)
190         {
191                 int ret = deflate(&priv->stream, flush_mode);
192                 if(flush_mode==Z_FINISH && ret==Z_STREAM_END)
193                         finished = true;
194                 else if(ret!=Z_OK)
195                         throw zlib_error("deflate", ret);
196         }
197
198         // Write compressed data into the underlying object
199         size_t len = 0;
200         if(priv->stream.next_out>out_buffer)
201                 len = below.write(reinterpret_cast<char *>(out_buffer), priv->stream.next_out-out_buffer);
202         if(len>0)
203         {
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;
208         }
209         else if(!can_deflate)
210                 // We weren't able to do anything
211                 return false;
212
213         return !finished;
214 #else
215         (void)flush_mode;
216         return false;
217 #endif
218 }
219
220 size_t ZlibCompressed::do_read(char *data, size_t size)
221 {
222         check_access(M_READ);
223
224         size_t processed = 0;
225 #ifdef WITH_ZLIB
226         while(processed<size)
227         {
228                 if(priv->stream.next_out>out_buffer)
229                 {
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);
232
233                         copy(out_buffer, out_buffer+len, data+processed);
234                         processed += len;
235
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;
240
241                         continue;
242                 }
243
244                 bool need_more_input = !priv->stream.avail_in;
245                 if(priv->stream.avail_in)
246                 {
247                         int ret = inflate(&priv->stream, Z_NO_FLUSH);
248                         if(ret==Z_STREAM_END)
249                                 stream_end = true;
250                         else if(ret!=Z_OK)
251                                 throw zlib_error("inflate", ret);
252                         need_more_input = (priv->stream.next_out==out_buffer);
253                 }
254
255                 if(need_more_input)
256                 {
257                         if(stream_end)
258                                 break;
259
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;
263
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())
267                                 stream_end = true;
268                 }
269         }
270
271         if(size>0 && processed==0 && stream_end)
272                 set_eof();
273 #else
274         (void)data;
275         (void)size;
276 #endif
277
278         return processed;
279 }
280
281 const Handle &ZlibCompressed::get_handle(Mode)
282 {
283         throw logic_error("ZlibCompressed::get_handle");
284 }
285
286 } // namespace IO
287 } // namespace Msp