summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Knight <andrew.knight@digia.com>2014-06-05 13:39:41 +0300
committerAndrew Knight <andrew.knight@digia.com>2014-06-14 09:52:05 +0200
commitf1d1e853d53bc677a912e221515397651d1369ef (patch)
tree85f3be7f97cd7731e12c8420c38ffc691669591a
parent47ec82cc6adf991e0c2d1f83bfeb957adfd9e1fa (diff)
downloadqttools-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.cpp92
-rw-r--r--src/winrtrunner/appxengine.h1
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;