コード例 #1
0
        public DirectoryInfoFileReaderAdapter(DirectoryInfo appxManifestFolder)
        {
            if (!appxManifestFolder.Exists)
            {
                throw new ArgumentException($"Directory {appxManifestFolder.FullName} does not exist.");
            }

            this.RootDirectory = appxManifestFolder.FullName;

            var appxManifest = Path.Combine(appxManifestFolder.FullName, FileConstants.AppxManifestFile);

            if (!File.Exists(appxManifest))
            {
                appxManifest = Path.Combine(appxManifestFolder.FullName, FileConstants.AppxBundleManifestFilePath);
                if (!File.Exists(appxManifest))
                {
                    throw new ArgumentException("This folder does not contain APPX/MSIX package nor APPX bundle.", nameof(appxManifestFolder));
                }

                adapter = new FileInfoFileReaderAdapter(appxManifest);
            }
            else
            {
                adapter = new FileInfoFileReaderAdapter(Path.Combine(appxManifestFolder.FullName, FileConstants.AppxManifestFile));
            }
        }
コード例 #2
0
        public async Task <AppxBundle> ReadBundle(IAppxFileReader fileReader, CancellationToken cancellationToken)
        {
            var bundle = new AppxBundle();

            using (var file = fileReader.GetFile(FileConstants.AppxBundleManifestFilePath))
            {
                var document = await XDocument.LoadAsync(file, LoadOptions.None, cancellationToken).ConfigureAwait(false);

                if (document.Root == null)
                {
                    throw new FormatException("The manifest is malformed. There is no root element.");
                }

                // var b4 = XNamespace.Get("http://schemas.microsoft.com/appx/2018/bundle");
                // var b5 = XNamespace.Get("http://schemas.microsoft.com/appx/2019/bundle");
                var ns = XNamespace.Get("http://schemas.microsoft.com/appx/2013/bundle");

                var identity = document.Root.Element(ns + "Identity");
                if (identity == null)
                {
                    throw new FormatException("The manifest is malformed, missing <Identity />.");
                }

                bundle.Version   = identity.Attribute("Version")?.Value;
                bundle.Name      = identity.Attribute("Name")?.Value;
                bundle.Publisher = identity.Attribute("Publisher")?.Value;
            }

            return(bundle);
        }
コード例 #3
0
        // ReSharper disable once MemberCanBeMadeStatic.Local
        private async Task <AppxPackage> LoadManifest(IAppxFileReader fileReader, CancellationToken cancellation = default)
        {
            var manifestReader = new AppxManifestReader();
            var manifest       = await manifestReader.Read(fileReader, cancellation).ConfigureAwait(false);

            return(manifest);
        }
コード例 #4
0
        // ReSharper disable once MemberCanBeMadeStatic.Local
        private async Task <PsfContentViewModel> LoadPsf(IAppxFileReader source, AppxPackage manifest)
        {
            var paths = manifest.Applications.Where(a => PackageTypeConverter.GetPackageTypeFrom(a.EntryPoint, a.Executable, a.StartPage, manifest.IsFramework) == MsixPackageType.BridgePsf).Select(a => a.Executable).Where(a => a != null).Select(Path.GetDirectoryName).Where(a => !string.IsNullOrEmpty(a)).Distinct().ToList();

            paths.Add(string.Empty);

            foreach (var items in paths)
            {
                var configJsonPath = string.IsNullOrWhiteSpace(items)
                    ? "config.json"
                    : Path.Combine(items, "config.json");
                if (!source.FileExists(configJsonPath))
                {
                    continue;
                }

                using (var s = source.GetFile(configJsonPath))
                {
                    using var stringReader = new StreamReader(s);
                    var all = await stringReader.ReadToEndAsync().ConfigureAwait(false);

                    var psfSerializer = new PsfConfigSerializer();

                    var configJson = psfSerializer.Deserialize(all);
                    return(new PsfContentViewModel(configJson));
                }
            }

            return(null);
        }
コード例 #5
0
        public Stream GetResource(string resourceFilePath)
        {
            if (string.IsNullOrEmpty(resourceFilePath))
            {
                return(null);
            }

            if (this.adapter == null)
            {
                this.adapter = this.GetAdapter();
            }

            return(this.adapter.GetResource(resourceFilePath));
        }
コード例 #6
0
        public Stream GetFile(string filePath)
        {
            if (string.IsNullOrEmpty(filePath))
            {
                return(null);
            }

            if (this.adapter == null)
            {
                this.adapter = this.GetAdapter();
            }

            return(this.adapter.GetFile(filePath));
        }
コード例 #7
0
        public bool FileExists(string filePath)
        {
            if (string.IsNullOrEmpty(filePath))
            {
                return(false);
            }

            if (this.adapter == null)
            {
                this.adapter = this.GetAdapter();
            }

            return(this.adapter.FileExists(filePath));
        }
コード例 #8
0
        public Task <AppxPackage> Read(IAppxFileReader fileReader, CancellationToken cancellationToken = default)
        {
            var isMsix = fileReader.FileExists(FileConstants.AppxManifestFile);

            if (isMsix)
            {
                return(this.ReadMsix(fileReader, FileConstants.AppxManifestFile, cancellationToken));
            }

            var isAppxBundle = fileReader.FileExists(FileConstants.AppxBundleManifestFilePath);

            if (isAppxBundle)
            {
                throw new NotSupportedException("Bundles are not supported.");
            }

            throw new NotSupportedException("Required package source is not supported.");
        }
コード例 #9
0
        public async Task <string> GetDiskPath(IAppxFileReader fileReader, string filePath)
        {
            if (!fileReader.FileExists(filePath))
            {
                throw new FileNotFoundException();
            }

            await using var fileStream = fileReader.GetFile(filePath);
            if (fileStream is FileStream fs)
            {
                // we can assume the file is directly accessible
                return(fs.Name);
            }

            var    index = 0;
            string fullPath;

            this.tempDirectory ??= new DirectoryInfo(Path.Combine(Path.GetTempPath(), "MSIX-Hero", Guid.NewGuid().ToString("N").Substring(10)));

            while (true)
            {
                fullPath = Path.Combine(this.tempDirectory.FullName, index.ToString("0"), Path.GetFileName(filePath));

                if (!File.Exists(fullPath))
                {
                    break;
                }

                index++;
            }

            var fileInfo = new FileInfo(fullPath);

            if (fileInfo.Directory?.Exists == false)
            {
                fileInfo.Directory.Create();
            }

            await using var targetStream = File.OpenWrite(fileInfo.FullName);
            await fileStream.CopyToAsync(targetStream).ConfigureAwait(false);

            return(fileInfo.FullName);
        }
コード例 #10
0
        private void SourcePathOnValueChanged(object sender, ValueChangedEventArgs e)
        {
            try
            {
                using IAppxFileReader reader = FileReaderFactory.CreateFileReader((string)e.NewValue);
                var mr   = new AppxManifestReader();
                var read = mr.Read(reader).GetAwaiter().GetResult();
                if (string.IsNullOrWhiteSpace(this.DisplayName.CurrentValue))
                {
                    this.DisplayName.CurrentValue = read.DisplayName + " - Modification package";
                }

                this.ParentName.CurrentValue      = read.Name;
                this.ParentPublisher.CurrentValue = read.Publisher;

                this.OnPropertyChanged(nameof(IsIncludeVfsFoldersEnabled));
            }
            catch (Exception exception)
            {
                Logger.Error(exception);
                this.interactionService.ShowError("Could not read the properties from the package.", exception);
            }
        }
コード例 #11
0
        public async Task <AppxPackage> Read(IAppxFileReader fileReader, bool resolveDependencies, CancellationToken cancellationToken = default)
        {
            var result = await this.Read(fileReader, cancellationToken).ConfigureAwait(false);

            if (resolveDependencies)
            {
                foreach (var item in result.PackageDependencies)
                {
                    cancellationToken.ThrowIfCancellationRequested();

                    using IAppxFileReader tempReader = new PackageIdentityFileReaderAdapter(PackageContext.CurrentUser, item.Name, item.Publisher, item.Version);
                    try
                    {
                        item.Dependency = await this.Read(tempReader, cancellationToken).ConfigureAwait(false);
                    }
                    catch (Exception)
                    {
                        Logger.Warn("Could not read a dependency to {0} {2} by {1}", item.Name, item.Publisher, item.Version);
                    }
                }
            }

            return(result);
        }
コード例 #12
0
 public AuthoringAppDetector(IAppxFileReader fileReader)
 {
     this.fileReader = fileReader;
 }
コード例 #13
0
        private async Task PrepareModificationPackage(XDocument template, ModificationPackageConfig config)
        {
            XNamespace nsUap4           = "http://schemas.microsoft.com/appx/manifest/uap/windows10/4";
            XNamespace nsUap6           = "http://schemas.microsoft.com/appx/manifest/uap/windows10/6";
            XNamespace nsRescap         = "http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities";
            XNamespace nsRescap6        = "http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities/6";
            XNamespace nsBuild          = "http://schemas.microsoft.com/developer/appx/2015/build";
            XNamespace defaultNamespace = "http://schemas.microsoft.com/appx/manifest/foundation/windows10";

            var root = template.Root;

            if (root == null)
            {
                root = new XElement(defaultNamespace + "Package");
                template.Add(root);
            }
            else
            {
                defaultNamespace = root.GetDefaultNamespace();
            }

            if (root.GetPrefixOfNamespace(nsUap4) == null)
            {
                root.Add(new XAttribute(XNamespace.Xmlns + "uap4", nsUap6.NamespaceName));
            }

            if (root.GetPrefixOfNamespace(nsUap6) == null)
            {
                root.Add(new XAttribute(XNamespace.Xmlns + "uap6", nsUap6.NamespaceName));
            }

            if (root.GetPrefixOfNamespace(nsRescap) == null)
            {
                root.Add(new XAttribute(XNamespace.Xmlns + "rescap", nsRescap.NamespaceName));
            }

            if (root.GetPrefixOfNamespace(nsRescap6) == null)
            {
                root.Add(new XAttribute(XNamespace.Xmlns + "rescap6", nsRescap6.NamespaceName));
            }

            if (root.GetPrefixOfNamespace(nsBuild) == null)
            {
                root.Add(new XAttribute(XNamespace.Xmlns + "build", nsBuild.NamespaceName));
            }

            var package      = GetOrCreateNode(template, "Package", defaultNamespace);
            var dependencies = GetOrCreateNode(package, "Dependencies", defaultNamespace);

            var dependency = new XElement(nsUap4 + "MainPackageDependency");

            dependencies.Add(dependency);

            var parentName      = config.ParentName;
            var parentPublisher = config.ParentPublisher;

            if (string.IsNullOrEmpty(parentPublisher) || string.IsNullOrEmpty(parentName))
            {
                IAppxFileReader reader = null;
                try
                {
                    if (string.Equals(FileConstants.AppxManifestFile, Path.GetFileName(config.ParentPackagePath), StringComparison.OrdinalIgnoreCase))
                    {
                        reader = new FileInfoFileReaderAdapter(config.ParentPackagePath);
                    }
                    else
                    {
                        reader = new ZipArchiveFileReaderAdapter(config.ParentPackagePath);
                    }

                    var manifestReader = new AppxManifestReader();
                    var read           = await manifestReader.Read(reader).ConfigureAwait(false);

                    if (string.IsNullOrEmpty(parentPublisher))
                    {
                        parentPublisher = read.Publisher;
                    }

                    if (string.IsNullOrEmpty(parentName))
                    {
                        parentName = read.Name;
                    }
                }
                finally
                {
                    reader?.Dispose();
                }
            }

            dependency.SetAttributeValue("Name", parentName);
            dependency.SetAttributeValue("Publisher", parentPublisher);

            var identity = GetOrCreateNode(package, "Identity", defaultNamespace);

            identity.SetAttributeValue("Name", config.Name);
            identity.SetAttributeValue("Publisher", config.Publisher);

            var fixVersion = Version.Parse(config.Version);

            var major    = fixVersion.Major;
            var minor    = fixVersion.Minor;
            var build    = fixVersion.Build;
            var revision = fixVersion.Revision;

            if (major < 0)
            {
                throw new FormatException("Invalid version format, major version is required.");
            }

            if (minor < 0)
            {
                throw new FormatException("Invalid version format, major version is required.");
            }

            if (revision < 0)
            {
                revision = 0;
            }

            if (build < 0)
            {
                build = 0;
            }

            identity.SetAttributeValue("Version", new Version(major, minor, build, revision).ToString(4));

            var properties = GetOrCreateNode(package, "Properties", defaultNamespace);

            GetOrCreateNode(properties, "DisplayName", defaultNamespace).Value          = config.DisplayName ?? "Modification Package Name";
            GetOrCreateNode(properties, "PublisherDisplayName", defaultNamespace).Value = config.DisplayPublisher ?? "Modification Package Publisher Name";
            GetOrCreateNode(properties, "Description", defaultNamespace).Value          = "Modification Package for " + parentName;
            GetOrCreateNode(properties, "Logo", defaultNamespace).Value         = "Assets\\Logo.png";
            GetOrCreateNode(properties, "ModificationPackage", nsRescap6).Value = "true";

            var branding = new MsixHeroBrandingInjector();

            branding.Inject(template);
        }
コード例 #14
0
        private async Task <YamlManifest> CreateFromMsix(string filePath, CancellationToken cancellationToken = default)
        {
            var yamlDefinition = new YamlManifest()
            {
                Installers = new List <YamlInstaller>
                {
                    new YamlInstaller
                    {
                        Scope         = YamlScope.User,
                        InstallerType = YamlInstallerType.Msix
                    }
                }
            };

            using IAppxFileReader reader = FileReaderFactory.CreateFileReader(filePath);
            try
            {
                yamlDefinition.Installers[0].SignatureSha256 = await this.CalculateSignatureHashAsync(new FileInfo(filePath), cancellationToken).ConfigureAwait(false);
            }
            catch (ArgumentException)
            {
            }

            var manifestReader = new AppxManifestReader();
            var details        = await manifestReader.Read(reader, cancellationToken).ConfigureAwait(false);

            yamlDefinition.PackageName                          = details.DisplayName;
            yamlDefinition.Publisher                            = details.PublisherDisplayName;
            yamlDefinition.PackageVersion                       = details.Version;
            yamlDefinition.ShortDescription                     = details.Description;
            yamlDefinition.Installers[0].Capabilities           = details.Capabilities?.Where(c => c.Type == CapabilityType.General || c.Type == CapabilityType.Device).Select(c => c.Name).ToList();
            yamlDefinition.Installers[0].RestrictedCapabilities = details.Capabilities?.Where(c => c.Type == CapabilityType.Restricted).Select(c => c.Name).ToList();

            if (details.Applications?.Any() == true)
            {
                // Exclude some unrelated PSF stuff - they are not the right choice for the app moniker.
                var candidateForAppMoniker = details.Applications.Select(a => a.Executable)
                                             .FirstOrDefault(a =>
                                                             !string.IsNullOrEmpty(a) && !a.StartsWith("psf", StringComparison.OrdinalIgnoreCase) &&
                                                             !a.StartsWith("AI_stubs", StringComparison.OrdinalIgnoreCase) &&
                                                             a.EndsWith(".exe", StringComparison.OrdinalIgnoreCase));

                yamlDefinition.Platform = new List <YamlPlatform>()
                {
                    details.Applications.Any(a => a.EntryPoint == "Windows.FullTrustApplication") ? YamlPlatform.WindowsDesktop : YamlPlatform.WindowsUniversal
                };

                if (!string.IsNullOrEmpty(candidateForAppMoniker))
                {
                    yamlDefinition.Moniker = candidateForAppMoniker.Substring(0, candidateForAppMoniker.Length - ".exe".Length).Split('\\', '/').Last();
                }
            }

            switch (details.ProcessorArchitecture)
            {
            case AppxPackageArchitecture.Arm:
                yamlDefinition.Installers[0].Architecture = YamlArchitecture.Arm;
                break;

            case AppxPackageArchitecture.Neutral:
                yamlDefinition.Installers[0].Architecture = YamlArchitecture.Neutral;
                break;

            case AppxPackageArchitecture.Arm64:
                yamlDefinition.Installers[0].Architecture = YamlArchitecture.Arm64;
                break;

            case AppxPackageArchitecture.x86:
                yamlDefinition.Installers[0].Architecture = YamlArchitecture.X86;
                break;

            case AppxPackageArchitecture.x64:
                yamlDefinition.Installers[0].Architecture = YamlArchitecture.X64;
                break;
            }

            return(yamlDefinition);
        }
コード例 #15
0
        public PsfApplicationDescriptor Read(string applicationId, string originalEntryPoint, IAppxFileReader fileReader)
        {
            if (
                string.Equals(originalEntryPoint, @"AI_STUBS\AiStub.exe", StringComparison.OrdinalIgnoreCase) ||
                string.Equals(originalEntryPoint, @"AI_STUBS\AiStubElevated.exe", StringComparison.OrdinalIgnoreCase))
            {
                if (fileReader.FileExists(@"AI_STUBS\AiStub.exe") || fileReader.FileExists(@"AI_STUBS\AiStubElevated.exe"))
                {
                    // This is an old Advanced Installer stuff
                    if (fileReader.FileExists("Registry.dat"))
                    {
                        RegistryHiveOnDemand reg;
                        using (var stream = fileReader.GetFile("Registry.dat"))
                        {
                            if (stream is FileStream fileStream)
                            {
                                reg = new RegistryHiveOnDemand(fileStream.Name);
                            }
                            else
                            {
                                using var memoryStream = new MemoryStream();
                                stream.CopyTo(memoryStream);
                                memoryStream.Flush();
                                reg = new RegistryHiveOnDemand(memoryStream.ToArray(), "Registry.dat");
                            }
                        }

                        var key = reg.GetKey(@"root\registry\machine\software\caphyon\advanced installer\" + applicationId);
                        if (key?.Values != null)
                        {
                            var psfDef = new PsfApplicationDescriptor();

                            foreach (var item in key.Values.Where(item => item.ValueName != null))
                            {
                                switch (item.ValueName.ToLowerInvariant())
                                {
                                case "path":
                                    psfDef.Executable = (item.ValueData ?? string.Empty).Replace("[{AppVPackageRoot}]\\", string.Empty);
                                    break;

                                case "pathai":
                                    psfDef.Executable = (item.ValueData ?? string.Empty).Replace("[{AppVPackageRoot}]\\", string.Empty);
                                    break;

                                case "workingdirectory":
                                    psfDef.WorkingDirectory = (item.ValueData ?? string.Empty).Replace("[{AppVPackageRoot}]\\", string.Empty);
                                    break;

                                case "workingdirectoryai":
                                    psfDef.WorkingDirectory = (item.ValueData ?? string.Empty).Replace("[{AppVPackageRoot}]\\", string.Empty);
                                    break;

                                case "args":
                                    psfDef.Arguments = item.ValueData;
                                    break;
                                }
                            }

                            if (string.IsNullOrWhiteSpace(psfDef.Executable))
                            {
                                psfDef.Executable = null;
                            }
                            else if (psfDef.Executable.StartsWith("[{", StringComparison.OrdinalIgnoreCase))
                            {
                                var indexOfClosing = psfDef.Executable.IndexOf("}]", StringComparison.OrdinalIgnoreCase);
                                if (indexOfClosing != -1)
                                {
                                    var middlePart = psfDef.Executable.Substring(2, indexOfClosing - 2);
                                    var testedPath = "VFS\\" + middlePart + psfDef.Executable.Substring(indexOfClosing + 2);

                                    if (fileReader.FileExists(testedPath))
                                    {
                                        // this is to make sure that a path like [{ProgramFilesX86}]\test is replaced to VFS\ProgramFilesX86\test if present
                                        psfDef.Executable = testedPath;
                                    }
                                }
                            }

                            if (string.IsNullOrWhiteSpace(psfDef.WorkingDirectory))
                            {
                                psfDef.WorkingDirectory = null;
                            }

                            if (string.IsNullOrWhiteSpace(psfDef.Arguments))
                            {
                                psfDef.Arguments = null;
                            }

                            return(psfDef);
                        }
                    }
                }
            }

            var    dir = Path.GetDirectoryName(originalEntryPoint);
            string configJson;

            if (string.IsNullOrEmpty(dir))
            {
                configJson = "config.json";
            }
            else
            {
                configJson = Path.Combine(dir, "config.json");
            }

            if (fileReader.FileExists(configJson))
            {
                using (var stream = fileReader.GetFile(configJson))
                {
                    using (var streamReader = new StreamReader(stream))
                    {
                        return(this.Read(applicationId, originalEntryPoint, streamReader));
                    }
                }
            }

            return(null);
        }
コード例 #16
0
        private static async Task <AppxPackage> Translate(IAppxFileReader fileReader, AppxPackage package, CancellationToken cancellationToken)
        {
            var translationRequired = package.DisplayName?.StartsWith("ms-resource:") == true ||
                                      package.PublisherDisplayName?.StartsWith("ms-resource:") == true ||
                                      package.Description?.StartsWith("ms-resource:") == true ||
                                      package.Applications.Any(a => a.DisplayName?.StartsWith("ms-resource:") == true) ||
                                      package.Applications.Any(a => a.Description?.StartsWith("ms-resource:") == true);

            if (!translationRequired)
            {
                return(package);
            }

            string priFullPath = null;
            var    cleanup     = false;

            try
            {
                if (fileReader.FileExists("resources.pri"))
                {
                    using (var stream = fileReader.GetFile("resources.pri"))
                    {
                        if (stream is FileStream fileStream)
                        {
                            priFullPath = fileStream.Name;
                        }
                        else
                        {
                            priFullPath = Path.GetTempFileName();
                            cleanup     = true;

                            using (var fs = File.OpenWrite(priFullPath))
                            {
                                await stream.CopyToAsync(fs, cancellationToken).ConfigureAwait(false);

                                await fs.FlushAsync(cancellationToken).ConfigureAwait(false);
                            }
                        }
                    }

                    package.DisplayName          = StringLocalizer.Localize(priFullPath, package.Name, package.FullName, package.DisplayName);
                    package.Description          = StringLocalizer.Localize(priFullPath, package.Name, package.FullName, package.Description);
                    package.PublisherDisplayName = StringLocalizer.Localize(priFullPath, package.Name, package.FullName, package.PublisherDisplayName);

                    if (string.IsNullOrEmpty(package.DisplayName))
                    {
                        package.DisplayName = package.Name;
                    }

                    if (string.IsNullOrEmpty(package.PublisherDisplayName))
                    {
                        package.PublisherDisplayName = package.Publisher;
                    }

                    foreach (var app in package.Applications ?? Enumerable.Empty <AppxApplication>())
                    {
                        app.DisplayName = StringLocalizer.Localize(priFullPath, app.Id, package.FullName, app.DisplayName);

                        if (string.IsNullOrEmpty(app.DisplayName))
                        {
                            app.DisplayName = app.Id;
                        }

                        app.Description = StringLocalizer.Localize(priFullPath, app.Id, package.FullName, app.Description);
                    }
                }

                return(package);
            }
            finally
            {
                if (cleanup && File.Exists(priFullPath))
                {
                    File.Delete(priFullPath);
                }
            }
        }
コード例 #17
0
        private async Task <AppxPackage> ReadMsix(IAppxFileReader fileReader, string manifestFileName, CancellationToken cancellationToken = default)
        {
            using (var file = fileReader.GetFile(manifestFileName))
            {
                var document = await XDocument.LoadAsync(file, LoadOptions.None, cancellationToken).ConfigureAwait(false);

                if (document.Root == null)
                {
                    throw new FormatException("The manifest is malformed. There is no root element.");
                }

                var ns        = XNamespace.Get("http://schemas.microsoft.com/appx/manifest/foundation/windows10");
                var ns2       = XNamespace.Get("http://schemas.microsoft.com/appx/2010/manifest");
                var uap       = XNamespace.Get("http://schemas.microsoft.com/appx/manifest/uap/windows10");
                var uap10     = XNamespace.Get("http://schemas.microsoft.com/appx/manifest/uap/windows10/10");
                var uap5      = XNamespace.Get("http://schemas.microsoft.com/appx/manifest/uap/windows10/5");
                var uap3      = XNamespace.Get("http://schemas.microsoft.com/appx/manifest/uap/windows10/3");
                var desktop10 = XNamespace.Get("http://schemas.microsoft.com/appx/manifest/desktop/windows10");
                var desktop6  = XNamespace.Get("http://schemas.microsoft.com/appx/manifest/desktop/windows10/6");
                var desktop2  = XNamespace.Get("http://schemas.microsoft.com/appx/manifest/desktop/windows10/2");
                var build     = XNamespace.Get("http://schemas.microsoft.com/developer/appx/2015/build");

                if (document.Root == null)
                {
                    throw new FormatException("The manifest is malformed. The document root must be <Package /> element.");
                }

                if (document.Root.Name.LocalName != "Package")
                {
                    throw new FormatException("The manifest is malformed. The document root must be <Package /> element.");
                }

                if (document.Root.Name.Namespace != ns && document.Root.Name.Namespace != ns2)
                {
                    throw new FormatException("The manifest is malformed. The document root must be <Package /> element, belonging to a supported namespace.");
                }

                var nodePackage = document.Root;

                cancellationToken.ThrowIfCancellationRequested();
                var nodeIdentity = nodePackage.Element(ns + "Identity") ?? nodePackage.Element(ns2 + "Identity");

                cancellationToken.ThrowIfCancellationRequested();
                var nodeProperties = nodePackage.Element(ns + "Properties") ?? nodePackage.Element(ns2 + "Properties");

                cancellationToken.ThrowIfCancellationRequested();
                var nodeApplicationsRoot = nodePackage.Element(ns + "Applications") ?? nodePackage.Element(ns2 + "Applications");

                cancellationToken.ThrowIfCancellationRequested();
                var nodeCapabilitiesRoot = nodePackage.Element(ns + "Capabilities") ?? nodePackage.Element(ns2 + "Capabilities");

                cancellationToken.ThrowIfCancellationRequested();
                var nodeDependenciesRoot = nodePackage.Element(ns + "Dependencies") ?? nodePackage.Element(ns2 + "Dependencies");

                cancellationToken.ThrowIfCancellationRequested();
                var nodePrerequisitesRoot = nodePackage.Element(ns + "Prerequisites") ?? nodePackage.Element(ns2 + "Prerequisites");

                cancellationToken.ThrowIfCancellationRequested();
                var nodeBuild = nodePackage.Element(build + "Metadata");

                var appxPackage = new AppxPackage();

                if (fileReader is IAppxDiskFileReader diskReader)
                {
                    appxPackage.RootFolder = diskReader.RootDirectory;
                }
                else if (fileReader is ZipArchiveFileReaderAdapter zipArchiveReader)
                {
                    appxPackage.RootFolder = Path.GetDirectoryName(zipArchiveReader.PackagePath);
                }

                cancellationToken.ThrowIfCancellationRequested();
                if (nodeIdentity != null)
                {
                    appxPackage.Name = nodeIdentity.Attribute("Name")?.Value;
                    var procArch = nodeIdentity.Attribute("ProcessorArchitecture")?.Value;
                    if (Enum.TryParse(typeof(AppxPackageArchitecture), procArch ?? string.Empty, true, out object parsedArchitecture) && parsedArchitecture != null)
                    {
                        appxPackage.ProcessorArchitecture = (AppxPackageArchitecture)parsedArchitecture;
                    }
                    else
                    {
                        appxPackage.ProcessorArchitecture = AppxPackageArchitecture.Neutral;
                    }

                    appxPackage.Publisher = nodeIdentity.Attribute("Publisher")?.Value;
                    appxPackage.Version   = nodeIdentity.Attribute("Version")?.Value;
                }

                cancellationToken.ThrowIfCancellationRequested();
                if (nodeProperties != null)
                {
                    foreach (var node in nodeProperties.Elements())
                    {
                        switch (node.Name.LocalName)
                        {
                        case "Logo":
                            var logo = node.Value;
                            if (!string.IsNullOrEmpty(logo))
                            {
                                using (var resourceStream = fileReader.GetResource(logo))
                                {
                                    if (resourceStream != null)
                                    {
                                        using (var memoryStream = new MemoryStream())
                                        {
                                            await resourceStream.CopyToAsync(memoryStream, cancellationToken).ConfigureAwait(false);

                                            await memoryStream.FlushAsync(cancellationToken).ConfigureAwait(false);

                                            appxPackage.Logo = memoryStream.ToArray();
                                        }
                                    }
                                }
                            }

                            break;

                        case "DisplayName":
                            appxPackage.DisplayName = node.Value;
                            break;

                        case "PublisherDisplayName":
                            appxPackage.PublisherDisplayName = node.Value;
                            break;

                        case "PackageIntegrity":
                            var packageIntegrityContent = nodeProperties.Element(uap10 + "Content");
                            if (packageIntegrityContent != null)
                            {
                                appxPackage.PackageIntegrity = packageIntegrityContent.Attribute("Enforcement")?.Value == "on";
                            }

                            break;

                        case "Framework":
                            appxPackage.IsFramework = string.Equals(node.Value ?? "false", "true", StringComparison.OrdinalIgnoreCase);
                            break;

                        case "Description":
                            appxPackage.Description = node.Value;
                            break;
                        }
                    }
                }

                cancellationToken.ThrowIfCancellationRequested();
                appxPackage.PackageDependencies         = new List <AppxPackageDependency>();
                appxPackage.OperatingSystemDependencies = new List <AppxOperatingSystemDependency>();
                appxPackage.MainPackages = new List <AppxMainPackageDependency>();
                appxPackage.Applications = new List <AppxApplication>();

                if (nodeApplicationsRoot != null)
                {
                    foreach (var node in nodeApplicationsRoot.Elements().Where(x => x.Name.LocalName == "Application" && (x.Name.Namespace == ns || x.Name.Namespace == ns2)))
                    {
                        cancellationToken.ThrowIfCancellationRequested();

                        /*
                         * <Application EntryPoint="SparklerApp.App" Executable="XD.exe" Id="App">
                         *  <uap:VisualElements BackgroundColor="#2D001E" Description="Adobe XD" DisplayName="Adobe XD" Square150x150Logo="Assets\xd_med_tile.png" Square44x44Logo="Assets\xd_app_list_icon.png">
                         *    <uap:DefaultTile Square310x310Logo="Assets\xd_large_tile.png" Square71x71Logo="Assets\xd_small_tile.png" Wide310x150Logo="Assets\xd_wide_tile.png">
                         *      <uap:ShowNameOnTiles>
                         *        <uap:ShowOn Tile="square150x150Logo" />
                         *        <uap:ShowOn Tile="wide310x150Logo" />
                         *        <uap:ShowOn Tile="square310x310Logo" />
                         *      </uap:ShowNameOnTiles>
                         *    </uap:DefaultTile>
                         *    <uap:SplashScreen BackgroundColor="#FFFFFF" Image="Assets\xd_splash.png" />
                         *  </uap:VisualElements>
                         *
                         * <Application Id="RayEval" Executable="PsfLauncher32.exe" EntryPoint="Windows.FullTrustApplication">
                         *  <uap:VisualElements DisplayName="RayEval" Description="RayEval Raynet GmbH" BackgroundColor="transparent"
                         *      Square150x150Logo="Assets\Square150x150Logo.scale-100.png" Square44x44Logo="Assets\Square44x44Logo.scale-100.png">
                         *      <uap:DefaultTile Wide310x150Logo="Assets\Square310x150Logo.scale-100.png" Square310x310Logo="Assets\Square310x310Logo.scale-100.png" Square71x71Logo="Assets\Square71x71Logo.scale-100.png" />
                         *  </uap:VisualElements>
                         *  <Extensions />
                         * </Application>
                         */

                        var appxApplication = new AppxApplication
                        {
                            EntryPoint = node.Attribute("EntryPoint")?.Value,
                            StartPage  = node.Attribute("StartPage")?.Value,
                            Executable = node.Attribute("Executable")?.Value,
                            Id         = node.Attribute("Id")?.Value,
                            Extensions = new List <AppxExtension>()
                        };


                        /*
                         * <Extensions><desktop6:Extension Category="windows.service" Executable="VFS\ProgramFilesX86\RayPackStudio\FloatingLicenseServer\FloatingLicenseServer.exe" EntryPoint="Windows.FullTrustApplication"><desktop6:Service Name="PkgSuiteFloatingLicenseServer" StartupType="auto" StartAccount="networkService" /></desktop6:Extension></Extensions>
                         */

                        var nodeExtensions = node.Elements().FirstOrDefault(e => e.Name.LocalName == "Extensions");

                        if (nodeExtensions != null)
                        {
                            foreach (var extension in nodeExtensions.Elements().Where(e => e.Name.LocalName == "Extension" && (e.Name.Namespace == ns || e.Name.Namespace == ns2 || e.Name.Namespace == desktop6 || e.Name.Namespace == desktop2 || e.Name.Namespace == uap5 || e.Name.Namespace == uap3)))
                            {
                                cancellationToken.ThrowIfCancellationRequested();
                                var category = extension.Attribute("Category")?.Value;

                                switch (category)
                                {
                                case "windows.appExecutionAlias":
                                    var aliasNode = extension.Element(uap3 + "AppExecutionAlias") ?? extension.Element(uap5 + "AppExecutionAlias");
                                    if (aliasNode != null)
                                    {
                                        var desktopExecAliases = aliasNode.Elements(desktop10 + "ExecutionAlias").Concat(aliasNode.Elements(uap5 + "ExecutionAlias"));
                                        foreach (var desktopExecAlias in desktopExecAliases)
                                        {
                                            if (appxApplication.ExecutionAlias == null)
                                            {
                                                appxApplication.ExecutionAlias = new List <string>();
                                            }

                                            appxApplication.ExecutionAlias.Add(desktopExecAlias.Attribute("Alias")?.Value);
                                        }
                                    }

                                    break;

                                case "windows.service":
                                    var serviceNode = extension.Element(desktop6 + "Service");
                                    if (serviceNode == null)
                                    {
                                        continue;
                                    }

                                    var service = new AppxService
                                    {
                                        Category = "windows.service"
                                    };

                                    service.EntryPoint = extension.Attribute("EntryPoint")?.Value;
                                    service.Executable = extension.Attribute("Executable")?.Value;

                                    service.Name         = extension.Attribute("Name")?.Value;
                                    service.StartAccount = extension.Attribute("StartAccount")?.Value;
                                    service.StartupType  = extension.Attribute("StartupType")?.Value;

                                    appxApplication.Extensions.Add(service);
                                    break;
                                }
                            }
                        }

                        var visualElements = node.Elements().FirstOrDefault(e => e.Name.LocalName == "VisualElements");
                        if (visualElements != null)
                        {
                            cancellationToken.ThrowIfCancellationRequested();
                            appxApplication.Description       = visualElements.Attribute("Description")?.Value;
                            appxApplication.DisplayName       = visualElements.Attribute("DisplayName")?.Value;
                            appxApplication.BackgroundColor   = visualElements.Attribute("BackgroundColor")?.Value;
                            appxApplication.Square150x150Logo = visualElements.Attribute("Square150x150Logo")?.Value;
                            appxApplication.Square44x44Logo   = visualElements.Attribute("Square44x44Logo")?.Value;
                            appxApplication.Visible           = visualElements.Attribute("AppListEntry")?.Value != "none";

                            var defaultTile = visualElements.Element(uap + "DefaultTile");
                            if (defaultTile != null)
                            {
                                appxApplication.Wide310x150Logo   = defaultTile.Attribute("Wide310x150Logo")?.Value;
                                appxApplication.Square310x310Logo = defaultTile.Attribute("Square310x310Logo")?.Value;
                                appxApplication.Square71x71Logo   = defaultTile.Attribute("Square71x71Logo")?.Value;
                                appxApplication.ShortName         = defaultTile.Attribute("ShortName")?.Value;
                            }

                            var logo = appxApplication.Square44x44Logo ?? appxApplication.Square30x30Logo ?? appxApplication.Square71x71Logo ?? appxApplication.Square150x150Logo;
                            if (logo == null)
                            {
                                appxApplication.Logo = appxPackage.Logo;
                            }
                            else
                            {
                                using (var stream =
                                           fileReader.GetResource(appxApplication.Square44x44Logo) ??
                                           fileReader.GetResource(appxApplication.Square30x30Logo) ??
                                           fileReader.GetResource(appxApplication.Square71x71Logo) ??
                                           fileReader.GetResource(appxApplication.Square150x150Logo))
                                {
                                    if (stream != null)
                                    {
                                        var bytes = new byte[stream.Length];
                                        await stream.ReadAsync(bytes, 0, bytes.Length, cancellationToken).ConfigureAwait(false);

                                        appxApplication.Logo = bytes;
                                    }
                                    else
                                    {
                                        appxApplication.Logo = appxPackage.Logo;
                                    }
                                }
                            }
                        }

                        appxPackage.Applications.Add(appxApplication);
                    }

                    var psfApps = appxPackage.Applications.Where(a =>
                                                                 PackageTypeConverter.GetPackageTypeFrom(a.EntryPoint, a.Executable, a.StartPage, appxPackage.IsFramework) ==
                                                                 MsixPackageType.BridgePsf).ToArray();

                    if (psfApps.Any())
                    {
                        foreach (var psfApp in psfApps)
                        {
                            cancellationToken.ThrowIfCancellationRequested();
                            psfApp.Psf = this.PsfReader.Read(psfApp.Id, psfApp.Executable, fileReader);
                        }
                    }
                }

                if (nodeDependenciesRoot != null)
                {
                    var dependencies = nodeDependenciesRoot.Elements();

                    if (dependencies != null)
                    {
                        foreach (var node in dependencies)
                        {
                            switch (node.Name.LocalName)
                            {
                            case "MainPackageDependency":
                                var modName = node.Attribute("Name")?.Value;

                                var appxModPackDependency = new AppxMainPackageDependency
                                {
                                    Name = modName,
                                };

                                appxPackage.MainPackages.Add(appxModPackDependency);

                                break;

                            case "TargetDeviceFamily":
                            {
                                /*
                                 * <TargetDeviceFamily MaxVersionTested="10.0.15063.0" MinVersion="10.0.15063.0" Name="Windows.Universal" />
                                 */

                                var minVersion = node.Attribute("MinVersion")?.Value;
                                var maxVersion = node.Attribute("MaxVersionTested")?.Value;
                                var name       = node.Attribute("Name")?.Value;

                                appxPackage.OperatingSystemDependencies.Add(new AppxOperatingSystemDependency
                                    {
                                        Minimum = WindowsNames.GetOperatingSystemFromNameAndVersion(name, minVersion),
                                        Tested  = WindowsNames.GetOperatingSystemFromNameAndVersion(name, maxVersion),
                                    });

                                break;
                            }

                            case "PackageDependency":
                            {
                                /*
                                 * <PackageDependency MinVersion="1.4.24201.0" Name="Microsoft.NET.Native.Runtime.1.4" Publisher="CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US" />
                                 */

                                var minVersion = node.Attribute("MinVersion")?.Value;
                                var name       = node.Attribute("Name")?.Value;
                                var publisher  = node.Attribute("Publisher")?.Value;

                                var appxDependency = new AppxPackageDependency
                                {
                                    Publisher = publisher,
                                    Name      = name,
                                    Version   = minVersion
                                };

                                appxPackage.PackageDependencies.Add(appxDependency);
                                break;
                            }
                            }
                        }
                    }
                }

                if (nodePrerequisitesRoot != null)
                {
                    var min = nodePrerequisitesRoot.Element(ns2 + "OSMinVersion")?.Value;
                    var max = nodePrerequisitesRoot.Element(ns2 + "OSMaxVersionTested")?.Value;

                    appxPackage.OperatingSystemDependencies.Add(new AppxOperatingSystemDependency
                    {
                        Minimum = min == null ? null : WindowsNames.GetOperatingSystemFromNameAndVersion("Windows.Desktop", min),
                        Tested  = max == null ? null : WindowsNames.GetOperatingSystemFromNameAndVersion("Windows.Desktop", max),
                    });
                }

                if (nodeBuild != null)
                {
                    var buildKeyValues = new Dictionary <string, string>();

                    foreach (var buildNode in nodeBuild.Elements(build + "Item"))
                    {
                        var attrName = buildNode.Attribute("Name")?.Value;
                        if (attrName == null)
                        {
                            continue;
                        }

                        var attrVersion = buildNode.Attribute("Version")?.Value;
                        if (attrVersion == null)
                        {
                            attrVersion = buildNode.Attribute("Value")?.Value;
                            if (attrVersion == null)
                            {
                                continue;
                            }
                        }

                        buildKeyValues[attrName] = attrVersion;
                    }

                    var appDetector = new AuthoringAppDetector(fileReader);
                    if (appDetector.TryDetectAny(buildKeyValues, out var buildInfo))
                    {
                        appxPackage.BuildInfo = buildInfo;
                    }
                }

                appxPackage.FamilyName = AppxPackaging.GetPackageFamilyName(appxPackage.Name, appxPackage.Publisher);
                appxPackage.FullName   = AppxPackaging.GetPackageFullName(appxPackage.Name, appxPackage.Publisher, appxPackage.ProcessorArchitecture, appxPackage.Version, appxPackage.ResourceId);

                appxPackage.Capabilities = this.GetCapabilities(nodeCapabilitiesRoot);

                var pkgManager = new PackageManager();
                var pkg        = pkgManager.FindPackageForUser(string.Empty, appxPackage.FullName);
                if (pkg == null && appxPackage.ResourceId == null)
                {
                    appxPackage.FullName = AppxPackaging.GetPackageFullName(appxPackage.Name, appxPackage.Publisher, appxPackage.ProcessorArchitecture, appxPackage.Version, "neutral");
                    pkg = pkgManager.FindPackageForUser(string.Empty, appxPackage.FullName);
                }

                string manifestFilePath;
                if (pkg?.InstalledLocation != null)
                {
                    manifestFilePath = Path.Combine(pkg.InstalledLocation.Path, FileConstants.AppxManifestFile);
                }
                else if (fileReader is IAppxDiskFileReader appxDiskReader)
                {
                    manifestFilePath = Path.Combine(appxDiskReader.RootDirectory, manifestFileName);
                }
                else
                {
                    manifestFilePath = manifestFileName;
                }

                if (pkg == null)
                {
                    appxPackage.Source = new NotInstalledSource();
                }
                else if (pkg.SignatureKind == PackageSignatureKind.System)
                {
                    appxPackage.Source = new SystemSource(manifestFilePath);
                }
                else if (pkg.SignatureKind == PackageSignatureKind.None || pkg.IsDevelopmentMode)
                {
                    appxPackage.Source = new DeveloperSource(Path.Combine(appxPackage.RootFolder, manifestFileName));
                }
                else if (pkg.SignatureKind == PackageSignatureKind.Store)
                {
                    appxPackage.Source = new StorePackageSource(appxPackage.FamilyName, Path.GetDirectoryName(manifestFilePath));
                }
                else
                {
                    var appInstaller = pkg.GetAppInstallerInfo();
                    if (appInstaller != null)
                    {
                        appxPackage.Source = new AppInstallerPackageSource(appInstaller.Uri, Path.GetDirectoryName(manifestFilePath));
                    }
                }

                if (appxPackage.Source == null)
                {
                    appxPackage.Source = new StandardSource(manifestFilePath);
                }

                return(await Translate(fileReader, appxPackage, cancellationToken).ConfigureAwait(false));
            }
        }