diff --git a/cockatrice/src/lzma/decompress.cpp b/cockatrice/src/lzma/decompress.cpp deleted file mode 100644 index 718cde207..000000000 --- a/cockatrice/src/lzma/decompress.cpp +++ /dev/null @@ -1,250 +0,0 @@ -/* - * Simple routing to extract a single file from a xz archive - * Heavily based from doc/examples/02_decompress.c obtained from - * the official xz git repository: git.tukaani.org/xz.git - * The license from the original file header follows - * - * Author: Lasse Collin - * This file has been put into the public domain. - * You can do whatever you want with this file. - */ - - -#include -#include - -#include "decompress.h" - -XzDecompressor::XzDecompressor(QObject *parent) - : QObject(parent) -{ - -} - -bool XzDecompressor::decompress(QBuffer *in, QBuffer *out) -{ - lzma_stream strm = LZMA_STREAM_INIT; - bool success; - - if (!init_decoder(&strm)) { - return false; - } - - success = internal_decompress(&strm, in, out); - - // Free the memory allocated for the decoder. This only needs to be - // done after the last file. - lzma_end(&strm); - - return success; -} - -bool XzDecompressor::init_decoder(lzma_stream *strm) -{ - // Initialize a .xz decoder. The decoder supports a memory usage limit - // and a set of flags. - // - // The memory usage of the decompressor depends on the settings used - // to compress a .xz file. It can vary from less than a megabyte to - // a few gigabytes, but in practice (at least for now) it rarely - // exceeds 65 MiB because that's how much memory is required to - // decompress files created with "xz -9". Settings requiring more - // memory take extra effort to use and don't (at least for now) - // provide significantly better compression in most cases. - // - // Memory usage limit is useful if it is important that the - // decompressor won't consume gigabytes of memory. The need - // for limiting depends on the application. In this example, - // no memory usage limiting is used. This is done by setting - // the limit to UINT64_MAX. - // - // The .xz format allows concatenating compressed files as is: - // - // echo foo | xz > foobar.xz - // echo bar | xz >> foobar.xz - // - // When decompressing normal standalone .xz files, LZMA_CONCATENATED - // should always be used to support decompression of concatenated - // .xz files. If LZMA_CONCATENATED isn't used, the decoder will stop - // after the first .xz stream. This can be useful when .xz data has - // been embedded inside another file format. - // - // Flags other than LZMA_CONCATENATED are supported too, and can - // be combined with bitwise-or. See lzma/container.h - // (src/liblzma/api/lzma/container.h in the source package or e.g. - // /usr/include/lzma/container.h depending on the install prefix) - // for details. - lzma_ret ret = lzma_stream_decoder( - strm, UINT64_MAX, LZMA_CONCATENATED); - - // Return successfully if the initialization went fine. - if (ret == LZMA_OK) - return true; - - // Something went wrong. The possible errors are documented in - // lzma/container.h (src/liblzma/api/lzma/container.h in the source - // package or e.g. /usr/include/lzma/container.h depending on the - // install prefix). - // - // Note that LZMA_MEMLIMIT_ERROR is never possible here. If you - // specify a very tiny limit, the error will be delayed until - // the first headers have been parsed by a call to lzma_code(). - const char *msg; - switch (ret) { - case LZMA_MEM_ERROR: - msg = "Memory allocation failed"; - break; - - case LZMA_OPTIONS_ERROR: - msg = "Unsupported decompressor flags"; - break; - - default: - // This is most likely LZMA_PROG_ERROR indicating a bug in - // this program or in liblzma. It is inconvenient to have a - // separate error message for errors that should be impossible - // to occur, but knowing the error code is important for - // debugging. That's why it is good to print the error code - // at least when there is no good error message to show. - msg = "Unknown error, possibly a bug"; - break; - } - - qDebug() << "Error initializing the decoder:" << msg << "(error code " << ret << ")"; - return false; -} - - -bool XzDecompressor::internal_decompress(lzma_stream *strm, QBuffer *in, QBuffer *out) -{ - // When LZMA_CONCATENATED flag was used when initializing the decoder, - // we need to tell lzma_code() when there will be no more input. - // This is done by setting action to LZMA_FINISH instead of LZMA_RUN - // in the same way as it is done when encoding. - // - // When LZMA_CONCATENATED isn't used, there is no need to use - // LZMA_FINISH to tell when all the input has been read, but it - // is still OK to use it if you want. When LZMA_CONCATENATED isn't - // used, the decoder will stop after the first .xz stream. In that - // case some unused data may be left in strm->next_in. - lzma_action action = LZMA_RUN; - - uint8_t inbuf[BUFSIZ]; - uint8_t outbuf[BUFSIZ]; - qint64 bytesAvailable; - - strm->next_in = NULL; - strm->avail_in = 0; - strm->next_out = outbuf; - strm->avail_out = sizeof(outbuf); - while (true) { - if (strm->avail_in == 0) { - strm->next_in = inbuf; - bytesAvailable = in->bytesAvailable(); - if(bytesAvailable == 0) { - // Once the end of the input file has been reached, - // we need to tell lzma_code() that no more input - // will be coming. As said before, this isn't required - // if the LZMA_CONCATENATED flag isn't used when - // initializing the decoder. - action = LZMA_FINISH; - } else if(bytesAvailable >= BUFSIZ) { - in->read((char*) inbuf, BUFSIZ); - strm->avail_in = BUFSIZ; - } else { - in->read((char*) inbuf, bytesAvailable); - strm->avail_in = bytesAvailable; - } - } - - lzma_ret ret = lzma_code(strm, action); - - if (strm->avail_out == 0 || ret == LZMA_STREAM_END) { - qint64 write_size = sizeof(outbuf) - strm->avail_out; - - if (out->write((char *) outbuf, write_size) != write_size) { - qDebug() << "Write error"; - return false; - } - - strm->next_out = outbuf; - strm->avail_out = sizeof(outbuf); - } - - if (ret != LZMA_OK) { - // Once everything has been decoded successfully, the - // return value of lzma_code() will be LZMA_STREAM_END. - // - // It is important to check for LZMA_STREAM_END. Do not - // assume that getting ret != LZMA_OK would mean that - // everything has gone well or that when you aren't - // getting more output it must have successfully - // decoded everything. - if (ret == LZMA_STREAM_END) - return true; - - // It's not LZMA_OK nor LZMA_STREAM_END, - // so it must be an error code. See lzma/base.h - // (src/liblzma/api/lzma/base.h in the source package - // or e.g. /usr/include/lzma/base.h depending on the - // install prefix) for the list and documentation of - // possible values. Many values listen in lzma_ret - // enumeration aren't possible in this example, but - // can be made possible by enabling memory usage limit - // or adding flags to the decoder initialization. - const char *msg; - switch (ret) { - case LZMA_MEM_ERROR: - msg = "Memory allocation failed"; - break; - - case LZMA_FORMAT_ERROR: - // .xz magic bytes weren't found. - msg = "The input is not in the .xz format"; - break; - - case LZMA_OPTIONS_ERROR: - // For example, the headers specify a filter - // that isn't supported by this liblzma - // version (or it hasn't been enabled when - // building liblzma, but no-one sane does - // that unless building liblzma for an - // embedded system). Upgrading to a newer - // liblzma might help. - // - // Note that it is unlikely that the file has - // accidentally became corrupt if you get this - // error. The integrity of the .xz headers is - // always verified with a CRC32, so - // unintentionally corrupt files can be - // distinguished from unsupported files. - msg = "Unsupported compression options"; - break; - - case LZMA_DATA_ERROR: - msg = "Compressed file is corrupt"; - break; - - case LZMA_BUF_ERROR: - // Typically this error means that a valid - // file has got truncated, but it might also - // be a damaged part in the file that makes - // the decoder think the file is truncated. - // If you prefer, you can use the same error - // message for this as for LZMA_DATA_ERROR. - msg = "Compressed file is truncated or " - "otherwise corrupt"; - break; - - default: - // This is most likely LZMA_PROG_ERROR. - msg = "Unknown error, possibly a bug"; - break; - } - - qDebug() << "Decoder error:" << msg << "(error code " << ret << ")"; - return false; - } - } -} - diff --git a/cockatrice/src/lzma/decompress.h b/cockatrice/src/lzma/decompress.h deleted file mode 100644 index f0e315f8b..000000000 --- a/cockatrice/src/lzma/decompress.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef XZ_DECOMPRESS_H -#define XZ_DECOMPRESS_H - -#include -#include - -class XzDecompressor : public QObject -{ - Q_OBJECT -public: - XzDecompressor(QObject *parent = 0); - ~XzDecompressor() { }; - bool decompress(QBuffer *in, QBuffer *out); -private: - bool init_decoder(lzma_stream *strm); - bool internal_decompress(lzma_stream *strm, QBuffer *in, QBuffer *out); -}; - -#endif diff --git a/cockatrice/src/qt-json/json.cpp b/cockatrice/src/qt-json/json.cpp deleted file mode 100644 index 2fffd0f70..000000000 --- a/cockatrice/src/qt-json/json.cpp +++ /dev/null @@ -1,573 +0,0 @@ -/* Copyright 2011 Eeli Reilin. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY ''AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL EELI REILIN OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, - * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation - * are those of the authors and should not be interpreted as representing - * official policies, either expressed or implied, of Eeli Reilin. - */ - -/** - * \file json.cpp - */ - -#include "json.h" - -#include -#include - -namespace QtJson -{ - -static QString sanitizeString(QString str) -{ - str.replace(QLatin1String("\\"), QLatin1String("\\\\")); - str.replace(QLatin1String("\""), QLatin1String("\\\"")); - str.replace(QLatin1String("\b"), QLatin1String("\\b")); - str.replace(QLatin1String("\f"), QLatin1String("\\f")); - str.replace(QLatin1String("\n"), QLatin1String("\\n")); - str.replace(QLatin1String("\r"), QLatin1String("\\r")); - str.replace(QLatin1String("\t"), QLatin1String("\\t")); - return QString(QLatin1String("\"%1\"")).arg(str); -} - -static QByteArray join(const QList &list, const QByteArray &sep) -{ - QByteArray res; - for (const QByteArray &i : list) { - if (!res.isEmpty()) { - res += sep; - } - res += i; - } - return res; -} - -/** - * parse - */ -QVariant Json::parse(const QString &json) -{ - bool success = true; - return Json::parse(json, success); -} - -/** - * parse - */ -QVariant Json::parse(const QString &json, bool &success) -{ - success = true; - - // Return an empty QVariant if the JSON data is either null or empty - if (!json.isNull() || !json.isEmpty()) { - // We'll start from index 0 - int index = 0; - - // Parse the first value - QVariant value = Json::parseValue(json, index, success); - - // Return the parsed value - return value; - } else { - // Return the empty QVariant - return QVariant(); - } -} - -QByteArray Json::serialize(const QVariant &data) -{ - bool success = true; - return Json::serialize(data, success); -} - -QByteArray Json::serialize(const QVariant &data, bool &success) -{ - QByteArray str; - success = true; - - if (!data.isValid()) // invalid or null? - { - str = "null"; - } -#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) - else if ((data.typeId() == QMetaType::Type::QVariantList) || - (data.typeId() == QMetaType::Type::QStringList)) // variant is a list? -#else - else if ((data.type() == QVariant::List) || (data.type() == QVariant::StringList)) // variant is a list? -#endif - { - QList values; - const QVariantList list = data.toList(); - for (const QVariant &v : list) { - QByteArray serializedValue = serialize(v); - if (serializedValue.isNull()) { - success = false; - break; - } - values << serializedValue; - } - - str = "[ " + join(values, ", ") + " ]"; - } -#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) - else if ((data.typeId() == QMetaType::Type::QVariantHash)) // variant is a list? -#else - else if (data.type() == QVariant::Hash) // variant is a hash? -#endif - { - const QVariantHash vhash = data.toHash(); - QHashIterator it(vhash); - str = "{ "; - QList pairs; - - while (it.hasNext()) { - it.next(); - QByteArray serializedValue = serialize(it.value()); - - if (serializedValue.isNull()) { - success = false; - break; - } - - pairs << sanitizeString(it.key()).toUtf8() + " : " + serializedValue; - } - - str += join(pairs, ", "); - str += " }"; - } -#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) - else if ((data.typeId() == QMetaType::Type::QVariantMap)) // variant is a list? -#else - else if (data.type() == QVariant::Map) // variant is a map? -#endif - { - const QVariantMap vmap = data.toMap(); - QMapIterator it(vmap); - str = "{ "; - QList pairs; - while (it.hasNext()) { - it.next(); - QByteArray serializedValue = serialize(it.value()); - if (serializedValue.isNull()) { - success = false; - break; - } - pairs << sanitizeString(it.key()).toUtf8() + " : " + serializedValue; - } - str += join(pairs, ", "); - str += " }"; - } -#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) - else if ((data.typeId() == QMetaType::Type::QString) || - (data.typeId() == QMetaType::Type::QByteArray)) // variant is a list? -#else - else if ((data.type() == QVariant::String) || (data.type() == QVariant::ByteArray)) // a string or a byte array? -#endif - { - str = sanitizeString(data.toString()).toUtf8(); - } -#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) - else if (data.typeId() == QMetaType::Type::Double) -#else - else if (data.type() == QVariant::Double) // double? -#endif - { - str = QByteArray::number(data.toDouble(), 'g', 20); - if (!str.contains(".") && !str.contains("e")) { - str += ".0"; - } - } -#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) - else if (data.typeId() == QMetaType::Type::Bool) -#else - else if (data.type() == QVariant::Bool) // boolean value? -#endif - { - str = data.toBool() ? "true" : "false"; - } -#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) - else if (data.typeId() == QMetaType::Type::ULongLong) -#else - else if (data.type() == QVariant::ULongLong) // large unsigned number? -#endif - { - str = QByteArray::number(data.value()); - } else if (data.canConvert()) // any signed number? - { - str = QByteArray::number(data.value()); - } else if (data.canConvert()) { - str = QString::number(data.value()).toUtf8(); - } else if (data.canConvert()) // can value be converted to string? - { - // this will catch QDate, QDateTime, QUrl, ... - str = sanitizeString(data.toString()).toUtf8(); - } else { - success = false; - } - if (success) { - return str; - } else { - return QByteArray(); - } -} - -/** - * parseValue - */ -QVariant Json::parseValue(const QString &json, int &index, bool &success) -{ - // Determine what kind of data we should parse by - // checking out the upcoming token - switch (Json::lookAhead(json, index)) { - case JsonTokenString: - return Json::parseString(json, index, success); - case JsonTokenNumber: - return Json::parseNumber(json, index); - case JsonTokenCurlyOpen: - return Json::parseObject(json, index, success); - case JsonTokenSquaredOpen: - return Json::parseArray(json, index, success); - case JsonTokenTrue: - Json::nextToken(json, index); - return QVariant(true); - case JsonTokenFalse: - Json::nextToken(json, index); - return QVariant(false); - case JsonTokenNull: - Json::nextToken(json, index); - return QVariant(); - case JsonTokenNone: - break; - } - - // If there were no tokens, flag the failure and return an empty QVariant - success = false; - return QVariant(); -} - -/** - * parseObject - */ -QVariant Json::parseObject(const QString &json, int &index, bool &success) -{ - QVariantMap map; - int token; - - // Get rid of the whitespace and increment index - Json::nextToken(json, index); - - // Loop through all of the key/value pairs of the object - bool done = false; - while (!done) { - // Get the upcoming token - token = Json::lookAhead(json, index); - - if (token == JsonTokenNone) { - success = false; - return QVariantMap(); - } else if (token == JsonTokenComma) { - Json::nextToken(json, index); - } else if (token == JsonTokenCurlyClose) { - Json::nextToken(json, index); - return map; - } else { - // Parse the key/value pair's name - QString name = Json::parseString(json, index, success).toString(); - - if (!success) { - return QVariantMap(); - } - - // Get the next token - token = Json::nextToken(json, index); - - // If the next token is not a colon, flag the failure - // return an empty QVariant - if (token != JsonTokenColon) { - success = false; - return QVariant(QVariantMap()); - } - - // Parse the key/value pair's value - QVariant value = Json::parseValue(json, index, success); - - if (!success) { - return QVariantMap(); - } - - // Assign the value to the key in the map - map[name] = value; - } - } - - // Return the map successfully - return QVariant(map); -} - -/** - * parseArray - */ -QVariant Json::parseArray(const QString &json, int &index, bool &success) -{ - QVariantList list; - - Json::nextToken(json, index); - - bool done = false; - while (!done) { - int token = Json::lookAhead(json, index); - - if (token == JsonTokenNone) { - success = false; - return QVariantList(); - } else if (token == JsonTokenComma) { - Json::nextToken(json, index); - } else if (token == JsonTokenSquaredClose) { - Json::nextToken(json, index); - break; - } else { - QVariant value = Json::parseValue(json, index, success); - - if (!success) { - return QVariantList(); - } - - list.push_back(value); - } - } - - return QVariant(list); -} - -/** - * parseString - */ -QVariant Json::parseString(const QString &json, int &index, bool &success) -{ - QString s; - QChar c; - - Json::eatWhitespace(json, index); - - c = json[index++]; - - bool complete = false; - while (!complete) { - if (index == json.size()) { - break; - } - - c = json[index++]; - - if (c == '\"') { - complete = true; - break; - } else if (c == '\\') { - if (index == json.size()) { - break; - } - - c = json[index++]; - - if (c == '\"') { - s.append('\"'); - } else if (c == '\\') { - s.append('\\'); - } else if (c == '/') { - s.append('/'); - } else if (c == 'b') { - s.append('\b'); - } else if (c == 'f') { - s.append('\f'); - } else if (c == 'n') { - s.append('\n'); - } else if (c == 'r') { - s.append('\r'); - } else if (c == 't') { - s.append('\t'); - } else if (c == 'u') { - int remainingLength = json.size() - index; - - if (remainingLength >= 4) { - QString unicodeStr = json.mid(index, 4); - - int symbol = unicodeStr.toInt(0, 16); - - s.append(QChar(symbol)); - - index += 4; - } else { - break; - } - } - } else { - s.append(c); - } - } - - if (!complete) { - success = false; - return QVariant(); - } - - return QVariant(s); -} - -/** - * parseNumber - */ -QVariant Json::parseNumber(const QString &json, int &index) -{ - Json::eatWhitespace(json, index); - - int lastIndex = Json::lastIndexOfNumber(json, index); - int charLength = (lastIndex - index) + 1; - QString numberStr; - - numberStr = json.mid(index, charLength); - - index = lastIndex + 1; - - if (numberStr.contains('.')) { - return QVariant(numberStr.toDouble(NULL)); - } else if (numberStr.startsWith('-')) { - return QVariant(numberStr.toLongLong(NULL)); - } else { - return QVariant(numberStr.toULongLong(NULL)); - } -} - -/** - * lastIndexOfNumber - */ -int Json::lastIndexOfNumber(const QString &json, int index) -{ - static const QString numericCharacters("0123456789+-.eE"); - int lastIndex; - - for (lastIndex = index; lastIndex < json.size(); lastIndex++) { - if (numericCharacters.indexOf(json[lastIndex]) == -1) { - break; - } - } - - return lastIndex - 1; -} - -/** - * eatWhitespace - */ -void Json::eatWhitespace(const QString &json, int &index) -{ - static const QString whitespaceChars(" \t\n\r"); - for (; index < json.size(); index++) { - if (whitespaceChars.indexOf(json[index]) == -1) { - break; - } - } -} - -/** - * lookAhead - */ -int Json::lookAhead(const QString &json, int index) -{ - int saveIndex = index; - return Json::nextToken(json, saveIndex); -} - -/** - * nextToken - */ -int Json::nextToken(const QString &json, int &index) -{ - Json::eatWhitespace(json, index); - - if (index == json.size()) { - return JsonTokenNone; - } - - QChar c = json[index]; - index++; - switch (c.toLatin1()) { - case '{': - return JsonTokenCurlyOpen; - case '}': - return JsonTokenCurlyClose; - case '[': - return JsonTokenSquaredOpen; - case ']': - return JsonTokenSquaredClose; - case ',': - return JsonTokenComma; - case '"': - return JsonTokenString; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - case '-': - return JsonTokenNumber; - case ':': - return JsonTokenColon; - } - - index--; - - int remainingLength = json.size() - index; - - // True - if (remainingLength >= 4) { - if (json[index] == 't' && json[index + 1] == 'r' && json[index + 2] == 'u' && json[index + 3] == 'e') { - index += 4; - return JsonTokenTrue; - } - } - - // False - if (remainingLength >= 5) { - if (json[index] == 'f' && json[index + 1] == 'a' && json[index + 2] == 'l' && json[index + 3] == 's' && - json[index + 4] == 'e') { - index += 5; - return JsonTokenFalse; - } - } - - // Null - if (remainingLength >= 4) { - if (json[index] == 'n' && json[index + 1] == 'u' && json[index + 2] == 'l' && json[index + 3] == 'l') { - index += 4; - return JsonTokenNull; - } - } - - return JsonTokenNone; -} - -} // namespace QtJson diff --git a/cockatrice/src/qt-json/json.h b/cockatrice/src/qt-json/json.h deleted file mode 100644 index cf0499d4e..000000000 --- a/cockatrice/src/qt-json/json.h +++ /dev/null @@ -1,204 +0,0 @@ -/* Copyright 2011 Eeli Reilin. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY ''AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL EELI REILIN OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, - * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation - * are those of the authors and should not be interpreted as representing - * official policies, either expressed or implied, of Eeli Reilin. - */ - -/** - * \file json.h - */ - -#ifndef JSON_H -#define JSON_H - -#include -#include - -namespace QtJson -{ - -/** - * \enum JsonToken - */ -enum JsonToken -{ - JsonTokenNone = 0, - JsonTokenCurlyOpen = 1, - JsonTokenCurlyClose = 2, - JsonTokenSquaredOpen = 3, - JsonTokenSquaredClose = 4, - JsonTokenColon = 5, - JsonTokenComma = 6, - JsonTokenString = 7, - JsonTokenNumber = 8, - JsonTokenTrue = 9, - JsonTokenFalse = 10, - JsonTokenNull = 11 -}; - -/** - * \class Json - * \brief A JSON data parser - * - * Json parses a JSON data into a QVariant hierarchy. - */ -class Json -{ - public: - /** - * Parse a JSON string - * - * \param json The JSON data - */ - static QVariant parse(const QString &json); - - /** - * Parse a JSON string - * - * \param json The JSON data - * \param success The success of the parsing - */ - static QVariant parse(const QString &json, bool &success); - - /** - * This method generates a textual JSON representation - * - * \param data The JSON data generated by the parser. - * \param success The success of the serialization - */ - static QByteArray serialize(const QVariant &data); - - /** - * This method generates a textual JSON representation - * - * \param data The JSON data generated by the parser. - * \param success The success of the serialization - * - * \return QByteArray Textual JSON representation - */ - static QByteArray serialize(const QVariant &data, bool &success); - - private: - /** - * Parses a value starting from index - * - * \param json The JSON data - * \param index The start index - * \param success The success of the parse process - * - * \return QVariant The parsed value - */ - static QVariant parseValue(const QString &json, int &index, - bool &success); - - /** - * Parses an object starting from index - * - * \param json The JSON data - * \param index The start index - * \param success The success of the object parse - * - * \return QVariant The parsed object map - */ - static QVariant parseObject(const QString &json, int &index, - bool &success); - - /** - * Parses an array starting from index - * - * \param json The JSON data - * \param index The starting index - * \param success The success of the array parse - * - * \return QVariant The parsed variant array - */ - static QVariant parseArray(const QString &json, int &index, - bool &success); - - /** - * Parses a string starting from index - * - * \param json The JSON data - * \param index The starting index - * \param success The success of the string parse - * - * \return QVariant The parsed string - */ - static QVariant parseString(const QString &json, int &index, - bool &success); - - /** - * Parses a number starting from index - * - * \param json The JSON data - * \param index The starting index - * - * \return QVariant The parsed number - */ - static QVariant parseNumber(const QString &json, int &index); - - /** - * Get the last index of a number starting from index - * - * \param json The JSON data - * \param index The starting index - * - * \return The last index of the number - */ - static int lastIndexOfNumber(const QString &json, int index); - - /** - * Skip unwanted whitespace symbols starting from index - * - * \param json The JSON data - * \param index The start index - */ - static void eatWhitespace(const QString &json, int &index); - - /** - * Check what token lies ahead - * - * \param json The JSON data - * \param index The starting index - * - * \return int The upcoming token - */ - static int lookAhead(const QString &json, int index); - - /** - * Get the next JSON token - * - * \param json The JSON data - * \param index The starting index - * - * \return int The next JSON token - */ - static int nextToken(const QString &json, int &index); -}; - - -} //end namespace - -#endif //JSON_H diff --git a/cockatrice/src/zip/unzip.cpp b/cockatrice/src/zip/unzip.cpp deleted file mode 100755 index 1e5910051..000000000 --- a/cockatrice/src/zip/unzip.cpp +++ /dev/null @@ -1,1425 +0,0 @@ -/**************************************************************************** -** Filename: unzip.cpp -** Last updated [dd/mm/yyyy]: 08/07/2010 -** -** pkzip 2.0 decompression. -** -** 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-2012 Angius Fabrizio. All rights reserved. -** -** This file is part of the OSDaB project (http://osdab.42cows.org/). -** -** 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 "unzip.h" -#include "unzip_p.h" -#include "zipentry_p.h" - -#include -#include -#include -#include -#include - -// You can remove this #include if you replace the qDebug() statements. -#include - -/*! - \class UnZip unzip.h - - \brief PKZip 2.0 file decompression. - Compatibility with later versions is not ensured as they may use - unsupported compression algorithms. - Versions after 2.7 may have an incompatible header format and thus be - completely incompatible. -*/ - -/*! \enum UnZip::ErrorCode The result of a decompression operation. - \value UnZip::Ok No error occurred. - \value UnZip::ZlibInit Failed to init or load the zlib library. - \value UnZip::ZlibError The zlib library returned some error. - \value UnZip::OpenFailed Unable to create or open a device. - \value UnZip::PartiallyCorrupted Corrupted zip archive - some files could be extracted. - \value UnZip::Corrupted Corrupted or invalid zip archive. - \value UnZip::WrongPassword Unable to decrypt a password protected file. - \value UnZip::NoOpenArchive No archive has been opened yet. - \value UnZip::FileNotFound Unable to find the requested file in the archive. - \value UnZip::ReadFailed Reading of a file failed. - \value UnZip::WriteFailed Writing of a file failed. - \value UnZip::SeekFailed Seek failed. - \value UnZip::CreateDirFailed Could not create a directory. - \value UnZip::InvalidDevice A null device has been passed as parameter. - \value UnZip::InvalidArchive This is not a valid (or supported) ZIP archive. - \value UnZip::HeaderConsistencyError Local header record info does not match with the central directory record info. The archive may be corrupted. - - \value UnZip::Skip Internal use only. - \value UnZip::SkipAll Internal use only. -*/ - -/*! \enum UnZip::ExtractionOptions Some options for the file extraction methods. - \value UnZip::ExtractPaths Default. Does not ignore the path of the zipped files. - \value UnZip::SkipPaths Default. Ignores the path of the zipped files and extracts them all to the same root directory. - \value UnZip::VerifyOnly Doesn't actually extract files. - \value UnZip::NoSilentDirectoryCreation Doesn't attempt to silently create missing output directories. -*/ - -//! Local header size (excluding signature, excluding variable length fields) -#define UNZIP_LOCAL_HEADER_SIZE 26 -//! Central Directory file entry size (excluding signature, excluding variable length fields) -#define UNZIP_CD_ENTRY_SIZE_NS 42 -//! Data descriptor size (excluding signature) -#define UNZIP_DD_SIZE 12 -//! End Of Central Directory size (including signature, excluding variable length fields) -#define UNZIP_EOCD_SIZE 22 -//! Local header entry encryption header size -#define UNZIP_LOCAL_ENC_HEADER_SIZE 12 - -// Some offsets inside a CD record (excluding signature) -#define UNZIP_CD_OFF_VERSION_MADE 0 -#define UNZIP_CD_OFF_VERSION 2 -#define UNZIP_CD_OFF_GPFLAG 4 -#define UNZIP_CD_OFF_CMETHOD 6 -#define UNZIP_CD_OFF_MODT 8 -#define UNZIP_CD_OFF_MODD 10 -#define UNZIP_CD_OFF_CRC32 12 -#define UNZIP_CD_OFF_CSIZE 16 -#define UNZIP_CD_OFF_USIZE 20 -#define UNZIP_CD_OFF_NAMELEN 24 -#define UNZIP_CD_OFF_XLEN 26 -#define UNZIP_CD_OFF_COMMLEN 28 -#define UNZIP_CD_OFF_LHOFFSET 38 - -// Some offsets inside a local header record (excluding signature) -#define UNZIP_LH_OFF_VERSION 0 -#define UNZIP_LH_OFF_GPFLAG 2 -#define UNZIP_LH_OFF_CMETHOD 4 -#define UNZIP_LH_OFF_MODT 6 -#define UNZIP_LH_OFF_MODD 8 -#define UNZIP_LH_OFF_CRC32 10 -#define UNZIP_LH_OFF_CSIZE 14 -#define UNZIP_LH_OFF_USIZE 18 -#define UNZIP_LH_OFF_NAMELEN 22 -#define UNZIP_LH_OFF_XLEN 24 - -// Some offsets inside a data descriptor record (excluding signature) -#define UNZIP_DD_OFF_CRC32 0 -#define UNZIP_DD_OFF_CSIZE 4 -#define UNZIP_DD_OFF_USIZE 8 - -// Some offsets inside a EOCD record -#define UNZIP_EOCD_OFF_ENTRIES 6 -#define UNZIP_EOCD_OFF_CDOFF 12 -#define UNZIP_EOCD_OFF_COMMLEN 16 - -/*! - Max version handled by this API. - 0x14 = 2.0 --> full compatibility only up to this version; - later versions use unsupported features -*/ -#define UNZIP_VERSION 0x14 - -//! CRC32 routine -#define CRC32(c, b) crcTable[((int)c^b) & 0xff] ^ (c >> 8) - -OSDAB_BEGIN_NAMESPACE(Zip) - - -/************************************************************************ - ZipEntry -*************************************************************************/ - -/*! - ZipEntry constructor - initialize data. Type is set to File. -*/ -UnZip::ZipEntry::ZipEntry() -{ - compressedSize = uncompressedSize = crc32 = 0; - compression = NoCompression; - type = File; - encrypted = false; -} - - -/************************************************************************ - Private interface -*************************************************************************/ - -//! \internal -UnzipPrivate::UnzipPrivate() : - password(), - skipAllEncrypted(false), - headers(0), - device(0), - file(0), - uBuffer(0), - crcTable(0), - cdOffset(0), - eocdOffset(0), - cdEntryCount(0), - unsupportedEntryCount(0), - comment() -{ - uBuffer = (unsigned char*) buffer1; - crcTable = (quint32*) get_crc_table(); -} - -//! \internal -void UnzipPrivate::deviceDestroyed(QObject*) -{ - qDebug("Unexpected device destruction detected."); - do_closeArchive(); -} - -//! \internal Parses a Zip archive. -UnZip::ErrorCode UnzipPrivate::openArchive(QIODevice* dev) -{ - Q_ASSERT(!device); - Q_ASSERT(dev); - - if (!(dev->isOpen() || dev->open(QIODevice::ReadOnly))) { - qDebug() << "Unable to open device for reading"; - return UnZip::OpenFailed; - } - - device = dev; - if (device != file) - connect(device, SIGNAL(destroyed(QObject*)), this, SLOT(deviceDestroyed(QObject*))); - - UnZip::ErrorCode ec; - - ec = seekToCentralDirectory(); - if (ec != UnZip::Ok) { - closeArchive(); - return ec; - } - - //! \todo Ignore CD entry count? CD may be corrupted. - if (cdEntryCount == 0) { - return UnZip::Ok; - } - - bool continueParsing = true; - - while (continueParsing) { - if (device->read(buffer1, 4) != 4) { - if (headers) { - qDebug() << "Corrupted zip archive. Some files might be extracted."; - ec = headers->size() != 0 ? UnZip::PartiallyCorrupted : UnZip::Corrupted; - break; - } else { - closeArchive(); - qDebug() << "Corrupted or invalid zip archive. Closing."; - ec = UnZip::Corrupted; - break; - } - } - - if (! (buffer1[0] == 'P' && buffer1[1] == 'K' && buffer1[2] == 0x01 && buffer1[3] == 0x02) ) - break; - - if ((ec = parseCentralDirectoryRecord()) != UnZip::Ok) - break; - } - - if (ec != UnZip::Ok) - closeArchive(); - - return ec; -} - -/* - \internal Parses a local header record and makes some consistency check - with the information stored in the Central Directory record for this entry - that has been previously parsed. - \todo Optional consistency check (as a ExtractionOptions flag) - - local file header signature 4 bytes (0x04034b50) - version needed to extract 2 bytes - general purpose bit flag 2 bytes - compression method 2 bytes - last mod file time 2 bytes - last mod file date 2 bytes - crc-32 4 bytes - compressed size 4 bytes - uncompressed size 4 bytes - file name length 2 bytes - extra field length 2 bytes - - file name (variable size) - extra field (variable size) -*/ -UnZip::ErrorCode UnzipPrivate::parseLocalHeaderRecord(const QString& path, const ZipEntryP& entry) -{ - Q_ASSERT(device); - - if (!device->seek(entry.lhOffset)) - return UnZip::SeekFailed; - - // Test signature - if (device->read(buffer1, 4) != 4) - return UnZip::ReadFailed; - - if ((buffer1[0] != 'P') || (buffer1[1] != 'K') || (buffer1[2] != 0x03) || (buffer1[3] != 0x04)) - return UnZip::InvalidArchive; - - if (device->read(buffer1, UNZIP_LOCAL_HEADER_SIZE) != UNZIP_LOCAL_HEADER_SIZE) - return UnZip::ReadFailed; - - /* - Check 3rd general purpose bit flag. - - "bit 3: If this bit is set, the fields crc-32, compressed size - and uncompressed size are set to zero in the local - header. The correct values are put in the data descriptor - immediately following the compressed data." - */ - bool hasDataDescriptor = entry.hasDataDescriptor(); - bool checkFailed = entry.compMethod != getUShort(uBuffer, UNZIP_LH_OFF_CMETHOD); - - if (!checkFailed) - checkFailed = entry.gpFlag[0] != uBuffer[UNZIP_LH_OFF_GPFLAG]; - if (!checkFailed) - checkFailed = entry.gpFlag[1] != uBuffer[UNZIP_LH_OFF_GPFLAG + 1]; - if (!checkFailed) - checkFailed = entry.modTime[0] != uBuffer[UNZIP_LH_OFF_MODT]; - if (!checkFailed) - checkFailed = entry.modTime[1] != uBuffer[UNZIP_LH_OFF_MODT + 1]; - if (!checkFailed) - checkFailed = entry.modDate[0] != uBuffer[UNZIP_LH_OFF_MODD]; - if (!checkFailed) - checkFailed = entry.modDate[1] != uBuffer[UNZIP_LH_OFF_MODD + 1]; - if (!hasDataDescriptor) - { - if (!checkFailed) - checkFailed = entry.crc != getULong(uBuffer, UNZIP_LH_OFF_CRC32); - if (!checkFailed) - checkFailed = entry.szComp != getULong(uBuffer, UNZIP_LH_OFF_CSIZE); - if (!checkFailed) - checkFailed = entry.szUncomp != getULong(uBuffer, UNZIP_LH_OFF_USIZE); - } - - if (checkFailed) - return UnZip::HeaderConsistencyError; - - // Check filename - quint16 szName = getUShort(uBuffer, UNZIP_LH_OFF_NAMELEN); - if (szName == 0) - return UnZip::HeaderConsistencyError; - - if (device->read(buffer2, szName) != szName) - return UnZip::ReadFailed; - - QString filename = QString::fromLatin1(buffer2, szName); - if (filename != path) { - qDebug() << "Filename in local header mismatches."; - return UnZip::HeaderConsistencyError; - } - - // Skip extra field - quint16 szExtra = getUShort(uBuffer, UNZIP_LH_OFF_XLEN); - if (szExtra != 0) { - if (!device->seek(device->pos() + szExtra)) - return UnZip::SeekFailed; - } - - entry.dataOffset = device->pos(); - - if (hasDataDescriptor) { - /* - The data descriptor has this OPTIONAL signature: PK\7\8 - We try to skip the compressed data relying on the size set in the - Central Directory record. - */ - if (!device->seek(device->pos() + entry.szComp)) - return UnZip::SeekFailed; - - // Read 4 bytes and check if there is a data descriptor signature - if (device->read(buffer2, 4) != 4) - return UnZip::ReadFailed; - - bool hasSignature = buffer2[0] == 'P' && buffer2[1] == 'K' && buffer2[2] == 0x07 && buffer2[3] == 0x08; - if (hasSignature) { - if (device->read(buffer2, UNZIP_DD_SIZE) != UNZIP_DD_SIZE) - return UnZip::ReadFailed; - } else { - if (device->read(buffer2 + 4, UNZIP_DD_SIZE - 4) != UNZIP_DD_SIZE - 4) - return UnZip::ReadFailed; - } - - // DD: crc, compressed size, uncompressed size - if ( - entry.crc != getULong((unsigned char*)buffer2, UNZIP_DD_OFF_CRC32) || - entry.szComp != getULong((unsigned char*)buffer2, UNZIP_DD_OFF_CSIZE) || - entry.szUncomp != getULong((unsigned char*)buffer2, UNZIP_DD_OFF_USIZE) - ) - return UnZip::HeaderConsistencyError; - } - - return UnZip::Ok; -} - -/*! \internal Attempts to find the start of the central directory record. - - We seek the file back until we reach the "End Of Central Directory" - signature PK\5\6. - - end of central dir signature 4 bytes (0x06054b50) - number of this disk 2 bytes - number of the disk with the - start of the central directory 2 bytes - total number of entries in the - central directory on this disk 2 bytes - total number of entries in - the central directory 2 bytes - size of the central directory 4 bytes - offset of start of central - directory with respect to - the starting disk number 4 bytes - .ZIP file comment length 2 bytes - --- SIZE UNTIL HERE: UNZIP_EOCD_SIZE --- - .ZIP file comment (variable size) -*/ -UnZip::ErrorCode UnzipPrivate::seekToCentralDirectory() -{ - Q_ASSERT(device); - - qint64 length = device->size(); - qint64 offset = length - UNZIP_EOCD_SIZE; - - if (length < UNZIP_EOCD_SIZE) - return UnZip::InvalidArchive; - - if (!device->seek( offset )) - return UnZip::SeekFailed; - - if (device->read(buffer1, UNZIP_EOCD_SIZE) != UNZIP_EOCD_SIZE) - return UnZip::ReadFailed; - - bool eocdFound = (buffer1[0] == 'P' && buffer1[1] == 'K' && buffer1[2] == 0x05 && buffer1[3] == 0x06); - - if (eocdFound) { - // Zip file has no comment (the only variable length field in the EOCD record) - eocdOffset = offset; - } else { - qint64 read; - char* p = 0; - - offset -= UNZIP_EOCD_SIZE; - - if (offset <= 0) - return UnZip::InvalidArchive; - - if (!device->seek( offset )) - return UnZip::SeekFailed; - - while ((read = device->read(buffer1, UNZIP_EOCD_SIZE)) >= 0) { - if ( (p = strstr(buffer1, "PK\5\6")) != 0) { - // Seek to the start of the EOCD record so we can read it fully - // Yes... we could simply read the missing bytes and append them to the buffer - // but this is far easier so heck it! - device->seek( offset + (p - buffer1) ); - eocdFound = true; - eocdOffset = offset + (p - buffer1); - - // Read EOCD record - if (device->read(buffer1, UNZIP_EOCD_SIZE) != UNZIP_EOCD_SIZE) - return UnZip::ReadFailed; - - break; - } - - // TODO: This is very slow and only a temporary bug fix. Need some pattern matching algorithm here. - offset -= 1 /*UNZIP_EOCD_SIZE*/; - if (offset <= 0) - return UnZip::InvalidArchive; - - if (!device->seek( offset )) - return UnZip::SeekFailed; - } - } - - if (!eocdFound) - return UnZip::InvalidArchive; - - // Parse EOCD to locate CD offset - offset = getULong((const unsigned char*)buffer1, UNZIP_EOCD_OFF_CDOFF + 4); - - cdOffset = offset; - - cdEntryCount = getUShort((const unsigned char*)buffer1, UNZIP_EOCD_OFF_ENTRIES + 4); - - quint16 commentLength = getUShort((const unsigned char*)buffer1, UNZIP_EOCD_OFF_COMMLEN + 4); - if (commentLength != 0) { - QByteArray c = device->read(commentLength); - if (c.size() != commentLength) - return UnZip::ReadFailed; - - comment = c; - } - - // Seek to the start of the CD record - if (!device->seek( cdOffset )) - return UnZip::SeekFailed; - - return UnZip::Ok; -} - -/*! - \internal Parses a central directory record. - - Central Directory record structure: - - [file header 1] - . - . - . - [file header n] - [digital signature] // PKZip 6.2 or later only - - File header: - - central file header signature 4 bytes (0x02014b50) - version made by 2 bytes - version needed to extract 2 bytes - general purpose bit flag 2 bytes - compression method 2 bytes - last mod file time 2 bytes - last mod file date 2 bytes - crc-32 4 bytes - compressed size 4 bytes - uncompressed size 4 bytes - file name length 2 bytes - extra field length 2 bytes - file comment length 2 bytes - disk number start 2 bytes - internal file attributes 2 bytes - external file attributes 4 bytes - relative offset of local header 4 bytes - - file name (variable size) - extra field (variable size) - file comment (variable size) -*/ -UnZip::ErrorCode UnzipPrivate::parseCentralDirectoryRecord() -{ - Q_ASSERT(device); - - // Read CD record - if (device->read(buffer1, UNZIP_CD_ENTRY_SIZE_NS) != UNZIP_CD_ENTRY_SIZE_NS) - return UnZip::ReadFailed; - - bool skipEntry = false; - - // Get compression type so we can skip non compatible algorithms - quint16 compMethod = getUShort(uBuffer, UNZIP_CD_OFF_CMETHOD); - - // Get variable size fields length so we can skip the whole record - // if necessary - quint16 szName = getUShort(uBuffer, UNZIP_CD_OFF_NAMELEN); - quint16 szExtra = getUShort(uBuffer, UNZIP_CD_OFF_XLEN); - quint16 szComment = getUShort(uBuffer, UNZIP_CD_OFF_COMMLEN); - - quint32 skipLength = szName + szExtra + szComment; - - UnZip::ErrorCode ec = UnZip::Ok; - - if ((compMethod != 0) && (compMethod != 8)) { - qDebug() << "Unsupported compression method. Skipping file."; - skipEntry = true; - } - - if (!skipEntry && szName == 0) { - qDebug() << "Skipping file with no name."; - skipEntry = true; - } - - QString filename; - if (device->read(buffer2, szName) != szName) { - ec = UnZip::ReadFailed; - skipEntry = true; - } else { - filename = QString::fromLatin1(buffer2, szName); - } - - // Unsupported features if version is bigger than UNZIP_VERSION - if (!skipEntry && buffer1[UNZIP_CD_OFF_VERSION] > UNZIP_VERSION) { - QString v = QString::number(buffer1[UNZIP_CD_OFF_VERSION]); - if (v.length() == 2) - v.insert(1, QLatin1Char('.')); - v = QString::fromLatin1("Unsupported PKZip version (%1). Skipping file: %2") - .arg(v, filename.isEmpty() ? QString::fromLatin1("") : filename); - qDebug() << v.toLatin1().constData(); - skipEntry = true; - } - - if (skipEntry) { - if (ec == UnZip::Ok) { - if (!device->seek( device->pos() + skipLength )) - ec = UnZip::SeekFailed; - unsupportedEntryCount++; - } - - return ec; - } - - ZipEntryP* h = new ZipEntryP; - h->compMethod = compMethod; - - h->gpFlag[0] = buffer1[UNZIP_CD_OFF_GPFLAG]; - h->gpFlag[1] = buffer1[UNZIP_CD_OFF_GPFLAG + 1]; - - h->modTime[0] = buffer1[UNZIP_CD_OFF_MODT]; - h->modTime[1] = buffer1[UNZIP_CD_OFF_MODT + 1]; - - h->modDate[0] = buffer1[UNZIP_CD_OFF_MODD]; - h->modDate[1] = buffer1[UNZIP_CD_OFF_MODD + 1]; - - h->crc = getULong(uBuffer, UNZIP_CD_OFF_CRC32); - h->szComp = getULong(uBuffer, UNZIP_CD_OFF_CSIZE); - h->szUncomp = getULong(uBuffer, UNZIP_CD_OFF_USIZE); - - // Skip extra field (if any) - if (szExtra != 0) { - if (!device->seek( device->pos() + szExtra )) { - delete h; - return UnZip::SeekFailed; - } - } - - // Read comment field (if any) - if (szComment != 0) { - if (device->read(buffer2, szComment) != szComment) { - delete h; - return UnZip::ReadFailed; - } - - h->comment = QString::fromLatin1(buffer2, szComment); - } - - h->lhOffset = getULong(uBuffer, UNZIP_CD_OFF_LHOFFSET); - - if (!headers) - headers = new QMap(); - headers->insert(filename, h); - - return UnZip::Ok; -} - -//! \internal Closes the archive and resets the internal status. -void UnzipPrivate::closeArchive() -{ - if (!device) { - Q_ASSERT(!file); - return; - } - - if (device != file) - disconnect(device, 0, this, 0); - - do_closeArchive(); -} - -//! \internal -void UnzipPrivate::do_closeArchive() -{ - skipAllEncrypted = false; - - if (headers) { - if (headers) - qDeleteAll(*headers); - delete headers; - headers = 0; - } - - device = 0; - - if (file) - delete file; - file = 0; - - cdOffset = eocdOffset = 0; - cdEntryCount = 0; - unsupportedEntryCount = 0; - - comment.clear(); -} - -//! \internal -UnZip::ErrorCode UnzipPrivate::extractFile(const QString& path, const ZipEntryP& entry, - const QDir& dir, UnZip::ExtractionOptions options) -{ - QString name(path); - QString dirname; - QString directory; - - const bool verify = (options & UnZip::VerifyOnly); - const int pos = name.lastIndexOf('/'); - - // This entry is for a directory - if (pos == name.length() - 1) { - if (verify) - return UnZip::Ok; - - if (options & UnZip::SkipPaths) - return UnZip::Ok; - - directory = QString("%1/%2").arg(dir.absolutePath()).arg(QDir::cleanPath(name)); - if (!createDirectory(directory)) { - qDebug() << QString("Unable to create directory: %1").arg(directory); - return UnZip::CreateDirFailed; - } - - return UnZip::Ok; - } - - // Extract path from entry - if (verify) { - return extractFile(path, entry, 0, options); - } - - if (pos > 0) { - // get directory part - dirname = name.left(pos); - if (options & UnZip::SkipPaths) { - directory = dir.absolutePath(); - } else { - directory = QString("%1/%2").arg(dir.absolutePath()).arg(QDir::cleanPath(dirname)); - if (!createDirectory(directory)) { - qDebug() << QString("Unable to create directory: %1").arg(directory); - return UnZip::CreateDirFailed; - } - } - name = name.right(name.length() - pos - 1); - } else { - directory = dir.absolutePath(); - } - - const bool silentDirectoryCreation = !(options & UnZip::NoSilentDirectoryCreation); - if (silentDirectoryCreation) { - if (!createDirectory(directory)) { - qDebug() << QString("Unable to create output directory %1").arg(directory); - return UnZip::CreateDirFailed; - } - } - - name = QString("%1/%2").arg(directory).arg(name); - - QFile outFile(name); - if (!outFile.open(QIODevice::WriteOnly)) { - qDebug() << QString("Unable to open %1 for writing").arg(name); - return UnZip::OpenFailed; - } - - UnZip::ErrorCode ec = extractFile(path, entry, &outFile, options); - outFile.close(); - - const QDateTime lastModified = convertDateTime(entry.modDate, entry.modTime); - const bool setTimeOk = OSDAB_ZIP_MANGLE(setFileTimestamp)(name, lastModified); - if (!setTimeOk) { - qDebug() << QString("Unable to set last modified time on file: %1").arg(name); - } - - if (ec != UnZip::Ok) { - if (!outFile.remove()) - qDebug() << QString("Unable to remove corrupted file: %1").arg(name); - } - - return ec; -} - -//! \internal -UnZip::ErrorCode UnzipPrivate::extractStoredFile( - const quint32 szComp, quint32** keys, quint32& myCRC, QIODevice* outDev, - UnZip::ExtractionOptions options) -{ - const bool verify = (options & UnZip::VerifyOnly); - const bool isEncrypted = keys != 0; - - uInt rep = szComp / UNZIP_READ_BUFFER; - uInt rem = szComp % UNZIP_READ_BUFFER; - uInt cur = 0; - - // extract data - qint64 read; - quint64 tot = 0; - - while ( (read = device->read(buffer1, cur < rep ? UNZIP_READ_BUFFER : rem)) > 0 ) { - if (isEncrypted) - decryptBytes(*keys, buffer1, read); - - myCRC = crc32(myCRC, uBuffer, read); - if (!verify) { - if (outDev->write(buffer1, read) != read) - return UnZip::WriteFailed; - } - - cur++; - tot += read; - if (tot == szComp) - break; - } - - return (read < 0) - ? UnZip::ReadFailed - : UnZip::Ok; -} - -//! \internal -UnZip::ErrorCode UnzipPrivate::inflateFile( - const quint32 szComp, quint32** keys, quint32& myCRC, QIODevice* outDev, - UnZip::ExtractionOptions options) -{ - const bool verify = (options & UnZip::VerifyOnly); - const bool isEncrypted = keys != 0; - Q_ASSERT(verify ? true : outDev != 0); - - uInt rep = szComp / UNZIP_READ_BUFFER; - uInt rem = szComp % UNZIP_READ_BUFFER; - uInt cur = 0; - - // extract data - qint64 read; - - /* Allocate inflate state */ - z_stream zstr; - zstr.zalloc = Z_NULL; - zstr.zfree = Z_NULL; - zstr.opaque = Z_NULL; - zstr.next_in = Z_NULL; - zstr.avail_in = 0; - - int zret; - - // Use inflateInit2 with negative windowBits to get raw decompression - if ( (zret = inflateInit2_(&zstr, -MAX_WBITS, ZLIB_VERSION, sizeof(z_stream))) != Z_OK ) - return UnZip::ZlibError; - - int szDecomp; - - // Decompress until deflate stream ends or end of file - do { - read = device->read(buffer1, cur < rep ? UNZIP_READ_BUFFER : rem); - if (!read) - break; - - if (read < 0) { - (void)inflateEnd(&zstr); - return UnZip::ReadFailed; - } - - if (isEncrypted) - decryptBytes(*keys, buffer1, read); - - cur++; - - zstr.avail_in = (uInt) read; - zstr.next_in = (Bytef*) buffer1; - - // Run inflate() on input until output buffer not full - do { - zstr.avail_out = UNZIP_READ_BUFFER; - zstr.next_out = (Bytef*) buffer2;; - - zret = inflate(&zstr, Z_NO_FLUSH); - - switch (zret) { - case Z_NEED_DICT: - case Z_DATA_ERROR: - case Z_MEM_ERROR: - inflateEnd(&zstr); - return UnZip::WriteFailed; - default: - ; - } - - szDecomp = UNZIP_READ_BUFFER - zstr.avail_out; - if (!verify) { - if (outDev->write(buffer2, szDecomp) != szDecomp) { - inflateEnd(&zstr); - return UnZip::ZlibError; - } - } - - myCRC = crc32(myCRC, (const Bytef*) buffer2, szDecomp); - - } while (zstr.avail_out == 0); - - } while (zret != Z_STREAM_END); - - inflateEnd(&zstr); - return UnZip::Ok; -} - -//! \internal \p outDev is null if the VerifyOnly option is set -UnZip::ErrorCode UnzipPrivate::extractFile(const QString& path, const ZipEntryP& entry, - QIODevice* outDev, UnZip::ExtractionOptions options) -{ - const bool verify = (options & UnZip::VerifyOnly); - - Q_UNUSED(options); - Q_ASSERT(device); - Q_ASSERT(verify ? true : outDev != 0); - - if (!entry.lhEntryChecked) { - UnZip::ErrorCode ec = parseLocalHeaderRecord(path, entry); - entry.lhEntryChecked = true; - if (ec != UnZip::Ok) - return ec; - } - - if (!device->seek(entry.dataOffset)) - return UnZip::SeekFailed; - - // Encryption keys - quint32 keys[3]; - quint32 szComp = entry.szComp; - if (entry.isEncrypted()) { - UnZip::ErrorCode e = testPassword(keys, path, entry); - if (e != UnZip::Ok) - { - qDebug() << QString("Unable to decrypt %1").arg(path); - return e; - }//! Encryption header size - szComp -= UNZIP_LOCAL_ENC_HEADER_SIZE; // remove encryption header size - } - - if (szComp == 0) { - if (entry.crc != 0) - return UnZip::Corrupted; - return UnZip::Ok; - } - - quint32 myCRC = crc32(0L, Z_NULL, 0); - quint32* k = keys; - - UnZip::ErrorCode ec = UnZip::Ok; - if (entry.compMethod == 0) { - ec = extractStoredFile(szComp, entry.isEncrypted() ? &k : 0, myCRC, outDev, options); - } else if (entry.compMethod == 8) { - ec = inflateFile(szComp, entry.isEncrypted() ? &k : 0, myCRC, outDev, options); - } - - if (ec == UnZip::Ok && myCRC != entry.crc) - return UnZip::Corrupted; - - return UnZip::Ok; -} - -//! \internal Creates a new directory and all the needed parent directories. -bool UnzipPrivate::createDirectory(const QString& path) -{ - QDir d(path); - if (!d.exists() && !d.mkpath(path)) { - qDebug() << QString("Unable to create directory: %1").arg(path); - return false; - } - - return true; -} - -/*! - \internal Reads an quint32 (4 bytes) from a byte array starting at given offset. -*/ -quint32 UnzipPrivate::getULong(const unsigned char* data, quint32 offset) const -{ - quint32 res = (quint32) data[offset]; - res |= (((quint32)data[offset+1]) << 8); - res |= (((quint32)data[offset+2]) << 16); - res |= (((quint32)data[offset+3]) << 24); - - return res; -} - -/*! - \internal Reads an quint64 (8 bytes) from a byte array starting at given offset. -*/ -quint64 UnzipPrivate::getULLong(const unsigned char* data, quint32 offset) const -{ - quint64 res = (quint64) data[offset]; - res |= (((quint64)data[offset+1]) << 8); - res |= (((quint64)data[offset+2]) << 16); - res |= (((quint64)data[offset+3]) << 24); - res |= (((quint64)data[offset+1]) << 32); - res |= (((quint64)data[offset+2]) << 40); - res |= (((quint64)data[offset+3]) << 48); - res |= (((quint64)data[offset+3]) << 56); - - return res; -} - -/*! - \internal Reads an quint16 (2 bytes) from a byte array starting at given offset. -*/ -quint16 UnzipPrivate::getUShort(const unsigned char* data, quint32 offset) const -{ - return (quint16) data[offset] | (((quint16)data[offset+1]) << 8); -} - -/*! - \internal Return the next byte in the pseudo-random sequence - */ -int UnzipPrivate::decryptByte(quint32 key2) const -{ - quint16 temp = ((quint16)(key2) & 0xffff) | 2; - return (int)(((temp * (temp ^ 1)) >> 8) & 0xff); -} - -/*! - \internal Update the encryption keys with the next byte of plain text - */ -void UnzipPrivate::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 Initialize the encryption keys and the random header according to - the given password. - */ -void UnzipPrivate::initKeys(const QString& pwd, quint32* keys) const -{ - keys[0] = 305419896L; - keys[1] = 591751049L; - keys[2] = 878082192L; - - QByteArray pwdBytes = pwd.toLatin1(); - int sz = pwdBytes.size(); - const char* ascii = pwdBytes.data(); - - for (int i = 0; i < sz; ++i) - updateKeys(keys, (int)ascii[i]); -} - -/*! - \internal Attempts to test a password without actually extracting a file. - The \p file parameter can be used in the user interface or for debugging purposes - as it is the name of the encrypted file for wich the password is being tested. -*/ -UnZip::ErrorCode UnzipPrivate::testPassword(quint32* keys, const QString&_file, const ZipEntryP& header) -{ - Q_UNUSED(_file); - Q_ASSERT(device); - - // read encryption keys - if (device->read(buffer1, 12) != 12) - return UnZip::Corrupted; - - // Replace this code if you want to i.e. call some dialog and ask the user for a password - initKeys(password, keys); - if (testKeys(header, keys)) - return UnZip::Ok; - - return UnZip::Skip; -} - -/*! - \internal Tests a set of keys on the encryption header. -*/ -bool UnzipPrivate::testKeys(const ZipEntryP& header, quint32* keys) -{ - char lastByte; - - // decrypt encryption header - for (int i = 0; i < 11; ++i) - updateKeys(keys, lastByte = buffer1[i] ^ decryptByte(keys[2])); - updateKeys(keys, lastByte = buffer1[11] ^ decryptByte(keys[2])); - - // if there is an extended header (bit in the gp flag) buffer[11] is a byte from the file time - // with no extended header we have to check the crc high-order byte - char c = ((header.gpFlag[0] & 0x08) == 8) ? header.modTime[1] : header.crc >> 24; - - return (lastByte == c); -} - -/*! - \internal Decrypts an array of bytes long \p read. -*/ -void UnzipPrivate::decryptBytes(quint32* keys, char* buffer, qint64 read) -{ - for (int i = 0; i < (int)read; ++i) - updateKeys(keys, buffer[i] ^= decryptByte(keys[2])); -} - -/*! - \internal Converts date and time values from ZIP format to a QDateTime object. -*/ -QDateTime UnzipPrivate::convertDateTime(const unsigned char date[2], const unsigned char time[2]) const -{ - QDateTime dt; - - // Usual PKZip low-byte to high-byte order - - // Date: 7 bits = years from 1980, 4 bits = month, 5 bits = day - quint16 year = (date[1] >> 1) & 127; - quint16 month = ((date[1] << 3) & 14) | ((date[0] >> 5) & 7); - quint16 day = date[0] & 31; - - // Time: 5 bits hour, 6 bits minutes, 5 bits seconds with a 2sec precision - quint16 hour = (time[1] >> 3) & 31; - quint16 minutes = ((time[1] << 3) & 56) | ((time[0] >> 5) & 7); - quint16 seconds = (time[0] & 31) * 2; - - dt.setDate(QDate(1980 + year, month, day)); - dt.setTime(QTime(hour, minutes, seconds)); - return dt; -} - - -/************************************************************************ - Public interface -*************************************************************************/ - -/*! - Creates a new Zip file decompressor. -*/ -UnZip::UnZip() : d(new UnzipPrivate) -{ -} - -/*! - Closes any open archive and releases used resources. -*/ -UnZip::~UnZip() -{ - closeArchive(); - delete d; -} - -/*! - Returns true if there is an open archive. -*/ -bool UnZip::isOpen() const -{ - return d->device; -} - -/*! - Opens a zip archive and reads the files list. Closes any previously opened archive. -*/ -UnZip::ErrorCode UnZip::openArchive(const QString& filename) -{ - closeArchive(); - - // closeArchive will destroy the file - d->file = new QFile(filename); - - if (!d->file->exists()) { - delete d->file; - d->file = 0; - return UnZip::FileNotFound; - } - - if (!d->file->open(QIODevice::ReadOnly)) { - delete d->file; - d->file = 0; - return UnZip::OpenFailed; - } - - return d->openArchive(d->file); -} - -/*! - Opens a zip archive and reads the entries list. - Closes any previously opened archive. - \warning The class takes DOES NOT take ownership of the device. -*/ -UnZip::ErrorCode UnZip::openArchive(QIODevice* device) -{ - closeArchive(); - - if (!device) { - qDebug() << "Invalid device."; - return UnZip::InvalidDevice; - } - - return d->openArchive(device); -} - -/*! - Closes the archive and releases all the used resources (like cached passwords). -*/ -void UnZip::closeArchive() -{ - d->closeArchive(); -} - -QString UnZip::archiveComment() const -{ - return d->comment; -} - -/*! - Returns a locale translated error string for a given error code. -*/ -QString UnZip::formatError(UnZip::ErrorCode c) const -{ - switch (c) - { - case Ok: return QCoreApplication::translate("UnZip", "ZIP operation completed successfully."); break; - case ZlibInit: return QCoreApplication::translate("UnZip", "Failed to initialize or load zlib library."); break; - case ZlibError: return QCoreApplication::translate("UnZip", "zlib library error."); break; - case OpenFailed: return QCoreApplication::translate("UnZip", "Unable to create or open file."); break; - case PartiallyCorrupted: return QCoreApplication::translate("UnZip", "Partially corrupted archive. Some files might be extracted."); break; - case Corrupted: return QCoreApplication::translate("UnZip", "Corrupted archive."); break; - case WrongPassword: return QCoreApplication::translate("UnZip", "Wrong password."); break; - case NoOpenArchive: return QCoreApplication::translate("UnZip", "No archive has been created yet."); break; - case FileNotFound: return QCoreApplication::translate("UnZip", "File or directory does not exist."); break; - case ReadFailed: return QCoreApplication::translate("UnZip", "File read error."); break; - case WriteFailed: return QCoreApplication::translate("UnZip", "File write error."); break; - case SeekFailed: return QCoreApplication::translate("UnZip", "File seek error."); break; - case CreateDirFailed: return QCoreApplication::translate("UnZip", "Unable to create a directory."); break; - case InvalidDevice: return QCoreApplication::translate("UnZip", "Invalid device."); break; - case InvalidArchive: return QCoreApplication::translate("UnZip", "Invalid or incompatible zip archive."); break; - case HeaderConsistencyError: return QCoreApplication::translate("UnZip", "Inconsistent headers. Archive might be corrupted."); break; - default: ; - } - - return QCoreApplication::translate("UnZip", "Unknown error."); -} - -/*! - Returns true if the archive contains a file with the given path and name. -*/ -bool UnZip::contains(const QString& file) const -{ - return d->headers ? d->headers->contains(file) : false; -} - -/*! - Returns complete paths of files and directories in this archive. -*/ -QStringList UnZip::fileList() const -{ - return d->headers ? d->headers->keys() : QStringList(); -} - -/*! - Returns information for each (correctly parsed) entry of this archive. -*/ -QList UnZip::entryList() const -{ - QList list; - if (!d->headers) - return list; - - for (QMap::ConstIterator it = d->headers->constBegin(); - it != d->headers->constEnd(); ++it) { - const ZipEntryP* entry = it.value(); - Q_ASSERT(entry != 0); - - ZipEntry z; - - z.filename = it.key(); - if (!entry->comment.isEmpty()) - z.comment = entry->comment; - z.compressedSize = entry->szComp; - z.uncompressedSize = entry->szUncomp; - z.crc32 = entry->crc; - z.lastModified = d->convertDateTime(entry->modDate, entry->modTime); - - z.compression = entry->compMethod == 0 ? NoCompression : entry->compMethod == 8 ? Deflated : UnknownCompression; - z.type = z.filename.endsWith("/") ? Directory : File; - - z.encrypted = entry->isEncrypted(); - - list.append(z); - } - - return list; -} - -/*! - Extracts the whole archive to a directory. -*/ -UnZip::ErrorCode UnZip::verifyArchive() -{ - return extractAll(QDir(), VerifyOnly); -} - -/*! - Extracts the whole archive to a directory. -*/ -UnZip::ErrorCode UnZip::extractAll(const QString& dirname, ExtractionOptions options) -{ - return extractAll(QDir(dirname), options); -} - -/*! - Extracts the whole archive to a directory. - Stops extraction at the first error. -*/ -UnZip::ErrorCode UnZip::extractAll(const QDir& dir, ExtractionOptions options) -{ - // this should only happen if we didn't call openArchive() yet - if (!d->device) - return NoOpenArchive; - - if (!d->headers) - return Ok; - - ErrorCode ec = Ok; - - QMap::ConstIterator it = d->headers->constBegin(); - const QMap::ConstIterator end = d->headers->constEnd(); - while (it != end) { - ZipEntryP* entry = it.value(); - Q_ASSERT(entry != 0); - if ((entry->isEncrypted()) && d->skipAllEncrypted) { - ++it; - continue; - } - - bool skip = false; - ec = d->extractFile(it.key(), *entry, dir, options); - switch (ec) { - case Corrupted: - qDebug() << "Corrupted entry" << it.key(); - break; - case CreateDirFailed: - break; - case Skip: - skip = true; - break; - case SkipAll: - skip = true; - d->skipAllEncrypted = true; - break; - default: - ; - } - - if (ec != Ok && !skip) { - break; - } - - ++it; - } - - return ec; -} - -/*! - Extracts a single file to a directory. -*/ -UnZip::ErrorCode UnZip::extractFile(const QString& filename, const QString& dirname, ExtractionOptions options) -{ - return extractFile(filename, QDir(dirname), options); -} - -/*! - Extracts a single file to a directory. -*/ -UnZip::ErrorCode UnZip::extractFile(const QString& filename, const QDir& dir, ExtractionOptions options) -{ - if (!d->device) - return NoOpenArchive; - if (!d->headers) - return FileNotFound; - - QMap::Iterator itr = d->headers->find(filename); - if (itr != d->headers->end()) { - ZipEntryP* entry = itr.value(); - Q_ASSERT(entry != 0); - return d->extractFile(itr.key(), *entry, dir, options); - } - - return FileNotFound; -} - -/*! - Extracts a single file to a directory. -*/ -UnZip::ErrorCode UnZip::extractFile(const QString& filename, QIODevice* outDev, ExtractionOptions options) -{ - if (!d->device) - return NoOpenArchive; - if (!d->headers) - return FileNotFound; - if (!outDev) - return InvalidDevice; - - QMap::Iterator itr = d->headers->find(filename); - if (itr != d->headers->end()) { - ZipEntryP* entry = itr.value(); - Q_ASSERT(entry != 0); - return d->extractFile(itr.key(), *entry, outDev, options); - } - - return FileNotFound; -} - -/*! - Extracts a list of files. - Stops extraction at the first error (but continues if a file does not exist in the archive). - */ -UnZip::ErrorCode UnZip::extractFiles(const QStringList& filenames, const QString& dirname, ExtractionOptions options) -{ - if (!d->device) - return NoOpenArchive; - if (!d->headers) - return Ok; - - QDir dir(dirname); - ErrorCode ec; - - for (QStringList::ConstIterator itr = filenames.constBegin(); itr != filenames.constEnd(); ++itr) { - ec = extractFile(*itr, dir, options); - if (ec == FileNotFound) - continue; - if (ec != Ok) - return ec; - } - - return Ok; -} - -/*! - Extracts a list of files. - Stops extraction at the first error (but continues if a file does not exist in the archive). - */ -UnZip::ErrorCode UnZip::extractFiles(const QStringList& filenames, const QDir& dir, ExtractionOptions options) -{ - if (!d->device) - return NoOpenArchive; - if (!d->headers) - return Ok; - - ErrorCode ec; - - for (QStringList::ConstIterator itr = filenames.constBegin(); itr != filenames.constEnd(); ++itr) { - ec = extractFile(*itr, dir, options); - if (ec == FileNotFound) - continue; - if (ec != Ok) - return ec; - } - - return Ok; -} - -/*! - Remove/replace this method to add your own password retrieval routine. -*/ -void UnZip::setPassword(const QString& pwd) -{ - d->password = pwd; -} - -OSDAB_END_NAMESPACE diff --git a/cockatrice/src/zip/unzip.h b/cockatrice/src/zip/unzip.h deleted file mode 100644 index ab57fdc36..000000000 --- a/cockatrice/src/zip/unzip.h +++ /dev/null @@ -1,155 +0,0 @@ -/**************************************************************************** -** Filename: unzip.h -** Last updated [dd/mm/yyyy]: 27/03/2011 -** -** pkzip 2.0 decompression. -** -** 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-2012 Angius Fabrizio. All rights reserved. -** -** This file is part of the OSDaB project (http://osdab.42cows.org/). -** -** 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. -** -**********************************************************************/ - -#ifndef OSDAB_UNZIP__H -#define OSDAB_UNZIP__H - -#include "zipglobal.h" - -#include -#include -#include -#include - -class QDir; -class QFile; -class QIODevice; -class QString; - -OSDAB_BEGIN_NAMESPACE(Zip) - -class UnzipPrivate; - -class OSDAB_ZIP_EXPORT UnZip -{ -public: - enum ErrorCode - { - Ok, - ZlibInit, - ZlibError, - OpenFailed, - PartiallyCorrupted, - Corrupted, - WrongPassword, - NoOpenArchive, - FileNotFound, - ReadFailed, - WriteFailed, - SeekFailed, - CreateDirFailed, - InvalidDevice, - InvalidArchive, - HeaderConsistencyError, - - Skip, - SkipAll // internal use only - }; - - enum ExtractionOption - { - ExtractPaths = 0x0001, - SkipPaths = 0x0002, - VerifyOnly = 0x0004, - NoSilentDirectoryCreation = 0x0008 - }; - Q_DECLARE_FLAGS(ExtractionOptions, ExtractionOption) - - enum CompressionMethod - { - NoCompression, - Deflated, - UnknownCompression - }; - - enum FileType - { - File, - Directory - }; - - struct ZipEntry - { - ZipEntry(); - - QString filename; - QString comment; - - quint32 compressedSize; - quint32 uncompressedSize; - quint32 crc32; - - QDateTime lastModified; - - CompressionMethod compression; - FileType type; - - bool encrypted; - }; - - UnZip(); - virtual ~UnZip(); - - bool isOpen() const; - - ErrorCode openArchive(const QString &filename); - ErrorCode openArchive(QIODevice *device); - void closeArchive(); - - QString archiveComment() const; - - QString formatError(UnZip::ErrorCode c) const; - - bool contains(const QString &file) const; - - QStringList fileList() const; - QList entryList() const; - - ErrorCode verifyArchive(); - - ErrorCode extractAll(const QString &dirname, ExtractionOptions options = ExtractPaths); - ErrorCode extractAll(const QDir &dir, ExtractionOptions options = ExtractPaths); - - ErrorCode extractFile(const QString &filename, const QString &dirname, ExtractionOptions options = ExtractPaths); - ErrorCode extractFile(const QString &filename, const QDir &dir, ExtractionOptions options = ExtractPaths); - ErrorCode extractFile(const QString &filename, QIODevice *device, ExtractionOptions options = ExtractPaths); - - ErrorCode - extractFiles(const QStringList &filenames, const QString &dirname, ExtractionOptions options = ExtractPaths); - ErrorCode extractFiles(const QStringList &filenames, const QDir &dir, ExtractionOptions options = ExtractPaths); - - void setPassword(const QString &pwd); - -private: - UnzipPrivate *d; -}; - -Q_DECLARE_OPERATORS_FOR_FLAGS(UnZip::ExtractionOptions) - -OSDAB_END_NAMESPACE - -#endif // OSDAB_UNZIP__H diff --git a/cockatrice/src/zip/unzip_p.h b/cockatrice/src/zip/unzip_p.h deleted file mode 100755 index fca2b071d..000000000 --- a/cockatrice/src/zip/unzip_p.h +++ /dev/null @@ -1,130 +0,0 @@ -/**************************************************************************** -** Filename: unzip_p.h -** Last updated [dd/mm/yyyy]: 27/03/2011 -** -** pkzip 2.0 decompression. -** -** 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-2012 Angius Fabrizio. All rights reserved. -** -** This file is part of the OSDaB project (http://osdab.42cows.org/). -** -** 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. -** -**********************************************************************/ - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Zip/UnZip API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#ifndef OSDAB_UNZIP_P__H -#define OSDAB_UNZIP_P__H - -#include "unzip.h" -#include "zipentry_p.h" - -#include -#include - -// zLib authors suggest using larger buffers (128K or 256K) for (de)compression (especially for inflate()) -// we use a 256K buffer here - if you want to use this code on a pre-iceage mainframe please change it ;) -#define UNZIP_READ_BUFFER (256*1024) - -OSDAB_BEGIN_NAMESPACE(Zip) - -class UnzipPrivate : public QObject -{ - Q_OBJECT - -public: - UnzipPrivate(); - - // Replace this with whatever else you use to store/retrieve the password. - QString password; - - bool skipAllEncrypted; - - QMap* headers; - - QIODevice* device; - QFile* file; - - char buffer1[UNZIP_READ_BUFFER]; - char buffer2[UNZIP_READ_BUFFER]; - - unsigned char* uBuffer; - const quint32* crcTable; - - // Central Directory (CD) offset - quint32 cdOffset; - // End of Central Directory (EOCD) offset - quint32 eocdOffset; - - // Number of entries in the Central Directory (as to the EOCD record) - quint16 cdEntryCount; - - // The number of detected entries that have been skipped because of a non compatible format - quint16 unsupportedEntryCount; - - QString comment; - - UnZip::ErrorCode openArchive(QIODevice* device); - - UnZip::ErrorCode seekToCentralDirectory(); - UnZip::ErrorCode parseCentralDirectoryRecord(); - UnZip::ErrorCode parseLocalHeaderRecord(const QString& path, const ZipEntryP& entry); - - void closeArchive(); - - UnZip::ErrorCode extractFile(const QString& path, const ZipEntryP& entry, const QDir& dir, UnZip::ExtractionOptions options); - UnZip::ErrorCode extractFile(const QString& path, const ZipEntryP& entry, QIODevice* device, UnZip::ExtractionOptions options); - - UnZip::ErrorCode testPassword(quint32* keys, const QString&_file, const ZipEntryP& header); - bool testKeys(const ZipEntryP& header, quint32* keys); - - bool createDirectory(const QString& path); - - inline void decryptBytes(quint32* keys, char* buffer, qint64 read); - - inline quint32 getULong(const unsigned char* data, quint32 offset) const; - inline quint64 getULLong(const unsigned char* data, quint32 offset) const; - inline quint16 getUShort(const unsigned char* data, quint32 offset) const; - inline int decryptByte(quint32 key2) const; - inline void updateKeys(quint32* keys, int c) const; - inline void initKeys(const QString& pwd, quint32* keys) const; - - inline QDateTime convertDateTime(const unsigned char date[2], const unsigned char time[2]) const; - -private slots: - void deviceDestroyed(QObject*); - -private: - UnZip::ErrorCode extractStoredFile(const quint32 szComp, quint32** keys, - quint32& myCRC, QIODevice* outDev, UnZip::ExtractionOptions options); - UnZip::ErrorCode inflateFile(const quint32 szComp, quint32** keys, - quint32& myCRC, QIODevice* outDev, UnZip::ExtractionOptions options); - void do_closeArchive(); -}; - -OSDAB_END_NAMESPACE - -#endif // OSDAB_UNZIP_P__H diff --git a/cockatrice/src/zip/zip.cpp b/cockatrice/src/zip/zip.cpp deleted file mode 100755 index 5b0177293..000000000 --- a/cockatrice/src/zip/zip.cpp +++ /dev/null @@ -1,1619 +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-2012 Angius Fabrizio. All rights reserved. -** -** This file is part of the OSDaB project (http://osdab.42cows.org/). -** -** 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 - -#include -#include -#include -#include -#include -#include -#include - -// You can remove this #include if you replace the qDebug() statements. -#include - - -/*! #define OSDAB_ZIP_NO_PNG_RLE to disable the use of Z_RLE compression strategy with - PNG files (achieves slightly better compression levels according to the authors). -*/ -// #define OSDAB_ZIP_NO_PNG_RLE - -#define OSDAB_ZIP_NO_DEBUG - -//! 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 - -/*! - \class Zip zip.h - - \brief Zip file compression. - - Some quick usage examples. - - \verbatim - Suppose you have this directory structure: - - /home/user/dir1/file1.1 - /home/user/dir1/file1.2 - /home/user/dir1/dir1.1/ - /home/user/dir1/dir1.2/file1.2.1 - - EXAMPLE 1: - myZipInstance.addDirectory("/home/user/dir1"); - - RESULT: - Beheaves like any common zip software and creates a zip file with this structure: - - dir1/file1.1 - dir1/file1.2 - dir1/dir1.1/ - dir1/dir1.2/file1.2.1 - - EXAMPLE 2: - myZipInstance.addDirectory("/home/user/dir1", "myRoot/myFolder"); - - RESULT: - Adds a custom root to the paths and creates a zip file with this structure: - - 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("/home/user/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: - - /home/user/dir1/file1.1 - /home/user/dir1/file1.2 - /home/user/dir1/dir1.1/ - /home/user/dir1/dir1.2/file1.2.1 - - EXAMPLE 4: - myZipInstance.setPassword("hellopass"); - myZipInstance.addDirectory("/home/user/dir1", "/"); - - RESULT: - Adds and encrypts the files in /home/user/dir1, creating the following zip structure: - - /dir1/file1.1 - /dir1/file1.2 - /dir1/dir1.1/ - /dir1/dir1.2/file1.2.1 - - EXAMPLE 5: - myZipInstance.addDirectory("/home/user/dir1", Zip::IgnoreRoot); - - RESULT: - Adds the files in /home/user/dir1 but doesn't create the top level - directory: - - file1.1 - file1.2 - dir1.1/ - dir1.2/file1.2.1 - - EXAMPLE 5: - myZipInstance.addDirectory("/home/user/dir1", "data/backup", Zip::IgnoreRoot); - - RESULT: - Adds the files in /home/user/dir1 but uses "data/backup" as top level - directory instead of "dir1": - - data/backup/file1.1 - data/backup/file1.2 - data/backup/dir1.1/ - data/backup/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. -*/ - -namespace { - -struct ZippedDir { - bool init; - QString actualRoot; - int files; - ZippedDir() : init(false), actualRoot(), files(0) {} -}; - -void checkRootPath(QString& path) -{ - const bool isUnixRoot = path.length() == 1 && path.at(0) == QLatin1Char('/'); - if (!path.isEmpty() && !isUnixRoot) { - while (path.endsWith(QLatin1String("\\"))) - path.truncate(path.length() - 1); - - int sepCount = 0; - for (int i = path.length()-1; i >= 0; --i) { - if (path.at(i) == QLatin1Char('/')) - ++sepCount; - else break; - } - - if (sepCount > 1) - path.truncate(path.length() - (sepCount-1)); - else if (sepCount == 0) - path.append(QLatin1String("/")); - } -} - -} - -////////////////////////////////////////////////////////////////////////// - -OSDAB_BEGIN_NAMESPACE(Zip) - -/************************************************************************ - Private interface -*************************************************************************/ - -//! \internal -ZipPrivate::ZipPrivate() : - headers(0), - device(0), - file(0), - uBuffer(0), - crcTable(0), - comment(), - password() -{ - // keep an unsigned pointer so we avoid to over bloat the code with casts - uBuffer = (unsigned char*) buffer1; - crcTable = get_crc_table(); -} - -//! \internal -ZipPrivate::~ZipPrivate() -{ - closeArchive(); -} - -//! \internal -Zip::ErrorCode ZipPrivate::createArchive(QIODevice* dev) -{ - Q_ASSERT(dev); - - if (device) - closeArchive(); - - device = dev; - if (device != file) - connect(device, SIGNAL(destroyed(QObject*)), this, SLOT(deviceDestroyed(QObject*))); - - 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; - return Zip::Ok; -} - -//! \internal -void ZipPrivate::deviceDestroyed(QObject*) -{ - qDebug("Unexpected device destruction detected."); - do_closeArchive(); -} - -/*! Returns true if an entry for \p info has already been added. - Uses file size and lower case absolute path to compare entries. -*/ -bool ZipPrivate::containsEntry(const QFileInfo& info) const -{ - if (!headers || headers->isEmpty()) - return false; - - const qint64 sz = info.size(); - const QString path = info.absoluteFilePath().toLower(); - - QMap::ConstIterator b = headers->constBegin(); - const QMap::ConstIterator e = headers->constEnd(); - while (b != e) { - const ZipEntryP* e = b.value(); - if (e->fileSize == sz && e->absolutePath == path) - return true; - ++b; - } - - return false; -} - -//! \internal Actual implementation of the addDirectory* methods. -Zip::ErrorCode ZipPrivate::addDirectory(const QString& path, const QString& root, - Zip::CompressionOptions options, Zip::CompressionLevel level, int hierarchyLevel, - int* addedFiles) -{ - if (addedFiles) - ++(*addedFiles); - - // Bad boy didn't call createArchive() yet :) - if (!device) - return Zip::NoOpenArchive; - - QDir dir(path); - if (!dir.exists()) - return Zip::FileNotFound; - - // Remove any trailing separator - QString actualRoot = root.trimmed(); - - // Preserve Unix root but make sure the path ends only with a single - // unix like separator - ::checkRootPath(actualRoot); - - // QDir::cleanPath() fixes some issues with QDir::dirName() - QFileInfo current(QDir::cleanPath(path)); - - const bool path_absolute = options.testFlag(Zip::AbsolutePaths); - const bool path_ignore = options.testFlag(Zip::IgnorePaths); - const bool path_noroot = options.testFlag(Zip::IgnoreRoot); - - if (path_absolute && !path_ignore && !path_noroot) { - QString absolutePath = extractRoot(path, options); - if (!absolutePath.isEmpty() && absolutePath != QLatin1String("/")) - absolutePath.append(QLatin1String("/")); - actualRoot.append(absolutePath); - } - - const bool skipDirName = !hierarchyLevel && path_noroot; - if (!path_ignore && !skipDirName) { - actualRoot.append(QDir(current.absoluteFilePath()).dirName()); - actualRoot.append(QLatin1String("/")); - } - - // actualRoot now contains the path of the file relative to the zip archive - // with a trailing / - - const bool skipBad = options & Zip::SkipBadFiles; - const bool noDups = options & Zip::CheckForDuplicates; - - const QDir::Filters dir_filter = - QDir::Files | - QDir::Dirs | - QDir::NoDotAndDotDot | - QDir::NoSymLinks; - const QDir::SortFlags dir_sort = - QDir::DirsFirst; - QFileInfoList list = dir.entryInfoList(dir_filter, dir_sort); - - Zip::ErrorCode ec = Zip::Ok; - bool filesAdded = false; - - Zip::CompressionOptions recursionOptions; - if (path_ignore) - recursionOptions |= Zip::IgnorePaths; - else recursionOptions |= Zip::RelativePaths; - - for (int i = 0; i < list.size(); ++i) { - QFileInfo info = list.at(i); - const QString absPath = info.absoluteFilePath(); - if (noDups && containsEntry(info)) - continue; - if (info.isDir()) { - // Recursion - ec = addDirectory(absPath, actualRoot, recursionOptions, - level, hierarchyLevel + 1, addedFiles); - } else { - ec = createEntry(info, actualRoot, level); - if (ec == Zip::Ok) { - filesAdded = true; - if (addedFiles) - ++(*addedFiles); - } - } - - if (ec != Zip::Ok && !skipBad) { - break; - } - } - - // 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 && !path_ignore) - ec = createEntry(current, actualRoot, level); - - return ec; -} - -//! \internal Actual implementation of the addFile methods. -Zip::ErrorCode ZipPrivate::addFiles(const QStringList& files, const QString& root, - Zip::CompressionOptions options, Zip::CompressionLevel level, - int* addedFiles) -{ - if (addedFiles) - *addedFiles = 0; - - const bool skipBad = options & Zip::SkipBadFiles; - const bool noDups = options & Zip::CheckForDuplicates; - - // Bad boy didn't call createArchive() yet :) - if (!device) - return Zip::NoOpenArchive; - - QFileInfoList paths; - paths.reserve(files.size()); - for (int i = 0; i < files.size(); ++i) { - QFileInfo info(files.at(i)); - if (noDups && (paths.contains(info) || containsEntry(info))) - continue; - if (!info.exists() || !info.isReadable()) { - if (skipBad) { - continue; - } else { - return Zip::FileNotFound; - } - } - paths.append(info); - } - - if (paths.isEmpty()) - return Zip::Ok; - - // Remove any trailing separator - QString actualRoot = root.trimmed(); - - // Preserve Unix root but make sure the path ends only with a single - // unix like separator - ::checkRootPath(actualRoot); - - const bool path_absolute = options.testFlag(Zip::AbsolutePaths); - const bool path_ignore = options.testFlag(Zip::IgnorePaths); - const bool path_noroot = options.testFlag(Zip::IgnoreRoot); - - Zip::ErrorCode ec = Zip::Ok; - QHash dirMap; - - for (int i = 0; i < paths.size(); ++i) { - const QFileInfo& info = paths.at(i); - const QString path = QFileInfo(QDir::cleanPath(info.absolutePath())).absolutePath(); - - ZippedDir& zd = dirMap[path]; - if (!zd.init) { - zd.init = true; - zd.actualRoot = actualRoot; - if (path_absolute && !path_ignore && !path_noroot) { - QString absolutePath = extractRoot(path, options); - if (!absolutePath.isEmpty() && absolutePath != QLatin1String("/")) - absolutePath.append(QLatin1String("/")); - zd.actualRoot.append(absolutePath); - } - - if (!path_ignore && !path_noroot) { - zd.actualRoot.append(QDir(path).dirName()); - zd.actualRoot.append(QLatin1String("/")); - } - } - - // zd.actualRoot now contains the path of the file relative to the zip archive - // with a trailing / - - if (info.isDir()) { - // Recursion - ec = addDirectory(info.absoluteFilePath(), actualRoot, options, - level, 1, addedFiles); - } else { - ec = createEntry(info, actualRoot, level); - if (ec == Zip::Ok) { - ++zd.files; - if (addedFiles) - ++(*addedFiles); - } - } - - if (ec != Zip::Ok && !skipBad) { - break; - } - } - - // Create explicit records for empty directories - if (!path_ignore) { - QHash::ConstIterator b = dirMap.constBegin(); - const QHash::ConstIterator e = dirMap.constEnd(); - while (b != e) { - const ZippedDir& zd = b.value(); - if (zd.files <= 0) { - ec = createEntry(b.key(), zd.actualRoot, level); - } - ++b; - } - } - - return ec; -} - -//! \internal \p file must be a file and not a directory. -Zip::ErrorCode ZipPrivate::deflateFile(const QFileInfo& fileInfo, - quint32& crc, qint64& written, const Zip::CompressionLevel& level, quint32** keys) -{ - const QString path = fileInfo.absoluteFilePath(); - QFile file(path); - if (!file.open(QIODevice::ReadOnly)) { - qDebug() << QString("An error occurred while opening %1").arg(path); - return Zip::OpenFailed; - } - - const Zip::ErrorCode ec = (level == Zip::Store) - ? storeFile(path, file, crc, written, keys) - : compressFile(path, file, crc, written, level, keys); - - file.close(); - return ec; -} - -//! \internal -Zip::ErrorCode ZipPrivate::storeFile(const QString& path, QIODevice& file, - quint32& crc, qint64& totalWritten, quint32** keys) -{ - Q_UNUSED(path); - - qint64 read = 0; - qint64 written = 0; - - const bool encrypt = keys != 0; - - totalWritten = 0; - crc = crc32(0L, Z_NULL, 0); - - while ( (read = file.read(buffer1, ZIP_READ_BUFFER)) > 0 ) { - crc = crc32(crc, uBuffer, read); - if (encrypt) - encryptBytes(*keys, buffer1, read); - written = device->write(buffer1, read); - totalWritten += written; - if (written != read) { - return Zip::WriteFailed; - } - } - - return Zip::Ok; -} - -//! \internal -int ZipPrivate::compressionStrategy(const QString& path, QIODevice& file) const -{ - Q_UNUSED(file); - -#ifndef OSDAB_ZIP_NO_PNG_RLE - return Z_DEFAULT_STRATEGY; -#endif - const bool isPng = path.endsWith(QLatin1String("png"), Qt::CaseInsensitive); - return isPng ? Z_RLE : Z_DEFAULT_STRATEGY; -} - -//! \internal -Zip::ErrorCode ZipPrivate::compressFile(const QString& path, QIODevice& file, - quint32& crc, qint64& totalWritten, const Zip::CompressionLevel& level, quint32** keys) -{ - qint64 read = 0; - qint64 written = 0; - - qint64 totRead = 0; - qint64 toRead = file.size(); - - const bool encrypt = keys != 0; - const int strategy = compressionStrategy(path, file); - - totalWritten = 0; - crc = crc32(0L, Z_NULL, 0); - - 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, // compression level - Z_DEFLATED, // method - -MAX_WBITS, // windowBits - 8, // memLevel - strategy, - ZLIB_VERSION, - sizeof(z_stream) - )) != Z_OK ) { - qDebug() << "Could not initialize zlib for compression"; - return Zip::ZlibError; - } - - qint64 compressed; - int flush = Z_NO_FLUSH; - do { - read = file.read(buffer1, ZIP_READ_BUFFER); - totRead += read; - if (!read) - break; - - if (read < 0) { - deflateEnd(&zstr); - qDebug() << QString("Error while reading %1").arg(path); - 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 (encrypt) - encryptBytes(*keys, buffer2, compressed); - - written = device->write(buffer2, compressed); - totalWritten += written; - - if (written != compressed) { - deflateEnd(&zstr); - qDebug() << QString("Error while writing %1").arg(path); - return Zip::WriteFailed; - } - - } 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); - - 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) -{ - const bool dirOnly = file.isDir(); - - // entryName contains the path as it should be written - // in the zip file records - const QString entryName = dirOnly - ? root - : root + file.fileName(); - - // Directory entry - if (dirOnly || file.size() < ZIP_COMPRESSION_THRESHOLD) { - level = Zip::Store; - } else { - switch (level) { - case Zip::AutoCPU: - level = Zip::Deflate5; -#ifndef OSDAB_ZIP_NO_DEBUG - qDebug("Compression level for '%s': %d", entryName.toLatin1().constData(), (int)level); -#endif - break; - case Zip::AutoMIME: - level = detectCompressionByMime(file.completeSuffix().toLower()); -#ifndef OSDAB_ZIP_NO_DEBUG - qDebug("Compression level for '%s': %d", entryName.toLatin1().constData(), (int)level); -#endif - break; - case Zip::AutoFull: - level = detectCompressionByMime(file.completeSuffix().toLower()); -#ifndef OSDAB_ZIP_NO_DEBUG - qDebug("Compression level for '%s': %d", entryName.toLatin1().constData(), (int)level); -#endif - break; - default: ; - } - } - - - - // create header and store it to write a central directory later - QScopedPointer h(new ZipEntryP); - h->absolutePath = file.absoluteFilePath().toLower(); - h->fileSize = file.size(); - - // 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(); - dt = OSDAB_ZIP_MANGLE(fromFileTimestamp)(dt); - 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(); - - h->compMethod = (level == Zip::Store) ? 0 : 0x0008; - - // **** 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.toLatin1(); - 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) { - return Zip::WriteFailed; - } - - // Write out filename - if (device->write(entryNameBytes) != sz) { - 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) { - return Zip::WriteFailed; - } - } - - quint32 crc = 0; - qint64 written = 0; - - if (!dirOnly) { - quint32* k = keys; - const Zip::ErrorCode ec = deflateFile(file, crc, written, level, encrypt ? &k : 0); - if (ec != Zip::Ok) - return ec; - Q_ASSERT(!h.isNull()); - } - - // Store end of entry offset - quint32 current = device->pos(); - - // Update crc and compressed size in local header - if (!device->seek(crcOffset)) { - 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) { - return Zip::WriteFailed; - } - - // Seek to end of entry - if (!device->seek(current)) { - 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) { - return Zip::WriteFailed; - } - } - - headers->insert(entryName, h.take()); - 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.toLatin1(); - int sz = pwdBytes.size(); - const char* ascii = pwdBytes.data(); - - for (int i = 0; i < sz; ++i) - updateKeys(keys, (int)ascii[i]); -} - -//! Updates a one-char-only CRC; it's the Info-Zip macro re-adapted. -quint32 ZipPrivate::updateChecksum(const quint32& crc, const quint32& val) const -{ - return quint32(crcTable[quint32(crc^val) & 0xff] ^ crc_t(crc >> 8)); -} - -//! \internal Updates encryption keys. -void ZipPrivate::updateKeys(quint32* keys, int c) const -{ - keys[0] = updateChecksum(keys[0], c); - keys[1] += keys[0] & 0xff; - keys[1] = keys[1] * 134775813L + 1; - keys[2] = updateChecksum(keys[2], ((int)keys[1]) >> 24); -} - -//! \internal Encrypts a byte array. -void ZipPrivate::encryptBytes(quint32* keys, char* buffer, qint64 read) -{ - char t; - - for (qint64 i = 0; i < read; ++i) { - t = buffer[i]; - buffer[i] ^= decryptByte(keys[2]); - updateKeys(keys, t); - } -} - -namespace { -struct KeywordHelper { - const QString needle; - inline KeywordHelper(const QString& keyword) : needle(keyword) {} -}; - -bool operator<(const KeywordHelper& helper, const char* keyword) { - return helper.needle.compare(QLatin1String(keyword)) < 0; -} - -bool operator<(const char* keyword, const KeywordHelper& helper) { - return helper.needle.compare(QLatin1String(keyword)) > 0; -} - -bool hasExtension(const QString& ext, const char* const* map, int max) { - const char* const* start = &map[0]; - const char* const* end = &map[max - 1]; - const char* const* kw = qBinaryFind(start, end, KeywordHelper(ext)); - return kw != end; -} -} - -//! \internal Detects the best compression level for a given file extension. -Zip::CompressionLevel ZipPrivate::detectCompressionByMime(const QString& ext) -{ - // NOTE: Keep the MAX_* and the number of strings in the map up to date. - // NOTE: Alphabetically sort the strings in the map -- we use a binary search! - - // Archives or files that will hardly compress - const int MAX_EXT1 = 14; - const char* const ext1[MAX_EXT1] = { - "7z", "bin", "deb", "exe", "gz", "gz2", "jar", "rar", "rpm", "tar", "tgz", "z", "zip", - 0 // # MAX_EXT1 - }; - - // Slow or usually large files that we should not spend to much time with - const int MAX_EXT2 = 24; - const char* const ext2[MAX_EXT2] = { - "asf", - "avi", - "divx", - "doc", - "docx", - "flv", - "gif", - "iso", - "jpg", - "jpeg", - "mka", - "mkv", - "mp3", - "mp4", - "mpeg", - "mpg", - "odt", - "ogg", - "ogm", - "ra", - "rm", - "wma", - "wmv", - 0 // # MAX_EXT2 - }; - - // Files with high compression ratio - const int MAX_EXT3 = 28; - const char* const ext3[MAX_EXT3] = { - "asp", "bat", "c", "conf", "cpp", "cpp", "css", "csv", "cxx", "h", "hpp", "htm", "html", "hxx", - "ini", "js", "php", "pl", "py", "rtf", "sh", "tsv", "txt", "vb", "vbs", "xml", "xst", - 0 // # MAX_EXT3 - }; - - const char* const* map = ext1; - if (hasExtension(ext, map, MAX_EXT1)) - return Zip::Store; - - map = ext2; - if (hasExtension(ext, map, MAX_EXT2)) - return Zip::Deflate2; - - map = ext3; - if (hasExtension(ext, map, MAX_EXT3)) - return Zip::Deflate9; - - return Zip::Deflate5; -} - -/*! - Closes the current archive and writes out pending data. -*/ -Zip::ErrorCode ZipPrivate::closeArchive() -{ - if (!device) { - Q_ASSERT(!file); - return Zip::Ok; - } - - if (device != file) - disconnect(device, 0, this, 0); - - return do_closeArchive(); -} - -//! \internal -Zip::ErrorCode ZipPrivate::do_closeArchive() -{ - // Close current archive by writing out central directory - // and free up resources - - if (!device && !headers) - return Zip::Ok; - - quint32 szCentralDir = 0; - quint32 offCentralDir = device->pos(); - Zip::ErrorCode c = Zip::Ok; - - if (headers && device) { - for (QMap::ConstIterator itr = headers->constBegin(); - itr != headers->constEnd(); ++itr) { - const QString fileName = itr.key(); - const ZipEntryP* h = itr.value(); - c = writeEntry(fileName, h, szCentralDir); - } - } - - if (c == Zip::Ok) - c = writeCentralDir(offCentralDir, szCentralDir); - - if (c != Zip::Ok) { - if (file) { - file->close(); - if (!file->remove()) { - qDebug() << "Failed to delete corrupt archive."; - } - } - } - - return c; -} - -//! \internal -Zip::ErrorCode ZipPrivate::writeEntry(const QString& fileName, const ZipEntryP* h, quint32& szCentralDir) -{ - unsigned int sz; - - Q_ASSERT(h && device && headers); - - // 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 = fileName.toLatin1(); - 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) { - return Zip::WriteFailed; - } - - // Write out filename - if ((unsigned int)device->write(fileNameBytes) != sz) { - return Zip::WriteFailed; - } - - szCentralDir += (ZIP_CD_SIZE + sz); - - return Zip::Ok; -} - -//! \internal -Zip::ErrorCode ZipPrivate::writeCentralDir(quint32 offCentralDir, quint32 szCentralDir) -{ - Q_ASSERT(device && headers); - - unsigned int sz; - - // 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.toLatin1(); - 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) { - return Zip::WriteFailed; - } - - if (commentLength != 0) { - if ((unsigned int)device->write(commentBytes) != commentLength) { - return Zip::WriteFailed; - } - } - - return Zip::Ok; -} - -//! \internal -void ZipPrivate::reset() -{ - comment.clear(); - - if (headers) { - qDeleteAll(*headers); - delete headers; - headers = 0; - } - - device = 0; - - if (file) - delete file; - file = 0; -} - -//! \internal Returns the path of the parent directory -QString ZipPrivate::extractRoot(const QString& p, Zip::CompressionOptions o) -{ - Q_UNUSED(o); - QDir d(QDir::cleanPath(p)); - if (!d.exists()) - return QString(); - - if (!d.cdUp()) - return QString(); - - return d.absolutePath(); -} - - -/************************************************************************ - 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; -} - -/*! - 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) -{ - closeArchive(); - Q_ASSERT(!d->device && !d->file); - - if (filename.isEmpty()) - return Zip::FileNotFound; - - d->file = new QFile(filename); - - if (d->file->exists() && !overwrite) { - delete d->file; - d->file = 0; - return Zip::FileExists; - } - - if (!d->file->open(QIODevice::WriteOnly)) { - delete d->file; - d->file = 0; - return Zip::OpenFailed; - } - - const Zip::ErrorCode ec = createArchive(d->file); - if (ec != Zip::Ok) { - closeArchive(); - } - - 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) { - 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) -{ - d->comment = comment; -} - -/*! - 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. - - The result is that all files found in \p path (and in subdirectories) are - added to the zip file without a directory entry. -*/ -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. - - The result is that all files found in \p path (and in subdirectories) are - added to the zip file without a directory entry (or within a directory - structure specified by \p root). -*/ -Zip::ErrorCode Zip::addDirectoryContents(const QString& path, const QString& root, CompressionLevel level) -{ - return addDirectory(path, root, IgnorePaths, level); -} - -/*! - Convenience method, same as calling - Zip::addDirectory(const QString&,const QString&,CompressionLevel) - with an empty \p root parameter and Zip::RelativePaths flag as compression option. - */ -Zip::ErrorCode Zip::addDirectory(const QString& path, CompressionLevel level) -{ - return addDirectory(path, QString(), Zip::RelativePaths, 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); -} - -/*! - 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!). - - If \p addedFiles is not null it is set to the number of successfully added - files. -*/ -Zip::ErrorCode Zip::addDirectory(const QString& path, const QString& root, - CompressionOptions options, CompressionLevel level, int* addedFiles) -{ - const int hierarchyLev = 0; - return d->addDirectory(path, root, options, level, hierarchyLev, addedFiles); -} - -/*! - Convenience method, same as calling Zip::addFile(const QString&,const QString&,CompressionOptions,CompressionLevel) - with an empty \p root parameter and Zip::RelativePaths as compression option. - */ -Zip::ErrorCode Zip::addFile(const QString& path, CompressionLevel level) -{ - return addFile(path, QString(), Zip::RelativePaths, level); -} - -/*! - Convenience method, same as calling Zip::addFile(const QString&,const QString&,CompressionOptions,CompressionLevel) - with the Zip::RelativePaths flag as compression option. - */ -Zip::ErrorCode Zip::addFile(const QString& path, const QString& root, - CompressionLevel level) -{ - return addFile(path, root, Zip::RelativePaths, level); -} - -/*! - Adds the file at \p path to the archive, using \p root as name for the root folder. - If \p path points to a directory the behaviour is basically the same as - addDirectory(). - - 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::addFile(const QString& path, const QString& root, - CompressionOptions options, CompressionLevel level) -{ - if (path.isEmpty()) - return Zip::Ok; - return addFiles(QStringList() << path, root, options, level); -} - -/*! - Convenience method, same as calling Zip::addFiles(const QStringList&,const QString&,CompressionOptions,CompressionLevel) - with an empty \p root parameter and Zip::RelativePaths as compression option. - */ -Zip::ErrorCode Zip::addFiles(const QStringList& paths, CompressionLevel level) -{ - return addFiles(paths, QString(), Zip::RelativePaths, level); -} - -/*! - Convenience method, same as calling Zip::addFiles(const QStringList&,const QString&,CompressionOptions,CompressionLevel) - with the Zip::RelativePaths flag as compression option. - */ -Zip::ErrorCode Zip::addFiles(const QStringList& paths, const QString& root, - CompressionLevel level) -{ - return addFiles(paths, root, Zip::RelativePaths, level); -} - -/*! - Adds the files or directories in \p paths to the archive, using \p root as - name for the root folder. - This is similar to calling addFile or addDirectory for all the entries in - \p paths, except it is slightly faster. - - 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!). - - If \p addedFiles is not null it is set to the number of successfully added - files. -*/ -Zip::ErrorCode Zip::addFiles(const QStringList& paths, const QString& root, - CompressionOptions options, CompressionLevel level, int* addedFiles) -{ - return d->addFiles(paths, root, options, level, addedFiles); -} - -/*! - 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."); -} - -OSDAB_END_NAMESPACE diff --git a/cockatrice/src/zip/zip.h b/cockatrice/src/zip/zip.h deleted file mode 100755 index 79f32ada5..000000000 --- a/cockatrice/src/zip/zip.h +++ /dev/null @@ -1,158 +0,0 @@ -/**************************************************************************** -** Filename: zip.h -** Last updated [dd/mm/yyyy]: 27/03/2011 -** -** 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-2012 Angius Fabrizio. All rights reserved. -** -** This file is part of the OSDaB project (http://osdab.42cows.org/). -** -** 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. -** -**********************************************************************/ - -#ifndef OSDAB_ZIP__H -#define OSDAB_ZIP__H - -#include "zipglobal.h" - -#include -#include - -#include - -class QIODevice; -class QFile; -class QDir; -class QStringList; -class QString; - -OSDAB_BEGIN_NAMESPACE(Zip) - -class ZipPrivate; - -class OSDAB_ZIP_EXPORT Zip -{ -public: - enum ErrorCode - { - Ok, - ZlibInit, - ZlibError, - FileExists, - OpenFailed, - NoOpenArchive, - FileNotFound, - ReadFailed, - WriteFailed, - SeekFailed, - InternalError - }; - - enum CompressionLevel - { - Store, - Deflate1 = 1, Deflate2, Deflate3, Deflate4, - Deflate5, Deflate6, Deflate7, Deflate8, Deflate9, - AutoCPU, AutoMIME, AutoFull - }; - - enum CompressionOption - { - /*! Does not preserve absolute paths in the zip file when adding a - file or directory (default) */ - RelativePaths = 0x0001, - /*! Preserve absolute paths */ - AbsolutePaths = 0x0002, - /*! Do not store paths. All the files are put in the (evtl. user defined) - root of the zip file */ - IgnorePaths = 0x0004, - /*! Works only with addDirectory(). Adds the directory's contents, - including subdirectories, but does not add an entry for the root - directory itself. */ - IgnoreRoot = 0x0008, - /*! Used only when compressing a directory or multiple files. - If set invalid or unreadable files are simply skipped. - */ - SkipBadFiles = 0x0020, - /*! Makes sure a file is never added twice to the same zip archive. - This check is only necessary in certain usage scenarios and given - that it slows down processing you need to enable it explicitly with - this flag. - */ - CheckForDuplicates = 0x0040 - }; - Q_DECLARE_FLAGS(CompressionOptions, CompressionOption) - - Zip(); - virtual ~Zip(); - - bool isOpen() const; - - void setPassword(const QString& pwd); - void clearPassword(); - QString password() const; - - ErrorCode createArchive(const QString& file, bool overwrite = true); - ErrorCode createArchive(QIODevice* device); - - QString archiveComment() const; - void setArchiveComment(const QString& comment); - - ErrorCode addDirectoryContents(const QString& path, - CompressionLevel level = AutoFull); - ErrorCode addDirectoryContents(const QString& path, const QString& root, - CompressionLevel level = AutoFull); - - ErrorCode addDirectory(const QString& path, - CompressionLevel level = AutoFull); - ErrorCode addDirectory(const QString& path, const QString& root, - CompressionLevel level = AutoFull); - ErrorCode addDirectory(const QString& path, const QString& root, - CompressionOptions options, CompressionLevel level = AutoFull, - int* addedFiles = 0); - - ErrorCode addFile(const QString& path, - CompressionLevel level = AutoFull); - ErrorCode addFile(const QString& path, const QString& root, - CompressionLevel level = AutoFull); - ErrorCode addFile(const QString& path, const QString& root, - CompressionOptions options, - CompressionLevel level = AutoFull); - - ErrorCode addFiles(const QStringList& paths, - CompressionLevel level = AutoFull); - ErrorCode addFiles(const QStringList& paths, const QString& root, - CompressionLevel level = AutoFull); - ErrorCode addFiles(const QStringList& paths, const QString& root, - CompressionOptions options, - CompressionLevel level = AutoFull, - int* addedFiles = 0); - - ErrorCode closeArchive(); - - QString formatError(ErrorCode c) const; - -private: - ZipPrivate* d; -}; - -Q_DECLARE_OPERATORS_FOR_FLAGS(Zip::CompressionOptions) - -OSDAB_END_NAMESPACE - -#endif // OSDAB_ZIP__H diff --git a/cockatrice/src/zip/zip_p.h b/cockatrice/src/zip/zip_p.h deleted file mode 100755 index b8ec6564b..000000000 --- a/cockatrice/src/zip/zip_p.h +++ /dev/null @@ -1,133 +0,0 @@ -/**************************************************************************** -** Filename: zip_p.h -** Last updated [dd/mm/yyyy]: 27/03/2011 -** -** 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-2012 Angius Fabrizio. All rights reserved. -** -** This file is part of the OSDaB project (http://osdab.42cows.org/). -** -** 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. -** -**********************************************************************/ - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Zip/UnZip API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#ifndef OSDAB_ZIP_P__H -#define OSDAB_ZIP_P__H - -#include "zip.h" -#include "zipentry_p.h" - -#include -#include -#include - -#include - -/*! - zLib authors suggest using larger buffers (128K or 256K) for (de)compression (especially for inflate()) - we use a 256K buffer here - if you want to use this code on a pre-iceage mainframe please change it ;) -*/ -#define ZIP_READ_BUFFER (256*1024) - -OSDAB_BEGIN_NAMESPACE(Zip) - -class ZipPrivate : public QObject -{ - Q_OBJECT - -public: - // uLongf from zconf.h - typedef uLongf crc_t; - - ZipPrivate(); - virtual ~ZipPrivate(); - - QMap* headers; - - QIODevice* device; - QFile* file; - - char buffer1[ZIP_READ_BUFFER]; - char buffer2[ZIP_READ_BUFFER]; - - unsigned char* uBuffer; - - const crc_t* crcTable; - - QString comment; - QString password; - - Zip::ErrorCode createArchive(QIODevice* device); - Zip::ErrorCode closeArchive(); - void reset(); - - bool zLibInit(); - - bool containsEntry(const QFileInfo& info) const; - - Zip::ErrorCode addDirectory(const QString& path, const QString& root, - Zip::CompressionOptions options, Zip::CompressionLevel level, - int hierarchyLevel, int* addedFiles = 0); - Zip::ErrorCode addFiles(const QStringList& paths, const QString& root, - Zip::CompressionOptions options, Zip::CompressionLevel level, - int* addedFiles); - - Zip::ErrorCode createEntry(const QFileInfo& file, const QString& root, - Zip::CompressionLevel level); - Zip::CompressionLevel detectCompressionByMime(const QString& ext); - - inline quint32 updateChecksum(const quint32& crc, const quint32& val) const; - - inline void encryptBytes(quint32* keys, char* buffer, qint64 read); - - inline void setULong(quint32 v, char* buffer, unsigned int offset); - inline void updateKeys(quint32* keys, int c) const; - inline void initKeys(quint32* keys) const; - inline int decryptByte(quint32 key2) const; - - inline QString extractRoot(const QString& p, Zip::CompressionOptions o); - -private slots: - void deviceDestroyed(QObject*); - -private: - int compressionStrategy(const QString& path, QIODevice& file) const; - Zip::ErrorCode deflateFile(const QFileInfo& fileInfo, - quint32& crc, qint64& written, const Zip::CompressionLevel& level, quint32** keys); - Zip::ErrorCode storeFile(const QString& path, QIODevice& file, - quint32& crc, qint64& written, quint32** keys); - Zip::ErrorCode compressFile(const QString& path, QIODevice& file, - quint32& crc, qint64& written, const Zip::CompressionLevel& level, quint32** keys); - Zip::ErrorCode do_closeArchive(); - Zip::ErrorCode writeEntry(const QString& fileName, const ZipEntryP* h, quint32& szCentralDir); - Zip::ErrorCode writeCentralDir(quint32 offCentralDir, quint32 szCentralDir); -}; - -OSDAB_END_NAMESPACE - -#endif // OSDAB_ZIP_P__H diff --git a/cockatrice/src/zip/zipentry_p.h b/cockatrice/src/zip/zipentry_p.h deleted file mode 100755 index f0675b6b6..000000000 --- a/cockatrice/src/zip/zipentry_p.h +++ /dev/null @@ -1,91 +0,0 @@ -/**************************************************************************** -** Filename: ZipEntryP.h -** Last updated [dd/mm/yyyy]: 27/03/2011 -** -** Wrapper for a ZIP local header. -** -** 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-2012 Angius Fabrizio. All rights reserved. -** -** This file is part of the OSDaB project (http://osdab.42cows.org/). -** -** 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. -** -**********************************************************************/ - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Zip/UnZip API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#ifndef OSDAB_ZIPENTRY_P__H -#define OSDAB_ZIPENTRY_P__H - -#include -#include - -OSDAB_BEGIN_NAMESPACE(Zip) - -class ZipEntryP -{ -public: - ZipEntryP() : - lhOffset(0), - dataOffset(0), - gpFlag(), - compMethod(0), - modTime(), - modDate(), - crc(0), - szComp(0), - szUncomp(0), - absolutePath(), - fileSize(0), - lhEntryChecked(false) - { - gpFlag[0] = gpFlag[1] = 0; - modTime[0] = modTime[1] = 0; - modDate[0] = modDate[1] = 0; - } - - quint32 lhOffset; // Offset of the local header record for this entry - mutable quint32 dataOffset; // Offset of the file data for this entry - unsigned char gpFlag[2]; // General purpose flag - quint16 compMethod; // Compression method - unsigned char modTime[2]; // Last modified time - unsigned char modDate[2]; // Last modified date - quint32 crc; // CRC32 - quint32 szComp; // Compressed file size - quint32 szUncomp; // Uncompressed file size - QString comment; // File comment - - QString absolutePath; // Internal use - qint64 fileSize; // Internal use - - mutable bool lhEntryChecked; // Is true if the local header record for this entry has been parsed - - inline bool isEncrypted() const { return gpFlag[0] & 0x01; } - inline bool hasDataDescriptor() const { return gpFlag[0] & 0x08; } -}; - -OSDAB_END_NAMESPACE - -#endif // OSDAB_ZIPENTRY_P__H diff --git a/cockatrice/src/zip/zipglobal.cpp b/cockatrice/src/zip/zipglobal.cpp deleted file mode 100644 index e972005f5..000000000 --- a/cockatrice/src/zip/zipglobal.cpp +++ /dev/null @@ -1,150 +0,0 @@ -/**************************************************************************** -** Filename: zipglobal.cpp -** Last updated [dd/mm/yyyy]: 06/02/2011 -** -** 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-2012 Angius Fabrizio. All rights reserved. -** -** This file is part of the OSDaB project (http://osdab.42cows.org/). -** -** 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 "zipglobal.h" - -#if defined(Q_OS_WIN) || defined(Q_OS_WINCE) || defined(Q_OS_LINUX) || defined(Q_OS_MACOS) -#define OSDAB_ZIP_HAS_UTC -#include -#else -#undef OSDAB_ZIP_HAS_UTC -#endif - -#if defined(Q_OS_WIN) -#include -#elif defined(Q_OS_LINUX) || defined(Q_OS_MACOS) -#include -#endif - -OSDAB_BEGIN_NAMESPACE(Zip) - -/*! Returns the current UTC offset in seconds unless OSDAB_ZIP_NO_UTC is defined - and method is implemented for the current platform and 0 otherwise. -*/ -int OSDAB_ZIP_MANGLE(currentUtcOffset)() -{ -#if !(!defined OSDAB_ZIP_NO_UTC && defined OSDAB_ZIP_HAS_UTC) - return 0; -#else - time_t curr_time_t; - time(&curr_time_t); - -#if defined Q_OS_WIN - struct tm _tm_struct; - struct tm *tm_struct = &_tm_struct; -#else - struct tm *tm_struct = 0; -#endif - -#if !defined(QT_NO_THREAD) && defined(_POSIX_THREAD_SAFE_FUNCTIONS) - // use the reentrant version of localtime() where available - tzset(); - tm res; - tm_struct = gmtime_r(&curr_time_t, &res); -#elif defined Q_OS_WIN && !defined Q_CC_MINGW - if (gmtime_s(tm_struct, &curr_time_t)) - return 0; -#else - tm_struct = gmtime(&curr_time_t); -#endif - - if (!tm_struct) - return 0; - - const time_t global_time_t = mktime(tm_struct); - -#if !defined(QT_NO_THREAD) && defined(_POSIX_THREAD_SAFE_FUNCTIONS) - // use the reentrant version of localtime() where available - tm_struct = localtime_r(&curr_time_t, &res); -#elif defined Q_OS_WIN && !defined Q_CC_MINGW - if (localtime_s(tm_struct, &curr_time_t)) - return 0; -#else - tm_struct = localtime(&curr_time_t); -#endif - - if (!tm_struct) - return 0; - - const time_t local_time_t = mktime(tm_struct); - - const int utcOffset = -qRound(difftime(global_time_t, local_time_t)); - return tm_struct->tm_isdst > 0 ? utcOffset + 3600 : utcOffset; -#endif // No UTC -} - -QDateTime OSDAB_ZIP_MANGLE(fromFileTimestamp)(const QDateTime &dateTime) -{ -#if !defined OSDAB_ZIP_NO_UTC && defined OSDAB_ZIP_HAS_UTC - const int utc = OSDAB_ZIP_MANGLE(currentUtcOffset)(); - return dateTime.toUTC().addSecs(utc); -#else - return dateTime; -#endif // OSDAB_ZIP_NO_UTC -} - -bool OSDAB_ZIP_MANGLE(setFileTimestamp)(const QString &fileName, const QDateTime &dateTime) -{ - if (fileName.isEmpty()) - return true; - -#ifdef Q_OS_WIN - HANDLE hFile = - CreateFileW(fileName.toStdWString().c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0); - if (hFile == INVALID_HANDLE_VALUE) { - return false; - } - - SYSTEMTIME st; - FILETIME ft, ftLastMod; - const QDate date = dateTime.date(); - const QTime time = dateTime.time(); - st.wYear = date.year(); - st.wMonth = date.month(); - st.wDay = date.day(); - st.wHour = time.hour(); - st.wMinute = time.minute(); - st.wSecond = time.second(); - st.wMilliseconds = time.msec(); - - SystemTimeToFileTime(&st, &ft); - LocalFileTimeToFileTime(&ft, &ftLastMod); - - const bool success = SetFileTime(hFile, NULL, NULL, &ftLastMod); - CloseHandle(hFile); - return success; - -#elif defined(Q_OS_LINUX) || defined(Q_OS_MACOS) - - struct utimbuf t_buffer; - t_buffer.actime = t_buffer.modtime = dateTime.toSecsSinceEpoch(); - return utime(fileName.toLocal8Bit().constData(), &t_buffer) == 0; -#endif - - return true; -} -OSDAB_END_NAMESPACE diff --git a/cockatrice/src/zip/zipglobal.h b/cockatrice/src/zip/zipglobal.h deleted file mode 100755 index e7ff33105..000000000 --- a/cockatrice/src/zip/zipglobal.h +++ /dev/null @@ -1,77 +0,0 @@ -/**************************************************************************** -** Filename: zipglobal.h -** Last updated [dd/mm/yyyy]: 27/03/2011 -** -** 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-2012 Angius Fabrizio. All rights reserved. -** -** This file is part of the OSDaB project (http://osdab.42cows.org/). -** -** 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. -** -**********************************************************************/ - -#ifndef OSDAB_ZIPGLOBAL__H -#define OSDAB_ZIPGLOBAL__H - -#include -#include - -/* If you want to build the OSDaB Zip code as - a library, define OSDAB_ZIP_LIB in the library's .pro file and - in the libraries using it OR remove the #ifndef OSDAB_ZIP_LIB - define below and leave the #else body. Also remember to define - OSDAB_ZIP_BUILD_LIB in the library's project). -*/ - -#ifndef OSDAB_ZIP_LIB -# define OSDAB_ZIP_EXPORT -#else -# if defined(OSDAB_ZIP_BUILD_LIB) -# define OSDAB_ZIP_EXPORT Q_DECL_EXPORT -# else -# define OSDAB_ZIP_EXPORT Q_DECL_IMPORT -# endif -#endif - -#ifdef OSDAB_NAMESPACE -#define OSDAB_BEGIN_NAMESPACE(ModuleName) namespace Osdab { namespace ModuleName { -#else -#define OSDAB_BEGIN_NAMESPACE(ModuleName) -#endif - -#ifdef OSDAB_NAMESPACE -#define OSDAB_END_NAMESPACE } } -#else -#define OSDAB_END_NAMESPACE -#endif - -#ifndef OSDAB_NAMESPACE -#define OSDAB_ZIP_MANGLE(x) zip_##x -#else -#define OSDAB_ZIP_MANGLE(x) x -#endif - -OSDAB_BEGIN_NAMESPACE(Zip) - -OSDAB_ZIP_EXPORT int OSDAB_ZIP_MANGLE(currentUtcOffset)(); -OSDAB_ZIP_EXPORT QDateTime OSDAB_ZIP_MANGLE(fromFileTimestamp)(const QDateTime& dateTime); -OSDAB_ZIP_EXPORT bool OSDAB_ZIP_MANGLE(setFileTimestamp)(const QString& fileName, const QDateTime& dateTime); - -OSDAB_END_NAMESPACE - -#endif // OSDAB_ZIPGLOBAL__H