OSDN Git Service

Updated cURL binary to v7.69.1 (2020-03-11).
[x264-launcher/x264-launcher.git] / src / win_updater.cpp
index 57298d4..f34399a 100644 (file)
@@ -1,6 +1,6 @@
 ///////////////////////////////////////////////////////////////////////////////
 // Simple x264 Launcher
-// Copyright (C) 2004-2016 LoRd_MuldeR <MuldeR2@GMX.de>
+// Copyright (C) 2004-2020 LoRd_MuldeR <MuldeR2@GMX.de>
 //
 // This program is free software; you can redistribute it and/or modify
 // it under the terms of the GNU General Public License as published by
@@ -44,6 +44,7 @@
 #include <QFileInfo>
 #include <QDir>
 #include <QMap>
+#include <QElapsedTimer>
 
 ///////////////////////////////////////////////////////////////////////////////
 
@@ -51,11 +52,10 @@ static const char *const DIGEST_KEY = "~Dv/bW3/7t>6?RXVwkaZk-hmS0#O4JS/5YQAO>\\8
 
 const UpdaterDialog::binary_t UpdaterDialog::BINARIES[] =
 {
-       { "wget.exe", "35d70bf8a1799956b5de3975ff99088a4444a2d17202059afb63949b297e2cc81e5e49e2b95df1c4e26b49ab7430399c293bf805a0b250d686c6f4dd994a0764", 1 },
-       { "netc.exe", "2e890533473134e074d65e1670c4212a06e4f685c4ee202593b0427defdf2f01e4d22cf7b48855436f1c57109c131f3469daa1a523a5a05fc9d23fb41d2e6ea9", 1 },
-       { "gpgv.exe", "a8d4d1702e5fb1eee5a2c22fdaf255816a9199ae48142aeec1c8ce16bbcf61d6d634f1e769e62d05cf52c204ba2611f09c9bb661bc6688b937749d478af3e47d", 1 },
+       { "curl.exe", "4d51862b5df757e177a578fd6fabf631b78d9eccedfb71249db0dfb5c1b721f59f4eb7f7046e1c1054b76b9af7a0bed2479b09b7599df51236aee42c3625e67c", 1 },
+       { "gpgv.exe", "d0869bd858294520c992b66e1c7594176ebfb51bd64c4f50f782a4749118498a29c9fc70da5ed08cda9837ff7099d950428ca9f1968fa69883929bd0dba8c9e5", 1 },
        { "gpgv.gpg", "1a2f528e551b9abfb064f08674fdd421d3abe403469ddfee2beafd007775a6c684212a6274dc2b41a0b20dd5c2200021c91320e737f7a90b2ac5a40a6221d93f", 0 },
-       { "wupd.exe", "c7fe72259ae781889a18f688321275e3bae39d75fb96c9c650446e177cb3af3d3ea84db2c1590e44bc2440b2ea79f9684e3a14e47e57e6083ec6f98c5bf72a73", 1 },
+       { "wupd.exe", "018a8d0d848407fb0cb530b4540c6f025fd4c280885becd37f83feed8aeb3af6f8e8e0d45066a36549efac7e64706ac1ef09aaa5c75ab8d12c4a70f41518a894", 1 },
        { NULL, NULL, 0 }
 };
 
@@ -72,6 +72,20 @@ const UpdaterDialog::binary_t UpdaterDialog::BINARIES[] =
 } \
 while(0)
 
+static inline QString getBin(const QMap<QString, QSharedPointer<QFile>> &binaries, const QString &nameName)
+{
+       const QSharedPointer<QFile> file = binaries.value(nameName);
+       return file.isNull() ? QString() : file->fileName();
+}
+
+static void qFileDeleter(QFile *const file)
+{
+       if(file)
+       {
+               file->close();
+               delete file;
+       }
+}
 
 ///////////////////////////////////////////////////////////////////////////////
 // Constructor & Destructor
@@ -93,7 +107,8 @@ UpdaterDialog::UpdaterDialog(QWidget *parent, const SysinfoModel *sysinfo, const
        ui->setupUi(this);
        setWindowFlags(windowFlags() & (~Qt::WindowContextHelpButtonHint));
 
-       //Fix size
+       //Scale and fix size
+       MUtils::GUI::scale_widget(this);
        setFixedSize(size());
 
        //Enable buttons
@@ -112,6 +127,7 @@ UpdaterDialog::UpdaterDialog(QWidget *parent, const SysinfoModel *sysinfo, const
        ui->buttonCancel->setEnabled(false);
        ui->buttonRetry->hide();
        ui->buttonDownload->hide();
+       ui->labelCancel->hide();
 
        //Start animation
        SHOW_ANIMATION(true);
@@ -127,18 +143,10 @@ UpdaterDialog::~UpdaterDialog(void)
                        m_thread->wait();
                }
        }
-
-       cleanFiles();
        delete ui;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
-// Public Functions
-///////////////////////////////////////////////////////////////////////////////
-
-/*None yet*/
-
-///////////////////////////////////////////////////////////////////////////////
 // Events
 ///////////////////////////////////////////////////////////////////////////////
 
@@ -170,24 +178,45 @@ void UpdaterDialog::closeEvent(QCloseEvent *e)
 
 void UpdaterDialog::keyPressEvent(QKeyEvent *event)
 {
-       if(event->key() == Qt::Key_F11)
+       switch (event->key())
        {
-               const QString logFilePath = MUtils::make_temp_file(MUtils::temp_folder(), "log", true);
-               if (!logFilePath.isEmpty())
+       case Qt::Key_Escape:
+               if ((!m_thread.isNull()) && m_thread->isRunning())
+               {
+                       if (m_status >= MUtils::UpdateChecker::UpdateStatus_FetchingUpdates)
+                       {
+                               UPDATE_TEXT(2, tr("Cancellation requested..."));
+                       }
+                       else
+                       {
+                               UPDATE_TEXT(1, tr("Cancellation requested..."));
+                       }
+                       m_thread->cancel();
+               }
+               break;
+       case Qt::Key_F11:
                {
-                       QFile logFile(logFilePath);
-                       if (logFile.open(QIODevice::WriteOnly | QIODevice::Truncate))
+                       const QString logFilePath = MUtils::make_temp_file(MUtils::temp_folder(), "txt", true);
+                       if (!logFilePath.isEmpty())
                        {
-                               logFile.write("\xEF\xBB\xBF");
-                               for (QStringList::ConstIterator iter = m_logFile.constBegin(); iter != m_logFile.constEnd(); iter++)
+                               qWarning("Write log to: '%s'", MUTILS_UTF8(logFilePath));
+                               QFile logFile(logFilePath);
+                               if (logFile.open(QIODevice::WriteOnly | QIODevice::Truncate))
                                {
-                                       logFile.write(iter->toUtf8());
-                                       logFile.write("\r\n");
+                                       logFile.write("\xEF\xBB\xBF");
+                                       for (QStringList::ConstIterator iter = m_logFile.constBegin(); iter != m_logFile.constEnd(); iter++)
+                                       {
+                                               logFile.write(iter->toUtf8());
+                                               logFile.write("\r\n");
+                                       }
+                                       logFile.close();
+                                       QDesktopServices::openUrl(QUrl::fromLocalFile(logFile.fileName()));
                                }
-                               logFile.close();
-                               QDesktopServices::openUrl(QUrl::fromLocalFile(logFile.fileName()));
                        }
                }
+               break;
+       default:
+               QDialog::keyPressEvent(event);
        }
 }
 
@@ -197,12 +226,6 @@ void UpdaterDialog::keyPressEvent(QKeyEvent *event)
 
 void UpdaterDialog::initUpdate(void)
 {
-       //Clean up files from previous attempt
-       if(!m_binaries.isEmpty())
-       {
-               cleanFiles();
-       }
-
        //Check binary files
        if(!checkBinaries())
        {
@@ -212,7 +235,8 @@ void UpdaterDialog::initUpdate(void)
                {
                        QDesktopServices::openUrl(QUrl(QString::fromLatin1(m_updateUrl)));
                }
-               close(); return;
+               close();
+               return;
        }
 
        //Make sure user does have admin access
@@ -225,14 +249,15 @@ void UpdaterDialog::initUpdate(void)
                if(QMessageBox::critical(this, this->windowTitle(), message, tr("Discard"), tr("Ignore")) != 1)
                {
                        ui->buttonCancel->setEnabled(true);
-                       close(); return;
+                       close();
+                       return;
                }
        }
        
        //Create and setup thread
        if(!m_thread)
        {
-               m_thread.reset(new MUtils::UpdateChecker(m_binaries.value("wget.exe"), m_binaries.value("netc.exe"), m_binaries.value("gpgv.exe"), m_binaries.value("gpgv.gpg"), "Simple x264 Launcher", x264_version_build(), false));
+               m_thread.reset(new MUtils::UpdateChecker(getBin(m_binaries, "curl.exe"), getBin(m_binaries, "gpgv.exe"), getBin(m_binaries, "gpgv.gpg"), "Simple x264 Launcher", x264_version_build(), false));
                connect(m_thread.data(), SIGNAL(statusChanged(int)), this, SLOT(threadStatusChanged(int)));
                connect(m_thread.data(), SIGNAL(finished()), this, SLOT(threadFinished()));
                connect(m_thread.data(), SIGNAL(terminated()), this, SLOT(threadFinished()));
@@ -262,6 +287,7 @@ void UpdaterDialog::checkForUpdates(void)
        //Hide labels
        ui->labelInfo->hide();
        ui->labelUrl->hide();
+       ui->labelCancel->show();
 
        //Update status
        threadStatusChanged(MUtils::UpdateChecker::UpdateStatus_NotStartedYet);
@@ -276,12 +302,17 @@ void UpdaterDialog::checkForUpdates(void)
        //Clear log
        m_logFile.clear();
 
+       //Init timer
+       m_elapsed.reset(new QElapsedTimer());
+       m_elapsed->start();
+
        //Start the updater thread
-       QTimer::singleShot(250, m_thread.data(), SLOT(start()));
+       QTimer::singleShot(125, m_thread.data(), SLOT(start()));
 }
 
 void UpdaterDialog::threadStatusChanged(int status)
 {
+       const int prevStatus = m_status;
        switch(m_status = status)
        {
        case MUtils::UpdateChecker::UpdateStatus_NotStartedYet:
@@ -321,6 +352,21 @@ void UpdaterDialog::threadStatusChanged(int status)
                UPDATE_TEXT(2, tr("Update information received successfully."));
                UPDATE_ICON(3, "play");
                break;
+       case MUtils::UpdateChecker::UpdateStatus_CancelledByUser:
+               if (prevStatus >= MUtils::UpdateChecker::UpdateStatus_FetchingUpdates)
+               {
+                       UPDATE_ICON(2, "shield_error");
+                       UPDATE_TEXT(2, tr("Operation was cancelled by the user!"));
+                       UPDATE_ICON(3, "shield_grey");
+               }
+               else
+               {
+                       UPDATE_ICON(1, "shield_error");
+                       UPDATE_TEXT(1, tr("Operation was cancelled by the user!"));
+                       UPDATE_ICON(2, "shield_grey");
+                       UPDATE_ICON(3, "shield_grey");
+               }
+               break;
        default:
                MUTILS_THROW("Unknown status code!");
        }
@@ -329,11 +375,19 @@ void UpdaterDialog::threadStatusChanged(int status)
 void UpdaterDialog::threadFinished(void)
 {
        m_success = m_thread->getSuccess();
-       QTimer::singleShot((m_success ? 1000 : 0), this, SLOT(updateFinished()));
+       ui->labelCancel->hide();
+       QTimer::singleShot((m_success ? 500 : 0), this, SLOT(updateFinished()));
 }
 
 void UpdaterDialog::updateFinished(void)
 {
+       //Query the timer, if available
+       if (!m_elapsed.isNull())
+       {
+               const quint64 elapsed = m_elapsed->restart();
+               qDebug("Update check completed after %.2f seconds.", double(elapsed) / 1000.0);
+       }
+
        //Restore cursor
        QApplication::restoreOverrideCursor();
 
@@ -373,6 +427,7 @@ void UpdaterDialog::updateFinished(void)
        case MUtils::UpdateChecker::UpdateStatus_ErrorNoConnection:
        case MUtils::UpdateChecker::UpdateStatus_ErrorConnectionTestFailed:
        case MUtils::UpdateChecker::UpdateStatus_ErrorFetchUpdateInfo:
+       case MUtils::UpdateChecker::UpdateStatus_CancelledByUser:
                m_animator->stop();
                ui->buttonRetry->show();
                break;
@@ -428,7 +483,7 @@ void UpdaterDialog::installUpdate(void)
        args << QString("/ToExFile=%1.exe").arg(QFileInfo(QFileInfo(QApplication::applicationFilePath()).canonicalFilePath()).completeBaseName());
        args << QString("/AppTitle=Simple x264 Launcher (Build #%1)").arg(QString::number(updateInfo->getBuildNo()));
 
-       process.start(m_binaries.value("wupd.exe"), args);
+       process.start(getBin(m_binaries, "wupd.exe"), args);
        if(!process.waitForStarted())
        {
                QApplication::restoreOverrideCursor();
@@ -467,36 +522,40 @@ void UpdaterDialog::installUpdate(void)
 bool UpdaterDialog::checkBinaries(void)
 {
        qDebug("[File Verification]");
-       m_binaries.clear();
-
-       //Validate hashes first
-       const QString tempPath = MUtils::temp_folder();
        for(size_t i = 0; BINARIES[i].name; i++)
        {
-               const QString orgName = QString::fromLatin1(BINARIES[i].name);
-               const QString binPath = QString("%1/toolset/common/%2").arg(m_sysinfo->getAppPath(), orgName);
-               const QString outPath = MUtils::make_unique_file(tempPath, QFileInfo(orgName).baseName(), QFileInfo(orgName).suffix());
-               if(!checkFileHash(binPath, BINARIES[i].hash))
+               const QString name = QString::fromLatin1(BINARIES[i].name);
+               if (!m_binaries.contains(name))
                {
-                       qWarning("Verification of '%s' has failed!", MUTILS_UTF8(orgName));
-                       return false;
-               }
-               if(outPath.isEmpty() || (!QFile::copy(binPath, outPath)))
-               {
-                       qWarning("Copying of '%s' has failed!", MUTILS_UTF8(orgName));
-                       return false;
+                       QScopedPointer<QFile> binary(new QFile(QString("%1/toolset/common/%2").arg(m_sysinfo->getAppPath(), name)));
+                       if (binary->open(QIODevice::ReadOnly))
+                       {
+                               if (checkFileHash(binary->fileName(), BINARIES[i].hash))
+                               {
+                                       QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
+                                       m_binaries.insert(name, QSharedPointer<QFile>(binary.take(), qFileDeleter));
+                               }
+                               else
+                               {
+                                       qWarning("Verification of '%s' has failed!", MUTILS_UTF8(name));
+                                       binary->close();
+                                       return false;
+                               }
+                       }
+                       else
+                       {
+                               qWarning("File '%s' could not be opened!", MUTILS_UTF8(name));
+                               return false;
+                       }
                }
-               QFile::setPermissions(outPath, QFile::ReadOwner);
-               m_binaries.insert(BINARIES[i].name, outPath);
-               QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
        }
-
+       qDebug("File check completed.\n");
        return true;
 }
 
 bool UpdaterDialog::checkFileHash(const QString &filePath, const char *expectedHash)
 {
-       qDebug("Checking file: %s", filePath.toUtf8().constData());
+       qDebug("Checking file: %s", MUTILS_UTF8(filePath));
        QScopedPointer<MUtils::Hash::Hash> checksum(MUtils::Hash::create(MUtils::Hash::HASH_BLAKE2_512, DIGEST_KEY));
        QFile file(filePath);
        if(file.open(QIODevice::ReadOnly))
@@ -517,18 +576,3 @@ bool UpdaterDialog::checkFileHash(const QString &filePath, const char *expectedH
                return false;
        }
 }
-
-void UpdaterDialog::cleanFiles(void)
-{
-       const QStringList keys = m_binaries.keys();
-       foreach(const QString &key, keys)
-       {
-               const QString fileName = m_binaries.value(key);
-               QFile::setPermissions(fileName, QFile::ReadOwner | QFile::WriteOwner);
-               if(!QFile::remove(fileName))
-               {
-                       qWarning("Failed to remove file: %s", MUTILS_UTF8(fileName));
-               }
-               m_binaries.remove(key);
-       }
-}