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