2
Copyright (C) 2005-2011 Sergey A. Tachenov
4
This program is free software; you can redistribute it and/or modify it
5
under the terms of the GNU Lesser General Public License as published by
6
the Free Software Foundation; either version 2 of the License, or (at
7
your option) any later version.
9
This program is distributed in the hope that it will be useful, but
10
WITHOUT ANY WARRANTY; without even the implied warranty of
11
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
12
General Public License for more details.
14
You should have received a copy of the GNU Lesser General Public License
15
along with this program; if not, write to the Free Software Foundation,
16
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
See COPYING file for the full LGPL text.
20
Original ZIP package is copyrighted by Gilles Vollant, see
21
quazip/(un)zip.h files for details, basically it's zlib license.
24
#include "quazipfile.h"
28
class QuaZipFilePrivate {
29
friend class QuaZipFile;
34
QuaZip::CaseSensitivity caseSensitivity;
37
// these two are for writing raw files
38
ulong uncompressedSize;
42
inline void resetZipError() const {setZipError(UNZ_OK);}
43
// const, but sets zipError!
44
void setZipError(int zipError) const;
45
inline QuaZipFilePrivate(QuaZipFile *q):
46
q(q), zip(NULL), internal(true), zipError(UNZ_OK) {}
47
inline QuaZipFilePrivate(QuaZipFile *q, const QString &zipName):
48
q(q), internal(true), zipError(UNZ_OK)
50
zip=new QuaZip(zipName);
52
inline QuaZipFilePrivate(QuaZipFile *q, const QString &zipName, const QString &fileName,
53
QuaZip::CaseSensitivity cs):
54
q(q), internal(true), zipError(UNZ_OK)
56
zip=new QuaZip(zipName);
57
this->fileName=fileName;
58
this->caseSensitivity=cs;
60
inline QuaZipFilePrivate(QuaZipFile *q, QuaZip *zip):
61
q(q), zip(zip), internal(false), zipError(UNZ_OK) {}
62
inline ~QuaZipFilePrivate()
69
QuaZipFile::QuaZipFile():
70
p(new QuaZipFilePrivate(this))
74
QuaZipFile::QuaZipFile(QObject *parent):
76
p(new QuaZipFilePrivate(this))
80
QuaZipFile::QuaZipFile(const QString& zipName, QObject *parent):
82
p(new QuaZipFilePrivate(this, zipName))
86
QuaZipFile::QuaZipFile(const QString& zipName, const QString& fileName,
87
QuaZip::CaseSensitivity cs, QObject *parent):
89
p(new QuaZipFilePrivate(this, zipName, fileName, cs))
93
QuaZipFile::QuaZipFile(QuaZip *zip, QObject *parent):
95
p(new QuaZipFilePrivate(this, zip))
99
QuaZipFile::~QuaZipFile()
106
QString QuaZipFile::getZipName() const
108
return p->zip==NULL ? QString() : p->zip->getZipName();
111
QString QuaZipFile::getActualFileName()const
113
p->setZipError(UNZ_OK);
114
if (p->zip == NULL || (openMode() & WriteOnly))
116
QString name=p->zip->getCurrentFileName();
118
p->setZipError(p->zip->getZipError());
122
void QuaZipFile::setZipName(const QString& zipName)
125
qWarning("QuaZipFile::setZipName(): file is already open - can not set ZIP name");
128
if(p->zip!=NULL && p->internal)
130
p->zip=new QuaZip(zipName);
134
void QuaZipFile::setZip(QuaZip *zip)
137
qWarning("QuaZipFile::setZip(): file is already open - can not set ZIP");
140
if(p->zip!=NULL && p->internal)
143
p->fileName=QString();
147
void QuaZipFile::setFileName(const QString& fileName, QuaZip::CaseSensitivity cs)
150
qWarning("QuaZipFile::setFileName(): call setZipName() first");
154
qWarning("QuaZipFile::setFileName(): should not be used when not using internal QuaZip");
158
qWarning("QuaZipFile::setFileName(): can not set file name for already opened file");
161
p->fileName=fileName;
162
p->caseSensitivity=cs;
165
void QuaZipFilePrivate::setZipError(int zipError) const
167
QuaZipFilePrivate *fakeThis = const_cast<QuaZipFilePrivate*>(this); // non-const
168
fakeThis->zipError=zipError;
170
q->setErrorString(QString());
172
q->setErrorString(q->tr("ZIP/UNZIP API error %1").arg(zipError));
175
bool QuaZipFile::open(OpenMode mode)
177
return open(mode, NULL);
180
bool QuaZipFile::open(OpenMode mode, int *method, int *level, bool raw, const char *password)
184
qWarning("QuaZipFile::open(): already opened");
187
if(mode&Unbuffered) {
188
qWarning("QuaZipFile::open(): Unbuffered mode is not supported");
191
if((mode&ReadOnly)&&!(mode&WriteOnly)) {
193
if(!p->zip->open(QuaZip::mdUnzip)) {
194
p->setZipError(p->zip->getZipError());
197
if(!p->zip->setCurrentFile(p->fileName, p->caseSensitivity)) {
198
p->setZipError(p->zip->getZipError());
204
qWarning("QuaZipFile::open(): zip is NULL");
207
if(p->zip->getMode()!=QuaZip::mdUnzip) {
208
qWarning("QuaZipFile::open(): file open mode %d incompatible with ZIP open mode %d",
209
(int)mode, (int)p->zip->getMode());
212
if(!p->zip->hasCurrentFile()) {
213
qWarning("QuaZipFile::open(): zip does not have current file");
217
p->setZipError(unzOpenCurrentFile3(p->zip->getUnzFile(), method, level, (int)raw, password));
218
if(p->zipError==UNZ_OK) {
225
qWarning("QuaZipFile::open(): open mode %d not supported by this function", (int)mode);
229
bool QuaZipFile::open(OpenMode mode, const QuaZipNewInfo& info,
230
const char *password, quint32 crc,
231
int method, int level, bool raw,
232
int windowBits, int memLevel, int strategy)
237
qWarning("QuaZipFile::open(): already opened");
240
if((mode&WriteOnly)&&!(mode&ReadOnly)) {
242
qWarning("QuaZipFile::open(): write mode is incompatible with internal QuaZip approach");
246
qWarning("QuaZipFile::open(): zip is NULL");
249
if(p->zip->getMode()!=QuaZip::mdCreate&&p->zip->getMode()!=QuaZip::mdAppend&&p->zip->getMode()!=QuaZip::mdAdd) {
250
qWarning("QuaZipFile::open(): file open mode %d incompatible with ZIP open mode %d",
251
(int)mode, (int)p->zip->getMode());
254
info_z.tmz_date.tm_year=info.dateTime.date().year();
255
info_z.tmz_date.tm_mon=info.dateTime.date().month() - 1;
256
info_z.tmz_date.tm_mday=info.dateTime.date().day();
257
info_z.tmz_date.tm_hour=info.dateTime.time().hour();
258
info_z.tmz_date.tm_min=info.dateTime.time().minute();
259
info_z.tmz_date.tm_sec=info.dateTime.time().second();
261
info_z.internal_fa=(uLong)info.internalAttr;
262
info_z.external_fa=(uLong)info.externalAttr;
263
if (!p->zip->isDataDescriptorWritingEnabled())
264
zipClearFlags(p->zip->getZipFile(), ZIP_WRITE_DATA_DESCRIPTOR);
265
p->setZipError(zipOpenNewFileInZip3(p->zip->getZipFile(),
266
p->zip->getFileNameCodec()->fromUnicode(info.name).constData(), &info_z,
267
info.extraLocal.constData(), info.extraLocal.length(),
268
info.extraGlobal.constData(), info.extraGlobal.length(),
269
p->zip->getCommentCodec()->fromUnicode(info.comment).constData(),
270
method, level, (int)raw,
271
windowBits, memLevel, strategy,
272
password, (uLong)crc));
273
if(p->zipError==UNZ_OK) {
279
p->uncompressedSize=info.uncompressedSize;
285
qWarning("QuaZipFile::open(): open mode %d not supported by this function", (int)mode);
289
bool QuaZipFile::isSequential()const
294
qint64 QuaZipFile::pos()const
297
qWarning("QuaZipFile::pos(): call setZipName() or setZip() first");
301
qWarning("QuaZipFile::pos(): file is not open");
304
if(openMode()&ReadOnly)
305
// QIODevice::pos() is broken for sequential devices,
306
// but thankfully bytesAvailable() returns the number of
307
// bytes buffered, so we know how far ahead we are.
308
return unztell(p->zip->getUnzFile()) - QIODevice::bytesAvailable();
313
bool QuaZipFile::atEnd()const
316
qWarning("QuaZipFile::atEnd(): call setZipName() or setZip() first");
320
qWarning("QuaZipFile::atEnd(): file is not open");
323
if(openMode()&ReadOnly)
324
// the same problem as with pos()
325
return QIODevice::bytesAvailable() == 0
326
&& unzeof(p->zip->getUnzFile())==1;
331
qint64 QuaZipFile::size()const
334
qWarning("QuaZipFile::atEnd(): file is not open");
337
if(openMode()&ReadOnly)
338
return p->raw?csize():usize();
343
qint64 QuaZipFile::csize()const
345
unz_file_info info_z;
346
p->setZipError(UNZ_OK);
347
if(p->zip==NULL||p->zip->getMode()!=QuaZip::mdUnzip) return -1;
348
p->setZipError(unzGetCurrentFileInfo(p->zip->getUnzFile(), &info_z, NULL, 0, NULL, 0, NULL, 0));
349
if(p->zipError!=UNZ_OK)
351
return info_z.compressed_size;
354
qint64 QuaZipFile::usize()const
356
unz_file_info info_z;
357
p->setZipError(UNZ_OK);
358
if(p->zip==NULL||p->zip->getMode()!=QuaZip::mdUnzip) return -1;
359
p->setZipError(unzGetCurrentFileInfo(p->zip->getUnzFile(), &info_z, NULL, 0, NULL, 0, NULL, 0));
360
if(p->zipError!=UNZ_OK)
362
return info_z.uncompressed_size;
365
bool QuaZipFile::getFileInfo(QuaZipFileInfo *info)
367
if(p->zip==NULL||p->zip->getMode()!=QuaZip::mdUnzip) return false;
368
p->zip->getCurrentFileInfo(info);
369
p->setZipError(p->zip->getZipError());
370
return p->zipError==UNZ_OK;
373
void QuaZipFile::close()
376
if(p->zip==NULL||!p->zip->isOpen()) return;
378
qWarning("QuaZipFile::close(): file isn't open");
381
if(openMode()&ReadOnly)
382
p->setZipError(unzCloseCurrentFile(p->zip->getUnzFile()));
383
else if(openMode()&WriteOnly)
384
if(isRaw()) p->setZipError(zipCloseFileInZipRaw(p->zip->getZipFile(), p->uncompressedSize, p->crc));
385
else p->setZipError(zipCloseFileInZip(p->zip->getZipFile()));
387
qWarning("Wrong open mode: %d", (int)openMode());
390
if(p->zipError==UNZ_OK) setOpenMode(QIODevice::NotOpen);
394
p->setZipError(p->zip->getZipError());
398
qint64 QuaZipFile::readData(char *data, qint64 maxSize)
400
p->setZipError(UNZ_OK);
401
qint64 bytesRead=unzReadCurrentFile(p->zip->getUnzFile(), data, (unsigned)maxSize);
402
if(bytesRead<0) p->setZipError((int)bytesRead);
406
qint64 QuaZipFile::writeData(const char* data, qint64 maxSize)
408
p->setZipError(ZIP_OK);
409
p->setZipError(zipWriteInFileInZip(p->zip->getZipFile(), data, (uint)maxSize));
410
if(p->zipError!=ZIP_OK) return -1;
412
p->writePos+=maxSize;
417
QString QuaZipFile::getFileName() const
422
QuaZip::CaseSensitivity QuaZipFile::getCaseSensitivity() const
424
return p->caseSensitivity;
427
bool QuaZipFile::isRaw() const
432
int QuaZipFile::getZipError() const
437
qint64 QuaZipFile::bytesAvailable() const
439
return size() - pos();