summaryrefslogtreecommitdiffstats
path: root/src/libs
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs')
-rw-r--r--src/libs/installer/abstractfiletask.cpp117
-rw-r--r--src/libs/installer/abstractfiletask.h152
-rw-r--r--src/libs/installer/abstracttask.h76
-rw-r--r--src/libs/installer/copyfiletask.cpp130
-rw-r--r--src/libs/installer/copyfiletask.h66
-rw-r--r--src/libs/installer/downloadfiletask.cpp380
-rw-r--r--src/libs/installer/downloadfiletask.h87
-rw-r--r--src/libs/installer/downloadfiletask_p.h116
-rw-r--r--src/libs/installer/installer.pro17
-rw-r--r--src/libs/installer/observer.cpp191
-rw-r--r--src/libs/installer/observer.h105
-rw-r--r--src/libs/installer/runextensions.h435
-rw-r--r--src/libs/installer/unziptask.cpp304
-rw-r--r--src/libs/installer/unziptask.h70
14 files changed, 2244 insertions, 2 deletions
diff --git a/src/libs/installer/abstractfiletask.cpp b/src/libs/installer/abstractfiletask.cpp
new file mode 100644
index 000000000..ce18422a0
--- /dev/null
+++ b/src/libs/installer/abstractfiletask.cpp
@@ -0,0 +1,117 @@
+/**************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Installer Framework.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+**************************************************************************/
+#include "abstractfiletask.h"
+
+namespace QInstaller {
+
+AbstractFileTask::AbstractFileTask()
+{
+ registerMetaTypes();
+}
+
+AbstractFileTask::AbstractFileTask(const QString &source)
+{
+ registerMetaTypes();
+ setTaskItem(FileTaskItem(source));
+}
+
+AbstractFileTask::AbstractFileTask(const FileTaskItem &item)
+{
+ registerMetaTypes();
+ setTaskItem(item);
+}
+
+AbstractFileTask::AbstractFileTask(const QString &source, const QString &target)
+{
+ registerMetaTypes();
+ setTaskItem(FileTaskItem(source, target));
+}
+
+QList<FileTaskItem> AbstractFileTask::taskItems() const
+{
+ QReadLocker _(&m_lock);
+ return m_items;
+}
+
+void AbstractFileTask::setTaskItem(const FileTaskItem &item)
+{
+ clearTaskItems();
+ addTaskItem(item);
+}
+
+
+// -- protected
+
+void AbstractFileTask::clearTaskItems()
+{
+ QWriteLocker _(&m_lock);
+ m_items.clear();
+}
+
+void AbstractFileTask::addTaskItem(const FileTaskItem &item)
+{
+ QWriteLocker _(&m_lock);
+ m_items.append(item);
+}
+
+void AbstractFileTask::setTaskItems(const QList<FileTaskItem> &items)
+{
+ clearTaskItems();
+ addTaskItems(items);
+}
+
+void AbstractFileTask::addTaskItems(const QList<FileTaskItem> &items)
+{
+ QWriteLocker _(&m_lock);
+ m_items.append(items);
+}
+
+
+// -- private
+
+void AbstractFileTask::registerMetaTypes()
+{
+ qRegisterMetaType<QInstaller::FileTaskItem>();
+ qRegisterMetaType<QInstaller::FileTaskResult>();
+ qRegisterMetaType<QInstaller::FileTaskException>();
+}
+
+} // namespace QInstaller
diff --git a/src/libs/installer/abstractfiletask.h b/src/libs/installer/abstractfiletask.h
new file mode 100644
index 000000000..6c6e7810e
--- /dev/null
+++ b/src/libs/installer/abstractfiletask.h
@@ -0,0 +1,152 @@
+/**************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Installer Framework.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+**************************************************************************/
+
+#ifndef ABSTRACTFILETASK_H
+#define ABSTRACTFILETASK_H
+
+#include "abstracttask.h"
+#include "installer_global.h"
+
+#include <QObject>
+#include <QReadWriteLock>
+
+#if QT_VERSION < 0x050000
+#include <qtconcurrentexception.h>
+#define QException QtConcurrent::Exception
+#endif
+
+namespace QInstaller {
+
+namespace FileTaskRole {
+enum
+{
+ Checksum,
+ SourceFile,
+ TargetFile,
+ UserRole = 1000
+};
+}
+
+class FileTaskItem : public TaskData
+{
+public:
+ FileTaskItem() {}
+ explicit FileTaskItem(const QString &s)
+ {
+ insert(FileTaskRole::SourceFile, s);
+ }
+ FileTaskItem(const QString &s, const QString &t)
+ {
+ insert(FileTaskRole::SourceFile, s);
+ insert(FileTaskRole::TargetFile, t);
+ }
+
+ QString source() const { return value(FileTaskRole::SourceFile).toString(); }
+ QString target() const { return value(FileTaskRole::TargetFile).toString(); }
+};
+
+class FileTaskResult : public TaskData
+{
+public:
+ FileTaskResult() {}
+ FileTaskResult(const QString &t, const QByteArray &c)
+ {
+ insert(FileTaskRole::Checksum, c);
+ insert(FileTaskRole::TargetFile, t);
+ }
+
+ QString target() const { return value(FileTaskRole::TargetFile).toString(); }
+ QByteArray checkSum() const { return value(FileTaskRole::Checksum).toByteArray(); }
+};
+
+class FileTaskException : public QException
+{
+public:
+ FileTaskException() {}
+ ~FileTaskException() throw() {}
+ explicit FileTaskException(const QString &message)
+ : m_message(message) {}
+
+ void raise() const { throw *this; }
+ QString message() const { return m_message; }
+ FileTaskException *clone() const { return new FileTaskException(*this); }
+
+private:
+ QString m_message;
+};
+
+class INSTALLER_EXPORT AbstractFileTask : public AbstractTask<FileTaskResult>
+{
+ Q_OBJECT
+ Q_DISABLE_COPY(AbstractFileTask)
+
+public:
+ AbstractFileTask();
+ virtual ~AbstractFileTask() {}
+
+ explicit AbstractFileTask(const QString &source);
+ explicit AbstractFileTask(const FileTaskItem &item);
+ AbstractFileTask(const QString &source, const QString &target);
+
+ QList<FileTaskItem> taskItems() const;
+ void setTaskItem(const FileTaskItem &item);
+
+protected:
+ void clearTaskItems();
+ void addTaskItem(const FileTaskItem &item);
+ void setTaskItems(const QList<FileTaskItem> &items);
+ void addTaskItems(const QList<FileTaskItem> &items);
+
+private:
+ void registerMetaTypes();
+
+private:
+ QList<FileTaskItem> m_items;
+ mutable QReadWriteLock m_lock;
+};
+
+} // namespace QInstaller
+
+Q_DECLARE_METATYPE(QInstaller::FileTaskItem)
+Q_DECLARE_METATYPE(QInstaller::FileTaskResult)
+Q_DECLARE_METATYPE(QInstaller::FileTaskException)
+
+#endif // ABSTRACTFILETASK_H
diff --git a/src/libs/installer/abstracttask.h b/src/libs/installer/abstracttask.h
new file mode 100644
index 000000000..75fc1fa78
--- /dev/null
+++ b/src/libs/installer/abstracttask.h
@@ -0,0 +1,76 @@
+/**************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Installer Framework.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+**************************************************************************/
+
+#ifndef ABSTRACTTASK_H
+#define ABSTRACTTASK_H
+
+#include "runextensions.h"
+
+#include <QFutureInterface>
+
+namespace QInstaller {
+
+class TaskData
+{
+public:
+ TaskData() {}
+ QVariant value(int role) const { return m_data.value(role); }
+ void insert(int key, const QVariant &value) { m_data.insert(key, value); }
+
+private:
+ QHash<int, QVariant> m_data;
+};
+
+template <typename T>
+class AbstractTask : public QObject
+{
+ Q_DISABLE_COPY(AbstractTask)
+
+public:
+ AbstractTask() {}
+ virtual ~AbstractTask() {}
+
+ virtual void doTask(QFutureInterface<T> &futureInterface) = 0;
+};
+
+} // namespace QInstaller
+
+#endif // ABSTRACTTASK_H
diff --git a/src/libs/installer/copyfiletask.cpp b/src/libs/installer/copyfiletask.cpp
new file mode 100644
index 000000000..ca31b7873
--- /dev/null
+++ b/src/libs/installer/copyfiletask.cpp
@@ -0,0 +1,130 @@
+/**************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Installer Framework.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+**************************************************************************/
+#include "copyfiletask.h"
+#include "observer.h"
+
+#include <QFileInfo>
+#include <QTemporaryFile>
+
+namespace QInstaller {
+
+CopyFileTask::CopyFileTask(const FileTaskItem &item)
+ : AbstractFileTask(item)
+{
+}
+
+CopyFileTask::CopyFileTask(const QString &source)
+ : AbstractFileTask(source)
+{
+}
+
+CopyFileTask::CopyFileTask(const QString &source, const QString &target)
+ : AbstractFileTask(source, target)
+{
+}
+
+void CopyFileTask::doTask(QFutureInterface<FileTaskResult> &fi)
+{
+ fi.reportStarted();
+ fi.setExpectedResultCount(1);
+
+ if (taskItems().isEmpty()) {
+ fi.reportException(FileTaskException(QLatin1String("Invalid task item count.")));
+ fi.reportFinished(); return; // error
+ }
+
+ const FileTaskItem item = taskItems().first();
+ FileTaskObserver observer(QCryptographicHash::Sha1);
+
+ QFile source(item.source());
+ if (!source.open(QIODevice::ReadOnly)) {
+ fi.reportException(FileTaskException(QString::fromLatin1("Could not open source '%1' "
+ "for read. Error: %2.").arg(source.fileName(), source.errorString())));
+ fi.reportFinished(); return; // error
+ }
+ observer.setBytesToTransfer(source.size());
+
+ QScopedPointer<QFile> file;
+ const QString target = item.target();
+ if (target.isEmpty()) {
+ QTemporaryFile *tmp = new QTemporaryFile;
+ tmp->setAutoRemove(false);
+ file.reset(tmp);
+ } else {
+ file.reset(new QFile(target));
+ }
+ if (!file->open(QIODevice::WriteOnly | QIODevice::Truncate)) {
+ fi.reportException(FileTaskException(QString::fromLatin1("Could not open target '%1' "
+ "for write. Error: %2.").arg(file->fileName(), file->errorString())));
+ fi.reportFinished(); return; // error
+ }
+
+ QByteArray buffer(32768, Qt::Uninitialized);
+ while (!source.atEnd() && source.error() == QFile::NoError) {
+ if (fi.isCanceled())
+ break;
+ if (fi.isPaused())
+ fi.waitForResume();
+
+ const qint64 read = source.read(buffer.data(), buffer.size());
+ qint64 written = 0;
+ while (written < read) {
+ const qint64 toWrite = file->write(buffer.constData() + written, read - written);
+ if (toWrite < 0) {
+ fi.reportException(FileTaskException(QString::fromLatin1("Writing to target "
+ "'%1' failed. Error: %2.").arg(file->fileName(), file->errorString())));
+ }
+ written += toWrite;
+ }
+
+ observer.addSample(read);
+ observer.timerEvent(NULL);
+ observer.addBytesTransfered(read);
+ observer.addCheckSumData(buffer.data(), read);
+
+ fi.setProgressValueAndText(observer.progressValue(), observer.progressText());
+ }
+
+ fi.reportResult(FileTaskResult(file->fileName(), observer.checkSum()), 0);
+ fi.reportFinished();
+}
+
+} // namespace QInstaller
diff --git a/src/libs/installer/copyfiletask.h b/src/libs/installer/copyfiletask.h
new file mode 100644
index 000000000..d9cc20f93
--- /dev/null
+++ b/src/libs/installer/copyfiletask.h
@@ -0,0 +1,66 @@
+/**************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Installer Framework.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+**************************************************************************/
+
+#ifndef COPYFILETASK_H
+#define COPYFILETASK_H
+
+#include "abstractfiletask.h"
+
+namespace QInstaller {
+
+class INSTALLER_EXPORT CopyFileTask : public AbstractFileTask
+{
+ Q_OBJECT
+ Q_DISABLE_COPY(CopyFileTask)
+
+public:
+ CopyFileTask() {}
+ explicit CopyFileTask(const FileTaskItem &item);
+
+ explicit CopyFileTask(const QString &source);
+ CopyFileTask(const QString &source, const QString &target);
+
+ void doTask(QFutureInterface<FileTaskResult> &fi);
+};
+
+} // namespace QInstaller
+
+#endif // COPYFILETASK_H
diff --git a/src/libs/installer/downloadfiletask.cpp b/src/libs/installer/downloadfiletask.cpp
new file mode 100644
index 000000000..3e1c903d2
--- /dev/null
+++ b/src/libs/installer/downloadfiletask.cpp
@@ -0,0 +1,380 @@
+/**************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Installer Framework.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+**************************************************************************/
+#include "downloadfiletask.h"
+
+#include "downloadfiletask_p.h"
+#include "observer.h"
+
+#include <QEventLoop>
+#include <QFile>
+#include <QNetworkProxyFactory>
+#include <QSslError>
+#include <QTemporaryFile>
+#include <QTimer>
+
+namespace QInstaller {
+
+Downloader::Downloader()
+ : m_finished(0)
+{
+ connect(&m_nam, SIGNAL(finished(QNetworkReply*)), SLOT(onFinished(QNetworkReply*)));
+}
+
+Downloader::~Downloader()
+{
+ m_nam.disconnect();
+ foreach (QNetworkReply *const reply, m_downloads.keys()) {
+ reply->disconnect();
+ reply->abort();
+ reply->deleteLater();
+ }
+
+ foreach (const Data &data, m_downloads.values()) {
+ data.file->close();
+ delete data.file;
+ delete data.observer;
+ }
+}
+
+void Downloader::download(QFutureInterface<FileTaskResult> &fi, const QList<FileTaskItem> &items,
+ const QAuthenticator &authenticator, QNetworkProxyFactory *networkProxyFactory)
+{
+ m_items = items;
+ m_futureInterface = &fi;
+ m_authenticator = authenticator;
+
+ fi.reportStarted();
+ fi.setExpectedResultCount(items.count());
+
+ m_nam.setProxyFactory(networkProxyFactory);
+ connect(&m_nam, SIGNAL(authenticationRequired(QNetworkReply*, QAuthenticator*)), this,
+ SLOT(onAuthenticationRequired(QNetworkReply*, QAuthenticator*)));
+ QTimer::singleShot(0, this, SLOT(doDownload()));
+}
+
+void Downloader::doDownload()
+{
+ foreach (const FileTaskItem &item, m_items) {
+ if (!startDownload(item))
+ break;
+ }
+
+ if (m_items.isEmpty() || m_futureInterface->isCanceled()) {
+ m_futureInterface->reportFinished();
+ emit finished(); // emit finished, so the event loop can shutdown
+ }
+}
+
+
+// -- private slots
+
+void Downloader::onReadyRead()
+{
+ if (testCanceled()) {
+ m_futureInterface->reportFinished();
+ emit finished(); return; // error
+ }
+
+ QNetworkReply *const reply = qobject_cast<QNetworkReply *>(sender());
+ if (!reply)
+ return;
+
+ const Data &data = m_downloads[reply];
+ if (!data.file->isOpen()) {
+ m_futureInterface->reportException(FileTaskException(QString::fromLatin1("Target '%1' not "
+ "open for write. Error: %2.").arg(data.file->fileName(), data.file->errorString())));
+ return;
+ }
+
+ QByteArray buffer(32768, Qt::Uninitialized);
+ while (reply->bytesAvailable()) {
+ if (testCanceled()) {
+ m_futureInterface->reportFinished();
+ emit finished(); return; // error
+ }
+
+ const qint64 read = reply->read(buffer.data(), buffer.size());
+ qint64 written = 0;
+ while (written < read) {
+ const qint64 toWrite = data.file->write(buffer.constData() + written, read - written);
+ if (toWrite < 0) {
+ m_futureInterface->reportException(FileTaskException(QString::fromLatin1("Writing "
+ "to target '%1' failed. Error: %2.").arg(data.file->fileName(),
+ data.file->errorString())));
+ return;
+ }
+ written += toWrite;
+ }
+
+ data.observer->addSample(read);
+ data.observer->addBytesTransfered(read);
+ data.observer->addCheckSumData(buffer.data(), read);
+
+ int progress = m_finished * 100;
+ foreach (const Data &data, m_downloads.values())
+ progress += data.observer->progressValue();
+ if (!reply->attribute(QNetworkRequest::RedirectionTargetAttribute).isValid()) {
+ m_futureInterface->setProgressValueAndText(progress / m_items.count(),
+ data.observer->progressText());
+ }
+ }
+}
+
+void Downloader::onFinished(QNetworkReply *reply)
+{
+ const Data &data = m_downloads[reply];
+ const QString filename = data.file->fileName();
+ if (!m_futureInterface->isCanceled()) {
+ if (reply->attribute(QNetworkRequest::RedirectionTargetAttribute).isValid()) {
+ const QUrl url = reply->url()
+ .resolved(reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl());
+ const QList<QUrl> redirects = m_redirects.values(reply);
+ if (!redirects.contains(url)) {
+ data.file->close();
+ data.file->remove();
+ delete data.file;
+ delete data.observer;
+
+ FileTaskItem taskItem(url.toString(), filename);
+ taskItem.insert(FileTaskRole::Checksum, data.expectedCheckSum);
+ QNetworkReply *const redirectReply = startDownload(taskItem);
+
+ foreach (const QUrl &redirect, redirects)
+ m_redirects.insertMulti(redirectReply, redirect);
+ m_redirects.insertMulti(redirectReply, url);
+
+ m_downloads.remove(reply);
+ m_redirects.remove(reply);
+ reply->deleteLater();
+ return;
+ } else {
+ m_futureInterface->reportException(FileTaskException(QString::fromLatin1("Redirect"
+ " loop detected '%1'.").arg(url.toString())));
+ return;
+ }
+ }
+ }
+
+ const QByteArray ba = reply->readAll();
+ if (!ba.isEmpty()) {
+ data.observer->addSample(ba.size());
+ data.observer->addBytesTransfered(ba.size());
+ data.observer->addCheckSumData(ba.data(), ba.size());
+ }
+ m_futureInterface->reportResult(FileTaskResult(filename, data.observer->checkSum()));
+
+ if (!data.expectedCheckSum.isEmpty()) {
+ if (data.expectedCheckSum != data.observer->checkSum().toHex()) {
+ m_futureInterface->reportException(FileTaskException(QString::fromLatin1("Checksum"
+ " mismatch detected '%1'.").arg(reply->url().toString())));
+ }
+ }
+
+ data.file->close();
+ delete data.file;
+ delete data.observer;
+
+ m_downloads.remove(reply);
+ m_redirects.remove(reply);
+ reply->deleteLater();
+
+ m_finished++;
+ if (m_downloads.isEmpty() || m_futureInterface->isCanceled()) {
+ m_futureInterface->reportFinished();
+ emit finished(); // emit finished, so the event loop can shutdown
+ }
+}
+
+void Downloader::onError(QNetworkReply::NetworkError error)
+{
+ QNetworkReply *const reply = qobject_cast<QNetworkReply *>(sender());
+ if (reply) {
+ const Data &data = m_downloads[reply];
+ m_futureInterface->reportException(FileTaskException(QString::fromLatin1("Network error "
+ "while downloading target '%1'. Error: %2.").arg(data.file->fileName(),
+ reply->errorString())));
+ } else {
+ m_futureInterface->reportException(FileTaskException(QString::fromLatin1("Unknown network "
+ "error while downloading. Error: %1.").arg(error)));
+ }
+}
+
+void Downloader::onSslErrors(const QList<QSslError> &sslErrors)
+{
+#if defined(QT_NO_SSL) || defined(QT_NO_OPENSSL)
+ Q_UNUSED(sslErrors);
+#else
+ foreach (const QSslError &error, sslErrors)
+ qDebug() << QString::fromLatin1("SSL error: %s").arg(error.errorString());
+#endif
+}
+
+void Downloader::onDownloadProgress(qint64 bytesReceived, qint64 bytesTotal)
+{
+ Q_UNUSED(bytesReceived)
+ QNetworkReply *const reply = qobject_cast<QNetworkReply *>(sender());
+ if (reply) {
+ const Data &data = m_downloads[reply];
+ data.observer->setBytesToTransfer(bytesTotal);
+ }
+}
+
+void Downloader::onAuthenticationRequired(QNetworkReply *reply, QAuthenticator *authenticator)
+{
+ Q_UNUSED(reply)
+ if (!authenticator)
+ return;
+
+ if (!m_authenticator.user().isEmpty()) {
+ authenticator->setUser(m_authenticator.user());
+ authenticator->setPassword(m_authenticator.password());
+ m_authenticator = QAuthenticator(); // clear so we fail on next call
+ } else {
+ m_futureInterface->reportException(FileTaskException(QString::fromLatin1("Could not "
+ "authenticate using the provided credentials. Source: '%1'.").arg(reply->url()
+ .toString())));
+ }
+}
+
+
+// -- private
+
+bool Downloader::testCanceled()
+{
+ // TODO: figure out how to implement pause and resume
+ if (m_futureInterface->isPaused()) {
+ m_futureInterface->togglePaused(); // Note: this will trigger cancel
+ m_futureInterface->reportException(FileTaskException(QLatin1String("Pause and resume not "
+ "supported by network transfers.")));
+ }
+ return m_futureInterface->isCanceled();
+}
+
+QNetworkReply *Downloader::startDownload(const FileTaskItem &item)
+{
+ QUrl const source = item.source();
+ if (!source.isValid()) {
+ m_futureInterface->reportException(FileTaskException(QString::fromLatin1("Invalid source "
+ "'%1'. Error: %2.").arg(source.toString(), source.errorString())));
+ return 0;
+ }
+
+ QScopedPointer<QFile> file;
+ const QString target = item.target();
+ if (target.isEmpty()) {
+ QTemporaryFile *tmp = new QTemporaryFile;
+ tmp->setAutoRemove(false);
+ file.reset(tmp);
+ } else {
+ file.reset(new QFile(target));
+ }
+ if (!file->open(QIODevice::WriteOnly | QIODevice::Truncate)) {
+ file->remove();
+ m_futureInterface->reportException(FileTaskException(QString::fromLatin1("Could not open "
+ "target '%1' for write. Error: %2.").arg(file->fileName(), file->errorString())));
+ return 0;
+ }
+
+ QNetworkReply *reply = m_nam.get(QNetworkRequest(source));
+ m_downloads.insert(reply, Data(file.take(), new FileTaskObserver(QCryptographicHash::Sha1),
+ item.value(FileTaskRole::Checksum).toByteArray()));
+
+ connect(reply, SIGNAL(readyRead()), this, SLOT(onReadyRead()));
+ connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), this,
+ SLOT(onError(QNetworkReply::NetworkError)));
+#ifndef QT_NO_SSL
+ connect(reply, SIGNAL(sslErrors(QList<QSslError>)), SLOT(onSslErrors(QList<QSslError>)));
+#endif
+ connect(reply, SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(onDownloadProgress(qint64,
+ qint64)));
+ return reply;
+}
+
+
+// -- DownloadFileTask
+
+DownloadFileTask::DownloadFileTask(const QList<FileTaskItem> &items)
+ : AbstractFileTask()
+{
+ setTaskItems(items);
+}
+
+void DownloadFileTask::setTaskItem(const FileTaskItem &item)
+{
+ AbstractFileTask::setTaskItem(item);
+}
+
+void DownloadFileTask::addTaskItem(const FileTaskItem &item)
+{
+ AbstractFileTask::addTaskItem(item);
+}
+
+void DownloadFileTask::setTaskItems(const QList<FileTaskItem> &items)
+{
+ AbstractFileTask::setTaskItems(items);
+}
+
+void DownloadFileTask::addTaskItems(const QList<FileTaskItem> &items)
+{
+ AbstractFileTask::addTaskItems(items);
+}
+
+void DownloadFileTask::setAuthenticator(const QAuthenticator &authenticator)
+{
+ m_authenticator = authenticator;
+}
+
+void DownloadFileTask::setProxyFactory(KDUpdater::FileDownloaderProxyFactory *factory)
+{
+ m_proxyFactory.reset(factory);
+}
+
+void DownloadFileTask::doTask(QFutureInterface<FileTaskResult> &fi)
+{
+ QEventLoop el;
+ Downloader downloader;
+ connect(&downloader, SIGNAL(finished()), &el, SLOT(quit()));
+ downloader.download(fi, taskItems(), m_authenticator, (m_proxyFactory.isNull() ? 0
+ : m_proxyFactory->clone())); // Downloader takes ownership of this copy.
+ el.exec(); // That's tricky here, we run our own event loop to keep QNAM working
+}
+
+} // namespace QInstaller
diff --git a/src/libs/installer/downloadfiletask.h b/src/libs/installer/downloadfiletask.h
new file mode 100644
index 000000000..4e2cd2312
--- /dev/null
+++ b/src/libs/installer/downloadfiletask.h
@@ -0,0 +1,87 @@
+/**************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Installer Framework.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+**************************************************************************/
+
+#ifndef DOWNLOADFILETASK_H
+#define DOWNLOADFILETASK_H
+
+#include "abstractfiletask.h"
+#include "kdupdaterfiledownloaderfactory.h"
+
+#include <QAuthenticator>
+
+namespace QInstaller {
+
+class INSTALLER_EXPORT DownloadFileTask : public AbstractFileTask
+{
+ Q_OBJECT
+ Q_DISABLE_COPY(DownloadFileTask)
+
+public:
+ DownloadFileTask() {}
+ explicit DownloadFileTask(const FileTaskItem &item)
+ : AbstractFileTask(item) {}
+ explicit DownloadFileTask(const QList<FileTaskItem> &items);
+
+ explicit DownloadFileTask(const QString &source)
+ : AbstractFileTask(source) {}
+ DownloadFileTask(const QString &source, const QString &target)
+ : AbstractFileTask(source, target) {}
+
+ void addTaskItem(const FileTaskItem &items);
+ void addTaskItems(const QList<FileTaskItem> &items);
+
+ void setTaskItem(const FileTaskItem &items);
+ void setTaskItems(const QList<FileTaskItem> &items);
+
+ void setAuthenticator(const QAuthenticator &authenticator);
+ void setProxyFactory(KDUpdater::FileDownloaderProxyFactory *factory);
+
+ void doTask(QFutureInterface<FileTaskResult> &fi);
+
+private:
+ friend class Downloader;
+ QAuthenticator m_authenticator;
+ QScopedPointer<KDUpdater::FileDownloaderProxyFactory> m_proxyFactory;
+};
+
+} // namespace QInstaller
+
+#endif // DOWNLOADFILETASK_H
diff --git a/src/libs/installer/downloadfiletask_p.h b/src/libs/installer/downloadfiletask_p.h
new file mode 100644
index 000000000..66b14767c
--- /dev/null
+++ b/src/libs/installer/downloadfiletask_p.h
@@ -0,0 +1,116 @@
+/**************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Installer Framework.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+**************************************************************************/
+
+#ifndef DOWNLOADFILETASK_P_H
+#define DOWNLOADFILETASK_P_H
+
+#include "downloadfiletask.h"
+
+#include <QNetworkAccessManager>
+#include <QNetworkReply>
+#include <QNetworkRequest>
+
+QT_BEGIN_NAMESPACE
+class QFile;
+class QSslError;
+QT_END_NAMESPACE
+
+namespace QInstaller {
+
+class FileTaskObserver;
+
+struct Data
+{
+ Data()
+ : file(0), observer(0) {}
+ Data(QFile *f, FileTaskObserver *o)
+ : file(f), observer(o) {}
+ Data(QFile *f, FileTaskObserver *o, const QByteArray &e)
+ : file(f), observer(o), expectedCheckSum(e)
+ {}
+ QFile *file;
+ FileTaskObserver *observer;
+ QByteArray expectedCheckSum;
+};
+
+class Downloader : public QObject
+{
+ Q_OBJECT
+ Q_DISABLE_COPY(Downloader)
+
+public:
+ Downloader();
+ ~Downloader();
+
+ void download(QFutureInterface<FileTaskResult> &fi, const QList<FileTaskItem> &items,
+ const QAuthenticator &authenticator, QNetworkProxyFactory *networkProxyFactory);
+
+signals:
+ void finished();
+
+private slots:
+ void doDownload();
+ void onReadyRead();
+ void onFinished(QNetworkReply *reply);
+ void onError(QNetworkReply::NetworkError error);
+ void onSslErrors(const QList<QSslError> &sslErrors);
+ void onDownloadProgress(qint64 bytesReceived, qint64 bytesTotal);
+ void onAuthenticationRequired(QNetworkReply *reply, QAuthenticator *authenticator);
+
+
+private:
+ bool testCanceled();
+ QNetworkReply *startDownload(const FileTaskItem &item);
+
+private:
+ QFutureInterface<FileTaskResult> *m_futureInterface;
+
+ int m_finished;
+ QNetworkAccessManager m_nam;
+ QList<FileTaskItem> m_items;
+ QAuthenticator m_authenticator;
+ QHash<QNetworkReply*, Data> m_downloads;
+ QMultiHash<QNetworkReply*, QUrl> m_redirects;
+};
+
+} // namespace QInstaller
+
+#endif // DOWNLOADFILETASK_P_H
diff --git a/src/libs/installer/installer.pro b/src/libs/installer/installer.pro
index 149287428..766525e17 100644
--- a/src/libs/installer/installer.pro
+++ b/src/libs/installer/installer.pro
@@ -104,7 +104,15 @@ HEADERS += packagemanagercore.h \
graph.h \
settingsoperation.h \
testrepository.h \
- packagemanagerpagefactory.h
+ packagemanagerpagefactory.h \
+ abstracttask.h\
+ abstractfiletask.h \
+ copyfiletask.h \
+ downloadfiletask.h \
+ downloadfiletask_p.h \
+ unziptask.h \
+ observer.h \
+ runextensions.h
SOURCES += packagemanagercore.cpp \
packagemanagercore_p.cpp \
@@ -169,7 +177,12 @@ HEADERS += packagemanagercore.h \
globals.cpp \
settingsoperation.cpp \
testrepository.cpp \
- packagemanagerpagefactory.cpp
+ packagemanagerpagefactory.cpp \
+ abstractfiletask.cpp \
+ copyfiletask.cpp \
+ downloadfiletask.cpp \
+ unziptask.cpp \
+ observer.cpp
RESOURCES += resources/patch_file_lists.qrc \
resources/installer.qrc
diff --git a/src/libs/installer/observer.cpp b/src/libs/installer/observer.cpp
new file mode 100644
index 000000000..617cd744d
--- /dev/null
+++ b/src/libs/installer/observer.cpp
@@ -0,0 +1,191 @@
+/**************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Installer Framework.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+**************************************************************************/
+#include "observer.h"
+
+#include <fileutils.h>
+
+namespace QInstaller {
+
+FileTaskObserver::FileTaskObserver(QCryptographicHash::Algorithm algorithm)
+ : m_hash(algorithm)
+{
+ init();
+}
+
+FileTaskObserver::~FileTaskObserver()
+{
+ if (m_timerId >= 0)
+ killTimer(m_timerId);
+}
+
+int FileTaskObserver::progressValue() const
+{
+ if (m_bytesToTransfer <= 0 || m_bytesTransfered > m_bytesToTransfer)
+ return 0;
+ return 100 * m_bytesTransfered / m_bytesToTransfer;
+}
+
+QString FileTaskObserver::progressText() const
+{
+ QString progressText;
+ if (m_bytesToTransfer > 0) {
+ QString bytesReceived = QInstaller::humanReadableSize(m_bytesTransfered);
+ const QString bytesToReceive = QInstaller::humanReadableSize(m_bytesToTransfer);
+
+ // remove the unit from the bytesReceived value if bytesToReceive has the same
+ const QString tmp = bytesToReceive.mid(bytesToReceive.indexOf(QLatin1Char(' ')));
+ if (bytesReceived.endsWith(tmp))
+ bytesReceived.chop(tmp.length());
+
+ progressText = bytesReceived + tr(" of ") + bytesToReceive;
+ } else {
+ if (m_bytesTransfered > 0)
+ progressText = QInstaller::humanReadableSize(m_bytesTransfered) + tr(" received.");
+ }
+
+ progressText += QLatin1String(" (") + QInstaller::humanReadableSize(m_bytesPerSecond) + tr("/sec")
+ + QLatin1Char(')');
+ if (m_bytesToTransfer > 0 && m_bytesPerSecond > 0) {
+ const qint64 time = (m_bytesToTransfer - m_bytesTransfered) / m_bytesPerSecond;
+
+ int s = time % 60;
+ const int d = time / 86400;
+ const int h = (time / 3600) - (d * 24);
+ const int m = (time / 60) - (d * 1440) - (h * 60);
+
+ QString days;
+ if (d > 0)
+ days = QString::number(d) + (d < 2 ? tr(" day") : tr(" days")) + QLatin1String(", ");
+
+ QString hours;
+ if (h > 0)
+ hours = QString::number(h) + (h < 2 ? tr(" hour") : tr(" hours")) + QLatin1String(", ");
+
+ QString minutes;
+ if (m > 0)
+ minutes = QString::number(m) + (m < 2 ? tr(" minute") : tr(" minutes"));
+
+ QString seconds;
+ if (s >= 0 && minutes.isEmpty()) {
+ s = (s <= 0 ? 1 : s);
+ seconds = QString::number(s) + (s < 2 ? tr(" second") : tr(" seconds"));
+ }
+ progressText += tr(" - ") + days + hours + minutes + seconds + tr(" remaining.");
+ } else {
+ progressText += tr(" - unknown time remaining.");
+ }
+
+ return progressText;
+}
+
+QByteArray FileTaskObserver::checkSum() const
+{
+ return m_hash.result();
+}
+
+void FileTaskObserver::addCheckSumData(const char *data, int length)
+{
+ m_hash.addData(data, length);
+}
+
+void FileTaskObserver::addSample(qint64 sample)
+{
+ m_currentSpeedBin += sample;
+}
+
+void FileTaskObserver::setBytesTransfered(qint64 bytesReceived)
+{
+ m_bytesTransfered = bytesReceived;
+}
+
+void FileTaskObserver::addBytesTransfered(qint64 bytesReceived)
+{
+ m_bytesTransfered += bytesReceived;
+}
+
+void FileTaskObserver::setBytesToTransfer(qint64 bytesToReceive)
+{
+ m_bytesToTransfer = bytesToReceive;
+}
+
+
+// -- private
+
+void FileTaskObserver::init()
+{
+ m_hash.reset();
+ m_sampleIndex = 0;
+ m_bytesTransfered = 0;
+ m_bytesToTransfer = 0;
+ m_bytesPerSecond = 0;
+ m_currentSpeedBin = 0;
+
+ m_timerId = -1;
+ m_timerInterval = 100;
+ memset(m_samples, 0, sizeof(m_samples));
+ m_timerId = startTimer(m_timerInterval);
+}
+
+void FileTaskObserver::timerEvent(QTimerEvent *event)
+{
+ Q_UNUSED(event)
+ unsigned int windowSize = sizeof(m_samples) / sizeof(qint64);
+
+ // add speed of last time bin to the window
+ m_samples[m_sampleIndex % windowSize] = m_currentSpeedBin;
+ m_currentSpeedBin = 0; // reset bin for next time interval
+
+ // advance the sample index
+ m_sampleIndex++;
+ m_bytesPerSecond = 0;
+
+ // dynamic window size until the window is completely filled
+ if (m_sampleIndex < windowSize)
+ windowSize = m_sampleIndex;
+
+ for (unsigned int i = 0; i < windowSize; ++i)
+ m_bytesPerSecond += m_samples[i];
+
+ m_bytesPerSecond /= windowSize; // computer average
+ m_bytesPerSecond *= 1000.0 / m_timerInterval; // rescale to bytes/second
+}
+
+} // namespace QInstaller
diff --git a/src/libs/installer/observer.h b/src/libs/installer/observer.h
new file mode 100644
index 000000000..539d6b2da
--- /dev/null
+++ b/src/libs/installer/observer.h
@@ -0,0 +1,105 @@
+/**************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Installer Framework.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+**************************************************************************/
+
+#ifndef OBSERVER_H
+#define OBSERVER_H
+
+#include <QCryptographicHash>
+#include <QObject>
+
+namespace QInstaller {
+
+class Observer : public QObject
+{
+ Q_OBJECT
+ Q_DISABLE_COPY(Observer)
+
+public:
+ Observer() {}
+ virtual ~Observer() {}
+
+ virtual int progressValue() const = 0;
+ virtual QString progressText() const = 0;
+};
+
+class FileTaskObserver : public Observer
+{
+ Q_OBJECT
+ Q_DISABLE_COPY(FileTaskObserver)
+
+public:
+ FileTaskObserver(QCryptographicHash::Algorithm algorithm);
+ ~FileTaskObserver();
+
+ int progressValue() const;
+ QString progressText() const;
+
+ QByteArray checkSum() const;
+ void addCheckSumData(const char *data, int length);
+
+ void addSample(qint64 sample);
+ void timerEvent(QTimerEvent *event);
+
+ void setBytesTransfered(qint64 bytesTransfered);
+ void addBytesTransfered(qint64 bytesTransfered);
+ void setBytesToTransfer(qint64 bytesToTransfer);
+
+private:
+ void init();
+
+private:
+ int m_timerId;
+ int m_timerInterval;
+
+ qint64 m_bytesTransfered;
+ qint64 m_bytesToTransfer;
+
+ qint64 m_samples[50];
+ quint32 m_sampleIndex;
+ qint64 m_bytesPerSecond;
+ qint64 m_currentSpeedBin;
+
+ QCryptographicHash m_hash;
+};
+
+} // namespace QInstaller
+
+#endif // OBSERVER_H
diff --git a/src/libs/installer/runextensions.h b/src/libs/installer/runextensions.h
new file mode 100644
index 000000000..e4c7fb2be
--- /dev/null
+++ b/src/libs/installer/runextensions.h
@@ -0,0 +1,435 @@
+/**************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Installer Framework.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+**************************************************************************/
+
+#ifndef QTCONCURRENT_RUNEX_H
+#define QTCONCURRENT_RUNEX_H
+
+#include <qrunnable.h>
+#include <qfutureinterface.h>
+#include <qthreadpool.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QtConcurrent {
+
+template <typename T, typename FunctionPointer>
+class StoredInterfaceFunctionCall0 : public QRunnable
+{
+public:
+ StoredInterfaceFunctionCall0(void (fn)(QFutureInterface<T> &))
+ : fn(fn) { }
+
+ QFuture<T> start()
+ {
+ futureInterface.reportStarted();
+ QFuture<T> future = futureInterface.future();
+ QThreadPool::globalInstance()->start(this);
+ return future;
+ }
+
+ void run()
+ {
+ fn(futureInterface);
+ futureInterface.reportFinished();
+ }
+private:
+ QFutureInterface<T> futureInterface;
+ FunctionPointer fn;
+
+};
+template <typename T, typename FunctionPointer, typename Class>
+class StoredInterfaceMemberFunctionCall0 : public QRunnable
+{
+public:
+ StoredInterfaceMemberFunctionCall0(void (Class::*fn)(QFutureInterface<T> &), Class *object)
+ : fn(fn), object(object) { }
+
+ QFuture<T> start()
+ {
+ futureInterface.reportStarted();
+ QFuture<T> future = futureInterface.future();
+ QThreadPool::globalInstance()->start(this);
+ return future;
+ }
+
+ void run()
+ {
+ (object->*fn)(futureInterface);
+ futureInterface.reportFinished();
+ }
+private:
+ QFutureInterface<T> futureInterface;
+ FunctionPointer fn;
+ Class *object;
+
+};
+
+template <typename T, typename FunctionPointer, typename Arg1>
+class StoredInterfaceFunctionCall1 : public QRunnable
+{
+public:
+ StoredInterfaceFunctionCall1(void (fn)(QFutureInterface<T> &, Arg1), const Arg1 &arg1)
+ : fn(fn), arg1(arg1) { }
+
+ QFuture<T> start()
+ {
+ futureInterface.reportStarted();
+ QFuture<T> future = futureInterface.future();
+ QThreadPool::globalInstance()->start(this);
+ return future;
+ }
+
+ void run()
+ {
+ fn(futureInterface, arg1);
+ futureInterface.reportFinished();
+ }
+private:
+ QFutureInterface<T> futureInterface;
+ FunctionPointer fn;
+ Arg1 arg1;
+};
+template <typename T, typename FunctionPointer, typename Class, typename Arg1>
+class StoredInterfaceMemberFunctionCall1 : public QRunnable
+{
+public:
+ StoredInterfaceMemberFunctionCall1(void (Class::*fn)(QFutureInterface<T> &, Arg1), Class *object, const Arg1 &arg1)
+ : fn(fn), object(object), arg1(arg1) { }
+
+ QFuture<T> start()
+ {
+ futureInterface.reportStarted();
+ QFuture<T> future = futureInterface.future();
+ QThreadPool::globalInstance()->start(this);
+ return future;
+ }
+
+ void run()
+ {
+ (object->*fn)(futureInterface, arg1);
+ futureInterface.reportFinished();
+ }
+private:
+ QFutureInterface<T> futureInterface;
+ FunctionPointer fn;
+ Class *object;
+ Arg1 arg1;
+};
+
+template <typename T, typename FunctionPointer, typename Arg1, typename Arg2>
+class StoredInterfaceFunctionCall2 : public QRunnable
+{
+public:
+ StoredInterfaceFunctionCall2(void (fn)(QFutureInterface<T> &, Arg1, Arg2), const Arg1 &arg1, const Arg2 &arg2)
+ : fn(fn), arg1(arg1), arg2(arg2) { }
+
+ QFuture<T> start()
+ {
+ futureInterface.reportStarted();
+ QFuture<T> future = futureInterface.future();
+ QThreadPool::globalInstance()->start(this);
+ return future;
+ }
+
+ void run()
+ {
+ fn(futureInterface, arg1, arg2);
+ futureInterface.reportFinished();
+ }
+private:
+ QFutureInterface<T> futureInterface;
+ FunctionPointer fn;
+ Arg1 arg1; Arg2 arg2;
+};
+template <typename T, typename FunctionPointer, typename Class, typename Arg1, typename Arg2>
+class StoredInterfaceMemberFunctionCall2 : public QRunnable
+{
+public:
+ StoredInterfaceMemberFunctionCall2(void (Class::*fn)(QFutureInterface<T> &, Arg1, Arg2), Class *object, const Arg1 &arg1, const Arg2 &arg2)
+ : fn(fn), object(object), arg1(arg1), arg2(arg2) { }
+
+ QFuture<T> start()
+ {
+ futureInterface.reportStarted();
+ QFuture<T> future = futureInterface.future();
+ QThreadPool::globalInstance()->start(this);
+ return future;
+ }
+
+ void run()
+ {
+ (object->*fn)(futureInterface, arg1, arg2);
+ futureInterface.reportFinished();
+ }
+private:
+ QFutureInterface<T> futureInterface;
+ FunctionPointer fn;
+ Class *object;
+ Arg1 arg1; Arg2 arg2;
+};
+
+template <typename T, typename FunctionPointer, typename Arg1, typename Arg2, typename Arg3>
+class StoredInterfaceFunctionCall3 : public QRunnable
+{
+public:
+ StoredInterfaceFunctionCall3(void (fn)(QFutureInterface<T> &, Arg1, Arg2, Arg3), const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3)
+ : fn(fn), arg1(arg1), arg2(arg2), arg3(arg3) { }
+
+ QFuture<T> start()
+ {
+ futureInterface.reportStarted();
+ QFuture<T> future = futureInterface.future();
+ QThreadPool::globalInstance()->start(this);
+ return future;
+ }
+
+ void run()
+ {
+ fn(futureInterface, arg1, arg2, arg3);
+ futureInterface.reportFinished();
+ }
+private:
+ QFutureInterface<T> futureInterface;
+ FunctionPointer fn;
+ Arg1 arg1; Arg2 arg2; Arg3 arg3;
+};
+template <typename T, typename FunctionPointer, typename Class, typename Arg1, typename Arg2, typename Arg3>
+class StoredInterfaceMemberFunctionCall3 : public QRunnable
+{
+public:
+ StoredInterfaceMemberFunctionCall3(void (Class::*fn)(QFutureInterface<T> &, Arg1, Arg2, Arg3), Class *object, const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3)
+ : fn(fn), object(object), arg1(arg1), arg2(arg2), arg3(arg3) { }
+
+ QFuture<T> start()
+ {
+ futureInterface.reportStarted();
+ QFuture<T> future = futureInterface.future();
+ QThreadPool::globalInstance()->start(this);
+ return future;
+ }
+
+ void run()
+ {
+ (object->*fn)(futureInterface, arg1, arg2, arg3);
+ futureInterface.reportFinished();
+ }
+private:
+ QFutureInterface<T> futureInterface;
+ FunctionPointer fn;
+ Class *object;
+ Arg1 arg1; Arg2 arg2; Arg3 arg3;
+};
+
+template <typename T, typename FunctionPointer, typename Arg1, typename Arg2, typename Arg3, typename Arg4>
+class StoredInterfaceFunctionCall4 : public QRunnable
+{
+public:
+ StoredInterfaceFunctionCall4(void (fn)(QFutureInterface<T> &, Arg1, Arg2, Arg3, Arg4), const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4)
+ : fn(fn), arg1(arg1), arg2(arg2), arg3(arg3), arg4(arg4) { }
+
+ QFuture<T> start()
+ {
+ futureInterface.reportStarted();
+ QFuture<T> future = futureInterface.future();
+ QThreadPool::globalInstance()->start(this);
+ return future;
+ }
+
+ void run()
+ {
+ fn(futureInterface, arg1, arg2, arg3, arg4);
+ futureInterface.reportFinished();
+ }
+private:
+ QFutureInterface<T> futureInterface;
+ FunctionPointer fn;
+ Arg1 arg1; Arg2 arg2; Arg3 arg3; Arg4 arg4;
+};
+template <typename T, typename FunctionPointer, typename Class, typename Arg1, typename Arg2, typename Arg3, typename Arg4>
+class StoredInterfaceMemberFunctionCall4 : public QRunnable
+{
+public:
+ StoredInterfaceMemberFunctionCall4(void (Class::*fn)(QFutureInterface<T> &, Arg1, Arg2, Arg3, Arg4), Class *object, const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4)
+ : fn(fn), object(object), arg1(arg1), arg2(arg2), arg3(arg3), arg4(arg4) { }
+
+ QFuture<T> start()
+ {
+ futureInterface.reportStarted();
+ QFuture<T> future = futureInterface.future();
+ QThreadPool::globalInstance()->start(this);
+ return future;
+ }
+
+ void run()
+ {
+ (object->*fn)(futureInterface, arg1, arg2, arg3, arg4);
+ futureInterface.reportFinished();
+ }
+private:
+ QFutureInterface<T> futureInterface;
+ FunctionPointer fn;
+ Class *object;
+ Arg1 arg1; Arg2 arg2; Arg3 arg3; Arg4 arg4;
+};
+
+template <typename T, typename FunctionPointer, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5>
+class StoredInterfaceFunctionCall5 : public QRunnable
+{
+public:
+ StoredInterfaceFunctionCall5(void (fn)(QFutureInterface<T> &, Arg1, Arg2, Arg3, Arg4, Arg5), const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4, const Arg5 &arg5)
+ : fn(fn), arg1(arg1), arg2(arg2), arg3(arg3), arg4(arg4), arg5(arg5) { }
+
+ QFuture<T> start()
+ {
+ futureInterface.reportStarted();
+ QFuture<T> future = futureInterface.future();
+ QThreadPool::globalInstance()->start(this);
+ return future;
+ }
+
+ void run()
+ {
+ fn(futureInterface, arg1, arg2, arg3, arg4, arg5);
+ futureInterface.reportFinished();
+ }
+private:
+ QFutureInterface<T> futureInterface;
+ FunctionPointer fn;
+ Arg1 arg1; Arg2 arg2; Arg3 arg3; Arg4 arg4; Arg5 arg5;
+};
+template <typename T, typename FunctionPointer, typename Class, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5>
+class StoredInterfaceMemberFunctionCall5 : public QRunnable
+{
+public:
+ StoredInterfaceMemberFunctionCall5(void (Class::*fn)(QFutureInterface<T> &, Arg1, Arg2, Arg3, Arg4, Arg5), Class *object, const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4, const Arg5 &arg5)
+ : fn(fn), object(object), arg1(arg1), arg2(arg2), arg3(arg3), arg4(arg4), arg5(arg5) { }
+
+ QFuture<T> start()
+ {
+ futureInterface.reportStarted();
+ QFuture<T> future = futureInterface.future();
+ QThreadPool::globalInstance()->start(this);
+ return future;
+ }
+
+ void run()
+ {
+ (object->*fn)(futureInterface, arg1, arg2, arg3, arg4, arg5);
+ futureInterface.reportFinished();
+ }
+private:
+ QFutureInterface<T> futureInterface;
+ FunctionPointer fn;
+ Class *object;
+ Arg1 arg1; Arg2 arg2; Arg3 arg3; Arg4 arg4; Arg5 arg5;
+};
+
+template <typename T>
+QFuture<T> run(void (*functionPointer)(QFutureInterface<T> &))
+{
+ return (new StoredInterfaceFunctionCall0<T, void (*)(QFutureInterface<T> &)>(functionPointer))->start();
+}
+template <typename T, typename Arg1>
+QFuture<T> run(void (*functionPointer)(QFutureInterface<T> &, Arg1), const Arg1 &arg1)
+{
+ return (new StoredInterfaceFunctionCall1<T, void (*)(QFutureInterface<T> &, Arg1), Arg1>(functionPointer, arg1))->start();
+}
+template <typename T, typename Arg1, typename Arg2>
+QFuture<T> run(void (*functionPointer)(QFutureInterface<T> &, Arg1, Arg2), const Arg1 &arg1, const Arg2 &arg2)
+{
+ return (new StoredInterfaceFunctionCall2<T, void (*)(QFutureInterface<T> &, Arg1, Arg2), Arg1, Arg2>(functionPointer, arg1, arg2))->start();
+}
+template <typename T, typename Arg1, typename Arg2, typename Arg3>
+QFuture<T> run(void (*functionPointer)(QFutureInterface<T> &, Arg1, Arg2, Arg3), const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3)
+{
+ return (new StoredInterfaceFunctionCall3<T, void (*)(QFutureInterface<T> &, Arg1, Arg2, Arg3), Arg1, Arg2, Arg3>(functionPointer, arg1, arg2, arg3))->start();
+}
+template <typename T, typename Arg1, typename Arg2, typename Arg3, typename Arg4>
+QFuture<T> run(void (*functionPointer)(QFutureInterface<T> &, Arg1, Arg2, Arg3, Arg4), const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4)
+{
+ return (new StoredInterfaceFunctionCall4<T, void (*)(QFutureInterface<T> &, Arg1, Arg2, Arg3, Arg4), Arg1, Arg2, Arg3, Arg4>(functionPointer, arg1, arg2, arg3, arg4))->start();
+}
+template <typename T, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5>
+QFuture<T> run(void (*functionPointer)(QFutureInterface<T> &, Arg1, Arg2, Arg3, Arg4, Arg5), const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4, const Arg5 &arg5)
+{
+ return (new StoredInterfaceFunctionCall5<T, void (*)(QFutureInterface<T> &, Arg1, Arg2, Arg3, Arg4, Arg5), Arg1, Arg2, Arg3, Arg4, Arg5>(functionPointer, arg1, arg2, arg3, arg4, arg5))->start();
+}
+
+template <typename Class, typename T>
+QFuture<T> run(void (Class::*fn)(QFutureInterface<T> &), Class *object)
+{
+ return (new StoredInterfaceMemberFunctionCall0<T, void (Class::*)(QFutureInterface<T> &), Class>(fn, object))->start();
+}
+
+template <typename Class, typename T, typename Arg1>
+QFuture<T> run(void (Class::*fn)(QFutureInterface<T> &, Arg1), Class *object, Arg1 arg1)
+{
+ return (new StoredInterfaceMemberFunctionCall1<T, void (Class::*)(QFutureInterface<T> &, Arg1), Class, Arg1>(fn, object, arg1))->start();
+}
+
+template <typename Class, typename T, typename Arg1, typename Arg2>
+QFuture<T> run(void (Class::*fn)(QFutureInterface<T> &, Arg1, Arg2), Class *object, const Arg1 &arg1, const Arg2 &arg2)
+{
+ return (new StoredInterfaceMemberFunctionCall2<T, void (Class::*)(QFutureInterface<T> &, Arg1, Arg2), Class, Arg1, Arg2>(fn, object, arg1, arg2))->start();
+}
+
+template <typename Class, typename T, typename Arg1, typename Arg2, typename Arg3>
+QFuture<T> run(void (Class::*fn)(QFutureInterface<T> &, Arg1, Arg2, Arg3), Class *object, const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3)
+{
+ return (new StoredInterfaceMemberFunctionCall3<T, void (Class::*)(QFutureInterface<T> &, Arg1, Arg2, Arg3), Class, Arg1, Arg2, Arg3>(fn, object, arg1, arg2, arg3))->start();
+}
+
+template <typename Class, typename T, typename Arg1, typename Arg2, typename Arg3, typename Arg4>
+QFuture<T> run(void (Class::*fn)(QFutureInterface<T> &, Arg1, Arg2, Arg3, Arg4), Class *object, const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4)
+{
+ return (new StoredInterfaceMemberFunctionCall4<T, void (Class::*)(QFutureInterface<T> &, Arg1, Arg2, Arg3, Arg4), Class, Arg1, Arg2, Arg3, Arg4>(fn, object, arg1, arg2, arg3, arg4))->start();
+}
+
+template <typename Class, typename T, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5>
+QFuture<T> run(void (Class::*fn)(QFutureInterface<T> &, Arg1, Arg2, Arg3, Arg4, Arg5), Class *object, const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4, const Arg5 &arg5)
+{
+ return (new StoredInterfaceMemberFunctionCall5<T, void (Class::*)(QFutureInterface<T> &, Arg1, Arg2, Arg3, Arg4, Arg5), Class, Arg1, Arg2, Arg3, Arg4, Arg5>(fn, object, arg1, arg2, arg3, arg4, arg5))->start();
+}
+} // namespace QtConcurrent
+
+QT_END_NAMESPACE
+
+#endif // QTCONCURRENT_RUNEX_H
diff --git a/src/libs/installer/unziptask.cpp b/src/libs/installer/unziptask.cpp
new file mode 100644
index 000000000..b3a0b6bb2
--- /dev/null
+++ b/src/libs/installer/unziptask.cpp
@@ -0,0 +1,304 @@
+/**************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Installer Framework.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+**************************************************************************/
+#include "unziptask.h"
+
+#ifdef Q_OS_UNIX
+# include "StdAfx.h"
+#endif
+#include "Common/ComTry.h"
+// TODO: include once we switch from lib7z_fascade.h
+//#include "Common/MyInitGuid.h"
+
+#include "7zip/IPassword.h"
+#include "7zip/Common/FileStreams.h"
+#include "7zip/UI/Common/OpenArchive.h"
+
+#include "Windows/FileDir.h"
+#include "Windows/PropVariant.h"
+
+#include "7zCrc.h"
+
+#include <QDir>
+
+void registerArc7z();
+void registerCodecLZMA();
+void registerCodecLZMA2();
+
+namespace QInstaller {
+
+class ArchiveExtractCallback : public IArchiveExtractCallback, public CMyUnknownImp
+{
+public:
+ MY_UNKNOWN_IMP
+ ArchiveExtractCallback(const QString &target, const CArc &arc, QFutureInterface<QString> &fi)
+ : m_target(target)
+ , m_arc(arc)
+ {
+ m_futureInterface = &fi;
+ }
+
+
+ // -- IProgress
+
+ STDMETHOD(SetTotal)(UInt64 total)
+ {
+ COM_TRY_BEGIN
+ m_totalUnpacked = 0;
+ m_totalUnpackedExpected = total;
+ return S_OK;
+ COM_TRY_END
+ }
+
+ STDMETHOD(SetCompleted)(const UInt64 *completeValue)
+ {
+ COM_TRY_BEGIN
+ Q_UNUSED(completeValue)
+ return S_OK; // return S_OK here as we do not support sub archive extracting
+ COM_TRY_END
+ }
+
+
+ // -- IArchiveExtractCallback
+
+ STDMETHOD(GetStream)(UInt32 index, ISequentialOutStream **outStream, Int32 askExtractMode)
+ {
+ if (m_futureInterface->isCanceled())
+ return E_FAIL;
+ if (m_futureInterface->isPaused())
+ m_futureInterface->waitForResume();
+
+ COM_TRY_BEGIN
+ *outStream = 0;
+ m_currentIndex = index;
+ if (askExtractMode != NArchive::NExtract::NAskMode::kExtract)
+ return E_FAIL;
+
+ bool isDir = false;
+ if (IsArchiveItemFolder(m_arc.Archive, m_currentIndex, isDir) != S_OK)
+ return E_FAIL;
+
+ bool isEncrypted = false;
+ if (GetArchiveItemBoolProp(m_arc.Archive, m_currentIndex, kpidEncrypted, isEncrypted) != S_OK)
+ return E_FAIL;
+
+ if (isDir || isEncrypted)
+ return E_FAIL;
+
+ UString itemPath;
+ if (m_arc.GetItemPath(m_currentIndex, itemPath) != S_OK)
+ return E_FAIL;
+
+ QDir().mkpath(m_target);
+ m_currentTarget = m_target + QLatin1Char('/') + QString::fromStdWString((const wchar_t*)(itemPath))
+ .replace(QLatin1Char('\\'), QLatin1Char('/'));
+
+ m_outFileStream = new COutFileStream;
+ CMyComPtr<ISequentialOutStream> scopedPointer(m_outFileStream);
+ if (!m_outFileStream->Open((wchar_t*)(m_currentTarget.utf16()), CREATE_ALWAYS))
+ return E_FAIL;
+
+ m_outFileStreamComPtr = scopedPointer;
+ *outStream = scopedPointer.Detach();
+
+ return S_OK;
+ COM_TRY_END
+ }
+
+ STDMETHOD(PrepareOperation)(Int32 askExtractMode)
+ {
+ COM_TRY_BEGIN
+ Q_UNUSED(askExtractMode)
+ m_futureInterface->setProgressValueAndText(0, QLatin1String("Started to extract archive."));
+ return S_OK; // return S_OK here as we do not need to prepare anything
+ COM_TRY_END
+ }
+
+ STDMETHOD(SetOperationResult)(Int32 resultEOperationResult)
+ {
+ COM_TRY_BEGIN
+ switch (resultEOperationResult)
+ {
+ case NArchive::NExtract::NOperationResult::kOK:
+ break;
+
+ default: // fall through and bail
+ case NArchive::NExtract::NOperationResult::kCRCError:
+ case NArchive::NExtract::NOperationResult::kDataError:
+ case NArchive::NExtract::NOperationResult::kUnSupportedMethod:
+ m_outFileStream->Close();
+ m_outFileStreamComPtr.Release();
+ return E_FAIL;
+ }
+
+ UInt32 attributes;
+ if (GetAttributes(&attributes))
+ NWindows::NFile::NDirectory::MySetFileAttributes((wchar_t*)(m_currentTarget.utf16()), attributes);
+
+ FILETIME accessTime, creationTime, modificationTime;
+ const bool writeAccessTime = GetTime(kpidATime, &accessTime);
+ const bool writeCreationTime = GetTime(kpidCTime, &creationTime);
+ const bool writeModificationTime = GetTime(kpidMTime, &modificationTime);
+
+ m_outFileStream->SetTime((writeCreationTime ? &creationTime : NULL),
+ (writeAccessTime ? &accessTime : NULL), (writeModificationTime ? &modificationTime : NULL));
+
+ m_totalUnpacked += m_outFileStream->ProcessedSize;
+ m_outFileStream->Close();
+ m_outFileStreamComPtr.Release();
+
+ m_futureInterface->reportResult(m_currentTarget);
+ m_futureInterface->setProgressValueAndText(100 * m_totalUnpacked / m_totalUnpackedExpected,
+ m_currentTarget);
+ return S_OK;
+ COM_TRY_END
+ }
+
+private:
+ bool GetAttributes(UInt32 *attributes) const
+ {
+ *attributes = 0;
+ NWindows::NCOM::CPropVariant property;
+ if (m_arc.Archive->GetProperty(m_currentIndex, kpidAttrib, &property) != S_OK)
+ return false;
+
+ if (property.vt != VT_UI4)
+ return false;
+
+ *attributes = property.ulVal;
+ return (property.vt == VT_UI4);
+ }
+
+ bool GetTime(PROPID propertyId, FILETIME *filetime) const
+ {
+ if (!filetime)
+ return false;
+
+ filetime->dwLowDateTime = 0;
+ filetime->dwHighDateTime = 0;
+
+ NWindows::NCOM::CPropVariant property;
+ if (m_arc.Archive->GetProperty(m_currentIndex, propertyId, &property) != S_OK)
+ return false;
+
+ if (property.vt != VT_FILETIME)
+ return false;
+
+ *filetime = property.filetime;
+ return (filetime->dwHighDateTime != 0 || filetime->dwLowDateTime != 0);
+ }
+
+private:
+ QString m_target;
+ const CArc &m_arc;
+ UnzipTask *m_unzipTask;
+ QFutureInterface<QString> *m_futureInterface;
+
+ UInt32 m_currentIndex;
+ QString m_currentTarget;
+
+ UInt64 m_totalUnpacked;
+ UInt64 m_totalUnpackedExpected;
+
+ COutFileStream *m_outFileStream;
+ CMyComPtr<ISequentialOutStream> m_outFileStreamComPtr;
+};
+
+
+// -- UnzipTask
+
+UnzipTask::UnzipTask(const QString &source, const QString &target)
+ : m_source(source)
+ , m_target(target)
+{
+ {
+ CrcGenerateTable();
+
+ registerArc7z();
+ registerCodecLZMA();
+ registerCodecLZMA2();
+ }
+}
+
+void UnzipTask::doTask(QFutureInterface<QString> &fi)
+{
+ fi.reportStarted();
+
+ CCodecs codecs;
+ if (codecs.Load() != S_OK)
+ return;
+
+ CIntVector formatIndices;
+ if (!codecs.FindFormatForArchiveType(L"", formatIndices))
+ return;
+
+ CInFileStream *fileStream = new CInFileStream;
+ fileStream->Open((wchar_t*) (m_source.utf16()));
+
+ CArchiveLink archiveLink;
+ if (archiveLink.Open2(&codecs, formatIndices, false, fileStream, UString(), 0) != S_OK)
+ return;
+
+ UINT32 count = 0;
+ for (int i = 0; i < archiveLink.Arcs.Size(); ++i) {
+ const CArc& arc = archiveLink.Arcs[i];
+ UInt32 numItems = 0;
+ if (arc.Archive->GetNumberOfItems(&numItems) != S_OK)
+ break;
+ count += numItems;
+ }
+ fi.setExpectedResultCount(count);
+
+ for (int i = 0; i < archiveLink.Arcs.Size(); ++i) {
+ if (fi.isCanceled())
+ break;
+ if (fi.isPaused())
+ fi.waitForResume();
+
+ const UInt32 extractAll = UInt32(-1);
+ const CArc &arc = archiveLink.Arcs[i];
+ arc.Archive->Extract(0, extractAll, NArchive::NExtract::NAskMode::kExtract,
+ new ArchiveExtractCallback(m_target, arc, fi));
+ }
+
+ fi.reportFinished();
+}
+
+} // namespace QInstaller
diff --git a/src/libs/installer/unziptask.h b/src/libs/installer/unziptask.h
new file mode 100644
index 000000000..40e1c6722
--- /dev/null
+++ b/src/libs/installer/unziptask.h
@@ -0,0 +1,70 @@
+/**************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Installer Framework.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+**************************************************************************/
+
+#ifndef UNZIPTASK_H
+#define UNZIPTASK_H
+
+#include "abstracttask.h"
+#include "installer_global.h"
+
+namespace QInstaller {
+
+class INSTALLER_EXPORT UnzipTask : public AbstractTask<QString>
+{
+public:
+ UnzipTask() {}
+ UnzipTask(const QString &source, const QString &target);
+
+ void doTask(QFutureInterface<QString> &fi);
+
+private:
+ void setBytesToExtract(qint64 bytes);
+ void addBytesExtracted(qint64 bytes);
+
+private:
+ QString m_source;
+ QString m_target;
+ friend class ArchiveExtractCallback;
+};
+
+} // namespace QInstaller
+
+#endif // UNZIPTASK_H