| 1 | /*
|
|---|
| 2 | -- A kind of "standard" GPL license statement --
|
|---|
| 3 | QuaZIP - a Qt/C++ wrapper for the ZIP/UNZIP package
|
|---|
| 4 | Copyright (C) 2005-2007 Sergey A. Tachenov
|
|---|
| 5 |
|
|---|
| 6 | This program is free software; you can redistribute it and/or modify it
|
|---|
| 7 | under the terms of the GNU General Public License as published by the
|
|---|
| 8 | Free Software Foundation; either version 2 of the License, or (at your
|
|---|
| 9 | option) any later version.
|
|---|
| 10 |
|
|---|
| 11 | This program is distributed in the hope that it will be useful, but
|
|---|
| 12 | WITHOUT ANY WARRANTY; without even the implied warranty of
|
|---|
| 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
|---|
| 14 | Public License for more details.
|
|---|
| 15 |
|
|---|
| 16 | You should have received a copy of the GNU General Public License along
|
|---|
| 17 | with this program; if not, write to the Free Software Foundation, Inc.,
|
|---|
| 18 | 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|---|
| 19 |
|
|---|
| 20 | -- A kind of "standard" GPL license statement ends here --
|
|---|
| 21 |
|
|---|
| 22 | See COPYING file for GPL.
|
|---|
| 23 |
|
|---|
| 24 | You are also permitted to use QuaZIP under the terms of LGPL (see
|
|---|
| 25 | COPYING.LGPL). You are free to choose either license, but please note
|
|---|
| 26 | that QuaZIP makes use of Qt, which is not licensed under LGPL. So if
|
|---|
| 27 | you are using Open Source edition of Qt, you therefore MUST use GPL for
|
|---|
| 28 | your code based on QuaZIP, since it would be also based on Qt in this
|
|---|
| 29 | case. If you are Qt commercial license owner, then you are free to use
|
|---|
| 30 | QuaZIP as long as you respect either GPL or LGPL for QuaZIP code.
|
|---|
| 31 | **/
|
|---|
| 32 |
|
|---|
| 33 | #include "quazipfile.h"
|
|---|
| 34 |
|
|---|
| 35 | using namespace std;
|
|---|
| 36 |
|
|---|
| 37 | QuaZipFile::QuaZipFile():
|
|---|
| 38 | zip(NULL), internal(true), zipError(UNZ_OK)
|
|---|
| 39 | {
|
|---|
| 40 | }
|
|---|
| 41 |
|
|---|
| 42 | QuaZipFile::QuaZipFile(QObject *parent):
|
|---|
| 43 | QIODevice(parent), zip(NULL), internal(true), zipError(UNZ_OK)
|
|---|
| 44 | {
|
|---|
| 45 | }
|
|---|
| 46 |
|
|---|
| 47 | QuaZipFile::QuaZipFile(const QString& zipName, QObject *parent):
|
|---|
| 48 | QIODevice(parent), internal(true), zipError(UNZ_OK)
|
|---|
| 49 | {
|
|---|
| 50 | zip=new QuaZip(zipName);
|
|---|
| 51 | Q_CHECK_PTR(zip);
|
|---|
| 52 | }
|
|---|
| 53 |
|
|---|
| 54 | QuaZipFile::QuaZipFile(const QString& zipName, const QString& fileName,
|
|---|
| 55 | QuaZip::CaseSensitivity cs, QObject *parent):
|
|---|
| 56 | QIODevice(parent), internal(true), zipError(UNZ_OK)
|
|---|
| 57 | {
|
|---|
| 58 | zip=new QuaZip(zipName);
|
|---|
| 59 | Q_CHECK_PTR(zip);
|
|---|
| 60 | this->fileName=fileName;
|
|---|
| 61 | this->caseSensitivity=cs;
|
|---|
| 62 | }
|
|---|
| 63 |
|
|---|
| 64 | QuaZipFile::QuaZipFile(QuaZip *zip, QObject *parent):
|
|---|
| 65 | QIODevice(parent),
|
|---|
| 66 | zip(zip), internal(false),
|
|---|
| 67 | zipError(UNZ_OK)
|
|---|
| 68 | {
|
|---|
| 69 | }
|
|---|
| 70 |
|
|---|
| 71 | QuaZipFile::~QuaZipFile()
|
|---|
| 72 | {
|
|---|
| 73 | if(isOpen()) close();
|
|---|
| 74 | if(internal) delete zip;
|
|---|
| 75 | }
|
|---|
| 76 |
|
|---|
| 77 | QString QuaZipFile::getZipName()const
|
|---|
| 78 | {
|
|---|
| 79 | return zip==NULL?QString():zip->getZipName();
|
|---|
| 80 | }
|
|---|
| 81 |
|
|---|
| 82 | QString QuaZipFile::getActualFileName()const
|
|---|
| 83 | {
|
|---|
| 84 | setZipError(UNZ_OK);
|
|---|
| 85 | if(zip==NULL||(openMode()&WriteOnly)) return QString();
|
|---|
| 86 | QString name=zip->getCurrentFileName();
|
|---|
| 87 | if(name.isNull())
|
|---|
| 88 | setZipError(zip->getZipError());
|
|---|
| 89 | return name;
|
|---|
| 90 | }
|
|---|
| 91 |
|
|---|
| 92 | void QuaZipFile::setZipName(const QString& zipName)
|
|---|
| 93 | {
|
|---|
| 94 | if(isOpen()) {
|
|---|
| 95 | qWarning("QuaZipFile::setZipName(): file is already open - can not set ZIP name");
|
|---|
| 96 | return;
|
|---|
| 97 | }
|
|---|
| 98 | if(zip!=NULL&&internal) delete zip;
|
|---|
| 99 | zip=new QuaZip(zipName);
|
|---|
| 100 | Q_CHECK_PTR(zip);
|
|---|
| 101 | internal=true;
|
|---|
| 102 | }
|
|---|
| 103 |
|
|---|
| 104 | void QuaZipFile::setZip(QuaZip *zip)
|
|---|
| 105 | {
|
|---|
| 106 | if(isOpen()) {
|
|---|
| 107 | qWarning("QuaZipFile::setZip(): file is already open - can not set ZIP");
|
|---|
| 108 | return;
|
|---|
| 109 | }
|
|---|
| 110 | if(this->zip!=NULL&&internal) delete this->zip;
|
|---|
| 111 | this->zip=zip;
|
|---|
| 112 | this->fileName=QString();
|
|---|
| 113 | internal=false;
|
|---|
| 114 | }
|
|---|
| 115 |
|
|---|
| 116 | void QuaZipFile::setFileName(const QString& fileName, QuaZip::CaseSensitivity cs)
|
|---|
| 117 | {
|
|---|
| 118 | if(zip==NULL) {
|
|---|
| 119 | qWarning("QuaZipFile::setFileName(): call setZipName() first");
|
|---|
| 120 | return;
|
|---|
| 121 | }
|
|---|
| 122 | if(!internal) {
|
|---|
| 123 | qWarning("QuaZipFile::setFileName(): should not be used when not using internal QuaZip");
|
|---|
| 124 | return;
|
|---|
| 125 | }
|
|---|
| 126 | if(isOpen()) {
|
|---|
| 127 | qWarning("QuaZipFile::setFileName(): can not set file name for already opened file");
|
|---|
| 128 | return;
|
|---|
| 129 | }
|
|---|
| 130 | this->fileName=fileName;
|
|---|
| 131 | this->caseSensitivity=cs;
|
|---|
| 132 | }
|
|---|
| 133 |
|
|---|
| 134 | void QuaZipFile::setZipError(int zipError)const
|
|---|
| 135 | {
|
|---|
| 136 | QuaZipFile *fakeThis=(QuaZipFile*)this; // non-const
|
|---|
| 137 | fakeThis->zipError=zipError;
|
|---|
| 138 | if(zipError==UNZ_OK)
|
|---|
| 139 | fakeThis->setErrorString(QString());
|
|---|
| 140 | else
|
|---|
| 141 | fakeThis->setErrorString(tr("ZIP/UNZIP API error %1").arg(zipError));
|
|---|
| 142 | }
|
|---|
| 143 |
|
|---|
| 144 | bool QuaZipFile::open(OpenMode mode)
|
|---|
| 145 | {
|
|---|
| 146 | return open(mode, NULL);
|
|---|
| 147 | }
|
|---|
| 148 |
|
|---|
| 149 | bool QuaZipFile::open(OpenMode mode, int *method, int *level, bool raw, const char *password)
|
|---|
| 150 | {
|
|---|
| 151 | resetZipError();
|
|---|
| 152 | if(isOpen()) {
|
|---|
| 153 | qWarning("QuaZipFile::open(): already opened");
|
|---|
| 154 | return false;
|
|---|
| 155 | }
|
|---|
| 156 | if(mode&Unbuffered) {
|
|---|
| 157 | qWarning("QuaZipFile::open(): Unbuffered mode is not supported");
|
|---|
| 158 | return false;
|
|---|
| 159 | }
|
|---|
| 160 | if((mode&ReadOnly)&&!(mode&WriteOnly)) {
|
|---|
| 161 | if(internal) {
|
|---|
| 162 | if(!zip->open(QuaZip::mdUnzip)) {
|
|---|
| 163 | setZipError(zip->getZipError());
|
|---|
| 164 | return false;
|
|---|
| 165 | }
|
|---|
| 166 | if(!zip->setCurrentFile(fileName, caseSensitivity)) {
|
|---|
| 167 | setZipError(zip->getZipError());
|
|---|
| 168 | zip->close();
|
|---|
| 169 | return false;
|
|---|
| 170 | }
|
|---|
| 171 | } else {
|
|---|
| 172 | if(zip==NULL) {
|
|---|
| 173 | qWarning("QuaZipFile::open(): zip is NULL");
|
|---|
| 174 | return false;
|
|---|
| 175 | }
|
|---|
| 176 | if(zip->getMode()!=QuaZip::mdUnzip) {
|
|---|
| 177 | qWarning("QuaZipFile::open(): file open mode %d incompatible with ZIP open mode %d",
|
|---|
| 178 | (int)mode, (int)zip->getMode());
|
|---|
| 179 | return false;
|
|---|
| 180 | }
|
|---|
| 181 | if(!zip->hasCurrentFile()) {
|
|---|
| 182 | qWarning("QuaZipFile::open(): zip does not have current file");
|
|---|
| 183 | return false;
|
|---|
| 184 | }
|
|---|
| 185 | }
|
|---|
| 186 | setZipError(unzOpenCurrentFile3(zip->getUnzFile(), method, level, (int)raw, password));
|
|---|
| 187 | if(zipError==UNZ_OK) {
|
|---|
| 188 | setOpenMode(mode);
|
|---|
| 189 | this->raw=raw;
|
|---|
| 190 | return true;
|
|---|
| 191 | } else
|
|---|
| 192 | return false;
|
|---|
| 193 | }
|
|---|
| 194 | qWarning("QuaZipFile::open(): open mode %d not supported by this function", (int)mode);
|
|---|
| 195 | return false;
|
|---|
| 196 | }
|
|---|
| 197 |
|
|---|
| 198 | bool QuaZipFile::open(OpenMode mode, const QuaZipNewInfo& info,
|
|---|
| 199 | const char *password, quint32 crc,
|
|---|
| 200 | int method, int level, bool raw,
|
|---|
| 201 | int windowBits, int memLevel, int strategy)
|
|---|
| 202 | {
|
|---|
| 203 | zip_fileinfo info_z;
|
|---|
| 204 | resetZipError();
|
|---|
| 205 | if(isOpen()) {
|
|---|
| 206 | qWarning("QuaZipFile::open(): already opened");
|
|---|
| 207 | return false;
|
|---|
| 208 | }
|
|---|
| 209 | if((mode&WriteOnly)&&!(mode&ReadOnly)) {
|
|---|
| 210 | if(internal) {
|
|---|
| 211 | qWarning("QuaZipFile::open(): write mode is incompatible with internal QuaZip approach");
|
|---|
| 212 | return false;
|
|---|
| 213 | }
|
|---|
| 214 | if(zip==NULL) {
|
|---|
| 215 | qWarning("QuaZipFile::open(): zip is NULL");
|
|---|
| 216 | return false;
|
|---|
| 217 | }
|
|---|
| 218 | if(zip->getMode()!=QuaZip::mdCreate&&zip->getMode()!=QuaZip::mdAppend&&zip->getMode()!=QuaZip::mdAdd) {
|
|---|
| 219 | qWarning("QuaZipFile::open(): file open mode %d incompatible with ZIP open mode %d",
|
|---|
| 220 | (int)mode, (int)zip->getMode());
|
|---|
| 221 | return false;
|
|---|
| 222 | }
|
|---|
| 223 | info_z.tmz_date.tm_year=info.dateTime.date().year();
|
|---|
| 224 | info_z.tmz_date.tm_mon=info.dateTime.date().month() - 1;
|
|---|
| 225 | info_z.tmz_date.tm_mday=info.dateTime.date().day();
|
|---|
| 226 | info_z.tmz_date.tm_hour=info.dateTime.time().hour();
|
|---|
| 227 | info_z.tmz_date.tm_min=info.dateTime.time().minute();
|
|---|
| 228 | info_z.tmz_date.tm_sec=info.dateTime.time().second();
|
|---|
| 229 | info_z.dosDate = 0;
|
|---|
| 230 | info_z.internal_fa=(uLong)info.internalAttr;
|
|---|
| 231 | info_z.external_fa=(uLong)info.externalAttr;
|
|---|
| 232 | setZipError(zipOpenNewFileInZip3(zip->getZipFile(),
|
|---|
| 233 | zip->getFileNameCodec()->fromUnicode(info.name).constData(), &info_z,
|
|---|
| 234 | info.extraLocal.constData(), info.extraLocal.length(),
|
|---|
| 235 | info.extraGlobal.constData(), info.extraGlobal.length(),
|
|---|
| 236 | zip->getCommentCodec()->fromUnicode(info.comment).constData(),
|
|---|
| 237 | method, level, (int)raw,
|
|---|
| 238 | windowBits, memLevel, strategy,
|
|---|
| 239 | password, (uLong)crc));
|
|---|
| 240 | if(zipError==UNZ_OK) {
|
|---|
| 241 | writePos=0;
|
|---|
| 242 | setOpenMode(mode);
|
|---|
| 243 | this->raw=raw;
|
|---|
| 244 | if(raw) {
|
|---|
| 245 | this->crc=crc;
|
|---|
| 246 | this->uncompressedSize=info.uncompressedSize;
|
|---|
| 247 | }
|
|---|
| 248 | return true;
|
|---|
| 249 | } else
|
|---|
| 250 | return false;
|
|---|
| 251 | }
|
|---|
| 252 | qWarning("QuaZipFile::open(): open mode %d not supported by this function", (int)mode);
|
|---|
| 253 | return false;
|
|---|
| 254 | }
|
|---|
| 255 |
|
|---|
| 256 | bool QuaZipFile::isSequential()const
|
|---|
| 257 | {
|
|---|
| 258 | return true;
|
|---|
| 259 | }
|
|---|
| 260 |
|
|---|
| 261 | qint64 QuaZipFile::pos()const
|
|---|
| 262 | {
|
|---|
| 263 | if(zip==NULL) {
|
|---|
| 264 | qWarning("QuaZipFile::pos(): call setZipName() or setZip() first");
|
|---|
| 265 | return -1;
|
|---|
| 266 | }
|
|---|
| 267 | if(!isOpen()) {
|
|---|
| 268 | qWarning("QuaZipFile::pos(): file is not open");
|
|---|
| 269 | return -1;
|
|---|
| 270 | }
|
|---|
| 271 | if(openMode()&ReadOnly)
|
|---|
| 272 | return unztell(zip->getUnzFile());
|
|---|
| 273 | else
|
|---|
| 274 | return writePos;
|
|---|
| 275 | }
|
|---|
| 276 |
|
|---|
| 277 | bool QuaZipFile::atEnd()const
|
|---|
| 278 | {
|
|---|
| 279 | if(zip==NULL) {
|
|---|
| 280 | qWarning("QuaZipFile::atEnd(): call setZipName() or setZip() first");
|
|---|
| 281 | return false;
|
|---|
| 282 | }
|
|---|
| 283 | if(!isOpen()) {
|
|---|
| 284 | qWarning("QuaZipFile::atEnd(): file is not open");
|
|---|
| 285 | return false;
|
|---|
| 286 | }
|
|---|
| 287 | if(openMode()&ReadOnly)
|
|---|
| 288 | return unzeof(zip->getUnzFile())==1;
|
|---|
| 289 | else
|
|---|
| 290 | return true;
|
|---|
| 291 | }
|
|---|
| 292 |
|
|---|
| 293 | qint64 QuaZipFile::size()const
|
|---|
| 294 | {
|
|---|
| 295 | if(!isOpen()) {
|
|---|
| 296 | qWarning("QuaZipFile::atEnd(): file is not open");
|
|---|
| 297 | return -1;
|
|---|
| 298 | }
|
|---|
| 299 | if(openMode()&ReadOnly)
|
|---|
| 300 | return raw?csize():usize();
|
|---|
| 301 | else
|
|---|
| 302 | return writePos;
|
|---|
| 303 | }
|
|---|
| 304 |
|
|---|
| 305 | qint64 QuaZipFile::csize()const
|
|---|
| 306 | {
|
|---|
| 307 | unz_file_info info_z;
|
|---|
| 308 | setZipError(UNZ_OK);
|
|---|
| 309 | if(zip==NULL||zip->getMode()!=QuaZip::mdUnzip) return -1;
|
|---|
| 310 | setZipError(unzGetCurrentFileInfo(zip->getUnzFile(), &info_z, NULL, 0, NULL, 0, NULL, 0));
|
|---|
| 311 | if(zipError!=UNZ_OK)
|
|---|
| 312 | return -1;
|
|---|
| 313 | return info_z.compressed_size;
|
|---|
| 314 | }
|
|---|
| 315 |
|
|---|
| 316 | qint64 QuaZipFile::usize()const
|
|---|
| 317 | {
|
|---|
| 318 | unz_file_info info_z;
|
|---|
| 319 | setZipError(UNZ_OK);
|
|---|
| 320 | if(zip==NULL||zip->getMode()!=QuaZip::mdUnzip) return -1;
|
|---|
| 321 | setZipError(unzGetCurrentFileInfo(zip->getUnzFile(), &info_z, NULL, 0, NULL, 0, NULL, 0));
|
|---|
| 322 | if(zipError!=UNZ_OK)
|
|---|
| 323 | return -1;
|
|---|
| 324 | return info_z.uncompressed_size;
|
|---|
| 325 | }
|
|---|
| 326 |
|
|---|
| 327 | bool QuaZipFile::getFileInfo(QuaZipFileInfo *info)
|
|---|
| 328 | {
|
|---|
| 329 | if(zip==NULL||zip->getMode()!=QuaZip::mdUnzip) return false;
|
|---|
| 330 | zip->getCurrentFileInfo(info);
|
|---|
| 331 | setZipError(zip->getZipError());
|
|---|
| 332 | return zipError==UNZ_OK;
|
|---|
| 333 | }
|
|---|
| 334 |
|
|---|
| 335 | void QuaZipFile::close()
|
|---|
| 336 | {
|
|---|
| 337 | resetZipError();
|
|---|
| 338 | if(zip==NULL||!zip->isOpen()) return;
|
|---|
| 339 | if(!isOpen()) {
|
|---|
| 340 | qWarning("QuaZipFile::close(): file isn't open");
|
|---|
| 341 | return;
|
|---|
| 342 | }
|
|---|
| 343 | if(openMode()&ReadOnly)
|
|---|
| 344 | setZipError(unzCloseCurrentFile(zip->getUnzFile()));
|
|---|
| 345 | else if(openMode()&WriteOnly)
|
|---|
| 346 | if(isRaw()) setZipError(zipCloseFileInZipRaw(zip->getZipFile(), uncompressedSize, crc));
|
|---|
| 347 | else setZipError(zipCloseFileInZip(zip->getZipFile()));
|
|---|
| 348 | else {
|
|---|
| 349 | qWarning("Wrong open mode: %d", (int)openMode());
|
|---|
| 350 | return;
|
|---|
| 351 | }
|
|---|
| 352 | if(zipError==UNZ_OK) setOpenMode(QIODevice::NotOpen);
|
|---|
| 353 | else return;
|
|---|
| 354 | if(internal) {
|
|---|
| 355 | zip->close();
|
|---|
| 356 | setZipError(zip->getZipError());
|
|---|
| 357 | }
|
|---|
| 358 | }
|
|---|
| 359 |
|
|---|
| 360 | qint64 QuaZipFile::readData(char *data, qint64 maxSize)
|
|---|
| 361 | {
|
|---|
| 362 | setZipError(UNZ_OK);
|
|---|
| 363 | qint64 bytesRead=unzReadCurrentFile(zip->getUnzFile(), data, (unsigned)maxSize);
|
|---|
| 364 | if(bytesRead<0) setZipError((int)bytesRead);
|
|---|
| 365 | return bytesRead;
|
|---|
| 366 | }
|
|---|
| 367 |
|
|---|
| 368 | qint64 QuaZipFile::writeData(const char* data, qint64 maxSize)
|
|---|
| 369 | {
|
|---|
| 370 | setZipError(ZIP_OK);
|
|---|
| 371 | setZipError(zipWriteInFileInZip(zip->getZipFile(), data, (uint)maxSize));
|
|---|
| 372 | if(zipError!=ZIP_OK) return -1;
|
|---|
| 373 | else {
|
|---|
| 374 | writePos+=maxSize;
|
|---|
| 375 | return maxSize;
|
|---|
| 376 | }
|
|---|
| 377 | }
|
|---|