ckb-next  v0.2.8 at branch master
ckb-next driver for corsair devices
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
quaziodevice.cpp
Go to the documentation of this file.
1 /*
2 Copyright (C) 2005-2014 Sergey A. Tachenov
3 
4 This file is part of QuaZIP.
5 
6 QuaZIP is free software: you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation, either version 2.1 of the License, or
9 (at your option) any later version.
10 
11 QuaZIP is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU Lesser General Public License for more details.
15 
16 You should have received a copy of the GNU Lesser General Public License
17 along with QuaZIP. If not, see <http://www.gnu.org/licenses/>.
18 
19 See COPYING file for the full LGPL text.
20 
21 Original ZIP package is copyrighted by Gilles Vollant and contributors,
22 see 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 
31 class 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  int doFlush(QString &error);
46 };
47 
48 QuaZIODevicePrivate::QuaZIODevicePrivate(QIODevice *io):
49  io(io),
50  inBuf(NULL),
51  inBufPos(0),
52  inBufSize(0),
53  outBuf(NULL),
54  outBufPos(0),
55  outBufSize(0),
56  zBufError(false)
57 {
58  zins.zalloc = (alloc_func) NULL;
59  zins.zfree = (free_func) NULL;
60  zins.opaque = NULL;
61  zouts.zalloc = (alloc_func) NULL;
62  zouts.zfree = (free_func) NULL;
63  zouts.opaque = NULL;
64  inBuf = new char[QUAZIO_INBUFSIZE];
65  outBuf = new char[QUAZIO_OUTBUFSIZE];
66 #ifdef QUAZIP_ZIODEVICE_DEBUG_OUTPUT
67  debug.setFileName("debug.out");
68  debug.open(QIODevice::WriteOnly);
69 #endif
70 #ifdef QUAZIP_ZIODEVICE_DEBUG_INPUT
71  indebug.setFileName("debug.in");
72  indebug.open(QIODevice::WriteOnly);
73 #endif
74 }
75 
76 QuaZIODevicePrivate::~QuaZIODevicePrivate()
77 {
78 #ifdef QUAZIP_ZIODEVICE_DEBUG_OUTPUT
79  debug.close();
80 #endif
81 #ifdef QUAZIP_ZIODEVICE_DEBUG_INPUT
82  indebug.close();
83 #endif
84  if (inBuf != NULL)
85  delete[] inBuf;
86  if (outBuf != NULL)
87  delete[] outBuf;
88 }
89 
90 int QuaZIODevicePrivate::doFlush(QString &error)
91 {
92  int flushed = 0;
93  while (outBufPos < outBufSize) {
94  int more = io->write(outBuf + outBufPos, outBufSize - outBufPos);
95  if (more == -1) {
96  error = io->errorString();
97  return -1;
98  }
99  if (more == 0)
100  break;
101  outBufPos += more;
102  flushed += more;
103  }
104  if (outBufPos == outBufSize) {
105  outBufPos = outBufSize = 0;
106  }
107  return flushed;
108 }
109 
111 
112 // #define QUAZIP_ZIODEVICE_DEBUG_OUTPUT
113 // #define QUAZIP_ZIODEVICE_DEBUG_INPUT
114 #ifdef QUAZIP_ZIODEVICE_DEBUG_OUTPUT
115 #include <QFile>
116 static QFile debug;
117 #endif
118 #ifdef QUAZIP_ZIODEVICE_DEBUG_INPUT
119 #include <QFile>
120 static QFile indebug;
121 #endif
122 
124  QIODevice(parent),
125  d(new QuaZIODevicePrivate(io))
126 {
127  connect(io, SIGNAL(readyRead()), SIGNAL(readyRead()));
128 }
129 
131 {
132  if (isOpen())
133  close();
134  delete d;
135 }
136 
138 {
139  return d->io;
140 }
141 
142 bool QuaZIODevice::open(QIODevice::OpenMode mode)
143 {
144  if ((mode & QIODevice::Append) != 0) {
145  setErrorString(trUtf8("QIODevice::Append is not supported for"
146  " QuaZIODevice"));
147  return false;
148  }
149  if ((mode & QIODevice::ReadWrite) == QIODevice::ReadWrite) {
150  setErrorString(trUtf8("QIODevice::ReadWrite is not supported for"
151  " QuaZIODevice"));
152  return false;
153  }
154  if ((mode & QIODevice::ReadOnly) != 0) {
155  if (inflateInit(&d->zins) != Z_OK) {
156  setErrorString(d->zins.msg);
157  return false;
158  }
159  }
160  if ((mode & QIODevice::WriteOnly) != 0) {
161  if (deflateInit(&d->zouts, Z_DEFAULT_COMPRESSION) != Z_OK) {
162  setErrorString(d->zouts.msg);
163  return false;
164  }
165  }
166  return QIODevice::open(mode);
167 }
168 
170 {
171  if ((openMode() & QIODevice::ReadOnly) != 0) {
172  if (inflateEnd(&d->zins) != Z_OK) {
173  setErrorString(d->zins.msg);
174  }
175  }
176  if ((openMode() & QIODevice::WriteOnly) != 0) {
177  flush();
178  if (deflateEnd(&d->zouts) != Z_OK) {
179  setErrorString(d->zouts.msg);
180  }
181  }
182  QIODevice::close();
183 }
184 
185 qint64 QuaZIODevice::readData(char *data, qint64 maxSize)
186 {
187  int read = 0;
188  while (read < maxSize) {
189  if (d->inBufPos == d->inBufSize) {
190  d->inBufPos = 0;
191  d->inBufSize = d->io->read(d->inBuf, QUAZIO_INBUFSIZE);
192  if (d->inBufSize == -1) {
193  d->inBufSize = 0;
194  setErrorString(d->io->errorString());
195  return -1;
196  }
197  if (d->inBufSize == 0)
198  break;
199  }
200  while (read < maxSize && d->inBufPos < d->inBufSize) {
201  d->zins.next_in = (Bytef *) (d->inBuf + d->inBufPos);
202  d->zins.avail_in = d->inBufSize - d->inBufPos;
203  d->zins.next_out = (Bytef *) (data + read);
204  d->zins.avail_out = (uInt) (maxSize - read); // hope it's less than 2GB
205  int more = 0;
206  switch (inflate(&d->zins, Z_SYNC_FLUSH)) {
207  case Z_OK:
208  read = (char *) d->zins.next_out - data;
209  d->inBufPos = (char *) d->zins.next_in - d->inBuf;
210  break;
211  case Z_STREAM_END:
212  read = (char *) d->zins.next_out - data;
213  d->inBufPos = (char *) d->zins.next_in - d->inBuf;
214  return read;
215  case Z_BUF_ERROR: // this should never happen, but just in case
216  if (!d->zBufError) {
217  qWarning("Z_BUF_ERROR detected with %d/%d in/out, weird",
218  d->zins.avail_in, d->zins.avail_out);
219  d->zBufError = true;
220  }
221  memmove(d->inBuf, d->inBuf + d->inBufPos, d->inBufSize - d->inBufPos);
222  d->inBufSize -= d->inBufPos;
223  d->inBufPos = 0;
224  more = d->io->read(d->inBuf + d->inBufSize, QUAZIO_INBUFSIZE - d->inBufSize);
225  if (more == -1) {
226  setErrorString(d->io->errorString());
227  return -1;
228  }
229  if (more == 0)
230  return read;
231  d->inBufSize += more;
232  break;
233  default:
234  setErrorString(QString::fromLocal8Bit(d->zins.msg));
235  return -1;
236  }
237  }
238  }
239 #ifdef QUAZIP_ZIODEVICE_DEBUG_INPUT
240  indebug.write(data, read);
241 #endif
242  return read;
243 }
244 
245 qint64 QuaZIODevice::writeData(const char *data, qint64 maxSize)
246 {
247  int written = 0;
248  QString error;
249  if (d->doFlush(error) == -1) {
250  setErrorString(error);
251  return -1;
252  }
253  while (written < maxSize) {
254  // there is some data waiting in the output buffer
255  if (d->outBufPos < d->outBufSize)
256  return written;
257  d->zouts.next_in = (Bytef *) (data + written);
258  d->zouts.avail_in = (uInt) (maxSize - written); // hope it's less than 2GB
259  d->zouts.next_out = (Bytef *) d->outBuf;
260  d->zouts.avail_out = QUAZIO_OUTBUFSIZE;
261  switch (deflate(&d->zouts, Z_NO_FLUSH)) {
262  case Z_OK:
263  written = (char *) d->zouts.next_in - data;
264  d->outBufSize = (char *) d->zouts.next_out - d->outBuf;
265  break;
266  default:
267  setErrorString(QString::fromLocal8Bit(d->zouts.msg));
268  return -1;
269  }
270  if (d->doFlush(error) == -1) {
271  setErrorString(error);
272  return -1;
273  }
274  }
275 #ifdef QUAZIP_ZIODEVICE_DEBUG_OUTPUT
276  debug.write(data, written);
277 #endif
278  return written;
279 }
280 
282 {
283  QString error;
284  if (d->doFlush(error) < 0) {
285  setErrorString(error);
286  return false;
287  }
288  // can't flush buffer, some data is still waiting
289  if (d->outBufPos < d->outBufSize)
290  return true;
291  Bytef c = 0;
292  d->zouts.next_in = &c; // fake input buffer
293  d->zouts.avail_in = 0; // of zero size
294  do {
295  d->zouts.next_out = (Bytef *) d->outBuf;
296  d->zouts.avail_out = QUAZIO_OUTBUFSIZE;
297  switch (deflate(&d->zouts, Z_SYNC_FLUSH)) {
298  case Z_OK:
299  d->outBufSize = (char *) d->zouts.next_out - d->outBuf;
300  if (d->doFlush(error) < 0) {
301  setErrorString(error);
302  return false;
303  }
304  if (d->outBufPos < d->outBufSize)
305  return true;
306  break;
307  case Z_BUF_ERROR: // nothing to write?
308  return true;
309  default:
310  setErrorString(QString::fromLocal8Bit(d->zouts.msg));
311  return false;
312  }
313  } while (d->zouts.avail_out == 0);
314  return true;
315 }
316 
318 {
319  return true;
320 }
QuaZIODevice(QIODevice *io, QObject *parent=NULL)
Constructor.
virtual qint64 readData(char *data, qint64 maxSize)
Implementation of QIODevice::readData().
virtual bool flush()
Flushes data waiting to be written.
QIODevice * getIoDevice() const
Returns the underlying device.
virtual void close()
Closes this device, but not the underlying one.
QuaZIODevicePrivate * d
Definition: quaziodevice.h:96
#define QUAZIO_INBUFSIZE
#define QUAZIO_OUTBUFSIZE
~QuaZIODevice()
Destructor.
virtual bool isSequential() const
Returns true.
A class to compress/decompress QIODevice.
Definition: quaziodevice.h:41
virtual bool open(QIODevice::OpenMode mode)
Opens the device.
virtual qint64 writeData(const char *data, qint64 maxSize)
Implementation of QIODevice::writeData().