1 | // |
2 | // DeflatingStream.cpp |
3 | // |
4 | // Library: Foundation |
5 | // Package: Streams |
6 | // Module: ZLibStream |
7 | // |
8 | // Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH. |
9 | // and Contributors. |
10 | // |
11 | // SPDX-License-Identifier: BSL-1.0 |
12 | // |
13 | |
14 | |
15 | #include "Poco/DeflatingStream.h" |
16 | #include "Poco/Exception.h" |
17 | |
18 | |
19 | namespace Poco { |
20 | |
21 | |
22 | DeflatingStreamBuf::DeflatingStreamBuf(std::istream& istr, StreamType type, int level): |
23 | BufferedStreamBuf(STREAM_BUFFER_SIZE, std::ios::in), |
24 | _pIstr(&istr), |
25 | _pOstr(0), |
26 | _eof(false) |
27 | { |
28 | _zstr.next_in = 0; |
29 | _zstr.avail_in = 0; |
30 | _zstr.total_in = 0; |
31 | _zstr.next_out = 0; |
32 | _zstr.avail_out = 0; |
33 | _zstr.total_out = 0; |
34 | _zstr.msg = 0; |
35 | _zstr.state = 0; |
36 | _zstr.zalloc = Z_NULL; |
37 | _zstr.zfree = Z_NULL; |
38 | _zstr.opaque = Z_NULL; |
39 | _zstr.data_type = 0; |
40 | _zstr.adler = 0; |
41 | _zstr.reserved = 0; |
42 | |
43 | _buffer = new char[DEFLATE_BUFFER_SIZE]; |
44 | |
45 | int rc = deflateInit2(&_zstr, level, Z_DEFLATED, 15 + (type == STREAM_GZIP ? 16 : 0), 8, Z_DEFAULT_STRATEGY); |
46 | if (rc != Z_OK) |
47 | { |
48 | delete [] _buffer; |
49 | throw IOException(zError(rc)); |
50 | } |
51 | } |
52 | |
53 | |
54 | DeflatingStreamBuf::DeflatingStreamBuf(std::istream& istr, int windowBits, int level): |
55 | BufferedStreamBuf(STREAM_BUFFER_SIZE, std::ios::in), |
56 | _pIstr(&istr), |
57 | _pOstr(0), |
58 | _eof(false) |
59 | { |
60 | _zstr.zalloc = Z_NULL; |
61 | _zstr.zfree = Z_NULL; |
62 | _zstr.opaque = Z_NULL; |
63 | _zstr.next_in = 0; |
64 | _zstr.avail_in = 0; |
65 | _zstr.next_out = 0; |
66 | _zstr.avail_out = 0; |
67 | |
68 | _buffer = new char[DEFLATE_BUFFER_SIZE]; |
69 | |
70 | int rc = deflateInit2(&_zstr, level, Z_DEFLATED, windowBits, 8, Z_DEFAULT_STRATEGY); |
71 | if (rc != Z_OK) |
72 | { |
73 | delete [] _buffer; |
74 | throw IOException(zError(rc)); |
75 | } |
76 | } |
77 | |
78 | |
79 | DeflatingStreamBuf::DeflatingStreamBuf(std::ostream& ostr, StreamType type, int level): |
80 | BufferedStreamBuf(STREAM_BUFFER_SIZE, std::ios::out), |
81 | _pIstr(0), |
82 | _pOstr(&ostr), |
83 | _eof(false) |
84 | { |
85 | _zstr.zalloc = Z_NULL; |
86 | _zstr.zfree = Z_NULL; |
87 | _zstr.opaque = Z_NULL; |
88 | _zstr.next_in = 0; |
89 | _zstr.avail_in = 0; |
90 | _zstr.next_out = 0; |
91 | _zstr.avail_out = 0; |
92 | |
93 | _buffer = new char[DEFLATE_BUFFER_SIZE]; |
94 | |
95 | int rc = deflateInit2(&_zstr, level, Z_DEFLATED, 15 + (type == STREAM_GZIP ? 16 : 0), 8, Z_DEFAULT_STRATEGY); |
96 | if (rc != Z_OK) |
97 | { |
98 | delete [] _buffer; |
99 | throw IOException(zError(rc)); |
100 | } |
101 | } |
102 | |
103 | |
104 | DeflatingStreamBuf::DeflatingStreamBuf(std::ostream& ostr, int windowBits, int level): |
105 | BufferedStreamBuf(STREAM_BUFFER_SIZE, std::ios::out), |
106 | _pIstr(0), |
107 | _pOstr(&ostr), |
108 | _eof(false) |
109 | { |
110 | _zstr.zalloc = Z_NULL; |
111 | _zstr.zfree = Z_NULL; |
112 | _zstr.opaque = Z_NULL; |
113 | _zstr.next_in = 0; |
114 | _zstr.avail_in = 0; |
115 | _zstr.next_out = 0; |
116 | _zstr.avail_out = 0; |
117 | |
118 | _buffer = new char[DEFLATE_BUFFER_SIZE]; |
119 | |
120 | int rc = deflateInit2(&_zstr, level, Z_DEFLATED, windowBits, 8, Z_DEFAULT_STRATEGY); |
121 | if (rc != Z_OK) |
122 | { |
123 | delete [] _buffer; |
124 | throw IOException(zError(rc)); |
125 | } |
126 | } |
127 | |
128 | |
129 | DeflatingStreamBuf::~DeflatingStreamBuf() |
130 | { |
131 | try |
132 | { |
133 | close(); |
134 | } |
135 | catch (...) |
136 | { |
137 | } |
138 | delete [] _buffer; |
139 | deflateEnd(&_zstr); |
140 | } |
141 | |
142 | |
143 | int DeflatingStreamBuf::close() |
144 | { |
145 | BufferedStreamBuf::sync(); |
146 | _pIstr = 0; |
147 | if (_pOstr) |
148 | { |
149 | if (_zstr.next_out) |
150 | { |
151 | int rc = deflate(&_zstr, Z_FINISH); |
152 | if (rc != Z_OK && rc != Z_STREAM_END) throw IOException(zError(rc)); |
153 | _pOstr->write(_buffer, DEFLATE_BUFFER_SIZE - _zstr.avail_out); |
154 | if (!_pOstr->good()) throw IOException(zError(rc)); |
155 | _zstr.next_out = (unsigned char*) _buffer; |
156 | _zstr.avail_out = DEFLATE_BUFFER_SIZE; |
157 | while (rc != Z_STREAM_END) |
158 | { |
159 | rc = deflate(&_zstr, Z_FINISH); |
160 | if (rc != Z_OK && rc != Z_STREAM_END) throw IOException(zError(rc)); |
161 | _pOstr->write(_buffer, DEFLATE_BUFFER_SIZE - _zstr.avail_out); |
162 | if (!_pOstr->good()) throw IOException(zError(rc)); |
163 | _zstr.next_out = (unsigned char*) _buffer; |
164 | _zstr.avail_out = DEFLATE_BUFFER_SIZE; |
165 | } |
166 | } |
167 | _pOstr->flush(); |
168 | _pOstr = 0; |
169 | } |
170 | return 0; |
171 | } |
172 | |
173 | |
174 | int DeflatingStreamBuf::sync() |
175 | { |
176 | if (BufferedStreamBuf::sync()) |
177 | return -1; |
178 | |
179 | if (_pOstr && _zstr.next_out) |
180 | { |
181 | int rc = deflate(&_zstr, Z_SYNC_FLUSH); |
182 | if (rc != Z_OK) throw IOException(zError(rc)); |
183 | _pOstr->write(_buffer, DEFLATE_BUFFER_SIZE - _zstr.avail_out); |
184 | if (!_pOstr->good()) throw IOException(zError(rc)); |
185 | while (_zstr.avail_out == 0) |
186 | { |
187 | _zstr.next_out = (unsigned char*) _buffer; |
188 | _zstr.avail_out = DEFLATE_BUFFER_SIZE; |
189 | rc = deflate(&_zstr, Z_SYNC_FLUSH); |
190 | if (rc != Z_OK) throw IOException(zError(rc)); |
191 | _pOstr->write(_buffer, DEFLATE_BUFFER_SIZE - _zstr.avail_out); |
192 | if (!_pOstr->good()) throw IOException(zError(rc)); |
193 | }; |
194 | _zstr.next_out = (unsigned char*) _buffer; |
195 | _zstr.avail_out = DEFLATE_BUFFER_SIZE; |
196 | } |
197 | return 0; |
198 | } |
199 | |
200 | |
201 | int DeflatingStreamBuf::readFromDevice(char* buffer, std::streamsize length) |
202 | { |
203 | if (!_pIstr) return 0; |
204 | if (_zstr.avail_in == 0 && !_eof) |
205 | { |
206 | int n = 0; |
207 | if (_pIstr->good()) |
208 | { |
209 | _pIstr->read(_buffer, DEFLATE_BUFFER_SIZE); |
210 | n = static_cast<int>(_pIstr->gcount()); |
211 | } |
212 | if (n > 0) |
213 | { |
214 | _zstr.next_in = (unsigned char*) _buffer; |
215 | _zstr.avail_in = n; |
216 | } |
217 | else |
218 | { |
219 | _zstr.next_in = 0; |
220 | _zstr.avail_in = 0; |
221 | _eof = true; |
222 | } |
223 | } |
224 | _zstr.next_out = (unsigned char*) buffer; |
225 | _zstr.avail_out = static_cast<unsigned>(length); |
226 | for (;;) |
227 | { |
228 | int rc = deflate(&_zstr, _eof ? Z_FINISH : Z_NO_FLUSH); |
229 | if (_eof && rc == Z_STREAM_END) |
230 | { |
231 | _pIstr = 0; |
232 | return static_cast<int>(length) - _zstr.avail_out; |
233 | } |
234 | if (rc != Z_OK) throw IOException(zError(rc)); |
235 | if (_zstr.avail_out == 0) |
236 | { |
237 | return static_cast<int>(length); |
238 | } |
239 | if (_zstr.avail_in == 0) |
240 | { |
241 | int n = 0; |
242 | if (_pIstr->good()) |
243 | { |
244 | _pIstr->read(_buffer, DEFLATE_BUFFER_SIZE); |
245 | n = static_cast<int>(_pIstr->gcount()); |
246 | } |
247 | if (n > 0) |
248 | { |
249 | _zstr.next_in = (unsigned char*) _buffer; |
250 | _zstr.avail_in = n; |
251 | } |
252 | else |
253 | { |
254 | _zstr.next_in = 0; |
255 | _zstr.avail_in = 0; |
256 | _eof = true; |
257 | } |
258 | } |
259 | } |
260 | } |
261 | |
262 | |
263 | int DeflatingStreamBuf::writeToDevice(const char* buffer, std::streamsize length) |
264 | { |
265 | if (length == 0 || !_pOstr) return 0; |
266 | |
267 | _zstr.next_in = (unsigned char*) buffer; |
268 | _zstr.avail_in = static_cast<unsigned>(length); |
269 | _zstr.next_out = (unsigned char*) _buffer; |
270 | _zstr.avail_out = DEFLATE_BUFFER_SIZE; |
271 | for (;;) |
272 | { |
273 | int rc = deflate(&_zstr, Z_NO_FLUSH); |
274 | if (rc != Z_OK) throw IOException(zError(rc)); |
275 | if (_zstr.avail_out == 0) |
276 | { |
277 | _pOstr->write(_buffer, DEFLATE_BUFFER_SIZE); |
278 | if (!_pOstr->good()) throw IOException(zError(rc)); |
279 | _zstr.next_out = (unsigned char*) _buffer; |
280 | _zstr.avail_out = DEFLATE_BUFFER_SIZE; |
281 | } |
282 | if (_zstr.avail_in == 0) |
283 | { |
284 | _pOstr->write(_buffer, DEFLATE_BUFFER_SIZE - _zstr.avail_out); |
285 | if (!_pOstr->good()) throw IOException(zError(rc)); |
286 | _zstr.next_out = (unsigned char*) _buffer; |
287 | _zstr.avail_out = DEFLATE_BUFFER_SIZE; |
288 | break; |
289 | } |
290 | } |
291 | return static_cast<int>(length); |
292 | } |
293 | |
294 | |
295 | DeflatingIOS::DeflatingIOS(std::ostream& ostr, DeflatingStreamBuf::StreamType type, int level): |
296 | _buf(ostr, type, level) |
297 | { |
298 | poco_ios_init(&_buf); |
299 | } |
300 | |
301 | |
302 | DeflatingIOS::DeflatingIOS(std::ostream& ostr, int windowBits, int level): |
303 | _buf(ostr, windowBits, level) |
304 | { |
305 | poco_ios_init(&_buf); |
306 | } |
307 | |
308 | |
309 | DeflatingIOS::DeflatingIOS(std::istream& istr, DeflatingStreamBuf::StreamType type, int level): |
310 | _buf(istr, type, level) |
311 | { |
312 | poco_ios_init(&_buf); |
313 | } |
314 | |
315 | |
316 | DeflatingIOS::DeflatingIOS(std::istream& istr, int windowBits, int level): |
317 | _buf(istr, windowBits, level) |
318 | { |
319 | poco_ios_init(&_buf); |
320 | } |
321 | |
322 | |
323 | DeflatingIOS::~DeflatingIOS() |
324 | { |
325 | } |
326 | |
327 | |
328 | DeflatingStreamBuf* DeflatingIOS::rdbuf() |
329 | { |
330 | return &_buf; |
331 | } |
332 | |
333 | |
334 | DeflatingOutputStream::DeflatingOutputStream(std::ostream& ostr, DeflatingStreamBuf::StreamType type, int level): |
335 | std::ostream(&_buf), |
336 | DeflatingIOS(ostr, type, level) |
337 | { |
338 | } |
339 | |
340 | |
341 | DeflatingOutputStream::DeflatingOutputStream(std::ostream& ostr, int windowBits, int level): |
342 | std::ostream(&_buf), |
343 | DeflatingIOS(ostr, windowBits, level) |
344 | { |
345 | } |
346 | |
347 | |
348 | DeflatingOutputStream::~DeflatingOutputStream() |
349 | { |
350 | } |
351 | |
352 | |
353 | int DeflatingOutputStream::close() |
354 | { |
355 | return _buf.close(); |
356 | } |
357 | |
358 | |
359 | int DeflatingOutputStream::sync() |
360 | { |
361 | return _buf.pubsync(); |
362 | } |
363 | |
364 | |
365 | DeflatingInputStream::DeflatingInputStream(std::istream& istr, DeflatingStreamBuf::StreamType type, int level): |
366 | std::istream(&_buf), |
367 | DeflatingIOS(istr, type, level) |
368 | { |
369 | } |
370 | |
371 | |
372 | DeflatingInputStream::DeflatingInputStream(std::istream& istr, int windowBits, int level): |
373 | std::istream(&_buf), |
374 | DeflatingIOS(istr, windowBits, level) |
375 | { |
376 | } |
377 | |
378 | |
379 | DeflatingInputStream::~DeflatingInputStream() |
380 | { |
381 | } |
382 | |
383 | |
384 | } // namespace Poco |
385 | |