source: Vago/quazip-0.7.2/quazip/quaziodevice.cpp@ 1075

Last change on this file since 1075 was 1049, checked in by s10k, 8 years ago
File size: 9.4 KB
Line 
1/*
2Copyright (C) 2005-2014 Sergey A. Tachenov
3
4This file is part of QuaZIP.
5
6QuaZIP is free software: you can redistribute it and/or modify
7it under the terms of the GNU Lesser General Public License as published by
8the Free Software Foundation, either version 2.1 of the License, or
9(at your option) any later version.
10
11QuaZIP is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU Lesser General Public License for more details.
15
16You should have received a copy of the GNU Lesser General Public License
17along with QuaZIP. If not, see <http://www.gnu.org/licenses/>.
18
19See COPYING file for the full LGPL text.
20
21Original ZIP package is copyrighted by Gilles Vollant and contributors,
22see quazip/(un)zip.h files for details. Basically it's the zlib license.
23*/
24
25#include "quaziodevice.h"
26
27#define QUAZIO_INBUFSIZE 4096
28#define QUAZIO_OUTBUFSIZE 4096
29
30/// \cond internal
31class QuaZIODevicePrivate {
32 friend class QuaZIODevice;
33 QuaZIODevicePrivate(QIODevice *io);
34 ~QuaZIODevicePrivate();
35 QIODevice *io;
36 z_stream zins;
37 z_stream zouts;
38 char *inBuf;
39 int inBufPos;
40 int inBufSize;
41 char *outBuf;
42 int outBufPos;
43 int outBufSize;
44 bool zBufError;
45 bool atEnd;
46 int doFlush(QString &error);
47};
48
49QuaZIODevicePrivate::QuaZIODevicePrivate(QIODevice *io):
50 io(io),
51 inBuf(NULL),
52 inBufPos(0),
53 inBufSize(0),
54 outBuf(NULL),
55 outBufPos(0),
56 outBufSize(0),
57 zBufError(false),
58 atEnd(false)
59{
60 zins.zalloc = (alloc_func) NULL;
61 zins.zfree = (free_func) NULL;
62 zins.opaque = NULL;
63 zouts.zalloc = (alloc_func) NULL;
64 zouts.zfree = (free_func) NULL;
65 zouts.opaque = NULL;
66 inBuf = new char[QUAZIO_INBUFSIZE];
67 outBuf = new char[QUAZIO_OUTBUFSIZE];
68#ifdef QUAZIP_ZIODEVICE_DEBUG_OUTPUT
69 debug.setFileName("debug.out");
70 debug.open(QIODevice::WriteOnly);
71#endif
72#ifdef QUAZIP_ZIODEVICE_DEBUG_INPUT
73 indebug.setFileName("debug.in");
74 indebug.open(QIODevice::WriteOnly);
75#endif
76}
77
78QuaZIODevicePrivate::~QuaZIODevicePrivate()
79{
80#ifdef QUAZIP_ZIODEVICE_DEBUG_OUTPUT
81 debug.close();
82#endif
83#ifdef QUAZIP_ZIODEVICE_DEBUG_INPUT
84 indebug.close();
85#endif
86 if (inBuf != NULL)
87 delete[] inBuf;
88 if (outBuf != NULL)
89 delete[] outBuf;
90}
91
92int QuaZIODevicePrivate::doFlush(QString &error)
93{
94 int flushed = 0;
95 while (outBufPos < outBufSize) {
96 int more = io->write(outBuf + outBufPos, outBufSize - outBufPos);
97 if (more == -1) {
98 error = io->errorString();
99 return -1;
100 }
101 if (more == 0)
102 break;
103 outBufPos += more;
104 flushed += more;
105 }
106 if (outBufPos == outBufSize) {
107 outBufPos = outBufSize = 0;
108 }
109 return flushed;
110}
111
112/// \endcond
113
114// #define QUAZIP_ZIODEVICE_DEBUG_OUTPUT
115// #define QUAZIP_ZIODEVICE_DEBUG_INPUT
116#ifdef QUAZIP_ZIODEVICE_DEBUG_OUTPUT
117#include <QFile>
118static QFile debug;
119#endif
120#ifdef QUAZIP_ZIODEVICE_DEBUG_INPUT
121#include <QFile>
122static QFile indebug;
123#endif
124
125QuaZIODevice::QuaZIODevice(QIODevice *io, QObject *parent):
126 QIODevice(parent),
127 d(new QuaZIODevicePrivate(io))
128{
129 connect(io, SIGNAL(readyRead()), SIGNAL(readyRead()));
130}
131
132QuaZIODevice::~QuaZIODevice()
133{
134 if (isOpen())
135 close();
136 delete d;
137}
138
139QIODevice *QuaZIODevice::getIoDevice() const
140{
141 return d->io;
142}
143
144bool QuaZIODevice::open(QIODevice::OpenMode mode)
145{
146 if ((mode & QIODevice::Append) != 0) {
147 setErrorString(trUtf8("QIODevice::Append is not supported for"
148 " QuaZIODevice"));
149 return false;
150 }
151 if ((mode & QIODevice::ReadWrite) == QIODevice::ReadWrite) {
152 setErrorString(trUtf8("QIODevice::ReadWrite is not supported for"
153 " QuaZIODevice"));
154 return false;
155 }
156 if ((mode & QIODevice::ReadOnly) != 0) {
157 if (inflateInit(&d->zins) != Z_OK) {
158 setErrorString(d->zins.msg);
159 return false;
160 }
161 }
162 if ((mode & QIODevice::WriteOnly) != 0) {
163 if (deflateInit(&d->zouts, Z_DEFAULT_COMPRESSION) != Z_OK) {
164 setErrorString(d->zouts.msg);
165 return false;
166 }
167 }
168 return QIODevice::open(mode);
169}
170
171void QuaZIODevice::close()
172{
173 if ((openMode() & QIODevice::ReadOnly) != 0) {
174 if (inflateEnd(&d->zins) != Z_OK) {
175 setErrorString(d->zins.msg);
176 }
177 }
178 if ((openMode() & QIODevice::WriteOnly) != 0) {
179 flush();
180 if (deflateEnd(&d->zouts) != Z_OK) {
181 setErrorString(d->zouts.msg);
182 }
183 }
184 QIODevice::close();
185}
186
187qint64 QuaZIODevice::readData(char *data, qint64 maxSize)
188{
189 int read = 0;
190 while (read < maxSize) {
191 if (d->inBufPos == d->inBufSize) {
192 d->inBufPos = 0;
193 d->inBufSize = d->io->read(d->inBuf, QUAZIO_INBUFSIZE);
194 if (d->inBufSize == -1) {
195 d->inBufSize = 0;
196 setErrorString(d->io->errorString());
197 return -1;
198 }
199 if (d->inBufSize == 0)
200 break;
201 }
202 while (read < maxSize && d->inBufPos < d->inBufSize) {
203 d->zins.next_in = (Bytef *) (d->inBuf + d->inBufPos);
204 d->zins.avail_in = d->inBufSize - d->inBufPos;
205 d->zins.next_out = (Bytef *) (data + read);
206 d->zins.avail_out = (uInt) (maxSize - read); // hope it's less than 2GB
207 int more = 0;
208 switch (inflate(&d->zins, Z_SYNC_FLUSH)) {
209 case Z_OK:
210 read = (char *) d->zins.next_out - data;
211 d->inBufPos = (char *) d->zins.next_in - d->inBuf;
212 break;
213 case Z_STREAM_END:
214 read = (char *) d->zins.next_out - data;
215 d->inBufPos = (char *) d->zins.next_in - d->inBuf;
216 d->atEnd = true;
217 return read;
218 case Z_BUF_ERROR: // this should never happen, but just in case
219 if (!d->zBufError) {
220 qWarning("Z_BUF_ERROR detected with %d/%d in/out, weird",
221 d->zins.avail_in, d->zins.avail_out);
222 d->zBufError = true;
223 }
224 memmove(d->inBuf, d->inBuf + d->inBufPos, d->inBufSize - d->inBufPos);
225 d->inBufSize -= d->inBufPos;
226 d->inBufPos = 0;
227 more = d->io->read(d->inBuf + d->inBufSize, QUAZIO_INBUFSIZE - d->inBufSize);
228 if (more == -1) {
229 setErrorString(d->io->errorString());
230 return -1;
231 }
232 if (more == 0)
233 return read;
234 d->inBufSize += more;
235 break;
236 default:
237 setErrorString(QString::fromLocal8Bit(d->zins.msg));
238 return -1;
239 }
240 }
241 }
242#ifdef QUAZIP_ZIODEVICE_DEBUG_INPUT
243 indebug.write(data, read);
244#endif
245 return read;
246}
247
248qint64 QuaZIODevice::writeData(const char *data, qint64 maxSize)
249{
250 int written = 0;
251 QString error;
252 if (d->doFlush(error) == -1) {
253 setErrorString(error);
254 return -1;
255 }
256 while (written < maxSize) {
257 // there is some data waiting in the output buffer
258 if (d->outBufPos < d->outBufSize)
259 return written;
260 d->zouts.next_in = (Bytef *) (data + written);
261 d->zouts.avail_in = (uInt) (maxSize - written); // hope it's less than 2GB
262 d->zouts.next_out = (Bytef *) d->outBuf;
263 d->zouts.avail_out = QUAZIO_OUTBUFSIZE;
264 switch (deflate(&d->zouts, Z_NO_FLUSH)) {
265 case Z_OK:
266 written = (char *) d->zouts.next_in - data;
267 d->outBufSize = (char *) d->zouts.next_out - d->outBuf;
268 break;
269 default:
270 setErrorString(QString::fromLocal8Bit(d->zouts.msg));
271 return -1;
272 }
273 if (d->doFlush(error) == -1) {
274 setErrorString(error);
275 return -1;
276 }
277 }
278#ifdef QUAZIP_ZIODEVICE_DEBUG_OUTPUT
279 debug.write(data, written);
280#endif
281 return written;
282}
283
284bool QuaZIODevice::flush()
285{
286 QString error;
287 if (d->doFlush(error) < 0) {
288 setErrorString(error);
289 return false;
290 }
291 // can't flush buffer, some data is still waiting
292 if (d->outBufPos < d->outBufSize)
293 return true;
294 Bytef c = 0;
295 d->zouts.next_in = &c; // fake input buffer
296 d->zouts.avail_in = 0; // of zero size
297 do {
298 d->zouts.next_out = (Bytef *) d->outBuf;
299 d->zouts.avail_out = QUAZIO_OUTBUFSIZE;
300 switch (deflate(&d->zouts, Z_SYNC_FLUSH)) {
301 case Z_OK:
302 d->outBufSize = (char *) d->zouts.next_out - d->outBuf;
303 if (d->doFlush(error) < 0) {
304 setErrorString(error);
305 return false;
306 }
307 if (d->outBufPos < d->outBufSize)
308 return true;
309 break;
310 case Z_BUF_ERROR: // nothing to write?
311 return true;
312 default:
313 setErrorString(QString::fromLocal8Bit(d->zouts.msg));
314 return false;
315 }
316 } while (d->zouts.avail_out == 0);
317 return true;
318}
319
320bool QuaZIODevice::isSequential() const
321{
322 return true;
323}
324
325bool QuaZIODevice::atEnd() const
326{
327 // Here we MUST check QIODevice::bytesAvailable() because WE
328 // might have reached the end, but QIODevice didn't--
329 // it could have simply pre-buffered all remaining data.
330 return (openMode() == NotOpen) || (QIODevice::bytesAvailable() == 0 && d->atEnd);
331}
332
333qint64 QuaZIODevice::bytesAvailable() const
334{
335 // If we haven't recevied Z_STREAM_END, it means that
336 // we have at least one more input byte available.
337 // Plus whatever QIODevice has buffered.
338 return (d->atEnd ? 0 : 1) + QIODevice::bytesAvailable();
339}
Note: See TracBrowser for help on using the repository browser.