misc/quazip/quazipfile.cpp
changeset 8057 93e16240f178
parent 8051 f26422ef0333
parent 8055 04dd8b7fb605
child 8058 bcebfc477459
equal deleted inserted replaced
8051:f26422ef0333 8057:93e16240f178
     1 /*
       
     2 Copyright (C) 2005-2011 Sergey A. Tachenov
       
     3 
       
     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.
       
     8 
       
     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.
       
    13 
       
    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
       
    17 
       
    18 See COPYING file for the full LGPL text.
       
    19 
       
    20 Original ZIP package is copyrighted by Gilles Vollant, see
       
    21 quazip/(un)zip.h files for details, basically it's zlib license.
       
    22  **/
       
    23 
       
    24 #include "quazipfile.h"
       
    25 
       
    26 using namespace std;
       
    27 
       
    28 class QuaZipFilePrivate {
       
    29   friend class QuaZipFile;
       
    30   private:
       
    31     QuaZipFile *q;
       
    32     QuaZip *zip;
       
    33     QString fileName;
       
    34     QuaZip::CaseSensitivity caseSensitivity;
       
    35     bool raw;
       
    36     qint64 writePos;
       
    37     // these two are for writing raw files
       
    38     ulong uncompressedSize;
       
    39     quint32 crc;
       
    40     bool internal;
       
    41     int zipError;
       
    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)
       
    49       {
       
    50         zip=new QuaZip(zipName);
       
    51       }
       
    52     inline QuaZipFilePrivate(QuaZipFile *q, const QString &zipName, const QString &fileName,
       
    53         QuaZip::CaseSensitivity cs):
       
    54       q(q), internal(true), zipError(UNZ_OK)
       
    55       {
       
    56         zip=new QuaZip(zipName);
       
    57         this->fileName=fileName;
       
    58         this->caseSensitivity=cs;
       
    59       }
       
    60     inline QuaZipFilePrivate(QuaZipFile *q, QuaZip *zip):
       
    61       q(q), zip(zip), internal(false), zipError(UNZ_OK) {}
       
    62     inline ~QuaZipFilePrivate()
       
    63     {
       
    64       if (internal)
       
    65         delete zip;
       
    66     }
       
    67 };
       
    68 
       
    69 QuaZipFile::QuaZipFile():
       
    70   p(new QuaZipFilePrivate(this))
       
    71 {
       
    72 }
       
    73 
       
    74 QuaZipFile::QuaZipFile(QObject *parent):
       
    75   QIODevice(parent),
       
    76   p(new QuaZipFilePrivate(this))
       
    77 {
       
    78 }
       
    79 
       
    80 QuaZipFile::QuaZipFile(const QString& zipName, QObject *parent):
       
    81   QIODevice(parent),
       
    82   p(new QuaZipFilePrivate(this, zipName))
       
    83 {
       
    84 }
       
    85 
       
    86 QuaZipFile::QuaZipFile(const QString& zipName, const QString& fileName,
       
    87     QuaZip::CaseSensitivity cs, QObject *parent):
       
    88   QIODevice(parent),
       
    89   p(new QuaZipFilePrivate(this, zipName, fileName, cs))
       
    90 {
       
    91 }
       
    92 
       
    93 QuaZipFile::QuaZipFile(QuaZip *zip, QObject *parent):
       
    94   QIODevice(parent),
       
    95   p(new QuaZipFilePrivate(this, zip))
       
    96 {
       
    97 }
       
    98 
       
    99 QuaZipFile::~QuaZipFile()
       
   100 {
       
   101   if (isOpen())
       
   102     close();
       
   103   delete p;
       
   104 }
       
   105 
       
   106 QString QuaZipFile::getZipName() const
       
   107 {
       
   108   return p->zip==NULL ? QString() : p->zip->getZipName();
       
   109 }
       
   110 
       
   111 QString QuaZipFile::getActualFileName()const
       
   112 {
       
   113   p->setZipError(UNZ_OK);
       
   114   if (p->zip == NULL || (openMode() & WriteOnly))
       
   115     return QString();
       
   116   QString name=p->zip->getCurrentFileName();
       
   117   if(name.isNull())
       
   118     p->setZipError(p->zip->getZipError());
       
   119   return name;
       
   120 }
       
   121 
       
   122 void QuaZipFile::setZipName(const QString& zipName)
       
   123 {
       
   124   if(isOpen()) {
       
   125     qWarning("QuaZipFile::setZipName(): file is already open - can not set ZIP name");
       
   126     return;
       
   127   }
       
   128   if(p->zip!=NULL && p->internal)
       
   129     delete p->zip;
       
   130   p->zip=new QuaZip(zipName);
       
   131   p->internal=true;
       
   132 }
       
   133 
       
   134 void QuaZipFile::setZip(QuaZip *zip)
       
   135 {
       
   136   if(isOpen()) {
       
   137     qWarning("QuaZipFile::setZip(): file is already open - can not set ZIP");
       
   138     return;
       
   139   }
       
   140   if(p->zip!=NULL && p->internal)
       
   141     delete p->zip;
       
   142   p->zip=zip;
       
   143   p->fileName=QString();
       
   144   p->internal=false;
       
   145 }
       
   146 
       
   147 void QuaZipFile::setFileName(const QString& fileName, QuaZip::CaseSensitivity cs)
       
   148 {
       
   149   if(p->zip==NULL) {
       
   150     qWarning("QuaZipFile::setFileName(): call setZipName() first");
       
   151     return;
       
   152   }
       
   153   if(!p->internal) {
       
   154     qWarning("QuaZipFile::setFileName(): should not be used when not using internal QuaZip");
       
   155     return;
       
   156   }
       
   157   if(isOpen()) {
       
   158     qWarning("QuaZipFile::setFileName(): can not set file name for already opened file");
       
   159     return;
       
   160   }
       
   161   p->fileName=fileName;
       
   162   p->caseSensitivity=cs;
       
   163 }
       
   164 
       
   165 void QuaZipFilePrivate::setZipError(int zipError) const
       
   166 {
       
   167   QuaZipFilePrivate *fakeThis = const_cast<QuaZipFilePrivate*>(this); // non-const
       
   168   fakeThis->zipError=zipError;
       
   169   if(zipError==UNZ_OK)
       
   170     q->setErrorString(QString());
       
   171   else
       
   172     q->setErrorString(q->tr("ZIP/UNZIP API error %1").arg(zipError));
       
   173 }
       
   174 
       
   175 bool QuaZipFile::open(OpenMode mode)
       
   176 {
       
   177   return open(mode, NULL);
       
   178 }
       
   179 
       
   180 bool QuaZipFile::open(OpenMode mode, int *method, int *level, bool raw, const char *password)
       
   181 {
       
   182   p->resetZipError();
       
   183   if(isOpen()) {
       
   184     qWarning("QuaZipFile::open(): already opened");
       
   185     return false;
       
   186   }
       
   187   if(mode&Unbuffered) {
       
   188     qWarning("QuaZipFile::open(): Unbuffered mode is not supported");
       
   189     return false;
       
   190   }
       
   191   if((mode&ReadOnly)&&!(mode&WriteOnly)) {
       
   192     if(p->internal) {
       
   193       if(!p->zip->open(QuaZip::mdUnzip)) {
       
   194         p->setZipError(p->zip->getZipError());
       
   195         return false;
       
   196       }
       
   197       if(!p->zip->setCurrentFile(p->fileName, p->caseSensitivity)) {
       
   198         p->setZipError(p->zip->getZipError());
       
   199         p->zip->close();
       
   200         return false;
       
   201       }
       
   202     } else {
       
   203       if(p->zip==NULL) {
       
   204         qWarning("QuaZipFile::open(): zip is NULL");
       
   205         return false;
       
   206       }
       
   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());
       
   210         return false;
       
   211       }
       
   212       if(!p->zip->hasCurrentFile()) {
       
   213         qWarning("QuaZipFile::open(): zip does not have current file");
       
   214         return false;
       
   215       }
       
   216     }
       
   217     p->setZipError(unzOpenCurrentFile3(p->zip->getUnzFile(), method, level, (int)raw, password));
       
   218     if(p->zipError==UNZ_OK) {
       
   219       setOpenMode(mode);
       
   220       p->raw=raw;
       
   221       return true;
       
   222     } else
       
   223       return false;
       
   224   }
       
   225   qWarning("QuaZipFile::open(): open mode %d not supported by this function", (int)mode);
       
   226   return false;
       
   227 }
       
   228 
       
   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)
       
   233 {
       
   234   zip_fileinfo info_z;
       
   235   p->resetZipError();
       
   236   if(isOpen()) {
       
   237     qWarning("QuaZipFile::open(): already opened");
       
   238     return false;
       
   239   }
       
   240   if((mode&WriteOnly)&&!(mode&ReadOnly)) {
       
   241     if(p->internal) {
       
   242       qWarning("QuaZipFile::open(): write mode is incompatible with internal QuaZip approach");
       
   243       return false;
       
   244     }
       
   245     if(p->zip==NULL) {
       
   246       qWarning("QuaZipFile::open(): zip is NULL");
       
   247       return false;
       
   248     }
       
   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());
       
   252       return false;
       
   253     }
       
   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();
       
   260     info_z.dosDate = 0;
       
   261     info_z.internal_fa=(uLong)info.internalAttr;
       
   262     info_z.external_fa=(uLong)info.externalAttr;
       
   263     p->setZipError(zipOpenNewFileInZip3(p->zip->getZipFile(),
       
   264           p->zip->getFileNameCodec()->fromUnicode(info.name).constData(), &info_z,
       
   265           info.extraLocal.constData(), info.extraLocal.length(),
       
   266           info.extraGlobal.constData(), info.extraGlobal.length(),
       
   267           p->zip->getCommentCodec()->fromUnicode(info.comment).constData(),
       
   268           method, level, (int)raw,
       
   269           windowBits, memLevel, strategy,
       
   270           password, (uLong)crc));
       
   271     if(p->zipError==UNZ_OK) {
       
   272       p->writePos=0;
       
   273       setOpenMode(mode);
       
   274       p->raw=raw;
       
   275       if(raw) {
       
   276         p->crc=crc;
       
   277         p->uncompressedSize=info.uncompressedSize;
       
   278       }
       
   279       return true;
       
   280     } else
       
   281       return false;
       
   282   }
       
   283   qWarning("QuaZipFile::open(): open mode %d not supported by this function", (int)mode);
       
   284   return false;
       
   285 }
       
   286 
       
   287 bool QuaZipFile::isSequential()const
       
   288 {
       
   289   return true;
       
   290 }
       
   291 
       
   292 qint64 QuaZipFile::pos()const
       
   293 {
       
   294   if(p->zip==NULL) {
       
   295     qWarning("QuaZipFile::pos(): call setZipName() or setZip() first");
       
   296     return -1;
       
   297   }
       
   298   if(!isOpen()) {
       
   299     qWarning("QuaZipFile::pos(): file is not open");
       
   300     return -1;
       
   301   }
       
   302   if(openMode()&ReadOnly)
       
   303     return unztell(p->zip->getUnzFile());
       
   304   else
       
   305     return p->writePos;
       
   306 }
       
   307 
       
   308 bool QuaZipFile::atEnd()const
       
   309 {
       
   310   if(p->zip==NULL) {
       
   311     qWarning("QuaZipFile::atEnd(): call setZipName() or setZip() first");
       
   312     return false;
       
   313   }
       
   314   if(!isOpen()) {
       
   315     qWarning("QuaZipFile::atEnd(): file is not open");
       
   316     return false;
       
   317   }
       
   318   if(openMode()&ReadOnly)
       
   319     return unzeof(p->zip->getUnzFile())==1;
       
   320   else
       
   321     return true;
       
   322 }
       
   323 
       
   324 qint64 QuaZipFile::size()const
       
   325 {
       
   326   if(!isOpen()) {
       
   327     qWarning("QuaZipFile::atEnd(): file is not open");
       
   328     return -1;
       
   329   }
       
   330   if(openMode()&ReadOnly)
       
   331     return p->raw?csize():usize();
       
   332   else
       
   333     return p->writePos;
       
   334 }
       
   335 
       
   336 qint64 QuaZipFile::csize()const
       
   337 {
       
   338   unz_file_info info_z;
       
   339   p->setZipError(UNZ_OK);
       
   340   if(p->zip==NULL||p->zip->getMode()!=QuaZip::mdUnzip) return -1;
       
   341   p->setZipError(unzGetCurrentFileInfo(p->zip->getUnzFile(), &info_z, NULL, 0, NULL, 0, NULL, 0));
       
   342   if(p->zipError!=UNZ_OK)
       
   343     return -1;
       
   344   return info_z.compressed_size;
       
   345 }
       
   346 
       
   347 qint64 QuaZipFile::usize()const
       
   348 {
       
   349   unz_file_info info_z;
       
   350   p->setZipError(UNZ_OK);
       
   351   if(p->zip==NULL||p->zip->getMode()!=QuaZip::mdUnzip) return -1;
       
   352   p->setZipError(unzGetCurrentFileInfo(p->zip->getUnzFile(), &info_z, NULL, 0, NULL, 0, NULL, 0));
       
   353   if(p->zipError!=UNZ_OK)
       
   354     return -1;
       
   355   return info_z.uncompressed_size;
       
   356 }
       
   357 
       
   358 bool QuaZipFile::getFileInfo(QuaZipFileInfo *info)
       
   359 {
       
   360   if(p->zip==NULL||p->zip->getMode()!=QuaZip::mdUnzip) return false;
       
   361   p->zip->getCurrentFileInfo(info);
       
   362   p->setZipError(p->zip->getZipError());
       
   363   return p->zipError==UNZ_OK;
       
   364 }
       
   365 
       
   366 void QuaZipFile::close()
       
   367 {
       
   368   p->resetZipError();
       
   369   if(p->zip==NULL||!p->zip->isOpen()) return;
       
   370   if(!isOpen()) {
       
   371     qWarning("QuaZipFile::close(): file isn't open");
       
   372     return;
       
   373   }
       
   374   if(openMode()&ReadOnly)
       
   375     p->setZipError(unzCloseCurrentFile(p->zip->getUnzFile()));
       
   376   else if(openMode()&WriteOnly)
       
   377     if(isRaw()) p->setZipError(zipCloseFileInZipRaw(p->zip->getZipFile(), p->uncompressedSize, p->crc));
       
   378     else p->setZipError(zipCloseFileInZip(p->zip->getZipFile()));
       
   379   else {
       
   380     qWarning("Wrong open mode: %d", (int)openMode());
       
   381     return;
       
   382   }
       
   383   if(p->zipError==UNZ_OK) setOpenMode(QIODevice::NotOpen);
       
   384   else return;
       
   385   if(p->internal) {
       
   386     p->zip->close();
       
   387     p->setZipError(p->zip->getZipError());
       
   388   }
       
   389 }
       
   390 
       
   391 qint64 QuaZipFile::readData(char *data, qint64 maxSize)
       
   392 {
       
   393   p->setZipError(UNZ_OK);
       
   394   qint64 bytesRead=unzReadCurrentFile(p->zip->getUnzFile(), data, (unsigned)maxSize);
       
   395   if(bytesRead<0) p->setZipError((int)bytesRead);
       
   396   return bytesRead;
       
   397 }
       
   398 
       
   399 qint64 QuaZipFile::writeData(const char* data, qint64 maxSize)
       
   400 {
       
   401   p->setZipError(ZIP_OK);
       
   402   p->setZipError(zipWriteInFileInZip(p->zip->getZipFile(), data, (uint)maxSize));
       
   403   if(p->zipError!=ZIP_OK) return -1;
       
   404   else {
       
   405     p->writePos+=maxSize;
       
   406     return maxSize;
       
   407   }
       
   408 }
       
   409 
       
   410 QString QuaZipFile::getFileName() const
       
   411 {
       
   412   return p->fileName;
       
   413 }
       
   414 
       
   415 QuaZip::CaseSensitivity QuaZipFile::getCaseSensitivity() const
       
   416 {
       
   417   return p->caseSensitivity;
       
   418 }
       
   419 
       
   420 bool QuaZipFile::isRaw() const
       
   421 {
       
   422   return p->raw;
       
   423 }
       
   424 
       
   425 int QuaZipFile::getZipError() const
       
   426 {
       
   427   return p->zipError;
       
   428 }