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;
}