From 4449fcc5b8d104817c67135229682c66c3d892ca Mon Sep 17 00:00:00 2001 From: Rob Mensching Date: Fri, 2 Apr 2021 14:41:49 -0700 Subject: Enable codepages and languages to be set via .wxl files Fixes wixtoolset/issues#5801 --- .../Bind/AttachPatchTransformsCommand.cs | 26 ++--- .../Bind/BindDatabaseCommand.cs | 127 ++++++++++++--------- .../Bind/BindSummaryInfoCommand.cs | 61 +++++++--- .../Bind/BindTransformCommand.cs | 2 +- .../Bind/CreateDeltaPatchesCommand.cs | 4 +- .../Bind/CreateIdtFileCommand.cs | 42 ++++--- .../CreateWindowsInstallerDataFromIRCommand.cs | 32 +++++- .../Bind/GenerateDatabaseCommand.cs | 11 +- .../Bind/GenerateTransformCommand.cs | 1 - .../Bind/ProcessPropertiesCommand.cs | 101 ++++++++++++++++ 10 files changed, 289 insertions(+), 118 deletions(-) create mode 100644 src/WixToolset.Core.WindowsInstaller/Bind/ProcessPropertiesCommand.cs (limited to 'src/WixToolset.Core.WindowsInstaller/Bind') diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/AttachPatchTransformsCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/AttachPatchTransformsCommand.cs index 5f8df92c..76bcd532 100644 --- a/src/WixToolset.Core.WindowsInstaller/Bind/AttachPatchTransformsCommand.cs +++ b/src/WixToolset.Core.WindowsInstaller/Bind/AttachPatchTransformsCommand.cs @@ -91,15 +91,15 @@ namespace WixToolset.Core.WindowsInstaller.Bind var symbols = this.Intermediate.Sections.SelectMany(s => s.Symbols).ToList(); // Get the patch id from the WixPatchId symbol. - var patchIdSymbol = symbols.OfType().FirstOrDefault(); + var patchSymbol = symbols.OfType().FirstOrDefault(); - if (String.IsNullOrEmpty(patchIdSymbol.Id?.Id)) + if (String.IsNullOrEmpty(patchSymbol.Id?.Id)) { this.Messaging.Write(ErrorMessages.ExpectedPatchIdInWixMsp()); return subStorages; } - if (String.IsNullOrEmpty(patchIdSymbol.ClientPatchId)) + if (String.IsNullOrEmpty(patchSymbol.ClientPatchId)) { this.Messaging.Write(ErrorMessages.ExpectedClientPatchIdInWixMsp()); return subStorages; @@ -115,7 +115,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind } // populate MSP summary information - var patchMetadata = this.PopulateSummaryInformation(summaryInfo, symbols, patchIdSymbol, section.Codepage); + var patchMetadata = this.PopulateSummaryInformation(summaryInfo, symbols, patchSymbol); // enumerate transforms var productCodes = new SortedSet(); @@ -168,7 +168,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind mainTransform.Transform.Tables.Remove("Media"); mainTransform.Transform.Tables.Remove("MsiDigitalSignature"); - var pairedTransform = this.BuildPairedTransform(summaryInfo, patchMetadata, patchIdSymbol, mainTransform.Transform, mediaSymbol, baselineSymbol, out var productCode); + var pairedTransform = this.BuildPairedTransform(summaryInfo, patchMetadata, patchSymbol, mainTransform.Transform, mediaSymbol, baselineSymbol, out var productCode); productCode = productCode.ToUpperInvariant(); productCodes.Add(productCode); @@ -211,14 +211,14 @@ namespace WixToolset.Core.WindowsInstaller.Bind productCodes = FinalizePatchProductCodes(symbols, productCodes); // Semicolon delimited list of the product codes that can accept the patch. - summaryInfo.Add(SummaryInformationType.PatchProductCodes, new SummaryInformationSymbol(patchIdSymbol.SourceLineNumbers) + summaryInfo.Add(SummaryInformationType.PatchProductCodes, new SummaryInformationSymbol(patchSymbol.SourceLineNumbers) { PropertyId = SummaryInformationType.PatchProductCodes, Value = String.Join(";", productCodes) }); // Semicolon delimited list of transform substorage names in the order they are applied. - summaryInfo.Add(SummaryInformationType.TransformNames, new SummaryInformationSymbol(patchIdSymbol.SourceLineNumbers) + summaryInfo.Add(SummaryInformationType.TransformNames, new SummaryInformationSymbol(patchSymbol.SourceLineNumbers) { PropertyId = SummaryInformationType.TransformNames, Value = String.Join(";", transformNames) @@ -262,25 +262,25 @@ namespace WixToolset.Core.WindowsInstaller.Bind return result; } - private Dictionary PopulateSummaryInformation(Dictionary summaryInfo, List symbols, WixPatchIdSymbol patchIdSymbol, int codepage) + private Dictionary PopulateSummaryInformation(Dictionary summaryInfo, List symbols, WixPatchSymbol patchSymbol) { // PID_CODEPAGE if (!summaryInfo.ContainsKey(SummaryInformationType.Codepage)) { // Set the code page by default to the same code page for the // string pool in the database. - AddSummaryInformation(SummaryInformationType.Codepage, codepage.ToString(CultureInfo.InvariantCulture), patchIdSymbol.SourceLineNumbers); + AddSummaryInformation(SummaryInformationType.Codepage, patchSymbol.Codepage?.ToString(CultureInfo.InvariantCulture) ?? "0", patchSymbol.SourceLineNumbers); } // GUID patch code for the patch. - AddSummaryInformation(SummaryInformationType.PatchCode, patchIdSymbol.Id.Id, patchIdSymbol.SourceLineNumbers); + AddSummaryInformation(SummaryInformationType.PatchCode, patchSymbol.Id.Id, patchSymbol.SourceLineNumbers); // Indicates the minimum Windows Installer version that is required to install the patch. - AddSummaryInformation(SummaryInformationType.PatchInstallerRequirement, ((int)SummaryInformation.InstallerRequirement.Version31).ToString(CultureInfo.InvariantCulture), patchIdSymbol.SourceLineNumbers); + AddSummaryInformation(SummaryInformationType.PatchInstallerRequirement, ((int)SummaryInformation.InstallerRequirement.Version31).ToString(CultureInfo.InvariantCulture), patchSymbol.SourceLineNumbers); if (!summaryInfo.ContainsKey(SummaryInformationType.Security)) { - AddSummaryInformation(SummaryInformationType.Security, "4", patchIdSymbol.SourceLineNumbers); // Read-only enforced; + AddSummaryInformation(SummaryInformationType.Security, "4", patchSymbol.SourceLineNumbers); // Read-only enforced; } // Use authored comments or default to display name. @@ -1090,7 +1090,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind /// /// Create the #transform for the given main transform. /// - private WindowsInstallerData BuildPairedTransform(Dictionary summaryInfo, Dictionary patchMetadata, WixPatchIdSymbol patchIdSymbol, WindowsInstallerData mainTransform, MediaSymbol mediaSymbol, WixPatchBaselineSymbol baselineSymbol, out string productCode) + private WindowsInstallerData BuildPairedTransform(Dictionary summaryInfo, Dictionary patchMetadata, WixPatchSymbol patchIdSymbol, WindowsInstallerData mainTransform, MediaSymbol mediaSymbol, WixPatchBaselineSymbol baselineSymbol, out string productCode) { productCode = null; diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs index fb5d7b83..06b51ba1 100644 --- a/src/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs +++ b/src/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs @@ -37,7 +37,6 @@ namespace WixToolset.Core.WindowsInstaller.Bind this.CabbingThreadCount = context.CabbingThreadCount; this.CabCachePath = context.CabCachePath; - this.Codepage = context.Codepage; this.DefaultCompressionLevel = context.DefaultCompressionLevel; this.DelayedFields = context.DelayedFields; this.ExpectedEmbeddedFiles = context.ExpectedEmbeddedFiles; @@ -47,6 +46,9 @@ namespace WixToolset.Core.WindowsInstaller.Bind this.OutputPath = context.OutputPath; this.OutputPdbPath = context.PdbPath; this.PdbType = context.PdbType; + this.ResolvedCodepage = context.ResolvedCodepage; + this.ResolvedSummaryInformationCodepage = context.ResolvedSummaryInformationCodepage; + this.ResolvedLcid = context.ResolvedLcid; this.SuppressLayout = context.SuppressLayout; this.SubStorages = subStorages; @@ -67,8 +69,6 @@ namespace WixToolset.Core.WindowsInstaller.Bind private IPathResolver PathResolver { get; } - private int Codepage { get; } - private int CabbingThreadCount { get; } private string CabCachePath { get; } @@ -95,6 +95,12 @@ namespace WixToolset.Core.WindowsInstaller.Bind private string OutputPdbPath { get; } + private int? ResolvedCodepage { get; } + + private int? ResolvedSummaryInformationCodepage { get; } + + private int? ResolvedLcid { get; } + private bool SuppressAddingValidationRows { get; } private bool SuppressLayout { get; } @@ -111,21 +117,22 @@ namespace WixToolset.Core.WindowsInstaller.Bind public IBindResult Execute() { - if (!this.Intermediate.HasLevel(Data.IntermediateLevels.Linked) && !this.Intermediate.HasLevel(Data.IntermediateLevels.Resolved)) + if (!this.Intermediate.HasLevel(Data.IntermediateLevels.Linked) || !this.Intermediate.HasLevel(Data.IntermediateLevels.Resolved)) { this.Messaging.Write(ErrorMessages.IntermediatesMustBeResolved(this.Intermediate.Id)); } var section = this.Intermediate.Sections.Single(); + var packageSymbol = (section.Type == SectionType.Product) ? this.GetSingleSymbol(section) : null; + var moduleSymbol = (section.Type == SectionType.Module) ? this.GetSingleSymbol(section) : null; + var patchSymbol = (section.Type == SectionType.Patch) ? this.GetSingleSymbol(section) : null; + var fileTransfers = new List(); var trackedFiles = new List(); var containsMergeModules = false; - // If there are any fields to resolve later, create the cache to populate during bind. - var variableCache = this.DelayedFields.Any() ? new Dictionary(StringComparer.InvariantCultureIgnoreCase) : null; - // Load standard tables, authored custom tables, and extension custom tables. TableDefinitionCollection tableDefinitions; { @@ -135,7 +142,21 @@ namespace WixToolset.Core.WindowsInstaller.Bind tableDefinitions = command.TableDefinitions; } - // Process the summary information table before the other tables. + // Calculate codepage + var codepage = this.CalculateCodepage(packageSymbol, moduleSymbol, patchSymbol); + + // Process properties and create the delayed variable cache if needed. + Dictionary variableCache = null; + string productLanguage = null; + { + var command = new ProcessPropertiesCommand(section, packageSymbol, this.ResolvedLcid ?? 0, this.DelayedFields.Any(), this.WindowsInstallerBackendHelper); + command.Execute(); + + variableCache = command.DelayedVariablesCache; + productLanguage = command.ProductLanguage; + } + + // Process the summary information table after properties are processed. bool compressed; bool longNames; int installerVersion; @@ -144,7 +165,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind { var branding = this.ServiceProvider.GetService(); - var command = new BindSummaryInfoCommand(section, this.WindowsInstallerBackendHelper, branding); + var command = new BindSummaryInfoCommand(section, this.ResolvedSummaryInformationCodepage, productLanguage, this.WindowsInstallerBackendHelper, branding); command.Execute(); compressed = command.Compressed; @@ -154,49 +175,6 @@ namespace WixToolset.Core.WindowsInstaller.Bind modularizationSuffix = command.ModularizationSuffix; } - // Add binder variables for all properties. - if (SectionType.Product == section.Type || variableCache != null) - { - foreach (var propertyRow in section.Symbols.OfType()) - { - // Set the ProductCode if it is to be generated. - if ("ProductCode".Equals(propertyRow.Id.Id, StringComparison.Ordinal) && "*".Equals(propertyRow.Value, StringComparison.Ordinal)) - { - propertyRow.Value = this.WindowsInstallerBackendHelper.CreateGuid(); - -#if TODO_PATCHING // Is this still necessary? - - // Update the target ProductCode in any instance transforms. - foreach (SubStorage subStorage in this.Output.SubStorages) - { - Output subStorageOutput = subStorage.Data; - if (OutputType.Transform != subStorageOutput.Type) - { - continue; - } - - Table instanceSummaryInformationTable = subStorageOutput.Tables["_SummaryInformation"]; - foreach (Row row in instanceSummaryInformationTable.Rows) - { - if ((int)SummaryInformation.Transform.ProductCodes == row.FieldAsInteger(0)) - { - row[1] = row.FieldAsString(1).Replace("*", propertyRow.Value); - break; - } - } - } -#endif - } - - // Add the property name and value to the variableCache. - if (variableCache != null) - { - var key = String.Concat("property.", propertyRow.Id.Id); - variableCache[key] = propertyRow.Value; - } - } - } - // Sequence all the actions. { var command = new SequenceActionsCommand(this.Messaging, section); @@ -415,7 +393,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind // Time to create the WindowsInstallerData object. Try to put as much above here as possible, updating the IR is better. WindowsInstallerData data; { - var command = new CreateWindowsInstallerDataFromIRCommand(this.Messaging, section, tableDefinitions, this.BackendExtensions, this.WindowsInstallerBackendHelper); + var command = new CreateWindowsInstallerDataFromIRCommand(this.Messaging, section, tableDefinitions, codepage, this.BackendExtensions, this.WindowsInstallerBackendHelper); data = command.Execute(); } @@ -450,7 +428,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind if (SectionType.Patch == section.Type && this.DeltaBinaryPatch) { - var command = new CreateDeltaPatchesCommand(fileFacades, this.IntermediateFolder, section.Symbols.OfType().FirstOrDefault()); + var command = new CreateDeltaPatchesCommand(fileFacades, this.IntermediateFolder, section.Symbols.OfType().FirstOrDefault()); command.Execute(); } @@ -508,7 +486,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind var trackMsi = this.WindowsInstallerBackendHelper.TrackFile(this.OutputPath, TrackedFileType.Final); trackedFiles.Add(trackMsi); - var command = new GenerateDatabaseCommand(this.Messaging, this.WindowsInstallerBackendHelper, this.FileSystemManager, data, trackMsi.Path, tableDefinitions, this.IntermediateFolder, this.Codepage, keepAddedColumns: false, this.SuppressAddingValidationRows, useSubdirectory: false); + var command = new GenerateDatabaseCommand(this.Messaging, this.WindowsInstallerBackendHelper, this.FileSystemManager, data, trackMsi.Path, tableDefinitions, this.IntermediateFolder, keepAddedColumns: false, this.SuppressAddingValidationRows, useSubdirectory: false); command.Execute(); trackedFiles.AddRange(command.GeneratedTemporaryFiles); @@ -532,7 +510,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind if (this.Messaging.EncounteredError) { return null; - } + } // Validate the output if there are CUBe files and we're not explicitly suppressing validation. if (this.CubeFiles != null && !this.SuppressValidation) @@ -575,6 +553,43 @@ namespace WixToolset.Core.WindowsInstaller.Bind return result; } + private int CalculateCodepage(WixPackageSymbol packageSymbol, WixModuleSymbol moduleSymbol, WixPatchSymbol patchSymbol) + { + var codepage = packageSymbol?.Codepage ?? moduleSymbol?.Codepage ?? patchSymbol?.Codepage; + + if (String.IsNullOrEmpty(codepage)) + { + codepage = this.ResolvedCodepage?.ToString() ?? "65001"; + + if (packageSymbol != null) + { + packageSymbol.Codepage = codepage; + } + else if (moduleSymbol != null) + { + moduleSymbol.Codepage = codepage; + } + else if (patchSymbol != null) + { + patchSymbol.Codepage = codepage; + } + } + + return this.WindowsInstallerBackendHelper.GetValidCodePage(codepage); + } + + private T GetSingleSymbol(IntermediateSection section) where T : IntermediateSymbol + { + var symbols = section.Symbols.OfType().ToList(); + + if (1 != symbols.Count) + { + throw new WixException(ErrorMessages.MissingBundleInformation(nameof(T))); + } + + return symbols[0]; + } + private WixOutput CreateWixout(List trackedFiles, Intermediate intermediate, WindowsInstallerData data) { WixOutput wixout; diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/BindSummaryInfoCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/BindSummaryInfoCommand.cs index babe0c1b..41da2a13 100644 --- a/src/WixToolset.Core.WindowsInstaller/Bind/BindSummaryInfoCommand.cs +++ b/src/WixToolset.Core.WindowsInstaller/Bind/BindSummaryInfoCommand.cs @@ -14,15 +14,21 @@ namespace WixToolset.Core.WindowsInstaller.Bind /// internal class BindSummaryInfoCommand { - public BindSummaryInfoCommand(IntermediateSection section, IBackendHelper backendHelper, IWixBranding branding) + public BindSummaryInfoCommand(IntermediateSection section, int? summaryInformationCodepage, string productLanguage, IBackendHelper backendHelper, IWixBranding branding) { this.Section = section; + this.SummaryInformationCodepage = summaryInformationCodepage; + this.ProductLanguage = productLanguage; this.BackendHelper = backendHelper; this.Branding = branding; } private IntermediateSection Section { get; } + private int? SummaryInformationCodepage { get; } + + private string ProductLanguage { get; } + private IBackendHelper BackendHelper { get; } private IWixBranding Branding { get; } @@ -53,6 +59,8 @@ namespace WixToolset.Core.WindowsInstaller.Bind this.InstallerVersion = 0; this.ModularizationSuffix = null; + SummaryInformationSymbol summaryInformationCodepageSymbol = null; + SummaryInformationSymbol platformAndLanguageSymbol = null; var foundCreateDateTime = false; var foundLastSaveDataTime = false; var foundCreatingApplication = false; @@ -64,20 +72,11 @@ namespace WixToolset.Core.WindowsInstaller.Bind switch (summaryInformationSymbol.PropertyId) { case SummaryInformationType.Codepage: // PID_CODEPAGE - // make sure the code page is an int and not a web name or null - var codepage = summaryInformationSymbol.Value; - - if (String.IsNullOrEmpty(codepage)) - { - codepage = "0"; - } - else - { - summaryInformationSymbol.Value = this.BackendHelper.GetValidCodePage(codepage, false, false, summaryInformationSymbol.SourceLineNumbers).ToString(CultureInfo.InvariantCulture); - } + summaryInformationCodepageSymbol = summaryInformationSymbol; break; + case SummaryInformationType.PlatformAndLanguage: - this.Platform = GetPlatformFromSummaryInformation(summaryInformationSymbol.Value); + platformAndLanguageSymbol = summaryInformationSymbol; break; case SummaryInformationType.PackageCode: // PID_REVNUMBER @@ -117,7 +116,31 @@ namespace WixToolset.Core.WindowsInstaller.Bind } } - // set the revision number (package/patch code) if it should be automatically generated + // Ensure the codepage is set properly. + if (summaryInformationCodepageSymbol == null) + { + summaryInformationCodepageSymbol = this.Section.AddSymbol(new SummaryInformationSymbol(null) + { + PropertyId = SummaryInformationType.Codepage + }); + } + + var codepage = summaryInformationCodepageSymbol.Value; + + if (String.IsNullOrEmpty(codepage)) + { + codepage = this.SummaryInformationCodepage?.ToString(CultureInfo.InvariantCulture) ?? "1252"; + } + + summaryInformationCodepageSymbol.Value = this.BackendHelper.GetValidCodePage(codepage, onlyAnsi: true).ToString(CultureInfo.InvariantCulture); + + // Ensure the language is set properly and figure out what platform we are targeting. + if (platformAndLanguageSymbol != null) + { + this.Platform = EnsureLanguageAndGetPlatformFromSummaryInformation(platformAndLanguageSymbol, this.ProductLanguage); + } + + // Set the revision number (package/patch code) if it should be automatically generated. if (!foundPackageCode) { this.Section.AddSymbol(new SummaryInformationSymbol(null) @@ -158,11 +181,19 @@ namespace WixToolset.Core.WindowsInstaller.Bind } } - private static Platform GetPlatformFromSummaryInformation(string value) + private static Platform EnsureLanguageAndGetPlatformFromSummaryInformation(SummaryInformationSymbol symbol, string language) { + var value = symbol.Value; var separatorIndex = value.IndexOf(';'); var platformValue = separatorIndex > 0 ? value.Substring(0, separatorIndex) : value; + // If the language was provided and there was language value after the separator + // (or the separator was absent) then use the provided language. + if (!String.IsNullOrEmpty(language) && (separatorIndex < 0 || separatorIndex + 1 == value.Length)) + { + symbol.Value = platformValue + ';' + language; + } + switch (platformValue) { case "x64": diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/BindTransformCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/BindTransformCommand.cs index 3a9bd545..3379ec5d 100644 --- a/src/WixToolset.Core.WindowsInstaller/Bind/BindTransformCommand.cs +++ b/src/WixToolset.Core.WindowsInstaller/Bind/BindTransformCommand.cs @@ -438,7 +438,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind private void GenerateDatabase(WindowsInstallerData output, string outputPath, bool keepAddedColumns) { - var command = new GenerateDatabaseCommand(this.Messaging, this.BackendHelper, this.FileSystemManager, output, outputPath, this.TableDefinitions, this.IntermediateFolder, codepage: -1, keepAddedColumns, suppressAddingValidationRows: true, useSubdirectory: true); + var command = new GenerateDatabaseCommand(this.Messaging, this.BackendHelper, this.FileSystemManager, output, outputPath, this.TableDefinitions, this.IntermediateFolder, keepAddedColumns, suppressAddingValidationRows: true, useSubdirectory: true); command.Execute(); } } diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/CreateDeltaPatchesCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/CreateDeltaPatchesCommand.cs index b587e6d9..47d8399f 100644 --- a/src/WixToolset.Core.WindowsInstaller/Bind/CreateDeltaPatchesCommand.cs +++ b/src/WixToolset.Core.WindowsInstaller/Bind/CreateDeltaPatchesCommand.cs @@ -15,7 +15,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind /// internal class CreateDeltaPatchesCommand { - public CreateDeltaPatchesCommand(List fileFacades, string intermediateFolder, WixPatchIdSymbol wixPatchId) + public CreateDeltaPatchesCommand(List fileFacades, string intermediateFolder, WixPatchSymbol wixPatchId) { this.FileFacades = fileFacades; this.IntermediateFolder = intermediateFolder; @@ -24,7 +24,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind private IEnumerable FileFacades { get; } - private WixPatchIdSymbol WixPatchId { get; } + private WixPatchSymbol WixPatchId { get; } private string IntermediateFolder { get; } diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/CreateIdtFileCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/CreateIdtFileCommand.cs index f09a2e47..ff03413c 100644 --- a/src/WixToolset.Core.WindowsInstaller/Bind/CreateIdtFileCommand.cs +++ b/src/WixToolset.Core.WindowsInstaller/Bind/CreateIdtFileCommand.cs @@ -36,23 +36,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind public void Execute() { // write out the table to an IDT file - Encoding encoding; - - // If UTF8 encoding, use the UTF8-specific constructor to avoid writing - // the byte order mark at the beginning of the file - if (this.Codepage == Encoding.UTF8.CodePage) - { - encoding = new UTF8Encoding(false, true); - } - else - { - if (this.Codepage == 0) - { - this.Codepage = Encoding.ASCII.CodePage; - } - - encoding = Encoding.GetEncoding(this.Codepage, new EncoderExceptionFallback(), new DecoderExceptionFallback()); - } + var encoding = GetCodepageEncoding(this.Codepage); this.IdtPath = Path.Combine(this.IntermediateFolder, String.Concat(this.Table.Name, ".idt")); @@ -209,6 +193,30 @@ namespace WixToolset.Core.WindowsInstaller.Bind .Replace('\n', '\x19'); } + private static Encoding GetCodepageEncoding(int codepage) + { + Encoding encoding; + + // If UTF8 encoding, use the UTF8-specific constructor to avoid writing + // the byte order mark at the beginning of the file + if (codepage == Encoding.UTF8.CodePage) + { + encoding = new UTF8Encoding(false, true); + } + else + { + if (codepage == 0) + { + codepage = Encoding.ASCII.CodePage; + } + + Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); + + encoding = Encoding.GetEncoding(codepage, new EncoderExceptionFallback(), new DecoderExceptionFallback()); + } + + return encoding; + } /// /// Gets the type of the column in IDT format. diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/CreateWindowsInstallerDataFromIRCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/CreateWindowsInstallerDataFromIRCommand.cs index bc95fd4c..1bd00900 100644 --- a/src/WixToolset.Core.WindowsInstaller/Bind/CreateWindowsInstallerDataFromIRCommand.cs +++ b/src/WixToolset.Core.WindowsInstaller/Bind/CreateWindowsInstallerDataFromIRCommand.cs @@ -18,11 +18,12 @@ namespace WixToolset.Core.WindowsInstaller.Bind internal class CreateWindowsInstallerDataFromIRCommand { - public CreateWindowsInstallerDataFromIRCommand(IMessaging messaging, IntermediateSection section, TableDefinitionCollection tableDefinitions, IEnumerable backendExtensions, IWindowsInstallerBackendHelper backendHelper) + public CreateWindowsInstallerDataFromIRCommand(IMessaging messaging, IntermediateSection section, TableDefinitionCollection tableDefinitions, int codepage, IEnumerable backendExtensions, IWindowsInstallerBackendHelper backendHelper) { this.Messaging = messaging; this.Section = section; this.TableDefinitions = tableDefinitions; + this.Codepage = codepage; this.BackendExtensions = backendExtensions; this.BackendHelper = backendHelper; this.GeneratedShortNames = new Dictionary>(); @@ -36,6 +37,8 @@ namespace WixToolset.Core.WindowsInstaller.Bind private TableDefinitionCollection TableDefinitions { get; } + private int Codepage { get; } + private IntermediateSection Section { get; } private Dictionary> GeneratedShortNames { get; } @@ -46,7 +49,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind { this.Data = new WindowsInstallerData(this.Section.Symbols.First().SourceLineNumbers) { - Codepage = this.Section.Codepage, + Codepage = this.Codepage, Type = SectionTypeToOutputType(this.Section.Type) }; @@ -219,6 +222,10 @@ namespace WixToolset.Core.WindowsInstaller.Bind this.AddWixEnsureTableSymbol((WixEnsureTableSymbol)symbol); break; + case SymbolDefinitionType.WixPackage: + this.AddWixPackageSymbol((WixPackageSymbol)symbol); + break; + // Symbols used internally and are not added to the output. case SymbolDefinitionType.WixBuildInfo: case SymbolDefinitionType.WixBindUpdatedFiles: @@ -237,7 +244,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind case SymbolDefinitionType.WixOrdering: case SymbolDefinitionType.WixPatchBaseline: case SymbolDefinitionType.WixPatchFamilyGroup: - case SymbolDefinitionType.WixPatchId: + case SymbolDefinitionType.WixPatch: case SymbolDefinitionType.WixPatchRef: case SymbolDefinitionType.WixPatchTarget: case SymbolDefinitionType.WixProperty: @@ -1214,6 +1221,25 @@ namespace WixToolset.Core.WindowsInstaller.Bind this.Data.EnsureTable(tableDefinition); } + private void AddWixPackageSymbol(WixPackageSymbol symbol) + { + // TODO: Remove the following from the compiler and do it here instead. + //this.AddProperty(sourceLineNumbers, new Identifier(AccessModifier.Global, "Manufacturer"), manufacturer, false, false, false, true); + //this.AddProperty(sourceLineNumbers, new Identifier(AccessModifier.Global, "ProductCode"), productCode, false, false, false, true); + //this.AddProperty(sourceLineNumbers, new Identifier(AccessModifier.Global, "ProductLanguage"), productLanguage, false, false, false, true); + //this.AddProperty(sourceLineNumbers, new Identifier(AccessModifier.Global, "ProductName"), this.activeName, false, false, false, true); + //this.AddProperty(sourceLineNumbers, new Identifier(AccessModifier.Global, "ProductVersion"), version, false, false, false, true); + //if (null != upgradeCode) + //{ + // this.AddProperty(sourceLineNumbers, new Identifier(AccessModifier.Global, "UpgradeCode"), upgradeCode, false, false, false, true); + //} + + //if (isPerMachine) + //{ + // this.AddProperty(sourceLineNumbers, new Identifier(AccessModifier.Global, "ALLUSERS"), "1", false, false, false, false); + //} + } + private bool AddSymbolFromExtension(IntermediateSymbol symbol) { foreach (var extension in this.BackendExtensions) diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/GenerateDatabaseCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/GenerateDatabaseCommand.cs index f125f497..b8cca752 100644 --- a/src/WixToolset.Core.WindowsInstaller/Bind/GenerateDatabaseCommand.cs +++ b/src/WixToolset.Core.WindowsInstaller/Bind/GenerateDatabaseCommand.cs @@ -18,7 +18,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind { private const string IdtsSubFolder = "_idts"; - public GenerateDatabaseCommand(IMessaging messaging, IBackendHelper backendHelper, FileSystemManager fileSystemManager, WindowsInstallerData data, string outputPath, TableDefinitionCollection tableDefinitions, string intermediateFolder, int codepage, bool keepAddedColumns, bool suppressAddingValidationRows, bool useSubdirectory) + public GenerateDatabaseCommand(IMessaging messaging, IBackendHelper backendHelper, FileSystemManager fileSystemManager, WindowsInstallerData data, string outputPath, TableDefinitionCollection tableDefinitions, string intermediateFolder, bool keepAddedColumns, bool suppressAddingValidationRows, bool useSubdirectory) { this.Messaging = messaging; this.BackendHelper = backendHelper; @@ -27,14 +27,11 @@ namespace WixToolset.Core.WindowsInstaller.Bind this.OutputPath = outputPath; this.TableDefinitions = tableDefinitions; this.IntermediateFolder = intermediateFolder; - this.Codepage = codepage; this.KeepAddedColumns = keepAddedColumns; this.SuppressAddingValidationRows = suppressAddingValidationRows; this.UseSubDirectory = useSubdirectory; } - private int Codepage { get; } - private IBackendHelper BackendHelper { get; } private FileSystemManager FileSystemManager { get; } @@ -88,12 +85,6 @@ namespace WixToolset.Core.WindowsInstaller.Bind type |= OpenDatabase.OpenPatchFile; } - // Localize the codepage if a value was specified directly. - if (-1 != this.Codepage) - { - this.Data.Codepage = this.Codepage; - } - try { Directory.CreateDirectory(Path.GetDirectoryName(this.OutputPath)); diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/GenerateTransformCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/GenerateTransformCommand.cs index ef141795..faa03762 100644 --- a/src/WixToolset.Core.WindowsInstaller/Bind/GenerateTransformCommand.cs +++ b/src/WixToolset.Core.WindowsInstaller/Bind/GenerateTransformCommand.cs @@ -9,7 +9,6 @@ namespace WixToolset.Core.WindowsInstaller using WixToolset.Data; using WixToolset.Data.Symbols; using WixToolset.Data.WindowsInstaller; - using WixToolset.Data.WindowsInstaller.Rows; using WixToolset.Extensibility.Services; /// diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/ProcessPropertiesCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/ProcessPropertiesCommand.cs new file mode 100644 index 00000000..217609be --- /dev/null +++ b/src/WixToolset.Core.WindowsInstaller/Bind/ProcessPropertiesCommand.cs @@ -0,0 +1,101 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.Core.WindowsInstaller.Bind +{ + using System; + using System.Collections.Generic; + using System.Linq; + using WixToolset.Data; + using WixToolset.Data.Symbols; + using WixToolset.Extensibility.Services; + + internal class ProcessPropertiesCommand + { + public ProcessPropertiesCommand(IntermediateSection section, WixPackageSymbol packageSymbol, int fallbackLcid, bool populateDelayedVariables, IBackendHelper backendHelper) + { + this.Section = section; + this.PackageSymbol = packageSymbol; + this.FallbackLcid = fallbackLcid; + this.PopulateDelayedVariables = populateDelayedVariables; + this.BackendHelper = backendHelper; + } + + private IntermediateSection Section { get; } + + private WixPackageSymbol PackageSymbol { get; } + + private int FallbackLcid { get; } + + private bool PopulateDelayedVariables { get; } + + private IBackendHelper BackendHelper { get; } + + public Dictionary DelayedVariablesCache { get; private set; } + + public string ProductLanguage { get; private set; } + + public void Execute() + { + PropertySymbol languageSymbol = null; + var variableCache = this.PopulateDelayedVariables ? new Dictionary(StringComparer.OrdinalIgnoreCase) : null; + + if (SectionType.Product == this.Section.Type || variableCache != null) + { + foreach (var propertySymbol in this.Section.Symbols.OfType()) + { + // Set the ProductCode if it is to be generated. + if ("ProductCode" == propertySymbol.Id.Id && "*".Equals(propertySymbol.Value, StringComparison.Ordinal)) + { + propertySymbol.Value = this.BackendHelper.CreateGuid(); + +#if TODO_PATCHING // Is this still necessary? + // Update the target ProductCode in any instance transforms. + foreach (SubStorage subStorage in this.Output.SubStorages) + { + Output subStorageOutput = subStorage.Data; + if (OutputType.Transform != subStorageOutput.Type) + { + continue; + } + + Table instanceSummaryInformationTable = subStorageOutput.Tables["_SummaryInformation"]; + foreach (Row row in instanceSummaryInformationTable.Rows) + { + if ((int)SummaryInformation.Transform.ProductCodes == row.FieldAsInteger(0)) + { + row[1] = row.FieldAsString(1).Replace("*", propertyRow.Value); + break; + } + } + } +#endif + } + else if ("ProductLanguage" == propertySymbol.Id.Id) + { + languageSymbol = propertySymbol; + } + + // Add the property name and value to the variableCache. + if (variableCache != null) + { + variableCache[$"property.{propertySymbol.Id.Id}"] = propertySymbol.Value; + } + } + + if (this.Section.Type == SectionType.Product && String.IsNullOrEmpty(languageSymbol?.Value)) + { + if (languageSymbol == null) + { + languageSymbol = this.Section.AddSymbol(new PropertySymbol(this.PackageSymbol.SourceLineNumbers, new Identifier(AccessModifier.Section, "ProductLanguage"))); + } + + this.PackageSymbol.Language = this.FallbackLcid.ToString(); + languageSymbol.Value = this.FallbackLcid.ToString(); + } + } + + this.DelayedVariablesCache = variableCache; + this.ProductLanguage = languageSymbol?.Value; + } + } +} -- cgit v1.2.3-55-g6feb