File indexing completed on 2025-02-23 04:26:27

0001 /*
0002 Copyright (C) 2005-2014 Sergey A. Tachenov
0003 
0004 This file is part of QuaZIP.
0005 
0006 QuaZIP is free software: you can redistribute it and/or modify
0007 it under the terms of the GNU Lesser General Public License as published by
0008 the Free Software Foundation, either version 2.1 of the License, or
0009 (at your option) any later version.
0010 
0011 QuaZIP is distributed in the hope that it will be useful,
0012 but WITHOUT ANY WARRANTY; without even the implied warranty of
0013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0014 GNU Lesser General Public License for more details.
0015 
0016 You should have received a copy of the GNU Lesser General Public License
0017 along with QuaZIP.  If not, see <http://www.gnu.org/licenses/>.
0018 
0019 See COPYING file for the full LGPL text.
0020 
0021 Original ZIP package is copyrighted by Gilles Vollant and contributors,
0022 see quazip/(un)zip.h files for details. Basically it's the zlib license.
0023 */
0024 
0025 #include "quaziodevice.h"
0026 
0027 #define QUAZIO_INBUFSIZE 4096
0028 #define QUAZIO_OUTBUFSIZE 4096
0029 
0030 /// \cond internal
0031 class QuaZIODevicePrivate {
0032     friend class QuaZIODevice;
0033     QuaZIODevicePrivate(QIODevice *io);
0034     ~QuaZIODevicePrivate();
0035     QIODevice *io;
0036     z_stream zins;
0037     z_stream zouts;
0038     char *inBuf;
0039     int inBufPos;
0040     int inBufSize;
0041     char *outBuf;
0042     int outBufPos;
0043     int outBufSize;
0044     bool zBufError;
0045     bool atEnd;
0046     int doFlush(QString &error);
0047 };
0048 
0049 QuaZIODevicePrivate::QuaZIODevicePrivate(QIODevice *io):
0050   io(io),
0051   inBuf(NULL),
0052   inBufPos(0),
0053   inBufSize(0),
0054   outBuf(NULL),
0055   outBufPos(0),
0056   outBufSize(0),
0057   zBufError(false),
0058   atEnd(false)
0059 {
0060   zins.zalloc = (alloc_func) NULL;
0061   zins.zfree = (free_func) NULL;
0062   zins.opaque = NULL;
0063   zouts.zalloc = (alloc_func) NULL;
0064   zouts.zfree = (free_func) NULL;
0065   zouts.opaque = NULL;
0066   inBuf = new char[QUAZIO_INBUFSIZE];
0067   outBuf = new char[QUAZIO_OUTBUFSIZE];
0068 #ifdef QUAZIP_ZIODEVICE_DEBUG_OUTPUT
0069   debug.setFileName("debug.out");
0070   debug.open(QIODevice::WriteOnly);
0071 #endif
0072 #ifdef QUAZIP_ZIODEVICE_DEBUG_INPUT
0073   indebug.setFileName("debug.in");
0074   indebug.open(QIODevice::WriteOnly);
0075 #endif
0076 }
0077 
0078 QuaZIODevicePrivate::~QuaZIODevicePrivate()
0079 {
0080 #ifdef QUAZIP_ZIODEVICE_DEBUG_OUTPUT
0081   debug.close();
0082 #endif
0083 #ifdef QUAZIP_ZIODEVICE_DEBUG_INPUT
0084   indebug.close();
0085 #endif
0086   if (inBuf != NULL)
0087     delete[] inBuf;
0088   if (outBuf != NULL)
0089     delete[] outBuf;
0090 }
0091 
0092 int QuaZIODevicePrivate::doFlush(QString &error)
0093 {
0094   int flushed = 0;
0095   while (outBufPos < outBufSize) {
0096     int more = io->write(outBuf + outBufPos, outBufSize - outBufPos);
0097     if (more == -1) {
0098       error = io->errorString();
0099       return -1;
0100     }
0101     if (more == 0)
0102       break;
0103     outBufPos += more;
0104     flushed += more;
0105   }
0106   if (outBufPos == outBufSize) {
0107     outBufPos = outBufSize = 0;
0108   }
0109   return flushed;
0110 }
0111 
0112 /// \endcond
0113 
0114 // #define QUAZIP_ZIODEVICE_DEBUG_OUTPUT
0115 // #define QUAZIP_ZIODEVICE_DEBUG_INPUT
0116 #ifdef QUAZIP_ZIODEVICE_DEBUG_OUTPUT
0117 #include <QFile>
0118 static QFile debug;
0119 #endif
0120 #ifdef QUAZIP_ZIODEVICE_DEBUG_INPUT
0121 #include <QFile>
0122 static QFile indebug;
0123 #endif
0124 
0125 QuaZIODevice::QuaZIODevice(QIODevice *io, QObject *parent):
0126     QIODevice(parent),
0127     d(new QuaZIODevicePrivate(io))
0128 {
0129   connect(io, SIGNAL(readyRead()), SIGNAL(readyRead()));
0130 }
0131 
0132 QuaZIODevice::~QuaZIODevice()
0133 {
0134     if (isOpen())
0135         close();
0136     delete d;
0137 }
0138 
0139 QIODevice *QuaZIODevice::getIoDevice() const
0140 {
0141     return d->io;
0142 }
0143 
0144 bool QuaZIODevice::open(QIODevice::OpenMode mode)
0145 {
0146     if ((mode & QIODevice::Append) != 0) {
0147         setErrorString(trUtf8("QIODevice::Append is not supported for"
0148                     " QuaZIODevice"));
0149         return false;
0150     }
0151     if ((mode & QIODevice::ReadWrite) == QIODevice::ReadWrite) {
0152         setErrorString(trUtf8("QIODevice::ReadWrite is not supported for"
0153                     " QuaZIODevice"));
0154         return false;
0155     }
0156     if ((mode & QIODevice::ReadOnly) != 0) {
0157         if (inflateInit(&d->zins) != Z_OK) {
0158             setErrorString(d->zins.msg);
0159             return false;
0160         }
0161     }
0162     if ((mode & QIODevice::WriteOnly) != 0) {
0163         if (deflateInit(&d->zouts, Z_DEFAULT_COMPRESSION) != Z_OK) {
0164             setErrorString(d->zouts.msg);
0165             return false;
0166         }
0167     }
0168     return QIODevice::open(mode);
0169 }
0170 
0171 void QuaZIODevice::close()
0172 {
0173     if ((openMode() & QIODevice::ReadOnly) != 0) {
0174         if (inflateEnd(&d->zins) != Z_OK) {
0175             setErrorString(d->zins.msg);
0176         }
0177     }
0178     if ((openMode() & QIODevice::WriteOnly) != 0) {
0179         flush();
0180         if (deflateEnd(&d->zouts) != Z_OK) {
0181             setErrorString(d->zouts.msg);
0182         }
0183     }
0184     QIODevice::close();
0185 }
0186 
0187 qint64 QuaZIODevice::readData(char *data, qint64 maxSize)
0188 {
0189   int read = 0;
0190   while (read < maxSize) {
0191     if (d->inBufPos == d->inBufSize) {
0192       d->inBufPos = 0;
0193       d->inBufSize = d->io->read(d->inBuf, QUAZIO_INBUFSIZE);
0194       if (d->inBufSize == -1) {
0195         d->inBufSize = 0;
0196         setErrorString(d->io->errorString());
0197         return -1;
0198       }
0199       if (d->inBufSize == 0)
0200         break;
0201     }
0202     while (read < maxSize && d->inBufPos < d->inBufSize) {
0203       d->zins.next_in = (Bytef *) (d->inBuf + d->inBufPos);
0204       d->zins.avail_in = d->inBufSize - d->inBufPos;
0205       d->zins.next_out = (Bytef *) (data + read);
0206       d->zins.avail_out = (uInt) (maxSize - read); // hope it's less than 2GB
0207       int more = 0;
0208       switch (inflate(&d->zins, Z_SYNC_FLUSH)) {
0209       case Z_OK:
0210         read = (char *) d->zins.next_out - data;
0211         d->inBufPos = (char *) d->zins.next_in - d->inBuf;
0212         break;
0213       case Z_STREAM_END:
0214         read = (char *) d->zins.next_out - data;
0215         d->inBufPos = (char *) d->zins.next_in - d->inBuf;
0216         d->atEnd = true;
0217         return read;
0218       case Z_BUF_ERROR: // this should never happen, but just in case
0219         if (!d->zBufError) {
0220           qWarning("Z_BUF_ERROR detected with %d/%d in/out, weird",
0221               d->zins.avail_in, d->zins.avail_out);
0222           d->zBufError = true;
0223         }
0224         memmove(d->inBuf, d->inBuf + d->inBufPos, d->inBufSize - d->inBufPos);
0225         d->inBufSize -= d->inBufPos;
0226         d->inBufPos = 0;
0227         more = d->io->read(d->inBuf + d->inBufSize, QUAZIO_INBUFSIZE - d->inBufSize);
0228         if (more == -1) {
0229           setErrorString(d->io->errorString());
0230           return -1;
0231         }
0232         if (more == 0)
0233           return read;
0234         d->inBufSize += more;
0235         break;
0236       default:
0237         setErrorString(QString::fromLocal8Bit(d->zins.msg));
0238         return -1;
0239       }
0240     }
0241   }
0242 #ifdef QUAZIP_ZIODEVICE_DEBUG_INPUT
0243   indebug.write(data, read);
0244 #endif
0245   return read;
0246 }
0247 
0248 qint64 QuaZIODevice::writeData(const char *data, qint64 maxSize)
0249 {
0250   int written = 0;
0251   QString error;
0252   if (d->doFlush(error) == -1) {
0253     setErrorString(error);
0254     return -1;
0255   }
0256   while (written < maxSize) {
0257       // there is some data waiting in the output buffer
0258     if (d->outBufPos < d->outBufSize)
0259       return written;
0260     d->zouts.next_in = (Bytef *) (data + written);
0261     d->zouts.avail_in = (uInt) (maxSize - written); // hope it's less than 2GB
0262     d->zouts.next_out = (Bytef *) d->outBuf;
0263     d->zouts.avail_out = QUAZIO_OUTBUFSIZE;
0264     switch (deflate(&d->zouts, Z_NO_FLUSH)) {
0265     case Z_OK:
0266       written = (char *) d->zouts.next_in - data;
0267       d->outBufSize = (char *) d->zouts.next_out - d->outBuf;
0268       break;
0269     default:
0270       setErrorString(QString::fromLocal8Bit(d->zouts.msg));
0271       return -1;
0272     }
0273     if (d->doFlush(error) == -1) {
0274       setErrorString(error);
0275       return -1;
0276     }
0277   }
0278 #ifdef QUAZIP_ZIODEVICE_DEBUG_OUTPUT
0279   debug.write(data, written);
0280 #endif
0281   return written;
0282 }
0283 
0284 bool QuaZIODevice::flush()
0285 {
0286     QString error;
0287     if (d->doFlush(error) < 0) {
0288         setErrorString(error);
0289         return false;
0290     }
0291     // can't flush buffer, some data is still waiting
0292     if (d->outBufPos < d->outBufSize)
0293         return true;
0294     Bytef c = 0;
0295     d->zouts.next_in = &c; // fake input buffer
0296     d->zouts.avail_in = 0; // of zero size
0297     do {
0298         d->zouts.next_out = (Bytef *) d->outBuf;
0299         d->zouts.avail_out = QUAZIO_OUTBUFSIZE;
0300         switch (deflate(&d->zouts, Z_SYNC_FLUSH)) {
0301         case Z_OK:
0302           d->outBufSize = (char *) d->zouts.next_out - d->outBuf;
0303           if (d->doFlush(error) < 0) {
0304               setErrorString(error);
0305               return false;
0306           }
0307           if (d->outBufPos < d->outBufSize)
0308               return true;
0309           break;
0310         case Z_BUF_ERROR: // nothing to write?
0311           return true;
0312         default:
0313           setErrorString(QString::fromLocal8Bit(d->zouts.msg));
0314           return false;
0315         }
0316     } while (d->zouts.avail_out == 0);
0317     return true;
0318 }
0319 
0320 bool QuaZIODevice::isSequential() const
0321 {
0322     return true;
0323 }
0324 
0325 bool QuaZIODevice::atEnd() const
0326 {
0327     // Here we MUST check QIODevice::bytesAvailable() because WE
0328     // might have reached the end, but QIODevice didn't--
0329     // it could have simply pre-buffered all remaining data.
0330     return (openMode() == NotOpen) || (QIODevice::bytesAvailable() == 0 && d->atEnd);
0331 }
0332 
0333 qint64 QuaZIODevice::bytesAvailable() const
0334 {
0335     // If we haven't recevied Z_STREAM_END, it means that
0336     // we have at least one more input byte available.
0337     // Plus whatever QIODevice has buffered.
0338     return (d->atEnd ? 0 : 1) + QIODevice::bytesAvailable();
0339 }