mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-06-27 17:13:54 -07:00
Add precon import dialog.
This commit is contained in:
parent
ab5d6db8a2
commit
f64d0ec71d
17 changed files with 5795 additions and 1 deletions
683
cockatrice/src/interface/widgets/dialogs/dlg_import_precons.cpp
Normal file
683
cockatrice/src/interface/widgets/dialogs/dlg_import_precons.cpp
Normal file
|
|
@ -0,0 +1,683 @@
|
||||||
|
#include "dlg_import_precons.h"
|
||||||
|
|
||||||
|
#include "../deck/deck_loader.h"
|
||||||
|
#include "../settings/cache_settings.h"
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QFileDialog>
|
||||||
|
#include <QGridLayout>
|
||||||
|
#include <QJsonDocument>
|
||||||
|
#include <QMessageBox>
|
||||||
|
#include <QNetworkReply>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QTemporaryDir>
|
||||||
|
#include <decklist.h>
|
||||||
|
|
||||||
|
#ifdef HAS_LZMA
|
||||||
|
#include "../../src/utility/external/lzma/decompress.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAS_ZLIB
|
||||||
|
#include "../../src/utility/external/zip/unzip.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define ZIP_SIGNATURE "PK"
|
||||||
|
// Xz stream header: 0xFD + "7zXZ"
|
||||||
|
#define XZ_SIGNATURE "\xFD\x37\x7A\x58\x5A"
|
||||||
|
#define MTGJSON_V4_URL_COMPONENT "mtgjson.com/files/"
|
||||||
|
#define MTGJSON_VERSION_URL "https://www.mtgjson.com/api/v5/Meta.json"
|
||||||
|
|
||||||
|
#define ALLDECKS_URL_FALLBACK "https://mtgjson.com/api/v5/AllDeckFiles.zip"
|
||||||
|
|
||||||
|
#ifdef HAS_LZMA
|
||||||
|
#define ALLDECKS_URL "https://mtgjson.com/api/v5/AllDeckFiles.tar.xz"
|
||||||
|
#elif defined(HAS_ZLIB)
|
||||||
|
#define ALLDECKS_URL "https://mtgjson.com/api/v5/AllDeckFiles.zip"
|
||||||
|
#else
|
||||||
|
#define ALLDECKS_URL ""
|
||||||
|
#endif
|
||||||
|
|
||||||
|
DlgImportPrecons::DlgImportPrecons(QWidget *parent) : QWizard(parent)
|
||||||
|
{
|
||||||
|
// define a dummy context that will be used where needed
|
||||||
|
QString dummy = QT_TRANSLATE_NOOP("i18n", "English");
|
||||||
|
|
||||||
|
nam = new QNetworkAccessManager(this);
|
||||||
|
|
||||||
|
addPage(new LoadPreconsPage);
|
||||||
|
addPage(new SavePreconsPage);
|
||||||
|
|
||||||
|
retranslateUi();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DlgImportPrecons::retranslateUi()
|
||||||
|
{
|
||||||
|
setWindowTitle(tr("Preconstructed Deck Importer"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void DlgImportPrecons::accept()
|
||||||
|
{
|
||||||
|
QDialog::accept();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DlgImportPrecons::enableButtons()
|
||||||
|
{
|
||||||
|
button(QWizard::NextButton)->setDisabled(false);
|
||||||
|
button(QWizard::BackButton)->setDisabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DlgImportPrecons::disableButtons()
|
||||||
|
{
|
||||||
|
button(QWizard::NextButton)->setDisabled(true);
|
||||||
|
button(QWizard::BackButton)->setDisabled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
LoadPreconsPage::LoadPreconsPage(QWidget *parent) : QWizardPage(parent)
|
||||||
|
{
|
||||||
|
urlRadioButton = new QRadioButton(this);
|
||||||
|
fileRadioButton = new QRadioButton(this);
|
||||||
|
|
||||||
|
urlLineEdit = new QLineEdit(this);
|
||||||
|
fileLineEdit = new QLineEdit(this);
|
||||||
|
|
||||||
|
progressLabel = new QLabel(this);
|
||||||
|
progressBar = new QProgressBar(this);
|
||||||
|
|
||||||
|
urlRadioButton->setChecked(true);
|
||||||
|
|
||||||
|
urlButton = new QPushButton(this);
|
||||||
|
connect(urlButton, &QPushButton::clicked, this, &LoadPreconsPage::actRestoreDefaultUrl);
|
||||||
|
|
||||||
|
fileButton = new QPushButton(this);
|
||||||
|
connect(fileButton, &QPushButton::clicked, this, &LoadPreconsPage::actLoadPreconsFile);
|
||||||
|
|
||||||
|
auto *layout = new QGridLayout(this);
|
||||||
|
layout->addWidget(urlRadioButton, 0, 0);
|
||||||
|
layout->addWidget(urlLineEdit, 0, 1);
|
||||||
|
layout->addWidget(urlButton, 1, 1, Qt::AlignRight);
|
||||||
|
layout->addWidget(fileRadioButton, 2, 0);
|
||||||
|
layout->addWidget(fileLineEdit, 2, 1);
|
||||||
|
layout->addWidget(fileButton, 3, 1, Qt::AlignRight);
|
||||||
|
layout->addWidget(progressLabel, 4, 0);
|
||||||
|
layout->addWidget(progressBar, 4, 1);
|
||||||
|
|
||||||
|
connect(&watcher, &QFutureWatcher<bool>::finished, this, &LoadPreconsPage::importFinished);
|
||||||
|
|
||||||
|
setLayout(layout);
|
||||||
|
|
||||||
|
retranslateUi();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LoadPreconsPage::initializePage()
|
||||||
|
{
|
||||||
|
urlLineEdit->setText(ALLDECKS_URL);
|
||||||
|
|
||||||
|
progressLabel->hide();
|
||||||
|
progressBar->hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LoadPreconsPage::retranslateUi()
|
||||||
|
{
|
||||||
|
setTitle(tr("Source selection"));
|
||||||
|
setSubTitle(tr("Please specify a compatible source for the list of preconstructed Decks. "
|
||||||
|
"You can specify a URL address that will be downloaded or "
|
||||||
|
"use an existing file from your computer."));
|
||||||
|
|
||||||
|
urlRadioButton->setText(tr("Download URL:"));
|
||||||
|
fileRadioButton->setText(tr("Local file:"));
|
||||||
|
urlButton->setText(tr("Restore default URL"));
|
||||||
|
fileButton->setText(tr("Choose file..."));
|
||||||
|
}
|
||||||
|
|
||||||
|
void LoadPreconsPage::actRestoreDefaultUrl()
|
||||||
|
{
|
||||||
|
urlLineEdit->setText(ALLDECKS_URL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LoadPreconsPage::actLoadPreconsFile()
|
||||||
|
{
|
||||||
|
QFileDialog dialog(this, tr("Load preconstructed Deck file"));
|
||||||
|
dialog.setFileMode(QFileDialog::ExistingFile);
|
||||||
|
|
||||||
|
QString extensions = "*.json *.xml";
|
||||||
|
#ifdef HAS_ZLIB
|
||||||
|
extensions += " *.zip";
|
||||||
|
#endif
|
||||||
|
#ifdef HAS_LZMA
|
||||||
|
extensions += " *.xz";
|
||||||
|
#endif
|
||||||
|
dialog.setNameFilter(tr("Precons file (%1)").arg(extensions));
|
||||||
|
|
||||||
|
if (!fileLineEdit->text().isEmpty() && QFile::exists(fileLineEdit->text())) {
|
||||||
|
dialog.selectFile(fileLineEdit->text());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dialog.exec()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fileLineEdit->setText(dialog.selectedFiles().at(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LoadPreconsPage::validatePage()
|
||||||
|
{
|
||||||
|
// once the import is finished, we call next(); skip validation
|
||||||
|
if (dynamic_cast<DlgImportPrecons *>(wizard())->doneWithParsing) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (urlRadioButton->isChecked()) {
|
||||||
|
const auto url = QUrl::fromUserInput(urlLineEdit->text());
|
||||||
|
|
||||||
|
if (!url.isValid()) {
|
||||||
|
QMessageBox::critical(this, tr("Error"), tr("The provided URL is not valid."));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
progressLabel->setText(tr("Downloading (0MB)"));
|
||||||
|
// show an infinite progressbar
|
||||||
|
progressBar->setMaximum(0);
|
||||||
|
progressBar->setMinimum(0);
|
||||||
|
progressBar->setValue(0);
|
||||||
|
progressLabel->show();
|
||||||
|
progressBar->show();
|
||||||
|
|
||||||
|
dynamic_cast<DlgImportPrecons *>(wizard())->disableButtons();
|
||||||
|
setEnabled(false);
|
||||||
|
|
||||||
|
downloadPreconsFile(url);
|
||||||
|
} else if (fileRadioButton->isChecked()) {
|
||||||
|
QFile setsFile(fileLineEdit->text());
|
||||||
|
if (!setsFile.exists()) {
|
||||||
|
QMessageBox::critical(this, tr("Error"), tr("Please choose a file."));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!setsFile.open(QIODevice::ReadOnly)) {
|
||||||
|
QMessageBox::critical(nullptr, tr("Error"), tr("Cannot open file '%1'.").arg(fileLineEdit->text()));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
dynamic_cast<DlgImportPrecons *>(wizard())->disableButtons();
|
||||||
|
setEnabled(false);
|
||||||
|
|
||||||
|
dynamic_cast<DlgImportPrecons *>(wizard())->setCardSourceUrl(setsFile.fileName());
|
||||||
|
|
||||||
|
readPreconsFromByteArray(setsFile.readAll());
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LoadPreconsPage::downloadPreconsFile(const QUrl &url)
|
||||||
|
{
|
||||||
|
const auto urlString = url.toString();
|
||||||
|
if (urlString == ALLDECKS_URL || urlString == ALLDECKS_URL_FALLBACK) {
|
||||||
|
const auto versionUrl = QUrl::fromUserInput(MTGJSON_VERSION_URL);
|
||||||
|
auto *versionReply = dynamic_cast<DlgImportPrecons *>(wizard())->nam->get(QNetworkRequest(versionUrl));
|
||||||
|
connect(versionReply, &QNetworkReply::finished, [versionReply]() {
|
||||||
|
if (versionReply->error() == QNetworkReply::NoError) {
|
||||||
|
auto jsonData = versionReply->readAll();
|
||||||
|
QJsonParseError jsonError{};
|
||||||
|
auto jsonResponse = QJsonDocument::fromJson(jsonData, &jsonError);
|
||||||
|
|
||||||
|
if (jsonError.error == QJsonParseError::NoError) {
|
||||||
|
const auto jsonMap = jsonResponse.toVariant().toMap();
|
||||||
|
|
||||||
|
auto versionString = jsonMap.value("meta").toMap().value("version").toString();
|
||||||
|
if (versionString.isEmpty()) {
|
||||||
|
versionString = "unknown";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
versionReply->deleteLater();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
dynamic_cast<DlgImportPrecons *>(wizard())->setCardSourceUrl(url.toString());
|
||||||
|
|
||||||
|
auto *reply = dynamic_cast<DlgImportPrecons *>(wizard())->nam->get(QNetworkRequest(url));
|
||||||
|
|
||||||
|
connect(reply, &QNetworkReply::finished, this, &LoadPreconsPage::actDownloadFinishedPreconsFile);
|
||||||
|
connect(reply, &QNetworkReply::downloadProgress, this, &LoadPreconsPage::actDownloadProgressPreconsFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LoadPreconsPage::actDownloadProgressPreconsFile(qint64 received, qint64 total)
|
||||||
|
{
|
||||||
|
if (total > 0) {
|
||||||
|
progressBar->setMaximum(static_cast<int>(total));
|
||||||
|
progressBar->setValue(static_cast<int>(received));
|
||||||
|
}
|
||||||
|
progressLabel->setText(tr("Downloading (%1MB)").arg((int)received / (1024 * 1024)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void LoadPreconsPage::actDownloadFinishedPreconsFile()
|
||||||
|
{
|
||||||
|
// check for a reply
|
||||||
|
auto *reply = dynamic_cast<QNetworkReply *>(sender());
|
||||||
|
auto errorCode = reply->error();
|
||||||
|
if (errorCode != QNetworkReply::NoError) {
|
||||||
|
QMessageBox::critical(this, tr("Error"), tr("Network error: %1.").arg(reply->errorString()));
|
||||||
|
|
||||||
|
dynamic_cast<DlgImportPrecons *>(wizard())->enableButtons();
|
||||||
|
setEnabled(true);
|
||||||
|
|
||||||
|
reply->deleteLater();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||||
|
if (statusCode == 301 || statusCode == 302) {
|
||||||
|
const auto redirectUrl = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
|
||||||
|
qDebug() << "following redirect url:" << redirectUrl.toString();
|
||||||
|
downloadPreconsFile(redirectUrl);
|
||||||
|
reply->deleteLater();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
progressLabel->hide();
|
||||||
|
progressBar->hide();
|
||||||
|
|
||||||
|
readPreconsFromByteArray(reply->readAll());
|
||||||
|
reply->deleteLater();
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <QJsonArray>
|
||||||
|
#include <QJsonDocument>
|
||||||
|
#include <QJsonObject>
|
||||||
|
#include <QJsonValue>
|
||||||
|
|
||||||
|
bool LoadPreconsPage::parsePreconsFromByteArray(const QByteArray &data, QString folderPath)
|
||||||
|
{
|
||||||
|
QJsonParseError parseError;
|
||||||
|
QJsonDocument doc = QJsonDocument::fromJson(data, &parseError);
|
||||||
|
|
||||||
|
if (parseError.error != QJsonParseError::NoError || !doc.isObject()) {
|
||||||
|
qWarning() << "JSON parse error:" << parseError.errorString();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonObject rootObj = doc.object();
|
||||||
|
QJsonObject preconData = rootObj.value("data").toObject();
|
||||||
|
|
||||||
|
QString deckName = preconData.value("name").toString();
|
||||||
|
QString shortName = preconData.value("code").toString().toUpper();
|
||||||
|
QString deckType = preconData.value("type").toString();
|
||||||
|
QJsonArray mainBoard = preconData.value("mainBoard").toArray();
|
||||||
|
int releaseYear = preconData.value("releaseDate").toString().split("-").at(0).toInt();
|
||||||
|
|
||||||
|
qInfo() << "Importing '" << deckName << "' from" << shortName;
|
||||||
|
|
||||||
|
auto *precon = new DeckLoader();
|
||||||
|
|
||||||
|
for (const auto &cardVal : mainBoard) {
|
||||||
|
QJsonObject cardObj = cardVal.toObject();
|
||||||
|
QString name = cardObj.value("name").toString();
|
||||||
|
QString setCode = cardObj.value("setCode").toString();
|
||||||
|
QString number = cardObj.value("number").toString();
|
||||||
|
int count = cardObj.value("count").toInt();
|
||||||
|
QString scryfallId = cardObj.value("identifiers").toObject().value("scryfallId").toString();
|
||||||
|
|
||||||
|
DecklistCardNode *addedCard = precon->addCard(name, "main", -1, setCode, number, scryfallId);
|
||||||
|
if (count != 1) {
|
||||||
|
addedCard->setNumber(count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
precon->setName(deckName);
|
||||||
|
|
||||||
|
QJsonArray commanderArray = preconData.value("commander").toArray();
|
||||||
|
if (!commanderArray.isEmpty()) {
|
||||||
|
QJsonObject commanderObj = commanderArray.first().toObject();
|
||||||
|
QString commanderName = commanderObj.value("name").toString();
|
||||||
|
QString commanderId = commanderObj.value("identifiers").toObject().value("scryfallId").toString();
|
||||||
|
precon->setBannerCard(QPair<QString, QString>(commanderName, commanderId));
|
||||||
|
} else {
|
||||||
|
qInfo() << "No commander data found.";
|
||||||
|
}
|
||||||
|
|
||||||
|
QString dirPath = QDir::cleanPath(folderPath + QDir::separator() + deckType + QDir::separator() +
|
||||||
|
QString::number(releaseYear) + QDir::separator() + shortName);
|
||||||
|
|
||||||
|
QString fullPath = QDir(dirPath).filePath(precon->getName());
|
||||||
|
|
||||||
|
QDir dir;
|
||||||
|
if (!dir.exists(dirPath)) {
|
||||||
|
if (!dir.mkpath(dirPath)) {
|
||||||
|
qWarning() << "Failed to create directory:" << dirPath;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (precon->getCardList().length() > 1) {
|
||||||
|
precon->saveToFile(fullPath + ".cod", DeckLoader::CockatriceFormat);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LoadPreconsPage::readPreconsFromByteArray(QByteArray _data)
|
||||||
|
{
|
||||||
|
progressBar->setMaximum(0);
|
||||||
|
progressBar->setMinimum(0);
|
||||||
|
progressBar->setValue(0);
|
||||||
|
progressLabel->setText(tr("Parsing file"));
|
||||||
|
progressLabel->show();
|
||||||
|
progressBar->show();
|
||||||
|
|
||||||
|
dynamic_cast<DlgImportPrecons *>(wizard())->doneWithParsing = false;
|
||||||
|
dynamic_cast<DlgImportPrecons *>(wizard())->xmlData.clear();
|
||||||
|
readPreconsFromByteArrayRef(_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString LoadPreconsPage::createTmpDirectory()
|
||||||
|
{
|
||||||
|
QTemporaryDir tempDir;
|
||||||
|
if (tempDir.isValid()) {
|
||||||
|
return tempDir.path();
|
||||||
|
}
|
||||||
|
QString tmpPath = QDir::cleanPath(SettingsCache::instance().getDeckPath() + "/Precons/tmp");
|
||||||
|
QDir tmpDir(tmpPath);
|
||||||
|
if (!tmpDir.exists()) {
|
||||||
|
if (!QDir().mkpath(tmpPath)) {
|
||||||
|
qWarning() << "Failed to create temporary directory.";
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return tmpPath;
|
||||||
|
}
|
||||||
|
return tmpPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LoadPreconsPage::processTarArchive(const QByteArray &tarData)
|
||||||
|
{
|
||||||
|
const int blockSize = 512;
|
||||||
|
int offset = 0;
|
||||||
|
|
||||||
|
dynamic_cast<DlgImportPrecons *>(wizard())->setTempDir(createTmpDirectory());
|
||||||
|
|
||||||
|
while (offset + blockSize <= tarData.size()) {
|
||||||
|
QByteArray header = tarData.mid(offset, blockSize);
|
||||||
|
QString fileName = QString::fromLatin1(header.left(100).trimmed());
|
||||||
|
if (fileName.isEmpty())
|
||||||
|
break;
|
||||||
|
|
||||||
|
QByteArray sizeField = header.mid(124, 12).trimmed();
|
||||||
|
bool ok = false;
|
||||||
|
int fileSize = sizeField.toInt(&ok, 8);
|
||||||
|
if (!ok || fileSize < 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
int fileStart = offset + blockSize;
|
||||||
|
QByteArray fileContents = tarData.mid(fileStart, fileSize);
|
||||||
|
|
||||||
|
parsePreconsFromByteArray(fileContents, dynamic_cast<DlgImportPrecons *>(wizard())->getTempDir());
|
||||||
|
|
||||||
|
offset = fileStart + ((fileSize + blockSize - 1) / blockSize) * blockSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
dynamic_cast<DlgImportPrecons *>(wizard())->doneWithParsing = true;
|
||||||
|
|
||||||
|
importFinished();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LoadPreconsPage::readPreconsFromByteArrayRef(QByteArray &_data)
|
||||||
|
{
|
||||||
|
// XZ-compressed TAR archive
|
||||||
|
if (_data.startsWith(XZ_SIGNATURE)) {
|
||||||
|
#ifdef HAS_LZMA
|
||||||
|
qInfo() << "Unzipping precon tar.xz file";
|
||||||
|
auto *inBuffer = new QBuffer(&_data);
|
||||||
|
QByteArray tarData;
|
||||||
|
auto *outBuffer = new QBuffer(&tarData);
|
||||||
|
inBuffer->open(QBuffer::ReadOnly);
|
||||||
|
outBuffer->open(QBuffer::WriteOnly);
|
||||||
|
XzDecompressor xz;
|
||||||
|
if (!xz.decompress(inBuffer, outBuffer)) {
|
||||||
|
zipDownloadFailed(tr("Xz extraction failed."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_data.clear();
|
||||||
|
processTarArchive(tarData);
|
||||||
|
return;
|
||||||
|
#else
|
||||||
|
zipDownloadFailed(tr("Sorry, your computer does not support xz compressed files."));
|
||||||
|
static_cast<DlgImportPrecons *>(wizard())->enableButtons();
|
||||||
|
setEnabled(true);
|
||||||
|
progressLabel->hide();
|
||||||
|
progressBar->hide();
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// ZIP archive
|
||||||
|
else if (_data.startsWith(ZIP_SIGNATURE)) {
|
||||||
|
#ifdef HAS_ZLIB
|
||||||
|
qInfo() << "Unzipping precon ZIP file";
|
||||||
|
QBuffer inBuffer(&_data);
|
||||||
|
UnZip uz;
|
||||||
|
UnZip::ErrorCode ec = uz.openArchive(&inBuffer);
|
||||||
|
|
||||||
|
if (ec != UnZip::Ok) {
|
||||||
|
zipDownloadFailed(tr("Failed to open Zip archive: %1.").arg(uz.formatError(ec)));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QStringList files = uz.fileList();
|
||||||
|
if (files.isEmpty()) {
|
||||||
|
zipDownloadFailed(tr("Zip extraction failed: the Zip archive is empty."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const QString &fileName : files) {
|
||||||
|
if (!fileName.endsWith(".json", Qt::CaseInsensitive))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
QBuffer *outBuffer = new QBuffer();
|
||||||
|
outBuffer->open(QIODevice::ReadWrite);
|
||||||
|
ec = uz.extractFile(fileName, outBuffer);
|
||||||
|
if (ec != UnZip::Ok) {
|
||||||
|
zipDownloadFailed(tr("Zip extraction failed for file %1: %2").arg(fileName, uz.formatError(ec)));
|
||||||
|
uz.closeArchive();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
outBuffer->seek(0);
|
||||||
|
delete outBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
uz.closeArchive();
|
||||||
|
importFinished(); // Continue processing
|
||||||
|
return;
|
||||||
|
#else
|
||||||
|
zipDownloadFailed(tr("Sorry, your computer does not support zipped files."));
|
||||||
|
static_cast<DlgImportPrecons *>(wizard())->enableButtons();
|
||||||
|
setEnabled(true);
|
||||||
|
progressLabel->hide();
|
||||||
|
progressBar->hide();
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// Raw JSON content
|
||||||
|
else if (_data.startsWith("{")) {
|
||||||
|
jsonData = std::move(_data);
|
||||||
|
watcher.setFuture(future);
|
||||||
|
}
|
||||||
|
|
||||||
|
// XML content
|
||||||
|
else if (_data.startsWith("<")) {
|
||||||
|
dynamic_cast<DlgImportPrecons *>(wizard())->doneWithParsing = true;
|
||||||
|
dynamic_cast<DlgImportPrecons *>(wizard())->xmlData = std::move(_data);
|
||||||
|
importFinished();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unknown format
|
||||||
|
else {
|
||||||
|
static_cast<DlgImportPrecons *>(wizard())->enableButtons();
|
||||||
|
setEnabled(true);
|
||||||
|
progressLabel->hide();
|
||||||
|
progressBar->hide();
|
||||||
|
QMessageBox::critical(this, tr("Error"), tr("Failed to interpret downloaded data."));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LoadPreconsPage::zipDownloadFailed(const QString &message)
|
||||||
|
{
|
||||||
|
dynamic_cast<DlgImportPrecons *>(wizard())->enableButtons();
|
||||||
|
setEnabled(true);
|
||||||
|
progressLabel->hide();
|
||||||
|
progressBar->hide();
|
||||||
|
|
||||||
|
QMessageBox::StandardButton reply;
|
||||||
|
reply = static_cast<QMessageBox::StandardButton>(QMessageBox::question(
|
||||||
|
this, tr("Error"), message + "<br>" + tr("Do you want to download the uncompressed file instead?"),
|
||||||
|
QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes));
|
||||||
|
|
||||||
|
if (reply == QMessageBox::Yes) {
|
||||||
|
urlRadioButton->setChecked(true);
|
||||||
|
urlLineEdit->setText(ALLDECKS_URL_FALLBACK);
|
||||||
|
|
||||||
|
wizard()->next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LoadPreconsPage::importFinished()
|
||||||
|
{
|
||||||
|
dynamic_cast<DlgImportPrecons *>(wizard())->enableButtons();
|
||||||
|
setEnabled(true);
|
||||||
|
progressLabel->hide();
|
||||||
|
progressBar->hide();
|
||||||
|
|
||||||
|
if (dynamic_cast<DlgImportPrecons *>(wizard())->doneWithParsing || watcher.future().result()) {
|
||||||
|
wizard()->next();
|
||||||
|
} else {
|
||||||
|
QMessageBox::critical(
|
||||||
|
this, tr("Error"),
|
||||||
|
tr("The file was retrieved successfully, but it does not contain any preconstructed decks data."));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SavePreconsPage::SavePreconsPage(QWidget *parent) : QWizardPage(parent)
|
||||||
|
{
|
||||||
|
saveLabel = new QLabel(this);
|
||||||
|
|
||||||
|
folderTreeWidget = new QTreeWidget(this);
|
||||||
|
folderTreeWidget->setHeaderHidden(true);
|
||||||
|
folderTreeWidget->setSelectionMode(QAbstractItemView::NoSelection);
|
||||||
|
folderTreeWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||||
|
|
||||||
|
auto *layout = new QGridLayout(this);
|
||||||
|
layout->addWidget(saveLabel, 0, 0);
|
||||||
|
layout->addWidget(folderTreeWidget, 1, 0);
|
||||||
|
|
||||||
|
setLayout(layout);
|
||||||
|
|
||||||
|
retranslateUi();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SavePreconsPage::cleanupPage()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void SavePreconsPage::initializePage()
|
||||||
|
{
|
||||||
|
QDir tempDir(dynamic_cast<DlgImportPrecons *>(wizard())->getTempDir());
|
||||||
|
folderTreeWidget->clear();
|
||||||
|
|
||||||
|
for (const QString &dirName : tempDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot)) {
|
||||||
|
QString absPath = tempDir.absoluteFilePath(dirName);
|
||||||
|
QTreeWidgetItem *item = new QTreeWidgetItem(folderTreeWidget, QStringList() << dirName);
|
||||||
|
item->setData(0, Qt::UserRole, absPath);
|
||||||
|
item->setFlags(item->flags() | Qt::ItemIsUserCheckable | Qt::ItemIsAutoTristate);
|
||||||
|
item->setCheckState(0, Qt::Unchecked);
|
||||||
|
|
||||||
|
populateFolderTree(item, absPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
retranslateUi();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SavePreconsPage::populateFolderTree(QTreeWidgetItem *parent, const QString &path)
|
||||||
|
{
|
||||||
|
QDir dir(path);
|
||||||
|
for (const QString &subdir : dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot)) {
|
||||||
|
QString absPath = dir.absoluteFilePath(subdir);
|
||||||
|
QTreeWidgetItem *child = new QTreeWidgetItem(parent, QStringList() << subdir);
|
||||||
|
child->setData(0, Qt::UserRole, absPath);
|
||||||
|
child->setFlags(child->flags() | Qt::ItemIsUserCheckable | Qt::ItemIsAutoTristate);
|
||||||
|
child->setCheckState(0, Qt::Unchecked);
|
||||||
|
|
||||||
|
populateFolderTree(child, absPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SavePreconsPage::retranslateUi()
|
||||||
|
{
|
||||||
|
setTitle(tr("Precons imported"));
|
||||||
|
setSubTitle(tr("The following preconstructed deck types have been found:"));
|
||||||
|
|
||||||
|
saveLabel->setText(tr("Select the product types you'd like to import and then press \"Save\" to store the imported "
|
||||||
|
"preconstructed decks in your deck folder. \n (Note: It is not recommended to import all "
|
||||||
|
"products unless you are sure your computer can handle it. \n It might cause Cockatrice to "
|
||||||
|
"load a very large amount of decks when using the visual deck storage"));
|
||||||
|
|
||||||
|
setButtonText(QWizard::NextButton, tr("&Save"));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SavePreconsPage::validatePage()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < folderTreeWidget->topLevelItemCount(); ++i) {
|
||||||
|
QTreeWidgetItem *item = folderTreeWidget->topLevelItem(i);
|
||||||
|
copyCheckedFolders(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
QDir(dynamic_cast<DlgImportPrecons *>(wizard())->getTempDir()).removeRecursively();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SavePreconsPage::copyCheckedFolders(QTreeWidgetItem *item)
|
||||||
|
{
|
||||||
|
Qt::CheckState state = item->checkState(0);
|
||||||
|
if (state == Qt::Unchecked)
|
||||||
|
return;
|
||||||
|
|
||||||
|
QString srcPath = item->data(0, Qt::UserRole).toString();
|
||||||
|
QString relativePath = QDir(dynamic_cast<DlgImportPrecons *>(wizard())->getTempDir()).relativeFilePath(srcPath);
|
||||||
|
QString destPath = QDir::cleanPath(SettingsCache::instance().getDeckPath() + QDir::separator() + "Precons" +
|
||||||
|
QDir::separator() + relativePath);
|
||||||
|
|
||||||
|
if (!copyDirectory(srcPath, destPath))
|
||||||
|
qWarning() << "Failed to copy" << srcPath;
|
||||||
|
|
||||||
|
for (int i = 0; i < item->childCount(); ++i) {
|
||||||
|
copyCheckedFolders(item->child(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SavePreconsPage::copyDirectory(const QString &srcPath, const QString &destPath)
|
||||||
|
{
|
||||||
|
QDir srcDir(srcPath);
|
||||||
|
if (!srcDir.exists())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
QDir destDir;
|
||||||
|
if (!destDir.mkpath(destPath))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
QFileInfoList entries = srcDir.entryInfoList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot);
|
||||||
|
for (const QFileInfo &entry : entries) {
|
||||||
|
QString src = entry.absoluteFilePath();
|
||||||
|
QString dest = destPath + "/" + entry.fileName();
|
||||||
|
|
||||||
|
if (entry.isDir()) {
|
||||||
|
if (!copyDirectory(src, dest))
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
if (!QFile::copy(src, dest))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
116
cockatrice/src/interface/widgets/dialogs/dlg_import_precons.h
Normal file
116
cockatrice/src/interface/widgets/dialogs/dlg_import_precons.h
Normal file
|
|
@ -0,0 +1,116 @@
|
||||||
|
#ifndef DLG_IMPORT_PRECONS_H
|
||||||
|
#define DLG_IMPORT_PRECONS_H
|
||||||
|
|
||||||
|
#include <QCheckBox>
|
||||||
|
#include <QFutureWatcher>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QLineEdit>
|
||||||
|
#include <QListWidget>
|
||||||
|
#include <QNetworkAccessManager>
|
||||||
|
#include <QProgressBar>
|
||||||
|
#include <QRadioButton>
|
||||||
|
#include <QSettings>
|
||||||
|
#include <QTextEdit>
|
||||||
|
#include <QTreeWidget>
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QWizardPage>
|
||||||
|
|
||||||
|
class DlgImportPrecons : public QWizard
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit DlgImportPrecons(QWidget *parent = nullptr);
|
||||||
|
void accept() override;
|
||||||
|
void enableButtons();
|
||||||
|
void disableButtons();
|
||||||
|
void retranslateUi();
|
||||||
|
void setCardSourceUrl(const QString &sourceUrl)
|
||||||
|
{
|
||||||
|
cardSourceUrl = sourceUrl;
|
||||||
|
}
|
||||||
|
const QString &getCardSourceUrl() const
|
||||||
|
{
|
||||||
|
return cardSourceUrl;
|
||||||
|
}
|
||||||
|
void setTempDir(const QString &tempDir)
|
||||||
|
{
|
||||||
|
tmpDir = tempDir;
|
||||||
|
}
|
||||||
|
const QString &getTempDir() const
|
||||||
|
{
|
||||||
|
return tmpDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
QNetworkAccessManager *nam;
|
||||||
|
QByteArray xmlData;
|
||||||
|
bool doneWithParsing = false;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString cardSourceUrl;
|
||||||
|
QString tmpDir;
|
||||||
|
};
|
||||||
|
|
||||||
|
class LoadPreconsPage : public QWizardPage
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit LoadPreconsPage(QWidget *parent = nullptr);
|
||||||
|
void retranslateUi();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void initializePage() override;
|
||||||
|
bool validatePage() override;
|
||||||
|
bool parsePreconsFromByteArray(const QByteArray &data, QString folderPath);
|
||||||
|
void readPreconsFromByteArray(QByteArray _data);
|
||||||
|
static QString createTmpDirectory();
|
||||||
|
void processTarArchive(const QByteArray &tarData);
|
||||||
|
void readPreconsFromByteArrayRef(QByteArray &_data);
|
||||||
|
void downloadPreconsFile(const QUrl &url);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QRadioButton *urlRadioButton;
|
||||||
|
QRadioButton *fileRadioButton;
|
||||||
|
QLineEdit *urlLineEdit;
|
||||||
|
QLineEdit *fileLineEdit;
|
||||||
|
QPushButton *urlButton;
|
||||||
|
QPushButton *fileButton;
|
||||||
|
QLabel *progressLabel;
|
||||||
|
QProgressBar *progressBar;
|
||||||
|
|
||||||
|
QFutureWatcher<bool> watcher;
|
||||||
|
QFuture<bool> future;
|
||||||
|
QByteArray jsonData;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void actLoadPreconsFile();
|
||||||
|
void actRestoreDefaultUrl();
|
||||||
|
void actDownloadProgressPreconsFile(qint64 received, qint64 total);
|
||||||
|
void actDownloadFinishedPreconsFile();
|
||||||
|
void importFinished();
|
||||||
|
void zipDownloadFailed(const QString &message);
|
||||||
|
};
|
||||||
|
|
||||||
|
class SavePreconsPage : public QWizardPage
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit SavePreconsPage(QWidget *parent = nullptr);
|
||||||
|
void retranslateUi();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QTreeWidget *folderTreeWidget;
|
||||||
|
QLabel *saveLabel;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void initializePage() override;
|
||||||
|
void populateFolderTree(QTreeWidgetItem *parent, const QString &path);
|
||||||
|
void onItemChanged(QTreeWidgetItem *item, int column);
|
||||||
|
void cleanupPage() override;
|
||||||
|
bool validatePage() override;
|
||||||
|
void copyCheckedFolders(QTreeWidgetItem *item);
|
||||||
|
bool copyDirectory(const QString &srcPath, const QString &destPath);
|
||||||
|
};
|
||||||
|
|
||||||
|
bool readPreconsFromByteArray(const QByteArray &data);
|
||||||
|
|
||||||
|
#endif // DLG_IMPORT_PRECONS_H
|
||||||
|
|
@ -696,6 +696,7 @@ void MainWindow::retranslateUi()
|
||||||
aCheckCardUpdates->setText(tr("Check for Card Updates..."));
|
aCheckCardUpdates->setText(tr("Check for Card Updates..."));
|
||||||
aCheckCardUpdatesBackground->setText(tr("Check for Card Updates (Automatic)"));
|
aCheckCardUpdatesBackground->setText(tr("Check for Card Updates (Automatic)"));
|
||||||
aStatusBar->setText(tr("Show Status Bar"));
|
aStatusBar->setText(tr("Show Status Bar"));
|
||||||
|
aImportPrecons->setText(tr("Import preconstructed Decks..."));
|
||||||
aViewLog->setText(tr("View &Debug Log"));
|
aViewLog->setText(tr("View &Debug Log"));
|
||||||
aOpenSettingsFolder->setText(tr("Open Settings Folder"));
|
aOpenSettingsFolder->setText(tr("Open Settings Folder"));
|
||||||
|
|
||||||
|
|
@ -754,6 +755,8 @@ void MainWindow::createActions()
|
||||||
aStatusBar->setCheckable(true);
|
aStatusBar->setCheckable(true);
|
||||||
aStatusBar->setChecked(SettingsCache::instance().getShowStatusBar());
|
aStatusBar->setChecked(SettingsCache::instance().getShowStatusBar());
|
||||||
connect(aStatusBar, &QAction::triggered, &SettingsCache::instance(), &SettingsCache::setShowStatusBar);
|
connect(aStatusBar, &QAction::triggered, &SettingsCache::instance(), &SettingsCache::setShowStatusBar);
|
||||||
|
aImportPrecons = new QAction(this);
|
||||||
|
connect(aImportPrecons, &QAction::triggered, this, &MainWindow::actImportPrecons);
|
||||||
aViewLog = new QAction(this);
|
aViewLog = new QAction(this);
|
||||||
connect(aViewLog, &QAction::triggered, this, &MainWindow::actViewLog);
|
connect(aViewLog, &QAction::triggered, this, &MainWindow::actViewLog);
|
||||||
aOpenSettingsFolder = new QAction(this);
|
aOpenSettingsFolder = new QAction(this);
|
||||||
|
|
@ -832,6 +835,7 @@ void MainWindow::createMenus()
|
||||||
helpMenu->addAction(aUpdate);
|
helpMenu->addAction(aUpdate);
|
||||||
helpMenu->addAction(aCheckCardUpdates);
|
helpMenu->addAction(aCheckCardUpdates);
|
||||||
helpMenu->addAction(aCheckCardUpdatesBackground);
|
helpMenu->addAction(aCheckCardUpdatesBackground);
|
||||||
|
helpMenu->addAction(aImportPrecons);
|
||||||
helpMenu->addSeparator();
|
helpMenu->addSeparator();
|
||||||
helpMenu->addAction(aStatusBar);
|
helpMenu->addAction(aStatusBar);
|
||||||
helpMenu->addAction(aViewLog);
|
helpMenu->addAction(aViewLog);
|
||||||
|
|
@ -1347,6 +1351,12 @@ void MainWindow::checkClientUpdatesFinished(bool needToUpdate, bool /* isCompati
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::actImportPrecons()
|
||||||
|
{
|
||||||
|
auto preconImporter = new DlgImportPrecons(this);
|
||||||
|
preconImporter->show();
|
||||||
|
}
|
||||||
|
|
||||||
void MainWindow::refreshShortcuts()
|
void MainWindow::refreshShortcuts()
|
||||||
{
|
{
|
||||||
ShortcutsSettings &shortcuts = SettingsCache::instance().shortcuts();
|
ShortcutsSettings &shortcuts = SettingsCache::instance().shortcuts();
|
||||||
|
|
|
||||||
|
|
@ -110,6 +110,7 @@ private slots:
|
||||||
void cardDatabaseAllNewSetsEnabled();
|
void cardDatabaseAllNewSetsEnabled();
|
||||||
|
|
||||||
void checkClientUpdatesFinished(bool needToUpdate, bool isCompatible, Release *release);
|
void checkClientUpdatesFinished(bool needToUpdate, bool isCompatible, Release *release);
|
||||||
|
void actImportPrecons();
|
||||||
|
|
||||||
void actOpenCustomFolder();
|
void actOpenCustomFolder();
|
||||||
void actOpenCustomsetsFolder();
|
void actOpenCustomsetsFolder();
|
||||||
|
|
@ -147,7 +148,7 @@ private:
|
||||||
QAction *aConnect, *aDisconnect, *aRegister, *aForgotPassword, *aSinglePlayer, *aWatchReplay, *aFullScreen;
|
QAction *aConnect, *aDisconnect, *aRegister, *aForgotPassword, *aSinglePlayer, *aWatchReplay, *aFullScreen;
|
||||||
QAction *aManageSets, *aEditTokens, *aOpenCustomFolder, *aOpenCustomsetsFolder, *aAddCustomSet,
|
QAction *aManageSets, *aEditTokens, *aOpenCustomFolder, *aOpenCustomsetsFolder, *aAddCustomSet,
|
||||||
*aReloadCardDatabase;
|
*aReloadCardDatabase;
|
||||||
QAction *aTips, *aUpdate, *aCheckCardUpdates, *aCheckCardUpdatesBackground, *aStatusBar, *aViewLog,
|
QAction *aTips, *aUpdate, *aCheckCardUpdates, *aCheckCardUpdatesBackground, *aImportPrecons, *aStatusBar, *aViewLog,
|
||||||
*aOpenSettingsFolder;
|
*aOpenSettingsFolder;
|
||||||
|
|
||||||
TabSupervisor *tabSupervisor;
|
TabSupervisor *tabSupervisor;
|
||||||
|
|
|
||||||
250
cockatrice/src/utility/external/lzma/decompress.cpp
vendored
Normal file
250
cockatrice/src/utility/external/lzma/decompress.cpp
vendored
Normal file
|
|
@ -0,0 +1,250 @@
|
||||||
|
/*
|
||||||
|
* 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 <lzma.h>
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
19
cockatrice/src/utility/external/lzma/decompress.h
vendored
Normal file
19
cockatrice/src/utility/external/lzma/decompress.h
vendored
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
#ifndef XZ_DECOMPRESS_H
|
||||||
|
#define XZ_DECOMPRESS_H
|
||||||
|
|
||||||
|
#include <lzma.h>
|
||||||
|
#include <QBuffer>
|
||||||
|
|
||||||
|
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
|
||||||
573
cockatrice/src/utility/external/qt-json/json.cpp
vendored
Normal file
573
cockatrice/src/utility/external/qt-json/json.cpp
vendored
Normal file
|
|
@ -0,0 +1,573 @@
|
||||||
|
/* 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 <COPYRIGHT HOLDER> ''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 <QMetaType>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
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<QByteArray> &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<QByteArray> 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<QString, QVariant> it(vhash);
|
||||||
|
str = "{ ";
|
||||||
|
QList<QByteArray> 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<QString, QVariant> it(vmap);
|
||||||
|
str = "{ ";
|
||||||
|
QList<QByteArray> 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<qulonglong>());
|
||||||
|
} else if (data.canConvert<qlonglong>()) // any signed number?
|
||||||
|
{
|
||||||
|
str = QByteArray::number(data.value<qlonglong>());
|
||||||
|
} else if (data.canConvert<long>()) {
|
||||||
|
str = QString::number(data.value<long>()).toUtf8();
|
||||||
|
} else if (data.canConvert<QString>()) // 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
|
||||||
204
cockatrice/src/utility/external/qt-json/json.h
vendored
Normal file
204
cockatrice/src/utility/external/qt-json/json.h
vendored
Normal file
|
|
@ -0,0 +1,204 @@
|
||||||
|
/* 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 <COPYRIGHT HOLDER> ''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 <QVariant>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
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
|
||||||
1425
cockatrice/src/utility/external/zip/unzip.cpp
vendored
Executable file
1425
cockatrice/src/utility/external/zip/unzip.cpp
vendored
Executable file
File diff suppressed because it is too large
Load diff
155
cockatrice/src/utility/external/zip/unzip.h
vendored
Normal file
155
cockatrice/src/utility/external/zip/unzip.h
vendored
Normal file
|
|
@ -0,0 +1,155 @@
|
||||||
|
/****************************************************************************
|
||||||
|
** 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 <QtCore/QDateTime>
|
||||||
|
#include <QtCore/QMap>
|
||||||
|
#include <QtCore/QtGlobal>
|
||||||
|
#include <zlib.h>
|
||||||
|
|
||||||
|
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<ZipEntry> 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
|
||||||
130
cockatrice/src/utility/external/zip/unzip_p.h
vendored
Executable file
130
cockatrice/src/utility/external/zip/unzip_p.h
vendored
Executable file
|
|
@ -0,0 +1,130 @@
|
||||||
|
/****************************************************************************
|
||||||
|
** 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 <QtCore/QObject>
|
||||||
|
#include <QtCore/QtGlobal>
|
||||||
|
|
||||||
|
// 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<QString,ZipEntryP*>* 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
|
||||||
1619
cockatrice/src/utility/external/zip/zip.cpp
vendored
Executable file
1619
cockatrice/src/utility/external/zip/zip.cpp
vendored
Executable file
File diff suppressed because it is too large
Load diff
158
cockatrice/src/utility/external/zip/zip.h
vendored
Executable file
158
cockatrice/src/utility/external/zip/zip.h
vendored
Executable file
|
|
@ -0,0 +1,158 @@
|
||||||
|
/****************************************************************************
|
||||||
|
** 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 <QtCore/QMap>
|
||||||
|
#include <QtCore/QtGlobal>
|
||||||
|
|
||||||
|
#include <zlib/zlib.h>
|
||||||
|
|
||||||
|
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
|
||||||
133
cockatrice/src/utility/external/zip/zip_p.h
vendored
Executable file
133
cockatrice/src/utility/external/zip/zip_p.h
vendored
Executable file
|
|
@ -0,0 +1,133 @@
|
||||||
|
/****************************************************************************
|
||||||
|
** 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 <QtCore/QFileInfo>
|
||||||
|
#include <QtCore/QObject>
|
||||||
|
#include <QtCore/QtGlobal>
|
||||||
|
|
||||||
|
#include <zlib/zconf.h>
|
||||||
|
|
||||||
|
/*!
|
||||||
|
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<QString,ZipEntryP*>* 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
|
||||||
91
cockatrice/src/utility/external/zip/zipentry_p.h
vendored
Executable file
91
cockatrice/src/utility/external/zip/zipentry_p.h
vendored
Executable file
|
|
@ -0,0 +1,91 @@
|
||||||
|
/****************************************************************************
|
||||||
|
** 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 <QtCore/QString>
|
||||||
|
#include <QtCore/QtGlobal>
|
||||||
|
|
||||||
|
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
|
||||||
150
cockatrice/src/utility/external/zip/zipglobal.cpp
vendored
Normal file
150
cockatrice/src/utility/external/zip/zipglobal.cpp
vendored
Normal file
|
|
@ -0,0 +1,150 @@
|
||||||
|
/****************************************************************************
|
||||||
|
** 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 <ctime>
|
||||||
|
#else
|
||||||
|
#undef OSDAB_ZIP_HAS_UTC
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(Q_OS_WIN)
|
||||||
|
#include <QtCore/qt_windows.h>
|
||||||
|
#elif defined(Q_OS_LINUX) || defined(Q_OS_MACOS)
|
||||||
|
#include <utime.h>
|
||||||
|
#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
|
||||||
77
cockatrice/src/utility/external/zip/zipglobal.h
vendored
Executable file
77
cockatrice/src/utility/external/zip/zipglobal.h
vendored
Executable file
|
|
@ -0,0 +1,77 @@
|
||||||
|
/****************************************************************************
|
||||||
|
** 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 <QtCore/QDateTime>
|
||||||
|
#include <QtCore/QtGlobal>
|
||||||
|
|
||||||
|
/* 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
|
||||||
Loading…
Add table
Add a link
Reference in a new issue