summaryrefslogtreecommitdiff
path: root/utils/rbutilqt/quazip/quazipfile.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'utils/rbutilqt/quazip/quazipfile.cpp')
-rw-r--r--utils/rbutilqt/quazip/quazipfile.cpp570
1 files changed, 570 insertions, 0 deletions
diff --git a/utils/rbutilqt/quazip/quazipfile.cpp b/utils/rbutilqt/quazip/quazipfile.cpp
new file mode 100644
index 0000000000..b984de7279
--- /dev/null
+++ b/utils/rbutilqt/quazip/quazipfile.cpp
@@ -0,0 +1,570 @@
1/*
2Copyright (C) 2005-2014 Sergey A. Tachenov
3
4This file is part of QuaZIP.
5
6QuaZIP is free software: you can redistribute it and/or modify
7it under the terms of the GNU Lesser General Public License as published by
8the Free Software Foundation, either version 2.1 of the License, or
9(at your option) any later version.
10
11QuaZIP is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU Lesser General Public License for more details.
15
16You should have received a copy of the GNU Lesser General Public License
17along with QuaZIP. If not, see <http://www.gnu.org/licenses/>.
18
19See COPYING file for the full LGPL text.
20
21Original ZIP package is copyrighted by Gilles Vollant, see
22quazip/(un)zip.h files for details, basically it's zlib license.
23 **/
24
25#include "quazipfile.h"
26
27#include "quazipfileinfo.h"
28
29using namespace std;
30
31#define QUAZIP_VERSION_MADE_BY 0x1Eu
32
33/// The implementation class for QuaZip.
34/**
35\internal
36
37This class contains all the private stuff for the QuaZipFile class, thus
38allowing to preserve binary compatibility between releases, the
39technique known as the Pimpl (private implementation) idiom.
40*/
41class QuaZipFilePrivate {
42 friend class QuaZipFile;
43 private:
44 Q_DISABLE_COPY(QuaZipFilePrivate)
45 /// The pointer to the associated QuaZipFile instance.
46 QuaZipFile *q;
47 /// The QuaZip object to work with.
48 QuaZip *zip;
49 /// The file name.
50 QString fileName;
51 /// Case sensitivity mode.
52 QuaZip::CaseSensitivity caseSensitivity;
53 /// Whether this file is opened in the raw mode.
54 bool raw;
55 /// Write position to keep track of.
56 /**
57 QIODevice::pos() is broken for non-seekable devices, so we need
58 our own position.
59 */
60 qint64 writePos;
61 /// Uncompressed size to write along with a raw file.
62 quint64 uncompressedSize;
63 /// CRC to write along with a raw file.
64 quint32 crc;
65 /// Whether \ref zip points to an internal QuaZip instance.
66 /**
67 This is true if the archive was opened by name, rather than by
68 supplying an existing QuaZip instance.
69 */
70 bool internal;
71 /// The last error.
72 int zipError;
73 /// Resets \ref zipError.
74 inline void resetZipError() const {setZipError(UNZ_OK);}
75 /// Sets the zip error.
76 /**
77 This function is marked as const although it changes one field.
78 This allows to call it from const functions that don't change
79 anything by themselves.
80 */
81 void setZipError(int zipError) const;
82 /// The constructor for the corresponding QuaZipFile constructor.
83 inline QuaZipFilePrivate(QuaZipFile *q):
84 q(q),
85 zip(NULL),
86 caseSensitivity(QuaZip::csDefault),
87 raw(false),
88 writePos(0),
89 uncompressedSize(0),
90 crc(0),
91 internal(true),
92 zipError(UNZ_OK) {}
93 /// The constructor for the corresponding QuaZipFile constructor.
94 inline QuaZipFilePrivate(QuaZipFile *q, const QString &zipName):
95 q(q),
96 caseSensitivity(QuaZip::csDefault),
97 raw(false),
98 writePos(0),
99 uncompressedSize(0),
100 crc(0),
101 internal(true),
102 zipError(UNZ_OK)
103 {
104 zip=new QuaZip(zipName);
105 }
106 /// The constructor for the corresponding QuaZipFile constructor.
107 inline QuaZipFilePrivate(QuaZipFile *q, const QString &zipName, const QString &fileName,
108 QuaZip::CaseSensitivity cs):
109 q(q),
110 raw(false),
111 writePos(0),
112 uncompressedSize(0),
113 crc(0),
114 internal(true),
115 zipError(UNZ_OK)
116 {
117 zip=new QuaZip(zipName);
118 this->fileName=fileName;
119 if (this->fileName.startsWith(QLatin1String("/")))
120 this->fileName = this->fileName.mid(1);
121 this->caseSensitivity=cs;
122 }
123 /// The constructor for the QuaZipFile constructor accepting a file name.
124 inline QuaZipFilePrivate(QuaZipFile *q, QuaZip *zip):
125 q(q),
126 zip(zip),
127 raw(false),
128 writePos(0),
129 uncompressedSize(0),
130 crc(0),
131 internal(false),
132 zipError(UNZ_OK) {}
133 /// The destructor.
134 inline ~QuaZipFilePrivate()
135 {
136 if (internal)
137 delete zip;
138 }
139};
140
141QuaZipFile::QuaZipFile():
142 p(new QuaZipFilePrivate(this))
143{
144}
145
146QuaZipFile::QuaZipFile(QObject *parent):
147 QIODevice(parent),
148 p(new QuaZipFilePrivate(this))
149{
150}
151
152QuaZipFile::QuaZipFile(const QString& zipName, QObject *parent):
153 QIODevice(parent),
154 p(new QuaZipFilePrivate(this, zipName))
155{
156}
157
158QuaZipFile::QuaZipFile(const QString& zipName, const QString& fileName,
159 QuaZip::CaseSensitivity cs, QObject *parent):
160 QIODevice(parent),
161 p(new QuaZipFilePrivate(this, zipName, fileName, cs))
162{
163}
164
165QuaZipFile::QuaZipFile(QuaZip *zip, QObject *parent):
166 QIODevice(parent),
167 p(new QuaZipFilePrivate(this, zip))
168{
169}
170
171QuaZipFile::~QuaZipFile()
172{
173 if (isOpen())
174 close();
175 delete p;
176}
177
178QString QuaZipFile::getZipName() const
179{
180 return p->zip==NULL ? QString() : p->zip->getZipName();
181}
182
183QuaZip *QuaZipFile::getZip() const
184{
185 return p->internal ? NULL : p->zip;
186}
187
188QString QuaZipFile::getActualFileName()const
189{
190 p->setZipError(UNZ_OK);
191 if (p->zip == NULL || (openMode() & WriteOnly))
192 return QString();
193 QString name=p->zip->getCurrentFileName();
194 if(name.isNull())
195 p->setZipError(p->zip->getZipError());
196 return name;
197}
198
199void QuaZipFile::setZipName(const QString& zipName)
200{
201 if(isOpen()) {
202 qWarning("QuaZipFile::setZipName(): file is already open - can not set ZIP name");
203 return;
204 }
205 if(p->zip!=NULL && p->internal)
206 delete p->zip;
207 p->zip=new QuaZip(zipName);
208 p->internal=true;
209}
210
211void QuaZipFile::setZip(QuaZip *zip)
212{
213 if(isOpen()) {
214 qWarning("QuaZipFile::setZip(): file is already open - can not set ZIP");
215 return;
216 }
217 if(p->zip!=NULL && p->internal)
218 delete p->zip;
219 p->zip=zip;
220 p->fileName=QString();
221 p->internal=false;
222}
223
224void QuaZipFile::setFileName(const QString& fileName, QuaZip::CaseSensitivity cs)
225{
226 if(p->zip==NULL) {
227 qWarning("QuaZipFile::setFileName(): call setZipName() first");
228 return;
229 }
230 if(!p->internal) {
231 qWarning("QuaZipFile::setFileName(): should not be used when not using internal QuaZip");
232 return;
233 }
234 if(isOpen()) {
235 qWarning("QuaZipFile::setFileName(): can not set file name for already opened file");
236 return;
237 }
238 p->fileName=fileName;
239 if (p->fileName.startsWith(QLatin1String("/")))
240 p->fileName = p->fileName.mid(1);
241 p->caseSensitivity=cs;
242}
243
244void QuaZipFilePrivate::setZipError(int zipError) const
245{
246 QuaZipFilePrivate *fakeThis = const_cast<QuaZipFilePrivate*>(this); // non-const
247 fakeThis->zipError=zipError;
248 if(zipError==UNZ_OK)
249 q->setErrorString(QString());
250 else
251 q->setErrorString(QuaZipFile::tr("ZIP/UNZIP API error %1").arg(zipError));
252}
253
254bool QuaZipFile::open(OpenMode mode)
255{
256 return open(mode, NULL);
257}
258
259bool QuaZipFile::open(OpenMode mode, int *method, int *level, bool raw, const char *password)
260{
261 p->resetZipError();
262 if(isOpen()) {
263 qWarning("QuaZipFile::open(): already opened");
264 return false;
265 }
266 if(mode&Unbuffered) {
267 qWarning("QuaZipFile::open(): Unbuffered mode is not supported");
268 return false;
269 }
270 if((mode&ReadOnly)&&!(mode&WriteOnly)) {
271 if(p->internal) {
272 if(!p->zip->open(QuaZip::mdUnzip)) {
273 p->setZipError(p->zip->getZipError());
274 return false;
275 }
276 if(!p->zip->setCurrentFile(p->fileName, p->caseSensitivity)) {
277 p->setZipError(p->zip->getZipError());
278 p->zip->close();
279 return false;
280 }
281 } else {
282 if(p->zip==NULL) {
283 qWarning("QuaZipFile::open(): zip is NULL");
284 return false;
285 }
286 if(p->zip->getMode()!=QuaZip::mdUnzip) {
287 qWarning("QuaZipFile::open(): file open mode %d incompatible with ZIP open mode %d",
288 (int)mode, (int)p->zip->getMode());
289 return false;
290 }
291 if(!p->zip->hasCurrentFile()) {
292 qWarning("QuaZipFile::open(): zip does not have current file");
293 return false;
294 }
295 }
296 p->setZipError(unzOpenCurrentFile3(p->zip->getUnzFile(), method, level, (int)raw, password));
297 if(p->zipError==UNZ_OK) {
298 setOpenMode(mode);
299 p->raw=raw;
300 return true;
301 } else
302 return false;
303 }
304 qWarning("QuaZipFile::open(): open mode %d not supported by this function", (int)mode);
305 return false;
306}
307
308bool QuaZipFile::open(OpenMode mode, const QuaZipNewInfo& info,
309 const char *password, quint32 crc,
310 int method, int level, bool raw,
311 int windowBits, int memLevel, int strategy)
312{
313 zip_fileinfo info_z;
314 p->resetZipError();
315 if(isOpen()) {
316 qWarning("QuaZipFile::open(): already opened");
317 return false;
318 }
319 if((mode&WriteOnly)&&!(mode&ReadOnly)) {
320 if(p->internal) {
321 qWarning("QuaZipFile::open(): write mode is incompatible with internal QuaZip approach");
322 return false;
323 }
324 if(p->zip==NULL) {
325 qWarning("QuaZipFile::open(): zip is NULL");
326 return false;
327 }
328 if(p->zip->getMode()!=QuaZip::mdCreate&&p->zip->getMode()!=QuaZip::mdAppend&&p->zip->getMode()!=QuaZip::mdAdd) {
329 qWarning("QuaZipFile::open(): file open mode %d incompatible with ZIP open mode %d",
330 (int)mode, (int)p->zip->getMode());
331 return false;
332 }
333 info_z.tmz_date.tm_year=info.dateTime.date().year();
334 info_z.tmz_date.tm_mon=info.dateTime.date().month() - 1;
335 info_z.tmz_date.tm_mday=info.dateTime.date().day();
336 info_z.tmz_date.tm_hour=info.dateTime.time().hour();
337 info_z.tmz_date.tm_min=info.dateTime.time().minute();
338 info_z.tmz_date.tm_sec=info.dateTime.time().second();
339 info_z.dosDate = 0;
340 info_z.internal_fa=(uLong)info.internalAttr;
341 info_z.external_fa=(uLong)info.externalAttr;
342 if (p->zip->isDataDescriptorWritingEnabled())
343 zipSetFlags(p->zip->getZipFile(), ZIP_WRITE_DATA_DESCRIPTOR);
344 else
345 zipClearFlags(p->zip->getZipFile(), ZIP_WRITE_DATA_DESCRIPTOR);
346 p->setZipError(zipOpenNewFileInZip4_64(p->zip->getZipFile(),
347 p->zip->isUtf8Enabled()
348 ? info.name.toUtf8().constData()
349 : p->zip->getFileNameCodec()->fromUnicode(info.name).constData(),
350 &info_z,
351 info.extraLocal.constData(), info.extraLocal.length(),
352 info.extraGlobal.constData(), info.extraGlobal.length(),
353 p->zip->isUtf8Enabled()
354 ? info.comment.toUtf8().constData()
355 : p->zip->getCommentCodec()->fromUnicode(info.comment).constData(),
356 method, level, (int)raw,
357 windowBits, memLevel, strategy,
358 password, (uLong)crc,
359 (p->zip->getOsCode() << 8) | QUAZIP_VERSION_MADE_BY,
360 0,
361 p->zip->isZip64Enabled()));
362 if(p->zipError==UNZ_OK) {
363 p->writePos=0;
364 setOpenMode(mode);
365 p->raw=raw;
366 if(raw) {
367 p->crc=crc;
368 p->uncompressedSize=info.uncompressedSize;
369 }
370 return true;
371 } else
372 return false;
373 }
374 qWarning("QuaZipFile::open(): open mode %d not supported by this function", (int)mode);
375 return false;
376}
377
378bool QuaZipFile::isSequential()const
379{
380 return true;
381}
382
383qint64 QuaZipFile::pos()const
384{
385 if(p->zip==NULL) {
386 qWarning("QuaZipFile::pos(): call setZipName() or setZip() first");
387 return -1;
388 }
389 if(!isOpen()) {
390 qWarning("QuaZipFile::pos(): file is not open");
391 return -1;
392 }
393 if(openMode()&ReadOnly)
394 // QIODevice::pos() is broken for sequential devices,
395 // but thankfully bytesAvailable() returns the number of
396 // bytes buffered, so we know how far ahead we are.
397 return unztell64(p->zip->getUnzFile()) - QIODevice::bytesAvailable();
398 else
399 return p->writePos;
400}
401
402bool QuaZipFile::atEnd()const
403{
404 if(p->zip==NULL) {
405 qWarning("QuaZipFile::atEnd(): call setZipName() or setZip() first");
406 return false;
407 }
408 if(!isOpen()) {
409 qWarning("QuaZipFile::atEnd(): file is not open");
410 return false;
411 }
412 if(openMode()&ReadOnly)
413 // the same problem as with pos()
414 return QIODevice::bytesAvailable() == 0
415 && unzeof(p->zip->getUnzFile())==1;
416 else
417 return true;
418}
419
420qint64 QuaZipFile::size()const
421{
422 if(!isOpen()) {
423 qWarning("QuaZipFile::atEnd(): file is not open");
424 return -1;
425 }
426 if(openMode()&ReadOnly)
427 return p->raw?csize():usize();
428 else
429 return p->writePos;
430}
431
432qint64 QuaZipFile::csize()const
433{
434 unz_file_info64 info_z;
435 p->setZipError(UNZ_OK);
436 if(p->zip==NULL||p->zip->getMode()!=QuaZip::mdUnzip) return -1;
437 p->setZipError(unzGetCurrentFileInfo64(p->zip->getUnzFile(), &info_z, NULL, 0, NULL, 0, NULL, 0));
438 if(p->zipError!=UNZ_OK)
439 return -1;
440 return info_z.compressed_size;
441}
442
443qint64 QuaZipFile::usize()const
444{
445 unz_file_info64 info_z;
446 p->setZipError(UNZ_OK);
447 if(p->zip==NULL||p->zip->getMode()!=QuaZip::mdUnzip) return -1;
448 p->setZipError(unzGetCurrentFileInfo64(p->zip->getUnzFile(), &info_z, NULL, 0, NULL, 0, NULL, 0));
449 if(p->zipError!=UNZ_OK)
450 return -1;
451 return info_z.uncompressed_size;
452}
453
454bool QuaZipFile::getFileInfo(QuaZipFileInfo *info)
455{
456 QuaZipFileInfo64 info64;
457 if (getFileInfo(&info64)) {
458 info64.toQuaZipFileInfo(*info);
459 return true;
460 } else {
461 return false;
462 }
463}
464
465bool QuaZipFile::getFileInfo(QuaZipFileInfo64 *info)
466{
467 if(p->zip==NULL||p->zip->getMode()!=QuaZip::mdUnzip) return false;
468 p->zip->getCurrentFileInfo(info);
469 p->setZipError(p->zip->getZipError());
470 return p->zipError==UNZ_OK;
471}
472
473void QuaZipFile::close()
474{
475 p->resetZipError();
476 if(p->zip==NULL||!p->zip->isOpen()) return;
477 if(!isOpen()) {
478 qWarning("QuaZipFile::close(): file isn't open");
479 return;
480 }
481 if(openMode()&ReadOnly)
482 p->setZipError(unzCloseCurrentFile(p->zip->getUnzFile()));
483 else if(openMode()&WriteOnly)
484 if(isRaw()) p->setZipError(zipCloseFileInZipRaw64(p->zip->getZipFile(), p->uncompressedSize, p->crc));
485 else p->setZipError(zipCloseFileInZip(p->zip->getZipFile()));
486 else {
487 qWarning("Wrong open mode: %d", (int)openMode());
488 return;
489 }
490 if(p->zipError==UNZ_OK) setOpenMode(QIODevice::NotOpen);
491 else return;
492 if(p->internal) {
493 p->zip->close();
494 p->setZipError(p->zip->getZipError());
495 }
496}
497
498qint64 QuaZipFile::readData(char *data, qint64 maxSize)
499{
500 p->setZipError(UNZ_OK);
501 qint64 bytesRead=unzReadCurrentFile(p->zip->getUnzFile(), data, (unsigned)maxSize);
502 if (bytesRead < 0) {
503 p->setZipError((int) bytesRead);
504 return -1;
505 }
506 return bytesRead;
507}
508
509qint64 QuaZipFile::writeData(const char* data, qint64 maxSize)
510{
511 p->setZipError(ZIP_OK);
512 p->setZipError(zipWriteInFileInZip(p->zip->getZipFile(), data, (uint)maxSize));
513 if(p->zipError!=ZIP_OK) return -1;
514 else {
515 p->writePos+=maxSize;
516 return maxSize;
517 }
518}
519
520QString QuaZipFile::getFileName() const
521{
522 return p->fileName;
523}
524
525QuaZip::CaseSensitivity QuaZipFile::getCaseSensitivity() const
526{
527 return p->caseSensitivity;
528}
529
530bool QuaZipFile::isRaw() const
531{
532 return p->raw;
533}
534
535int QuaZipFile::getZipError() const
536{
537 return p->zipError;
538}
539
540qint64 QuaZipFile::bytesAvailable() const
541{
542 return size() - pos();
543}
544
545QByteArray QuaZipFile::getLocalExtraField()
546{
547 int size = unzGetLocalExtrafield(p->zip->getUnzFile(), NULL, 0);
548 QByteArray extra(size, '\0');
549 int err = unzGetLocalExtrafield(p->zip->getUnzFile(), extra.data(), static_cast<uint>(extra.size()));
550 if (err < 0) {
551 p->setZipError(err);
552 return QByteArray();
553 }
554 return extra;
555}
556
557QDateTime QuaZipFile::getExtModTime()
558{
559 return QuaZipFileInfo64::getExtTime(getLocalExtraField(), QUAZIP_EXTRA_EXT_MOD_TIME_FLAG);
560}
561
562QDateTime QuaZipFile::getExtAcTime()
563{
564 return QuaZipFileInfo64::getExtTime(getLocalExtraField(), QUAZIP_EXTRA_EXT_AC_TIME_FLAG);
565}
566
567QDateTime QuaZipFile::getExtCrTime()
568{
569 return QuaZipFileInfo64::getExtTime(getLocalExtraField(), QUAZIP_EXTRA_EXT_CR_TIME_FLAG);
570}