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) |
180 | { |
181 | if (_zstr.next_out) |
182 | { |
183 | int rc = deflate(&_zstr, Z_SYNC_FLUSH); |
184 | if (rc != Z_OK) throw IOException(zError(rc)); |
185 | _pOstr->write(_buffer, DEFLATE_BUFFER_SIZE - _zstr.avail_out); |
186 | if (!_pOstr->good()) throw IOException(zError(rc)); |
187 | while (_zstr.avail_out == 0) |
188 | { |
189 | _zstr.next_out = (unsigned char*) _buffer; |
190 | _zstr.avail_out = DEFLATE_BUFFER_SIZE; |
191 | rc = deflate(&_zstr, Z_SYNC_FLUSH); |
192 | if (rc != Z_OK) throw IOException(zError(rc)); |
193 | _pOstr->write(_buffer, DEFLATE_BUFFER_SIZE - _zstr.avail_out); |
194 | if (!_pOstr->good()) throw IOException(zError(rc)); |
195 | }; |
196 | _zstr.next_out = (unsigned char*) _buffer; |
197 | _zstr.avail_out = DEFLATE_BUFFER_SIZE; |
198 | } |
199 | // NOTE: This breaks the Zip library and causes corruption in some files. |
200 | // See GH #1828 |
201 | // _pOstr->flush(); |
202 | } |
203 | return 0; |
204 | } |
205 | |
206 | |
207 | int DeflatingStreamBuf::readFromDevice(char* buffer, std::streamsize length) |
208 | { |
209 | if (!_pIstr) return 0; |
210 | if (_zstr.avail_in == 0 && !_eof) |
211 | { |
212 | int n = 0; |
213 | if (_pIstr->good()) |
214 | { |
215 | _pIstr->read(_buffer, DEFLATE_BUFFER_SIZE); |
216 | n = static_cast<int>(_pIstr->gcount()); |
217 | } |
218 | if (n > 0) |
219 | { |
220 | _zstr.next_in = (unsigned char*) _buffer; |
221 | _zstr.avail_in = n; |
222 | } |
223 | else |
224 | { |
225 | _zstr.next_in = 0; |
226 | _zstr.avail_in = 0; |
227 | _eof = true; |
228 | } |
229 | } |
230 | _zstr.next_out = (unsigned char*) buffer; |
231 | _zstr.avail_out = static_cast<unsigned>(length); |
232 | for (;;) |
233 | { |
234 | int rc = deflate(&_zstr, _eof ? Z_FINISH : Z_NO_FLUSH); |
235 | if (_eof && rc == Z_STREAM_END) |
236 | { |
237 | _pIstr = 0; |
238 | return static_cast<int>(length) - _zstr.avail_out; |
239 | } |
240 | if (rc != Z_OK) throw IOException(zError(rc)); |
241 | if (_zstr.avail_out == 0) |
242 | { |
243 | return static_cast<int>(length); |
244 | } |
245 | if (_zstr.avail_in == 0) |
246 | { |
247 | int n = 0; |
248 | if (_pIstr->good()) |
249 | { |
250 | _pIstr->read(_buffer, DEFLATE_BUFFER_SIZE); |
251 | n = static_cast<int>(_pIstr->gcount()); |
252 | } |
253 | if (n > 0) |
254 | { |
255 | _zstr.next_in = (unsigned char*) _buffer; |
256 | _zstr.avail_in = n; |
257 | } |
258 | else |
259 | { |
260 | _zstr.next_in = 0; |
261 | _zstr.avail_in = 0; |
262 | _eof = true; |
263 | } |
264 | } |
265 | } |
266 | } |
267 | |
268 | |
269 | int DeflatingStreamBuf::writeToDevice(const char* buffer, std::streamsize length) |
270 | { |
271 | if (length == 0 || !_pOstr) return 0; |
272 | |
273 | _zstr.next_in = (unsigned char*) buffer; |
274 | _zstr.avail_in = static_cast<unsigned>(length); |
275 | _zstr.next_out = (unsigned char*) _buffer; |
276 | _zstr.avail_out = DEFLATE_BUFFER_SIZE; |
277 | for (;;) |
278 | { |
279 | int rc = deflate(&_zstr, Z_NO_FLUSH); |
280 | if (rc != Z_OK) throw IOException(zError(rc)); |
281 | if (_zstr.avail_out == 0) |
282 | { |
283 | _pOstr->write(_buffer, DEFLATE_BUFFER_SIZE); |
284 | if (!_pOstr->good()) throw IOException(zError(rc)); |
285 | _zstr.next_out = (unsigned char*) _buffer; |
286 | _zstr.avail_out = DEFLATE_BUFFER_SIZE; |
287 | } |
288 | if (_zstr.avail_in == 0) |
289 | { |
290 | _pOstr->write(_buffer, DEFLATE_BUFFER_SIZE - _zstr.avail_out); |
291 | if (!_pOstr->good()) throw IOException(zError(rc)); |
292 | _zstr.next_out = (unsigned char*) _buffer; |
293 | _zstr.avail_out = DEFLATE_BUFFER_SIZE; |
294 | break; |
295 | } |
296 | } |
297 | return static_cast<int>(length); |
298 | } |
299 | |
300 | |
301 | DeflatingIOS::DeflatingIOS(std::ostream& ostr, DeflatingStreamBuf::StreamType type, int level): |
302 | _buf(ostr, type, level) |
303 | { |
304 | poco_ios_init(&_buf); |
305 | } |
306 | |
307 | |
308 | DeflatingIOS::DeflatingIOS(std::ostream& ostr, int windowBits, int level): |
309 | _buf(ostr, windowBits, level) |
310 | { |
311 | poco_ios_init(&_buf); |
312 | } |
313 | |
314 | |
315 | DeflatingIOS::DeflatingIOS(std::istream& istr, DeflatingStreamBuf::StreamType type, int level): |
316 | _buf(istr, type, level) |
317 | { |
318 | poco_ios_init(&_buf); |
319 | } |
320 | |
321 | |
322 | DeflatingIOS::DeflatingIOS(std::istream& istr, int windowBits, int level): |
323 | _buf(istr, windowBits, level) |
324 | { |
325 | poco_ios_init(&_buf); |
326 | } |
327 | |
328 | |
329 | DeflatingIOS::~DeflatingIOS() |
330 | { |
331 | } |
332 | |
333 | |
334 | DeflatingStreamBuf* DeflatingIOS::rdbuf() |
335 | { |
336 | return &_buf; |
337 | } |
338 | |
339 | |
340 | DeflatingOutputStream::DeflatingOutputStream(std::ostream& ostr, DeflatingStreamBuf::StreamType type, int level): |
341 | std::ostream(&_buf), |
342 | DeflatingIOS(ostr, type, level) |
343 | { |
344 | } |
345 | |
346 | |
347 | DeflatingOutputStream::DeflatingOutputStream(std::ostream& ostr, int windowBits, int level): |
348 | std::ostream(&_buf), |
349 | DeflatingIOS(ostr, windowBits, level) |
350 | { |
351 | } |
352 | |
353 | |
354 | DeflatingOutputStream::~DeflatingOutputStream() |
355 | { |
356 | } |
357 | |
358 | |
359 | int DeflatingOutputStream::close() |
360 | { |
361 | return _buf.close(); |
362 | } |
363 | |
364 | |
365 | int DeflatingOutputStream::sync() |
366 | { |
367 | return _buf.pubsync(); |
368 | } |
369 | |
370 | |
371 | DeflatingInputStream::DeflatingInputStream(std::istream& istr, DeflatingStreamBuf::StreamType type, int level): |
372 | std::istream(&_buf), |
373 | DeflatingIOS(istr, type, level) |
374 | { |
375 | } |
376 | |
377 | |
378 | DeflatingInputStream::DeflatingInputStream(std::istream& istr, int windowBits, int level): |
379 | std::istream(&_buf), |
380 | DeflatingIOS(istr, windowBits, level) |
381 | { |
382 | } |
383 | |
384 | |
385 | DeflatingInputStream::~DeflatingInputStream() |
386 | { |
387 | } |
388 | |
389 | |
390 | } // namespace Poco |
391 | |