main
cs 211 lines 8.48 KB
Raw
1 // 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.
2
3 namespace WixToolset.Core.WindowsInstaller.Bind
4 {
5 using System;
6 using System.Globalization;
7 using System.Linq;
8 using WixToolset.Data;
9 using WixToolset.Data.Symbols;
10 using WixToolset.Extensibility.Services;
11
12 /// <summary>
13 /// Binds the summary information table of a database.
14 /// </summary>
15 internal class BindSummaryInfoCommand
16 {
17 public BindSummaryInfoCommand(IntermediateSection section, int? summaryInformationCodepage, string productLanguage, IBackendHelper backendHelper, IWixBranding branding)
18 {
19 this.Section = section;
20 this.SummaryInformationCodepage = summaryInformationCodepage;
21 this.ProductLanguage = productLanguage;
22 this.BackendHelper = backendHelper;
23 this.Branding = branding;
24 }
25
26 private IntermediateSection Section { get; }
27
28 private int? SummaryInformationCodepage { get; }
29
30 private string ProductLanguage { get; }
31
32 private IBackendHelper BackendHelper { get; }
33
34 private IWixBranding Branding { get; }
35
36 /// <summary>
37 /// Returns a flag indicating if files are compressed by default.
38 /// </summary>
39 public bool Compressed { get; private set; }
40
41 /// <summary>
42 /// Returns a flag indicating if uncompressed files use long filenames.
43 /// </summary>
44 public bool LongNames { get; private set; }
45
46 public int InstallerVersion { get; private set; }
47
48 public Platform Platform { get; private set; }
49
50 /// <summary>
51 /// Modularization guid, or null if the output is not a module.
52 /// </summary>
53 public string ModularizationSuffix { get; private set; }
54
55 public void Execute()
56 {
57 this.Compressed = false;
58 this.LongNames = false;
59 this.InstallerVersion = 0;
60 this.ModularizationSuffix = null;
61
62 SummaryInformationSymbol summaryInformationCodepageSymbol = null;
63 SummaryInformationSymbol platformAndLanguageSymbol = null;
64 var foundCreateDateTime = false;
65 var foundLastSaveDataTime = false;
66 var foundCreatingApplication = false;
67 var foundPackageCode = false;
68 var now = DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss", CultureInfo.InvariantCulture);
69
70 foreach (var summaryInformationSymbol in this.Section.Symbols.OfType<SummaryInformationSymbol>())
71 {
72 switch (summaryInformationSymbol.PropertyId)
73 {
74 case SummaryInformationType.Codepage: // PID_CODEPAGE
75 summaryInformationCodepageSymbol = summaryInformationSymbol;
76 break;
77
78 case SummaryInformationType.PlatformAndLanguage:
79 platformAndLanguageSymbol = summaryInformationSymbol;
80 break;
81
82 case SummaryInformationType.PackageCode: // PID_REVNUMBER
83 foundPackageCode = true;
84 var packageCode = summaryInformationSymbol.Value;
85
86 if (SectionType.Module == this.Section.Type)
87 {
88 this.ModularizationSuffix = "." + packageCode.Substring(1, 36).Replace('-', '_');
89 }
90 break;
91 case SummaryInformationType.Created:
92 foundCreateDateTime = true;
93 break;
94 case SummaryInformationType.LastSaved:
95 foundLastSaveDataTime = true;
96 break;
97 case SummaryInformationType.WindowsInstallerVersion:
98 this.InstallerVersion = summaryInformationSymbol[SummaryInformationSymbolFields.Value].AsNumber();
99 break;
100 case SummaryInformationType.WordCount:
101 if (SectionType.Patch == this.Section.Type)
102 {
103 this.LongNames = true;
104 this.Compressed = true;
105 }
106 else
107 {
108 var attributes = summaryInformationSymbol[SummaryInformationSymbolFields.Value].AsNumber();
109 this.LongNames = (0 == (attributes & 1));
110 this.Compressed = (2 == (attributes & 2));
111 }
112 break;
113 case SummaryInformationType.CreatingApplication: // PID_APPNAME
114 foundCreatingApplication = true;
115 break;
116 }
117 }
118
119 // Ensure the codepage is set properly.
120 if (summaryInformationCodepageSymbol == null)
121 {
122 summaryInformationCodepageSymbol = this.Section.AddSymbol(new SummaryInformationSymbol(null)
123 {
124 PropertyId = SummaryInformationType.Codepage
125 });
126 }
127
128 var codepage = summaryInformationCodepageSymbol.Value;
129
130 if (String.IsNullOrEmpty(codepage))
131 {
132 codepage = this.SummaryInformationCodepage?.ToString(CultureInfo.InvariantCulture) ?? "1252";
133 }
134
135 summaryInformationCodepageSymbol.Value = this.BackendHelper.GetValidCodePage(codepage, onlyAnsi: true).ToString(CultureInfo.InvariantCulture);
136
137 // Ensure the language is set properly and figure out what platform we are targeting.
138 if (platformAndLanguageSymbol != null)
139 {
140 this.Platform = EnsureLanguageAndGetPlatformFromSummaryInformation(platformAndLanguageSymbol, this.ProductLanguage);
141 }
142
143 // Set the revision number (package/patch code) if it should be automatically generated.
144 if (!foundPackageCode)
145 {
146 this.Section.AddSymbol(new SummaryInformationSymbol(null)
147 {
148 PropertyId = SummaryInformationType.PackageCode,
149 Value = this.BackendHelper.CreateGuid(),
150 });
151 }
152
153 // add a summary information row for the create time/date property if its not already set
154 if (!foundCreateDateTime)
155 {
156 this.Section.AddSymbol(new SummaryInformationSymbol(null)
157 {
158 PropertyId = SummaryInformationType.Created,
159 Value = now,
160 });
161 }
162
163 // add a summary information row for the last save time/date property if its not already set
164 if (!foundLastSaveDataTime)
165 {
166 this.Section.AddSymbol(new SummaryInformationSymbol(null)
167 {
168 PropertyId = SummaryInformationType.LastSaved,
169 Value = now,
170 });
171 }
172
173 // add a summary information row for the creating application property if its not already set
174 if (!foundCreatingApplication)
175 {
176 this.Section.AddSymbol(new SummaryInformationSymbol(null)
177 {
178 PropertyId = SummaryInformationType.CreatingApplication,
179 Value = this.Branding.GetCreatingApplication(),
180 });
181 }
182 }
183
184 private static Platform EnsureLanguageAndGetPlatformFromSummaryInformation(SummaryInformationSymbol symbol, string language)
185 {
186 var value = symbol.Value;
187 var separatorIndex = value.IndexOf(';');
188 var platformValue = separatorIndex > 0 ? value.Substring(0, separatorIndex) : value;
189
190 // If the language was provided and there was language value after the separator
191 // (or the separator was absent) then use the provided language.
192 if (!String.IsNullOrEmpty(language) && (separatorIndex < 0 || separatorIndex + 1 == value.Length))
193 {
194 symbol.Value = platformValue + ';' + language;
195 }
196
197 switch (platformValue)
198 {
199 case "x64":
200 return Platform.X64;
201
202 case "Arm64":
203 return Platform.ARM64;
204
205 case "Intel":
206 default:
207 return Platform.X86;
208 }
209 }
210 }
211 }