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 }