diff --git a/.gitignore b/.gitignore
index c1d9862..93b516e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -11,6 +11,7 @@ log.*
# Test files
[Tt]est/
+private
# *nix related
# Common convention for backup or temporary files
diff --git a/CCR-Plus.pro b/CCR-Plus.pro
index 888153a..f5a8766 100644
--- a/CCR-Plus.pro
+++ b/CCR-Plus.pro
@@ -1,7 +1,8 @@
TEMPLATE = subdirs
SUBDIRS += ccr-plus \
- src/tools/checker
+ src/tools/checker \
+ src/updater
unix: SUBDIRS += src/tools/monitor
diff --git a/resources/icon.rc b/resources/CCR_icon.rc
similarity index 100%
rename from resources/icon.rc
rename to resources/CCR_icon.rc
diff --git a/resources/image.qrc b/resources/image.qrc
index af28033..a8468ab 100644
--- a/resources/image.qrc
+++ b/resources/image.qrc
@@ -4,5 +4,6 @@
folder.pnglogo.pnglogo2.png
+ update.ico
diff --git a/resources/update.ico b/resources/update.ico
new file mode 100644
index 0000000..627b47f
Binary files /dev/null and b/resources/update.ico differ
diff --git a/resources/updater_icon.rc b/resources/updater_icon.rc
new file mode 100644
index 0000000..79a3eb1
--- /dev/null
+++ b/resources/updater_icon.rc
@@ -0,0 +1,36 @@
+IDI_ICON1 ICON DISCARDABLE "update.ico"
+#if defined(UNDER_CE)
+#include
+#else
+#include
+#endif
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 1,1,0,0
+ PRODUCTVERSION 1,1,0,0
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS VS_FF_DEBUG
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS VOS__WINDOWS32
+ FILETYPE VFT_DLL
+ FILESUBTYPE 0x0L
+ BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "080404b0"
+ BEGIN
+ VALUE "CompanyName", "绍兴一中 贾越凯"
+ VALUE "FileDescription", "CCR Plus 更新程序"
+ VALUE "ProductName", "CCR Plus"
+ VALUE "OriginalFilename", "upgrader.exe"
+ VALUE "ProductVersion", "1.1.0"
+ VALUE "LegalCopyright", "Copyright (C) 2017 Yuekai Jia. All Rights Reserved."
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x804, 1200
+ END
+ END
diff --git a/src/CCR-Plus.pro b/src/CCR-Plus.pro
index 020075e..a23f333 100644
--- a/src/CCR-Plus.pro
+++ b/src/CCR-Plus.pro
@@ -68,6 +68,6 @@ FORMS += configure/configuredialog.ui \
RESOURCES = ../resources/image.qrc \
../resources/trans.qrc
-RC_FILE = ../resources/icon.rc
+RC_FILE = ../resources/CCR_icon.rc
win32: LIBS += -lpsapi
diff --git a/src/mainwindow/mainwindow.cpp b/src/mainwindow/mainwindow.cpp
index f49b4e4..2e8a16f 100644
--- a/src/mainwindow/mainwindow.cpp
+++ b/src/mainwindow/mainwindow.cpp
@@ -2,11 +2,13 @@
#include
#include
#include
+#include
#include
#include
#include
#include
+#include "updater/updaterconst.h"
#include "common/global.h"
#include "common/player.h"
#include "common/problem.h"
@@ -66,6 +68,7 @@ MainWindow::MainWindow(QWidget* parent) :
CreateActions();
UpdateRecentContest(true);
+ CheckUpdates(true);
this->activateWindow();
}
@@ -90,6 +93,15 @@ void MainWindow::UnlockTable()
detail_table->Unlock();
}
+void MainWindow::CheckUpdates(bool dontShowError)
+{
+ QString dir = QCoreApplication::applicationDirPath();
+ QStringList arguments = { "-c", "-p" };
+ arguments.append(QString("%1").arg(QCoreApplication::applicationPid()));
+ if (dontShowError) arguments.append("-n");
+ QProcess::startDetached(dir + "/" + Updater::UPDATER_NAME, arguments, dir);
+}
+
// Last contest path
static QString lastContest;
@@ -773,6 +785,11 @@ void MainWindow::on_action_help_triggered()
}
+void MainWindow::on_action_update_triggered()
+{
+ CheckUpdates(false);
+}
+
void MainWindow::on_action_about_triggered()
{
QMessageBox msgBox(this);
diff --git a/src/mainwindow/mainwindow.h b/src/mainwindow/mainwindow.h
index c267037..627c20c 100644
--- a/src/mainwindow/mainwindow.h
+++ b/src/mainwindow/mainwindow.h
@@ -46,6 +46,9 @@ class MainWindow : public QMainWindow
void LockTable();
void UnlockTable();
+ /// 妫鏌ユ洿鏂帮紝鏄惁鍙綋鏈夋洿鏂版椂鎵嶆樉绀哄璇濇
+ void CheckUpdates(bool dontShowError);
+
/// 鏇存柊鏈杩戞墦寮鐨勭珵璧涘垪琛紝鏄惁鏇存柊 listWidget_recent
void UpdateRecentContest(bool);
@@ -107,6 +110,7 @@ private slots:
// Help menu actions
void on_action_help_triggered();
+ void on_action_update_triggered();
void on_action_about_triggered();
protected:
diff --git a/src/mainwindow/mainwindow.ui b/src/mainwindow/mainwindow.ui
index 015f86c..0febaa4 100644
--- a/src/mainwindow/mainwindow.ui
+++ b/src/mainwindow/mainwindow.ui
@@ -200,6 +200,7 @@ QMainWindow
甯姪(&H)
+
@@ -338,6 +339,11 @@ QMainWindow
F1
+
+
+ 妫鏌ユ洿鏂(&U)...
+
+
diff --git a/src/updater/checkupdatesdialog.cpp b/src/updater/checkupdatesdialog.cpp
new file mode 100644
index 0000000..eaade91
--- /dev/null
+++ b/src/updater/checkupdatesdialog.cpp
@@ -0,0 +1,193 @@
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "../common/version.h"
+#include "updaterconst.h"
+#include "checkupdatesdialog.h"
+#include "ui_checkupdatesdialog.h"
+
+CheckUpdatesDialog::CheckUpdatesDialog(bool dontShowError, QWidget* parent) :
+ QDialog(parent),
+ ui(new Ui::CheckUpdatesDialog),
+ download_button(new QPushButton("绔嬪嵆涓嬭浇(&D)", this)),
+ manager(new QNetworkAccessManager(this)), timer(new QTimer(this)), dont_show_error(dontShowError), need_recheck(false)
+{
+ ui->setupUi(this);
+ this->setWindowFlags(Qt::Dialog | Qt::WindowCloseButtonHint);
+
+ ui->label_now->setText(VERSION_SHORT);
+ ui->label_1->hide();
+ ui->label_2->hide();
+ ui->label_3->hide();
+ ui->label_now->hide();
+ ui->label_latest->hide();
+ ui->plainTextEdit->hide();
+ download_button->hide();
+ this->setFixedHeight(120);
+ this->setVisible(!dontShowError);
+
+ qDebug() << "Request URL:" << Updater::RELEASE_INFO_URL;
+ reply = manager->get(QNetworkRequest(QUrl(Updater::RELEASE_INFO_URL)));
+
+ connect(this, &QDialog::finished, reply, &QNetworkReply::abort);
+ connect(timer, &QTimer::timeout, this, [this]()
+ {
+ if (reply->isRunning())
+ {
+ reply->abort();
+ showError("妫鏌ユ洿鏂板け璐: 杩炴帴瓒呮椂锛岃妫鏌ョ綉缁滆繛鎺ャ");
+ }
+ });
+ connect(manager, &QNetworkAccessManager::finished, this, &CheckUpdatesDialog::onReplyFinished);
+
+ timer->setSingleShot(true);
+ timer->start(Updater::CONNECT_TIME_OUT);
+}
+
+CheckUpdatesDialog::~CheckUpdatesDialog()
+{
+ delete ui;
+}
+
+int CheckUpdatesDialog::exec()
+{
+ if (dont_show_error)
+ {
+ QEventLoop loop;
+ connect(this, &QDialog::finished, &loop, &QEventLoop::quit);
+ loop.exec();
+ return this->result();
+ }
+ else
+ return QDialog::exec();
+}
+
+
+
+void CheckUpdatesDialog::showError(const QString& msg)
+{
+ if (dont_show_error)
+ {
+ qDebug() << msg;
+ QDialog::reject();
+ return;
+ }
+
+ if (need_recheck) return;
+ need_recheck = true;
+
+ ui->label_info->setText(msg);
+ ui->progressBar->hide();
+ ui->buttonBox->setStandardButtons(QDialogButtonBox::Cancel | QDialogButtonBox::Retry);
+
+ QEventLoop loop;
+ connect(this, &QDialog::finished, &loop, &QEventLoop::quit);
+ loop.exec();
+}
+
+void CheckUpdatesDialog::noUpdates()
+{
+ if (dont_show_error)
+ {
+ qDebug() << "娌℃湁鏇存柊";
+ QDialog::reject();
+ return;
+ }
+
+ this->setWindowTitle("娌℃湁鏇存柊");
+ ui->label_info->setText(QString("%1 宸叉槸鏈鏂扮増鏈 %2銆").arg(Updater::APP_NAME).arg(VERSION_SHORT));
+ ui->progressBar->hide();
+}
+
+void CheckUpdatesDialog::foundUpdates(const QString& version, const QString& log, int bytes)
+{
+ this->setWindowTitle("鍙戠幇鏂扮増鏈");
+ ui->label_latest->setText(version);
+ ui->label_info->setText(QString("灏嗕細涓嬭浇 %1銆").arg(Updater::FormatFileSize(bytes)));
+ ui->plainTextEdit->setPlainText(log);
+ ui->buttonBox->addButton(download_button, QDialogButtonBox::AcceptRole);
+
+ ui->label_1->show();
+ ui->label_2->show();
+ ui->label_3->show();
+ ui->label_now->show();
+ ui->label_latest->show();
+ ui->plainTextEdit->show();
+ ui->progressBar->hide();
+ download_button->show();
+
+ this->setFixedSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
+ this->resize(400, 300);
+ this->show();
+}
+
+
+
+void CheckUpdatesDialog::onReplyFinished()
+{
+ qDebug() << "Status Code:" << reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
+
+ timer->stop();
+ if (reply->error() != QNetworkReply::NoError)
+ {
+ if (reply->error() != QNetworkReply::OperationCanceledError)
+ showError(QString("妫鏌ユ洿鏂板け璐: 鏃犳硶璁块棶鏇存柊鏈嶅姟鍣(閿欒浠g爜 %1)锛岃妫鏌ョ綉缁滆繛鎺ャ").arg(reply->error()));
+ reply->deleteLater();
+ }
+ else if (download_url.isEmpty())
+ {
+ QString errorString;
+ QJsonObject json = Updater::ParseToJson(reply->readAll(), &errorString);
+ if (!errorString.isEmpty())
+ {
+ showError(QString("妫鏌ユ洿鏂板け璐: %1").arg(errorString));
+ reply->deleteLater();
+ return;
+ }
+
+ QString latestVersion = json.value("tag_name").toString();
+ if (latestVersion.isEmpty())
+ {
+ showError("妫鏌ユ洿鏂板け璐: 鏃犳硶鑾峰彇鏂扮増鏈俊鎭");
+ reply->deleteLater();
+ return;
+ }
+ qDebug() << "Latest Version:" << latestVersion;
+
+ if (latestVersion != VERSION_SHORT)
+ {
+ download_size = 0;
+ QJsonArray array = json.value("assets").toArray();
+ for (int i = 0; i < array.size(); i++)
+ {
+ QJsonObject obj = array[i].toObject();
+ if (obj.value("name") == Updater::GetFileNameByPlatform(latestVersion))
+ {
+ download_url = obj.value("browser_download_url").toString();
+ download_size = obj.value("size").toInt();
+ break;
+ }
+ }
+ if (download_url.isEmpty() || !download_size)
+ {
+ showError("妫鏌ユ洿鏂板け璐: 鏃犳硶鑾峰彇鏂扮増鏈笅杞藉湴鍧銆");
+ reply->deleteLater();
+ return;
+ }
+
+ reply->deleteLater();
+ QString log = json.value("body").toString();
+ foundUpdates(latestVersion, log, download_size);
+ }
+ else
+ {
+ noUpdates();
+ reply->deleteLater();
+ }
+ }
+}
diff --git a/src/updater/checkupdatesdialog.h b/src/updater/checkupdatesdialog.h
new file mode 100644
index 0000000..5532889
--- /dev/null
+++ b/src/updater/checkupdatesdialog.h
@@ -0,0 +1,57 @@
+#ifndef CHECKUPDATESDIALOG_H
+#define CHECKUPDATESDIALOG_H
+
+#include
+
+class QTimer;
+class QPushButton;
+class QNetworkReply;
+class QNetworkAccessManager;
+
+namespace Ui
+{
+class CheckUpdatesDialog;
+}
+
+class CheckUpdatesDialog : public QDialog
+{
+ Q_OBJECT
+public:
+ explicit CheckUpdatesDialog(bool dontShowError = false, QWidget* parent = nullptr);
+ ~CheckUpdatesDialog();
+
+ /// 閲嶆柊妫鏌ユ洿鏂
+ bool NeedRecheck() const { return need_recheck; }
+
+ QString DownloadUrl() const { return download_url; }
+ int DownloadSize() const { return download_size; }
+
+public slots:
+ virtual int exec() override;
+
+private:
+ Ui::CheckUpdatesDialog* ui;
+ QPushButton* download_button;
+
+ QNetworkAccessManager* manager;
+ QNetworkReply* reply;
+ QTimer* timer;
+
+ bool dont_show_error, need_recheck;
+ QString download_url;
+ int download_size;
+
+ /// 鍙戠敓閿欒锛屼細闃诲鍏朵粬鎿嶄綔
+ void showError(const QString& msg);
+
+ /// 娌℃湁鏇存柊
+ void noUpdates();
+
+ /// 鍙戠幇鏇存柊
+ void foundUpdates(const QString& version, const QString& log, int bytes);
+
+private slots:
+ void onReplyFinished();
+};
+
+#endif // CHECKUPDATESDIALOG_H
diff --git a/src/updater/checkupdatesdialog.ui b/src/updater/checkupdatesdialog.ui
new file mode 100644
index 0000000..fa943a9
--- /dev/null
+++ b/src/updater/checkupdatesdialog.ui
@@ -0,0 +1,171 @@
+
+
+ CheckUpdatesDialog
+
+
+
+ 0
+ 0
+ 400
+ 300
+
+
+
+
+ 400
+ 0
+
+
+
+ 妫鏌ユ洿鏂
+
+
+
+ :/image/update.ico:/image/update.ico
+
+
+ QWidget
+{
+ font-family: "寰蒋闆呴粦";
+}
+QMainWindow
+{
+ background-color:rgb(250,250,250);
+}
+
+
+
+
+
+
+
+
+
+ 0
+ 0
+
+
+
+ 褰撳墠鐗堟湰:
+
+
+
+
+
+
+
+ 0
+ 0
+
+
+
+ 鏇存柊璇存槑:
+
+
+
+
+
+
+
+ 0
+ 0
+
+
+
+ 鏈鏂扮増鏈:
+
+
+
+
+
+
+ V1.0.0
+
+
+
+
+
+
+ V1.1.0
+
+
+
+
+
+
+
+
+ true
+
+
+
+
+
+
+ 姝e湪妫鏌ユ洿鏂...
+
+
+ true
+
+
+
+
+
+
+ 0
+
+
+ false
+
+
+
+
+
+
+ Qt::Horizontal
+
+
+ QDialogButtonBox::Cancel
+
+
+
+
+
+
+
+
+
+
+ buttonBox
+ accepted()
+ CheckUpdatesDialog
+ accept()
+
+
+ 248
+ 254
+
+
+ 157
+ 274
+
+
+
+
+ buttonBox
+ rejected()
+ CheckUpdatesDialog
+ reject()
+
+
+ 316
+ 260
+
+
+ 286
+ 274
+
+
+
+
+
diff --git a/src/updater/downloaddialog.cpp b/src/updater/downloaddialog.cpp
new file mode 100644
index 0000000..793e573
--- /dev/null
+++ b/src/updater/downloaddialog.cpp
@@ -0,0 +1,229 @@
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "updaterconst.h"
+#include "mycompress.h"
+#include "downloaddialog.h"
+#include "ui_downloaddialog.h"
+
+DownloadDialog::DownloadDialog(const QString urlString, const QString installDir, QWidget* parent) :
+ QDialog(parent),
+ ui(new Ui::DownloadDialog),
+ redownload_button(new QPushButton("閲嶆柊涓嬭浇(&R)", this)),
+ manager(new QNetworkAccessManager(this)), timer(new QTimer(this)),
+ url_string(urlString), file_name(QFileInfo(urlString).fileName()), download_dir(QDir::tempPath() + "/CCR-Plus/"), install_dir(installDir),
+ file_downloaded(new QFile(download_dir + file_name, this)), file_tmp(new QFile(download_dir + file_name + ".download", this)),
+ last_bytes(0), current_bytes(0), total_bytes(0),
+ download_ok(false), uncompress_ok(false), need_redownload(false), need_reuncompress(false), create_shortcut(false)
+{
+ ui->setupUi(this);
+ this->setWindowFlags(Qt::Dialog | Qt::WindowCloseButtonHint);
+
+ ui->checkBox->hide();
+ ui->buttonBox->addButton(redownload_button, QDialogButtonBox::AcceptRole);
+ redownload_button->hide();
+ this->setFixedHeight(this->sizeHint().height());
+
+ file_downloaded->remove();
+ file_tmp->remove();
+ if (!file_tmp->open(QIODevice::WriteOnly))
+ {
+ showError("涓嬭浇澶辫触: 鏃犳硶鍒涘缓涓存椂鏂囦欢銆", false);
+ return;
+ }
+
+ connect(redownload_button, &QPushButton::clicked, this, &DownloadDialog::onRedownload);
+ connect(timer, &QTimer::timeout, this, &DownloadDialog::onTimeOut);
+
+ timer->start(500);
+}
+
+DownloadDialog::~DownloadDialog()
+{
+ delete ui;
+}
+
+void DownloadDialog::done(int r)
+{
+ if (need_reuncompress)
+ {
+ need_reuncompress = false;
+ return;
+ }
+ if (uncompress_ok) create_shortcut = ui->checkBox->isChecked();
+ QDialog::done(r);
+}
+
+
+
+void DownloadDialog::showError(const QString& msg, bool isBlocked)
+{
+ ui->label_info->setText(msg);
+ ui->label_size->hide();
+ ui->progressBar->hide();
+ redownload_button->show();
+ this->setFixedHeight(120);
+
+ if (isBlocked)
+ {
+ QEventLoop loop;
+ connect(this, &QDialog::finished, &loop, &QEventLoop::quit);
+ loop.exec();
+ }
+}
+
+bool DownloadDialog::uncompress()
+{
+ ui->label_info->setText("姝e湪瑙e帇...");
+ ui->buttonBox->setStandardButtons(QDialogButtonBox::Cancel);
+ QApplication::processEvents();
+
+ QString error = MyCompress::extractDir(file_downloaded->fileName(), Updater::APP_NAME, install_dir);
+ if (!error.isEmpty())
+ {
+ ui->buttonBox->setStandardButtons(QDialogButtonBox::Retry | QDialogButtonBox::Cancel);
+ showError(QString("瑙e帇澶辫触: %1").arg(error));
+ return false;
+ }
+ uncompress_ok = true;
+ return true;
+}
+
+void DownloadDialog::updateSuccessed()
+{
+ ui->label_info->setText("鏇存柊鎴愬姛!");
+ ui->label_size->hide();
+ ui->progressBar->hide();
+ ui->checkBox->show();
+ ui->buttonBox->setStandardButtons(QDialogButtonBox::Close);
+ redownload_button->setText("绔嬪嵆鍚姩(&S)");
+ this->setFixedHeight(120);
+}
+
+
+
+void DownloadDialog::onTimeOut()
+{
+ if (timer->interval() == 500) // start download
+ {
+ onStartDownload();
+ timer->start(Updater::CONNECT_TIME_OUT);
+ return;
+ }
+ else if (timer->interval() == Updater::CONNECT_TIME_OUT) // connect timeout
+ {
+ if (reply->isRunning())
+ {
+ reply->abort();
+ showError("涓嬭浇澶辫触: 杩炴帴瓒呮椂锛岃妫鏌ョ綉缁滆繛鎺ャ");
+ }
+ return;
+ }
+
+ static int zero_speed_times = 0;
+ qint64 speed = current_bytes - last_bytes;
+ last_bytes = current_bytes;
+ ui->progressBar->setValue(current_bytes);
+
+ if (!speed)
+ zero_speed_times++;
+ else
+ zero_speed_times = 0;
+
+// if (zero_speed_times > Updater::CONNECT_TIME_OUT / 1000)
+// {
+// reply->abort();
+// showError("涓嬭浇澶辫触: 杩炴帴瓒呮椂锛岃妫鏌ョ綉缁滆繛鎺ャ");
+// return;
+// }
+ if (speed || zero_speed_times >= 2)
+ {
+ QString info = QString("%1/s - %2").arg(Updater::FormatFileSize(speed)).arg(Updater::FormatFileSize(current_bytes));
+ if (total_bytes) info += QString(", 鍏 %1").arg(Updater::FormatFileSize(total_bytes));
+ if (speed && total_bytes) info += QString(", 杩樺墿 %1").arg(Updater::FormatTime(1.0 * (total_bytes - current_bytes) / speed + 0.5));
+ ui->label_size->setText(info);
+ }
+}
+
+void DownloadDialog::onStartDownload()
+{
+ QNetworkRequest request = QNetworkRequest(QUrl(url_string));
+ request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
+ reply = manager->get(request);
+
+ connect(this, &QDialog::finished, reply, &QNetworkReply::abort);
+ connect(reply, &QNetworkReply::finished, this, &DownloadDialog::onDownloadFinished);
+ connect(reply, &QNetworkReply::downloadProgress, this, &DownloadDialog::onUpdateDownloadProgress);
+ connect(reply, &QNetworkReply::readyRead, this, [this]()
+ {
+ file_tmp->write(reply->readAll());
+ });
+}
+
+void DownloadDialog::onRedownload()
+{
+ if (!download_ok) reply->abort();
+ if (!uncompress_ok) need_redownload = true;
+ QDialog::accept();
+}
+
+void DownloadDialog::onUpdateDownloadProgress(qint64 bytesReceived, qint64 bytesTotal)
+{
+ current_bytes = bytesReceived;
+ total_bytes = bytesTotal == -1 ? 0 : bytesTotal;
+ ui->progressBar->setMaximum(total_bytes);
+ if (total_bytes) ui->progressBar->setTextVisible(true);
+
+ if (timer->interval() == Updater::CONNECT_TIME_OUT) timer->stop();
+ if (!timer->isActive())
+ {
+ timer->start(1000);
+ ui->label_info->setText(QString("姝e湪涓嬭浇 %1 ...").arg(file_name));
+ ui->progressBar->setValue(0);
+ redownload_button->show();
+ onTimeOut();
+ }
+}
+
+void DownloadDialog::onDownloadFinished()
+{
+ file_tmp->close();
+ timer->stop();
+ if (reply->error() == QNetworkReply::NoError)
+ {
+ ui->label_info->setText("涓嬭浇瀹屾垚");
+ ui->label_size->setText("");
+ ui->progressBar->setValue(total_bytes);
+ redownload_button->hide();
+ download_ok = true;
+ QApplication::processEvents();
+
+ if (file_downloaded->exists()) file_downloaded->remove();
+ if (!file_tmp->rename(file_downloaded->fileName()))
+ showError(QString("涓嬭浇澶辫触: 鏃犳硶鍒涘缓鏂囦欢 \"%1\"銆").arg(file_downloaded->fileName()));
+ else if (uncompress()) updateSuccessed();
+ }
+ else
+ {
+ if (reply->error() != QNetworkReply::OperationCanceledError)
+ showError(QString("涓嬭浇澶辫触: 鏃犳硶璁块棶鏇存柊鏈嶅姟鍣(閿欒浠g爜 %1)锛岃妫鏌ョ綉缁滆繛鎺ャ").arg(reply->error()));
+ file_tmp->remove();
+ }
+ reply->deleteLater();
+}
+
+
+
+void DownloadDialog::on_buttonBox_clicked(QAbstractButton* button)
+{
+ if (ui->buttonBox->standardButton(button) == QDialogButtonBox::Retry)
+ {
+ if (uncompress()) updateSuccessed();
+ need_reuncompress = true;
+ }
+}
diff --git a/src/updater/downloaddialog.h b/src/updater/downloaddialog.h
new file mode 100644
index 0000000..0c49b23
--- /dev/null
+++ b/src/updater/downloaddialog.h
@@ -0,0 +1,65 @@
+#ifndef DOWNLOADDIALOG_H
+#define DOWNLOADDIALOG_H
+
+#include
+
+class QFile;
+class QTimer;
+class QAbstractButton;
+class QNetworkReply;
+class QNetworkAccessManager;
+
+namespace Ui
+{
+class DownloadDialog;
+}
+
+class DownloadDialog : public QDialog
+{
+ Q_OBJECT
+public:
+ explicit DownloadDialog(const QString urlString, const QString installDir, QWidget* parent = nullptr);
+ ~DownloadDialog();
+
+ /// 闇瑕侀噸鏂颁笅杞
+ bool NeedRedownload() const { return need_redownload; }
+
+ /// 鏄惁鍒涘缓蹇嵎鏂瑰紡
+ bool ShouldCreateShortcut() const { return create_shortcut; }
+
+public slots:
+ virtual void done(int r) override;
+
+private:
+ Ui::DownloadDialog* ui;
+ QPushButton* redownload_button;
+
+ QNetworkAccessManager* manager;
+ QNetworkReply* reply;
+ QTimer* timer;
+
+ QString url_string, file_name, download_dir, install_dir;
+ QFile *file_downloaded, *file_tmp;
+ qint64 last_bytes, current_bytes, total_bytes;
+ bool download_ok, uncompress_ok, need_redownload, need_reuncompress, create_shortcut;
+
+ /// 鏄剧ず閿欒
+ void showError(const QString& msg, bool isBlocked = true);
+
+ /// 瑙e帇涓嬭浇鏂囦欢
+ bool uncompress();
+
+ /// 鏇存柊鎴愬姛
+ void updateSuccessed();
+
+private slots:
+ void onTimeOut();
+ void onStartDownload();
+ void onRedownload();
+ void onUpdateDownloadProgress(qint64 bytesReceived, qint64 bytesTotal);
+ void onDownloadFinished();
+
+ void on_buttonBox_clicked(QAbstractButton* button);
+};
+
+#endif // DOWNLOADDIALOG_H
diff --git a/src/updater/downloaddialog.ui b/src/updater/downloaddialog.ui
new file mode 100644
index 0000000..50ca154
--- /dev/null
+++ b/src/updater/downloaddialog.ui
@@ -0,0 +1,122 @@
+
+
+ DownloadDialog
+
+
+
+ 400
+ 0
+
+
+
+
+ 400
+ 16777215
+
+
+
+ 涓嬭浇鏇存柊
+
+
+
+ :/image/update.ico:/image/update.ico
+
+
+ QWidget
+{
+ font-family: "寰蒋闆呴粦";
+}
+QMainWindow
+{
+ background-color:rgb(250,250,250);
+}
+
+
+
+
+
+
+ 姝e湪鑾峰彇涓嬭浇鍦板潃...
+
+
+ true
+
+
+
+
+
+
+ 0
+
+
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 鍒涘缓妗岄潰蹇嵎鏂瑰紡
+
+
+ true
+
+
+
+
+
+
+ Qt::Horizontal
+
+
+ QDialogButtonBox::Cancel
+
+
+
+
+
+
+
+
+
+
+ buttonBox
+ accepted()
+ DownloadDialog
+ accept()
+
+
+ 248
+ 254
+
+
+ 157
+ 274
+
+
+
+
+ buttonBox
+ rejected()
+ DownloadDialog
+ reject()
+
+
+ 316
+ 260
+
+
+ 286
+ 274
+
+
+
+
+
diff --git a/src/updater/main.cpp b/src/updater/main.cpp
new file mode 100644
index 0000000..002213c
--- /dev/null
+++ b/src/updater/main.cpp
@@ -0,0 +1,196 @@
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "../common/version.h"
+#include "updaterconst.h"
+#include "downloaddialog.h"
+#include "checkupdatesdialog.h"
+
+const QString tempPath = QDir::tempPath() + "/" + Updater::APP_NAME + "/";
+const QString tempUpdaterPath = tempPath + Updater::UPDATER_NAME;
+
+#if defined(Q_OS_WIN)
+
+#define INITGUID
+#include
+#include
+#include
+
+/// 鏉姝昏繘绋 pid
+void killProcess(int pid)
+{
+ HANDLE hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, pid);
+ if (hProcess != NULL) TerminateProcess(hProcess, 0);
+}
+
+/// 鍒涘缓蹇嵎鏂瑰紡
+bool createShortcut(const QString& installDir, const QString& destinationDir)
+{
+ CoInitialize(NULL);
+ IShellLink* pShellLink = NULL;
+
+ HRESULT hres;
+ hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_ALL, IID_IShellLink, (void**)&pShellLink);
+
+ LPCTSTR appPath = (LPCTSTR)QDir(installDir).absoluteFilePath(Updater::RUN_APP_CMD).utf16();
+ LPCTSTR lnkPath = (LPCTSTR)QDir(destinationDir).absoluteFilePath("CCR Plus 娴嬭瘎鍣.lnk").utf16();
+
+ if (SUCCEEDED(hres))
+ {
+ pShellLink->SetPath(appPath);
+ pShellLink->SetDescription(L"CCR Plus 娴嬭瘎鍣");
+ pShellLink->SetWorkingDirectory((LPCTSTR)installDir.utf16());
+
+ IPersistFile* pPersistFile;
+ hres = pShellLink->QueryInterface(IID_IPersistFile, (void**)&pPersistFile);
+
+ if (SUCCEEDED(hres))
+ {
+ hres = pPersistFile->Save(lnkPath, TRUE);
+ pPersistFile->Release();
+ }
+ pShellLink->Release();
+ }
+ CoUninitialize();
+
+ return SUCCEEDED(hres);
+}
+
+#elif defined(Q_OS_LINUX)
+
+/// 鏉姝昏繘绋 pid
+void killProcess(int pid)
+{
+ QProcess::execute(QString("kill -9 %1").arg(pid));
+}
+
+/// 鍒涘缓蹇嵎鏂瑰紡
+bool createShortcut(const QString& installDir, const QString& destinationDir)
+{
+ return !QProcess::execute(QString("%1/install.sh").arg(installDir), { installDir, destinationDir });
+}
+
+#endif
+
+void cleanTemp()
+{
+ QDir(tempPath).removeRecursively();
+ QDir().mkpath(tempPath);
+}
+
+int main(int argc, char* argv[])
+{
+ QApplication a(argc, argv);
+
+ QTranslator translator;
+ translator.load(":/trans/qt_zh_CN.qm");
+ a.installTranslator(&translator);
+
+ bool _c = argc == 1, _d = false, _n = false, _h = false, _v = false;
+ int pid = 0;
+ QString url, dir;
+
+ if (!QDir(tempPath).exists()) QDir().mkpath(tempPath);
+
+// Debug for download
+// for (;;)
+// {
+// //DownloadDialog dialog("file:///C:/Users/Equation/Desktop/CCR-Plus_1.0.0.150712_release_windows_x86.zip", "C:/Users/equation/Desktop/a");
+// //DownloadDialog dialog("file:///home/equation/Desktop/CCR-Plus_v1.1.0_linux_x64.zip", "/home/equation/Desktop/a");
+// //DownloadDialog dialog("https://svwh.dl.sourceforge.net/project/ccr-plus/Beta/1.0.0.150712_beta2/CCR-Plus_1.0.0.150712_beta2_linux_x64.zip", "/home/equation/Desktop/a");
+
+// dialog.exec();
+// qDebug()< Kill the process when accepted to download updates\n";
+ std::cout << " -d Download the file from and install in the directory \n";
+ }
+ else if (_v) // version info
+ {
+ std::cout << "Update manager for CCR Plus judging environment.\n";
+ std::cout << VERSION_LONG << "\n";
+ std::cout << "Copyright(C) 2017 Yuekai Jia. All rights reserved.\n";
+ }
+ else if (_c) // check updates
+ {
+ cleanTemp();
+ QString appPath = QCoreApplication::applicationDirPath();
+ QString updaterPath = appPath + "/" + Updater::UPDATER_NAME;
+
+ for (;;)
+ {
+ CheckUpdatesDialog dialog(_n);
+ if (dialog.exec() == QDialog::Accepted)
+ {
+ if (dialog.NeedRecheck()) continue;
+ QFile::copy(updaterPath, tempUpdaterPath);
+ QProcess::startDetached(tempUpdaterPath, { "-d", dialog.DownloadUrl(), appPath });
+ if (pid > 0) killProcess(pid);
+ }
+ break;
+ }
+ return 0;
+ }
+ else if (_d) // download new files
+ {
+ //url = "file:///C:/Users/Equation/Desktop/CCR-Plus_1.0.0.150712_release_windows_x86.zip";
+ //url = "file:///home/equation/Desktop/CCR-Plus_v1.1.0_linux_x64.zip";
+ //url = "https://svwh.dl.sourceforge.net/project/ccr-plus/Beta/1.0.0.150712_beta2/CCR-Plus_1.0.0.150712_beta2_linux_x64.zip";
+ for (;;)
+ {
+ DownloadDialog dialog(url, dir);
+ if (dialog.exec() == QDialog::Accepted)
+ {
+ if (dialog.NeedRedownload()) continue;
+ QProcess::startDetached(QDir(dir).absoluteFilePath(Updater::RUN_APP_CMD), {}, dir);
+ }
+ if (dialog.ShouldCreateShortcut())
+ createShortcut(dir, QStandardPaths::writableLocation(QStandardPaths::DesktopLocation));
+
+ break;
+ }
+ }
+}
diff --git a/src/updater/mycompress.cpp b/src/updater/mycompress.cpp
new file mode 100644
index 0000000..2acb9a0
--- /dev/null
+++ b/src/updater/mycompress.cpp
@@ -0,0 +1,110 @@
+#include
+
+#include "mycompress.h"
+#include
+
+static bool copyData(QIODevice& inFile, QIODevice& outFile)
+{
+ while (!inFile.atEnd())
+ {
+ char buf[4096];
+ qint64 readLen = inFile.read(buf, 4096);
+ if (readLen <= 0)
+ return false;
+ if (outFile.write(buf, readLen) != readLen)
+ return false;
+ }
+ return true;
+}
+
+QString MyCompress::extractFile(QuaZip* zip, QString fileName, QString fileDest)
+{
+ // zip: oggetto dove aggiungere il file
+ // filename: nome del file reale
+ // fileincompress: nome del file all'interno del file compresso
+
+ // Apro il file compresso
+ if (!fileName.isEmpty())
+ zip->setCurrentFile(fileName);
+ fileName = zip->getCurrentFileName();
+
+ QuaZipFile inFile(zip);
+ if (!inFile.open(QIODevice::ReadOnly) || inFile.getZipError() != UNZ_OK)
+ return QString("鏃犳硶瑙e帇鏂囦欢 \"%1\" (閿欒浠g爜 %2)銆").arg(fileName).arg(inFile.getZipError());
+
+ // Controllo esistenza cartella file risultato
+ QDir curDir;
+ if (fileDest.endsWith('/'))
+ {
+ if (!curDir.mkpath(fileDest))
+ return QString("鏃犳硶鍒涘缓鐩綍 \"%1\"銆").arg(fileDest);
+ }
+ else
+ {
+ if (!curDir.mkpath(QFileInfo(fileDest).absolutePath()))
+ return QString("鏃犳硶鍒涘缓鐩綍 \"%1\"銆").arg(QFileInfo(fileDest).absolutePath());
+ }
+
+ QuaZipFileInfo64 info;
+ if (!zip->getCurrentFileInfo(&info))
+ return QString("鏃犳硶鑾峰彇鏂囦欢 \"%1\" 鐨勪俊鎭").arg(fileName);
+
+ QFile::Permissions srcPerm = info.getPermissions();
+ if (fileDest.endsWith('/') && QFileInfo(fileDest).isDir())
+ {
+ if (srcPerm != 0)
+ QFile(fileDest).setPermissions(srcPerm);
+ return "";
+ }
+
+ // Apro il file risultato
+ QFile outFile;
+ outFile.setFileName(fileDest);
+ if (!outFile.open(QIODevice::WriteOnly))
+ return QString("鏃犳硶鍐欏叆鏂囦欢 \"%1\"銆").arg(fileDest);
+
+ // Copio i dati
+ if (!copyData(inFile, outFile) || inFile.getZipError() != UNZ_OK)
+ {
+ outFile.close();
+ return QString("瑙e帇鏂囦欢 \"%1\" 澶辫触(閿欒浠g爜 %1)銆").arg(fileName).arg(inFile.getZipError());
+ }
+ outFile.close();
+
+ // Chiudo i file
+ inFile.close();
+ if (inFile.getZipError() != UNZ_OK)
+ return QString("瑙e帇鏂囦欢 \"%1\" 澶辫触(閿欒浠g爜 %1)銆").arg(fileName).arg(zip->getCurrentFileName()).arg(inFile.getZipError());
+
+ if (srcPerm != 0)
+ outFile.setPermissions(srcPerm);
+ return "";
+}
+
+QString MyCompress::extractDir(QString fileCompressed, QString dirName, QString dirDest)
+{
+ QuaZip zip(fileCompressed);
+ QDir directory(dirDest);
+ if (!dirName.isEmpty() && !dirName.endsWith('/')) dirName.append('/');
+
+ if (!zip.open(QuaZip::mdUnzip))
+ return QString("鍘嬬缉鏂囦欢 \"%1\" 鏃犳硶鎵撳紑(閿欒浠g爜 %2)銆").arg(QFileInfo(fileCompressed).fileName()).arg(zip.getZipError());
+
+ for (bool f = zip.goToFirstFile(); f; f = zip.goToNextFile())
+ {
+ QString name = zip.getCurrentFileName();
+
+ if (name.startsWith(dirName) && name != dirName)
+ {
+ QString error = extractFile(&zip, "", directory.absoluteFilePath(name.mid(dirName.length())));
+ if (!error.isEmpty()) return error;
+ }
+ }
+
+ // Chiudo il file zip
+ zip.close();
+ if (zip.getZipError() != 0)
+ return QString("鍘嬬缉鏂囦欢 \"%1\" 瑙e帇澶辫触(閿欒浠g爜 %2)銆").arg(QFileInfo(fileCompressed).fileName()).arg(zip.getZipError());
+
+ return "";
+}
diff --git a/src/updater/mycompress.h b/src/updater/mycompress.h
new file mode 100644
index 0000000..aeb93ad
--- /dev/null
+++ b/src/updater/mycompress.h
@@ -0,0 +1,16 @@
+#ifndef MYCOMPRESS_H
+#define MYCOMPRESS_H
+
+#include
+#include
+
+class MyCompress
+{
+public:
+ static QString extractDir(QString fileCompressed, QString dirName = QString(), QString dirDest = QString());
+
+private:
+ static QString extractFile(QuaZip* zip, QString fileName, QString fileDest);
+};
+
+#endif // MYCOMPRESS_H
diff --git a/src/updater/quazip/JlCompress.cpp b/src/updater/quazip/JlCompress.cpp
new file mode 100644
index 0000000..a62af80
--- /dev/null
+++ b/src/updater/quazip/JlCompress.cpp
@@ -0,0 +1,443 @@
+/*
+Copyright (C) 2010 Roberto Pompermaier
+Copyright (C) 2005-2014 Sergey A. Tachenov
+
+This file is part of QuaZIP.
+
+QuaZIP is free software: you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation, either version 2.1 of the License, or
+(at your option) any later version.
+
+QuaZIP is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with QuaZIP. If not, see .
+
+See COPYING file for the full LGPL text.
+
+Original ZIP package is copyrighted by Gilles Vollant and contributors,
+see quazip/(un)zip.h files for details. Basically it's the zlib license.
+*/
+
+#include "JlCompress.h"
+#include
+
+static bool copyData(QIODevice &inFile, QIODevice &outFile)
+{
+ while (!inFile.atEnd()) {
+ char buf[4096];
+ qint64 readLen = inFile.read(buf, 4096);
+ if (readLen <= 0)
+ return false;
+ if (outFile.write(buf, readLen) != readLen)
+ return false;
+ }
+ return true;
+}
+
+bool JlCompress::compressFile(QuaZip* zip, QString fileName, QString fileDest) {
+ // zip: oggetto dove aggiungere il file
+ // fileName: nome del file reale
+ // fileDest: nome del file all'interno del file compresso
+
+ // Controllo l'apertura dello zip
+ if (!zip) return false;
+ if (zip->getMode()!=QuaZip::mdCreate &&
+ zip->getMode()!=QuaZip::mdAppend &&
+ zip->getMode()!=QuaZip::mdAdd) return false;
+
+ // Apro il file originale
+ QFile inFile;
+ inFile.setFileName(fileName);
+ if(!inFile.open(QIODevice::ReadOnly)) return false;
+
+ // Apro il file risulato
+ QuaZipFile outFile(zip);
+ if(!outFile.open(QIODevice::WriteOnly, QuaZipNewInfo(fileDest, inFile.fileName()))) return false;
+
+ // Copio i dati
+ if (!copyData(inFile, outFile) || outFile.getZipError()!=UNZ_OK) {
+ return false;
+ }
+
+ // Chiudo i file
+ outFile.close();
+ if (outFile.getZipError()!=UNZ_OK) return false;
+ inFile.close();
+
+ return true;
+}
+
+bool JlCompress::compressSubDir(QuaZip* zip, QString dir, QString origDir, bool recursive, QDir::Filters filters) {
+ // zip: oggetto dove aggiungere il file
+ // dir: cartella reale corrente
+ // origDir: cartella reale originale
+ // (path(dir)-path(origDir)) = path interno all'oggetto zip
+
+ // Controllo l'apertura dello zip
+ if (!zip) return false;
+ if (zip->getMode()!=QuaZip::mdCreate &&
+ zip->getMode()!=QuaZip::mdAppend &&
+ zip->getMode()!=QuaZip::mdAdd) return false;
+
+ // Controllo la cartella
+ QDir directory(dir);
+ if (!directory.exists()) return false;
+
+ QDir origDirectory(origDir);
+ if (dir != origDir) {
+ QuaZipFile dirZipFile(zip);
+ if (!dirZipFile.open(QIODevice::WriteOnly,
+ QuaZipNewInfo(origDirectory.relativeFilePath(dir) + "/", dir), 0, 0, 0)) {
+ return false;
+ }
+ dirZipFile.close();
+ }
+
+
+ // Se comprimo anche le sotto cartelle
+ if (recursive) {
+ // Per ogni sotto cartella
+ QFileInfoList files = directory.entryInfoList(QDir::AllDirs|QDir::NoDotAndDotDot|filters);
+ Q_FOREACH (QFileInfo file, files) {
+ // Comprimo la sotto cartella
+ if(!compressSubDir(zip,file.absoluteFilePath(),origDir,recursive,filters)) return false;
+ }
+ }
+
+ // Per ogni file nella cartella
+ QFileInfoList files = directory.entryInfoList(QDir::Files|filters);
+ Q_FOREACH (QFileInfo file, files) {
+ // Se non e un file o e il file compresso che sto creando
+ if(!file.isFile()||file.absoluteFilePath()==zip->getZipName()) continue;
+
+ // Creo il nome relativo da usare all'interno del file compresso
+ QString filename = origDirectory.relativeFilePath(file.absoluteFilePath());
+
+ // Comprimo il file
+ if (!compressFile(zip,file.absoluteFilePath(),filename)) return false;
+ }
+
+ return true;
+}
+
+bool JlCompress::extractFile(QuaZip* zip, QString fileName, QString fileDest) {
+ // zip: oggetto dove aggiungere il file
+ // filename: nome del file reale
+ // fileincompress: nome del file all'interno del file compresso
+
+ // Controllo l'apertura dello zip
+ if (!zip) return false;
+ if (zip->getMode()!=QuaZip::mdUnzip) return false;
+
+ // Apro il file compresso
+ if (!fileName.isEmpty())
+ zip->setCurrentFile(fileName);
+ QuaZipFile inFile(zip);
+ if(!inFile.open(QIODevice::ReadOnly) || inFile.getZipError()!=UNZ_OK) return false;
+
+ // Controllo esistenza cartella file risultato
+ QDir curDir;
+ if (fileDest.endsWith('/')) {
+ if (!curDir.mkpath(fileDest)) {
+ return false;
+ }
+ } else {
+ if (!curDir.mkpath(QFileInfo(fileDest).absolutePath())) {
+ return false;
+ }
+ }
+
+ QuaZipFileInfo64 info;
+ if (!zip->getCurrentFileInfo(&info))
+ return false;
+
+ QFile::Permissions srcPerm = info.getPermissions();
+ if (fileDest.endsWith('/') && QFileInfo(fileDest).isDir()) {
+ if (srcPerm != 0) {
+ QFile(fileDest).setPermissions(srcPerm);
+ }
+ return true;
+ }
+
+ // Apro il file risultato
+ QFile outFile;
+ outFile.setFileName(fileDest);
+ if(!outFile.open(QIODevice::WriteOnly)) return false;
+
+ // Copio i dati
+ if (!copyData(inFile, outFile) || inFile.getZipError()!=UNZ_OK) {
+ outFile.close();
+ removeFile(QStringList(fileDest));
+ return false;
+ }
+ outFile.close();
+
+ // Chiudo i file
+ inFile.close();
+ if (inFile.getZipError()!=UNZ_OK) {
+ removeFile(QStringList(fileDest));
+ return false;
+ }
+
+ if (srcPerm != 0) {
+ outFile.setPermissions(srcPerm);
+ }
+ return true;
+}
+
+bool JlCompress::removeFile(QStringList listFile) {
+ bool ret = true;
+ // Per ogni file
+ for (int i=0; iopen(QuaZip::mdUnzip)) {
+ delete zip;
+ return QStringList();
+ }
+
+ // Estraggo i nomi dei file
+ QStringList lst;
+ QuaZipFileInfo64 info;
+ for(bool more=zip->goToFirstFile(); more; more=zip->goToNextFile()) {
+ if(!zip->getCurrentFileInfo(&info)) {
+ delete zip;
+ return QStringList();
+ }
+ lst << info.name;
+ //info.name.toLocal8Bit().constData()
+ }
+
+ // Chiudo il file zip
+ zip->close();
+ if(zip->getZipError()!=0) {
+ delete zip;
+ return QStringList();
+ }
+ delete zip;
+ return lst;
+}
+
+QStringList JlCompress::extractDir(QIODevice *ioDevice, QString dir)
+{
+ QuaZip zip(ioDevice);
+ return extractDir(zip, dir);
+}
+
+QStringList JlCompress::getFileList(QIODevice *ioDevice)
+{
+ QuaZip *zip = new QuaZip(ioDevice);
+ return getFileList(zip);
+}
+
+QString JlCompress::extractFile(QIODevice *ioDevice, QString fileName, QString fileDest)
+{
+ QuaZip zip(ioDevice);
+ return extractFile(zip, fileName, fileDest);
+}
+
+QStringList JlCompress::extractFiles(QIODevice *ioDevice, QStringList files, QString dir)
+{
+ QuaZip zip(ioDevice);
+ return extractFiles(zip, files, dir);
+}
diff --git a/src/updater/quazip/JlCompress.h b/src/updater/quazip/JlCompress.h
new file mode 100644
index 0000000..49c5086
--- /dev/null
+++ b/src/updater/quazip/JlCompress.h
@@ -0,0 +1,197 @@
+#ifndef JLCOMPRESSFOLDER_H_
+#define JLCOMPRESSFOLDER_H_
+
+/*
+Copyright (C) 2010 Roberto Pompermaier
+Copyright (C) 2005-2016 Sergey A. Tachenov
+
+This file is part of QuaZIP.
+
+QuaZIP is free software: you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation, either version 2.1 of the License, or
+(at your option) any later version.
+
+QuaZIP is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with QuaZIP. If not, see .
+
+See COPYING file for the full LGPL text.
+
+Original ZIP package is copyrighted by Gilles Vollant and contributors,
+see quazip/(un)zip.h files for details. Basically it's the zlib license.
+*/
+
+#include "quazip.h"
+#include "quazipfile.h"
+#include "quazipfileinfo.h"
+#include
+#include
+#include
+#include
+
+/// Utility class for typical operations.
+/**
+ This class contains a number of useful static functions to perform
+ simple operations, such as mass ZIP packing or extraction.
+ */
+class QUAZIP_EXPORT JlCompress {
+private:
+ static QStringList extractDir(QuaZip &zip, const QString &dir);
+ static QStringList getFileList(QuaZip *zip);
+ static QString extractFile(QuaZip &zip, QString fileName, QString fileDest);
+ static QStringList extractFiles(QuaZip &zip, const QStringList &files, const QString &dir);
+ /// Compress a single file.
+ /**
+ \param zip Opened zip to compress the file to.
+ \param fileName The full path to the source file.
+ \param fileDest The full name of the file inside the archive.
+ \return true if success, false otherwise.
+ */
+ static bool compressFile(QuaZip* zip, QString fileName, QString fileDest);
+ /// Compress a subdirectory.
+ /**
+ \param parentZip Opened zip containing the parent directory.
+ \param dir The full path to the directory to pack.
+ \param parentDir The full path to the directory corresponding to
+ the root of the ZIP.
+ \param recursive Whether to pack sub-directories as well or only
+ files.
+ \return true if success, false otherwise.
+ */
+ static bool compressSubDir(QuaZip* parentZip, QString dir, QString parentDir, bool recursive,
+ QDir::Filters filters);
+ /// Extract a single file.
+ /**
+ \param zip The opened zip archive to extract from.
+ \param fileName The full name of the file to extract.
+ \param fileDest The full path to the destination file.
+ \return true if success, false otherwise.
+ */
+ static bool extractFile(QuaZip* zip, QString fileName, QString fileDest);
+ /// Remove some files.
+ /**
+ \param listFile The list of files to remove.
+ \return true if success, false otherwise.
+ */
+ static bool removeFile(QStringList listFile);
+
+public:
+ /// Compress a single file.
+ /**
+ \param fileCompressed The name of the archive.
+ \param file The file to compress.
+ \return true if success, false otherwise.
+ */
+ static bool compressFile(QString fileCompressed, QString file);
+ /// Compress a list of files.
+ /**
+ \param fileCompressed The name of the archive.
+ \param files The file list to compress.
+ \return true if success, false otherwise.
+ */
+ static bool compressFiles(QString fileCompressed, QStringList files);
+ /// Compress a whole directory.
+ /**
+ Does not compress hidden files. See compressDir(QString, QString, bool, QDir::Filters).
+
+ \param fileCompressed The name of the archive.
+ \param dir The directory to compress.
+ \param recursive Whether to pack the subdirectories as well, or
+ just regular files.
+ \return true if success, false otherwise.
+ */
+ static bool compressDir(QString fileCompressed, QString dir = QString(), bool recursive = true);
+ /**
+ * @brief Compress a whole directory.
+ *
+ * Unless filters are specified explicitly, packs
+ * only regular non-hidden files (and subdirs, if @c recursive is true).
+ * If filters are specified, they are OR-combined with
+ * %QDir::AllDirs|%QDir::NoDotAndDotDot when searching for dirs
+ * and with QDir::Files when searching for files.
+ *
+ * @param fileCompressed path to the resulting archive
+ * @param dir path to the directory being compressed
+ * @param recursive if true, then the subdirectories are packed as well
+ * @param filters what to pack, filters are applied both when searching
+ * for subdirs (if packing recursively) and when looking for files to pack
+ * @return true on success, false otherwise
+ */
+ static bool compressDir(QString fileCompressed, QString dir,
+ bool recursive, QDir::Filters filters);
+
+public:
+ /// Extract a single file.
+ /**
+ \param fileCompressed The name of the archive.
+ \param fileName The file to extract.
+ \param fileDest The destination file, assumed to be identical to
+ \a file if left empty.
+ \return The list of the full paths of the files extracted, empty on failure.
+ */
+ static QString extractFile(QString fileCompressed, QString fileName, QString fileDest = QString());
+ /// Extract a list of files.
+ /**
+ \param fileCompressed The name of the archive.
+ \param files The file list to extract.
+ \param dir The directory to put the files to, the current
+ directory if left empty.
+ \return The list of the full paths of the files extracted, empty on failure.
+ */
+ static QStringList extractFiles(QString fileCompressed, QStringList files, QString dir = QString());
+ /// Extract a whole archive.
+ /**
+ \param fileCompressed The name of the archive.
+ \param dir The directory to extract to, the current directory if
+ left empty.
+ \return The list of the full paths of the files extracted, empty on failure.
+ */
+ static QStringList extractDir(QString fileCompressed, QString dir = QString());
+ /// Get the file list.
+ /**
+ \return The list of the files in the archive, or, more precisely, the
+ list of the entries, including both files and directories if they
+ are present separately.
+ */
+ static QStringList getFileList(QString fileCompressed);
+ /// Extract a single file.
+ /**
+ \param ioDevice pointer to device with compressed data.
+ \param fileName The file to extract.
+ \param fileDest The destination file, assumed to be identical to
+ \a file if left empty.
+ \return The list of the full paths of the files extracted, empty on failure.
+ */
+ static QString extractFile(QIODevice *ioDevice, QString fileName, QString fileDest = QString());
+ /// Extract a list of files.
+ /**
+ \param ioDevice pointer to device with compressed data.
+ \param files The file list to extract.
+ \param dir The directory to put the files to, the current
+ directory if left empty.
+ \return The list of the full paths of the files extracted, empty on failure.
+ */
+ static QStringList extractFiles(QIODevice *ioDevice, QStringList files, QString dir = QString());
+ /// Extract a whole archive.
+ /**
+ \param ioDevice pointer to device with compressed data.
+ \param dir The directory to extract to, the current directory if
+ left empty.
+ \return The list of the full paths of the files extracted, empty on failure.
+ */
+ static QStringList extractDir(QIODevice *ioDevice, QString dir = QString());
+ /// Get the file list.
+ /**
+ \return The list of the files in the archive, or, more precisely, the
+ list of the entries, including both files and directories if they
+ are present separately.
+ */
+ static QStringList getFileList(QIODevice *ioDevice);
+};
+
+#endif /* JLCOMPRESSFOLDER_H_ */
diff --git a/src/updater/quazip/crypt.h b/src/updater/quazip/crypt.h
new file mode 100644
index 0000000..ddee28e
--- /dev/null
+++ b/src/updater/quazip/crypt.h
@@ -0,0 +1,135 @@
+/* crypt.h -- base code for crypt/uncrypt ZIPfile
+
+
+ Version 1.01e, February 12th, 2005
+
+ Copyright (C) 1998-2005 Gilles Vollant
+
+ This code is a modified version of crypting code in Infozip distribution
+
+ The encryption/decryption parts of this source code (as opposed to the
+ non-echoing password parts) were originally written in Europe. The
+ whole source package can be freely distributed, including from the USA.
+ (Prior to January 2000, re-export from the US was a violation of US law.)
+
+ This encryption code is a direct transcription of the algorithm from
+ Roger Schlafly, described by Phil Katz in the file appnote.txt. This
+ file (appnote.txt) is distributed with the PKZIP program (even in the
+ version without encryption capabilities).
+
+ If you don't need crypting in your application, just define symbols
+ NOCRYPT and NOUNCRYPT.
+
+ This code support the "Traditional PKWARE Encryption".
+
+ The new AES encryption added on Zip format by Winzip (see the page
+ http://www.winzip.com/aes_info.htm ) and PKWare PKZip 5.x Strong
+ Encryption is not supported.
+*/
+
+#include "quazip_global.h"
+
+#define CRC32(c, b) ((*(pcrc_32_tab+(((int)(c) ^ (b)) & 0xff))) ^ ((c) >> 8))
+
+/***********************************************************************
+ * Return the next byte in the pseudo-random sequence
+ */
+static int decrypt_byte(unsigned long* pkeys, const z_crc_t FAR * pcrc_32_tab UNUSED)
+{
+ //(void) pcrc_32_tab; /* avoid "unused parameter" warning */
+ unsigned temp; /* POTENTIAL BUG: temp*(temp^1) may overflow in an
+ * unpredictable manner on 16-bit systems; not a problem
+ * with any known compiler so far, though */
+
+ temp = ((unsigned)(*(pkeys+2)) & 0xffff) | 2;
+ return (int)(((temp * (temp ^ 1)) >> 8) & 0xff);
+}
+
+/***********************************************************************
+ * Update the encryption keys with the next byte of plain text
+ */
+static int update_keys(unsigned long* pkeys,const z_crc_t FAR * pcrc_32_tab,int c)
+{
+ (*(pkeys+0)) = CRC32((*(pkeys+0)), c);
+ (*(pkeys+1)) += (*(pkeys+0)) & 0xff;
+ (*(pkeys+1)) = (*(pkeys+1)) * 134775813L + 1;
+ {
+ register int keyshift = (int)((*(pkeys+1)) >> 24);
+ (*(pkeys+2)) = CRC32((*(pkeys+2)), keyshift);
+ }
+ return c;
+}
+
+
+/***********************************************************************
+ * Initialize the encryption keys and the random header according to
+ * the given password.
+ */
+static void init_keys(const char* passwd,unsigned long* pkeys,const z_crc_t FAR * pcrc_32_tab)
+{
+ *(pkeys+0) = 305419896L;
+ *(pkeys+1) = 591751049L;
+ *(pkeys+2) = 878082192L;
+ while (*passwd != '\0') {
+ update_keys(pkeys,pcrc_32_tab,(int)*passwd);
+ passwd++;
+ }
+}
+
+#define zdecode(pkeys,pcrc_32_tab,c) \
+ (update_keys(pkeys,pcrc_32_tab,c ^= decrypt_byte(pkeys,pcrc_32_tab)))
+
+#define zencode(pkeys,pcrc_32_tab,c,t) \
+ (t=decrypt_byte(pkeys,pcrc_32_tab), update_keys(pkeys,pcrc_32_tab,c), t^(c))
+
+#ifdef INCLUDECRYPTINGCODE_IFCRYPTALLOWED
+
+#define RAND_HEAD_LEN 12
+ /* "last resort" source for second part of crypt seed pattern */
+# ifndef ZCR_SEED2
+# define ZCR_SEED2 3141592654UL /* use PI as default pattern */
+# endif
+
+static int crypthead(passwd, buf, bufSize, pkeys, pcrc_32_tab, crcForCrypting)
+ const char *passwd; /* password string */
+ unsigned char *buf; /* where to write header */
+ int bufSize;
+ unsigned long* pkeys;
+ const z_crc_t FAR * pcrc_32_tab;
+ unsigned long crcForCrypting;
+{
+ int n; /* index in random header */
+ int t; /* temporary */
+ int c; /* random byte */
+ unsigned char header[RAND_HEAD_LEN-2]; /* random header */
+ static unsigned calls = 0; /* ensure different random header each time */
+
+ if (bufSize> 7) & 0xff;
+ header[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, c, t);
+ }
+ /* Encrypt random header (last two bytes is high word of crc) */
+ init_keys(passwd, pkeys, pcrc_32_tab);
+ for (n = 0; n < RAND_HEAD_LEN-2; n++)
+ {
+ buf[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, header[n], t);
+ }
+ buf[n++] = zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 16) & 0xff, t);
+ buf[n++] = zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 24) & 0xff, t);
+ return n;
+}
+
+#endif
diff --git a/src/updater/quazip/ioapi.h b/src/updater/quazip/ioapi.h
new file mode 100644
index 0000000..bbb94c8
--- /dev/null
+++ b/src/updater/quazip/ioapi.h
@@ -0,0 +1,207 @@
+/* ioapi.h -- IO base function header for compress/uncompress .zip
+ part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html )
+
+ Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html )
+
+ Modifications for Zip64 support
+ Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com )
+
+ Modified by Sergey A. Tachenov to allow QIODevice API usage.
+
+ For more info read MiniZip_info.txt
+
+ Changes
+
+ Oct-2009 - Defined ZPOS64_T to fpos_t on windows and u_int64_t on linux. (might need to find a better why for this)
+ Oct-2009 - Change to fseeko64, ftello64 and fopen64 so large files would work on linux.
+ More if/def section may be needed to support other platforms
+ Oct-2009 - Defined fxxxx64 calls to normal fopen/ftell/fseek so they would compile on windows.
+ (but you should use iowin32.c for windows instead)
+
+*/
+
+#ifndef _ZLIBIOAPI64_H
+#define _ZLIBIOAPI64_H
+
+#if (!defined(_WIN32)) && (!defined(WIN32))
+
+ // Linux needs this to support file operation on files larger then 4+GB
+ // But might need better if/def to select just the platforms that needs them.
+
+ #ifndef __USE_FILE_OFFSET64
+ #define __USE_FILE_OFFSET64
+ #endif
+ #ifndef __USE_LARGEFILE64
+ #define __USE_LARGEFILE64
+ #endif
+ #ifndef _LARGEFILE64_SOURCE
+ #define _LARGEFILE64_SOURCE
+ #endif
+ #ifndef _FILE_OFFSET_BIT
+ #define _FILE_OFFSET_BIT 64
+ #endif
+#endif
+
+#include
+#include
+#include "zlib.h"
+
+#if defined(USE_FILE32API)
+#define fopen64 fopen
+#define ftello64 ftell
+#define fseeko64 fseek
+#else
+#ifdef _MSC_VER
+ #define fopen64 fopen
+ #if (_MSC_VER >= 1400) && (!(defined(NO_MSCVER_FILE64_FUNC)))
+ #define ftello64 _ftelli64
+ #define fseeko64 _fseeki64
+ #else // old MSC
+ #define ftello64 ftell
+ #define fseeko64 fseek
+ #endif
+#endif
+#endif
+
+/*
+#ifndef ZPOS64_T
+ #ifdef _WIN32
+ #define ZPOS64_T fpos_t
+ #else
+ #include
+ #define ZPOS64_T uint64_t
+ #endif
+#endif
+*/
+
+#ifdef HAVE_MINIZIP64_CONF_H
+#include "mz64conf.h"
+#endif
+
+/* a type choosen by DEFINE */
+#ifdef HAVE_64BIT_INT_CUSTOM
+typedef 64BIT_INT_CUSTOM_TYPE ZPOS64_T;
+#else
+#ifdef HAS_STDINT_H
+#include "stdint.h"
+typedef uint64_t ZPOS64_T;
+#else
+
+
+#if defined(_MSC_VER) || defined(__BORLANDC__)
+typedef unsigned __int64 ZPOS64_T;
+#else
+typedef unsigned long long int ZPOS64_T;
+#endif
+#endif
+#endif
+
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef OF
+#define OF _Z_OF
+#endif
+
+#define ZLIB_FILEFUNC_SEEK_CUR (1)
+#define ZLIB_FILEFUNC_SEEK_END (2)
+#define ZLIB_FILEFUNC_SEEK_SET (0)
+
+#define ZLIB_FILEFUNC_MODE_READ (1)
+#define ZLIB_FILEFUNC_MODE_WRITE (2)
+#define ZLIB_FILEFUNC_MODE_READWRITEFILTER (3)
+
+#define ZLIB_FILEFUNC_MODE_EXISTING (4)
+#define ZLIB_FILEFUNC_MODE_CREATE (8)
+
+
+#ifndef ZCALLBACK
+ #if (defined(WIN32) || defined(_WIN32) || defined (WINDOWS) || defined (_WINDOWS)) && defined(CALLBACK) && defined (USEWINDOWS_CALLBACK)
+ #define ZCALLBACK CALLBACK
+ #else
+ #define ZCALLBACK
+ #endif
+#endif
+
+
+
+
+typedef voidpf (ZCALLBACK *open_file_func) OF((voidpf opaque, voidpf file, int mode));
+typedef uLong (ZCALLBACK *read_file_func) OF((voidpf opaque, voidpf stream, void* buf, uLong size));
+typedef uLong (ZCALLBACK *write_file_func) OF((voidpf opaque, voidpf stream, const void* buf, uLong size));
+typedef int (ZCALLBACK *close_file_func) OF((voidpf opaque, voidpf stream));
+typedef int (ZCALLBACK *testerror_file_func) OF((voidpf opaque, voidpf stream));
+
+typedef uLong (ZCALLBACK *tell_file_func) OF((voidpf opaque, voidpf stream));
+typedef int (ZCALLBACK *seek_file_func) OF((voidpf opaque, voidpf stream, uLong offset, int origin));
+
+
+/* here is the "old" 32 bits structure structure */
+typedef struct zlib_filefunc_def_s
+{
+ open_file_func zopen_file;
+ read_file_func zread_file;
+ write_file_func zwrite_file;
+ tell_file_func ztell_file;
+ seek_file_func zseek_file;
+ close_file_func zclose_file;
+ testerror_file_func zerror_file;
+ voidpf opaque;
+} zlib_filefunc_def;
+
+typedef ZPOS64_T (ZCALLBACK *tell64_file_func) OF((voidpf opaque, voidpf stream));
+typedef int (ZCALLBACK *seek64_file_func) OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin));
+typedef voidpf (ZCALLBACK *open64_file_func) OF((voidpf opaque, voidpf file, int mode));
+
+typedef struct zlib_filefunc64_def_s
+{
+ open64_file_func zopen64_file;
+ read_file_func zread_file;
+ write_file_func zwrite_file;
+ tell64_file_func ztell64_file;
+ seek64_file_func zseek64_file;
+ close_file_func zclose_file;
+ testerror_file_func zerror_file;
+ voidpf opaque;
+ close_file_func zfakeclose_file; // for no-auto-close flag
+} zlib_filefunc64_def;
+
+void fill_qiodevice64_filefunc OF((zlib_filefunc64_def* pzlib_filefunc_def));
+void fill_qiodevice_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def));
+
+/* now internal definition, only for zip.c and unzip.h */
+typedef struct zlib_filefunc64_32_def_s
+{
+ zlib_filefunc64_def zfile_func64;
+ open_file_func zopen32_file;
+ tell_file_func ztell32_file;
+ seek_file_func zseek32_file;
+} zlib_filefunc64_32_def;
+
+
+#define ZREAD64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zread_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size))
+#define ZWRITE64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zwrite_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size))
+//#define ZTELL64(filefunc,filestream) ((*((filefunc).ztell64_file)) ((filefunc).opaque,filestream))
+//#define ZSEEK64(filefunc,filestream,pos,mode) ((*((filefunc).zseek64_file)) ((filefunc).opaque,filestream,pos,mode))
+#define ZCLOSE64(filefunc,filestream) ((*((filefunc).zfile_func64.zclose_file)) ((filefunc).zfile_func64.opaque,filestream))
+#define ZFAKECLOSE64(filefunc,filestream) ((*((filefunc).zfile_func64.zfakeclose_file)) ((filefunc).zfile_func64.opaque,filestream))
+#define ZERROR64(filefunc,filestream) ((*((filefunc).zfile_func64.zerror_file)) ((filefunc).zfile_func64.opaque,filestream))
+
+voidpf call_zopen64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf file,int mode));
+int call_zseek64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin));
+ZPOS64_T call_ztell64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf filestream));
+
+void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32);
+
+#define ZOPEN64(filefunc,filename,mode) (call_zopen64((&(filefunc)),(filename),(mode)))
+#define ZTELL64(filefunc,filestream) (call_ztell64((&(filefunc)),(filestream)))
+#define ZSEEK64(filefunc,filestream,pos,mode) (call_zseek64((&(filefunc)),(filestream),(pos),(mode)))
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/updater/quazip/qioapi.cpp b/src/updater/quazip/qioapi.cpp
new file mode 100644
index 0000000..641883b
--- /dev/null
+++ b/src/updater/quazip/qioapi.cpp
@@ -0,0 +1,363 @@
+/* ioapi.c -- IO base function header for compress/uncompress .zip
+ files using zlib + zip or unzip API
+
+ Version 1.01e, February 12th, 2005
+
+ Copyright (C) 1998-2005 Gilles Vollant
+
+ Modified by Sergey A. Tachenov to integrate with Qt.
+*/
+
+#include
+#include
+#include
+
+#include "zlib.h"
+#include "ioapi.h"
+#include "quazip_global.h"
+#include
+#if (QT_VERSION >= 0x050100)
+#define QUAZIP_QSAVEFILE_BUG_WORKAROUND
+#endif
+#ifdef QUAZIP_QSAVEFILE_BUG_WORKAROUND
+#include
+#endif
+
+/* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */
+
+#ifndef SEEK_CUR
+#define SEEK_CUR 1
+#endif
+
+#ifndef SEEK_END
+#define SEEK_END 2
+#endif
+
+#ifndef SEEK_SET
+#define SEEK_SET 0
+#endif
+
+voidpf call_zopen64 (const zlib_filefunc64_32_def* pfilefunc,voidpf file,int mode)
+{
+ if (pfilefunc->zfile_func64.zopen64_file != NULL)
+ return (*(pfilefunc->zfile_func64.zopen64_file)) (pfilefunc->zfile_func64.opaque,file,mode);
+ else
+ {
+ return (*(pfilefunc->zopen32_file))(pfilefunc->zfile_func64.opaque,file,mode);
+ }
+}
+
+int call_zseek64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin)
+{
+ if (pfilefunc->zfile_func64.zseek64_file != NULL)
+ return (*(pfilefunc->zfile_func64.zseek64_file)) (pfilefunc->zfile_func64.opaque,filestream,offset,origin);
+ else
+ {
+ uLong offsetTruncated = (uLong)offset;
+ if (offsetTruncated != offset)
+ return -1;
+ else
+ return (*(pfilefunc->zseek32_file))(pfilefunc->zfile_func64.opaque,filestream,offsetTruncated,origin);
+ }
+}
+
+ZPOS64_T call_ztell64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream)
+{
+ if (pfilefunc->zfile_func64.zseek64_file != NULL)
+ return (*(pfilefunc->zfile_func64.ztell64_file)) (pfilefunc->zfile_func64.opaque,filestream);
+ else
+ {
+ uLong tell_uLong = (*(pfilefunc->ztell32_file))(pfilefunc->zfile_func64.opaque,filestream);
+ if ((tell_uLong) == ((uLong)-1))
+ return (ZPOS64_T)-1;
+ else
+ return tell_uLong;
+ }
+}
+
+/// @cond internal
+struct QIODevice_descriptor {
+ // Position only used for writing to sequential devices.
+ qint64 pos;
+ inline QIODevice_descriptor():
+ pos(0)
+ {}
+};
+/// @endcond
+
+voidpf ZCALLBACK qiodevice_open_file_func (
+ voidpf opaque,
+ voidpf file,
+ int mode)
+{
+ QIODevice_descriptor *d = reinterpret_cast(opaque);
+ QIODevice *iodevice = reinterpret_cast(file);
+ QIODevice::OpenMode desiredMode;
+ if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ)
+ desiredMode = QIODevice::ReadOnly;
+ else if (mode & ZLIB_FILEFUNC_MODE_EXISTING)
+ desiredMode = QIODevice::ReadWrite;
+ else if (mode & ZLIB_FILEFUNC_MODE_CREATE)
+ desiredMode = QIODevice::WriteOnly;
+ if (iodevice->isOpen()) {
+ if ((iodevice->openMode() & desiredMode) == desiredMode) {
+ if (desiredMode != QIODevice::WriteOnly
+ && iodevice->isSequential()) {
+ // We can use sequential devices only for writing.
+ delete d;
+ return NULL;
+ } else {
+ if ((desiredMode & QIODevice::WriteOnly) != 0) {
+ // open for writing, need to seek existing device
+ if (!iodevice->isSequential()) {
+ iodevice->seek(0);
+ } else {
+ d->pos = iodevice->pos();
+ }
+ }
+ }
+ return iodevice;
+ } else {
+ delete d;
+ return NULL;
+ }
+ }
+ iodevice->open(desiredMode);
+ if (iodevice->isOpen()) {
+ if (desiredMode != QIODevice::WriteOnly && iodevice->isSequential()) {
+ // We can use sequential devices only for writing.
+ iodevice->close();
+ delete d;
+ return NULL;
+ } else {
+ return iodevice;
+ }
+ } else {
+ delete d;
+ return NULL;
+ }
+}
+
+
+uLong ZCALLBACK qiodevice_read_file_func (
+ voidpf opaque,
+ voidpf stream,
+ void* buf,
+ uLong size)
+{
+ QIODevice_descriptor *d = reinterpret_cast(opaque);
+ QIODevice *iodevice = reinterpret_cast(stream);
+ qint64 ret64 = iodevice->read((char*)buf,size);
+ uLong ret;
+ ret = (uLong) ret64;
+ if (ret64 != -1) {
+ d->pos += ret64;
+ }
+ return ret;
+}
+
+
+uLong ZCALLBACK qiodevice_write_file_func (
+ voidpf opaque,
+ voidpf stream,
+ const void* buf,
+ uLong size)
+{
+ QIODevice_descriptor *d = reinterpret_cast(opaque);
+ QIODevice *iodevice = reinterpret_cast(stream);
+ uLong ret;
+ qint64 ret64 = iodevice->write((char*)buf,size);
+ if (ret64 != -1) {
+ d->pos += ret64;
+ }
+ ret = (uLong) ret64;
+ return ret;
+}
+
+uLong ZCALLBACK qiodevice_tell_file_func (
+ voidpf opaque,
+ voidpf stream)
+{
+ QIODevice_descriptor *d = reinterpret_cast(opaque);
+ QIODevice *iodevice = reinterpret_cast(stream);
+ uLong ret;
+ qint64 ret64;
+ if (iodevice->isSequential()) {
+ ret64 = d->pos;
+ } else {
+ ret64 = iodevice->pos();
+ }
+ ret = static_cast(ret64);
+ return ret;
+}
+
+ZPOS64_T ZCALLBACK qiodevice64_tell_file_func (
+ voidpf opaque,
+ voidpf stream)
+{
+ QIODevice_descriptor *d = reinterpret_cast(opaque);
+ QIODevice *iodevice = reinterpret_cast(stream);
+ qint64 ret;
+ if (iodevice->isSequential()) {
+ ret = d->pos;
+ } else {
+ ret = iodevice->pos();
+ }
+ return static_cast(ret);
+}
+
+int ZCALLBACK qiodevice_seek_file_func (
+ voidpf /*opaque UNUSED*/,
+ voidpf stream,
+ uLong offset,
+ int origin)
+{
+ QIODevice *iodevice = reinterpret_cast(stream);
+ if (iodevice->isSequential()) {
+ if (origin == ZLIB_FILEFUNC_SEEK_END
+ && offset == 0) {
+ // sequential devices are always at end (needed in mdAppend)
+ return 0;
+ } else {
+ qWarning("qiodevice_seek_file_func() called for sequential device");
+ return -1;
+ }
+ }
+ uLong qiodevice_seek_result=0;
+ int ret;
+ switch (origin)
+ {
+ case ZLIB_FILEFUNC_SEEK_CUR :
+ qiodevice_seek_result = ((QIODevice*)stream)->pos() + offset;
+ break;
+ case ZLIB_FILEFUNC_SEEK_END :
+ qiodevice_seek_result = ((QIODevice*)stream)->size() - offset;
+ break;
+ case ZLIB_FILEFUNC_SEEK_SET :
+ qiodevice_seek_result = offset;
+ break;
+ default:
+ return -1;
+ }
+ ret = !iodevice->seek(qiodevice_seek_result);
+ return ret;
+}
+
+int ZCALLBACK qiodevice64_seek_file_func (
+ voidpf /*opaque UNUSED*/,
+ voidpf stream,
+ ZPOS64_T offset,
+ int origin)
+{
+ QIODevice *iodevice = reinterpret_cast(stream);
+ if (iodevice->isSequential()) {
+ if (origin == ZLIB_FILEFUNC_SEEK_END
+ && offset == 0) {
+ // sequential devices are always at end (needed in mdAppend)
+ return 0;
+ } else {
+ qWarning("qiodevice_seek_file_func() called for sequential device");
+ return -1;
+ }
+ }
+ qint64 qiodevice_seek_result=0;
+ int ret;
+ switch (origin)
+ {
+ case ZLIB_FILEFUNC_SEEK_CUR :
+ qiodevice_seek_result = ((QIODevice*)stream)->pos() + offset;
+ break;
+ case ZLIB_FILEFUNC_SEEK_END :
+ qiodevice_seek_result = ((QIODevice*)stream)->size() - offset;
+ break;
+ case ZLIB_FILEFUNC_SEEK_SET :
+ qiodevice_seek_result = offset;
+ break;
+ default:
+ return -1;
+ }
+ ret = !iodevice->seek(qiodevice_seek_result);
+ return ret;
+}
+
+int ZCALLBACK qiodevice_close_file_func (
+ voidpf opaque,
+ voidpf stream)
+{
+ QIODevice_descriptor *d = reinterpret_cast(opaque);
+ delete d;
+ QIODevice *device = reinterpret_cast(stream);
+#ifdef QUAZIP_QSAVEFILE_BUG_WORKAROUND
+ // QSaveFile terribly breaks the is-a idiom:
+ // it IS a QIODevice, but it is NOT compatible with it: close() is private
+ QSaveFile *file = qobject_cast(device);
+ if (file != NULL) {
+ // We have to call the ugly commit() instead:
+ return file->commit() ? 0 : -1;
+ }
+#endif
+ device->close();
+ return 0;
+}
+
+int ZCALLBACK qiodevice_fakeclose_file_func (
+ voidpf opaque,
+ voidpf /*stream*/)
+{
+ QIODevice_descriptor *d = reinterpret_cast(opaque);
+ delete d;
+ return 0;
+}
+
+int ZCALLBACK qiodevice_error_file_func (
+ voidpf /*opaque UNUSED*/,
+ voidpf /*stream UNUSED*/)
+{
+ // can't check for error due to the QIODevice API limitation
+ return 0;
+}
+
+void fill_qiodevice_filefunc (
+ zlib_filefunc_def* pzlib_filefunc_def)
+{
+ pzlib_filefunc_def->zopen_file = qiodevice_open_file_func;
+ pzlib_filefunc_def->zread_file = qiodevice_read_file_func;
+ pzlib_filefunc_def->zwrite_file = qiodevice_write_file_func;
+ pzlib_filefunc_def->ztell_file = qiodevice_tell_file_func;
+ pzlib_filefunc_def->zseek_file = qiodevice_seek_file_func;
+ pzlib_filefunc_def->zclose_file = qiodevice_close_file_func;
+ pzlib_filefunc_def->zerror_file = qiodevice_error_file_func;
+ pzlib_filefunc_def->opaque = new QIODevice_descriptor;
+}
+
+void fill_qiodevice64_filefunc (
+ zlib_filefunc64_def* pzlib_filefunc_def)
+{
+ // Open functions are the same for Qt.
+ pzlib_filefunc_def->zopen64_file = qiodevice_open_file_func;
+ pzlib_filefunc_def->zread_file = qiodevice_read_file_func;
+ pzlib_filefunc_def->zwrite_file = qiodevice_write_file_func;
+ pzlib_filefunc_def->ztell64_file = qiodevice64_tell_file_func;
+ pzlib_filefunc_def->zseek64_file = qiodevice64_seek_file_func;
+ pzlib_filefunc_def->zclose_file = qiodevice_close_file_func;
+ pzlib_filefunc_def->zerror_file = qiodevice_error_file_func;
+ pzlib_filefunc_def->opaque = new QIODevice_descriptor;
+ pzlib_filefunc_def->zfakeclose_file = qiodevice_fakeclose_file_func;
+}
+
+void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32)
+{
+ p_filefunc64_32->zfile_func64.zopen64_file = NULL;
+ p_filefunc64_32->zopen32_file = p_filefunc32->zopen_file;
+ p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file;
+ p_filefunc64_32->zfile_func64.zread_file = p_filefunc32->zread_file;
+ p_filefunc64_32->zfile_func64.zwrite_file = p_filefunc32->zwrite_file;
+ p_filefunc64_32->zfile_func64.ztell64_file = NULL;
+ p_filefunc64_32->zfile_func64.zseek64_file = NULL;
+ p_filefunc64_32->zfile_func64.zclose_file = p_filefunc32->zclose_file;
+ p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file;
+ p_filefunc64_32->zfile_func64.opaque = p_filefunc32->opaque;
+ p_filefunc64_32->zfile_func64.zfakeclose_file = NULL;
+ p_filefunc64_32->zseek32_file = p_filefunc32->zseek_file;
+ p_filefunc64_32->ztell32_file = p_filefunc32->ztell_file;
+}
diff --git a/src/updater/quazip/quaadler32.cpp b/src/updater/quazip/quaadler32.cpp
new file mode 100644
index 0000000..161db11
--- /dev/null
+++ b/src/updater/quazip/quaadler32.cpp
@@ -0,0 +1,53 @@
+/*
+Copyright (C) 2010 Adam Walczak
+Copyright (C) 2005-2014 Sergey A. Tachenov
+
+This file is part of QuaZIP.
+
+QuaZIP is free software: you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation, either version 2.1 of the License, or
+(at your option) any later version.
+
+QuaZIP is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with QuaZIP. If not, see .
+
+See COPYING file for the full LGPL text.
+
+Original ZIP package is copyrighted by Gilles Vollant and contributors,
+see quazip/(un)zip.h files for details. Basically it's the zlib license.
+*/
+
+#include "quaadler32.h"
+
+#include "zlib.h"
+
+QuaAdler32::QuaAdler32()
+{
+ reset();
+}
+
+quint32 QuaAdler32::calculate(const QByteArray &data)
+{
+ return adler32( adler32(0L, Z_NULL, 0), (const Bytef*)data.data(), data.size() );
+}
+
+void QuaAdler32::reset()
+{
+ checksum = adler32(0L, Z_NULL, 0);
+}
+
+void QuaAdler32::update(const QByteArray &buf)
+{
+ checksum = adler32( checksum, (const Bytef*)buf.data(), buf.size() );
+}
+
+quint32 QuaAdler32::value()
+{
+ return checksum;
+}
diff --git a/src/updater/quazip/quaadler32.h b/src/updater/quazip/quaadler32.h
new file mode 100644
index 0000000..e8847f4
--- /dev/null
+++ b/src/updater/quazip/quaadler32.h
@@ -0,0 +1,54 @@
+#ifndef QUAADLER32_H
+#define QUAADLER32_H
+
+/*
+Copyright (C) 2010 Adam Walczak
+Copyright (C) 2005-2014 Sergey A. Tachenov
+
+This file is part of QuaZIP.
+
+QuaZIP is free software: you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation, either version 2.1 of the License, or
+(at your option) any later version.
+
+QuaZIP is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with QuaZIP. If not, see .
+
+See COPYING file for the full LGPL text.
+
+Original ZIP package is copyrighted by Gilles Vollant and contributors,
+see quazip/(un)zip.h files for details. Basically it's the zlib license.
+*/
+
+#include
+
+#include "quachecksum32.h"
+
+/// Adler32 checksum
+/** \class QuaAdler32 quaadler32.h
+ * This class wrappers the adler32 function with the QuaChecksum32 interface.
+ * See QuaChecksum32 for more info.
+ */
+class QUAZIP_EXPORT QuaAdler32 : public QuaChecksum32
+{
+
+public:
+ QuaAdler32();
+
+ quint32 calculate(const QByteArray &data);
+
+ void reset();
+ void update(const QByteArray &buf);
+ quint32 value();
+
+private:
+ quint32 checksum;
+};
+
+#endif //QUAADLER32_H
diff --git a/src/updater/quazip/quachecksum32.h b/src/updater/quazip/quachecksum32.h
new file mode 100644
index 0000000..40ff451
--- /dev/null
+++ b/src/updater/quazip/quachecksum32.h
@@ -0,0 +1,78 @@
+#ifndef QUACHECKSUM32_H
+#define QUACHECKSUM32_H
+
+/*
+Copyright (C) 2005-2014 Sergey A. Tachenov
+
+This file is part of QuaZIP.
+
+QuaZIP is free software: you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation, either version 2.1 of the License, or
+(at your option) any later version.
+
+QuaZIP is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with QuaZIP. If not, see .
+
+See COPYING file for the full LGPL text.
+
+Original ZIP package is copyrighted by Gilles Vollant and contributors,
+see quazip/(un)zip.h files for details. Basically it's the zlib license.
+*/
+
+#include
+#include "quazip_global.h"
+
+/// Checksum interface.
+/** \class QuaChecksum32 quachecksum32.h
+ * This is an interface for 32 bit checksums.
+ * Classes implementing this interface can calcunate a certin
+ * checksum in a single step:
+ * \code
+ * QChecksum32 *crc32 = new QuaCrc32();
+ * rasoult = crc32->calculate(data);
+ * \endcode
+ * or by streaming the data:
+ * \code
+ * QChecksum32 *crc32 = new QuaCrc32();
+ * while(!fileA.atEnd())
+ * crc32->update(fileA.read(bufSize));
+ * resoultA = crc32->value();
+ * crc32->reset();
+ * while(!fileB.atEnd())
+ * crc32->update(fileB.read(bufSize));
+ * resoultB = crc32->value();
+ * \endcode
+ */
+class QUAZIP_EXPORT QuaChecksum32
+{
+
+public:
+ ///Calculates the checksum for data.
+ /** \a data source data
+ * \return data checksum
+ *
+ * This function has no efect on the value returned by value().
+ */
+ virtual quint32 calculate(const QByteArray &data) = 0;
+
+ ///Resets the calculation on a checksun for a stream.
+ virtual void reset() = 0;
+
+ ///Updates the calculated checksum for the stream
+ /** \a buf next portion of data from the stream
+ */
+ virtual void update(const QByteArray &buf) = 0;
+
+ ///Value of the checksum calculated for the stream passed throw update().
+ /** \return checksum
+ */
+ virtual quint32 value() = 0;
+};
+
+#endif //QUACHECKSUM32_H
diff --git a/src/updater/quazip/quacrc32.cpp b/src/updater/quazip/quacrc32.cpp
new file mode 100644
index 0000000..2de5117
--- /dev/null
+++ b/src/updater/quazip/quacrc32.cpp
@@ -0,0 +1,52 @@
+/*
+Copyright (C) 2005-2014 Sergey A. Tachenov
+
+This file is part of QuaZIP.
+
+QuaZIP is free software: you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation, either version 2.1 of the License, or
+(at your option) any later version.
+
+QuaZIP is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with QuaZIP. If not, see .
+
+See COPYING file for the full LGPL text.
+
+Original ZIP package is copyrighted by Gilles Vollant and contributors,
+see quazip/(un)zip.h files for details. Basically it's the zlib license.
+*/
+
+#include "quacrc32.h"
+
+#include "zlib.h"
+
+QuaCrc32::QuaCrc32()
+{
+ reset();
+}
+
+quint32 QuaCrc32::calculate(const QByteArray &data)
+{
+ return crc32( crc32(0L, Z_NULL, 0), (const Bytef*)data.data(), data.size() );
+}
+
+void QuaCrc32::reset()
+{
+ checksum = crc32(0L, Z_NULL, 0);
+}
+
+void QuaCrc32::update(const QByteArray &buf)
+{
+ checksum = crc32( checksum, (const Bytef*)buf.data(), buf.size() );
+}
+
+quint32 QuaCrc32::value()
+{
+ return checksum;
+}
diff --git a/src/updater/quazip/quacrc32.h b/src/updater/quazip/quacrc32.h
new file mode 100644
index 0000000..af7703b
--- /dev/null
+++ b/src/updater/quazip/quacrc32.h
@@ -0,0 +1,50 @@
+#ifndef QUACRC32_H
+#define QUACRC32_H
+
+/*
+Copyright (C) 2005-2014 Sergey A. Tachenov
+
+This file is part of QuaZIP.
+
+QuaZIP is free software: you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation, either version 2.1 of the License, or
+(at your option) any later version.
+
+QuaZIP is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with QuaZIP. If not, see .
+
+See COPYING file for the full LGPL text.
+
+Original ZIP package is copyrighted by Gilles Vollant and contributors,
+see quazip/(un)zip.h files for details. Basically it's the zlib license.
+*/
+
+#include "quachecksum32.h"
+
+///CRC32 checksum
+/** \class QuaCrc32 quacrc32.h
+* This class wrappers the crc32 function with the QuaChecksum32 interface.
+* See QuaChecksum32 for more info.
+*/
+class QUAZIP_EXPORT QuaCrc32 : public QuaChecksum32 {
+
+public:
+ QuaCrc32();
+
+ quint32 calculate(const QByteArray &data);
+
+ void reset();
+ void update(const QByteArray &buf);
+ quint32 value();
+
+private:
+ quint32 checksum;
+};
+
+#endif //QUACRC32_H
diff --git a/src/updater/quazip/quagzipfile.cpp b/src/updater/quazip/quagzipfile.cpp
new file mode 100644
index 0000000..efc54c1
--- /dev/null
+++ b/src/updater/quazip/quagzipfile.cpp
@@ -0,0 +1,172 @@
+/*
+Copyright (C) 2005-2014 Sergey A. Tachenov
+
+This file is part of QuaZIP.
+
+QuaZIP is free software: you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation, either version 2.1 of the License, or
+(at your option) any later version.
+
+QuaZIP is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with QuaZIP. If not, see .
+
+See COPYING file for the full LGPL text.
+
+Original ZIP package is copyrighted by Gilles Vollant and contributors,
+see quazip/(un)zip.h files for details. Basically it's the zlib license.
+*/
+
+#include
+
+#include "quagzipfile.h"
+
+/// \cond internal
+class QuaGzipFilePrivate {
+ friend class QuaGzipFile;
+ QString fileName;
+ gzFile gzd;
+ inline QuaGzipFilePrivate(): gzd(NULL) {}
+ inline QuaGzipFilePrivate(const QString &fileName):
+ fileName(fileName), gzd(NULL) {}
+ template bool open(FileId id,
+ QIODevice::OpenMode mode, QString &error);
+ gzFile open(int fd, const char *modeString);
+ gzFile open(const QString &name, const char *modeString);
+};
+
+gzFile QuaGzipFilePrivate::open(const QString &name, const char *modeString)
+{
+ return gzopen(QFile::encodeName(name).constData(), modeString);
+}
+
+gzFile QuaGzipFilePrivate::open(int fd, const char *modeString)
+{
+ return gzdopen(fd, modeString);
+}
+
+template
+bool QuaGzipFilePrivate::open(FileId id, QIODevice::OpenMode mode,
+ QString &error)
+{
+ char modeString[2];
+ modeString[0] = modeString[1] = '\0';
+ if ((mode & QIODevice::Append) != 0) {
+ error = QuaGzipFile::trUtf8("QIODevice::Append is not "
+ "supported for GZIP");
+ return false;
+ }
+ if ((mode & QIODevice::ReadOnly) != 0
+ && (mode & QIODevice::WriteOnly) != 0) {
+ error = QuaGzipFile::trUtf8("Opening gzip for both reading"
+ " and writing is not supported");
+ return false;
+ } else if ((mode & QIODevice::ReadOnly) != 0) {
+ modeString[0] = 'r';
+ } else if ((mode & QIODevice::WriteOnly) != 0) {
+ modeString[0] = 'w';
+ } else {
+ error = QuaGzipFile::trUtf8("You can open a gzip either for reading"
+ " or for writing. Which is it?");
+ return false;
+ }
+ gzd = open(id, modeString);
+ if (gzd == NULL) {
+ error = QuaGzipFile::trUtf8("Could not gzopen() file");
+ return false;
+ }
+ return true;
+}
+/// \endcond
+
+QuaGzipFile::QuaGzipFile():
+d(new QuaGzipFilePrivate())
+{
+}
+
+QuaGzipFile::QuaGzipFile(QObject *parent):
+QIODevice(parent),
+d(new QuaGzipFilePrivate())
+{
+}
+
+QuaGzipFile::QuaGzipFile(const QString &fileName, QObject *parent):
+ QIODevice(parent),
+d(new QuaGzipFilePrivate(fileName))
+{
+}
+
+QuaGzipFile::~QuaGzipFile()
+{
+ if (isOpen()) {
+ close();
+ }
+ delete d;
+}
+
+void QuaGzipFile::setFileName(const QString& fileName)
+{
+ d->fileName = fileName;
+}
+
+QString QuaGzipFile::getFileName() const
+{
+ return d->fileName;
+}
+
+bool QuaGzipFile::isSequential() const
+{
+ return true;
+}
+
+bool QuaGzipFile::open(QIODevice::OpenMode mode)
+{
+ QString error;
+ if (!d->open(d->fileName, mode, error)) {
+ setErrorString(error);
+ return false;
+ }
+ return QIODevice::open(mode);
+}
+
+bool QuaGzipFile::open(int fd, QIODevice::OpenMode mode)
+{
+ QString error;
+ if (!d->open(fd, mode, error)) {
+ setErrorString(error);
+ return false;
+ }
+ return QIODevice::open(mode);
+}
+
+bool QuaGzipFile::flush()
+{
+ return gzflush(d->gzd, Z_SYNC_FLUSH) == Z_OK;
+}
+
+void QuaGzipFile::close()
+{
+ QIODevice::close();
+ gzclose(d->gzd);
+}
+
+qint64 QuaGzipFile::readData(char *data, qint64 maxSize)
+{
+ return gzread(d->gzd, (voidp)data, (unsigned)maxSize);
+}
+
+qint64 QuaGzipFile::writeData(const char *data, qint64 maxSize)
+{
+ if (maxSize == 0)
+ return 0;
+ int written = gzwrite(d->gzd, (voidp)data, (unsigned)maxSize);
+ if (written == 0)
+ return -1;
+ else
+ return written;
+}
diff --git a/src/updater/quazip/quagzipfile.h b/src/updater/quazip/quagzipfile.h
new file mode 100644
index 0000000..e2f9d97
--- /dev/null
+++ b/src/updater/quazip/quagzipfile.h
@@ -0,0 +1,108 @@
+#ifndef QUAZIP_QUAGZIPFILE_H
+#define QUAZIP_QUAGZIPFILE_H
+
+/*
+Copyright (C) 2005-2014 Sergey A. Tachenov
+
+This file is part of QuaZIP.
+
+QuaZIP is free software: you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation, either version 2.1 of the License, or
+(at your option) any later version.
+
+QuaZIP is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with QuaZIP. If not, see .
+
+See COPYING file for the full LGPL text.
+
+Original ZIP package is copyrighted by Gilles Vollant and contributors,
+see quazip/(un)zip.h files for details. Basically it's the zlib license.
+*/
+
+#include
+#include "quazip_global.h"
+
+#include
+
+class QuaGzipFilePrivate;
+
+/// GZIP file
+/**
+ This class is a wrapper around GZIP file access functions in zlib. Unlike QuaZip classes, it doesn't allow reading from a GZIP file opened as QIODevice, for example, if your GZIP file is in QBuffer. It only provides QIODevice access to a GZIP file contents, but the GZIP file itself must be identified by its name on disk or by descriptor id.
+ */
+class QUAZIP_EXPORT QuaGzipFile: public QIODevice {
+ Q_OBJECT
+public:
+ /// Empty constructor.
+ /**
+ Must call setFileName() before trying to open.
+ */
+ QuaGzipFile();
+ /// Empty constructor with a parent.
+ /**
+ Must call setFileName() before trying to open.
+ \param parent The parent object, as per QObject logic.
+ */
+ QuaGzipFile(QObject *parent);
+ /// Constructor.
+ /**
+ \param fileName The name of the GZIP file.
+ \param parent The parent object, as per QObject logic.
+ */
+ QuaGzipFile(const QString &fileName, QObject *parent = NULL);
+ /// Destructor.
+ virtual ~QuaGzipFile();
+ /// Sets the name of the GZIP file to be opened.
+ void setFileName(const QString& fileName);
+ /// Returns the name of the GZIP file.
+ QString getFileName() const;
+ /// Returns true.
+ /**
+ Strictly speaking, zlib supports seeking for GZIP files, but it is
+ poorly implemented, because there is no way to implement it
+ properly. For reading, seeking backwards is very slow, and for
+ writing, it is downright impossible. Therefore, QuaGzipFile does not
+ support seeking at all.
+ */
+ virtual bool isSequential() const;
+ /// Opens the file.
+ /**
+ \param mode Can be either QIODevice::Write or QIODevice::Read.
+ ReadWrite and Append aren't supported.
+ */
+ virtual bool open(QIODevice::OpenMode mode);
+ /// Opens the file.
+ /**
+ \overload
+ \param fd The file descriptor to read/write the GZIP file from/to.
+ \param mode Can be either QIODevice::Write or QIODevice::Read.
+ ReadWrite and Append aren't supported.
+ */
+ virtual bool open(int fd, QIODevice::OpenMode mode);
+ /// Flushes data to file.
+ /**
+ The data is written using Z_SYNC_FLUSH mode. Doesn't make any sense
+ when reading.
+ */
+ virtual bool flush();
+ /// Closes the file.
+ virtual void close();
+protected:
+ /// Implementation of QIODevice::readData().
+ virtual qint64 readData(char *data, qint64 maxSize);
+ /// Implementation of QIODevice::writeData().
+ virtual qint64 writeData(const char *data, qint64 maxSize);
+private:
+ // not implemented by design to disable copy
+ QuaGzipFile(const QuaGzipFile &that);
+ QuaGzipFile& operator=(const QuaGzipFile &that);
+ QuaGzipFilePrivate *d;
+};
+
+#endif // QUAZIP_QUAGZIPFILE_H
diff --git a/src/updater/quazip/quaziodevice.cpp b/src/updater/quazip/quaziodevice.cpp
new file mode 100644
index 0000000..04f34bf
--- /dev/null
+++ b/src/updater/quazip/quaziodevice.cpp
@@ -0,0 +1,339 @@
+/*
+Copyright (C) 2005-2014 Sergey A. Tachenov
+
+This file is part of QuaZIP.
+
+QuaZIP is free software: you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation, either version 2.1 of the License, or
+(at your option) any later version.
+
+QuaZIP is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with QuaZIP. If not, see .
+
+See COPYING file for the full LGPL text.
+
+Original ZIP package is copyrighted by Gilles Vollant and contributors,
+see quazip/(un)zip.h files for details. Basically it's the zlib license.
+*/
+
+#include "quaziodevice.h"
+
+#define QUAZIO_INBUFSIZE 4096
+#define QUAZIO_OUTBUFSIZE 4096
+
+/// \cond internal
+class QuaZIODevicePrivate {
+ friend class QuaZIODevice;
+ QuaZIODevicePrivate(QIODevice *io);
+ ~QuaZIODevicePrivate();
+ QIODevice *io;
+ z_stream zins;
+ z_stream zouts;
+ char *inBuf;
+ int inBufPos;
+ int inBufSize;
+ char *outBuf;
+ int outBufPos;
+ int outBufSize;
+ bool zBufError;
+ bool atEnd;
+ int doFlush(QString &error);
+};
+
+QuaZIODevicePrivate::QuaZIODevicePrivate(QIODevice *io):
+ io(io),
+ inBuf(NULL),
+ inBufPos(0),
+ inBufSize(0),
+ outBuf(NULL),
+ outBufPos(0),
+ outBufSize(0),
+ zBufError(false),
+ atEnd(false)
+{
+ zins.zalloc = (alloc_func) NULL;
+ zins.zfree = (free_func) NULL;
+ zins.opaque = NULL;
+ zouts.zalloc = (alloc_func) NULL;
+ zouts.zfree = (free_func) NULL;
+ zouts.opaque = NULL;
+ inBuf = new char[QUAZIO_INBUFSIZE];
+ outBuf = new char[QUAZIO_OUTBUFSIZE];
+#ifdef QUAZIP_ZIODEVICE_DEBUG_OUTPUT
+ debug.setFileName("debug.out");
+ debug.open(QIODevice::WriteOnly);
+#endif
+#ifdef QUAZIP_ZIODEVICE_DEBUG_INPUT
+ indebug.setFileName("debug.in");
+ indebug.open(QIODevice::WriteOnly);
+#endif
+}
+
+QuaZIODevicePrivate::~QuaZIODevicePrivate()
+{
+#ifdef QUAZIP_ZIODEVICE_DEBUG_OUTPUT
+ debug.close();
+#endif
+#ifdef QUAZIP_ZIODEVICE_DEBUG_INPUT
+ indebug.close();
+#endif
+ if (inBuf != NULL)
+ delete[] inBuf;
+ if (outBuf != NULL)
+ delete[] outBuf;
+}
+
+int QuaZIODevicePrivate::doFlush(QString &error)
+{
+ int flushed = 0;
+ while (outBufPos < outBufSize) {
+ int more = io->write(outBuf + outBufPos, outBufSize - outBufPos);
+ if (more == -1) {
+ error = io->errorString();
+ return -1;
+ }
+ if (more == 0)
+ break;
+ outBufPos += more;
+ flushed += more;
+ }
+ if (outBufPos == outBufSize) {
+ outBufPos = outBufSize = 0;
+ }
+ return flushed;
+}
+
+/// \endcond
+
+// #define QUAZIP_ZIODEVICE_DEBUG_OUTPUT
+// #define QUAZIP_ZIODEVICE_DEBUG_INPUT
+#ifdef QUAZIP_ZIODEVICE_DEBUG_OUTPUT
+#include
+static QFile debug;
+#endif
+#ifdef QUAZIP_ZIODEVICE_DEBUG_INPUT
+#include
+static QFile indebug;
+#endif
+
+QuaZIODevice::QuaZIODevice(QIODevice *io, QObject *parent):
+ QIODevice(parent),
+ d(new QuaZIODevicePrivate(io))
+{
+ connect(io, SIGNAL(readyRead()), SIGNAL(readyRead()));
+}
+
+QuaZIODevice::~QuaZIODevice()
+{
+ if (isOpen())
+ close();
+ delete d;
+}
+
+QIODevice *QuaZIODevice::getIoDevice() const
+{
+ return d->io;
+}
+
+bool QuaZIODevice::open(QIODevice::OpenMode mode)
+{
+ if ((mode & QIODevice::Append) != 0) {
+ setErrorString(trUtf8("QIODevice::Append is not supported for"
+ " QuaZIODevice"));
+ return false;
+ }
+ if ((mode & QIODevice::ReadWrite) == QIODevice::ReadWrite) {
+ setErrorString(trUtf8("QIODevice::ReadWrite is not supported for"
+ " QuaZIODevice"));
+ return false;
+ }
+ if ((mode & QIODevice::ReadOnly) != 0) {
+ if (inflateInit(&d->zins) != Z_OK) {
+ setErrorString(d->zins.msg);
+ return false;
+ }
+ }
+ if ((mode & QIODevice::WriteOnly) != 0) {
+ if (deflateInit(&d->zouts, Z_DEFAULT_COMPRESSION) != Z_OK) {
+ setErrorString(d->zouts.msg);
+ return false;
+ }
+ }
+ return QIODevice::open(mode);
+}
+
+void QuaZIODevice::close()
+{
+ if ((openMode() & QIODevice::ReadOnly) != 0) {
+ if (inflateEnd(&d->zins) != Z_OK) {
+ setErrorString(d->zins.msg);
+ }
+ }
+ if ((openMode() & QIODevice::WriteOnly) != 0) {
+ flush();
+ if (deflateEnd(&d->zouts) != Z_OK) {
+ setErrorString(d->zouts.msg);
+ }
+ }
+ QIODevice::close();
+}
+
+qint64 QuaZIODevice::readData(char *data, qint64 maxSize)
+{
+ int read = 0;
+ while (read < maxSize) {
+ if (d->inBufPos == d->inBufSize) {
+ d->inBufPos = 0;
+ d->inBufSize = d->io->read(d->inBuf, QUAZIO_INBUFSIZE);
+ if (d->inBufSize == -1) {
+ d->inBufSize = 0;
+ setErrorString(d->io->errorString());
+ return -1;
+ }
+ if (d->inBufSize == 0)
+ break;
+ }
+ while (read < maxSize && d->inBufPos < d->inBufSize) {
+ d->zins.next_in = (Bytef *) (d->inBuf + d->inBufPos);
+ d->zins.avail_in = d->inBufSize - d->inBufPos;
+ d->zins.next_out = (Bytef *) (data + read);
+ d->zins.avail_out = (uInt) (maxSize - read); // hope it's less than 2GB
+ int more = 0;
+ switch (inflate(&d->zins, Z_SYNC_FLUSH)) {
+ case Z_OK:
+ read = (char *) d->zins.next_out - data;
+ d->inBufPos = (char *) d->zins.next_in - d->inBuf;
+ break;
+ case Z_STREAM_END:
+ read = (char *) d->zins.next_out - data;
+ d->inBufPos = (char *) d->zins.next_in - d->inBuf;
+ d->atEnd = true;
+ return read;
+ case Z_BUF_ERROR: // this should never happen, but just in case
+ if (!d->zBufError) {
+ qWarning("Z_BUF_ERROR detected with %d/%d in/out, weird",
+ d->zins.avail_in, d->zins.avail_out);
+ d->zBufError = true;
+ }
+ memmove(d->inBuf, d->inBuf + d->inBufPos, d->inBufSize - d->inBufPos);
+ d->inBufSize -= d->inBufPos;
+ d->inBufPos = 0;
+ more = d->io->read(d->inBuf + d->inBufSize, QUAZIO_INBUFSIZE - d->inBufSize);
+ if (more == -1) {
+ setErrorString(d->io->errorString());
+ return -1;
+ }
+ if (more == 0)
+ return read;
+ d->inBufSize += more;
+ break;
+ default:
+ setErrorString(QString::fromLocal8Bit(d->zins.msg));
+ return -1;
+ }
+ }
+ }
+#ifdef QUAZIP_ZIODEVICE_DEBUG_INPUT
+ indebug.write(data, read);
+#endif
+ return read;
+}
+
+qint64 QuaZIODevice::writeData(const char *data, qint64 maxSize)
+{
+ int written = 0;
+ QString error;
+ if (d->doFlush(error) == -1) {
+ setErrorString(error);
+ return -1;
+ }
+ while (written < maxSize) {
+ // there is some data waiting in the output buffer
+ if (d->outBufPos < d->outBufSize)
+ return written;
+ d->zouts.next_in = (Bytef *) (data + written);
+ d->zouts.avail_in = (uInt) (maxSize - written); // hope it's less than 2GB
+ d->zouts.next_out = (Bytef *) d->outBuf;
+ d->zouts.avail_out = QUAZIO_OUTBUFSIZE;
+ switch (deflate(&d->zouts, Z_NO_FLUSH)) {
+ case Z_OK:
+ written = (char *) d->zouts.next_in - data;
+ d->outBufSize = (char *) d->zouts.next_out - d->outBuf;
+ break;
+ default:
+ setErrorString(QString::fromLocal8Bit(d->zouts.msg));
+ return -1;
+ }
+ if (d->doFlush(error) == -1) {
+ setErrorString(error);
+ return -1;
+ }
+ }
+#ifdef QUAZIP_ZIODEVICE_DEBUG_OUTPUT
+ debug.write(data, written);
+#endif
+ return written;
+}
+
+bool QuaZIODevice::flush()
+{
+ QString error;
+ if (d->doFlush(error) < 0) {
+ setErrorString(error);
+ return false;
+ }
+ // can't flush buffer, some data is still waiting
+ if (d->outBufPos < d->outBufSize)
+ return true;
+ Bytef c = 0;
+ d->zouts.next_in = &c; // fake input buffer
+ d->zouts.avail_in = 0; // of zero size
+ do {
+ d->zouts.next_out = (Bytef *) d->outBuf;
+ d->zouts.avail_out = QUAZIO_OUTBUFSIZE;
+ switch (deflate(&d->zouts, Z_SYNC_FLUSH)) {
+ case Z_OK:
+ d->outBufSize = (char *) d->zouts.next_out - d->outBuf;
+ if (d->doFlush(error) < 0) {
+ setErrorString(error);
+ return false;
+ }
+ if (d->outBufPos < d->outBufSize)
+ return true;
+ break;
+ case Z_BUF_ERROR: // nothing to write?
+ return true;
+ default:
+ setErrorString(QString::fromLocal8Bit(d->zouts.msg));
+ return false;
+ }
+ } while (d->zouts.avail_out == 0);
+ return true;
+}
+
+bool QuaZIODevice::isSequential() const
+{
+ return true;
+}
+
+bool QuaZIODevice::atEnd() const
+{
+ // Here we MUST check QIODevice::bytesAvailable() because WE
+ // might have reached the end, but QIODevice didn't--
+ // it could have simply pre-buffered all remaining data.
+ return (openMode() == NotOpen) || (QIODevice::bytesAvailable() == 0 && d->atEnd);
+}
+
+qint64 QuaZIODevice::bytesAvailable() const
+{
+ // If we haven't recevied Z_STREAM_END, it means that
+ // we have at least one more input byte available.
+ // Plus whatever QIODevice has buffered.
+ return (d->atEnd ? 0 : 1) + QIODevice::bytesAvailable();
+}
diff --git a/src/updater/quazip/quaziodevice.h b/src/updater/quazip/quaziodevice.h
new file mode 100644
index 0000000..63499c3
--- /dev/null
+++ b/src/updater/quazip/quaziodevice.h
@@ -0,0 +1,102 @@
+#ifndef QUAZIP_QUAZIODEVICE_H
+#define QUAZIP_QUAZIODEVICE_H
+
+/*
+Copyright (C) 2005-2014 Sergey A. Tachenov
+
+This file is part of QuaZIP.
+
+QuaZIP is free software: you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation, either version 2.1 of the License, or
+(at your option) any later version.
+
+QuaZIP is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with QuaZIP. If not, see .
+
+See COPYING file for the full LGPL text.
+
+Original ZIP package is copyrighted by Gilles Vollant and contributors,
+see quazip/(un)zip.h files for details. Basically it's the zlib license.
+*/
+
+#include
+#include "quazip_global.h"
+
+#include
+
+class QuaZIODevicePrivate;
+
+/// A class to compress/decompress QIODevice.
+/**
+ This class can be used to compress any data written to QIODevice or
+ decompress it back. Compressing data sent over a QTcpSocket is a good
+ example.
+ */
+class QUAZIP_EXPORT QuaZIODevice: public QIODevice {
+ Q_OBJECT
+public:
+ /// Constructor.
+ /**
+ \param io The QIODevice to read/write.
+ \param parent The parent object, as per QObject logic.
+ */
+ QuaZIODevice(QIODevice *io, QObject *parent = NULL);
+ /// Destructor.
+ ~QuaZIODevice();
+ /// Flushes data waiting to be written.
+ /**
+ Unfortunately, as QIODevice doesn't support flush() by itself, the
+ only thing this method does is write the compressed data into the
+ device using Z_SYNC_FLUSH mode. If you need the compressed data to
+ actually be flushed from the buffer of the underlying QIODevice, you
+ need to call its flush() method as well, providing it supports it
+ (like QTcpSocket does). Example:
+ \code
+ QuaZIODevice dev(&sock);
+ dev.open(QIODevice::Write);
+ dev.write(yourDataGoesHere);
+ dev.flush();
+ sock->flush(); // this actually sends data to network
+ \endcode
+
+ This may change in the future versions of QuaZIP by implementing an
+ ugly hack: trying to cast the QIODevice using qobject_cast to known
+ flush()-supporting subclasses, and calling flush if the resulting
+ pointer is not zero.
+ */
+ virtual bool flush();
+ /// Opens the device.
+ /**
+ \param mode Neither QIODevice::ReadWrite nor QIODevice::Append are
+ not supported.
+ */
+ virtual bool open(QIODevice::OpenMode mode);
+ /// Closes this device, but not the underlying one.
+ /**
+ The underlying QIODevice is not closed in case you want to write
+ something else to it.
+ */
+ virtual void close();
+ /// Returns the underlying device.
+ QIODevice *getIoDevice() const;
+ /// Returns true.
+ virtual bool isSequential() const;
+ /// Returns true iff the end of the compressed stream is reached.
+ virtual bool atEnd() const;
+ /// Returns the number of the bytes buffered.
+ virtual qint64 bytesAvailable() const;
+protected:
+ /// Implementation of QIODevice::readData().
+ virtual qint64 readData(char *data, qint64 maxSize);
+ /// Implementation of QIODevice::writeData().
+ virtual qint64 writeData(const char *data, qint64 maxSize);
+private:
+ QuaZIODevicePrivate *d;
+};
+#endif // QUAZIP_QUAZIODEVICE_H
diff --git a/src/updater/quazip/quazip.cpp b/src/updater/quazip/quazip.cpp
new file mode 100644
index 0000000..a5bc44e
--- /dev/null
+++ b/src/updater/quazip/quazip.cpp
@@ -0,0 +1,795 @@
+/*
+Copyright (C) 2005-2014 Sergey A. Tachenov
+
+This file is part of QuaZIP.
+
+QuaZIP is free software: you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation, either version 2.1 of the License, or
+(at your option) any later version.
+
+QuaZIP is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with QuaZIP. If not, see .
+
+See COPYING file for the full LGPL text.
+
+Original ZIP package is copyrighted by Gilles Vollant, see
+quazip/(un)zip.h files for details, basically it's zlib license.
+ **/
+
+#include
+#include
+#include
+
+#include "quazip.h"
+
+/// All the internal stuff for the QuaZip class.
+/**
+ \internal
+
+ This class keeps all the private stuff for the QuaZip class so it can
+ be changed without breaking binary compatibility, according to the
+ Pimpl idiom.
+ */
+class QuaZipPrivate {
+ friend class QuaZip;
+ private:
+ Q_DISABLE_COPY(QuaZipPrivate)
+ /// The pointer to the corresponding QuaZip instance.
+ QuaZip *q;
+ /// The codec for file names.
+ QTextCodec *fileNameCodec;
+ /// The codec for comments.
+ QTextCodec *commentCodec;
+ /// The archive file name.
+ QString zipName;
+ /// The device to access the archive.
+ QIODevice *ioDevice;
+ /// The global comment.
+ QString comment;
+ /// The open mode.
+ QuaZip::Mode mode;
+ union {
+ /// The internal handle for UNZIP modes.
+ unzFile unzFile_f;
+ /// The internal handle for ZIP modes.
+ zipFile zipFile_f;
+ };
+ /// Whether a current file is set.
+ bool hasCurrentFile_f;
+ /// The last error.
+ int zipError;
+ /// Whether \ref QuaZip::setDataDescriptorWritingEnabled() "the data descriptor writing mode" is enabled.
+ bool dataDescriptorWritingEnabled;
+ /// The zip64 mode.
+ bool zip64;
+ /// The auto-close flag.
+ bool autoClose;
+ inline QTextCodec *getDefaultFileNameCodec()
+ {
+ if (defaultFileNameCodec == NULL) {
+ return QTextCodec::codecForLocale();
+ } else {
+ return defaultFileNameCodec;
+ }
+ }
+ /// The constructor for the corresponding QuaZip constructor.
+ inline QuaZipPrivate(QuaZip *q):
+ q(q),
+ fileNameCodec(getDefaultFileNameCodec()),
+ commentCodec(QTextCodec::codecForLocale()),
+ ioDevice(NULL),
+ mode(QuaZip::mdNotOpen),
+ hasCurrentFile_f(false),
+ zipError(UNZ_OK),
+ dataDescriptorWritingEnabled(true),
+ zip64(false),
+ autoClose(true)
+ {
+ unzFile_f = NULL;
+ zipFile_f = NULL;
+ lastMappedDirectoryEntry.num_of_file = 0;
+ lastMappedDirectoryEntry.pos_in_zip_directory = 0;
+ }
+ /// The constructor for the corresponding QuaZip constructor.
+ inline QuaZipPrivate(QuaZip *q, const QString &zipName):
+ q(q),
+ fileNameCodec(getDefaultFileNameCodec()),
+ commentCodec(QTextCodec::codecForLocale()),
+ zipName(zipName),
+ ioDevice(NULL),
+ mode(QuaZip::mdNotOpen),
+ hasCurrentFile_f(false),
+ zipError(UNZ_OK),
+ dataDescriptorWritingEnabled(true),
+ zip64(false),
+ autoClose(true)
+ {
+ unzFile_f = NULL;
+ zipFile_f = NULL;
+ lastMappedDirectoryEntry.num_of_file = 0;
+ lastMappedDirectoryEntry.pos_in_zip_directory = 0;
+ }
+ /// The constructor for the corresponding QuaZip constructor.
+ inline QuaZipPrivate(QuaZip *q, QIODevice *ioDevice):
+ q(q),
+ fileNameCodec(getDefaultFileNameCodec()),
+ commentCodec(QTextCodec::codecForLocale()),
+ ioDevice(ioDevice),
+ mode(QuaZip::mdNotOpen),
+ hasCurrentFile_f(false),
+ zipError(UNZ_OK),
+ dataDescriptorWritingEnabled(true),
+ zip64(false),
+ autoClose(true)
+ {
+ unzFile_f = NULL;
+ zipFile_f = NULL;
+ lastMappedDirectoryEntry.num_of_file = 0;
+ lastMappedDirectoryEntry.pos_in_zip_directory = 0;
+ }
+ /// Returns either a list of file names or a list of QuaZipFileInfo.
+ template
+ bool getFileInfoList(QList *result) const;
+
+ /// Stores map of filenames and file locations for unzipping
+ inline void clearDirectoryMap();
+ inline void addCurrentFileToDirectoryMap(const QString &fileName);
+ bool goToFirstUnmappedFile();
+ QHash directoryCaseSensitive;
+ QHash directoryCaseInsensitive;
+ unz64_file_pos lastMappedDirectoryEntry;
+ static QTextCodec *defaultFileNameCodec;
+};
+
+QTextCodec *QuaZipPrivate::defaultFileNameCodec = NULL;
+
+void QuaZipPrivate::clearDirectoryMap()
+{
+ directoryCaseInsensitive.clear();
+ directoryCaseSensitive.clear();
+ lastMappedDirectoryEntry.num_of_file = 0;
+ lastMappedDirectoryEntry.pos_in_zip_directory = 0;
+}
+
+void QuaZipPrivate::addCurrentFileToDirectoryMap(const QString &fileName)
+{
+ if (!hasCurrentFile_f || fileName.isEmpty()) {
+ return;
+ }
+ // Adds current file to filename map as fileName
+ unz64_file_pos fileDirectoryPos;
+ unzGetFilePos64(unzFile_f, &fileDirectoryPos);
+ directoryCaseSensitive.insert(fileName, fileDirectoryPos);
+ // Only add lowercase to directory map if not already there
+ // ensures only map the first one seen
+ QString lower = fileName.toLower();
+ if (!directoryCaseInsensitive.contains(lower))
+ directoryCaseInsensitive.insert(lower, fileDirectoryPos);
+ // Mark last one
+ if (fileDirectoryPos.pos_in_zip_directory > lastMappedDirectoryEntry.pos_in_zip_directory)
+ lastMappedDirectoryEntry = fileDirectoryPos;
+}
+
+bool QuaZipPrivate::goToFirstUnmappedFile()
+{
+ zipError = UNZ_OK;
+ if (mode != QuaZip::mdUnzip) {
+ qWarning("QuaZipPrivate::goToNextUnmappedFile(): ZIP is not open in mdUnzip mode");
+ return false;
+ }
+ // If not mapped anything, go to beginning
+ if (lastMappedDirectoryEntry.pos_in_zip_directory == 0) {
+ unzGoToFirstFile(unzFile_f);
+ } else {
+ // Goto the last one mapped, plus one
+ unzGoToFilePos64(unzFile_f, &lastMappedDirectoryEntry);
+ unzGoToNextFile(unzFile_f);
+ }
+ hasCurrentFile_f=zipError==UNZ_OK;
+ if(zipError==UNZ_END_OF_LIST_OF_FILE)
+ zipError=UNZ_OK;
+ return hasCurrentFile_f;
+}
+
+QuaZip::QuaZip():
+ p(new QuaZipPrivate(this))
+{
+}
+
+QuaZip::QuaZip(const QString& zipName):
+ p(new QuaZipPrivate(this, zipName))
+{
+}
+
+QuaZip::QuaZip(QIODevice *ioDevice):
+ p(new QuaZipPrivate(this, ioDevice))
+{
+}
+
+QuaZip::~QuaZip()
+{
+ if(isOpen())
+ close();
+ delete p;
+}
+
+bool QuaZip::open(Mode mode, zlib_filefunc_def* ioApi)
+{
+ p->zipError=UNZ_OK;
+ if(isOpen()) {
+ qWarning("QuaZip::open(): ZIP already opened");
+ return false;
+ }
+ QIODevice *ioDevice = p->ioDevice;
+ if (ioDevice == NULL) {
+ if (p->zipName.isEmpty()) {
+ qWarning("QuaZip::open(): set either ZIP file name or IO device first");
+ return false;
+ } else {
+ ioDevice = new QFile(p->zipName);
+ }
+ }
+ unsigned flags = 0;
+ switch(mode) {
+ case mdUnzip:
+ if (ioApi == NULL) {
+ if (p->autoClose)
+ flags |= UNZ_AUTO_CLOSE;
+ p->unzFile_f=unzOpenInternal(ioDevice, NULL, 1, flags);
+ } else {
+ // QuaZIP pre-zip64 compatibility mode
+ p->unzFile_f=unzOpen2(ioDevice, ioApi);
+ if (p->unzFile_f != NULL) {
+ if (p->autoClose) {
+ unzSetFlags(p->unzFile_f, UNZ_AUTO_CLOSE);
+ } else {
+ unzClearFlags(p->unzFile_f, UNZ_AUTO_CLOSE);
+ }
+ }
+ }
+ if(p->unzFile_f!=NULL) {
+ if (ioDevice->isSequential()) {
+ unzClose(p->unzFile_f);
+ if (!p->zipName.isEmpty())
+ delete ioDevice;
+ qWarning("QuaZip::open(): "
+ "only mdCreate can be used with "
+ "sequential devices");
+ return false;
+ }
+ p->mode=mode;
+ p->ioDevice = ioDevice;
+ return true;
+ } else {
+ p->zipError=UNZ_OPENERROR;
+ if (!p->zipName.isEmpty())
+ delete ioDevice;
+ return false;
+ }
+ case mdCreate:
+ case mdAppend:
+ case mdAdd:
+ if (ioApi == NULL) {
+ if (p->autoClose)
+ flags |= ZIP_AUTO_CLOSE;
+ if (p->dataDescriptorWritingEnabled)
+ flags |= ZIP_WRITE_DATA_DESCRIPTOR;
+ p->zipFile_f=zipOpen3(ioDevice,
+ mode==mdCreate?APPEND_STATUS_CREATE:
+ mode==mdAppend?APPEND_STATUS_CREATEAFTER:
+ APPEND_STATUS_ADDINZIP,
+ NULL, NULL, flags);
+ } else {
+ // QuaZIP pre-zip64 compatibility mode
+ p->zipFile_f=zipOpen2(ioDevice,
+ mode==mdCreate?APPEND_STATUS_CREATE:
+ mode==mdAppend?APPEND_STATUS_CREATEAFTER:
+ APPEND_STATUS_ADDINZIP,
+ NULL,
+ ioApi);
+ if (p->zipFile_f != NULL) {
+ zipSetFlags(p->zipFile_f, flags);
+ }
+ }
+ if(p->zipFile_f!=NULL) {
+ if (ioDevice->isSequential()) {
+ if (mode != mdCreate) {
+ zipClose(p->zipFile_f, NULL);
+ qWarning("QuaZip::open(): "
+ "only mdCreate can be used with "
+ "sequential devices");
+ if (!p->zipName.isEmpty())
+ delete ioDevice;
+ return false;
+ }
+ zipSetFlags(p->zipFile_f, ZIP_SEQUENTIAL);
+ }
+ p->mode=mode;
+ p->ioDevice = ioDevice;
+ return true;
+ } else {
+ p->zipError=UNZ_OPENERROR;
+ if (!p->zipName.isEmpty())
+ delete ioDevice;
+ return false;
+ }
+ default:
+ qWarning("QuaZip::open(): unknown mode: %d", (int)mode);
+ if (!p->zipName.isEmpty())
+ delete ioDevice;
+ return false;
+ break;
+ }
+}
+
+void QuaZip::close()
+{
+ p->zipError=UNZ_OK;
+ switch(p->mode) {
+ case mdNotOpen:
+ qWarning("QuaZip::close(): ZIP is not open");
+ return;
+ case mdUnzip:
+ p->zipError=unzClose(p->unzFile_f);
+ break;
+ case mdCreate:
+ case mdAppend:
+ case mdAdd:
+ p->zipError=zipClose(p->zipFile_f,
+ p->comment.isNull() ? NULL
+ : p->commentCodec->fromUnicode(p->comment).constData());
+ break;
+ default:
+ qWarning("QuaZip::close(): unknown mode: %d", (int)p->mode);
+ return;
+ }
+ // opened by name, need to delete the internal IO device
+ if (!p->zipName.isEmpty()) {
+ delete p->ioDevice;
+ p->ioDevice = NULL;
+ }
+ p->clearDirectoryMap();
+ if(p->zipError==UNZ_OK)
+ p->mode=mdNotOpen;
+}
+
+void QuaZip::setZipName(const QString& zipName)
+{
+ if(isOpen()) {
+ qWarning("QuaZip::setZipName(): ZIP is already open!");
+ return;
+ }
+ p->zipName=zipName;
+ p->ioDevice = NULL;
+}
+
+void QuaZip::setIoDevice(QIODevice *ioDevice)
+{
+ if(isOpen()) {
+ qWarning("QuaZip::setIoDevice(): ZIP is already open!");
+ return;
+ }
+ p->ioDevice = ioDevice;
+ p->zipName = QString();
+}
+
+int QuaZip::getEntriesCount()const
+{
+ QuaZip *fakeThis=(QuaZip*)this; // non-const
+ fakeThis->p->zipError=UNZ_OK;
+ if(p->mode!=mdUnzip) {
+ qWarning("QuaZip::getEntriesCount(): ZIP is not open in mdUnzip mode");
+ return -1;
+ }
+ unz_global_info64 globalInfo;
+ if((fakeThis->p->zipError=unzGetGlobalInfo64(p->unzFile_f, &globalInfo))!=UNZ_OK)
+ return p->zipError;
+ return (int)globalInfo.number_entry;
+}
+
+QString QuaZip::getComment()const
+{
+ QuaZip *fakeThis=(QuaZip*)this; // non-const
+ fakeThis->p->zipError=UNZ_OK;
+ if(p->mode!=mdUnzip) {
+ qWarning("QuaZip::getComment(): ZIP is not open in mdUnzip mode");
+ return QString();
+ }
+ unz_global_info64 globalInfo;
+ QByteArray comment;
+ if((fakeThis->p->zipError=unzGetGlobalInfo64(p->unzFile_f, &globalInfo))!=UNZ_OK)
+ return QString();
+ comment.resize(globalInfo.size_comment);
+ if((fakeThis->p->zipError=unzGetGlobalComment(p->unzFile_f, comment.data(), comment.size())) < 0)
+ return QString();
+ fakeThis->p->zipError = UNZ_OK;
+ return p->commentCodec->toUnicode(comment);
+}
+
+bool QuaZip::setCurrentFile(const QString& fileName, CaseSensitivity cs)
+{
+ p->zipError=UNZ_OK;
+ if(p->mode!=mdUnzip) {
+ qWarning("QuaZip::setCurrentFile(): ZIP is not open in mdUnzip mode");
+ return false;
+ }
+ if(fileName.isEmpty()) {
+ p->hasCurrentFile_f=false;
+ return true;
+ }
+ // Unicode-aware reimplementation of the unzLocateFile function
+ if(p->unzFile_f==NULL) {
+ p->zipError=UNZ_PARAMERROR;
+ return false;
+ }
+ if(fileName.length()>MAX_FILE_NAME_LENGTH) {
+ p->zipError=UNZ_PARAMERROR;
+ return false;
+ }
+ // Find the file by name
+ bool sens = convertCaseSensitivity(cs) == Qt::CaseSensitive;
+ QString lower, current;
+ if(!sens) lower=fileName.toLower();
+ p->hasCurrentFile_f=false;
+
+ // Check the appropriate Map
+ unz64_file_pos fileDirPos;
+ fileDirPos.pos_in_zip_directory = 0;
+ if (sens) {
+ if (p->directoryCaseSensitive.contains(fileName))
+ fileDirPos = p->directoryCaseSensitive.value(fileName);
+ } else {
+ if (p->directoryCaseInsensitive.contains(lower))
+ fileDirPos = p->directoryCaseInsensitive.value(lower);
+ }
+
+ if (fileDirPos.pos_in_zip_directory != 0) {
+ p->zipError = unzGoToFilePos64(p->unzFile_f, &fileDirPos);
+ p->hasCurrentFile_f = p->zipError == UNZ_OK;
+ }
+
+ if (p->hasCurrentFile_f)
+ return p->hasCurrentFile_f;
+
+ // Not mapped yet, start from where we have got to so far
+ for(bool more=p->goToFirstUnmappedFile(); more; more=goToNextFile()) {
+ current=getCurrentFileName();
+ if(current.isEmpty()) return false;
+ if(sens) {
+ if(current==fileName) break;
+ } else {
+ if(current.toLower()==lower) break;
+ }
+ }
+ return p->hasCurrentFile_f;
+}
+
+bool QuaZip::goToFirstFile()
+{
+ p->zipError=UNZ_OK;
+ if(p->mode!=mdUnzip) {
+ qWarning("QuaZip::goToFirstFile(): ZIP is not open in mdUnzip mode");
+ return false;
+ }
+ p->zipError=unzGoToFirstFile(p->unzFile_f);
+ p->hasCurrentFile_f=p->zipError==UNZ_OK;
+ return p->hasCurrentFile_f;
+}
+
+bool QuaZip::goToNextFile()
+{
+ p->zipError=UNZ_OK;
+ if(p->mode!=mdUnzip) {
+ qWarning("QuaZip::goToFirstFile(): ZIP is not open in mdUnzip mode");
+ return false;
+ }
+ p->zipError=unzGoToNextFile(p->unzFile_f);
+ p->hasCurrentFile_f=p->zipError==UNZ_OK;
+ if(p->zipError==UNZ_END_OF_LIST_OF_FILE)
+ p->zipError=UNZ_OK;
+ return p->hasCurrentFile_f;
+}
+
+bool QuaZip::getCurrentFileInfo(QuaZipFileInfo *info)const
+{
+ QuaZipFileInfo64 info64;
+ if (info == NULL) { // Very unlikely because of the overloads
+ return false;
+ }
+ if (getCurrentFileInfo(&info64)) {
+ info64.toQuaZipFileInfo(*info);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool QuaZip::getCurrentFileInfo(QuaZipFileInfo64 *info)const
+{
+ QuaZip *fakeThis=(QuaZip*)this; // non-const
+ fakeThis->p->zipError=UNZ_OK;
+ if(p->mode!=mdUnzip) {
+ qWarning("QuaZip::getCurrentFileInfo(): ZIP is not open in mdUnzip mode");
+ return false;
+ }
+ unz_file_info64 info_z;
+ QByteArray fileName;
+ QByteArray extra;
+ QByteArray comment;
+ if(info==NULL) return false;
+ if(!isOpen()||!hasCurrentFile()) return false;
+ if((fakeThis->p->zipError=unzGetCurrentFileInfo64(p->unzFile_f, &info_z, NULL, 0, NULL, 0, NULL, 0))!=UNZ_OK)
+ return false;
+ fileName.resize(info_z.size_filename);
+ extra.resize(info_z.size_file_extra);
+ comment.resize(info_z.size_file_comment);
+ if((fakeThis->p->zipError=unzGetCurrentFileInfo64(p->unzFile_f, NULL,
+ fileName.data(), fileName.size(),
+ extra.data(), extra.size(),
+ comment.data(), comment.size()))!=UNZ_OK)
+ return false;
+ info->versionCreated=info_z.version;
+ info->versionNeeded=info_z.version_needed;
+ info->flags=info_z.flag;
+ info->method=info_z.compression_method;
+ info->crc=info_z.crc;
+ info->compressedSize=info_z.compressed_size;
+ info->uncompressedSize=info_z.uncompressed_size;
+ info->diskNumberStart=info_z.disk_num_start;
+ info->internalAttr=info_z.internal_fa;
+ info->externalAttr=info_z.external_fa;
+ info->name=p->fileNameCodec->toUnicode(fileName);
+ info->comment=p->commentCodec->toUnicode(comment);
+ info->extra=extra;
+ info->dateTime=QDateTime(
+ QDate(info_z.tmu_date.tm_year, info_z.tmu_date.tm_mon+1, info_z.tmu_date.tm_mday),
+ QTime(info_z.tmu_date.tm_hour, info_z.tmu_date.tm_min, info_z.tmu_date.tm_sec));
+ // Add to directory map
+ p->addCurrentFileToDirectoryMap(info->name);
+ return true;
+}
+
+QString QuaZip::getCurrentFileName()const
+{
+ QuaZip *fakeThis=(QuaZip*)this; // non-const
+ fakeThis->p->zipError=UNZ_OK;
+ if(p->mode!=mdUnzip) {
+ qWarning("QuaZip::getCurrentFileName(): ZIP is not open in mdUnzip mode");
+ return QString();
+ }
+ if(!isOpen()||!hasCurrentFile()) return QString();
+ QByteArray fileName(MAX_FILE_NAME_LENGTH, 0);
+ if((fakeThis->p->zipError=unzGetCurrentFileInfo64(p->unzFile_f, NULL, fileName.data(), fileName.size(),
+ NULL, 0, NULL, 0))!=UNZ_OK)
+ return QString();
+ QString result = p->fileNameCodec->toUnicode(fileName.constData());
+ if (result.isEmpty())
+ return result;
+ // Add to directory map
+ p->addCurrentFileToDirectoryMap(result);
+ return result;
+}
+
+void QuaZip::setFileNameCodec(QTextCodec *fileNameCodec)
+{
+ p->fileNameCodec=fileNameCodec;
+}
+
+void QuaZip::setFileNameCodec(const char *fileNameCodecName)
+{
+ p->fileNameCodec=QTextCodec::codecForName(fileNameCodecName);
+}
+
+QTextCodec *QuaZip::getFileNameCodec()const
+{
+ return p->fileNameCodec;
+}
+
+void QuaZip::setCommentCodec(QTextCodec *commentCodec)
+{
+ p->commentCodec=commentCodec;
+}
+
+void QuaZip::setCommentCodec(const char *commentCodecName)
+{
+ p->commentCodec=QTextCodec::codecForName(commentCodecName);
+}
+
+QTextCodec *QuaZip::getCommentCodec()const
+{
+ return p->commentCodec;
+}
+
+QString QuaZip::getZipName() const
+{
+ return p->zipName;
+}
+
+QIODevice *QuaZip::getIoDevice() const
+{
+ if (!p->zipName.isEmpty()) // opened by name, using an internal QIODevice
+ return NULL;
+ return p->ioDevice;
+}
+
+QuaZip::Mode QuaZip::getMode()const
+{
+ return p->mode;
+}
+
+bool QuaZip::isOpen()const
+{
+ return p->mode!=mdNotOpen;
+}
+
+int QuaZip::getZipError() const
+{
+ return p->zipError;
+}
+
+void QuaZip::setComment(const QString& comment)
+{
+ p->comment=comment;
+}
+
+bool QuaZip::hasCurrentFile()const
+{
+ return p->hasCurrentFile_f;
+}
+
+unzFile QuaZip::getUnzFile()
+{
+ return p->unzFile_f;
+}
+
+zipFile QuaZip::getZipFile()
+{
+ return p->zipFile_f;
+}
+
+void QuaZip::setDataDescriptorWritingEnabled(bool enabled)
+{
+ p->dataDescriptorWritingEnabled = enabled;
+}
+
+bool QuaZip::isDataDescriptorWritingEnabled() const
+{
+ return p->dataDescriptorWritingEnabled;
+}
+
+template
+TFileInfo QuaZip_getFileInfo(QuaZip *zip, bool *ok);
+
+template<>
+QuaZipFileInfo QuaZip_getFileInfo(QuaZip *zip, bool *ok)
+{
+ QuaZipFileInfo info;
+ *ok = zip->getCurrentFileInfo(&info);
+ return info;
+}
+
+template<>
+QuaZipFileInfo64 QuaZip_getFileInfo(QuaZip *zip, bool *ok)
+{
+ QuaZipFileInfo64 info;
+ *ok = zip->getCurrentFileInfo(&info);
+ return info;
+}
+
+template<>
+QString QuaZip_getFileInfo(QuaZip *zip, bool *ok)
+{
+ QString name = zip->getCurrentFileName();
+ *ok = !name.isEmpty();
+ return name;
+}
+
+template
+bool QuaZipPrivate::getFileInfoList(QList *result) const
+{
+ QuaZipPrivate *fakeThis=const_cast(this);
+ fakeThis->zipError=UNZ_OK;
+ if (mode!=QuaZip::mdUnzip) {
+ qWarning("QuaZip::getFileNameList/getFileInfoList(): "
+ "ZIP is not open in mdUnzip mode");
+ return false;
+ }
+ QString currentFile;
+ if (q->hasCurrentFile()) {
+ currentFile = q->getCurrentFileName();
+ }
+ if (q->goToFirstFile()) {
+ do {
+ bool ok;
+ result->append(QuaZip_getFileInfo(q, &ok));
+ if (!ok)
+ return false;
+ } while (q->goToNextFile());
+ }
+ if (zipError != UNZ_OK)
+ return false;
+ if (currentFile.isEmpty()) {
+ if (!q->goToFirstFile())
+ return false;
+ } else {
+ if (!q->setCurrentFile(currentFile))
+ return false;
+ }
+ return true;
+}
+
+QStringList QuaZip::getFileNameList() const
+{
+ QStringList list;
+ if (p->getFileInfoList(&list))
+ return list;
+ else
+ return QStringList();
+}
+
+QList QuaZip::getFileInfoList() const
+{
+ QList list;
+ if (p->getFileInfoList(&list))
+ return list;
+ else
+ return QList();
+}
+
+QList QuaZip::getFileInfoList64() const
+{
+ QList list;
+ if (p->getFileInfoList(&list))
+ return list;
+ else
+ return QList();
+}
+
+Qt::CaseSensitivity QuaZip::convertCaseSensitivity(QuaZip::CaseSensitivity cs)
+{
+ if (cs == csDefault) {
+#ifdef Q_OS_WIN
+ return Qt::CaseInsensitive;
+#else
+ return Qt::CaseSensitive;
+#endif
+ } else {
+ return cs == csSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive;
+ }
+}
+
+void QuaZip::setDefaultFileNameCodec(QTextCodec *codec)
+{
+ QuaZipPrivate::defaultFileNameCodec = codec;
+}
+
+void QuaZip::setDefaultFileNameCodec(const char *codecName)
+{
+ setDefaultFileNameCodec(QTextCodec::codecForName(codecName));
+}
+
+void QuaZip::setZip64Enabled(bool zip64)
+{
+ p->zip64 = zip64;
+}
+
+bool QuaZip::isZip64Enabled() const
+{
+ return p->zip64;
+}
+
+bool QuaZip::isAutoClose() const
+{
+ return p->autoClose;
+}
+
+void QuaZip::setAutoClose(bool autoClose) const
+{
+ p->autoClose = autoClose;
+}
diff --git a/src/updater/quazip/quazip.h b/src/updater/quazip/quazip.h
new file mode 100644
index 0000000..ae2c8f4
--- /dev/null
+++ b/src/updater/quazip/quazip.h
@@ -0,0 +1,571 @@
+#ifndef QUA_ZIP_H
+#define QUA_ZIP_H
+
+/*
+Copyright (C) 2005-2014 Sergey A. Tachenov
+
+This file is part of QuaZIP.
+
+QuaZIP is free software: you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation, either version 2.1 of the License, or
+(at your option) any later version.
+
+QuaZIP is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with QuaZIP. If not, see .
+
+See COPYING file for the full LGPL text.
+
+Original ZIP package is copyrighted by Gilles Vollant, see
+quazip/(un)zip.h files for details, basically it's zlib license.
+ **/
+
+#include
+#include
+#include
+
+#include "zip.h"
+#include "unzip.h"
+
+#include "quazip_global.h"
+#include "quazipfileinfo.h"
+
+// just in case it will be defined in the later versions of the ZIP/UNZIP
+#ifndef UNZ_OPENERROR
+// define additional error code
+#define UNZ_OPENERROR -1000
+#endif
+
+class QuaZipPrivate;
+
+/// ZIP archive.
+/** \class QuaZip quazip.h
+ * This class implements basic interface to the ZIP archive. It can be
+ * used to read table contents of the ZIP archive and retreiving
+ * information about the files inside it.
+ *
+ * You can also use this class to open files inside archive by passing
+ * pointer to the instance of this class to the constructor of the
+ * QuaZipFile class. But see QuaZipFile::QuaZipFile(QuaZip*, QObject*)
+ * for the possible pitfalls.
+ *
+ * This class is indended to provide interface to the ZIP subpackage of
+ * the ZIP/UNZIP package as well as to the UNZIP subpackage. But
+ * currently it supports only UNZIP.
+ *
+ * The use of this class is simple - just create instance using
+ * constructor, then set ZIP archive file name using setFile() function
+ * (if you did not passed the name to the constructor), then open() and
+ * then use different functions to work with it! Well, if you are
+ * paranoid, you may also wish to call close before destructing the
+ * instance, to check for errors on close.
+ *
+ * You may also use getUnzFile() and getZipFile() functions to get the
+ * ZIP archive handle and use it with ZIP/UNZIP package API directly.
+ *
+ * This class supports localized file names inside ZIP archive, but you
+ * have to set up proper codec with setCodec() function. By default,
+ * locale codec will be used, which is probably ok for UNIX systems, but
+ * will almost certainly fail with ZIP archives created in Windows. This
+ * is because Windows ZIP programs have strange habit of using DOS
+ * encoding for file names in ZIP archives. For example, ZIP archive
+ * with cyrillic names created in Windows will have file names in \c
+ * IBM866 encoding instead of \c WINDOWS-1251. I think that calling one
+ * function is not much trouble, but for true platform independency it
+ * would be nice to have some mechanism for file name encoding auto
+ * detection using locale information. Does anyone know a good way to do
+ * it?
+ **/
+class QUAZIP_EXPORT QuaZip {
+ friend class QuaZipPrivate;
+ public:
+ /// Useful constants.
+ enum Constants {
+ MAX_FILE_NAME_LENGTH=256 /**< Maximum file name length. Taken from
+ \c UNZ_MAXFILENAMEINZIP constant in
+ unzip.c. */
+ };
+ /// Open mode of the ZIP file.
+ enum Mode {
+ mdNotOpen, ///< ZIP file is not open. This is the initial mode.
+ mdUnzip, ///< ZIP file is open for reading files inside it.
+ mdCreate, ///< ZIP file was created with open() call.
+ mdAppend, /**< ZIP file was opened in append mode. This refers to
+ * \c APPEND_STATUS_CREATEAFTER mode in ZIP/UNZIP package
+ * and means that zip is appended to some existing file
+ * what is useful when that file contains
+ * self-extractor code. This is obviously \em not what
+ * you whant to use to add files to the existing ZIP
+ * archive.
+ **/
+ mdAdd ///< ZIP file was opened for adding files in the archive.
+ };
+ /// Case sensitivity for the file names.
+ /** This is what you specify when accessing files in the archive.
+ * Works perfectly fine with any characters thanks to Qt's great
+ * unicode support. This is different from ZIP/UNZIP API, where
+ * only US-ASCII characters was supported.
+ **/
+ enum CaseSensitivity {
+ csDefault=0, ///< Default for platform. Case sensitive for UNIX, not for Windows.
+ csSensitive=1, ///< Case sensitive.
+ csInsensitive=2 ///< Case insensitive.
+ };
+ /// Returns the actual case sensitivity for the specified QuaZIP one.
+ /**
+ \param cs The value to convert.
+ \returns If CaseSensitivity::csDefault, then returns the default
+ file name case sensitivity for the platform. Otherwise, just
+ returns the appropriate value from the Qt::CaseSensitivity enum.
+ */
+ static Qt::CaseSensitivity convertCaseSensitivity(
+ CaseSensitivity cs);
+ private:
+ QuaZipPrivate *p;
+ // not (and will not be) implemented
+ QuaZip(const QuaZip& that);
+ // not (and will not be) implemented
+ QuaZip& operator=(const QuaZip& that);
+ public:
+ /// Constructs QuaZip object.
+ /** Call setName() before opening constructed object. */
+ QuaZip();
+ /// Constructs QuaZip object associated with ZIP file \a zipName.
+ QuaZip(const QString& zipName);
+ /// Constructs QuaZip object associated with ZIP file represented by \a ioDevice.
+ /** The IO device must be seekable, otherwise an error will occur when opening. */
+ QuaZip(QIODevice *ioDevice);
+ /// Destroys QuaZip object.
+ /** Calls close() if necessary. */
+ ~QuaZip();
+ /// Opens ZIP file.
+ /**
+ * Argument \a mode specifies open mode of the ZIP archive. See Mode
+ * for details. Note that there is zipOpen2() function in the
+ * ZIP/UNZIP API which accepts \a globalcomment argument, but it
+ * does not use it anywhere, so this open() function does not have this
+ * argument. See setComment() if you need to set global comment.
+ *
+ * If the ZIP file is accessed via explicitly set QIODevice, then
+ * this device is opened in the necessary mode. If the device was
+ * already opened by some other means, then QuaZIP checks if the
+ * open mode is compatible to the mode needed for the requested operation.
+ * If necessary, seeking is performed to position the device properly.
+ *
+ * \return \c true if successful, \c false otherwise.
+ *
+ * \note ZIP/UNZIP API open calls do not return error code - they
+ * just return \c NULL indicating an error. But to make things
+ * easier, quazip.h header defines additional error code \c
+ * UNZ_ERROROPEN and getZipError() will return it if the open call
+ * of the ZIP/UNZIP API returns \c NULL.
+ *
+ * Argument \a ioApi specifies IO function set for ZIP/UNZIP
+ * package to use. See unzip.h, zip.h and ioapi.h for details. Note
+ * that IO API for QuaZip is different from the original package.
+ * The file path argument was changed to be of type \c voidpf, and
+ * QuaZip passes a QIODevice pointer there. This QIODevice is either
+ * set explicitly via setIoDevice() or the QuaZip(QIODevice*)
+ * constructor, or it is created internally when opening the archive
+ * by its file name. The default API (qioapi.cpp) just delegates
+ * everything to the QIODevice API. Not only this allows to use a
+ * QIODevice instead of file name, but also has a nice side effect
+ * of raising the file size limit from 2G to 4G (in non-zip64 archives).
+ *
+ * \note If the zip64 support is needed, the ioApi argument \em must be NULL
+ * because due to the backwards compatibility issues it can be used to
+ * provide a 32-bit API only.
+ *
+ * \note If the \ref QuaZip::setAutoClose() "no-auto-close" feature is used,
+ * then the \a ioApi argument \em should be NULL because the old API
+ * doesn't support the 'fake close' operation, causing slight memory leaks
+ * and other possible troubles (like closing the output device in case
+ * when an error occurs during opening).
+ *
+ * In short: just forget about the \a ioApi argument and you'll be
+ * fine.
+ **/
+ bool open(Mode mode, zlib_filefunc_def *ioApi =NULL);
+ /// Closes ZIP file.
+ /** Call getZipError() to determine if the close was successful.
+ *
+ * If the file was opened by name, then the underlying QIODevice is closed
+ * and deleted.
+ *
+ * If the underlying QIODevice was set explicitly using setIoDevice() or
+ * the appropriate constructor, then it is closed if the auto-close flag
+ * is set (which it is by default). Call setAutoClose() to clear the
+ * auto-close flag if this behavior is undesirable.
+ *
+ * Since Qt 5.1, the QSaveFile was introduced. It breaks the QIODevice API
+ * by making close() private and crashing the application if it is called
+ * from the base class where it is public. It is an excellent example
+ * of poor design that illustrates why you should never ever break
+ * an is-a relationship between the base class and a subclass. QuaZIP
+ * works around this bug by checking if the QIODevice is an instance
+ * of QSaveFile, using qobject_cast<>, and if it is, calls
+ * QSaveFile::commit() instead of close(). It is a really ugly hack,
+ * but at least it makes your programs work instead of crashing. Note that
+ * if the auto-close flag is cleared, then this is a non-issue, and
+ * commit() isn't called.
+ */
+ void close();
+ /// Sets the codec used to encode/decode file names inside archive.
+ /** This is necessary to access files in the ZIP archive created
+ * under Windows with non-latin characters in file names. For
+ * example, file names with cyrillic letters will be in \c IBM866
+ * encoding.
+ **/
+ void setFileNameCodec(QTextCodec *fileNameCodec);
+ /// Sets the codec used to encode/decode file names inside archive.
+ /** \overload
+ * Equivalent to calling setFileNameCodec(QTextCodec::codecForName(codecName));
+ **/
+ void setFileNameCodec(const char *fileNameCodecName);
+ /// Returns the codec used to encode/decode comments inside archive.
+ QTextCodec* getFileNameCodec() const;
+ /// Sets the codec used to encode/decode comments inside archive.
+ /** This codec defaults to locale codec, which is probably ok.
+ **/
+ void setCommentCodec(QTextCodec *commentCodec);
+ /// Sets the codec used to encode/decode comments inside archive.
+ /** \overload
+ * Equivalent to calling setCommentCodec(QTextCodec::codecForName(codecName));
+ **/
+ void setCommentCodec(const char *commentCodecName);
+ /// Returns the codec used to encode/decode comments inside archive.
+ QTextCodec* getCommentCodec() const;
+ /// Returns the name of the ZIP file.
+ /** Returns null string if no ZIP file name has been set, for
+ * example when the QuaZip instance is set up to use a QIODevice
+ * instead.
+ * \sa setZipName(), setIoDevice(), getIoDevice()
+ **/
+ QString getZipName() const;
+ /// Sets the name of the ZIP file.
+ /** Does nothing if the ZIP file is open.
+ *
+ * Does not reset error code returned by getZipError().
+ * \sa setIoDevice(), getIoDevice(), getZipName()
+ **/
+ void setZipName(const QString& zipName);
+ /// Returns the device representing this ZIP file.
+ /** Returns null string if no device has been set explicitly, for
+ * example when opening a ZIP file by name.
+ * \sa setIoDevice(), getZipName(), setZipName()
+ **/
+ QIODevice *getIoDevice() const;
+ /// Sets the device representing the ZIP file.
+ /** Does nothing if the ZIP file is open.
+ *
+ * Does not reset error code returned by getZipError().
+ * \sa getIoDevice(), getZipName(), setZipName()
+ **/
+ void setIoDevice(QIODevice *ioDevice);
+ /// Returns the mode in which ZIP file was opened.
+ Mode getMode() const;
+ /// Returns \c true if ZIP file is open, \c false otherwise.
+ bool isOpen() const;
+ /// Returns the error code of the last operation.
+ /** Returns \c UNZ_OK if the last operation was successful.
+ *
+ * Error code resets to \c UNZ_OK every time you call any function
+ * that accesses something inside ZIP archive, even if it is \c
+ * const (like getEntriesCount()). open() and close() calls reset
+ * error code too. See documentation for the specific functions for
+ * details on error detection.
+ **/
+ int getZipError() const;
+ /// Returns number of the entries in the ZIP central directory.
+ /** Returns negative error code in the case of error. The same error
+ * code will be returned by subsequent getZipError() call.
+ **/
+ int getEntriesCount() const;
+ /// Returns global comment in the ZIP file.
+ QString getComment() const;
+ /// Sets the global comment in the ZIP file.
+ /** The comment will be written to the archive on close operation.
+ * QuaZip makes a distinction between a null QByteArray() comment
+ * and an empty "" comment in the QuaZip::mdAdd mode.
+ * A null comment is the default and it means "don't change
+ * the comment". An empty comment removes the original comment.
+ *
+ * \sa open()
+ **/
+ void setComment(const QString& comment);
+ /// Sets the current file to the first file in the archive.
+ /** Returns \c true on success, \c false otherwise. Call
+ * getZipError() to get the error code.
+ **/
+ bool goToFirstFile();
+ /// Sets the current file to the next file in the archive.
+ /** Returns \c true on success, \c false otherwise. Call
+ * getZipError() to determine if there was an error.
+ *
+ * Should be used only in QuaZip::mdUnzip mode.
+ *
+ * \note If the end of file was reached, getZipError() will return
+ * \c UNZ_OK instead of \c UNZ_END_OF_LIST_OF_FILE. This is to make
+ * things like this easier:
+ * \code
+ * for(bool more=zip.goToFirstFile(); more; more=zip.goToNextFile()) {
+ * // do something
+ * }
+ * if(zip.getZipError()==UNZ_OK) {
+ * // ok, there was no error
+ * }
+ * \endcode
+ **/
+ bool goToNextFile();
+ /// Sets current file by its name.
+ /** Returns \c true if successful, \c false otherwise. Argument \a
+ * cs specifies case sensitivity of the file name. Call
+ * getZipError() in the case of a failure to get error code.
+ *
+ * This is not a wrapper to unzLocateFile() function. That is
+ * because I had to implement locale-specific case-insensitive
+ * comparison.
+ *
+ * Here are the differences from the original implementation:
+ *
+ * - If the file was not found, error code is \c UNZ_OK, not \c
+ * UNZ_END_OF_LIST_OF_FILE (see also goToNextFile()).
+ * - If this function fails, it unsets the current file rather than
+ * resetting it back to what it was before the call.
+ *
+ * If \a fileName is null string then this function unsets the
+ * current file and return \c true. Note that you should close the
+ * file first if it is open! See
+ * QuaZipFile::QuaZipFile(QuaZip*,QObject*) for the details.
+ *
+ * Should be used only in QuaZip::mdUnzip mode.
+ *
+ * \sa setFileNameCodec(), CaseSensitivity
+ **/
+ bool setCurrentFile(const QString& fileName, CaseSensitivity cs =csDefault);
+ /// Returns \c true if the current file has been set.
+ bool hasCurrentFile() const;
+ /// Retrieves information about the current file.
+ /** Fills the structure pointed by \a info. Returns \c true on
+ * success, \c false otherwise. In the latter case structure pointed
+ * by \a info remains untouched. If there was an error,
+ * getZipError() returns error code.
+ *
+ * Should be used only in QuaZip::mdUnzip mode.
+ *
+ * Does nothing and returns \c false in any of the following cases.
+ * - ZIP is not open;
+ * - ZIP does not have current file.
+ *
+ * In both cases getZipError() returns \c UNZ_OK since there
+ * is no ZIP/UNZIP API call.
+ *
+ * This overload doesn't support zip64, but will work OK on zip64 archives
+ * except that if one of the sizes (compressed or uncompressed) is greater
+ * than 0xFFFFFFFFu, it will be set to exactly 0xFFFFFFFFu.
+ *
+ * \sa getCurrentFileInfo(QuaZipFileInfo64* info)const
+ * \sa QuaZipFileInfo64::toQuaZipFileInfo(QuaZipFileInfo&)const
+ **/
+ bool getCurrentFileInfo(QuaZipFileInfo* info)const;
+ /// Retrieves information about the current file.
+ /** \overload
+ *
+ * This function supports zip64. If the archive doesn't use zip64, it is
+ * completely equivalent to getCurrentFileInfo(QuaZipFileInfo* info)
+ * except for the argument type.
+ *
+ * \sa
+ **/
+ bool getCurrentFileInfo(QuaZipFileInfo64* info)const;
+ /// Returns the current file name.
+ /** Equivalent to calling getCurrentFileInfo() and then getting \c
+ * name field of the QuaZipFileInfo structure, but faster and more
+ * convenient.
+ *
+ * Should be used only in QuaZip::mdUnzip mode.
+ **/
+ QString getCurrentFileName()const;
+ /// Returns \c unzFile handle.
+ /** You can use this handle to directly call UNZIP part of the
+ * ZIP/UNZIP package functions (see unzip.h).
+ *
+ * \warning When using the handle returned by this function, please
+ * keep in mind that QuaZip class is unable to detect any changes
+ * you make in the ZIP file state (e. g. changing current file, or
+ * closing the handle). So please do not do anything with this
+ * handle that is possible to do with the functions of this class.
+ * Or at least return the handle in the original state before
+ * calling some another function of this class (including implicit
+ * destructor calls and calls from the QuaZipFile objects that refer
+ * to this QuaZip instance!). So if you have changed the current
+ * file in the ZIP archive - then change it back or you may
+ * experience some strange behavior or even crashes.
+ **/
+ unzFile getUnzFile();
+ /// Returns \c zipFile handle.
+ /** You can use this handle to directly call ZIP part of the
+ * ZIP/UNZIP package functions (see zip.h). Warnings about the
+ * getUnzFile() function also apply to this function.
+ **/
+ zipFile getZipFile();
+ /// Changes the data descriptor writing mode.
+ /**
+ According to the ZIP format specification, a file inside archive
+ may have a data descriptor immediately following the file
+ data. This is reflected by a special flag in the local file header
+ and in the central directory. By default, QuaZIP sets this flag
+ and writes the data descriptor unless both method and level were
+ set to 0, in which case it operates in 1.0-compatible mode and
+ never writes data descriptors.
+
+ By setting this flag to false, it is possible to disable data
+ descriptor writing, thus increasing compatibility with archive
+ readers that don't understand this feature of the ZIP file format.
+
+ Setting this flag affects all the QuaZipFile instances that are
+ opened after this flag is set.
+
+ The data descriptor writing mode is enabled by default.
+
+ Note that if the ZIP archive is written into a QIODevice for which
+ QIODevice::isSequential() returns \c true, then the data descriptor
+ is mandatory and will be written even if this flag is set to false.
+
+ \param enabled If \c true, enable local descriptor writing,
+ disable it otherwise.
+
+ \sa QuaZipFile::isDataDescriptorWritingEnabled()
+ */
+ void setDataDescriptorWritingEnabled(bool enabled);
+ /// Returns the data descriptor default writing mode.
+ /**
+ \sa setDataDescriptorWritingEnabled()
+ */
+ bool isDataDescriptorWritingEnabled() const;
+ /// Returns a list of files inside the archive.
+ /**
+ \return A list of file names or an empty list if there
+ was an error or if the archive is empty (call getZipError() to
+ figure out which).
+ \sa getFileInfoList()
+ */
+ QStringList getFileNameList() const;
+ /// Returns information list about all files inside the archive.
+ /**
+ \return A list of QuaZipFileInfo objects or an empty list if there
+ was an error or if the archive is empty (call getZipError() to
+ figure out which).
+
+ This function doesn't support zip64, but will still work with zip64
+ archives, converting results using QuaZipFileInfo64::toQuaZipFileInfo().
+ If all file sizes are below 4 GB, it will work just fine.
+
+ \sa getFileNameList()
+ \sa getFileInfoList64()
+ */
+ QList getFileInfoList() const;
+ /// Returns information list about all files inside the archive.
+ /**
+ \overload
+
+ This function supports zip64.
+
+ \sa getFileNameList()
+ \sa getFileInfoList()
+ */
+ QList getFileInfoList64() const;
+ /// Enables the zip64 mode.
+ /**
+ * @param zip64 If \c true, the zip64 mode is enabled, disabled otherwise.
+ *
+ * Once this is enabled, all new files (until the mode is disabled again)
+ * will be created in the zip64 mode, thus enabling the ability to write
+ * files larger than 4 GB. By default, the zip64 mode is off due to
+ * compatibility reasons.
+ *
+ * Note that this does not affect the ability to read zip64 archives in any
+ * way.
+ *
+ * \sa isZip64Enabled()
+ */
+ void setZip64Enabled(bool zip64);
+ /// Returns whether the zip64 mode is enabled.
+ /**
+ * @return \c true if and only if the zip64 mode is enabled.
+ *
+ * \sa setZip64Enabled()
+ */
+ bool isZip64Enabled() const;
+ /// Returns the auto-close flag.
+ /**
+ @sa setAutoClose()
+ */
+ bool isAutoClose() const;
+ /// Sets or unsets the auto-close flag.
+ /**
+ By default, QuaZIP opens the underlying QIODevice when open() is called,
+ and closes it when close() is called. In some cases, when the device
+ is set explicitly using setIoDevice(), it may be desirable to
+ leave the device open. If the auto-close flag is unset using this method,
+ then the device isn't closed automatically if it was set explicitly.
+
+ If it is needed to clear this flag, it is recommended to do so before
+ opening the archive because otherwise QuaZIP may close the device
+ during the open() call if an error is encountered after the device
+ is opened.
+
+ If the device was not set explicitly, but rather the setZipName() or
+ the appropriate constructor was used to set the ZIP file name instead,
+ then the auto-close flag has no effect, and the internal device
+ is closed nevertheless because there is no other way to close it.
+
+ @sa isAutoClose()
+ @sa setIoDevice()
+ */
+ void setAutoClose(bool autoClose) const;
+ /// Sets the default file name codec to use.
+ /**
+ * The default codec is used by the constructors, so calling this function
+ * won't affect the QuaZip instances already created at that moment.
+ *
+ * The codec specified here can be overriden by calling setFileNameCodec().
+ * If neither function is called, QTextCodec::codecForLocale() will be used
+ * to decode or encode file names. Use this function with caution if
+ * the application uses other libraries that depend on QuaZIP. Those
+ * libraries can either call this function by themselves, thus overriding
+ * your setting or can rely on the default encoding, thus failing
+ * mysteriously if you change it. For these reasons, it isn't recommended
+ * to use this function if you are developing a library, not an application.
+ * Instead, ask your library users to call it in case they need specific
+ * encoding.
+ *
+ * In most cases, using setFileNameCodec() instead is the right choice.
+ * However, if you depend on third-party code that uses QuaZIP, then the
+ * reasons stated above can actually become a reason to use this function
+ * in case the third-party code in question fails because it doesn't
+ * understand the encoding you need and doesn't provide a way to specify it.
+ * This applies to the JlCompress class as well, as it was contributed and
+ * doesn't support explicit encoding parameters.
+ *
+ * In short: use setFileNameCodec() when you can, resort to
+ * setDefaultFileNameCodec() when you don't have access to the QuaZip
+ * instance.
+ *
+ * @param codec The codec to use by default. If NULL, resets to default.
+ */
+ static void setDefaultFileNameCodec(QTextCodec *codec);
+ /**
+ * @overload
+ * Equivalent to calling
+ * setDefltFileNameCodec(QTextCodec::codecForName(codecName)).
+ */
+ static void setDefaultFileNameCodec(const char *codecName);
+};
+
+#endif
diff --git a/src/updater/quazip/quazip.pri b/src/updater/quazip/quazip.pri
new file mode 100644
index 0000000..6952a7a
--- /dev/null
+++ b/src/updater/quazip/quazip.pri
@@ -0,0 +1,36 @@
+DEFINES += QUAZIP_STATIC
+LIBS += -lz
+
+INCLUDEPATH += $$PWD
+DEPENDPATH += $$PWD
+HEADERS += \
+ $$PWD/crypt.h \
+ $$PWD/ioapi.h \
+ $$PWD/JlCompress.h \
+ $$PWD/quaadler32.h \
+ $$PWD/quachecksum32.h \
+ $$PWD/quacrc32.h \
+ $$PWD/quagzipfile.h \
+ $$PWD/quaziodevice.h \
+ $$PWD/quazipdir.h \
+ $$PWD/quazipfile.h \
+ $$PWD/quazipfileinfo.h \
+ $$PWD/quazip_global.h \
+ $$PWD/quazip.h \
+ $$PWD/quazipnewinfo.h \
+ $$PWD/unzip.h \
+ $$PWD/zip.h
+
+SOURCES += $$PWD/qioapi.cpp \
+ $$PWD/JlCompress.cpp \
+ $$PWD/quaadler32.cpp \
+ $$PWD/quacrc32.cpp \
+ $$PWD/quagzipfile.cpp \
+ $$PWD/quaziodevice.cpp \
+ $$PWD/quazip.cpp \
+ $$PWD/quazipdir.cpp \
+ $$PWD/quazipfile.cpp \
+ $$PWD/quazipfileinfo.cpp \
+ $$PWD/quazipnewinfo.cpp \
+ $$PWD/unzip.c \
+ $$PWD/zip.c
diff --git a/src/updater/quazip/quazip_global.h b/src/updater/quazip/quazip_global.h
new file mode 100644
index 0000000..7e3798a
--- /dev/null
+++ b/src/updater/quazip/quazip_global.h
@@ -0,0 +1,59 @@
+#ifndef QUAZIP_GLOBAL_H
+#define QUAZIP_GLOBAL_H
+
+/*
+Copyright (C) 2005-2014 Sergey A. Tachenov
+
+This file is part of QuaZIP.
+
+QuaZIP is free software: you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation, either version 2.1 of the License, or
+(at your option) any later version.
+
+QuaZIP is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with QuaZIP. If not, see .
+
+See COPYING file for the full LGPL text.
+
+Original ZIP package is copyrighted by Gilles Vollant and contributors,
+see quazip/(un)zip.h files for details. Basically it's the zlib license.
+*/
+
+#include
+
+/**
+ This is automatically defined when building a static library, but when
+ including QuaZip sources directly into a project, QUAZIP_STATIC should
+ be defined explicitly to avoid possible troubles with unnecessary
+ importing/exporting.
+ */
+#ifdef QUAZIP_STATIC
+#define QUAZIP_EXPORT
+#else
+/**
+ * When building a DLL with MSVC, QUAZIP_BUILD must be defined.
+ * qglobal.h takes care of defining Q_DECL_* correctly for msvc/gcc.
+ */
+#if defined(QUAZIP_BUILD)
+ #define QUAZIP_EXPORT Q_DECL_EXPORT
+#else
+ #define QUAZIP_EXPORT Q_DECL_IMPORT
+#endif
+#endif // QUAZIP_STATIC
+
+#ifdef __GNUC__
+#define UNUSED __attribute__((__unused__))
+#else
+#define UNUSED
+#endif
+
+#define QUAZIP_EXTRA_NTFS_MAGIC 0x000Au
+#define QUAZIP_EXTRA_NTFS_TIME_MAGIC 0x0001u
+
+#endif // QUAZIP_GLOBAL_H
diff --git a/src/updater/quazip/quazipdir.cpp b/src/updater/quazip/quazipdir.cpp
new file mode 100644
index 0000000..5ae08a0
--- /dev/null
+++ b/src/updater/quazip/quazipdir.cpp
@@ -0,0 +1,567 @@
+/*
+Copyright (C) 2005-2014 Sergey A. Tachenov
+
+This file is part of QuaZIP.
+
+QuaZIP is free software: you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation, either version 2.1 of the License, or
+(at your option) any later version.
+
+QuaZIP is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with QuaZIP. If not, see .
+
+See COPYING file for the full LGPL text.
+
+Original ZIP package is copyrighted by Gilles Vollant and contributors,
+see quazip/(un)zip.h files for details. Basically it's the zlib license.
+*/
+
+#include "quazipdir.h"
+
+#include
+#include
+
+/// \cond internal
+class QuaZipDirPrivate: public QSharedData {
+ friend class QuaZipDir;
+private:
+ QuaZipDirPrivate(QuaZip *zip, const QString &dir = QString()):
+ zip(zip), dir(dir), caseSensitivity(QuaZip::csDefault),
+ filter(QDir::NoFilter), sorting(QDir::NoSort) {}
+ QuaZip *zip;
+ QString dir;
+ QuaZip::CaseSensitivity caseSensitivity;
+ QDir::Filters filter;
+ QStringList nameFilters;
+ QDir::SortFlags sorting;
+ template
+ bool entryInfoList(QStringList nameFilters, QDir::Filters filter,
+ QDir::SortFlags sort, TFileInfoList &result) const;
+ inline QString simplePath() const {return QDir::cleanPath(dir);}
+};
+/// \endcond
+
+QuaZipDir::QuaZipDir(const QuaZipDir &that):
+ d(that.d)
+{
+}
+
+QuaZipDir::QuaZipDir(QuaZip *zip, const QString &dir):
+ d(new QuaZipDirPrivate(zip, dir))
+{
+ if (d->dir.startsWith('/'))
+ d->dir = d->dir.mid(1);
+}
+
+QuaZipDir::~QuaZipDir()
+{
+}
+
+bool QuaZipDir::operator==(const QuaZipDir &that)
+{
+ return d->zip == that.d->zip && d->dir == that.d->dir;
+}
+
+QuaZipDir& QuaZipDir::operator=(const QuaZipDir &that)
+{
+ this->d = that.d;
+ return *this;
+}
+
+QString QuaZipDir::operator[](int pos) const
+{
+ return entryList().at(pos);
+}
+
+QuaZip::CaseSensitivity QuaZipDir::caseSensitivity() const
+{
+ return d->caseSensitivity;
+}
+
+bool QuaZipDir::cd(const QString &directoryName)
+{
+ if (directoryName == "/") {
+ d->dir = "";
+ return true;
+ }
+ QString dirName = directoryName;
+ if (dirName.endsWith('/'))
+ dirName.chop(1);
+ if (dirName.contains('/')) {
+ QuaZipDir dir(*this);
+ if (dirName.startsWith('/')) {
+#ifdef QUAZIP_QUAZIPDIR_DEBUG
+ qDebug("QuaZipDir::cd(%s): going to /",
+ dirName.toUtf8().constData());
+#endif
+ if (!dir.cd("/"))
+ return false;
+ }
+ QStringList path = dirName.split('/', QString::SkipEmptyParts);
+ for (QStringList::const_iterator i = path.constBegin();
+ i != path.end();
+ ++i) {
+ const QString &step = *i;
+#ifdef QUAZIP_QUAZIPDIR_DEBUG
+ qDebug("QuaZipDir::cd(%s): going to %s",
+ dirName.toUtf8().constData(),
+ step.toUtf8().constData());
+#endif
+ if (!dir.cd(step))
+ return false;
+ }
+ d->dir = dir.path();
+ return true;
+ } else { // no '/'
+ if (dirName == ".") {
+ return true;
+ } else if (dirName == "..") {
+ if (isRoot()) {
+ return false;
+ } else {
+ int slashPos = d->dir.lastIndexOf('/');
+ if (slashPos == -1) {
+ d->dir = "";
+ } else {
+ d->dir = d->dir.left(slashPos);
+ }
+ return true;
+ }
+ } else { // a simple subdirectory
+ if (exists(dirName)) {
+ if (isRoot())
+ d->dir = dirName;
+ else
+ d->dir += "/" + dirName;
+ return true;
+ } else {
+ return false;
+ }
+ }
+ }
+}
+
+bool QuaZipDir::cdUp()
+{
+ return cd("..");
+}
+
+uint QuaZipDir::count() const
+{
+ return entryList().count();
+}
+
+QString QuaZipDir::dirName() const
+{
+ return QDir(d->dir).dirName();
+}
+
+QuaZipFileInfo64 QuaZipDir_getFileInfo(QuaZip *zip, bool *ok,
+ const QString &relativeName,
+ bool isReal)
+{
+ QuaZipFileInfo64 info;
+ if (isReal) {
+ *ok = zip->getCurrentFileInfo(&info);
+ } else {
+ *ok = true;
+ info.compressedSize = 0;
+ info.crc = 0;
+ info.diskNumberStart = 0;
+ info.externalAttr = 0;
+ info.flags = 0;
+ info.internalAttr = 0;
+ info.method = 0;
+ info.uncompressedSize = 0;
+ info.versionCreated = info.versionNeeded = 0;
+ }
+ info.name = relativeName;
+ return info;
+}
+
+static void QuaZipDir_convertInfoList(const QList &from,
+ QList &to)
+{
+ to = from;
+}
+
+static void QuaZipDir_convertInfoList(const QList &from,
+ QStringList &to)
+{
+ to.clear();
+ for (QList::const_iterator i = from.constBegin();
+ i != from.constEnd();
+ ++i) {
+ to.append(i->name);
+ }
+}
+
+static void QuaZipDir_convertInfoList(const QList &from,
+ QList &to)
+{
+ to.clear();
+ for (QList::const_iterator i = from.constBegin();
+ i != from.constEnd();
+ ++i) {
+ QuaZipFileInfo info32;
+ i->toQuaZipFileInfo(info32);
+ to.append(info32);
+ }
+}
+
+/// \cond internal
+/**
+ An utility class to restore the current file.
+ */
+class QuaZipDirRestoreCurrent {
+public:
+ inline QuaZipDirRestoreCurrent(QuaZip *zip):
+ zip(zip), currentFile(zip->getCurrentFileName()) {}
+ inline ~QuaZipDirRestoreCurrent()
+ {
+ zip->setCurrentFile(currentFile);
+ }
+private:
+ QuaZip *zip;
+ QString currentFile;
+};
+/// \endcond
+
+/// \cond internal
+class QuaZipDirComparator
+{
+ private:
+ QDir::SortFlags sort;
+ static QString getExtension(const QString &name);
+ int compareStrings(const QString &string1, const QString &string2);
+ public:
+ inline QuaZipDirComparator(QDir::SortFlags sort): sort(sort) {}
+ bool operator()(const QuaZipFileInfo64 &info1, const QuaZipFileInfo64 &info2);
+};
+
+QString QuaZipDirComparator::getExtension(const QString &name)
+{
+ if (name.endsWith('.') || name.indexOf('.', 1) == -1) {
+ return "";
+ } else {
+ return name.mid(name.lastIndexOf('.') + 1);
+ }
+
+}
+
+int QuaZipDirComparator::compareStrings(const QString &string1,
+ const QString &string2)
+{
+ if (sort & QDir::LocaleAware) {
+ if (sort & QDir::IgnoreCase) {
+ return string1.toLower().localeAwareCompare(string2.toLower());
+ } else {
+ return string1.localeAwareCompare(string2);
+ }
+ } else {
+ return string1.compare(string2, (sort & QDir::IgnoreCase)
+ ? Qt::CaseInsensitive : Qt::CaseSensitive);
+ }
+}
+
+bool QuaZipDirComparator::operator()(const QuaZipFileInfo64 &info1,
+ const QuaZipFileInfo64 &info2)
+{
+ QDir::SortFlags order = sort
+ & (QDir::Name | QDir::Time | QDir::Size | QDir::Type);
+ if ((sort & QDir::DirsFirst) == QDir::DirsFirst
+ || (sort & QDir::DirsLast) == QDir::DirsLast) {
+ if (info1.name.endsWith('/') && !info2.name.endsWith('/'))
+ return (sort & QDir::DirsFirst) == QDir::DirsFirst;
+ else if (!info1.name.endsWith('/') && info2.name.endsWith('/'))
+ return (sort & QDir::DirsLast) == QDir::DirsLast;
+ }
+ bool result;
+ int extDiff;
+ switch (order) {
+ case QDir::Name:
+ result = compareStrings(info1.name, info2.name) < 0;
+ break;
+ case QDir::Type:
+ extDiff = compareStrings(getExtension(info1.name),
+ getExtension(info2.name));
+ if (extDiff == 0) {
+ result = compareStrings(info1.name, info2.name) < 0;
+ } else {
+ result = extDiff < 0;
+ }
+ break;
+ case QDir::Size:
+ if (info1.uncompressedSize == info2.uncompressedSize) {
+ result = compareStrings(info1.name, info2.name) < 0;
+ } else {
+ result = info1.uncompressedSize < info2.uncompressedSize;
+ }
+ break;
+ case QDir::Time:
+ if (info1.dateTime == info2.dateTime) {
+ result = compareStrings(info1.name, info2.name) < 0;
+ } else {
+ result = info1.dateTime < info2.dateTime;
+ }
+ break;
+ default:
+ qWarning("QuaZipDirComparator(): Invalid sort mode 0x%2X",
+ static_cast(sort));
+ return false;
+ }
+ return (sort & QDir::Reversed) ? !result : result;
+}
+
+template
+bool QuaZipDirPrivate::entryInfoList(QStringList nameFilters,
+ QDir::Filters filter, QDir::SortFlags sort, TFileInfoList &result) const
+{
+ QString basePath = simplePath();
+ if (!basePath.isEmpty())
+ basePath += "/";
+ int baseLength = basePath.length();
+ result.clear();
+ QuaZipDirRestoreCurrent saveCurrent(zip);
+ if (!zip->goToFirstFile()) {
+ return zip->getZipError() == UNZ_OK;
+ }
+ QDir::Filters fltr = filter;
+ if (fltr == QDir::NoFilter)
+ fltr = this->filter;
+ if (fltr == QDir::NoFilter)
+ fltr = QDir::AllEntries;
+ QStringList nmfltr = nameFilters;
+ if (nmfltr.isEmpty())
+ nmfltr = this->nameFilters;
+ QSet dirsFound;
+ QList list;
+ do {
+ QString name = zip->getCurrentFileName();
+ if (!name.startsWith(basePath))
+ continue;
+ QString relativeName = name.mid(baseLength);
+ if (relativeName.isEmpty())
+ continue;
+ bool isDir = false;
+ bool isReal = true;
+ if (relativeName.contains('/')) {
+ int indexOfSlash = relativeName.indexOf('/');
+ // something like "subdir/"
+ isReal = indexOfSlash == relativeName.length() - 1;
+ relativeName = relativeName.left(indexOfSlash + 1);
+ if (dirsFound.contains(relativeName))
+ continue;
+ isDir = true;
+ }
+ dirsFound.insert(relativeName);
+ if ((fltr & QDir::Dirs) == 0 && isDir)
+ continue;
+ if ((fltr & QDir::Files) == 0 && !isDir)
+ continue;
+ if (!nmfltr.isEmpty() && !QDir::match(nmfltr, relativeName))
+ continue;
+ bool ok;
+ QuaZipFileInfo64 info = QuaZipDir_getFileInfo(zip, &ok, relativeName,
+ isReal);
+ if (!ok) {
+ return false;
+ }
+ list.append(info);
+ } while (zip->goToNextFile());
+ QDir::SortFlags srt = sort;
+ if (srt == QDir::NoSort)
+ srt = sorting;
+#ifdef QUAZIP_QUAZIPDIR_DEBUG
+ qDebug("QuaZipDirPrivate::entryInfoList(): before sort:");
+ foreach (QuaZipFileInfo64 info, list) {
+ qDebug("%s\t%s", info.name.toUtf8().constData(),
+ info.dateTime.toString(Qt::ISODate).toUtf8().constData());
+ }
+#endif
+ if (srt != QDir::NoSort && (srt & QDir::Unsorted) != QDir::Unsorted) {
+ if (QuaZip::convertCaseSensitivity(caseSensitivity)
+ == Qt::CaseInsensitive)
+ srt |= QDir::IgnoreCase;
+ QuaZipDirComparator lessThan(srt);
+ qSort(list.begin(), list.end(), lessThan);
+ }
+ QuaZipDir_convertInfoList(list, result);
+ return true;
+}
+
+/// \endcond
+
+QList QuaZipDir::entryInfoList(const QStringList &nameFilters,
+ QDir::Filters filters, QDir::SortFlags sort) const
+{
+ QList result;
+ if (d->entryInfoList(nameFilters, filters, sort, result))
+ return result;
+ else
+ return QList();
+}
+
+QList QuaZipDir::entryInfoList(QDir::Filters filters,
+ QDir::SortFlags sort) const
+{
+ return entryInfoList(QStringList(), filters, sort);
+}
+
+QList QuaZipDir::entryInfoList64(const QStringList &nameFilters,
+ QDir::Filters filters, QDir::SortFlags sort) const
+{
+ QList result;
+ if (d->entryInfoList(nameFilters, filters, sort, result))
+ return result;
+ else
+ return QList();
+}
+
+QList QuaZipDir::entryInfoList64(QDir::Filters filters,
+ QDir::SortFlags sort) const
+{
+ return entryInfoList64(QStringList(), filters, sort);
+}
+
+QStringList QuaZipDir::entryList(const QStringList &nameFilters,
+ QDir::Filters filters, QDir::SortFlags sort) const
+{
+ QStringList result;
+ if (d->entryInfoList(nameFilters, filters, sort, result))
+ return result;
+ else
+ return QStringList();
+}
+
+QStringList QuaZipDir::entryList(QDir::Filters filters,
+ QDir::SortFlags sort) const
+{
+ return entryList(QStringList(), filters, sort);
+}
+
+bool QuaZipDir::exists(const QString &filePath) const
+{
+ if (filePath == "/" || filePath.isEmpty())
+ return true;
+ QString fileName = filePath;
+ if (fileName.endsWith('/'))
+ fileName.chop(1);
+ if (fileName.contains('/')) {
+ QFileInfo fileInfo(fileName);
+#ifdef QUAZIP_QUAZIPDIR_DEBUG
+ qDebug("QuaZipDir::exists(): fileName=%s, fileInfo.fileName()=%s, "
+ "fileInfo.path()=%s", fileName.toUtf8().constData(),
+ fileInfo.fileName().toUtf8().constData(),
+ fileInfo.path().toUtf8().constData());
+#endif
+ QuaZipDir dir(*this);
+ return dir.cd(fileInfo.path()) && dir.exists(fileInfo.fileName());
+ } else {
+ if (fileName == "..") {
+ return !isRoot();
+ } else if (fileName == ".") {
+ return true;
+ } else {
+ QStringList entries = entryList(QDir::AllEntries, QDir::NoSort);
+#ifdef QUAZIP_QUAZIPDIR_DEBUG
+ qDebug("QuaZipDir::exists(): looking for %s",
+ fileName.toUtf8().constData());
+ for (QStringList::const_iterator i = entries.constBegin();
+ i != entries.constEnd();
+ ++i) {
+ qDebug("QuaZipDir::exists(): entry: %s",
+ i->toUtf8().constData());
+ }
+#endif
+ Qt::CaseSensitivity cs = QuaZip::convertCaseSensitivity(
+ d->caseSensitivity);
+ if (filePath.endsWith('/')) {
+ return entries.contains(filePath, cs);
+ } else {
+ return entries.contains(fileName, cs)
+ || entries.contains(fileName + "/", cs);
+ }
+ }
+ }
+}
+
+bool QuaZipDir::exists() const
+{
+ return QuaZipDir(d->zip).exists(d->dir);
+}
+
+QString QuaZipDir::filePath(const QString &fileName) const
+{
+ return QDir(d->dir).filePath(fileName);
+}
+
+QDir::Filters QuaZipDir::filter()
+{
+ return d->filter;
+}
+
+bool QuaZipDir::isRoot() const
+{
+ return d->simplePath().isEmpty();
+}
+
+QStringList QuaZipDir::nameFilters() const
+{
+ return d->nameFilters;
+}
+
+QString QuaZipDir::path() const
+{
+ return d->dir;
+}
+
+QString QuaZipDir::relativeFilePath(const QString &fileName) const
+{
+ return QDir("/" + d->dir).relativeFilePath(fileName);
+}
+
+void QuaZipDir::setCaseSensitivity(QuaZip::CaseSensitivity caseSensitivity)
+{
+ d->caseSensitivity = caseSensitivity;
+}
+
+void QuaZipDir::setFilter(QDir::Filters filters)
+{
+ d->filter = filters;
+}
+
+void QuaZipDir::setNameFilters(const QStringList &nameFilters)
+{
+ d->nameFilters = nameFilters;
+}
+
+void QuaZipDir::setPath(const QString &path)
+{
+ QString newDir = path;
+ if (newDir == "/") {
+ d->dir = "";
+ } else {
+ if (newDir.endsWith('/'))
+ newDir.chop(1);
+ if (newDir.startsWith('/'))
+ newDir = newDir.mid(1);
+ d->dir = newDir;
+ }
+}
+
+void QuaZipDir::setSorting(QDir::SortFlags sort)
+{
+ d->sorting = sort;
+}
+
+QDir::SortFlags QuaZipDir::sorting() const
+{
+ return d->sorting;
+}
diff --git a/src/updater/quazip/quazipdir.h b/src/updater/quazip/quazipdir.h
new file mode 100644
index 0000000..4626b17
--- /dev/null
+++ b/src/updater/quazip/quazipdir.h
@@ -0,0 +1,223 @@
+#ifndef QUAZIP_QUAZIPDIR_H
+#define QUAZIP_QUAZIPDIR_H
+
+/*
+Copyright (C) 2005-2014 Sergey A. Tachenov
+
+This file is part of QuaZIP.
+
+QuaZIP is free software: you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation, either version 2.1 of the License, or
+(at your option) any later version.
+
+QuaZIP is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with QuaZIP. If not, see .
+
+See COPYING file for the full LGPL text.
+
+Original ZIP package is copyrighted by Gilles Vollant and contributors,
+see quazip/(un)zip.h files for details. Basically it's the zlib license.
+*/
+
+class QuaZipDirPrivate;
+
+#include "quazip.h"
+#include "quazipfileinfo.h"
+#include
+#include
+#include
+
+/// Provides ZIP archive navigation.
+/**
+* This class is modelled after QDir, and is designed to provide similar
+* features for ZIP archives.
+*
+* The only significant difference from QDir is that the root path is not
+* '/', but an empty string since that's how the file paths are stored in
+* the archive. However, QuaZipDir understands the paths starting with
+* '/'. It is important in a few places:
+*
+* - In the cd() function.
+* - In the constructor.
+* - In the exists() function.
+* - In the relativePath() function.
+*
+* Note that since ZIP uses '/' on all platforms, the '\' separator is
+* not supported.
+*/
+class QUAZIP_EXPORT QuaZipDir {
+private:
+ QSharedDataPointer d;
+public:
+ /// The copy constructor.
+ QuaZipDir(const QuaZipDir &that);
+ /// Constructs a QuaZipDir instance pointing to the specified directory.
+ /**
+ If \a dir is not specified, points to the root of the archive.
+ The same happens if the \a dir is "/".
+ */
+ QuaZipDir(QuaZip *zip, const QString &dir = QString());
+ /// Destructor.
+ ~QuaZipDir();
+ /// The assignment operator.
+ bool operator==(const QuaZipDir &that);
+ /// operator!=
+ /**
+ \return \c true if either this and \a that use different QuaZip
+ instances or if they point to different directories.
+ */
+ inline bool operator!=(const QuaZipDir &that) {return !operator==(that);}
+ /// operator==
+ /**
+ \return \c true if both this and \a that use the same QuaZip
+ instance and point to the same directory.
+ */
+ QuaZipDir& operator=(const QuaZipDir &that);
+ /// Returns the name of the entry at the specified position.
+ QString operator[](int pos) const;
+ /// Returns the current case sensitivity mode.
+ QuaZip::CaseSensitivity caseSensitivity() const;
+ /// Changes the 'current' directory.
+ /**
+ * If the path starts with '/', it is interpreted as an absolute
+ * path from the root of the archive. Otherwise, it is interpreted
+ * as a path relative to the current directory as was set by the
+ * previous cd() or the constructor.
+ *
+ * Note that the subsequent path() call will not return a path
+ * starting with '/' in all cases.
+ */
+ bool cd(const QString &dirName);
+ /// Goes up.
+ bool cdUp();
+ /// Returns the number of entries in the directory.
+ uint count() const;
+ /// Returns the current directory name.
+ /**
+ The name doesn't include the path.
+ */
+ QString dirName() const;
+ /// Returns the list of the entries in the directory.
+ /**
+ \param nameFilters The list of file patterns to list, uses the same
+ syntax as QDir.
+ \param filters The entry type filters, only Files and Dirs are
+ accepted.
+ \param sort Sorting mode.
+ */
+ QList entryInfoList(const QStringList &nameFilters,
+ QDir::Filters filters = QDir::NoFilter,
+ QDir::SortFlags sort = QDir::NoSort) const;
+ /// Returns the list of the entries in the directory.
+ /**
+ \overload
+
+ The same as entryInfoList(QStringList(), filters, sort).
+ */
+ QList entryInfoList(QDir::Filters filters = QDir::NoFilter,
+ QDir::SortFlags sort = QDir::NoSort) const;
+ /// Returns the list of the entries in the directory with zip64 support.
+ /**
+ \param nameFilters The list of file patterns to list, uses the same
+ syntax as QDir.
+ \param filters The entry type filters, only Files and Dirs are
+ accepted.
+ \param sort Sorting mode.
+ */
+ QList entryInfoList64(const QStringList &nameFilters,
+ QDir::Filters filters = QDir::NoFilter,
+ QDir::SortFlags sort = QDir::NoSort) const;
+ /// Returns the list of the entries in the directory with zip64 support.
+ /**
+ \overload
+
+ The same as entryInfoList64(QStringList(), filters, sort).
+ */
+ QList entryInfoList64(QDir::Filters filters = QDir::NoFilter,
+ QDir::SortFlags sort = QDir::NoSort) const;
+ /// Returns the list of the entry names in the directory.
+ /**
+ The same as entryInfoList(nameFilters, filters, sort), but only
+ returns entry names.
+ */
+ QStringList entryList(const QStringList &nameFilters,
+ QDir::Filters filters = QDir::NoFilter,
+ QDir::SortFlags sort = QDir::NoSort) const;
+ /// Returns the list of the entry names in the directory.
+ /**
+ \overload
+
+ The same as entryList(QStringList(), filters, sort).
+ */
+ QStringList entryList(QDir::Filters filters = QDir::NoFilter,
+ QDir::SortFlags sort = QDir::NoSort) const;
+ /// Returns \c true if the entry with the specified name exists.
+ /**
+ The ".." is considered to exist if the current directory
+ is not root. The "." and "/" are considered to
+ always exist. Paths starting with "/" are relative to
+ the archive root, other paths are relative to the current dir.
+ */
+ bool exists(const QString &fileName) const;
+ /// Return \c true if the directory pointed by this QuaZipDir exists.
+ bool exists() const;
+ /// Returns the full path to the specified file.
+ /**
+ Doesn't check if the file actually exists.
+ */
+ QString filePath(const QString &fileName) const;
+ /// Returns the default filter.
+ QDir::Filters filter();
+ /// Returns if the QuaZipDir points to the root of the archive.
+ /**
+ Not that the root path is the empty string, not '/'.
+ */
+ bool isRoot() const;
+ /// Return the default name filter.
+ QStringList nameFilters() const;
+ /// Returns the path to the current dir.
+ /**
+ The path never starts with '/', and the root path is an empty
+ string.
+ */
+ QString path() const;
+ /// Returns the path to the specified file relative to the current dir.
+ /**
+ * This function is mostly useless, provided only for the sake of
+ * completeness.
+ *
+ * @param fileName The path to the file, should start with "/"
+ * if relative to the archive root.
+ * @return Path relative to the current dir.
+ */
+ QString relativeFilePath(const QString &fileName) const;
+ /// Sets the default case sensitivity mode.
+ void setCaseSensitivity(QuaZip::CaseSensitivity caseSensitivity);
+ /// Sets the default filter.
+ void setFilter(QDir::Filters filters);
+ /// Sets the default name filter.
+ void setNameFilters(const QStringList &nameFilters);
+ /// Goes to the specified path.
+ /**
+ The difference from cd() is that this function never checks if the
+ path actually exists and doesn't use relative paths, so it's
+ possible to go to the root directory with setPath("").
+
+ Note that this function still chops the trailing and/or leading
+ '/' and treats a single '/' as the root path (path() will still
+ return an empty string).
+ */
+ void setPath(const QString &path);
+ /// Sets the default sorting mode.
+ void setSorting(QDir::SortFlags sort);
+ /// Returns the default sorting mode.
+ QDir::SortFlags sorting() const;
+};
+
+#endif // QUAZIP_QUAZIPDIR_H
diff --git a/src/updater/quazip/quazipfile.cpp b/src/updater/quazip/quazipfile.cpp
new file mode 100644
index 0000000..3ce895a
--- /dev/null
+++ b/src/updater/quazip/quazipfile.cpp
@@ -0,0 +1,531 @@
+/*
+Copyright (C) 2005-2014 Sergey A. Tachenov
+
+This file is part of QuaZIP.
+
+QuaZIP is free software: you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation, either version 2.1 of the License, or
+(at your option) any later version.
+
+QuaZIP is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with QuaZIP. If not, see .
+
+See COPYING file for the full LGPL text.
+
+Original ZIP package is copyrighted by Gilles Vollant, see
+quazip/(un)zip.h files for details, basically it's zlib license.
+ **/
+
+#include "quazipfile.h"
+
+using namespace std;
+
+/// The implementation class for QuaZip.
+/**
+\internal
+
+This class contains all the private stuff for the QuaZipFile class, thus
+allowing to preserve binary compatibility between releases, the
+technique known as the Pimpl (private implementation) idiom.
+*/
+class QuaZipFilePrivate {
+ friend class QuaZipFile;
+ private:
+ Q_DISABLE_COPY(QuaZipFilePrivate)
+ /// The pointer to the associated QuaZipFile instance.
+ QuaZipFile *q;
+ /// The QuaZip object to work with.
+ QuaZip *zip;
+ /// The file name.
+ QString fileName;
+ /// Case sensitivity mode.
+ QuaZip::CaseSensitivity caseSensitivity;
+ /// Whether this file is opened in the raw mode.
+ bool raw;
+ /// Write position to keep track of.
+ /**
+ QIODevice::pos() is broken for non-seekable devices, so we need
+ our own position.
+ */
+ qint64 writePos;
+ /// Uncompressed size to write along with a raw file.
+ quint64 uncompressedSize;
+ /// CRC to write along with a raw file.
+ quint32 crc;
+ /// Whether \ref zip points to an internal QuaZip instance.
+ /**
+ This is true if the archive was opened by name, rather than by
+ supplying an existing QuaZip instance.
+ */
+ bool internal;
+ /// The last error.
+ int zipError;
+ /// Resets \ref zipError.
+ inline void resetZipError() const {setZipError(UNZ_OK);}
+ /// Sets the zip error.
+ /**
+ This function is marked as const although it changes one field.
+ This allows to call it from const functions that don't change
+ anything by themselves.
+ */
+ void setZipError(int zipError) const;
+ /// The constructor for the corresponding QuaZipFile constructor.
+ inline QuaZipFilePrivate(QuaZipFile *q):
+ q(q),
+ zip(NULL),
+ caseSensitivity(QuaZip::csDefault),
+ raw(false),
+ writePos(0),
+ uncompressedSize(0),
+ crc(0),
+ internal(true),
+ zipError(UNZ_OK) {}
+ /// The constructor for the corresponding QuaZipFile constructor.
+ inline QuaZipFilePrivate(QuaZipFile *q, const QString &zipName):
+ q(q),
+ caseSensitivity(QuaZip::csDefault),
+ raw(false),
+ writePos(0),
+ uncompressedSize(0),
+ crc(0),
+ internal(true),
+ zipError(UNZ_OK)
+ {
+ zip=new QuaZip(zipName);
+ }
+ /// The constructor for the corresponding QuaZipFile constructor.
+ inline QuaZipFilePrivate(QuaZipFile *q, const QString &zipName, const QString &fileName,
+ QuaZip::CaseSensitivity cs):
+ q(q),
+ raw(false),
+ writePos(0),
+ uncompressedSize(0),
+ crc(0),
+ internal(true),
+ zipError(UNZ_OK)
+ {
+ zip=new QuaZip(zipName);
+ this->fileName=fileName;
+ if (this->fileName.startsWith('/'))
+ this->fileName = this->fileName.mid(1);
+ this->caseSensitivity=cs;
+ }
+ /// The constructor for the QuaZipFile constructor accepting a file name.
+ inline QuaZipFilePrivate(QuaZipFile *q, QuaZip *zip):
+ q(q),
+ zip(zip),
+ raw(false),
+ writePos(0),
+ uncompressedSize(0),
+ crc(0),
+ internal(false),
+ zipError(UNZ_OK) {}
+ /// The destructor.
+ inline ~QuaZipFilePrivate()
+ {
+ if (internal)
+ delete zip;
+ }
+};
+
+QuaZipFile::QuaZipFile():
+ p(new QuaZipFilePrivate(this))
+{
+}
+
+QuaZipFile::QuaZipFile(QObject *parent):
+ QIODevice(parent),
+ p(new QuaZipFilePrivate(this))
+{
+}
+
+QuaZipFile::QuaZipFile(const QString& zipName, QObject *parent):
+ QIODevice(parent),
+ p(new QuaZipFilePrivate(this, zipName))
+{
+}
+
+QuaZipFile::QuaZipFile(const QString& zipName, const QString& fileName,
+ QuaZip::CaseSensitivity cs, QObject *parent):
+ QIODevice(parent),
+ p(new QuaZipFilePrivate(this, zipName, fileName, cs))
+{
+}
+
+QuaZipFile::QuaZipFile(QuaZip *zip, QObject *parent):
+ QIODevice(parent),
+ p(new QuaZipFilePrivate(this, zip))
+{
+}
+
+QuaZipFile::~QuaZipFile()
+{
+ if (isOpen())
+ close();
+ delete p;
+}
+
+QString QuaZipFile::getZipName() const
+{
+ return p->zip==NULL ? QString() : p->zip->getZipName();
+}
+
+QuaZip *QuaZipFile::getZip() const
+{
+ return p->internal ? NULL : p->zip;
+}
+
+QString QuaZipFile::getActualFileName()const
+{
+ p->setZipError(UNZ_OK);
+ if (p->zip == NULL || (openMode() & WriteOnly))
+ return QString();
+ QString name=p->zip->getCurrentFileName();
+ if(name.isNull())
+ p->setZipError(p->zip->getZipError());
+ return name;
+}
+
+void QuaZipFile::setZipName(const QString& zipName)
+{
+ if(isOpen()) {
+ qWarning("QuaZipFile::setZipName(): file is already open - can not set ZIP name");
+ return;
+ }
+ if(p->zip!=NULL && p->internal)
+ delete p->zip;
+ p->zip=new QuaZip(zipName);
+ p->internal=true;
+}
+
+void QuaZipFile::setZip(QuaZip *zip)
+{
+ if(isOpen()) {
+ qWarning("QuaZipFile::setZip(): file is already open - can not set ZIP");
+ return;
+ }
+ if(p->zip!=NULL && p->internal)
+ delete p->zip;
+ p->zip=zip;
+ p->fileName=QString();
+ p->internal=false;
+}
+
+void QuaZipFile::setFileName(const QString& fileName, QuaZip::CaseSensitivity cs)
+{
+ if(p->zip==NULL) {
+ qWarning("QuaZipFile::setFileName(): call setZipName() first");
+ return;
+ }
+ if(!p->internal) {
+ qWarning("QuaZipFile::setFileName(): should not be used when not using internal QuaZip");
+ return;
+ }
+ if(isOpen()) {
+ qWarning("QuaZipFile::setFileName(): can not set file name for already opened file");
+ return;
+ }
+ p->fileName=fileName;
+ if (p->fileName.startsWith('/'))
+ p->fileName = p->fileName.mid(1);
+ p->caseSensitivity=cs;
+}
+
+void QuaZipFilePrivate::setZipError(int zipError) const
+{
+ QuaZipFilePrivate *fakeThis = const_cast(this); // non-const
+ fakeThis->zipError=zipError;
+ if(zipError==UNZ_OK)
+ q->setErrorString(QString());
+ else
+ q->setErrorString(QuaZipFile::tr("ZIP/UNZIP API error %1").arg(zipError));
+}
+
+bool QuaZipFile::open(OpenMode mode)
+{
+ return open(mode, NULL);
+}
+
+bool QuaZipFile::open(OpenMode mode, int *method, int *level, bool raw, const char *password)
+{
+ p->resetZipError();
+ if(isOpen()) {
+ qWarning("QuaZipFile::open(): already opened");
+ return false;
+ }
+ if(mode&Unbuffered) {
+ qWarning("QuaZipFile::open(): Unbuffered mode is not supported");
+ return false;
+ }
+ if((mode&ReadOnly)&&!(mode&WriteOnly)) {
+ if(p->internal) {
+ if(!p->zip->open(QuaZip::mdUnzip)) {
+ p->setZipError(p->zip->getZipError());
+ return false;
+ }
+ if(!p->zip->setCurrentFile(p->fileName, p->caseSensitivity)) {
+ p->setZipError(p->zip->getZipError());
+ p->zip->close();
+ return false;
+ }
+ } else {
+ if(p->zip==NULL) {
+ qWarning("QuaZipFile::open(): zip is NULL");
+ return false;
+ }
+ if(p->zip->getMode()!=QuaZip::mdUnzip) {
+ qWarning("QuaZipFile::open(): file open mode %d incompatible with ZIP open mode %d",
+ (int)mode, (int)p->zip->getMode());
+ return false;
+ }
+ if(!p->zip->hasCurrentFile()) {
+ qWarning("QuaZipFile::open(): zip does not have current file");
+ return false;
+ }
+ }
+ p->setZipError(unzOpenCurrentFile3(p->zip->getUnzFile(), method, level, (int)raw, password));
+ if(p->zipError==UNZ_OK) {
+ setOpenMode(mode);
+ p->raw=raw;
+ return true;
+ } else
+ return false;
+ }
+ qWarning("QuaZipFile::open(): open mode %d not supported by this function", (int)mode);
+ return false;
+}
+
+bool QuaZipFile::open(OpenMode mode, const QuaZipNewInfo& info,
+ const char *password, quint32 crc,
+ int method, int level, bool raw,
+ int windowBits, int memLevel, int strategy)
+{
+ zip_fileinfo info_z;
+ p->resetZipError();
+ if(isOpen()) {
+ qWarning("QuaZipFile::open(): already opened");
+ return false;
+ }
+ if((mode&WriteOnly)&&!(mode&ReadOnly)) {
+ if(p->internal) {
+ qWarning("QuaZipFile::open(): write mode is incompatible with internal QuaZip approach");
+ return false;
+ }
+ if(p->zip==NULL) {
+ qWarning("QuaZipFile::open(): zip is NULL");
+ return false;
+ }
+ if(p->zip->getMode()!=QuaZip::mdCreate&&p->zip->getMode()!=QuaZip::mdAppend&&p->zip->getMode()!=QuaZip::mdAdd) {
+ qWarning("QuaZipFile::open(): file open mode %d incompatible with ZIP open mode %d",
+ (int)mode, (int)p->zip->getMode());
+ return false;
+ }
+ info_z.tmz_date.tm_year=info.dateTime.date().year();
+ info_z.tmz_date.tm_mon=info.dateTime.date().month() - 1;
+ info_z.tmz_date.tm_mday=info.dateTime.date().day();
+ info_z.tmz_date.tm_hour=info.dateTime.time().hour();
+ info_z.tmz_date.tm_min=info.dateTime.time().minute();
+ info_z.tmz_date.tm_sec=info.dateTime.time().second();
+ info_z.dosDate = 0;
+ info_z.internal_fa=(uLong)info.internalAttr;
+ info_z.external_fa=(uLong)info.externalAttr;
+ if (p->zip->isDataDescriptorWritingEnabled())
+ zipSetFlags(p->zip->getZipFile(), ZIP_WRITE_DATA_DESCRIPTOR);
+ else
+ zipClearFlags(p->zip->getZipFile(), ZIP_WRITE_DATA_DESCRIPTOR);
+ p->setZipError(zipOpenNewFileInZip3_64(p->zip->getZipFile(),
+ p->zip->getFileNameCodec()->fromUnicode(info.name).constData(), &info_z,
+ info.extraLocal.constData(), info.extraLocal.length(),
+ info.extraGlobal.constData(), info.extraGlobal.length(),
+ p->zip->getCommentCodec()->fromUnicode(info.comment).constData(),
+ method, level, (int)raw,
+ windowBits, memLevel, strategy,
+ password, (uLong)crc, p->zip->isZip64Enabled()));
+ if(p->zipError==UNZ_OK) {
+ p->writePos=0;
+ setOpenMode(mode);
+ p->raw=raw;
+ if(raw) {
+ p->crc=crc;
+ p->uncompressedSize=info.uncompressedSize;
+ }
+ return true;
+ } else
+ return false;
+ }
+ qWarning("QuaZipFile::open(): open mode %d not supported by this function", (int)mode);
+ return false;
+}
+
+bool QuaZipFile::isSequential()const
+{
+ return true;
+}
+
+qint64 QuaZipFile::pos()const
+{
+ if(p->zip==NULL) {
+ qWarning("QuaZipFile::pos(): call setZipName() or setZip() first");
+ return -1;
+ }
+ if(!isOpen()) {
+ qWarning("QuaZipFile::pos(): file is not open");
+ return -1;
+ }
+ if(openMode()&ReadOnly)
+ // QIODevice::pos() is broken for sequential devices,
+ // but thankfully bytesAvailable() returns the number of
+ // bytes buffered, so we know how far ahead we are.
+ return unztell64(p->zip->getUnzFile()) - QIODevice::bytesAvailable();
+ else
+ return p->writePos;
+}
+
+bool QuaZipFile::atEnd()const
+{
+ if(p->zip==NULL) {
+ qWarning("QuaZipFile::atEnd(): call setZipName() or setZip() first");
+ return false;
+ }
+ if(!isOpen()) {
+ qWarning("QuaZipFile::atEnd(): file is not open");
+ return false;
+ }
+ if(openMode()&ReadOnly)
+ // the same problem as with pos()
+ return QIODevice::bytesAvailable() == 0
+ && unzeof(p->zip->getUnzFile())==1;
+ else
+ return true;
+}
+
+qint64 QuaZipFile::size()const
+{
+ if(!isOpen()) {
+ qWarning("QuaZipFile::atEnd(): file is not open");
+ return -1;
+ }
+ if(openMode()&ReadOnly)
+ return p->raw?csize():usize();
+ else
+ return p->writePos;
+}
+
+qint64 QuaZipFile::csize()const
+{
+ unz_file_info64 info_z;
+ p->setZipError(UNZ_OK);
+ if(p->zip==NULL||p->zip->getMode()!=QuaZip::mdUnzip) return -1;
+ p->setZipError(unzGetCurrentFileInfo64(p->zip->getUnzFile(), &info_z, NULL, 0, NULL, 0, NULL, 0));
+ if(p->zipError!=UNZ_OK)
+ return -1;
+ return info_z.compressed_size;
+}
+
+qint64 QuaZipFile::usize()const
+{
+ unz_file_info64 info_z;
+ p->setZipError(UNZ_OK);
+ if(p->zip==NULL||p->zip->getMode()!=QuaZip::mdUnzip) return -1;
+ p->setZipError(unzGetCurrentFileInfo64(p->zip->getUnzFile(), &info_z, NULL, 0, NULL, 0, NULL, 0));
+ if(p->zipError!=UNZ_OK)
+ return -1;
+ return info_z.uncompressed_size;
+}
+
+bool QuaZipFile::getFileInfo(QuaZipFileInfo *info)
+{
+ QuaZipFileInfo64 info64;
+ if (getFileInfo(&info64)) {
+ info64.toQuaZipFileInfo(*info);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool QuaZipFile::getFileInfo(QuaZipFileInfo64 *info)
+{
+ if(p->zip==NULL||p->zip->getMode()!=QuaZip::mdUnzip) return false;
+ p->zip->getCurrentFileInfo(info);
+ p->setZipError(p->zip->getZipError());
+ return p->zipError==UNZ_OK;
+}
+
+void QuaZipFile::close()
+{
+ p->resetZipError();
+ if(p->zip==NULL||!p->zip->isOpen()) return;
+ if(!isOpen()) {
+ qWarning("QuaZipFile::close(): file isn't open");
+ return;
+ }
+ if(openMode()&ReadOnly)
+ p->setZipError(unzCloseCurrentFile(p->zip->getUnzFile()));
+ else if(openMode()&WriteOnly)
+ if(isRaw()) p->setZipError(zipCloseFileInZipRaw64(p->zip->getZipFile(), p->uncompressedSize, p->crc));
+ else p->setZipError(zipCloseFileInZip(p->zip->getZipFile()));
+ else {
+ qWarning("Wrong open mode: %d", (int)openMode());
+ return;
+ }
+ if(p->zipError==UNZ_OK) setOpenMode(QIODevice::NotOpen);
+ else return;
+ if(p->internal) {
+ p->zip->close();
+ p->setZipError(p->zip->getZipError());
+ }
+}
+
+qint64 QuaZipFile::readData(char *data, qint64 maxSize)
+{
+ p->setZipError(UNZ_OK);
+ qint64 bytesRead=unzReadCurrentFile(p->zip->getUnzFile(), data, (unsigned)maxSize);
+ if (bytesRead < 0) {
+ p->setZipError((int) bytesRead);
+ return -1;
+ }
+ return bytesRead;
+}
+
+qint64 QuaZipFile::writeData(const char* data, qint64 maxSize)
+{
+ p->setZipError(ZIP_OK);
+ p->setZipError(zipWriteInFileInZip(p->zip->getZipFile(), data, (uint)maxSize));
+ if(p->zipError!=ZIP_OK) return -1;
+ else {
+ p->writePos+=maxSize;
+ return maxSize;
+ }
+}
+
+QString QuaZipFile::getFileName() const
+{
+ return p->fileName;
+}
+
+QuaZip::CaseSensitivity QuaZipFile::getCaseSensitivity() const
+{
+ return p->caseSensitivity;
+}
+
+bool QuaZipFile::isRaw() const
+{
+ return p->raw;
+}
+
+int QuaZipFile::getZipError() const
+{
+ return p->zipError;
+}
+
+qint64 QuaZipFile::bytesAvailable() const
+{
+ return size() - pos();
+}
diff --git a/src/updater/quazip/quazipfile.h b/src/updater/quazip/quazipfile.h
new file mode 100644
index 0000000..e27b7a4
--- /dev/null
+++ b/src/updater/quazip/quazipfile.h
@@ -0,0 +1,456 @@
+#ifndef QUA_ZIPFILE_H
+#define QUA_ZIPFILE_H
+
+/*
+Copyright (C) 2005-2014 Sergey A. Tachenov
+
+This file is part of QuaZIP.
+
+QuaZIP is free software: you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation, either version 2.1 of the License, or
+(at your option) any later version.
+
+QuaZIP is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with QuaZIP. If not, see .
+
+See COPYING file for the full LGPL text.
+
+Original ZIP package is copyrighted by Gilles Vollant, see
+quazip/(un)zip.h files for details, basically it's zlib license.
+ **/
+
+#include
+
+#include "quazip_global.h"
+#include "quazip.h"
+#include "quazipnewinfo.h"
+
+class QuaZipFilePrivate;
+
+/// A file inside ZIP archive.
+/** \class QuaZipFile quazipfile.h
+ * This is the most interesting class. Not only it provides C++
+ * interface to the ZIP/UNZIP package, but also integrates it with Qt by
+ * subclassing QIODevice. This makes possible to access files inside ZIP
+ * archive using QTextStream or QDataStream, for example. Actually, this
+ * is the main purpose of the whole QuaZIP library.
+ *
+ * You can either use existing QuaZip instance to create instance of
+ * this class or pass ZIP archive file name to this class, in which case
+ * it will create internal QuaZip object. See constructors' descriptions
+ * for details. Writing is only possible with the existing instance.
+ *
+ * Note that due to the underlying library's limitation it is not
+ * possible to use multiple QuaZipFile instances to open several files
+ * in the same archive at the same time. If you need to write to
+ * multiple files in parallel, then you should write to temporary files
+ * first, then pack them all at once when you have finished writing. If
+ * you need to read multiple files inside the same archive in parallel,
+ * you should extract them all into a temporary directory first.
+ *
+ * \section quazipfile-sequential Sequential or random-access?
+ *
+ * At the first thought, QuaZipFile has fixed size, the start and the
+ * end and should be therefore considered random-access device. But
+ * there is one major obstacle to making it random-access: ZIP/UNZIP API
+ * does not support seek() operation and the only way to implement it is
+ * through reopening the file and re-reading to the required position,
+ * but this is prohibitively slow.
+ *
+ * Therefore, QuaZipFile is considered to be a sequential device. This
+ * has advantage of availability of the ungetChar() operation (QIODevice
+ * does not implement it properly for non-sequential devices unless they
+ * support seek()). Disadvantage is a somewhat strange behaviour of the
+ * size() and pos() functions. This should be kept in mind while using
+ * this class.
+ *
+ **/
+class QUAZIP_EXPORT QuaZipFile: public QIODevice {
+ friend class QuaZipFilePrivate;
+ Q_OBJECT
+ private:
+ QuaZipFilePrivate *p;
+ // these are not supported nor implemented
+ QuaZipFile(const QuaZipFile& that);
+ QuaZipFile& operator=(const QuaZipFile& that);
+ protected:
+ /// Implementation of the QIODevice::readData().
+ qint64 readData(char *data, qint64 maxSize);
+ /// Implementation of the QIODevice::writeData().
+ qint64 writeData(const char *data, qint64 maxSize);
+ public:
+ /// Constructs a QuaZipFile instance.
+ /** You should use setZipName() and setFileName() or setZip() before
+ * trying to call open() on the constructed object.
+ **/
+ QuaZipFile();
+ /// Constructs a QuaZipFile instance.
+ /** \a parent argument specifies this object's parent object.
+ *
+ * You should use setZipName() and setFileName() or setZip() before
+ * trying to call open() on the constructed object.
+ **/
+ QuaZipFile(QObject *parent);
+ /// Constructs a QuaZipFile instance.
+ /** \a parent argument specifies this object's parent object and \a
+ * zipName specifies ZIP archive file name.
+ *
+ * You should use setFileName() before trying to call open() on the
+ * constructed object.
+ *
+ * QuaZipFile constructed by this constructor can be used for read
+ * only access. Use QuaZipFile(QuaZip*,QObject*) for writing.
+ **/
+ QuaZipFile(const QString& zipName, QObject *parent =NULL);
+ /// Constructs a QuaZipFile instance.
+ /** \a parent argument specifies this object's parent object, \a
+ * zipName specifies ZIP archive file name and \a fileName and \a cs
+ * specify a name of the file to open inside archive.
+ *
+ * QuaZipFile constructed by this constructor can be used for read
+ * only access. Use QuaZipFile(QuaZip*,QObject*) for writing.
+ *
+ * \sa QuaZip::setCurrentFile()
+ **/
+ QuaZipFile(const QString& zipName, const QString& fileName,
+ QuaZip::CaseSensitivity cs =QuaZip::csDefault, QObject *parent =NULL);
+ /// Constructs a QuaZipFile instance.
+ /** \a parent argument specifies this object's parent object.
+ *
+ * \a zip is the pointer to the existing QuaZip object. This
+ * QuaZipFile object then can be used to read current file in the
+ * \a zip or to write to the file inside it.
+ *
+ * \warning Using this constructor for reading current file can be
+ * tricky. Let's take the following example:
+ * \code
+ * QuaZip zip("archive.zip");
+ * zip.open(QuaZip::mdUnzip);
+ * zip.setCurrentFile("file-in-archive");
+ * QuaZipFile file(&zip);
+ * file.open(QIODevice::ReadOnly);
+ * // ok, now we can read from the file
+ * file.read(somewhere, some);
+ * zip.setCurrentFile("another-file-in-archive"); // oops...
+ * QuaZipFile anotherFile(&zip);
+ * anotherFile.open(QIODevice::ReadOnly);
+ * anotherFile.read(somewhere, some); // this is still ok...
+ * file.read(somewhere, some); // and this is NOT
+ * \endcode
+ * So, what exactly happens here? When we change current file in the
+ * \c zip archive, \c file that references it becomes invalid
+ * (actually, as far as I understand ZIP/UNZIP sources, it becomes
+ * closed, but QuaZipFile has no means to detect it).
+ *
+ * Summary: do not close \c zip object or change its current file as
+ * long as QuaZipFile is open. Even better - use another constructors
+ * which create internal QuaZip instances, one per object, and
+ * therefore do not cause unnecessary trouble. This constructor may
+ * be useful, though, if you already have a QuaZip instance and do
+ * not want to access several files at once. Good example:
+ * \code
+ * QuaZip zip("archive.zip");
+ * zip.open(QuaZip::mdUnzip);
+ * // first, we need some information about archive itself
+ * QByteArray comment=zip.getComment();
+ * // and now we are going to access files inside it
+ * QuaZipFile file(&zip);
+ * for(bool more=zip.goToFirstFile(); more; more=zip.goToNextFile()) {
+ * file.open(QIODevice::ReadOnly);
+ * // do something cool with file here
+ * file.close(); // do not forget to close!
+ * }
+ * zip.close();
+ * \endcode
+ **/
+ QuaZipFile(QuaZip *zip, QObject *parent =NULL);
+ /// Destroys a QuaZipFile instance.
+ /** Closes file if open, destructs internal QuaZip object (if it
+ * exists and \em is internal, of course).
+ **/
+ virtual ~QuaZipFile();
+ /// Returns the ZIP archive file name.
+ /** If this object was created by passing QuaZip pointer to the
+ * constructor, this function will return that QuaZip's file name
+ * (or null string if that object does not have file name yet).
+ *
+ * Otherwise, returns associated ZIP archive file name or null
+ * string if there are no name set yet.
+ *
+ * \sa setZipName() getFileName()
+ **/
+ QString getZipName()const;
+ /// Returns a pointer to the associated QuaZip object.
+ /** Returns \c NULL if there is no associated QuaZip or it is
+ * internal (so you will not mess with it).
+ **/
+ QuaZip* getZip()const;
+ /// Returns file name.
+ /** This function returns file name you passed to this object either
+ * by using
+ * QuaZipFile(const QString&,const QString&,QuaZip::CaseSensitivity,QObject*)
+ * or by calling setFileName(). Real name of the file may differ in
+ * case if you used case-insensitivity.
+ *
+ * Returns null string if there is no file name set yet. This is the
+ * case when this QuaZipFile operates on the existing QuaZip object
+ * (constructor QuaZipFile(QuaZip*,QObject*) or setZip() was used).
+ *
+ * \sa getActualFileName
+ **/
+ QString getFileName() const;
+ /// Returns case sensitivity of the file name.
+ /** This function returns case sensitivity argument you passed to
+ * this object either by using
+ * QuaZipFile(const QString&,const QString&,QuaZip::CaseSensitivity,QObject*)
+ * or by calling setFileName().
+ *
+ * Returns unpredictable value if getFileName() returns null string
+ * (this is the case when you did not used setFileName() or
+ * constructor above).
+ *
+ * \sa getFileName
+ **/
+ QuaZip::CaseSensitivity getCaseSensitivity() const;
+ /// Returns the actual file name in the archive.
+ /** This is \em not a ZIP archive file name, but a name of file inside
+ * archive. It is not necessary the same name that you have passed
+ * to the
+ * QuaZipFile(const QString&,const QString&,QuaZip::CaseSensitivity,QObject*),
+ * setFileName() or QuaZip::setCurrentFile() - this is the real file
+ * name inside archive, so it may differ in case if the file name
+ * search was case-insensitive.
+ *
+ * Equivalent to calling getCurrentFileName() on the associated
+ * QuaZip object. Returns null string if there is no associated
+ * QuaZip object or if it does not have a current file yet. And this
+ * is the case if you called setFileName() but did not open the
+ * file yet. So this is perfectly fine:
+ * \code
+ * QuaZipFile file("somezip.zip");
+ * file.setFileName("somefile");
+ * QString name=file.getName(); // name=="somefile"
+ * QString actual=file.getActualFileName(); // actual is null string
+ * file.open(QIODevice::ReadOnly);
+ * QString actual=file.getActualFileName(); // actual can be "SoMeFiLe" on Windows
+ * \endcode
+ *
+ * \sa getZipName(), getFileName(), QuaZip::CaseSensitivity
+ **/
+ QString getActualFileName()const;
+ /// Sets the ZIP archive file name.
+ /** Automatically creates internal QuaZip object and destroys
+ * previously created internal QuaZip object, if any.
+ *
+ * Will do nothing if this file is already open. You must close() it
+ * first.
+ **/
+ void setZipName(const QString& zipName);
+ /// Returns \c true if the file was opened in raw mode.
+ /** If the file is not open, the returned value is undefined.
+ *
+ * \sa open(OpenMode,int*,int*,bool,const char*)
+ **/
+ bool isRaw() const;
+ /// Binds to the existing QuaZip instance.
+ /** This function destroys internal QuaZip object, if any, and makes
+ * this QuaZipFile to use current file in the \a zip object for any
+ * further operations. See QuaZipFile(QuaZip*,QObject*) for the
+ * possible pitfalls.
+ *
+ * Will do nothing if the file is currently open. You must close()
+ * it first.
+ **/
+ void setZip(QuaZip *zip);
+ /// Sets the file name.
+ /** Will do nothing if at least one of the following conditions is
+ * met:
+ * - ZIP name has not been set yet (getZipName() returns null
+ * string).
+ * - This QuaZipFile is associated with external QuaZip. In this
+ * case you should call that QuaZip's setCurrentFile() function
+ * instead!
+ * - File is already open so setting the name is meaningless.
+ *
+ * \sa QuaZip::setCurrentFile
+ **/
+ void setFileName(const QString& fileName, QuaZip::CaseSensitivity cs =QuaZip::csDefault);
+ /// Opens a file for reading.
+ /** Returns \c true on success, \c false otherwise.
+ * Call getZipError() to get error code.
+ *
+ * \note Since ZIP/UNZIP API provides buffered reading only,
+ * QuaZipFile does not support unbuffered reading. So do not pass
+ * QIODevice::Unbuffered flag in \a mode, or open will fail.
+ **/
+ virtual bool open(OpenMode mode);
+ /// Opens a file for reading.
+ /** \overload
+ * Argument \a password specifies a password to decrypt the file. If
+ * it is NULL then this function behaves just like open(OpenMode).
+ **/
+ inline bool open(OpenMode mode, const char *password)
+ {return open(mode, NULL, NULL, false, password);}
+ /// Opens a file for reading.
+ /** \overload
+ * Argument \a password specifies a password to decrypt the file.
+ *
+ * An integers pointed by \a method and \a level will receive codes
+ * of the compression method and level used. See unzip.h.
+ *
+ * If raw is \c true then no decompression is performed.
+ *
+ * \a method should not be \c NULL. \a level can be \c NULL if you
+ * don't want to know the compression level.
+ **/
+ bool open(OpenMode mode, int *method, int *level, bool raw, const char *password =NULL);
+ /// Opens a file for writing.
+ /** \a info argument specifies information about file. It should at
+ * least specify a correct file name. Also, it is a good idea to
+ * specify correct timestamp (by default, current time will be
+ * used). See QuaZipNewInfo.
+ *
+ * The \a password argument specifies the password for crypting. Pass NULL
+ * if you don't need any crypting. The \a crc argument was supposed
+ * to be used for crypting too, but then it turned out that it's
+ * false information, so you need to set it to 0 unless you want to
+ * use the raw mode (see below).
+ *
+ * Arguments \a method and \a level specify compression method and
+ * level. The only method supported is Z_DEFLATED, but you may also
+ * specify 0 for no compression. If all of the files in the archive
+ * use both method 0 and either level 0 is explicitly specified or
+ * data descriptor writing is disabled with
+ * QuaZip::setDataDescriptorWritingEnabled(), then the
+ * resulting archive is supposed to be compatible with the 1.0 ZIP
+ * format version, should you need that. Except for this, \a level
+ * has no other effects with method 0.
+ *
+ * If \a raw is \c true, no compression is performed. In this case,
+ * \a crc and uncompressedSize field of the \a info are required.
+ *
+ * Arguments \a windowBits, \a memLevel, \a strategy provide zlib
+ * algorithms tuning. See deflateInit2() in zlib.
+ **/
+ bool open(OpenMode mode, const QuaZipNewInfo& info,
+ const char *password =NULL, quint32 crc =0,
+ int method =Z_DEFLATED, int level =Z_DEFAULT_COMPRESSION, bool raw =false,
+ int windowBits =-MAX_WBITS, int memLevel =DEF_MEM_LEVEL, int strategy =Z_DEFAULT_STRATEGY);
+ /// Returns \c true, but \ref quazipfile-sequential "beware"!
+ virtual bool isSequential()const;
+ /// Returns current position in the file.
+ /** Implementation of the QIODevice::pos(). When reading, this
+ * function is a wrapper to the ZIP/UNZIP unztell(), therefore it is
+ * unable to keep track of the ungetChar() calls (which is
+ * non-virtual and therefore is dangerous to reimplement). So if you
+ * are using ungetChar() feature of the QIODevice, this function
+ * reports incorrect value until you get back characters which you
+ * ungot.
+ *
+ * When writing, pos() returns number of bytes already written
+ * (uncompressed unless you use raw mode).
+ *
+ * \note Although
+ * \ref quazipfile-sequential "QuaZipFile is a sequential device"
+ * and therefore pos() should always return zero, it does not,
+ * because it would be misguiding. Keep this in mind.
+ *
+ * This function returns -1 if the file or archive is not open.
+ *
+ * Error code returned by getZipError() is not affected by this
+ * function call.
+ **/
+ virtual qint64 pos()const;
+ /// Returns \c true if the end of file was reached.
+ /** This function returns \c false in the case of error. This means
+ * that you called this function on either not open file, or a file
+ * in the not open archive or even on a QuaZipFile instance that
+ * does not even have QuaZip instance associated. Do not do that
+ * because there is no means to determine whether \c false is
+ * returned because of error or because end of file was reached.
+ * Well, on the other side you may interpret \c false return value
+ * as "there is no file open to check for end of file and there is
+ * no end of file therefore".
+ *
+ * When writing, this function always returns \c true (because you
+ * are always writing to the end of file).
+ *
+ * Error code returned by getZipError() is not affected by this
+ * function call.
+ **/
+ virtual bool atEnd()const;
+ /// Returns file size.
+ /** This function returns csize() if the file is open for reading in
+ * raw mode, usize() if it is open for reading in normal mode and
+ * pos() if it is open for writing.
+ *
+ * Returns -1 on error, call getZipError() to get error code.
+ *
+ * \note This function returns file size despite that
+ * \ref quazipfile-sequential "QuaZipFile is considered to be sequential device",
+ * for which size() should return bytesAvailable() instead. But its
+ * name would be very misguiding otherwise, so just keep in mind
+ * this inconsistence.
+ **/
+ virtual qint64 size()const;
+ /// Returns compressed file size.
+ /** Equivalent to calling getFileInfo() and then getting
+ * compressedSize field, but more convenient and faster.
+ *
+ * File must be open for reading before calling this function.
+ *
+ * Returns -1 on error, call getZipError() to get error code.
+ **/
+ qint64 csize()const;
+ /// Returns uncompressed file size.
+ /** Equivalent to calling getFileInfo() and then getting
+ * uncompressedSize field, but more convenient and faster. See
+ * getFileInfo() for a warning.
+ *
+ * File must be open for reading before calling this function.
+ *
+ * Returns -1 on error, call getZipError() to get error code.
+ **/
+ qint64 usize()const;
+ /// Gets information about current file.
+ /** This function does the same thing as calling
+ * QuaZip::getCurrentFileInfo() on the associated QuaZip object,
+ * but you can not call getCurrentFileInfo() if the associated
+ * QuaZip is internal (because you do not have access to it), while
+ * you still can call this function in that case.
+ *
+ * File must be open for reading before calling this function.
+ *
+ * \return \c false in the case of an error.
+ *
+ * This function doesn't support zip64, but will still work fine on zip64
+ * archives if file sizes are below 4 GB, otherwise the values will be set
+ * as if converted using QuaZipFileInfo64::toQuaZipFileInfo().
+ *
+ * \sa getFileInfo(QuaZipFileInfo64*)
+ **/
+ bool getFileInfo(QuaZipFileInfo *info);
+ /// Gets information about current file with zip64 support.
+ /**
+ * @overload
+ *
+ * \sa getFileInfo(QuaZipFileInfo*)
+ */
+ bool getFileInfo(QuaZipFileInfo64 *info);
+ /// Closes the file.
+ /** Call getZipError() to determine if the close was successful.
+ **/
+ virtual void close();
+ /// Returns the error code returned by the last ZIP/UNZIP API call.
+ int getZipError() const;
+ /// Returns the number of bytes available for reading.
+ virtual qint64 bytesAvailable() const;
+};
+
+#endif
diff --git a/src/updater/quazip/quazipfileinfo.cpp b/src/updater/quazip/quazipfileinfo.cpp
new file mode 100644
index 0000000..f11c910
--- /dev/null
+++ b/src/updater/quazip/quazipfileinfo.cpp
@@ -0,0 +1,176 @@
+/*
+Copyright (C) 2005-2014 Sergey A. Tachenov
+
+This file is part of QuaZIP.
+
+QuaZIP is free software: you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation, either version 2.1 of the License, or
+(at your option) any later version.
+
+QuaZIP is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with QuaZIP. If not, see .
+
+See COPYING file for the full LGPL text.
+
+Original ZIP package is copyrighted by Gilles Vollant and contributors,
+see quazip/(un)zip.h files for details. Basically it's the zlib license.
+*/
+
+#include "quazipfileinfo.h"
+
+static QFile::Permissions permissionsFromExternalAttr(quint32 externalAttr) {
+ quint32 uPerm = (externalAttr & 0xFFFF0000u) >> 16;
+ QFile::Permissions perm = 0;
+ if ((uPerm & 0400) != 0)
+ perm |= QFile::ReadOwner;
+ if ((uPerm & 0200) != 0)
+ perm |= QFile::WriteOwner;
+ if ((uPerm & 0100) != 0)
+ perm |= QFile::ExeOwner;
+ if ((uPerm & 0040) != 0)
+ perm |= QFile::ReadGroup;
+ if ((uPerm & 0020) != 0)
+ perm |= QFile::WriteGroup;
+ if ((uPerm & 0010) != 0)
+ perm |= QFile::ExeGroup;
+ if ((uPerm & 0004) != 0)
+ perm |= QFile::ReadOther;
+ if ((uPerm & 0002) != 0)
+ perm |= QFile::WriteOther;
+ if ((uPerm & 0001) != 0)
+ perm |= QFile::ExeOther;
+ return perm;
+
+}
+
+QFile::Permissions QuaZipFileInfo::getPermissions() const
+{
+ return permissionsFromExternalAttr(externalAttr);
+}
+
+QFile::Permissions QuaZipFileInfo64::getPermissions() const
+{
+ return permissionsFromExternalAttr(externalAttr);
+}
+
+bool QuaZipFileInfo64::toQuaZipFileInfo(QuaZipFileInfo &info) const
+{
+ bool noOverflow = true;
+ info.name = name;
+ info.versionCreated = versionCreated;
+ info.versionNeeded = versionNeeded;
+ info.flags = flags;
+ info.method = method;
+ info.dateTime = dateTime;
+ info.crc = crc;
+ if (compressedSize > 0xFFFFFFFFu) {
+ info.compressedSize = 0xFFFFFFFFu;
+ noOverflow = false;
+ } else {
+ info.compressedSize = compressedSize;
+ }
+ if (uncompressedSize > 0xFFFFFFFFu) {
+ info.uncompressedSize = 0xFFFFFFFFu;
+ noOverflow = false;
+ } else {
+ info.uncompressedSize = uncompressedSize;
+ }
+ info.diskNumberStart = diskNumberStart;
+ info.internalAttr = internalAttr;
+ info.externalAttr = externalAttr;
+ info.comment = comment;
+ info.extra = extra;
+ return noOverflow;
+}
+
+static QDateTime getNTFSTime(const QByteArray &extra, int position,
+ int *fineTicks)
+{
+ QDateTime dateTime;
+ for (int i = 0; i <= extra.size() - 4; ) {
+ unsigned type = static_cast(static_cast(
+ extra.at(i)))
+ | (static_cast(static_cast(
+ extra.at(i + 1))) << 8);
+ i += 2;
+ unsigned length = static_cast(static_cast(
+ extra.at(i)))
+ | (static_cast(static_cast(
+ extra.at(i + 1))) << 8);
+ i += 2;
+ if (type == QUAZIP_EXTRA_NTFS_MAGIC && length >= 32) {
+ i += 4; // reserved
+ while (i <= extra.size() - 4) {
+ unsigned tag = static_cast(
+ static_cast(extra.at(i)))
+ | (static_cast(
+ static_cast(extra.at(i + 1)))
+ << 8);
+ i += 2;
+ int tagsize = static_cast(
+ static_cast(extra.at(i)))
+ | (static_cast(
+ static_cast(extra.at(i + 1)))
+ << 8);
+ i += 2;
+ if (tag == QUAZIP_EXTRA_NTFS_TIME_MAGIC
+ && tagsize >= position + 8) {
+ i += position;
+ quint64 mtime = static_cast(
+ static_cast(extra.at(i)))
+ | (static_cast(static_cast(
+ extra.at(i + 1))) << 8)
+ | (static_cast(static_cast(
+ extra.at(i + 2))) << 16)
+ | (static_cast(static_cast(
+ extra.at(i + 3))) << 24)
+ | (static_cast(static_cast(
+ extra.at(i + 4))) << 32)
+ | (static_cast(static_cast(
+ extra.at(i + 5))) << 40)
+ | (static_cast(static_cast(
+ extra.at(i + 6))) << 48)
+ | (static_cast(static_cast(
+ extra.at(i + 7))) << 56);
+ // the NTFS time is measured from 1601 for whatever reason
+ QDateTime base(QDate(1601, 1, 1), QTime(0, 0), Qt::UTC);
+ dateTime = base.addMSecs(mtime / 10000);
+ if (fineTicks != NULL) {
+ *fineTicks = static_cast(mtime % 10000);
+ }
+ i += tagsize - position;
+ } else {
+ i += tagsize;
+ }
+
+ }
+ } else {
+ i += length;
+ }
+ }
+ if (fineTicks != NULL && dateTime.isNull()) {
+ *fineTicks = 0;
+ }
+ return dateTime;
+}
+
+QDateTime QuaZipFileInfo64::getNTFSmTime(int *fineTicks) const
+{
+ return getNTFSTime(extra, 0, fineTicks);
+}
+
+QDateTime QuaZipFileInfo64::getNTFSaTime(int *fineTicks) const
+{
+ return getNTFSTime(extra, 8, fineTicks);
+}
+
+QDateTime QuaZipFileInfo64::getNTFScTime(int *fineTicks) const
+{
+ return getNTFSTime(extra, 16, fineTicks);
+}
diff --git a/src/updater/quazip/quazipfileinfo.h b/src/updater/quazip/quazipfileinfo.h
new file mode 100644
index 0000000..4e142a4
--- /dev/null
+++ b/src/updater/quazip/quazipfileinfo.h
@@ -0,0 +1,178 @@
+#ifndef QUA_ZIPFILEINFO_H
+#define QUA_ZIPFILEINFO_H
+
+/*
+Copyright (C) 2005-2014 Sergey A. Tachenov
+
+This file is part of QuaZIP.
+
+QuaZIP is free software: you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation, either version 2.1 of the License, or
+(at your option) any later version.
+
+QuaZIP is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with QuaZIP. If not, see .
+
+See COPYING file for the full LGPL text.
+
+Original ZIP package is copyrighted by Gilles Vollant and contributors,
+see quazip/(un)zip.h files for details. Basically it's the zlib license.
+*/
+
+#include
+#include
+#include
+
+#include "quazip_global.h"
+
+/// Information about a file inside archive.
+/**
+ * \deprecated Use QuaZipFileInfo64 instead. Not only it supports large files,
+ * but also more convenience methods as well.
+ *
+ * Call QuaZip::getCurrentFileInfo() or QuaZipFile::getFileInfo() to
+ * fill this structure. */
+struct QUAZIP_EXPORT QuaZipFileInfo {
+ /// File name.
+ QString name;
+ /// Version created by.
+ quint16 versionCreated;
+ /// Version needed to extract.
+ quint16 versionNeeded;
+ /// General purpose flags.
+ quint16 flags;
+ /// Compression method.
+ quint16 method;
+ /// Last modification date and time.
+ QDateTime dateTime;
+ /// CRC.
+ quint32 crc;
+ /// Compressed file size.
+ quint32 compressedSize;
+ /// Uncompressed file size.
+ quint32 uncompressedSize;
+ /// Disk number start.
+ quint16 diskNumberStart;
+ /// Internal file attributes.
+ quint16 internalAttr;
+ /// External file attributes.
+ quint32 externalAttr;
+ /// Comment.
+ QString comment;
+ /// Extra field.
+ QByteArray extra;
+ /// Get the file permissions.
+ /**
+ Returns the high 16 bits of external attributes converted to
+ QFile::Permissions.
+ */
+ QFile::Permissions getPermissions() const;
+};
+
+/// Information about a file inside archive (with zip64 support).
+/** Call QuaZip::getCurrentFileInfo() or QuaZipFile::getFileInfo() to
+ * fill this structure. */
+struct QUAZIP_EXPORT QuaZipFileInfo64 {
+ /// File name.
+ QString name;
+ /// Version created by.
+ quint16 versionCreated;
+ /// Version needed to extract.
+ quint16 versionNeeded;
+ /// General purpose flags.
+ quint16 flags;
+ /// Compression method.
+ quint16 method;
+ /// Last modification date and time.
+ /**
+ * This is the time stored in the standard ZIP header. This format only allows
+ * to store time with 2-second precision, so the seconds will always be even
+ * and the milliseconds will always be zero. If you need more precise
+ * date and time, you can try to call the getNTFSmTime() function or
+ * its siblings, provided that the archive itself contains these NTFS times.
+ */
+ QDateTime dateTime;
+ /// CRC.
+ quint32 crc;
+ /// Compressed file size.
+ quint64 compressedSize;
+ /// Uncompressed file size.
+ quint64 uncompressedSize;
+ /// Disk number start.
+ quint16 diskNumberStart;
+ /// Internal file attributes.
+ quint16 internalAttr;
+ /// External file attributes.
+ quint32 externalAttr;
+ /// Comment.
+ QString comment;
+ /// Extra field.
+ QByteArray extra;
+ /// Get the file permissions.
+ /**
+ Returns the high 16 bits of external attributes converted to
+ QFile::Permissions.
+ */
+ QFile::Permissions getPermissions() const;
+ /// Converts to QuaZipFileInfo
+ /**
+ If any of the fields are greater than 0xFFFFFFFFu, they are set to
+ 0xFFFFFFFFu exactly, not just truncated. This function should be mainly used
+ for compatibility with the old code expecting QuaZipFileInfo, in the cases
+ when it's impossible or otherwise unadvisable (due to ABI compatibility
+ reasons, for example) to modify that old code to use QuaZipFileInfo64.
+
+ \return \c true if all fields converted correctly, \c false if an overflow
+ occured.
+ */
+ bool toQuaZipFileInfo(QuaZipFileInfo &info) const;
+ /// Returns the NTFS modification time
+ /**
+ * The getNTFS*Time() functions only work if there is an NTFS extra field
+ * present. Otherwise, they all return invalid null timestamps.
+ * @param fineTicks If not NULL, the fractional part of milliseconds returned
+ * there, measured in 100-nanosecond ticks. Will be set to
+ * zero if there is no NTFS extra field.
+ * @sa dateTime
+ * @sa getNTFSaTime()
+ * @sa getNTFScTime()
+ * @return The NTFS modification time, UTC
+ */
+ QDateTime getNTFSmTime(int *fineTicks = NULL) const;
+ /// Returns the NTFS access time
+ /**
+ * The getNTFS*Time() functions only work if there is an NTFS extra field
+ * present. Otherwise, they all return invalid null timestamps.
+ * @param fineTicks If not NULL, the fractional part of milliseconds returned
+ * there, measured in 100-nanosecond ticks. Will be set to
+ * zero if there is no NTFS extra field.
+ * @sa dateTime
+ * @sa getNTFSmTime()
+ * @sa getNTFScTime()
+ * @return The NTFS access time, UTC
+ */
+ QDateTime getNTFSaTime(int *fineTicks = NULL) const;
+ /// Returns the NTFS creation time
+ /**
+ * The getNTFS*Time() functions only work if there is an NTFS extra field
+ * present. Otherwise, they all return invalid null timestamps.
+ * @param fineTicks If not NULL, the fractional part of milliseconds returned
+ * there, measured in 100-nanosecond ticks. Will be set to
+ * zero if there is no NTFS extra field.
+ * @sa dateTime
+ * @sa getNTFSmTime()
+ * @sa getNTFSaTime()
+ * @return The NTFS creation time, UTC
+ */
+ QDateTime getNTFScTime(int *fineTicks = NULL) const;
+ /// Checks whether the file is encrypted.
+ bool isEncrypted() const {return (flags & 1) != 0;}
+};
+
+#endif
diff --git a/src/updater/quazip/quazipnewinfo.cpp b/src/updater/quazip/quazipnewinfo.cpp
new file mode 100644
index 0000000..8015d92
--- /dev/null
+++ b/src/updater/quazip/quazipnewinfo.cpp
@@ -0,0 +1,286 @@
+/*
+Copyright (C) 2005-2014 Sergey A. Tachenov
+
+This file is part of QuaZIP.
+
+QuaZIP is free software: you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation, either version 2.1 of the License, or
+(at your option) any later version.
+
+QuaZIP is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with QuaZIP. If not, see .
+
+See COPYING file for the full LGPL text.
+
+Original ZIP package is copyrighted by Gilles Vollant and contributors,
+see quazip/(un)zip.h files for details. Basically it's the zlib license.
+*/
+
+#include
+
+#include "quazipnewinfo.h"
+
+#include
+
+static void QuaZipNewInfo_setPermissions(QuaZipNewInfo *info,
+ QFile::Permissions perm, bool isDir, bool isSymLink = false)
+{
+ quint32 uPerm = isDir ? 0040000 : 0100000;
+
+ if ( isSymLink ) {
+#ifdef Q_OS_WIN
+ uPerm = 0200000;
+#else
+ uPerm = 0120000;
+#endif
+ }
+
+ if ((perm & QFile::ReadOwner) != 0)
+ uPerm |= 0400;
+ if ((perm & QFile::WriteOwner) != 0)
+ uPerm |= 0200;
+ if ((perm & QFile::ExeOwner) != 0)
+ uPerm |= 0100;
+ if ((perm & QFile::ReadGroup) != 0)
+ uPerm |= 0040;
+ if ((perm & QFile::WriteGroup) != 0)
+ uPerm |= 0020;
+ if ((perm & QFile::ExeGroup) != 0)
+ uPerm |= 0010;
+ if ((perm & QFile::ReadOther) != 0)
+ uPerm |= 0004;
+ if ((perm & QFile::WriteOther) != 0)
+ uPerm |= 0002;
+ if ((perm & QFile::ExeOther) != 0)
+ uPerm |= 0001;
+ info->externalAttr = (info->externalAttr & ~0xFFFF0000u) | (uPerm << 16);
+}
+
+template
+void QuaZipNewInfo_init(QuaZipNewInfo &self, const FileInfo &existing)
+{
+ self.name = existing.name;
+ self.dateTime = existing.dateTime;
+ self.internalAttr = existing.internalAttr;
+ self.externalAttr = existing.externalAttr;
+ self.comment = existing.comment;
+ self.extraLocal = existing.extra;
+ self.extraGlobal = existing.extra;
+ self.uncompressedSize = existing.uncompressedSize;
+}
+
+QuaZipNewInfo::QuaZipNewInfo(const QuaZipFileInfo &existing)
+{
+ QuaZipNewInfo_init(*this, existing);
+}
+
+QuaZipNewInfo::QuaZipNewInfo(const QuaZipFileInfo64 &existing)
+{
+ QuaZipNewInfo_init(*this, existing);
+}
+
+QuaZipNewInfo::QuaZipNewInfo(const QString& name):
+ name(name), dateTime(QDateTime::currentDateTime()), internalAttr(0), externalAttr(0),
+ uncompressedSize(0)
+{
+}
+
+QuaZipNewInfo::QuaZipNewInfo(const QString& name, const QString& file):
+ name(name), internalAttr(0), externalAttr(0), uncompressedSize(0)
+{
+ QFileInfo info(file);
+ QDateTime lm = info.lastModified();
+ if (!info.exists()) {
+ dateTime = QDateTime::currentDateTime();
+ } else {
+ dateTime = lm;
+ QuaZipNewInfo_setPermissions(this, info.permissions(), info.isDir(), info.isSymLink());
+ }
+}
+
+void QuaZipNewInfo::setFileDateTime(const QString& file)
+{
+ QFileInfo info(file);
+ QDateTime lm = info.lastModified();
+ if (info.exists())
+ dateTime = lm;
+}
+
+void QuaZipNewInfo::setFilePermissions(const QString &file)
+{
+ QFileInfo info = QFileInfo(file);
+ QFile::Permissions perm = info.permissions();
+ QuaZipNewInfo_setPermissions(this, perm, info.isDir(), info.isSymLink());
+}
+
+void QuaZipNewInfo::setPermissions(QFile::Permissions permissions)
+{
+ QuaZipNewInfo_setPermissions(this, permissions, name.endsWith('/'));
+}
+
+void QuaZipNewInfo::setFileNTFSTimes(const QString &fileName)
+{
+ QFileInfo fi(fileName);
+ if (!fi.exists()) {
+ qWarning("QuaZipNewInfo::setFileNTFSTimes(): '%s' doesn't exist",
+ fileName.toUtf8().constData());
+ return;
+ }
+ setFileNTFSmTime(fi.lastModified());
+ setFileNTFSaTime(fi.lastRead());
+ setFileNTFScTime(fi.created());
+}
+
+static void setNTFSTime(QByteArray &extra, const QDateTime &time, int position,
+ int fineTicks) {
+ int ntfsPos = -1, timesPos = -1;
+ unsigned ntfsLength = 0, ntfsTimesLength = 0;
+ for (int i = 0; i <= extra.size() - 4; ) {
+ unsigned type = static_cast(static_cast(
+ extra.at(i)))
+ | (static_cast(static_cast(
+ extra.at(i + 1))) << 8);
+ i += 2;
+ unsigned length = static_cast(static_cast(
+ extra.at(i)))
+ | (static_cast(static_cast(
+ extra.at(i + 1))) << 8);
+ i += 2;
+ if (type == QUAZIP_EXTRA_NTFS_MAGIC) {
+ ntfsPos = i - 4; // the beginning of the NTFS record
+ ntfsLength = length;
+ if (length <= 4) {
+ break; // no times in the NTFS record
+ }
+ i += 4; // reserved
+ while (i <= extra.size() - 4) {
+ unsigned tag = static_cast(
+ static_cast(extra.at(i)))
+ | (static_cast(
+ static_cast(extra.at(i + 1)))
+ << 8);
+ i += 2;
+ unsigned tagsize = static_cast(
+ static_cast(extra.at(i)))
+ | (static_cast(
+ static_cast(extra.at(i + 1)))
+ << 8);
+ i += 2;
+ if (tag == QUAZIP_EXTRA_NTFS_TIME_MAGIC) {
+ timesPos = i - 4; // the beginning of the NTFS times tag
+ ntfsTimesLength = tagsize;
+ break;
+ } else {
+ i += tagsize;
+ }
+ }
+ break; // I ain't going to search for yet another NTFS record!
+ } else {
+ i += length;
+ }
+ }
+ if (ntfsPos == -1) {
+ // No NTFS record, need to create one.
+ ntfsPos = extra.size();
+ ntfsLength = 32;
+ extra.resize(extra.size() + 4 + ntfsLength);
+ // the NTFS record header
+ extra[ntfsPos] = static_cast(QUAZIP_EXTRA_NTFS_MAGIC);
+ extra[ntfsPos + 1] = static_cast(QUAZIP_EXTRA_NTFS_MAGIC >> 8);
+ extra[ntfsPos + 2] = 32; // the 2-byte size in LittleEndian
+ extra[ntfsPos + 3] = 0;
+ // zero the record
+ memset(extra.data() + ntfsPos + 4, 0, 32);
+ timesPos = ntfsPos + 8;
+ // now set the tag data
+ extra[timesPos] = static_cast(QUAZIP_EXTRA_NTFS_TIME_MAGIC);
+ extra[timesPos + 1] = static_cast(QUAZIP_EXTRA_NTFS_TIME_MAGIC
+ >> 8);
+ // the size:
+ extra[timesPos + 2] = 24;
+ extra[timesPos + 3] = 0;
+ ntfsTimesLength = 24;
+ }
+ if (timesPos == -1) {
+ // No time tag in the NTFS record, need to add one.
+ timesPos = ntfsPos + 4 + ntfsLength;
+ extra.resize(extra.size() + 28);
+ // Now we need to move the rest of the field
+ // (possibly zero bytes, but memmove() is OK with that).
+ // 0 ......... ntfsPos .. ntfsPos + 4 ... timesPos
+ //
+ memmove(extra.data() + timesPos + 28, extra.data() + timesPos,
+ extra.size() - 28 - timesPos);
+ ntfsLength += 28;
+ // now set the tag data
+ extra[timesPos] = static_cast(QUAZIP_EXTRA_NTFS_TIME_MAGIC);
+ extra[timesPos + 1] = static_cast(QUAZIP_EXTRA_NTFS_TIME_MAGIC
+ >> 8);
+ // the size:
+ extra[timesPos + 2] = 24;
+ extra[timesPos + 3] = 0;
+ // zero the record
+ memset(extra.data() + timesPos + 4, 0, 24);
+ ntfsTimesLength = 24;
+ }
+ if (ntfsTimesLength < 24) {
+ // Broken times field. OK, this is really unlikely, but just in case...
+ size_t timesEnd = timesPos + 4 + ntfsTimesLength;
+ extra.resize(extra.size() + (24 - ntfsTimesLength));
+ // Move it!
+ // 0 ......... timesPos .... timesPos + 4 .. timesEnd
+ //