summaryrefslogtreecommitdiffstats
path: root/src/libs/installer/unziptask.cpp
diff options
context:
space:
mode:
authorkh1 <karsten.heimrich@digia.com>2014-01-16 12:55:00 +0100
committerKarsten Heimrich <karsten.heimrich@digia.com>2014-01-22 17:19:53 +0100
commitdab03d22574735c50c8429f1797b3f0a7bd599b0 (patch)
treeca53f81eef5a0129c00a254cef812fc08da8b782 /src/libs/installer/unziptask.cpp
parentfe92a09482c5abf7f2c56901f2d60e287282f939 (diff)
QFuture based asynchronous Task implementation.
Change-Id: I538a2fc40b67d6d27f120afe3705065ab98f8f99 Reviewed-by: Tim Jenssen <tim.jenssen@digia.com>
Diffstat (limited to 'src/libs/installer/unziptask.cpp')
-rw-r--r--src/libs/installer/unziptask.cpp304
1 files changed, 304 insertions, 0 deletions
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