diff options
author | Andrew Knight <andrew.knight@digia.com> | 2014-06-05 13:39:41 +0300 |
---|---|---|
committer | Andrew Knight <andrew.knight@digia.com> | 2014-06-14 09:52:05 +0200 |
commit | f1d1e853d53bc677a912e221515397651d1369ef (patch) | |
tree | 85f3be7f97cd7731e12c8420c38ffc691669591a | |
parent | 47ec82cc6adf991e0c2d1f83bfeb957adfd9e1fa (diff) | |
download | qttools-f1d1e853d53bc677a912e221515397651d1369ef.tar.gz |
winrtrunner: Add an inherited method for creating packages
This method can be used by AppxEngine subclasses for creating package
(*.appx) files.
Change-Id: I7aab9bced144353c3c9e8cf6fbb914bd2f5b7fbb
Reviewed-by: Oliver Wolff <oliver.wolff@digia.com>
-rw-r--r-- | src/winrtrunner/appxengine.cpp | 92 | ||||
-rw-r--r-- | src/winrtrunner/appxengine.h | 1 |
2 files changed, 93 insertions, 0 deletions
diff --git a/src/winrtrunner/appxengine.cpp b/src/winrtrunner/appxengine.cpp index 0ef84655b..a0b5ea653 100644 --- a/src/winrtrunner/appxengine.cpp +++ b/src/winrtrunner/appxengine.cpp @@ -343,3 +343,95 @@ bool AppxEngine::installDependencies() return true; } + +bool AppxEngine::createPackage(const QString &packageFileName) +{ + Q_D(AppxEngine); + + static QHash<QString, QString> contentTypes; + if (contentTypes.isEmpty()) { + contentTypes.insert(QStringLiteral("dll"), QStringLiteral("application/x-msdownload")); + contentTypes.insert(QStringLiteral("exe"), QStringLiteral("application/x-msdownload")); + contentTypes.insert(QStringLiteral("png"), QStringLiteral("image/png")); + contentTypes.insert(QStringLiteral("xml"), QStringLiteral("vnd.ms-appx.manifest+xml")); + } + + // Check for package map, or create one if needed + QDir base = QFileInfo(d->manifest).absoluteDir(); + QFile packageFile(packageFileName); + + QHash<QString, QString> files; + QFile mappingFile(base.absoluteFilePath(QStringLiteral("AppxManifest.map"))); + if (mappingFile.exists()) { + qCWarning(lcWinRtRunner) << "Creating package from mapping file:" << mappingFile.fileName(); + if (!mappingFile.open(QFile::ReadOnly)) { + qCWarning(lcWinRtRunner) << "Unable to read mapping file:" << mappingFile.errorString(); + return false; + } + + QRegExp pattern(QStringLiteral("^\"([^\"]*)\"\\s*\"([^\"]*)\"$")); + bool inFileSection = false; + while (!mappingFile.atEnd()) { + const QString line = QString::fromUtf8(mappingFile.readLine()).trimmed(); + if (line.startsWith(QLatin1Char('['))) { + inFileSection = line == QStringLiteral("[Files]"); + continue; + } + if (pattern.cap(2).compare(QStringLiteral("AppxManifest.xml"), Qt::CaseInsensitive) == 0) + continue; + if (inFileSection && pattern.indexIn(line) >= 0 && pattern.captureCount() == 2) { + QString inputFile = pattern.cap(1); + if (!QFile::exists(inputFile)) + inputFile = base.absoluteFilePath(inputFile); + files.insert(QDir::toNativeSeparators(inputFile), QDir::toNativeSeparators(pattern.cap(2))); + } + } + } else { + qCWarning(lcWinRtRunner) << "No mapping file exists. Only recognized files will be packaged."; + // Add executable + files.insert(QDir::toNativeSeparators(d->executable), QFileInfo(d->executable).fileName()); + // Add potential Qt files + const QStringList fileTypes = QStringList() + << QStringLiteral("*.dll") << QStringLiteral("*.png") << QStringLiteral("*.qm") + << QStringLiteral("*.qml") << QStringLiteral("*.qmldir"); + QDirIterator dirIterator(base.absolutePath(), fileTypes, QDir::Files, QDirIterator::Subdirectories); + while (dirIterator.hasNext()) { + const QString filePath = dirIterator.next(); + files.insert(QDir::toNativeSeparators(filePath), QDir::toNativeSeparators(base.relativeFilePath(filePath))); + } + } + + ComPtr<IStream> outputStream; + HRESULT hr = SHCreateStreamOnFile(wchar(packageFile.fileName()), STGM_WRITE|STGM_CREATE, &outputStream); + RETURN_FALSE_IF_FAILED("Failed to create package file output stream"); + + ComPtr<IUri> hashMethod; + hr = CreateUri(L"http://www.w3.org/2001/04/xmlenc#sha512", Uri_CREATE_CANONICALIZE, 0, &hashMethod); + RETURN_FALSE_IF_FAILED("Failed to create the has method URI"); + + APPX_PACKAGE_SETTINGS packageSettings = { FALSE, hashMethod.Get() }; + ComPtr<IAppxPackageWriter> packageWriter; + hr = d->packageFactory->CreatePackageWriter(outputStream.Get(), &packageSettings, &packageWriter); + RETURN_FALSE_IF_FAILED("Failed to create package writer"); + + for (QHash<QString, QString>::const_iterator i = files.begin(); i != files.end(); ++i) { + qCDebug(lcWinRtRunner) << "Packaging" << i.key() << i.value(); + ComPtr<IStream> inputStream; + hr = SHCreateStreamOnFile(wchar(i.key()), STGM_READ, &inputStream); + RETURN_FALSE_IF_FAILED("Failed to open file"); + const QString contentType = contentTypes.value(QFileInfo(i.key()).suffix().toLower(), + QStringLiteral("application/octet-stream")); + hr = packageWriter->AddPayloadFile(wchar(i.value()), wchar(contentType), + APPX_COMPRESSION_OPTION_NORMAL, inputStream.Get()); + RETURN_FALSE_IF_FAILED("Failed to add payload file"); + } + + // Write out the manifest + ComPtr<IStream> manifestStream; + hr = SHCreateStreamOnFile(wchar(d->manifest), STGM_READ, &manifestStream); + RETURN_FALSE_IF_FAILED("Failed to open manifest for packaging"); + hr = packageWriter->Close(manifestStream.Get()); + RETURN_FALSE_IF_FAILED("Failed to finalize package."); + + return true; +} diff --git a/src/winrtrunner/appxengine.h b/src/winrtrunner/appxengine.h index 0390eeaec..2e1b74e1b 100644 --- a/src/winrtrunner/appxengine.h +++ b/src/winrtrunner/appxengine.h @@ -67,6 +67,7 @@ protected: virtual bool installPackage(IAppxManifestReader *reader, const QString &filePath) = 0; bool installDependencies(); + bool createPackage(const QString &packageFileName); static bool getManifestFile(const QString &fileName, QString *manifest = 0); QScopedPointer<AppxEnginePrivate> d_ptr; |