FFSM++ 1.1.0
French Forest Sector Model ++
Loading...
Searching...
No Matches
unzip.cpp
Go to the documentation of this file.
1/****************************************************************************
2** Filename: unzip.cpp
3** Last updated [dd/mm/yyyy]: 28/01/2007
4**
5** pkzip 2.0 decompression.
6**
7** Some of the code has been inspired by other open source projects,
8** (mainly Info-Zip and Gilles Vollant's minizip).
9** Compression and decompression actually uses the zlib library.
10**
11** Copyright (C) 2007 Angius Fabrizio. All rights reserved.
12**
13** This file is part of the OSDaB project (http://osdab.sourceforge.net/).
14**
15** This file may be distributed and/or modified under the terms of the
16** GNU General Public License version 2 as published by the Free Software
17** Foundation and appearing in the file LICENSE.GPL included in the
18** packaging of this file.
19**
20** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
21** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
22**
23** See the file LICENSE.GPL that came with this software distribution or
24** visit http://www.gnu.org/copyleft/gpl.html for GPL licensing information.
25**
26**********************************************************************/
27
28#include "unzip.h"
29#include "unzip_p.h"
30#include "zipentry_p.h"
31
32#include <QString>
33#include <QStringList>
34#include <QDir>
35#include <QFile>
36#include <QCoreApplication>
37
38// You can remove this #include if you replace the qDebug() statements.
39#include <QtDebug>
40
41/*!
42 \class UnZip unzip.h
43
44 \brief PKZip 2.0 file decompression.
45 Compatibility with later versions is not ensured as they may use
46 unsupported compression algorithms.
47 Versions after 2.7 may have an incompatible header format and thus be
48 completely incompatible.
49*/
50
51/*! \enum UnZip::ErrorCode The result of a decompression operation.
52 \value UnZip::Ok No error occurred.
53 \value UnZip::ZlibInit Failed to init or load the zlib library.
54 \value UnZip::ZlibError The zlib library returned some error.
55 \value UnZip::OpenFailed Unable to create or open a device.
56 \value UnZip::PartiallyCorrupted Corrupted zip archive - some files could be extracted.
57 \value UnZip::Corrupted Corrupted or invalid zip archive.
58 \value UnZip::WrongPassword Unable to decrypt a password protected file.
59 \value UnZip::NoOpenArchive No archive has been opened yet.
60 \value UnZip::FileNotFound Unable to find the requested file in the archive.
61 \value UnZip::ReadFailed Reading of a file failed.
62 \value UnZip::WriteFailed Writing of a file failed.
63 \value UnZip::SeekFailed Seek failed.
64 \value UnZip::CreateDirFailed Could not create a directory.
65 \value UnZip::InvalidDevice A null device has been passed as parameter.
66 \value UnZip::InvalidArchive This is not a valid (or supported) ZIP archive.
67 \value UnZip::HeaderConsistencyError Local header record info does not match with the central directory record info. The archive may be corrupted.
68
69 \value UnZip::Skip Internal use only.
70 \value UnZip::SkipAll Internal use only.
71*/
72
73/*! \enum UnZip::ExtractionOptions Some options for the file extraction methods.
74 \value UnZip::ExtractPaths Default. Does not ignore the path of the zipped files.
75 \value UnZip::SkipPaths Default. Ignores the path of the zipped files and extracts them all to the same root directory.
76*/
77
78//! Local header size (excluding signature, excluding variable length fields)
79#define UNZIP_LOCAL_HEADER_SIZE 26
80//! Central Directory file entry size (excluding signature, excluding variable length fields)
81#define UNZIP_CD_ENTRY_SIZE_NS 42
82//! Data descriptor size (excluding signature)
83#define UNZIP_DD_SIZE 12
84//! End Of Central Directory size (including signature, excluding variable length fields)
85#define UNZIP_EOCD_SIZE 22
86//! Local header entry encryption header size
87#define UNZIP_LOCAL_ENC_HEADER_SIZE 12
88
89// Some offsets inside a CD record (excluding signature)
90#define UNZIP_CD_OFF_VERSION 0
91#define UNZIP_CD_OFF_GPFLAG 4
92#define UNZIP_CD_OFF_CMETHOD 6
93#define UNZIP_CD_OFF_MODT 8
94#define UNZIP_CD_OFF_MODD 10
95#define UNZIP_CD_OFF_CRC32 12
96#define UNZIP_CD_OFF_CSIZE 16
97#define UNZIP_CD_OFF_USIZE 20
98#define UNZIP_CD_OFF_NAMELEN 24
99#define UNZIP_CD_OFF_XLEN 26
100#define UNZIP_CD_OFF_COMMLEN 28
101#define UNZIP_CD_OFF_LHOFFSET 38
102
103// Some offsets inside a local header record (excluding signature)
104#define UNZIP_LH_OFF_VERSION 0
105#define UNZIP_LH_OFF_GPFLAG 2
106#define UNZIP_LH_OFF_CMETHOD 4
107#define UNZIP_LH_OFF_MODT 6
108#define UNZIP_LH_OFF_MODD 8
109#define UNZIP_LH_OFF_CRC32 10
110#define UNZIP_LH_OFF_CSIZE 14
111#define UNZIP_LH_OFF_USIZE 18
112#define UNZIP_LH_OFF_NAMELEN 22
113#define UNZIP_LH_OFF_XLEN 24
114
115// Some offsets inside a data descriptor record (excluding signature)
116#define UNZIP_DD_OFF_CRC32 0
117#define UNZIP_DD_OFF_CSIZE 4
118#define UNZIP_DD_OFF_USIZE 8
119
120// Some offsets inside a EOCD record
121#define UNZIP_EOCD_OFF_ENTRIES 6
122#define UNZIP_EOCD_OFF_CDOFF 12
123#define UNZIP_EOCD_OFF_COMMLEN 16
124
125/*!
126 Max version handled by this API.
127 0x1B = 2.7 --> full compatibility only up to version 2.0 (0x14)
128 versions from 2.1 to 2.7 may use unsupported compression methods
129 versions after 2.7 may have an incompatible header format
130*/
131#define UNZIP_VERSION 0x1B
132//! Full compatibility granted until this version
133#define UNZIP_VERSION_STRICT 0x14
134
135//! CRC32 routine
136#define CRC32(c, b) crcTable[((int)c^b) & 0xff] ^ (c >> 8)
137
138//! Checks if some file has been already extracted.
139#define UNZIP_CHECK_FOR_VALID_DATA \
140 {\
141 if (headers != 0)\
142 {\
143 qDebug() << "Corrupted zip archive. Some files might be extracted.";\
144 ec = headers->size() != 0 ? UnZip::PartiallyCorrupted : UnZip::Corrupted;\
145 break;\
146 }\
147 else\
148 {\
149 delete device;\
150 device = 0;\
151 qDebug() << "Corrupted or invalid zip archive";\
152 ec = UnZip::Corrupted;\
153 break;\
154 }\
155 }
156
157
158/************************************************************************
159 Public interface
160*************************************************************************/
161
162/*!
163 Creates a new Zip file decompressor.
164*/
166{
167 d = new UnzipPrivate;
168}
169
170/*!
171 Closes any open archive and releases used resources.
172*/
174{
175 closeArchive();
176 delete d;
177}
178
179/*!
180 Returns true if there is an open archive.
181*/
182bool UnZip::isOpen() const
183{
184 return d->device != 0;
185}
186
187/*!
188 Opens a zip archive and reads the files list. Closes any previously opened archive.
189*/
190UnZip::ErrorCode UnZip::openArchive(const QString& filename)
191{
192 QFile* file = new QFile(filename);
193
194 if (!file->exists()) {
195 delete file;
196 return UnZip::FileNotFound;
197 }
198
199 if (!file->open(QIODevice::ReadOnly)) {
200 delete file;
201 return UnZip::OpenFailed;
202 }
203
204 return openArchive(file);
205}
206
207/*!
208 Opens a zip archive and reads the entries list.
209 Closes any previously opened archive.
210 \warning The class takes ownership of the device so don't delete it!
211*/
213{
214 if (device == 0)
215 {
216 qDebug() << "Invalid device.";
218 }
219
220 return d->openArchive(device);
221}
222
223/*!
224 Closes the archive and releases all the used resources (like cached passwords).
225*/
227{
228 d->closeArchive();
229}
230
232{
233 if (d->device == 0)
234 return QString();
235 return d->comment;
236}
237
238/*!
239 Returns a locale translated error string for a given error code.
240*/
242{
243 switch (c)
244 {
245 case Ok: return QCoreApplication::translate("UnZip", "ZIP operation completed successfully."); break;
246 case ZlibInit: return QCoreApplication::translate("UnZip", "Failed to initialize or load zlib library."); break;
247 case ZlibError: return QCoreApplication::translate("UnZip", "zlib library error."); break;
248 case OpenFailed: return QCoreApplication::translate("UnZip", "Unable to create or open file."); break;
249 case PartiallyCorrupted: return QCoreApplication::translate("UnZip", "Partially corrupted archive. Some files might be extracted."); break;
250 case Corrupted: return QCoreApplication::translate("UnZip", "Corrupted archive."); break;
251 case WrongPassword: return QCoreApplication::translate("UnZip", "Wrong password."); break;
252 case NoOpenArchive: return QCoreApplication::translate("UnZip", "No archive has been created yet."); break;
253 case FileNotFound: return QCoreApplication::translate("UnZip", "File or directory does not exist."); break;
254 case ReadFailed: return QCoreApplication::translate("UnZip", "File read error."); break;
255 case WriteFailed: return QCoreApplication::translate("UnZip", "File write error."); break;
256 case SeekFailed: return QCoreApplication::translate("UnZip", "File seek error."); break;
257 case CreateDirFailed: return QCoreApplication::translate("UnZip", "Unable to create a directory."); break;
258 case InvalidDevice: return QCoreApplication::translate("UnZip", "Invalid device."); break;
259 case InvalidArchive: return QCoreApplication::translate("UnZip", "Invalid or incompatible zip archive."); break;
260 case HeaderConsistencyError: return QCoreApplication::translate("UnZip", "Inconsistent headers. Archive might be corrupted."); break;
261 default: ;
262 }
263
264 return QCoreApplication::translate("UnZip", "Unknown error.");
265}
266
267/*!
268 Returns true if the archive contains a file with the given path and name.
269*/
270bool UnZip::contains(const QString& file) const
271{
272 if (d->headers == 0)
273 return false;
274
275 return d->headers->contains(file);
276}
277
278/*!
279 Returns complete paths of files and directories in this archive.
280*/
281QStringList UnZip::fileList() const
282{
283 return d->headers == 0 ? QStringList() : d->headers->keys();
284}
285
286/*!
287 Returns information for each (correctly parsed) entry of this archive.
288*/
289QList<UnZip::ZipEntry> UnZip::entryList() const
290{
291 QList<UnZip::ZipEntry> list;
292
293 if (d->headers != 0)
294 {
295 for (QMap<QString,ZipEntryP*>::ConstIterator it = d->headers->constBegin(); it != d->headers->constEnd(); ++it)
296 {
297 const ZipEntryP* entry = it.value();
298 Q_ASSERT(entry != 0);
299
300 ZipEntry z;
301
302 z.filename = it.key();
303 if (!entry->comment.isEmpty())
304 z.comment = entry->comment;
305 z.compressedSize = entry->szComp;
306 z.uncompressedSize = entry->szUncomp;
307 z.crc32 = entry->crc;
308 z.lastModified = d->convertDateTime(entry->modDate, entry->modTime);
309
310 z.compression = entry->compMethod == 0 ? NoCompression : entry->compMethod == 8 ? Deflated : UnknownCompression;
311 z.type = z.filename.endsWith("/") ? Directory : File;
312
313 z.encrypted = entry->isEncrypted();
314
315 list.append(z);
316 }
317 }
318
319 return list;
320}
321
322/*!
323 Extracts the whole archive to a directory.
324*/
325UnZip::ErrorCode UnZip::extractAll(const QString& dirname, ExtractionOptions options)
326{
327 return extractAll(QDir(dirname), options);
328}
329
330/*!
331 Extracts the whole archive to a directory.
332*/
333UnZip::ErrorCode UnZip::extractAll(const QDir& dir, ExtractionOptions options)
334{
335 // this should only happen if we didn't call openArchive() yet
336 if (d->device == 0)
337 return NoOpenArchive;
338
339 if (d->headers == 0)
340 return Ok;
341
342 bool end = false;
343 for (QMap<QString,ZipEntryP*>::Iterator itr = d->headers->begin(); itr != d->headers->end(); ++itr)
344 {
345 ZipEntryP* entry = itr.value();
346 Q_ASSERT(entry != 0);
347
348 if ((entry->isEncrypted()) && d->skipAllEncrypted)
349 continue;
350
351 switch (d->extractFile(itr.key(), *entry, dir, options))
352 {
353 case Corrupted:
354 qDebug() << "Removing corrupted entry" << itr.key();
355 d->headers->erase(itr++);
356 if (itr == d->headers->end())
357 end = true;
358 break;
359 case CreateDirFailed:
360 break;
361 case Skip:
362 break;
363 case SkipAll:
364 d->skipAllEncrypted = true;
365 break;
366 default:
367 ;
368 }
369
370 if (end)
371 break;
372 }
373
374 return Ok;
375}
376
377/*!
378 Extracts a single file to a directory.
379*/
380UnZip::ErrorCode UnZip::extractFile(const QString& filename, const QString& dirname, ExtractionOptions options)
381{
382 return extractFile(filename, QDir(dirname), options);
383}
384
385/*!
386 Extracts a single file to a directory.
387*/
388UnZip::ErrorCode UnZip::extractFile(const QString& filename, const QDir& dir, ExtractionOptions options)
389{
390 QMap<QString,ZipEntryP*>::Iterator itr = d->headers->find(filename);
391 if (itr != d->headers->end())
392 {
393 ZipEntryP* entry = itr.value();
394 Q_ASSERT(entry != 0);
395 return d->extractFile(itr.key(), *entry, dir, options);
396 }
397
398 return FileNotFound;
399}
400
401/*!
402 Extracts a single file to a directory.
403*/
404UnZip::ErrorCode UnZip::extractFile(const QString& filename, QIODevice* dev, ExtractionOptions options)
405{
406 if (dev == 0)
407 return InvalidDevice;
408
409 QMap<QString,ZipEntryP*>::Iterator itr = d->headers->find(filename);
410 if (itr != d->headers->end()) {
411 ZipEntryP* entry = itr.value();
412 Q_ASSERT(entry != 0);
413 return d->extractFile(itr.key(), *entry, dev, options);
414 }
415
416 return FileNotFound;
417}
418
419/*!
420 Extracts a list of files.
421 Stops extraction at the first error (but continues if a file does not exist in the archive).
422 */
423UnZip::ErrorCode UnZip::extractFiles(const QStringList& filenames, const QString& dirname, ExtractionOptions options)
424{
425 QDir dir(dirname);
426 ErrorCode ec;
427
428 for (QStringList::ConstIterator itr = filenames.constBegin(); itr != filenames.constEnd(); ++itr)
429 {
430 ec = extractFile(*itr, dir, options);
431 if (ec == FileNotFound)
432 continue;
433 if (ec != Ok)
434 return ec;
435 }
436
437 return Ok;
438}
439
440/*!
441 Extracts a list of files.
442 Stops extraction at the first error (but continues if a file does not exist in the archive).
443 */
444UnZip::ErrorCode UnZip::extractFiles(const QStringList& filenames, const QDir& dir, ExtractionOptions options)
445{
446 ErrorCode ec;
447
448 for (QStringList::ConstIterator itr = filenames.constBegin(); itr != filenames.constEnd(); ++itr)
449 {
450 ec = extractFile(*itr, dir, options);
451 if (ec == FileNotFound)
452 continue;
453 if (ec != Ok)
454 return ec;
455 }
456
457 return Ok;
458}
459
460/*!
461 Remove/replace this method to add your own password retrieval routine.
462*/
463void UnZip::setPassword(const QString& pwd)
464{
465 d->password = pwd;
466}
467
468/*!
469 ZipEntry constructor - initialize data. Type is set to File.
470*/
478
479
480/************************************************************************
481 Private interface
482*************************************************************************/
483
484//! \internal
486{
487 skipAllEncrypted = false;
488 headers = 0;
489 device = 0;
490
491 uBuffer = (unsigned char*) buffer1;
492 crcTable = (quint32*) get_crc_table();
493
494 cdOffset = eocdOffset = 0;
495 cdEntryCount = 0;
496 unsupportedEntryCount = 0;
497}
498
499//! \internal Parses a Zip archive.
501{
502 Q_ASSERT(dev != 0);
503
504 if (device != 0)
505 closeArchive();
506
507 device = dev;
508
509 if (!(device->isOpen() || device->open(QIODevice::ReadOnly)))
510 {
511 delete device;
512 device = 0;
513
514 qDebug() << "Unable to open device for reading";
515 return UnZip::OpenFailed;
516 }
517
519
520 ec = seekToCentralDirectory();
521 if (ec != UnZip::Ok)
522 {
523 closeArchive();
524 return ec;
525 }
526
527 //! \todo Ignore CD entry count? CD may be corrupted.
528 if (cdEntryCount == 0)
529 {
530 return UnZip::Ok;
531 }
532
533 bool continueParsing = true;
534
535 while (continueParsing)
536 {
537 if (device->read(buffer1, 4) != 4)
539
540 if (! (buffer1[0] == 'P' && buffer1[1] == 'K' && buffer1[2] == 0x01 && buffer1[3] == 0x02) )
541 break;
542
543 if ( (ec = parseCentralDirectoryRecord()) != UnZip::Ok )
544 break;
545 }
546
547 if (ec != UnZip::Ok)
548 closeArchive();
549
550 return ec;
551}
552
553/*
554 \internal Parses a local header record and makes some consistency check
555 with the information stored in the Central Directory record for this entry
556 that has been previously parsed.
557 \todo Optional consistency check (as a ExtractionOptions flag)
558
559 local file header signature 4 bytes (0x04034b50)
560 version needed to extract 2 bytes
561 general purpose bit flag 2 bytes
562 compression method 2 bytes
563 last mod file time 2 bytes
564 last mod file date 2 bytes
565 crc-32 4 bytes
566 compressed size 4 bytes
567 uncompressed size 4 bytes
568 file name length 2 bytes
569 extra field length 2 bytes
570
571 file name (variable size)
572 extra field (variable size)
573*/
575{
576 if (!device->seek(entry.lhOffset))
577 return UnZip::SeekFailed;
578
579 // Test signature
580 if (device->read(buffer1, 4) != 4)
581 return UnZip::ReadFailed;
582
583 if ((buffer1[0] != 'P') || (buffer1[1] != 'K') || (buffer1[2] != 0x03) || (buffer1[3] != 0x04))
585
586 if (device->read(buffer1, UNZIP_LOCAL_HEADER_SIZE) != UNZIP_LOCAL_HEADER_SIZE)
587 return UnZip::ReadFailed;
588
589 /*
590 Check 3rd general purpose bit flag.
591
592 "bit 3: If this bit is set, the fields crc-32, compressed size
593 and uncompressed size are set to zero in the local
594 header. The correct values are put in the data descriptor
595 immediately following the compressed data."
596 */
597 bool hasDataDescriptor = entry.hasDataDescriptor();
598
599 bool checkFailed = false;
600
601 if (!checkFailed)
602 checkFailed = entry.compMethod != getUShort(uBuffer, UNZIP_LH_OFF_CMETHOD);
603 if (!checkFailed)
604 checkFailed = entry.gpFlag[0] != uBuffer[UNZIP_LH_OFF_GPFLAG];
605 if (!checkFailed)
606 checkFailed = entry.gpFlag[1] != uBuffer[UNZIP_LH_OFF_GPFLAG + 1];
607 if (!checkFailed)
608 checkFailed = entry.modTime[0] != uBuffer[UNZIP_LH_OFF_MODT];
609 if (!checkFailed)
610 checkFailed = entry.modTime[1] != uBuffer[UNZIP_LH_OFF_MODT + 1];
611 if (!checkFailed)
612 checkFailed = entry.modDate[0] != uBuffer[UNZIP_LH_OFF_MODD];
613 if (!checkFailed)
614 checkFailed = entry.modDate[1] != uBuffer[UNZIP_LH_OFF_MODD + 1];
615 if (!hasDataDescriptor)
616 {
617 if (!checkFailed)
618 checkFailed = entry.crc != getULong(uBuffer, UNZIP_LH_OFF_CRC32);
619 if (!checkFailed)
620 checkFailed = entry.szComp != getULong(uBuffer, UNZIP_LH_OFF_CSIZE);
621 if (!checkFailed)
622 checkFailed = entry.szUncomp != getULong(uBuffer, UNZIP_LH_OFF_USIZE);
623 }
624
625 if (checkFailed)
627
628 // Check filename
629 quint16 szName = getUShort(uBuffer, UNZIP_LH_OFF_NAMELEN);
630 if (szName == 0)
632
633 if (device->read(buffer2, szName) != szName)
634 return UnZip::ReadFailed;
635
636 //QString filename = QString::fromAscii(buffer2, szName); // Qt4
637 QString filename = QString::fromLatin1(buffer2, szName); // Qt5
638 if (filename != path)
639 {
640 qDebug() << "Filename in local header mismatches.";
642 }
643
644 // Skip extra field
645 quint16 szExtra = getUShort(uBuffer, UNZIP_LH_OFF_XLEN);
646 if (szExtra != 0)
647 {
648 if (!device->seek(device->pos() + szExtra))
649 return UnZip::SeekFailed;
650 }
651
652 entry.dataOffset = device->pos();
653
654 if (hasDataDescriptor)
655 {
656 /*
657 The data descriptor has this OPTIONAL signature: PK\7\8
658 We try to skip the compressed data relying on the size set in the
659 Central Directory record.
660 */
661 if (!device->seek(device->pos() + entry.szComp))
662 return UnZip::SeekFailed;
663
664 // Read 4 bytes and check if there is a data descriptor signature
665 if (device->read(buffer2, 4) != 4)
666 return UnZip::ReadFailed;
667
668 bool hasSignature = buffer2[0] == 'P' && buffer2[1] == 'K' && buffer2[2] == 0x07 && buffer2[3] == 0x08;
669 if (hasSignature)
670 {
671 if (device->read(buffer2, UNZIP_DD_SIZE) != UNZIP_DD_SIZE)
672 return UnZip::ReadFailed;
673 }
674 else
675 {
676 if (device->read(buffer2 + 4, UNZIP_DD_SIZE - 4) != UNZIP_DD_SIZE - 4)
677 return UnZip::ReadFailed;
678 }
679
680 // DD: crc, compressed size, uncompressed size
681 if (
682 entry.crc != getULong((unsigned char*)buffer2, UNZIP_DD_OFF_CRC32) ||
683 entry.szComp != getULong((unsigned char*)buffer2, UNZIP_DD_OFF_CSIZE) ||
684 entry.szUncomp != getULong((unsigned char*)buffer2, UNZIP_DD_OFF_USIZE)
685 )
687 }
688
689 return UnZip::Ok;
690}
691
692/*! \internal Attempts to find the start of the central directory record.
693
694 We seek the file back until we reach the "End Of Central Directory"
695 signature PK\5\6.
696
697 end of central dir signature 4 bytes (0x06054b50)
698 number of this disk 2 bytes
699 number of the disk with the
700 start of the central directory 2 bytes
701 total number of entries in the
702 central directory on this disk 2 bytes
703 total number of entries in
704 the central directory 2 bytes
705 size of the central directory 4 bytes
706 offset of start of central
707 directory with respect to
708 the starting disk number 4 bytes
709 .ZIP file comment length 2 bytes
710 --- SIZE UNTIL HERE: UNZIP_EOCD_SIZE ---
711 .ZIP file comment (variable size)
712*/
714{
715 qint64 length = device->size();
716 qint64 offset = length - UNZIP_EOCD_SIZE;
717
718 if (length < UNZIP_EOCD_SIZE)
720
721 if (!device->seek( offset ))
722 return UnZip::SeekFailed;
723
724 if (device->read(buffer1, UNZIP_EOCD_SIZE) != UNZIP_EOCD_SIZE)
725 return UnZip::ReadFailed;
726
727 bool eocdFound = (buffer1[0] == 'P' && buffer1[1] == 'K' && buffer1[2] == 0x05 && buffer1[3] == 0x06);
728
729 if (eocdFound)
730 {
731 // Zip file has no comment (the only variable length field in the EOCD record)
732 eocdOffset = offset;
733 }
734 else
735 {
736 qint64 read;
737 char* p = 0;
738
739 offset -= UNZIP_EOCD_SIZE;
740
741 if (offset <= 0)
743
744 if (!device->seek( offset ))
745 return UnZip::SeekFailed;
746
747 while ((read = device->read(buffer1, UNZIP_EOCD_SIZE)) >= 0)
748 {
749 if ( (p = strstr(buffer1, "PK\5\6")) != 0)
750 {
751 // Seek to the start of the EOCD record so we can read it fully
752 // Yes... we could simply read the missing bytes and append them to the buffer
753 // but this is far easier so heck it!
754 device->seek( offset + (p - buffer1) );
755 eocdFound = true;
756 eocdOffset = offset + (p - buffer1);
757
758 // Read EOCD record
759 if (device->read(buffer1, UNZIP_EOCD_SIZE) != UNZIP_EOCD_SIZE)
760 return UnZip::ReadFailed;
761
762 break;
763 }
764
765 offset -= UNZIP_EOCD_SIZE;
766 if (offset <= 0)
768
769 if (!device->seek( offset ))
770 return UnZip::SeekFailed;
771 }
772 }
773
774 if (!eocdFound)
776
777 // Parse EOCD to locate CD offset
778 offset = getULong((const unsigned char*)buffer1, UNZIP_EOCD_OFF_CDOFF + 4);
779
780 cdOffset = offset;
781
782 cdEntryCount = getUShort((const unsigned char*)buffer1, UNZIP_EOCD_OFF_ENTRIES + 4);
783
784 quint16 commentLength = getUShort((const unsigned char*)buffer1, UNZIP_EOCD_OFF_COMMLEN + 4);
785 if (commentLength != 0)
786 {
787 QByteArray c = device->read(commentLength);
788 if (c.count() != commentLength)
789 return UnZip::ReadFailed;
790
791 comment = c;
792 }
793
794 // Seek to the start of the CD record
795 if (!device->seek( cdOffset ))
796 return UnZip::SeekFailed;
797
798 return UnZip::Ok;
799}
800
801/*!
802 \internal Parses a central directory record.
803
804 Central Directory record structure:
805
806 [file header 1]
807 .
808 .
809 .
810 [file header n]
811 [digital signature] // PKZip 6.2 or later only
812
813 File header:
814
815 central file header signature 4 bytes (0x02014b50)
816 version made by 2 bytes
817 version needed to extract 2 bytes
818 general purpose bit flag 2 bytes
819 compression method 2 bytes
820 last mod file time 2 bytes
821 last mod file date 2 bytes
822 crc-32 4 bytes
823 compressed size 4 bytes
824 uncompressed size 4 bytes
825 file name length 2 bytes
826 extra field length 2 bytes
827 file comment length 2 bytes
828 disk number start 2 bytes
829 internal file attributes 2 bytes
830 external file attributes 4 bytes
831 relative offset of local header 4 bytes
832
833 file name (variable size)
834 extra field (variable size)
835 file comment (variable size)
836*/
838{
839 // Read CD record
840 if (device->read(buffer1, UNZIP_CD_ENTRY_SIZE_NS) != UNZIP_CD_ENTRY_SIZE_NS)
841 return UnZip::ReadFailed;
842
843 bool skipEntry = false;
844
845 // Get compression type so we can skip non compatible algorithms
846 quint16 compMethod = getUShort(uBuffer, UNZIP_CD_OFF_CMETHOD);
847
848 // Get variable size fields length so we can skip the whole record
849 // if necessary
850 quint16 szName = getUShort(uBuffer, UNZIP_CD_OFF_NAMELEN);
851 quint16 szExtra = getUShort(uBuffer, UNZIP_CD_OFF_XLEN);
852 quint16 szComment = getUShort(uBuffer, UNZIP_CD_OFF_COMMLEN);
853
854 quint32 skipLength = szName + szExtra + szComment;
855
857
858 if ((compMethod != 0) && (compMethod != 8))
859 {
860 qDebug() << "Unsupported compression method. Skipping file.";
861 skipEntry = true;
862 }
863
864 // Header parsing may be a problem if version is bigger than UNZIP_VERSION
865 if (!skipEntry && buffer1[UNZIP_CD_OFF_VERSION] > UNZIP_VERSION)
866 {
867 qDebug() << "Unsupported PKZip version. Skipping file.";
868 skipEntry = true;
869 }
870
871 if (!skipEntry && szName == 0)
872 {
873 qDebug() << "Skipping file with no name.";
874 skipEntry = true;
875 }
876
877 if (!skipEntry && device->read(buffer2, szName) != szName)
878 {
880 skipEntry = true;
881 }
882
883 if (skipEntry)
884 {
885 if (ec == UnZip::Ok)
886 {
887 if (!device->seek( device->pos() + skipLength ))
889
890 unsupportedEntryCount++;
891 }
892
893 return ec;
894 }
895
896 //QString filename = QString::fromAscii(buffer2, szName); // Qt4
897 QString filename = QString::fromLatin1(buffer2, szName); // Qt5
898
899 ZipEntryP* h = new ZipEntryP;
900 h->compMethod = compMethod;
901
902 h->gpFlag[0] = buffer1[UNZIP_CD_OFF_GPFLAG];
903 h->gpFlag[1] = buffer1[UNZIP_CD_OFF_GPFLAG + 1];
904
905 h->modTime[0] = buffer1[UNZIP_CD_OFF_MODT];
906 h->modTime[1] = buffer1[UNZIP_CD_OFF_MODT + 1];
907
908 h->modDate[0] = buffer1[UNZIP_CD_OFF_MODD];
909 h->modDate[1] = buffer1[UNZIP_CD_OFF_MODD + 1];
910
911 h->crc = getULong(uBuffer, UNZIP_CD_OFF_CRC32);
912 h->szComp = getULong(uBuffer, UNZIP_CD_OFF_CSIZE);
913 h->szUncomp = getULong(uBuffer, UNZIP_CD_OFF_USIZE);
914
915 // Skip extra field (if any)
916 if (szExtra != 0)
917 {
918 if (!device->seek( device->pos() + szExtra ))
919 {
920 delete h;
921 return UnZip::SeekFailed;
922 }
923 }
924
925 // Read comment field (if any)
926 if (szComment != 0)
927 {
928 if (device->read(buffer2, szComment) != szComment)
929 {
930 delete h;
931 return UnZip::ReadFailed;
932 }
933
934 //h->comment = QString::fromAscii(buffer2, szComment); // Qt4
935 h->comment = QString::fromLatin1(buffer2, szComment); // Qt5
936 }
937
938 h->lhOffset = getULong(uBuffer, UNZIP_CD_OFF_LHOFFSET);
939
940 if (headers == 0)
941 headers = new QMap<QString, ZipEntryP*>();
942 headers->insert(filename, h);
943
944 return UnZip::Ok;
945}
946
947//! \internal Closes the archive and resets the internal status.
949{
950 if (device == 0)
951 return;
952
953 skipAllEncrypted = false;
954
955 if (headers != 0)
956 {
957 qDeleteAll(*headers);
958 delete headers;
959 headers = 0;
960 }
961
962 delete device; device = 0;
963
964 cdOffset = eocdOffset = 0;
965 cdEntryCount = 0;
966 unsupportedEntryCount = 0;
967
968 comment.clear();
969}
970
971//! \internal
972UnZip::ErrorCode UnzipPrivate::extractFile(const QString& path, ZipEntryP& entry, const QDir& dir, UnZip::ExtractionOptions options)
973{
974 QString name(path);
975 QString dirname;
976 QString directory;
977
978 int pos = name.lastIndexOf('/');
979
980 // This entry is for a directory
981 if (pos == name.length() - 1)
982 {
983 if (options.testFlag(UnZip::SkipPaths))
984 return UnZip::Ok;
985
986 directory = QString("%1/%2").arg(dir.absolutePath()).arg(QDir::cleanPath(name));
987 if (!createDirectory(directory))
988 {
989 qDebug() << QString("Unable to create directory: %1").arg(directory);
991 }
992
993 return UnZip::Ok;
994 }
995
996 // Extract path from entry
997 if (pos > 0)
998 {
999 // get directory part
1000 dirname = name.left(pos);
1001 if (options.testFlag(UnZip::SkipPaths))
1002 {
1003 directory = dir.absolutePath();
1004 }
1005 else
1006 {
1007 directory = QString("%1/%2").arg(dir.absolutePath()).arg(QDir::cleanPath(dirname));
1008 if (!createDirectory(directory))
1009 {
1010 qDebug() << QString("Unable to create directory: %1").arg(directory);
1012 }
1013 }
1014 name = name.right(name.length() - pos - 1);
1015 } else directory = dir.absolutePath();
1016
1017 name = QString("%1/%2").arg(directory).arg(name);
1018
1019 QFile outFile(name);
1020
1021 if (!outFile.open(QIODevice::WriteOnly))
1022 {
1023 qDebug() << QString("Unable to open %1 for writing").arg(name);
1024 return UnZip::OpenFailed;
1025 }
1026
1027 //! \todo Set creation/last_modified date/time
1028
1029 UnZip::ErrorCode ec = extractFile(path, entry, &outFile, options);
1030
1031 outFile.close();
1032
1033 if (ec != UnZip::Ok)
1034 {
1035 if (!outFile.remove())
1036 qDebug() << QString("Unable to remove corrupted file: %1").arg(name);
1037 }
1038
1039 return ec;
1040}
1041
1042//! \internal
1043UnZip::ErrorCode UnzipPrivate::extractFile(const QString& path, ZipEntryP& entry, QIODevice* dev, UnZip::ExtractionOptions options)
1044{
1045 Q_UNUSED(options);
1046 Q_ASSERT(dev != 0);
1047
1048 if (!entry.lhEntryChecked)
1049 {
1050 UnZip::ErrorCode ec = parseLocalHeaderRecord(path, entry);
1051 entry.lhEntryChecked = true;
1052
1053 if (ec != UnZip::Ok)
1054 return ec;
1055 }
1056
1057 if (!device->seek(entry.dataOffset))
1058 return UnZip::SeekFailed;
1059
1060 // Encryption keys
1061 quint32 keys[3];
1062
1063 if (entry.isEncrypted())
1064 {
1065 UnZip::ErrorCode e = testPassword(keys, path, entry);
1066 if (e != UnZip::Ok)
1067 {
1068 qDebug() << QString("Unable to decrypt %1").arg(path);
1069 return e;
1070 }//! Encryption header size
1071 entry.szComp -= UNZIP_LOCAL_ENC_HEADER_SIZE; // remove encryption header size
1072 }
1073
1074 if (entry.szComp == 0)
1075 {
1076 if (entry.crc != 0)
1077 return UnZip::Corrupted;
1078
1079 return UnZip::Ok;
1080 }
1081
1082 uInt rep = entry.szComp / UNZIP_READ_BUFFER;
1083 uInt rem = entry.szComp % UNZIP_READ_BUFFER;
1084 uInt cur = 0;
1085
1086 // extract data
1087 qint64 read;
1088 quint64 tot = 0;
1089
1090 quint32 myCRC = crc32(0L, Z_NULL, 0);
1091
1092 if (entry.compMethod == 0)
1093 {
1094 while ( (read = device->read(buffer1, cur < rep ? UNZIP_READ_BUFFER : rem)) > 0 )
1095 {
1096 if (entry.isEncrypted())
1097 decryptBytes(keys, buffer1, read);
1098
1099 myCRC = crc32(myCRC, uBuffer, read);
1100
1101 if (dev->write(buffer1, read) != read)
1102 return UnZip::WriteFailed;
1103
1104 cur++;
1105 tot += read;
1106
1107 if (tot == entry.szComp)
1108 break;
1109 }
1110
1111 if (read < 0)
1112 return UnZip::ReadFailed;
1113 }
1114 else if (entry.compMethod == 8)
1115 {
1116 /* Allocate inflate state */
1117 z_stream zstr;
1118 zstr.zalloc = Z_NULL;
1119 zstr.zfree = Z_NULL;
1120 zstr.opaque = Z_NULL;
1121 zstr.next_in = Z_NULL;
1122 zstr.avail_in = 0;
1123
1124 int zret;
1125
1126 // Use inflateInit2 with negative windowBits to get raw decompression
1127 if ( (zret = inflateInit2_(&zstr, -MAX_WBITS, ZLIB_VERSION, sizeof(z_stream))) != Z_OK )
1128 return UnZip::ZlibError;
1129
1130 int szDecomp;
1131
1132 // Decompress until deflate stream ends or end of file
1133 do
1134 {
1135 read = device->read(buffer1, cur < rep ? UNZIP_READ_BUFFER : rem);
1136 if (read == 0)
1137 break;
1138 if (read < 0)
1139 {
1140 (void)inflateEnd(&zstr);
1141 return UnZip::ReadFailed;
1142 }
1143
1144 if (entry.isEncrypted())
1145 decryptBytes(keys, buffer1, read);
1146
1147 cur++;
1148 tot += read;
1149
1150 zstr.avail_in = (uInt) read;
1151 zstr.next_in = (Bytef*) buffer1;
1152
1153
1154 // Run inflate() on input until output buffer not full
1155 do {
1156 zstr.avail_out = UNZIP_READ_BUFFER;
1157 zstr.next_out = (Bytef*) buffer2;;
1158
1159 zret = inflate(&zstr, Z_NO_FLUSH);
1160
1161 switch (zret) {
1162 case Z_NEED_DICT:
1163 case Z_DATA_ERROR:
1164 case Z_MEM_ERROR:
1165 inflateEnd(&zstr);
1166 return UnZip::WriteFailed;
1167 default:
1168 ;
1169 }
1170
1171 szDecomp = UNZIP_READ_BUFFER - zstr.avail_out;
1172 if (dev->write(buffer2, szDecomp) != szDecomp)
1173 {
1174 inflateEnd(&zstr);
1175 return UnZip::ZlibError;
1176 }
1177
1178 myCRC = crc32(myCRC, (const Bytef*) buffer2, szDecomp);
1179
1180 } while (zstr.avail_out == 0);
1181
1182 }
1183 while (zret != Z_STREAM_END);
1184
1185 inflateEnd(&zstr);
1186 }
1187
1188 if (myCRC != entry.crc)
1189 return UnZip::Corrupted;
1190
1191 return UnZip::Ok;
1192}
1193
1194//! \internal Creates a new directory and all the needed parent directories.
1195bool UnzipPrivate::createDirectory(const QString& path)
1196{
1197 QDir d(path);
1198 if (!d.exists())
1199 {
1200 int sep = path.lastIndexOf("/");
1201 if (sep <= 0) return true;
1202
1203 if (!createDirectory(path.left(sep)))
1204 return false;
1205
1206 if (!d.mkdir(path))
1207 {
1208 qDebug() << QString("Unable to create directory: %1").arg(path);
1209 return false;
1210 }
1211 }
1212
1213 return true;
1214}
1215
1216/*!
1217 \internal Reads an quint32 (4 bytes) from a byte array starting at given offset.
1218*/
1219quint32 UnzipPrivate::getULong(const unsigned char* data, quint32 offset) const
1220{
1221 quint32 res = (quint32) data[offset];
1222 res |= (((quint32)data[offset+1]) << 8);
1223 res |= (((quint32)data[offset+2]) << 16);
1224 res |= (((quint32)data[offset+3]) << 24);
1225
1226 return res;
1227}
1228
1229/*!
1230 \internal Reads an quint64 (8 bytes) from a byte array starting at given offset.
1231*/
1232quint64 UnzipPrivate::getULLong(const unsigned char* data, quint32 offset) const
1233{
1234 quint64 res = (quint64) data[offset];
1235 res |= (((quint64)data[offset+1]) << 8);
1236 res |= (((quint64)data[offset+2]) << 16);
1237 res |= (((quint64)data[offset+3]) << 24);
1238 res |= (((quint64)data[offset+1]) << 32);
1239 res |= (((quint64)data[offset+2]) << 40);
1240 res |= (((quint64)data[offset+3]) << 48);
1241 res |= (((quint64)data[offset+3]) << 56);
1242
1243 return res;
1244}
1245
1246/*!
1247 \internal Reads an quint16 (2 bytes) from a byte array starting at given offset.
1248*/
1249quint16 UnzipPrivate::getUShort(const unsigned char* data, quint32 offset) const
1250{
1251 return (quint16) data[offset] | (((quint16)data[offset+1]) << 8);
1252}
1253
1254/*!
1255 \internal Return the next byte in the pseudo-random sequence
1256 */
1257int UnzipPrivate::decryptByte(quint32 key2) const
1258{
1259 quint16 temp = ((quint16)(key2) & 0xffff) | 2;
1260 return (int)(((temp * (temp ^ 1)) >> 8) & 0xff);
1261}
1262
1263/*!
1264 \internal Update the encryption keys with the next byte of plain text
1265 */
1266void UnzipPrivate::updateKeys(quint32* keys, int c) const
1267{
1268 keys[0] = CRC32(keys[0], c);
1269 keys[1] += keys[0] & 0xff;
1270 keys[1] = keys[1] * 134775813L + 1;
1271 keys[2] = CRC32(keys[2], ((int)keys[1]) >> 24);
1272}
1273
1274/*!
1275 \internal Initialize the encryption keys and the random header according to
1276 the given password.
1277 */
1278void UnzipPrivate::initKeys(const QString& pwd, quint32* keys) const
1279{
1280 keys[0] = 305419896L;
1281 keys[1] = 591751049L;
1282 keys[2] = 878082192L;
1283
1284 //QByteArray pwdBytes = pwd.toAscii(); // Qt4
1285 QByteArray pwdBytes = pwd.toLatin1(); // Qt5
1286 int sz = pwdBytes.size();
1287 const char* ascii = pwdBytes.data();
1288
1289 for (int i=0; i<sz; ++i)
1290 updateKeys(keys, (int)ascii[i]);
1291}
1292
1293/*!
1294 \internal Attempts to test a password without actually extracting a file.
1295 The \p file parameter can be used in the user interface or for debugging purposes
1296 as it is the name of the encrypted file for wich the password is being tested.
1297*/
1298UnZip::ErrorCode UnzipPrivate::testPassword(quint32* keys, const QString& file, const ZipEntryP& header)
1299{
1300 Q_UNUSED(file);
1301
1302 // read encryption keys
1303 if (device->read(buffer1, 12) != 12)
1304 return UnZip::Corrupted;
1305
1306 // Replace this code if you want to i.e. call some dialog and ask the user for a password
1307 initKeys(password, keys);
1308 if (testKeys(header, keys))
1309 return UnZip::Ok;
1310
1311 return UnZip::Skip;
1312}
1313
1314/*!
1315 \internal Tests a set of keys on the encryption header.
1316*/
1317bool UnzipPrivate::testKeys(const ZipEntryP& header, quint32* keys)
1318{
1319 char lastByte;
1320
1321 // decrypt encryption header
1322 for (int i=0; i<11; ++i)
1323 updateKeys(keys, lastByte = buffer1[i] ^ decryptByte(keys[2]));
1324 updateKeys(keys, lastByte = buffer1[11] ^ decryptByte(keys[2]));
1325
1326 // if there is an extended header (bit in the gp flag) buffer[11] is a byte from the file time
1327 // with no extended header we have to check the crc high-order byte
1328 char c = ((header.gpFlag[0] & 0x08) == 8) ? header.modTime[1] : header.crc >> 24;
1329
1330 return (lastByte == c);
1331}
1332
1333/*!
1334 \internal Decrypts an array of bytes long \p read.
1335*/
1336void UnzipPrivate::decryptBytes(quint32* keys, char* buffer, qint64 read)
1337{
1338 for (int i=0; i<(int)read; ++i)
1339 updateKeys(keys, buffer[i] ^= decryptByte(keys[2]));
1340}
1341
1342/*!
1343 \internal Converts date and time values from ZIP format to a QDateTime object.
1344*/
1345QDateTime UnzipPrivate::convertDateTime(const unsigned char date[2], const unsigned char time[2]) const
1346{
1347 QDateTime dt;
1348
1349 // Usual PKZip low-byte to high-byte order
1350
1351 // Date: 7 bits = years from 1980, 4 bits = month, 5 bits = day
1352 quint16 year = (date[1] >> 1) & 127;
1353 quint16 month = ((date[1] << 3) & 14) | ((date[0] >> 5) & 7);
1354 quint16 day = date[0] & 31;
1355
1356 // Time: 5 bits hour, 6 bits minutes, 5 bits seconds with a 2sec precision
1357 quint16 hour = (time[1] >> 3) & 31;
1358 quint16 minutes = ((time[1] << 3) & 56) | ((time[0] >> 5) & 7);
1359 quint16 seconds = (time[0] & 31) * 2;
1360
1361 dt.setDate(QDate(1980 + year, month, day));
1362 dt.setTime(QTime(hour, minutes, seconds));
1363 return dt;
1364}
bool isOpen() const
Definition unzip.cpp:182
QStringList fileList() const
Definition unzip.cpp:281
@ Directory
Definition unzip.h:86
@ File
Definition unzip.h:86
@ NoCompression
Definition unzip.h:81
@ Deflated
Definition unzip.h:81
@ UnknownCompression
Definition unzip.h:81
void setPassword(const QString &pwd)
Definition unzip.cpp:463
void closeArchive()
Definition unzip.cpp:226
virtual ~UnZip()
Definition unzip.cpp:173
ErrorCode openArchive(const QString &filename)
Definition unzip.cpp:190
QString formatError(UnZip::ErrorCode c) const
Definition unzip.cpp:241
QList< ZipEntry > entryList() const
Definition unzip.cpp:289
UnZip()
Definition unzip.cpp:165
ErrorCode
Definition unzip.h:49
@ OpenFailed
Definition unzip.h:53
@ ZlibError
Definition unzip.h:52
@ Ok
Definition unzip.h:50
@ NoOpenArchive
Definition unzip.h:57
@ ReadFailed
Definition unzip.h:59
@ SeekFailed
Definition unzip.h:61
@ FileNotFound
Definition unzip.h:58
@ HeaderConsistencyError
Definition unzip.h:65
@ WrongPassword
Definition unzip.h:56
@ InvalidDevice
Definition unzip.h:63
@ Skip
Definition unzip.h:67
@ Corrupted
Definition unzip.h:55
@ SkipAll
Definition unzip.h:67
@ WriteFailed
Definition unzip.h:60
@ ZlibInit
Definition unzip.h:51
@ CreateDirFailed
Definition unzip.h:62
@ PartiallyCorrupted
Definition unzip.h:54
@ InvalidArchive
Definition unzip.h:64
@ SkipPaths
Ignores paths and extracts all the files to the same directory.
Definition unzip.h:75
ErrorCode extractAll(const QString &dirname, ExtractionOptions options=ExtractPaths)
Definition unzip.cpp:325
ErrorCode extractFile(const QString &filename, const QString &dirname, ExtractionOptions options=ExtractPaths)
Definition unzip.cpp:380
ErrorCode extractFiles(const QStringList &filenames, const QString &dirname, ExtractionOptions options=ExtractPaths)
Definition unzip.cpp:423
UnzipPrivate * d
Definition unzip.h:139
QString archiveComment() const
Definition unzip.cpp:231
bool contains(const QString &file) const
Definition unzip.cpp:270
void initKeys(const QString &pwd, quint32 *keys) const
Definition unzip.cpp:1278
QIODevice * device
Definition unzip_p.h:63
QString comment
Definition unzip_p.h:82
void closeArchive()
Definition unzip.cpp:948
quint16 getUShort(const unsigned char *data, quint32 offset) const
Definition unzip.cpp:1249
quint32 getULong(const unsigned char *data, quint32 offset) const
Definition unzip.cpp:1219
bool createDirectory(const QString &path)
Definition unzip.cpp:1195
bool skipAllEncrypted
Definition unzip_p.h:59
UnZip::ErrorCode parseLocalHeaderRecord(const QString &path, ZipEntryP &entry)
Definition unzip.cpp:574
UnZip::ErrorCode seekToCentralDirectory()
Definition unzip.cpp:713
int decryptByte(quint32 key2) const
Definition unzip.cpp:1257
void updateKeys(quint32 *keys, int c) const
Definition unzip.cpp:1266
UnZip::ErrorCode extractFile(const QString &path, ZipEntryP &entry, const QDir &dir, UnZip::ExtractionOptions options)
Definition unzip.cpp:972
QDateTime convertDateTime(const unsigned char date[2], const unsigned char time[2]) const
Definition unzip.cpp:1345
UnZip::ErrorCode parseCentralDirectoryRecord()
Definition unzip.cpp:837
UnZip::ErrorCode openArchive(QIODevice *device)
Definition unzip.cpp:500
UnZip::ErrorCode testPassword(quint32 *keys, const QString &file, const ZipEntryP &header)
Definition unzip.cpp:1298
void decryptBytes(quint32 *keys, char *buffer, qint64 read)
Definition unzip.cpp:1336
bool testKeys(const ZipEntryP &header, quint32 *keys)
Definition unzip.cpp:1317
QString password
Definition unzip_p.h:57
quint64 getULLong(const unsigned char *data, quint32 offset) const
Definition unzip.cpp:1232
QMap< QString, ZipEntryP * > * headers
Definition unzip_p.h:61
bool hasDataDescriptor() const
Definition zipentry_p.h:75
unsigned char gpFlag[2]
Definition zipentry_p.h:63
QString comment
Definition zipentry_p.h:70
quint32 crc
Definition zipentry_p.h:67
quint32 szComp
Definition zipentry_p.h:68
quint32 szUncomp
Definition zipentry_p.h:69
unsigned char modTime[2]
Definition zipentry_p.h:65
bool isEncrypted() const
Definition zipentry_p.h:74
quint16 compMethod
Definition zipentry_p.h:64
quint32 dataOffset
Definition zipentry_p.h:62
bool lhEntryChecked
Definition zipentry_p.h:72
unsigned char modDate[2]
Definition zipentry_p.h:66
quint32 lhOffset
Definition zipentry_p.h:61
quint32 uncompressedSize
Definition unzip.h:97
QString comment
Definition unzip.h:94
quint32 crc32
Definition unzip.h:98
FileType type
Definition unzip.h:103
bool encrypted
Definition unzip.h:105
CompressionMethod compression
Definition unzip.h:102
quint32 compressedSize
Definition unzip.h:96
QString filename
Definition unzip.h:93
QDateTime lastModified
Definition unzip.h:100
#define UNZIP_LH_OFF_USIZE
Definition unzip.cpp:111
#define UNZIP_LOCAL_ENC_HEADER_SIZE
Local header entry encryption header size.
Definition unzip.cpp:87
#define UNZIP_LH_OFF_CRC32
Definition unzip.cpp:109
#define UNZIP_CD_ENTRY_SIZE_NS
Central Directory file entry size (excluding signature, excluding variable length fields)
Definition unzip.cpp:81
#define UNZIP_CD_OFF_VERSION
Definition unzip.cpp:90
#define UNZIP_DD_OFF_CSIZE
Definition unzip.cpp:117
#define UNZIP_CD_OFF_GPFLAG
Definition unzip.cpp:91
#define UNZIP_CD_OFF_MODD
Definition unzip.cpp:94
#define UNZIP_CHECK_FOR_VALID_DATA
Checks if some file has been already extracted.
Definition unzip.cpp:139
#define UNZIP_LH_OFF_MODT
Definition unzip.cpp:107
#define UNZIP_CD_OFF_CMETHOD
Definition unzip.cpp:92
#define UNZIP_LH_OFF_NAMELEN
Definition unzip.cpp:112
#define UNZIP_CD_OFF_USIZE
Definition unzip.cpp:97
#define UNZIP_DD_OFF_CRC32
Definition unzip.cpp:116
#define UNZIP_LOCAL_HEADER_SIZE
Local header size (excluding signature, excluding variable length fields)
Definition unzip.cpp:79
#define UNZIP_VERSION
Definition unzip.cpp:131
#define UNZIP_LH_OFF_GPFLAG
Definition unzip.cpp:105
#define UNZIP_CD_OFF_XLEN
Definition unzip.cpp:99
#define UNZIP_DD_SIZE
Data descriptor size (excluding signature)
Definition unzip.cpp:83
#define UNZIP_EOCD_OFF_ENTRIES
Definition unzip.cpp:121
#define UNZIP_EOCD_OFF_CDOFF
Definition unzip.cpp:122
#define CRC32(c, b)
CRC32 routine.
Definition unzip.cpp:136
#define UNZIP_CD_OFF_LHOFFSET
Definition unzip.cpp:101
#define UNZIP_CD_OFF_NAMELEN
Definition unzip.cpp:98
#define UNZIP_EOCD_OFF_COMMLEN
Definition unzip.cpp:123
#define UNZIP_LH_OFF_CSIZE
Definition unzip.cpp:110
#define UNZIP_LH_OFF_MODD
Definition unzip.cpp:108
#define UNZIP_EOCD_SIZE
End Of Central Directory size (including signature, excluding variable length fields)
Definition unzip.cpp:85
#define UNZIP_CD_OFF_COMMLEN
Definition unzip.cpp:100
#define UNZIP_CD_OFF_CSIZE
Definition unzip.cpp:96
#define UNZIP_LH_OFF_CMETHOD
Definition unzip.cpp:106
#define UNZIP_DD_OFF_USIZE
Definition unzip.cpp:118
#define UNZIP_LH_OFF_XLEN
Definition unzip.cpp:113
#define UNZIP_CD_OFF_CRC32
Definition unzip.cpp:95
#define UNZIP_CD_OFF_MODT
Definition unzip.cpp:93
#define UNZIP_READ_BUFFER
Definition unzip_p.h:49