aboutsummaryrefslogtreecommitdiff
path: root/src/WixToolset.Core.WindowsInstaller/Decompile
diff options
context:
space:
mode:
authorRob Mensching <rob@firegiant.com>2018-10-24 21:06:51 -0700
committerRob Mensching <rob@robmensching.com>2018-10-24 21:17:34 -0700
commit822d917960cbd35f506598af4baa6a20ad4b447e (patch)
tree0d4cf39e25f5fe213bbeac2fb546d2aa86b172db /src/WixToolset.Core.WindowsInstaller/Decompile
parent7a2859709034f7f4f048a0757779a6e2fee6df5b (diff)
downloadwix-822d917960cbd35f506598af4baa6a20ad4b447e.tar.gz
wix-822d917960cbd35f506598af4baa6a20ad4b447e.tar.bz2
wix-822d917960cbd35f506598af4baa6a20ad4b447e.zip
Re-introduce "decompile" to backend
Diffstat (limited to 'src/WixToolset.Core.WindowsInstaller/Decompile')
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Decompile/DecompileMsiOrMsmCommand.cs75
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Decompile/Decompiler.cs9229
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Decompile/DecompilerCore.cs110
3 files changed, 9414 insertions, 0 deletions
diff --git a/src/WixToolset.Core.WindowsInstaller/Decompile/DecompileMsiOrMsmCommand.cs b/src/WixToolset.Core.WindowsInstaller/Decompile/DecompileMsiOrMsmCommand.cs
new file mode 100644
index 00000000..130f5ea8
--- /dev/null
+++ b/src/WixToolset.Core.WindowsInstaller/Decompile/DecompileMsiOrMsmCommand.cs
@@ -0,0 +1,75 @@
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
3namespace WixToolset.Core.WindowsInstaller.Unbind
4{
5 using System;
6 using System.Collections.Generic;
7 using System.ComponentModel;
8 using System.Xml.Linq;
9 using WixToolset.Core.Native;
10 using WixToolset.Data;
11 using WixToolset.Extensibility;
12 using WixToolset.Extensibility.Data;
13 using WixToolset.Extensibility.Services;
14 using WixToolset.Msi;
15
16 internal class DecompileMsiOrMsmCommand
17 {
18 public DecompileMsiOrMsmCommand(IDecompileContext context, IEnumerable<IWindowsInstallerBackendDecompilerExtension> backendExtensions)
19 {
20 this.Context = context;
21 this.Extensions = backendExtensions;
22 this.Messaging = context.ServiceProvider.GetService<IMessaging>();
23 }
24
25 private IDecompileContext Context { get; }
26
27 private IEnumerable<IWindowsInstallerBackendDecompilerExtension> Extensions { get; }
28
29 private IMessaging Messaging { get; }
30
31 public DecompileResult Execute()
32 {
33 var result = new DecompileResult();
34
35 try
36 {
37 using (var database = new Database(this.Context.DecompilePath, OpenDatabase.ReadOnly))
38 {
39 var unbindCommand = new UnbindDatabaseCommand(this.Messaging, database, this.Context.DecompilePath, this.Context.DecompileType, this.Context.ExtractFolder, this.Context.IntermediateFolder, this.Context.IsAdminImage, false, skipSummaryInfo: false);
40 var output = unbindCommand.Execute();
41
42 var decompiler = new Decompiler(this.Messaging, this.Extensions, this.Context.BaseSourcePath, this.Context.SuppressCustomTables, this.Context.SuppressDroppingEmptyTables, this.Context.SuppressUI, this.Context.TreatProductAsModule);
43 var wxs = decompiler.Decompile(output);
44
45 wxs.Save(this.Context.OutputPath, SaveOptions.OmitDuplicateNamespaces);
46 result.SourceDocumentPath = this.Context.OutputPath;
47
48 // extract the files from the cabinets
49 if (!String.IsNullOrEmpty(this.Context.ExtractFolder) && !this.Context.SuppressExtractCabinets)
50 {
51 var extractCommand = new ExtractCabinetsCommand(output, database, this.Context.DecompilePath, this.Context.ExtractFolder, this.Context.IntermediateFolder);
52 extractCommand.Execute();
53
54 result.ExtractedFilePaths = extractCommand.ExtractedFiles;
55 }
56 else
57 {
58 result.ExtractedFilePaths = new string[0];
59 }
60 }
61 }
62 catch (Win32Exception e)
63 {
64 if (0x6E == e.NativeErrorCode) // ERROR_OPEN_FAILED
65 {
66 throw new WixException(ErrorMessages.OpenDatabaseFailed(this.Context.DecompilePath));
67 }
68
69 throw;
70 }
71
72 return result;
73 }
74 }
75}
diff --git a/src/WixToolset.Core.WindowsInstaller/Decompile/Decompiler.cs b/src/WixToolset.Core.WindowsInstaller/Decompile/Decompiler.cs
new file mode 100644
index 00000000..26e1f399
--- /dev/null
+++ b/src/WixToolset.Core.WindowsInstaller/Decompile/Decompiler.cs
@@ -0,0 +1,9229 @@
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
3namespace WixToolset.Core.WindowsInstaller
4{
5 using System;
6 using System.Collections;
7 using System.Collections.Generic;
8 using System.Collections.Specialized;
9 using System.Globalization;
10 using System.IO;
11 using System.Linq;
12 using System.Text;
13 using System.Text.RegularExpressions;
14 using System.Xml.Linq;
15 using WixToolset.Core;
16 using WixToolset.Core.Native;
17 using WixToolset.Core.WindowsInstaller.Rows;
18 using WixToolset.Data;
19 using WixToolset.Data.Tuples;
20 using WixToolset.Data.WindowsInstaller;
21 using WixToolset.Data.WindowsInstaller.Rows;
22 using WixToolset.Extensibility;
23 using WixToolset.Extensibility.Services;
24 using Wix = WixToolset.Data.Serialize;
25
26 /// <summary>
27 /// Decompiles an msi database into WiX source.
28 /// </summary>
29 internal class Decompiler
30 {
31 private static readonly Regex NullSplitter = new Regex(@"\[~]");
32
33 private bool compressed;
34 private bool shortNames;
35 private DecompilerCore core;
36 private string modularizationGuid;
37 private readonly Hashtable patchTargetFiles;
38 private readonly Hashtable sequenceElements;
39 private readonly TableDefinitionCollection tableDefinitions;
40
41 /// <summary>
42 /// Creates a new decompiler object with a default set of table definitions.
43 /// </summary>
44 public Decompiler(IMessaging messaging, IEnumerable<IWindowsInstallerBackendDecompilerExtension> extensions, string baseSourcePath, bool suppressCustomTables, bool suppressDroppingEmptyTables, bool suppressUI, bool treatProductAsModule)
45 {
46 this.Messaging = messaging;
47 this.Extensions = extensions;
48 this.BaseSourcePath = String.IsNullOrEmpty(baseSourcePath) ? "SourceDir" : baseSourcePath;
49 this.SuppressCustomTables = suppressCustomTables;
50 this.SuppressDroppingEmptyTables = suppressDroppingEmptyTables;
51 this.SuppressUI = suppressUI;
52 this.TreatProductAsModule = treatProductAsModule;
53
54 this.ExtensionsByTableName = new Dictionary<string, IWindowsInstallerBackendDecompilerExtension>();
55 this.StandardActions = WindowsInstallerStandard.StandardActions().ToDictionary(a => a.Id.Id);
56
57 this.patchTargetFiles = new Hashtable();
58 this.sequenceElements = new Hashtable();
59 this.tableDefinitions = new TableDefinitionCollection();
60 }
61
62 private IMessaging Messaging { get; }
63
64 private IEnumerable<IWindowsInstallerBackendDecompilerExtension> Extensions { get; }
65
66 private Dictionary<string, IWindowsInstallerBackendDecompilerExtension> ExtensionsByTableName { get; }
67
68 private string BaseSourcePath { get; }
69
70 private bool SuppressCustomTables { get; }
71
72 private bool SuppressDroppingEmptyTables { get; }
73
74 private bool SuppressRelativeActionSequencing { get; }
75
76 private bool SuppressUI { get; }
77
78 private bool TreatProductAsModule { get; }
79
80 private OutputType OutputType { get; set; }
81
82 private Dictionary<string, WixActionTuple> StandardActions { get; }
83
84 /// <summary>
85 /// Decompile the database file.
86 /// </summary>
87 /// <param name="output">The output to decompile.</param>
88 /// <returns>The serialized WiX source code.</returns>
89 public XDocument Decompile(Output output)
90 {
91 if (null == output)
92 {
93 throw new ArgumentNullException("output");
94 }
95
96 this.OutputType = output.Type;
97
98 // collect the table definitions from the output
99 this.tableDefinitions.Clear();
100 foreach (var table in output.Tables)
101 {
102 this.tableDefinitions.Add(table.Definition);
103 }
104
105 // add any missing standard and wix-specific table definitions
106 foreach (var tableDefinition in WindowsInstallerStandardInternal.GetTableDefinitions())
107 {
108 if (!this.tableDefinitions.Contains(tableDefinition.Name))
109 {
110 this.tableDefinitions.Add(tableDefinition);
111 }
112 }
113
114 // add any missing extension table definitions
115#if TODO_DECOMPILER_EXTENSIONS
116 foreach (var extension in this.Extensions)
117 {
118 this.AddExtension(extension);
119 }
120#endif
121
122 var wixElement = new Wix.Wix();
123 Wix.IParentElement rootElement;
124
125 switch (this.OutputType)
126 {
127 case OutputType.Module:
128 rootElement = new Wix.Module();
129 break;
130 case OutputType.PatchCreation:
131 rootElement = new Wix.PatchCreation();
132 break;
133 case OutputType.Product:
134 rootElement = new Wix.Product();
135 break;
136 default:
137 throw new InvalidOperationException("Unknown output type.");
138 }
139 wixElement.AddChild((Wix.ISchemaElement)rootElement);
140
141 // try to decompile the database file
142 try
143 {
144 this.core = new DecompilerCore(rootElement);
145
146 // stop processing if an error previously occurred
147 if (this.Messaging.EncounteredError)
148 {
149 return null;
150 }
151
152 this.InitializeDecompile(output.Tables, output.Codepage);
153
154 // stop processing if an error previously occurred
155 if (this.Messaging.EncounteredError)
156 {
157 return null;
158 }
159
160 // decompile the tables
161 this.DecompileTables(output);
162
163 // finalize the decompiler and its extensions
164 this.FinalizeDecompile(output.Tables);
165 }
166 finally
167 {
168 this.core = null;
169 }
170
171 var document = new XDocument();
172 using (var writer = document.CreateWriter())
173 {
174 wixElement.OutputXml(writer);
175 }
176
177 // return the XML document only if decompilation completed successfully
178 return this.Messaging.EncounteredError ? null : document;
179 }
180
181#if TODO_DECOMPILER_EXTENSIONS
182 private void AddExtension(IWindowsInstallerBackendDecompilerExtension extension)
183 {
184 if (null != extension.TableDefinitions)
185 {
186 foreach (TableDefinition tableDefinition in extension.TableDefinitions)
187 {
188 if (!this.ExtensionsByTableName.ContainsKey(tableDefinition.Name))
189 {
190 this.ExtensionsByTableName.Add(tableDefinition.Name, extension);
191 }
192 else
193 {
194 this.Messaging.Write(ErrorMessages.DuplicateExtensionTable(extension.GetType().ToString(), tableDefinition.Name));
195 }
196 }
197 }
198 }
199#endif
200
201 /// <summary>
202 /// Set the common control attributes in a control element.
203 /// </summary>
204 /// <param name="attributes">The control attributes.</param>
205 /// <param name="control">The control element.</param>
206 private static void SetControlAttributes(int attributes, Wix.Control control)
207 {
208 if (0 == (attributes & MsiInterop.MsidbControlAttributesEnabled))
209 {
210 control.Disabled = Wix.YesNoType.yes;
211 }
212
213 if (MsiInterop.MsidbControlAttributesIndirect == (attributes & MsiInterop.MsidbControlAttributesIndirect))
214 {
215 control.Indirect = Wix.YesNoType.yes;
216 }
217
218 if (MsiInterop.MsidbControlAttributesInteger == (attributes & MsiInterop.MsidbControlAttributesInteger))
219 {
220 control.Integer = Wix.YesNoType.yes;
221 }
222
223 if (MsiInterop.MsidbControlAttributesLeftScroll == (attributes & MsiInterop.MsidbControlAttributesLeftScroll))
224 {
225 control.LeftScroll = Wix.YesNoType.yes;
226 }
227
228 if (MsiInterop.MsidbControlAttributesRightAligned == (attributes & MsiInterop.MsidbControlAttributesRightAligned))
229 {
230 control.RightAligned = Wix.YesNoType.yes;
231 }
232
233 if (MsiInterop.MsidbControlAttributesRTLRO == (attributes & MsiInterop.MsidbControlAttributesRTLRO))
234 {
235 control.RightToLeft = Wix.YesNoType.yes;
236 }
237
238 if (MsiInterop.MsidbControlAttributesSunken == (attributes & MsiInterop.MsidbControlAttributesSunken))
239 {
240 control.Sunken = Wix.YesNoType.yes;
241 }
242
243 if (0 == (attributes & MsiInterop.MsidbControlAttributesVisible))
244 {
245 control.Hidden = Wix.YesNoType.yes;
246 }
247 }
248
249 /// <summary>
250 /// Creates an action element.
251 /// </summary>
252 /// <param name="actionRow">The action row from which the element should be created.</param>
253 private void CreateActionElement(WixActionRow actionRow)
254 {
255 Wix.ISchemaElement actionElement = null;
256
257 if (null != this.core.GetIndexedElement("CustomAction", actionRow.Action)) // custom action
258 {
259 var custom = new Wix.Custom();
260
261 custom.Action = actionRow.Action;
262
263 if (null != actionRow.Condition)
264 {
265 custom.Content = actionRow.Condition;
266 }
267
268 switch (actionRow.Sequence)
269 {
270 case (-4):
271 custom.OnExit = Wix.ExitType.suspend;
272 break;
273 case (-3):
274 custom.OnExit = Wix.ExitType.error;
275 break;
276 case (-2):
277 custom.OnExit = Wix.ExitType.cancel;
278 break;
279 case (-1):
280 custom.OnExit = Wix.ExitType.success;
281 break;
282 default:
283 if (null != actionRow.Before)
284 {
285 custom.Before = actionRow.Before;
286 }
287 else if (null != actionRow.After)
288 {
289 custom.After = actionRow.After;
290 }
291 else if (0 < actionRow.Sequence)
292 {
293 custom.Sequence = actionRow.Sequence;
294 }
295 break;
296 }
297
298 actionElement = custom;
299 }
300 else if (null != this.core.GetIndexedElement("Dialog", actionRow.Action)) // dialog
301 {
302 var show = new Wix.Show();
303
304 show.Dialog = actionRow.Action;
305
306 if (null != actionRow.Condition)
307 {
308 show.Content = actionRow.Condition;
309 }
310
311 switch (actionRow.Sequence)
312 {
313 case (-4):
314 show.OnExit = Wix.ExitType.suspend;
315 break;
316 case (-3):
317 show.OnExit = Wix.ExitType.error;
318 break;
319 case (-2):
320 show.OnExit = Wix.ExitType.cancel;
321 break;
322 case (-1):
323 show.OnExit = Wix.ExitType.success;
324 break;
325 default:
326 if (null != actionRow.Before)
327 {
328 show.Before = actionRow.Before;
329 }
330 else if (null != actionRow.After)
331 {
332 show.After = actionRow.After;
333 }
334 else if (0 < actionRow.Sequence)
335 {
336 show.Sequence = actionRow.Sequence;
337 }
338 break;
339 }
340
341 actionElement = show;
342 }
343 else // possibly a standard action without suggested sequence information
344 {
345 actionElement = this.CreateStandardActionElement(actionRow);
346 }
347
348 // add the action element to the appropriate sequence element
349 if (null != actionElement)
350 {
351 var sequenceTable = actionRow.SequenceTable.ToString();
352 var sequenceElement = (Wix.IParentElement)this.sequenceElements[sequenceTable];
353
354 if (null == sequenceElement)
355 {
356 switch (actionRow.SequenceTable)
357 {
358 case SequenceTable.AdminExecuteSequence:
359 sequenceElement = new Wix.AdminExecuteSequence();
360 break;
361 case SequenceTable.AdminUISequence:
362 sequenceElement = new Wix.AdminUISequence();
363 break;
364 case SequenceTable.AdvtExecuteSequence:
365 sequenceElement = new Wix.AdvertiseExecuteSequence();
366 break;
367 case SequenceTable.InstallExecuteSequence:
368 sequenceElement = new Wix.InstallExecuteSequence();
369 break;
370 case SequenceTable.InstallUISequence:
371 sequenceElement = new Wix.InstallUISequence();
372 break;
373 default:
374 throw new InvalidOperationException("Unknown sequence table.");
375 }
376
377 this.core.RootElement.AddChild((Wix.ISchemaElement)sequenceElement);
378 this.sequenceElements.Add(sequenceTable, sequenceElement);
379 }
380
381 try
382 {
383 sequenceElement.AddChild(actionElement);
384 }
385 catch (System.ArgumentException) // action/dialog is not valid for this sequence
386 {
387 this.Messaging.Write(WarningMessages.IllegalActionInSequence(actionRow.SourceLineNumbers, actionRow.SequenceTable.ToString(), actionRow.Action));
388 }
389 }
390 }
391
392 /// <summary>
393 /// Creates a standard action element.
394 /// </summary>
395 /// <param name="actionRow">The action row from which the element should be created.</param>
396 /// <returns>The created element.</returns>
397 private Wix.ISchemaElement CreateStandardActionElement(WixActionRow actionRow)
398 {
399 Wix.ActionSequenceType actionElement = null;
400
401 switch (actionRow.Action)
402 {
403 case "AllocateRegistrySpace":
404 actionElement = new Wix.AllocateRegistrySpace();
405 break;
406 case "AppSearch":
407 this.StandardActions.TryGetValue(actionRow.GetPrimaryKey(), out var appSearchActionRow);
408
409 if (null != actionRow.Before || null != actionRow.After || (null != appSearchActionRow && actionRow.Sequence != appSearchActionRow.Sequence))
410 {
411 var appSearch = new Wix.AppSearch();
412
413 if (null != actionRow.Condition)
414 {
415 appSearch.Content = actionRow.Condition;
416 }
417
418 if (null != actionRow.Before)
419 {
420 appSearch.Before = actionRow.Before;
421 }
422 else if (null != actionRow.After)
423 {
424 appSearch.After = actionRow.After;
425 }
426 else if (0 < actionRow.Sequence)
427 {
428 appSearch.Sequence = actionRow.Sequence;
429 }
430
431 return appSearch;
432 }
433 break;
434 case "BindImage":
435 actionElement = new Wix.BindImage();
436 break;
437 case "CCPSearch":
438 var ccpSearch = new Wix.CCPSearch();
439 Decompiler.SequenceRelativeAction(actionRow, ccpSearch);
440 return ccpSearch;
441 case "CostFinalize":
442 actionElement = new Wix.CostFinalize();
443 break;
444 case "CostInitialize":
445 actionElement = new Wix.CostInitialize();
446 break;
447 case "CreateFolders":
448 actionElement = new Wix.CreateFolders();
449 break;
450 case "CreateShortcuts":
451 actionElement = new Wix.CreateShortcuts();
452 break;
453 case "DeleteServices":
454 actionElement = new Wix.DeleteServices();
455 break;
456 case "DisableRollback":
457 var disableRollback = new Wix.DisableRollback();
458 Decompiler.SequenceRelativeAction(actionRow, disableRollback);
459 return disableRollback;
460 case "DuplicateFiles":
461 actionElement = new Wix.DuplicateFiles();
462 break;
463 case "ExecuteAction":
464 actionElement = new Wix.ExecuteAction();
465 break;
466 case "FileCost":
467 actionElement = new Wix.FileCost();
468 break;
469 case "FindRelatedProducts":
470 var findRelatedProducts = new Wix.FindRelatedProducts();
471 Decompiler.SequenceRelativeAction(actionRow, findRelatedProducts);
472 return findRelatedProducts;
473 case "ForceReboot":
474 var forceReboot = new Wix.ForceReboot();
475 Decompiler.SequenceRelativeAction(actionRow, forceReboot);
476 return forceReboot;
477 case "InstallAdminPackage":
478 actionElement = new Wix.InstallAdminPackage();
479 break;
480 case "InstallExecute":
481 var installExecute = new Wix.InstallExecute();
482 Decompiler.SequenceRelativeAction(actionRow, installExecute);
483 return installExecute;
484 case "InstallExecuteAgain":
485 var installExecuteAgain = new Wix.InstallExecuteAgain();
486 Decompiler.SequenceRelativeAction(actionRow, installExecuteAgain);
487 return installExecuteAgain;
488 case "InstallFiles":
489 actionElement = new Wix.InstallFiles();
490 break;
491 case "InstallFinalize":
492 actionElement = new Wix.InstallFinalize();
493 break;
494 case "InstallInitialize":
495 actionElement = new Wix.InstallInitialize();
496 break;
497 case "InstallODBC":
498 actionElement = new Wix.InstallODBC();
499 break;
500 case "InstallServices":
501 actionElement = new Wix.InstallServices();
502 break;
503 case "InstallValidate":
504 actionElement = new Wix.InstallValidate();
505 break;
506 case "IsolateComponents":
507 actionElement = new Wix.IsolateComponents();
508 break;
509 case "LaunchConditions":
510 var launchConditions = new Wix.LaunchConditions();
511 Decompiler.SequenceRelativeAction(actionRow, launchConditions);
512 return launchConditions;
513 case "MigrateFeatureStates":
514 actionElement = new Wix.MigrateFeatureStates();
515 break;
516 case "MoveFiles":
517 actionElement = new Wix.MoveFiles();
518 break;
519 case "MsiPublishAssemblies":
520 actionElement = new Wix.MsiPublishAssemblies();
521 break;
522 case "MsiUnpublishAssemblies":
523 actionElement = new Wix.MsiUnpublishAssemblies();
524 break;
525 case "PatchFiles":
526 actionElement = new Wix.PatchFiles();
527 break;
528 case "ProcessComponents":
529 actionElement = new Wix.ProcessComponents();
530 break;
531 case "PublishComponents":
532 actionElement = new Wix.PublishComponents();
533 break;
534 case "PublishFeatures":
535 actionElement = new Wix.PublishFeatures();
536 break;
537 case "PublishProduct":
538 actionElement = new Wix.PublishProduct();
539 break;
540 case "RegisterClassInfo":
541 actionElement = new Wix.RegisterClassInfo();
542 break;
543 case "RegisterComPlus":
544 actionElement = new Wix.RegisterComPlus();
545 break;
546 case "RegisterExtensionInfo":
547 actionElement = new Wix.RegisterExtensionInfo();
548 break;
549 case "RegisterFonts":
550 actionElement = new Wix.RegisterFonts();
551 break;
552 case "RegisterMIMEInfo":
553 actionElement = new Wix.RegisterMIMEInfo();
554 break;
555 case "RegisterProduct":
556 actionElement = new Wix.RegisterProduct();
557 break;
558 case "RegisterProgIdInfo":
559 actionElement = new Wix.RegisterProgIdInfo();
560 break;
561 case "RegisterTypeLibraries":
562 actionElement = new Wix.RegisterTypeLibraries();
563 break;
564 case "RegisterUser":
565 actionElement = new Wix.RegisterUser();
566 break;
567 case "RemoveDuplicateFiles":
568 actionElement = new Wix.RemoveDuplicateFiles();
569 break;
570 case "RemoveEnvironmentStrings":
571 actionElement = new Wix.RemoveEnvironmentStrings();
572 break;
573 case "RemoveExistingProducts":
574 var removeExistingProducts = new Wix.RemoveExistingProducts();
575 Decompiler.SequenceRelativeAction(actionRow, removeExistingProducts);
576 return removeExistingProducts;
577 case "RemoveFiles":
578 actionElement = new Wix.RemoveFiles();
579 break;
580 case "RemoveFolders":
581 actionElement = new Wix.RemoveFolders();
582 break;
583 case "RemoveIniValues":
584 actionElement = new Wix.RemoveIniValues();
585 break;
586 case "RemoveODBC":
587 actionElement = new Wix.RemoveODBC();
588 break;
589 case "RemoveRegistryValues":
590 actionElement = new Wix.RemoveRegistryValues();
591 break;
592 case "RemoveShortcuts":
593 actionElement = new Wix.RemoveShortcuts();
594 break;
595 case "ResolveSource":
596 var resolveSource = new Wix.ResolveSource();
597 Decompiler.SequenceRelativeAction(actionRow, resolveSource);
598 return resolveSource;
599 case "RMCCPSearch":
600 var rmccpSearch = new Wix.RMCCPSearch();
601 Decompiler.SequenceRelativeAction(actionRow, rmccpSearch);
602 return rmccpSearch;
603 case "ScheduleReboot":
604 var scheduleReboot = new Wix.ScheduleReboot();
605 Decompiler.SequenceRelativeAction(actionRow, scheduleReboot);
606 return scheduleReboot;
607 case "SelfRegModules":
608 actionElement = new Wix.SelfRegModules();
609 break;
610 case "SelfUnregModules":
611 actionElement = new Wix.SelfUnregModules();
612 break;
613 case "SetODBCFolders":
614 actionElement = new Wix.SetODBCFolders();
615 break;
616 case "StartServices":
617 actionElement = new Wix.StartServices();
618 break;
619 case "StopServices":
620 actionElement = new Wix.StopServices();
621 break;
622 case "UnpublishComponents":
623 actionElement = new Wix.UnpublishComponents();
624 break;
625 case "UnpublishFeatures":
626 actionElement = new Wix.UnpublishFeatures();
627 break;
628 case "UnregisterClassInfo":
629 actionElement = new Wix.UnregisterClassInfo();
630 break;
631 case "UnregisterComPlus":
632 actionElement = new Wix.UnregisterComPlus();
633 break;
634 case "UnregisterExtensionInfo":
635 actionElement = new Wix.UnregisterExtensionInfo();
636 break;
637 case "UnregisterFonts":
638 actionElement = new Wix.UnregisterFonts();
639 break;
640 case "UnregisterMIMEInfo":
641 actionElement = new Wix.UnregisterMIMEInfo();
642 break;
643 case "UnregisterProgIdInfo":
644 actionElement = new Wix.UnregisterProgIdInfo();
645 break;
646 case "UnregisterTypeLibraries":
647 actionElement = new Wix.UnregisterTypeLibraries();
648 break;
649 case "ValidateProductID":
650 actionElement = new Wix.ValidateProductID();
651 break;
652 case "WriteEnvironmentStrings":
653 actionElement = new Wix.WriteEnvironmentStrings();
654 break;
655 case "WriteIniValues":
656 actionElement = new Wix.WriteIniValues();
657 break;
658 case "WriteRegistryValues":
659 actionElement = new Wix.WriteRegistryValues();
660 break;
661 default:
662 this.Messaging.Write(WarningMessages.UnknownAction(actionRow.SourceLineNumbers, actionRow.SequenceTable.ToString(), actionRow.Action));
663 return null;
664 }
665
666 if (actionElement != null)
667 {
668 this.SequenceStandardAction(actionRow, actionElement);
669 }
670
671 return actionElement;
672 }
673
674 /// <summary>
675 /// Applies the condition and sequence to a standard action element based on the action row data.
676 /// </summary>
677 /// <param name="actionRow">Action row data from the database.</param>
678 /// <param name="actionElement">Element to be sequenced.</param>
679 private void SequenceStandardAction(WixActionRow actionRow, Wix.ActionSequenceType actionElement)
680 {
681 if (null != actionRow.Condition)
682 {
683 actionElement.Content = actionRow.Condition;
684 }
685
686 if ((null != actionRow.Before || null != actionRow.After) && 0 == actionRow.Sequence)
687 {
688 this.Messaging.Write(WarningMessages.DecompiledStandardActionRelativelyScheduledInModule(actionRow.SourceLineNumbers, actionRow.SequenceTable.ToString(), actionRow.Action));
689 }
690 else if (0 < actionRow.Sequence)
691 {
692 actionElement.Sequence = actionRow.Sequence;
693 }
694 }
695
696 /// <summary>
697 /// Applies the condition and relative sequence to an action element based on the action row data.
698 /// </summary>
699 /// <param name="actionRow">Action row data from the database.</param>
700 /// <param name="actionElement">Element to be sequenced.</param>
701 private static void SequenceRelativeAction(WixActionRow actionRow, Wix.ActionModuleSequenceType actionElement)
702 {
703 if (null != actionRow.Condition)
704 {
705 actionElement.Content = actionRow.Condition;
706 }
707
708 if (null != actionRow.Before)
709 {
710 actionElement.Before = actionRow.Before;
711 }
712 else if (null != actionRow.After)
713 {
714 actionElement.After = actionRow.After;
715 }
716 else if (0 < actionRow.Sequence)
717 {
718 actionElement.Sequence = actionRow.Sequence;
719 }
720 }
721
722 /// <summary>
723 /// Ensure that a particular property exists in the decompiled output.
724 /// </summary>
725 /// <param name="id">The identifier of the property.</param>
726 /// <returns>The property element.</returns>
727 private Wix.Property EnsureProperty(string id)
728 {
729 var property = (Wix.Property)this.core.GetIndexedElement("Property", id);
730
731 if (null == property)
732 {
733 property = new Wix.Property();
734 property.Id = id;
735
736 // create a dummy row for indexing
737 var row = new Row(null, this.tableDefinitions["Property"]);
738 row[0] = id;
739
740 this.core.RootElement.AddChild(property);
741 this.core.IndexElement(row, property);
742 }
743
744 return property;
745 }
746
747 /// <summary>
748 /// Finalize decompilation.
749 /// </summary>
750 /// <param name="tables">The collection of all tables.</param>
751 private void FinalizeDecompile(TableIndexedCollection tables)
752 {
753 if (OutputType.PatchCreation == this.OutputType)
754 {
755 this.FinalizeFamilyFileRangesTable(tables);
756 }
757 else
758 {
759 this.FinalizeCheckBoxTable(tables);
760 this.FinalizeComponentTable(tables);
761 this.FinalizeDialogTable(tables);
762 this.FinalizeDuplicateMoveFileTables(tables);
763 this.FinalizeFeatureComponentsTable(tables);
764 this.FinalizeFileTable(tables);
765 this.FinalizeMIMETable(tables);
766 this.FinalizeMsiLockPermissionsExTable(tables);
767 this.FinalizeLockPermissionsTable(tables);
768 this.FinalizeProgIdTable(tables);
769 this.FinalizePropertyTable(tables);
770 this.FinalizeRemoveFileTable(tables);
771 this.FinalizeSearchTables(tables);
772 this.FinalizeUpgradeTable(tables);
773 this.FinalizeSequenceTables(tables);
774 this.FinalizeVerbTable(tables);
775 }
776 }
777
778 /// <summary>
779 /// Finalize the CheckBox table.
780 /// </summary>
781 /// <param name="tables">The collection of all tables.</param>
782 /// <remarks>
783 /// Enumerates through all the Control rows, looking for controls of type "CheckBox" with
784 /// a value in the Property column. This is then possibly matched up with a CheckBox row
785 /// to retrieve a CheckBoxValue. There is no foreign key from the Control to CheckBox table.
786 /// </remarks>
787 private void FinalizeCheckBoxTable(TableIndexedCollection tables)
788 {
789 // if the user has requested to suppress the UI elements, we have nothing to do
790 if (this.SuppressUI)
791 {
792 return;
793 }
794
795 var checkBoxTable = tables["CheckBox"];
796 var controlTable = tables["Control"];
797
798 var checkBoxes = new Hashtable();
799 var checkBoxProperties = new Hashtable();
800
801 // index the CheckBox table
802 if (null != checkBoxTable)
803 {
804 foreach (var row in checkBoxTable.Rows)
805 {
806 checkBoxes.Add(row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), row);
807 checkBoxProperties.Add(row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), false);
808 }
809 }
810
811 // enumerate through the Control table, adding CheckBox values where appropriate
812 if (null != controlTable)
813 {
814 foreach (var row in controlTable.Rows)
815 {
816 var control = (Wix.Control)this.core.GetIndexedElement(row);
817
818 if ("CheckBox" == Convert.ToString(row[2]) && null != row[8])
819 {
820 var checkBoxRow = (Row)checkBoxes[row[8]];
821
822 if (null == checkBoxRow)
823 {
824 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, "Control", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Property", Convert.ToString(row[8]), "CheckBox"));
825 }
826 else
827 {
828 // if we've seen this property already, create a reference to it
829 if (Convert.ToBoolean(checkBoxProperties[row[8]]))
830 {
831 control.CheckBoxPropertyRef = Convert.ToString(row[8]);
832 }
833 else
834 {
835 control.Property = Convert.ToString(row[8]);
836 checkBoxProperties[row[8]] = true;
837 }
838
839 if (null != checkBoxRow[1])
840 {
841 control.CheckBoxValue = Convert.ToString(checkBoxRow[1]);
842 }
843 }
844 }
845 }
846 }
847 }
848
849 /// <summary>
850 /// Finalize the Component table.
851 /// </summary>
852 /// <param name="tables">The collection of all tables.</param>
853 /// <remarks>
854 /// Set the keypaths for each component.
855 /// </remarks>
856 private void FinalizeComponentTable(TableIndexedCollection tables)
857 {
858 var componentTable = tables["Component"];
859 var fileTable = tables["File"];
860 var odbcDataSourceTable = tables["ODBCDataSource"];
861 var registryTable = tables["Registry"];
862
863 // set the component keypaths
864 if (null != componentTable)
865 {
866 foreach (var row in componentTable.Rows)
867 {
868 var attributes = Convert.ToInt32(row[3]);
869
870 if (null == row[5])
871 {
872 var component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[0]));
873
874 component.KeyPath = Wix.YesNoType.yes;
875 }
876 else if (MsiInterop.MsidbComponentAttributesRegistryKeyPath == (attributes & MsiInterop.MsidbComponentAttributesRegistryKeyPath))
877 {
878 object registryObject = this.core.GetIndexedElement("Registry", Convert.ToString(row[5]));
879
880 if (null != registryObject)
881 {
882 var registryValue = registryObject as Wix.RegistryValue;
883
884 if (null != registryValue)
885 {
886 registryValue.KeyPath = Wix.YesNoType.yes;
887 }
888 else
889 {
890 this.Messaging.Write(WarningMessages.IllegalRegistryKeyPath(row.SourceLineNumbers, "Component", Convert.ToString(row[5])));
891 }
892 }
893 else
894 {
895 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, "Component", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "KeyPath", Convert.ToString(row[5]), "Registry"));
896 }
897 }
898 else if (MsiInterop.MsidbComponentAttributesODBCDataSource == (attributes & MsiInterop.MsidbComponentAttributesODBCDataSource))
899 {
900 var odbcDataSource = (Wix.ODBCDataSource)this.core.GetIndexedElement("ODBCDataSource", Convert.ToString(row[5]));
901
902 if (null != odbcDataSource)
903 {
904 odbcDataSource.KeyPath = Wix.YesNoType.yes;
905 }
906 else
907 {
908 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, "Component", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "KeyPath", Convert.ToString(row[5]), "ODBCDataSource"));
909 }
910 }
911 else
912 {
913 var file = (Wix.File)this.core.GetIndexedElement("File", Convert.ToString(row[5]));
914
915 if (null != file)
916 {
917 file.KeyPath = Wix.YesNoType.yes;
918 }
919 else
920 {
921 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, "Component", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "KeyPath", Convert.ToString(row[5]), "File"));
922 }
923 }
924 }
925 }
926
927 // add the File children elements
928 if (null != fileTable)
929 {
930 foreach (FileRow fileRow in fileTable.Rows)
931 {
932 var component = (Wix.Component)this.core.GetIndexedElement("Component", fileRow.Component);
933 var file = (Wix.File)this.core.GetIndexedElement(fileRow);
934
935 if (null != component)
936 {
937 component.AddChild(file);
938 }
939 else
940 {
941 this.Messaging.Write(WarningMessages.ExpectedForeignRow(fileRow.SourceLineNumbers, "File", fileRow.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", fileRow.Component, "Component"));
942 }
943 }
944 }
945
946 // add the ODBCDataSource children elements
947 if (null != odbcDataSourceTable)
948 {
949 foreach (var row in odbcDataSourceTable.Rows)
950 {
951 var component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[1]));
952 var odbcDataSource = (Wix.ODBCDataSource)this.core.GetIndexedElement(row);
953
954 if (null != component)
955 {
956 component.AddChild(odbcDataSource);
957 }
958 else
959 {
960 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, "ODBCDataSource", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[1]), "Component"));
961 }
962 }
963 }
964
965 // add the Registry children elements
966 if (null != registryTable)
967 {
968 foreach (var row in registryTable.Rows)
969 {
970 var component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[5]));
971 var registryElement = this.core.GetIndexedElement(row);
972
973 if (null != component)
974 {
975 component.AddChild(registryElement);
976 }
977 else
978 {
979 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, "Registry", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[5]), "Component"));
980 }
981 }
982 }
983 }
984
985 /// <summary>
986 /// Finalize the Dialog table.
987 /// </summary>
988 /// <param name="tables">The collection of all tables.</param>
989 /// <remarks>
990 /// Sets the first, default, and cancel control for each dialog and adds all child control
991 /// elements to the dialog.
992 /// </remarks>
993 private void FinalizeDialogTable(TableIndexedCollection tables)
994 {
995 // if the user has requested to suppress the UI elements, we have nothing to do
996 if (this.SuppressUI)
997 {
998 return;
999 }
1000
1001 var controlTable = tables["Control"];
1002 var dialogTable = tables["Dialog"];
1003
1004 var addedControls = new Hashtable();
1005 var controlRows = new Hashtable();
1006
1007 // index the rows in the control rows (because we need the Control_Next value)
1008 if (null != controlTable)
1009 {
1010 foreach (var row in controlTable.Rows)
1011 {
1012 controlRows.Add(row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), row);
1013 }
1014 }
1015
1016 if (null != dialogTable)
1017 {
1018 foreach (var row in dialogTable.Rows)
1019 {
1020 var dialog = (Wix.Dialog)this.core.GetIndexedElement(row);
1021 var dialogId = Convert.ToString(row[0]);
1022
1023 var control = (Wix.Control)this.core.GetIndexedElement("Control", dialogId, Convert.ToString(row[7]));
1024 if (null == control)
1025 {
1026 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, "Dialog", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Dialog", dialogId, "Control_First", Convert.ToString(row[7]), "Control"));
1027 }
1028
1029 // add tabbable controls
1030 while (null != control)
1031 {
1032 var controlRow = (Row)controlRows[String.Concat(dialogId, DecompilerConstants.PrimaryKeyDelimiter, control.Id)];
1033
1034 control.TabSkip = Wix.YesNoType.no;
1035 dialog.AddChild(control);
1036 addedControls.Add(control, null);
1037
1038 if (null != controlRow[10])
1039 {
1040 control = (Wix.Control)this.core.GetIndexedElement("Control", dialogId, Convert.ToString(controlRow[10]));
1041 if (null != control)
1042 {
1043 // looped back to the first control in the dialog
1044 if (addedControls.Contains(control))
1045 {
1046 control = null;
1047 }
1048 }
1049 else
1050 {
1051 this.Messaging.Write(WarningMessages.ExpectedForeignRow(controlRow.SourceLineNumbers, "Control", controlRow.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Dialog_", dialogId, "Control_Next", Convert.ToString(controlRow[10]), "Control"));
1052 }
1053 }
1054 else
1055 {
1056 control = null;
1057 }
1058 }
1059
1060 // set default control
1061 if (null != row[8])
1062 {
1063 var defaultControl = (Wix.Control)this.core.GetIndexedElement("Control", dialogId, Convert.ToString(row[8]));
1064
1065 if (null != defaultControl)
1066 {
1067 defaultControl.Default = Wix.YesNoType.yes;
1068 }
1069 else
1070 {
1071 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, "Dialog", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Dialog", dialogId, "Control_Default", Convert.ToString(row[8]), "Control"));
1072 }
1073 }
1074
1075 // set cancel control
1076 if (null != row[9])
1077 {
1078 var cancelControl = (Wix.Control)this.core.GetIndexedElement("Control", dialogId, Convert.ToString(row[9]));
1079
1080 if (null != cancelControl)
1081 {
1082 cancelControl.Cancel = Wix.YesNoType.yes;
1083 }
1084 else
1085 {
1086 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, "Dialog", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Dialog", dialogId, "Control_Cancel", Convert.ToString(row[9]), "Control"));
1087 }
1088 }
1089 }
1090 }
1091
1092 // add the non-tabbable controls to the dialog
1093 if (null != controlTable)
1094 {
1095 foreach (var row in controlTable.Rows)
1096 {
1097 var control = (Wix.Control)this.core.GetIndexedElement(row);
1098 var dialog = (Wix.Dialog)this.core.GetIndexedElement("Dialog", Convert.ToString(row[0]));
1099
1100 if (null == dialog)
1101 {
1102 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, "Control", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Dialog_", Convert.ToString(row[0]), "Dialog"));
1103 continue;
1104 }
1105
1106 if (!addedControls.Contains(control))
1107 {
1108 control.TabSkip = Wix.YesNoType.yes;
1109 dialog.AddChild(control);
1110 }
1111 }
1112 }
1113 }
1114
1115 /// <summary>
1116 /// Finalize the DuplicateFile and MoveFile tables.
1117 /// </summary>
1118 /// <param name="tables">The collection of all tables.</param>
1119 /// <remarks>
1120 /// Sets the source/destination property/directory for each DuplicateFile or
1121 /// MoveFile row.
1122 /// </remarks>
1123 private void FinalizeDuplicateMoveFileTables(TableIndexedCollection tables)
1124 {
1125 var duplicateFileTable = tables["DuplicateFile"];
1126 var moveFileTable = tables["MoveFile"];
1127
1128 if (null != duplicateFileTable)
1129 {
1130 foreach (var row in duplicateFileTable.Rows)
1131 {
1132 var copyFile = (Wix.CopyFile)this.core.GetIndexedElement(row);
1133
1134 if (null != row[4])
1135 {
1136 if (null != this.core.GetIndexedElement("Directory", Convert.ToString(row[4])))
1137 {
1138 copyFile.DestinationDirectory = Convert.ToString(row[4]);
1139 }
1140 else
1141 {
1142 copyFile.DestinationProperty = Convert.ToString(row[4]);
1143 }
1144 }
1145 }
1146 }
1147
1148 if (null != moveFileTable)
1149 {
1150 foreach (var row in moveFileTable.Rows)
1151 {
1152 var copyFile = (Wix.CopyFile)this.core.GetIndexedElement(row);
1153
1154 if (null != row[4])
1155 {
1156 if (null != this.core.GetIndexedElement("Directory", Convert.ToString(row[4])))
1157 {
1158 copyFile.SourceDirectory = Convert.ToString(row[4]);
1159 }
1160 else
1161 {
1162 copyFile.SourceProperty = Convert.ToString(row[4]);
1163 }
1164 }
1165
1166 if (null != this.core.GetIndexedElement("Directory", Convert.ToString(row[5])))
1167 {
1168 copyFile.DestinationDirectory = Convert.ToString(row[5]);
1169 }
1170 else
1171 {
1172 copyFile.DestinationProperty = Convert.ToString(row[5]);
1173 }
1174 }
1175 }
1176 }
1177
1178 /// <summary>
1179 /// Finalize the FamilyFileRanges table.
1180 /// </summary>
1181 /// <param name="tables">The collection of all tables.</param>
1182 private void FinalizeFamilyFileRangesTable(TableIndexedCollection tables)
1183 {
1184 var externalFilesTable = tables["ExternalFiles"];
1185 var familyFileRangesTable = tables["FamilyFileRanges"];
1186 var targetFiles_OptionalDataTable = tables["TargetFiles_OptionalData"];
1187
1188 var usedProtectRanges = new Hashtable();
1189
1190 if (null != familyFileRangesTable)
1191 {
1192 foreach (var row in familyFileRangesTable.Rows)
1193 {
1194 var protectRange = new Wix.ProtectRange();
1195
1196 if (null != row[2] && null != row[3])
1197 {
1198 var retainOffsets = (Convert.ToString(row[2])).Split(',');
1199 var retainLengths = (Convert.ToString(row[3])).Split(',');
1200
1201 if (retainOffsets.Length == retainLengths.Length)
1202 {
1203 for (var i = 0; i < retainOffsets.Length; i++)
1204 {
1205 if (retainOffsets[i].StartsWith("0x", StringComparison.Ordinal))
1206 {
1207 protectRange.Offset = Convert.ToInt32(retainOffsets[i].Substring(2), 16);
1208 }
1209 else
1210 {
1211 protectRange.Offset = Convert.ToInt32(retainOffsets[i], CultureInfo.InvariantCulture);
1212 }
1213
1214 if (retainLengths[i].StartsWith("0x", StringComparison.Ordinal))
1215 {
1216 protectRange.Length = Convert.ToInt32(retainLengths[i].Substring(2), 16);
1217 }
1218 else
1219 {
1220 protectRange.Length = Convert.ToInt32(retainLengths[i], CultureInfo.InvariantCulture);
1221 }
1222 }
1223 }
1224 else
1225 {
1226 // TODO: warn
1227 }
1228 }
1229 else if (null != row[2] || null != row[3])
1230 {
1231 // TODO: warn about mismatch between columns
1232 }
1233
1234 this.core.IndexElement(row, protectRange);
1235 }
1236 }
1237
1238 if (null != externalFilesTable)
1239 {
1240 foreach (var row in externalFilesTable.Rows)
1241 {
1242 var externalFile = (Wix.ExternalFile)this.core.GetIndexedElement(row);
1243
1244 var protectRange = (Wix.ProtectRange)this.core.GetIndexedElement("FamilyFileRanges", Convert.ToString(row[0]), Convert.ToString(row[1]));
1245 if (null != protectRange)
1246 {
1247 externalFile.AddChild(protectRange);
1248 usedProtectRanges[protectRange] = null;
1249 }
1250 }
1251 }
1252
1253 if (null != targetFiles_OptionalDataTable)
1254 {
1255 var targetImagesTable = tables["TargetImages"];
1256 var upgradedImagesTable = tables["UpgradedImages"];
1257
1258 var targetImageRows = new Hashtable();
1259 var upgradedImagesRows = new Hashtable();
1260
1261 // index the TargetImages table
1262 if (null != targetImagesTable)
1263 {
1264 foreach (var row in targetImagesTable.Rows)
1265 {
1266 targetImageRows.Add(row[0], row);
1267 }
1268 }
1269
1270 // index the UpgradedImages table
1271 if (null != upgradedImagesTable)
1272 {
1273 foreach (var row in upgradedImagesTable.Rows)
1274 {
1275 upgradedImagesRows.Add(row[0], row);
1276 }
1277 }
1278
1279 foreach (var row in targetFiles_OptionalDataTable.Rows)
1280 {
1281 var targetFile = (Wix.TargetFile)this.patchTargetFiles[row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter)];
1282
1283 var targetImageRow = (Row)targetImageRows[row[0]];
1284 if (null == targetImageRow)
1285 {
1286 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, targetFiles_OptionalDataTable.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Target", Convert.ToString(row[0]), "TargetImages"));
1287 continue;
1288 }
1289
1290 var upgradedImagesRow = (Row)upgradedImagesRows[targetImageRow[3]];
1291 if (null == upgradedImagesRow)
1292 {
1293 this.Messaging.Write(WarningMessages.ExpectedForeignRow(targetImageRow.SourceLineNumbers, targetImageRow.Table.Name, targetImageRow.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Upgraded", Convert.ToString(row[3]), "UpgradedImages"));
1294 continue;
1295 }
1296
1297 var protectRange = (Wix.ProtectRange)this.core.GetIndexedElement("FamilyFileRanges", Convert.ToString(upgradedImagesRow[4]), Convert.ToString(row[1]));
1298 if (null != protectRange)
1299 {
1300 targetFile.AddChild(protectRange);
1301 usedProtectRanges[protectRange] = null;
1302 }
1303 }
1304 }
1305
1306 if (null != familyFileRangesTable)
1307 {
1308 foreach (var row in familyFileRangesTable.Rows)
1309 {
1310 var protectRange = (Wix.ProtectRange)this.core.GetIndexedElement(row);
1311
1312 if (!usedProtectRanges.Contains(protectRange))
1313 {
1314 var protectFile = new Wix.ProtectFile();
1315
1316 protectFile.File = Convert.ToString(row[1]);
1317
1318 protectFile.AddChild(protectRange);
1319
1320 var family = (Wix.Family)this.core.GetIndexedElement("ImageFamilies", Convert.ToString(row[0]));
1321 if (null != family)
1322 {
1323 family.AddChild(protectFile);
1324 }
1325 else
1326 {
1327 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, familyFileRangesTable.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Family", Convert.ToString(row[0]), "ImageFamilies"));
1328 }
1329 }
1330 }
1331 }
1332 }
1333
1334 /// <summary>
1335 /// Finalize the FeatureComponents table.
1336 /// </summary>
1337 /// <param name="tables">The collection of all tables.</param>
1338 /// <remarks>
1339 /// Since tables specifying references to the FeatureComponents table have references to
1340 /// the Feature and Component table separately, but not the FeatureComponents table specifically,
1341 /// the FeatureComponents table and primary features must be decompiled during finalization.
1342 /// </remarks>
1343 private void FinalizeFeatureComponentsTable(TableIndexedCollection tables)
1344 {
1345 var classTable = tables["Class"];
1346 var extensionTable = tables["Extension"];
1347 var msiAssemblyTable = tables["MsiAssembly"];
1348 var publishComponentTable = tables["PublishComponent"];
1349 var shortcutTable = tables["Shortcut"];
1350 var typeLibTable = tables["TypeLib"];
1351
1352 if (null != classTable)
1353 {
1354 foreach (var row in classTable.Rows)
1355 {
1356 this.SetPrimaryFeature(row, 11, 2);
1357 }
1358 }
1359
1360 if (null != extensionTable)
1361 {
1362 foreach (var row in extensionTable.Rows)
1363 {
1364 this.SetPrimaryFeature(row, 4, 1);
1365 }
1366 }
1367
1368 if (null != msiAssemblyTable)
1369 {
1370 foreach (var row in msiAssemblyTable.Rows)
1371 {
1372 this.SetPrimaryFeature(row, 1, 0);
1373 }
1374 }
1375
1376 if (null != publishComponentTable)
1377 {
1378 foreach (var row in publishComponentTable.Rows)
1379 {
1380 this.SetPrimaryFeature(row, 4, 2);
1381 }
1382 }
1383
1384 if (null != shortcutTable)
1385 {
1386 foreach (var row in shortcutTable.Rows)
1387 {
1388 var target = Convert.ToString(row[4]);
1389
1390 if (!target.StartsWith("[", StringComparison.Ordinal) && !target.EndsWith("]", StringComparison.Ordinal))
1391 {
1392 this.SetPrimaryFeature(row, 4, 3);
1393 }
1394 }
1395 }
1396
1397 if (null != typeLibTable)
1398 {
1399 foreach (var row in typeLibTable.Rows)
1400 {
1401 this.SetPrimaryFeature(row, 6, 2);
1402 }
1403 }
1404 }
1405
1406 /// <summary>
1407 /// Finalize the File table.
1408 /// </summary>
1409 /// <param name="tables">The collection of all tables.</param>
1410 /// <remarks>
1411 /// Sets the source, diskId, and assembly information for each file.
1412 /// </remarks>
1413 private void FinalizeFileTable(TableIndexedCollection tables)
1414 {
1415 var fileTable = tables["File"];
1416 var mediaTable = tables["Media"];
1417 var msiAssemblyTable = tables["MsiAssembly"];
1418 var typeLibTable = tables["TypeLib"];
1419
1420 // index the media table by media id
1421 RowDictionary<MediaRow> mediaRows;
1422 if (null != mediaTable)
1423 {
1424 mediaRows = new RowDictionary<MediaRow>(mediaTable);
1425 }
1426
1427 // set the disk identifiers and sources for files
1428 if (null != fileTable)
1429 {
1430 foreach (FileRow fileRow in fileTable.Rows)
1431 {
1432 var file = (Wix.File)this.core.GetIndexedElement("File", fileRow.File);
1433
1434 // Don't bother processing files that are orphaned (and won't show up in the output anyway)
1435 if (null != file.ParentElement)
1436 {
1437 // set the diskid
1438 if (null != mediaTable)
1439 {
1440 foreach (MediaRow mediaRow in mediaTable.Rows)
1441 {
1442 if (fileRow.Sequence <= mediaRow.LastSequence && mediaRow.DiskId != 1)
1443 {
1444 file.DiskId = Convert.ToString(mediaRow.DiskId);
1445 break;
1446 }
1447 }
1448 }
1449
1450 // set the source (done here because it requires information from the Directory table)
1451 if (OutputType.Module == this.OutputType)
1452 {
1453 file.Source = String.Concat(this.BaseSourcePath, Path.DirectorySeparatorChar, "File", Path.DirectorySeparatorChar, file.Id, '.', this.modularizationGuid.Substring(1, 36).Replace('-', '_'));
1454 }
1455 else if (Wix.YesNoDefaultType.yes == file.Compressed || (Wix.YesNoDefaultType.no != file.Compressed && this.compressed))
1456 {
1457 file.Source = String.Concat(this.BaseSourcePath, Path.DirectorySeparatorChar, "File", Path.DirectorySeparatorChar, file.Id);
1458 }
1459 else // uncompressed
1460 {
1461 var fileName = (null != file.ShortName ? file.ShortName : file.Name);
1462
1463 if (!this.shortNames && null != file.Name)
1464 {
1465 fileName = file.Name;
1466 }
1467
1468 if (this.compressed) // uncompressed at the root of the source image
1469 {
1470 file.Source = String.Concat("SourceDir", Path.DirectorySeparatorChar, fileName);
1471 }
1472 else
1473 {
1474 var sourcePath = this.GetSourcePath(file);
1475
1476 file.Source = Path.Combine(sourcePath, fileName);
1477 }
1478 }
1479 }
1480 }
1481 }
1482
1483 // set the file assemblies and manifests
1484 if (null != msiAssemblyTable)
1485 {
1486 foreach (var row in msiAssemblyTable.Rows)
1487 {
1488 var component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[0]));
1489
1490 if (null == component)
1491 {
1492 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, "MsiAssembly", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[0]), "Component"));
1493 }
1494 else
1495 {
1496 foreach (Wix.ISchemaElement element in component.Children)
1497 {
1498 var file = element as Wix.File;
1499
1500 if (null != file && Wix.YesNoType.yes == file.KeyPath)
1501 {
1502 if (null != row[2])
1503 {
1504 file.AssemblyManifest = Convert.ToString(row[2]);
1505 }
1506
1507 if (null != row[3])
1508 {
1509 file.AssemblyApplication = Convert.ToString(row[3]);
1510 }
1511
1512 if (null == row[4] || 0 == Convert.ToInt32(row[4]))
1513 {
1514 file.Assembly = Wix.File.AssemblyType.net;
1515 }
1516 else
1517 {
1518 file.Assembly = Wix.File.AssemblyType.win32;
1519 }
1520 }
1521 }
1522 }
1523 }
1524 }
1525
1526 // nest the TypeLib elements
1527 if (null != typeLibTable)
1528 {
1529 foreach (var row in typeLibTable.Rows)
1530 {
1531 var component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[2]));
1532 var typeLib = (Wix.TypeLib)this.core.GetIndexedElement(row);
1533
1534 foreach (Wix.ISchemaElement element in component.Children)
1535 {
1536 var file = element as Wix.File;
1537
1538 if (null != file && Wix.YesNoType.yes == file.KeyPath)
1539 {
1540 file.AddChild(typeLib);
1541 }
1542 }
1543 }
1544 }
1545 }
1546
1547 /// <summary>
1548 /// Finalize the MIME table.
1549 /// </summary>
1550 /// <param name="tables">The collection of all tables.</param>
1551 /// <remarks>
1552 /// There is a foreign key shared between the MIME and Extension
1553 /// tables so either one would be valid to be decompiled first, so
1554 /// the only safe way to nest the MIME elements is to do it during finalize.
1555 /// </remarks>
1556 private void FinalizeMIMETable(TableIndexedCollection tables)
1557 {
1558 var extensionTable = tables["Extension"];
1559 var mimeTable = tables["MIME"];
1560
1561 var comExtensions = new Hashtable();
1562
1563 if (null != extensionTable)
1564 {
1565 foreach (var row in extensionTable.Rows)
1566 {
1567 var extension = (Wix.Extension)this.core.GetIndexedElement(row);
1568
1569 // index the extension
1570 if (!comExtensions.Contains(row[0]))
1571 {
1572 comExtensions.Add(row[0], new ArrayList());
1573 }
1574 ((ArrayList)comExtensions[row[0]]).Add(extension);
1575
1576 // set the default MIME element for this extension
1577 if (null != row[3])
1578 {
1579 var mime = (Wix.MIME)this.core.GetIndexedElement("MIME", Convert.ToString(row[3]));
1580
1581 if (null != mime)
1582 {
1583 mime.Default = Wix.YesNoType.yes;
1584 }
1585 else
1586 {
1587 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, "Extension", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "MIME_", Convert.ToString(row[3]), "MIME"));
1588 }
1589 }
1590 }
1591 }
1592
1593 if (null != mimeTable)
1594 {
1595 foreach (var row in mimeTable.Rows)
1596 {
1597 var mime = (Wix.MIME)this.core.GetIndexedElement(row);
1598
1599 if (comExtensions.Contains(row[1]))
1600 {
1601 var extensionElements = (ArrayList)comExtensions[row[1]];
1602
1603 foreach (Wix.Extension extension in extensionElements)
1604 {
1605 extension.AddChild(mime);
1606 }
1607 }
1608 else
1609 {
1610 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, "MIME", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Extension_", Convert.ToString(row[1]), "Extension"));
1611 }
1612 }
1613 }
1614 }
1615
1616 /// <summary>
1617 /// Finalize the ProgId table.
1618 /// </summary>
1619 /// <param name="tables">The collection of all tables.</param>
1620 /// <remarks>
1621 /// Enumerates through all the Class rows, looking for child ProgIds (these are the
1622 /// default ProgIds for a given Class). Then go through the ProgId table and add any
1623 /// remaining ProgIds for each Class. This happens during finalize because there is
1624 /// a circular dependency between the Class and ProgId tables.
1625 /// </remarks>
1626 private void FinalizeProgIdTable(TableIndexedCollection tables)
1627 {
1628 var classTable = tables["Class"];
1629 var progIdTable = tables["ProgId"];
1630 var extensionTable = tables["Extension"];
1631 var componentTable = tables["Component"];
1632
1633 var addedProgIds = new Hashtable();
1634 var classes = new Hashtable();
1635 var components = new Hashtable();
1636
1637 // add the default ProgIds for each class (and index the class table)
1638 if (null != classTable)
1639 {
1640 foreach (var row in classTable.Rows)
1641 {
1642 var wixClass = (Wix.Class)this.core.GetIndexedElement(row);
1643
1644 if (null != row[3])
1645 {
1646 var progId = (Wix.ProgId)this.core.GetIndexedElement("ProgId", Convert.ToString(row[3]));
1647
1648 if (null != progId)
1649 {
1650 if (addedProgIds.Contains(progId))
1651 {
1652 this.Messaging.Write(WarningMessages.TooManyProgIds(row.SourceLineNumbers, Convert.ToString(row[0]), Convert.ToString(row[3]), Convert.ToString(addedProgIds[progId])));
1653 }
1654 else
1655 {
1656 wixClass.AddChild(progId);
1657 addedProgIds.Add(progId, wixClass.Id);
1658 }
1659 }
1660 else
1661 {
1662 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, "Class", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "ProgId_Default", Convert.ToString(row[3]), "ProgId"));
1663 }
1664 }
1665
1666 // index the Class elements for nesting of ProgId elements (which don't use the full Class primary key)
1667 if (!classes.Contains(wixClass.Id))
1668 {
1669 classes.Add(wixClass.Id, new ArrayList());
1670 }
1671 ((ArrayList)classes[wixClass.Id]).Add(wixClass);
1672 }
1673 }
1674
1675 // add the remaining non-default ProgId entries for each class
1676 if (null != progIdTable)
1677 {
1678 foreach (var row in progIdTable.Rows)
1679 {
1680 var progId = (Wix.ProgId)this.core.GetIndexedElement(row);
1681
1682 if (!addedProgIds.Contains(progId) && null != row[2] && null == progId.ParentElement)
1683 {
1684 var classElements = (ArrayList)classes[row[2]];
1685
1686 if (null != classElements)
1687 {
1688 foreach (Wix.Class wixClass in classElements)
1689 {
1690 wixClass.AddChild(progId);
1691 addedProgIds.Add(progId, wixClass.Id);
1692 }
1693 }
1694 else
1695 {
1696 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, "ProgId", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Class_", Convert.ToString(row[2]), "Class"));
1697 }
1698 }
1699 }
1700 }
1701
1702 if (null != componentTable)
1703 {
1704 foreach (var row in componentTable.Rows)
1705 {
1706 var wixComponent = (Wix.Component)this.core.GetIndexedElement(row);
1707
1708 // index the Class elements for nesting of ProgId elements (which don't use the full Class primary key)
1709 if (!components.Contains(wixComponent.Id))
1710 {
1711 components.Add(wixComponent.Id, new ArrayList());
1712 }
1713 ((ArrayList)components[wixComponent.Id]).Add(wixComponent);
1714 }
1715 }
1716
1717 // Check for any progIds that are not hooked up to a class and hook them up to the component specified by the extension
1718 if (null != extensionTable)
1719 {
1720 foreach (var row in extensionTable.Rows)
1721 {
1722 // ignore the extension if it isn't associated with a progId
1723 if (null == row[2])
1724 {
1725 continue;
1726 }
1727
1728 var progId = (Wix.ProgId)this.core.GetIndexedElement("ProgId", Convert.ToString(row[2]));
1729
1730 // Haven't added the progId yet and it doesn't have a parent progId
1731 if (!addedProgIds.Contains(progId) && null == progId.ParentElement)
1732 {
1733 var componentElements = (ArrayList)components[row[1]];
1734
1735 if (null != componentElements)
1736 {
1737 foreach (Wix.Component wixComponent in componentElements)
1738 {
1739 wixComponent.AddChild(progId);
1740 }
1741 }
1742 else
1743 {
1744 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, "Extension", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[1]), "Component"));
1745 }
1746 }
1747 }
1748 }
1749 }
1750
1751 /// <summary>
1752 /// Finalize the Property table.
1753 /// </summary>
1754 /// <param name="tables">The collection of all tables.</param>
1755 /// <remarks>
1756 /// Removes properties that are generated from other entries.
1757 /// </remarks>
1758 private void FinalizePropertyTable(TableIndexedCollection tables)
1759 {
1760 var propertyTable = tables["Property"];
1761 var customActionTable = tables["CustomAction"];
1762
1763 if (null != propertyTable && null != customActionTable)
1764 {
1765 foreach (var row in customActionTable.Rows)
1766 {
1767 var bits = Convert.ToInt32(row[1]);
1768 if (MsiInterop.MsidbCustomActionTypeHideTarget == (bits & MsiInterop.MsidbCustomActionTypeHideTarget) &&
1769 MsiInterop.MsidbCustomActionTypeInScript == (bits & MsiInterop.MsidbCustomActionTypeInScript))
1770 {
1771 var property = (Wix.Property)this.core.GetIndexedElement("Property", Convert.ToString(row[0]));
1772
1773 // If no other fields on the property are set we must have created it during link
1774 if (null != property && null == property.Value && Wix.YesNoType.yes != property.Secure && Wix.YesNoType.yes != property.SuppressModularization)
1775 {
1776 this.core.RootElement.RemoveChild(property);
1777 }
1778 }
1779 }
1780 }
1781 }
1782
1783 /// <summary>
1784 /// Finalize the RemoveFile table.
1785 /// </summary>
1786 /// <param name="tables">The collection of all tables.</param>
1787 /// <remarks>
1788 /// Sets the directory/property for each RemoveFile row.
1789 /// </remarks>
1790 private void FinalizeRemoveFileTable(TableIndexedCollection tables)
1791 {
1792 var removeFileTable = tables["RemoveFile"];
1793
1794 if (null != removeFileTable)
1795 {
1796 foreach (var row in removeFileTable.Rows)
1797 {
1798 var isDirectory = false;
1799 var property = Convert.ToString(row[3]);
1800
1801 // determine if the property is actually authored as a directory
1802 if (null != this.core.GetIndexedElement("Directory", property))
1803 {
1804 isDirectory = true;
1805 }
1806
1807 var element = this.core.GetIndexedElement(row);
1808
1809 var removeFile = element as Wix.RemoveFile;
1810 if (null != removeFile)
1811 {
1812 if (isDirectory)
1813 {
1814 removeFile.Directory = property;
1815 }
1816 else
1817 {
1818 removeFile.Property = property;
1819 }
1820 }
1821 else
1822 {
1823 var removeFolder = (Wix.RemoveFolder)element;
1824
1825 if (isDirectory)
1826 {
1827 removeFolder.Directory = property;
1828 }
1829 else
1830 {
1831 removeFolder.Property = property;
1832 }
1833 }
1834 }
1835 }
1836 }
1837
1838 /// <summary>
1839 /// Finalize the LockPermissions table.
1840 /// </summary>
1841 /// <param name="tables">The collection of all tables.</param>
1842 /// <remarks>
1843 /// Nests the Permission elements below their parent elements. There are no declared foreign
1844 /// keys for the parents of the LockPermissions table.
1845 /// </remarks>
1846 private void FinalizeLockPermissionsTable(TableIndexedCollection tables)
1847 {
1848 var createFolderTable = tables["CreateFolder"];
1849 var lockPermissionsTable = tables["LockPermissions"];
1850
1851 var createFolders = new Hashtable();
1852
1853 // index the CreateFolder table because the foreign key to this table from the
1854 // LockPermissions table is only part of the primary key of this table
1855 if (null != createFolderTable)
1856 {
1857 foreach (var row in createFolderTable.Rows)
1858 {
1859 var createFolder = (Wix.CreateFolder)this.core.GetIndexedElement(row);
1860 var directoryId = Convert.ToString(row[0]);
1861
1862 if (!createFolders.Contains(directoryId))
1863 {
1864 createFolders.Add(directoryId, new ArrayList());
1865 }
1866 ((ArrayList)createFolders[directoryId]).Add(createFolder);
1867 }
1868 }
1869
1870 if (null != lockPermissionsTable)
1871 {
1872 foreach (var row in lockPermissionsTable.Rows)
1873 {
1874 var id = Convert.ToString(row[0]);
1875 var table = Convert.ToString(row[1]);
1876
1877 var permission = (Wix.Permission)this.core.GetIndexedElement(row);
1878
1879 if ("CreateFolder" == table)
1880 {
1881 var createFolderElements = (ArrayList)createFolders[id];
1882
1883 if (null != createFolderElements)
1884 {
1885 foreach (Wix.CreateFolder createFolder in createFolderElements)
1886 {
1887 createFolder.AddChild(permission);
1888 }
1889 }
1890 else
1891 {
1892 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, "LockPermissions", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "LockObject", id, table));
1893 }
1894 }
1895 else
1896 {
1897 var parentElement = (Wix.IParentElement)this.core.GetIndexedElement(table, id);
1898
1899 if (null != parentElement)
1900 {
1901 parentElement.AddChild(permission);
1902 }
1903 else
1904 {
1905 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, "LockPermissions", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "LockObject", id, table));
1906 }
1907 }
1908 }
1909 }
1910 }
1911
1912 /// <summary>
1913 /// Finalize the MsiLockPermissionsEx table.
1914 /// </summary>
1915 /// <param name="tables">The collection of all tables.</param>
1916 /// <remarks>
1917 /// Nests the PermissionEx elements below their parent elements. There are no declared foreign
1918 /// keys for the parents of the MsiLockPermissionsEx table.
1919 /// </remarks>
1920 private void FinalizeMsiLockPermissionsExTable(TableIndexedCollection tables)
1921 {
1922 var createFolderTable = tables["CreateFolder"];
1923 var msiLockPermissionsExTable = tables["MsiLockPermissionsEx"];
1924
1925 var createFolders = new Hashtable();
1926
1927 // index the CreateFolder table because the foreign key to this table from the
1928 // MsiLockPermissionsEx table is only part of the primary key of this table
1929 if (null != createFolderTable)
1930 {
1931 foreach (var row in createFolderTable.Rows)
1932 {
1933 var createFolder = (Wix.CreateFolder)this.core.GetIndexedElement(row);
1934 var directoryId = Convert.ToString(row[0]);
1935
1936 if (!createFolders.Contains(directoryId))
1937 {
1938 createFolders.Add(directoryId, new ArrayList());
1939 }
1940 ((ArrayList)createFolders[directoryId]).Add(createFolder);
1941 }
1942 }
1943
1944 if (null != msiLockPermissionsExTable)
1945 {
1946 foreach (var row in msiLockPermissionsExTable.Rows)
1947 {
1948 var id = Convert.ToString(row[1]);
1949 var table = Convert.ToString(row[2]);
1950
1951 var permissionEx = (Wix.PermissionEx)this.core.GetIndexedElement(row);
1952
1953 if ("CreateFolder" == table)
1954 {
1955 var createFolderElements = (ArrayList)createFolders[id];
1956
1957 if (null != createFolderElements)
1958 {
1959 foreach (Wix.CreateFolder createFolder in createFolderElements)
1960 {
1961 createFolder.AddChild(permissionEx);
1962 }
1963 }
1964 else
1965 {
1966 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, "MsiLockPermissionsEx", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "LockObject", id, table));
1967 }
1968 }
1969 else
1970 {
1971 var parentElement = (Wix.IParentElement)this.core.GetIndexedElement(table, id);
1972
1973 if (null != parentElement)
1974 {
1975 parentElement.AddChild(permissionEx);
1976 }
1977 else
1978 {
1979 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, "MsiLockPermissionsEx", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "LockObject", id, table));
1980 }
1981 }
1982 }
1983 }
1984 }
1985
1986 /// <summary>
1987 /// Finalize the search tables.
1988 /// </summary>
1989 /// <param name="tables">The collection of all tables.</param>
1990 /// <remarks>Does all the complex linking required for the search tables.</remarks>
1991 private void FinalizeSearchTables(TableIndexedCollection tables)
1992 {
1993 var appSearchTable = tables["AppSearch"];
1994 var ccpSearchTable = tables["CCPSearch"];
1995 var drLocatorTable = tables["DrLocator"];
1996
1997 var appSearches = new Hashtable();
1998 var ccpSearches = new Hashtable();
1999 var drLocators = new Hashtable();
2000 var locators = new Hashtable();
2001 var usedSearchElements = new Hashtable();
2002 var unusedSearchElements = new ArrayList();
2003
2004 Wix.ComplianceCheck complianceCheck = null;
2005
2006 // index the AppSearch table by signatures
2007 if (null != appSearchTable)
2008 {
2009 foreach (var row in appSearchTable.Rows)
2010 {
2011 var property = Convert.ToString(row[0]);
2012 var signature = Convert.ToString(row[1]);
2013
2014 if (!appSearches.Contains(signature))
2015 {
2016 appSearches.Add(signature, new StringCollection());
2017 }
2018
2019 ((StringCollection)appSearches[signature]).Add(property);
2020 }
2021 }
2022
2023 // index the CCPSearch table by signatures
2024 if (null != ccpSearchTable)
2025 {
2026 foreach (var row in ccpSearchTable.Rows)
2027 {
2028 var signature = Convert.ToString(row[0]);
2029
2030 if (!ccpSearches.Contains(signature))
2031 {
2032 ccpSearches.Add(signature, new StringCollection());
2033 }
2034
2035 ((StringCollection)ccpSearches[signature]).Add(null);
2036
2037 if (null == complianceCheck && !appSearches.Contains(signature))
2038 {
2039 complianceCheck = new Wix.ComplianceCheck();
2040 this.core.RootElement.AddChild(complianceCheck);
2041 }
2042 }
2043 }
2044
2045 // index the directory searches by their search elements (to get back the original row)
2046 if (null != drLocatorTable)
2047 {
2048 foreach (var row in drLocatorTable.Rows)
2049 {
2050 drLocators.Add(this.core.GetIndexedElement(row), row);
2051 }
2052 }
2053
2054 // index the locator tables by their signatures
2055 var locatorTableNames = new string[] { "CompLocator", "RegLocator", "IniLocator", "DrLocator", "Signature" };
2056 foreach (var locatorTableName in locatorTableNames)
2057 {
2058 var locatorTable = tables[locatorTableName];
2059
2060 if (null != locatorTable)
2061 {
2062 foreach (var row in locatorTable.Rows)
2063 {
2064 var signature = Convert.ToString(row[0]);
2065
2066 if (!locators.Contains(signature))
2067 {
2068 locators.Add(signature, new ArrayList());
2069 }
2070
2071 ((ArrayList)locators[signature]).Add(row);
2072 }
2073 }
2074 }
2075
2076 // move the DrLocator rows with a parent of CCP_DRIVE first to ensure they get FileSearch children (not FileSearchRef)
2077 foreach (ArrayList locatorRows in locators.Values)
2078 {
2079 var firstDrLocator = -1;
2080
2081 for (var i = 0; i < locatorRows.Count; i++)
2082 {
2083 var locatorRow = (Row)locatorRows[i];
2084
2085 if ("DrLocator" == locatorRow.TableDefinition.Name)
2086 {
2087 if (-1 == firstDrLocator)
2088 {
2089 firstDrLocator = i;
2090 }
2091
2092 if ("CCP_DRIVE" == Convert.ToString(locatorRow[1]))
2093 {
2094 locatorRows.RemoveAt(i);
2095 locatorRows.Insert(firstDrLocator, locatorRow);
2096 break;
2097 }
2098 }
2099 }
2100 }
2101
2102 foreach (string signature in locators.Keys)
2103 {
2104 var locatorRows = (ArrayList)locators[signature];
2105 var signatureSearchElements = new ArrayList();
2106
2107 foreach (Row locatorRow in locatorRows)
2108 {
2109 var used = true;
2110 var searchElement = this.core.GetIndexedElement(locatorRow);
2111
2112 if ("Signature" == locatorRow.TableDefinition.Name && 0 < signatureSearchElements.Count)
2113 {
2114 foreach (Wix.IParentElement searchParentElement in signatureSearchElements)
2115 {
2116 if (!usedSearchElements.Contains(searchElement))
2117 {
2118 searchParentElement.AddChild(searchElement);
2119 usedSearchElements[searchElement] = null;
2120 }
2121 else
2122 {
2123 var fileSearchRef = new Wix.FileSearchRef();
2124
2125 fileSearchRef.Id = signature;
2126
2127 searchParentElement.AddChild(fileSearchRef);
2128 }
2129 }
2130 }
2131 else if ("DrLocator" == locatorRow.TableDefinition.Name && null != locatorRow[1])
2132 {
2133 var parentSignature = Convert.ToString(locatorRow[1]);
2134
2135 if ("CCP_DRIVE" == parentSignature)
2136 {
2137 if (appSearches.Contains(signature))
2138 {
2139 var appSearchPropertyIds = (StringCollection)appSearches[signature];
2140
2141 foreach (var propertyId in appSearchPropertyIds)
2142 {
2143 var property = this.EnsureProperty(propertyId);
2144 Wix.ComplianceDrive complianceDrive = null;
2145
2146 if (ccpSearches.Contains(signature))
2147 {
2148 property.ComplianceCheck = Wix.YesNoType.yes;
2149 }
2150
2151 foreach (Wix.ISchemaElement element in property.Children)
2152 {
2153 complianceDrive = element as Wix.ComplianceDrive;
2154 if (null != complianceDrive)
2155 {
2156 break;
2157 }
2158 }
2159
2160 if (null == complianceDrive)
2161 {
2162 complianceDrive = new Wix.ComplianceDrive();
2163 property.AddChild(complianceDrive);
2164 }
2165
2166 if (!usedSearchElements.Contains(searchElement))
2167 {
2168 complianceDrive.AddChild(searchElement);
2169 usedSearchElements[searchElement] = null;
2170 }
2171 else
2172 {
2173 var directorySearchRef = new Wix.DirectorySearchRef();
2174
2175 directorySearchRef.Id = signature;
2176
2177 if (null != locatorRow[1])
2178 {
2179 directorySearchRef.Parent = Convert.ToString(locatorRow[1]);
2180 }
2181
2182 if (null != locatorRow[2])
2183 {
2184 directorySearchRef.Path = Convert.ToString(locatorRow[2]);
2185 }
2186
2187 complianceDrive.AddChild(directorySearchRef);
2188 signatureSearchElements.Add(directorySearchRef);
2189 }
2190 }
2191 }
2192 else if (ccpSearches.Contains(signature))
2193 {
2194 Wix.ComplianceDrive complianceDrive = null;
2195
2196 foreach (Wix.ISchemaElement element in complianceCheck.Children)
2197 {
2198 complianceDrive = element as Wix.ComplianceDrive;
2199 if (null != complianceDrive)
2200 {
2201 break;
2202 }
2203 }
2204
2205 if (null == complianceDrive)
2206 {
2207 complianceDrive = new Wix.ComplianceDrive();
2208 complianceCheck.AddChild(complianceDrive);
2209 }
2210
2211 if (!usedSearchElements.Contains(searchElement))
2212 {
2213 complianceDrive.AddChild(searchElement);
2214 usedSearchElements[searchElement] = null;
2215 }
2216 else
2217 {
2218 var directorySearchRef = new Wix.DirectorySearchRef();
2219
2220 directorySearchRef.Id = signature;
2221
2222 if (null != locatorRow[1])
2223 {
2224 directorySearchRef.Parent = Convert.ToString(locatorRow[1]);
2225 }
2226
2227 if (null != locatorRow[2])
2228 {
2229 directorySearchRef.Path = Convert.ToString(locatorRow[2]);
2230 }
2231
2232 complianceDrive.AddChild(directorySearchRef);
2233 signatureSearchElements.Add(directorySearchRef);
2234 }
2235 }
2236 }
2237 else
2238 {
2239 var usedDrLocator = false;
2240 var parentLocatorRows = (ArrayList)locators[parentSignature];
2241
2242 if (null != parentLocatorRows)
2243 {
2244 foreach (Row parentLocatorRow in parentLocatorRows)
2245 {
2246 if ("DrLocator" == parentLocatorRow.TableDefinition.Name)
2247 {
2248 var parentSearchElement = (Wix.IParentElement)this.core.GetIndexedElement(parentLocatorRow);
2249
2250 if (parentSearchElement.Children.GetEnumerator().MoveNext())
2251 {
2252 var parentDrLocatorRow = (Row)drLocators[parentSearchElement];
2253 var directorySeachRef = new Wix.DirectorySearchRef();
2254
2255 directorySeachRef.Id = parentSignature;
2256
2257 if (null != parentDrLocatorRow[1])
2258 {
2259 directorySeachRef.Parent = Convert.ToString(parentDrLocatorRow[1]);
2260 }
2261
2262 if (null != parentDrLocatorRow[2])
2263 {
2264 directorySeachRef.Path = Convert.ToString(parentDrLocatorRow[2]);
2265 }
2266
2267 parentSearchElement = directorySeachRef;
2268 unusedSearchElements.Add(directorySeachRef);
2269 }
2270
2271 if (!usedSearchElements.Contains(searchElement))
2272 {
2273 parentSearchElement.AddChild(searchElement);
2274 usedSearchElements[searchElement] = null;
2275 usedDrLocator = true;
2276 }
2277 else
2278 {
2279 var directorySearchRef = new Wix.DirectorySearchRef();
2280
2281 directorySearchRef.Id = signature;
2282
2283 directorySearchRef.Parent = parentSignature;
2284
2285 if (null != locatorRow[2])
2286 {
2287 directorySearchRef.Path = Convert.ToString(locatorRow[2]);
2288 }
2289
2290 parentSearchElement.AddChild(searchElement);
2291 usedDrLocator = true;
2292 }
2293 }
2294 }
2295
2296 // keep track of unused DrLocator rows
2297 if (!usedDrLocator)
2298 {
2299 unusedSearchElements.Add(searchElement);
2300 }
2301 }
2302 else
2303 {
2304 // TODO: warn
2305 }
2306 }
2307 }
2308 else if (appSearches.Contains(signature))
2309 {
2310 var appSearchPropertyIds = (StringCollection)appSearches[signature];
2311
2312 foreach (var propertyId in appSearchPropertyIds)
2313 {
2314 var property = this.EnsureProperty(propertyId);
2315
2316 if (ccpSearches.Contains(signature))
2317 {
2318 property.ComplianceCheck = Wix.YesNoType.yes;
2319 }
2320
2321 if (!usedSearchElements.Contains(searchElement))
2322 {
2323 property.AddChild(searchElement);
2324 usedSearchElements[searchElement] = null;
2325 }
2326 else if ("RegLocator" == locatorRow.TableDefinition.Name)
2327 {
2328 var registrySearchRef = new Wix.RegistrySearchRef();
2329
2330 registrySearchRef.Id = signature;
2331
2332 property.AddChild(registrySearchRef);
2333 signatureSearchElements.Add(registrySearchRef);
2334 }
2335 else
2336 {
2337 // TODO: warn about unavailable Ref element
2338 }
2339 }
2340 }
2341 else if (ccpSearches.Contains(signature))
2342 {
2343 if (!usedSearchElements.Contains(searchElement))
2344 {
2345 complianceCheck.AddChild(searchElement);
2346 usedSearchElements[searchElement] = null;
2347 }
2348 else if ("RegLocator" == locatorRow.TableDefinition.Name)
2349 {
2350 var registrySearchRef = new Wix.RegistrySearchRef();
2351
2352 registrySearchRef.Id = signature;
2353
2354 complianceCheck.AddChild(registrySearchRef);
2355 signatureSearchElements.Add(registrySearchRef);
2356 }
2357 else
2358 {
2359 // TODO: warn about unavailable Ref element
2360 }
2361 }
2362 else
2363 {
2364 if ("DrLocator" == locatorRow.TableDefinition.Name)
2365 {
2366 unusedSearchElements.Add(searchElement);
2367 }
2368 else
2369 {
2370 // TODO: warn
2371 used = false;
2372 }
2373 }
2374
2375 // keep track of the search elements for this signature so that nested searches go in the proper parents
2376 if (used)
2377 {
2378 signatureSearchElements.Add(searchElement);
2379 }
2380 }
2381 }
2382
2383 foreach (Wix.IParentElement unusedSearchElement in unusedSearchElements)
2384 {
2385 var used = false;
2386
2387 foreach (Wix.ISchemaElement schemaElement in unusedSearchElement.Children)
2388 {
2389 var directorySearch = schemaElement as Wix.DirectorySearch;
2390 if (null != directorySearch)
2391 {
2392 var appSearchProperties = (StringCollection)appSearches[directorySearch.Id];
2393
2394 var unusedSearchSchemaElement = unusedSearchElement as Wix.ISchemaElement;
2395 if (null != appSearchProperties)
2396 {
2397 var property = this.EnsureProperty(appSearchProperties[0]);
2398
2399 property.AddChild(unusedSearchSchemaElement);
2400 used = true;
2401 break;
2402 }
2403 else if (ccpSearches.Contains(directorySearch.Id))
2404 {
2405 complianceCheck.AddChild(unusedSearchSchemaElement);
2406 used = true;
2407 break;
2408 }
2409 else
2410 {
2411 // TODO: warn
2412 }
2413 }
2414 }
2415
2416 if (!used)
2417 {
2418 // TODO: warn
2419 }
2420 }
2421 }
2422
2423 /// <summary>
2424 /// Finalize the sequence tables.
2425 /// </summary>
2426 /// <param name="tables">The collection of all tables.</param>
2427 /// <remarks>
2428 /// Creates the sequence elements. Occurs during finalization because its
2429 /// not known if sequences refer to custom actions or dialogs during decompilation.
2430 /// </remarks>
2431 private void FinalizeSequenceTables(TableIndexedCollection tables)
2432 {
2433 // finalize the normal sequence tables
2434 if (OutputType.Product == this.OutputType && !this.TreatProductAsModule)
2435 {
2436 foreach (SequenceTable sequenceTable in Enum.GetValues(typeof(SequenceTable)))
2437 {
2438 // if suppressing UI elements, skip UI-related sequence tables
2439 if (this.SuppressUI && ("AdminUISequence" == sequenceTable.ToString() || "InstallUISequence" == sequenceTable.ToString()))
2440 {
2441 continue;
2442 }
2443
2444 var actionsTable = new Table(this.tableDefinitions["WixAction"]);
2445 var table = tables[sequenceTable.ToString()];
2446
2447 if (null != table)
2448 {
2449 var actionRows = new ArrayList();
2450 var needAbsoluteScheduling = this.SuppressRelativeActionSequencing;
2451 var nonSequencedActionRows = new WixActionRowCollection();
2452 var suppressedRelativeActionRows = new WixActionRowCollection();
2453
2454 // create a sorted array of actions in this table
2455 foreach (var row in table.Rows)
2456 {
2457 var actionRow = (WixActionRow)actionsTable.CreateRow(null);
2458
2459 actionRow.Action = Convert.ToString(row[0]);
2460
2461 if (null != row[1])
2462 {
2463 actionRow.Condition = Convert.ToString(row[1]);
2464 }
2465
2466 actionRow.Sequence = Convert.ToInt32(row[2]);
2467
2468 actionRow.SequenceTable = sequenceTable;
2469
2470 actionRows.Add(actionRow);
2471 }
2472 actionRows.Sort();
2473
2474 for (var i = 0; i < actionRows.Count && !needAbsoluteScheduling; i++)
2475 {
2476 var actionRow = (WixActionRow)actionRows[i];
2477 this.StandardActions.TryGetValue(actionRow.GetPrimaryKey(), out var standardActionRow);
2478
2479 // create actions for custom actions, dialogs, AppSearch when its moved, and standard actions with non-standard conditions
2480 if ("AppSearch" == actionRow.Action || null == standardActionRow || actionRow.Condition != standardActionRow.Condition)
2481 {
2482 WixActionRow previousActionRow = null;
2483 WixActionRow nextActionRow = null;
2484
2485 // find the previous action row if there is one
2486 if (0 <= i - 1)
2487 {
2488 previousActionRow = (WixActionRow)actionRows[i - 1];
2489 }
2490
2491 // find the next action row if there is one
2492 if (actionRows.Count > i + 1)
2493 {
2494 nextActionRow = (WixActionRow)actionRows[i + 1];
2495 }
2496
2497 // the logic for setting the before or after attribute for an action:
2498 // 1. If more than one action shares the same sequence number, everything must be absolutely sequenced.
2499 // 2. If the next action is a standard action and is 1 sequence number higher, this action occurs before it.
2500 // 3. If the previous action is a standard action and is 1 sequence number lower, this action occurs after it.
2501 // 4. If this action is not standard and the previous action is 1 sequence number lower and does not occur before this action, this action occurs after it.
2502 // 5. If this action is not standard and the previous action does not have the same sequence number and the next action is 1 sequence number higher, this action occurs before it.
2503 // 6. If this action is AppSearch and has all standard information, ignore it.
2504 // 7. If this action is standard and has a non-standard condition, create the action without any scheduling information.
2505 // 8. Everything must be absolutely sequenced.
2506 if ((null != previousActionRow && actionRow.Sequence == previousActionRow.Sequence) || (null != nextActionRow && actionRow.Sequence == nextActionRow.Sequence))
2507 {
2508 needAbsoluteScheduling = true;
2509 }
2510 else if (null != nextActionRow && this.StandardActions.ContainsKey(nextActionRow.GetPrimaryKey()) && actionRow.Sequence + 1 == nextActionRow.Sequence)
2511 {
2512 actionRow.Before = nextActionRow.Action;
2513 }
2514 else if (null != previousActionRow && this.StandardActions.ContainsKey(previousActionRow.GetPrimaryKey()) && actionRow.Sequence - 1 == previousActionRow.Sequence)
2515 {
2516 actionRow.After = previousActionRow.Action;
2517 }
2518 else if (null == standardActionRow && null != previousActionRow && actionRow.Sequence - 1 == previousActionRow.Sequence && previousActionRow.Before != actionRow.Action)
2519 {
2520 actionRow.After = previousActionRow.Action;
2521 }
2522 else if (null == standardActionRow && null != previousActionRow && actionRow.Sequence != previousActionRow.Sequence && null != nextActionRow && actionRow.Sequence + 1 == nextActionRow.Sequence)
2523 {
2524 actionRow.Before = nextActionRow.Action;
2525 }
2526 else if ("AppSearch" == actionRow.Action && null != standardActionRow && actionRow.Sequence == standardActionRow.Sequence && actionRow.Condition == standardActionRow.Condition)
2527 {
2528 // ignore an AppSearch row which has the WiX standard sequence and a standard condition
2529 }
2530 else if (null != standardActionRow && actionRow.Condition != standardActionRow.Condition) // standard actions get their standard sequence numbers
2531 {
2532 nonSequencedActionRows.Add(actionRow);
2533 }
2534 else if (0 < actionRow.Sequence)
2535 {
2536 needAbsoluteScheduling = true;
2537 }
2538 }
2539 else
2540 {
2541 suppressedRelativeActionRows.Add(actionRow);
2542 }
2543 }
2544
2545 // create the actions now that we know if they must be absolutely or relatively scheduled
2546 foreach (WixActionRow actionRow in actionRows)
2547 {
2548 if (needAbsoluteScheduling)
2549 {
2550 // remove any before/after information to ensure this is absolutely sequenced
2551 actionRow.Before = null;
2552 actionRow.After = null;
2553 }
2554 else if (nonSequencedActionRows.Contains(actionRow.SequenceTable, actionRow.Action))
2555 {
2556 // clear the sequence attribute to ensure this action is scheduled without a sequence number (or before/after)
2557 actionRow.Sequence = 0;
2558 }
2559 else if (suppressedRelativeActionRows.Contains(actionRow.SequenceTable, actionRow.Action))
2560 {
2561 // skip the suppressed relatively scheduled action rows
2562 continue;
2563 }
2564
2565 // create the action element
2566 this.CreateActionElement(actionRow);
2567 }
2568 }
2569 }
2570 }
2571 else if (OutputType.Module == this.OutputType || this.TreatProductAsModule) // finalize the Module sequence tables
2572 {
2573 foreach (SequenceTable sequenceTable in Enum.GetValues(typeof(SequenceTable)))
2574 {
2575 // if suppressing UI elements, skip UI-related sequence tables
2576 if (this.SuppressUI && ("AdminUISequence" == sequenceTable.ToString() || "InstallUISequence" == sequenceTable.ToString()))
2577 {
2578 continue;
2579 }
2580
2581 var actionsTable = new Table(this.tableDefinitions["WixAction"]);
2582 var table = tables[String.Concat("Module", sequenceTable.ToString())];
2583
2584 if (null != table)
2585 {
2586 foreach (var row in table.Rows)
2587 {
2588 var actionRow = (WixActionRow)actionsTable.CreateRow(null);
2589
2590 actionRow.Action = Convert.ToString(row[0]);
2591
2592 if (null != row[1])
2593 {
2594 actionRow.Sequence = Convert.ToInt32(row[1]);
2595 }
2596
2597 if (null != row[2] && null != row[3])
2598 {
2599 switch (Convert.ToInt32(row[3]))
2600 {
2601 case 0:
2602 actionRow.Before = Convert.ToString(row[2]);
2603 break;
2604 case 1:
2605 actionRow.After = Convert.ToString(row[2]);
2606 break;
2607 default:
2608 this.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[3].Column.Name, row[3]));
2609 break;
2610 }
2611 }
2612
2613 if (null != row[4])
2614 {
2615 actionRow.Condition = Convert.ToString(row[4]);
2616 }
2617
2618 actionRow.SequenceTable = sequenceTable;
2619
2620 // create action elements for non-standard actions
2621 if (!this.StandardActions.ContainsKey(actionRow.GetPrimaryKey()) || null != actionRow.After || null != actionRow.Before)
2622 {
2623 this.CreateActionElement(actionRow);
2624 }
2625 }
2626 }
2627 }
2628 }
2629 }
2630
2631 /// <summary>
2632 /// Finalize the Upgrade table.
2633 /// </summary>
2634 /// <param name="tables">The collection of all tables.</param>
2635 /// <remarks>
2636 /// Decompile the rows from the Upgrade and LaunchCondition tables
2637 /// created by the MajorUpgrade element.
2638 /// </remarks>
2639 private void FinalizeUpgradeTable(TableIndexedCollection tables)
2640 {
2641 var launchConditionTable = tables["LaunchCondition"];
2642 var upgradeTable = tables["Upgrade"];
2643 string downgradeErrorMessage = null;
2644 string disallowUpgradeErrorMessage = null;
2645 var majorUpgrade = new Wix.MajorUpgrade();
2646
2647 // find the DowngradePreventedCondition launch condition message
2648 if (null != launchConditionTable && 0 < launchConditionTable.Rows.Count)
2649 {
2650 foreach (var launchRow in launchConditionTable.Rows)
2651 {
2652 if (Common.DowngradePreventedCondition == Convert.ToString(launchRow[0]))
2653 {
2654 downgradeErrorMessage = Convert.ToString(launchRow[1]);
2655 }
2656 else if (Common.UpgradePreventedCondition == Convert.ToString(launchRow[0]))
2657 {
2658 disallowUpgradeErrorMessage = Convert.ToString(launchRow[1]);
2659 }
2660 }
2661 }
2662
2663 if (null != upgradeTable && 0 < upgradeTable.Rows.Count)
2664 {
2665 var hasMajorUpgrade = false;
2666
2667 foreach (var row in upgradeTable.Rows)
2668 {
2669 var upgradeRow = (UpgradeRow)row;
2670
2671 if (Common.UpgradeDetectedProperty == upgradeRow.ActionProperty)
2672 {
2673 hasMajorUpgrade = true;
2674 var attr = upgradeRow.Attributes;
2675 var removeFeatures = upgradeRow.Remove;
2676
2677 if (MsiInterop.MsidbUpgradeAttributesVersionMaxInclusive == (attr & MsiInterop.MsidbUpgradeAttributesVersionMaxInclusive))
2678 {
2679 majorUpgrade.AllowSameVersionUpgrades = Wix.YesNoType.yes;
2680 }
2681
2682 if (MsiInterop.MsidbUpgradeAttributesMigrateFeatures != (attr & MsiInterop.MsidbUpgradeAttributesMigrateFeatures))
2683 {
2684 majorUpgrade.MigrateFeatures = Wix.YesNoType.no;
2685 }
2686
2687 if (MsiInterop.MsidbUpgradeAttributesIgnoreRemoveFailure == (attr & MsiInterop.MsidbUpgradeAttributesIgnoreRemoveFailure))
2688 {
2689 majorUpgrade.IgnoreRemoveFailure = Wix.YesNoType.yes;
2690 }
2691
2692 if (!String.IsNullOrEmpty(removeFeatures))
2693 {
2694 majorUpgrade.RemoveFeatures = removeFeatures;
2695 }
2696 }
2697 else if (Common.DowngradeDetectedProperty == upgradeRow.ActionProperty)
2698 {
2699 hasMajorUpgrade = true;
2700 majorUpgrade.DowngradeErrorMessage = downgradeErrorMessage;
2701 }
2702 }
2703
2704 if (hasMajorUpgrade)
2705 {
2706 if (String.IsNullOrEmpty(downgradeErrorMessage))
2707 {
2708 majorUpgrade.AllowDowngrades = Wix.YesNoType.yes;
2709 }
2710
2711 if (!String.IsNullOrEmpty(disallowUpgradeErrorMessage))
2712 {
2713 majorUpgrade.Disallow = Wix.YesNoType.yes;
2714 majorUpgrade.DisallowUpgradeErrorMessage = disallowUpgradeErrorMessage;
2715 }
2716
2717 var scheduledType = DetermineMajorUpgradeScheduling(tables);
2718 if (Wix.MajorUpgrade.ScheduleType.afterInstallValidate != scheduledType)
2719 {
2720 majorUpgrade.Schedule = scheduledType;
2721 }
2722
2723 this.core.RootElement.AddChild(majorUpgrade);
2724 }
2725 }
2726 }
2727
2728 /// <summary>
2729 /// Finalize the Verb table.
2730 /// </summary>
2731 /// <param name="tables">The collection of all tables.</param>
2732 /// <remarks>
2733 /// The Extension table is a foreign table for the Verb table, but the
2734 /// foreign key is only part of the primary key of the Extension table,
2735 /// so it needs special logic to be nested properly.
2736 /// </remarks>
2737 private void FinalizeVerbTable(TableIndexedCollection tables)
2738 {
2739 var extensionTable = tables["Extension"];
2740 var verbTable = tables["Verb"];
2741
2742 var extensionElements = new Hashtable();
2743
2744 if (null != extensionTable)
2745 {
2746 foreach (var row in extensionTable.Rows)
2747 {
2748 var extension = (Wix.Extension)this.core.GetIndexedElement(row);
2749
2750 if (!extensionElements.Contains(row[0]))
2751 {
2752 extensionElements.Add(row[0], new ArrayList());
2753 }
2754
2755 ((ArrayList)extensionElements[row[0]]).Add(extension);
2756 }
2757 }
2758
2759 if (null != verbTable)
2760 {
2761 foreach (var row in verbTable.Rows)
2762 {
2763 var verb = (Wix.Verb)this.core.GetIndexedElement(row);
2764
2765 var extensionsArray = (ArrayList)extensionElements[row[0]];
2766 if (null != extensionsArray)
2767 {
2768 foreach (Wix.Extension extension in extensionsArray)
2769 {
2770 extension.AddChild(verb);
2771 }
2772 }
2773 else
2774 {
2775 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, verbTable.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Extension_", Convert.ToString(row[0]), "Extension"));
2776 }
2777 }
2778 }
2779 }
2780
2781 /// <summary>
2782 /// Get the path to a file in the source image.
2783 /// </summary>
2784 /// <param name="file">The file.</param>
2785 /// <returns>The path to the file in the source image.</returns>
2786 private string GetSourcePath(Wix.File file)
2787 {
2788 var sourcePath = new StringBuilder();
2789
2790 var component = (Wix.Component)file.ParentElement;
2791
2792 for (var directory = (Wix.Directory)component.ParentElement; null != directory; directory = directory.ParentElement as Wix.Directory)
2793 {
2794 string name;
2795
2796 if (!this.shortNames && null != directory.SourceName)
2797 {
2798 name = directory.SourceName;
2799 }
2800 else if (null != directory.ShortSourceName)
2801 {
2802 name = directory.ShortSourceName;
2803 }
2804 else if (!this.shortNames || null == directory.ShortName)
2805 {
2806 name = directory.Name;
2807 }
2808 else
2809 {
2810 name = directory.ShortName;
2811 }
2812
2813 if (0 == sourcePath.Length)
2814 {
2815 sourcePath.Append(name);
2816 }
2817 else
2818 {
2819 sourcePath.Insert(0, Path.DirectorySeparatorChar);
2820 sourcePath.Insert(0, name);
2821 }
2822 }
2823
2824 return sourcePath.ToString();
2825 }
2826
2827 /// <summary>
2828 /// Resolve the dependencies for a table (this is a helper method for GetSortedTableNames).
2829 /// </summary>
2830 /// <param name="tableName">The name of the table to resolve.</param>
2831 /// <param name="unsortedTableNames">The unsorted table names.</param>
2832 /// <param name="sortedTableNames">The sorted table names.</param>
2833 private void ResolveTableDependencies(string tableName, SortedList unsortedTableNames, StringCollection sortedTableNames)
2834 {
2835 unsortedTableNames.Remove(tableName);
2836
2837 foreach (var columnDefinition in this.tableDefinitions[tableName].Columns)
2838 {
2839 // no dependency to resolve because this column doesn't reference another table
2840 if (null == columnDefinition.KeyTable)
2841 {
2842 continue;
2843 }
2844
2845 foreach (var keyTable in columnDefinition.KeyTable.Split(';'))
2846 {
2847 if (tableName == keyTable)
2848 {
2849 continue; // self-referencing dependency
2850 }
2851 else if (sortedTableNames.Contains(keyTable))
2852 {
2853 continue; // dependent table has already been sorted
2854 }
2855 else if (!this.tableDefinitions.Contains(keyTable))
2856 {
2857 this.Messaging.Write(ErrorMessages.MissingTableDefinition(keyTable));
2858 }
2859 else if (unsortedTableNames.Contains(keyTable))
2860 {
2861 this.ResolveTableDependencies(keyTable, unsortedTableNames, sortedTableNames);
2862 }
2863 else
2864 {
2865 // found a circular dependency, so ignore it (this assumes that the tables will
2866 // use a finalize method to nest their elements since the ordering will not be
2867 // deterministic
2868 }
2869 }
2870 }
2871
2872 sortedTableNames.Add(tableName);
2873 }
2874
2875 /// <summary>
2876 /// Get the names of the tables to process in the order they should be processed, according to their dependencies.
2877 /// </summary>
2878 /// <returns>A StringCollection containing the ordered table names.</returns>
2879 private StringCollection GetSortedTableNames()
2880 {
2881 var sortedTableNames = new StringCollection();
2882 var unsortedTableNames = new SortedList();
2883
2884 // index the table names
2885 foreach (var tableDefinition in this.tableDefinitions)
2886 {
2887 unsortedTableNames.Add(tableDefinition.Name, tableDefinition.Name);
2888 }
2889
2890 // resolve the dependencies for each table
2891 while (0 < unsortedTableNames.Count)
2892 {
2893 this.ResolveTableDependencies(Convert.ToString(unsortedTableNames.GetByIndex(0)), unsortedTableNames, sortedTableNames);
2894 }
2895
2896 return sortedTableNames;
2897 }
2898
2899 /// <summary>
2900 /// Initialize decompilation.
2901 /// </summary>
2902 /// <param name="tables">The collection of all tables.</param>
2903 private void InitializeDecompile(TableIndexedCollection tables, int codepage)
2904 {
2905 // reset all the state information
2906 this.compressed = false;
2907 this.patchTargetFiles.Clear();
2908 this.sequenceElements.Clear();
2909 this.shortNames = false;
2910
2911 // set the codepage if its not neutral (0)
2912 if (0 != codepage)
2913 {
2914 switch (this.OutputType)
2915 {
2916 case OutputType.Module:
2917 ((Wix.Module)this.core.RootElement).Codepage = codepage.ToString(CultureInfo.InvariantCulture);
2918 break;
2919 case OutputType.PatchCreation:
2920 ((Wix.PatchCreation)this.core.RootElement).Codepage = codepage.ToString(CultureInfo.InvariantCulture);
2921 break;
2922 case OutputType.Product:
2923 ((Wix.Product)this.core.RootElement).Codepage = codepage.ToString(CultureInfo.InvariantCulture);
2924 break;
2925 }
2926 }
2927
2928 // index the rows from the extension libraries
2929 var indexedExtensionTables = new Dictionary<string, HashSet<string>>();
2930#if TODO_DECOMPILER_EXTENSIONS
2931 foreach (IDecompilerExtension extension in this.extensions)
2932 {
2933 // Get the optional library from the extension with the rows to be removed.
2934 Library library = extension.GetLibraryToRemove(this.tableDefinitions);
2935 if (null != library)
2936 {
2937 foreach (var section in library.Sections)
2938 {
2939 foreach (Table table in section.Tables)
2940 {
2941 foreach (Row row in table.Rows)
2942 {
2943 string primaryKey;
2944 string tableName;
2945
2946 // the Actions table needs to be handled specially
2947 if ("WixAction" == table.Name)
2948 {
2949 primaryKey = Convert.ToString(row[1]);
2950
2951 if (OutputType.Module == this.outputType)
2952 {
2953 tableName = String.Concat("Module", Convert.ToString(row[0]));
2954 }
2955 else
2956 {
2957 tableName = Convert.ToString(row[0]);
2958 }
2959 }
2960 else
2961 {
2962 primaryKey = row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter);
2963 tableName = table.Name;
2964 }
2965
2966 if (null != primaryKey)
2967 {
2968 HashSet<string> indexedExtensionRows;
2969 if (!indexedExtensionTables.TryGetValue(tableName, out indexedExtensionRows))
2970 {
2971 indexedExtensionRows = new HashSet<string>();
2972 indexedExtensionTables.Add(tableName, indexedExtensionRows);
2973 }
2974
2975 indexedExtensionRows.Add(primaryKey);
2976 }
2977 }
2978 }
2979 }
2980 }
2981 }
2982#endif
2983
2984 // remove the rows from the extension libraries (to allow full round-tripping)
2985 foreach (var kvp in indexedExtensionTables)
2986 {
2987 var tableName = kvp.Key;
2988 var indexedExtensionRows = kvp.Value;
2989
2990 var table = tables[tableName];
2991 if (null != table)
2992 {
2993 var originalRows = new RowDictionary<Row>(table);
2994
2995 // remove the original rows so that they can be added back if they should remain
2996 table.Rows.Clear();
2997
2998 foreach (var row in originalRows.Values)
2999 {
3000 if (!indexedExtensionRows.Contains(row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter)))
3001 {
3002 table.Rows.Add(row);
3003 }
3004 }
3005 }
3006 }
3007 }
3008
3009 /// <summary>
3010 /// Decompile the tables.
3011 /// </summary>
3012 /// <param name="output">The output being decompiled.</param>
3013 private void DecompileTables(Output output)
3014 {
3015 var sortedTableNames = this.GetSortedTableNames();
3016
3017 foreach (var tableName in sortedTableNames)
3018 {
3019 var table = output.Tables[tableName];
3020
3021 // table does not exist in this database or should not be decompiled
3022 if (null == table || !this.DecompilableTable(output, tableName))
3023 {
3024 continue;
3025 }
3026
3027 this.Messaging.Write(VerboseMessages.DecompilingTable(table.Name));
3028
3029 // empty tables may be kept with EnsureTable if the user set the proper option
3030 if (0 == table.Rows.Count && this.SuppressDroppingEmptyTables)
3031 {
3032 var ensureTable = new Wix.EnsureTable();
3033 ensureTable.Id = table.Name;
3034 this.core.RootElement.AddChild(ensureTable);
3035 }
3036
3037 switch (table.Name)
3038 {
3039 case "_SummaryInformation":
3040 this.Decompile_SummaryInformationTable(table);
3041 break;
3042 case "AdminExecuteSequence":
3043 case "AdminUISequence":
3044 case "AdvtExecuteSequence":
3045 case "InstallExecuteSequence":
3046 case "InstallUISequence":
3047 case "ModuleAdminExecuteSequence":
3048 case "ModuleAdminUISequence":
3049 case "ModuleAdvtExecuteSequence":
3050 case "ModuleInstallExecuteSequence":
3051 case "ModuleInstallUISequence":
3052 // handled in FinalizeSequenceTables
3053 break;
3054 case "ActionText":
3055 this.DecompileActionTextTable(table);
3056 break;
3057 case "AdvtUISequence":
3058 this.Messaging.Write(WarningMessages.DeprecatedTable(table.Name));
3059 break;
3060 case "AppId":
3061 this.DecompileAppIdTable(table);
3062 break;
3063 case "AppSearch":
3064 // handled in FinalizeSearchTables
3065 break;
3066 case "BBControl":
3067 this.DecompileBBControlTable(table);
3068 break;
3069 case "Billboard":
3070 this.DecompileBillboardTable(table);
3071 break;
3072 case "Binary":
3073 this.DecompileBinaryTable(table);
3074 break;
3075 case "BindImage":
3076 this.DecompileBindImageTable(table);
3077 break;
3078 case "CCPSearch":
3079 // handled in FinalizeSearchTables
3080 break;
3081 case "CheckBox":
3082 // handled in FinalizeCheckBoxTable
3083 break;
3084 case "Class":
3085 this.DecompileClassTable(table);
3086 break;
3087 case "ComboBox":
3088 this.DecompileComboBoxTable(table);
3089 break;
3090 case "Control":
3091 this.DecompileControlTable(table);
3092 break;
3093 case "ControlCondition":
3094 this.DecompileControlConditionTable(table);
3095 break;
3096 case "ControlEvent":
3097 this.DecompileControlEventTable(table);
3098 break;
3099 case "CreateFolder":
3100 this.DecompileCreateFolderTable(table);
3101 break;
3102 case "CustomAction":
3103 this.DecompileCustomActionTable(table);
3104 break;
3105 case "CompLocator":
3106 this.DecompileCompLocatorTable(table);
3107 break;
3108 case "Complus":
3109 this.DecompileComplusTable(table);
3110 break;
3111 case "Component":
3112 this.DecompileComponentTable(table);
3113 break;
3114 case "Condition":
3115 this.DecompileConditionTable(table);
3116 break;
3117 case "Dialog":
3118 this.DecompileDialogTable(table);
3119 break;
3120 case "Directory":
3121 this.DecompileDirectoryTable(table);
3122 break;
3123 case "DrLocator":
3124 this.DecompileDrLocatorTable(table);
3125 break;
3126 case "DuplicateFile":
3127 this.DecompileDuplicateFileTable(table);
3128 break;
3129 case "Environment":
3130 this.DecompileEnvironmentTable(table);
3131 break;
3132 case "Error":
3133 this.DecompileErrorTable(table);
3134 break;
3135 case "EventMapping":
3136 this.DecompileEventMappingTable(table);
3137 break;
3138 case "Extension":
3139 this.DecompileExtensionTable(table);
3140 break;
3141 case "ExternalFiles":
3142 this.DecompileExternalFilesTable(table);
3143 break;
3144 case "FamilyFileRanges":
3145 // handled in FinalizeFamilyFileRangesTable
3146 break;
3147 case "Feature":
3148 this.DecompileFeatureTable(table);
3149 break;
3150 case "FeatureComponents":
3151 this.DecompileFeatureComponentsTable(table);
3152 break;
3153 case "File":
3154 this.DecompileFileTable(table);
3155 break;
3156 case "FileSFPCatalog":
3157 this.DecompileFileSFPCatalogTable(table);
3158 break;
3159 case "Font":
3160 this.DecompileFontTable(table);
3161 break;
3162 case "Icon":
3163 this.DecompileIconTable(table);
3164 break;
3165 case "ImageFamilies":
3166 this.DecompileImageFamiliesTable(table);
3167 break;
3168 case "IniFile":
3169 this.DecompileIniFileTable(table);
3170 break;
3171 case "IniLocator":
3172 this.DecompileIniLocatorTable(table);
3173 break;
3174 case "IsolatedComponent":
3175 this.DecompileIsolatedComponentTable(table);
3176 break;
3177 case "LaunchCondition":
3178 this.DecompileLaunchConditionTable(table);
3179 break;
3180 case "ListBox":
3181 this.DecompileListBoxTable(table);
3182 break;
3183 case "ListView":
3184 this.DecompileListViewTable(table);
3185 break;
3186 case "LockPermissions":
3187 this.DecompileLockPermissionsTable(table);
3188 break;
3189 case "Media":
3190 this.DecompileMediaTable(table);
3191 break;
3192 case "MIME":
3193 this.DecompileMIMETable(table);
3194 break;
3195 case "ModuleAdvtUISequence":
3196 this.Messaging.Write(WarningMessages.DeprecatedTable(table.Name));
3197 break;
3198 case "ModuleComponents":
3199 // handled by DecompileComponentTable (since the ModuleComponents table
3200 // rows are created by nesting components under the Module element)
3201 break;
3202 case "ModuleConfiguration":
3203 this.DecompileModuleConfigurationTable(table);
3204 break;
3205 case "ModuleDependency":
3206 this.DecompileModuleDependencyTable(table);
3207 break;
3208 case "ModuleExclusion":
3209 this.DecompileModuleExclusionTable(table);
3210 break;
3211 case "ModuleIgnoreTable":
3212 this.DecompileModuleIgnoreTableTable(table);
3213 break;
3214 case "ModuleSignature":
3215 this.DecompileModuleSignatureTable(table);
3216 break;
3217 case "ModuleSubstitution":
3218 this.DecompileModuleSubstitutionTable(table);
3219 break;
3220 case "MoveFile":
3221 this.DecompileMoveFileTable(table);
3222 break;
3223 case "MsiAssembly":
3224 // handled in FinalizeFileTable
3225 break;
3226 case "MsiDigitalCertificate":
3227 this.DecompileMsiDigitalCertificateTable(table);
3228 break;
3229 case "MsiDigitalSignature":
3230 this.DecompileMsiDigitalSignatureTable(table);
3231 break;
3232 case "MsiEmbeddedChainer":
3233 this.DecompileMsiEmbeddedChainerTable(table);
3234 break;
3235 case "MsiEmbeddedUI":
3236 this.DecompileMsiEmbeddedUITable(table);
3237 break;
3238 case "MsiLockPermissionsEx":
3239 this.DecompileMsiLockPermissionsExTable(table);
3240 break;
3241 case "MsiPackageCertificate":
3242 this.DecompileMsiPackageCertificateTable(table);
3243 break;
3244 case "MsiPatchCertificate":
3245 this.DecompileMsiPatchCertificateTable(table);
3246 break;
3247 case "MsiShortcutProperty":
3248 this.DecompileMsiShortcutPropertyTable(table);
3249 break;
3250 case "ODBCAttribute":
3251 this.DecompileODBCAttributeTable(table);
3252 break;
3253 case "ODBCDataSource":
3254 this.DecompileODBCDataSourceTable(table);
3255 break;
3256 case "ODBCDriver":
3257 this.DecompileODBCDriverTable(table);
3258 break;
3259 case "ODBCSourceAttribute":
3260 this.DecompileODBCSourceAttributeTable(table);
3261 break;
3262 case "ODBCTranslator":
3263 this.DecompileODBCTranslatorTable(table);
3264 break;
3265 case "PatchMetadata":
3266 this.DecompilePatchMetadataTable(table);
3267 break;
3268 case "PatchSequence":
3269 this.DecompilePatchSequenceTable(table);
3270 break;
3271 case "ProgId":
3272 this.DecompileProgIdTable(table);
3273 break;
3274 case "Properties":
3275 this.DecompilePropertiesTable(table);
3276 break;
3277 case "Property":
3278 this.DecompilePropertyTable(table);
3279 break;
3280 case "PublishComponent":
3281 this.DecompilePublishComponentTable(table);
3282 break;
3283 case "RadioButton":
3284 this.DecompileRadioButtonTable(table);
3285 break;
3286 case "Registry":
3287 this.DecompileRegistryTable(table);
3288 break;
3289 case "RegLocator":
3290 this.DecompileRegLocatorTable(table);
3291 break;
3292 case "RemoveFile":
3293 this.DecompileRemoveFileTable(table);
3294 break;
3295 case "RemoveIniFile":
3296 this.DecompileRemoveIniFileTable(table);
3297 break;
3298 case "RemoveRegistry":
3299 this.DecompileRemoveRegistryTable(table);
3300 break;
3301 case "ReserveCost":
3302 this.DecompileReserveCostTable(table);
3303 break;
3304 case "SelfReg":
3305 this.DecompileSelfRegTable(table);
3306 break;
3307 case "ServiceControl":
3308 this.DecompileServiceControlTable(table);
3309 break;
3310 case "ServiceInstall":
3311 this.DecompileServiceInstallTable(table);
3312 break;
3313 case "SFPCatalog":
3314 this.DecompileSFPCatalogTable(table);
3315 break;
3316 case "Shortcut":
3317 this.DecompileShortcutTable(table);
3318 break;
3319 case "Signature":
3320 this.DecompileSignatureTable(table);
3321 break;
3322 case "TargetFiles_OptionalData":
3323 this.DecompileTargetFiles_OptionalDataTable(table);
3324 break;
3325 case "TargetImages":
3326 this.DecompileTargetImagesTable(table);
3327 break;
3328 case "TextStyle":
3329 this.DecompileTextStyleTable(table);
3330 break;
3331 case "TypeLib":
3332 this.DecompileTypeLibTable(table);
3333 break;
3334 case "Upgrade":
3335 this.DecompileUpgradeTable(table);
3336 break;
3337 case "UpgradedFiles_OptionalData":
3338 this.DecompileUpgradedFiles_OptionalDataTable(table);
3339 break;
3340 case "UpgradedFilesToIgnore":
3341 this.DecompileUpgradedFilesToIgnoreTable(table);
3342 break;
3343 case "UpgradedImages":
3344 this.DecompileUpgradedImagesTable(table);
3345 break;
3346 case "UIText":
3347 this.DecompileUITextTable(table);
3348 break;
3349 case "Verb":
3350 this.DecompileVerbTable(table);
3351 break;
3352
3353 default:
3354#if TODO_DECOMPILER_EXTENSIONS
3355 if (this.ExtensionsByTableName.TryGetValue(table.Name, out var extension)
3356 {
3357 extension.DecompileTable(table);
3358 }
3359 else
3360#endif
3361 if (!this.SuppressCustomTables)
3362 {
3363 this.DecompileCustomTable(table);
3364 }
3365 break;
3366 }
3367 }
3368 }
3369
3370 /// <summary>
3371 /// Determine if a particular table should be decompiled with the current settings.
3372 /// </summary>
3373 /// <param name="output">The output being decompiled.</param>
3374 /// <param name="tableName">The name of a table.</param>
3375 /// <returns>true if the table should be decompiled; false otherwise.</returns>
3376 private bool DecompilableTable(Output output, string tableName)
3377 {
3378 switch (tableName)
3379 {
3380 case "ActionText":
3381 case "BBControl":
3382 case "Billboard":
3383 case "CheckBox":
3384 case "Control":
3385 case "ControlCondition":
3386 case "ControlEvent":
3387 case "Dialog":
3388 case "Error":
3389 case "EventMapping":
3390 case "RadioButton":
3391 case "TextStyle":
3392 case "UIText":
3393 return !this.SuppressUI;
3394 case "ModuleAdminExecuteSequence":
3395 case "ModuleAdminUISequence":
3396 case "ModuleAdvtExecuteSequence":
3397 case "ModuleAdvtUISequence":
3398 case "ModuleComponents":
3399 case "ModuleConfiguration":
3400 case "ModuleDependency":
3401 case "ModuleIgnoreTable":
3402 case "ModuleInstallExecuteSequence":
3403 case "ModuleInstallUISequence":
3404 case "ModuleExclusion":
3405 case "ModuleSignature":
3406 case "ModuleSubstitution":
3407 if (OutputType.Module != output.Type)
3408 {
3409 this.Messaging.Write(WarningMessages.SkippingMergeModuleTable(output.SourceLineNumbers, tableName));
3410 return false;
3411 }
3412 else
3413 {
3414 return true;
3415 }
3416 case "ExternalFiles":
3417 case "FamilyFileRanges":
3418 case "ImageFamilies":
3419 case "PatchMetadata":
3420 case "PatchSequence":
3421 case "Properties":
3422 case "TargetFiles_OptionalData":
3423 case "TargetImages":
3424 case "UpgradedFiles_OptionalData":
3425 case "UpgradedFilesToIgnore":
3426 case "UpgradedImages":
3427 if (OutputType.PatchCreation != output.Type)
3428 {
3429 this.Messaging.Write(WarningMessages.SkippingPatchCreationTable(output.SourceLineNumbers, tableName));
3430 return false;
3431 }
3432 else
3433 {
3434 return true;
3435 }
3436 case "MsiPatchHeaders":
3437 case "MsiPatchMetadata":
3438 case "MsiPatchOldAssemblyName":
3439 case "MsiPatchOldAssemblyFile":
3440 case "MsiPatchSequence":
3441 case "Patch":
3442 case "PatchPackage":
3443 this.Messaging.Write(WarningMessages.PatchTable(output.SourceLineNumbers, tableName));
3444 return false;
3445 case "_SummaryInformation":
3446 return true;
3447 case "_Validation":
3448 case "MsiAssemblyName":
3449 case "MsiFileHash":
3450 return false;
3451 default: // all other tables are allowed in any output except for a patch creation package
3452 if (OutputType.PatchCreation == output.Type)
3453 {
3454 this.Messaging.Write(WarningMessages.IllegalPatchCreationTable(output.SourceLineNumbers, tableName));
3455 return false;
3456 }
3457 else
3458 {
3459 return true;
3460 }
3461 }
3462 }
3463
3464 /// <summary>
3465 /// Decompile the _SummaryInformation table.
3466 /// </summary>
3467 /// <param name="table">The table to decompile.</param>
3468 private void Decompile_SummaryInformationTable(Table table)
3469 {
3470 if (OutputType.Module == this.OutputType || OutputType.Product == this.OutputType)
3471 {
3472 var package = new Wix.Package();
3473
3474 foreach (var row in table.Rows)
3475 {
3476 var value = Convert.ToString(row[1]);
3477
3478 if (null != value && 0 < value.Length)
3479 {
3480 switch (Convert.ToInt32(row[0]))
3481 {
3482 case 1:
3483 if ("1252" != value)
3484 {
3485 package.SummaryCodepage = value;
3486 }
3487 break;
3488 case 3:
3489 package.Description = value;
3490 break;
3491 case 4:
3492 package.Manufacturer = value;
3493 break;
3494 case 5:
3495 if ("Installer" != value)
3496 {
3497 package.Keywords = value;
3498 }
3499 break;
3500 case 6:
3501 if (!value.StartsWith("This installer database contains the logic and data required to install "))
3502 {
3503 package.Comments = value;
3504 }
3505 break;
3506 case 7:
3507 var template = value.Split(';');
3508 if (0 < template.Length && 0 < template[template.Length - 1].Length)
3509 {
3510 package.Languages = template[template.Length - 1];
3511 }
3512
3513 if (1 < template.Length && null != template[0] && 0 < template[0].Length)
3514 {
3515 switch (template[0])
3516 {
3517 case "Intel":
3518 package.Platform = WixToolset.Data.Serialize.Package.PlatformType.x86;
3519 break;
3520 case "Intel64":
3521 package.Platform = WixToolset.Data.Serialize.Package.PlatformType.ia64;
3522 break;
3523 case "x64":
3524 package.Platform = WixToolset.Data.Serialize.Package.PlatformType.x64;
3525 break;
3526 }
3527 }
3528 break;
3529 case 9:
3530 if (OutputType.Module == this.OutputType)
3531 {
3532 this.modularizationGuid = value;
3533 package.Id = value;
3534 }
3535 break;
3536 case 14:
3537 package.InstallerVersion = Convert.ToInt32(row[1], CultureInfo.InvariantCulture);
3538 break;
3539 case 15:
3540 var wordCount = Convert.ToInt32(row[1], CultureInfo.InvariantCulture);
3541 if (0x1 == (wordCount & 0x1))
3542 {
3543 this.shortNames = true;
3544 package.ShortNames = Wix.YesNoType.yes;
3545 }
3546
3547 if (0x2 == (wordCount & 0x2))
3548 {
3549 this.compressed = true;
3550
3551 if (OutputType.Product == this.OutputType)
3552 {
3553 package.Compressed = Wix.YesNoType.yes;
3554 }
3555 }
3556
3557 if (0x4 == (wordCount & 0x4))
3558 {
3559 package.AdminImage = Wix.YesNoType.yes;
3560 }
3561
3562 if (0x8 == (wordCount & 0x8))
3563 {
3564 package.InstallPrivileges = Wix.Package.InstallPrivilegesType.limited;
3565 }
3566
3567 break;
3568 case 19:
3569 var security = Convert.ToInt32(row[1], CultureInfo.InvariantCulture);
3570 switch (security)
3571 {
3572 case 0:
3573 package.ReadOnly = Wix.YesNoDefaultType.no;
3574 break;
3575 case 4:
3576 package.ReadOnly = Wix.YesNoDefaultType.yes;
3577 break;
3578 }
3579 break;
3580 }
3581 }
3582 }
3583
3584 this.core.RootElement.AddChild(package);
3585 }
3586 else
3587 {
3588 var patchInformation = new Wix.PatchInformation();
3589
3590 foreach (var row in table.Rows)
3591 {
3592 var propertyId = Convert.ToInt32(row[0]);
3593 var value = Convert.ToString(row[1]);
3594
3595 if (null != row[1] && 0 < value.Length)
3596 {
3597 switch (propertyId)
3598 {
3599 case 1:
3600 if ("1252" != value)
3601 {
3602 patchInformation.SummaryCodepage = value;
3603 }
3604 break;
3605 case 3:
3606 patchInformation.Description = value;
3607 break;
3608 case 4:
3609 patchInformation.Manufacturer = value;
3610 break;
3611 case 5:
3612 if ("Installer,Patching,PCP,Database" != value)
3613 {
3614 patchInformation.Keywords = value;
3615 }
3616 break;
3617 case 6:
3618 patchInformation.Comments = value;
3619 break;
3620 case 7:
3621 var template = value.Split(';');
3622 if (0 < template.Length && 0 < template[template.Length - 1].Length)
3623 {
3624 patchInformation.Languages = template[template.Length - 1];
3625 }
3626
3627 if (1 < template.Length && null != template[0] && 0 < template[0].Length)
3628 {
3629 patchInformation.Platforms = template[0];
3630 }
3631 break;
3632 case 15:
3633 var wordCount = Convert.ToInt32(value, CultureInfo.InvariantCulture);
3634 if (0x1 == (wordCount & 0x1))
3635 {
3636 patchInformation.ShortNames = Wix.YesNoType.yes;
3637 }
3638
3639 if (0x2 == (wordCount & 0x2))
3640 {
3641 patchInformation.Compressed = Wix.YesNoType.yes;
3642 }
3643
3644 if (0x4 == (wordCount & 0x4))
3645 {
3646 patchInformation.AdminImage = Wix.YesNoType.yes;
3647 }
3648 break;
3649 case 19:
3650 var security = Convert.ToInt32(value, CultureInfo.InvariantCulture);
3651 switch (security)
3652 {
3653 case 0:
3654 patchInformation.ReadOnly = Wix.YesNoDefaultType.no;
3655 break;
3656 case 4:
3657 patchInformation.ReadOnly = Wix.YesNoDefaultType.yes;
3658 break;
3659 }
3660 break;
3661 }
3662 }
3663 }
3664
3665 this.core.RootElement.AddChild(patchInformation);
3666 }
3667 }
3668
3669 /// <summary>
3670 /// Decompile the ActionText table.
3671 /// </summary>
3672 /// <param name="table">The table to decompile.</param>
3673 private void DecompileActionTextTable(Table table)
3674 {
3675 foreach (var row in table.Rows)
3676 {
3677 var progressText = new Wix.ProgressText();
3678
3679 progressText.Action = Convert.ToString(row[0]);
3680
3681 if (null != row[1])
3682 {
3683 progressText.Content = Convert.ToString(row[1]);
3684 }
3685
3686 if (null != row[2])
3687 {
3688 progressText.Template = Convert.ToString(row[2]);
3689 }
3690
3691 this.core.UIElement.AddChild(progressText);
3692 }
3693 }
3694
3695 /// <summary>
3696 /// Decompile the AppId table.
3697 /// </summary>
3698 /// <param name="table">The table to decompile.</param>
3699 private void DecompileAppIdTable(Table table)
3700 {
3701 foreach (var row in table.Rows)
3702 {
3703 var appId = new Wix.AppId();
3704
3705 appId.Advertise = Wix.YesNoType.yes;
3706
3707 appId.Id = Convert.ToString(row[0]);
3708
3709 if (null != row[1])
3710 {
3711 appId.RemoteServerName = Convert.ToString(row[1]);
3712 }
3713
3714 if (null != row[2])
3715 {
3716 appId.LocalService = Convert.ToString(row[2]);
3717 }
3718
3719 if (null != row[3])
3720 {
3721 appId.ServiceParameters = Convert.ToString(row[3]);
3722 }
3723
3724 if (null != row[4])
3725 {
3726 appId.DllSurrogate = Convert.ToString(row[4]);
3727 }
3728
3729 if (null != row[5] && Int32.Equals(row[5], 1))
3730 {
3731 appId.ActivateAtStorage = Wix.YesNoType.yes;
3732 }
3733
3734 if (null != row[6] && Int32.Equals(row[6], 1))
3735 {
3736 appId.RunAsInteractiveUser = Wix.YesNoType.yes;
3737 }
3738
3739 this.core.RootElement.AddChild(appId);
3740 this.core.IndexElement(row, appId);
3741 }
3742 }
3743
3744 /// <summary>
3745 /// Decompile the BBControl table.
3746 /// </summary>
3747 /// <param name="table">The table to decompile.</param>
3748 private void DecompileBBControlTable(Table table)
3749 {
3750 foreach (BBControlRow bbControlRow in table.Rows)
3751 {
3752 var control = new Wix.Control();
3753
3754 control.Id = bbControlRow.BBControl;
3755
3756 control.Type = bbControlRow.Type;
3757
3758 control.X = bbControlRow.X;
3759
3760 control.Y = bbControlRow.Y;
3761
3762 control.Width = bbControlRow.Width;
3763
3764 control.Height = bbControlRow.Height;
3765
3766 if (null != bbControlRow[7])
3767 {
3768 SetControlAttributes(bbControlRow.Attributes, control);
3769 }
3770
3771 if (null != bbControlRow.Text)
3772 {
3773 control.Text = bbControlRow.Text;
3774 }
3775
3776 var billboard = (Wix.Billboard)this.core.GetIndexedElement("Billboard", bbControlRow.Billboard);
3777 if (null != billboard)
3778 {
3779 billboard.AddChild(control);
3780 }
3781 else
3782 {
3783 this.Messaging.Write(WarningMessages.ExpectedForeignRow(bbControlRow.SourceLineNumbers, table.Name, bbControlRow.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Billboard_", bbControlRow.Billboard, "Billboard"));
3784 }
3785 }
3786 }
3787
3788 /// <summary>
3789 /// Decompile the Billboard table.
3790 /// </summary>
3791 /// <param name="table">The table to decompile.</param>
3792 private void DecompileBillboardTable(Table table)
3793 {
3794 var billboardActions = new Hashtable();
3795 var billboards = new SortedList();
3796
3797 foreach (var row in table.Rows)
3798 {
3799 var billboard = new Wix.Billboard();
3800
3801 billboard.Id = Convert.ToString(row[0]);
3802
3803 billboard.Feature = Convert.ToString(row[1]);
3804
3805 this.core.IndexElement(row, billboard);
3806 billboards.Add(String.Format(CultureInfo.InvariantCulture, "{0}|{1:0000000000}", row[0], row[3]), row);
3807 }
3808
3809 foreach (Row row in billboards.Values)
3810 {
3811 var billboard = (Wix.Billboard)this.core.GetIndexedElement(row);
3812 var billboardAction = (Wix.BillboardAction)billboardActions[row[2]];
3813
3814 if (null == billboardAction)
3815 {
3816 billboardAction = new Wix.BillboardAction();
3817
3818 billboardAction.Id = Convert.ToString(row[2]);
3819
3820 this.core.UIElement.AddChild(billboardAction);
3821 billboardActions.Add(row[2], billboardAction);
3822 }
3823
3824 billboardAction.AddChild(billboard);
3825 }
3826 }
3827
3828 /// <summary>
3829 /// Decompile the Binary table.
3830 /// </summary>
3831 /// <param name="table">The table to decompile.</param>
3832 private void DecompileBinaryTable(Table table)
3833 {
3834 foreach (var row in table.Rows)
3835 {
3836 var binary = new Wix.Binary();
3837
3838 binary.Id = Convert.ToString(row[0]);
3839
3840 binary.SourceFile = Convert.ToString(row[1]);
3841
3842 this.core.RootElement.AddChild(binary);
3843 }
3844 }
3845
3846 /// <summary>
3847 /// Decompile the BindImage table.
3848 /// </summary>
3849 /// <param name="table">The table to decompile.</param>
3850 private void DecompileBindImageTable(Table table)
3851 {
3852 foreach (var row in table.Rows)
3853 {
3854 var file = (Wix.File)this.core.GetIndexedElement("File", Convert.ToString(row[0]));
3855
3856 if (null != file)
3857 {
3858 file.BindPath = Convert.ToString(row[1]);
3859 }
3860 else
3861 {
3862 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "File_", Convert.ToString(row[0]), "File"));
3863 }
3864 }
3865 }
3866
3867 /// <summary>
3868 /// Decompile the Class table.
3869 /// </summary>
3870 /// <param name="table">The table to decompile.</param>
3871 private void DecompileClassTable(Table table)
3872 {
3873 foreach (var row in table.Rows)
3874 {
3875 var wixClass = new Wix.Class();
3876
3877 wixClass.Advertise = Wix.YesNoType.yes;
3878
3879 wixClass.Id = Convert.ToString(row[0]);
3880
3881 switch (Convert.ToString(row[1]))
3882 {
3883 case "LocalServer":
3884 wixClass.Context = Wix.Class.ContextType.LocalServer;
3885 break;
3886 case "LocalServer32":
3887 wixClass.Context = Wix.Class.ContextType.LocalServer32;
3888 break;
3889 case "InprocServer":
3890 wixClass.Context = Wix.Class.ContextType.InprocServer;
3891 break;
3892 case "InprocServer32":
3893 wixClass.Context = Wix.Class.ContextType.InprocServer32;
3894 break;
3895 default:
3896 this.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[1].Column.Name, row[1]));
3897 break;
3898 }
3899
3900 // ProgId children are handled in FinalizeProgIdTable
3901
3902 if (null != row[4])
3903 {
3904 wixClass.Description = Convert.ToString(row[4]);
3905 }
3906
3907 if (null != row[5])
3908 {
3909 wixClass.AppId = Convert.ToString(row[5]);
3910 }
3911
3912 if (null != row[6])
3913 {
3914 var fileTypeMaskStrings = (Convert.ToString(row[6])).Split(';');
3915
3916 try
3917 {
3918 foreach (var fileTypeMaskString in fileTypeMaskStrings)
3919 {
3920 var fileTypeMaskParts = fileTypeMaskString.Split(',');
3921
3922 if (4 == fileTypeMaskParts.Length)
3923 {
3924 var fileTypeMask = new Wix.FileTypeMask();
3925
3926 fileTypeMask.Offset = Convert.ToInt32(fileTypeMaskParts[0], CultureInfo.InvariantCulture);
3927
3928 fileTypeMask.Mask = fileTypeMaskParts[2];
3929
3930 fileTypeMask.Value = fileTypeMaskParts[3];
3931
3932 wixClass.AddChild(fileTypeMask);
3933 }
3934 else
3935 {
3936 // TODO: warn
3937 }
3938 }
3939 }
3940 catch (FormatException)
3941 {
3942 this.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[6].Column.Name, row[6]));
3943 }
3944 catch (OverflowException)
3945 {
3946 this.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[6].Column.Name, row[6]));
3947 }
3948 }
3949
3950 if (null != row[7])
3951 {
3952 wixClass.Icon = Convert.ToString(row[7]);
3953 }
3954
3955 if (null != row[8])
3956 {
3957 wixClass.IconIndex = Convert.ToInt32(row[8]);
3958 }
3959
3960 if (null != row[9])
3961 {
3962 wixClass.Handler = Convert.ToString(row[9]);
3963 }
3964
3965 if (null != row[10])
3966 {
3967 wixClass.Argument = Convert.ToString(row[10]);
3968 }
3969
3970 if (null != row[12])
3971 {
3972 if (1 == Convert.ToInt32(row[12]))
3973 {
3974 wixClass.RelativePath = Wix.YesNoType.yes;
3975 }
3976 else
3977 {
3978 this.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[12].Column.Name, row[12]));
3979 }
3980 }
3981
3982 var component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[2]));
3983 if (null != component)
3984 {
3985 component.AddChild(wixClass);
3986 }
3987 else
3988 {
3989 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[2]), "Component"));
3990 }
3991
3992 this.core.IndexElement(row, wixClass);
3993 }
3994 }
3995
3996 /// <summary>
3997 /// Decompile the ComboBox table.
3998 /// </summary>
3999 /// <param name="table">The table to decompile.</param>
4000 private void DecompileComboBoxTable(Table table)
4001 {
4002 Wix.ComboBox comboBox = null;
4003 var comboBoxRows = new SortedList();
4004
4005 // sort the combo boxes by their property and order
4006 foreach (var row in table.Rows)
4007 {
4008 comboBoxRows.Add(String.Concat("{0}|{1:0000000000}", row[0], row[1]), row);
4009 }
4010
4011 foreach (Row row in comboBoxRows.Values)
4012 {
4013 if (null == comboBox || Convert.ToString(row[0]) != comboBox.Property)
4014 {
4015 comboBox = new Wix.ComboBox();
4016
4017 comboBox.Property = Convert.ToString(row[0]);
4018
4019 this.core.UIElement.AddChild(comboBox);
4020 }
4021
4022 var listItem = new Wix.ListItem();
4023
4024 listItem.Value = Convert.ToString(row[2]);
4025
4026 if (null != row[3])
4027 {
4028 listItem.Text = Convert.ToString(row[3]);
4029 }
4030
4031 comboBox.AddChild(listItem);
4032 }
4033 }
4034
4035 /// <summary>
4036 /// Decompile the Control table.
4037 /// </summary>
4038 /// <param name="table">The table to decompile.</param>
4039 private void DecompileControlTable(Table table)
4040 {
4041 foreach (ControlRow controlRow in table.Rows)
4042 {
4043 var control = new Wix.Control();
4044
4045 control.Id = controlRow.Control;
4046
4047 control.Type = controlRow.Type;
4048
4049 control.X = controlRow.X;
4050
4051 control.Y = controlRow.Y;
4052
4053 control.Width = controlRow.Width;
4054
4055 control.Height = controlRow.Height;
4056
4057 if (null != controlRow[7])
4058 {
4059 string[] specialAttributes;
4060
4061 // sets various common attributes like Disabled, Indirect, Integer, ...
4062 SetControlAttributes(controlRow.Attributes, control);
4063
4064 switch (control.Type)
4065 {
4066 case "Bitmap":
4067 specialAttributes = MsiInterop.BitmapControlAttributes;
4068 break;
4069 case "CheckBox":
4070 specialAttributes = MsiInterop.CheckboxControlAttributes;
4071 break;
4072 case "ComboBox":
4073 specialAttributes = MsiInterop.ComboboxControlAttributes;
4074 break;
4075 case "DirectoryCombo":
4076 specialAttributes = MsiInterop.VolumeControlAttributes;
4077 break;
4078 case "Edit":
4079 specialAttributes = MsiInterop.EditControlAttributes;
4080 break;
4081 case "Icon":
4082 specialAttributes = MsiInterop.IconControlAttributes;
4083 break;
4084 case "ListBox":
4085 specialAttributes = MsiInterop.ListboxControlAttributes;
4086 break;
4087 case "ListView":
4088 specialAttributes = MsiInterop.ListviewControlAttributes;
4089 break;
4090 case "MaskedEdit":
4091 specialAttributes = MsiInterop.EditControlAttributes;
4092 break;
4093 case "PathEdit":
4094 specialAttributes = MsiInterop.EditControlAttributes;
4095 break;
4096 case "ProgressBar":
4097 specialAttributes = MsiInterop.ProgressControlAttributes;
4098 break;
4099 case "PushButton":
4100 specialAttributes = MsiInterop.ButtonControlAttributes;
4101 break;
4102 case "RadioButtonGroup":
4103 specialAttributes = MsiInterop.RadioControlAttributes;
4104 break;
4105 case "Text":
4106 specialAttributes = MsiInterop.TextControlAttributes;
4107 break;
4108 case "VolumeCostList":
4109 specialAttributes = MsiInterop.VolumeControlAttributes;
4110 break;
4111 case "VolumeSelectCombo":
4112 specialAttributes = MsiInterop.VolumeControlAttributes;
4113 break;
4114 default:
4115 specialAttributes = null;
4116 break;
4117 }
4118
4119 if (null != specialAttributes)
4120 {
4121 var iconSizeSet = false;
4122
4123 for (var i = 16; 32 > i; i++)
4124 {
4125 if (1 == ((controlRow.Attributes >> i) & 1))
4126 {
4127 string attribute = null;
4128
4129 if (specialAttributes.Length > (i - 16))
4130 {
4131 attribute = specialAttributes[i - 16];
4132 }
4133
4134 // unknown attribute
4135 if (null == attribute)
4136 {
4137 this.Messaging.Write(WarningMessages.IllegalColumnValue(controlRow.SourceLineNumbers, table.Name, controlRow.Fields[7].Column.Name, controlRow.Attributes));
4138 continue;
4139 }
4140
4141 switch (attribute)
4142 {
4143 case "Bitmap":
4144 control.Bitmap = Wix.YesNoType.yes;
4145 break;
4146 case "CDROM":
4147 control.CDROM = Wix.YesNoType.yes;
4148 break;
4149 case "ComboList":
4150 control.ComboList = Wix.YesNoType.yes;
4151 break;
4152 case "ElevationShield":
4153 control.ElevationShield = Wix.YesNoType.yes;
4154 break;
4155 case "Fixed":
4156 control.Fixed = Wix.YesNoType.yes;
4157 break;
4158 case "FixedSize":
4159 control.FixedSize = Wix.YesNoType.yes;
4160 break;
4161 case "Floppy":
4162 control.Floppy = Wix.YesNoType.yes;
4163 break;
4164 case "FormatSize":
4165 control.FormatSize = Wix.YesNoType.yes;
4166 break;
4167 case "HasBorder":
4168 control.HasBorder = Wix.YesNoType.yes;
4169 break;
4170 case "Icon":
4171 control.Icon = Wix.YesNoType.yes;
4172 break;
4173 case "Icon16":
4174 if (iconSizeSet)
4175 {
4176 control.IconSize = Wix.Control.IconSizeType.Item48;
4177 }
4178 else
4179 {
4180 iconSizeSet = true;
4181 control.IconSize = Wix.Control.IconSizeType.Item16;
4182 }
4183 break;
4184 case "Icon32":
4185 if (iconSizeSet)
4186 {
4187 control.IconSize = Wix.Control.IconSizeType.Item48;
4188 }
4189 else
4190 {
4191 iconSizeSet = true;
4192 control.IconSize = Wix.Control.IconSizeType.Item32;
4193 }
4194 break;
4195 case "Image":
4196 control.Image = Wix.YesNoType.yes;
4197 break;
4198 case "Multiline":
4199 control.Multiline = Wix.YesNoType.yes;
4200 break;
4201 case "NoPrefix":
4202 control.NoPrefix = Wix.YesNoType.yes;
4203 break;
4204 case "NoWrap":
4205 control.NoWrap = Wix.YesNoType.yes;
4206 break;
4207 case "Password":
4208 control.Password = Wix.YesNoType.yes;
4209 break;
4210 case "ProgressBlocks":
4211 control.ProgressBlocks = Wix.YesNoType.yes;
4212 break;
4213 case "PushLike":
4214 control.PushLike = Wix.YesNoType.yes;
4215 break;
4216 case "RAMDisk":
4217 control.RAMDisk = Wix.YesNoType.yes;
4218 break;
4219 case "Remote":
4220 control.Remote = Wix.YesNoType.yes;
4221 break;
4222 case "Removable":
4223 control.Removable = Wix.YesNoType.yes;
4224 break;
4225 case "ShowRollbackCost":
4226 control.ShowRollbackCost = Wix.YesNoType.yes;
4227 break;
4228 case "Sorted":
4229 control.Sorted = Wix.YesNoType.yes;
4230 break;
4231 case "Transparent":
4232 control.Transparent = Wix.YesNoType.yes;
4233 break;
4234 case "UserLanguage":
4235 control.UserLanguage = Wix.YesNoType.yes;
4236 break;
4237 default:
4238 throw new InvalidOperationException($"Unknown control attribute: '{attribute}'.");
4239 }
4240 }
4241 }
4242 }
4243 else if (0 < (controlRow.Attributes & 0xFFFF0000))
4244 {
4245 this.Messaging.Write(WarningMessages.IllegalColumnValue(controlRow.SourceLineNumbers, table.Name, controlRow.Fields[7].Column.Name, controlRow.Attributes));
4246 }
4247 }
4248
4249 // FinalizeCheckBoxTable adds Control/@Property|@CheckBoxPropertyRef
4250 if (null != controlRow.Property && 0 != String.CompareOrdinal("CheckBox", control.Type))
4251 {
4252 control.Property = controlRow.Property;
4253 }
4254
4255 if (null != controlRow.Text)
4256 {
4257 control.Text = controlRow.Text;
4258 }
4259
4260 if (null != controlRow.Help)
4261 {
4262 var help = controlRow.Help.Split('|');
4263
4264 if (2 == help.Length)
4265 {
4266 if (0 < help[0].Length)
4267 {
4268 control.ToolTip = help[0];
4269 }
4270
4271 if (0 < help[1].Length)
4272 {
4273 control.Help = help[1];
4274 }
4275 }
4276 }
4277
4278 this.core.IndexElement(controlRow, control);
4279 }
4280 }
4281
4282 /// <summary>
4283 /// Decompile the ControlCondition table.
4284 /// </summary>
4285 /// <param name="table">The table to decompile.</param>
4286 private void DecompileControlConditionTable(Table table)
4287 {
4288 foreach (var row in table.Rows)
4289 {
4290 var condition = new Wix.Condition();
4291
4292 switch (Convert.ToString(row[2]))
4293 {
4294 case "Default":
4295 condition.Action = Wix.Condition.ActionType.@default;
4296 break;
4297 case "Disable":
4298 condition.Action = Wix.Condition.ActionType.disable;
4299 break;
4300 case "Enable":
4301 condition.Action = Wix.Condition.ActionType.enable;
4302 break;
4303 case "Hide":
4304 condition.Action = Wix.Condition.ActionType.hide;
4305 break;
4306 case "Show":
4307 condition.Action = Wix.Condition.ActionType.show;
4308 break;
4309 default:
4310 this.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[2].Column.Name, row[2]));
4311 break;
4312 }
4313
4314 condition.Content = Convert.ToString(row[3]);
4315
4316 var control = (Wix.Control)this.core.GetIndexedElement("Control", Convert.ToString(row[0]), Convert.ToString(row[1]));
4317 if (null != control)
4318 {
4319 control.AddChild(condition);
4320 }
4321 else
4322 {
4323 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Dialog_", Convert.ToString(row[0]), "Control_", Convert.ToString(row[1]), "Control"));
4324 }
4325 }
4326 }
4327
4328 /// <summary>
4329 /// Decompile the ControlEvent table.
4330 /// </summary>
4331 /// <param name="table">The table to decompile.</param>
4332 private void DecompileControlEventTable(Table table)
4333 {
4334 var controlEvents = new SortedList();
4335
4336 foreach (var row in table.Rows)
4337 {
4338 var publish = new Wix.Publish();
4339
4340 var publishEvent = Convert.ToString(row[2]);
4341 if (publishEvent.StartsWith("[", StringComparison.Ordinal) && publishEvent.EndsWith("]", StringComparison.Ordinal))
4342 {
4343 publish.Property = publishEvent.Substring(1, publishEvent.Length - 2);
4344
4345 if ("{}" != Convert.ToString(row[3]))
4346 {
4347 publish.Value = Convert.ToString(row[3]);
4348 }
4349 }
4350 else
4351 {
4352 publish.Event = publishEvent;
4353 publish.Value = Convert.ToString(row[3]);
4354 }
4355
4356 if (null != row[4])
4357 {
4358 publish.Content = Convert.ToString(row[4]);
4359 }
4360
4361 controlEvents.Add(String.Format(CultureInfo.InvariantCulture, "{0}|{1}|{2:0000000000}|{3}|{4}|{5}", row[0], row[1], (null == row[5] ? 0 : Convert.ToInt32(row[5])), row[2], row[3], row[4]), row);
4362
4363 this.core.IndexElement(row, publish);
4364 }
4365
4366 foreach (Row row in controlEvents.Values)
4367 {
4368 var control = (Wix.Control)this.core.GetIndexedElement("Control", Convert.ToString(row[0]), Convert.ToString(row[1]));
4369 var publish = (Wix.Publish)this.core.GetIndexedElement(row);
4370
4371 if (null != control)
4372 {
4373 control.AddChild(publish);
4374 }
4375 else
4376 {
4377 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Dialog_", Convert.ToString(row[0]), "Control_", Convert.ToString(row[1]), "Control"));
4378 }
4379 }
4380 }
4381
4382 /// <summary>
4383 /// Decompile a custom table.
4384 /// </summary>
4385 /// <param name="table">The table to decompile.</param>
4386 private void DecompileCustomTable(Table table)
4387 {
4388 if (0 < table.Rows.Count || this.SuppressDroppingEmptyTables)
4389 {
4390 var customTable = new Wix.CustomTable();
4391
4392 this.Messaging.Write(WarningMessages.DecompilingAsCustomTable(table.Rows[0].SourceLineNumbers, table.Name));
4393
4394 customTable.Id = table.Name;
4395
4396 foreach (var columnDefinition in table.Definition.Columns)
4397 {
4398 var column = new Wix.Column();
4399
4400 column.Id = columnDefinition.Name;
4401
4402 if (ColumnCategory.Unknown != columnDefinition.Category)
4403 {
4404 switch (columnDefinition.Category)
4405 {
4406 case ColumnCategory.Text:
4407 column.Category = Wix.Column.CategoryType.Text;
4408 break;
4409 case ColumnCategory.UpperCase:
4410 column.Category = Wix.Column.CategoryType.UpperCase;
4411 break;
4412 case ColumnCategory.LowerCase:
4413 column.Category = Wix.Column.CategoryType.LowerCase;
4414 break;
4415 case ColumnCategory.Integer:
4416 column.Category = Wix.Column.CategoryType.Integer;
4417 break;
4418 case ColumnCategory.DoubleInteger:
4419 column.Category = Wix.Column.CategoryType.DoubleInteger;
4420 break;
4421 case ColumnCategory.TimeDate:
4422 column.Category = Wix.Column.CategoryType.TimeDate;
4423 break;
4424 case ColumnCategory.Identifier:
4425 column.Category = Wix.Column.CategoryType.Identifier;
4426 break;
4427 case ColumnCategory.Property:
4428 column.Category = Wix.Column.CategoryType.Property;
4429 break;
4430 case ColumnCategory.Filename:
4431 column.Category = Wix.Column.CategoryType.Filename;
4432 break;
4433 case ColumnCategory.WildCardFilename:
4434 column.Category = Wix.Column.CategoryType.WildCardFilename;
4435 break;
4436 case ColumnCategory.Path:
4437 column.Category = Wix.Column.CategoryType.Path;
4438 break;
4439 case ColumnCategory.Paths:
4440 column.Category = Wix.Column.CategoryType.Paths;
4441 break;
4442 case ColumnCategory.AnyPath:
4443 column.Category = Wix.Column.CategoryType.AnyPath;
4444 break;
4445 case ColumnCategory.DefaultDir:
4446 column.Category = Wix.Column.CategoryType.DefaultDir;
4447 break;
4448 case ColumnCategory.RegPath:
4449 column.Category = Wix.Column.CategoryType.RegPath;
4450 break;
4451 case ColumnCategory.Formatted:
4452 column.Category = Wix.Column.CategoryType.Formatted;
4453 break;
4454 case ColumnCategory.FormattedSDDLText:
4455 column.Category = Wix.Column.CategoryType.FormattedSddl;
4456 break;
4457 case ColumnCategory.Template:
4458 column.Category = Wix.Column.CategoryType.Template;
4459 break;
4460 case ColumnCategory.Condition:
4461 column.Category = Wix.Column.CategoryType.Condition;
4462 break;
4463 case ColumnCategory.Guid:
4464 column.Category = Wix.Column.CategoryType.Guid;
4465 break;
4466 case ColumnCategory.Version:
4467 column.Category = Wix.Column.CategoryType.Version;
4468 break;
4469 case ColumnCategory.Language:
4470 column.Category = Wix.Column.CategoryType.Language;
4471 break;
4472 case ColumnCategory.Binary:
4473 column.Category = Wix.Column.CategoryType.Binary;
4474 break;
4475 case ColumnCategory.CustomSource:
4476 column.Category = Wix.Column.CategoryType.CustomSource;
4477 break;
4478 case ColumnCategory.Cabinet:
4479 column.Category = Wix.Column.CategoryType.Cabinet;
4480 break;
4481 case ColumnCategory.Shortcut:
4482 column.Category = Wix.Column.CategoryType.Shortcut;
4483 break;
4484 default:
4485 throw new InvalidOperationException($"Unknown custom column category '{columnDefinition.Category.ToString()}'.");
4486 }
4487 }
4488
4489 if (null != columnDefinition.Description)
4490 {
4491 column.Description = columnDefinition.Description;
4492 }
4493
4494 if (columnDefinition.KeyColumn.HasValue)
4495 {
4496 column.KeyColumn = columnDefinition.KeyColumn.Value;
4497 }
4498
4499 if (null != columnDefinition.KeyTable)
4500 {
4501 column.KeyTable = columnDefinition.KeyTable;
4502 }
4503
4504 if (columnDefinition.IsLocalizable)
4505 {
4506 column.Localizable = Wix.YesNoType.yes;
4507 }
4508
4509 if (columnDefinition.MaxValue.HasValue)
4510 {
4511 column.MaxValue = columnDefinition.MaxValue.Value;
4512 }
4513
4514 if (columnDefinition.MinValue.HasValue)
4515 {
4516 column.MinValue = columnDefinition.MinValue.Value;
4517 }
4518
4519 if (ColumnModularizeType.None != columnDefinition.ModularizeType)
4520 {
4521 switch (columnDefinition.ModularizeType)
4522 {
4523 case ColumnModularizeType.Column:
4524 column.Modularize = Wix.Column.ModularizeType.Column;
4525 break;
4526 case ColumnModularizeType.Condition:
4527 column.Modularize = Wix.Column.ModularizeType.Condition;
4528 break;
4529 case ColumnModularizeType.Icon:
4530 column.Modularize = Wix.Column.ModularizeType.Icon;
4531 break;
4532 case ColumnModularizeType.Property:
4533 column.Modularize = Wix.Column.ModularizeType.Property;
4534 break;
4535 case ColumnModularizeType.SemicolonDelimited:
4536 column.Modularize = Wix.Column.ModularizeType.SemicolonDelimited;
4537 break;
4538 default:
4539 throw new InvalidOperationException($"Unknown custom column modularization type '{columnDefinition.ModularizeType.ToString()}'.");
4540 }
4541 }
4542
4543 if (columnDefinition.Nullable)
4544 {
4545 column.Nullable = Wix.YesNoType.yes;
4546 }
4547
4548 if (columnDefinition.PrimaryKey)
4549 {
4550 column.PrimaryKey = Wix.YesNoType.yes;
4551 }
4552
4553 if (null != columnDefinition.Possibilities)
4554 {
4555 column.Set = columnDefinition.Possibilities;
4556 }
4557
4558 if (ColumnType.Unknown != columnDefinition.Type)
4559 {
4560 switch (columnDefinition.Type)
4561 {
4562 case ColumnType.Localized:
4563 column.Localizable = Wix.YesNoType.yes;
4564 column.Type = Wix.Column.TypeType.@string;
4565 break;
4566 case ColumnType.Number:
4567 column.Type = Wix.Column.TypeType.@int;
4568 break;
4569 case ColumnType.Object:
4570 column.Type = Wix.Column.TypeType.binary;
4571 break;
4572 case ColumnType.Preserved:
4573 case ColumnType.String:
4574 column.Type = Wix.Column.TypeType.@string;
4575 break;
4576 default:
4577 throw new InvalidOperationException($"Unknown custom column type '{columnDefinition.Type.ToString()}'.");
4578 }
4579 }
4580
4581 column.Width = columnDefinition.Length;
4582
4583 customTable.AddChild(column);
4584 }
4585
4586 foreach (var row in table.Rows)
4587 {
4588 var wixRow = new Wix.Row();
4589
4590 foreach (var field in row.Fields)
4591 {
4592 var data = new Wix.Data();
4593
4594 data.Column = field.Column.Name;
4595
4596 data.Content = Convert.ToString(field.Data, CultureInfo.InvariantCulture);
4597
4598 wixRow.AddChild(data);
4599 }
4600
4601 customTable.AddChild(wixRow);
4602 }
4603
4604 this.core.RootElement.AddChild(customTable);
4605 }
4606 }
4607
4608 /// <summary>
4609 /// Decompile the CreateFolder table.
4610 /// </summary>
4611 /// <param name="table">The table to decompile.</param>
4612 private void DecompileCreateFolderTable(Table table)
4613 {
4614 foreach (var row in table.Rows)
4615 {
4616 var createFolder = new Wix.CreateFolder();
4617
4618 createFolder.Directory = Convert.ToString(row[0]);
4619
4620 var component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[1]));
4621 if (null != component)
4622 {
4623 component.AddChild(createFolder);
4624 }
4625 else
4626 {
4627 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[1]), "Component"));
4628 }
4629 this.core.IndexElement(row, createFolder);
4630 }
4631 }
4632
4633 /// <summary>
4634 /// Decompile the CustomAction table.
4635 /// </summary>
4636 /// <param name="table">The table to decompile.</param>
4637 private void DecompileCustomActionTable(Table table)
4638 {
4639 foreach (var row in table.Rows)
4640 {
4641 var customAction = new Wix.CustomAction();
4642
4643 customAction.Id = Convert.ToString(row[0]);
4644
4645 var type = Convert.ToInt32(row[1]);
4646
4647 if (MsiInterop.MsidbCustomActionTypeHideTarget == (type & MsiInterop.MsidbCustomActionTypeHideTarget))
4648 {
4649 customAction.HideTarget = Wix.YesNoType.yes;
4650 }
4651
4652 if (MsiInterop.MsidbCustomActionTypeNoImpersonate == (type & MsiInterop.MsidbCustomActionTypeNoImpersonate))
4653 {
4654 customAction.Impersonate = Wix.YesNoType.no;
4655 }
4656
4657 if (MsiInterop.MsidbCustomActionTypeTSAware == (type & MsiInterop.MsidbCustomActionTypeTSAware))
4658 {
4659 customAction.TerminalServerAware = Wix.YesNoType.yes;
4660 }
4661
4662 if (MsiInterop.MsidbCustomActionType64BitScript == (type & MsiInterop.MsidbCustomActionType64BitScript))
4663 {
4664 customAction.Win64 = Wix.YesNoType.yes;
4665 }
4666
4667 switch (type & MsiInterop.MsidbCustomActionTypeExecuteBits)
4668 {
4669 case 0:
4670 // this is the default value
4671 break;
4672 case MsiInterop.MsidbCustomActionTypeFirstSequence:
4673 customAction.Execute = Wix.CustomAction.ExecuteType.firstSequence;
4674 break;
4675 case MsiInterop.MsidbCustomActionTypeOncePerProcess:
4676 customAction.Execute = Wix.CustomAction.ExecuteType.oncePerProcess;
4677 break;
4678 case MsiInterop.MsidbCustomActionTypeClientRepeat:
4679 customAction.Execute = Wix.CustomAction.ExecuteType.secondSequence;
4680 break;
4681 case MsiInterop.MsidbCustomActionTypeInScript:
4682 customAction.Execute = Wix.CustomAction.ExecuteType.deferred;
4683 break;
4684 case MsiInterop.MsidbCustomActionTypeInScript + MsiInterop.MsidbCustomActionTypeRollback:
4685 customAction.Execute = Wix.CustomAction.ExecuteType.rollback;
4686 break;
4687 case MsiInterop.MsidbCustomActionTypeInScript + MsiInterop.MsidbCustomActionTypeCommit:
4688 customAction.Execute = Wix.CustomAction.ExecuteType.commit;
4689 break;
4690 default:
4691 this.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[1].Column.Name, row[1]));
4692 break;
4693 }
4694
4695 switch (type & MsiInterop.MsidbCustomActionTypeReturnBits)
4696 {
4697 case 0:
4698 // this is the default value
4699 break;
4700 case MsiInterop.MsidbCustomActionTypeContinue:
4701 customAction.Return = Wix.CustomAction.ReturnType.ignore;
4702 break;
4703 case MsiInterop.MsidbCustomActionTypeAsync:
4704 customAction.Return = Wix.CustomAction.ReturnType.asyncWait;
4705 break;
4706 case MsiInterop.MsidbCustomActionTypeAsync + MsiInterop.MsidbCustomActionTypeContinue:
4707 customAction.Return = Wix.CustomAction.ReturnType.asyncNoWait;
4708 break;
4709 default:
4710 this.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[1].Column.Name, row[1]));
4711 break;
4712 }
4713
4714 var source = type & MsiInterop.MsidbCustomActionTypeSourceBits;
4715 switch (source)
4716 {
4717 case MsiInterop.MsidbCustomActionTypeBinaryData:
4718 customAction.BinaryKey = Convert.ToString(row[2]);
4719 break;
4720 case MsiInterop.MsidbCustomActionTypeSourceFile:
4721 if (null != row[2])
4722 {
4723 customAction.FileKey = Convert.ToString(row[2]);
4724 }
4725 break;
4726 case MsiInterop.MsidbCustomActionTypeDirectory:
4727 if (null != row[2])
4728 {
4729 customAction.Directory = Convert.ToString(row[2]);
4730 }
4731 break;
4732 case MsiInterop.MsidbCustomActionTypeProperty:
4733 customAction.Property = Convert.ToString(row[2]);
4734 break;
4735 default:
4736 this.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[1].Column.Name, row[1]));
4737 break;
4738 }
4739
4740 switch (type & MsiInterop.MsidbCustomActionTypeTargetBits)
4741 {
4742 case MsiInterop.MsidbCustomActionTypeDll:
4743 customAction.DllEntry = Convert.ToString(row[3]);
4744 break;
4745 case MsiInterop.MsidbCustomActionTypeExe:
4746 customAction.ExeCommand = Convert.ToString(row[3]);
4747 break;
4748 case MsiInterop.MsidbCustomActionTypeTextData:
4749 if (MsiInterop.MsidbCustomActionTypeSourceFile == source)
4750 {
4751 customAction.Error = Convert.ToString(row[3]);
4752 }
4753 else
4754 {
4755 customAction.Value = Convert.ToString(row[3]);
4756 }
4757 break;
4758 case MsiInterop.MsidbCustomActionTypeJScript:
4759 if (MsiInterop.MsidbCustomActionTypeDirectory == source)
4760 {
4761 customAction.Script = Wix.CustomAction.ScriptType.jscript;
4762 customAction.Content = Convert.ToString(row[3]);
4763 }
4764 else
4765 {
4766 customAction.JScriptCall = Convert.ToString(row[3]);
4767 }
4768 break;
4769 case MsiInterop.MsidbCustomActionTypeVBScript:
4770 if (MsiInterop.MsidbCustomActionTypeDirectory == source)
4771 {
4772 customAction.Script = Wix.CustomAction.ScriptType.vbscript;
4773 customAction.Content = Convert.ToString(row[3]);
4774 }
4775 else
4776 {
4777 customAction.VBScriptCall = Convert.ToString(row[3]);
4778 }
4779 break;
4780 case MsiInterop.MsidbCustomActionTypeInstall:
4781 this.Messaging.Write(WarningMessages.NestedInstall(row.SourceLineNumbers, table.Name, row.Fields[1].Column.Name, row[1]));
4782 continue;
4783 default:
4784 this.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[1].Column.Name, row[1]));
4785 break;
4786 }
4787
4788 var extype = 4 < row.Fields.Length && null != row[4] ? Convert.ToInt32(row[4]) : 0;
4789 if (MsiInterop.MsidbCustomActionTypePatchUninstall == (extype & MsiInterop.MsidbCustomActionTypePatchUninstall))
4790 {
4791 customAction.PatchUninstall = Wix.YesNoType.yes;
4792 }
4793
4794 this.core.RootElement.AddChild(customAction);
4795 this.core.IndexElement(row, customAction);
4796 }
4797 }
4798
4799 /// <summary>
4800 /// Decompile the CompLocator table.
4801 /// </summary>
4802 /// <param name="table">The table to decompile.</param>
4803 private void DecompileCompLocatorTable(Table table)
4804 {
4805 foreach (var row in table.Rows)
4806 {
4807 var componentSearch = new Wix.ComponentSearch();
4808
4809 componentSearch.Id = Convert.ToString(row[0]);
4810
4811 componentSearch.Guid = Convert.ToString(row[1]);
4812
4813 if (null != row[2])
4814 {
4815 switch (Convert.ToInt32(row[2]))
4816 {
4817 case MsiInterop.MsidbLocatorTypeDirectory:
4818 componentSearch.Type = Wix.ComponentSearch.TypeType.directory;
4819 break;
4820 case MsiInterop.MsidbLocatorTypeFileName:
4821 // this is the default value
4822 break;
4823 default:
4824 this.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[2].Column.Name, row[2]));
4825 break;
4826 }
4827 }
4828
4829 this.core.IndexElement(row, componentSearch);
4830 }
4831 }
4832
4833 /// <summary>
4834 /// Decompile the Complus table.
4835 /// </summary>
4836 /// <param name="table">The table to decompile.</param>
4837 private void DecompileComplusTable(Table table)
4838 {
4839 foreach (var row in table.Rows)
4840 {
4841 if (null != row[1])
4842 {
4843 var component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[0]));
4844
4845 if (null != component)
4846 {
4847 component.ComPlusFlags = Convert.ToInt32(row[1]);
4848 }
4849 else
4850 {
4851 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[0]), "Component"));
4852 }
4853 }
4854 }
4855 }
4856
4857 /// <summary>
4858 /// Decompile the Component table.
4859 /// </summary>
4860 /// <param name="table">The table to decompile.</param>
4861 private void DecompileComponentTable(Table table)
4862 {
4863 foreach (var row in table.Rows)
4864 {
4865 var component = new Wix.Component();
4866
4867 component.Id = Convert.ToString(row[0]);
4868
4869 component.Guid = Convert.ToString(row[1]);
4870
4871 var attributes = Convert.ToInt32(row[3]);
4872
4873 if (MsiInterop.MsidbComponentAttributesSourceOnly == (attributes & MsiInterop.MsidbComponentAttributesSourceOnly))
4874 {
4875 component.Location = Wix.Component.LocationType.source;
4876 }
4877 else if (MsiInterop.MsidbComponentAttributesOptional == (attributes & MsiInterop.MsidbComponentAttributesOptional))
4878 {
4879 component.Location = Wix.Component.LocationType.either;
4880 }
4881
4882 if (MsiInterop.MsidbComponentAttributesSharedDllRefCount == (attributes & MsiInterop.MsidbComponentAttributesSharedDllRefCount))
4883 {
4884 component.SharedDllRefCount = Wix.YesNoType.yes;
4885 }
4886
4887 if (MsiInterop.MsidbComponentAttributesPermanent == (attributes & MsiInterop.MsidbComponentAttributesPermanent))
4888 {
4889 component.Permanent = Wix.YesNoType.yes;
4890 }
4891
4892 if (MsiInterop.MsidbComponentAttributesTransitive == (attributes & MsiInterop.MsidbComponentAttributesTransitive))
4893 {
4894 component.Transitive = Wix.YesNoType.yes;
4895 }
4896
4897 if (MsiInterop.MsidbComponentAttributesNeverOverwrite == (attributes & MsiInterop.MsidbComponentAttributesNeverOverwrite))
4898 {
4899 component.NeverOverwrite = Wix.YesNoType.yes;
4900 }
4901
4902 if (MsiInterop.MsidbComponentAttributes64bit == (attributes & MsiInterop.MsidbComponentAttributes64bit))
4903 {
4904 component.Win64 = Wix.YesNoType.yes;
4905 }
4906
4907 if (MsiInterop.MsidbComponentAttributesDisableRegistryReflection == (attributes & MsiInterop.MsidbComponentAttributesDisableRegistryReflection))
4908 {
4909 component.DisableRegistryReflection = Wix.YesNoType.yes;
4910 }
4911
4912 if (MsiInterop.MsidbComponentAttributesUninstallOnSupersedence == (attributes & MsiInterop.MsidbComponentAttributesUninstallOnSupersedence))
4913 {
4914 component.UninstallWhenSuperseded = Wix.YesNoType.yes;
4915 }
4916
4917 if (MsiInterop.MsidbComponentAttributesShared == (attributes & MsiInterop.MsidbComponentAttributesShared))
4918 {
4919 component.Shared = Wix.YesNoType.yes;
4920 }
4921
4922 if (null != row[4])
4923 {
4924 var condition = new Wix.Condition();
4925
4926 condition.Content = Convert.ToString(row[4]);
4927
4928 component.AddChild(condition);
4929 }
4930
4931 var directory = (Wix.Directory)this.core.GetIndexedElement("Directory", Convert.ToString(row[2]));
4932 if (null != directory)
4933 {
4934 directory.AddChild(component);
4935 }
4936 else
4937 {
4938 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Directory_", Convert.ToString(row[2]), "Directory"));
4939 }
4940 this.core.IndexElement(row, component);
4941 }
4942 }
4943
4944 /// <summary>
4945 /// Decompile the Condition table.
4946 /// </summary>
4947 /// <param name="table">The table to decompile.</param>
4948 private void DecompileConditionTable(Table table)
4949 {
4950 foreach (var row in table.Rows)
4951 {
4952 var condition = new Wix.Condition();
4953
4954 condition.Level = Convert.ToInt32(row[1]);
4955
4956 if (null != row[2])
4957 {
4958 condition.Content = Convert.ToString(row[2]);
4959 }
4960
4961 var feature = (Wix.Feature)this.core.GetIndexedElement("Feature", Convert.ToString(row[0]));
4962 if (null != feature)
4963 {
4964 feature.AddChild(condition);
4965 }
4966 else
4967 {
4968 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Feature_", Convert.ToString(row[0]), "Feature"));
4969 }
4970 }
4971 }
4972
4973 /// <summary>
4974 /// Decompile the Dialog table.
4975 /// </summary>
4976 /// <param name="table">The table to decompile.</param>
4977 private void DecompileDialogTable(Table table)
4978 {
4979 foreach (var row in table.Rows)
4980 {
4981 var dialog = new Wix.Dialog();
4982
4983 dialog.Id = Convert.ToString(row[0]);
4984
4985 dialog.X = Convert.ToInt32(row[1]);
4986
4987 dialog.Y = Convert.ToInt32(row[2]);
4988
4989 dialog.Width = Convert.ToInt32(row[3]);
4990
4991 dialog.Height = Convert.ToInt32(row[4]);
4992
4993 if (null != row[5])
4994 {
4995 var attributes = Convert.ToInt32(row[5]);
4996
4997 if (0 == (attributes & MsiInterop.MsidbDialogAttributesVisible))
4998 {
4999 dialog.Hidden = Wix.YesNoType.yes;
5000 }
5001
5002 if (0 == (attributes & MsiInterop.MsidbDialogAttributesModal))
5003 {
5004 dialog.Modeless = Wix.YesNoType.yes;
5005 }
5006
5007 if (0 == (attributes & MsiInterop.MsidbDialogAttributesMinimize))
5008 {
5009 dialog.NoMinimize = Wix.YesNoType.yes;
5010 }
5011
5012 if (MsiInterop.MsidbDialogAttributesSysModal == (attributes & MsiInterop.MsidbDialogAttributesSysModal))
5013 {
5014 dialog.SystemModal = Wix.YesNoType.yes;
5015 }
5016
5017 if (MsiInterop.MsidbDialogAttributesKeepModeless == (attributes & MsiInterop.MsidbDialogAttributesKeepModeless))
5018 {
5019 dialog.KeepModeless = Wix.YesNoType.yes;
5020 }
5021
5022 if (MsiInterop.MsidbDialogAttributesTrackDiskSpace == (attributes & MsiInterop.MsidbDialogAttributesTrackDiskSpace))
5023 {
5024 dialog.TrackDiskSpace = Wix.YesNoType.yes;
5025 }
5026
5027 if (MsiInterop.MsidbDialogAttributesUseCustomPalette == (attributes & MsiInterop.MsidbDialogAttributesUseCustomPalette))
5028 {
5029 dialog.CustomPalette = Wix.YesNoType.yes;
5030 }
5031
5032 if (MsiInterop.MsidbDialogAttributesRTLRO == (attributes & MsiInterop.MsidbDialogAttributesRTLRO))
5033 {
5034 dialog.RightToLeft = Wix.YesNoType.yes;
5035 }
5036
5037 if (MsiInterop.MsidbDialogAttributesRightAligned == (attributes & MsiInterop.MsidbDialogAttributesRightAligned))
5038 {
5039 dialog.RightAligned = Wix.YesNoType.yes;
5040 }
5041
5042 if (MsiInterop.MsidbDialogAttributesLeftScroll == (attributes & MsiInterop.MsidbDialogAttributesLeftScroll))
5043 {
5044 dialog.LeftScroll = Wix.YesNoType.yes;
5045 }
5046
5047 if (MsiInterop.MsidbDialogAttributesError == (attributes & MsiInterop.MsidbDialogAttributesError))
5048 {
5049 dialog.ErrorDialog = Wix.YesNoType.yes;
5050 }
5051 }
5052
5053 if (null != row[6])
5054 {
5055 dialog.Title = Convert.ToString(row[6]);
5056 }
5057
5058 this.core.UIElement.AddChild(dialog);
5059 this.core.IndexElement(row, dialog);
5060 }
5061 }
5062
5063 /// <summary>
5064 /// Decompile the Directory table.
5065 /// </summary>
5066 /// <param name="table">The table to decompile.</param>
5067 private void DecompileDirectoryTable(Table table)
5068 {
5069 foreach (var row in table.Rows)
5070 {
5071 var directory = new Wix.Directory();
5072
5073 directory.Id = Convert.ToString(row[0]);
5074
5075 var names = Common.GetNames(Convert.ToString(row[2]));
5076
5077 if (String.Equals(directory.Id, "TARGETDIR", StringComparison.Ordinal) && !String.Equals(names[0], "SourceDir", StringComparison.Ordinal))
5078 {
5079 this.Messaging.Write(WarningMessages.TargetDirCorrectedDefaultDir());
5080 directory.Name = "SourceDir";
5081 }
5082 else
5083 {
5084 if (null != names[0] && "." != names[0])
5085 {
5086 if (null != names[1])
5087 {
5088 directory.ShortName = names[0];
5089 }
5090 else
5091 {
5092 directory.Name = names[0];
5093 }
5094 }
5095
5096 if (null != names[1])
5097 {
5098 directory.Name = names[1];
5099 }
5100 }
5101
5102 if (null != names[2])
5103 {
5104 if (null != names[3])
5105 {
5106 directory.ShortSourceName = names[2];
5107 }
5108 else
5109 {
5110 directory.SourceName = names[2];
5111 }
5112 }
5113
5114 if (null != names[3])
5115 {
5116 directory.SourceName = names[3];
5117 }
5118
5119 this.core.IndexElement(row, directory);
5120 }
5121
5122 // nest the directories
5123 foreach (var row in table.Rows)
5124 {
5125 var directory = (Wix.Directory)this.core.GetIndexedElement(row);
5126
5127 if (null == row[1])
5128 {
5129 this.core.RootElement.AddChild(directory);
5130 }
5131 else
5132 {
5133 var parentDirectory = (Wix.Directory)this.core.GetIndexedElement("Directory", Convert.ToString(row[1]));
5134
5135 if (null == parentDirectory)
5136 {
5137 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Directory_Parent", Convert.ToString(row[1]), "Directory"));
5138 }
5139 else if (parentDirectory == directory) // another way to specify a root directory
5140 {
5141 this.core.RootElement.AddChild(directory);
5142 }
5143 else
5144 {
5145 parentDirectory.AddChild(directory);
5146 }
5147 }
5148 }
5149 }
5150
5151 /// <summary>
5152 /// Decompile the DrLocator table.
5153 /// </summary>
5154 /// <param name="table">The table to decompile.</param>
5155 private void DecompileDrLocatorTable(Table table)
5156 {
5157 foreach (var row in table.Rows)
5158 {
5159 var directorySearch = new Wix.DirectorySearch();
5160
5161 directorySearch.Id = Convert.ToString(row[0]);
5162
5163 if (null != row[2])
5164 {
5165 directorySearch.Path = Convert.ToString(row[2]);
5166 }
5167
5168 if (null != row[3])
5169 {
5170 directorySearch.Depth = Convert.ToInt32(row[3]);
5171 }
5172
5173 this.core.IndexElement(row, directorySearch);
5174 }
5175 }
5176
5177 /// <summary>
5178 /// Decompile the DuplicateFile table.
5179 /// </summary>
5180 /// <param name="table">The table to decompile.</param>
5181 private void DecompileDuplicateFileTable(Table table)
5182 {
5183 foreach (var row in table.Rows)
5184 {
5185 var copyFile = new Wix.CopyFile();
5186
5187 copyFile.Id = Convert.ToString(row[0]);
5188
5189 copyFile.FileId = Convert.ToString(row[2]);
5190
5191 if (null != row[3])
5192 {
5193 var names = Common.GetNames(Convert.ToString(row[3]));
5194 if (null != names[0] && null != names[1])
5195 {
5196 copyFile.DestinationShortName = names[0];
5197 copyFile.DestinationName = names[1];
5198 }
5199 else if (null != names[0])
5200 {
5201 copyFile.DestinationName = names[0];
5202 }
5203 }
5204
5205 // destination directory/property is set in FinalizeDuplicateMoveFileTables
5206
5207 var component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[1]));
5208 if (null != component)
5209 {
5210 component.AddChild(copyFile);
5211 }
5212 else
5213 {
5214 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[1]), "Component"));
5215 }
5216 this.core.IndexElement(row, copyFile);
5217 }
5218 }
5219
5220 /// <summary>
5221 /// Decompile the Environment table.
5222 /// </summary>
5223 /// <param name="table">The table to decompile.</param>
5224 private void DecompileEnvironmentTable(Table table)
5225 {
5226 foreach (var row in table.Rows)
5227 {
5228 var environment = new Wix.Environment();
5229
5230 environment.Id = Convert.ToString(row[0]);
5231
5232 var done = false;
5233 var permanent = true;
5234 var name = Convert.ToString(row[1]);
5235 for (var i = 0; i < name.Length && !done; i++)
5236 {
5237 switch (name[i])
5238 {
5239 case '=':
5240 environment.Action = Wix.Environment.ActionType.set;
5241 break;
5242 case '+':
5243 environment.Action = Wix.Environment.ActionType.create;
5244 break;
5245 case '-':
5246 permanent = false;
5247 break;
5248 case '!':
5249 environment.Action = Wix.Environment.ActionType.remove;
5250 break;
5251 case '*':
5252 environment.System = Wix.YesNoType.yes;
5253 break;
5254 default:
5255 environment.Name = name.Substring(i);
5256 done = true;
5257 break;
5258 }
5259 }
5260
5261 if (permanent)
5262 {
5263 environment.Permanent = Wix.YesNoType.yes;
5264 }
5265
5266 if (null != row[2])
5267 {
5268 var value = Convert.ToString(row[2]);
5269
5270 if (value.StartsWith("[~]", StringComparison.Ordinal))
5271 {
5272 environment.Part = Wix.Environment.PartType.last;
5273
5274 if (3 < value.Length)
5275 {
5276 environment.Separator = value.Substring(3, 1);
5277 environment.Value = value.Substring(4);
5278 }
5279 }
5280 else if (value.EndsWith("[~]", StringComparison.Ordinal))
5281 {
5282 environment.Part = Wix.Environment.PartType.first;
5283
5284 if (3 < value.Length)
5285 {
5286 environment.Separator = value.Substring(value.Length - 4, 1);
5287 environment.Value = value.Substring(0, value.Length - 4);
5288 }
5289 }
5290 else
5291 {
5292 environment.Value = value;
5293 }
5294 }
5295
5296 var component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[3]));
5297 if (null != component)
5298 {
5299 component.AddChild(environment);
5300 }
5301 else
5302 {
5303 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[3]), "Component"));
5304 }
5305 }
5306 }
5307
5308 /// <summary>
5309 /// Decompile the Error table.
5310 /// </summary>
5311 /// <param name="table">The table to decompile.</param>
5312 private void DecompileErrorTable(Table table)
5313 {
5314 foreach (var row in table.Rows)
5315 {
5316 var error = new Wix.Error();
5317
5318 error.Id = Convert.ToInt32(row[0]);
5319
5320 error.Content = Convert.ToString(row[1]);
5321
5322 this.core.UIElement.AddChild(error);
5323 }
5324 }
5325
5326 /// <summary>
5327 /// Decompile the EventMapping table.
5328 /// </summary>
5329 /// <param name="table">The table to decompile.</param>
5330 private void DecompileEventMappingTable(Table table)
5331 {
5332 foreach (var row in table.Rows)
5333 {
5334 var subscribe = new Wix.Subscribe();
5335
5336 subscribe.Event = Convert.ToString(row[2]);
5337
5338 subscribe.Attribute = Convert.ToString(row[3]);
5339
5340 var control = (Wix.Control)this.core.GetIndexedElement("Control", Convert.ToString(row[0]), Convert.ToString(row[1]));
5341 if (null != control)
5342 {
5343 control.AddChild(subscribe);
5344 }
5345 else
5346 {
5347 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Dialog_", Convert.ToString(row[0]), "Control_", Convert.ToString(row[1]), "Control"));
5348 }
5349 }
5350 }
5351
5352 /// <summary>
5353 /// Decompile the Extension table.
5354 /// </summary>
5355 /// <param name="table">The table to decompile.</param>
5356 private void DecompileExtensionTable(Table table)
5357 {
5358 foreach (var row in table.Rows)
5359 {
5360 var extension = new Wix.Extension();
5361
5362 extension.Advertise = Wix.YesNoType.yes;
5363
5364 extension.Id = Convert.ToString(row[0]);
5365
5366 if (null != row[3])
5367 {
5368 var mime = (Wix.MIME)this.core.GetIndexedElement("MIME", Convert.ToString(row[3]));
5369
5370 if (null != mime)
5371 {
5372 mime.Default = Wix.YesNoType.yes;
5373 }
5374 else
5375 {
5376 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "MIME_", Convert.ToString(row[3]), "MIME"));
5377 }
5378 }
5379
5380 if (null != row[2])
5381 {
5382 var progId = (Wix.ProgId)this.core.GetIndexedElement("ProgId", Convert.ToString(row[2]));
5383
5384 if (null != progId)
5385 {
5386 progId.AddChild(extension);
5387 }
5388 else
5389 {
5390 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "ProgId_", Convert.ToString(row[2]), "ProgId"));
5391 }
5392 }
5393 else
5394 {
5395 var component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[1]));
5396
5397 if (null != component)
5398 {
5399 component.AddChild(extension);
5400 }
5401 else
5402 {
5403 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[1]), "Component"));
5404 }
5405 }
5406
5407 this.core.IndexElement(row, extension);
5408 }
5409 }
5410
5411 /// <summary>
5412 /// Decompile the ExternalFiles table.
5413 /// </summary>
5414 /// <param name="table">The table to decompile.</param>
5415 private void DecompileExternalFilesTable(Table table)
5416 {
5417 foreach (var row in table.Rows)
5418 {
5419 var externalFile = new Wix.ExternalFile();
5420
5421 externalFile.File = Convert.ToString(row[1]);
5422
5423 externalFile.Source = Convert.ToString(row[2]);
5424
5425 if (null != row[3])
5426 {
5427 var symbolPaths = (Convert.ToString(row[3])).Split(';');
5428
5429 foreach (var symbolPathString in symbolPaths)
5430 {
5431 var symbolPath = new Wix.SymbolPath();
5432
5433 symbolPath.Path = symbolPathString;
5434
5435 externalFile.AddChild(symbolPath);
5436 }
5437 }
5438
5439 if (null != row[4] && null != row[5])
5440 {
5441 var ignoreOffsets = (Convert.ToString(row[4])).Split(',');
5442 var ignoreLengths = (Convert.ToString(row[5])).Split(',');
5443
5444 if (ignoreOffsets.Length == ignoreLengths.Length)
5445 {
5446 for (var i = 0; i < ignoreOffsets.Length; i++)
5447 {
5448 var ignoreRange = new Wix.IgnoreRange();
5449
5450 if (ignoreOffsets[i].StartsWith("0x", StringComparison.Ordinal))
5451 {
5452 ignoreRange.Offset = Convert.ToInt32(ignoreOffsets[i].Substring(2), 16);
5453 }
5454 else
5455 {
5456 ignoreRange.Offset = Convert.ToInt32(ignoreOffsets[i], CultureInfo.InvariantCulture);
5457 }
5458
5459 if (ignoreLengths[i].StartsWith("0x", StringComparison.Ordinal))
5460 {
5461 ignoreRange.Length = Convert.ToInt32(ignoreLengths[i].Substring(2), 16);
5462 }
5463 else
5464 {
5465 ignoreRange.Length = Convert.ToInt32(ignoreLengths[i], CultureInfo.InvariantCulture);
5466 }
5467
5468 externalFile.AddChild(ignoreRange);
5469 }
5470 }
5471 else
5472 {
5473 // TODO: warn
5474 }
5475 }
5476 else if (null != row[4] || null != row[5])
5477 {
5478 // TODO: warn about mismatch between columns
5479 }
5480
5481 // the RetainOffsets column is handled in FinalizeFamilyFileRangesTable
5482
5483 if (null != row[7])
5484 {
5485 externalFile.Order = Convert.ToInt32(row[7]);
5486 }
5487
5488 var family = (Wix.Family)this.core.GetIndexedElement("ImageFamilies", Convert.ToString(row[0]));
5489 if (null != family)
5490 {
5491 family.AddChild(externalFile);
5492 }
5493 else
5494 {
5495 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Family", Convert.ToString(row[0]), "ImageFamilies"));
5496 }
5497 this.core.IndexElement(row, externalFile);
5498 }
5499 }
5500
5501 /// <summary>
5502 /// Decompile the Feature table.
5503 /// </summary>
5504 /// <param name="table">The table to decompile.</param>
5505 private void DecompileFeatureTable(Table table)
5506 {
5507 var sortedFeatures = new SortedList();
5508
5509 foreach (var row in table.Rows)
5510 {
5511 var feature = new Wix.Feature();
5512
5513 feature.Id = Convert.ToString(row[0]);
5514
5515 if (null != row[2])
5516 {
5517 feature.Title = Convert.ToString(row[2]);
5518 }
5519
5520 if (null != row[3])
5521 {
5522 feature.Description = Convert.ToString(row[3]);
5523 }
5524
5525 if (null == row[4])
5526 {
5527 feature.Display = "hidden";
5528 }
5529 else
5530 {
5531 var display = Convert.ToInt32(row[4]);
5532
5533 if (0 == display)
5534 {
5535 feature.Display = "hidden";
5536 }
5537 else if (1 == display % 2)
5538 {
5539 feature.Display = "expand";
5540 }
5541 }
5542
5543 feature.Level = Convert.ToInt32(row[5]);
5544
5545 if (null != row[6])
5546 {
5547 feature.ConfigurableDirectory = Convert.ToString(row[6]);
5548 }
5549
5550 var attributes = Convert.ToInt32(row[7]);
5551
5552 if (MsiInterop.MsidbFeatureAttributesFavorSource == (attributes & MsiInterop.MsidbFeatureAttributesFavorSource) && MsiInterop.MsidbFeatureAttributesFollowParent == (attributes & MsiInterop.MsidbFeatureAttributesFollowParent))
5553 {
5554 // TODO: display a warning for setting favor local and follow parent together
5555 }
5556 else if (MsiInterop.MsidbFeatureAttributesFavorSource == (attributes & MsiInterop.MsidbFeatureAttributesFavorSource))
5557 {
5558 feature.InstallDefault = Wix.Feature.InstallDefaultType.source;
5559 }
5560 else if (MsiInterop.MsidbFeatureAttributesFollowParent == (attributes & MsiInterop.MsidbFeatureAttributesFollowParent))
5561 {
5562 feature.InstallDefault = Wix.Feature.InstallDefaultType.followParent;
5563 }
5564
5565 if (MsiInterop.MsidbFeatureAttributesFavorAdvertise == (attributes & MsiInterop.MsidbFeatureAttributesFavorAdvertise))
5566 {
5567 feature.TypicalDefault = Wix.Feature.TypicalDefaultType.advertise;
5568 }
5569
5570 if (MsiInterop.MsidbFeatureAttributesDisallowAdvertise == (attributes & MsiInterop.MsidbFeatureAttributesDisallowAdvertise) &&
5571 MsiInterop.MsidbFeatureAttributesNoUnsupportedAdvertise == (attributes & MsiInterop.MsidbFeatureAttributesNoUnsupportedAdvertise))
5572 {
5573 this.Messaging.Write(WarningMessages.InvalidAttributeCombination(row.SourceLineNumbers, "msidbFeatureAttributesDisallowAdvertise", "msidbFeatureAttributesNoUnsupportedAdvertise", "Feature.AllowAdvertiseType", "no"));
5574 feature.AllowAdvertise = Wix.Feature.AllowAdvertiseType.no;
5575 }
5576 else if (MsiInterop.MsidbFeatureAttributesDisallowAdvertise == (attributes & MsiInterop.MsidbFeatureAttributesDisallowAdvertise))
5577 {
5578 feature.AllowAdvertise = Wix.Feature.AllowAdvertiseType.no;
5579 }
5580 else if (MsiInterop.MsidbFeatureAttributesNoUnsupportedAdvertise == (attributes & MsiInterop.MsidbFeatureAttributesNoUnsupportedAdvertise))
5581 {
5582 feature.AllowAdvertise = Wix.Feature.AllowAdvertiseType.system;
5583 }
5584
5585 if (MsiInterop.MsidbFeatureAttributesUIDisallowAbsent == (attributes & MsiInterop.MsidbFeatureAttributesUIDisallowAbsent))
5586 {
5587 feature.Absent = Wix.Feature.AbsentType.disallow;
5588 }
5589
5590 this.core.IndexElement(row, feature);
5591
5592 // sort the features by their display column (and append the identifier to ensure unique keys)
5593 sortedFeatures.Add(String.Format(CultureInfo.InvariantCulture, "{0:00000}|{1}", Convert.ToInt32(row[4], CultureInfo.InvariantCulture), row[0]), row);
5594 }
5595
5596 // nest the features
5597 foreach (Row row in sortedFeatures.Values)
5598 {
5599 var feature = (Wix.Feature)this.core.GetIndexedElement("Feature", Convert.ToString(row[0]));
5600
5601 if (null == row[1])
5602 {
5603 this.core.RootElement.AddChild(feature);
5604 }
5605 else
5606 {
5607 var parentFeature = (Wix.Feature)this.core.GetIndexedElement("Feature", Convert.ToString(row[1]));
5608
5609 if (null == parentFeature)
5610 {
5611 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Feature_Parent", Convert.ToString(row[1]), "Feature"));
5612 }
5613 else if (parentFeature == feature)
5614 {
5615 // TODO: display a warning about self-nesting
5616 }
5617 else
5618 {
5619 parentFeature.AddChild(feature);
5620 }
5621 }
5622 }
5623 }
5624
5625 /// <summary>
5626 /// Decompile the FeatureComponents table.
5627 /// </summary>
5628 /// <param name="table">The table to decompile.</param>
5629 private void DecompileFeatureComponentsTable(Table table)
5630 {
5631 foreach (var row in table.Rows)
5632 {
5633 var componentRef = new Wix.ComponentRef();
5634
5635 componentRef.Id = Convert.ToString(row[1]);
5636
5637 var parentFeature = (Wix.Feature)this.core.GetIndexedElement("Feature", Convert.ToString(row[0]));
5638 if (null != parentFeature)
5639 {
5640 parentFeature.AddChild(componentRef);
5641 }
5642 else
5643 {
5644 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Feature_", Convert.ToString(row[0]), "Feature"));
5645 }
5646 this.core.IndexElement(row, componentRef);
5647 }
5648 }
5649
5650 /// <summary>
5651 /// Decompile the File table.
5652 /// </summary>
5653 /// <param name="table">The table to decompile.</param>
5654 private void DecompileFileTable(Table table)
5655 {
5656 foreach (FileRow fileRow in table.Rows)
5657 {
5658 var file = new Wix.File();
5659
5660 file.Id = fileRow.File;
5661
5662 var names = Common.GetNames(fileRow.FileName);
5663 if (null != names[0] && null != names[1])
5664 {
5665 file.ShortName = names[0];
5666 file.Name = names[1];
5667 }
5668 else if (null != names[0])
5669 {
5670 file.Name = names[0];
5671 }
5672
5673 if (null != fileRow.Version && 0 < fileRow.Version.Length)
5674 {
5675 if (!Char.IsDigit(fileRow.Version[0]))
5676 {
5677 file.CompanionFile = fileRow.Version;
5678 }
5679 }
5680
5681 if (MsiInterop.MsidbFileAttributesReadOnly == (fileRow.Attributes & MsiInterop.MsidbFileAttributesReadOnly))
5682 {
5683 file.ReadOnly = Wix.YesNoType.yes;
5684 }
5685
5686 if (MsiInterop.MsidbFileAttributesHidden == (fileRow.Attributes & MsiInterop.MsidbFileAttributesHidden))
5687 {
5688 file.Hidden = Wix.YesNoType.yes;
5689 }
5690
5691 if (MsiInterop.MsidbFileAttributesSystem == (fileRow.Attributes & MsiInterop.MsidbFileAttributesSystem))
5692 {
5693 file.System = Wix.YesNoType.yes;
5694 }
5695
5696 if (MsiInterop.MsidbFileAttributesVital != (fileRow.Attributes & MsiInterop.MsidbFileAttributesVital))
5697 {
5698 file.Vital = Wix.YesNoType.no;
5699 }
5700
5701 if (MsiInterop.MsidbFileAttributesChecksum == (fileRow.Attributes & MsiInterop.MsidbFileAttributesChecksum))
5702 {
5703 file.Checksum = Wix.YesNoType.yes;
5704 }
5705
5706 if (MsiInterop.MsidbFileAttributesNoncompressed == (fileRow.Attributes & MsiInterop.MsidbFileAttributesNoncompressed) &&
5707 MsiInterop.MsidbFileAttributesCompressed == (fileRow.Attributes & MsiInterop.MsidbFileAttributesCompressed))
5708 {
5709 // TODO: error
5710 }
5711 else if (MsiInterop.MsidbFileAttributesNoncompressed == (fileRow.Attributes & MsiInterop.MsidbFileAttributesNoncompressed))
5712 {
5713 file.Compressed = Wix.YesNoDefaultType.no;
5714 }
5715 else if (MsiInterop.MsidbFileAttributesCompressed == (fileRow.Attributes & MsiInterop.MsidbFileAttributesCompressed))
5716 {
5717 file.Compressed = Wix.YesNoDefaultType.yes;
5718 }
5719
5720 this.core.IndexElement(fileRow, file);
5721 }
5722 }
5723
5724 /// <summary>
5725 /// Decompile the FileSFPCatalog table.
5726 /// </summary>
5727 /// <param name="table">The table to decompile.</param>
5728 private void DecompileFileSFPCatalogTable(Table table)
5729 {
5730 foreach (var row in table.Rows)
5731 {
5732 var sfpFile = new Wix.SFPFile();
5733
5734 sfpFile.Id = Convert.ToString(row[0]);
5735
5736 var sfpCatalog = (Wix.SFPCatalog)this.core.GetIndexedElement("SFPCatalog", Convert.ToString(row[1]));
5737 if (null != sfpCatalog)
5738 {
5739 sfpCatalog.AddChild(sfpFile);
5740 }
5741 else
5742 {
5743 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "SFPCatalog_", Convert.ToString(row[1]), "SFPCatalog"));
5744 }
5745 }
5746 }
5747
5748 /// <summary>
5749 /// Decompile the Font table.
5750 /// </summary>
5751 /// <param name="table">The table to decompile.</param>
5752 private void DecompileFontTable(Table table)
5753 {
5754 foreach (var row in table.Rows)
5755 {
5756 var file = (Wix.File)this.core.GetIndexedElement("File", Convert.ToString(row[0]));
5757
5758 if (null != file)
5759 {
5760 if (null != row[1])
5761 {
5762 file.FontTitle = Convert.ToString(row[1]);
5763 }
5764 else
5765 {
5766 file.TrueType = Wix.YesNoType.yes;
5767 }
5768 }
5769 else
5770 {
5771 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "File_", Convert.ToString(row[0]), "File"));
5772 }
5773 }
5774 }
5775
5776 /// <summary>
5777 /// Decompile the Icon table.
5778 /// </summary>
5779 /// <param name="table">The table to decompile.</param>
5780 private void DecompileIconTable(Table table)
5781 {
5782 foreach (var row in table.Rows)
5783 {
5784 var icon = new Wix.Icon();
5785
5786 icon.Id = Convert.ToString(row[0]);
5787
5788 icon.SourceFile = Convert.ToString(row[1]);
5789
5790 this.core.RootElement.AddChild(icon);
5791 }
5792 }
5793
5794 /// <summary>
5795 /// Decompile the ImageFamilies table.
5796 /// </summary>
5797 /// <param name="table">The table to decompile.</param>
5798 private void DecompileImageFamiliesTable(Table table)
5799 {
5800 foreach (var row in table.Rows)
5801 {
5802 var family = new Wix.Family();
5803
5804 family.Name = Convert.ToString(row[0]);
5805
5806 if (null != row[1])
5807 {
5808 family.MediaSrcProp = Convert.ToString(row[1]);
5809 }
5810
5811 if (null != row[2])
5812 {
5813 family.DiskId = Convert.ToString(Convert.ToInt32(row[2]));
5814 }
5815
5816 if (null != row[3])
5817 {
5818 family.SequenceStart = Convert.ToInt32(row[3]);
5819 }
5820
5821 if (null != row[4])
5822 {
5823 family.DiskPrompt = Convert.ToString(row[4]);
5824 }
5825
5826 if (null != row[5])
5827 {
5828 family.VolumeLabel = Convert.ToString(row[5]);
5829 }
5830
5831 this.core.RootElement.AddChild(family);
5832 this.core.IndexElement(row, family);
5833 }
5834 }
5835
5836 /// <summary>
5837 /// Decompile the IniFile table.
5838 /// </summary>
5839 /// <param name="table">The table to decompile.</param>
5840 private void DecompileIniFileTable(Table table)
5841 {
5842 foreach (var row in table.Rows)
5843 {
5844 var iniFile = new Wix.IniFile();
5845
5846 iniFile.Id = Convert.ToString(row[0]);
5847
5848 var names = Common.GetNames(Convert.ToString(row[1]));
5849
5850 if (null != names[0])
5851 {
5852 if (null == names[1])
5853 {
5854 iniFile.Name = names[0];
5855 }
5856 else
5857 {
5858 iniFile.ShortName = names[0];
5859 }
5860 }
5861
5862 if (null != names[1])
5863 {
5864 iniFile.Name = names[1];
5865 }
5866
5867 if (null != row[2])
5868 {
5869 iniFile.Directory = Convert.ToString(row[2]);
5870 }
5871
5872 iniFile.Section = Convert.ToString(row[3]);
5873
5874 iniFile.Key = Convert.ToString(row[4]);
5875
5876 iniFile.Value = Convert.ToString(row[5]);
5877
5878 switch (Convert.ToInt32(row[6]))
5879 {
5880 case MsiInterop.MsidbIniFileActionAddLine:
5881 iniFile.Action = Wix.IniFile.ActionType.addLine;
5882 break;
5883 case MsiInterop.MsidbIniFileActionCreateLine:
5884 iniFile.Action = Wix.IniFile.ActionType.createLine;
5885 break;
5886 case MsiInterop.MsidbIniFileActionAddTag:
5887 iniFile.Action = Wix.IniFile.ActionType.addTag;
5888 break;
5889 default:
5890 this.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[6].Column.Name, row[6]));
5891 break;
5892 }
5893
5894 var component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[7]));
5895 if (null != component)
5896 {
5897 component.AddChild(iniFile);
5898 }
5899 else
5900 {
5901 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[7]), "Component"));
5902 }
5903 }
5904 }
5905
5906 /// <summary>
5907 /// Decompile the IniLocator table.
5908 /// </summary>
5909 /// <param name="table">The table to decompile.</param>
5910 private void DecompileIniLocatorTable(Table table)
5911 {
5912 foreach (var row in table.Rows)
5913 {
5914 var iniFileSearch = new Wix.IniFileSearch();
5915
5916 iniFileSearch.Id = Convert.ToString(row[0]);
5917
5918 var names = Common.GetNames(Convert.ToString(row[1]));
5919 if (null != names[0] && null != names[1])
5920 {
5921 iniFileSearch.ShortName = names[0];
5922 iniFileSearch.Name = names[1];
5923 }
5924 else if (null != names[0])
5925 {
5926 iniFileSearch.Name = names[0];
5927 }
5928
5929 iniFileSearch.Section = Convert.ToString(row[2]);
5930
5931 iniFileSearch.Key = Convert.ToString(row[3]);
5932
5933 if (null != row[4])
5934 {
5935 var field = Convert.ToInt32(row[4]);
5936
5937 if (0 != field)
5938 {
5939 iniFileSearch.Field = field;
5940 }
5941 }
5942
5943 if (null != row[5])
5944 {
5945 switch (Convert.ToInt32(row[5]))
5946 {
5947 case MsiInterop.MsidbLocatorTypeDirectory:
5948 iniFileSearch.Type = Wix.IniFileSearch.TypeType.directory;
5949 break;
5950 case MsiInterop.MsidbLocatorTypeFileName:
5951 // this is the default value
5952 break;
5953 case MsiInterop.MsidbLocatorTypeRawValue:
5954 iniFileSearch.Type = Wix.IniFileSearch.TypeType.raw;
5955 break;
5956 default:
5957 this.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[5].Column.Name, row[5]));
5958 break;
5959 }
5960 }
5961
5962 this.core.IndexElement(row, iniFileSearch);
5963 }
5964 }
5965
5966 /// <summary>
5967 /// Decompile the IsolatedComponent table.
5968 /// </summary>
5969 /// <param name="table">The table to decompile.</param>
5970 private void DecompileIsolatedComponentTable(Table table)
5971 {
5972 foreach (var row in table.Rows)
5973 {
5974 var isolateComponent = new Wix.IsolateComponent();
5975
5976 isolateComponent.Shared = Convert.ToString(row[0]);
5977
5978 var component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[1]));
5979 if (null != component)
5980 {
5981 component.AddChild(isolateComponent);
5982 }
5983 else
5984 {
5985 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[1]), "Component"));
5986 }
5987 }
5988 }
5989
5990 /// <summary>
5991 /// Decompile the LaunchCondition table.
5992 /// </summary>
5993 /// <param name="table">The table to decompile.</param>
5994 private void DecompileLaunchConditionTable(Table table)
5995 {
5996 foreach (var row in table.Rows)
5997 {
5998 if (Common.DowngradePreventedCondition == Convert.ToString(row[0]) || Common.UpgradePreventedCondition == Convert.ToString(row[0]))
5999 {
6000 continue; // MajorUpgrade rows processed in FinalizeUpgradeTable
6001 }
6002
6003 var condition = new Wix.Condition();
6004
6005 condition.Content = Convert.ToString(row[0]);
6006
6007 condition.Message = Convert.ToString(row[1]);
6008
6009 this.core.RootElement.AddChild(condition);
6010 }
6011 }
6012
6013 /// <summary>
6014 /// Decompile the ListBox table.
6015 /// </summary>
6016 /// <param name="table">The table to decompile.</param>
6017 private void DecompileListBoxTable(Table table)
6018 {
6019 Wix.ListBox listBox = null;
6020 var listBoxRows = new SortedList();
6021
6022 // sort the list boxes by their property and order
6023 foreach (var row in table.Rows)
6024 {
6025 listBoxRows.Add(String.Concat("{0}|{1:0000000000}", row[0], row[1]), row);
6026 }
6027
6028 foreach (Row row in listBoxRows.Values)
6029 {
6030 if (null == listBox || Convert.ToString(row[0]) != listBox.Property)
6031 {
6032 listBox = new Wix.ListBox();
6033
6034 listBox.Property = Convert.ToString(row[0]);
6035
6036 this.core.UIElement.AddChild(listBox);
6037 }
6038
6039 var listItem = new Wix.ListItem();
6040
6041 listItem.Value = Convert.ToString(row[2]);
6042
6043 if (null != row[3])
6044 {
6045 listItem.Text = Convert.ToString(row[3]);
6046 }
6047
6048 listBox.AddChild(listItem);
6049 }
6050 }
6051
6052 /// <summary>
6053 /// Decompile the ListView table.
6054 /// </summary>
6055 /// <param name="table">The table to decompile.</param>
6056 private void DecompileListViewTable(Table table)
6057 {
6058 Wix.ListView listView = null;
6059 var listViewRows = new SortedList();
6060
6061 // sort the list views by their property and order
6062 foreach (var row in table.Rows)
6063 {
6064 listViewRows.Add(String.Concat("{0}|{1:0000000000}", row[0], row[1]), row);
6065 }
6066
6067 foreach (Row row in listViewRows.Values)
6068 {
6069 if (null == listView || Convert.ToString(row[0]) != listView.Property)
6070 {
6071 listView = new Wix.ListView();
6072
6073 listView.Property = Convert.ToString(row[0]);
6074
6075 this.core.UIElement.AddChild(listView);
6076 }
6077
6078 var listItem = new Wix.ListItem();
6079
6080 listItem.Value = Convert.ToString(row[2]);
6081
6082 if (null != row[3])
6083 {
6084 listItem.Text = Convert.ToString(row[3]);
6085 }
6086
6087 if (null != row[4])
6088 {
6089 listItem.Icon = Convert.ToString(row[4]);
6090 }
6091
6092 listView.AddChild(listItem);
6093 }
6094 }
6095
6096 /// <summary>
6097 /// Decompile the LockPermissions table.
6098 /// </summary>
6099 /// <param name="table">The table to decompile.</param>
6100 private void DecompileLockPermissionsTable(Table table)
6101 {
6102 foreach (var row in table.Rows)
6103 {
6104 var permission = new Wix.Permission();
6105 string[] specialPermissions;
6106
6107 switch (Convert.ToString(row[1]))
6108 {
6109 case "CreateFolder":
6110 specialPermissions = Common.FolderPermissions;
6111 break;
6112 case "File":
6113 specialPermissions = Common.FilePermissions;
6114 break;
6115 case "Registry":
6116 specialPermissions = Common.RegistryPermissions;
6117 break;
6118 default:
6119 this.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, row.Table.Name, row.Fields[1].Column.Name, row[1]));
6120 return;
6121 }
6122
6123 var permissionBits = Convert.ToInt32(row[4]);
6124 for (var i = 0; i < 32; i++)
6125 {
6126 if (0 != ((permissionBits >> i) & 1))
6127 {
6128 string name = null;
6129
6130 if (specialPermissions.Length > i)
6131 {
6132 name = specialPermissions[i];
6133 }
6134 else if (16 > i && specialPermissions.Length <= i)
6135 {
6136 name = "SpecificRightsAll";
6137 }
6138 else if (28 > i && Common.StandardPermissions.Length > (i - 16))
6139 {
6140 name = Common.StandardPermissions[i - 16];
6141 }
6142 else if (0 <= (i - 28) && Common.GenericPermissions.Length > (i - 28))
6143 {
6144 name = Common.GenericPermissions[i - 28];
6145 }
6146
6147 if (null == name)
6148 {
6149 this.Messaging.Write(WarningMessages.UnknownPermission(row.SourceLineNumbers, row.Table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), i));
6150 }
6151 else
6152 {
6153 switch (name)
6154 {
6155 case "Append":
6156 permission.Append = Wix.YesNoType.yes;
6157 break;
6158 case "ChangePermission":
6159 permission.ChangePermission = Wix.YesNoType.yes;
6160 break;
6161 case "CreateChild":
6162 permission.CreateChild = Wix.YesNoType.yes;
6163 break;
6164 case "CreateFile":
6165 permission.CreateFile = Wix.YesNoType.yes;
6166 break;
6167 case "CreateLink":
6168 permission.CreateLink = Wix.YesNoType.yes;
6169 break;
6170 case "CreateSubkeys":
6171 permission.CreateSubkeys = Wix.YesNoType.yes;
6172 break;
6173 case "Delete":
6174 permission.Delete = Wix.YesNoType.yes;
6175 break;
6176 case "DeleteChild":
6177 permission.DeleteChild = Wix.YesNoType.yes;
6178 break;
6179 case "EnumerateSubkeys":
6180 permission.EnumerateSubkeys = Wix.YesNoType.yes;
6181 break;
6182 case "Execute":
6183 permission.Execute = Wix.YesNoType.yes;
6184 break;
6185 case "FileAllRights":
6186 permission.FileAllRights = Wix.YesNoType.yes;
6187 break;
6188 case "GenericAll":
6189 permission.GenericAll = Wix.YesNoType.yes;
6190 break;
6191 case "GenericExecute":
6192 permission.GenericExecute = Wix.YesNoType.yes;
6193 break;
6194 case "GenericRead":
6195 permission.GenericRead = Wix.YesNoType.yes;
6196 break;
6197 case "GenericWrite":
6198 permission.GenericWrite = Wix.YesNoType.yes;
6199 break;
6200 case "Notify":
6201 permission.Notify = Wix.YesNoType.yes;
6202 break;
6203 case "Read":
6204 permission.Read = Wix.YesNoType.yes;
6205 break;
6206 case "ReadAttributes":
6207 permission.ReadAttributes = Wix.YesNoType.yes;
6208 break;
6209 case "ReadExtendedAttributes":
6210 permission.ReadExtendedAttributes = Wix.YesNoType.yes;
6211 break;
6212 case "ReadPermission":
6213 permission.ReadPermission = Wix.YesNoType.yes;
6214 break;
6215 case "SpecificRightsAll":
6216 permission.SpecificRightsAll = Wix.YesNoType.yes;
6217 break;
6218 case "Synchronize":
6219 permission.Synchronize = Wix.YesNoType.yes;
6220 break;
6221 case "TakeOwnership":
6222 permission.TakeOwnership = Wix.YesNoType.yes;
6223 break;
6224 case "Traverse":
6225 permission.Traverse = Wix.YesNoType.yes;
6226 break;
6227 case "Write":
6228 permission.Write = Wix.YesNoType.yes;
6229 break;
6230 case "WriteAttributes":
6231 permission.WriteAttributes = Wix.YesNoType.yes;
6232 break;
6233 case "WriteExtendedAttributes":
6234 permission.WriteExtendedAttributes = Wix.YesNoType.yes;
6235 break;
6236 default:
6237 throw new InvalidOperationException($"Unknown permission attribute '{name}'.");
6238 }
6239 }
6240 }
6241 }
6242
6243 if (null != row[2])
6244 {
6245 permission.Domain = Convert.ToString(row[2]);
6246 }
6247
6248 permission.User = Convert.ToString(row[3]);
6249
6250 this.core.IndexElement(row, permission);
6251 }
6252 }
6253
6254 /// <summary>
6255 /// Decompile the Media table.
6256 /// </summary>
6257 /// <param name="table">The table to decompile.</param>
6258 private void DecompileMediaTable(Table table)
6259 {
6260 foreach (MediaRow mediaRow in table.Rows)
6261 {
6262 var media = new Wix.Media();
6263
6264 media.Id = Convert.ToString(mediaRow.DiskId);
6265
6266 if (null != mediaRow.DiskPrompt)
6267 {
6268 media.DiskPrompt = mediaRow.DiskPrompt;
6269 }
6270
6271 if (null != mediaRow.Cabinet)
6272 {
6273 var cabinet = mediaRow.Cabinet;
6274
6275 if (cabinet.StartsWith("#", StringComparison.Ordinal))
6276 {
6277 media.EmbedCab = Wix.YesNoType.yes;
6278 cabinet = cabinet.Substring(1);
6279 }
6280
6281 media.Cabinet = cabinet;
6282 }
6283
6284 if (null != mediaRow.VolumeLabel)
6285 {
6286 media.VolumeLabel = mediaRow.VolumeLabel;
6287 }
6288
6289 this.core.RootElement.AddChild(media);
6290 this.core.IndexElement(mediaRow, media);
6291 }
6292 }
6293
6294 /// <summary>
6295 /// Decompile the MIME table.
6296 /// </summary>
6297 /// <param name="table">The table to decompile.</param>
6298 private void DecompileMIMETable(Table table)
6299 {
6300 foreach (var row in table.Rows)
6301 {
6302 var mime = new Wix.MIME();
6303
6304 mime.ContentType = Convert.ToString(row[0]);
6305
6306 if (null != row[2])
6307 {
6308 mime.Class = Convert.ToString(row[2]);
6309 }
6310
6311 this.core.IndexElement(row, mime);
6312 }
6313 }
6314
6315 /// <summary>
6316 /// Decompile the ModuleConfiguration table.
6317 /// </summary>
6318 /// <param name="table">The table to decompile.</param>
6319 private void DecompileModuleConfigurationTable(Table table)
6320 {
6321 foreach (var row in table.Rows)
6322 {
6323 var configuration = new Wix.Configuration();
6324
6325 configuration.Name = Convert.ToString(row[0]);
6326
6327 switch (Convert.ToInt32(row[1]))
6328 {
6329 case 0:
6330 configuration.Format = Wix.Configuration.FormatType.Text;
6331 break;
6332 case 1:
6333 configuration.Format = Wix.Configuration.FormatType.Key;
6334 break;
6335 case 2:
6336 configuration.Format = Wix.Configuration.FormatType.Integer;
6337 break;
6338 case 3:
6339 configuration.Format = Wix.Configuration.FormatType.Bitfield;
6340 break;
6341 default:
6342 this.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[1].Column.Name, row[1]));
6343 break;
6344 }
6345
6346 if (null != row[2])
6347 {
6348 configuration.Type = Convert.ToString(row[2]);
6349 }
6350
6351 if (null != row[3])
6352 {
6353 configuration.ContextData = Convert.ToString(row[3]);
6354 }
6355
6356 if (null != row[4])
6357 {
6358 configuration.DefaultValue = Convert.ToString(row[4]);
6359 }
6360
6361 if (null != row[5])
6362 {
6363 var attributes = Convert.ToInt32(row[5]);
6364
6365 if (MsiInterop.MsidbMsmConfigurableOptionKeyNoOrphan == (attributes & MsiInterop.MsidbMsmConfigurableOptionKeyNoOrphan))
6366 {
6367 configuration.KeyNoOrphan = Wix.YesNoType.yes;
6368 }
6369
6370 if (MsiInterop.MsidbMsmConfigurableOptionNonNullable == (attributes & MsiInterop.MsidbMsmConfigurableOptionNonNullable))
6371 {
6372 configuration.NonNullable = Wix.YesNoType.yes;
6373 }
6374
6375 if (3 < attributes)
6376 {
6377 this.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[5].Column.Name, row[5]));
6378 }
6379 }
6380
6381 if (null != row[6])
6382 {
6383 configuration.DisplayName = Convert.ToString(row[6]);
6384 }
6385
6386 if (null != row[7])
6387 {
6388 configuration.Description = Convert.ToString(row[7]);
6389 }
6390
6391 if (null != row[8])
6392 {
6393 configuration.HelpLocation = Convert.ToString(row[8]);
6394 }
6395
6396 if (null != row[9])
6397 {
6398 configuration.HelpKeyword = Convert.ToString(row[9]);
6399 }
6400
6401 this.core.RootElement.AddChild(configuration);
6402 }
6403 }
6404
6405 /// <summary>
6406 /// Decompile the ModuleDependency table.
6407 /// </summary>
6408 /// <param name="table">The table to decompile.</param>
6409 private void DecompileModuleDependencyTable(Table table)
6410 {
6411 foreach (var row in table.Rows)
6412 {
6413 var dependency = new Wix.Dependency();
6414
6415 dependency.RequiredId = Convert.ToString(row[2]);
6416
6417 dependency.RequiredLanguage = Convert.ToInt32(row[3], CultureInfo.InvariantCulture);
6418
6419 if (null != row[4])
6420 {
6421 dependency.RequiredVersion = Convert.ToString(row[4]);
6422 }
6423
6424 this.core.RootElement.AddChild(dependency);
6425 }
6426 }
6427
6428 /// <summary>
6429 /// Decompile the ModuleExclusion table.
6430 /// </summary>
6431 /// <param name="table">The table to decompile.</param>
6432 private void DecompileModuleExclusionTable(Table table)
6433 {
6434 foreach (var row in table.Rows)
6435 {
6436 var exclusion = new Wix.Exclusion();
6437
6438 exclusion.ExcludedId = Convert.ToString(row[2]);
6439
6440 var excludedLanguage = Convert.ToInt32(Convert.ToString(row[3]), CultureInfo.InvariantCulture);
6441 if (0 < excludedLanguage)
6442 {
6443 exclusion.ExcludeLanguage = excludedLanguage;
6444 }
6445 else if (0 > excludedLanguage)
6446 {
6447 exclusion.ExcludeExceptLanguage = -excludedLanguage;
6448 }
6449
6450 if (null != row[4])
6451 {
6452 exclusion.ExcludedMinVersion = Convert.ToString(row[4]);
6453 }
6454
6455 if (null != row[5])
6456 {
6457 exclusion.ExcludedMinVersion = Convert.ToString(row[5]);
6458 }
6459
6460 this.core.RootElement.AddChild(exclusion);
6461 }
6462 }
6463
6464 /// <summary>
6465 /// Decompile the ModuleIgnoreTable table.
6466 /// </summary>
6467 /// <param name="table">The table to decompile.</param>
6468 private void DecompileModuleIgnoreTableTable(Table table)
6469 {
6470 foreach (var row in table.Rows)
6471 {
6472 var tableName = Convert.ToString(row[0]);
6473
6474 // the linker automatically adds a ModuleIgnoreTable row for some tables
6475 if ("ModuleConfiguration" != tableName && "ModuleSubstitution" != tableName)
6476 {
6477 var ignoreTable = new Wix.IgnoreTable();
6478
6479 ignoreTable.Id = tableName;
6480
6481 this.core.RootElement.AddChild(ignoreTable);
6482 }
6483 }
6484 }
6485
6486 /// <summary>
6487 /// Decompile the ModuleSignature table.
6488 /// </summary>
6489 /// <param name="table">The table to decompile.</param>
6490 private void DecompileModuleSignatureTable(Table table)
6491 {
6492 if (1 == table.Rows.Count)
6493 {
6494 var row = table.Rows[0];
6495
6496 var module = (Wix.Module)this.core.RootElement;
6497
6498 module.Id = Convert.ToString(row[0]);
6499
6500 // support Language columns that are treated as integers as well as strings (the WiX default, to support localizability)
6501 module.Language = Convert.ToString(row[1], CultureInfo.InvariantCulture);
6502
6503 module.Version = Convert.ToString(row[2]);
6504 }
6505 else
6506 {
6507 // TODO: warn
6508 }
6509 }
6510
6511 /// <summary>
6512 /// Decompile the ModuleSubstitution table.
6513 /// </summary>
6514 /// <param name="table">The table to decompile.</param>
6515 private void DecompileModuleSubstitutionTable(Table table)
6516 {
6517 foreach (var row in table.Rows)
6518 {
6519 var substitution = new Wix.Substitution();
6520
6521 substitution.Table = Convert.ToString(row[0]);
6522
6523 substitution.Row = Convert.ToString(row[1]);
6524
6525 substitution.Column = Convert.ToString(row[2]);
6526
6527 if (null != row[3])
6528 {
6529 substitution.Value = Convert.ToString(row[3]);
6530 }
6531
6532 this.core.RootElement.AddChild(substitution);
6533 }
6534 }
6535
6536 /// <summary>
6537 /// Decompile the MoveFile table.
6538 /// </summary>
6539 /// <param name="table">The table to decompile.</param>
6540 private void DecompileMoveFileTable(Table table)
6541 {
6542 foreach (var row in table.Rows)
6543 {
6544 var copyFile = new Wix.CopyFile();
6545
6546 copyFile.Id = Convert.ToString(row[0]);
6547
6548 if (null != row[2])
6549 {
6550 copyFile.SourceName = Convert.ToString(row[2]);
6551 }
6552
6553 if (null != row[3])
6554 {
6555 var names = Common.GetNames(Convert.ToString(row[3]));
6556 if (null != names[0] && null != names[1])
6557 {
6558 copyFile.DestinationShortName = names[0];
6559 copyFile.DestinationName = names[1];
6560 }
6561 else if (null != names[0])
6562 {
6563 copyFile.DestinationName = names[0];
6564 }
6565 }
6566
6567 // source/destination directory/property is set in FinalizeDuplicateMoveFileTables
6568
6569 switch (Convert.ToInt32(row[6]))
6570 {
6571 case 0:
6572 break;
6573 case MsiInterop.MsidbMoveFileOptionsMove:
6574 copyFile.Delete = Wix.YesNoType.yes;
6575 break;
6576 default:
6577 this.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[6].Column.Name, row[6]));
6578 break;
6579 }
6580
6581 var component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[1]));
6582 if (null != component)
6583 {
6584 component.AddChild(copyFile);
6585 }
6586 else
6587 {
6588 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[1]), "Component"));
6589 }
6590 this.core.IndexElement(row, copyFile);
6591 }
6592 }
6593
6594 /// <summary>
6595 /// Decompile the MsiDigitalCertificate table.
6596 /// </summary>
6597 /// <param name="table">The table to decompile.</param>
6598 private void DecompileMsiDigitalCertificateTable(Table table)
6599 {
6600 foreach (var row in table.Rows)
6601 {
6602 var digitalCertificate = new Wix.DigitalCertificate();
6603
6604 digitalCertificate.Id = Convert.ToString(row[0]);
6605
6606 digitalCertificate.SourceFile = Convert.ToString(row[1]);
6607
6608 this.core.IndexElement(row, digitalCertificate);
6609 }
6610 }
6611
6612 /// <summary>
6613 /// Decompile the MsiDigitalSignature table.
6614 /// </summary>
6615 /// <param name="table">The table to decompile.</param>
6616 private void DecompileMsiDigitalSignatureTable(Table table)
6617 {
6618 foreach (var row in table.Rows)
6619 {
6620 var digitalSignature = new Wix.DigitalSignature();
6621
6622 if (null != row[3])
6623 {
6624 digitalSignature.SourceFile = Convert.ToString(row[3]);
6625 }
6626
6627 var digitalCertificate = (Wix.DigitalCertificate)this.core.GetIndexedElement("MsiDigitalCertificate", Convert.ToString(row[2]));
6628 if (null != digitalCertificate)
6629 {
6630 digitalSignature.AddChild(digitalCertificate);
6631 }
6632 else
6633 {
6634 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "DigitalCertificate_", Convert.ToString(row[2]), "MsiDigitalCertificate"));
6635 }
6636
6637 var parentElement = (Wix.IParentElement)this.core.GetIndexedElement(Convert.ToString(row[0]), Convert.ToString(row[1]));
6638 if (null != parentElement)
6639 {
6640 parentElement.AddChild(digitalSignature);
6641 }
6642 else
6643 {
6644 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "SignObject", Convert.ToString(row[1]), Convert.ToString(row[0])));
6645 }
6646 }
6647 }
6648
6649 /// <summary>
6650 /// Decompile the MsiEmbeddedChainer table.
6651 /// </summary>
6652 /// <param name="table">The table to decompile.</param>
6653 private void DecompileMsiEmbeddedChainerTable(Table table)
6654 {
6655 foreach (var row in table.Rows)
6656 {
6657 var embeddedChainer = new Wix.EmbeddedChainer();
6658
6659 embeddedChainer.Id = Convert.ToString(row[0]);
6660
6661 embeddedChainer.Content = Convert.ToString(row[1]);
6662
6663 if (null != row[2])
6664 {
6665 embeddedChainer.CommandLine = Convert.ToString(row[2]);
6666 }
6667
6668 switch (Convert.ToInt32(row[4]))
6669 {
6670 case MsiInterop.MsidbCustomActionTypeExe + MsiInterop.MsidbCustomActionTypeBinaryData:
6671 embeddedChainer.BinarySource = Convert.ToString(row[3]);
6672 break;
6673 case MsiInterop.MsidbCustomActionTypeExe + MsiInterop.MsidbCustomActionTypeSourceFile:
6674 embeddedChainer.FileSource = Convert.ToString(row[3]);
6675 break;
6676 case MsiInterop.MsidbCustomActionTypeExe + MsiInterop.MsidbCustomActionTypeProperty:
6677 embeddedChainer.PropertySource = Convert.ToString(row[3]);
6678 break;
6679 default:
6680 this.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[4].Column.Name, row[4]));
6681 break;
6682 }
6683
6684 this.core.RootElement.AddChild(embeddedChainer);
6685 }
6686 }
6687
6688 /// <summary>
6689 /// Decompile the MsiEmbeddedUI table.
6690 /// </summary>
6691 /// <param name="table">The table to decompile.</param>
6692 private void DecompileMsiEmbeddedUITable(Table table)
6693 {
6694 var embeddedUI = new Wix.EmbeddedUI();
6695 var foundEmbeddedUI = false;
6696 var foundEmbeddedResources = false;
6697
6698 foreach (var row in table.Rows)
6699 {
6700 var attributes = Convert.ToInt32(row[2]);
6701
6702 if (MsiInterop.MsidbEmbeddedUI == (attributes & MsiInterop.MsidbEmbeddedUI))
6703 {
6704 if (foundEmbeddedUI)
6705 {
6706 this.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[2].Column.Name, row[2]));
6707 }
6708 else
6709 {
6710 embeddedUI.Id = Convert.ToString(row[0]);
6711 embeddedUI.Name = Convert.ToString(row[1]);
6712
6713 var messageFilter = Convert.ToInt32(row[3]);
6714 if (0 == (messageFilter & MsiInterop.INSTALLLOGMODE_FATALEXIT))
6715 {
6716 embeddedUI.IgnoreFatalExit = Wix.YesNoType.yes;
6717 }
6718
6719 if (0 == (messageFilter & MsiInterop.INSTALLLOGMODE_ERROR))
6720 {
6721 embeddedUI.IgnoreError = Wix.YesNoType.yes;
6722 }
6723
6724 if (0 == (messageFilter & MsiInterop.INSTALLLOGMODE_WARNING))
6725 {
6726 embeddedUI.IgnoreWarning = Wix.YesNoType.yes;
6727 }
6728
6729 if (0 == (messageFilter & MsiInterop.INSTALLLOGMODE_USER))
6730 {
6731 embeddedUI.IgnoreUser = Wix.YesNoType.yes;
6732 }
6733
6734 if (0 == (messageFilter & MsiInterop.INSTALLLOGMODE_INFO))
6735 {
6736 embeddedUI.IgnoreInfo = Wix.YesNoType.yes;
6737 }
6738
6739 if (0 == (messageFilter & MsiInterop.INSTALLLOGMODE_FILESINUSE))
6740 {
6741 embeddedUI.IgnoreFilesInUse = Wix.YesNoType.yes;
6742 }
6743
6744 if (0 == (messageFilter & MsiInterop.INSTALLLOGMODE_RESOLVESOURCE))
6745 {
6746 embeddedUI.IgnoreResolveSource = Wix.YesNoType.yes;
6747 }
6748
6749 if (0 == (messageFilter & MsiInterop.INSTALLLOGMODE_OUTOFDISKSPACE))
6750 {
6751 embeddedUI.IgnoreOutOfDiskSpace = Wix.YesNoType.yes;
6752 }
6753
6754 if (0 == (messageFilter & MsiInterop.INSTALLLOGMODE_ACTIONSTART))
6755 {
6756 embeddedUI.IgnoreActionStart = Wix.YesNoType.yes;
6757 }
6758
6759 if (0 == (messageFilter & MsiInterop.INSTALLLOGMODE_ACTIONDATA))
6760 {
6761 embeddedUI.IgnoreActionData = Wix.YesNoType.yes;
6762 }
6763
6764 if (0 == (messageFilter & MsiInterop.INSTALLLOGMODE_PROGRESS))
6765 {
6766 embeddedUI.IgnoreProgress = Wix.YesNoType.yes;
6767 }
6768
6769 if (0 == (messageFilter & MsiInterop.INSTALLLOGMODE_COMMONDATA))
6770 {
6771 embeddedUI.IgnoreCommonData = Wix.YesNoType.yes;
6772 }
6773
6774 if (0 == (messageFilter & MsiInterop.INSTALLLOGMODE_INITIALIZE))
6775 {
6776 embeddedUI.IgnoreInitialize = Wix.YesNoType.yes;
6777 }
6778
6779 if (0 == (messageFilter & MsiInterop.INSTALLLOGMODE_TERMINATE))
6780 {
6781 embeddedUI.IgnoreTerminate = Wix.YesNoType.yes;
6782 }
6783
6784 if (0 == (messageFilter & MsiInterop.INSTALLLOGMODE_SHOWDIALOG))
6785 {
6786 embeddedUI.IgnoreShowDialog = Wix.YesNoType.yes;
6787 }
6788
6789 if (0 == (messageFilter & MsiInterop.INSTALLLOGMODE_RMFILESINUSE))
6790 {
6791 embeddedUI.IgnoreRMFilesInUse = Wix.YesNoType.yes;
6792 }
6793
6794 if (0 == (messageFilter & MsiInterop.INSTALLLOGMODE_INSTALLSTART))
6795 {
6796 embeddedUI.IgnoreInstallStart = Wix.YesNoType.yes;
6797 }
6798
6799 if (0 == (messageFilter & MsiInterop.INSTALLLOGMODE_INSTALLEND))
6800 {
6801 embeddedUI.IgnoreInstallEnd = Wix.YesNoType.yes;
6802 }
6803
6804 if (MsiInterop.MsidbEmbeddedHandlesBasic == (attributes & MsiInterop.MsidbEmbeddedHandlesBasic))
6805 {
6806 embeddedUI.SupportBasicUI = Wix.YesNoType.yes;
6807 }
6808
6809 embeddedUI.SourceFile = Convert.ToString(row[4]);
6810
6811 this.core.UIElement.AddChild(embeddedUI);
6812 foundEmbeddedUI = true;
6813 }
6814 }
6815 else
6816 {
6817 var embeddedResource = new Wix.EmbeddedUIResource();
6818
6819 embeddedResource.Id = Convert.ToString(row[0]);
6820 embeddedResource.Name = Convert.ToString(row[1]);
6821 embeddedResource.SourceFile = Convert.ToString(row[4]);
6822
6823 embeddedUI.AddChild(embeddedResource);
6824 foundEmbeddedResources = true;
6825 }
6826 }
6827
6828 if (!foundEmbeddedUI && foundEmbeddedResources)
6829 {
6830 // TODO: warn
6831 }
6832 }
6833
6834 /// <summary>
6835 /// Decompile the MsiLockPermissionsEx table.
6836 /// </summary>
6837 /// <param name="table">The table to decompile.</param>
6838 private void DecompileMsiLockPermissionsExTable(Table table)
6839 {
6840 foreach (var row in table.Rows)
6841 {
6842 var permissionEx = new Wix.PermissionEx();
6843 permissionEx.Id = Convert.ToString(row[0]);
6844 permissionEx.Sddl = Convert.ToString(row[3]);
6845
6846 if (null != row[4])
6847 {
6848 var condition = new Wix.Condition();
6849 condition.Content = Convert.ToString(row[4]);
6850 permissionEx.AddChild(condition);
6851 }
6852
6853 switch (Convert.ToString(row[2]))
6854 {
6855 case "CreateFolder":
6856 case "File":
6857 case "Registry":
6858 case "ServiceInstall":
6859 break;
6860 default:
6861 this.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, row.Table.Name, row.Fields[1].Column.Name, row[1]));
6862 return;
6863 }
6864
6865 this.core.IndexElement(row, permissionEx);
6866 }
6867 }
6868
6869 /// <summary>
6870 /// Decompile the MsiPackageCertificate table.
6871 /// </summary>
6872 /// <param name="table">The table to decompile.</param>
6873 private void DecompileMsiPackageCertificateTable(Table table)
6874 {
6875 if (0 < table.Rows.Count)
6876 {
6877 var packageCertificates = new Wix.PackageCertificates();
6878 this.core.RootElement.AddChild(packageCertificates);
6879 this.AddCertificates(table, packageCertificates);
6880 }
6881 }
6882
6883 /// <summary>
6884 /// Decompile the MsiPatchCertificate table.
6885 /// </summary>
6886 /// <param name="table">The table to decompile.</param>
6887 private void DecompileMsiPatchCertificateTable(Table table)
6888 {
6889 if (0 < table.Rows.Count)
6890 {
6891 var patchCertificates = new Wix.PatchCertificates();
6892 this.core.RootElement.AddChild(patchCertificates);
6893 this.AddCertificates(table, patchCertificates);
6894 }
6895 }
6896
6897 /// <summary>
6898 /// Insert DigitalCertificate records associated with passed msiPackageCertificate or msiPatchCertificate table.
6899 /// </summary>
6900 /// <param name="table">The table being decompiled.</param>
6901 /// <param name="parent">DigitalCertificate parent</param>
6902 private void AddCertificates(Table table, Wix.IParentElement parent)
6903 {
6904 foreach (var row in table.Rows)
6905 {
6906 var digitalCertificate = (Wix.DigitalCertificate)this.core.GetIndexedElement("MsiDigitalCertificate", Convert.ToString(row[1]));
6907
6908 if (null != digitalCertificate)
6909 {
6910 parent.AddChild(digitalCertificate);
6911 }
6912 else
6913 {
6914 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "DigitalCertificate_", Convert.ToString(row[1]), "MsiDigitalCertificate"));
6915 }
6916 }
6917 }
6918
6919 /// <summary>
6920 /// Decompile the MsiShortcutProperty table.
6921 /// </summary>
6922 /// <param name="table">The table to decompile.</param>
6923 private void DecompileMsiShortcutPropertyTable(Table table)
6924 {
6925 foreach (var row in table.Rows)
6926 {
6927 var property = new Wix.ShortcutProperty();
6928 property.Id = Convert.ToString(row[0]);
6929 property.Key = Convert.ToString(row[2]);
6930 property.Value = Convert.ToString(row[3]);
6931
6932 var shortcut = (Wix.Shortcut)this.core.GetIndexedElement("Shortcut", Convert.ToString(row[1]));
6933 if (null != shortcut)
6934 {
6935 shortcut.AddChild(property);
6936 }
6937 else
6938 {
6939 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Shortcut_", Convert.ToString(row[1]), "Shortcut"));
6940 }
6941 }
6942 }
6943
6944 /// <summary>
6945 /// Decompile the ODBCAttribute table.
6946 /// </summary>
6947 /// <param name="table">The table to decompile.</param>
6948 private void DecompileODBCAttributeTable(Table table)
6949 {
6950 foreach (var row in table.Rows)
6951 {
6952 var property = new Wix.Property();
6953
6954 property.Id = Convert.ToString(row[1]);
6955
6956 if (null != row[2])
6957 {
6958 property.Value = Convert.ToString(row[2]);
6959 }
6960
6961 var odbcDriver = (Wix.ODBCDriver)this.core.GetIndexedElement("ODBCDriver", Convert.ToString(row[0]));
6962 if (null != odbcDriver)
6963 {
6964 odbcDriver.AddChild(property);
6965 }
6966 else
6967 {
6968 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Driver_", Convert.ToString(row[0]), "ODBCDriver"));
6969 }
6970 }
6971 }
6972
6973 /// <summary>
6974 /// Decompile the ODBCDataSource table.
6975 /// </summary>
6976 /// <param name="table">The table to decompile.</param>
6977 private void DecompileODBCDataSourceTable(Table table)
6978 {
6979 foreach (var row in table.Rows)
6980 {
6981 var odbcDataSource = new Wix.ODBCDataSource();
6982
6983 odbcDataSource.Id = Convert.ToString(row[0]);
6984
6985 odbcDataSource.Name = Convert.ToString(row[2]);
6986
6987 odbcDataSource.DriverName = Convert.ToString(row[3]);
6988
6989 switch (Convert.ToInt32(row[4]))
6990 {
6991 case MsiInterop.MsidbODBCDataSourceRegistrationPerMachine:
6992 odbcDataSource.Registration = Wix.ODBCDataSource.RegistrationType.machine;
6993 break;
6994 case MsiInterop.MsidbODBCDataSourceRegistrationPerUser:
6995 odbcDataSource.Registration = Wix.ODBCDataSource.RegistrationType.user;
6996 break;
6997 default:
6998 this.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[4].Column.Name, row[4]));
6999 break;
7000 }
7001
7002 this.core.IndexElement(row, odbcDataSource);
7003 }
7004 }
7005
7006 /// <summary>
7007 /// Decompile the ODBCDriver table.
7008 /// </summary>
7009 /// <param name="table">The table to decompile.</param>
7010 private void DecompileODBCDriverTable(Table table)
7011 {
7012 foreach (var row in table.Rows)
7013 {
7014 var odbcDriver = new Wix.ODBCDriver();
7015
7016 odbcDriver.Id = Convert.ToString(row[0]);
7017
7018 odbcDriver.Name = Convert.ToString(row[2]);
7019
7020 odbcDriver.File = Convert.ToString(row[3]);
7021
7022 if (null != row[4])
7023 {
7024 odbcDriver.SetupFile = Convert.ToString(row[4]);
7025 }
7026
7027 var component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[1]));
7028 if (null != component)
7029 {
7030 component.AddChild(odbcDriver);
7031 }
7032 else
7033 {
7034 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[1]), "Component"));
7035 }
7036 this.core.IndexElement(row, odbcDriver);
7037 }
7038 }
7039
7040 /// <summary>
7041 /// Decompile the ODBCSourceAttribute table.
7042 /// </summary>
7043 /// <param name="table">The table to decompile.</param>
7044 private void DecompileODBCSourceAttributeTable(Table table)
7045 {
7046 foreach (var row in table.Rows)
7047 {
7048 var property = new Wix.Property();
7049
7050 property.Id = Convert.ToString(row[1]);
7051
7052 if (null != row[2])
7053 {
7054 property.Value = Convert.ToString(row[2]);
7055 }
7056
7057 var odbcDataSource = (Wix.ODBCDataSource)this.core.GetIndexedElement("ODBCDataSource", Convert.ToString(row[0]));
7058 if (null != odbcDataSource)
7059 {
7060 odbcDataSource.AddChild(property);
7061 }
7062 else
7063 {
7064 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "DataSource_", Convert.ToString(row[0]), "ODBCDataSource"));
7065 }
7066 }
7067 }
7068
7069 /// <summary>
7070 /// Decompile the ODBCTranslator table.
7071 /// </summary>
7072 /// <param name="table">The table to decompile.</param>
7073 private void DecompileODBCTranslatorTable(Table table)
7074 {
7075 foreach (var row in table.Rows)
7076 {
7077 var odbcTranslator = new Wix.ODBCTranslator();
7078
7079 odbcTranslator.Id = Convert.ToString(row[0]);
7080
7081 odbcTranslator.Name = Convert.ToString(row[2]);
7082
7083 odbcTranslator.File = Convert.ToString(row[3]);
7084
7085 if (null != row[4])
7086 {
7087 odbcTranslator.SetupFile = Convert.ToString(row[4]);
7088 }
7089
7090 var component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[1]));
7091 if (null != component)
7092 {
7093 component.AddChild(odbcTranslator);
7094 }
7095 else
7096 {
7097 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[1]), "Component"));
7098 }
7099 }
7100 }
7101
7102 /// <summary>
7103 /// Decompile the PatchMetadata table.
7104 /// </summary>
7105 /// <param name="table">The table to decompile.</param>
7106 private void DecompilePatchMetadataTable(Table table)
7107 {
7108 if (0 < table.Rows.Count)
7109 {
7110 var patchMetadata = new Wix.PatchMetadata();
7111
7112 foreach (var row in table.Rows)
7113 {
7114 var value = Convert.ToString(row[2]);
7115
7116 switch (Convert.ToString(row[1]))
7117 {
7118 case "AllowRemoval":
7119 if ("1" == value)
7120 {
7121 patchMetadata.AllowRemoval = Wix.YesNoType.yes;
7122 }
7123 break;
7124 case "Classification":
7125 if (null != value)
7126 {
7127 patchMetadata.Classification = value;
7128 }
7129 break;
7130 case "CreationTimeUTC":
7131 if (null != value)
7132 {
7133 patchMetadata.CreationTimeUTC = value;
7134 }
7135 break;
7136 case "Description":
7137 if (null != value)
7138 {
7139 patchMetadata.Description = value;
7140 }
7141 break;
7142 case "DisplayName":
7143 if (null != value)
7144 {
7145 patchMetadata.DisplayName = value;
7146 }
7147 break;
7148 case "ManufacturerName":
7149 if (null != value)
7150 {
7151 patchMetadata.ManufacturerName = value;
7152 }
7153 break;
7154 case "MinorUpdateTargetRTM":
7155 if (null != value)
7156 {
7157 patchMetadata.MinorUpdateTargetRTM = value;
7158 }
7159 break;
7160 case "MoreInfoURL":
7161 if (null != value)
7162 {
7163 patchMetadata.MoreInfoURL = value;
7164 }
7165 break;
7166 case "OptimizeCA":
7167 var optimizeCustomActions = new Wix.OptimizeCustomActions();
7168 var optimizeCA = Int32.Parse(value, CultureInfo.InvariantCulture);
7169 if (0 != (Convert.ToInt32(OptimizeCA.SkipAssignment) & optimizeCA))
7170 {
7171 optimizeCustomActions.SkipAssignment = Wix.YesNoType.yes;
7172 }
7173
7174 if (0 != (Convert.ToInt32(OptimizeCA.SkipImmediate) & optimizeCA))
7175 {
7176 optimizeCustomActions.SkipImmediate = Wix.YesNoType.yes;
7177 }
7178
7179 if (0 != (Convert.ToInt32(OptimizeCA.SkipDeferred) & optimizeCA))
7180 {
7181 optimizeCustomActions.SkipDeferred = Wix.YesNoType.yes;
7182 }
7183
7184 patchMetadata.AddChild(optimizeCustomActions);
7185 break;
7186 case "OptimizedInstallMode":
7187 if ("1" == value)
7188 {
7189 patchMetadata.OptimizedInstallMode = Wix.YesNoType.yes;
7190 }
7191 break;
7192 case "TargetProductName":
7193 if (null != value)
7194 {
7195 patchMetadata.TargetProductName = value;
7196 }
7197 break;
7198 default:
7199 var customProperty = new Wix.CustomProperty();
7200
7201 if (null != row[0])
7202 {
7203 customProperty.Company = Convert.ToString(row[0]);
7204 }
7205
7206 customProperty.Property = Convert.ToString(row[1]);
7207
7208 if (null != row[2])
7209 {
7210 customProperty.Value = Convert.ToString(row[2]);
7211 }
7212
7213 patchMetadata.AddChild(customProperty);
7214 break;
7215 }
7216 }
7217
7218 this.core.RootElement.AddChild(patchMetadata);
7219 }
7220 }
7221
7222 /// <summary>
7223 /// Decompile the PatchSequence table.
7224 /// </summary>
7225 /// <param name="table">The table to decompile.</param>
7226 private void DecompilePatchSequenceTable(Table table)
7227 {
7228 foreach (var row in table.Rows)
7229 {
7230 var patchSequence = new Wix.PatchSequence();
7231
7232 patchSequence.PatchFamily = Convert.ToString(row[0]);
7233
7234 if (null != row[1])
7235 {
7236 try
7237 {
7238 var guid = new Guid(Convert.ToString(row[1]));
7239
7240 patchSequence.ProductCode = Convert.ToString(row[1]);
7241 }
7242 catch // non-guid value
7243 {
7244 patchSequence.TargetImage = Convert.ToString(row[1]);
7245 }
7246 }
7247
7248 if (null != row[2])
7249 {
7250 patchSequence.Sequence = Convert.ToString(row[2]);
7251 }
7252
7253 if (null != row[3] && 0x1 == Convert.ToInt32(row[3]))
7254 {
7255 patchSequence.Supersede = Wix.YesNoType.yes;
7256 }
7257
7258 this.core.RootElement.AddChild(patchSequence);
7259 }
7260 }
7261
7262 /// <summary>
7263 /// Decompile the ProgId table.
7264 /// </summary>
7265 /// <param name="table">The table to decompile.</param>
7266 private void DecompileProgIdTable(Table table)
7267 {
7268 foreach (var row in table.Rows)
7269 {
7270 var progId = new Wix.ProgId();
7271
7272 progId.Advertise = Wix.YesNoType.yes;
7273
7274 progId.Id = Convert.ToString(row[0]);
7275
7276 if (null != row[3])
7277 {
7278 progId.Description = Convert.ToString(row[3]);
7279 }
7280
7281 if (null != row[4])
7282 {
7283 progId.Icon = Convert.ToString(row[4]);
7284 }
7285
7286 if (null != row[5])
7287 {
7288 progId.IconIndex = Convert.ToInt32(row[5]);
7289 }
7290
7291 this.core.IndexElement(row, progId);
7292 }
7293
7294 // nest the ProgIds
7295 foreach (var row in table.Rows)
7296 {
7297 var progId = (Wix.ProgId)this.core.GetIndexedElement(row);
7298
7299 if (null != row[1])
7300 {
7301 var parentProgId = (Wix.ProgId)this.core.GetIndexedElement("ProgId", Convert.ToString(row[1]));
7302
7303 if (null != parentProgId)
7304 {
7305 parentProgId.AddChild(progId);
7306 }
7307 else
7308 {
7309 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "ProgId_Parent", Convert.ToString(row[1]), "ProgId"));
7310 }
7311 }
7312 else if (null != row[2])
7313 {
7314 // nesting is handled in FinalizeProgIdTable
7315 }
7316 else
7317 {
7318 // TODO: warn for orphaned ProgId
7319 }
7320 }
7321 }
7322
7323 /// <summary>
7324 /// Decompile the Properties table.
7325 /// </summary>
7326 /// <param name="table">The table to decompile.</param>
7327 private void DecompilePropertiesTable(Table table)
7328 {
7329 var patchCreation = (Wix.PatchCreation)this.core.RootElement;
7330
7331 foreach (var row in table.Rows)
7332 {
7333 var name = Convert.ToString(row[0]);
7334 var value = Convert.ToString(row[1]);
7335
7336 switch (name)
7337 {
7338 case "AllowProductCodeMismatches":
7339 if ("1" == value)
7340 {
7341 patchCreation.AllowProductCodeMismatches = Wix.YesNoType.yes;
7342 }
7343 break;
7344 case "AllowProductVersionMajorMismatches":
7345 if ("1" == value)
7346 {
7347 patchCreation.AllowMajorVersionMismatches = Wix.YesNoType.yes;
7348 }
7349 break;
7350 case "ApiPatchingSymbolFlags":
7351 if (null != value)
7352 {
7353 try
7354 {
7355 // remove the leading "0x" if its present
7356 if (value.StartsWith("0x", StringComparison.Ordinal))
7357 {
7358 value = value.Substring(2);
7359 }
7360
7361 patchCreation.SymbolFlags = Convert.ToInt32(value, 16);
7362 }
7363 catch
7364 {
7365 this.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[1].Column.Name, row[1]));
7366 }
7367 }
7368 break;
7369 case "DontRemoveTempFolderWhenFinished":
7370 if ("1" == value)
7371 {
7372 patchCreation.CleanWorkingFolder = Wix.YesNoType.no;
7373 }
7374 break;
7375 case "IncludeWholeFilesOnly":
7376 if ("1" == value)
7377 {
7378 patchCreation.WholeFilesOnly = Wix.YesNoType.yes;
7379 }
7380 break;
7381 case "ListOfPatchGUIDsToReplace":
7382 if (null != value)
7383 {
7384 var guidRegex = new Regex(@"\{[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}\}");
7385 var guidMatches = guidRegex.Matches(value);
7386
7387 foreach (Match guidMatch in guidMatches)
7388 {
7389 var replacePatch = new Wix.ReplacePatch();
7390
7391 replacePatch.Id = guidMatch.Value;
7392
7393 this.core.RootElement.AddChild(replacePatch);
7394 }
7395 }
7396 break;
7397 case "ListOfTargetProductCodes":
7398 if (null != value)
7399 {
7400 var targetProductCodes = value.Split(';');
7401
7402 foreach (var targetProductCodeString in targetProductCodes)
7403 {
7404 var targetProductCode = new Wix.TargetProductCode();
7405
7406 targetProductCode.Id = targetProductCodeString;
7407
7408 this.core.RootElement.AddChild(targetProductCode);
7409 }
7410 }
7411 break;
7412 case "PatchGUID":
7413 patchCreation.Id = value;
7414 break;
7415 case "PatchSourceList":
7416 patchCreation.SourceList = value;
7417 break;
7418 case "PatchOutputPath":
7419 patchCreation.OutputPath = value;
7420 break;
7421 default:
7422 var patchProperty = new Wix.PatchProperty();
7423
7424 patchProperty.Name = name;
7425
7426 patchProperty.Value = value;
7427
7428 this.core.RootElement.AddChild(patchProperty);
7429 break;
7430 }
7431 }
7432 }
7433
7434 /// <summary>
7435 /// Decompile the Property table.
7436 /// </summary>
7437 /// <param name="table">The table to decompile.</param>
7438 private void DecompilePropertyTable(Table table)
7439 {
7440 foreach (var row in table.Rows)
7441 {
7442 var id = Convert.ToString(row[0]);
7443 var value = Convert.ToString(row[1]);
7444
7445 if ("AdminProperties" == id || "MsiHiddenProperties" == id || "SecureCustomProperties" == id)
7446 {
7447 if (0 < value.Length)
7448 {
7449 foreach (var propertyId in value.Split(';'))
7450 {
7451 if (Common.DowngradeDetectedProperty == propertyId || Common.UpgradeDetectedProperty == propertyId)
7452 {
7453 continue;
7454 }
7455
7456 var property = propertyId;
7457 var suppressModulularization = false;
7458 if (OutputType.Module == this.OutputType)
7459 {
7460 if (propertyId.EndsWith(this.modularizationGuid.Substring(1, 36).Replace('-', '_'), StringComparison.Ordinal))
7461 {
7462 property = propertyId.Substring(0, propertyId.Length - this.modularizationGuid.Length + 1);
7463 }
7464 else
7465 {
7466 suppressModulularization = true;
7467 }
7468 }
7469
7470 var specialProperty = this.EnsureProperty(property);
7471 if (suppressModulularization)
7472 {
7473 specialProperty.SuppressModularization = Wix.YesNoType.yes;
7474 }
7475
7476 switch (id)
7477 {
7478 case "AdminProperties":
7479 specialProperty.Admin = Wix.YesNoType.yes;
7480 break;
7481 case "MsiHiddenProperties":
7482 specialProperty.Hidden = Wix.YesNoType.yes;
7483 break;
7484 case "SecureCustomProperties":
7485 specialProperty.Secure = Wix.YesNoType.yes;
7486 break;
7487 }
7488 }
7489 }
7490
7491 continue;
7492 }
7493 else if (OutputType.Product == this.OutputType)
7494 {
7495 var product = (Wix.Product)this.core.RootElement;
7496
7497 switch (id)
7498 {
7499 case "Manufacturer":
7500 product.Manufacturer = value;
7501 continue;
7502 case "ProductCode":
7503 product.Id = value.ToUpper(CultureInfo.InvariantCulture);
7504 continue;
7505 case "ProductLanguage":
7506 product.Language = value;
7507 continue;
7508 case "ProductName":
7509 product.Name = value;
7510 continue;
7511 case "ProductVersion":
7512 product.Version = value;
7513 continue;
7514 case "UpgradeCode":
7515 product.UpgradeCode = value;
7516 continue;
7517 }
7518 }
7519
7520 if (!this.SuppressUI || "ErrorDialog" != id)
7521 {
7522 var property = this.EnsureProperty(id);
7523
7524 property.Value = value;
7525 }
7526 }
7527 }
7528
7529 /// <summary>
7530 /// Decompile the PublishComponent table.
7531 /// </summary>
7532 /// <param name="table">The table to decompile.</param>
7533 private void DecompilePublishComponentTable(Table table)
7534 {
7535 foreach (var row in table.Rows)
7536 {
7537 var category = new Wix.Category();
7538
7539 category.Id = Convert.ToString(row[0]);
7540
7541 category.Qualifier = Convert.ToString(row[1]);
7542
7543 if (null != row[3])
7544 {
7545 category.AppData = Convert.ToString(row[3]);
7546 }
7547
7548 var component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[2]));
7549 if (null != component)
7550 {
7551 component.AddChild(category);
7552 }
7553 else
7554 {
7555 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[2]), "Component"));
7556 }
7557 }
7558 }
7559
7560 /// <summary>
7561 /// Decompile the RadioButton table.
7562 /// </summary>
7563 /// <param name="table">The table to decompile.</param>
7564 private void DecompileRadioButtonTable(Table table)
7565 {
7566 var radioButtons = new SortedList();
7567 var radioButtonGroups = new Hashtable();
7568
7569 foreach (var row in table.Rows)
7570 {
7571 var radioButton = new Wix.RadioButton();
7572
7573 radioButton.Value = Convert.ToString(row[2]);
7574
7575 radioButton.X = Convert.ToString(row[3], CultureInfo.InvariantCulture);
7576
7577 radioButton.Y = Convert.ToString(row[4], CultureInfo.InvariantCulture);
7578
7579 radioButton.Width = Convert.ToString(row[5], CultureInfo.InvariantCulture);
7580
7581 radioButton.Height = Convert.ToString(row[6], CultureInfo.InvariantCulture);
7582
7583 if (null != row[7])
7584 {
7585 radioButton.Text = Convert.ToString(row[7]);
7586 }
7587
7588 if (null != row[8])
7589 {
7590 var help = (Convert.ToString(row[8])).Split('|');
7591
7592 if (2 == help.Length)
7593 {
7594 if (0 < help[0].Length)
7595 {
7596 radioButton.ToolTip = help[0];
7597 }
7598
7599 if (0 < help[1].Length)
7600 {
7601 radioButton.Help = help[1];
7602 }
7603 }
7604 }
7605
7606 radioButtons.Add(String.Format(CultureInfo.InvariantCulture, "{0}|{1:0000000000}", row[0], row[1]), row);
7607 this.core.IndexElement(row, radioButton);
7608 }
7609
7610 // nest the radio buttons
7611 foreach (Row row in radioButtons.Values)
7612 {
7613 var radioButton = (Wix.RadioButton)this.core.GetIndexedElement(row);
7614 var radioButtonGroup = (Wix.RadioButtonGroup)radioButtonGroups[Convert.ToString(row[0])];
7615
7616 if (null == radioButtonGroup)
7617 {
7618 radioButtonGroup = new Wix.RadioButtonGroup();
7619
7620 radioButtonGroup.Property = Convert.ToString(row[0]);
7621
7622 this.core.UIElement.AddChild(radioButtonGroup);
7623 radioButtonGroups.Add(Convert.ToString(row[0]), radioButtonGroup);
7624 }
7625
7626 radioButtonGroup.AddChild(radioButton);
7627 }
7628 }
7629
7630 /// <summary>
7631 /// Decompile the Registry table.
7632 /// </summary>
7633 /// <param name="table">The table to decompile.</param>
7634 private void DecompileRegistryTable(Table table)
7635 {
7636 foreach (var row in table.Rows)
7637 {
7638 if (("-" == Convert.ToString(row[3]) || "+" == Convert.ToString(row[3]) || "*" == Convert.ToString(row[3])) && null == row[4])
7639 {
7640 var registryKey = new Wix.RegistryKey();
7641
7642 registryKey.Id = Convert.ToString(row[0]);
7643
7644 if (this.GetRegistryRootType(row.SourceLineNumbers, table.Name, row.Fields[1], out var registryRootType))
7645 {
7646 registryKey.Root = registryRootType;
7647 }
7648
7649 registryKey.Key = Convert.ToString(row[2]);
7650
7651 switch (Convert.ToString(row[3]))
7652 {
7653 case "+":
7654 registryKey.ForceCreateOnInstall = Wix.YesNoType.yes;
7655 break;
7656 case "-":
7657 registryKey.ForceDeleteOnUninstall = Wix.YesNoType.yes;
7658 break;
7659 case "*":
7660 registryKey.ForceDeleteOnUninstall = Wix.YesNoType.yes;
7661 registryKey.ForceCreateOnInstall = Wix.YesNoType.yes;
7662 break;
7663 }
7664
7665 this.core.IndexElement(row, registryKey);
7666 }
7667 else
7668 {
7669 var registryValue = new Wix.RegistryValue();
7670
7671 registryValue.Id = Convert.ToString(row[0]);
7672
7673 if (this.GetRegistryRootType(row.SourceLineNumbers, table.Name, row.Fields[1], out var registryRootType))
7674 {
7675 registryValue.Root = registryRootType;
7676 }
7677
7678 registryValue.Key = Convert.ToString(row[2]);
7679
7680 if (null != row[3])
7681 {
7682 registryValue.Name = Convert.ToString(row[3]);
7683 }
7684
7685 if (null != row[4])
7686 {
7687 var value = Convert.ToString(row[4]);
7688
7689 if (value.StartsWith("#x", StringComparison.Ordinal))
7690 {
7691 registryValue.Type = Wix.RegistryValue.TypeType.binary;
7692 registryValue.Value = value.Substring(2);
7693 }
7694 else if (value.StartsWith("#%", StringComparison.Ordinal))
7695 {
7696 registryValue.Type = Wix.RegistryValue.TypeType.expandable;
7697 registryValue.Value = value.Substring(2);
7698 }
7699 else if (value.StartsWith("#", StringComparison.Ordinal) && !value.StartsWith("##", StringComparison.Ordinal))
7700 {
7701 registryValue.Type = Wix.RegistryValue.TypeType.integer;
7702 registryValue.Value = value.Substring(1);
7703 }
7704 else
7705 {
7706 if (value.StartsWith("##", StringComparison.Ordinal))
7707 {
7708 value = value.Substring(1);
7709 }
7710
7711 if (0 <= value.IndexOf("[~]", StringComparison.Ordinal))
7712 {
7713 registryValue.Type = Wix.RegistryValue.TypeType.multiString;
7714
7715 if ("[~]" == value)
7716 {
7717 value = String.Empty;
7718 }
7719 else if (value.StartsWith("[~]", StringComparison.Ordinal) && value.EndsWith("[~]", StringComparison.Ordinal))
7720 {
7721 value = value.Substring(3, value.Length - 6);
7722 }
7723 else if (value.StartsWith("[~]", StringComparison.Ordinal))
7724 {
7725 registryValue.Action = Wix.RegistryValue.ActionType.append;
7726 value = value.Substring(3);
7727 }
7728 else if (value.EndsWith("[~]", StringComparison.Ordinal))
7729 {
7730 registryValue.Action = Wix.RegistryValue.ActionType.prepend;
7731 value = value.Substring(0, value.Length - 3);
7732 }
7733
7734 var multiValues = NullSplitter.Split(value);
7735 foreach (var multiValue in multiValues)
7736 {
7737 var multiStringValue = new Wix.MultiStringValue();
7738
7739 multiStringValue.Content = multiValue;
7740
7741 registryValue.AddChild(multiStringValue);
7742 }
7743 }
7744 else
7745 {
7746 registryValue.Type = Wix.RegistryValue.TypeType.@string;
7747 registryValue.Value = value;
7748 }
7749 }
7750 }
7751 else
7752 {
7753 registryValue.Type = Wix.RegistryValue.TypeType.@string;
7754 registryValue.Value = String.Empty;
7755 }
7756
7757 this.core.IndexElement(row, registryValue);
7758 }
7759 }
7760 }
7761
7762 /// <summary>
7763 /// Decompile the RegLocator table.
7764 /// </summary>
7765 /// <param name="table">The table to decompile.</param>
7766 private void DecompileRegLocatorTable(Table table)
7767 {
7768 foreach (var row in table.Rows)
7769 {
7770 var registrySearch = new Wix.RegistrySearch();
7771
7772 registrySearch.Id = Convert.ToString(row[0]);
7773
7774 switch (Convert.ToInt32(row[1]))
7775 {
7776 case MsiInterop.MsidbRegistryRootClassesRoot:
7777 registrySearch.Root = Wix.RegistrySearch.RootType.HKCR;
7778 break;
7779 case MsiInterop.MsidbRegistryRootCurrentUser:
7780 registrySearch.Root = Wix.RegistrySearch.RootType.HKCU;
7781 break;
7782 case MsiInterop.MsidbRegistryRootLocalMachine:
7783 registrySearch.Root = Wix.RegistrySearch.RootType.HKLM;
7784 break;
7785 case MsiInterop.MsidbRegistryRootUsers:
7786 registrySearch.Root = Wix.RegistrySearch.RootType.HKU;
7787 break;
7788 default:
7789 this.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[1].Column.Name, row[1]));
7790 break;
7791 }
7792
7793 registrySearch.Key = Convert.ToString(row[2]);
7794
7795 if (null != row[3])
7796 {
7797 registrySearch.Name = Convert.ToString(row[3]);
7798 }
7799
7800 if (null == row[4])
7801 {
7802 registrySearch.Type = Wix.RegistrySearch.TypeType.file;
7803 }
7804 else
7805 {
7806 var type = Convert.ToInt32(row[4]);
7807
7808 if (MsiInterop.MsidbLocatorType64bit == (type & MsiInterop.MsidbLocatorType64bit))
7809 {
7810 registrySearch.Win64 = Wix.YesNoType.yes;
7811 type &= ~MsiInterop.MsidbLocatorType64bit;
7812 }
7813
7814 switch (type)
7815 {
7816 case MsiInterop.MsidbLocatorTypeDirectory:
7817 registrySearch.Type = Wix.RegistrySearch.TypeType.directory;
7818 break;
7819 case MsiInterop.MsidbLocatorTypeFileName:
7820 registrySearch.Type = Wix.RegistrySearch.TypeType.file;
7821 break;
7822 case MsiInterop.MsidbLocatorTypeRawValue:
7823 registrySearch.Type = Wix.RegistrySearch.TypeType.raw;
7824 break;
7825 default:
7826 this.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[4].Column.Name, row[4]));
7827 break;
7828 }
7829 }
7830
7831 this.core.IndexElement(row, registrySearch);
7832 }
7833 }
7834
7835 /// <summary>
7836 /// Decompile the RemoveFile table.
7837 /// </summary>
7838 /// <param name="table">The table to decompile.</param>
7839 private void DecompileRemoveFileTable(Table table)
7840 {
7841 foreach (var row in table.Rows)
7842 {
7843 if (null == row[2])
7844 {
7845 var removeFolder = new Wix.RemoveFolder();
7846
7847 removeFolder.Id = Convert.ToString(row[0]);
7848
7849 // directory/property is set in FinalizeDecompile
7850
7851 switch (Convert.ToInt32(row[4]))
7852 {
7853 case MsiInterop.MsidbRemoveFileInstallModeOnInstall:
7854 removeFolder.On = Wix.InstallUninstallType.install;
7855 break;
7856 case MsiInterop.MsidbRemoveFileInstallModeOnRemove:
7857 removeFolder.On = Wix.InstallUninstallType.uninstall;
7858 break;
7859 case MsiInterop.MsidbRemoveFileInstallModeOnBoth:
7860 removeFolder.On = Wix.InstallUninstallType.both;
7861 break;
7862 default:
7863 this.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[4].Column.Name, row[4]));
7864 break;
7865 }
7866
7867 var component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[1]));
7868 if (null != component)
7869 {
7870 component.AddChild(removeFolder);
7871 }
7872 else
7873 {
7874 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[1]), "Component"));
7875 }
7876 this.core.IndexElement(row, removeFolder);
7877 }
7878 else
7879 {
7880 var removeFile = new Wix.RemoveFile();
7881
7882 removeFile.Id = Convert.ToString(row[0]);
7883
7884 var names = Common.GetNames(Convert.ToString(row[2]));
7885 if (null != names[0] && null != names[1])
7886 {
7887 removeFile.ShortName = names[0];
7888 removeFile.Name = names[1];
7889 }
7890 else if (null != names[0])
7891 {
7892 removeFile.Name = names[0];
7893 }
7894
7895 // directory/property is set in FinalizeDecompile
7896
7897 switch (Convert.ToInt32(row[4]))
7898 {
7899 case MsiInterop.MsidbRemoveFileInstallModeOnInstall:
7900 removeFile.On = Wix.InstallUninstallType.install;
7901 break;
7902 case MsiInterop.MsidbRemoveFileInstallModeOnRemove:
7903 removeFile.On = Wix.InstallUninstallType.uninstall;
7904 break;
7905 case MsiInterop.MsidbRemoveFileInstallModeOnBoth:
7906 removeFile.On = Wix.InstallUninstallType.both;
7907 break;
7908 default:
7909 this.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[4].Column.Name, row[4]));
7910 break;
7911 }
7912
7913 var component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[1]));
7914 if (null != component)
7915 {
7916 component.AddChild(removeFile);
7917 }
7918 else
7919 {
7920 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[1]), "Component"));
7921 }
7922 this.core.IndexElement(row, removeFile);
7923 }
7924 }
7925 }
7926
7927 /// <summary>
7928 /// Decompile the RemoveIniFile table.
7929 /// </summary>
7930 /// <param name="table">The table to decompile.</param>
7931 private void DecompileRemoveIniFileTable(Table table)
7932 {
7933 foreach (var row in table.Rows)
7934 {
7935 var iniFile = new Wix.IniFile();
7936
7937 iniFile.Id = Convert.ToString(row[0]);
7938
7939 var names = Common.GetNames(Convert.ToString(row[1]));
7940 if (null != names[0] && null != names[1])
7941 {
7942 iniFile.ShortName = names[0];
7943 iniFile.Name = names[1];
7944 }
7945 else if (null != names[0])
7946 {
7947 iniFile.Name = names[0];
7948 }
7949
7950 if (null != row[2])
7951 {
7952 iniFile.Directory = Convert.ToString(row[2]);
7953 }
7954
7955 iniFile.Section = Convert.ToString(row[3]);
7956
7957 iniFile.Key = Convert.ToString(row[4]);
7958
7959 if (null != row[5])
7960 {
7961 iniFile.Value = Convert.ToString(row[5]);
7962 }
7963
7964 switch (Convert.ToInt32(row[6]))
7965 {
7966 case MsiInterop.MsidbIniFileActionRemoveLine:
7967 iniFile.Action = Wix.IniFile.ActionType.removeLine;
7968 break;
7969 case MsiInterop.MsidbIniFileActionRemoveTag:
7970 iniFile.Action = Wix.IniFile.ActionType.removeTag;
7971 break;
7972 default:
7973 this.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[6].Column.Name, row[6]));
7974 break;
7975 }
7976
7977 var component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[7]));
7978 if (null != component)
7979 {
7980 component.AddChild(iniFile);
7981 }
7982 else
7983 {
7984 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[7]), "Component"));
7985 }
7986 }
7987 }
7988
7989 /// <summary>
7990 /// Decompile the RemoveRegistry table.
7991 /// </summary>
7992 /// <param name="table">The table to decompile.</param>
7993 private void DecompileRemoveRegistryTable(Table table)
7994 {
7995 foreach (var row in table.Rows)
7996 {
7997 if ("-" == Convert.ToString(row[3]))
7998 {
7999 var removeRegistryKey = new Wix.RemoveRegistryKey();
8000
8001 removeRegistryKey.Id = Convert.ToString(row[0]);
8002
8003 if (this.GetRegistryRootType(row.SourceLineNumbers, table.Name, row.Fields[1], out var registryRootType))
8004 {
8005 removeRegistryKey.Root = registryRootType;
8006 }
8007
8008 removeRegistryKey.Key = Convert.ToString(row[2]);
8009
8010 removeRegistryKey.Action = Wix.RemoveRegistryKey.ActionType.removeOnInstall;
8011
8012 var component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[4]));
8013 if (null != component)
8014 {
8015 component.AddChild(removeRegistryKey);
8016 }
8017 else
8018 {
8019 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[4]), "Component"));
8020 }
8021 }
8022 else
8023 {
8024 var removeRegistryValue = new Wix.RemoveRegistryValue();
8025
8026 removeRegistryValue.Id = Convert.ToString(row[0]);
8027
8028 if (this.GetRegistryRootType(row.SourceLineNumbers, table.Name, row.Fields[1], out var registryRootType))
8029 {
8030 removeRegistryValue.Root = registryRootType;
8031 }
8032
8033 removeRegistryValue.Key = Convert.ToString(row[2]);
8034
8035 if (null != row[3])
8036 {
8037 removeRegistryValue.Name = Convert.ToString(row[3]);
8038 }
8039
8040 var component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[4]));
8041 if (null != component)
8042 {
8043 component.AddChild(removeRegistryValue);
8044 }
8045 else
8046 {
8047 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[4]), "Component"));
8048 }
8049 }
8050 }
8051 }
8052
8053 /// <summary>
8054 /// Decompile the ReserveCost table.
8055 /// </summary>
8056 /// <param name="table">The table to decompile.</param>
8057 private void DecompileReserveCostTable(Table table)
8058 {
8059 foreach (var row in table.Rows)
8060 {
8061 var reserveCost = new Wix.ReserveCost();
8062
8063 reserveCost.Id = Convert.ToString(row[0]);
8064
8065 if (null != row[2])
8066 {
8067 reserveCost.Directory = Convert.ToString(row[2]);
8068 }
8069
8070 reserveCost.RunLocal = Convert.ToInt32(row[3]);
8071
8072 reserveCost.RunFromSource = Convert.ToInt32(row[4]);
8073
8074 var component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[1]));
8075 if (null != component)
8076 {
8077 component.AddChild(reserveCost);
8078 }
8079 else
8080 {
8081 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[1]), "Component"));
8082 }
8083 }
8084 }
8085
8086 /// <summary>
8087 /// Decompile the SelfReg table.
8088 /// </summary>
8089 /// <param name="table">The table to decompile.</param>
8090 private void DecompileSelfRegTable(Table table)
8091 {
8092 foreach (var row in table.Rows)
8093 {
8094 var file = (Wix.File)this.core.GetIndexedElement("File", Convert.ToString(row[0]));
8095
8096 if (null != file)
8097 {
8098 if (null != row[1])
8099 {
8100 file.SelfRegCost = Convert.ToInt32(row[1]);
8101 }
8102 else
8103 {
8104 file.SelfRegCost = 0;
8105 }
8106 }
8107 else
8108 {
8109 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "File_", Convert.ToString(row[0]), "File"));
8110 }
8111 }
8112 }
8113
8114 /// <summary>
8115 /// Decompile the ServiceControl table.
8116 /// </summary>
8117 /// <param name="table">The table to decompile.</param>
8118 private void DecompileServiceControlTable(Table table)
8119 {
8120 foreach (var row in table.Rows)
8121 {
8122 var serviceControl = new Wix.ServiceControl();
8123
8124 serviceControl.Id = Convert.ToString(row[0]);
8125
8126 serviceControl.Name = Convert.ToString(row[1]);
8127
8128 var eventValue = Convert.ToInt32(row[2]);
8129 if (MsiInterop.MsidbServiceControlEventStart == (eventValue & MsiInterop.MsidbServiceControlEventStart) &&
8130 MsiInterop.MsidbServiceControlEventUninstallStart == (eventValue & MsiInterop.MsidbServiceControlEventUninstallStart))
8131 {
8132 serviceControl.Start = Wix.InstallUninstallType.both;
8133 }
8134 else if (MsiInterop.MsidbServiceControlEventStart == (eventValue & MsiInterop.MsidbServiceControlEventStart))
8135 {
8136 serviceControl.Start = Wix.InstallUninstallType.install;
8137 }
8138 else if (MsiInterop.MsidbServiceControlEventUninstallStart == (eventValue & MsiInterop.MsidbServiceControlEventUninstallStart))
8139 {
8140 serviceControl.Start = Wix.InstallUninstallType.uninstall;
8141 }
8142
8143 if (MsiInterop.MsidbServiceControlEventStop == (eventValue & MsiInterop.MsidbServiceControlEventStop) &&
8144 MsiInterop.MsidbServiceControlEventUninstallStop == (eventValue & MsiInterop.MsidbServiceControlEventUninstallStop))
8145 {
8146 serviceControl.Stop = Wix.InstallUninstallType.both;
8147 }
8148 else if (MsiInterop.MsidbServiceControlEventStop == (eventValue & MsiInterop.MsidbServiceControlEventStop))
8149 {
8150 serviceControl.Stop = Wix.InstallUninstallType.install;
8151 }
8152 else if (MsiInterop.MsidbServiceControlEventUninstallStop == (eventValue & MsiInterop.MsidbServiceControlEventUninstallStop))
8153 {
8154 serviceControl.Stop = Wix.InstallUninstallType.uninstall;
8155 }
8156
8157 if (MsiInterop.MsidbServiceControlEventDelete == (eventValue & MsiInterop.MsidbServiceControlEventDelete) &&
8158 MsiInterop.MsidbServiceControlEventUninstallDelete == (eventValue & MsiInterop.MsidbServiceControlEventUninstallDelete))
8159 {
8160 serviceControl.Remove = Wix.InstallUninstallType.both;
8161 }
8162 else if (MsiInterop.MsidbServiceControlEventDelete == (eventValue & MsiInterop.MsidbServiceControlEventDelete))
8163 {
8164 serviceControl.Remove = Wix.InstallUninstallType.install;
8165 }
8166 else if (MsiInterop.MsidbServiceControlEventUninstallDelete == (eventValue & MsiInterop.MsidbServiceControlEventUninstallDelete))
8167 {
8168 serviceControl.Remove = Wix.InstallUninstallType.uninstall;
8169 }
8170
8171 if (null != row[3])
8172 {
8173 var arguments = NullSplitter.Split(Convert.ToString(row[3]));
8174
8175 foreach (var argument in arguments)
8176 {
8177 var serviceArgument = new Wix.ServiceArgument();
8178
8179 serviceArgument.Content = argument;
8180
8181 serviceControl.AddChild(serviceArgument);
8182 }
8183 }
8184
8185 if (null != row[4])
8186 {
8187 if (0 == Convert.ToInt32(row[4]))
8188 {
8189 serviceControl.Wait = Wix.YesNoType.no;
8190 }
8191 else
8192 {
8193 serviceControl.Wait = Wix.YesNoType.yes;
8194 }
8195 }
8196
8197 var component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[5]));
8198 if (null != component)
8199 {
8200 component.AddChild(serviceControl);
8201 }
8202 else
8203 {
8204 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[5]), "Component"));
8205 }
8206 }
8207 }
8208
8209 /// <summary>
8210 /// Decompile the ServiceInstall table.
8211 /// </summary>
8212 /// <param name="table">The table to decompile.</param>
8213 private void DecompileServiceInstallTable(Table table)
8214 {
8215 foreach (var row in table.Rows)
8216 {
8217 var serviceInstall = new Wix.ServiceInstall();
8218
8219 serviceInstall.Id = Convert.ToString(row[0]);
8220
8221 serviceInstall.Name = Convert.ToString(row[1]);
8222
8223 if (null != row[2])
8224 {
8225 serviceInstall.DisplayName = Convert.ToString(row[2]);
8226 }
8227
8228 var serviceType = Convert.ToInt32(row[3]);
8229 if (MsiInterop.MsidbServiceInstallInteractive == (serviceType & MsiInterop.MsidbServiceInstallInteractive))
8230 {
8231 serviceInstall.Interactive = Wix.YesNoType.yes;
8232 }
8233
8234 if (MsiInterop.MsidbServiceInstallOwnProcess == (serviceType & MsiInterop.MsidbServiceInstallOwnProcess) &&
8235 MsiInterop.MsidbServiceInstallShareProcess == (serviceType & MsiInterop.MsidbServiceInstallShareProcess))
8236 {
8237 // TODO: warn
8238 }
8239 else if (MsiInterop.MsidbServiceInstallOwnProcess == (serviceType & MsiInterop.MsidbServiceInstallOwnProcess))
8240 {
8241 serviceInstall.Type = Wix.ServiceInstall.TypeType.ownProcess;
8242 }
8243 else if (MsiInterop.MsidbServiceInstallShareProcess == (serviceType & MsiInterop.MsidbServiceInstallShareProcess))
8244 {
8245 serviceInstall.Type = Wix.ServiceInstall.TypeType.shareProcess;
8246 }
8247
8248 var startType = Convert.ToInt32(row[4]);
8249 if (MsiInterop.MsidbServiceInstallDisabled == startType)
8250 {
8251 serviceInstall.Start = Wix.ServiceInstall.StartType.disabled;
8252 }
8253 else if (MsiInterop.MsidbServiceInstallDemandStart == startType)
8254 {
8255 serviceInstall.Start = Wix.ServiceInstall.StartType.demand;
8256 }
8257 else if (MsiInterop.MsidbServiceInstallAutoStart == startType)
8258 {
8259 serviceInstall.Start = Wix.ServiceInstall.StartType.auto;
8260 }
8261 else
8262 {
8263 this.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[4].Column.Name, row[4]));
8264 }
8265
8266 var errorControl = Convert.ToInt32(row[5]);
8267 if (MsiInterop.MsidbServiceInstallErrorCritical == (errorControl & MsiInterop.MsidbServiceInstallErrorCritical))
8268 {
8269 serviceInstall.ErrorControl = Wix.ServiceInstall.ErrorControlType.critical;
8270 }
8271 else if (MsiInterop.MsidbServiceInstallErrorNormal == (errorControl & MsiInterop.MsidbServiceInstallErrorNormal))
8272 {
8273 serviceInstall.ErrorControl = Wix.ServiceInstall.ErrorControlType.normal;
8274 }
8275 else
8276 {
8277 serviceInstall.ErrorControl = Wix.ServiceInstall.ErrorControlType.ignore;
8278 }
8279
8280 if (MsiInterop.MsidbServiceInstallErrorControlVital == (errorControl & MsiInterop.MsidbServiceInstallErrorControlVital))
8281 {
8282 serviceInstall.Vital = Wix.YesNoType.yes;
8283 }
8284
8285 if (null != row[6])
8286 {
8287 serviceInstall.LoadOrderGroup = Convert.ToString(row[6]);
8288 }
8289
8290 if (null != row[7])
8291 {
8292 var dependencies = NullSplitter.Split(Convert.ToString(row[7]));
8293
8294 foreach (var dependency in dependencies)
8295 {
8296 if (0 < dependency.Length)
8297 {
8298 var serviceDependency = new Wix.ServiceDependency();
8299
8300 if (dependency.StartsWith("+", StringComparison.Ordinal))
8301 {
8302 serviceDependency.Group = Wix.YesNoType.yes;
8303 serviceDependency.Id = dependency.Substring(1);
8304 }
8305 else
8306 {
8307 serviceDependency.Id = dependency;
8308 }
8309
8310 serviceInstall.AddChild(serviceDependency);
8311 }
8312 }
8313 }
8314
8315 if (null != row[8])
8316 {
8317 serviceInstall.Account = Convert.ToString(row[8]);
8318 }
8319
8320 if (null != row[9])
8321 {
8322 serviceInstall.Password = Convert.ToString(row[9]);
8323 }
8324
8325 if (null != row[10])
8326 {
8327 serviceInstall.Arguments = Convert.ToString(row[10]);
8328 }
8329
8330 if (null != row[12])
8331 {
8332 serviceInstall.Description = Convert.ToString(row[12]);
8333 }
8334
8335 var component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[11]));
8336 if (null != component)
8337 {
8338 component.AddChild(serviceInstall);
8339 }
8340 else
8341 {
8342 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[11]), "Component"));
8343 }
8344 this.core.IndexElement(row, serviceInstall);
8345 }
8346 }
8347
8348 /// <summary>
8349 /// Decompile the SFPCatalog table.
8350 /// </summary>
8351 /// <param name="table">The table to decompile.</param>
8352 private void DecompileSFPCatalogTable(Table table)
8353 {
8354 foreach (var row in table.Rows)
8355 {
8356 var sfpCatalog = new Wix.SFPCatalog();
8357
8358 sfpCatalog.Name = Convert.ToString(row[0]);
8359
8360 sfpCatalog.SourceFile = Convert.ToString(row[1]);
8361
8362 this.core.IndexElement(row, sfpCatalog);
8363 }
8364
8365 // nest the SFPCatalog elements
8366 foreach (var row in table.Rows)
8367 {
8368 var sfpCatalog = (Wix.SFPCatalog)this.core.GetIndexedElement(row);
8369
8370 if (null != row[2])
8371 {
8372 var parentSFPCatalog = (Wix.SFPCatalog)this.core.GetIndexedElement("SFPCatalog", Convert.ToString(row[2]));
8373
8374 if (null != parentSFPCatalog)
8375 {
8376 parentSFPCatalog.AddChild(sfpCatalog);
8377 }
8378 else
8379 {
8380 sfpCatalog.Dependency = Convert.ToString(row[2]);
8381
8382 this.core.RootElement.AddChild(sfpCatalog);
8383 }
8384 }
8385 else
8386 {
8387 this.core.RootElement.AddChild(sfpCatalog);
8388 }
8389 }
8390 }
8391
8392 /// <summary>
8393 /// Decompile the Shortcut table.
8394 /// </summary>
8395 /// <param name="table">The table to decompile.</param>
8396 private void DecompileShortcutTable(Table table)
8397 {
8398 foreach (var row in table.Rows)
8399 {
8400 var shortcut = new Wix.Shortcut();
8401
8402 shortcut.Id = Convert.ToString(row[0]);
8403
8404 shortcut.Directory = Convert.ToString(row[1]);
8405
8406 var names = Common.GetNames(Convert.ToString(row[2]));
8407 if (null != names[0] && null != names[1])
8408 {
8409 shortcut.ShortName = names[0];
8410 shortcut.Name = names[1];
8411 }
8412 else if (null != names[0])
8413 {
8414 shortcut.Name = names[0];
8415 }
8416
8417 var target = Convert.ToString(row[4]);
8418 if (target.StartsWith("[", StringComparison.Ordinal) && target.EndsWith("]", StringComparison.Ordinal))
8419 {
8420 // TODO: use this value to do a "more-correct" nesting under the indicated File or CreateDirectory element
8421 shortcut.Target = target;
8422 }
8423 else
8424 {
8425 shortcut.Advertise = Wix.YesNoType.yes;
8426
8427 // primary feature is set in FinalizeFeatureComponentsTable
8428 }
8429
8430 if (null != row[5])
8431 {
8432 shortcut.Arguments = Convert.ToString(row[5]);
8433 }
8434
8435 if (null != row[6])
8436 {
8437 shortcut.Description = Convert.ToString(row[6]);
8438 }
8439
8440 if (null != row[7])
8441 {
8442 shortcut.Hotkey = Convert.ToInt32(row[7]);
8443 }
8444
8445 if (null != row[8])
8446 {
8447 shortcut.Icon = Convert.ToString(row[8]);
8448 }
8449
8450 if (null != row[9])
8451 {
8452 shortcut.IconIndex = Convert.ToInt32(row[9]);
8453 }
8454
8455 if (null != row[10])
8456 {
8457 switch (Convert.ToInt32(row[10]))
8458 {
8459 case 1:
8460 shortcut.Show = Wix.Shortcut.ShowType.normal;
8461 break;
8462 case 3:
8463 shortcut.Show = Wix.Shortcut.ShowType.maximized;
8464 break;
8465 case 7:
8466 shortcut.Show = Wix.Shortcut.ShowType.minimized;
8467 break;
8468 default:
8469 this.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[10].Column.Name, row[10]));
8470 break;
8471 }
8472 }
8473
8474 if (null != row[11])
8475 {
8476 shortcut.WorkingDirectory = Convert.ToString(row[11]);
8477 }
8478
8479 // Only try to read the MSI 4.0-specific columns if they actually exist
8480 if (15 < row.Fields.Length)
8481 {
8482 if (null != row[12])
8483 {
8484 shortcut.DisplayResourceDll = Convert.ToString(row[12]);
8485 }
8486
8487 if (null != row[13])
8488 {
8489 shortcut.DisplayResourceId = Convert.ToInt32(row[13]);
8490 }
8491
8492 if (null != row[14])
8493 {
8494 shortcut.DescriptionResourceDll = Convert.ToString(row[14]);
8495 }
8496
8497 if (null != row[15])
8498 {
8499 shortcut.DescriptionResourceId = Convert.ToInt32(row[15]);
8500 }
8501 }
8502
8503 var component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[3]));
8504 if (null != component)
8505 {
8506 component.AddChild(shortcut);
8507 }
8508 else
8509 {
8510 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[3]), "Component"));
8511 }
8512
8513 this.core.IndexElement(row, shortcut);
8514 }
8515 }
8516
8517 /// <summary>
8518 /// Decompile the Signature table.
8519 /// </summary>
8520 /// <param name="table">The table to decompile.</param>
8521 private void DecompileSignatureTable(Table table)
8522 {
8523 foreach (var row in table.Rows)
8524 {
8525 var fileSearch = new Wix.FileSearch();
8526
8527 fileSearch.Id = Convert.ToString(row[0]);
8528
8529 var names = Common.GetNames(Convert.ToString(row[1]));
8530 if (null != names[0])
8531 {
8532 // it is permissable to just have a long name
8533 if (!this.core.IsValidShortFilename(names[0], false) && null == names[1])
8534 {
8535 fileSearch.Name = names[0];
8536 }
8537 else
8538 {
8539 fileSearch.ShortName = names[0];
8540 }
8541 }
8542
8543 if (null != names[1])
8544 {
8545 fileSearch.Name = names[1];
8546 }
8547
8548 if (null != row[2])
8549 {
8550 fileSearch.MinVersion = Convert.ToString(row[2]);
8551 }
8552
8553 if (null != row[3])
8554 {
8555 fileSearch.MaxVersion = Convert.ToString(row[3]);
8556 }
8557
8558 if (null != row[4])
8559 {
8560 fileSearch.MinSize = Convert.ToInt32(row[4]);
8561 }
8562
8563 if (null != row[5])
8564 {
8565 fileSearch.MaxSize = Convert.ToInt32(row[5]);
8566 }
8567
8568 if (null != row[6])
8569 {
8570 fileSearch.MinDate = this.core.ConvertIntegerToDateTime(Convert.ToInt32(row[6]));
8571 }
8572
8573 if (null != row[7])
8574 {
8575 fileSearch.MaxDate = this.core.ConvertIntegerToDateTime(Convert.ToInt32(row[7]));
8576 }
8577
8578 if (null != row[8])
8579 {
8580 fileSearch.Languages = Convert.ToString(row[8]);
8581 }
8582
8583 this.core.IndexElement(row, fileSearch);
8584 }
8585 }
8586
8587 /// <summary>
8588 /// Decompile the TargetFiles_OptionalData table.
8589 /// </summary>
8590 /// <param name="table">The table to decompile.</param>
8591 private void DecompileTargetFiles_OptionalDataTable(Table table)
8592 {
8593 foreach (var row in table.Rows)
8594 {
8595 var targetFile = (Wix.TargetFile)this.patchTargetFiles[row[0]];
8596 if (null == targetFile)
8597 {
8598 targetFile = new Wix.TargetFile();
8599
8600 targetFile.Id = Convert.ToString(row[1]);
8601
8602 var targetImage = (Wix.TargetImage)this.core.GetIndexedElement("TargetImages", Convert.ToString(row[0]));
8603 if (null != targetImage)
8604 {
8605 targetImage.AddChild(targetFile);
8606 }
8607 else
8608 {
8609 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Target", Convert.ToString(row[0]), "TargetImages"));
8610 }
8611 this.patchTargetFiles.Add(row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), targetFile);
8612 }
8613
8614 if (null != row[2])
8615 {
8616 var symbolPaths = (Convert.ToString(row[2])).Split(';');
8617
8618 foreach (var symbolPathString in symbolPaths)
8619 {
8620 var symbolPath = new Wix.SymbolPath();
8621
8622 symbolPath.Path = symbolPathString;
8623
8624 targetFile.AddChild(symbolPath);
8625 }
8626 }
8627
8628 if (null != row[3] && null != row[4])
8629 {
8630 var ignoreOffsets = (Convert.ToString(row[3])).Split(',');
8631 var ignoreLengths = (Convert.ToString(row[4])).Split(',');
8632
8633 if (ignoreOffsets.Length == ignoreLengths.Length)
8634 {
8635 for (var i = 0; i < ignoreOffsets.Length; i++)
8636 {
8637 var ignoreRange = new Wix.IgnoreRange();
8638
8639 if (ignoreOffsets[i].StartsWith("0x", StringComparison.Ordinal))
8640 {
8641 ignoreRange.Offset = Convert.ToInt32(ignoreOffsets[i].Substring(2), 16);
8642 }
8643 else
8644 {
8645 ignoreRange.Offset = Convert.ToInt32(ignoreOffsets[i], CultureInfo.InvariantCulture);
8646 }
8647
8648 if (ignoreLengths[i].StartsWith("0x", StringComparison.Ordinal))
8649 {
8650 ignoreRange.Length = Convert.ToInt32(ignoreLengths[i].Substring(2), 16);
8651 }
8652 else
8653 {
8654 ignoreRange.Length = Convert.ToInt32(ignoreLengths[i], CultureInfo.InvariantCulture);
8655 }
8656
8657 targetFile.AddChild(ignoreRange);
8658 }
8659 }
8660 else
8661 {
8662 // TODO: warn
8663 }
8664 }
8665 else if (null != row[3] || null != row[4])
8666 {
8667 // TODO: warn about mismatch between columns
8668 }
8669
8670 // the RetainOffsets column is handled in FinalizeFamilyFileRangesTable
8671 }
8672 }
8673
8674 /// <summary>
8675 /// Decompile the TargetImages table.
8676 /// </summary>
8677 /// <param name="table">The table to decompile.</param>
8678 private void DecompileTargetImagesTable(Table table)
8679 {
8680 foreach (var row in table.Rows)
8681 {
8682 var targetImage = new Wix.TargetImage();
8683
8684 targetImage.Id = Convert.ToString(row[0]);
8685
8686 targetImage.SourceFile = Convert.ToString(row[1]);
8687
8688 if (null != row[2])
8689 {
8690 var symbolPaths = (Convert.ToString(row[3])).Split(';');
8691
8692 foreach (var symbolPathString in symbolPaths)
8693 {
8694 var symbolPath = new Wix.SymbolPath();
8695
8696 symbolPath.Path = symbolPathString;
8697
8698 targetImage.AddChild(symbolPath);
8699 }
8700 }
8701
8702 targetImage.Order = Convert.ToInt32(row[4]);
8703
8704 if (null != row[5])
8705 {
8706 targetImage.Validation = Convert.ToString(row[5]);
8707 }
8708
8709 if (0 != Convert.ToInt32(row[6]))
8710 {
8711 targetImage.IgnoreMissingFiles = Wix.YesNoType.yes;
8712 }
8713
8714 var upgradeImage = (Wix.UpgradeImage)this.core.GetIndexedElement("UpgradedImages", Convert.ToString(row[3]));
8715 if (null != upgradeImage)
8716 {
8717 upgradeImage.AddChild(targetImage);
8718 }
8719 else
8720 {
8721 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Upgraded", Convert.ToString(row[3]), "UpgradedImages"));
8722 }
8723 this.core.IndexElement(row, targetImage);
8724 }
8725 }
8726
8727 /// <summary>
8728 /// Decompile the TextStyle table.
8729 /// </summary>
8730 /// <param name="table">The table to decompile.</param>
8731 private void DecompileTextStyleTable(Table table)
8732 {
8733 foreach (var row in table.Rows)
8734 {
8735 var textStyle = new Wix.TextStyle();
8736
8737 textStyle.Id = Convert.ToString(row[0]);
8738
8739 textStyle.FaceName = Convert.ToString(row[1]);
8740
8741 textStyle.Size = Convert.ToString(row[2]);
8742
8743 if (null != row[3])
8744 {
8745 var color = Convert.ToInt32(row[3]);
8746
8747 textStyle.Red = color & 0xFF;
8748
8749 textStyle.Green = (color & 0xFF00) >> 8;
8750
8751 textStyle.Blue = (color & 0xFF0000) >> 16;
8752 }
8753
8754 if (null != row[4])
8755 {
8756 var styleBits = Convert.ToInt32(row[4]);
8757
8758 if (MsiInterop.MsidbTextStyleStyleBitsBold == (styleBits & MsiInterop.MsidbTextStyleStyleBitsBold))
8759 {
8760 textStyle.Bold = Wix.YesNoType.yes;
8761 }
8762
8763 if (MsiInterop.MsidbTextStyleStyleBitsItalic == (styleBits & MsiInterop.MsidbTextStyleStyleBitsItalic))
8764 {
8765 textStyle.Italic = Wix.YesNoType.yes;
8766 }
8767
8768 if (MsiInterop.MsidbTextStyleStyleBitsUnderline == (styleBits & MsiInterop.MsidbTextStyleStyleBitsUnderline))
8769 {
8770 textStyle.Underline = Wix.YesNoType.yes;
8771 }
8772
8773 if (MsiInterop.MsidbTextStyleStyleBitsStrike == (styleBits & MsiInterop.MsidbTextStyleStyleBitsStrike))
8774 {
8775 textStyle.Strike = Wix.YesNoType.yes;
8776 }
8777 }
8778
8779 this.core.UIElement.AddChild(textStyle);
8780 }
8781 }
8782
8783 /// <summary>
8784 /// Decompile the TypeLib table.
8785 /// </summary>
8786 /// <param name="table">The table to decompile.</param>
8787 private void DecompileTypeLibTable(Table table)
8788 {
8789 foreach (var row in table.Rows)
8790 {
8791 var typeLib = new Wix.TypeLib();
8792
8793 typeLib.Id = Convert.ToString(row[0]);
8794
8795 typeLib.Advertise = Wix.YesNoType.yes;
8796
8797 typeLib.Language = Convert.ToInt32(row[1]);
8798
8799 if (null != row[3])
8800 {
8801 var version = Convert.ToInt32(row[3]);
8802
8803 if (65536 == version)
8804 {
8805 this.Messaging.Write(WarningMessages.PossiblyIncorrectTypelibVersion(row.SourceLineNumbers, typeLib.Id));
8806 }
8807
8808 typeLib.MajorVersion = ((version & 0xFFFF00) >> 8);
8809 typeLib.MinorVersion = (version & 0xFF);
8810 }
8811
8812 if (null != row[4])
8813 {
8814 typeLib.Description = Convert.ToString(row[4]);
8815 }
8816
8817 if (null != row[5])
8818 {
8819 typeLib.HelpDirectory = Convert.ToString(row[5]);
8820 }
8821
8822 if (null != row[7])
8823 {
8824 typeLib.Cost = Convert.ToInt32(row[7]);
8825 }
8826
8827 // nested under the appropriate File element in FinalizeFileTable
8828 this.core.IndexElement(row, typeLib);
8829 }
8830 }
8831
8832 /// <summary>
8833 /// Decompile the Upgrade table.
8834 /// </summary>
8835 /// <param name="table">The table to decompile.</param>
8836 private void DecompileUpgradeTable(Table table)
8837 {
8838 var upgradeElements = new Hashtable();
8839
8840 foreach (UpgradeRow upgradeRow in table.Rows)
8841 {
8842 if (Common.UpgradeDetectedProperty == upgradeRow.ActionProperty || Common.DowngradeDetectedProperty == upgradeRow.ActionProperty)
8843 {
8844 continue; // MajorUpgrade rows processed in FinalizeUpgradeTable
8845 }
8846
8847 var upgrade = (Wix.Upgrade)upgradeElements[upgradeRow.UpgradeCode];
8848
8849 // create the parent Upgrade element if it doesn't already exist
8850 if (null == upgrade)
8851 {
8852 upgrade = new Wix.Upgrade();
8853
8854 upgrade.Id = upgradeRow.UpgradeCode;
8855
8856 this.core.RootElement.AddChild(upgrade);
8857 upgradeElements.Add(upgrade.Id, upgrade);
8858 }
8859
8860 var upgradeVersion = new Wix.UpgradeVersion();
8861
8862 if (null != upgradeRow.VersionMin)
8863 {
8864 upgradeVersion.Minimum = upgradeRow.VersionMin;
8865 }
8866
8867 if (null != upgradeRow.VersionMax)
8868 {
8869 upgradeVersion.Maximum = upgradeRow.VersionMax;
8870 }
8871
8872 if (null != upgradeRow.Language)
8873 {
8874 upgradeVersion.Language = upgradeRow.Language;
8875 }
8876
8877 if (MsiInterop.MsidbUpgradeAttributesMigrateFeatures == (upgradeRow.Attributes & MsiInterop.MsidbUpgradeAttributesMigrateFeatures))
8878 {
8879 upgradeVersion.MigrateFeatures = Wix.YesNoType.yes;
8880 }
8881
8882 if (MsiInterop.MsidbUpgradeAttributesOnlyDetect == (upgradeRow.Attributes & MsiInterop.MsidbUpgradeAttributesOnlyDetect))
8883 {
8884 upgradeVersion.OnlyDetect = Wix.YesNoType.yes;
8885 }
8886
8887 if (MsiInterop.MsidbUpgradeAttributesIgnoreRemoveFailure == (upgradeRow.Attributes & MsiInterop.MsidbUpgradeAttributesIgnoreRemoveFailure))
8888 {
8889 upgradeVersion.IgnoreRemoveFailure = Wix.YesNoType.yes;
8890 }
8891
8892 if (MsiInterop.MsidbUpgradeAttributesVersionMinInclusive == (upgradeRow.Attributes & MsiInterop.MsidbUpgradeAttributesVersionMinInclusive))
8893 {
8894 upgradeVersion.IncludeMinimum = Wix.YesNoType.yes;
8895 }
8896
8897 if (MsiInterop.MsidbUpgradeAttributesVersionMaxInclusive == (upgradeRow.Attributes & MsiInterop.MsidbUpgradeAttributesVersionMaxInclusive))
8898 {
8899 upgradeVersion.IncludeMaximum = Wix.YesNoType.yes;
8900 }
8901
8902 if (MsiInterop.MsidbUpgradeAttributesLanguagesExclusive == (upgradeRow.Attributes & MsiInterop.MsidbUpgradeAttributesLanguagesExclusive))
8903 {
8904 upgradeVersion.ExcludeLanguages = Wix.YesNoType.yes;
8905 }
8906
8907 if (null != upgradeRow.Remove)
8908 {
8909 upgradeVersion.RemoveFeatures = upgradeRow.Remove;
8910 }
8911
8912 upgradeVersion.Property = upgradeRow.ActionProperty;
8913
8914 upgrade.AddChild(upgradeVersion);
8915 }
8916 }
8917
8918 /// <summary>
8919 /// Decompile the UpgradedFiles_OptionalData table.
8920 /// </summary>
8921 /// <param name="table">The table to decompile.</param>
8922 private void DecompileUpgradedFiles_OptionalDataTable(Table table)
8923 {
8924 foreach (var row in table.Rows)
8925 {
8926 var upgradeFile = new Wix.UpgradeFile();
8927
8928 upgradeFile.File = Convert.ToString(row[1]);
8929
8930 if (null != row[2])
8931 {
8932 var symbolPaths = (Convert.ToString(row[2])).Split(';');
8933
8934 foreach (var symbolPathString in symbolPaths)
8935 {
8936 var symbolPath = new Wix.SymbolPath();
8937
8938 symbolPath.Path = symbolPathString;
8939
8940 upgradeFile.AddChild(symbolPath);
8941 }
8942 }
8943
8944 if (null != row[3] && 1 == Convert.ToInt32(row[3]))
8945 {
8946 upgradeFile.AllowIgnoreOnError = Wix.YesNoType.yes;
8947 }
8948
8949 if (null != row[4] && 0 != Convert.ToInt32(row[4]))
8950 {
8951 upgradeFile.WholeFile = Wix.YesNoType.yes;
8952 }
8953
8954 upgradeFile.Ignore = Wix.YesNoType.no;
8955
8956 var upgradeImage = (Wix.UpgradeImage)this.core.GetIndexedElement("UpgradedImages", Convert.ToString(row[0]));
8957 if (null != upgradeImage)
8958 {
8959 upgradeImage.AddChild(upgradeFile);
8960 }
8961 else
8962 {
8963 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Upgraded", Convert.ToString(row[0]), "UpgradedImages"));
8964 }
8965 }
8966 }
8967
8968 /// <summary>
8969 /// Decompile the UpgradedFilesToIgnore table.
8970 /// </summary>
8971 /// <param name="table">The table to decompile.</param>
8972 private void DecompileUpgradedFilesToIgnoreTable(Table table)
8973 {
8974 foreach (var row in table.Rows)
8975 {
8976 if ("*" != Convert.ToString(row[0]))
8977 {
8978 var upgradeFile = new Wix.UpgradeFile();
8979
8980 upgradeFile.File = Convert.ToString(row[1]);
8981
8982 upgradeFile.Ignore = Wix.YesNoType.yes;
8983
8984 var upgradeImage = (Wix.UpgradeImage)this.core.GetIndexedElement("UpgradedImages", Convert.ToString(row[0]));
8985 if (null != upgradeImage)
8986 {
8987 upgradeImage.AddChild(upgradeFile);
8988 }
8989 else
8990 {
8991 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Upgraded", Convert.ToString(row[0]), "UpgradedImages"));
8992 }
8993 }
8994 else
8995 {
8996 this.Messaging.Write(WarningMessages.UnrepresentableColumnValue(row.SourceLineNumbers, table.Name, row.Fields[0].Column.Name, row[0]));
8997 }
8998 }
8999 }
9000
9001 /// <summary>
9002 /// Decompile the UpgradedImages table.
9003 /// </summary>
9004 /// <param name="table">The table to decompile.</param>
9005 private void DecompileUpgradedImagesTable(Table table)
9006 {
9007 foreach (var row in table.Rows)
9008 {
9009 var upgradeImage = new Wix.UpgradeImage();
9010
9011 upgradeImage.Id = Convert.ToString(row[0]);
9012
9013 upgradeImage.SourceFile = Convert.ToString(row[1]);
9014
9015 if (null != row[2])
9016 {
9017 upgradeImage.SourcePatch = Convert.ToString(row[2]);
9018 }
9019
9020 if (null != row[3])
9021 {
9022 var symbolPaths = (Convert.ToString(row[3])).Split(';');
9023
9024 foreach (var symbolPathString in symbolPaths)
9025 {
9026 var symbolPath = new Wix.SymbolPath();
9027
9028 symbolPath.Path = symbolPathString;
9029
9030 upgradeImage.AddChild(symbolPath);
9031 }
9032 }
9033
9034 var family = (Wix.Family)this.core.GetIndexedElement("ImageFamilies", Convert.ToString(row[4]));
9035 if (null != family)
9036 {
9037 family.AddChild(upgradeImage);
9038 }
9039 else
9040 {
9041 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Family", Convert.ToString(row[4]), "ImageFamilies"));
9042 }
9043 this.core.IndexElement(row, upgradeImage);
9044 }
9045 }
9046
9047 /// <summary>
9048 /// Decompile the UIText table.
9049 /// </summary>
9050 /// <param name="table">The table to decompile.</param>
9051 private void DecompileUITextTable(Table table)
9052 {
9053 foreach (var row in table.Rows)
9054 {
9055 var uiText = new Wix.UIText();
9056
9057 uiText.Id = Convert.ToString(row[0]);
9058
9059 uiText.Content = Convert.ToString(row[1]);
9060
9061 this.core.UIElement.AddChild(uiText);
9062 }
9063 }
9064
9065 /// <summary>
9066 /// Decompile the Verb table.
9067 /// </summary>
9068 /// <param name="table">The table to decompile.</param>
9069 private void DecompileVerbTable(Table table)
9070 {
9071 foreach (var row in table.Rows)
9072 {
9073 var verb = new Wix.Verb();
9074
9075 verb.Id = Convert.ToString(row[1]);
9076
9077 if (null != row[2])
9078 {
9079 verb.Sequence = Convert.ToInt32(row[2]);
9080 }
9081
9082 if (null != row[3])
9083 {
9084 verb.Command = Convert.ToString(row[3]);
9085 }
9086
9087 if (null != row[4])
9088 {
9089 verb.Argument = Convert.ToString(row[4]);
9090 }
9091
9092 this.core.IndexElement(row, verb);
9093 }
9094 }
9095
9096 /// <summary>
9097 /// Gets the RegistryRootType from an integer representation of the root.
9098 /// </summary>
9099 /// <param name="sourceLineNumbers">The source line information for the root.</param>
9100 /// <param name="tableName">The name of the table containing the field.</param>
9101 /// <param name="field">The field containing the root value.</param>
9102 /// <param name="registryRootType">The strongly-typed representation of the root.</param>
9103 /// <returns>true if the value could be converted; false otherwise.</returns>
9104 private bool GetRegistryRootType(SourceLineNumber sourceLineNumbers, string tableName, Field field, out Wix.RegistryRootType registryRootType)
9105 {
9106 switch (Convert.ToInt32(field.Data))
9107 {
9108 case (-1):
9109 registryRootType = Wix.RegistryRootType.HKMU;
9110 return true;
9111 case MsiInterop.MsidbRegistryRootClassesRoot:
9112 registryRootType = Wix.RegistryRootType.HKCR;
9113 return true;
9114 case MsiInterop.MsidbRegistryRootCurrentUser:
9115 registryRootType = Wix.RegistryRootType.HKCU;
9116 return true;
9117 case MsiInterop.MsidbRegistryRootLocalMachine:
9118 registryRootType = Wix.RegistryRootType.HKLM;
9119 return true;
9120 case MsiInterop.MsidbRegistryRootUsers:
9121 registryRootType = Wix.RegistryRootType.HKU;
9122 return true;
9123 default:
9124 this.Messaging.Write(WarningMessages.IllegalColumnValue(sourceLineNumbers, tableName, field.Column.Name, field.Data));
9125 registryRootType = Wix.RegistryRootType.HKCR; // assign anything to satisfy the out parameter
9126 return false;
9127 }
9128 }
9129
9130 /// <summary>
9131 /// Set the primary feature for a component.
9132 /// </summary>
9133 /// <param name="row">The row which specifies a primary feature.</param>
9134 /// <param name="featureColumnIndex">The index of the column contaning the feature identifier.</param>
9135 /// <param name="componentColumnIndex">The index of the column containing the component identifier.</param>
9136 private void SetPrimaryFeature(Row row, int featureColumnIndex, int componentColumnIndex)
9137 {
9138 // only products contain primary features
9139 if (OutputType.Product == this.OutputType)
9140 {
9141 var featureField = row.Fields[featureColumnIndex];
9142 var componentField = row.Fields[componentColumnIndex];
9143
9144 var componentRef = (Wix.ComponentRef)this.core.GetIndexedElement("FeatureComponents", Convert.ToString(featureField.Data), Convert.ToString(componentField.Data));
9145
9146 if (null != componentRef)
9147 {
9148 componentRef.Primary = Wix.YesNoType.yes;
9149 }
9150 else
9151 {
9152 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, row.TableDefinition.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), featureField.Column.Name, Convert.ToString(featureField.Data), componentField.Column.Name, Convert.ToString(componentField.Data), "FeatureComponents"));
9153 }
9154 }
9155 }
9156
9157 /// <summary>
9158 /// Checks the InstallExecuteSequence table to determine where RemoveExistingProducts is scheduled and removes it.
9159 /// </summary>
9160 /// <param name="tables">The collection of all tables.</param>
9161 private static Wix.MajorUpgrade.ScheduleType DetermineMajorUpgradeScheduling(TableIndexedCollection tables)
9162 {
9163 var sequenceRemoveExistingProducts = 0;
9164 var sequenceInstallValidate = 0;
9165 var sequenceInstallInitialize = 0;
9166 var sequenceInstallFinalize = 0;
9167 var sequenceInstallExecute = 0;
9168 var sequenceInstallExecuteAgain = 0;
9169
9170 var installExecuteSequenceTable = tables["InstallExecuteSequence"];
9171 if (null != installExecuteSequenceTable)
9172 {
9173 var removeExistingProductsRow = -1;
9174 for (var i = 0; i < installExecuteSequenceTable.Rows.Count; i++)
9175 {
9176 var row = installExecuteSequenceTable.Rows[i];
9177 var action = Convert.ToString(row[0]);
9178 var sequence = Convert.ToInt32(row[2]);
9179
9180 switch (action)
9181 {
9182 case "RemoveExistingProducts":
9183 sequenceRemoveExistingProducts = sequence;
9184 removeExistingProductsRow = i;
9185 break;
9186 case "InstallValidate":
9187 sequenceInstallValidate = sequence;
9188 break;
9189 case "InstallInitialize":
9190 sequenceInstallInitialize = sequence;
9191 break;
9192 case "InstallExecute":
9193 sequenceInstallExecute = sequence;
9194 break;
9195 case "InstallExecuteAgain":
9196 sequenceInstallExecuteAgain = sequence;
9197 break;
9198 case "InstallFinalize":
9199 sequenceInstallFinalize = sequence;
9200 break;
9201 }
9202 }
9203
9204 installExecuteSequenceTable.Rows.RemoveAt(removeExistingProductsRow);
9205 }
9206
9207 if (0 != sequenceInstallValidate && sequenceInstallValidate < sequenceRemoveExistingProducts && sequenceRemoveExistingProducts < sequenceInstallInitialize)
9208 {
9209 return Wix.MajorUpgrade.ScheduleType.afterInstallValidate;
9210 }
9211 else if (0 != sequenceInstallInitialize && sequenceInstallInitialize < sequenceRemoveExistingProducts && sequenceRemoveExistingProducts < sequenceInstallExecute)
9212 {
9213 return Wix.MajorUpgrade.ScheduleType.afterInstallInitialize;
9214 }
9215 else if (0 != sequenceInstallExecute && sequenceInstallExecute < sequenceRemoveExistingProducts && sequenceRemoveExistingProducts < sequenceInstallExecuteAgain)
9216 {
9217 return Wix.MajorUpgrade.ScheduleType.afterInstallExecute;
9218 }
9219 else if (0 != sequenceInstallExecuteAgain && sequenceInstallExecuteAgain < sequenceRemoveExistingProducts && sequenceRemoveExistingProducts < sequenceInstallFinalize)
9220 {
9221 return Wix.MajorUpgrade.ScheduleType.afterInstallExecuteAgain;
9222 }
9223 else
9224 {
9225 return Wix.MajorUpgrade.ScheduleType.afterInstallFinalize;
9226 }
9227 }
9228 }
9229}
diff --git a/src/WixToolset.Core.WindowsInstaller/Decompile/DecompilerCore.cs b/src/WixToolset.Core.WindowsInstaller/Decompile/DecompilerCore.cs
new file mode 100644
index 00000000..17c97e09
--- /dev/null
+++ b/src/WixToolset.Core.WindowsInstaller/Decompile/DecompilerCore.cs
@@ -0,0 +1,110 @@
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
3namespace WixToolset
4{
5 using System;
6 using System.Collections;
7 using WixToolset.Data.WindowsInstaller;
8 using WixToolset.Extensibility;
9 using Wix = WixToolset.Data.Serialize;
10
11 /// <summary>
12 /// The base of the decompiler. Holds some variables used by the decompiler and extensions,
13 /// as well as some utility methods.
14 /// </summary>
15 internal class DecompilerCore
16 {
17 private readonly Hashtable elements;
18 private Wix.UI uiElement;
19
20 /// <summary>
21 /// Instantiate a new decompiler core.
22 /// </summary>
23 /// <param name="rootElement">The root element of the decompiled database.</param>
24 /// <param name="messageHandler">The message handler.</param>
25 internal DecompilerCore(Wix.IParentElement rootElement)
26 {
27 this.elements = new Hashtable();
28 this.RootElement = rootElement;
29 }
30
31 /// <summary>
32 /// Gets the root element of the decompiled output.
33 /// </summary>
34 /// <value>The root element of the decompiled output.</value>
35 public Wix.IParentElement RootElement { get; }
36
37 /// <summary>
38 /// Gets the UI element.
39 /// </summary>
40 /// <value>The UI element.</value>
41 public Wix.UI UIElement
42 {
43 get
44 {
45 if (null == this.uiElement)
46 {
47 this.uiElement = new Wix.UI();
48 this.RootElement.AddChild(this.uiElement);
49 }
50
51 return this.uiElement;
52 }
53 }
54
55 /// <summary>
56 /// Verifies if a filename is a valid short filename.
57 /// </summary>
58 /// <param name="filename">Filename to verify.</param>
59 /// <param name="allowWildcards">true if wildcards are allowed in the filename.</param>
60 /// <returns>True if the filename is a valid short filename</returns>
61 public virtual bool IsValidShortFilename(string filename, bool allowWildcards)
62 {
63 return false;
64 }
65
66 /// <summary>
67 /// Convert an Int32 into a DateTime.
68 /// </summary>
69 /// <param name="value">The Int32 value.</param>
70 /// <returns>The DateTime.</returns>
71 public DateTime ConvertIntegerToDateTime(int value)
72 {
73 var date = value / 65536;
74 var time = value % 65536;
75
76 return new DateTime(1980 + (date / 512), (date % 512) / 32, date % 32, time / 2048, (time % 2048) / 32, (time % 32) * 2);
77 }
78
79 /// <summary>
80 /// Gets the element corresponding to the row it came from.
81 /// </summary>
82 /// <param name="row">The row corresponding to the element.</param>
83 /// <returns>The indexed element.</returns>
84 public Wix.ISchemaElement GetIndexedElement(Row row)
85 {
86 return this.GetIndexedElement(row.TableDefinition.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter));
87 }
88
89 /// <summary>
90 /// Gets the element corresponding to the primary key of the given table.
91 /// </summary>
92 /// <param name="table">The table corresponding to the element.</param>
93 /// <param name="primaryKey">The primary key corresponding to the element.</param>
94 /// <returns>The indexed element.</returns>
95 public Wix.ISchemaElement GetIndexedElement(string table, params string[] primaryKey)
96 {
97 return (Wix.ISchemaElement)this.elements[String.Concat(table, ':', String.Join(DecompilerConstants.PrimaryKeyDelimiterString, primaryKey))];
98 }
99
100 /// <summary>
101 /// Index an element by its corresponding row.
102 /// </summary>
103 /// <param name="row">The row corresponding to the element.</param>
104 /// <param name="element">The element to index.</param>
105 public void IndexElement(Row row, Wix.ISchemaElement element)
106 {
107 this.elements.Add(String.Concat(row.TableDefinition.Name, ':', row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter)), element);
108 }
109 }
110}