summaryrefslogtreecommitdiffstats
path: root/rbutil/rbutilqt/zip/zip.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'rbutil/rbutilqt/zip/zip.cpp')
-rw-r--r--rbutil/rbutilqt/zip/zip.cpp1221
1 files changed, 0 insertions, 1221 deletions
diff --git a/rbutil/rbutilqt/zip/zip.cpp b/rbutil/rbutilqt/zip/zip.cpp
deleted file mode 100644
index 9ecd5531ef..0000000000
--- a/rbutil/rbutilqt/zip/zip.cpp
+++ /dev/null
@@ -1,1221 +0,0 @@
-/****************************************************************************
-** Filename: zip.cpp
-** Last updated [dd/mm/yyyy]: 01/02/2007
-**
-** pkzip 2.0 file compression.
-**
-** Some of the code has been inspired by other open source projects,
-** (mainly Info-Zip and Gilles Vollant's minizip).
-** Compression and decompression actually uses the zlib library.
-**
-** Copyright (C) 2007-2008 Angius Fabrizio. All rights reserved.
-**
-** This file is part of the OSDaB project (http://osdab.sourceforge.net/).
-**
-** This file may be distributed and/or modified under the terms of the
-** GNU General Public License version 2 as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL included in the
-** packaging of this file.
-**
-** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
-** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
-**
-** See the file LICENSE.GPL that came with this software distribution or
-** visit http://www.gnu.org/copyleft/gpl.html for GPL licensing information.
-**
-**********************************************************************/
-
-#include "zip.h"
-#include "zip_p.h"
-#include "zipentry_p.h"
-
-// we only use this to seed the random number generator
-#include <time.h>
-
-#include <QMap>
-#include <QString>
-#include <QStringList>
-#include <QDir>
-#include <QFile>
-#include <QDateTime>
-#include <QCoreApplication>
-
-// You can remove this #include if you replace the qDebug() statements.
-#include <QtDebug>
-
-//! Local header size (including signature, excluding variable length fields)
-#define ZIP_LOCAL_HEADER_SIZE 30
-//! Encryption header size
-#define ZIP_LOCAL_ENC_HEADER_SIZE 12
-//! Data descriptor size (signature included)
-#define ZIP_DD_SIZE_WS 16
-//! Central Directory record size (signature included)
-#define ZIP_CD_SIZE 46
-//! End of Central Directory record size (signature included)
-#define ZIP_EOCD_SIZE 22
-
-// Some offsets inside a local header record (signature included)
-#define ZIP_LH_OFF_VERS 4
-#define ZIP_LH_OFF_GPFLAG 6
-#define ZIP_LH_OFF_CMET 8
-#define ZIP_LH_OFF_MODT 10
-#define ZIP_LH_OFF_MODD 12
-#define ZIP_LH_OFF_CRC 14
-#define ZIP_LH_OFF_CSIZE 18
-#define ZIP_LH_OFF_USIZE 22
-#define ZIP_LH_OFF_NAMELEN 26
-#define ZIP_LH_OFF_XLEN 28
-
-// Some offsets inside a data descriptor record (including signature)
-#define ZIP_DD_OFF_CRC32 4
-#define ZIP_DD_OFF_CSIZE 8
-#define ZIP_DD_OFF_USIZE 12
-
-// Some offsets inside a Central Directory record (including signature)
-#define ZIP_CD_OFF_MADEBY 4
-#define ZIP_CD_OFF_VERSION 6
-#define ZIP_CD_OFF_GPFLAG 8
-#define ZIP_CD_OFF_CMET 10
-#define ZIP_CD_OFF_MODT 12
-#define ZIP_CD_OFF_MODD 14
-#define ZIP_CD_OFF_CRC 16
-#define ZIP_CD_OFF_CSIZE 20
-#define ZIP_CD_OFF_USIZE 24
-#define ZIP_CD_OFF_NAMELEN 28
-#define ZIP_CD_OFF_XLEN 30
-#define ZIP_CD_OFF_COMMLEN 32
-#define ZIP_CD_OFF_DISKSTART 34
-#define ZIP_CD_OFF_IATTR 36
-#define ZIP_CD_OFF_EATTR 38
-#define ZIP_CD_OFF_LHOFF 42
-
-// Some offsets inside a EOCD record (including signature)
-#define ZIP_EOCD_OFF_DISKNUM 4
-#define ZIP_EOCD_OFF_CDDISKNUM 6
-#define ZIP_EOCD_OFF_ENTRIES 8
-#define ZIP_EOCD_OFF_CDENTRIES 10
-#define ZIP_EOCD_OFF_CDSIZE 12
-#define ZIP_EOCD_OFF_CDOFF 16
-#define ZIP_EOCD_OFF_COMMLEN 20
-
-//! PKZip version for archives created by this API
-#define ZIP_VERSION 0x14
-
-//! Do not store very small files as the compression headers overhead would be to big
-#define ZIP_COMPRESSION_THRESHOLD 60
-
-//! This macro updates a one-char-only CRC; it's the Info-Zip macro re-adapted
-#define CRC32(c, b) crcTable[((int)c^b) & 0xff] ^ (c >> 8)
-
-/*!
- \class Zip zip.h
-
- \brief Zip file compression.
-
- Some quick usage examples.
-
- \verbatim
- Suppose you have this directory structure:
-
- /root/dir1/
- /root/dir1/file1.1
- /root/dir1/file1.2
- /root/dir1/dir1.1/
- /root/dir1/dir1.2/file1.2.1
-
- EXAMPLE 1:
- myZipInstance.addDirectory("/root/dir1");
-
- RESULT:
- Beheaves like any common zip software and creates a zip file with this structure:
-
- dir1/
- dir1/file1.1
- dir1/file1.2
- dir1/dir1.1/
- dir1/dir1.2/file1.2.1
-
- EXAMPLE 2:
- myZipInstance.addDirectory("/root/dir1", "myRoot/myFolder");
-
- RESULT:
- Adds a custom root to the paths and creates a zip file with this structure:
-
- myRoot/myFolder/dir1/
- myRoot/myFolder/dir1/file1.1
- myRoot/myFolder/dir1/file1.2
- myRoot/myFolder/dir1/dir1.1/
- myRoot/myFolder/dir1/dir1.2/file1.2.1
-
- EXAMPLE 3:
- myZipInstance.addDirectory("/root/dir1", Zip::AbsolutePaths);
-
- NOTE:
- Same as calling addDirectory(SOME_PATH, PARENT_PATH_of_SOME_PATH).
-
- RESULT:
- Preserves absolute paths and creates a zip file with this structure:
-
- /root/dir1/
- /root/dir1/file1.1
- /root/dir1/file1.2
- /root/dir1/dir1.1/
- /root/dir1/dir1.2/file1.2.1
-
- EXAMPLE 4:
- myZipInstance.setPassword("hellopass");
- myZipInstance.addDirectory("/root/dir1", "/");
-
- RESULT:
- Adds and encrypts the files in /root/dir1, creating the following zip structure:
-
- /dir1/
- /dir1/file1.1
- /dir1/file1.2
- /dir1/dir1.1/
- /dir1/dir1.2/file1.2.1
-
- \endverbatim
-*/
-
-/*! \enum Zip::ErrorCode The result of a compression operation.
- \value Zip::Ok No error occurred.
- \value Zip::ZlibInit Failed to init or load the zlib library.
- \value Zip::ZlibError The zlib library returned some error.
- \value Zip::FileExists The file already exists and will not be overwritten.
- \value Zip::OpenFailed Unable to create or open a device.
- \value Zip::NoOpenArchive CreateArchive() has not been called yet.
- \value Zip::FileNotFound File or directory does not exist.
- \value Zip::ReadFailed Reading of a file failed.
- \value Zip::WriteFailed Writing of a file failed.
- \value Zip::SeekFailed Seek failed.
-*/
-
-/*! \enum Zip::CompressionLevel Returns the result of a decompression operation.
- \value Zip::Store No compression.
- \value Zip::Deflate1 Deflate compression level 1(lowest compression).
- \value Zip::Deflate1 Deflate compression level 2.
- \value Zip::Deflate1 Deflate compression level 3.
- \value Zip::Deflate1 Deflate compression level 4.
- \value Zip::Deflate1 Deflate compression level 5.
- \value Zip::Deflate1 Deflate compression level 6.
- \value Zip::Deflate1 Deflate compression level 7.
- \value Zip::Deflate1 Deflate compression level 8.
- \value Zip::Deflate1 Deflate compression level 9 (maximum compression).
- \value Zip::AutoCPU Adapt compression level to CPU speed (faster CPU => better compression).
- \value Zip::AutoMIME Adapt compression level to MIME type of the file being compressed.
- \value Zip::AutoFull Use both CPU and MIME type detection.
-*/
-
-
-/************************************************************************
- Public interface
-*************************************************************************/
-
-/*!
- Creates a new Zip file compressor.
-*/
-Zip::Zip()
-{
- d = new ZipPrivate;
-}
-
-/*!
- Closes any open archive and releases used resources.
-*/
-Zip::~Zip()
-{
- closeArchive();
- delete d;
-}
-
-/*!
- Returns true if there is an open archive.
-*/
-bool Zip::isOpen() const
-{
- return d->device != 0;
-}
-
-/*!
- Sets the password to be used for the next files being added!
- Files added before calling this method will use the previously
- set password (if any).
- Closing the archive won't clear the password!
-*/
-void Zip::setPassword(const QString& pwd)
-{
- d->password = pwd;
-}
-
-//! Convenience method, clears the current password.
-void Zip::clearPassword()
-{
- d->password.clear();
-}
-
-//! Returns the currently used password.
-QString Zip::password() const
-{
- return d->password;
-}
-
-/*!
- Attempts to create a new Zip archive. If \p overwrite is true and the file
- already exist it will be overwritten.
- Any open archive will be closed.
- */
-Zip::ErrorCode Zip::createArchive(const QString& filename, bool overwrite)
-{
- QFile* file = new QFile(filename);
-
- if (file->exists() && !overwrite) {
- delete file;
- return Zip::FileExists;
- }
-
- if (!file->open(QIODevice::WriteOnly)) {
- delete file;
- return Zip::OpenFailed;
- }
-
- Zip::ErrorCode ec = createArchive(file);
- if (ec != Zip::Ok) {
- file->remove();
- }
-
- return ec;
-}
-
-/*!
- Attempts to create a new Zip archive. If there is another open archive this will be closed.
- \warning The class takes ownership of the device!
- */
-Zip::ErrorCode Zip::createArchive(QIODevice* device)
-{
- if (device == 0)
- {
- qDebug() << "Invalid device.";
- return Zip::OpenFailed;
- }
-
- return d->createArchive(device);
-}
-
-/*!
- Returns the current archive comment.
-*/
-QString Zip::archiveComment() const
-{
- return d->comment;
-}
-
-/*!
- Sets the comment for this archive. Note: createArchive() should have been
- called before.
-*/
-void Zip::setArchiveComment(const QString& comment)
-{
- if (d->device != 0)
- d->comment = comment;
-}
-
-/*!
- Convenience method, same as calling
- Zip::addDirectory(const QString&,const QString&,CompressionLevel)
- with an empty \p root parameter (or with the parent directory of \p path if the
- AbsolutePaths options is set).
-
- The ExtractionOptions are checked in the order they are defined in the zip.h heaser file.
- This means that the last one overwrites the previous one (if some conflict occurs), i.e.
- Zip::IgnorePaths | Zip::AbsolutePaths would be interpreted as Zip::IgnorePaths.
- */
-Zip::ErrorCode Zip::addDirectory(const QString& path, CompressionOptions options, CompressionLevel level)
-{
- return addDirectory(path, QString(), options, level);
-}
-
-/*!
- Convenience method, same as calling Zip::addDirectory(const QString&,const QString&,CompressionOptions,CompressionLevel)
- with the Zip::RelativePaths flag as compression option.
- */
-Zip::ErrorCode Zip::addDirectory(const QString& path, const QString& root, CompressionLevel level)
-{
- return addDirectory(path, root, Zip::RelativePaths, level);
-}
-
-/*!
- Convenience method, same as calling Zip::addDirectory(const QString&,const QString&,CompressionOptions,CompressionLevel)
- with the Zip::IgnorePaths flag as compression option and an empty \p root parameter.
-*/
-Zip::ErrorCode Zip::addDirectoryContents(const QString& path, CompressionLevel level)
-{
- return addDirectory(path, QString(), IgnorePaths, level);
-}
-
-/*!
- Convenience method, same as calling Zip::addDirectory(const QString&,const QString&,CompressionOptions,CompressionLevel)
- with the Zip::IgnorePaths flag as compression option.
-*/
-Zip::ErrorCode Zip::addDirectoryContents(const QString& path, const QString& root, CompressionLevel level)
-{
- return addDirectory(path, root, IgnorePaths, level);
-}
-
-/*!
- Recursively adds files contained in \p dir to the archive, using \p root as name for the root folder.
- Stops adding files if some error occurs.
-
- The ExtractionOptions are checked in the order they are defined in the zip.h heaser file.
- This means that the last one overwrites the previous one (if some conflict occurs), i.e.
- Zip::IgnorePaths | Zip::AbsolutePaths would be interpreted as Zip::IgnorePaths.
-
- The \p root parameter is ignored with the Zip::IgnorePaths parameter and used as path prefix (a trailing /
- is always added as directory separator!) otherwise (even with Zip::AbsolutePaths set!).
-*/
-Zip::ErrorCode Zip::addDirectory(const QString& path, const QString& root, CompressionOptions options, CompressionLevel level)
-{
- // qDebug() << QString("addDir(path=%1, root=%2)").arg(path, root);
-
- // Bad boy didn't call createArchive() yet :)
- if (d->device == 0)
- return Zip::NoOpenArchive;
-
- QDir dir(path);
- if (!dir.exists())
- return Zip::FileNotFound;
-
- // Remove any trailing separator
- QString actualRoot = root.trimmed();
-
- // Preserve Unix root
- if (actualRoot != "/")
- {
- while (actualRoot.endsWith("/") || actualRoot.endsWith("\\"))
- actualRoot.truncate(actualRoot.length() - 1);
- }
-
- // QDir::cleanPath() fixes some issues with QDir::dirName()
- QFileInfo current(QDir::cleanPath(path));
-
- if (!actualRoot.isEmpty() && actualRoot != "/")
- actualRoot.append("/");
-
- /* This part is quite confusing and needs some test or check */
- /* An attempt to compress the / root directory evtl. using a root prefix should be a good test */
- if (options.testFlag(AbsolutePaths) && !options.testFlag(IgnorePaths))
- {
- QString absolutePath = d->extractRoot(path);
- if (!absolutePath.isEmpty() && absolutePath != "/")
- absolutePath.append("/");
- actualRoot.append(absolutePath);
- }
-
- if (!options.testFlag(IgnorePaths))
- {
- actualRoot = actualRoot.append(QDir(current.absoluteFilePath()).dirName());
- actualRoot.append("/");
- }
-
- // actualRoot now contains the path of the file relative to the zip archive
- // with a trailing /
-
- QFileInfoList list = dir.entryInfoList(
- QDir::Files |
- QDir::Dirs |
- QDir::NoDotAndDotDot |
- QDir::NoSymLinks);
-
- ErrorCode ec = Zip::Ok;
- bool filesAdded = false;
-
- CompressionOptions recursionOptions;
- if (options.testFlag(IgnorePaths))
- recursionOptions |= IgnorePaths;
- else recursionOptions |= RelativePaths;
-
- for (int i = 0; i < list.size() && ec == Zip::Ok; ++i)
- {
- QFileInfo info = list.at(i);
-
- if (info.isDir())
- {
- // Recursion :)
- progress();
- ec = addDirectory(info.absoluteFilePath(), actualRoot, recursionOptions, level);
- }
- else
- {
- progress();
- ec = d->createEntry(info, actualRoot, level);
- filesAdded = true;
- }
- }
-
-
- // We need an explicit record for this dir
- // Non-empty directories don't need it because they have a path component in the filename
- if (!filesAdded && !options.testFlag(IgnorePaths))
- ec = d->createEntry(current, actualRoot, level);
-
- return ec;
-}
-
-/*!
- Closes the archive and writes any pending data.
-*/
-Zip::ErrorCode Zip::closeArchive()
-{
- Zip::ErrorCode ec = d->closeArchive();
- d->reset();
- return ec;
-}
-
-/*!
- Returns a locale translated error string for a given error code.
-*/
-QString Zip::formatError(Zip::ErrorCode c) const
-{
- switch (c)
- {
- case Ok: return QCoreApplication::translate("Zip", "ZIP operation completed successfully."); break;
- case ZlibInit: return QCoreApplication::translate("Zip", "Failed to initialize or load zlib library."); break;
- case ZlibError: return QCoreApplication::translate("Zip", "zlib library error."); break;
- case OpenFailed: return QCoreApplication::translate("Zip", "Unable to create or open file."); break;
- case NoOpenArchive: return QCoreApplication::translate("Zip", "No archive has been created yet."); break;
- case FileNotFound: return QCoreApplication::translate("Zip", "File or directory does not exist."); break;
- case ReadFailed: return QCoreApplication::translate("Zip", "File read error."); break;
- case WriteFailed: return QCoreApplication::translate("Zip", "File write error."); break;
- case SeekFailed: return QCoreApplication::translate("Zip", "File seek error."); break;
- default: ;
- }
-
- return QCoreApplication::translate("Zip", "Unknown error.");
-}
-
-
-/************************************************************************
- Private interface
-*************************************************************************/
-
-//! \internal
-ZipPrivate::ZipPrivate()
-{
- headers = 0;
- device = 0;
-
- // keep an unsigned pointer so we avoid to over bloat the code with casts
- uBuffer = (unsigned char*) buffer1;
- crcTable = (quint32*) get_crc_table();
-}
-
-//! \internal
-ZipPrivate::~ZipPrivate()
-{
- closeArchive();
-}
-
-//! \internal
-Zip::ErrorCode ZipPrivate::createArchive(QIODevice* dev)
-{
- Q_ASSERT(dev != 0);
-
- if (device != 0)
- closeArchive();
-
- device = dev;
-
- if (!device->isOpen())
- {
- if (!device->open(QIODevice::ReadOnly)) {
- delete device;
- device = 0;
- qDebug() << "Unable to open device for writing.";
- return Zip::OpenFailed;
- }
- }
-
- headers = new QMap<QString,ZipEntryP*>;
- return Zip::Ok;
-}
-
-//! \internal Writes a new entry in the zip file.
-Zip::ErrorCode ZipPrivate::createEntry(const QFileInfo& file, const QString& root, Zip::CompressionLevel level)
-{
- //! \todo Automatic level detection (cpu, extension & file size)
-
- // Directories and very small files are always stored
- // (small files would get bigger due to the compression headers overhead)
-
- // Need this for zlib
- bool isPNGFile = false;
- bool dirOnly = file.isDir();
-
- QString entryName = root;
-
- // Directory entry
- if (dirOnly)
- level = Zip::Store;
- else
- {
- entryName.append(file.fileName());
-
- QString ext = file.completeSuffix().toLower();
- isPNGFile = ext == "png";
-
- if (file.size() < ZIP_COMPRESSION_THRESHOLD)
- level = Zip::Store;
- else
- switch (level)
- {
- case Zip::AutoCPU:
- level = Zip::Deflate5;
- break;
- case Zip::AutoMIME:
- level = detectCompressionByMime(ext);
- break;
- case Zip::AutoFull:
- level = detectCompressionByMime(ext);
- break;
- default:
- ;
- }
- }
-
- // entryName contains the path as it should be written
- // in the zip file records
- // qDebug() << QString("addDir(file=%1, root=%2, entry=%3)").arg(file.absoluteFilePath(), root, entryName);
-
- // create header and store it to write a central directory later
- ZipEntryP* h = new ZipEntryP;
-
- h->compMethod = (level == Zip::Store) ? 0 : 0x0008;
-
- // Set encryption bit and set the data descriptor bit
- // so we can use mod time instead of crc for password check
- bool encrypt = !dirOnly && !password.isEmpty();
- if (encrypt)
- h->gpFlag[0] |= 9;
-
- QDateTime dt = file.lastModified();
- QDate d = dt.date();
- h->modDate[1] = ((d.year() - 1980) << 1) & 254;
- h->modDate[1] |= ((d.month() >> 3) & 1);
- h->modDate[0] = ((d.month() & 7) << 5) & 224;
- h->modDate[0] |= d.day();
-
- QTime t = dt.time();
- h->modTime[1] = (t.hour() << 3) & 248;
- h->modTime[1] |= ((t.minute() >> 3) & 7);
- h->modTime[0] = ((t.minute() & 7) << 5) & 224;
- h->modTime[0] |= t.second() / 2;
-
- h->szUncomp = dirOnly ? 0 : file.size();
-
- // **** Write local file header ****
-
- // signature
- buffer1[0] = 'P'; buffer1[1] = 'K';
- buffer1[2] = 0x3; buffer1[3] = 0x4;
-
- // version needed to extract
- buffer1[ZIP_LH_OFF_VERS] = ZIP_VERSION;
- buffer1[ZIP_LH_OFF_VERS + 1] = 0;
-
- // general purpose flag
- buffer1[ZIP_LH_OFF_GPFLAG] = h->gpFlag[0];
- buffer1[ZIP_LH_OFF_GPFLAG + 1] = h->gpFlag[1];
-
- // compression method
- buffer1[ZIP_LH_OFF_CMET] = h->compMethod & 0xFF;
- buffer1[ZIP_LH_OFF_CMET + 1] = (h->compMethod>>8) & 0xFF;
-
- // last mod file time
- buffer1[ZIP_LH_OFF_MODT] = h->modTime[0];
- buffer1[ZIP_LH_OFF_MODT + 1] = h->modTime[1];
-
- // last mod file date
- buffer1[ZIP_LH_OFF_MODD] = h->modDate[0];
- buffer1[ZIP_LH_OFF_MODD + 1] = h->modDate[1];
-
- // skip crc (4bytes) [14,15,16,17]
-
- // skip compressed size but include evtl. encryption header (4bytes: [18,19,20,21])
- buffer1[ZIP_LH_OFF_CSIZE] =
- buffer1[ZIP_LH_OFF_CSIZE + 1] =
- buffer1[ZIP_LH_OFF_CSIZE + 2] =
- buffer1[ZIP_LH_OFF_CSIZE + 3] = 0;
-
- h->szComp = encrypt ? ZIP_LOCAL_ENC_HEADER_SIZE : 0;
-
- // uncompressed size [22,23,24,25]
- setULong(h->szUncomp, buffer1, ZIP_LH_OFF_USIZE);
-
- // filename length
- QByteArray entryNameBytes = entryName.toAscii();
- int sz = entryNameBytes.size();
-
- buffer1[ZIP_LH_OFF_NAMELEN] = sz & 0xFF;
- buffer1[ZIP_LH_OFF_NAMELEN + 1] = (sz >> 8) & 0xFF;
-
- // extra field length
- buffer1[ZIP_LH_OFF_XLEN] = buffer1[ZIP_LH_OFF_XLEN + 1] = 0;
-
- // Store offset to write crc and compressed size
- h->lhOffset = device->pos();
- quint32 crcOffset = h->lhOffset + ZIP_LH_OFF_CRC;
-
- if (device->write(buffer1, ZIP_LOCAL_HEADER_SIZE) != ZIP_LOCAL_HEADER_SIZE)
- {
- delete h;
- return Zip::WriteFailed;
- }
-
- // Write out filename
- if (device->write(entryNameBytes) != sz)
- {
- delete h;
- return Zip::WriteFailed;
- }
-
- // Encryption keys
- quint32 keys[3] = { 0, 0, 0 };
-
- if (encrypt)
- {
- // **** encryption header ****
-
- // XOR with PI to ensure better random numbers
- // with poorly implemented rand() as suggested by Info-Zip
- srand(time(NULL) ^ 3141592654UL);
- int randByte;
-
- initKeys(keys);
- for (int i=0; i<10; ++i)
- {
- randByte = (rand() >> 7) & 0xff;
- buffer1[i] = decryptByte(keys[2]) ^ randByte;
- updateKeys(keys, randByte);
- }
-
- // Encrypt encryption header
- initKeys(keys);
- for (int i=0; i<10; ++i)
- {
- randByte = decryptByte(keys[2]);
- updateKeys(keys, buffer1[i]);
- buffer1[i] ^= randByte;
- }
-
- // We don't know the CRC at this time, so we use the modification time
- // as the last two bytes
- randByte = decryptByte(keys[2]);
- updateKeys(keys, h->modTime[0]);
- buffer1[10] ^= randByte;
-
- randByte = decryptByte(keys[2]);
- updateKeys(keys, h->modTime[1]);
- buffer1[11] ^= randByte;
-
- // Write out encryption header
- if (device->write(buffer1, ZIP_LOCAL_ENC_HEADER_SIZE) != ZIP_LOCAL_ENC_HEADER_SIZE)
- {
- delete h;
- return Zip::WriteFailed;
- }
- }
-
- qint64 written = 0;
- quint32 crc = crc32(0L, Z_NULL, 0);
-
- if (!dirOnly)
- {
- QFile actualFile(file.absoluteFilePath());
- if (!actualFile.open(QIODevice::ReadOnly))
- {
- qDebug() << QString("An error occurred while opening %1").arg(file.absoluteFilePath());
- return Zip::OpenFailed;
- }
-
- // Write file data
- qint64 read = 0;
- qint64 totRead = 0;
- qint64 toRead = actualFile.size();
-
- if (level == Zip::Store)
- {
- while ( (read = actualFile.read(buffer1, ZIP_READ_BUFFER)) > 0 )
- {
- crc = crc32(crc, uBuffer, read);
-
- if (password != 0)
- encryptBytes(keys, buffer1, read);
-
- if ( (written = device->write(buffer1, read)) != read )
- {
- actualFile.close();
- delete h;
- return Zip::WriteFailed;
- }
- }
- }
- else
- {
- z_stream zstr;
-
- // Initialize zalloc, zfree and opaque before calling the init function
- zstr.zalloc = Z_NULL;
- zstr.zfree = Z_NULL;
- zstr.opaque = Z_NULL;
-
- int zret;
-
- // Use deflateInit2 with negative windowBits to get raw compression
- if ((zret = deflateInit2_(
- &zstr,
- (int)level,
- Z_DEFLATED,
- -MAX_WBITS,
- 8,
- isPNGFile ? Z_RLE : Z_DEFAULT_STRATEGY,
- ZLIB_VERSION,
- sizeof(z_stream)
- )) != Z_OK )
- {
- actualFile.close();
- qDebug() << "Could not initialize zlib for compression";
- delete h;
- return Zip::ZlibError;
- }
-
- qint64 compressed;
-
- int flush = Z_NO_FLUSH;
-
- do
- {
- read = actualFile.read(buffer1, ZIP_READ_BUFFER);
- totRead += read;
-
- if (read == 0)
- break;
- if (read < 0)
- {
- actualFile.close();
- deflateEnd(&zstr);
- qDebug() << QString("Error while reading %1").arg(file.absoluteFilePath());
- delete h;
- return Zip::ReadFailed;
- }
-
- crc = crc32(crc, uBuffer, read);
-
- zstr.next_in = (Bytef*) buffer1;
- zstr.avail_in = (uInt)read;
-
- // Tell zlib if this is the last chunk we want to encode
- // by setting the flush parameter to Z_FINISH
- flush = (totRead == toRead) ? Z_FINISH : Z_NO_FLUSH;
-
- // Run deflate() on input until output buffer not full
- // finish compression if all of source has been read in
- do
- {
- zstr.next_out = (Bytef*) buffer2;
- zstr.avail_out = ZIP_READ_BUFFER;
-
- zret = deflate(&zstr, flush);
- // State not clobbered
- Q_ASSERT(zret != Z_STREAM_ERROR);
-
- // Write compressed data to file and empty buffer
- compressed = ZIP_READ_BUFFER - zstr.avail_out;
-
- if (password != 0)
- encryptBytes(keys, buffer2, compressed);
-
- if (device->write(buffer2, compressed) != compressed)
- {
- deflateEnd(&zstr);
- actualFile.close();
- qDebug() << QString("Error while writing %1").arg(file.absoluteFilePath());
- delete h;
- return Zip::WriteFailed;
- }
-
- written += compressed;
-
- } while (zstr.avail_out == 0);
-
- // All input will be used
- Q_ASSERT(zstr.avail_in == 0);
-
- } while (flush != Z_FINISH);
-
- // Stream will be complete
- Q_ASSERT(zret == Z_STREAM_END);
-
- deflateEnd(&zstr);
-
- } // if (level != STORE)
-
- actualFile.close();
- }
-
- // Store end of entry offset
- quint32 current = device->pos();
-
- // Update crc and compressed size in local header
- if (!device->seek(crcOffset))
- {
- delete h;
- return Zip::SeekFailed;
- }
-
- h->crc = dirOnly ? 0 : crc;
- h->szComp += written;
-
- setULong(h->crc, buffer1, 0);
- setULong(h->szComp, buffer1, 4);
- if ( device->write(buffer1, 8) != 8)
- {
- delete h;
- return Zip::WriteFailed;
- }
-
- // Seek to end of entry
- if (!device->seek(current))
- {
- delete h;
- return Zip::SeekFailed;
- }
-
- if ((h->gpFlag[0] & 8) == 8)
- {
- // Write data descriptor
-
- // Signature: PK\7\8
- buffer1[0] = 'P';
- buffer1[1] = 'K';
- buffer1[2] = 0x07;
- buffer1[3] = 0x08;
-
- // CRC
- setULong(h->crc, buffer1, ZIP_DD_OFF_CRC32);
-
- // Compressed size
- setULong(h->szComp, buffer1, ZIP_DD_OFF_CSIZE);
-
- // Uncompressed size
- setULong(h->szUncomp, buffer1, ZIP_DD_OFF_USIZE);
-
- if (device->write(buffer1, ZIP_DD_SIZE_WS) != ZIP_DD_SIZE_WS)
- {
- delete h;
- return Zip::WriteFailed;
- }
- }
-
- headers->insert(entryName, h);
- return Zip::Ok;
-}
-
-//! \internal
-int ZipPrivate::decryptByte(quint32 key2) const
-{
- quint16 temp = ((quint16)(key2) & 0xffff) | 2;
- return (int)(((temp * (temp ^ 1)) >> 8) & 0xff);
-}
-
-//! \internal Writes an quint32 (4 bytes) to a byte array at given offset.
-void ZipPrivate::setULong(quint32 v, char* buffer, unsigned int offset)
-{
- buffer[offset+3] = ((v >> 24) & 0xFF);
- buffer[offset+2] = ((v >> 16) & 0xFF);
- buffer[offset+1] = ((v >> 8) & 0xFF);
- buffer[offset] = (v & 0xFF);
-}
-
-//! \internal Initializes decryption keys using a password.
-void ZipPrivate::initKeys(quint32* keys) const
-{
- // Encryption keys initialization constants are taken from the
- // PKZip file format specification docs
- keys[0] = 305419896L;
- keys[1] = 591751049L;
- keys[2] = 878082192L;
-
- QByteArray pwdBytes = password.toAscii();
- int sz = pwdBytes.size();
- const char* ascii = pwdBytes.data();
-
- for (int i=0; i<sz; ++i)
- updateKeys(keys, (int)ascii[i]);
-}
-
-//! \internal Updates encryption keys.
-void ZipPrivate::updateKeys(quint32* keys, int c) const
-{
- keys[0] = CRC32(keys[0], c);
- keys[1] += keys[0] & 0xff;
- keys[1] = keys[1] * 134775813L + 1;
- keys[2] = CRC32(keys[2], ((int)keys[1]) >> 24);
-}
-
-//! \internal Encrypts a byte array.
-void ZipPrivate::encryptBytes(quint32* keys, char* buffer, qint64 read)
-{
- char t;
-
- for (int i=0; i<(int)read; ++i)
- {
- t = buffer[i];
- buffer[i] ^= decryptByte(keys[2]);
- updateKeys(keys, t);
- }
-}
-
-//! \internal Detects the best compression level for a given file extension.
-Zip::CompressionLevel ZipPrivate::detectCompressionByMime(const QString& ext)
-{
- // files really hard to compress
- if ((ext == "png") ||
- (ext == "jpg") ||
- (ext == "jpeg") ||
- (ext == "mp3") ||
- (ext == "ogg") ||
- (ext == "ogm") ||
- (ext == "avi") ||
- (ext == "mov") ||
- (ext == "rm") ||
- (ext == "ra") ||
- (ext == "zip") ||
- (ext == "rar") ||
- (ext == "bz2") ||
- (ext == "gz") ||
- (ext == "7z") ||
- (ext == "z") ||
- (ext == "jar")
- ) return Zip::Store;
-
- // files slow and hard to compress
- if ((ext == "exe") ||
- (ext == "bin") ||
- (ext == "rpm") ||
- (ext == "deb")
- ) return Zip::Deflate2;
-
- return Zip::Deflate9;
-}
-
-/*!
- Closes the current archive and writes out pending data.
-*/
-Zip::ErrorCode ZipPrivate::closeArchive()
-{
- // Close current archive by writing out central directory
- // and free up resources
-
- if (device == 0)
- return Zip::Ok;
-
- if (headers == 0)
- return Zip::Ok;
-
- const ZipEntryP* h;
-
- unsigned int sz;
- quint32 szCentralDir = 0;
- quint32 offCentralDir = device->pos();
-
- for (QMap<QString,ZipEntryP*>::ConstIterator itr = headers->constBegin(); itr != headers->constEnd(); ++itr)
- {
- h = itr.value();
-
- // signature
- buffer1[0] = 'P';
- buffer1[1] = 'K';
- buffer1[2] = 0x01;
- buffer1[3] = 0x02;
-
- // version made by (currently only MS-DOS/FAT - no symlinks or other stuff supported)
- buffer1[ZIP_CD_OFF_MADEBY] = buffer1[ZIP_CD_OFF_MADEBY + 1] = 0;
-
- // version needed to extract
- buffer1[ZIP_CD_OFF_VERSION] = ZIP_VERSION;
- buffer1[ZIP_CD_OFF_VERSION + 1] = 0;
-
- // general purpose flag
- buffer1[ZIP_CD_OFF_GPFLAG] = h->gpFlag[0];
- buffer1[ZIP_CD_OFF_GPFLAG + 1] = h->gpFlag[1];
-
- // compression method
- buffer1[ZIP_CD_OFF_CMET] = h->compMethod & 0xFF;
- buffer1[ZIP_CD_OFF_CMET + 1] = (h->compMethod >> 8) & 0xFF;
-
- // last mod file time
- buffer1[ZIP_CD_OFF_MODT] = h->modTime[0];
- buffer1[ZIP_CD_OFF_MODT + 1] = h->modTime[1];
-
- // last mod file date
- buffer1[ZIP_CD_OFF_MODD] = h->modDate[0];
- buffer1[ZIP_CD_OFF_MODD + 1] = h->modDate[1];
-
- // crc (4bytes) [16,17,18,19]
- setULong(h->crc, buffer1, ZIP_CD_OFF_CRC);
-
- // compressed size (4bytes: [20,21,22,23])
- setULong(h->szComp, buffer1, ZIP_CD_OFF_CSIZE);
-
- // uncompressed size [24,25,26,27]
- setULong(h->szUncomp, buffer1, ZIP_CD_OFF_USIZE);
-
- // filename
- QByteArray fileNameBytes = itr.key().toAscii();
- sz = fileNameBytes.size();
- buffer1[ZIP_CD_OFF_NAMELEN] = sz & 0xFF;
- buffer1[ZIP_CD_OFF_NAMELEN + 1] = (sz >> 8) & 0xFF;
-
- // extra field length
- buffer1[ZIP_CD_OFF_XLEN] = buffer1[ZIP_CD_OFF_XLEN + 1] = 0;
-
- // file comment length
- buffer1[ZIP_CD_OFF_COMMLEN] = buffer1[ZIP_CD_OFF_COMMLEN + 1] = 0;
-
- // disk number start
- buffer1[ZIP_CD_OFF_DISKSTART] = buffer1[ZIP_CD_OFF_DISKSTART + 1] = 0;
-
- // internal file attributes
- buffer1[ZIP_CD_OFF_IATTR] = buffer1[ZIP_CD_OFF_IATTR + 1] = 0;
-
- // external file attributes
- buffer1[ZIP_CD_OFF_EATTR] =
- buffer1[ZIP_CD_OFF_EATTR + 1] =
- buffer1[ZIP_CD_OFF_EATTR + 2] =
- buffer1[ZIP_CD_OFF_EATTR + 3] = 0;
-
- // relative offset of local header [42->45]
- setULong(h->lhOffset, buffer1, ZIP_CD_OFF_LHOFF);
-
- if (device->write(buffer1, ZIP_CD_SIZE) != ZIP_CD_SIZE)
- {
- //! \todo See if we can detect QFile objects using the Qt Meta Object System
- /*
- if (!device->remove())
- qDebug() << tr("Unable to delete corrupted archive: %1").arg(device->fileName());
- */
- return Zip::WriteFailed;
- }
-
- // Write out filename
- if ((unsigned int)device->write(fileNameBytes) != sz)
- {
- //! \todo SAME AS ABOVE: See if we can detect QFile objects using the Qt Meta Object System
- /*
- if (!device->remove())
- qDebug() << tr("Unable to delete corrupted archive: %1").arg(device->fileName());
- */
- return Zip::WriteFailed;
- }
-
- szCentralDir += (ZIP_CD_SIZE + sz);
-
- } // central dir headers loop
-
-
- // Write end of central directory
-
- // signature
- buffer1[0] = 'P';
- buffer1[1] = 'K';
- buffer1[2] = 0x05;
- buffer1[3] = 0x06;
-
- // number of this disk
- buffer1[ZIP_EOCD_OFF_DISKNUM] = buffer1[ZIP_EOCD_OFF_DISKNUM + 1] = 0;
-
- // number of disk with central directory
- buffer1[ZIP_EOCD_OFF_CDDISKNUM] = buffer1[ZIP_EOCD_OFF_CDDISKNUM + 1] = 0;
-
- // number of entries in this disk
- sz = headers->count();
- buffer1[ZIP_EOCD_OFF_ENTRIES] = sz & 0xFF;
- buffer1[ZIP_EOCD_OFF_ENTRIES + 1] = (sz >> 8) & 0xFF;
-
- // total number of entries
- buffer1[ZIP_EOCD_OFF_CDENTRIES] = buffer1[ZIP_EOCD_OFF_ENTRIES];
- buffer1[ZIP_EOCD_OFF_CDENTRIES + 1] = buffer1[ZIP_EOCD_OFF_ENTRIES + 1];
-
- // size of central directory [12->15]
- setULong(szCentralDir, buffer1, ZIP_EOCD_OFF_CDSIZE);
-
- // central dir offset [16->19]
- setULong(offCentralDir, buffer1, ZIP_EOCD_OFF_CDOFF);
-
- // ZIP file comment length
- QByteArray commentBytes = comment.toAscii();
- quint16 commentLength = commentBytes.size();
-
- if (commentLength == 0)
- {
- buffer1[ZIP_EOCD_OFF_COMMLEN] = buffer1[ZIP_EOCD_OFF_COMMLEN + 1] = 0;
- }
- else
- {
- buffer1[ZIP_EOCD_OFF_COMMLEN] = commentLength & 0xFF;
- buffer1[ZIP_EOCD_OFF_COMMLEN + 1] = (commentLength >> 8) & 0xFF;
- }
-
- if (device->write(buffer1, ZIP_EOCD_SIZE) != ZIP_EOCD_SIZE)
- {
- //! \todo SAME AS ABOVE: See if we can detect QFile objects using the Qt Meta Object System
- /*
- if (!device->remove())
- qDebug() << tr("Unable to delete corrupted archive: %1").arg(device->fileName());
- */
- return Zip::WriteFailed;
- }
-
- if (commentLength != 0)
- {
- if ((unsigned int)device->write(commentBytes) != commentLength)
- {
- //! \todo SAME AS ABOVE: See if we can detect QFile objects using the Qt Meta Object System
- /*
- if (!device->remove())
- qDebug() << tr("Unable to delete corrupted archive: %1").arg(device->fileName());
- */
- return Zip::WriteFailed;
- }
- }
-
- return Zip::Ok;
-}
-
-//! \internal
-void ZipPrivate::reset()
-{
- comment.clear();
-
- if (headers != 0)
- {
- qDeleteAll(*headers);
- delete headers;
- headers = 0;
- }
-
- delete device; device = 0;
-}
-
-//! \internal Returns the path of the parent directory
-QString ZipPrivate::extractRoot(const QString& p)
-{
- QDir d(QDir::cleanPath(p));
- if (!d.exists())
- return QString();
-
- if (!d.cdUp())
- return QString();
-
- return d.absolutePath();
-}