PageRenderTime 282ms CodeModel.GetById 60ms app.highlight 115ms RepoModel.GetById 81ms app.codeStats 1ms

/src/libtomahawk/thirdparty/quazip/quazip/quazipfile.cpp

http://github.com/tomahawk-player/tomahawk
C++ | 428 lines | 372 code | 32 blank | 24 comment | 61 complexity | 5c93b119b334321a8d942d7541f1582e MD5 | raw file
  1/*
  2Copyright (C) 2005-2011 Sergey A. Tachenov
  3
  4This program is free software; you can redistribute it and/or modify it
  5under the terms of the GNU Lesser General Public License as published by
  6the Free Software Foundation; either version 2 of the License, or (at
  7your option) any later version.
  8
  9This program is distributed in the hope that it will be useful, but
 10WITHOUT ANY WARRANTY; without even the implied warranty of
 11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
 12General Public License for more details.
 13
 14You should have received a copy of the GNU Lesser General Public License
 15along with this program; if not, write to the Free Software Foundation,
 16Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 17
 18See COPYING file for the full LGPL text.
 19
 20Original ZIP package is copyrighted by Gilles Vollant, see
 21quazip/(un)zip.h files for details, basically it's zlib license.
 22 **/
 23
 24#include "quazipfile.h"
 25
 26using namespace std;
 27
 28class 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
 69QuaZipFile::QuaZipFile():
 70  p(new QuaZipFilePrivate(this))
 71{
 72}
 73
 74QuaZipFile::QuaZipFile(QObject *parent):
 75  QIODevice(parent),
 76  p(new QuaZipFilePrivate(this))
 77{
 78}
 79
 80QuaZipFile::QuaZipFile(const QString& zipName, QObject *parent):
 81  QIODevice(parent),
 82  p(new QuaZipFilePrivate(this, zipName))
 83{
 84}
 85
 86QuaZipFile::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
 93QuaZipFile::QuaZipFile(QuaZip *zip, QObject *parent):
 94  QIODevice(parent),
 95  p(new QuaZipFilePrivate(this, zip))
 96{
 97}
 98
 99QuaZipFile::~QuaZipFile()
100{
101  if (isOpen())
102    close();
103  delete p;
104}
105
106QString QuaZipFile::getZipName() const
107{
108  return p->zip==NULL ? QString() : p->zip->getZipName();
109}
110
111QString 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
122void 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
134void 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
147void 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
165void 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
175bool QuaZipFile::open(OpenMode mode)
176{
177  return open(mode, NULL);
178}
179
180bool 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
229bool 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
287bool QuaZipFile::isSequential()const
288{
289  return true;
290}
291
292qint64 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
308bool 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
324qint64 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
336qint64 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
347qint64 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
358bool 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
366void 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
391qint64 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
399qint64 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
410QString QuaZipFile::getFileName() const
411{
412  return p->fileName;
413}
414
415QuaZip::CaseSensitivity QuaZipFile::getCaseSensitivity() const
416{
417  return p->caseSensitivity;
418}
419
420bool QuaZipFile::isRaw() const
421{
422  return p->raw;
423}
424
425int QuaZipFile::getZipError() const
426{
427  return p->zipError;
428}