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
20namespace Poco {
21
22
23InflatingStreamBuf::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
56InflatingStreamBuf::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
82InflatingStreamBuf::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
108InflatingStreamBuf::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
134InflatingStreamBuf::~InflatingStreamBuf()
135{
136 try
137 {
138 close();
139 }
140 catch (...)
141 {
142 }
143 delete [] _buffer;
144 inflateEnd(&_zstr);
145}
146
147
148int InflatingStreamBuf::close()
149{
150 sync();
151 _pIstr = 0;
152 _pOstr = 0;
153 return 0;
154}
155
156
157void 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
167int 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
224int 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
262int InflatingStreamBuf::sync()
263{
264 int n = BufferedStreamBuf::sync();
265 if (!n && _pOstr) _pOstr->flush();
266 return n;
267}
268
269
270InflatingIOS::InflatingIOS(std::ostream& ostr, InflatingStreamBuf::StreamType type):
271 _buf(ostr, type)
272{
273 poco_ios_init(&_buf);
274}
275
276
277InflatingIOS::InflatingIOS(std::ostream& ostr, int windowBits):
278 _buf(ostr, windowBits)
279{
280 poco_ios_init(&_buf);
281}
282
283
284InflatingIOS::InflatingIOS(std::istream& istr, InflatingStreamBuf::StreamType type):
285 _buf(istr, type)
286{
287 poco_ios_init(&_buf);
288}
289
290
291InflatingIOS::InflatingIOS(std::istream& istr, int windowBits):
292 _buf(istr, windowBits)
293{
294 poco_ios_init(&_buf);
295}
296
297
298InflatingIOS::~InflatingIOS()
299{
300}
301
302
303InflatingStreamBuf* InflatingIOS::rdbuf()
304{
305 return &_buf;
306}
307
308
309InflatingOutputStream::InflatingOutputStream(std::ostream& ostr, InflatingStreamBuf::StreamType type):
310 std::ostream(&_buf),
311 InflatingIOS(ostr, type)
312{
313}
314
315
316InflatingOutputStream::InflatingOutputStream(std::ostream& ostr, int windowBits):
317 std::ostream(&_buf),
318 InflatingIOS(ostr, windowBits)
319{
320}
321
322
323InflatingOutputStream::~InflatingOutputStream()
324{
325}
326
327
328int InflatingOutputStream::close()
329{
330 return _buf.close();
331}
332
333
334InflatingInputStream::InflatingInputStream(std::istream& istr, InflatingStreamBuf::StreamType type):
335 std::istream(&_buf),
336 InflatingIOS(istr, type)
337{
338}
339
340
341InflatingInputStream::InflatingInputStream(std::istream& istr, int windowBits):
342 std::istream(&_buf),
343 InflatingIOS(istr, windowBits)
344{
345}
346
347
348InflatingInputStream::~InflatingInputStream()
349{
350}
351
352
353void InflatingInputStream::reset()
354{
355 _buf.reset();
356 clear();
357}
358
359
360} // namespace Poco
361