예제 #1
0
        public void FillGaps(YamlManifest manifest)
        {
            if (manifest == null)
            {
                return;
            }

            // propagate installer type from parent to all children without the type. This property should normally be left
            // unused, but this is to retain compatibility with some earlier YAML formats.
#pragma warning disable 618
            if (manifest.Installers != null && manifest.InstallerType != default)
            {
                foreach (var installer in manifest.Installers.Where(i => i.InstallerType == default))
                {
                    installer.InstallerType = manifest.InstallerType;
                }
            }
#pragma warning restore 618

            if (manifest.PackageIdentifier == null && !string.IsNullOrEmpty(manifest.Publisher) && !string.IsNullOrEmpty(manifest.PackageName))
            {
                manifest.PackageIdentifier = (manifest.Publisher + "." + manifest.PackageName).Replace(" ", string.Empty);
            }
#pragma warning restore 618
        }
예제 #2
0
        public async Task <YamlManifest> CreateFromFile(string filePath, CancellationToken cancellationToken = default)
        {
            var detector = new InstallerTypeDetector();
            var detected = await detector.DetectSetupType(filePath, cancellationToken).ConfigureAwait(false);

            YamlManifest yaml;

            switch (detected)
            {
            case YamlInstallerType.Msi:
                yaml = await Task.Run(() => this.CreateFromMsi(filePath), cancellationToken).ConfigureAwait(false);

                break;

            case YamlInstallerType.None:
            case YamlInstallerType.Exe:
            case YamlInstallerType.InnoSetup:
            case YamlInstallerType.Nullsoft:
            case YamlInstallerType.Wix:
                yaml = await Task.Run(() => this.CreateFromExe(filePath), cancellationToken).ConfigureAwait(false);

                yaml.Installers[0].InstallerType = detected;
                break;

            case YamlInstallerType.Msix:
            case YamlInstallerType.Appx:
                yaml = await this.CreateFromMsix(filePath, cancellationToken).ConfigureAwait(false);

                yaml.Installers[0].InstallerType   = detected;
                yaml.MinimumOperatingSystemVersion = Version.Parse("10.0.0");
                break;

            default:
                yaml = new YamlManifest
                {
                    Installers = new List <YamlInstaller>
                    {
                        new YamlInstaller()
                    }
                };
                break;
            }

            yaml.PackageIdentifier             = (yaml.Publisher + "." + yaml.PackageName).Replace(" ", string.Empty);
            yaml.Installers[0].InstallerSha256 = await this.CalculateHashAsync(new FileInfo(filePath), cancellationToken).ConfigureAwait(false);

            if (yaml.Copyright != null && yaml.Copyright.IndexOf("Copy", StringComparison.OrdinalIgnoreCase) == -1 && yaml.Copyright.IndexOf("(C)", StringComparison.OrdinalIgnoreCase) == -1 && yaml.Copyright.IndexOf("http", StringComparison.OrdinalIgnoreCase) == -1)
            {
                yaml.Copyright = "Copyright (C) " + yaml.Copyright;
            }

            return(yaml);
        }
예제 #3
0
        /// <summary>
        /// Writes the given YAML definition to a text writer.
        /// </summary>
        /// <param name="manifest">The YAML definition.</param>
        /// <param name="textWriter">The text writer where the content will be written.</param>
        public void Write(YamlManifest manifest, TextWriter textWriter)
        {
            var stringBuilder = new StringBuilder();

            using (var stringWriter = new StringWriter(stringBuilder))
            {
                this.serializer.Value.Serialize(stringWriter, manifest);
            }

            stringBuilder.AppendLine();
            stringBuilder.AppendLine("# Edited with MSIX Hero");

            var serialized = stringBuilder.ToString();

            serialized = Regex.Replace(serialized, @"[\r\n]{2,}", Environment.NewLine);

            textWriter.Write(serialized);
        }
예제 #4
0
        /// <summary>
        /// Writes the given YAML definition to a given text writer and returns a task that represents the asynchronous operation.
        /// </summary>
        /// <param name="manifest">The YAML definition.</param>
        /// <param name="textWriter">The text writer where the content will be written.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>A task that represents the asynchronous operation.</returns>
        public async Task WriteAsync(YamlManifest manifest, TextWriter textWriter, CancellationToken cancellationToken = default)
        {
            var stringBuilder = new StringBuilder();

            await using (var stringWriter = new StringWriter(stringBuilder))
            {
                this.serializer.Value.Serialize(stringWriter, manifest);
            }

            cancellationToken.ThrowIfCancellationRequested();

            stringBuilder.AppendLine();
            stringBuilder.AppendLine("# Edited with MSIX Hero");

            cancellationToken.ThrowIfCancellationRequested();
            var serialized = stringBuilder.ToString();

            serialized = Regex.Replace(serialized, @"[\r\n]{2,}", Environment.NewLine);
            await textWriter.WriteAsync(serialized).ConfigureAwait(false);
        }
예제 #5
0
 /// <summary>
 /// Writes the given YAML definition to a stream.
 /// </summary>
 /// <param name="manifest">The YAML definition.</param>
 /// <param name="stream">The stream to which the content will be written.</param>
 public void Write(YamlManifest manifest, Stream stream)
 {
     using var textWriter = new StreamWriter(stream, leaveOpen: true);
     this.Write(manifest, textWriter);
 }
예제 #6
0
 /// <summary>
 /// Writes the given YAML definition to a stream and returns an asynchronous task.
 /// </summary>
 /// <param name="manifest">The YAML definition.</param>
 /// <param name="stream">The stream where to write the YAML content.</param>
 /// <param name="cancellationToken">The cancellation token.</param>
 /// <returns>A task that represents the asynchronous operation.</returns>
 public async Task WriteAsync(YamlManifest manifest, Stream stream, CancellationToken cancellationToken = default)
 {
     await using var textWriter = new StreamWriter(stream, leaveOpen: true);
     await this.WriteAsync(manifest, textWriter, cancellationToken).ConfigureAwait(false);
 }
예제 #7
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);
        }
예제 #8
0
        // ReSharper disable once MemberCanBeMadeStatic.Local
        private YamlManifest CreateFromExe(string filePath)
        {
            var fileVersionInfo = FileVersionInfo.GetVersionInfo(filePath);
            var yamlDefinition  = new YamlManifest
            {
                PackageName      = fileVersionInfo.ProductName?.Trim(),
                PackageVersion   = fileVersionInfo.ProductVersion?.Trim(),
                Publisher        = fileVersionInfo.CompanyName?.Trim(),
                ShortDescription = fileVersionInfo.FileDescription?.Trim(),
                License          = fileVersionInfo.LegalCopyright ?? fileVersionInfo.LegalTrademarks,
                Installers       = new List <YamlInstaller>
                {
                    new YamlInstaller
                    {
                        InstallerType = YamlInstallerType.Exe
                    }
                }
            };

            if (yamlDefinition.Copyright != null)
            {
                yamlDefinition.Copyright = yamlDefinition.Copyright.Trim();
                if (string.IsNullOrWhiteSpace(yamlDefinition.Copyright))
                {
                    yamlDefinition.Copyright = null;
                }
            }

            using var fs           = File.OpenRead(filePath);
            using var binaryReader = new BinaryReader(fs);
            var mz = binaryReader.ReadUInt16();

            if (mz != 0x5a4d)
            {
                return(yamlDefinition);
            }

            fs.Position = 60; // this location contains the offset for the PE header
            var offset = binaryReader.ReadUInt32();

            fs.Position = offset + sizeof(uint); // contains the architecture
            var machine = binaryReader.ReadUInt16();

            if (machine == 0x8664) // IMAGE_FILE_MACHINE_AMD64
            {
                yamlDefinition.Installers[0].Architecture = YamlArchitecture.X64;
            }
            else if (machine == 0x014c) // IMAGE_FILE_MACHINE_I386
            {
                yamlDefinition.Installers[0].Architecture = YamlArchitecture.X86;
            }
            else if (machine == 0x0200) // IMAGE_FILE_MACHINE_IA64
            {
                yamlDefinition.Installers[0].Architecture = YamlArchitecture.X64;
            }

            yamlDefinition.Installers[0].Platform = new List <YamlPlatform>()
            {
                YamlPlatform.WindowsDesktop
            };
            return(yamlDefinition);
        }