main
cs 878 lines 46.1 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.Converters.Symbolizer
4 {
5 using System;
6 using System.Collections.Generic;
7 using System.Linq;
8 using WixToolset.Data;
9 using WixToolset.Data.Symbols;
10 using WixToolset.Data.WindowsInstaller;
11 using Wix3 = Microsoft.Tools.WindowsInstallerXml;
12
13 #pragma warning disable 1591 // TODO: add documentation
14 public static class ConvertSymbols
15 {
16 public static Intermediate ConvertFile(string path)
17 {
18 var output = Wix3.Output.Load(path, suppressVersionCheck: true, suppressSchema: true);
19 return ConvertOutput(output);
20 }
21
22 public static Intermediate ConvertOutput(Wix3.Output output)
23 #pragma warning restore 1591
24 {
25 var section = new IntermediateSection(String.Empty, OutputType3ToSectionType4(output.Type));
26
27 var wixMediaByDiskId = IndexWixMediaTableByDiskId(output);
28 var componentsById = IndexById<Wix3.Row>(output, "Component");
29 var bindPathsById = IndexById<Wix3.Row>(output, "BindPath");
30 var fontsById = IndexById<Wix3.Row>(output, "Font");
31 var selfRegById = IndexById<Wix3.Row>(output, "SelfReg");
32 var wixDirectoryById = IndexById<Wix3.Row>(output, "WixDirectory");
33 var wixFileById = IndexById<Wix3.Row>(output, "WixFile");
34
35 foreach (Wix3.Table table in output.Tables)
36 {
37 foreach (Wix3.Row row in table.Rows)
38 {
39 var symbol = GenerateSymbolFromRow(row, wixMediaByDiskId, componentsById, fontsById, bindPathsById, selfRegById, wixFileById, wixDirectoryById);
40 if (symbol != null)
41 {
42 section.AddSymbol(symbol);
43 }
44 }
45 }
46
47 return new Intermediate(String.Empty, new[] { section }, localizationsByCulture: null);
48 }
49
50 private static Dictionary<int, Wix3.WixMediaRow> IndexWixMediaTableByDiskId(Wix3.Output output)
51 {
52 var wixMediaByDiskId = new Dictionary<int, Wix3.WixMediaRow>();
53 var wixMediaTable = output.Tables["WixMedia"];
54
55 if (wixMediaTable != null)
56 {
57 foreach (Wix3.WixMediaRow row in wixMediaTable.Rows)
58 {
59 wixMediaByDiskId.Add(FieldAsInt(row, 0), row);
60 }
61 }
62
63 return wixMediaByDiskId;
64 }
65
66 private static Dictionary<string, T> IndexById<T>(Wix3.Output output, string tableName) where T : Wix3.Row
67 {
68 var byId = new Dictionary<string, T>();
69 var table = output.Tables[tableName];
70
71 if (table != null)
72 {
73 foreach (T row in table.Rows)
74 {
75 byId.Add(FieldAsString(row, 0), row);
76 }
77 }
78
79 return byId;
80 }
81
82 private static IntermediateSymbol GenerateSymbolFromRow(Wix3.Row row, Dictionary<int, Wix3.WixMediaRow> wixMediaByDiskId, Dictionary<string, Wix3.Row> componentsById, Dictionary<string, Wix3.Row> fontsById, Dictionary<string, Wix3.Row> bindPathsById, Dictionary<string, Wix3.Row> selfRegById, Dictionary<string, Wix3.Row> wixFileById, Dictionary<string, Wix3.Row> wixDirectoryById)
83 {
84 var name = row.Table.Name;
85 switch (name)
86 {
87 case "_SummaryInformation":
88 return DefaultSymbolFromRow(typeof(SummaryInformationSymbol), row, columnZeroIsId: false);
89 case "ActionText":
90 return DefaultSymbolFromRow(typeof(ActionTextSymbol), row, columnZeroIsId: false);
91 case "AppId":
92 return DefaultSymbolFromRow(typeof(AppIdSymbol), row, columnZeroIsId: false);
93 case "AppSearch":
94 return DefaultSymbolFromRow(typeof(AppSearchSymbol), row, columnZeroIsId: false);
95 case "Billboard":
96 return DefaultSymbolFromRow(typeof(BillboardSymbol), row, columnZeroIsId: true);
97 case "Binary":
98 return DefaultSymbolFromRow(typeof(BinarySymbol), row, columnZeroIsId: true);
99 case "BindPath":
100 return null;
101 case "CCPSearch":
102 return DefaultSymbolFromRow(typeof(CCPSearchSymbol), row, columnZeroIsId: true);
103 case "Class":
104 return DefaultSymbolFromRow(typeof(ClassSymbol), row, columnZeroIsId: false);
105 case "CompLocator":
106 return DefaultSymbolFromRow(typeof(CompLocatorSymbol), row, columnZeroIsId: false);
107 case "Component":
108 {
109 var attributes = FieldAsNullableInt(row, 3);
110
111 var location = ComponentLocation.LocalOnly;
112 if ((attributes & WindowsInstallerConstants.MsidbComponentAttributesSourceOnly) == WindowsInstallerConstants.MsidbComponentAttributesSourceOnly)
113 {
114 location = ComponentLocation.SourceOnly;
115 }
116 else if ((attributes & WindowsInstallerConstants.MsidbComponentAttributesOptional) == WindowsInstallerConstants.MsidbComponentAttributesOptional)
117 {
118 location = ComponentLocation.Either;
119 }
120
121 var keyPath = FieldAsString(row, 5);
122 var keyPathType = String.IsNullOrEmpty(keyPath) ? ComponentKeyPathType.Directory : ComponentKeyPathType.File;
123 if ((attributes & WindowsInstallerConstants.MsidbComponentAttributesRegistryKeyPath) == WindowsInstallerConstants.MsidbComponentAttributesRegistryKeyPath)
124 {
125 keyPathType = ComponentKeyPathType.Registry;
126 }
127 else if ((attributes & WindowsInstallerConstants.MsidbComponentAttributesODBCDataSource) == WindowsInstallerConstants.MsidbComponentAttributesODBCDataSource)
128 {
129 keyPathType = ComponentKeyPathType.OdbcDataSource;
130 }
131
132 return new ComponentSymbol(SourceLineNumber4(row.SourceLineNumbers), new Identifier(AccessModifier.Global, FieldAsString(row, 0)))
133 {
134 ComponentId = FieldAsString(row, 1),
135 DirectoryRef = FieldAsString(row, 2),
136 Condition = FieldAsString(row, 4),
137 KeyPath = keyPath,
138 Location = location,
139 DisableRegistryReflection = (attributes & WindowsInstallerConstants.MsidbComponentAttributesDisableRegistryReflection) == WindowsInstallerConstants.MsidbComponentAttributesDisableRegistryReflection,
140 NeverOverwrite = (attributes & WindowsInstallerConstants.MsidbComponentAttributesNeverOverwrite) == WindowsInstallerConstants.MsidbComponentAttributesNeverOverwrite,
141 Permanent = (attributes & WindowsInstallerConstants.MsidbComponentAttributesPermanent) == WindowsInstallerConstants.MsidbComponentAttributesPermanent,
142 SharedDllRefCount = (attributes & WindowsInstallerConstants.MsidbComponentAttributesSharedDllRefCount) == WindowsInstallerConstants.MsidbComponentAttributesSharedDllRefCount,
143 Shared = (attributes & WindowsInstallerConstants.MsidbComponentAttributesShared) == WindowsInstallerConstants.MsidbComponentAttributesShared,
144 Transitive = (attributes & WindowsInstallerConstants.MsidbComponentAttributesTransitive) == WindowsInstallerConstants.MsidbComponentAttributesTransitive,
145 UninstallWhenSuperseded = (attributes & WindowsInstallerConstants.MsidbComponentAttributesUninstallOnSupersedence) == WindowsInstallerConstants.MsidbComponentAttributesUninstallOnSupersedence,
146 Win64 = (attributes & WindowsInstallerConstants.MsidbComponentAttributes64bit) == WindowsInstallerConstants.MsidbComponentAttributes64bit,
147 KeyPathType = keyPathType,
148 };
149 }
150
151 case "Condition":
152 return DefaultSymbolFromRow(typeof(ConditionSymbol), row, columnZeroIsId: false);
153 case "CreateFolder":
154 return DefaultSymbolFromRow(typeof(CreateFolderSymbol), row, columnZeroIsId: false);
155 case "CustomAction":
156 {
157 var caType = FieldAsInt(row, 1);
158 var executionType = DetermineCustomActionExecutionType(caType);
159 var sourceType = DetermineCustomActionSourceType(caType);
160 var targetType = DetermineCustomActionTargetType(caType);
161
162 return new CustomActionSymbol(SourceLineNumber4(row.SourceLineNumbers), new Identifier(AccessModifier.Global, FieldAsString(row, 0)))
163 {
164 ExecutionType = executionType,
165 SourceType = sourceType,
166 Source = FieldAsString(row, 2),
167 TargetType = targetType,
168 Target = FieldAsString(row, 3),
169 Win64 = (caType & WindowsInstallerConstants.MsidbCustomActionType64BitScript) == WindowsInstallerConstants.MsidbCustomActionType64BitScript,
170 TSAware = (caType & WindowsInstallerConstants.MsidbCustomActionTypeTSAware) == WindowsInstallerConstants.MsidbCustomActionTypeTSAware,
171 Impersonate = (caType & WindowsInstallerConstants.MsidbCustomActionTypeNoImpersonate) != WindowsInstallerConstants.MsidbCustomActionTypeNoImpersonate,
172 IgnoreResult = (caType & WindowsInstallerConstants.MsidbCustomActionTypeContinue) == WindowsInstallerConstants.MsidbCustomActionTypeContinue,
173 Hidden = (caType & WindowsInstallerConstants.MsidbCustomActionTypeHideTarget) == WindowsInstallerConstants.MsidbCustomActionTypeHideTarget,
174 Async = (caType & WindowsInstallerConstants.MsidbCustomActionTypeAsync) == WindowsInstallerConstants.MsidbCustomActionTypeAsync,
175 };
176 }
177
178 case "Directory":
179 {
180 var id = FieldAsString(row, 0);
181 var splits = SplitDefaultDir(FieldAsString(row, 2));
182
183 var symbol = new DirectorySymbol(SourceLineNumber4(row.SourceLineNumbers), new Identifier(AccessModifier.Global, id))
184 {
185 ParentDirectoryRef = FieldAsString(row, 1),
186 Name = splits[0],
187 ShortName = splits[1],
188 SourceName = splits[2],
189 SourceShortName = splits[3]
190 };
191
192 if (wixDirectoryById.TryGetValue(id, out var wixDirectoryRow))
193 {
194 symbol.ComponentGuidGenerationSeed = FieldAsString(wixDirectoryRow, 1);
195 }
196
197 return symbol;
198 }
199 case "DrLocator":
200 return DefaultSymbolFromRow(typeof(DrLocatorSymbol), row, columnZeroIsId: false);
201 case "DuplicateFile":
202 {
203 var splitName = FieldAsString(row, 3)?.Split('|');
204
205 var symbol = new DuplicateFileSymbol(SourceLineNumber4(row.SourceLineNumbers), new Identifier(AccessModifier.Global, FieldAsString(row, 0)))
206 {
207 ComponentRef = FieldAsString(row, 1),
208 FileRef = FieldAsString(row, 2),
209 DestinationName = splitName == null ? null : splitName.Length > 1 ? splitName[1] : splitName[0],
210 DestinationShortName = splitName == null ? null : splitName.Length > 1 ? splitName[0] : null,
211 DestinationFolder = FieldAsString(row, 4)
212 };
213
214 return symbol;
215 }
216 case "Error":
217 return DefaultSymbolFromRow(typeof(ErrorSymbol), row, columnZeroIsId: false);
218 case "Extension":
219 return DefaultSymbolFromRow(typeof(ExtensionSymbol), row, columnZeroIsId: false);
220 case "Feature":
221 {
222 var attributes = FieldAsInt(row, 7);
223 var installDefault = FeatureInstallDefault.Local;
224 if ((attributes & WindowsInstallerConstants.MsidbFeatureAttributesFollowParent) == WindowsInstallerConstants.MsidbFeatureAttributesFollowParent)
225 {
226 installDefault = FeatureInstallDefault.FollowParent;
227 }
228 else if ((attributes & WindowsInstallerConstants.MsidbFeatureAttributesFavorSource) == WindowsInstallerConstants.MsidbFeatureAttributesFavorSource)
229 {
230 installDefault = FeatureInstallDefault.Source;
231 }
232
233 return new FeatureSymbol(SourceLineNumber4(row.SourceLineNumbers), new Identifier(AccessModifier.Global, FieldAsString(row, 0)))
234 {
235 ParentFeatureRef = FieldAsString(row, 1),
236 Title = FieldAsString(row, 2),
237 Description = FieldAsString(row, 3),
238 Display = FieldAsInt(row, 4), // BUGBUGBUG: FieldAsNullableInt(row, 4),
239 Level = FieldAsInt(row, 5),
240 DirectoryRef = FieldAsString(row, 6),
241 DisallowAbsent = (attributes & WindowsInstallerConstants.MsidbFeatureAttributesUIDisallowAbsent) == WindowsInstallerConstants.MsidbFeatureAttributesUIDisallowAbsent,
242 DisallowAdvertise = (attributes & WindowsInstallerConstants.MsidbFeatureAttributesDisallowAdvertise) == WindowsInstallerConstants.MsidbFeatureAttributesDisallowAdvertise,
243 InstallDefault = installDefault,
244 TypicalDefault = (attributes & WindowsInstallerConstants.MsidbFeatureAttributesFavorAdvertise) == WindowsInstallerConstants.MsidbFeatureAttributesFavorAdvertise ? FeatureTypicalDefault.Advertise : FeatureTypicalDefault.Install,
245 };
246 }
247
248 case "FeatureComponents":
249 return DefaultSymbolFromRow(typeof(FeatureComponentsSymbol), row, columnZeroIsId: false);
250 case "File":
251 {
252 var attributes = FieldAsNullableInt(row, 6);
253
254 FileSymbolAttributes symbolAttributes = 0;
255 symbolAttributes |= (attributes & WindowsInstallerConstants.MsidbFileAttributesReadOnly) == WindowsInstallerConstants.MsidbFileAttributesReadOnly ? FileSymbolAttributes.ReadOnly : 0;
256 symbolAttributes |= (attributes & WindowsInstallerConstants.MsidbFileAttributesHidden) == WindowsInstallerConstants.MsidbFileAttributesHidden ? FileSymbolAttributes.Hidden : 0;
257 symbolAttributes |= (attributes & WindowsInstallerConstants.MsidbFileAttributesSystem) == WindowsInstallerConstants.MsidbFileAttributesSystem ? FileSymbolAttributes.System : 0;
258 symbolAttributes |= (attributes & WindowsInstallerConstants.MsidbFileAttributesVital) == WindowsInstallerConstants.MsidbFileAttributesVital ? FileSymbolAttributes.Vital : 0;
259 symbolAttributes |= (attributes & WindowsInstallerConstants.MsidbFileAttributesChecksum) == WindowsInstallerConstants.MsidbFileAttributesChecksum ? FileSymbolAttributes.Checksum : 0;
260 symbolAttributes |= (attributes & WindowsInstallerConstants.MsidbFileAttributesNoncompressed) == WindowsInstallerConstants.MsidbFileAttributesNoncompressed ? FileSymbolAttributes.Uncompressed : 0;
261 symbolAttributes |= (attributes & WindowsInstallerConstants.MsidbFileAttributesCompressed) == WindowsInstallerConstants.MsidbFileAttributesCompressed ? FileSymbolAttributes.Compressed : 0;
262
263 var id = FieldAsString(row, 0);
264 var splitName = FieldAsString(row, 2).Split('|');
265
266 var symbol = new FileSymbol(SourceLineNumber4(row.SourceLineNumbers), new Identifier(AccessModifier.Global, id))
267 {
268 ComponentRef = FieldAsString(row, 1),
269 Name = splitName.Length > 1 ? splitName[1] : splitName[0],
270 ShortName = splitName.Length > 1 ? splitName[0] : null,
271 FileSize = FieldAsInt(row, 3),
272 Version = FieldAsString(row, 4),
273 Language = FieldAsString(row, 5),
274 Attributes = symbolAttributes
275 };
276
277 if (bindPathsById.TryGetValue(id, out var bindPathRow))
278 {
279 symbol.BindPath = FieldAsString(bindPathRow, 1) ?? String.Empty;
280 }
281
282 if (fontsById.TryGetValue(id, out var fontRow))
283 {
284 symbol.FontTitle = FieldAsString(fontRow, 1) ?? String.Empty;
285 }
286
287 if (selfRegById.TryGetValue(id, out var selfRegRow))
288 {
289 symbol.SelfRegCost = FieldAsNullableInt(selfRegRow, 1) ?? 0;
290 }
291
292 if (wixFileById.TryGetValue(id, out var wixFileRow))
293 {
294 symbol.DirectoryRef = FieldAsString(wixFileRow, 4);
295 symbol.DiskId = FieldAsNullableInt(wixFileRow, 5) ?? 0;
296 symbol.Source = new IntermediateFieldPathValue { Path = FieldAsString(wixFileRow, 6) };
297 symbol.PatchGroup = FieldAsInt(wixFileRow, 8);
298 symbol.PatchAttributes = (PatchAttributeType)FieldAsInt(wixFileRow, 10);
299 }
300
301 return symbol;
302 }
303 case "Font":
304 return null;
305 case "Icon":
306 return DefaultSymbolFromRow(typeof(IconSymbol), row, columnZeroIsId: true);
307 case "IniFile":
308 {
309 var splitName = FieldAsString(row, 1).Split('|');
310 var action = FieldAsInt(row, 6);
311
312 var symbol = new IniFileSymbol(SourceLineNumber4(row.SourceLineNumbers), new Identifier(AccessModifier.Global, FieldAsString(row, 0)))
313 {
314 FileName = splitName.Length > 1 ? splitName[1] : splitName[0],
315 ShortFileName = splitName.Length > 1 ? splitName[0] : null,
316 DirProperty = FieldAsString(row, 2),
317 Section = FieldAsString(row, 3),
318 Key = FieldAsString(row, 4),
319 Value = FieldAsString(row, 5),
320 Action = action == 3 ? IniFileActionType.AddTag : action == 1 ? IniFileActionType.CreateLine : IniFileActionType.AddLine,
321 ComponentRef = FieldAsString(row, 7),
322 };
323
324 return symbol;
325 }
326 case "IniLocator":
327 {
328 var splitName = FieldAsString(row, 1).Split('|');
329
330 var symbol = new IniLocatorSymbol(SourceLineNumber4(row.SourceLineNumbers), new Identifier(AccessModifier.Global, FieldAsString(row, 0)))
331 {
332 FileName = splitName.Length > 1 ? splitName[1] : splitName[0],
333 ShortFileName = splitName.Length > 1 ? splitName[0] : null,
334 Section = FieldAsString(row, 2),
335 Key = FieldAsString(row, 3),
336 Field = FieldAsInt(row, 4),
337 Type = FieldAsInt(row, 5),
338 };
339
340 return symbol;
341 }
342 case "LockPermissions":
343 return DefaultSymbolFromRow(typeof(LockPermissionsSymbol), row, columnZeroIsId: false);
344 case "Media":
345 {
346 var diskId = FieldAsInt(row, 0);
347 var symbol = new MediaSymbol(SourceLineNumber4(row.SourceLineNumbers), new Identifier(AccessModifier.Global, diskId))
348 {
349 DiskId = diskId,
350 LastSequence = FieldAsNullableInt(row, 1),
351 DiskPrompt = FieldAsString(row, 2),
352 Cabinet = FieldAsString(row, 3),
353 VolumeLabel = FieldAsString(row, 4),
354 Source = FieldAsString(row, 5)
355 };
356
357 if (wixMediaByDiskId.TryGetValue(diskId, out var wixMediaRow))
358 {
359 var compressionLevel = FieldAsString(wixMediaRow, 1);
360
361 symbol.CompressionLevel = String.IsNullOrEmpty(compressionLevel) ? null : (CompressionLevel?)Enum.Parse(typeof(CompressionLevel), compressionLevel, true);
362 symbol.Layout = wixMediaRow.Layout;
363 }
364
365 return symbol;
366 }
367 case "MIME":
368 return DefaultSymbolFromRow(typeof(MIMESymbol), row, columnZeroIsId: false);
369 case "ModuleIgnoreTable":
370 return DefaultSymbolFromRow(typeof(ModuleIgnoreTableSymbol), row, columnZeroIsId: true);
371 case "MoveFile":
372 return DefaultSymbolFromRow(typeof(MoveFileSymbol), row, columnZeroIsId: true);
373 case "MsiAssembly":
374 {
375 var componentId = FieldAsString(row, 0);
376 if (componentsById.TryGetValue(componentId, out var componentRow))
377 {
378 return new AssemblySymbol(SourceLineNumber4(row.SourceLineNumbers), new Identifier(AccessModifier.Global, FieldAsString(componentRow, 5)))
379 {
380 ComponentRef = componentId,
381 FeatureRef = FieldAsString(row, 1),
382 ManifestFileRef = FieldAsString(row, 2),
383 ApplicationFileRef = FieldAsString(row, 3),
384 Type = FieldAsNullableInt(row, 4) == 1 ? AssemblyType.Win32Assembly : AssemblyType.DotNetAssembly,
385 };
386 }
387
388 return null;
389 }
390 case "MsiLockPermissionsEx":
391 return DefaultSymbolFromRow(typeof(MsiLockPermissionsExSymbol), row, columnZeroIsId: true);
392 case "MsiShortcutProperty":
393 return DefaultSymbolFromRow(typeof(MsiShortcutPropertySymbol), row, columnZeroIsId: true);
394 case "ODBCDataSource":
395 return DefaultSymbolFromRow(typeof(ODBCDataSourceSymbol), row, columnZeroIsId: true);
396 case "ODBCDriver":
397 return DefaultSymbolFromRow(typeof(ODBCDriverSymbol), row, columnZeroIsId: true);
398 case "ODBCTranslator":
399 return DefaultSymbolFromRow(typeof(ODBCTranslatorSymbol), row, columnZeroIsId: true);
400 case "ProgId":
401 return DefaultSymbolFromRow(typeof(ProgIdSymbol), row, columnZeroIsId: false);
402 case "Property":
403 return DefaultSymbolFromRow(typeof(PropertySymbol), row, columnZeroIsId: true);
404 case "PublishComponent":
405 return DefaultSymbolFromRow(typeof(PublishComponentSymbol), row, columnZeroIsId: false);
406 case "Registry":
407 {
408 var value = FieldAsString(row, 4);
409 var valueType = RegistryValueType.String;
410 var valueAction = RegistryValueActionType.Write;
411
412 if (!String.IsNullOrEmpty(value))
413 {
414 if (value.StartsWith("#x", StringComparison.Ordinal))
415 {
416 valueType = RegistryValueType.Binary;
417 value = value.Substring(2);
418 }
419 else if (value.StartsWith("#%", StringComparison.Ordinal))
420 {
421 valueType = RegistryValueType.Expandable;
422 value = value.Substring(2);
423 }
424 else if (value.StartsWith("#", StringComparison.Ordinal))
425 {
426 valueType = RegistryValueType.Integer;
427 value = value.Substring(1);
428 }
429 else if (value.StartsWith("[~]", StringComparison.Ordinal) && value.EndsWith("[~]", StringComparison.Ordinal))
430 {
431 value = value.Substring(3, value.Length - 6);
432 valueType = RegistryValueType.MultiString;
433 valueAction = RegistryValueActionType.Write;
434 }
435 else if (value.StartsWith("[~]", StringComparison.Ordinal))
436 {
437 value = value.Substring(3);
438 valueType = RegistryValueType.MultiString;
439 valueAction = RegistryValueActionType.Append;
440 }
441 else if (value.EndsWith("[~]", StringComparison.Ordinal))
442 {
443 value = value.Substring(0, value.Length - 3);
444 valueType = RegistryValueType.MultiString;
445 valueAction = RegistryValueActionType.Prepend;
446 }
447 }
448
449 return new RegistrySymbol(SourceLineNumber4(row.SourceLineNumbers), new Identifier(AccessModifier.Global, FieldAsString(row, 0)))
450 {
451 Root = (RegistryRootType)FieldAsInt(row, 1),
452 Key = FieldAsString(row, 2),
453 Name = FieldAsString(row, 3),
454 Value = value,
455 ComponentRef = FieldAsString(row, 5),
456 ValueAction = valueAction,
457 ValueType = valueType,
458 };
459 }
460 case "RegLocator":
461 {
462 var type = FieldAsInt(row, 4);
463
464 return new RegLocatorSymbol(SourceLineNumber4(row.SourceLineNumbers), new Identifier(AccessModifier.Global, FieldAsString(row, 0)))
465 {
466 Root = (RegistryRootType)FieldAsInt(row, 1),
467 Key = FieldAsString(row, 2),
468 Name = FieldAsString(row, 3),
469 Type = (RegLocatorType)(type & 0xF),
470 Win64 = (type & WindowsInstallerConstants.MsidbLocatorType64bit) == WindowsInstallerConstants.MsidbLocatorType64bit
471 };
472 }
473 case "RemoveFile":
474 {
475 var splitName = FieldAsString(row, 2).Split('|');
476 var installMode = FieldAsInt(row, 4);
477
478 return new RemoveFileSymbol(SourceLineNumber4(row.SourceLineNumbers), new Identifier(AccessModifier.Global, FieldAsString(row, 0)))
479 {
480 ComponentRef = FieldAsString(row, 1),
481 FileName = splitName.Length > 1 ? splitName[1] : splitName[0],
482 ShortFileName = splitName.Length > 1 ? splitName[0] : null,
483 DirPropertyRef = FieldAsString(row, 3),
484 OnInstall = (installMode & WindowsInstallerConstants.MsidbRemoveFileInstallModeOnInstall) == WindowsInstallerConstants.MsidbRemoveFileInstallModeOnInstall ? (bool?)true : null,
485 OnUninstall = (installMode & WindowsInstallerConstants.MsidbRemoveFileInstallModeOnRemove) == WindowsInstallerConstants.MsidbRemoveFileInstallModeOnRemove ? (bool?)true : null
486 };
487 }
488 case "RemoveRegistry":
489 {
490 return new RemoveRegistrySymbol(SourceLineNumber4(row.SourceLineNumbers), new Identifier(AccessModifier.Global, FieldAsString(row, 0)))
491 {
492 Action = RemoveRegistryActionType.RemoveOnInstall,
493 Root = (RegistryRootType)FieldAsInt(row, 1),
494 Key = FieldAsString(row, 2),
495 Name = FieldAsString(row, 3),
496 ComponentRef = FieldAsString(row, 4),
497 };
498 }
499
500 case "ReserveCost":
501 return DefaultSymbolFromRow(typeof(ReserveCostSymbol), row, columnZeroIsId: true);
502 case "SelfReg":
503 return null;
504 case "ServiceControl":
505 {
506 var events = FieldAsInt(row, 2);
507 var wait = FieldAsNullableInt(row, 4);
508 return new ServiceControlSymbol(SourceLineNumber4(row.SourceLineNumbers), new Identifier(AccessModifier.Global, FieldAsString(row, 0)))
509 {
510 Name = FieldAsString(row, 1),
511 Arguments = FieldAsString(row, 3),
512 Wait = !wait.HasValue || wait.Value == 1,
513 ComponentRef = FieldAsString(row, 5),
514 InstallRemove = (events & WindowsInstallerConstants.MsidbServiceControlEventDelete) == WindowsInstallerConstants.MsidbServiceControlEventDelete,
515 UninstallRemove = (events & WindowsInstallerConstants.MsidbServiceControlEventUninstallDelete) == WindowsInstallerConstants.MsidbServiceControlEventUninstallDelete,
516 InstallStart = (events & WindowsInstallerConstants.MsidbServiceControlEventStart) == WindowsInstallerConstants.MsidbServiceControlEventStart,
517 UninstallStart = (events & WindowsInstallerConstants.MsidbServiceControlEventUninstallStart) == WindowsInstallerConstants.MsidbServiceControlEventUninstallStart,
518 InstallStop = (events & WindowsInstallerConstants.MsidbServiceControlEventStop) == WindowsInstallerConstants.MsidbServiceControlEventStop,
519 UninstallStop = (events & WindowsInstallerConstants.MsidbServiceControlEventUninstallStop) == WindowsInstallerConstants.MsidbServiceControlEventUninstallStop,
520 };
521 }
522
523 case "ServiceInstall":
524 return DefaultSymbolFromRow(typeof(ServiceInstallSymbol), row, columnZeroIsId: true);
525 case "Shortcut":
526 {
527 var splitName = FieldAsString(row, 2).Split('|');
528
529 return new ShortcutSymbol(SourceLineNumber4(row.SourceLineNumbers), new Identifier(AccessModifier.Global, FieldAsString(row, 0)))
530 {
531 DirectoryRef = FieldAsString(row, 1),
532 Name = splitName.Length > 1 ? splitName[1] : splitName[0],
533 ShortName = splitName.Length > 1 ? splitName[0] : null,
534 ComponentRef = FieldAsString(row, 3),
535 Target = FieldAsString(row, 4),
536 Arguments = FieldAsString(row, 5),
537 Description = FieldAsString(row, 6),
538 Hotkey = FieldAsNullableInt(row, 7),
539 IconRef = FieldAsString(row, 8),
540 IconIndex = FieldAsNullableInt(row, 9),
541 Show = (ShortcutShowType?)FieldAsNullableInt(row, 10),
542 WorkingDirectory = FieldAsString(row, 11),
543 DisplayResourceDll = FieldAsString(row, 12),
544 DisplayResourceId = FieldAsNullableInt(row, 13),
545 DescriptionResourceDll = FieldAsString(row, 14),
546 DescriptionResourceId= FieldAsNullableInt(row, 15),
547 };
548 }
549 case "Signature":
550 return DefaultSymbolFromRow(typeof(SignatureSymbol), row, columnZeroIsId: true);
551 case "UIText":
552 return DefaultSymbolFromRow(typeof(UITextSymbol), row, columnZeroIsId: true);
553 case "Upgrade":
554 {
555 var attributes = FieldAsInt(row, 4);
556 return new UpgradeSymbol(SourceLineNumber4(row.SourceLineNumbers), new Identifier(AccessModifier.Global, FieldAsString(row, 0)))
557 {
558 UpgradeCode = FieldAsString(row, 0),
559 VersionMin = FieldAsString(row, 1),
560 VersionMax = FieldAsString(row, 2),
561 Language = FieldAsString(row, 3),
562 Remove = FieldAsString(row, 5),
563 ActionProperty = FieldAsString(row, 6),
564 MigrateFeatures = (attributes & WindowsInstallerConstants.MsidbUpgradeAttributesMigrateFeatures) == WindowsInstallerConstants.MsidbUpgradeAttributesMigrateFeatures,
565 OnlyDetect = (attributes & WindowsInstallerConstants.MsidbUpgradeAttributesOnlyDetect) == WindowsInstallerConstants.MsidbUpgradeAttributesOnlyDetect,
566 IgnoreRemoveFailures = (attributes & WindowsInstallerConstants.MsidbUpgradeAttributesIgnoreRemoveFailure) == WindowsInstallerConstants.MsidbUpgradeAttributesIgnoreRemoveFailure,
567 VersionMinInclusive = (attributes & WindowsInstallerConstants.MsidbUpgradeAttributesVersionMinInclusive) == WindowsInstallerConstants.MsidbUpgradeAttributesVersionMinInclusive,
568 VersionMaxInclusive = (attributes & WindowsInstallerConstants.MsidbUpgradeAttributesVersionMaxInclusive) == WindowsInstallerConstants.MsidbUpgradeAttributesVersionMaxInclusive,
569 ExcludeLanguages = (attributes & WindowsInstallerConstants.MsidbUpgradeAttributesLanguagesExclusive) == WindowsInstallerConstants.MsidbUpgradeAttributesLanguagesExclusive,
570 };
571 }
572 case "Verb":
573 return DefaultSymbolFromRow(typeof(VerbSymbol), row, columnZeroIsId: false);
574 case "WixAction":
575 {
576 var sequenceTable = FieldAsString(row, 0);
577 return new WixActionSymbol(SourceLineNumber4(row.SourceLineNumbers))
578 {
579 SequenceTable = (SequenceTable)Enum.Parse(typeof(SequenceTable), sequenceTable == "AdvtExecuteSequence" ? nameof(SequenceTable.AdvertiseExecuteSequence) : sequenceTable),
580 Action = FieldAsString(row, 1),
581 Condition = FieldAsString(row, 2),
582 Sequence = FieldAsNullableInt(row, 3),
583 Before = FieldAsString(row, 4),
584 After = FieldAsString(row, 5),
585 Overridable = FieldAsNullableInt(row, 6) != 0,
586 };
587 }
588 case "WixBootstrapperApplication":
589 return DefaultSymbolFromRow(typeof(WixBootstrapperApplicationSymbol), row, columnZeroIsId: true);
590 case "WixBundleContainer":
591 return DefaultSymbolFromRow(typeof(WixBundleContainerSymbol), row, columnZeroIsId: true);
592 case "WixBundleVariable":
593 return DefaultSymbolFromRow(typeof(WixBundleVariableSymbol), row, columnZeroIsId: true);
594 case "WixChainItem":
595 return DefaultSymbolFromRow(typeof(WixChainItemSymbol), row, columnZeroIsId: true);
596 case "WixComponentGroup":
597 return DefaultSymbolFromRow(typeof(WixComponentGroupSymbol), row, columnZeroIsId: true);
598 case "WixCustomTable":
599 return DefaultSymbolFromRow(typeof(WixCustomTableSymbol), row, columnZeroIsId: true);
600 case "WixDirectory":
601 return null;
602 case "WixFile":
603 return null;
604 case "WixInstanceTransforms":
605 return DefaultSymbolFromRow(typeof(WixInstanceTransformsSymbol), row, columnZeroIsId: true);
606 case "WixMedia":
607 return null;
608 case "WixMerge":
609 return DefaultSymbolFromRow(typeof(WixMergeSymbol), row, columnZeroIsId: true);
610 case "WixPatchBaseline":
611 return DefaultSymbolFromRow(typeof(WixPatchBaselineSymbol), row, columnZeroIsId: true);
612 case "WixProperty":
613 {
614 var attributes = FieldAsInt(row, 1);
615 return new WixPropertySymbol(SourceLineNumber4(row.SourceLineNumbers))
616 {
617 PropertyRef = FieldAsString(row, 0),
618 Admin = (attributes & 0x1) == 0x1,
619 Hidden = (attributes & 0x2) == 0x2,
620 Secure = (attributes & 0x4) == 0x4,
621 };
622 }
623 case "WixSuppressModularization":
624 {
625 return new WixSuppressModularizationSymbol(SourceLineNumber4(row.SourceLineNumbers))
626 {
627 SuppressIdentifier = FieldAsString(row, 0)
628 };
629 }
630 case "WixUI":
631 return DefaultSymbolFromRow(typeof(WixUISymbol), row, columnZeroIsId: true);
632 case "WixVariable":
633 return DefaultSymbolFromRow(typeof(WixVariableSymbol), row, columnZeroIsId: true);
634 default:
635 return GenericSymbolFromCustomRow(row, columnZeroIsId: false);
636 }
637 }
638
639 private static CustomActionTargetType DetermineCustomActionTargetType(int type)
640 {
641 var targetType = default(CustomActionTargetType);
642
643 if ((type & WindowsInstallerConstants.MsidbCustomActionTypeVBScript) == WindowsInstallerConstants.MsidbCustomActionTypeVBScript)
644 {
645 targetType = CustomActionTargetType.VBScript;
646 }
647 else if ((type & WindowsInstallerConstants.MsidbCustomActionTypeJScript) == WindowsInstallerConstants.MsidbCustomActionTypeJScript)
648 {
649 targetType = CustomActionTargetType.JScript;
650 }
651 else if ((type & WindowsInstallerConstants.MsidbCustomActionTypeTextData) == WindowsInstallerConstants.MsidbCustomActionTypeTextData)
652 {
653 targetType = CustomActionTargetType.TextData;
654 }
655 else if ((type & WindowsInstallerConstants.MsidbCustomActionTypeExe) == WindowsInstallerConstants.MsidbCustomActionTypeExe)
656 {
657 targetType = CustomActionTargetType.Exe;
658 }
659 else if ((type & WindowsInstallerConstants.MsidbCustomActionTypeDll) == WindowsInstallerConstants.MsidbCustomActionTypeDll)
660 {
661 targetType = CustomActionTargetType.Dll;
662 }
663
664 return targetType;
665 }
666
667 private static CustomActionSourceType DetermineCustomActionSourceType(int type)
668 {
669 var sourceType = CustomActionSourceType.Binary;
670
671 if ((type & WindowsInstallerConstants.MsidbCustomActionTypeProperty) == WindowsInstallerConstants.MsidbCustomActionTypeProperty)
672 {
673 sourceType = CustomActionSourceType.Property;
674 }
675 else if ((type & WindowsInstallerConstants.MsidbCustomActionTypeDirectory) == WindowsInstallerConstants.MsidbCustomActionTypeDirectory)
676 {
677 sourceType = CustomActionSourceType.Directory;
678 }
679 else if ((type & WindowsInstallerConstants.MsidbCustomActionTypeSourceFile) == WindowsInstallerConstants.MsidbCustomActionTypeSourceFile)
680 {
681 sourceType = CustomActionSourceType.File;
682 }
683
684 return sourceType;
685 }
686
687 private static CustomActionExecutionType DetermineCustomActionExecutionType(int type)
688 {
689 var executionType = CustomActionExecutionType.Immediate;
690
691 if ((type & (WindowsInstallerConstants.MsidbCustomActionTypeInScript | WindowsInstallerConstants.MsidbCustomActionTypeCommit)) == (WindowsInstallerConstants.MsidbCustomActionTypeInScript | WindowsInstallerConstants.MsidbCustomActionTypeCommit))
692 {
693 executionType = CustomActionExecutionType.Commit;
694 }
695 else if ((type & (WindowsInstallerConstants.MsidbCustomActionTypeInScript | WindowsInstallerConstants.MsidbCustomActionTypeRollback)) == (WindowsInstallerConstants.MsidbCustomActionTypeInScript | WindowsInstallerConstants.MsidbCustomActionTypeRollback))
696 {
697 executionType = CustomActionExecutionType.Rollback;
698 }
699 else if ((type & WindowsInstallerConstants.MsidbCustomActionTypeInScript) == WindowsInstallerConstants.MsidbCustomActionTypeInScript)
700 {
701 executionType = CustomActionExecutionType.Deferred;
702 }
703 else if ((type & WindowsInstallerConstants.MsidbCustomActionTypeClientRepeat) == WindowsInstallerConstants.MsidbCustomActionTypeClientRepeat)
704 {
705 executionType = CustomActionExecutionType.ClientRepeat;
706 }
707 else if ((type & WindowsInstallerConstants.MsidbCustomActionTypeOncePerProcess) == WindowsInstallerConstants.MsidbCustomActionTypeOncePerProcess)
708 {
709 executionType = CustomActionExecutionType.OncePerProcess;
710 }
711 else if ((type & WindowsInstallerConstants.MsidbCustomActionTypeFirstSequence) == WindowsInstallerConstants.MsidbCustomActionTypeFirstSequence)
712 {
713 executionType = CustomActionExecutionType.FirstSequence;
714 }
715
716 return executionType;
717 }
718
719 private static IntermediateFieldType ColumnType3ToIntermediateFieldType4(Wix3.ColumnType columnType)
720 {
721 switch (columnType)
722 {
723 case Wix3.ColumnType.Number:
724 return IntermediateFieldType.Number;
725 case Wix3.ColumnType.Object:
726 return IntermediateFieldType.Path;
727 case Wix3.ColumnType.Unknown:
728 case Wix3.ColumnType.String:
729 case Wix3.ColumnType.Localized:
730 case Wix3.ColumnType.Preserved:
731 default:
732 return IntermediateFieldType.String;
733 }
734 }
735
736 private static IntermediateSymbol DefaultSymbolFromRow(Type symbolType, Wix3.Row row, bool columnZeroIsId)
737 {
738 var id = columnZeroIsId ? GetIdentifierForRow(row) : null;
739
740 var createSymbol = symbolType.GetConstructor(new[] { typeof(SourceLineNumber), typeof(Identifier) });
741 var symbol = (IntermediateSymbol)createSymbol.Invoke(new object[] { SourceLineNumber4(row.SourceLineNumbers), id });
742
743 SetSymbolFieldsFromRow(row, symbol, columnZeroIsId);
744
745 return symbol;
746 }
747
748 private static IntermediateSymbol GenericSymbolFromCustomRow(Wix3.Row row, bool columnZeroIsId)
749 {
750 var columnDefinitions = row.Table.Definition.Columns.Cast<Wix3.ColumnDefinition>();
751 var fieldDefinitions = columnDefinitions.Select(columnDefinition =>
752 new IntermediateFieldDefinition(columnDefinition.Name, ColumnType3ToIntermediateFieldType4(columnDefinition.Type))).ToArray();
753 var symbolDefinition = new IntermediateSymbolDefinition(row.Table.Name, fieldDefinitions, null);
754
755 var id = columnZeroIsId ? GetIdentifierForRow(row) : null;
756
757 var createSymbol = typeof(IntermediateSymbol).GetConstructor(new[] { typeof(IntermediateSymbolDefinition), typeof(SourceLineNumber), typeof(Identifier) });
758 var symbol = (IntermediateSymbol)createSymbol.Invoke(new object[] { symbolDefinition, SourceLineNumber4(row.SourceLineNumbers), id });
759
760 SetSymbolFieldsFromRow(row, symbol, columnZeroIsId);
761
762 return symbol;
763 }
764
765 private static void SetSymbolFieldsFromRow(Wix3.Row row, IntermediateSymbol symbol, bool columnZeroIsId)
766 {
767 var offset = 0;
768 if (columnZeroIsId)
769 {
770 offset = 1;
771 }
772
773 for (var i = offset; i < row.Fields.Length; ++i)
774 {
775 var column = row.Fields[i].Column;
776 switch (column.Type)
777 {
778 case Wix3.ColumnType.String:
779 case Wix3.ColumnType.Localized:
780 case Wix3.ColumnType.Object:
781 case Wix3.ColumnType.Preserved:
782 symbol.Set(i - offset, FieldAsString(row, i));
783 break;
784 case Wix3.ColumnType.Number:
785 int? nullableValue = FieldAsNullableInt(row, i);
786 // TODO: Consider whether null values should be coerced to their default value when
787 // a column is not nullable. For now, just pass through the null.
788 //int value = FieldAsInt(row, i);
789 //symbol.Set(i - offset, column.IsNullable ? nullableValue : value);
790 symbol.Set(i - offset, nullableValue);
791 break;
792 case Wix3.ColumnType.Unknown:
793 break;
794 }
795 }
796 }
797
798 private static Identifier GetIdentifierForRow(Wix3.Row row)
799 {
800 var column = row.Fields[0].Column;
801 switch (column.Type)
802 {
803 case Wix3.ColumnType.String:
804 case Wix3.ColumnType.Localized:
805 case Wix3.ColumnType.Object:
806 case Wix3.ColumnType.Preserved:
807 return new Identifier(AccessModifier.Global, (string)row.Fields[0].Data);
808 case Wix3.ColumnType.Number:
809 return new Identifier(AccessModifier.Global, FieldAsInt(row, 0));
810 default:
811 return null;
812 }
813 }
814
815 private static SectionType OutputType3ToSectionType4(Wix3.OutputType outputType)
816 {
817 switch (outputType)
818 {
819 case Wix3.OutputType.Bundle:
820 return SectionType.Bundle;
821 case Wix3.OutputType.Module:
822 return SectionType.Module;
823 case Wix3.OutputType.Patch:
824 return SectionType.Patch;
825 case Wix3.OutputType.PatchCreation:
826 return SectionType.PatchCreation;
827 case Wix3.OutputType.Product:
828 return SectionType.Package;
829 case Wix3.OutputType.Transform:
830 case Wix3.OutputType.Unknown:
831 default:
832 return SectionType.Unknown;
833 }
834 }
835
836 private static SourceLineNumber SourceLineNumber4(Wix3.SourceLineNumberCollection source)
837 {
838 return String.IsNullOrEmpty(source?.EncodedSourceLineNumbers) ? null : SourceLineNumber.CreateFromEncoded(source.EncodedSourceLineNumbers);
839 }
840
841 private static string FieldAsString(Wix3.Row row, int column)
842 {
843 return (string)row[column];
844 }
845
846 private static int FieldAsInt(Wix3.Row row, int column)
847 {
848 return Convert.ToInt32(row[column]);
849 }
850
851 private static int? FieldAsNullableInt(Wix3.Row row, int column)
852 {
853 var field = row.Fields[column];
854 if (field.Data == null)
855 {
856 return null;
857 }
858 else
859 {
860 return Convert.ToInt32(field.Data);
861 }
862 }
863
864 private static string[] SplitDefaultDir(string defaultDir)
865 {
866 var split1 = defaultDir.Split(':');
867 var targetSplit = split1.Length > 1 ? split1[1].Split('|') : split1[0].Split('|');
868 var sourceSplit = split1.Length > 1 ? split1[0].Split('|') : new[] { String.Empty };
869 return new[]
870 {
871 targetSplit.Length > 1 ? targetSplit[1] : targetSplit[0],
872 targetSplit.Length > 1 ? targetSplit[0] : null,
873 sourceSplit.Length > 1 ? sourceSplit[1] : sourceSplit[0],
874 sourceSplit.Length > 1 ? sourceSplit[0] : null
875 };
876 }
877 }
878 }