misc/quazip/quazipfile.cpp
changeset 5752 ea95ee97c805
child 7889 57b117d441b9
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/quazip/quazipfile.cpp	Sun Sep 04 10:58:42 2011 +0400
@@ -0,0 +1,428 @@
+/*
+Copyright (C) 2005-2011 Sergey A. Tachenov
+
+This program is free software; you can redistribute it and/or modify it
+under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+This program is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
+General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program; if not, write to the Free Software Foundation,
+Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+See COPYING file for the full LGPL text.
+
+Original ZIP package is copyrighted by Gilles Vollant, see
+quazip/(un)zip.h files for details, basically it's zlib license.
+ **/
+
+#include "quazipfile.h"
+
+using namespace std;
+
+class QuaZipFilePrivate {
+  friend class QuaZipFile;
+  private:
+    QuaZipFile *q;
+    QuaZip *zip;
+    QString fileName;
+    QuaZip::CaseSensitivity caseSensitivity;
+    bool raw;
+    qint64 writePos;
+    // these two are for writing raw files
+    ulong uncompressedSize;
+    quint32 crc;
+    bool internal;
+    int zipError;
+    inline void resetZipError() const {setZipError(UNZ_OK);}
+    // const, but sets zipError!
+    void setZipError(int zipError) const;
+    inline QuaZipFilePrivate(QuaZipFile *q):
+      q(q), zip(NULL), internal(true), zipError(UNZ_OK) {}
+    inline QuaZipFilePrivate(QuaZipFile *q, const QString &zipName):
+      q(q), internal(true), zipError(UNZ_OK)
+      {
+        zip=new QuaZip(zipName);
+      }
+    inline QuaZipFilePrivate(QuaZipFile *q, const QString &zipName, const QString &fileName,
+        QuaZip::CaseSensitivity cs):
+      q(q), internal(true), zipError(UNZ_OK)
+      {
+        zip=new QuaZip(zipName);
+        this->fileName=fileName;
+        this->caseSensitivity=cs;
+      }
+    inline QuaZipFilePrivate(QuaZipFile *q, QuaZip *zip):
+      q(q), zip(zip), internal(false), zipError(UNZ_OK) {}
+    inline ~QuaZipFilePrivate()
+    {
+      if (internal)
+        delete zip;
+    }
+};
+
+QuaZipFile::QuaZipFile():
+  p(new QuaZipFilePrivate(this))
+{
+}
+
+QuaZipFile::QuaZipFile(QObject *parent):
+  QIODevice(parent),
+  p(new QuaZipFilePrivate(this))
+{
+}
+
+QuaZipFile::QuaZipFile(const QString& zipName, QObject *parent):
+  QIODevice(parent),
+  p(new QuaZipFilePrivate(this, zipName))
+{
+}
+
+QuaZipFile::QuaZipFile(const QString& zipName, const QString& fileName,
+    QuaZip::CaseSensitivity cs, QObject *parent):
+  QIODevice(parent),
+  p(new QuaZipFilePrivate(this, zipName, fileName, cs))
+{
+}
+
+QuaZipFile::QuaZipFile(QuaZip *zip, QObject *parent):
+  QIODevice(parent),
+  p(new QuaZipFilePrivate(this, zip))
+{
+}
+
+QuaZipFile::~QuaZipFile()
+{
+  if (isOpen())
+    close();
+  delete p;
+}
+
+QString QuaZipFile::getZipName() const
+{
+  return p->zip==NULL ? QString() : p->zip->getZipName();
+}
+
+QString QuaZipFile::getActualFileName()const
+{
+  p->setZipError(UNZ_OK);
+  if (p->zip == NULL || (openMode() & WriteOnly))
+    return QString();
+  QString name=p->zip->getCurrentFileName();
+  if(name.isNull())
+    p->setZipError(p->zip->getZipError());
+  return name;
+}
+
+void QuaZipFile::setZipName(const QString& zipName)
+{
+  if(isOpen()) {
+    qWarning("QuaZipFile::setZipName(): file is already open - can not set ZIP name");
+    return;
+  }
+  if(p->zip!=NULL && p->internal)
+    delete p->zip;
+  p->zip=new QuaZip(zipName);
+  p->internal=true;
+}
+
+void QuaZipFile::setZip(QuaZip *zip)
+{
+  if(isOpen()) {
+    qWarning("QuaZipFile::setZip(): file is already open - can not set ZIP");
+    return;
+  }
+  if(p->zip!=NULL && p->internal)
+    delete p->zip;
+  p->zip=zip;
+  p->fileName=QString();
+  p->internal=false;
+}
+
+void QuaZipFile::setFileName(const QString& fileName, QuaZip::CaseSensitivity cs)
+{
+  if(p->zip==NULL) {
+    qWarning("QuaZipFile::setFileName(): call setZipName() first");
+    return;
+  }
+  if(!p->internal) {
+    qWarning("QuaZipFile::setFileName(): should not be used when not using internal QuaZip");
+    return;
+  }
+  if(isOpen()) {
+    qWarning("QuaZipFile::setFileName(): can not set file name for already opened file");
+    return;
+  }
+  p->fileName=fileName;
+  p->caseSensitivity=cs;
+}
+
+void QuaZipFilePrivate::setZipError(int zipError) const
+{
+  QuaZipFilePrivate *fakeThis = const_cast<QuaZipFilePrivate*>(this); // non-const
+  fakeThis->zipError=zipError;
+  if(zipError==UNZ_OK)
+    q->setErrorString(QString());
+  else
+    q->setErrorString(q->tr("ZIP/UNZIP API error %1").arg(zipError));
+}
+
+bool QuaZipFile::open(OpenMode mode)
+{
+  return open(mode, NULL);
+}
+
+bool QuaZipFile::open(OpenMode mode, int *method, int *level, bool raw, const char *password)
+{
+  p->resetZipError();
+  if(isOpen()) {
+    qWarning("QuaZipFile::open(): already opened");
+    return false;
+  }
+  if(mode&Unbuffered) {
+    qWarning("QuaZipFile::open(): Unbuffered mode is not supported");
+    return false;
+  }
+  if((mode&ReadOnly)&&!(mode&WriteOnly)) {
+    if(p->internal) {
+      if(!p->zip->open(QuaZip::mdUnzip)) {
+        p->setZipError(p->zip->getZipError());
+        return false;
+      }
+      if(!p->zip->setCurrentFile(p->fileName, p->caseSensitivity)) {
+        p->setZipError(p->zip->getZipError());
+        p->zip->close();
+        return false;
+      }
+    } else {
+      if(p->zip==NULL) {
+        qWarning("QuaZipFile::open(): zip is NULL");
+        return false;
+      }
+      if(p->zip->getMode()!=QuaZip::mdUnzip) {
+        qWarning("QuaZipFile::open(): file open mode %d incompatible with ZIP open mode %d",
+            (int)mode, (int)p->zip->getMode());
+        return false;
+      }
+      if(!p->zip->hasCurrentFile()) {
+        qWarning("QuaZipFile::open(): zip does not have current file");
+        return false;
+      }
+    }
+    p->setZipError(unzOpenCurrentFile3(p->zip->getUnzFile(), method, level, (int)raw, password));
+    if(p->zipError==UNZ_OK) {
+      setOpenMode(mode);
+      p->raw=raw;
+      return true;
+    } else
+      return false;
+  }
+  qWarning("QuaZipFile::open(): open mode %d not supported by this function", (int)mode);
+  return false;
+}
+
+bool QuaZipFile::open(OpenMode mode, const QuaZipNewInfo& info,
+    const char *password, quint32 crc,
+    int method, int level, bool raw,
+    int windowBits, int memLevel, int strategy)
+{
+  zip_fileinfo info_z;
+  p->resetZipError();
+  if(isOpen()) {
+    qWarning("QuaZipFile::open(): already opened");
+    return false;
+  }
+  if((mode&WriteOnly)&&!(mode&ReadOnly)) {
+    if(p->internal) {
+      qWarning("QuaZipFile::open(): write mode is incompatible with internal QuaZip approach");
+      return false;
+    }
+    if(p->zip==NULL) {
+      qWarning("QuaZipFile::open(): zip is NULL");
+      return false;
+    }
+    if(p->zip->getMode()!=QuaZip::mdCreate&&p->zip->getMode()!=QuaZip::mdAppend&&p->zip->getMode()!=QuaZip::mdAdd) {
+      qWarning("QuaZipFile::open(): file open mode %d incompatible with ZIP open mode %d",
+          (int)mode, (int)p->zip->getMode());
+      return false;
+    }
+    info_z.tmz_date.tm_year=info.dateTime.date().year();
+    info_z.tmz_date.tm_mon=info.dateTime.date().month() - 1;
+    info_z.tmz_date.tm_mday=info.dateTime.date().day();
+    info_z.tmz_date.tm_hour=info.dateTime.time().hour();
+    info_z.tmz_date.tm_min=info.dateTime.time().minute();
+    info_z.tmz_date.tm_sec=info.dateTime.time().second();
+    info_z.dosDate = 0;
+    info_z.internal_fa=(uLong)info.internalAttr;
+    info_z.external_fa=(uLong)info.externalAttr;
+    p->setZipError(zipOpenNewFileInZip3(p->zip->getZipFile(),
+          p->zip->getFileNameCodec()->fromUnicode(info.name).constData(), &info_z,
+          info.extraLocal.constData(), info.extraLocal.length(),
+          info.extraGlobal.constData(), info.extraGlobal.length(),
+          p->zip->getCommentCodec()->fromUnicode(info.comment).constData(),
+          method, level, (int)raw,
+          windowBits, memLevel, strategy,
+          password, (uLong)crc));
+    if(p->zipError==UNZ_OK) {
+      p->writePos=0;
+      setOpenMode(mode);
+      p->raw=raw;
+      if(raw) {
+        p->crc=crc;
+        p->uncompressedSize=info.uncompressedSize;
+      }
+      return true;
+    } else
+      return false;
+  }
+  qWarning("QuaZipFile::open(): open mode %d not supported by this function", (int)mode);
+  return false;
+}
+
+bool QuaZipFile::isSequential()const
+{
+  return true;
+}
+
+qint64 QuaZipFile::pos()const
+{
+  if(p->zip==NULL) {
+    qWarning("QuaZipFile::pos(): call setZipName() or setZip() first");
+    return -1;
+  }
+  if(!isOpen()) {
+    qWarning("QuaZipFile::pos(): file is not open");
+    return -1;
+  }
+  if(openMode()&ReadOnly)
+    return unztell(p->zip->getUnzFile());
+  else
+    return p->writePos;
+}
+
+bool QuaZipFile::atEnd()const
+{
+  if(p->zip==NULL) {
+    qWarning("QuaZipFile::atEnd(): call setZipName() or setZip() first");
+    return false;
+  }
+  if(!isOpen()) {
+    qWarning("QuaZipFile::atEnd(): file is not open");
+    return false;
+  }
+  if(openMode()&ReadOnly)
+    return unzeof(p->zip->getUnzFile())==1;
+  else
+    return true;
+}
+
+qint64 QuaZipFile::size()const
+{
+  if(!isOpen()) {
+    qWarning("QuaZipFile::atEnd(): file is not open");
+    return -1;
+  }
+  if(openMode()&ReadOnly)
+    return p->raw?csize():usize();
+  else
+    return p->writePos;
+}
+
+qint64 QuaZipFile::csize()const
+{
+  unz_file_info info_z;
+  p->setZipError(UNZ_OK);
+  if(p->zip==NULL||p->zip->getMode()!=QuaZip::mdUnzip) return -1;
+  p->setZipError(unzGetCurrentFileInfo(p->zip->getUnzFile(), &info_z, NULL, 0, NULL, 0, NULL, 0));
+  if(p->zipError!=UNZ_OK)
+    return -1;
+  return info_z.compressed_size;
+}
+
+qint64 QuaZipFile::usize()const
+{
+  unz_file_info info_z;
+  p->setZipError(UNZ_OK);
+  if(p->zip==NULL||p->zip->getMode()!=QuaZip::mdUnzip) return -1;
+  p->setZipError(unzGetCurrentFileInfo(p->zip->getUnzFile(), &info_z, NULL, 0, NULL, 0, NULL, 0));
+  if(p->zipError!=UNZ_OK)
+    return -1;
+  return info_z.uncompressed_size;
+}
+
+bool QuaZipFile::getFileInfo(QuaZipFileInfo *info)
+{
+  if(p->zip==NULL||p->zip->getMode()!=QuaZip::mdUnzip) return false;
+  p->zip->getCurrentFileInfo(info);
+  p->setZipError(p->zip->getZipError());
+  return p->zipError==UNZ_OK;
+}
+
+void QuaZipFile::close()
+{
+  p->resetZipError();
+  if(p->zip==NULL||!p->zip->isOpen()) return;
+  if(!isOpen()) {
+    qWarning("QuaZipFile::close(): file isn't open");
+    return;
+  }
+  if(openMode()&ReadOnly)
+    p->setZipError(unzCloseCurrentFile(p->zip->getUnzFile()));
+  else if(openMode()&WriteOnly)
+    if(isRaw()) p->setZipError(zipCloseFileInZipRaw(p->zip->getZipFile(), p->uncompressedSize, p->crc));
+    else p->setZipError(zipCloseFileInZip(p->zip->getZipFile()));
+  else {
+    qWarning("Wrong open mode: %d", (int)openMode());
+    return;
+  }
+  if(p->zipError==UNZ_OK) setOpenMode(QIODevice::NotOpen);
+  else return;
+  if(p->internal) {
+    p->zip->close();
+    p->setZipError(p->zip->getZipError());
+  }
+}
+
+qint64 QuaZipFile::readData(char *data, qint64 maxSize)
+{
+  p->setZipError(UNZ_OK);
+  qint64 bytesRead=unzReadCurrentFile(p->zip->getUnzFile(), data, (unsigned)maxSize);
+  if(bytesRead<0) p->setZipError((int)bytesRead);
+  return bytesRead;
+}
+
+qint64 QuaZipFile::writeData(const char* data, qint64 maxSize)
+{
+  p->setZipError(ZIP_OK);
+  p->setZipError(zipWriteInFileInZip(p->zip->getZipFile(), data, (uint)maxSize));
+  if(p->zipError!=ZIP_OK) return -1;
+  else {
+    p->writePos+=maxSize;
+    return maxSize;
+  }
+}
+
+QString QuaZipFile::getFileName() const
+{
+  return p->fileName;
+}
+
+QuaZip::CaseSensitivity QuaZipFile::getCaseSensitivity() const
+{
+  return p->caseSensitivity;
+}
+
+bool QuaZipFile::isRaw() const
+{
+  return p->raw;
+}
+
+int QuaZipFile::getZipError() const
+{
+  return p->zipError;
+}