41#include <QCoreApplication>
47#define ZIP_LOCAL_HEADER_SIZE 30
49#define ZIP_LOCAL_ENC_HEADER_SIZE 12
51#define ZIP_DD_SIZE_WS 16
55#define ZIP_EOCD_SIZE 22
58#define ZIP_LH_OFF_VERS 4
59#define ZIP_LH_OFF_GPFLAG 6
60#define ZIP_LH_OFF_CMET 8
61#define ZIP_LH_OFF_MODT 10
62#define ZIP_LH_OFF_MODD 12
63#define ZIP_LH_OFF_CRC 14
64#define ZIP_LH_OFF_CSIZE 18
65#define ZIP_LH_OFF_USIZE 22
66#define ZIP_LH_OFF_NAMELEN 26
67#define ZIP_LH_OFF_XLEN 28
70#define ZIP_DD_OFF_CRC32 4
71#define ZIP_DD_OFF_CSIZE 8
72#define ZIP_DD_OFF_USIZE 12
75#define ZIP_CD_OFF_MADEBY 4
76#define ZIP_CD_OFF_VERSION 6
77#define ZIP_CD_OFF_GPFLAG 8
78#define ZIP_CD_OFF_CMET 10
79#define ZIP_CD_OFF_MODT 12
80#define ZIP_CD_OFF_MODD 14
81#define ZIP_CD_OFF_CRC 16
82#define ZIP_CD_OFF_CSIZE 20
83#define ZIP_CD_OFF_USIZE 24
84#define ZIP_CD_OFF_NAMELEN 28
85#define ZIP_CD_OFF_XLEN 30
86#define ZIP_CD_OFF_COMMLEN 32
87#define ZIP_CD_OFF_DISKSTART 34
88#define ZIP_CD_OFF_IATTR 36
89#define ZIP_CD_OFF_EATTR 38
90#define ZIP_CD_OFF_LHOFF 42
93#define ZIP_EOCD_OFF_DISKNUM 4
94#define ZIP_EOCD_OFF_CDDISKNUM 6
95#define ZIP_EOCD_OFF_ENTRIES 8
96#define ZIP_EOCD_OFF_CDENTRIES 10
97#define ZIP_EOCD_OFF_CDSIZE 12
98#define ZIP_EOCD_OFF_CDOFF 16
99#define ZIP_EOCD_OFF_COMMLEN 20
102#define ZIP_VERSION 0x14
105#define ZIP_COMPRESSION_THRESHOLD 60
108#define CRC32(c, b) crcTable[((int)c^b) & 0xff] ^ (c >> 8)
270 QFile* file =
new QFile(filename);
272 if (file->exists() && !overwrite) {
277 if (!file->open(QIODevice::WriteOnly)) {
298 qDebug() <<
"Invalid device.";
389 QString actualRoot = root.trimmed();
392 if (actualRoot !=
"/")
394 while (actualRoot.endsWith(
"/") || actualRoot.endsWith(
"\\"))
395 actualRoot.truncate(actualRoot.length() - 1);
399 QFileInfo current(QDir::cleanPath(path));
401 if (!actualRoot.isEmpty() && actualRoot !=
"/")
402 actualRoot.append(
"/");
409 if (!absolutePath.isEmpty() && absolutePath !=
"/")
410 absolutePath.append(
"/");
411 actualRoot.append(absolutePath);
416 actualRoot = actualRoot.append(QDir(current.absoluteFilePath()).dirName());
417 actualRoot.append(
"/");
423 QFileInfoList list = dir.entryInfoList(
426 QDir::NoDotAndDotDot |
430 bool filesAdded =
false;
432 CompressionOptions recursionOptions;
437 for (
int i = 0; i < list.size() && ec ==
Zip::Ok; ++i)
439 QFileInfo info = list.at(i);
444 ec =
addDirectory(info.absoluteFilePath(), actualRoot, recursionOptions, level);
479 case Ok:
return QCoreApplication::translate(
"Zip",
"ZIP operation completed successfully.");
break;
480 case ZlibInit:
return QCoreApplication::translate(
"Zip",
"Failed to initialize or load zlib library.");
break;
481 case ZlibError:
return QCoreApplication::translate(
"Zip",
"zlib library error.");
break;
482 case OpenFailed:
return QCoreApplication::translate(
"Zip",
"Unable to create or open file.");
break;
483 case NoOpenArchive:
return QCoreApplication::translate(
"Zip",
"No archive has been created yet.");
break;
484 case FileNotFound:
return QCoreApplication::translate(
"Zip",
"File or directory does not exist.");
break;
485 case ReadFailed:
return QCoreApplication::translate(
"Zip",
"File read error.");
break;
486 case WriteFailed:
return QCoreApplication::translate(
"Zip",
"File write error.");
break;
487 case SeekFailed:
return QCoreApplication::translate(
"Zip",
"File seek error.");
break;
491 return QCoreApplication::translate(
"Zip",
"Unknown error.");
507 crcTable = (quint32*) get_crc_table();
528 if (!
device->open(QIODevice::ReadOnly)) {
531 qDebug() <<
"Unable to open device for writing.";
536 headers =
new QMap<QString,ZipEntryP*>;
549 bool isPNGFile =
false;
550 bool dirOnly = file.isDir();
552 QString entryName = root;
559 entryName.append(file.fileName());
561 QString ext = file.completeSuffix().toLower();
562 isPNGFile = ext ==
"png";
594 bool encrypt = !dirOnly && !
password.isEmpty();
598 QDateTime dt = file.lastModified();
600 h->
modDate[1] = ((d.year() - 1980) << 1) & 254;
601 h->
modDate[1] |= ((d.month() >> 3) & 1);
602 h->
modDate[0] = ((d.month() & 7) << 5) & 224;
606 h->
modTime[1] = (t.hour() << 3) & 248;
607 h->
modTime[1] |= ((t.minute() >> 3) & 7);
608 h->
modTime[0] = ((t.minute() & 7) << 5) & 224;
609 h->
modTime[0] |= t.second() / 2;
611 h->
szUncomp = dirOnly ? 0 : file.size();
654 QByteArray entryNameBytes = entryName.toLatin1();
655 int sz = entryNameBytes.size();
674 if (
device->write(entryNameBytes) != sz)
681 quint32 keys[3] = { 0, 0, 0 };
689 srand(time(NULL) ^ 3141592654UL);
693 for (
int i=0; i<10; ++i)
695 randByte = (rand() >> 7) & 0xff;
702 for (
int i=0; i<10; ++i)
728 quint32 crc = crc32(0L, Z_NULL, 0);
732 QFile actualFile(file.absoluteFilePath());
733 if (!actualFile.open(QIODevice::ReadOnly))
735 qDebug() << QString(
"An error occurred while opening %1").arg(file.absoluteFilePath());
742 qint64 toRead = actualFile.size();
748 crc = crc32(crc,
uBuffer, read);
766 zstr.zalloc = Z_NULL;
768 zstr.opaque = Z_NULL;
773 if ((zret = deflateInit2_(
779 isPNGFile ? Z_RLE : Z_DEFAULT_STRATEGY,
785 qDebug() <<
"Could not initialize zlib for compression";
792 int flush = Z_NO_FLUSH;
805 qDebug() << QString(
"Error while reading %1").arg(file.absoluteFilePath());
810 crc = crc32(crc,
uBuffer, read);
812 zstr.next_in = (Bytef*)
buffer1;
813 zstr.avail_in = (uInt)read;
817 flush = (totRead == toRead) ? Z_FINISH : Z_NO_FLUSH;
823 zstr.next_out = (Bytef*)
buffer2;
826 zret = deflate(&zstr, flush);
828 Q_ASSERT(zret != Z_STREAM_ERROR);
840 qDebug() << QString(
"Error while writing %1").arg(file.absoluteFilePath());
845 written += compressed;
847 }
while (zstr.avail_out == 0);
850 Q_ASSERT(zstr.avail_in == 0);
852 }
while (flush != Z_FINISH);
855 Q_ASSERT(zret == Z_STREAM_END);
865 quint32 current =
device->pos();
868 if (!
device->seek(crcOffset))
874 h->
crc = dirOnly ? 0 : crc;
886 if (!
device->seek(current))
892 if ((h->
gpFlag[0] & 8) == 8)
925 quint16 temp = ((quint16)(key2) & 0xffff) | 2;
926 return (
int)(((temp * (temp ^ 1)) >> 8) & 0xff);
932 buffer[offset+3] = ((v >> 24) & 0xFF);
933 buffer[offset+2] = ((v >> 16) & 0xFF);
934 buffer[offset+1] = ((v >> 8) & 0xFF);
935 buffer[offset] = (v & 0xFF);
943 keys[0] = 305419896L;
944 keys[1] = 591751049L;
945 keys[2] = 878082192L;
948 QByteArray pwdBytes =
password.toLatin1();
949 int sz = pwdBytes.size();
950 const char* ascii = pwdBytes.data();
952 for (
int i=0; i<sz; ++i)
959 keys[0] =
CRC32(keys[0], c);
960 keys[1] += keys[0] & 0xff;
961 keys[1] = keys[1] * 134775813L + 1;
962 keys[2] =
CRC32(keys[2], ((
int)keys[1]) >> 24);
970 for (
int i=0; i<(int)read; ++i)
982 if ((ext ==
"png") ||
1002 if ((ext ==
"exe") ||
1028 quint32 szCentralDir = 0;
1029 quint32 offCentralDir =
device->pos();
1031 for (QMap<QString,ZipEntryP*>::ConstIterator itr =
headers->constBegin(); itr !=
headers->constEnd(); ++itr)
1075 QByteArray fileNameBytes = itr.key().toLatin1();
1076 sz = fileNameBytes.size();
1112 if ((
unsigned int)
device->write(fileNameBytes) != sz)
1158 QByteArray commentBytes =
comment.toLatin1();
1159 quint16 commentLength = commentBytes.size();
1161 if (commentLength == 0)
1181 if (commentLength != 0)
1183 if ((
unsigned int)
device->write(commentBytes) != commentLength)
1215 QDir d(QDir::cleanPath(p));
1222 return d.absolutePath();
char buffer2[ZIP_READ_BUFFER]
Zip::ErrorCode createArchive(QIODevice *device)
void initKeys(quint32 *keys) const
int decryptByte(quint32 key2) const
void updateKeys(quint32 *keys, int c) const
Zip::ErrorCode createEntry(const QFileInfo &file, const QString &root, Zip::CompressionLevel level)
Zip::CompressionLevel detectCompressionByMime(const QString &ext)
void encryptBytes(quint32 *keys, char *buffer, qint64 read)
QString extractRoot(const QString &p)
char buffer1[ZIP_READ_BUFFER]
void setULong(quint32 v, char *buffer, unsigned int offset)
Zip::ErrorCode closeArchive()
QMap< QString, ZipEntryP * > * headers
void setPassword(const QString &pwd)
ErrorCode createArchive(const QString &file, bool overwrite=true)
@ IgnorePaths
Do not store paths. All the files are put in the (evtl. user defined) root of the zip file.
@ AbsolutePaths
Preserve absolute paths.
@ RelativePaths
Does not preserve absolute paths in the zip file when adding a file/directory (default)
void clearPassword()
Convenience method, clears the current password.
ErrorCode addDirectory(const QString &path, CompressionOptions options=RelativePaths, CompressionLevel level=AutoFull)
QString password() const
Returns the currently used password.
QString formatError(ErrorCode c) const
void setArchiveComment(const QString &comment)
ErrorCode addDirectoryContents(const QString &path, CompressionLevel level=AutoFull)
QString archiveComment() const
#define CRC32(c, b)
CRC32 routine.
#define ZIP_VERSION
PKZip version for archives created by this API.
#define ZIP_EOCD_OFF_CDSIZE
#define ZIP_CD_SIZE
Central Directory record size (signature included)
#define ZIP_CD_OFF_GPFLAG
#define ZIP_CD_OFF_MADEBY
#define ZIP_CD_OFF_COMMLEN
#define ZIP_EOCD_SIZE
End of Central Directory record size (signature included)
#define ZIP_DD_SIZE_WS
Data descriptor size (signature included)
#define ZIP_LH_OFF_NAMELEN
#define ZIP_COMPRESSION_THRESHOLD
Do not store very small files as the compression headers overhead would be to big.
#define ZIP_LOCAL_ENC_HEADER_SIZE
Encryption header size.
#define ZIP_CD_OFF_DISKSTART
#define ZIP_CD_OFF_NAMELEN
#define ZIP_CD_OFF_VERSION
#define ZIP_LH_OFF_GPFLAG
#define ZIP_EOCD_OFF_ENTRIES
#define ZIP_EOCD_OFF_DISKNUM
#define ZIP_EOCD_OFF_CDENTRIES
#define ZIP_EOCD_OFF_COMMLEN
#define ZIP_LOCAL_HEADER_SIZE
Local header size (including signature, excluding variable length fields)
#define ZIP_EOCD_OFF_CDDISKNUM
#define ZIP_EOCD_OFF_CDOFF