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