diff options
author | kh1 <karsten.heimrich@digia.com> | 2014-01-16 12:55:00 +0100 |
---|---|---|
committer | Karsten Heimrich <karsten.heimrich@digia.com> | 2014-01-22 17:19:53 +0100 |
commit | dab03d22574735c50c8429f1797b3f0a7bd599b0 (patch) | |
tree | ca53f81eef5a0129c00a254cef812fc08da8b782 /src/libs/installer/unziptask.cpp | |
parent | fe92a09482c5abf7f2c56901f2d60e287282f939 (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.cpp | 304 |
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 |