aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBob Arnson <bob@firegiant.com>2020-08-24 17:25:00 -0400
committerBob Arnson <bob@firegiant.com>2020-08-24 18:57:49 -0400
commitc237bb3bb00d36c50271a70baac68f49890e35e1 (patch)
tree25f90ddb7b74180fc3ef299c899585f24e88809f
parent2c040e2d5b401af3607cf6e482cffeaa511d167a (diff)
downloadwix-c237bb3bb00d36c50271a70baac68f49890e35e1.tar.gz
wix-c237bb3bb00d36c50271a70baac68f49890e35e1.tar.bz2
wix-c237bb3bb00d36c50271a70baac68f49890e35e1.zip
Update decompiler to use XDocument rather than generated classes.
- Use CompareXml for diffing. - Change CustomAction/@ScriptFile to @ScriptSourceFile.
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Decompile/Decompiler.cs8217
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Decompile/DecompilerCore.cs110
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Decompile/Names.cs158
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Melter.cs1
-rw-r--r--src/WixToolset.Core/CommandLine/DecompileCommand.cs2
-rw-r--r--src/WixToolset.Core/Compiler.cs6
-rw-r--r--src/test/WixToolsetTest.CoreIntegration/CustomTableFixture.cs15
-rw-r--r--src/test/WixToolsetTest.CoreIntegration/DecompileFixture.cs140
-rw-r--r--src/test/WixToolsetTest.CoreIntegration/TestData/CustomTable/CustomTable-Expected.wxs8
9 files changed, 3427 insertions, 5230 deletions
diff --git a/src/WixToolset.Core.WindowsInstaller/Decompile/Decompiler.cs b/src/WixToolset.Core.WindowsInstaller/Decompile/Decompiler.cs
index 72985c1c..bc9e6de3 100644
--- a/src/WixToolset.Core.WindowsInstaller/Decompile/Decompiler.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Decompile/Decompiler.cs
@@ -3,9 +3,7 @@
3namespace WixToolset.Core.WindowsInstaller 3namespace WixToolset.Core.WindowsInstaller
4{ 4{
5 using System; 5 using System;
6 using System.Collections;
7 using System.Collections.Generic; 6 using System.Collections.Generic;
8 using System.Collections.Specialized;
9 using System.Globalization; 7 using System.Globalization;
10 using System.IO; 8 using System.IO;
11 using System.Linq; 9 using System.Linq;
@@ -13,13 +11,13 @@ namespace WixToolset.Core.WindowsInstaller
13 using System.Text.RegularExpressions; 11 using System.Text.RegularExpressions;
14 using System.Xml.Linq; 12 using System.Xml.Linq;
15 using WixToolset.Core; 13 using WixToolset.Core;
14 using WixToolset.Core.WindowsInstaller.Decompile;
16 using WixToolset.Data; 15 using WixToolset.Data;
17 using WixToolset.Data.Symbols; 16 using WixToolset.Data.Symbols;
18 using WixToolset.Data.WindowsInstaller; 17 using WixToolset.Data.WindowsInstaller;
19 using WixToolset.Data.WindowsInstaller.Rows; 18 using WixToolset.Data.WindowsInstaller.Rows;
20 using WixToolset.Extensibility; 19 using WixToolset.Extensibility;
21 using WixToolset.Extensibility.Services; 20 using WixToolset.Extensibility.Services;
22 using Wix = WixToolset.Data.Serialize;
23 21
24 /// <summary> 22 /// <summary>
25 /// Decompiles an msi database into WiX source. 23 /// Decompiles an msi database into WiX source.
@@ -42,14 +40,7 @@ namespace WixToolset.Core.WindowsInstaller
42 private static readonly string[] IconControlAttributes = { "Image", null, null, null, "FixedSize", "Icon16", "Icon32" }; 40 private static readonly string[] IconControlAttributes = { "Image", null, null, null, "FixedSize", "Icon16", "Icon32" };
43 private static readonly string[] BitmapControlAttributes = { "Image", null, null, null, "FixedSize" }; 41 private static readonly string[] BitmapControlAttributes = { "Image", null, null, null, "FixedSize" };
44 private static readonly string[] CheckboxControlAttributes = { null, "PushLike", "Bitmap", "Icon", "FixedSize", "Icon16", "Icon32" }; 42 private static readonly string[] CheckboxControlAttributes = { null, "PushLike", "Bitmap", "Icon", "FixedSize", "Icon16", "Icon32" };
45 43 private XElement uiElement;
46 private bool compressed;
47 private bool shortNames;
48 private DecompilerCore core;
49 private string modularizationGuid;
50 private readonly Hashtable patchTargetFiles;
51 private readonly Hashtable sequenceElements;
52 private readonly TableDefinitionCollection tableDefinitions;
53 44
54 /// <summary> 45 /// <summary>
55 /// Creates a new decompiler object with a default set of table definitions. 46 /// Creates a new decompiler object with a default set of table definitions.
@@ -58,7 +49,7 @@ namespace WixToolset.Core.WindowsInstaller
58 { 49 {
59 this.Messaging = messaging; 50 this.Messaging = messaging;
60 this.Extensions = extensions; 51 this.Extensions = extensions;
61 this.BaseSourcePath = String.IsNullOrEmpty(baseSourcePath) ? "SourceDir" : baseSourcePath; 52 this.BaseSourcePath = baseSourcePath ?? "SourceDir";
62 this.SuppressCustomTables = suppressCustomTables; 53 this.SuppressCustomTables = suppressCustomTables;
63 this.SuppressDroppingEmptyTables = suppressDroppingEmptyTables; 54 this.SuppressDroppingEmptyTables = suppressDroppingEmptyTables;
64 this.SuppressUI = suppressUI; 55 this.SuppressUI = suppressUI;
@@ -67,9 +58,7 @@ namespace WixToolset.Core.WindowsInstaller
67 this.ExtensionsByTableName = new Dictionary<string, IWindowsInstallerBackendDecompilerExtension>(); 58 this.ExtensionsByTableName = new Dictionary<string, IWindowsInstallerBackendDecompilerExtension>();
68 this.StandardActions = WindowsInstallerStandard.StandardActions().ToDictionary(a => a.Id.Id); 59 this.StandardActions = WindowsInstallerStandard.StandardActions().ToDictionary(a => a.Id.Id);
69 60
70 this.patchTargetFiles = new Hashtable(); 61 this.TableDefinitions = new TableDefinitionCollection();
71 this.sequenceElements = new Hashtable();
72 this.tableDefinitions = new TableDefinitionCollection();
73 } 62 }
74 63
75 private IMessaging Messaging { get; } 64 private IMessaging Messaging { get; }
@@ -94,6 +83,37 @@ namespace WixToolset.Core.WindowsInstaller
94 83
95 private Dictionary<string, WixActionSymbol> StandardActions { get; } 84 private Dictionary<string, WixActionSymbol> StandardActions { get; }
96 85
86 private bool Compressed { get; set; }
87
88 private XElement RootElement { get; set; }
89
90 private TableDefinitionCollection TableDefinitions { get; }
91
92 private bool ShortNames { get; set; }
93
94 private string ModularizationGuid { get; set; }
95
96 public XElement UIElement
97 {
98 get
99 {
100 if (null == this.uiElement)
101 {
102 this.uiElement = new XElement(Names.UIElement);
103 this.RootElement.Add(this.uiElement);
104 }
105
106 return this.uiElement;
107 }
108 }
109
110 public Dictionary<string, XElement> Singletons { get; } = new Dictionary<string, XElement>();
111
112 public Dictionary<string, XElement> IndexedElements { get; } = new Dictionary<string, XElement>();
113
114 public Dictionary<string, XElement> PatchTargetFiles { get; } = new Dictionary<string, XElement>();
115
116
97 /// <summary> 117 /// <summary>
98 /// Decompile the database file. 118 /// Decompile the database file.
99 /// </summary> 119 /// </summary>
@@ -109,18 +129,18 @@ namespace WixToolset.Core.WindowsInstaller
109 this.OutputType = output.Type; 129 this.OutputType = output.Type;
110 130
111 // collect the table definitions from the output 131 // collect the table definitions from the output
112 this.tableDefinitions.Clear(); 132 this.TableDefinitions.Clear();
113 foreach (var table in output.Tables) 133 foreach (var table in output.Tables)
114 { 134 {
115 this.tableDefinitions.Add(table.Definition); 135 this.TableDefinitions.Add(table.Definition);
116 } 136 }
117 137
118 // add any missing standard and wix-specific table definitions 138 // add any missing standard and wix-specific table definitions
119 foreach (var tableDefinition in WindowsInstallerTableDefinitions.All) 139 foreach (var tableDefinition in WindowsInstallerTableDefinitions.All)
120 { 140 {
121 if (!this.tableDefinitions.Contains(tableDefinition.Name)) 141 if (!this.TableDefinitions.Contains(tableDefinition.Name))
122 { 142 {
123 this.tableDefinitions.Add(tableDefinition); 143 this.TableDefinitions.Add(tableDefinition);
124 } 144 }
125 } 145 }
126 146
@@ -132,62 +152,46 @@ namespace WixToolset.Core.WindowsInstaller
132 } 152 }
133#endif 153#endif
134 154
135 var wixElement = new Wix.Wix();
136 Wix.IParentElement rootElement;
137
138 switch (this.OutputType) 155 switch (this.OutputType)
139 { 156 {
140 case OutputType.Module: 157 case OutputType.Module:
141 rootElement = new Wix.Module(); 158 this.RootElement = new XElement(Names.ModuleElement);
142 break; 159 break;
143 case OutputType.PatchCreation: 160 case OutputType.PatchCreation:
144 rootElement = new Wix.PatchCreation(); 161 this.RootElement = new XElement(Names.PatchCreationElement);
145 break; 162 break;
146 case OutputType.Product: 163 case OutputType.Product:
147 rootElement = new Wix.Product(); 164 this.RootElement = new XElement(Names.ProductElement);
148 break; 165 break;
149 default: 166 default:
150 throw new InvalidOperationException("Unknown output type."); 167 throw new InvalidOperationException("Unknown output type.");
151 } 168 }
152 wixElement.AddChild((Wix.ISchemaElement)rootElement); 169
170 var xWix = new XElement(Names.WixElement, this.RootElement);
153 171
154 // try to decompile the database file 172 // try to decompile the database file
155 try 173 // stop processing if an error previously occurred
174 if (this.Messaging.EncounteredError)
156 { 175 {
157 this.core = new DecompilerCore(rootElement); 176 return null;
158 177 }
159 // stop processing if an error previously occurred
160 if (this.Messaging.EncounteredError)
161 {
162 return null;
163 }
164
165 this.InitializeDecompile(output.Tables, output.Codepage);
166
167 // stop processing if an error previously occurred
168 if (this.Messaging.EncounteredError)
169 {
170 return null;
171 }
172 178
173 // decompile the tables 179 this.InitializeDecompile(output.Tables, output.Codepage);
174 this.DecompileTables(output);
175 180
176 // finalize the decompiler and its extensions 181 // stop processing if an error previously occurred
177 this.FinalizeDecompile(output.Tables); 182 if (this.Messaging.EncounteredError)
178 }
179 finally
180 { 183 {
181 this.core = null; 184 return null;
182 } 185 }
183 186
184 var document = new XDocument(); 187 // decompile the tables
185 using (var writer = document.CreateWriter()) 188 this.DecompileTables(output);
186 { 189
187 wixElement.OutputXml(writer); 190 // finalize the decompiler and its extensions
188 } 191 this.FinalizeDecompile(output.Tables);
189 192
190 // return the XML document only if decompilation completed successfully 193 // return the XML document only if decompilation completed successfully
194 var document = new XDocument(xWix);
191 return this.Messaging.EncounteredError ? null : document; 195 return this.Messaging.EncounteredError ? null : document;
192 } 196 }
193 197
@@ -212,50 +216,156 @@ namespace WixToolset.Core.WindowsInstaller
212#endif 216#endif
213 217
214 /// <summary> 218 /// <summary>
219 /// Gets the element corresponding to the row it came from.
220 /// </summary>
221 /// <param name="row">The row corresponding to the element.</param>
222 /// <returns>The indexed element.</returns>
223 public XElement GetIndexedElement(WixToolset.Data.WindowsInstaller.Row row) => this.GetIndexedElement(row.TableDefinition.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter));
224
225 /// <summary>
226 /// Gets the element corresponding to the primary key of the given table.
227 /// </summary>
228 /// <param name="table">The table corresponding to the element.</param>
229 /// <param name="primaryKey">The primary key corresponding to the element.</param>
230 /// <returns>The indexed element.</returns>
231 public XElement GetIndexedElement(string table, params string[] primaryKey) => this.IndexedElements[String.Concat(table, ':', String.Join(DecompilerConstants.PrimaryKeyDelimiterString, primaryKey))];
232
233 /// <summary>
234 /// Gets the element corresponding to the primary key of the given table.
235 /// </summary>
236 /// <param name="table">The table corresponding to the element.</param>
237 /// <param name="primaryKey">The primary key corresponding to the element.</param>
238 /// <returns>The indexed element.</returns>
239 public bool TryGetIndexedElement(WixToolset.Data.WindowsInstaller.Row row, out XElement xElement) => this.TryGetIndexedElement(row.TableDefinition.Name, out xElement, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter));
240
241 /// <summary>
242 /// Gets the element corresponding to the primary key of the given table.
243 /// </summary>
244 /// <param name="table">The table corresponding to the element.</param>
245 /// <param name="primaryKey">The primary key corresponding to the element.</param>
246 /// <returns>The indexed element.</returns>
247 public bool TryGetIndexedElement(string table, out XElement xElement, params string[] primaryKey) => this.IndexedElements.TryGetValue(String.Concat(table, ':', String.Join(DecompilerConstants.PrimaryKeyDelimiterString, primaryKey)), out xElement);
248
249 /// <summary>
250 /// Index an element by its corresponding row.
251 /// </summary>
252 /// <param name="row">The row corresponding to the element.</param>
253 /// <param name="element">The element to index.</param>
254 public void IndexElement(WixToolset.Data.WindowsInstaller.Row row, XElement element)
255 {
256 this.IndexedElements.Add(String.Concat(row.TableDefinition.Name, ':', row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter)), element);
257 }
258
259 /// <summary>
260 /// Index an element by its corresponding row.
261 /// </summary>
262 /// <param name="row">The row corresponding to the element.</param>
263 /// <param name="element">The element to index.</param>
264 public void IndexElement(XElement element, string table, params string[] primaryKey)
265 {
266 this.IndexedElements.Add(String.Concat(table, ':', String.Join(DecompilerConstants.PrimaryKeyDelimiterString, primaryKey)), element);
267 }
268
269 private Dictionary<string, List<XElement>> IndexTableOneToMany(IEnumerable<Row> rows, int column = 0)
270 {
271 return rows
272 .ToLookup(row => row.FieldAsString(column), row => this.GetIndexedElement(row))
273 .ToDictionary(lookup => lookup.Key, lookup => lookup.ToList());
274 }
275
276 private Dictionary<string, List<XElement>> IndexTableOneToMany(TableIndexedCollection tables, string tableName, int column = 0) => this.IndexTableOneToMany(tables[tableName]?.Rows ?? Enumerable.Empty<Row>(), column);
277
278 private Dictionary<string, List<XElement>> IndexTableOneToMany(Table table, int column = 0) => this.IndexTableOneToMany(table?.Rows ?? Enumerable.Empty<Row>(), column);
279
280 private void AddChildToParent(string parentName, XElement xChild, Row row, int column)
281 {
282 var key = row.FieldAsString(column);
283 if (this.TryGetIndexedElement(parentName, out var xParent, key))
284 {
285 xParent.Add(xChild);
286 }
287 else
288 {
289 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, row.Table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), row.Fields[column].Column.Name, key, parentName));
290 }
291 }
292
293 private static XAttribute XAttributeIfNotNull(string attributeName, Row row, int column) => row.IsColumnNull(column) ? null : new XAttribute(attributeName, row.FieldAsString(column));
294
295 private static void SetAttributeIfNotNull(XElement xElement, string attributeName, string value)
296 {
297 if (!String.IsNullOrEmpty(value))
298 {
299 xElement.SetAttributeValue(attributeName, value);
300 }
301 }
302
303 private static void SetAttributeIfNotNull(XElement xElement, string attributeName, int? value)
304 {
305 if (value.HasValue)
306 {
307 xElement.SetAttributeValue(attributeName, value);
308 }
309 }
310
311 /// <summary>
312 /// Convert an Int32 into a DateTime.
313 /// </summary>
314 /// <param name="value">The Int32 value.</param>
315 /// <returns>The DateTime.</returns>
316 private static DateTime ConvertIntegerToDateTime(int value)
317 {
318 var date = value / 65536;
319 var time = value % 65536;
320
321 return new DateTime(1980 + (date / 512), (date % 512) / 32, date % 32, time / 2048, (time % 2048) / 32, (time % 32) * 2);
322 }
323
324 /// <summary>
215 /// Set the common control attributes in a control element. 325 /// Set the common control attributes in a control element.
216 /// </summary> 326 /// </summary>
217 /// <param name="attributes">The control attributes.</param> 327 /// <param name="attributes">The control attributes.</param>
218 /// <param name="control">The control element.</param> 328 /// <param name="control">The control element.</param>
219 private static void SetControlAttributes(int attributes, Wix.Control control) 329 private static void SetControlAttributes(int attributes, XElement xControl)
220 { 330 {
221 if (0 == (attributes & WindowsInstallerConstants.MsidbControlAttributesEnabled)) 331 if (0 == (attributes & WindowsInstallerConstants.MsidbControlAttributesEnabled))
222 { 332 {
223 control.Disabled = Wix.YesNoType.yes; 333 xControl.SetAttributeValue("Disabled", "yes");
224 } 334 }
225 335
226 if (WindowsInstallerConstants.MsidbControlAttributesIndirect == (attributes & WindowsInstallerConstants.MsidbControlAttributesIndirect)) 336 if (WindowsInstallerConstants.MsidbControlAttributesIndirect == (attributes & WindowsInstallerConstants.MsidbControlAttributesIndirect))
227 { 337 {
228 control.Indirect = Wix.YesNoType.yes; 338 xControl.SetAttributeValue("Indirect", "yes");
229 } 339 }
230 340
231 if (WindowsInstallerConstants.MsidbControlAttributesInteger == (attributes & WindowsInstallerConstants.MsidbControlAttributesInteger)) 341 if (WindowsInstallerConstants.MsidbControlAttributesInteger == (attributes & WindowsInstallerConstants.MsidbControlAttributesInteger))
232 { 342 {
233 control.Integer = Wix.YesNoType.yes; 343 xControl.SetAttributeValue("Integer", "yes");
234 } 344 }
235 345
236 if (WindowsInstallerConstants.MsidbControlAttributesLeftScroll == (attributes & WindowsInstallerConstants.MsidbControlAttributesLeftScroll)) 346 if (WindowsInstallerConstants.MsidbControlAttributesLeftScroll == (attributes & WindowsInstallerConstants.MsidbControlAttributesLeftScroll))
237 { 347 {
238 control.LeftScroll = Wix.YesNoType.yes; 348 xControl.SetAttributeValue("LeftScroll", "yes");
239 } 349 }
240 350
241 if (WindowsInstallerConstants.MsidbControlAttributesRightAligned == (attributes & WindowsInstallerConstants.MsidbControlAttributesRightAligned)) 351 if (WindowsInstallerConstants.MsidbControlAttributesRightAligned == (attributes & WindowsInstallerConstants.MsidbControlAttributesRightAligned))
242 { 352 {
243 control.RightAligned = Wix.YesNoType.yes; 353 xControl.SetAttributeValue("RightAligned", "yes");
244 } 354 }
245 355
246 if (WindowsInstallerConstants.MsidbControlAttributesRTLRO == (attributes & WindowsInstallerConstants.MsidbControlAttributesRTLRO)) 356 if (WindowsInstallerConstants.MsidbControlAttributesRTLRO == (attributes & WindowsInstallerConstants.MsidbControlAttributesRTLRO))
247 { 357 {
248 control.RightToLeft = Wix.YesNoType.yes; 358 xControl.SetAttributeValue("RightToLeft", "yes");
249 } 359 }
250 360
251 if (WindowsInstallerConstants.MsidbControlAttributesSunken == (attributes & WindowsInstallerConstants.MsidbControlAttributesSunken)) 361 if (WindowsInstallerConstants.MsidbControlAttributesSunken == (attributes & WindowsInstallerConstants.MsidbControlAttributesSunken))
252 { 362 {
253 control.Sunken = Wix.YesNoType.yes; 363 xControl.SetAttributeValue("Sunken", "yes");
254 } 364 }
255 365
256 if (0 == (attributes & WindowsInstallerConstants.MsidbControlAttributesVisible)) 366 if (0 == (attributes & WindowsInstallerConstants.MsidbControlAttributesVisible))
257 { 367 {
258 control.Hidden = Wix.YesNoType.yes; 368 xControl.SetAttributeValue("Hidden", "yes");
259 } 369 }
260 } 370 }
261 371
@@ -265,137 +375,93 @@ namespace WixToolset.Core.WindowsInstaller
265 /// <param name="actionSymbol">The action from which the element should be created.</param> 375 /// <param name="actionSymbol">The action from which the element should be created.</param>
266 private void CreateActionElement(WixActionSymbol actionSymbol) 376 private void CreateActionElement(WixActionSymbol actionSymbol)
267 { 377 {
268 Wix.ISchemaElement actionElement = null; 378 XElement xAction;
269 379
270 if (null != this.core.GetIndexedElement("CustomAction", actionSymbol.Action)) // custom action 380 if (this.TryGetIndexedElement("CustomAction", out var _, actionSymbol.Action)) // custom action
271 { 381 {
272 var custom = new Wix.Custom(); 382 xAction = new XElement(Names.CustomElement,
273 383 new XAttribute("Action", actionSymbol.Action),
274 custom.Action = actionSymbol.Action; 384 String.IsNullOrEmpty(actionSymbol.Condition) ? null : new XAttribute("Condition", actionSymbol.Condition));
275
276 if (null != actionSymbol.Condition)
277 {
278 custom.Content = actionSymbol.Condition;
279 }
280 385
281 switch (actionSymbol.Sequence) 386 switch (actionSymbol.Sequence)
282 { 387 {
283 case (-4): 388 case (-4):
284 custom.OnExit = Wix.ExitType.suspend; 389 xAction.SetAttributeValue("OnExit", "suspend");
285 break; 390 break;
286 case (-3): 391 case (-3):
287 custom.OnExit = Wix.ExitType.error; 392 xAction.SetAttributeValue("OnExit", "error");
288 break; 393 break;
289 case (-2): 394 case (-2):
290 custom.OnExit = Wix.ExitType.cancel; 395 xAction.SetAttributeValue("OnExit", "cancel");
291 break; 396 break;
292 case (-1): 397 case (-1):
293 custom.OnExit = Wix.ExitType.success; 398 xAction.SetAttributeValue("OnExit", "success");
294 break; 399 break;
295 default: 400 default:
296 if (null != actionSymbol.Before) 401 if (null != actionSymbol.Before)
297 { 402 {
298 custom.Before = actionSymbol.Before; 403 xAction.SetAttributeValue("Before", actionSymbol.Before);
299 } 404 }
300 else if (null != actionSymbol.After) 405 else if (null != actionSymbol.After)
301 { 406 {
302 custom.After = actionSymbol.After; 407 xAction.SetAttributeValue("After", actionSymbol.After);
303 } 408 }
304 else if (actionSymbol.Sequence.HasValue) 409 else if (actionSymbol.Sequence.HasValue)
305 { 410 {
306 custom.Sequence = actionSymbol.Sequence.Value; 411 xAction.SetAttributeValue("Sequence", actionSymbol.Sequence.Value);
307 } 412 }
308 break; 413 break;
309 } 414 }
310
311 actionElement = custom;
312 } 415 }
313 else if (null != this.core.GetIndexedElement("Dialog", actionSymbol.Action)) // dialog 416 else if (this.TryGetIndexedElement("Dialog", out var _, actionSymbol.Action)) // dialog
314 { 417 {
315 var show = new Wix.Show(); 418 xAction = new XElement(Names.CustomElement,
316 419 new XAttribute("Dialog", actionSymbol.Action),
317 show.Dialog = actionSymbol.Action; 420 new XAttribute("Condition", actionSymbol.Condition));
318
319 if (null != actionSymbol.Condition)
320 {
321 show.Content = actionSymbol.Condition;
322 }
323 421
324 switch (actionSymbol.Sequence) 422 switch (actionSymbol.Sequence)
325 { 423 {
326 case (-4): 424 case (-4):
327 show.OnExit = Wix.ExitType.suspend; 425 xAction.SetAttributeValue("OnExit", "suspend");
328 break; 426 break;
329 case (-3): 427 case (-3):
330 show.OnExit = Wix.ExitType.error; 428 xAction.SetAttributeValue("OnExit", "error");
331 break; 429 break;
332 case (-2): 430 case (-2):
333 show.OnExit = Wix.ExitType.cancel; 431 xAction.SetAttributeValue("OnExit", "cancel");
334 break; 432 break;
335 case (-1): 433 case (-1):
336 show.OnExit = Wix.ExitType.success; 434 xAction.SetAttributeValue("OnExit", "success");
337 break; 435 break;
338 default: 436 default:
339 if (null != actionSymbol.Before) 437 SetAttributeIfNotNull(xAction, "Before", actionSymbol.Before);
340 { 438 SetAttributeIfNotNull(xAction, "After", actionSymbol.After);
341 show.Before = actionSymbol.Before; 439 SetAttributeIfNotNull(xAction, "Sequence", actionSymbol.Sequence);
342 } 440 break;
343 else if (null != actionSymbol.After)
344 {
345 show.After = actionSymbol.After;
346 }
347 else if (actionSymbol.Sequence.HasValue)
348 {
349 show.Sequence = actionSymbol.Sequence.Value;
350 }
351 break;
352 } 441 }
353
354 actionElement = show;
355 } 442 }
356 else // possibly a standard action without suggested sequence information 443 else // possibly a standard action without suggested sequence information
357 { 444 {
358 actionElement = this.CreateStandardActionElement(actionSymbol); 445 xAction = this.CreateStandardActionElement(actionSymbol);
359 } 446 }
360 447
361 // add the action element to the appropriate sequence element 448 // add the action element to the appropriate sequence element
362 if (null != actionElement) 449 if (null != xAction)
363 { 450 {
364 var sequenceTable = actionSymbol.SequenceTable.ToString(); 451 var sequenceTable = actionSymbol.SequenceTable.ToString();
365 var sequenceElement = (Wix.IParentElement)this.sequenceElements[sequenceTable]; 452 if (!this.Singletons.TryGetValue(sequenceTable, out var xSequence))
366
367 if (null == sequenceElement)
368 { 453 {
369 switch (actionSymbol.SequenceTable) 454 xSequence = new XElement(Names.WxsNamespace + sequenceTable);
370 {
371 case SequenceTable.AdminExecuteSequence:
372 sequenceElement = new Wix.AdminExecuteSequence();
373 break;
374 case SequenceTable.AdminUISequence:
375 sequenceElement = new Wix.AdminUISequence();
376 break;
377 case SequenceTable.AdvertiseExecuteSequence:
378 sequenceElement = new Wix.AdvertiseExecuteSequence();
379 break;
380 case SequenceTable.InstallExecuteSequence:
381 sequenceElement = new Wix.InstallExecuteSequence();
382 break;
383 case SequenceTable.InstallUISequence:
384 sequenceElement = new Wix.InstallUISequence();
385 break;
386 default:
387 throw new InvalidOperationException("Unknown sequence table.");
388 }
389 455
390 this.core.RootElement.AddChild((Wix.ISchemaElement)sequenceElement); 456 this.RootElement.Add(xSequence);
391 this.sequenceElements.Add(sequenceTable, sequenceElement); 457 this.Singletons.Add(sequenceTable, xSequence);
392 } 458 }
393 459
394 try 460 try
395 { 461 {
396 sequenceElement.AddChild(actionElement); 462 xSequence.Add(xAction);
397 } 463 }
398 catch (System.ArgumentException) // action/dialog is not valid for this sequence 464 catch (ArgumentException) // action/dialog is not valid for this sequence
399 { 465 {
400 this.Messaging.Write(WarningMessages.IllegalActionInSequence(actionSymbol.SourceLineNumbers, actionSymbol.SequenceTable.ToString(), actionSymbol.Action)); 466 this.Messaging.Write(WarningMessages.IllegalActionInSequence(actionSymbol.SourceLineNumbers, actionSymbol.SequenceTable.ToString(), actionSymbol.Action));
401 } 467 }
@@ -407,294 +473,129 @@ namespace WixToolset.Core.WindowsInstaller
407 /// </summary> 473 /// </summary>
408 /// <param name="actionSymbol">The action row from which the element should be created.</param> 474 /// <param name="actionSymbol">The action row from which the element should be created.</param>
409 /// <returns>The created element.</returns> 475 /// <returns>The created element.</returns>
410 private Wix.ISchemaElement CreateStandardActionElement(WixActionSymbol actionSymbol) 476 private XElement CreateStandardActionElement(WixActionSymbol actionSymbol)
411 { 477 {
412 Wix.ActionSequenceType actionElement = null; 478 XElement xStandardAction = null;
413 479
414 switch (actionSymbol.Action) 480 switch (actionSymbol.Action)
415 { 481 {
416 case "AllocateRegistrySpace": 482 case "AllocateRegistrySpace":
417 actionElement = new Wix.AllocateRegistrySpace(); 483 case "BindImage":
418 break; 484 case "CostFinalize":
419 case "AppSearch": 485 case "CostInitialize":
420 this.StandardActions.TryGetValue(actionSymbol.Id.Id, out var appSearchActionRow); 486 case "CreateFolders":
421 487 case "CreateShortcuts":
422 if (null != actionSymbol.Before || null != actionSymbol.After || (null != appSearchActionRow && actionSymbol.Sequence != appSearchActionRow.Sequence)) 488 case "DeleteServices":
423 { 489 case "DuplicateFiles":
424 var appSearch = new Wix.AppSearch(); 490 case "ExecuteAction":
425 491 case "FileCost":
426 if (null != actionSymbol.Condition) 492 case "InstallAdminPackage":
427 { 493 case "InstallFiles":
428 appSearch.Content = actionSymbol.Condition; 494 case "InstallFinalize":
429 } 495 case "InstallInitialize":
430 496 case "InstallODBC":
431 if (null != actionSymbol.Before) 497 case "InstallServices":
432 { 498 case "InstallValidate":
433 appSearch.Before = actionSymbol.Before; 499 case "IsolateComponents":
434 } 500 case "MigrateFeatureStates":
435 else if (null != actionSymbol.After) 501 case "MoveFiles":
436 { 502 case "MsiPublishAssemblies":
437 appSearch.After = actionSymbol.After; 503 case "MsiUnpublishAssemblies":
438 } 504 case "PatchFiles":
439 else if (actionSymbol.Sequence.HasValue) 505 case "ProcessComponents":
440 { 506 case "PublishComponents":
441 appSearch.Sequence = actionSymbol.Sequence.Value; 507 case "PublishFeatures":
442 } 508 case "PublishProduct":
443 509 case "RegisterClassInfo":
444 return appSearch; 510 case "RegisterComPlus":
445 } 511 case "RegisterExtensionInfo":
446 break; 512 case "RegisterFonts":
447 case "BindImage": 513 case "RegisterMIMEInfo":
448 actionElement = new Wix.BindImage(); 514 case "RegisterProduct":
449 break; 515 case "RegisterProgIdInfo":
450 case "CCPSearch": 516 case "RegisterTypeLibraries":
451 var ccpSearch = new Wix.CCPSearch(); 517 case "RegisterUser":
452 Decompiler.SequenceRelativeAction(actionSymbol, ccpSearch); 518 case "RemoveDuplicateFiles":
453 return ccpSearch; 519 case "RemoveEnvironmentStrings":
454 case "CostFinalize": 520 case "RemoveFiles":
455 actionElement = new Wix.CostFinalize(); 521 case "RemoveFolders":
456 break; 522 case "RemoveIniValues":
457 case "CostInitialize": 523 case "RemoveODBC":
458 actionElement = new Wix.CostInitialize(); 524 case "RemoveRegistryValues":
459 break; 525 case "RemoveShortcuts":
460 case "CreateFolders": 526 case "SelfRegModules":
461 actionElement = new Wix.CreateFolders(); 527 case "SelfUnregModules":
462 break; 528 case "SetODBCFolders":
463 case "CreateShortcuts": 529 case "StartServices":
464 actionElement = new Wix.CreateShortcuts(); 530 case "StopServices":
465 break; 531 case "UnpublishComponents":
466 case "DeleteServices": 532 case "UnpublishFeatures":
467 actionElement = new Wix.DeleteServices(); 533 case "UnregisterClassInfo":
468 break; 534 case "UnregisterComPlus":
469 case "DisableRollback": 535 case "UnregisterExtensionInfo":
470 var disableRollback = new Wix.DisableRollback(); 536 case "UnregisterFonts":
471 Decompiler.SequenceRelativeAction(actionSymbol, disableRollback); 537 case "UnregisterMIMEInfo":
472 return disableRollback; 538 case "UnregisterProgIdInfo":
473 case "DuplicateFiles": 539 case "UnregisterTypeLibraries":
474 actionElement = new Wix.DuplicateFiles(); 540 case "ValidateProductID":
475 break; 541 case "WriteEnvironmentStrings":
476 case "ExecuteAction": 542 case "WriteIniValues":
477 actionElement = new Wix.ExecuteAction(); 543 case "WriteRegistryValues":
478 break; 544 xStandardAction = new XElement(Names.WxsNamespace + actionSymbol.Action);
479 case "FileCost": 545 break;
480 actionElement = new Wix.FileCost(); 546
481 break; 547 case "AppSearch":
482 case "FindRelatedProducts": 548 this.StandardActions.TryGetValue(actionSymbol.Id.Id, out var appSearchActionRow);
483 var findRelatedProducts = new Wix.FindRelatedProducts(); 549
484 Decompiler.SequenceRelativeAction(actionSymbol, findRelatedProducts); 550 if (null != actionSymbol.Before || null != actionSymbol.After || (null != appSearchActionRow && actionSymbol.Sequence != appSearchActionRow.Sequence))
485 return findRelatedProducts; 551 {
486 case "ForceReboot": 552 xStandardAction = new XElement(Names.AppSearchElement);
487 var forceReboot = new Wix.ForceReboot(); 553
488 Decompiler.SequenceRelativeAction(actionSymbol, forceReboot); 554 SetAttributeIfNotNull(xStandardAction, "Condition", actionSymbol.Condition);
489 return forceReboot; 555 SetAttributeIfNotNull(xStandardAction, "Before", actionSymbol.Before);
490 case "InstallAdminPackage": 556 SetAttributeIfNotNull(xStandardAction, "After", actionSymbol.After);
491 actionElement = new Wix.InstallAdminPackage(); 557 SetAttributeIfNotNull(xStandardAction, "Sequence", actionSymbol.Sequence);
492 break; 558
493 case "InstallExecute": 559 return xStandardAction;
494 var installExecute = new Wix.InstallExecute(); 560 }
495 Decompiler.SequenceRelativeAction(actionSymbol, installExecute); 561 break;
496 return installExecute; 562
497 case "InstallExecuteAgain": 563 case "CCPSearch":
498 var installExecuteAgain = new Wix.InstallExecuteAgain(); 564 case "DisableRollback":
499 Decompiler.SequenceRelativeAction(actionSymbol, installExecuteAgain); 565 case "FindRelatedProducts":
500 return installExecuteAgain; 566 case "ForceReboot":
501 case "InstallFiles": 567 case "InstallExecute":
502 actionElement = new Wix.InstallFiles(); 568 case "InstallExecuteAgain":
503 break; 569 case "LaunchConditions":
504 case "InstallFinalize": 570 case "RemoveExistingProducts":
505 actionElement = new Wix.InstallFinalize(); 571 case "ResolveSource":
506 break; 572 case "RMCCPSearch":
507 case "InstallInitialize": 573 case "ScheduleReboot":
508 actionElement = new Wix.InstallInitialize(); 574 xStandardAction = new XElement(Names.WxsNamespace + actionSymbol.Action);
509 break; 575 Decompiler.SequenceRelativeAction(actionSymbol, xStandardAction);
510 case "InstallODBC": 576 return xStandardAction;
511 actionElement = new Wix.InstallODBC(); 577
512 break; 578 default:
513 case "InstallServices": 579 this.Messaging.Write(WarningMessages.UnknownAction(actionSymbol.SourceLineNumbers, actionSymbol.SequenceTable.ToString(), actionSymbol.Action));
514 actionElement = new Wix.InstallServices(); 580 return null;
515 break;
516 case "InstallValidate":
517 actionElement = new Wix.InstallValidate();
518 break;
519 case "IsolateComponents":
520 actionElement = new Wix.IsolateComponents();
521 break;
522 case "LaunchConditions":
523 var launchConditions = new Wix.LaunchConditions();
524 Decompiler.SequenceRelativeAction(actionSymbol, launchConditions);
525 return launchConditions;
526 case "MigrateFeatureStates":
527 actionElement = new Wix.MigrateFeatureStates();
528 break;
529 case "MoveFiles":
530 actionElement = new Wix.MoveFiles();
531 break;
532 case "MsiPublishAssemblies":
533 actionElement = new Wix.MsiPublishAssemblies();
534 break;
535 case "MsiUnpublishAssemblies":
536 actionElement = new Wix.MsiUnpublishAssemblies();
537 break;
538 case "PatchFiles":
539 actionElement = new Wix.PatchFiles();
540 break;
541 case "ProcessComponents":
542 actionElement = new Wix.ProcessComponents();
543 break;
544 case "PublishComponents":
545 actionElement = new Wix.PublishComponents();
546 break;
547 case "PublishFeatures":
548 actionElement = new Wix.PublishFeatures();
549 break;
550 case "PublishProduct":
551 actionElement = new Wix.PublishProduct();
552 break;
553 case "RegisterClassInfo":
554 actionElement = new Wix.RegisterClassInfo();
555 break;
556 case "RegisterComPlus":
557 actionElement = new Wix.RegisterComPlus();
558 break;
559 case "RegisterExtensionInfo":
560 actionElement = new Wix.RegisterExtensionInfo();
561 break;
562 case "RegisterFonts":
563 actionElement = new Wix.RegisterFonts();
564 break;
565 case "RegisterMIMEInfo":
566 actionElement = new Wix.RegisterMIMEInfo();
567 break;
568 case "RegisterProduct":
569 actionElement = new Wix.RegisterProduct();
570 break;
571 case "RegisterProgIdInfo":
572 actionElement = new Wix.RegisterProgIdInfo();
573 break;
574 case "RegisterTypeLibraries":
575 actionElement = new Wix.RegisterTypeLibraries();
576 break;
577 case "RegisterUser":
578 actionElement = new Wix.RegisterUser();
579 break;
580 case "RemoveDuplicateFiles":
581 actionElement = new Wix.RemoveDuplicateFiles();
582 break;
583 case "RemoveEnvironmentStrings":
584 actionElement = new Wix.RemoveEnvironmentStrings();
585 break;
586 case "RemoveExistingProducts":
587 var removeExistingProducts = new Wix.RemoveExistingProducts();
588 Decompiler.SequenceRelativeAction(actionSymbol, removeExistingProducts);
589 return removeExistingProducts;
590 case "RemoveFiles":
591 actionElement = new Wix.RemoveFiles();
592 break;
593 case "RemoveFolders":
594 actionElement = new Wix.RemoveFolders();
595 break;
596 case "RemoveIniValues":
597 actionElement = new Wix.RemoveIniValues();
598 break;
599 case "RemoveODBC":
600 actionElement = new Wix.RemoveODBC();
601 break;
602 case "RemoveRegistryValues":
603 actionElement = new Wix.RemoveRegistryValues();
604 break;
605 case "RemoveShortcuts":
606 actionElement = new Wix.RemoveShortcuts();
607 break;
608 case "ResolveSource":
609 var resolveSource = new Wix.ResolveSource();
610 Decompiler.SequenceRelativeAction(actionSymbol, resolveSource);
611 return resolveSource;
612 case "RMCCPSearch":
613 var rmccpSearch = new Wix.RMCCPSearch();
614 Decompiler.SequenceRelativeAction(actionSymbol, rmccpSearch);
615 return rmccpSearch;
616 case "ScheduleReboot":
617 var scheduleReboot = new Wix.ScheduleReboot();
618 Decompiler.SequenceRelativeAction(actionSymbol, scheduleReboot);
619 return scheduleReboot;
620 case "SelfRegModules":
621 actionElement = new Wix.SelfRegModules();
622 break;
623 case "SelfUnregModules":
624 actionElement = new Wix.SelfUnregModules();
625 break;
626 case "SetODBCFolders":
627 actionElement = new Wix.SetODBCFolders();
628 break;
629 case "StartServices":
630 actionElement = new Wix.StartServices();
631 break;
632 case "StopServices":
633 actionElement = new Wix.StopServices();
634 break;
635 case "UnpublishComponents":
636 actionElement = new Wix.UnpublishComponents();
637 break;
638 case "UnpublishFeatures":
639 actionElement = new Wix.UnpublishFeatures();
640 break;
641 case "UnregisterClassInfo":
642 actionElement = new Wix.UnregisterClassInfo();
643 break;
644 case "UnregisterComPlus":
645 actionElement = new Wix.UnregisterComPlus();
646 break;
647 case "UnregisterExtensionInfo":
648 actionElement = new Wix.UnregisterExtensionInfo();
649 break;
650 case "UnregisterFonts":
651 actionElement = new Wix.UnregisterFonts();
652 break;
653 case "UnregisterMIMEInfo":
654 actionElement = new Wix.UnregisterMIMEInfo();
655 break;
656 case "UnregisterProgIdInfo":
657 actionElement = new Wix.UnregisterProgIdInfo();
658 break;
659 case "UnregisterTypeLibraries":
660 actionElement = new Wix.UnregisterTypeLibraries();
661 break;
662 case "ValidateProductID":
663 actionElement = new Wix.ValidateProductID();
664 break;
665 case "WriteEnvironmentStrings":
666 actionElement = new Wix.WriteEnvironmentStrings();
667 break;
668 case "WriteIniValues":
669 actionElement = new Wix.WriteIniValues();
670 break;
671 case "WriteRegistryValues":
672 actionElement = new Wix.WriteRegistryValues();
673 break;
674 default:
675 this.Messaging.Write(WarningMessages.UnknownAction(actionSymbol.SourceLineNumbers, actionSymbol.SequenceTable.ToString(), actionSymbol.Action));
676 return null;
677 } 581 }
678 582
679 if (actionElement != null) 583 if (xStandardAction != null)
680 { 584 {
681 this.SequenceStandardAction(actionSymbol, actionElement); 585 this.SequenceStandardAction(actionSymbol, xStandardAction);
682 } 586 }
683 587
684 return actionElement; 588 return xStandardAction;
685 } 589 }
686 590
687 /// <summary> 591 /// <summary>
688 /// Applies the condition and sequence to a standard action element based on the action row data. 592 /// Applies the condition and sequence to a standard action element based on the action symbol data.
689 /// </summary> 593 /// </summary>
690 /// <param name="actionSymbol">Action data from the database.</param> 594 /// <param name="actionSymbol">Action data from the database.</param>
691 /// <param name="actionElement">Element to be sequenced.</param> 595 /// <param name="xAction">Element to be sequenced.</param>
692 private void SequenceStandardAction(WixActionSymbol actionSymbol, Wix.ActionSequenceType actionElement) 596 private void SequenceStandardAction(WixActionSymbol actionSymbol, XElement xAction)
693 { 597 {
694 if (null != actionSymbol.Condition) 598 xAction.SetAttributeValue("Condition", actionSymbol.Condition);
695 {
696 actionElement.Content = actionSymbol.Condition;
697 }
698 599
699 if ((null != actionSymbol.Before || null != actionSymbol.After) && 0 == actionSymbol.Sequence) 600 if ((null != actionSymbol.Before || null != actionSymbol.After) && 0 == actionSymbol.Sequence)
700 { 601 {
@@ -702,7 +603,7 @@ namespace WixToolset.Core.WindowsInstaller
702 } 603 }
703 else if (actionSymbol.Sequence.HasValue) 604 else if (actionSymbol.Sequence.HasValue)
704 { 605 {
705 actionElement.Sequence = actionSymbol.Sequence.Value; 606 xAction.SetAttributeValue("Sequence", actionSymbol.Sequence.Value);
706 } 607 }
707 } 608 }
708 609
@@ -710,26 +611,13 @@ namespace WixToolset.Core.WindowsInstaller
710 /// Applies the condition and relative sequence to an action element based on the action row data. 611 /// Applies the condition and relative sequence to an action element based on the action row data.
711 /// </summary> 612 /// </summary>
712 /// <param name="actionSymbol">Action data from the database.</param> 613 /// <param name="actionSymbol">Action data from the database.</param>
713 /// <param name="actionElement">Element to be sequenced.</param> 614 /// <param name="xAction">Element to be sequenced.</param>
714 private static void SequenceRelativeAction(WixActionSymbol actionSymbol, Wix.ActionModuleSequenceType actionElement) 615 private static void SequenceRelativeAction(WixActionSymbol actionSymbol, XElement xAction)
715 { 616 {
716 if (null != actionSymbol.Condition) 617 SetAttributeIfNotNull(xAction, "Condition", actionSymbol.Condition);
717 { 618 SetAttributeIfNotNull(xAction, "Before", actionSymbol.Before);
718 actionElement.Content = actionSymbol.Condition; 619 SetAttributeIfNotNull(xAction, "After", actionSymbol.After);
719 } 620 SetAttributeIfNotNull(xAction, "Sequence", actionSymbol.Sequence);
720
721 if (null != actionSymbol.Before)
722 {
723 actionElement.Before = actionSymbol.Before;
724 }
725 else if (null != actionSymbol.After)
726 {
727 actionElement.After = actionSymbol.After;
728 }
729 else if (actionSymbol.Sequence.HasValue)
730 {
731 actionElement.Sequence = actionSymbol.Sequence.Value;
732 }
733 } 621 }
734 622
735 /// <summary> 623 /// <summary>
@@ -737,24 +625,19 @@ namespace WixToolset.Core.WindowsInstaller
737 /// </summary> 625 /// </summary>
738 /// <param name="id">The identifier of the property.</param> 626 /// <param name="id">The identifier of the property.</param>
739 /// <returns>The property element.</returns> 627 /// <returns>The property element.</returns>
740 private Wix.Property EnsureProperty(string id) 628 private XElement EnsureProperty(string id)
741 { 629 {
742 var property = (Wix.Property)this.core.GetIndexedElement("Property", id); 630 XElement xProperty;
743 631
744 if (null == property) 632 if (!this.TryGetIndexedElement("Property", out xProperty, id))
745 { 633 {
746 property = new Wix.Property(); 634 xProperty = new XElement(Names.PropertyElement, new XAttribute("Id", id));
747 property.Id = id;
748
749 // create a dummy row for indexing
750 var row = this.tableDefinitions["Property"].CreateRow(null);
751 row[0] = id;
752 635
753 this.core.RootElement.AddChild(property); 636 this.RootElement.Add(xProperty);
754 this.core.IndexElement(row, property); 637 this.IndexElement(xProperty, "Property", id);
755 } 638 }
756 639
757 return property; 640 return xProperty;
758 } 641 }
759 642
760 /// <summary> 643 /// <summary>
@@ -809,51 +692,37 @@ namespace WixToolset.Core.WindowsInstaller
809 var checkBoxTable = tables["CheckBox"]; 692 var checkBoxTable = tables["CheckBox"];
810 var controlTable = tables["Control"]; 693 var controlTable = tables["Control"];
811 694
812 var checkBoxes = new Hashtable(); 695 var checkBoxes = checkBoxTable?.Rows.ToDictionary(row => row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter));
813 var checkBoxProperties = new Hashtable(); 696 var checkBoxProperties = checkBoxTable?.Rows.ToDictionary(row => row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), row => false);
814
815 // index the CheckBox table
816 if (null != checkBoxTable)
817 {
818 foreach (var row in checkBoxTable.Rows)
819 {
820 checkBoxes.Add(row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), row);
821 checkBoxProperties.Add(row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), false);
822 }
823 }
824 697
825 // enumerate through the Control table, adding CheckBox values where appropriate 698 // enumerate through the Control table, adding CheckBox values where appropriate
826 if (null != controlTable) 699 if (null != controlTable)
827 { 700 {
828 foreach (var row in controlTable.Rows) 701 foreach (var row in controlTable.Rows)
829 { 702 {
830 var control = (Wix.Control)this.core.GetIndexedElement(row); 703 var xControl = this.GetIndexedElement(row);
831 704
832 if ("CheckBox" == Convert.ToString(row[2]) && null != row[8]) 705 if ("CheckBox" == row.FieldAsString(2))
833 { 706 {
834 var checkBoxRow = (Row)checkBoxes[row[8]]; 707 var property = row.FieldAsString(8);
835 708 if (!String.IsNullOrEmpty(property) && checkBoxes.TryGetValue(property, out var checkBoxRow))
836 if (null == checkBoxRow)
837 {
838 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, "Control", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Property", Convert.ToString(row[8]), "CheckBox"));
839 }
840 else
841 { 709 {
842 // if we've seen this property already, create a reference to it 710 // if we've seen this property already, create a reference to it
843 if (Convert.ToBoolean(checkBoxProperties[row[8]])) 711 if (checkBoxProperties.TryGetValue(property, out var seen) && seen)
844 { 712 {
845 control.CheckBoxPropertyRef = Convert.ToString(row[8]); 713 xControl.SetAttributeValue("CheckBoxPropertyRef", property);
846 } 714 }
847 else 715 else
848 { 716 {
849 control.Property = Convert.ToString(row[8]); 717 xControl.SetAttributeValue("Property", property);
850 checkBoxProperties[row[8]] = true; 718 checkBoxProperties[property] = true;
851 } 719 }
852 720
853 if (null != checkBoxRow[1]) 721 xControl.SetAttributeValue("CheckBoxValue", checkBoxRow.FieldAsString(1));
854 { 722 }
855 control.CheckBoxValue = Convert.ToString(checkBoxRow[1]); 723 else
856 } 724 {
725 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, "Control", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Property", row.FieldAsString(8), "CheckBox"));
857 } 726 }
858 } 727 }
859 } 728 }
@@ -879,60 +748,52 @@ namespace WixToolset.Core.WindowsInstaller
879 { 748 {
880 foreach (var row in componentTable.Rows) 749 foreach (var row in componentTable.Rows)
881 { 750 {
882 var attributes = Convert.ToInt32(row[3]); 751 var attributes = row.FieldAsInteger(3);
752 var keyPath = row.FieldAsString(5);
883 753
884 if (null == row[5]) 754 if (String.IsNullOrEmpty(keyPath))
885 { 755 {
886 var component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[0])); 756 var xComponent = this.GetIndexedElement("Component", row.FieldAsString(0));
887 757 xComponent.SetAttributeValue("KeyPath", "yes");
888 component.KeyPath = Wix.YesNoType.yes;
889 } 758 }
890 else if (WindowsInstallerConstants.MsidbComponentAttributesRegistryKeyPath == (attributes & WindowsInstallerConstants.MsidbComponentAttributesRegistryKeyPath)) 759 else if (WindowsInstallerConstants.MsidbComponentAttributesRegistryKeyPath == (attributes & WindowsInstallerConstants.MsidbComponentAttributesRegistryKeyPath))
891 { 760 {
892 object registryObject = this.core.GetIndexedElement("Registry", Convert.ToString(row[5])); 761 if (this.TryGetIndexedElement("Registry", out var xRegistry, keyPath))
893
894 if (null != registryObject)
895 { 762 {
896 var registryValue = registryObject as Wix.RegistryValue; 763 if (xRegistry.Name.LocalName == "RegistryValue")
897
898 if (null != registryValue)
899 { 764 {
900 registryValue.KeyPath = Wix.YesNoType.yes; 765 xRegistry.SetAttributeValue("KeyPath", "yes");
901 } 766 }
902 else 767 else
903 { 768 {
904 this.Messaging.Write(WarningMessages.IllegalRegistryKeyPath(row.SourceLineNumbers, "Component", Convert.ToString(row[5]))); 769 this.Messaging.Write(WarningMessages.IllegalRegistryKeyPath(row.SourceLineNumbers, "Component", keyPath));
905 } 770 }
906 } 771 }
907 else 772 else
908 { 773 {
909 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, "Component", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "KeyPath", Convert.ToString(row[5]), "Registry")); 774 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, "Component", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "KeyPath", keyPath, "Registry"));
910 } 775 }
911 } 776 }
912 else if (WindowsInstallerConstants.MsidbComponentAttributesODBCDataSource == (attributes & WindowsInstallerConstants.MsidbComponentAttributesODBCDataSource)) 777 else if (WindowsInstallerConstants.MsidbComponentAttributesODBCDataSource == (attributes & WindowsInstallerConstants.MsidbComponentAttributesODBCDataSource))
913 { 778 {
914 var odbcDataSource = (Wix.ODBCDataSource)this.core.GetIndexedElement("ODBCDataSource", Convert.ToString(row[5])); 779 if (this.TryGetIndexedElement("ODBCDataSource", out var xOdbcDataSource, keyPath))
915
916 if (null != odbcDataSource)
917 { 780 {
918 odbcDataSource.KeyPath = Wix.YesNoType.yes; 781 xOdbcDataSource.SetAttributeValue("KeyPath", "yes");
919 } 782 }
920 else 783 else
921 { 784 {
922 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, "Component", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "KeyPath", Convert.ToString(row[5]), "ODBCDataSource")); 785 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, "Component", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "KeyPath", keyPath, "ODBCDataSource"));
923 } 786 }
924 } 787 }
925 else 788 else
926 { 789 {
927 var file = (Wix.File)this.core.GetIndexedElement("File", Convert.ToString(row[5])); 790 if (this.TryGetIndexedElement("File", out var xFile, keyPath))
928
929 if (null != file)
930 { 791 {
931 file.KeyPath = Wix.YesNoType.yes; 792 xFile.SetAttributeValue("KeyPath", "yes");
932 } 793 }
933 else 794 else
934 { 795 {
935 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, "Component", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "KeyPath", Convert.ToString(row[5]), "File")); 796 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, "Component", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "KeyPath", keyPath, "File"));
936 } 797 }
937 } 798 }
938 } 799 }
@@ -943,12 +804,10 @@ namespace WixToolset.Core.WindowsInstaller
943 { 804 {
944 foreach (FileRow fileRow in fileTable.Rows) 805 foreach (FileRow fileRow in fileTable.Rows)
945 { 806 {
946 var component = (Wix.Component)this.core.GetIndexedElement("Component", fileRow.Component); 807 if (this.TryGetIndexedElement("Component", out var xComponent, fileRow.Component)
947 var file = (Wix.File)this.core.GetIndexedElement(fileRow); 808 && this.TryGetIndexedElement(fileRow, out var xFile))
948
949 if (null != component)
950 { 809 {
951 component.AddChild(file); 810 xComponent.Add(xFile);
952 } 811 }
953 else 812 else
954 { 813 {
@@ -962,16 +821,14 @@ namespace WixToolset.Core.WindowsInstaller
962 { 821 {
963 foreach (var row in odbcDataSourceTable.Rows) 822 foreach (var row in odbcDataSourceTable.Rows)
964 { 823 {
965 var component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[1])); 824 if (this.TryGetIndexedElement("Component", out var xComponent, row.FieldAsString(1))
966 var odbcDataSource = (Wix.ODBCDataSource)this.core.GetIndexedElement(row); 825 && this.TryGetIndexedElement(row, out var xOdbcDataSource))
967
968 if (null != component)
969 { 826 {
970 component.AddChild(odbcDataSource); 827 xComponent.Add(xOdbcDataSource);
971 } 828 }
972 else 829 else
973 { 830 {
974 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, "ODBCDataSource", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[1]), "Component")); 831 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, "ODBCDataSource", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", row.FieldAsString(1), "Component"));
975 } 832 }
976 } 833 }
977 } 834 }
@@ -981,16 +838,14 @@ namespace WixToolset.Core.WindowsInstaller
981 { 838 {
982 foreach (var row in registryTable.Rows) 839 foreach (var row in registryTable.Rows)
983 { 840 {
984 var component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[5])); 841 if (this.TryGetIndexedElement("Component", out var xComponent, row.FieldAsString(5))
985 var registryElement = this.core.GetIndexedElement(row); 842 && this.TryGetIndexedElement(row, out var xRegistry))
986
987 if (null != component)
988 { 843 {
989 component.AddChild(registryElement); 844 xComponent.Add(xRegistry);
990 } 845 }
991 else 846 else
992 { 847 {
993 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, "Registry", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[5]), "Component")); 848 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, "Registry", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", row.FieldAsString(5), "Component"));
994 } 849 }
995 } 850 }
996 } 851 }
@@ -1012,92 +867,82 @@ namespace WixToolset.Core.WindowsInstaller
1012 return; 867 return;
1013 } 868 }
1014 869
1015 var controlTable = tables["Control"]; 870 var addedControls = new HashSet<XElement>();
1016 var dialogTable = tables["Dialog"];
1017 871
1018 var addedControls = new Hashtable(); 872 var controlTable = tables["Control"];
1019 var controlRows = new Hashtable(); 873 var controlRows = controlTable?.Rows.ToDictionary(row => row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter));
1020
1021 // index the rows in the control rows (because we need the Control_Next value)
1022 if (null != controlTable)
1023 {
1024 foreach (var row in controlTable.Rows)
1025 {
1026 controlRows.Add(row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), row);
1027 }
1028 }
1029 874
875 var dialogTable = tables["Dialog"];
1030 if (null != dialogTable) 876 if (null != dialogTable)
1031 { 877 {
1032 foreach (var row in dialogTable.Rows) 878 foreach (var dialogRow in dialogTable.Rows)
1033 { 879 {
1034 var dialog = (Wix.Dialog)this.core.GetIndexedElement(row); 880 var xDialog = this.GetIndexedElement(dialogRow);
1035 var dialogId = Convert.ToString(row[0]); 881 var dialogId = dialogRow.FieldAsString(0);
1036 882
1037 var control = (Wix.Control)this.core.GetIndexedElement("Control", dialogId, Convert.ToString(row[7])); 883 if (!this.TryGetIndexedElement("Control", out var xControl, dialogId, dialogRow.FieldAsString(7)))
1038 if (null == control)
1039 { 884 {
1040 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, "Dialog", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Dialog", dialogId, "Control_First", Convert.ToString(row[7]), "Control")); 885 this.Messaging.Write(WarningMessages.ExpectedForeignRow(dialogRow.SourceLineNumbers, "Dialog", dialogRow.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Dialog", dialogId, "Control_First", dialogRow.FieldAsString(7), "Control"));
1041 } 886 }
1042 887
1043 // add tabbable controls 888 // add tabbable controls
1044 while (null != control) 889 while (null != xControl)
1045 { 890 {
1046 var controlRow = (Row)controlRows[String.Concat(dialogId, DecompilerConstants.PrimaryKeyDelimiter, control.Id)]; 891 var controlId = xControl.Attribute("Id");
892 var controlRow = controlRows[String.Concat(dialogId, DecompilerConstants.PrimaryKeyDelimiter, controlId)];
893
894 xControl.SetAttributeValue("TabSkip", "no");
1047 895
1048 control.TabSkip = Wix.YesNoType.no; 896 xDialog.Add(xControl);
1049 dialog.AddChild(control); 897 addedControls.Add(xControl);
1050 addedControls.Add(control, null);
1051 898
1052 if (null != controlRow[10]) 899 var controlNext = controlRow.FieldAsString(10);
900 if (!String.IsNullOrEmpty(controlNext))
1053 { 901 {
1054 control = (Wix.Control)this.core.GetIndexedElement("Control", dialogId, Convert.ToString(controlRow[10])); 902 if (this.TryGetIndexedElement("Control", out xControl, dialogId, controlNext))
1055 if (null != control)
1056 { 903 {
1057 // looped back to the first control in the dialog 904 // looped back to the first control in the dialog
1058 if (addedControls.Contains(control)) 905 if (addedControls.Contains(xControl))
1059 { 906 {
1060 control = null; 907 xControl = null;
1061 } 908 }
1062 } 909 }
1063 else 910 else
1064 { 911 {
1065 this.Messaging.Write(WarningMessages.ExpectedForeignRow(controlRow.SourceLineNumbers, "Control", controlRow.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Dialog_", dialogId, "Control_Next", Convert.ToString(controlRow[10]), "Control")); 912 this.Messaging.Write(WarningMessages.ExpectedForeignRow(controlRow.SourceLineNumbers, "Control", controlRow.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Dialog_", dialogId, "Control_Next", controlNext, "Control"));
1066 } 913 }
1067 } 914 }
1068 else 915 else
1069 { 916 {
1070 control = null; 917 xControl = null;
1071 } 918 }
1072 } 919 }
1073 920
1074 // set default control 921 // set default control
1075 if (null != row[8]) 922 var controlDefault = dialogRow.FieldAsString(8);
923 if (!String.IsNullOrEmpty(controlDefault))
1076 { 924 {
1077 var defaultControl = (Wix.Control)this.core.GetIndexedElement("Control", dialogId, Convert.ToString(row[8])); 925 if (this.TryGetIndexedElement("Control", out var xDefaultControl, dialogId, controlDefault))
1078
1079 if (null != defaultControl)
1080 { 926 {
1081 defaultControl.Default = Wix.YesNoType.yes; 927 xDefaultControl.SetAttributeValue("Default", "yes");
1082 } 928 }
1083 else 929 else
1084 { 930 {
1085 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, "Dialog", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Dialog", dialogId, "Control_Default", Convert.ToString(row[8]), "Control")); 931 this.Messaging.Write(WarningMessages.ExpectedForeignRow(dialogRow.SourceLineNumbers, "Dialog", dialogRow.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Dialog", dialogId, "Control_Default", Convert.ToString(dialogRow[8]), "Control"));
1086 } 932 }
1087 } 933 }
1088 934
1089 // set cancel control 935 // set cancel control
1090 if (null != row[9]) 936 var controlCancel = dialogRow.FieldAsString(8);
937 if (!String.IsNullOrEmpty(controlCancel))
1091 { 938 {
1092 var cancelControl = (Wix.Control)this.core.GetIndexedElement("Control", dialogId, Convert.ToString(row[9])); 939 if (this.TryGetIndexedElement("Control", out var xCancelControl, dialogId, controlCancel))
1093
1094 if (null != cancelControl)
1095 { 940 {
1096 cancelControl.Cancel = Wix.YesNoType.yes; 941 xCancelControl.SetAttributeValue("Cancel", "yes");
1097 } 942 }
1098 else 943 else
1099 { 944 {
1100 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, "Dialog", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Dialog", dialogId, "Control_Cancel", Convert.ToString(row[9]), "Control")); 945 this.Messaging.Write(WarningMessages.ExpectedForeignRow(dialogRow.SourceLineNumbers, "Dialog", dialogRow.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Dialog", dialogId, "Control_Cancel", Convert.ToString(dialogRow[9]), "Control"));
1101 } 946 }
1102 } 947 }
1103 } 948 }
@@ -1106,21 +951,20 @@ namespace WixToolset.Core.WindowsInstaller
1106 // add the non-tabbable controls to the dialog 951 // add the non-tabbable controls to the dialog
1107 if (null != controlTable) 952 if (null != controlTable)
1108 { 953 {
1109 foreach (var row in controlTable.Rows) 954 foreach (var controlRow in controlTable.Rows)
1110 { 955 {
1111 var control = (Wix.Control)this.core.GetIndexedElement(row); 956 var dialogId = controlRow.FieldAsString(0);
1112 var dialog = (Wix.Dialog)this.core.GetIndexedElement("Dialog", Convert.ToString(row[0])); 957 if (!this.TryGetIndexedElement("Dialog", out var xDialog, dialogId))
1113
1114 if (null == dialog)
1115 { 958 {
1116 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, "Control", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Dialog_", Convert.ToString(row[0]), "Dialog")); 959 this.Messaging.Write(WarningMessages.ExpectedForeignRow(controlRow.SourceLineNumbers, "Control", controlRow.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Dialog_", dialogId, "Dialog"));
1117 continue; 960 continue;
1118 } 961 }
1119 962
1120 if (!addedControls.Contains(control)) 963 var xControl = this.GetIndexedElement(controlRow);
964 if (!addedControls.Contains(xControl))
1121 { 965 {
1122 control.TabSkip = Wix.YesNoType.yes; 966 xControl.SetAttributeValue("TabSkip", "yes");
1123 dialog.AddChild(control); 967 xDialog.Add(xControl);
1124 } 968 }
1125 } 969 }
1126 } 970 }
@@ -1137,53 +981,53 @@ namespace WixToolset.Core.WindowsInstaller
1137 private void FinalizeDuplicateMoveFileTables(TableIndexedCollection tables) 981 private void FinalizeDuplicateMoveFileTables(TableIndexedCollection tables)
1138 { 982 {
1139 var duplicateFileTable = tables["DuplicateFile"]; 983 var duplicateFileTable = tables["DuplicateFile"];
1140 var moveFileTable = tables["MoveFile"];
1141
1142 if (null != duplicateFileTable) 984 if (null != duplicateFileTable)
1143 { 985 {
1144 foreach (var row in duplicateFileTable.Rows) 986 foreach (var row in duplicateFileTable.Rows)
1145 { 987 {
1146 var copyFile = (Wix.CopyFile)this.core.GetIndexedElement(row); 988 var xCopyFile = this.GetIndexedElement(row);
1147 989 var destination = row.FieldAsString(4);
1148 if (null != row[4]) 990 if (!String.IsNullOrEmpty(destination))
1149 { 991 {
1150 if (null != this.core.GetIndexedElement("Directory", Convert.ToString(row[4]))) 992 if (this.TryGetIndexedElement("Directory", out var _, destination))
1151 { 993 {
1152 copyFile.DestinationDirectory = Convert.ToString(row[4]); 994 xCopyFile.SetAttributeValue("DestinationDirectory", destination);
1153 } 995 }
1154 else 996 else
1155 { 997 {
1156 copyFile.DestinationProperty = Convert.ToString(row[4]); 998 xCopyFile.SetAttributeValue("DestinationProperty", destination);
1157 } 999 }
1158 } 1000 }
1159 } 1001 }
1160 } 1002 }
1161 1003
1004 var moveFileTable = tables["MoveFile"];
1162 if (null != moveFileTable) 1005 if (null != moveFileTable)
1163 { 1006 {
1164 foreach (var row in moveFileTable.Rows) 1007 foreach (var row in moveFileTable.Rows)
1165 { 1008 {
1166 var copyFile = (Wix.CopyFile)this.core.GetIndexedElement(row); 1009 var xCopyFile = this.GetIndexedElement(row);
1167 1010 var source = row.FieldAsString(4);
1168 if (null != row[4]) 1011 if (!String.IsNullOrEmpty(source))
1169 { 1012 {
1170 if (null != this.core.GetIndexedElement("Directory", Convert.ToString(row[4]))) 1013 if (this.TryGetIndexedElement("Directory", out var _, source))
1171 { 1014 {
1172 copyFile.SourceDirectory = Convert.ToString(row[4]); 1015 xCopyFile.SetAttributeValue("SourceDirectory", source);
1173 } 1016 }
1174 else 1017 else
1175 { 1018 {
1176 copyFile.SourceProperty = Convert.ToString(row[4]); 1019 xCopyFile.SetAttributeValue("SourceProperty", source);
1177 } 1020 }
1178 } 1021 }
1179 1022
1180 if (null != this.core.GetIndexedElement("Directory", Convert.ToString(row[5]))) 1023 var destination = row.FieldAsString(5);
1024 if (this.TryGetIndexedElement("Directory", out var _, destination))
1181 { 1025 {
1182 copyFile.DestinationDirectory = Convert.ToString(row[5]); 1026 xCopyFile.SetAttributeValue("DestinationDirectory", destination);
1183 } 1027 }
1184 else 1028 else
1185 { 1029 {
1186 copyFile.DestinationProperty = Convert.ToString(row[5]); 1030 xCopyFile.SetAttributeValue("DestinationProperty", destination);
1187 } 1031 }
1188 } 1032 }
1189 } 1033 }
@@ -1195,22 +1039,17 @@ namespace WixToolset.Core.WindowsInstaller
1195 /// <param name="tables">The collection of all tables.</param> 1039 /// <param name="tables">The collection of all tables.</param>
1196 private void FinalizeFamilyFileRangesTable(TableIndexedCollection tables) 1040 private void FinalizeFamilyFileRangesTable(TableIndexedCollection tables)
1197 { 1041 {
1198 var externalFilesTable = tables["ExternalFiles"];
1199 var familyFileRangesTable = tables["FamilyFileRanges"]; 1042 var familyFileRangesTable = tables["FamilyFileRanges"];
1200 var targetFiles_OptionalDataTable = tables["TargetFiles_OptionalData"];
1201
1202 var usedProtectRanges = new Hashtable();
1203
1204 if (null != familyFileRangesTable) 1043 if (null != familyFileRangesTable)
1205 { 1044 {
1206 foreach (var row in familyFileRangesTable.Rows) 1045 foreach (var row in familyFileRangesTable.Rows)
1207 { 1046 {
1208 var protectRange = new Wix.ProtectRange(); 1047 var xProtectRange = new XElement(Names.ProtectRangeElement);
1209 1048
1210 if (null != row[2] && null != row[3]) 1049 if (!row.IsColumnNull(2) && !row.IsColumnNull(3))
1211 { 1050 {
1212 var retainOffsets = (Convert.ToString(row[2])).Split(','); 1051 var retainOffsets = row.FieldAsString(2).Split(',');
1213 var retainLengths = (Convert.ToString(row[3])).Split(','); 1052 var retainLengths = row.FieldAsString(3).Split(',');
1214 1053
1215 if (retainOffsets.Length == retainLengths.Length) 1054 if (retainOffsets.Length == retainLengths.Length)
1216 { 1055 {
@@ -1218,20 +1057,20 @@ namespace WixToolset.Core.WindowsInstaller
1218 { 1057 {
1219 if (retainOffsets[i].StartsWith("0x", StringComparison.Ordinal)) 1058 if (retainOffsets[i].StartsWith("0x", StringComparison.Ordinal))
1220 { 1059 {
1221 protectRange.Offset = Convert.ToInt32(retainOffsets[i].Substring(2), 16); 1060 xProtectRange.SetAttributeValue("Offset", Convert.ToInt32(retainOffsets[i].Substring(2), 16));
1222 } 1061 }
1223 else 1062 else
1224 { 1063 {
1225 protectRange.Offset = Convert.ToInt32(retainOffsets[i], CultureInfo.InvariantCulture); 1064 xProtectRange.SetAttributeValue("Offset", Convert.ToInt32(retainOffsets[i], CultureInfo.InvariantCulture));
1226 } 1065 }
1227 1066
1228 if (retainLengths[i].StartsWith("0x", StringComparison.Ordinal)) 1067 if (retainLengths[i].StartsWith("0x", StringComparison.Ordinal))
1229 { 1068 {
1230 protectRange.Length = Convert.ToInt32(retainLengths[i].Substring(2), 16); 1069 xProtectRange.SetAttributeValue("Length", Convert.ToInt32(retainLengths[i].Substring(2), 16));
1231 } 1070 }
1232 else 1071 else
1233 { 1072 {
1234 protectRange.Length = Convert.ToInt32(retainLengths[i], CultureInfo.InvariantCulture); 1073 xProtectRange.SetAttributeValue("Length", Convert.ToInt32(retainLengths[i], CultureInfo.InvariantCulture));
1235 } 1074 }
1236 } 1075 }
1237 } 1076 }
@@ -1240,79 +1079,59 @@ namespace WixToolset.Core.WindowsInstaller
1240 // TODO: warn 1079 // TODO: warn
1241 } 1080 }
1242 } 1081 }
1243 else if (null != row[2] || null != row[3]) 1082 else if (!row.IsColumnNull(2) || !row.IsColumnNull(3))
1244 { 1083 {
1245 // TODO: warn about mismatch between columns 1084 // TODO: warn about mismatch between columns
1246 } 1085 }
1247 1086
1248 this.core.IndexElement(row, protectRange); 1087 this.IndexElement(row, xProtectRange);
1249 } 1088 }
1250 } 1089 }
1251 1090
1091 var usedProtectRanges = new HashSet<XElement>();
1092 var externalFilesTable = tables["ExternalFiles"];
1252 if (null != externalFilesTable) 1093 if (null != externalFilesTable)
1253 { 1094 {
1254 foreach (var row in externalFilesTable.Rows) 1095 foreach (var row in externalFilesTable.Rows)
1255 { 1096 {
1256 var externalFile = (Wix.ExternalFile)this.core.GetIndexedElement(row); 1097 if (this.TryGetIndexedElement(row, out var xExternalFile)
1257 1098 && this.TryGetIndexedElement("FamilyFileRanges", out var xProtectRange, row.FieldAsString(0), row.FieldAsString(0)))
1258 var protectRange = (Wix.ProtectRange)this.core.GetIndexedElement("FamilyFileRanges", Convert.ToString(row[0]), Convert.ToString(row[1]));
1259 if (null != protectRange)
1260 { 1099 {
1261 externalFile.AddChild(protectRange); 1100 xExternalFile.Add(xProtectRange);
1262 usedProtectRanges[protectRange] = null; 1101 usedProtectRanges.Add(xProtectRange);
1263 } 1102 }
1264 } 1103 }
1265 } 1104 }
1266 1105
1106 var targetFiles_OptionalDataTable = tables["TargetFiles_OptionalData"];
1267 if (null != targetFiles_OptionalDataTable) 1107 if (null != targetFiles_OptionalDataTable)
1268 { 1108 {
1269 var targetImagesTable = tables["TargetImages"]; 1109 var targetImagesTable = tables["TargetImages"];
1270 var upgradedImagesTable = tables["UpgradedImages"]; 1110 var targetImageRows = targetImagesTable?.Rows.ToDictionary(row => row.FieldAsString(0));
1271
1272 var targetImageRows = new Hashtable();
1273 var upgradedImagesRows = new Hashtable();
1274
1275 // index the TargetImages table
1276 if (null != targetImagesTable)
1277 {
1278 foreach (var row in targetImagesTable.Rows)
1279 {
1280 targetImageRows.Add(row[0], row);
1281 }
1282 }
1283 1111
1284 // index the UpgradedImages table 1112 var upgradedImagesTable = tables["UpgradedImages"];
1285 if (null != upgradedImagesTable) 1113 var upgradedImagesRows = upgradedImagesTable?.Rows.ToDictionary(row => row.FieldAsString(0));
1286 {
1287 foreach (var row in upgradedImagesTable.Rows)
1288 {
1289 upgradedImagesRows.Add(row[0], row);
1290 }
1291 }
1292 1114
1293 foreach (var row in targetFiles_OptionalDataTable.Rows) 1115 foreach (var row in targetFiles_OptionalDataTable.Rows)
1294 { 1116 {
1295 var targetFile = (Wix.TargetFile)this.patchTargetFiles[row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter)]; 1117 var xTargetFile = this.PatchTargetFiles[row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter)];
1296 1118
1297 var targetImageRow = (Row)targetImageRows[row[0]]; 1119 if (!targetImageRows.TryGetValue(row.FieldAsString(0), out var targetImageRow))
1298 if (null == targetImageRow)
1299 { 1120 {
1300 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, targetFiles_OptionalDataTable.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Target", Convert.ToString(row[0]), "TargetImages")); 1121 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, targetFiles_OptionalDataTable.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Target", row.FieldAsString(0), "TargetImages"));
1301 continue; 1122 continue;
1302 } 1123 }
1303 1124
1304 var upgradedImagesRow = (Row)upgradedImagesRows[targetImageRow[3]]; 1125 if (!upgradedImagesRows.TryGetValue(row.FieldAsString(3), out var upgradedImagesRow))
1305 if (null == upgradedImagesRow)
1306 { 1126 {
1307 this.Messaging.Write(WarningMessages.ExpectedForeignRow(targetImageRow.SourceLineNumbers, targetImageRow.Table.Name, targetImageRow.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Upgraded", Convert.ToString(row[3]), "UpgradedImages")); 1127 this.Messaging.Write(WarningMessages.ExpectedForeignRow(targetImageRow.SourceLineNumbers, targetImageRow.Table.Name, targetImageRow.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Upgraded", row.FieldAsString(3), "UpgradedImages"));
1308 continue; 1128 continue;
1309 } 1129 }
1310 1130
1311 var protectRange = (Wix.ProtectRange)this.core.GetIndexedElement("FamilyFileRanges", Convert.ToString(upgradedImagesRow[4]), Convert.ToString(row[1])); 1131 if (this.TryGetIndexedElement("FamilyFileRanges", out var xProtectRange, upgradedImagesRow.FieldAsString(4), row.FieldAsString(1)))
1312 if (null != protectRange)
1313 { 1132 {
1314 targetFile.AddChild(protectRange); 1133 xTargetFile.Add(xProtectRange);
1315 usedProtectRanges[protectRange] = null; 1134 usedProtectRanges.Add(xProtectRange);
1316 } 1135 }
1317 } 1136 }
1318 } 1137 }
@@ -1321,25 +1140,14 @@ namespace WixToolset.Core.WindowsInstaller
1321 { 1140 {
1322 foreach (var row in familyFileRangesTable.Rows) 1141 foreach (var row in familyFileRangesTable.Rows)
1323 { 1142 {
1324 var protectRange = (Wix.ProtectRange)this.core.GetIndexedElement(row); 1143 var xProtectRange = this.GetIndexedElement(row);
1325 1144
1326 if (!usedProtectRanges.Contains(protectRange)) 1145 if (!usedProtectRanges.Contains(xProtectRange))
1327 { 1146 {
1328 var protectFile = new Wix.ProtectFile(); 1147 var xProtectFile = new XElement(Names.ProtectFileElement, new XAttribute("File", row.FieldAsString(1)));
1148 xProtectFile.Add(xProtectRange);
1329 1149
1330 protectFile.File = Convert.ToString(row[1]); 1150 this.AddChildToParent("ImageFamilies", xProtectFile, row, 0);
1331
1332 protectFile.AddChild(protectRange);
1333
1334 var family = (Wix.Family)this.core.GetIndexedElement("ImageFamilies", Convert.ToString(row[0]));
1335 if (null != family)
1336 {
1337 family.AddChild(protectFile);
1338 }
1339 else
1340 {
1341 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, familyFileRangesTable.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Family", Convert.ToString(row[0]), "ImageFamilies"));
1342 }
1343 } 1151 }
1344 } 1152 }
1345 } 1153 }
@@ -1357,11 +1165,6 @@ namespace WixToolset.Core.WindowsInstaller
1357 private void FinalizeFeatureComponentsTable(TableIndexedCollection tables) 1165 private void FinalizeFeatureComponentsTable(TableIndexedCollection tables)
1358 { 1166 {
1359 var classTable = tables["Class"]; 1167 var classTable = tables["Class"];
1360 var extensionTable = tables["Extension"];
1361 var msiAssemblyTable = tables["MsiAssembly"];
1362 var publishComponentTable = tables["PublishComponent"];
1363 var typeLibTable = tables["TypeLib"];
1364
1365 if (null != classTable) 1168 if (null != classTable)
1366 { 1169 {
1367 foreach (var row in classTable.Rows) 1170 foreach (var row in classTable.Rows)
@@ -1370,6 +1173,7 @@ namespace WixToolset.Core.WindowsInstaller
1370 } 1173 }
1371 } 1174 }
1372 1175
1176 var extensionTable = tables["Extension"];
1373 if (null != extensionTable) 1177 if (null != extensionTable)
1374 { 1178 {
1375 foreach (var row in extensionTable.Rows) 1179 foreach (var row in extensionTable.Rows)
@@ -1378,6 +1182,7 @@ namespace WixToolset.Core.WindowsInstaller
1378 } 1182 }
1379 } 1183 }
1380 1184
1185 var msiAssemblyTable = tables["MsiAssembly"];
1381 if (null != msiAssemblyTable) 1186 if (null != msiAssemblyTable)
1382 { 1187 {
1383 foreach (var row in msiAssemblyTable.Rows) 1188 foreach (var row in msiAssemblyTable.Rows)
@@ -1386,6 +1191,7 @@ namespace WixToolset.Core.WindowsInstaller
1386 } 1191 }
1387 } 1192 }
1388 1193
1194 var publishComponentTable = tables["PublishComponent"];
1389 if (null != publishComponentTable) 1195 if (null != publishComponentTable)
1390 { 1196 {
1391 foreach (var row in publishComponentTable.Rows) 1197 foreach (var row in publishComponentTable.Rows)
@@ -1394,6 +1200,7 @@ namespace WixToolset.Core.WindowsInstaller
1394 } 1200 }
1395 } 1201 }
1396 1202
1203 var typeLibTable = tables["TypeLib"];
1397 if (null != typeLibTable) 1204 if (null != typeLibTable)
1398 { 1205 {
1399 foreach (var row in typeLibTable.Rows) 1206 foreach (var row in typeLibTable.Rows)
@@ -1412,132 +1219,89 @@ namespace WixToolset.Core.WindowsInstaller
1412 /// </remarks> 1219 /// </remarks>
1413 private void FinalizeFileTable(TableIndexedCollection tables) 1220 private void FinalizeFileTable(TableIndexedCollection tables)
1414 { 1221 {
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 1222 // index the media table by media id
1421 RowDictionary<MediaRow> mediaRows; 1223 var mediaTable = tables["Media"];
1422 if (null != mediaTable) 1224 var mediaRows = new RowDictionary<MediaRow>(mediaTable);
1423 {
1424 mediaRows = new RowDictionary<MediaRow>(mediaTable);
1425 }
1426 1225
1427 // set the disk identifiers and sources for files 1226 // set the disk identifiers and sources for files
1428 if (null != fileTable) 1227 foreach (var fileRow in tables["File"]?.Rows.Cast<FileRow>() ?? Enumerable.Empty<FileRow>())
1429 { 1228 {
1430 foreach (FileRow fileRow in fileTable.Rows) 1229 var xFile = this.GetIndexedElement("File", fileRow.File);
1431 {
1432 var file = (Wix.File)this.core.GetIndexedElement("File", fileRow.File);
1433 1230
1434 // Don't bother processing files that are orphaned (and won't show up in the output anyway) 1231 // Don't bother processing files that are orphaned (and won't show up in the output anyway)
1435 if (null != file.ParentElement) 1232 if (null != xFile.Parent)
1233 {
1234 // set the diskid
1235 if (null != mediaTable)
1436 { 1236 {
1437 // set the diskid 1237 foreach (MediaRow mediaRow in mediaTable.Rows)
1438 if (null != mediaTable)
1439 { 1238 {
1440 foreach (MediaRow mediaRow in mediaTable.Rows) 1239 if (fileRow.Sequence <= mediaRow.LastSequence && mediaRow.DiskId != 1)
1441 { 1240 {
1442 if (fileRow.Sequence <= mediaRow.LastSequence && mediaRow.DiskId != 1) 1241 xFile.SetAttributeValue("DiskId", mediaRow.DiskId);
1443 { 1242 break;
1444 file.DiskId = Convert.ToString(mediaRow.DiskId);
1445 break;
1446 }
1447 } 1243 }
1448 } 1244 }
1245 }
1449 1246
1450 // set the source (done here because it requires information from the Directory table) 1247 var fileId = xFile?.Attribute("Id")?.Value;
1451 if (OutputType.Module == this.OutputType) 1248 var fileCompressed = xFile?.Attribute("Compressed")?.Value;
1452 { 1249 var fileShortName = xFile?.Attribute("ShortName")?.Value;
1453 file.Source = String.Concat(this.BaseSourcePath, Path.DirectorySeparatorChar, "File", Path.DirectorySeparatorChar, file.Id, '.', this.modularizationGuid.Substring(1, 36).Replace('-', '_')); 1250 var fileName = xFile?.Attribute("Name")?.Value;
1454 } 1251
1455 else if (Wix.YesNoDefaultType.yes == file.Compressed || (Wix.YesNoDefaultType.no != file.Compressed && this.compressed) || (OutputType.Product == this.OutputType && this.TreatProductAsModule)) 1252 // set the source (done here because it requires information from the Directory table)
1253 if (OutputType.Module == this.OutputType)
1254 {
1255 xFile.SetAttributeValue("Source", String.Concat(this.BaseSourcePath, Path.DirectorySeparatorChar, "File", Path.DirectorySeparatorChar, fileId, '.', this.ModularizationGuid.Substring(1, 36).Replace('-', '_')));
1256 }
1257 else if (fileCompressed == "yes" || (fileCompressed != "no" && this.Compressed) || (OutputType.Product == this.OutputType && this.TreatProductAsModule))
1258 {
1259 xFile.SetAttributeValue("Source", String.Concat(this.BaseSourcePath, Path.DirectorySeparatorChar, "File", Path.DirectorySeparatorChar, fileId));
1260 }
1261 else // uncompressed
1262 {
1263 var name = (!this.ShortNames && !String.IsNullOrEmpty(fileName)) ? fileName : fileShortName ?? fileName;
1264
1265 if (this.Compressed) // uncompressed at the root of the source image
1456 { 1266 {
1457 file.Source = String.Concat(this.BaseSourcePath, Path.DirectorySeparatorChar, "File", Path.DirectorySeparatorChar, file.Id); 1267 xFile.SetAttributeValue("Source", String.Concat("SourceDir", Path.DirectorySeparatorChar, name));
1458 } 1268 }
1459 else // uncompressed 1269 else
1460 { 1270 {
1461 var fileName = (null != file.ShortName ? file.ShortName : file.Name); 1271 var sourcePath = this.GetSourcePath(xFile);
1462 1272 xFile.SetAttributeValue("Source", Path.Combine(sourcePath, name));
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 } 1273 }
1479 } 1274 }
1480 } 1275 }
1481 } 1276 }
1482 1277
1483 // set the file assemblies and manifests 1278 // set the file assemblies and manifests
1484 if (null != msiAssemblyTable) 1279 foreach (var row in tables["MsiAssembly"]?.Rows ?? Enumerable.Empty<Row>())
1485 { 1280 {
1486 foreach (var row in msiAssemblyTable.Rows) 1281 if (this.TryGetIndexedElement("Component", out var xComponent, row.FieldAsString(0)))
1487 { 1282 {
1488 var component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[0])); 1283 foreach (var xFile in xComponent.Elements(Names.FileElement).Where(x => x.Attribute("KeyPath")?.Value == "yes"))
1489
1490 if (null == component)
1491 { 1284 {
1492 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, "MsiAssembly", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[0]), "Component")); 1285 xFile.SetAttributeValue("AssemblyManifest", row.FieldAsString(2));
1493 } 1286 xFile.SetAttributeValue("AssemblyApplication", row.FieldAsString(3));
1494 else 1287 xFile.SetAttributeValue("Assembly", row.FieldAsInteger(4) == 0 ? ".net" : "win32");
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 } 1288 }
1523 } 1289 }
1290 else
1291 {
1292 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, "MsiAssembly", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", row.FieldAsString(0), "Component"));
1293 }
1524 } 1294 }
1525 1295
1526 // nest the TypeLib elements 1296 // nest the TypeLib elements
1527 if (null != typeLibTable) 1297 foreach (var row in tables["TypeLib"]?.Rows ?? Enumerable.Empty<Row>())
1528 { 1298 {
1529 foreach (var row in typeLibTable.Rows) 1299 var xComponent = this.GetIndexedElement("Component", row.FieldAsString(2));
1530 { 1300 var xTypeLib = this.GetIndexedElement(row);
1531 var component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[2]));
1532 var typeLib = (Wix.TypeLib)this.core.GetIndexedElement(row);
1533 1301
1534 foreach (Wix.ISchemaElement element in component.Children) 1302 foreach (var xFile in xComponent.Elements(Names.FileElement).Where(x => x.Attribute("KeyPath")?.Value == "yes"))
1535 { 1303 {
1536 if (element is Wix.File file && Wix.YesNoType.yes == file.KeyPath) 1304 xFile.Add(xTypeLib);
1537 {
1538 file.AddChild(typeLib);
1539 }
1540 }
1541 } 1305 }
1542 } 1306 }
1543 } 1307 }
@@ -1553,61 +1317,41 @@ namespace WixToolset.Core.WindowsInstaller
1553 /// </remarks> 1317 /// </remarks>
1554 private void FinalizeMIMETable(TableIndexedCollection tables) 1318 private void FinalizeMIMETable(TableIndexedCollection tables)
1555 { 1319 {
1556 var extensionTable = tables["Extension"]; 1320 var extensionRows = tables["Extension"]?.Rows ?? Enumerable.Empty<Row>();
1557 var mimeTable = tables["MIME"]; 1321 foreach (var row in extensionRows)
1558
1559 var comExtensions = new Hashtable();
1560
1561 if (null != extensionTable)
1562 { 1322 {
1563 foreach (var row in extensionTable.Rows) 1323 // set the default MIME element for this extension
1324 var mimeRef = row.FieldAsString(3);
1325 if (null != mimeRef)
1564 { 1326 {
1565 var extension = (Wix.Extension)this.core.GetIndexedElement(row); 1327 if (this.TryGetIndexedElement("MIME", out var xMime, mimeRef))
1566
1567 // index the extension
1568 if (!comExtensions.Contains(row[0]))
1569 { 1328 {
1570 comExtensions.Add(row[0], new ArrayList()); 1329 xMime.SetAttributeValue("Default", "yes");
1571 } 1330 }
1572 ((ArrayList)comExtensions[row[0]]).Add(extension); 1331 else
1573
1574 // set the default MIME element for this extension
1575 if (null != row[3])
1576 { 1332 {
1577 var mime = (Wix.MIME)this.core.GetIndexedElement("MIME", Convert.ToString(row[3])); 1333 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, "Extension", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "MIME_", row.FieldAsString(3), "MIME"));
1578
1579 if (null != mime)
1580 {
1581 mime.Default = Wix.YesNoType.yes;
1582 }
1583 else
1584 {
1585 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, "Extension", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "MIME_", Convert.ToString(row[3]), "MIME"));
1586 }
1587 } 1334 }
1588 } 1335 }
1589 } 1336 }
1590 1337
1591 if (null != mimeTable) 1338 var extensionsByExtensionId = this.IndexTableOneToMany(extensionRows);
1592 {
1593 foreach (var row in mimeTable.Rows)
1594 {
1595 var mime = (Wix.MIME)this.core.GetIndexedElement(row);
1596 1339
1597 if (comExtensions.Contains(row[1])) 1340 foreach (var row in tables["MIME"]?.Rows ?? Enumerable.Empty<Row>())
1598 { 1341 {
1599 var extensionElements = (ArrayList)comExtensions[row[1]]; 1342 var xMime = this.GetIndexedElement(row);
1600 1343
1601 foreach (Wix.Extension extension in extensionElements) 1344 if (extensionsByExtensionId.TryGetValue(row.FieldAsString(1), out var xExtensions))
1602 { 1345 {
1603 extension.AddChild(mime); 1346 foreach (var extension in xExtensions)
1604 }
1605 }
1606 else
1607 { 1347 {
1608 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, "MIME", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Extension_", Convert.ToString(row[1]), "Extension")); 1348 extension.Add(xMime);
1609 } 1349 }
1610 } 1350 }
1351 else
1352 {
1353 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, "MIME", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Extension_", row.FieldAsString(1), "Extension"));
1354 }
1611 } 1355 }
1612 } 1356 }
1613 1357
@@ -1623,125 +1367,80 @@ namespace WixToolset.Core.WindowsInstaller
1623 /// </remarks> 1367 /// </remarks>
1624 private void FinalizeProgIdTable(TableIndexedCollection tables) 1368 private void FinalizeProgIdTable(TableIndexedCollection tables)
1625 { 1369 {
1626 var classTable = tables["Class"]; 1370 // add the default ProgIds for each class (and index the class table)
1627 var progIdTable = tables["ProgId"]; 1371 var classRows = tables["Class"]?.Rows?.Where(row => row.FieldAsString(3) != null) ?? Enumerable.Empty<Row>();
1628 var extensionTable = tables["Extension"];
1629 var componentTable = tables["Component"];
1630 1372
1631 var addedProgIds = new Hashtable(); 1373 var classesByCLSID = this.IndexTableOneToMany(classRows);
1632 var classes = new Hashtable();
1633 var components = new Hashtable();
1634 1374
1635 // add the default ProgIds for each class (and index the class table) 1375 var addedProgIds = new Dictionary<XElement, string>();
1636 if (null != classTable) 1376
1377 foreach (var row in classRows)
1637 { 1378 {
1638 foreach (var row in classTable.Rows) 1379 var clsid = row.FieldAsString(0);
1639 { 1380 var xClass = this.GetIndexedElement(row);
1640 var wixClass = (Wix.Class)this.core.GetIndexedElement(row);
1641 1381
1642 if (null != row[3]) 1382 if (this.TryGetIndexedElement("ProgId", out var xProgId, row.FieldAsString(3)))
1383 {
1384 if (addedProgIds.TryGetValue(xProgId, out var progid))
1643 { 1385 {
1644 var progId = (Wix.ProgId)this.core.GetIndexedElement("ProgId", Convert.ToString(row[3])); 1386 this.Messaging.Write(WarningMessages.TooManyProgIds(row.SourceLineNumbers, row.FieldAsString(0), row.FieldAsString(3), progid));
1645
1646 if (null != progId)
1647 {
1648 if (addedProgIds.Contains(progId))
1649 {
1650 this.Messaging.Write(WarningMessages.TooManyProgIds(row.SourceLineNumbers, Convert.ToString(row[0]), Convert.ToString(row[3]), Convert.ToString(addedProgIds[progId])));
1651 }
1652 else
1653 {
1654 wixClass.AddChild(progId);
1655 addedProgIds.Add(progId, wixClass.Id);
1656 }
1657 }
1658 else
1659 {
1660 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, "Class", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "ProgId_Default", Convert.ToString(row[3]), "ProgId"));
1661 }
1662 } 1387 }
1663 1388 else
1664 // index the Class elements for nesting of ProgId elements (which don't use the full Class primary key)
1665 if (!classes.Contains(wixClass.Id))
1666 { 1389 {
1667 classes.Add(wixClass.Id, new ArrayList()); 1390 xClass.Add(xProgId);
1391 addedProgIds.Add(xProgId, clsid);
1668 } 1392 }
1669 ((ArrayList)classes[wixClass.Id]).Add(wixClass); 1393 }
1394 else
1395 {
1396 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, "Class", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "ProgId_Default", row.FieldAsString(3), "ProgId"));
1670 } 1397 }
1671 } 1398 }
1672 1399
1673 // add the remaining non-default ProgId entries for each class 1400 // add the remaining non-default ProgId entries for each class
1674 if (null != progIdTable) 1401 foreach (var row in tables["ProgId"]?.Rows ?? Enumerable.Empty<Row>())
1675 { 1402 {
1676 foreach (var row in progIdTable.Rows) 1403 var clsid = row.FieldAsString(2);
1677 { 1404 var xProgId = this.GetIndexedElement(row);
1678 var progId = (Wix.ProgId)this.core.GetIndexedElement(row);
1679 1405
1680 if (!addedProgIds.Contains(progId) && null != row[2] && null == progId.ParentElement) 1406 if (!addedProgIds.ContainsKey(xProgId) && null != clsid && null == xProgId.Parent)
1407 {
1408 if (classesByCLSID.TryGetValue(clsid, out var xClasses))
1681 { 1409 {
1682 var classElements = (ArrayList)classes[row[2]]; 1410 foreach (var xClass in xClasses)
1683
1684 if (null != classElements)
1685 { 1411 {
1686 foreach (Wix.Class wixClass in classElements) 1412 xClass.Add(xProgId);
1687 { 1413 addedProgIds.Add(xProgId, clsid);
1688 wixClass.AddChild(progId);
1689 addedProgIds.Add(progId, wixClass.Id);
1690 }
1691 }
1692 else
1693 {
1694 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, "ProgId", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Class_", Convert.ToString(row[2]), "Class"));
1695 } 1414 }
1696 } 1415 }
1697 } 1416 else
1698 }
1699
1700 if (null != componentTable)
1701 {
1702 foreach (var row in componentTable.Rows)
1703 {
1704 var wixComponent = (Wix.Component)this.core.GetIndexedElement(row);
1705
1706 // index the Class elements for nesting of ProgId elements (which don't use the full Class primary key)
1707 if (!components.Contains(wixComponent.Id))
1708 { 1417 {
1709 components.Add(wixComponent.Id, new ArrayList()); 1418 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, "ProgId", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Class_", row.FieldAsString(2), "Class"));
1710 } 1419 }
1711 ((ArrayList)components[wixComponent.Id]).Add(wixComponent);
1712 } 1420 }
1713 } 1421 }
1714 1422
1715 // Check for any progIds that are not hooked up to a class and hook them up to the component specified by the extension 1423 // Check for any progIds that are not hooked up to a class and hook them up to the component specified by the extension
1716 if (null != extensionTable) 1424 var componentsById = this.IndexTableOneToMany(tables, "Component");
1717 {
1718 foreach (var row in extensionTable.Rows)
1719 {
1720 // ignore the extension if it isn't associated with a progId
1721 if (null == row[2])
1722 {
1723 continue;
1724 }
1725 1425
1726 var progId = (Wix.ProgId)this.core.GetIndexedElement("ProgId", Convert.ToString(row[2])); 1426 foreach (var row in tables["Extension"]?.Rows?.Where(row => row.FieldAsString(2) != null) ?? Enumerable.Empty<Row>())
1427 {
1428 var xProgId = this.GetIndexedElement("ProgId", row.FieldAsString(2));
1727 1429
1728 // Haven't added the progId yet and it doesn't have a parent progId 1430 // Haven't added the progId yet and it doesn't have a parent progId
1729 if (!addedProgIds.Contains(progId) && null == progId.ParentElement) 1431 if (!addedProgIds.ContainsKey(xProgId) && null == xProgId.Parent)
1432 {
1433 if (componentsById.TryGetValue(row.FieldAsString(1), out var xComponents))
1730 { 1434 {
1731 var componentElements = (ArrayList)components[row[1]]; 1435 foreach (var xComponent in xComponents)
1732
1733 if (null != componentElements)
1734 { 1436 {
1735 foreach (Wix.Component wixComponent in componentElements) 1437 xComponent.Add(xProgId);
1736 {
1737 wixComponent.AddChild(progId);
1738 }
1739 }
1740 else
1741 {
1742 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, "Extension", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[1]), "Component"));
1743 } 1438 }
1744 } 1439 }
1440 else
1441 {
1442 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, "Extension", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", row.FieldAsString(1), "Component"));
1443 }
1745 } 1444 }
1746 } 1445 }
1747 } 1446 }
@@ -1755,25 +1454,18 @@ namespace WixToolset.Core.WindowsInstaller
1755 /// </remarks> 1454 /// </remarks>
1756 private void FinalizePropertyTable(TableIndexedCollection tables) 1455 private void FinalizePropertyTable(TableIndexedCollection tables)
1757 { 1456 {
1758 var propertyTable = tables["Property"]; 1457 foreach (var row in tables["CustomAction"]?.Rows ?? Enumerable.Empty<Row>())
1759 var customActionTable = tables["CustomAction"];
1760
1761 if (null != propertyTable && null != customActionTable)
1762 { 1458 {
1763 foreach (var row in customActionTable.Rows) 1459 // If no other fields on the property are set we must have created it in the backend.
1460 var bits = row.FieldAsInteger(1);
1461 if (WindowsInstallerConstants.MsidbCustomActionTypeHideTarget == (bits & WindowsInstallerConstants.MsidbCustomActionTypeHideTarget)
1462 && WindowsInstallerConstants.MsidbCustomActionTypeInScript == (bits & WindowsInstallerConstants.MsidbCustomActionTypeInScript)
1463 && this.TryGetIndexedElement("Property", out var xProperty, row.FieldAsString(0))
1464 && String.IsNullOrEmpty(xProperty.Attribute("Value")?.Value)
1465 && xProperty.Attribute("Secure")?.Value != "yes"
1466 && xProperty.Attribute("SuppressModularization")?.Value != "yes")
1764 { 1467 {
1765 var bits = Convert.ToInt32(row[1]); 1468 xProperty.Remove();
1766 if (WindowsInstallerConstants.MsidbCustomActionTypeHideTarget == (bits & WindowsInstallerConstants.MsidbCustomActionTypeHideTarget) &&
1767 WindowsInstallerConstants.MsidbCustomActionTypeInScript == (bits & WindowsInstallerConstants.MsidbCustomActionTypeInScript))
1768 {
1769 var property = (Wix.Property)this.core.GetIndexedElement("Property", Convert.ToString(row[0]));
1770
1771 // If no other fields on the property are set we must have created it during link
1772 if (null != property && null == property.Value && Wix.YesNoType.yes != property.Secure && Wix.YesNoType.yes != property.SuppressModularization)
1773 {
1774 this.core.RootElement.RemoveChild(property);
1775 }
1776 }
1777 } 1469 }
1778 } 1470 }
1779 } 1471 }
@@ -1787,127 +1479,80 @@ namespace WixToolset.Core.WindowsInstaller
1787 /// </remarks> 1479 /// </remarks>
1788 private void FinalizeRemoveFileTable(TableIndexedCollection tables) 1480 private void FinalizeRemoveFileTable(TableIndexedCollection tables)
1789 { 1481 {
1790 var removeFileTable = tables["RemoveFile"]; 1482 foreach (var row in tables["RemoveFile"]?.Rows ?? Enumerable.Empty<Row>())
1791
1792 if (null != removeFileTable)
1793 { 1483 {
1794 foreach (var row in removeFileTable.Rows) 1484 var xRemove = this.GetIndexedElement(row);
1795 { 1485 var property = row.FieldAsString(3);
1796 var isDirectory = false;
1797 var property = Convert.ToString(row[3]);
1798 1486
1799 // determine if the property is actually authored as a directory 1487 if (this.TryGetIndexedElement("Directory", out var _, property))
1800 if (null != this.core.GetIndexedElement("Directory", property)) 1488 {
1801 { 1489 xRemove.SetAttributeValue("Directory", property);
1802 isDirectory = true; 1490 }
1803 } 1491 else
1804 1492 {
1805 var element = this.core.GetIndexedElement(row); 1493 xRemove.SetAttributeValue("Property", property);
1806
1807 var removeFile = element as Wix.RemoveFile;
1808 if (null != removeFile)
1809 {
1810 if (isDirectory)
1811 {
1812 removeFile.Directory = property;
1813 }
1814 else
1815 {
1816 removeFile.Property = property;
1817 }
1818 }
1819 else
1820 {
1821 var removeFolder = (Wix.RemoveFolder)element;
1822
1823 if (isDirectory)
1824 {
1825 removeFolder.Directory = property;
1826 }
1827 else
1828 {
1829 removeFolder.Property = property;
1830 }
1831 }
1832 } 1494 }
1833 } 1495 }
1834 } 1496 }
1835 1497
1836 /// <summary> 1498 /// <summary>
1837 /// Finalize the LockPermissions table. 1499 /// Finalize the LockPermissions or MsiLockPermissionsEx table.
1838 /// </summary> 1500 /// </summary>
1839 /// <param name="tables">The collection of all tables.</param> 1501 /// <param name="tables">The collection of all tables.</param>
1502 /// <param name="tableName">Which table to finalize.</param>
1840 /// <remarks> 1503 /// <remarks>
1841 /// Nests the Permission elements below their parent elements. There are no declared foreign 1504 /// Nests the Permission elements below their parent elements. There are no declared foreign
1842 /// keys for the parents of the LockPermissions table. 1505 /// keys for the parents of the LockPermissions table.
1843 /// </remarks> 1506 /// </remarks>
1844 private void FinalizeLockPermissionsTable(TableIndexedCollection tables) 1507 private void FinalizePermissionsTable(TableIndexedCollection tables, string tableName)
1845 { 1508 {
1846 var createFolderTable = tables["CreateFolder"]; 1509 var createFoldersById = this.IndexTableOneToMany(tables, tableName);
1847 var lockPermissionsTable = tables["LockPermissions"];
1848
1849 var createFolders = new Hashtable();
1850 1510
1851 // index the CreateFolder table because the foreign key to this table from the 1511 foreach (var row in tables[tableName]?.Rows ?? Enumerable.Empty<Row>())
1852 // LockPermissions table is only part of the primary key of this table
1853 if (null != createFolderTable)
1854 { 1512 {
1855 foreach (var row in createFolderTable.Rows) 1513 var id = row.FieldAsString(0);
1856 { 1514 var table = row.FieldAsString(1);
1857 var createFolder = (Wix.CreateFolder)this.core.GetIndexedElement(row); 1515 var xPermission = this.GetIndexedElement(row);
1858 var directoryId = Convert.ToString(row[0]);
1859 1516
1860 if (!createFolders.Contains(directoryId)) 1517 if ("CreateFolder" == table)
1518 {
1519 if (createFoldersById.TryGetValue(id, out var xCreateFolders))
1861 { 1520 {
1862 createFolders.Add(directoryId, new ArrayList()); 1521 foreach (var xCreateFolder in xCreateFolders)
1522 {
1523 xCreateFolder.Add(xPermission);
1524 }
1525 }
1526 else
1527 {
1528 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, tableName, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "LockObject", id, table));
1863 } 1529 }
1864 ((ArrayList)createFolders[directoryId]).Add(createFolder);
1865 } 1530 }
1866 } 1531 else
1867
1868 if (null != lockPermissionsTable)
1869 {
1870 foreach (var row in lockPermissionsTable.Rows)
1871 { 1532 {
1872 var id = Convert.ToString(row[0]); 1533 if (this.TryGetIndexedElement(table, out var xParent, id))
1873 var table = Convert.ToString(row[1]);
1874
1875 var permission = (Wix.Permission)this.core.GetIndexedElement(row);
1876
1877 if ("CreateFolder" == table)
1878 { 1534 {
1879 var createFolderElements = (ArrayList)createFolders[id]; 1535 xParent.Add(xPermission);
1880
1881 if (null != createFolderElements)
1882 {
1883 foreach (Wix.CreateFolder createFolder in createFolderElements)
1884 {
1885 createFolder.AddChild(permission);
1886 }
1887 }
1888 else
1889 {
1890 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, "LockPermissions", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "LockObject", id, table));
1891 }
1892 } 1536 }
1893 else 1537 else
1894 { 1538 {
1895 var parentElement = (Wix.IParentElement)this.core.GetIndexedElement(table, id); 1539 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, tableName, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "LockObject", id, table));
1896
1897 if (null != parentElement)
1898 {
1899 parentElement.AddChild(permission);
1900 }
1901 else
1902 {
1903 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, "LockPermissions", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "LockObject", id, table));
1904 }
1905 } 1540 }
1906 } 1541 }
1907 } 1542 }
1908 } 1543 }
1909 1544
1910 /// <summary> 1545 /// <summary>
1546 /// Finalize the LockPermissions table.
1547 /// </summary>
1548 /// <param name="tables">The collection of all tables.</param>
1549 /// <remarks>
1550 /// Nests the Permission elements below their parent elements. There are no declared foreign
1551 /// keys for the parents of the LockPermissions table.
1552 /// </remarks>
1553 private void FinalizeLockPermissionsTable(TableIndexedCollection tables) => this.FinalizePermissionsTable(tables, "LockPermissions");
1554
1555 /// <summary>
1911 /// Finalize the MsiLockPermissionsEx table. 1556 /// Finalize the MsiLockPermissionsEx table.
1912 /// </summary> 1557 /// </summary>
1913 /// <param name="tables">The collection of all tables.</param> 1558 /// <param name="tables">The collection of all tables.</param>
@@ -1915,70 +1560,30 @@ namespace WixToolset.Core.WindowsInstaller
1915 /// Nests the PermissionEx elements below their parent elements. There are no declared foreign 1560 /// Nests the PermissionEx elements below their parent elements. There are no declared foreign
1916 /// keys for the parents of the MsiLockPermissionsEx table. 1561 /// keys for the parents of the MsiLockPermissionsEx table.
1917 /// </remarks> 1562 /// </remarks>
1918 private void FinalizeMsiLockPermissionsExTable(TableIndexedCollection tables) 1563 private void FinalizeMsiLockPermissionsExTable(TableIndexedCollection tables) => this.FinalizePermissionsTable(tables, "MsiLockPermissionsEx");
1919 {
1920 var createFolderTable = tables["CreateFolder"];
1921 var msiLockPermissionsExTable = tables["MsiLockPermissionsEx"];
1922
1923 var createFolders = new Hashtable();
1924 1564
1925 // index the CreateFolder table because the foreign key to this table from the 1565 private static Dictionary<string, List<string>> IndexTable(Table table, int keyColumn, int? dataColumn)
1926 // MsiLockPermissionsEx table is only part of the primary key of this table 1566 {
1927 if (null != createFolderTable) 1567 if (table == null)
1928 { 1568 {
1929 foreach (var row in createFolderTable.Rows) 1569 return new Dictionary<string, List<string>>();
1930 {
1931 var createFolder = (Wix.CreateFolder)this.core.GetIndexedElement(row);
1932 var directoryId = Convert.ToString(row[0]);
1933
1934 if (!createFolders.Contains(directoryId))
1935 {
1936 createFolders.Add(directoryId, new ArrayList());
1937 }
1938 ((ArrayList)createFolders[directoryId]).Add(createFolder);
1939 }
1940 } 1570 }
1941 1571
1942 if (null != msiLockPermissionsExTable) 1572 return table.Rows
1943 { 1573 .ToLookup(row => row.FieldAsString(keyColumn), row => dataColumn.HasValue ? row.FieldAsString(dataColumn.Value) : null)
1944 foreach (var row in msiLockPermissionsExTable.Rows) 1574 .ToDictionary(lookup => lookup.Key, lookup => lookup.ToList());
1945 { 1575 }
1946 var id = Convert.ToString(row[1]);
1947 var table = Convert.ToString(row[2]);
1948
1949 var permissionEx = (Wix.PermissionEx)this.core.GetIndexedElement(row);
1950
1951 if ("CreateFolder" == table)
1952 {
1953 var createFolderElements = (ArrayList)createFolders[id];
1954
1955 if (null != createFolderElements)
1956 {
1957 foreach (Wix.CreateFolder createFolder in createFolderElements)
1958 {
1959 createFolder.AddChild(permissionEx);
1960 }
1961 }
1962 else
1963 {
1964 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, "MsiLockPermissionsEx", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "LockObject", id, table));
1965 }
1966 }
1967 else
1968 {
1969 var parentElement = (Wix.IParentElement)this.core.GetIndexedElement(table, id);
1970 1576
1971 if (null != parentElement) 1577 private static XElement FindComplianceDrive(XElement xSearch)
1972 { 1578 {
1973 parentElement.AddChild(permissionEx); 1579 var xComplianceDrive = xSearch.Element(Names.ComplianceDriveElement);
1974 } 1580 if (null == xComplianceDrive)
1975 else 1581 {
1976 { 1582 xComplianceDrive = new XElement(Names.ComplianceDriveElement);
1977 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, "MsiLockPermissionsEx", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "LockObject", id, table)); 1583 xSearch.Add(xComplianceDrive);
1978 }
1979 }
1980 }
1981 } 1584 }
1585
1586 return xComplianceDrive;
1982 } 1587 }
1983 1588
1984 /// <summary> 1589 /// <summary>
@@ -1988,91 +1593,25 @@ namespace WixToolset.Core.WindowsInstaller
1988 /// <remarks>Does all the complex linking required for the search tables.</remarks> 1593 /// <remarks>Does all the complex linking required for the search tables.</remarks>
1989 private void FinalizeSearchTables(TableIndexedCollection tables) 1594 private void FinalizeSearchTables(TableIndexedCollection tables)
1990 { 1595 {
1991 var appSearchTable = tables["AppSearch"]; 1596 var appSearches = IndexTable(tables["AppSearch"], keyColumn: 1, dataColumn: 0);
1992 var ccpSearchTable = tables["CCPSearch"]; 1597 var ccpSearches = IndexTable(tables["CCPSearch"], keyColumn: 0, dataColumn: null);
1993 var drLocatorTable = tables["DrLocator"]; 1598 var drLocators = tables["DrLocator"]?.Rows.ToDictionary(row => this.GetIndexedElement(row), row => row);
1994
1995 var appSearches = new Hashtable();
1996 var ccpSearches = new Hashtable();
1997 var drLocators = new Hashtable();
1998 var locators = new Hashtable();
1999 var usedSearchElements = new Hashtable();
2000 var unusedSearchElements = new Dictionary<string, Wix.IParentElement>();
2001
2002 Wix.ComplianceCheck complianceCheck = null;
2003
2004 // index the AppSearch table by signatures
2005 if (null != appSearchTable)
2006 {
2007 foreach (var row in appSearchTable.Rows)
2008 {
2009 var property = Convert.ToString(row[0]);
2010 var signature = Convert.ToString(row[1]);
2011
2012 if (!appSearches.Contains(signature))
2013 {
2014 appSearches.Add(signature, new StringCollection());
2015 }
2016
2017 ((StringCollection)appSearches[signature]).Add(property);
2018 }
2019 }
2020 1599
2021 // index the CCPSearch table by signatures 1600 var xComplianceCheck = new XElement(Names.ComplianceCheckElement);
2022 if (null != ccpSearchTable) 1601 if (ccpSearches.Keys.Any(ccpSignature => !appSearches.ContainsKey(ccpSignature)))
2023 { 1602 {
2024 foreach (var row in ccpSearchTable.Rows) 1603 this.RootElement.Add(xComplianceCheck);
2025 {
2026 var signature = Convert.ToString(row[0]);
2027
2028 if (!ccpSearches.Contains(signature))
2029 {
2030 ccpSearches.Add(signature, new StringCollection());
2031 }
2032
2033 ((StringCollection)ccpSearches[signature]).Add(null);
2034
2035 if (null == complianceCheck && !appSearches.Contains(signature))
2036 {
2037 complianceCheck = new Wix.ComplianceCheck();
2038 this.core.RootElement.AddChild(complianceCheck);
2039 }
2040 }
2041 }
2042
2043 // index the directory searches by their search elements (to get back the original row)
2044 if (null != drLocatorTable)
2045 {
2046 foreach (var row in drLocatorTable.Rows)
2047 {
2048 drLocators.Add(this.core.GetIndexedElement(row), row);
2049 }
2050 } 1604 }
2051 1605
2052 // index the locator tables by their signatures 1606 // index the locator tables by their signatures
2053 var locatorTableNames = new string[] { "CompLocator", "RegLocator", "IniLocator", "DrLocator", "Signature" }; 1607 var locators =
2054 foreach (var locatorTableName in locatorTableNames) 1608 new[] { "CompLocator", "RegLocator", "IniLocator", "DrLocator", "Signature" }
2055 { 1609 .SelectMany(table => tables[table]?.Rows ?? Enumerable.Empty<Row>())
2056 var locatorTable = tables[locatorTableName]; 1610 .ToLookup(row => row.FieldAsString(0), row => row)
2057 1611 .ToDictionary(lookup => lookup.Key, lookup => lookup.ToList());
2058 if (null != locatorTable)
2059 {
2060 foreach (var row in locatorTable.Rows)
2061 {
2062 var signature = Convert.ToString(row[0]);
2063
2064 if (!locators.Contains(signature))
2065 {
2066 locators.Add(signature, new ArrayList());
2067 }
2068
2069 ((ArrayList)locators[signature]).Add(row);
2070 }
2071 }
2072 }
2073 1612
2074 // move the DrLocator rows with a parent of CCP_DRIVE first to ensure they get FileSearch children (not FileSearchRef) 1613 // move the DrLocator rows with a parent of CCP_DRIVE first to ensure they get FileSearch children (not FileSearchRef)
2075 foreach (ArrayList locatorRows in locators.Values) 1614 foreach (var locatorRows in locators.Values)
2076 { 1615 {
2077 var firstDrLocator = -1; 1616 var firstDrLocator = -1;
2078 1617
@@ -2097,205 +1636,142 @@ namespace WixToolset.Core.WindowsInstaller
2097 } 1636 }
2098 } 1637 }
2099 1638
2100 foreach (string signature in locators.Keys) 1639 var xUsedSearches = new HashSet<XElement>();
1640 var xUnusedSearches = new Dictionary<string, XElement>();
1641
1642 foreach (var signature in locators.Keys)
2101 { 1643 {
2102 var locatorRows = (ArrayList)locators[signature]; 1644 var locatorRows = locators[signature];
2103 var signatureSearchElements = new ArrayList(); 1645 var xSignatureSearches = new List<XElement>();
2104 1646
2105 foreach (Row locatorRow in locatorRows) 1647 foreach (var locatorRow in locatorRows)
2106 { 1648 {
2107 var used = true; 1649 var used = true;
2108 var searchElement = this.core.GetIndexedElement(locatorRow); 1650 var xSearch = this.GetIndexedElement(locatorRow);
2109 1651
2110 if ("Signature" == locatorRow.TableDefinition.Name && 0 < signatureSearchElements.Count) 1652 if ("Signature" == locatorRow.TableDefinition.Name && 0 < xSignatureSearches.Count)
2111 { 1653 {
2112 foreach (Wix.IParentElement searchParentElement in signatureSearchElements) 1654 foreach (var xSearchParent in xSignatureSearches)
2113 { 1655 {
2114 if (!usedSearchElements.Contains(searchElement)) 1656 if (!xUsedSearches.Contains(xSearch))
2115 { 1657 {
2116 searchParentElement.AddChild(searchElement); 1658 xSearchParent.Add(xSearch);
2117 usedSearchElements[searchElement] = null; 1659 xUsedSearches.Add(xSearch);
2118 } 1660 }
2119 else 1661 else
2120 { 1662 {
2121 var fileSearchRef = new Wix.FileSearchRef(); 1663 var xFileSearchRef = new XElement(Names.FileSearchRefElement,
1664 new XAttribute("Id", signature));
2122 1665
2123 fileSearchRef.Id = signature; 1666 xSearchParent.Add(xFileSearchRef);
2124
2125 searchParentElement.AddChild(fileSearchRef);
2126 } 1667 }
2127 } 1668 }
2128 } 1669 }
2129 else if ("DrLocator" == locatorRow.TableDefinition.Name && null != locatorRow[1]) 1670 else if ("DrLocator" == locatorRow.TableDefinition.Name && !locatorRow.IsColumnNull(1))
2130 { 1671 {
2131 var drSearchElement = (Wix.DirectorySearch)searchElement; 1672 var parentSignature = locatorRow.FieldAsString(1);
2132 var parentSignature = Convert.ToString(locatorRow[1]);
2133 1673
2134 if ("CCP_DRIVE" == parentSignature) 1674 if ("CCP_DRIVE" == parentSignature)
2135 { 1675 {
2136 if (appSearches.Contains(signature)) 1676 if (appSearches.ContainsKey(signature)
1677 && appSearches.TryGetValue(signature, out var appSearchPropertyIds))
2137 { 1678 {
2138 var appSearchPropertyIds = (StringCollection)appSearches[signature];
2139
2140 foreach (var propertyId in appSearchPropertyIds) 1679 foreach (var propertyId in appSearchPropertyIds)
2141 { 1680 {
2142 var property = this.EnsureProperty(propertyId); 1681 var xProperty = this.EnsureProperty(propertyId);
2143 Wix.ComplianceDrive complianceDrive = null;
2144
2145 if (ccpSearches.Contains(signature))
2146 {
2147 property.ComplianceCheck = Wix.YesNoType.yes;
2148 }
2149 1682
2150 foreach (Wix.ISchemaElement element in property.Children) 1683 if (ccpSearches.ContainsKey(signature))
2151 { 1684 {
2152 complianceDrive = element as Wix.ComplianceDrive; 1685 xProperty.SetAttributeValue("ComplianceCheck", "yes");
2153 if (null != complianceDrive)
2154 {
2155 break;
2156 }
2157 } 1686 }
2158 1687
2159 if (null == complianceDrive) 1688 var xComplianceDrive = FindComplianceDrive(xProperty);
2160 {
2161 complianceDrive = new Wix.ComplianceDrive();
2162 property.AddChild(complianceDrive);
2163 }
2164 1689
2165 if (!usedSearchElements.Contains(searchElement)) 1690 if (!xUsedSearches.Contains(xSearch))
2166 { 1691 {
2167 complianceDrive.AddChild(searchElement); 1692 xComplianceDrive.Add(xSearch);
2168 usedSearchElements[searchElement] = null; 1693 xUsedSearches.Add(xSearch);
2169 } 1694 }
2170 else 1695 else
2171 { 1696 {
2172 var directorySearchRef = new Wix.DirectorySearchRef(); 1697 var directorySearchRef = new XElement(Names.DirectorySearchRefElement,
1698 new XAttribute("Id", signature),
1699 XAttributeIfNotNull("Parent", locatorRow, 1),
1700 XAttributeIfNotNull("Path", locatorRow, 2));
2173 1701
2174 directorySearchRef.Id = signature; 1702 xComplianceDrive.Add(directorySearchRef);
2175 1703 xSignatureSearches.Add(directorySearchRef);
2176 if (null != locatorRow[1])
2177 {
2178 directorySearchRef.Parent = Convert.ToString(locatorRow[1]);
2179 }
2180
2181 if (null != locatorRow[2])
2182 {
2183 directorySearchRef.Path = Convert.ToString(locatorRow[2]);
2184 }
2185
2186 complianceDrive.AddChild(directorySearchRef);
2187 signatureSearchElements.Add(directorySearchRef);
2188 } 1704 }
2189 } 1705 }
2190 } 1706 }
2191 else if (ccpSearches.Contains(signature)) 1707 else if (ccpSearches.ContainsKey(signature))
2192 { 1708 {
2193 Wix.ComplianceDrive complianceDrive = null; 1709 var xComplianceDrive = FindComplianceDrive(xComplianceCheck);
2194 1710
2195 foreach (Wix.ISchemaElement element in complianceCheck.Children) 1711 if (!xUsedSearches.Contains(xSearch))
2196 { 1712 {
2197 complianceDrive = element as Wix.ComplianceDrive; 1713 xComplianceDrive.Add(xSearch);
2198 if (null != complianceDrive) 1714 xUsedSearches.Add(xSearch);
2199 {
2200 break;
2201 }
2202 }
2203
2204 if (null == complianceDrive)
2205 {
2206 complianceDrive = new Wix.ComplianceDrive();
2207 complianceCheck.AddChild(complianceDrive);
2208 }
2209
2210 if (!usedSearchElements.Contains(searchElement))
2211 {
2212 complianceDrive.AddChild(searchElement);
2213 usedSearchElements[searchElement] = null;
2214 } 1715 }
2215 else 1716 else
2216 { 1717 {
2217 var directorySearchRef = new Wix.DirectorySearchRef(); 1718 var directorySearchRef = new XElement(Names.DirectorySearchRefElement,
1719 new XAttribute("Id", signature),
1720 XAttributeIfNotNull("Parent", locatorRow, 1),
1721 XAttributeIfNotNull("Path", locatorRow, 2));
2218 1722
2219 directorySearchRef.Id = signature; 1723 xComplianceDrive.Add(directorySearchRef);
2220 1724 xSignatureSearches.Add(directorySearchRef);
2221 if (null != locatorRow[1])
2222 {
2223 directorySearchRef.Parent = Convert.ToString(locatorRow[1]);
2224 }
2225
2226 if (null != locatorRow[2])
2227 {
2228 directorySearchRef.Path = Convert.ToString(locatorRow[2]);
2229 }
2230
2231 complianceDrive.AddChild(directorySearchRef);
2232 signatureSearchElements.Add(directorySearchRef);
2233 } 1725 }
2234 } 1726 }
2235 } 1727 }
2236 else 1728 else
2237 { 1729 {
2238 var usedDrLocator = false; 1730 var usedDrLocator = false;
2239 var parentLocatorRows = (ArrayList)locators[parentSignature];
2240 1731
2241 if (null != parentLocatorRows) 1732 if (locators.TryGetValue(parentSignature, out var parentLocatorRows))
2242 { 1733 {
2243 foreach (Row parentLocatorRow in parentLocatorRows) 1734 foreach (var parentLocatorRow in parentLocatorRows)
2244 { 1735 {
2245 if ("DrLocator" == parentLocatorRow.TableDefinition.Name) 1736 if ("DrLocator" == parentLocatorRow.TableDefinition.Name)
2246 { 1737 {
2247 var parentSearchElement = (Wix.IParentElement)this.core.GetIndexedElement(parentLocatorRow); 1738 var xParentSearch = this.GetIndexedElement(parentLocatorRow);
2248 1739
2249 if (parentSearchElement.Children.GetEnumerator().MoveNext()) 1740 if (xParentSearch.HasElements)
2250 { 1741 {
2251 var parentDrLocatorRow = (Row)drLocators[parentSearchElement]; 1742 var parentDrLocatorRow = drLocators[xParentSearch];
2252 var directorySeachRef = new Wix.DirectorySearchRef(); 1743 var xDirectorySearchRef = new XElement(Names.DirectorySearchRefElement,
2253 1744 new XAttribute("Id", parentSignature),
2254 directorySeachRef.Id = parentSignature; 1745 XAttributeIfNotNull("Parent", parentDrLocatorRow, 1),
2255 1746 XAttributeIfNotNull("Path", parentDrLocatorRow, 2));
2256 if (null != parentDrLocatorRow[1]) 1747
2257 { 1748 xParentSearch = xDirectorySearchRef;
2258 directorySeachRef.Parent = Convert.ToString(parentDrLocatorRow[1]); 1749 xUnusedSearches.Add(parentSignature, xDirectorySearchRef);
2259 }
2260
2261 if (null != parentDrLocatorRow[2])
2262 {
2263 directorySeachRef.Path = Convert.ToString(parentDrLocatorRow[2]);
2264 }
2265
2266 parentSearchElement = directorySeachRef;
2267 unusedSearchElements.Add(directorySeachRef.Id, directorySeachRef);
2268 } 1750 }
2269 1751
2270 if (!usedSearchElements.Contains(searchElement)) 1752 if (!xUsedSearches.Contains(xSearch))
2271 { 1753 {
2272 parentSearchElement.AddChild(searchElement); 1754 xParentSearch.Add(xSearch);
2273 usedSearchElements[searchElement] = null; 1755 xUsedSearches.Add(xSearch);
2274 usedDrLocator = true; 1756 usedDrLocator = true;
2275 } 1757 }
2276 else 1758 else
2277 { 1759 {
2278 var directorySearchRef = new Wix.DirectorySearchRef(); 1760 var xDirectorySearchRef = new XElement(Names.DirectorySearchRefElement,
2279 1761 new XAttribute("Id", signature),
2280 directorySearchRef.Id = signature; 1762 new XAttribute("Parent", parentSignature),
2281 1763 XAttributeIfNotNull("Path", locatorRow, 2));
2282 directorySearchRef.Parent = parentSignature;
2283 1764
2284 if (null != locatorRow[2]) 1765 xParentSearch.Add(xSearch);
2285 {
2286 directorySearchRef.Path = Convert.ToString(locatorRow[2]);
2287 }
2288
2289 parentSearchElement.AddChild(searchElement);
2290 usedDrLocator = true; 1766 usedDrLocator = true;
2291 } 1767 }
2292 } 1768 }
2293 else if ("RegLocator" == parentLocatorRow.TableDefinition.Name) 1769 else if ("RegLocator" == parentLocatorRow.TableDefinition.Name)
2294 { 1770 {
2295 var parentSearchElement = (Wix.IParentElement)this.core.GetIndexedElement(parentLocatorRow); 1771 var xParentSearch = this.GetIndexedElement(parentLocatorRow);
2296 1772
2297 parentSearchElement.AddChild(searchElement); 1773 xParentSearch.Add(xSearch);
2298 usedSearchElements[searchElement] = null; 1774 xUsedSearches.Add(xSearch);
2299 usedDrLocator = true; 1775 usedDrLocator = true;
2300 } 1776 }
2301 } 1777 }
@@ -2303,7 +1779,7 @@ namespace WixToolset.Core.WindowsInstaller
2303 // keep track of unused DrLocator rows 1779 // keep track of unused DrLocator rows
2304 if (!usedDrLocator) 1780 if (!usedDrLocator)
2305 { 1781 {
2306 unusedSearchElements.Add(drSearchElement.Id, drSearchElement); 1782 xUnusedSearches.Add(xSearch.Attribute("Id").Value, xSearch);
2307 } 1783 }
2308 } 1784 }
2309 else 1785 else
@@ -2312,32 +1788,30 @@ namespace WixToolset.Core.WindowsInstaller
2312 } 1788 }
2313 } 1789 }
2314 } 1790 }
2315 else if (appSearches.Contains(signature)) 1791 else if (appSearches.ContainsKey(signature)
1792 && appSearches.TryGetValue(signature, out var appSearchPropertyIds))
2316 { 1793 {
2317 var appSearchPropertyIds = (StringCollection)appSearches[signature];
2318
2319 foreach (var propertyId in appSearchPropertyIds) 1794 foreach (var propertyId in appSearchPropertyIds)
2320 { 1795 {
2321 var property = this.EnsureProperty(propertyId); 1796 var xProperty = this.EnsureProperty(propertyId);
2322 1797
2323 if (ccpSearches.Contains(signature)) 1798 if (ccpSearches.ContainsKey(signature))
2324 { 1799 {
2325 property.ComplianceCheck = Wix.YesNoType.yes; 1800 xProperty.SetAttributeValue("ComplianceCheck", "yes");
2326 } 1801 }
2327 1802
2328 if (!usedSearchElements.Contains(searchElement)) 1803 if (!xUsedSearches.Contains(xSearch))
2329 { 1804 {
2330 property.AddChild(searchElement); 1805 xProperty.Add(xSearch);
2331 usedSearchElements[searchElement] = null; 1806 xUsedSearches.Add(xSearch);
2332 } 1807 }
2333 else if ("RegLocator" == locatorRow.TableDefinition.Name) 1808 else if ("RegLocator" == locatorRow.TableDefinition.Name)
2334 { 1809 {
2335 var registrySearchRef = new Wix.RegistrySearchRef(); 1810 var xRegistrySearchRef = new XElement(Names.RegistrySearchRefElement,
1811 new XAttribute("Id", signature));
2336 1812
2337 registrySearchRef.Id = signature; 1813 xProperty.Add(xRegistrySearchRef);
2338 1814 xSignatureSearches.Add(xRegistrySearchRef);
2339 property.AddChild(registrySearchRef);
2340 signatureSearchElements.Add(registrySearchRef);
2341 } 1815 }
2342 else 1816 else
2343 { 1817 {
@@ -2345,21 +1819,20 @@ namespace WixToolset.Core.WindowsInstaller
2345 } 1819 }
2346 } 1820 }
2347 } 1821 }
2348 else if (ccpSearches.Contains(signature)) 1822 else if (ccpSearches.ContainsKey(signature))
2349 { 1823 {
2350 if (!usedSearchElements.Contains(searchElement)) 1824 if (!xUsedSearches.Contains(xSearch))
2351 { 1825 {
2352 complianceCheck.AddChild(searchElement); 1826 xComplianceCheck.Add(xSearch);
2353 usedSearchElements[searchElement] = null; 1827 xUsedSearches.Add(xSearch);
2354 } 1828 }
2355 else if ("RegLocator" == locatorRow.TableDefinition.Name) 1829 else if ("RegLocator" == locatorRow.TableDefinition.Name)
2356 { 1830 {
2357 var registrySearchRef = new Wix.RegistrySearchRef(); 1831 var xRegistrySearchRef = new XElement(Names.RegistrySearchRefElement,
2358 1832 new XAttribute("Id", signature));
2359 registrySearchRef.Id = signature;
2360 1833
2361 complianceCheck.AddChild(registrySearchRef); 1834 xComplianceCheck.Add(xRegistrySearchRef);
2362 signatureSearchElements.Add(registrySearchRef); 1835 xSignatureSearches.Add(xRegistrySearchRef);
2363 } 1836 }
2364 else 1837 else
2365 { 1838 {
@@ -2368,13 +1841,9 @@ namespace WixToolset.Core.WindowsInstaller
2368 } 1841 }
2369 else 1842 else
2370 { 1843 {
2371 if (searchElement is Wix.DirectorySearch directorySearch) 1844 if (xSearch.Name.LocalName == "DirectorySearch" || xSearch.Name.LocalName == "RegistrySearch")
2372 { 1845 {
2373 unusedSearchElements.Add(directorySearch.Id, directorySearch); 1846 xUnusedSearches.Add(xSearch.Attribute("Id").Value, xSearch);
2374 }
2375 else if (searchElement is Wix.RegistrySearch registrySearch)
2376 {
2377 unusedSearchElements.Add(registrySearch.Id, registrySearch);
2378 } 1847 }
2379 else 1848 else
2380 { 1849 {
@@ -2386,51 +1855,44 @@ namespace WixToolset.Core.WindowsInstaller
2386 // keep track of the search elements for this signature so that nested searches go in the proper parents 1855 // keep track of the search elements for this signature so that nested searches go in the proper parents
2387 if (used) 1856 if (used)
2388 { 1857 {
2389 signatureSearchElements.Add(searchElement); 1858 xSignatureSearches.Add(xSearch);
2390 } 1859 }
2391 } 1860 }
2392 } 1861 }
2393 1862
2394 // Iterate through the unused elements through a sorted list of their ids so the output is deterministic. 1863 // Iterate through the unused elements through a sorted list of their ids so the output is deterministic.
2395 var unusedSearchElementKeys = unusedSearchElements.Keys.ToList(); 1864 foreach (var unusedSearch in xUnusedSearches.OrderBy(kvp => kvp.Key))
2396 unusedSearchElementKeys.Sort();
2397 foreach (var unusedSearchElementKey in unusedSearchElementKeys)
2398 { 1865 {
2399 var unusedSearchElement = unusedSearchElements[unusedSearchElementKey];
2400 var used = false; 1866 var used = false;
2401 1867
2402 Wix.DirectorySearch leafDirectorySearch = null; 1868 XElement xLeafDirectorySearch = null;
2403 var parentElement = unusedSearchElement; 1869 var xUnusedSearch = unusedSearch.Value;
1870 var xParent = xUnusedSearch;
2404 var updatedLeaf = true; 1871 var updatedLeaf = true;
2405 while (updatedLeaf) 1872 while (updatedLeaf)
2406 { 1873 {
2407 updatedLeaf = false; 1874 updatedLeaf = false;
2408 foreach (var schemaElement in parentElement.Children) 1875
1876 var xDirectorySearch = xParent.Element(Names.DirectorySearchElement);
1877 if (xDirectorySearch != null)
2409 { 1878 {
2410 if (schemaElement is Wix.DirectorySearch directorySearch) 1879 xParent = xLeafDirectorySearch = xDirectorySearch;
2411 { 1880 updatedLeaf = true;
2412 parentElement = leafDirectorySearch = directorySearch;
2413 updatedLeaf = true;
2414 break;
2415 }
2416 } 1881 }
2417 } 1882 }
2418 1883
2419 if (leafDirectorySearch != null) 1884 if (xLeafDirectorySearch != null)
2420 { 1885 {
2421 var appSearchProperties = (StringCollection)appSearches[leafDirectorySearch.Id]; 1886 var leafDirectorySearchId = xLeafDirectorySearch.Attribute("Id").Value;
2422 1887 if (appSearches.TryGetValue(leafDirectorySearchId, out var appSearchPropertyIds))
2423 var unusedSearchSchemaElement = unusedSearchElement as Wix.ISchemaElement;
2424 if (null != appSearchProperties)
2425 { 1888 {
2426 var property = this.EnsureProperty(appSearchProperties[0]); 1889 var xProperty = this.EnsureProperty(appSearchPropertyIds[0]);
2427 1890 xProperty.Add(xUnusedSearch);
2428 property.AddChild(unusedSearchSchemaElement);
2429 used = true; 1891 used = true;
2430 } 1892 }
2431 else if (ccpSearches.Contains(leafDirectorySearch.Id)) 1893 else if (ccpSearches.ContainsKey(leafDirectorySearchId))
2432 { 1894 {
2433 complianceCheck.AddChild(unusedSearchSchemaElement); 1895 xComplianceCheck.Add(xUnusedSearch);
2434 used = true; 1896 used = true;
2435 } 1897 }
2436 else 1898 else
@@ -2464,18 +1926,19 @@ namespace WixToolset.Core.WindowsInstaller
2464 1926
2465 foreach (var row in shortcutTable.Rows) 1927 foreach (var row in shortcutTable.Rows)
2466 { 1928 {
2467 var shortcut = (Wix.Shortcut)this.core.GetIndexedElement(row); 1929 var xShortcut = this.GetIndexedElement(row);
2468 var target = Convert.ToString(row[4]); 1930
2469 var feature = this.core.GetIndexedElement("Feature", target); 1931 var target = row.FieldAsString(4);
2470 if (feature == null) 1932
1933 if (this.TryGetIndexedElement("Feature", out var _, target))
2471 { 1934 {
2472 // TODO: use this value to do a "more-correct" nesting under the indicated File or CreateDirectory element 1935 xShortcut.SetAttributeValue("Advertise", "yes");
2473 shortcut.Target = target; 1936 this.SetPrimaryFeature(row, 4, 3);
2474 } 1937 }
2475 else 1938 else
2476 { 1939 {
2477 shortcut.Advertise = Wix.YesNoType.yes; 1940 // TODO: use this value to do a "more-correct" nesting under the indicated File or CreateDirectory element
2478 this.SetPrimaryFeature(row, 4, 3); 1941 xShortcut.SetAttributeValue("Target", target);
2479 } 1942 }
2480 } 1943 }
2481 } 1944 }
@@ -2520,12 +1983,12 @@ namespace WixToolset.Core.WindowsInstaller
2520 1983
2521 actionSymbol.Action = action; 1984 actionSymbol.Action = action;
2522 1985
2523 if (null != row[1]) 1986 if (!row.IsColumnNull(1))
2524 { 1987 {
2525 actionSymbol.Condition = Convert.ToString(row[1]); 1988 actionSymbol.Condition = row.FieldAsString(1);
2526 } 1989 }
2527 1990
2528 actionSymbol.Sequence = Convert.ToInt32(row[2]); 1991 actionSymbol.Sequence = row.FieldAsInteger(2);
2529 1992
2530 actionSymbol.SequenceTable = sequenceTable; 1993 actionSymbol.SequenceTable = sequenceTable;
2531 1994
@@ -2654,30 +2117,30 @@ namespace WixToolset.Core.WindowsInstaller
2654 2117
2655 actionRow.Action = row.FieldAsString(0); 2118 actionRow.Action = row.FieldAsString(0);
2656 2119
2657 if (null != row[1]) 2120 if (!row.IsColumnNull(1))
2658 { 2121 {
2659 actionRow.Sequence = Convert.ToInt32(row[1]); 2122 actionRow.Sequence = row.FieldAsInteger(1);
2660 } 2123 }
2661 2124
2662 if (null != row[2] && null != row[3]) 2125 if (!row.IsColumnNull(2) && !row.IsColumnNull(3))
2663 { 2126 {
2664 switch (Convert.ToInt32(row[3])) 2127 switch (row.FieldAsInteger(3))
2665 { 2128 {
2666 case 0: 2129 case 0:
2667 actionRow.Before = Convert.ToString(row[2]); 2130 actionRow.Before = row.FieldAsString(2);
2668 break; 2131 break;
2669 case 1: 2132 case 1:
2670 actionRow.After = Convert.ToString(row[2]); 2133 actionRow.After = row.FieldAsString(2);
2671 break; 2134 break;
2672 default: 2135 default:
2673 this.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[3].Column.Name, row[3])); 2136 this.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[3].Column.Name, row[3]));
2674 break; 2137 break;
2675 } 2138 }
2676 } 2139 }
2677 2140
2678 if (null != row[4]) 2141 if (!row.IsColumnNull(4))
2679 { 2142 {
2680 actionRow.Condition = Convert.ToString(row[4]); 2143 actionRow.Condition = row.FieldAsString(4);
2681 } 2144 }
2682 2145
2683 actionRow.SequenceTable = sequenceTable; 2146 actionRow.SequenceTable = sequenceTable;
@@ -2707,7 +2170,6 @@ namespace WixToolset.Core.WindowsInstaller
2707 var upgradeTable = tables["Upgrade"]; 2170 var upgradeTable = tables["Upgrade"];
2708 string downgradeErrorMessage = null; 2171 string downgradeErrorMessage = null;
2709 string disallowUpgradeErrorMessage = null; 2172 string disallowUpgradeErrorMessage = null;
2710 var majorUpgrade = new Wix.MajorUpgrade();
2711 2173
2712 // find the DowngradePreventedCondition launch condition message 2174 // find the DowngradePreventedCondition launch condition message
2713 if (null != launchConditionTable && 0 < launchConditionTable.Rows.Count) 2175 if (null != launchConditionTable && 0 < launchConditionTable.Rows.Count)
@@ -2727,65 +2189,63 @@ namespace WixToolset.Core.WindowsInstaller
2727 2189
2728 if (null != upgradeTable && 0 < upgradeTable.Rows.Count) 2190 if (null != upgradeTable && 0 < upgradeTable.Rows.Count)
2729 { 2191 {
2730 var hasMajorUpgrade = false; 2192 XElement xMajorUpgrade = null;
2731 2193
2732 foreach (var row in upgradeTable.Rows) 2194 foreach (UpgradeRow upgradeRow in upgradeTable.Rows)
2733 { 2195 {
2734 var upgradeRow = (UpgradeRow)row;
2735
2736 if (Common.UpgradeDetectedProperty == upgradeRow.ActionProperty) 2196 if (Common.UpgradeDetectedProperty == upgradeRow.ActionProperty)
2737 { 2197 {
2738 hasMajorUpgrade = true;
2739 var attr = upgradeRow.Attributes; 2198 var attr = upgradeRow.Attributes;
2740 var removeFeatures = upgradeRow.Remove; 2199 var removeFeatures = upgradeRow.Remove;
2200 xMajorUpgrade = xMajorUpgrade ?? new XElement(Names.MajorUpgradeElement);
2741 2201
2742 if (WindowsInstallerConstants.MsidbUpgradeAttributesVersionMaxInclusive == (attr & WindowsInstallerConstants.MsidbUpgradeAttributesVersionMaxInclusive)) 2202 if (WindowsInstallerConstants.MsidbUpgradeAttributesVersionMaxInclusive == (attr & WindowsInstallerConstants.MsidbUpgradeAttributesVersionMaxInclusive))
2743 { 2203 {
2744 majorUpgrade.AllowSameVersionUpgrades = Wix.YesNoType.yes; 2204 xMajorUpgrade.SetAttributeValue("AllowSameVersionUpgrades", "yes");
2745 } 2205 }
2746 2206
2747 if (WindowsInstallerConstants.MsidbUpgradeAttributesMigrateFeatures != (attr & WindowsInstallerConstants.MsidbUpgradeAttributesMigrateFeatures)) 2207 if (WindowsInstallerConstants.MsidbUpgradeAttributesMigrateFeatures != (attr & WindowsInstallerConstants.MsidbUpgradeAttributesMigrateFeatures))
2748 { 2208 {
2749 majorUpgrade.MigrateFeatures = Wix.YesNoType.no; 2209 xMajorUpgrade.SetAttributeValue("MigrateFeatures", "no");
2750 } 2210 }
2751 2211
2752 if (WindowsInstallerConstants.MsidbUpgradeAttributesIgnoreRemoveFailure == (attr & WindowsInstallerConstants.MsidbUpgradeAttributesIgnoreRemoveFailure)) 2212 if (WindowsInstallerConstants.MsidbUpgradeAttributesIgnoreRemoveFailure == (attr & WindowsInstallerConstants.MsidbUpgradeAttributesIgnoreRemoveFailure))
2753 { 2213 {
2754 majorUpgrade.IgnoreRemoveFailure = Wix.YesNoType.yes; 2214 xMajorUpgrade.SetAttributeValue("IgnoreRemoveFailure", "yes");
2755 } 2215 }
2756 2216
2757 if (!String.IsNullOrEmpty(removeFeatures)) 2217 if (!String.IsNullOrEmpty(removeFeatures))
2758 { 2218 {
2759 majorUpgrade.RemoveFeatures = removeFeatures; 2219 xMajorUpgrade.SetAttributeValue("RemoveFeatures", removeFeatures);
2760 } 2220 }
2761 } 2221 }
2762 else if (Common.DowngradeDetectedProperty == upgradeRow.ActionProperty) 2222 else if (Common.DowngradeDetectedProperty == upgradeRow.ActionProperty)
2763 { 2223 {
2764 hasMajorUpgrade = true; 2224 xMajorUpgrade = xMajorUpgrade ?? new XElement(Names.MajorUpgradeElement);
2765 majorUpgrade.DowngradeErrorMessage = downgradeErrorMessage; 2225 xMajorUpgrade.SetAttributeValue("DowngradeErrorMessage", downgradeErrorMessage);
2766 } 2226 }
2767 } 2227 }
2768 2228
2769 if (hasMajorUpgrade) 2229 if (xMajorUpgrade != null)
2770 { 2230 {
2771 if (String.IsNullOrEmpty(downgradeErrorMessage)) 2231 if (String.IsNullOrEmpty(downgradeErrorMessage))
2772 { 2232 {
2773 majorUpgrade.AllowDowngrades = Wix.YesNoType.yes; 2233 xMajorUpgrade.SetAttributeValue("AllowDowngrades", "yes");
2774 } 2234 }
2775 2235
2776 if (!String.IsNullOrEmpty(disallowUpgradeErrorMessage)) 2236 if (!String.IsNullOrEmpty(disallowUpgradeErrorMessage))
2777 { 2237 {
2778 majorUpgrade.Disallow = Wix.YesNoType.yes; 2238 xMajorUpgrade.SetAttributeValue("Disallow", "yes");
2779 majorUpgrade.DisallowUpgradeErrorMessage = disallowUpgradeErrorMessage; 2239 xMajorUpgrade.SetAttributeValue("DisallowUpgradeErrorMessage", disallowUpgradeErrorMessage);
2780 } 2240 }
2781 2241
2782 var scheduledType = DetermineMajorUpgradeScheduling(tables); 2242 var scheduledType = DetermineMajorUpgradeScheduling(tables);
2783 if (Wix.MajorUpgrade.ScheduleType.afterInstallValidate != scheduledType) 2243 if (scheduledType != "afterInstallValidate")
2784 { 2244 {
2785 majorUpgrade.Schedule = scheduledType; 2245 xMajorUpgrade.SetAttributeValue("Schedule", scheduledType);
2786 } 2246 }
2787 2247
2788 this.core.RootElement.AddChild(majorUpgrade); 2248 this.RootElement.Add(xMajorUpgrade);
2789 } 2249 }
2790 } 2250 }
2791 } 2251 }
@@ -2801,43 +2261,25 @@ namespace WixToolset.Core.WindowsInstaller
2801 /// </remarks> 2261 /// </remarks>
2802 private void FinalizeVerbTable(TableIndexedCollection tables) 2262 private void FinalizeVerbTable(TableIndexedCollection tables)
2803 { 2263 {
2804 var extensionTable = tables["Extension"]; 2264 var xExtensions = this.IndexTableOneToMany(tables["Extension"]);
2805 var verbTable = tables["Verb"];
2806
2807 var extensionElements = new Hashtable();
2808
2809 if (null != extensionTable)
2810 {
2811 foreach (var row in extensionTable.Rows)
2812 {
2813 var extension = (Wix.Extension)this.core.GetIndexedElement(row);
2814
2815 if (!extensionElements.Contains(row[0]))
2816 {
2817 extensionElements.Add(row[0], new ArrayList());
2818 }
2819
2820 ((ArrayList)extensionElements[row[0]]).Add(extension);
2821 }
2822 }
2823 2265
2266 var verbTable = tables["Verb"];
2824 if (null != verbTable) 2267 if (null != verbTable)
2825 { 2268 {
2826 foreach (var row in verbTable.Rows) 2269 foreach (var row in verbTable.Rows)
2827 { 2270 {
2828 var verb = (Wix.Verb)this.core.GetIndexedElement(row); 2271 if (xExtensions.TryGetValue(row.FieldAsString(0), out var xVerbExtensions))
2829
2830 var extensionsArray = (ArrayList)extensionElements[row[0]];
2831 if (null != extensionsArray)
2832 { 2272 {
2833 foreach (Wix.Extension extension in extensionsArray) 2273 var xVerb = this.GetIndexedElement(row);
2274
2275 foreach (var xVerbExtension in xVerbExtensions)
2834 { 2276 {
2835 extension.AddChild(verb); 2277 xVerbExtension.Add(xVerb);
2836 } 2278 }
2837 } 2279 }
2838 else 2280 else
2839 { 2281 {
2840 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, verbTable.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Extension_", Convert.ToString(row[0]), "Extension")); 2282 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, verbTable.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Extension_", row.FieldAsString(0), "Extension"));
2841 } 2283 }
2842 } 2284 }
2843 } 2285 }
@@ -2846,33 +2288,38 @@ namespace WixToolset.Core.WindowsInstaller
2846 /// <summary> 2288 /// <summary>
2847 /// Get the path to a file in the source image. 2289 /// Get the path to a file in the source image.
2848 /// </summary> 2290 /// </summary>
2849 /// <param name="file">The file.</param> 2291 /// <param name="xFile">The file.</param>
2850 /// <returns>The path to the file in the source image.</returns> 2292 /// <returns>The path to the file in the source image.</returns>
2851 private string GetSourcePath(Wix.File file) 2293 private string GetSourcePath(XElement xFile)
2852 { 2294 {
2853 var sourcePath = new StringBuilder(); 2295 var sourcePath = new StringBuilder();
2854 2296
2855 var component = (Wix.Component)file.ParentElement; 2297 var component = xFile.Parent;
2856 2298
2857 for (var directory = (Wix.Directory)component.ParentElement; null != directory; directory = directory.ParentElement as Wix.Directory) 2299 for (var xDirectory = component.Parent; null != xDirectory && xDirectory.Name.LocalName == "Directory"; xDirectory = xDirectory.Parent)
2858 { 2300 {
2859 string name; 2301 string name;
2860 2302
2861 if (!this.shortNames && null != directory.SourceName) 2303 var dirSourceName = xDirectory.Attribute("SourceName")?.Value;
2304 var dirShortSourceName = xDirectory.Attribute("ShortSourceName")?.Value;
2305 var dirShortName = xDirectory.Attribute("ShortName")?.Value;
2306 var dirName = xDirectory.Attribute("Name")?.Value;
2307
2308 if (!this.ShortNames && null != dirSourceName)
2862 { 2309 {
2863 name = directory.SourceName; 2310 name = dirSourceName;
2864 } 2311 }
2865 else if (null != directory.ShortSourceName) 2312 else if (null != dirShortSourceName)
2866 { 2313 {
2867 name = directory.ShortSourceName; 2314 name = dirShortSourceName;
2868 } 2315 }
2869 else if (!this.shortNames || null == directory.ShortName) 2316 else if (!this.ShortNames || null == dirShortName)
2870 { 2317 {
2871 name = directory.Name; 2318 name = dirName;
2872 } 2319 }
2873 else 2320 else
2874 { 2321 {
2875 name = directory.ShortName; 2322 name = dirShortName;
2876 } 2323 }
2877 2324
2878 if (0 == sourcePath.Length) 2325 if (0 == sourcePath.Length)
@@ -2895,11 +2342,11 @@ namespace WixToolset.Core.WindowsInstaller
2895 /// <param name="tableName">The name of the table to resolve.</param> 2342 /// <param name="tableName">The name of the table to resolve.</param>
2896 /// <param name="unsortedTableNames">The unsorted table names.</param> 2343 /// <param name="unsortedTableNames">The unsorted table names.</param>
2897 /// <param name="sortedTableNames">The sorted table names.</param> 2344 /// <param name="sortedTableNames">The sorted table names.</param>
2898 private void ResolveTableDependencies(string tableName, SortedList unsortedTableNames, StringCollection sortedTableNames) 2345 private void ResolveTableDependencies(string tableName, List<string> unsortedTableNames, HashSet<string> sortedTableNames)
2899 { 2346 {
2900 unsortedTableNames.Remove(tableName); 2347 unsortedTableNames.Remove(tableName);
2901 2348
2902 foreach (var columnDefinition in this.tableDefinitions[tableName].Columns) 2349 foreach (var columnDefinition in this.TableDefinitions[tableName].Columns)
2903 { 2350 {
2904 // no dependency to resolve because this column doesn't reference another table 2351 // no dependency to resolve because this column doesn't reference another table
2905 if (null == columnDefinition.KeyTable) 2352 if (null == columnDefinition.KeyTable)
@@ -2917,7 +2364,7 @@ namespace WixToolset.Core.WindowsInstaller
2917 { 2364 {
2918 continue; // dependent table has already been sorted 2365 continue; // dependent table has already been sorted
2919 } 2366 }
2920 else if (!this.tableDefinitions.Contains(keyTable)) 2367 else if (!this.TableDefinitions.Contains(keyTable))
2921 { 2368 {
2922 this.Messaging.Write(ErrorMessages.MissingTableDefinition(keyTable)); 2369 this.Messaging.Write(ErrorMessages.MissingTableDefinition(keyTable));
2923 } 2370 }
@@ -2941,24 +2388,18 @@ namespace WixToolset.Core.WindowsInstaller
2941 /// Get the names of the tables to process in the order they should be processed, according to their dependencies. 2388 /// Get the names of the tables to process in the order they should be processed, according to their dependencies.
2942 /// </summary> 2389 /// </summary>
2943 /// <returns>A StringCollection containing the ordered table names.</returns> 2390 /// <returns>A StringCollection containing the ordered table names.</returns>
2944 private StringCollection GetSortedTableNames() 2391 private HashSet<string> GetOrderedTableNames()
2945 { 2392 {
2946 var sortedTableNames = new StringCollection(); 2393 var orderedTableNames = new HashSet<string>();
2947 var unsortedTableNames = new SortedList(); 2394 var unsortedTableNames = new List<string>(this.TableDefinitions.Select(t => t.Name));
2948
2949 // index the table names
2950 foreach (var tableDefinition in this.tableDefinitions)
2951 {
2952 unsortedTableNames.Add(tableDefinition.Name, tableDefinition.Name);
2953 }
2954 2395
2955 // resolve the dependencies for each table 2396 // resolve the dependencies for each table
2956 while (0 < unsortedTableNames.Count) 2397 while (0 < unsortedTableNames.Count)
2957 { 2398 {
2958 this.ResolveTableDependencies(Convert.ToString(unsortedTableNames.GetByIndex(0)), unsortedTableNames, sortedTableNames); 2399 this.ResolveTableDependencies(unsortedTableNames[0], unsortedTableNames, orderedTableNames);
2959 } 2400 }
2960 2401
2961 return sortedTableNames; 2402 return orderedTableNames;
2962 } 2403 }
2963 2404
2964 /// <summary> 2405 /// <summary>
@@ -2968,26 +2409,17 @@ namespace WixToolset.Core.WindowsInstaller
2968 private void InitializeDecompile(TableIndexedCollection tables, int codepage) 2409 private void InitializeDecompile(TableIndexedCollection tables, int codepage)
2969 { 2410 {
2970 // reset all the state information 2411 // reset all the state information
2971 this.compressed = false; 2412 this.Compressed = false;
2972 this.patchTargetFiles.Clear(); 2413 this.ShortNames = false;
2973 this.sequenceElements.Clear(); 2414
2974 this.shortNames = false; 2415 this.Singletons.Clear();
2416 this.IndexedElements.Clear();
2417 this.PatchTargetFiles.Clear();
2975 2418
2976 // set the codepage if its not neutral (0) 2419 // set the codepage if its not neutral (0)
2977 if (0 != codepage) 2420 if (0 != codepage)
2978 { 2421 {
2979 switch (this.OutputType) 2422 this.RootElement.SetAttributeValue("Codepage", codepage);
2980 {
2981 case OutputType.Module:
2982 ((Wix.Module)this.core.RootElement).Codepage = codepage.ToString(CultureInfo.InvariantCulture);
2983 break;
2984 case OutputType.PatchCreation:
2985 ((Wix.PatchCreation)this.core.RootElement).Codepage = codepage.ToString(CultureInfo.InvariantCulture);
2986 break;
2987 case OutputType.Product:
2988 ((Wix.Product)this.core.RootElement).Codepage = codepage.ToString(CultureInfo.InvariantCulture);
2989 break;
2990 }
2991 } 2423 }
2992 2424
2993 // index the rows from the extension libraries 2425 // index the rows from the extension libraries
@@ -3011,15 +2443,15 @@ namespace WixToolset.Core.WindowsInstaller
3011 // the Actions table needs to be handled specially 2443 // the Actions table needs to be handled specially
3012 if ("WixAction" == table.Name) 2444 if ("WixAction" == table.Name)
3013 { 2445 {
3014 primaryKey = Convert.ToString(row[1]); 2446 primaryKey = row.FieldAsString(1);
3015 2447
3016 if (OutputType.Module == this.outputType) 2448 if (OutputType.Module == this.outputType)
3017 { 2449 {
3018 tableName = String.Concat("Module", Convert.ToString(row[0])); 2450 tableName = String.Concat("Module", row.FieldAsString(0));
3019 } 2451 }
3020 else 2452 else
3021 { 2453 {
3022 tableName = Convert.ToString(row[0]); 2454 tableName = row.FieldAsString(0);
3023 } 2455 }
3024 } 2456 }
3025 else 2457 else
@@ -3077,9 +2509,8 @@ namespace WixToolset.Core.WindowsInstaller
3077 /// <param name="output">The output being decompiled.</param> 2509 /// <param name="output">The output being decompiled.</param>
3078 private void DecompileTables(WindowsInstallerData output) 2510 private void DecompileTables(WindowsInstallerData output)
3079 { 2511 {
3080 var sortedTableNames = this.GetSortedTableNames(); 2512 var orderedTableNames = this.GetOrderedTableNames();
3081 2513 foreach (var tableName in orderedTableNames)
3082 foreach (var tableName in sortedTableNames)
3083 { 2514 {
3084 var table = output.Tables[tableName]; 2515 var table = output.Tables[tableName];
3085 2516
@@ -3094,435 +2525,433 @@ namespace WixToolset.Core.WindowsInstaller
3094 // empty tables may be kept with EnsureTable if the user set the proper option 2525 // empty tables may be kept with EnsureTable if the user set the proper option
3095 if (0 == table.Rows.Count && this.SuppressDroppingEmptyTables) 2526 if (0 == table.Rows.Count && this.SuppressDroppingEmptyTables)
3096 { 2527 {
3097 var ensureTable = new Wix.EnsureTable(); 2528 this.RootElement.Add(new XElement(Names.EnsureTableElement, new XAttribute("Id", table.Name)));
3098 ensureTable.Id = table.Name;
3099 this.core.RootElement.AddChild(ensureTable);
3100 } 2529 }
3101 2530
3102 switch (table.Name) 2531 switch (table.Name)
3103 { 2532 {
3104 case "_SummaryInformation": 2533 case "_SummaryInformation":
3105 this.Decompile_SummaryInformationTable(table); 2534 this.Decompile_SummaryInformationTable(table);
3106 break; 2535 break;
3107 case "AdminExecuteSequence": 2536 case "AdminExecuteSequence":
3108 case "AdminUISequence": 2537 case "AdminUISequence":
3109 case "AdvtExecuteSequence": 2538 case "AdvtExecuteSequence":
3110 case "InstallExecuteSequence": 2539 case "InstallExecuteSequence":
3111 case "InstallUISequence": 2540 case "InstallUISequence":
3112 case "ModuleAdminExecuteSequence": 2541 case "ModuleAdminExecuteSequence":
3113 case "ModuleAdminUISequence": 2542 case "ModuleAdminUISequence":
3114 case "ModuleAdvtExecuteSequence": 2543 case "ModuleAdvtExecuteSequence":
3115 case "ModuleInstallExecuteSequence": 2544 case "ModuleInstallExecuteSequence":
3116 case "ModuleInstallUISequence": 2545 case "ModuleInstallUISequence":
3117 // handled in FinalizeSequenceTables 2546 // handled in FinalizeSequenceTables
3118 break; 2547 break;
2548 case "ActionText":
2549 this.DecompileActionTextTable(table);
2550 break;
2551 case "AdvtUISequence":
2552 this.Messaging.Write(WarningMessages.DeprecatedTable(table.Name));
2553 break;
2554 case "AppId":
2555 this.DecompileAppIdTable(table);
2556 break;
2557 case "AppSearch":
2558 // handled in FinalizeSearchTables
2559 break;
2560 case "BBControl":
2561 this.DecompileBBControlTable(table);
2562 break;
2563 case "Billboard":
2564 this.DecompileBillboardTable(table);
2565 break;
2566 case "Binary":
2567 this.DecompileBinaryTable(table);
2568 break;
2569 case "BindImage":
2570 this.DecompileBindImageTable(table);
2571 break;
2572 case "CCPSearch":
2573 // handled in FinalizeSearchTables
2574 break;
2575 case "CheckBox":
2576 // handled in FinalizeCheckBoxTable
2577 break;
2578 case "Class":
2579 this.DecompileClassTable(table);
2580 break;
2581 case "ComboBox":
2582 this.DecompileComboBoxTable(table);
2583 break;
2584 case "Control":
2585 this.DecompileControlTable(table);
2586 break;
2587 case "ControlCondition":
2588 this.DecompileControlConditionTable(table);
2589 break;
2590 case "ControlEvent":
2591 this.DecompileControlEventTable(table);
2592 break;
2593 case "CreateFolder":
2594 this.DecompileCreateFolderTable(table);
2595 break;
2596 case "CustomAction":
2597 this.DecompileCustomActionTable(table);
2598 break;
2599 case "CompLocator":
2600 this.DecompileCompLocatorTable(table);
2601 break;
2602 case "Complus":
2603 this.DecompileComplusTable(table);
2604 break;
2605 case "Component":
2606 this.DecompileComponentTable(table);
2607 break;
2608 case "Condition":
2609 this.DecompileConditionTable(table);
2610 break;
2611 case "Dialog":
2612 this.DecompileDialogTable(table);
2613 break;
2614 case "Directory":
2615 this.DecompileDirectoryTable(table);
2616 break;
2617 case "DrLocator":
2618 this.DecompileDrLocatorTable(table);
2619 break;
2620 case "DuplicateFile":
2621 this.DecompileDuplicateFileTable(table);
2622 break;
2623 case "Environment":
2624 this.DecompileEnvironmentTable(table);
2625 break;
2626 case "Error":
2627 this.DecompileErrorTable(table);
2628 break;
2629 case "EventMapping":
2630 this.DecompileEventMappingTable(table);
2631 break;
2632 case "Extension":
2633 this.DecompileExtensionTable(table);
2634 break;
2635 case "ExternalFiles":
2636 this.DecompileExternalFilesTable(table);
2637 break;
2638 case "FamilyFileRanges":
2639 // handled in FinalizeFamilyFileRangesTable
2640 break;
2641 case "Feature":
2642 this.DecompileFeatureTable(table);
2643 break;
2644 case "FeatureComponents":
2645 this.DecompileFeatureComponentsTable(table);
2646 break;
2647 case "File":
2648 this.DecompileFileTable(table);
2649 break;
2650 case "FileSFPCatalog":
2651 this.DecompileFileSFPCatalogTable(table);
2652 break;
2653 case "Font":
2654 this.DecompileFontTable(table);
2655 break;
2656 case "Icon":
2657 this.DecompileIconTable(table);
2658 break;
2659 case "ImageFamilies":
2660 this.DecompileImageFamiliesTable(table);
2661 break;
2662 case "IniFile":
2663 this.DecompileIniFileTable(table);
2664 break;
2665 case "IniLocator":
2666 this.DecompileIniLocatorTable(table);
2667 break;
2668 case "IsolatedComponent":
2669 this.DecompileIsolatedComponentTable(table);
2670 break;
2671 case "LaunchCondition":
2672 this.DecompileLaunchConditionTable(table);
2673 break;
2674 case "ListBox":
2675 this.DecompileListBoxTable(table);
2676 break;
2677 case "ListView":
2678 this.DecompileListViewTable(table);
2679 break;
2680 case "LockPermissions":
2681 this.DecompileLockPermissionsTable(table);
2682 break;
2683 case "Media":
2684 this.DecompileMediaTable(table);
2685 break;
2686 case "MIME":
2687 this.DecompileMIMETable(table);
2688 break;
2689 case "ModuleAdvtUISequence":
2690 this.Messaging.Write(WarningMessages.DeprecatedTable(table.Name));
2691 break;
2692 case "ModuleComponents":
2693 // handled by DecompileComponentTable (since the ModuleComponents table
2694 // rows are created by nesting components under the Module element)
2695 break;
2696 case "ModuleConfiguration":
2697 this.DecompileModuleConfigurationTable(table);
2698 break;
2699 case "ModuleDependency":
2700 this.DecompileModuleDependencyTable(table);
2701 break;
2702 case "ModuleExclusion":
2703 this.DecompileModuleExclusionTable(table);
2704 break;
2705 case "ModuleIgnoreTable":
2706 this.DecompileModuleIgnoreTableTable(table);
2707 break;
2708 case "ModuleSignature":
2709 this.DecompileModuleSignatureTable(table);
2710 break;
2711 case "ModuleSubstitution":
2712 this.DecompileModuleSubstitutionTable(table);
2713 break;
2714 case "MoveFile":
2715 this.DecompileMoveFileTable(table);
2716 break;
2717 case "MsiAssembly":
2718 // handled in FinalizeFileTable
2719 break;
2720 case "MsiDigitalCertificate":
2721 this.DecompileMsiDigitalCertificateTable(table);
2722 break;
2723 case "MsiDigitalSignature":
2724 this.DecompileMsiDigitalSignatureTable(table);
2725 break;
2726 case "MsiEmbeddedChainer":
2727 this.DecompileMsiEmbeddedChainerTable(table);
2728 break;
2729 case "MsiEmbeddedUI":
2730 this.DecompileMsiEmbeddedUITable(table);
2731 break;
2732 case "MsiLockPermissionsEx":
2733 this.DecompileMsiLockPermissionsExTable(table);
2734 break;
2735 case "MsiPackageCertificate":
2736 this.DecompileMsiPackageCertificateTable(table);
2737 break;
2738 case "MsiPatchCertificate":
2739 this.DecompileMsiPatchCertificateTable(table);
2740 break;
2741 case "MsiShortcutProperty":
2742 this.DecompileMsiShortcutPropertyTable(table);
2743 break;
2744 case "ODBCAttribute":
2745 this.DecompileODBCAttributeTable(table);
2746 break;
2747 case "ODBCDataSource":
2748 this.DecompileODBCDataSourceTable(table);
2749 break;
2750 case "ODBCDriver":
2751 this.DecompileODBCDriverTable(table);
2752 break;
2753 case "ODBCSourceAttribute":
2754 this.DecompileODBCSourceAttributeTable(table);
2755 break;
2756 case "ODBCTranslator":
2757 this.DecompileODBCTranslatorTable(table);
2758 break;
2759 case "PatchMetadata":
2760 this.DecompilePatchMetadataTable(table);
2761 break;
2762 case "PatchSequence":
2763 this.DecompilePatchSequenceTable(table);
2764 break;
2765 case "ProgId":
2766 this.DecompileProgIdTable(table);
2767 break;
2768 case "Properties":
2769 this.DecompilePropertiesTable(table);
2770 break;
2771 case "Property":
2772 this.DecompilePropertyTable(table);
2773 break;
2774 case "PublishComponent":
2775 this.DecompilePublishComponentTable(table);
2776 break;
2777 case "RadioButton":
2778 this.DecompileRadioButtonTable(table);
2779 break;
2780 case "Registry":
2781 this.DecompileRegistryTable(table);
2782 break;
2783 case "RegLocator":
2784 this.DecompileRegLocatorTable(table);
2785 break;
2786 case "RemoveFile":
2787 this.DecompileRemoveFileTable(table);
2788 break;
2789 case "RemoveIniFile":
2790 this.DecompileRemoveIniFileTable(table);
2791 break;
2792 case "RemoveRegistry":
2793 this.DecompileRemoveRegistryTable(table);
2794 break;
2795 case "ReserveCost":
2796 this.DecompileReserveCostTable(table);
2797 break;
2798 case "SelfReg":
2799 this.DecompileSelfRegTable(table);
2800 break;
2801 case "ServiceControl":
2802 this.DecompileServiceControlTable(table);
2803 break;
2804 case "ServiceInstall":
2805 this.DecompileServiceInstallTable(table);
2806 break;
2807 case "SFPCatalog":
2808 this.DecompileSFPCatalogTable(table);
2809 break;
2810 case "Shortcut":
2811 this.DecompileShortcutTable(table);
2812 break;
2813 case "Signature":
2814 this.DecompileSignatureTable(table);
2815 break;
2816 case "TargetFiles_OptionalData":
2817 this.DecompileTargetFiles_OptionalDataTable(table);
2818 break;
2819 case "TargetImages":
2820 this.DecompileTargetImagesTable(table);
2821 break;
2822 case "TextStyle":
2823 this.DecompileTextStyleTable(table);
2824 break;
2825 case "TypeLib":
2826 this.DecompileTypeLibTable(table);
2827 break;
2828 case "Upgrade":
2829 this.DecompileUpgradeTable(table);
2830 break;
2831 case "UpgradedFiles_OptionalData":
2832 this.DecompileUpgradedFiles_OptionalDataTable(table);
2833 break;
2834 case "UpgradedFilesToIgnore":
2835 this.DecompileUpgradedFilesToIgnoreTable(table);
2836 break;
2837 case "UpgradedImages":
2838 this.DecompileUpgradedImagesTable(table);
2839 break;
2840 case "UIText":
2841 this.DecompileUITextTable(table);
2842 break;
2843 case "Verb":
2844 this.DecompileVerbTable(table);
2845 break;
2846
2847 default:
2848#if TODO_DECOMPILER_EXTENSIONS
2849 if (this.ExtensionsByTableName.TryGetValue(table.Name, out var extension)
2850 {
2851 extension.DecompileTable(table);
2852 }
2853 else
2854#endif
2855 if (!this.SuppressCustomTables)
2856 {
2857 this.DecompileCustomTable(table);
2858 }
2859 break;
2860 }
2861 }
2862 }
2863
2864 /// <summary>
2865 /// Determine if a particular table should be decompiled with the current settings.
2866 /// </summary>
2867 /// <param name="output">The output being decompiled.</param>
2868 /// <param name="tableName">The name of a table.</param>
2869 /// <returns>true if the table should be decompiled; false otherwise.</returns>
2870 private bool DecompilableTable(WindowsInstallerData output, string tableName)
2871 {
2872 switch (tableName)
2873 {
3119 case "ActionText": 2874 case "ActionText":
3120 this.DecompileActionTextTable(table);
3121 break;
3122 case "AdvtUISequence":
3123 this.Messaging.Write(WarningMessages.DeprecatedTable(table.Name));
3124 break;
3125 case "AppId":
3126 this.DecompileAppIdTable(table);
3127 break;
3128 case "AppSearch":
3129 // handled in FinalizeSearchTables
3130 break;
3131 case "BBControl": 2875 case "BBControl":
3132 this.DecompileBBControlTable(table);
3133 break;
3134 case "Billboard": 2876 case "Billboard":
3135 this.DecompileBillboardTable(table);
3136 break;
3137 case "Binary":
3138 this.DecompileBinaryTable(table);
3139 break;
3140 case "BindImage":
3141 this.DecompileBindImageTable(table);
3142 break;
3143 case "CCPSearch":
3144 // handled in FinalizeSearchTables
3145 break;
3146 case "CheckBox": 2877 case "CheckBox":
3147 // handled in FinalizeCheckBoxTable
3148 break;
3149 case "Class":
3150 this.DecompileClassTable(table);
3151 break;
3152 case "ComboBox":
3153 this.DecompileComboBoxTable(table);
3154 break;
3155 case "Control": 2878 case "Control":
3156 this.DecompileControlTable(table);
3157 break;
3158 case "ControlCondition": 2879 case "ControlCondition":
3159 this.DecompileControlConditionTable(table);
3160 break;
3161 case "ControlEvent": 2880 case "ControlEvent":
3162 this.DecompileControlEventTable(table);
3163 break;
3164 case "CreateFolder":
3165 this.DecompileCreateFolderTable(table);
3166 break;
3167 case "CustomAction":
3168 this.DecompileCustomActionTable(table);
3169 break;
3170 case "CompLocator":
3171 this.DecompileCompLocatorTable(table);
3172 break;
3173 case "Complus":
3174 this.DecompileComplusTable(table);
3175 break;
3176 case "Component":
3177 this.DecompileComponentTable(table);
3178 break;
3179 case "Condition":
3180 this.DecompileConditionTable(table);
3181 break;
3182 case "Dialog": 2881 case "Dialog":
3183 this.DecompileDialogTable(table);
3184 break;
3185 case "Directory":
3186 this.DecompileDirectoryTable(table);
3187 break;
3188 case "DrLocator":
3189 this.DecompileDrLocatorTable(table);
3190 break;
3191 case "DuplicateFile":
3192 this.DecompileDuplicateFileTable(table);
3193 break;
3194 case "Environment":
3195 this.DecompileEnvironmentTable(table);
3196 break;
3197 case "Error": 2882 case "Error":
3198 this.DecompileErrorTable(table);
3199 break;
3200 case "EventMapping": 2883 case "EventMapping":
3201 this.DecompileEventMappingTable(table); 2884 case "RadioButton":
3202 break; 2885 case "TextStyle":
3203 case "Extension": 2886 case "UIText":
3204 this.DecompileExtensionTable(table); 2887 return !this.SuppressUI;
3205 break; 2888 case "ModuleAdminExecuteSequence":
3206 case "ExternalFiles": 2889 case "ModuleAdminUISequence":
3207 this.DecompileExternalFilesTable(table); 2890 case "ModuleAdvtExecuteSequence":
3208 break;
3209 case "FamilyFileRanges":
3210 // handled in FinalizeFamilyFileRangesTable
3211 break;
3212 case "Feature":
3213 this.DecompileFeatureTable(table);
3214 break;
3215 case "FeatureComponents":
3216 this.DecompileFeatureComponentsTable(table);
3217 break;
3218 case "File":
3219 this.DecompileFileTable(table);
3220 break;
3221 case "FileSFPCatalog":
3222 this.DecompileFileSFPCatalogTable(table);
3223 break;
3224 case "Font":
3225 this.DecompileFontTable(table);
3226 break;
3227 case "Icon":
3228 this.DecompileIconTable(table);
3229 break;
3230 case "ImageFamilies":
3231 this.DecompileImageFamiliesTable(table);
3232 break;
3233 case "IniFile":
3234 this.DecompileIniFileTable(table);
3235 break;
3236 case "IniLocator":
3237 this.DecompileIniLocatorTable(table);
3238 break;
3239 case "IsolatedComponent":
3240 this.DecompileIsolatedComponentTable(table);
3241 break;
3242 case "LaunchCondition":
3243 this.DecompileLaunchConditionTable(table);
3244 break;
3245 case "ListBox":
3246 this.DecompileListBoxTable(table);
3247 break;
3248 case "ListView":
3249 this.DecompileListViewTable(table);
3250 break;
3251 case "LockPermissions":
3252 this.DecompileLockPermissionsTable(table);
3253 break;
3254 case "Media":
3255 this.DecompileMediaTable(table);
3256 break;
3257 case "MIME":
3258 this.DecompileMIMETable(table);
3259 break;
3260 case "ModuleAdvtUISequence": 2891 case "ModuleAdvtUISequence":
3261 this.Messaging.Write(WarningMessages.DeprecatedTable(table.Name));
3262 break;
3263 case "ModuleComponents": 2892 case "ModuleComponents":
3264 // handled by DecompileComponentTable (since the ModuleComponents table
3265 // rows are created by nesting components under the Module element)
3266 break;
3267 case "ModuleConfiguration": 2893 case "ModuleConfiguration":
3268 this.DecompileModuleConfigurationTable(table);
3269 break;
3270 case "ModuleDependency": 2894 case "ModuleDependency":
3271 this.DecompileModuleDependencyTable(table);
3272 break;
3273 case "ModuleExclusion":
3274 this.DecompileModuleExclusionTable(table);
3275 break;
3276 case "ModuleIgnoreTable": 2895 case "ModuleIgnoreTable":
3277 this.DecompileModuleIgnoreTableTable(table); 2896 case "ModuleInstallExecuteSequence":
3278 break; 2897 case "ModuleInstallUISequence":
2898 case "ModuleExclusion":
3279 case "ModuleSignature": 2899 case "ModuleSignature":
3280 this.DecompileModuleSignatureTable(table);
3281 break;
3282 case "ModuleSubstitution": 2900 case "ModuleSubstitution":
3283 this.DecompileModuleSubstitutionTable(table); 2901 if (OutputType.Module != output.Type)
3284 break; 2902 {
3285 case "MoveFile": 2903 this.Messaging.Write(WarningMessages.SkippingMergeModuleTable(output.SourceLineNumbers, tableName));
3286 this.DecompileMoveFileTable(table); 2904 return false;
3287 break; 2905 }
3288 case "MsiAssembly": 2906 else
3289 // handled in FinalizeFileTable 2907 {
3290 break; 2908 return true;
3291 case "MsiDigitalCertificate": 2909 }
3292 this.DecompileMsiDigitalCertificateTable(table); 2910 case "ExternalFiles":
3293 break; 2911 case "FamilyFileRanges":
3294 case "MsiDigitalSignature": 2912 case "ImageFamilies":
3295 this.DecompileMsiDigitalSignatureTable(table);
3296 break;
3297 case "MsiEmbeddedChainer":
3298 this.DecompileMsiEmbeddedChainerTable(table);
3299 break;
3300 case "MsiEmbeddedUI":
3301 this.DecompileMsiEmbeddedUITable(table);
3302 break;
3303 case "MsiLockPermissionsEx":
3304 this.DecompileMsiLockPermissionsExTable(table);
3305 break;
3306 case "MsiPackageCertificate":
3307 this.DecompileMsiPackageCertificateTable(table);
3308 break;
3309 case "MsiPatchCertificate":
3310 this.DecompileMsiPatchCertificateTable(table);
3311 break;
3312 case "MsiShortcutProperty":
3313 this.DecompileMsiShortcutPropertyTable(table);
3314 break;
3315 case "ODBCAttribute":
3316 this.DecompileODBCAttributeTable(table);
3317 break;
3318 case "ODBCDataSource":
3319 this.DecompileODBCDataSourceTable(table);
3320 break;
3321 case "ODBCDriver":
3322 this.DecompileODBCDriverTable(table);
3323 break;
3324 case "ODBCSourceAttribute":
3325 this.DecompileODBCSourceAttributeTable(table);
3326 break;
3327 case "ODBCTranslator":
3328 this.DecompileODBCTranslatorTable(table);
3329 break;
3330 case "PatchMetadata": 2913 case "PatchMetadata":
3331 this.DecompilePatchMetadataTable(table);
3332 break;
3333 case "PatchSequence": 2914 case "PatchSequence":
3334 this.DecompilePatchSequenceTable(table);
3335 break;
3336 case "ProgId":
3337 this.DecompileProgIdTable(table);
3338 break;
3339 case "Properties": 2915 case "Properties":
3340 this.DecompilePropertiesTable(table);
3341 break;
3342 case "Property":
3343 this.DecompilePropertyTable(table);
3344 break;
3345 case "PublishComponent":
3346 this.DecompilePublishComponentTable(table);
3347 break;
3348 case "RadioButton":
3349 this.DecompileRadioButtonTable(table);
3350 break;
3351 case "Registry":
3352 this.DecompileRegistryTable(table);
3353 break;
3354 case "RegLocator":
3355 this.DecompileRegLocatorTable(table);
3356 break;
3357 case "RemoveFile":
3358 this.DecompileRemoveFileTable(table);
3359 break;
3360 case "RemoveIniFile":
3361 this.DecompileRemoveIniFileTable(table);
3362 break;
3363 case "RemoveRegistry":
3364 this.DecompileRemoveRegistryTable(table);
3365 break;
3366 case "ReserveCost":
3367 this.DecompileReserveCostTable(table);
3368 break;
3369 case "SelfReg":
3370 this.DecompileSelfRegTable(table);
3371 break;
3372 case "ServiceControl":
3373 this.DecompileServiceControlTable(table);
3374 break;
3375 case "ServiceInstall":
3376 this.DecompileServiceInstallTable(table);
3377 break;
3378 case "SFPCatalog":
3379 this.DecompileSFPCatalogTable(table);
3380 break;
3381 case "Shortcut":
3382 this.DecompileShortcutTable(table);
3383 break;
3384 case "Signature":
3385 this.DecompileSignatureTable(table);
3386 break;
3387 case "TargetFiles_OptionalData": 2916 case "TargetFiles_OptionalData":
3388 this.DecompileTargetFiles_OptionalDataTable(table);
3389 break;
3390 case "TargetImages": 2917 case "TargetImages":
3391 this.DecompileTargetImagesTable(table);
3392 break;
3393 case "TextStyle":
3394 this.DecompileTextStyleTable(table);
3395 break;
3396 case "TypeLib":
3397 this.DecompileTypeLibTable(table);
3398 break;
3399 case "Upgrade":
3400 this.DecompileUpgradeTable(table);
3401 break;
3402 case "UpgradedFiles_OptionalData": 2918 case "UpgradedFiles_OptionalData":
3403 this.DecompileUpgradedFiles_OptionalDataTable(table);
3404 break;
3405 case "UpgradedFilesToIgnore": 2919 case "UpgradedFilesToIgnore":
3406 this.DecompileUpgradedFilesToIgnoreTable(table);
3407 break;
3408 case "UpgradedImages": 2920 case "UpgradedImages":
3409 this.DecompileUpgradedImagesTable(table); 2921 if (OutputType.PatchCreation != output.Type)
3410 break;
3411 case "UIText":
3412 this.DecompileUITextTable(table);
3413 break;
3414 case "Verb":
3415 this.DecompileVerbTable(table);
3416 break;
3417
3418 default:
3419#if TODO_DECOMPILER_EXTENSIONS
3420 if (this.ExtensionsByTableName.TryGetValue(table.Name, out var extension)
3421 { 2922 {
3422 extension.DecompileTable(table); 2923 this.Messaging.Write(WarningMessages.SkippingPatchCreationTable(output.SourceLineNumbers, tableName));
2924 return false;
3423 } 2925 }
3424 else 2926 else
3425#endif
3426 if (!this.SuppressCustomTables)
3427 { 2927 {
3428 this.DecompileCustomTable(table); 2928 return true;
3429 } 2929 }
3430 break; 2930 case "MsiPatchHeaders":
3431 } 2931 case "MsiPatchMetadata":
3432 } 2932 case "MsiPatchOldAssemblyName":
3433 } 2933 case "MsiPatchOldAssemblyFile":
3434 2934 case "MsiPatchSequence":
3435 /// <summary> 2935 case "Patch":
3436 /// Determine if a particular table should be decompiled with the current settings. 2936 case "PatchPackage":
3437 /// </summary> 2937 this.Messaging.Write(WarningMessages.PatchTable(output.SourceLineNumbers, tableName));
3438 /// <param name="output">The output being decompiled.</param>
3439 /// <param name="tableName">The name of a table.</param>
3440 /// <returns>true if the table should be decompiled; false otherwise.</returns>
3441 private bool DecompilableTable(WindowsInstallerData output, string tableName)
3442 {
3443 switch (tableName)
3444 {
3445 case "ActionText":
3446 case "BBControl":
3447 case "Billboard":
3448 case "CheckBox":
3449 case "Control":
3450 case "ControlCondition":
3451 case "ControlEvent":
3452 case "Dialog":
3453 case "Error":
3454 case "EventMapping":
3455 case "RadioButton":
3456 case "TextStyle":
3457 case "UIText":
3458 return !this.SuppressUI;
3459 case "ModuleAdminExecuteSequence":
3460 case "ModuleAdminUISequence":
3461 case "ModuleAdvtExecuteSequence":
3462 case "ModuleAdvtUISequence":
3463 case "ModuleComponents":
3464 case "ModuleConfiguration":
3465 case "ModuleDependency":
3466 case "ModuleIgnoreTable":
3467 case "ModuleInstallExecuteSequence":
3468 case "ModuleInstallUISequence":
3469 case "ModuleExclusion":
3470 case "ModuleSignature":
3471 case "ModuleSubstitution":
3472 if (OutputType.Module != output.Type)
3473 {
3474 this.Messaging.Write(WarningMessages.SkippingMergeModuleTable(output.SourceLineNumbers, tableName));
3475 return false;
3476 }
3477 else
3478 {
3479 return true;
3480 }
3481 case "ExternalFiles":
3482 case "FamilyFileRanges":
3483 case "ImageFamilies":
3484 case "PatchMetadata":
3485 case "PatchSequence":
3486 case "Properties":
3487 case "TargetFiles_OptionalData":
3488 case "TargetImages":
3489 case "UpgradedFiles_OptionalData":
3490 case "UpgradedFilesToIgnore":
3491 case "UpgradedImages":
3492 if (OutputType.PatchCreation != output.Type)
3493 {
3494 this.Messaging.Write(WarningMessages.SkippingPatchCreationTable(output.SourceLineNumbers, tableName));
3495 return false; 2938 return false;
3496 } 2939 case "_SummaryInformation":
3497 else
3498 {
3499 return true; 2940 return true;
3500 } 2941 case "_Validation":
3501 case "MsiPatchHeaders": 2942 case "MsiAssemblyName":
3502 case "MsiPatchMetadata": 2943 case "MsiFileHash":
3503 case "MsiPatchOldAssemblyName":
3504 case "MsiPatchOldAssemblyFile":
3505 case "MsiPatchSequence":
3506 case "Patch":
3507 case "PatchPackage":
3508 this.Messaging.Write(WarningMessages.PatchTable(output.SourceLineNumbers, tableName));
3509 return false;
3510 case "_SummaryInformation":
3511 return true;
3512 case "_Validation":
3513 case "MsiAssemblyName":
3514 case "MsiFileHash":
3515 return false;
3516 default: // all other tables are allowed in any output except for a patch creation package
3517 if (OutputType.PatchCreation == output.Type)
3518 {
3519 this.Messaging.Write(WarningMessages.IllegalPatchCreationTable(output.SourceLineNumbers, tableName));
3520 return false; 2944 return false;
3521 } 2945 default: // all other tables are allowed in any output except for a patch creation package
3522 else 2946 if (OutputType.PatchCreation == output.Type)
3523 { 2947 {
3524 return true; 2948 this.Messaging.Write(WarningMessages.IllegalPatchCreationTable(output.SourceLineNumbers, tableName));
3525 } 2949 return false;
2950 }
2951 else
2952 {
2953 return true;
2954 }
3526 } 2955 }
3527 } 2956 }
3528 2957
@@ -3534,200 +2963,177 @@ namespace WixToolset.Core.WindowsInstaller
3534 { 2963 {
3535 if (OutputType.Module == this.OutputType || OutputType.Product == this.OutputType) 2964 if (OutputType.Module == this.OutputType || OutputType.Product == this.OutputType)
3536 { 2965 {
3537 var package = new Wix.Package(); 2966 var xPackage = new XElement(Names.PackageElement);
3538 2967
3539 foreach (var row in table.Rows) 2968 foreach (var row in table.Rows)
3540 { 2969 {
3541 var value = Convert.ToString(row[1]); 2970 var value = row.FieldAsString(1);
3542 2971
3543 if (null != value && 0 < value.Length) 2972 if (!String.IsNullOrEmpty(value))
3544 { 2973 {
3545 switch (Convert.ToInt32(row[0])) 2974 switch (row.FieldAsInteger(0))
3546 { 2975 {
3547 case 1: 2976 case 1:
3548 if ("1252" != value) 2977 if ("1252" != value)
3549 {
3550 package.SummaryCodepage = value;
3551 }
3552 break;
3553 case 3:
3554 package.Description = value;
3555 break;
3556 case 4:
3557 package.Manufacturer = value;
3558 break;
3559 case 5:
3560 if ("Installer" != value)
3561 {
3562 package.Keywords = value;
3563 }
3564 break;
3565 case 6:
3566 if (!value.StartsWith("This installer database contains the logic and data required to install "))
3567 {
3568 package.Comments = value;
3569 }
3570 break;
3571 case 7:
3572 var template = value.Split(';');
3573 if (0 < template.Length && 0 < template[template.Length - 1].Length)
3574 {
3575 package.Languages = template[template.Length - 1];
3576 }
3577
3578 if (1 < template.Length && null != template[0] && 0 < template[0].Length)
3579 {
3580 switch (template[0])
3581 { 2978 {
3582 case "Intel": 2979 xPackage.SetAttributeValue("SummaryCodepage", value);
3583 package.Platform = WixToolset.Data.Serialize.Package.PlatformType.x86; 2980 }
3584 break; 2981 break;
3585 case "Intel64": 2982 case 3:
3586 package.Platform = WixToolset.Data.Serialize.Package.PlatformType.ia64; 2983 xPackage.SetAttributeValue("Description", value);
3587 break; 2984 break;
3588 case "x64": 2985 case 4:
3589 package.Platform = WixToolset.Data.Serialize.Package.PlatformType.x64; 2986 xPackage.SetAttributeValue("Manufacturer", value);
3590 break; 2987 break;
2988 case 5:
2989 if ("Installer" != value)
2990 {
2991 xPackage.SetAttributeValue("Keywords", value);
2992 }
2993 break;
2994 case 6:
2995 if (!value.StartsWith("This installer database contains the logic and data required to install "))
2996 {
2997 xPackage.SetAttributeValue("Comments", value);
2998 }
2999 break;
3000 case 7:
3001 var template = value.Split(';');
3002 if (0 < template.Length && 0 < template[template.Length - 1].Length)
3003 {
3004 xPackage.SetAttributeValue("Languages", template[template.Length - 1]);
3591 } 3005 }
3592 }
3593 break;
3594 case 9:
3595 if (OutputType.Module == this.OutputType)
3596 {
3597 this.modularizationGuid = value;
3598 package.Id = value;
3599 }
3600 break;
3601 case 14:
3602 package.InstallerVersion = Convert.ToInt32(row[1], CultureInfo.InvariantCulture);
3603 break;
3604 case 15:
3605 var wordCount = Convert.ToInt32(row[1], CultureInfo.InvariantCulture);
3606 if (0x1 == (wordCount & 0x1))
3607 {
3608 this.shortNames = true;
3609 package.ShortNames = Wix.YesNoType.yes;
3610 }
3611 3006
3612 if (0x2 == (wordCount & 0x2)) 3007 if (1 < template.Length && null != template[0] && 0 < template[0].Length)
3613 { 3008 {
3614 this.compressed = true; 3009 switch (template[0])
3010 {
3011 case "Intel":
3012 xPackage.SetAttributeValue("Platform", "x86");
3013 break;
3014 case "Intel64":
3015 xPackage.SetAttributeValue("Platform", "ia64");
3016 break;
3017 case "x64":
3018 xPackage.SetAttributeValue("Platform", "x64");
3019 break;
3020 case "Arm":
3021 xPackage.SetAttributeValue("Platform", "arm");
3022 break;
3023 case "Arm64":
3024 xPackage.SetAttributeValue("Platform", "arm64");
3025 break;
3026 }
3027 }
3028 break;
3029 case 9:
3030 if (OutputType.Module == this.OutputType)
3031 {
3032 this.ModularizationGuid = value;
3033 xPackage.SetAttributeValue("Id", value);
3034 }
3035 break;
3036 case 14:
3037 xPackage.SetAttributeValue("InstallerVersion", row.FieldAsInteger(1));
3038 break;
3039 case 15:
3040 var wordCount = row.FieldAsInteger(1);
3041 if (0x1 == (wordCount & 0x1))
3042 {
3043 this.ShortNames = true;
3044 xPackage.SetAttributeValue("ShortNames", "yes");
3045 }
3615 3046
3616 if (OutputType.Product == this.OutputType) 3047 if (0x2 == (wordCount & 0x2))
3617 { 3048 {
3618 package.Compressed = Wix.YesNoType.yes; 3049 this.Compressed = true;
3050
3051 if (OutputType.Product == this.OutputType)
3052 {
3053 xPackage.SetAttributeValue("Compressed", "yes");
3054 }
3619 } 3055 }
3620 }
3621 3056
3622 if (0x4 == (wordCount & 0x4)) 3057 if (0x4 == (wordCount & 0x4))
3623 { 3058 {
3624 package.AdminImage = Wix.YesNoType.yes; 3059 xPackage.SetAttributeValue("AdminImage", "yes");
3625 } 3060 }
3626 3061
3627 if (0x8 == (wordCount & 0x8)) 3062 if (0x8 == (wordCount & 0x8))
3628 { 3063 {
3629 package.InstallPrivileges = Wix.Package.InstallPrivilegesType.limited; 3064 xPackage.SetAttributeValue("InstallPrivileges", "limited");
3630 } 3065 }
3631 3066
3632 break;
3633 case 19:
3634 var security = Convert.ToInt32(row[1], CultureInfo.InvariantCulture);
3635 switch (security)
3636 {
3637 case 0:
3638 package.ReadOnly = Wix.YesNoDefaultType.no;
3639 break; 3067 break;
3640 case 4: 3068 case 19:
3641 package.ReadOnly = Wix.YesNoDefaultType.yes; 3069 var security = row.FieldAsInteger(1);
3070 switch (security)
3071 {
3072 case 0:
3073 xPackage.SetAttributeValue("ReadOnly", "no");
3074 break;
3075 case 4:
3076 xPackage.SetAttributeValue("ReadOnly", "yes");
3077 break;
3078 }
3642 break; 3079 break;
3643 }
3644 break;
3645 } 3080 }
3646 } 3081 }
3647 } 3082 }
3648 3083
3649 this.core.RootElement.AddChild(package); 3084 this.RootElement.Add(xPackage);
3650 } 3085 }
3651 else 3086 else
3652 { 3087 {
3653 var patchInformation = new Wix.PatchInformation(); 3088 var xPatchInformation = new XElement(Names.PatchInformationElement);
3654 3089
3655 foreach (var row in table.Rows) 3090 foreach (var row in table.Rows)
3656 { 3091 {
3657 var propertyId = Convert.ToInt32(row[0]); 3092 var propertyId = row.FieldAsInteger(0);
3658 var value = Convert.ToString(row[1]); 3093 var value = row.FieldAsString(1);
3659 3094
3660 if (null != row[1] && 0 < value.Length) 3095 if (!String.IsNullOrEmpty(value))
3661 { 3096 {
3662 switch (propertyId) 3097 switch (propertyId)
3663 { 3098 {
3664 case 1: 3099 case 1:
3665 if ("1252" != value) 3100 if ("1252" != value)
3666 { 3101 {
3667 patchInformation.SummaryCodepage = value; 3102 xPatchInformation.SetAttributeValue("SummaryCodepage", value);
3668 } 3103 }
3669 break; 3104 break;
3670 case 3: 3105 case 3:
3671 patchInformation.Description = value; 3106 xPatchInformation.SetAttributeValue("Description", value);
3672 break;
3673 case 4:
3674 patchInformation.Manufacturer = value;
3675 break;
3676 case 5:
3677 if ("Installer,Patching,PCP,Database" != value)
3678 {
3679 patchInformation.Keywords = value;
3680 }
3681 break;
3682 case 6:
3683 patchInformation.Comments = value;
3684 break;
3685 case 7:
3686 var template = value.Split(';');
3687 if (0 < template.Length && 0 < template[template.Length - 1].Length)
3688 {
3689 patchInformation.Languages = template[template.Length - 1];
3690 }
3691
3692 if (1 < template.Length && null != template[0] && 0 < template[0].Length)
3693 {
3694 patchInformation.Platforms = template[0];
3695 }
3696 break;
3697 case 15:
3698 var wordCount = Convert.ToInt32(value, CultureInfo.InvariantCulture);
3699 if (0x1 == (wordCount & 0x1))
3700 {
3701 patchInformation.ShortNames = Wix.YesNoType.yes;
3702 }
3703
3704 if (0x2 == (wordCount & 0x2))
3705 {
3706 patchInformation.Compressed = Wix.YesNoType.yes;
3707 }
3708
3709 if (0x4 == (wordCount & 0x4))
3710 {
3711 patchInformation.AdminImage = Wix.YesNoType.yes;
3712 }
3713 break;
3714 case 19:
3715 var security = Convert.ToInt32(value, CultureInfo.InvariantCulture);
3716 switch (security)
3717 {
3718 case 0:
3719 patchInformation.ReadOnly = Wix.YesNoDefaultType.no;
3720 break; 3107 break;
3721 case 4: 3108 case 4:
3722 patchInformation.ReadOnly = Wix.YesNoDefaultType.yes; 3109 xPatchInformation.SetAttributeValue("Manufacturer", value);
3110 break;
3111 case 5:
3112 if ("Installer,Patching,PCP,Database" != value)
3113 {
3114 xPatchInformation.SetAttributeValue("Keywords", value);
3115 }
3116 break;
3117 case 6:
3118 xPatchInformation.SetAttributeValue("Comments", value);
3119 break;
3120 case 19:
3121 var security = Convert.ToInt32(value, CultureInfo.InvariantCulture);
3122 switch (security)
3123 {
3124 case 0:
3125 xPatchInformation.SetAttributeValue("ReadOnly", "no");
3126 break;
3127 case 4:
3128 xPatchInformation.SetAttributeValue("ReadOnly", "yes");
3129 break;
3130 }
3723 break; 3131 break;
3724 }
3725 break;
3726 } 3132 }
3727 } 3133 }
3728 } 3134 }
3729 3135
3730 this.core.RootElement.AddChild(patchInformation); 3136 this.RootElement.Add(xPatchInformation);
3731 } 3137 }
3732 } 3138 }
3733 3139
@@ -3739,21 +3145,12 @@ namespace WixToolset.Core.WindowsInstaller
3739 { 3145 {
3740 foreach (var row in table.Rows) 3146 foreach (var row in table.Rows)
3741 { 3147 {
3742 var progressText = new Wix.ProgressText(); 3148 var progressText = new XElement(Names.ProgressTextElement,
3743 3149 new XAttribute("Action", row.FieldAsString(0)),
3744 progressText.Action = Convert.ToString(row[0]); 3150 row.IsColumnNull(1) ? null : new XAttribute("Content", row.FieldAsString(1)),
3745 3151 row.IsColumnNull(2) ? null : new XAttribute("Template", row.FieldAsString(2)));
3746 if (null != row[1])
3747 {
3748 progressText.Content = Convert.ToString(row[1]);
3749 }
3750
3751 if (null != row[2])
3752 {
3753 progressText.Template = Convert.ToString(row[2]);
3754 }
3755 3152
3756 this.core.UIElement.AddChild(progressText); 3153 this.UIElement.Add(progressText);
3757 } 3154 }
3758 } 3155 }
3759 3156
@@ -3765,44 +3162,18 @@ namespace WixToolset.Core.WindowsInstaller
3765 { 3162 {
3766 foreach (var row in table.Rows) 3163 foreach (var row in table.Rows)
3767 { 3164 {
3768 var appId = new Wix.AppId(); 3165 var appId = new XElement(Names.AppIdElement,
3769 3166 new XAttribute("Advertise", "yes"),
3770 appId.Advertise = Wix.YesNoType.yes; 3167 new XAttribute("Id", row.FieldAsString(0)),
3771 3168 row.IsColumnNull(1) ? null : new XAttribute("RemoteServerName", row.FieldAsString(1)),
3772 appId.Id = Convert.ToString(row[0]); 3169 row.IsColumnNull(2) ? null : new XAttribute("LocalService", row.FieldAsString(2)),
3773 3170 row.IsColumnNull(3) ? null : new XAttribute("ServiceParameters", row.FieldAsString(3)),
3774 if (null != row[1]) 3171 row.IsColumnNull(4) ? null : new XAttribute("DllSurrogate", row.FieldAsString(4)),
3775 { 3172 row.IsColumnNull(5) || row.FieldAsInteger(5) != 1 ? null : new XAttribute("ActivateAtStorage", "yes"),
3776 appId.RemoteServerName = Convert.ToString(row[1]); 3173 row.IsColumnNull(6) || row.FieldAsInteger(6) != 1 ? null : new XAttribute("RunAsInteractiveUser", "yes"));
3777 }
3778
3779 if (null != row[2])
3780 {
3781 appId.LocalService = Convert.ToString(row[2]);
3782 }
3783 3174
3784 if (null != row[3]) 3175 this.RootElement.Add(appId);
3785 { 3176 this.IndexElement(row, appId);
3786 appId.ServiceParameters = Convert.ToString(row[3]);
3787 }
3788
3789 if (null != row[4])
3790 {
3791 appId.DllSurrogate = Convert.ToString(row[4]);
3792 }
3793
3794 if (null != row[5] && Int32.Equals(row[5], 1))
3795 {
3796 appId.ActivateAtStorage = Wix.YesNoType.yes;
3797 }
3798
3799 if (null != row[6] && Int32.Equals(row[6], 1))
3800 {
3801 appId.RunAsInteractiveUser = Wix.YesNoType.yes;
3802 }
3803
3804 this.core.RootElement.AddChild(appId);
3805 this.core.IndexElement(row, appId);
3806 } 3177 }
3807 } 3178 }
3808 3179
@@ -3814,34 +3185,23 @@ namespace WixToolset.Core.WindowsInstaller
3814 { 3185 {
3815 foreach (BBControlRow bbControlRow in table.Rows) 3186 foreach (BBControlRow bbControlRow in table.Rows)
3816 { 3187 {
3817 var control = new Wix.Control(); 3188 var xControl = new XElement(Names.ControlElement,
3818 3189 new XAttribute("Id", bbControlRow.BBControl),
3819 control.Id = bbControlRow.BBControl; 3190 new XAttribute("Type", bbControlRow.Type),
3820 3191 new XAttribute("X", bbControlRow.X),
3821 control.Type = bbControlRow.Type; 3192 new XAttribute("Y", bbControlRow.Y),
3822 3193 new XAttribute("Width", bbControlRow.Width),
3823 control.X = bbControlRow.X; 3194 new XAttribute("Height", bbControlRow.Height),
3824 3195 null == bbControlRow.Text ? null : new XAttribute("Text", bbControlRow.Text));
3825 control.Y = bbControlRow.Y;
3826
3827 control.Width = bbControlRow.Width;
3828
3829 control.Height = bbControlRow.Height;
3830 3196
3831 if (null != bbControlRow[7]) 3197 if (null != bbControlRow[7])
3832 { 3198 {
3833 SetControlAttributes(bbControlRow.Attributes, control); 3199 SetControlAttributes(bbControlRow.Attributes, xControl);
3834 }
3835
3836 if (null != bbControlRow.Text)
3837 {
3838 control.Text = bbControlRow.Text;
3839 } 3200 }
3840 3201
3841 var billboard = (Wix.Billboard)this.core.GetIndexedElement("Billboard", bbControlRow.Billboard); 3202 if (this.TryGetIndexedElement("Billboard", out var xBillboard, bbControlRow.Billboard))
3842 if (null != billboard)
3843 { 3203 {
3844 billboard.AddChild(control); 3204 xBillboard.Add(xControl);
3845 } 3205 }
3846 else 3206 else
3847 { 3207 {
@@ -3856,37 +3216,34 @@ namespace WixToolset.Core.WindowsInstaller
3856 /// <param name="table">The table to decompile.</param> 3216 /// <param name="table">The table to decompile.</param>
3857 private void DecompileBillboardTable(Table table) 3217 private void DecompileBillboardTable(Table table)
3858 { 3218 {
3859 var billboardActions = new Hashtable(); 3219 var billboards = new SortedList<string, Row>();
3860 var billboards = new SortedList();
3861 3220
3862 foreach (var row in table.Rows) 3221 foreach (var row in table.Rows)
3863 { 3222 {
3864 var billboard = new Wix.Billboard(); 3223 var xBillboard = new XElement(Names.BillboardElement,
3224 new XAttribute("Id", row.FieldAsString(0)),
3225 new XAttribute("Feature", row.FieldAsString(1)));
3865 3226
3866 billboard.Id = Convert.ToString(row[0]); 3227 this.IndexElement(row, xBillboard);
3867
3868 billboard.Feature = Convert.ToString(row[1]);
3869
3870 this.core.IndexElement(row, billboard);
3871 billboards.Add(String.Format(CultureInfo.InvariantCulture, "{0}|{1:0000000000}", row[0], row[3]), row); 3228 billboards.Add(String.Format(CultureInfo.InvariantCulture, "{0}|{1:0000000000}", row[0], row[3]), row);
3872 } 3229 }
3873 3230
3874 foreach (Row row in billboards.Values) 3231 var billboardActions = new Dictionary<string, XElement>();
3232
3233 foreach (var row in billboards.Values)
3875 { 3234 {
3876 var billboard = (Wix.Billboard)this.core.GetIndexedElement(row); 3235 var xBillboard = this.GetIndexedElement(row);
3877 var billboardAction = (Wix.BillboardAction)billboardActions[row[2]];
3878 3236
3879 if (null == billboardAction) 3237 if (!billboardActions.TryGetValue(row.FieldAsString(2), out var xBillboardAction))
3880 { 3238 {
3881 billboardAction = new Wix.BillboardAction(); 3239 xBillboardAction = new XElement(Names.BillboardActionElement,
3240 new XAttribute("Id", row.FieldAsString(2)));
3882 3241
3883 billboardAction.Id = Convert.ToString(row[2]); 3242 this.UIElement.Add(xBillboardAction);
3884 3243 billboardActions.Add(row.FieldAsString(2), xBillboardAction);
3885 this.core.UIElement.AddChild(billboardAction);
3886 billboardActions.Add(row[2], billboardAction);
3887 } 3244 }
3888 3245
3889 billboardAction.AddChild(billboard); 3246 xBillboardAction.Add(xBillboard);
3890 } 3247 }
3891 } 3248 }
3892 3249
@@ -3898,13 +3255,11 @@ namespace WixToolset.Core.WindowsInstaller
3898 { 3255 {
3899 foreach (var row in table.Rows) 3256 foreach (var row in table.Rows)
3900 { 3257 {
3901 var binary = new Wix.Binary(); 3258 var xBinary = new XElement(Names.BinaryElement,
3902 3259 new XAttribute("Id", row.FieldAsString(0)),
3903 binary.Id = Convert.ToString(row[0]); 3260 new XAttribute("SourceFile", row.FieldAsString(1)));
3904 3261
3905 binary.SourceFile = Convert.ToString(row[1]); 3262 this.RootElement.Add(xBinary);
3906
3907 this.core.RootElement.AddChild(binary);
3908 } 3263 }
3909 } 3264 }
3910 3265
@@ -3916,15 +3271,13 @@ namespace WixToolset.Core.WindowsInstaller
3916 { 3271 {
3917 foreach (var row in table.Rows) 3272 foreach (var row in table.Rows)
3918 { 3273 {
3919 var file = (Wix.File)this.core.GetIndexedElement("File", Convert.ToString(row[0])); 3274 if (this.TryGetIndexedElement("File", out var xFile, row.FieldAsString(0)))
3920
3921 if (null != file)
3922 { 3275 {
3923 file.BindPath = Convert.ToString(row[1]); 3276 xFile.SetAttributeValue("BindPath", row.FieldAsString(1));
3924 } 3277 }
3925 else 3278 else
3926 { 3279 {
3927 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "File_", Convert.ToString(row[0]), "File")); 3280 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "File_", row.FieldAsString(0), "File"));
3928 } 3281 }
3929 } 3282 }
3930 } 3283 }
@@ -3937,46 +3290,20 @@ namespace WixToolset.Core.WindowsInstaller
3937 { 3290 {
3938 foreach (var row in table.Rows) 3291 foreach (var row in table.Rows)
3939 { 3292 {
3940 var wixClass = new Wix.Class(); 3293 var xClass = new XElement(Names.ClassElement,
3941 3294 new XAttribute("Id", row.FieldAsString(0)),
3942 wixClass.Advertise = Wix.YesNoType.yes; 3295 new XAttribute("Advertise", "yes"),
3943 3296 new XAttribute("Context", row.FieldAsString(1)),
3944 wixClass.Id = Convert.ToString(row[0]); 3297 row.IsColumnNull(4) ? null : new XAttribute("Description", row.FieldAsString(4)),
3945 3298 row.IsColumnNull(5) ? null : new XAttribute("AppId", row.FieldAsString(5)),
3946 switch (Convert.ToString(row[1])) 3299 row.IsColumnNull(7) ? null : new XAttribute("Icon", row.FieldAsString(7)),
3947 { 3300 row.IsColumnNull(8) ? null : new XAttribute("IconIndex", row.FieldAsString(8)),
3948 case "LocalServer": 3301 row.IsColumnNull(9) ? null : new XAttribute("Handler", row.FieldAsString(9)),
3949 wixClass.Context = Wix.Class.ContextType.LocalServer; 3302 row.IsColumnNull(10) ? null : new XAttribute("Argument", row.FieldAsString(10)));
3950 break;
3951 case "LocalServer32":
3952 wixClass.Context = Wix.Class.ContextType.LocalServer32;
3953 break;
3954 case "InprocServer":
3955 wixClass.Context = Wix.Class.ContextType.InprocServer;
3956 break;
3957 case "InprocServer32":
3958 wixClass.Context = Wix.Class.ContextType.InprocServer32;
3959 break;
3960 default:
3961 this.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[1].Column.Name, row[1]));
3962 break;
3963 }
3964 3303
3965 // ProgId children are handled in FinalizeProgIdTable 3304 if (!row.IsColumnNull(6))
3966
3967 if (null != row[4])
3968 { 3305 {
3969 wixClass.Description = Convert.ToString(row[4]); 3306 var fileTypeMaskStrings = row.FieldAsString(6).Split(';');
3970 }
3971
3972 if (null != row[5])
3973 {
3974 wixClass.AppId = Convert.ToString(row[5]);
3975 }
3976
3977 if (null != row[6])
3978 {
3979 var fileTypeMaskStrings = (Convert.ToString(row[6])).Split(';');
3980 3307
3981 try 3308 try
3982 { 3309 {
@@ -3986,15 +3313,12 @@ namespace WixToolset.Core.WindowsInstaller
3986 3313
3987 if (4 == fileTypeMaskParts.Length) 3314 if (4 == fileTypeMaskParts.Length)
3988 { 3315 {
3989 var fileTypeMask = new Wix.FileTypeMask(); 3316 var xFileTypeMask = new XElement(Names.FileTypeMaskElement,
3990 3317 new XAttribute("Offset", Convert.ToInt32(fileTypeMaskParts[0], CultureInfo.InvariantCulture)),
3991 fileTypeMask.Offset = Convert.ToInt32(fileTypeMaskParts[0], CultureInfo.InvariantCulture); 3318 new XAttribute("Mask", fileTypeMaskParts[2]),
3319 new XAttribute("Value", fileTypeMaskParts[3]));
3992 3320
3993 fileTypeMask.Mask = fileTypeMaskParts[2]; 3321 xClass.Add(xFileTypeMask);
3994
3995 fileTypeMask.Value = fileTypeMaskParts[3];
3996
3997 wixClass.AddChild(fileTypeMask);
3998 } 3322 }
3999 else 3323 else
4000 { 3324 {
@@ -4012,31 +3336,11 @@ namespace WixToolset.Core.WindowsInstaller
4012 } 3336 }
4013 } 3337 }
4014 3338
4015 if (null != row[7]) 3339 if (!row.IsColumnNull(12))
4016 {
4017 wixClass.Icon = Convert.ToString(row[7]);
4018 }
4019
4020 if (null != row[8])
4021 { 3340 {
4022 wixClass.IconIndex = Convert.ToInt32(row[8]); 3341 if (1 == row.FieldAsInteger(12))
4023 }
4024
4025 if (null != row[9])
4026 {
4027 wixClass.Handler = Convert.ToString(row[9]);
4028 }
4029
4030 if (null != row[10])
4031 {
4032 wixClass.Argument = Convert.ToString(row[10]);
4033 }
4034
4035 if (null != row[12])
4036 {
4037 if (1 == Convert.ToInt32(row[12]))
4038 { 3342 {
4039 wixClass.RelativePath = Wix.YesNoType.yes; 3343 xClass.SetAttributeValue("RelativePath", "yes");
4040 } 3344 }
4041 else 3345 else
4042 { 3346 {
@@ -4044,17 +3348,8 @@ namespace WixToolset.Core.WindowsInstaller
4044 } 3348 }
4045 } 3349 }
4046 3350
4047 var component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[2])); 3351 this.AddChildToParent("Component", xClass, row, 2);
4048 if (null != component) 3352 this.IndexElement(row, xClass);
4049 {
4050 component.AddChild(wixClass);
4051 }
4052 else
4053 {
4054 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[2]), "Component"));
4055 }
4056
4057 this.core.IndexElement(row, wixClass);
4058 } 3353 }
4059 } 3354 }
4060 3355
@@ -4064,36 +3359,27 @@ namespace WixToolset.Core.WindowsInstaller
4064 /// <param name="table">The table to decompile.</param> 3359 /// <param name="table">The table to decompile.</param>
4065 private void DecompileComboBoxTable(Table table) 3360 private void DecompileComboBoxTable(Table table)
4066 { 3361 {
4067 Wix.ComboBox comboBox = null;
4068 var comboBoxRows = new SortedList();
4069
4070 // sort the combo boxes by their property and order 3362 // sort the combo boxes by their property and order
4071 foreach (var row in table.Rows) 3363 var comboBoxRows = table.Rows.Select(row => row).OrderBy(row => String.Format("{0}|{1:0000000000}", row.FieldAsString(0), row.FieldAsInteger(1)));
4072 {
4073 comboBoxRows.Add(String.Concat("{0}|{1:0000000000}", row[0], row[1]), row);
4074 }
4075 3364
4076 foreach (Row row in comboBoxRows.Values) 3365 XElement xComboBox = null;
3366 string property = null;
3367 foreach (var row in comboBoxRows)
4077 { 3368 {
4078 if (null == comboBox || Convert.ToString(row[0]) != comboBox.Property) 3369 if (null == xComboBox || row.FieldAsString(0) != property)
4079 { 3370 {
4080 comboBox = new Wix.ComboBox(); 3371 property = row.FieldAsString(0);
4081
4082 comboBox.Property = Convert.ToString(row[0]);
4083 3372
4084 this.core.UIElement.AddChild(comboBox); 3373 xComboBox = new XElement(Names.ComboBoxElement,
4085 } 3374 new XAttribute("Property", property));
4086
4087 var listItem = new Wix.ListItem();
4088
4089 listItem.Value = Convert.ToString(row[2]);
4090 3375
4091 if (null != row[3]) 3376 this.UIElement.Add(xComboBox);
4092 {
4093 listItem.Text = Convert.ToString(row[3]);
4094 } 3377 }
4095 3378
4096 comboBox.AddChild(listItem); 3379 var xListItem = new XElement(Names.ListItemElement,
3380 new XAttribute("Value", row.FieldAsString(2)),
3381 row.IsColumnNull(3) ? null : new XAttribute("Text", row.FieldAsString(3)));
3382 xComboBox.Add(xListItem);
4097 } 3383 }
4098 } 3384 }
4099 3385
@@ -4105,80 +3391,75 @@ namespace WixToolset.Core.WindowsInstaller
4105 { 3391 {
4106 foreach (ControlRow controlRow in table.Rows) 3392 foreach (ControlRow controlRow in table.Rows)
4107 { 3393 {
4108 var control = new Wix.Control(); 3394 var xControl = new XElement(Names.ControlElement,
4109 3395 new XAttribute("Id", controlRow.Control),
4110 control.Id = controlRow.Control; 3396 new XAttribute("Type", controlRow.Type),
4111 3397 new XAttribute("X", controlRow.X),
4112 control.Type = controlRow.Type; 3398 new XAttribute("Y", controlRow.Y),
4113 3399 new XAttribute("Width", controlRow.Width),
4114 control.X = controlRow.X; 3400 new XAttribute("Height", controlRow.Height),
4115 3401 new XAttribute("Text", controlRow.Text));
4116 control.Y = controlRow.Y;
4117
4118 control.Width = controlRow.Width;
4119
4120 control.Height = controlRow.Height;
4121 3402
4122 if (null != controlRow[7]) 3403 if (!controlRow.IsColumnNull(7))
4123 { 3404 {
4124 string[] specialAttributes; 3405 string[] specialAttributes;
4125 3406
4126 // sets various common attributes like Disabled, Indirect, Integer, ... 3407 // sets various common attributes like Disabled, Indirect, Integer, ...
4127 SetControlAttributes(controlRow.Attributes, control); 3408 SetControlAttributes(controlRow.Attributes, xControl);
4128 3409
4129 switch (control.Type) 3410 switch (controlRow.Type)
4130 { 3411 {
4131 case "Bitmap": 3412 case "Bitmap":
4132 specialAttributes = BitmapControlAttributes; 3413 specialAttributes = BitmapControlAttributes;
4133 break; 3414 break;
4134 case "CheckBox": 3415 case "CheckBox":
4135 specialAttributes = CheckboxControlAttributes; 3416 specialAttributes = CheckboxControlAttributes;
4136 break; 3417 break;
4137 case "ComboBox": 3418 case "ComboBox":
4138 specialAttributes = ComboboxControlAttributes; 3419 specialAttributes = ComboboxControlAttributes;
4139 break; 3420 break;
4140 case "DirectoryCombo": 3421 case "DirectoryCombo":
4141 specialAttributes = VolumeControlAttributes; 3422 specialAttributes = VolumeControlAttributes;
4142 break; 3423 break;
4143 case "Edit": 3424 case "Edit":
4144 specialAttributes = EditControlAttributes; 3425 specialAttributes = EditControlAttributes;
4145 break; 3426 break;
4146 case "Icon": 3427 case "Icon":
4147 specialAttributes = IconControlAttributes; 3428 specialAttributes = IconControlAttributes;
4148 break; 3429 break;
4149 case "ListBox": 3430 case "ListBox":
4150 specialAttributes = ListboxControlAttributes; 3431 specialAttributes = ListboxControlAttributes;
4151 break; 3432 break;
4152 case "ListView": 3433 case "ListView":
4153 specialAttributes = ListviewControlAttributes; 3434 specialAttributes = ListviewControlAttributes;
4154 break; 3435 break;
4155 case "MaskedEdit": 3436 case "MaskedEdit":
4156 specialAttributes = EditControlAttributes; 3437 specialAttributes = EditControlAttributes;
4157 break; 3438 break;
4158 case "PathEdit": 3439 case "PathEdit":
4159 specialAttributes = EditControlAttributes; 3440 specialAttributes = EditControlAttributes;
4160 break; 3441 break;
4161 case "ProgressBar": 3442 case "ProgressBar":
4162 specialAttributes = ProgressControlAttributes; 3443 specialAttributes = ProgressControlAttributes;
4163 break; 3444 break;
4164 case "PushButton": 3445 case "PushButton":
4165 specialAttributes = ButtonControlAttributes; 3446 specialAttributes = ButtonControlAttributes;
4166 break; 3447 break;
4167 case "RadioButtonGroup": 3448 case "RadioButtonGroup":
4168 specialAttributes = RadioControlAttributes; 3449 specialAttributes = RadioControlAttributes;
4169 break; 3450 break;
4170 case "Text": 3451 case "Text":
4171 specialAttributes = TextControlAttributes; 3452 specialAttributes = TextControlAttributes;
4172 break; 3453 break;
4173 case "VolumeCostList": 3454 case "VolumeCostList":
4174 specialAttributes = VolumeControlAttributes; 3455 specialAttributes = VolumeControlAttributes;
4175 break; 3456 break;
4176 case "VolumeSelectCombo": 3457 case "VolumeSelectCombo":
4177 specialAttributes = VolumeControlAttributes; 3458 specialAttributes = VolumeControlAttributes;
4178 break; 3459 break;
4179 default: 3460 default:
4180 specialAttributes = null; 3461 specialAttributes = null;
4181 break; 3462 break;
4182 } 3463 }
4183 3464
4184 if (null != specialAttributes) 3465 if (null != specialAttributes)
@@ -4205,102 +3486,102 @@ namespace WixToolset.Core.WindowsInstaller
4205 3486
4206 switch (attribute) 3487 switch (attribute)
4207 { 3488 {
4208 case "Bitmap": 3489 case "Bitmap":
4209 control.Bitmap = Wix.YesNoType.yes; 3490 xControl.SetAttributeValue("Bitmap", "yes");
4210 break; 3491 break;
4211 case "CDROM": 3492 case "CDROM":
4212 control.CDROM = Wix.YesNoType.yes; 3493 xControl.SetAttributeValue("CDROM", "yes");
4213 break; 3494 break;
4214 case "ComboList": 3495 case "ComboList":
4215 control.ComboList = Wix.YesNoType.yes; 3496 xControl.SetAttributeValue("ComboList", "yes");
4216 break; 3497 break;
4217 case "ElevationShield": 3498 case "ElevationShield":
4218 control.ElevationShield = Wix.YesNoType.yes; 3499 xControl.SetAttributeValue("ElevationShield", "yes");
4219 break; 3500 break;
4220 case "Fixed": 3501 case "Fixed":
4221 control.Fixed = Wix.YesNoType.yes; 3502 xControl.SetAttributeValue("Fixed", "yes");
4222 break; 3503 break;
4223 case "FixedSize": 3504 case "FixedSize":
4224 control.FixedSize = Wix.YesNoType.yes; 3505 xControl.SetAttributeValue("FixedSize", "yes");
4225 break; 3506 break;
4226 case "Floppy": 3507 case "Floppy":
4227 control.Floppy = Wix.YesNoType.yes; 3508 xControl.SetAttributeValue("Floppy", "yes");
4228 break; 3509 break;
4229 case "FormatSize": 3510 case "FormatSize":
4230 control.FormatSize = Wix.YesNoType.yes; 3511 xControl.SetAttributeValue("FormatSize", "yes");
4231 break; 3512 break;
4232 case "HasBorder": 3513 case "HasBorder":
4233 control.HasBorder = Wix.YesNoType.yes; 3514 xControl.SetAttributeValue("HasBorder", "yes");
4234 break; 3515 break;
4235 case "Icon": 3516 case "Icon":
4236 control.Icon = Wix.YesNoType.yes; 3517 xControl.SetAttributeValue("Icon", "yes");
4237 break; 3518 break;
4238 case "Icon16": 3519 case "Icon16":
4239 if (iconSizeSet) 3520 if (iconSizeSet)
4240 { 3521 {
4241 control.IconSize = Wix.Control.IconSizeType.Item48; 3522 xControl.SetAttributeValue("IconSize", "48");
4242 } 3523 }
4243 else 3524 else
4244 { 3525 {
4245 iconSizeSet = true; 3526 iconSizeSet = true;
4246 control.IconSize = Wix.Control.IconSizeType.Item16; 3527 xControl.SetAttributeValue("IconSize", "16");
4247 } 3528 }
4248 break; 3529 break;
4249 case "Icon32": 3530 case "Icon32":
4250 if (iconSizeSet) 3531 if (iconSizeSet)
4251 { 3532 {
4252 control.IconSize = Wix.Control.IconSizeType.Item48; 3533 xControl.SetAttributeValue("IconSize", "48");
4253 } 3534 }
4254 else 3535 else
4255 { 3536 {
4256 iconSizeSet = true; 3537 iconSizeSet = true;
4257 control.IconSize = Wix.Control.IconSizeType.Item32; 3538 xControl.SetAttributeValue("IconSize", "32");
4258 } 3539 }
4259 break; 3540 break;
4260 case "Image": 3541 case "Image":
4261 control.Image = Wix.YesNoType.yes; 3542 xControl.SetAttributeValue("Image", "yes");
4262 break; 3543 break;
4263 case "Multiline": 3544 case "Multiline":
4264 control.Multiline = Wix.YesNoType.yes; 3545 xControl.SetAttributeValue("Multiline", "yes");
4265 break; 3546 break;
4266 case "NoPrefix": 3547 case "NoPrefix":
4267 control.NoPrefix = Wix.YesNoType.yes; 3548 xControl.SetAttributeValue("NoPrefix", "yes");
4268 break; 3549 break;
4269 case "NoWrap": 3550 case "NoWrap":
4270 control.NoWrap = Wix.YesNoType.yes; 3551 xControl.SetAttributeValue("NoWrap", "yes");
4271 break; 3552 break;
4272 case "Password": 3553 case "Password":
4273 control.Password = Wix.YesNoType.yes; 3554 xControl.SetAttributeValue("Password", "yes");
4274 break; 3555 break;
4275 case "ProgressBlocks": 3556 case "ProgressBlocks":
4276 control.ProgressBlocks = Wix.YesNoType.yes; 3557 xControl.SetAttributeValue("ProgressBlocks", "yes");
4277 break; 3558 break;
4278 case "PushLike": 3559 case "PushLike":
4279 control.PushLike = Wix.YesNoType.yes; 3560 xControl.SetAttributeValue("PushLike", "yes");
4280 break; 3561 break;
4281 case "RAMDisk": 3562 case "RAMDisk":
4282 control.RAMDisk = Wix.YesNoType.yes; 3563 xControl.SetAttributeValue("RAMDisk", "yes");
4283 break; 3564 break;
4284 case "Remote": 3565 case "Remote":
4285 control.Remote = Wix.YesNoType.yes; 3566 xControl.SetAttributeValue("Remote", "yes");
4286 break; 3567 break;
4287 case "Removable": 3568 case "Removable":
4288 control.Removable = Wix.YesNoType.yes; 3569 xControl.SetAttributeValue("Removable", "yes");
4289 break; 3570 break;
4290 case "ShowRollbackCost": 3571 case "ShowRollbackCost":
4291 control.ShowRollbackCost = Wix.YesNoType.yes; 3572 xControl.SetAttributeValue("ShowRollbackCost", "yes");
4292 break; 3573 break;
4293 case "Sorted": 3574 case "Sorted":
4294 control.Sorted = Wix.YesNoType.yes; 3575 xControl.SetAttributeValue("Sorted", "yes");
4295 break; 3576 break;
4296 case "Transparent": 3577 case "Transparent":
4297 control.Transparent = Wix.YesNoType.yes; 3578 xControl.SetAttributeValue("Transparent", "yes");
4298 break; 3579 break;
4299 case "UserLanguage": 3580 case "UserLanguage":
4300 control.UserLanguage = Wix.YesNoType.yes; 3581 xControl.SetAttributeValue("UserLanguage", "yes");
4301 break; 3582 break;
4302 default: 3583 default:
4303 throw new InvalidOperationException($"Unknown control attribute: '{attribute}'."); 3584 throw new InvalidOperationException($"Unknown control attribute: '{attribute}'.");
4304 } 3585 }
4305 } 3586 }
4306 } 3587 }
@@ -4312,14 +3593,9 @@ namespace WixToolset.Core.WindowsInstaller
4312 } 3593 }
4313 3594
4314 // FinalizeCheckBoxTable adds Control/@Property|@CheckBoxPropertyRef 3595 // FinalizeCheckBoxTable adds Control/@Property|@CheckBoxPropertyRef
4315 if (null != controlRow.Property && 0 != String.CompareOrdinal("CheckBox", control.Type)) 3596 if (null != controlRow.Property && 0 != String.CompareOrdinal("CheckBox", controlRow.Type))
4316 {
4317 control.Property = controlRow.Property;
4318 }
4319
4320 if (null != controlRow.Text)
4321 { 3597 {
4322 control.Text = controlRow.Text; 3598 xControl.SetAttributeValue("Property", controlRow.Property);
4323 } 3599 }
4324 3600
4325 if (null != controlRow.Help) 3601 if (null != controlRow.Help)
@@ -4330,17 +3606,17 @@ namespace WixToolset.Core.WindowsInstaller
4330 { 3606 {
4331 if (0 < help[0].Length) 3607 if (0 < help[0].Length)
4332 { 3608 {
4333 control.ToolTip = help[0]; 3609 xControl.SetAttributeValue("ToolTip", help[0]);
4334 } 3610 }
4335 3611
4336 if (0 < help[1].Length) 3612 if (0 < help[1].Length)
4337 { 3613 {
4338 control.Help = help[1]; 3614 xControl.SetAttributeValue("Help", help[1]);
4339 } 3615 }
4340 } 3616 }
4341 } 3617 }
4342 3618
4343 this.core.IndexElement(controlRow, control); 3619 this.IndexElement(controlRow, xControl);
4344 } 3620 }
4345 } 3621 }
4346 3622
@@ -4352,40 +3628,33 @@ namespace WixToolset.Core.WindowsInstaller
4352 { 3628 {
4353 foreach (var row in table.Rows) 3629 foreach (var row in table.Rows)
4354 { 3630 {
4355 var condition = new Wix.Condition(); 3631 if (this.TryGetIndexedElement("Control", out var xControl, row.FieldAsString(0), row.FieldAsString(1)))
4356
4357 switch (Convert.ToString(row[2]))
4358 { 3632 {
4359 case "Default": 3633 switch (row.FieldAsString(2))
4360 condition.Action = Wix.Condition.ActionType.@default; 3634 {
4361 break; 3635 case "Default":
4362 case "Disable": 3636 xControl.SetAttributeValue("DefaultCondition", row.FieldAsString(3));
4363 condition.Action = Wix.Condition.ActionType.disable; 3637 break;
4364 break; 3638 case "Disable":
4365 case "Enable": 3639 xControl.SetAttributeValue("DisableCondition", row.FieldAsString(3));
4366 condition.Action = Wix.Condition.ActionType.enable; 3640 break;
4367 break; 3641 case "Enable":
4368 case "Hide": 3642 xControl.SetAttributeValue("EnableCondition", row.FieldAsString(3));
4369 condition.Action = Wix.Condition.ActionType.hide; 3643 break;
4370 break; 3644 case "Hide":
4371 case "Show": 3645 xControl.SetAttributeValue("HideCondition", row.FieldAsString(3));
4372 condition.Action = Wix.Condition.ActionType.show; 3646 break;
4373 break; 3647 case "Show":
4374 default: 3648 xControl.SetAttributeValue("ShowCondition", row.FieldAsString(3));
4375 this.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[2].Column.Name, row[2])); 3649 break;
4376 break; 3650 default:
4377 } 3651 this.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[2].Column.Name, row[2]));
4378 3652 break;
4379 condition.Content = Convert.ToString(row[3]); 3653 }
4380
4381 var control = (Wix.Control)this.core.GetIndexedElement("Control", Convert.ToString(row[0]), Convert.ToString(row[1]));
4382 if (null != control)
4383 {
4384 control.AddChild(condition);
4385 } 3654 }
4386 else 3655 else
4387 { 3656 {
4388 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Dialog_", Convert.ToString(row[0]), "Control_", Convert.ToString(row[1]), "Control")); 3657 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Dialog_", row.FieldAsString(0), "Control_", row.FieldAsString(1), "Control"));
4389 } 3658 }
4390 } 3659 }
4391 } 3660 }
@@ -4396,50 +3665,44 @@ namespace WixToolset.Core.WindowsInstaller
4396 /// <param name="table">The table to decompile.</param> 3665 /// <param name="table">The table to decompile.</param>
4397 private void DecompileControlEventTable(Table table) 3666 private void DecompileControlEventTable(Table table)
4398 { 3667 {
4399 var controlEvents = new SortedList(); 3668 var controlEvents = new SortedList<string, Row>();
4400 3669
4401 foreach (var row in table.Rows) 3670 foreach (var row in table.Rows)
4402 { 3671 {
4403 var publish = new Wix.Publish(); 3672 var xPublish = new XElement(Names.PublishElement,
3673 new XAttribute("Condition", row.FieldAsString(4)));
4404 3674
4405 var publishEvent = Convert.ToString(row[2]); 3675 var publishEvent = row.FieldAsString(2);
4406 if (publishEvent.StartsWith("[", StringComparison.Ordinal) && publishEvent.EndsWith("]", StringComparison.Ordinal)) 3676 if (publishEvent.StartsWith("[", StringComparison.Ordinal) && publishEvent.EndsWith("]", StringComparison.Ordinal))
4407 { 3677 {
4408 publish.Property = publishEvent.Substring(1, publishEvent.Length - 2); 3678 xPublish.SetAttributeValue("Property", publishEvent.Substring(1, publishEvent.Length - 2));
4409 3679
4410 if ("{}" != Convert.ToString(row[3])) 3680 if ("{}" != row.FieldAsString(3))
4411 { 3681 {
4412 publish.Value = Convert.ToString(row[3]); 3682 xPublish.SetAttributeValue("Value", row.FieldAsString(3));
4413 } 3683 }
4414 } 3684 }
4415 else 3685 else
4416 { 3686 {
4417 publish.Event = publishEvent; 3687 xPublish.SetAttributeValue("Event", publishEvent);
4418 publish.Value = Convert.ToString(row[3]); 3688 xPublish.SetAttributeValue("Value", row.FieldAsString(3));
4419 } 3689 }
4420 3690
4421 if (null != row[4]) 3691 controlEvents.Add(String.Format(CultureInfo.InvariantCulture, "{0}|{1}|{2:0000000000}|{3}|{4}|{5}", row.FieldAsString(0), row.FieldAsString(1), row.FieldAsNullableInteger(5) ?? 0, row.FieldAsString(2), row.FieldAsString(3), row.FieldAsString(4)), row);
4422 {
4423 publish.Content = Convert.ToString(row[4]);
4424 }
4425
4426 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);
4427 3692
4428 this.core.IndexElement(row, publish); 3693 this.IndexElement(row, xPublish);
4429 } 3694 }
4430 3695
4431 foreach (Row row in controlEvents.Values) 3696 foreach (var row in controlEvents.Values)
4432 { 3697 {
4433 var control = (Wix.Control)this.core.GetIndexedElement("Control", Convert.ToString(row[0]), Convert.ToString(row[1])); 3698 if (this.TryGetIndexedElement("Control", out var xControl, row.FieldAsString(0), row.FieldAsString(1)))
4434 var publish = (Wix.Publish)this.core.GetIndexedElement(row);
4435
4436 if (null != control)
4437 { 3699 {
4438 control.AddChild(publish); 3700 var xPublish = this.GetIndexedElement(row);
3701 xControl.Add(xPublish);
4439 } 3702 }
4440 else 3703 else
4441 { 3704 {
4442 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Dialog_", Convert.ToString(row[0]), "Control_", Convert.ToString(row[1]), "Control")); 3705 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Dialog_", row.FieldAsString(0), "Control_", row.FieldAsString(1), "Control"));
4443 } 3706 }
4444 } 3707 }
4445 } 3708 }
@@ -4452,221 +3715,180 @@ namespace WixToolset.Core.WindowsInstaller
4452 { 3715 {
4453 if (0 < table.Rows.Count || this.SuppressDroppingEmptyTables) 3716 if (0 < table.Rows.Count || this.SuppressDroppingEmptyTables)
4454 { 3717 {
4455 var customTable = new Wix.CustomTable();
4456
4457 this.Messaging.Write(WarningMessages.DecompilingAsCustomTable(table.Rows[0].SourceLineNumbers, table.Name)); 3718 this.Messaging.Write(WarningMessages.DecompilingAsCustomTable(table.Rows[0].SourceLineNumbers, table.Name));
4458 3719
4459 customTable.Id = table.Name; 3720 var xCustomTable = new XElement(Names.CustomTableElement,
3721 new XAttribute("Id", table.Name));
4460 3722
4461 foreach (var columnDefinition in table.Definition.Columns) 3723 foreach (var columnDefinition in table.Definition.Columns)
4462 { 3724 {
4463 var column = new Wix.Column(); 3725 var xColumn = new XElement(Names.ColumnElement,
4464 3726 new XAttribute("Id", columnDefinition.Name),
4465 column.Id = columnDefinition.Name; 3727 columnDefinition.Description == null ? null : new XAttribute("Description", columnDefinition.Description),
3728 columnDefinition.KeyTable == null ? null : new XAttribute("KeyTable", columnDefinition.KeyTable),
3729 !columnDefinition.KeyColumn.HasValue ? null : new XAttribute("KeyColumn", columnDefinition.KeyColumn.Value),
3730 !columnDefinition.IsLocalizable ? null : new XAttribute("Localizable", "yes"),
3731 !columnDefinition.MaxValue.HasValue ? null : new XAttribute("MaxValue", columnDefinition.MaxValue.Value),
3732 !columnDefinition.MinValue.HasValue ? null : new XAttribute("MinValue", columnDefinition.MinValue.Value),
3733 !columnDefinition.Nullable ? null : new XAttribute("Nullable", "yes"),
3734 !columnDefinition.PrimaryKey ? null : new XAttribute("PrimaryKey", "yes"),
3735 columnDefinition.Possibilities == null ? null : new XAttribute("Possibilities", "yes"),
3736 new XAttribute("Width", columnDefinition.Length));
4466 3737
4467 if (ColumnCategory.Unknown != columnDefinition.Category) 3738 if (ColumnCategory.Unknown != columnDefinition.Category)
4468 { 3739 {
4469 switch (columnDefinition.Category) 3740 switch (columnDefinition.Category)
4470 { 3741 {
4471 case ColumnCategory.Text: 3742 case ColumnCategory.Text:
4472 column.Category = Wix.Column.CategoryType.text; 3743 xColumn.SetAttributeValue("Category", "text");
4473 break; 3744 break;
4474 case ColumnCategory.UpperCase: 3745 case ColumnCategory.UpperCase:
4475 column.Category = Wix.Column.CategoryType.upperCase; 3746 xColumn.SetAttributeValue("Category", "upperCase");
4476 break; 3747 break;
4477 case ColumnCategory.LowerCase: 3748 case ColumnCategory.LowerCase:
4478 column.Category = Wix.Column.CategoryType.lowerCase; 3749 xColumn.SetAttributeValue("Category", "lowerCase");
4479 break; 3750 break;
4480 case ColumnCategory.Integer: 3751 case ColumnCategory.Integer:
4481 column.Category = Wix.Column.CategoryType.integer; 3752 xColumn.SetAttributeValue("Category", "integer");
4482 break; 3753 break;
4483 case ColumnCategory.DoubleInteger: 3754 case ColumnCategory.DoubleInteger:
4484 column.Category = Wix.Column.CategoryType.doubleInteger; 3755 xColumn.SetAttributeValue("Category", "doubleInteger");
4485 break; 3756 break;
4486 case ColumnCategory.TimeDate: 3757 case ColumnCategory.TimeDate:
4487 column.Category = Wix.Column.CategoryType.timeDate; 3758 xColumn.SetAttributeValue("Category", "timeDate");
4488 break; 3759 break;
4489 case ColumnCategory.Identifier: 3760 case ColumnCategory.Identifier:
4490 column.Category = Wix.Column.CategoryType.identifier; 3761 xColumn.SetAttributeValue("Category", "identifier");
4491 break; 3762 break;
4492 case ColumnCategory.Property: 3763 case ColumnCategory.Property:
4493 column.Category = Wix.Column.CategoryType.property; 3764 xColumn.SetAttributeValue("Category", "property");
4494 break; 3765 break;
4495 case ColumnCategory.Filename: 3766 case ColumnCategory.Filename:
4496 column.Category = Wix.Column.CategoryType.filename; 3767 xColumn.SetAttributeValue("Category", "filename");
4497 break; 3768 break;
4498 case ColumnCategory.WildCardFilename: 3769 case ColumnCategory.WildCardFilename:
4499 column.Category = Wix.Column.CategoryType.wildCardFilename; 3770 xColumn.SetAttributeValue("Category", "wildCardFilename");
4500 break; 3771 break;
4501 case ColumnCategory.Path: 3772 case ColumnCategory.Path:
4502 column.Category = Wix.Column.CategoryType.path; 3773 xColumn.SetAttributeValue("Category", "path");
4503 break; 3774 break;
4504 case ColumnCategory.Paths: 3775 case ColumnCategory.Paths:
4505 column.Category = Wix.Column.CategoryType.paths; 3776 xColumn.SetAttributeValue("Category", "paths");
4506 break; 3777 break;
4507 case ColumnCategory.AnyPath: 3778 case ColumnCategory.AnyPath:
4508 column.Category = Wix.Column.CategoryType.anyPath; 3779 xColumn.SetAttributeValue("Category", "anyPath");
4509 break; 3780 break;
4510 case ColumnCategory.DefaultDir: 3781 case ColumnCategory.DefaultDir:
4511 column.Category = Wix.Column.CategoryType.defaultDir; 3782 xColumn.SetAttributeValue("Category", "defaultDir");
4512 break; 3783 break;
4513 case ColumnCategory.RegPath: 3784 case ColumnCategory.RegPath:
4514 column.Category = Wix.Column.CategoryType.regPath; 3785 xColumn.SetAttributeValue("Category", "regPath");
4515 break; 3786 break;
4516 case ColumnCategory.Formatted: 3787 case ColumnCategory.Formatted:
4517 column.Category = Wix.Column.CategoryType.formatted; 3788 xColumn.SetAttributeValue("Category", "formatted");
4518 break; 3789 break;
4519 case ColumnCategory.FormattedSDDLText: 3790 case ColumnCategory.FormattedSDDLText:
4520 column.Category = Wix.Column.CategoryType.formattedSddl; 3791 xColumn.SetAttributeValue("Category", "formattedSddl");
4521 break; 3792 break;
4522 case ColumnCategory.Template: 3793 case ColumnCategory.Template:
4523 column.Category = Wix.Column.CategoryType.template; 3794 xColumn.SetAttributeValue("Category", "template");
4524 break; 3795 break;
4525 case ColumnCategory.Condition: 3796 case ColumnCategory.Condition:
4526 column.Category = Wix.Column.CategoryType.condition; 3797 xColumn.SetAttributeValue("Category", "condition");
4527 break; 3798 break;
4528 case ColumnCategory.Guid: 3799 case ColumnCategory.Guid:
4529 column.Category = Wix.Column.CategoryType.guid; 3800 xColumn.SetAttributeValue("Category", "guid");
4530 break; 3801 break;
4531 case ColumnCategory.Version: 3802 case ColumnCategory.Version:
4532 column.Category = Wix.Column.CategoryType.version; 3803 xColumn.SetAttributeValue("Category", "version");
4533 break; 3804 break;
4534 case ColumnCategory.Language: 3805 case ColumnCategory.Language:
4535 column.Category = Wix.Column.CategoryType.language; 3806 xColumn.SetAttributeValue("Category", "language");
4536 break; 3807 break;
4537 case ColumnCategory.Binary: 3808 case ColumnCategory.Binary:
4538 column.Category = Wix.Column.CategoryType.binary; 3809 xColumn.SetAttributeValue("Category", "binary");
4539 break; 3810 break;
4540 case ColumnCategory.CustomSource: 3811 case ColumnCategory.CustomSource:
4541 column.Category = Wix.Column.CategoryType.customSource; 3812 xColumn.SetAttributeValue("Category", "customSource");
4542 break; 3813 break;
4543 case ColumnCategory.Cabinet: 3814 case ColumnCategory.Cabinet:
4544 column.Category = Wix.Column.CategoryType.cabinet; 3815 xColumn.SetAttributeValue("Category", "cabinet");
4545 break; 3816 break;
4546 case ColumnCategory.Shortcut: 3817 case ColumnCategory.Shortcut:
4547 column.Category = Wix.Column.CategoryType.shortcut; 3818 xColumn.SetAttributeValue("Category", "shortcut");
4548 break; 3819 break;
4549 default: 3820 default:
4550 throw new InvalidOperationException($"Unknown custom column category '{columnDefinition.Category.ToString()}'."); 3821 throw new InvalidOperationException($"Unknown custom column category '{columnDefinition.Category.ToString()}'.");
4551 } 3822 }
4552 } 3823 }
4553 3824
4554 if (null != columnDefinition.Description)
4555 {
4556 column.Description = columnDefinition.Description;
4557 }
4558
4559 if (columnDefinition.KeyColumn.HasValue)
4560 {
4561 column.KeyColumn = columnDefinition.KeyColumn.Value;
4562 }
4563
4564 if (null != columnDefinition.KeyTable)
4565 {
4566 column.KeyTable = columnDefinition.KeyTable;
4567 }
4568
4569 if (columnDefinition.IsLocalizable)
4570 {
4571 column.Localizable = Wix.YesNoType.yes;
4572 }
4573
4574 if (columnDefinition.MaxValue.HasValue)
4575 {
4576 column.MaxValue = columnDefinition.MaxValue.Value;
4577 }
4578
4579 if (columnDefinition.MinValue.HasValue)
4580 {
4581 column.MinValue = columnDefinition.MinValue.Value;
4582 }
4583
4584 if (ColumnModularizeType.None != columnDefinition.ModularizeType) 3825 if (ColumnModularizeType.None != columnDefinition.ModularizeType)
4585 { 3826 {
4586 switch (columnDefinition.ModularizeType) 3827 switch (columnDefinition.ModularizeType)
4587 { 3828 {
4588 case ColumnModularizeType.Column: 3829 case ColumnModularizeType.Column:
4589 column.Modularize = Wix.Column.ModularizeType.Column; 3830 xColumn.SetAttributeValue("Modularize", "Column");
4590 break; 3831 break;
4591 case ColumnModularizeType.Condition: 3832 case ColumnModularizeType.Condition:
4592 column.Modularize = Wix.Column.ModularizeType.Condition; 3833 xColumn.SetAttributeValue("Modularize", "Condition");
4593 break; 3834 break;
4594 case ColumnModularizeType.Icon: 3835 case ColumnModularizeType.Icon:
4595 column.Modularize = Wix.Column.ModularizeType.Icon; 3836 xColumn.SetAttributeValue("Modularize", "Icon");
4596 break; 3837 break;
4597 case ColumnModularizeType.Property: 3838 case ColumnModularizeType.Property:
4598 column.Modularize = Wix.Column.ModularizeType.Property; 3839 xColumn.SetAttributeValue("Modularize", "Property");
4599 break; 3840 break;
4600 case ColumnModularizeType.SemicolonDelimited: 3841 case ColumnModularizeType.SemicolonDelimited:
4601 column.Modularize = Wix.Column.ModularizeType.SemicolonDelimited; 3842 xColumn.SetAttributeValue("Modularize", "SemicolonDelimited");
4602 break; 3843 break;
4603 default: 3844 default:
4604 throw new InvalidOperationException($"Unknown custom column modularization type '{columnDefinition.ModularizeType.ToString()}'."); 3845 throw new InvalidOperationException($"Unknown custom column modularization type '{columnDefinition.ModularizeType.ToString()}'.");
4605 } 3846 }
4606 } 3847 }
4607 3848
4608 if (columnDefinition.Nullable)
4609 {
4610 column.Nullable = Wix.YesNoType.yes;
4611 }
4612
4613 if (columnDefinition.PrimaryKey)
4614 {
4615 column.PrimaryKey = Wix.YesNoType.yes;
4616 }
4617
4618 if (null != columnDefinition.Possibilities)
4619 {
4620 column.Set = columnDefinition.Possibilities;
4621 }
4622
4623 if (ColumnType.Unknown != columnDefinition.Type) 3849 if (ColumnType.Unknown != columnDefinition.Type)
4624 { 3850 {
4625 switch (columnDefinition.Type) 3851 switch (columnDefinition.Type)
4626 { 3852 {
4627 case ColumnType.Localized: 3853 case ColumnType.Localized:
4628 column.Localizable = Wix.YesNoType.yes; 3854 xColumn.SetAttributeValue("Localizable", "yes");
4629 column.Type = Wix.Column.TypeType.@string; 3855 xColumn.SetAttributeValue("Type", "string");
4630 break; 3856 break;
4631 case ColumnType.Number: 3857 case ColumnType.Number:
4632 column.Type = Wix.Column.TypeType.@int; 3858 xColumn.SetAttributeValue("Type", "int");
4633 break; 3859 break;
4634 case ColumnType.Object: 3860 case ColumnType.Object:
4635 column.Type = Wix.Column.TypeType.binary; 3861 xColumn.SetAttributeValue("Type", "binary");
4636 break; 3862 break;
4637 case ColumnType.Preserved: 3863 case ColumnType.Preserved:
4638 case ColumnType.String: 3864 case ColumnType.String:
4639 column.Type = Wix.Column.TypeType.@string; 3865 xColumn.SetAttributeValue("Type", "string");
4640 break; 3866 break;
4641 default: 3867 default:
4642 throw new InvalidOperationException($"Unknown custom column type '{columnDefinition.Type.ToString()}'."); 3868 throw new InvalidOperationException($"Unknown custom column type '{columnDefinition.Type.ToString()}'.");
4643 } 3869 }
4644 } 3870 }
4645 3871
4646 column.Width = columnDefinition.Length; 3872 xCustomTable.Add(xColumn);
4647
4648 customTable.AddChild(column);
4649 } 3873 }
4650 3874
4651 foreach (var row in table.Rows) 3875 foreach (var row in table.Rows)
4652 { 3876 {
4653 var wixRow = new Wix.Row(); 3877 var xRow = new XElement(Names.RowElement);
4654 3878
4655 foreach (var field in row.Fields) 3879 foreach (var field in row.Fields)
4656 { 3880 {
4657 var data = new Wix.Data(); 3881 var xData = new XElement(Names.DataElement,
3882 new XAttribute("Column", field.Column.Name),
3883 new XAttribute("Value", field.AsString()));
4658 3884
4659 data.Column = field.Column.Name; 3885 xRow.Add(xData);
4660
4661 data.Content = Convert.ToString(field.Data, CultureInfo.InvariantCulture);
4662
4663 wixRow.AddChild(data);
4664 } 3886 }
4665 3887
4666 customTable.AddChild(wixRow); 3888 xCustomTable.Add(xRow);
4667 } 3889 }
4668 3890
4669 this.core.RootElement.AddChild(customTable); 3891 this.RootElement.Add(xCustomTable);
4670 } 3892 }
4671 } 3893 }
4672 3894
@@ -4678,20 +3900,11 @@ namespace WixToolset.Core.WindowsInstaller
4678 { 3900 {
4679 foreach (var row in table.Rows) 3901 foreach (var row in table.Rows)
4680 { 3902 {
4681 var createFolder = new Wix.CreateFolder(); 3903 var xCreateFolder = new XElement(Names.CreateFolderElement,
4682 3904 new XAttribute("Directory", row.FieldAsString(0)));
4683 createFolder.Directory = Convert.ToString(row[0]);
4684 3905
4685 var component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[1])); 3906 this.AddChildToParent("Component", xCreateFolder, row, 1);
4686 if (null != component) 3907 this.IndexElement(row, xCreateFolder);
4687 {
4688 component.AddChild(createFolder);
4689 }
4690 else
4691 {
4692 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[1]), "Component"));
4693 }
4694 this.core.IndexElement(row, createFolder);
4695 } 3908 }
4696 } 3909 }
4697 3910
@@ -4703,166 +3916,167 @@ namespace WixToolset.Core.WindowsInstaller
4703 { 3916 {
4704 foreach (var row in table.Rows) 3917 foreach (var row in table.Rows)
4705 { 3918 {
4706 var customAction = new Wix.CustomAction(); 3919 var xCustomAction = new XElement(Names.CustomActionElement,
3920 new XAttribute("Id", row.FieldAsString(0)));
4707 3921
4708 customAction.Id = Convert.ToString(row[0]); 3922 var type = row.FieldAsInteger(1);
4709
4710 var type = Convert.ToInt32(row[1]);
4711 3923
4712 if (WindowsInstallerConstants.MsidbCustomActionTypeHideTarget == (type & WindowsInstallerConstants.MsidbCustomActionTypeHideTarget)) 3924 if (WindowsInstallerConstants.MsidbCustomActionTypeHideTarget == (type & WindowsInstallerConstants.MsidbCustomActionTypeHideTarget))
4713 { 3925 {
4714 customAction.HideTarget = Wix.YesNoType.yes; 3926 xCustomAction.SetAttributeValue("HideTarget", "yes");
4715 } 3927 }
4716 3928
4717 if (WindowsInstallerConstants.MsidbCustomActionTypeNoImpersonate == (type & WindowsInstallerConstants.MsidbCustomActionTypeNoImpersonate)) 3929 if (WindowsInstallerConstants.MsidbCustomActionTypeNoImpersonate == (type & WindowsInstallerConstants.MsidbCustomActionTypeNoImpersonate))
4718 { 3930 {
4719 customAction.Impersonate = Wix.YesNoType.no; 3931 xCustomAction.SetAttributeValue("Impersonate", "no");
4720 } 3932 }
4721 3933
4722 if (WindowsInstallerConstants.MsidbCustomActionTypeTSAware == (type & WindowsInstallerConstants.MsidbCustomActionTypeTSAware)) 3934 if (WindowsInstallerConstants.MsidbCustomActionTypeTSAware == (type & WindowsInstallerConstants.MsidbCustomActionTypeTSAware))
4723 { 3935 {
4724 customAction.TerminalServerAware = Wix.YesNoType.yes; 3936 xCustomAction.SetAttributeValue("TerminalServerAware", "yes");
4725 } 3937 }
4726 3938
4727 if (WindowsInstallerConstants.MsidbCustomActionType64BitScript == (type & WindowsInstallerConstants.MsidbCustomActionType64BitScript)) 3939 if (WindowsInstallerConstants.MsidbCustomActionType64BitScript == (type & WindowsInstallerConstants.MsidbCustomActionType64BitScript))
4728 { 3940 {
4729 customAction.Win64 = Wix.YesNoType.yes; 3941 xCustomAction.SetAttributeValue("Win64", "yes");
4730 } 3942 }
4731 else if (WindowsInstallerConstants.MsidbCustomActionTypeVBScript == (type & WindowsInstallerConstants.MsidbCustomActionTypeVBScript) || 3943 else if (WindowsInstallerConstants.MsidbCustomActionTypeVBScript == (type & WindowsInstallerConstants.MsidbCustomActionTypeVBScript) ||
4732 WindowsInstallerConstants.MsidbCustomActionTypeJScript == (type & WindowsInstallerConstants.MsidbCustomActionTypeJScript)) 3944 WindowsInstallerConstants.MsidbCustomActionTypeJScript == (type & WindowsInstallerConstants.MsidbCustomActionTypeJScript))
4733 { 3945 {
4734 customAction.Win64 = Wix.YesNoType.no; 3946 xCustomAction.SetAttributeValue("Win64", "no");
4735 } 3947 }
4736 3948
4737 switch (type & WindowsInstallerConstants.MsidbCustomActionTypeExecuteBits) 3949 switch (type & WindowsInstallerConstants.MsidbCustomActionTypeExecuteBits)
4738 { 3950 {
4739 case 0: 3951 case 0:
4740 // this is the default value 3952 // this is the default value
4741 break; 3953 break;
4742 case WindowsInstallerConstants.MsidbCustomActionTypeFirstSequence: 3954 case WindowsInstallerConstants.MsidbCustomActionTypeFirstSequence:
4743 customAction.Execute = Wix.CustomAction.ExecuteType.firstSequence; 3955 xCustomAction.SetAttributeValue("Execute", "firstSequence");
4744 break; 3956 break;
4745 case WindowsInstallerConstants.MsidbCustomActionTypeOncePerProcess: 3957 case WindowsInstallerConstants.MsidbCustomActionTypeOncePerProcess:
4746 customAction.Execute = Wix.CustomAction.ExecuteType.oncePerProcess; 3958 xCustomAction.SetAttributeValue("Execute", "oncePerProcess");
4747 break; 3959 break;
4748 case WindowsInstallerConstants.MsidbCustomActionTypeClientRepeat: 3960 case WindowsInstallerConstants.MsidbCustomActionTypeClientRepeat:
4749 customAction.Execute = Wix.CustomAction.ExecuteType.secondSequence; 3961 xCustomAction.SetAttributeValue("Execute", "secondSequence");
4750 break; 3962 break;
4751 case WindowsInstallerConstants.MsidbCustomActionTypeInScript: 3963 case WindowsInstallerConstants.MsidbCustomActionTypeInScript:
4752 customAction.Execute = Wix.CustomAction.ExecuteType.deferred; 3964 xCustomAction.SetAttributeValue("Execute", "deferred");
4753 break; 3965 break;
4754 case WindowsInstallerConstants.MsidbCustomActionTypeInScript + WindowsInstallerConstants.MsidbCustomActionTypeRollback: 3966 case WindowsInstallerConstants.MsidbCustomActionTypeInScript + WindowsInstallerConstants.MsidbCustomActionTypeRollback:
4755 customAction.Execute = Wix.CustomAction.ExecuteType.rollback; 3967 xCustomAction.SetAttributeValue("Execute", "rollback");
4756 break; 3968 break;
4757 case WindowsInstallerConstants.MsidbCustomActionTypeInScript + WindowsInstallerConstants.MsidbCustomActionTypeCommit: 3969 case WindowsInstallerConstants.MsidbCustomActionTypeInScript + WindowsInstallerConstants.MsidbCustomActionTypeCommit:
4758 customAction.Execute = Wix.CustomAction.ExecuteType.commit; 3970 xCustomAction.SetAttributeValue("Execute", "commit");
4759 break; 3971 break;
4760 default: 3972 default:
4761 this.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[1].Column.Name, row[1])); 3973 this.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[1].Column.Name, row[1]));
4762 break; 3974 break;
4763 } 3975 }
4764 3976
4765 switch (type & WindowsInstallerConstants.MsidbCustomActionTypeReturnBits) 3977 switch (type & WindowsInstallerConstants.MsidbCustomActionTypeReturnBits)
4766 { 3978 {
4767 case 0: 3979 case 0:
4768 // this is the default value 3980 // this is the default value
4769 break; 3981 break;
4770 case WindowsInstallerConstants.MsidbCustomActionTypeContinue: 3982 case WindowsInstallerConstants.MsidbCustomActionTypeContinue:
4771 customAction.Return = Wix.CustomAction.ReturnType.ignore; 3983 xCustomAction.SetAttributeValue("Return", "ignore");
4772 break; 3984 break;
4773 case WindowsInstallerConstants.MsidbCustomActionTypeAsync: 3985 case WindowsInstallerConstants.MsidbCustomActionTypeAsync:
4774 customAction.Return = Wix.CustomAction.ReturnType.asyncWait; 3986 xCustomAction.SetAttributeValue("Return", "asyncWait");
4775 break; 3987 break;
4776 case WindowsInstallerConstants.MsidbCustomActionTypeAsync + WindowsInstallerConstants.MsidbCustomActionTypeContinue: 3988 case WindowsInstallerConstants.MsidbCustomActionTypeAsync + WindowsInstallerConstants.MsidbCustomActionTypeContinue:
4777 customAction.Return = Wix.CustomAction.ReturnType.asyncNoWait; 3989 xCustomAction.SetAttributeValue("Return", "asyncNoWait");
4778 break; 3990 break;
4779 default: 3991 default:
4780 this.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[1].Column.Name, row[1])); 3992 this.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[1].Column.Name, row[1]));
4781 break; 3993 break;
4782 } 3994 }
4783 3995
4784 var source = type & WindowsInstallerConstants.MsidbCustomActionTypeSourceBits; 3996 var source = type & WindowsInstallerConstants.MsidbCustomActionTypeSourceBits;
4785 switch (source) 3997 switch (source)
4786 { 3998 {
4787 case WindowsInstallerConstants.MsidbCustomActionTypeBinaryData: 3999 case WindowsInstallerConstants.MsidbCustomActionTypeBinaryData:
4788 customAction.BinaryKey = Convert.ToString(row[2]); 4000 xCustomAction.SetAttributeValue("BinaryKey", row.FieldAsString(2));
4789 break; 4001 break;
4790 case WindowsInstallerConstants.MsidbCustomActionTypeSourceFile: 4002 case WindowsInstallerConstants.MsidbCustomActionTypeSourceFile:
4791 if (null != row[2]) 4003 if (!row.IsColumnNull(2))
4792 { 4004 {
4793 customAction.FileKey = Convert.ToString(row[2]); 4005 xCustomAction.SetAttributeValue("FileKey", row.FieldAsString(2));
4794 } 4006 }
4795 break; 4007 break;
4796 case WindowsInstallerConstants.MsidbCustomActionTypeDirectory: 4008 case WindowsInstallerConstants.MsidbCustomActionTypeDirectory:
4797 if (null != row[2]) 4009 if (!row.IsColumnNull(2))
4798 { 4010 {
4799 customAction.Directory = Convert.ToString(row[2]); 4011 xCustomAction.SetAttributeValue("Directory", row.FieldAsString(2));
4800 } 4012 }
4801 break; 4013 break;
4802 case WindowsInstallerConstants.MsidbCustomActionTypeProperty: 4014 case WindowsInstallerConstants.MsidbCustomActionTypeProperty:
4803 customAction.Property = Convert.ToString(row[2]); 4015 xCustomAction.SetAttributeValue("Property", row.FieldAsString(2));
4804 break; 4016 break;
4805 default: 4017 default:
4806 this.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[1].Column.Name, row[1])); 4018 this.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[1].Column.Name, row[1]));
4807 break; 4019 break;
4808 } 4020 }
4809 4021
4810 switch (type & WindowsInstallerConstants.MsidbCustomActionTypeTargetBits) 4022 switch (type & WindowsInstallerConstants.MsidbCustomActionTypeTargetBits)
4811 { 4023 {
4812 case WindowsInstallerConstants.MsidbCustomActionTypeDll: 4024 case WindowsInstallerConstants.MsidbCustomActionTypeDll:
4813 customAction.DllEntry = Convert.ToString(row[3]); 4025 xCustomAction.SetAttributeValue("DllEntry", row.FieldAsString(3));
4814 break; 4026 break;
4815 case WindowsInstallerConstants.MsidbCustomActionTypeExe: 4027 case WindowsInstallerConstants.MsidbCustomActionTypeExe:
4816 customAction.ExeCommand = Convert.ToString(row[3]); 4028 xCustomAction.SetAttributeValue("ExeCommand", row.FieldAsString(3));
4817 break; 4029 break;
4818 case WindowsInstallerConstants.MsidbCustomActionTypeTextData: 4030 case WindowsInstallerConstants.MsidbCustomActionTypeTextData:
4819 if (WindowsInstallerConstants.MsidbCustomActionTypeSourceFile == source) 4031 if (WindowsInstallerConstants.MsidbCustomActionTypeSourceFile == source)
4820 { 4032 {
4821 customAction.Error = Convert.ToString(row[3]); 4033 xCustomAction.SetAttributeValue("Error", row.FieldAsString(3));
4822 } 4034 }
4823 else 4035 else
4824 { 4036 {
4825 customAction.Value = Convert.ToString(row[3]); 4037 xCustomAction.SetAttributeValue("Value", row.FieldAsString(3));
4826 } 4038 }
4827 break; 4039 break;
4828 case WindowsInstallerConstants.MsidbCustomActionTypeJScript: 4040 case WindowsInstallerConstants.MsidbCustomActionTypeJScript:
4829 if (WindowsInstallerConstants.MsidbCustomActionTypeDirectory == source) 4041 if (WindowsInstallerConstants.MsidbCustomActionTypeDirectory == source)
4830 { 4042 {
4831 customAction.Script = Wix.CustomAction.ScriptType.jscript; 4043 xCustomAction.SetAttributeValue("Script", "jscript");
4832 customAction.Content = Convert.ToString(row[3]); 4044 // TODO: Extract to @ScriptFile?
4833 } 4045 // xCustomAction.Content = row.FieldAsString(3);
4834 else 4046 }
4835 { 4047 else
4836 customAction.JScriptCall = Convert.ToString(row[3]); 4048 {
4837 } 4049 xCustomAction.SetAttributeValue("JScriptCall", row.FieldAsString(3));
4838 break; 4050 }
4839 case WindowsInstallerConstants.MsidbCustomActionTypeVBScript: 4051 break;
4840 if (WindowsInstallerConstants.MsidbCustomActionTypeDirectory == source) 4052 case WindowsInstallerConstants.MsidbCustomActionTypeVBScript:
4841 { 4053 if (WindowsInstallerConstants.MsidbCustomActionTypeDirectory == source)
4842 customAction.Script = Wix.CustomAction.ScriptType.vbscript; 4054 {
4843 customAction.Content = Convert.ToString(row[3]); 4055 xCustomAction.SetAttributeValue("Script", "vbscript");
4844 } 4056 // TODO: Extract to @ScriptFile?
4845 else 4057 // xCustomAction.Content = row.FieldAsString(3);
4846 { 4058 }
4847 customAction.VBScriptCall = Convert.ToString(row[3]); 4059 else
4848 } 4060 {
4849 break; 4061 xCustomAction.SetAttributeValue("VBScriptCall", row.FieldAsString(3));
4850 case WindowsInstallerConstants.MsidbCustomActionTypeInstall: 4062 }
4851 this.Messaging.Write(WarningMessages.NestedInstall(row.SourceLineNumbers, table.Name, row.Fields[1].Column.Name, row[1])); 4063 break;
4852 continue; 4064 case WindowsInstallerConstants.MsidbCustomActionTypeInstall:
4853 default: 4065 this.Messaging.Write(WarningMessages.NestedInstall(row.SourceLineNumbers, table.Name, row.Fields[1].Column.Name, row[1]));
4854 this.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[1].Column.Name, row[1])); 4066 continue;
4855 break; 4067 default:
4068 this.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[1].Column.Name, row[1]));
4069 break;
4856 } 4070 }
4857 4071
4858 var extype = 4 < row.Fields.Length && null != row[4] ? Convert.ToInt32(row[4]) : 0; 4072 var extype = 4 < row.Fields.Length && !row.IsColumnNull(4) ? row.FieldAsInteger(4) : 0;
4859 if (WindowsInstallerConstants.MsidbCustomActionTypePatchUninstall == (extype & WindowsInstallerConstants.MsidbCustomActionTypePatchUninstall)) 4073 if (WindowsInstallerConstants.MsidbCustomActionTypePatchUninstall == (extype & WindowsInstallerConstants.MsidbCustomActionTypePatchUninstall))
4860 { 4074 {
4861 customAction.PatchUninstall = Wix.YesNoType.yes; 4075 xCustomAction.SetAttributeValue("PatchUninstall", "yes");
4862 } 4076 }
4863 4077
4864 this.core.RootElement.AddChild(customAction); 4078 this.RootElement.Add(xCustomAction);
4865 this.core.IndexElement(row, customAction); 4079 this.IndexElement(row, xCustomAction);
4866 } 4080 }
4867 } 4081 }
4868 4082
@@ -4874,29 +4088,27 @@ namespace WixToolset.Core.WindowsInstaller
4874 { 4088 {
4875 foreach (var row in table.Rows) 4089 foreach (var row in table.Rows)
4876 { 4090 {
4877 var componentSearch = new Wix.ComponentSearch(); 4091 var xComponentSearch = new XElement(Names.ComponentSearchElement,
4878 4092 new XAttribute("Id", row.FieldAsString(0)),
4879 componentSearch.Id = Convert.ToString(row[0]); 4093 new XAttribute("Guid", row.FieldAsString(1)));
4880 4094
4881 componentSearch.Guid = Convert.ToString(row[1]); 4095 if (!row.IsColumnNull(2))
4882
4883 if (null != row[2])
4884 { 4096 {
4885 switch (Convert.ToInt32(row[2])) 4097 switch (row.FieldAsInteger(2))
4886 { 4098 {
4887 case WindowsInstallerConstants.MsidbLocatorTypeDirectory: 4099 case WindowsInstallerConstants.MsidbLocatorTypeDirectory:
4888 componentSearch.Type = Wix.ComponentSearch.TypeType.directory; 4100 xComponentSearch.SetAttributeValue("Type", "directory");
4889 break; 4101 break;
4890 case WindowsInstallerConstants.MsidbLocatorTypeFileName: 4102 case WindowsInstallerConstants.MsidbLocatorTypeFileName:
4891 // this is the default value 4103 // this is the default value
4892 break; 4104 break;
4893 default: 4105 default:
4894 this.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[2].Column.Name, row[2])); 4106 this.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[2].Column.Name, row[2]));
4895 break; 4107 break;
4896 } 4108 }
4897 } 4109 }
4898 4110
4899 this.core.IndexElement(row, componentSearch); 4111 this.IndexElement(row, xComponentSearch);
4900 } 4112 }
4901 } 4113 }
4902 4114
@@ -4908,17 +4120,15 @@ namespace WixToolset.Core.WindowsInstaller
4908 { 4120 {
4909 foreach (var row in table.Rows) 4121 foreach (var row in table.Rows)
4910 { 4122 {
4911 if (null != row[1]) 4123 if (!row.IsColumnNull(1))
4912 { 4124 {
4913 var component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[0])); 4125 if (this.TryGetIndexedElement("Component", out var xComponent, row.FieldAsString(0)))
4914
4915 if (null != component)
4916 { 4126 {
4917 component.ComPlusFlags = Convert.ToInt32(row[1]); 4127 xComponent.SetAttributeValue("ComPlusFlags", row.FieldAsInteger(1));
4918 } 4128 }
4919 else 4129 else
4920 { 4130 {
4921 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[0]), "Component")); 4131 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", row.FieldAsString(0), "Component"));
4922 } 4132 }
4923 } 4133 }
4924 } 4134 }
@@ -4932,86 +4142,72 @@ namespace WixToolset.Core.WindowsInstaller
4932 { 4142 {
4933 foreach (var row in table.Rows) 4143 foreach (var row in table.Rows)
4934 { 4144 {
4935 var component = new Wix.Component(); 4145 var xComponent = new XElement(Names.ComponentElement,
4146 new XAttribute("Id", row.FieldAsString(0)),
4147 new XAttribute("Guid", row.FieldAsString(1)));
4936 4148
4937 component.Id = Convert.ToString(row[0]); 4149 var attributes = row.FieldAsInteger(3);
4938
4939 component.Guid = Convert.ToString(row[1]);
4940
4941 var attributes = Convert.ToInt32(row[3]);
4942 4150
4943 if (WindowsInstallerConstants.MsidbComponentAttributesSourceOnly == (attributes & WindowsInstallerConstants.MsidbComponentAttributesSourceOnly)) 4151 if (WindowsInstallerConstants.MsidbComponentAttributesSourceOnly == (attributes & WindowsInstallerConstants.MsidbComponentAttributesSourceOnly))
4944 { 4152 {
4945 component.Location = Wix.Component.LocationType.source; 4153 xComponent.SetAttributeValue("Location", "source");
4946 } 4154 }
4947 else if (WindowsInstallerConstants.MsidbComponentAttributesOptional == (attributes & WindowsInstallerConstants.MsidbComponentAttributesOptional)) 4155 else if (WindowsInstallerConstants.MsidbComponentAttributesOptional == (attributes & WindowsInstallerConstants.MsidbComponentAttributesOptional))
4948 { 4156 {
4949 component.Location = Wix.Component.LocationType.either; 4157 xComponent.SetAttributeValue("Location", "either");
4950 } 4158 }
4951 4159
4952 if (WindowsInstallerConstants.MsidbComponentAttributesSharedDllRefCount == (attributes & WindowsInstallerConstants.MsidbComponentAttributesSharedDllRefCount)) 4160 if (WindowsInstallerConstants.MsidbComponentAttributesSharedDllRefCount == (attributes & WindowsInstallerConstants.MsidbComponentAttributesSharedDllRefCount))
4953 { 4161 {
4954 component.SharedDllRefCount = Wix.YesNoType.yes; 4162 xComponent.SetAttributeValue("SharedDllRefCount", "yes");
4955 } 4163 }
4956 4164
4957 if (WindowsInstallerConstants.MsidbComponentAttributesPermanent == (attributes & WindowsInstallerConstants.MsidbComponentAttributesPermanent)) 4165 if (WindowsInstallerConstants.MsidbComponentAttributesPermanent == (attributes & WindowsInstallerConstants.MsidbComponentAttributesPermanent))
4958 { 4166 {
4959 component.Permanent = Wix.YesNoType.yes; 4167 xComponent.SetAttributeValue("Permanent", "yes");
4960 } 4168 }
4961 4169
4962 if (WindowsInstallerConstants.MsidbComponentAttributesTransitive == (attributes & WindowsInstallerConstants.MsidbComponentAttributesTransitive)) 4170 if (WindowsInstallerConstants.MsidbComponentAttributesTransitive == (attributes & WindowsInstallerConstants.MsidbComponentAttributesTransitive))
4963 { 4171 {
4964 component.Transitive = Wix.YesNoType.yes; 4172 xComponent.SetAttributeValue("Transitive", "yes");
4965 } 4173 }
4966 4174
4967 if (WindowsInstallerConstants.MsidbComponentAttributesNeverOverwrite == (attributes & WindowsInstallerConstants.MsidbComponentAttributesNeverOverwrite)) 4175 if (WindowsInstallerConstants.MsidbComponentAttributesNeverOverwrite == (attributes & WindowsInstallerConstants.MsidbComponentAttributesNeverOverwrite))
4968 { 4176 {
4969 component.NeverOverwrite = Wix.YesNoType.yes; 4177 xComponent.SetAttributeValue("NeverOverwrite", "yes");
4970 } 4178 }
4971 4179
4972 if (WindowsInstallerConstants.MsidbComponentAttributes64bit == (attributes & WindowsInstallerConstants.MsidbComponentAttributes64bit)) 4180 if (WindowsInstallerConstants.MsidbComponentAttributes64bit == (attributes & WindowsInstallerConstants.MsidbComponentAttributes64bit))
4973 { 4181 {
4974 component.Win64 = Wix.YesNoType.yes; 4182 xComponent.SetAttributeValue("Win64", "yes");
4975 } 4183 }
4976 else 4184 else
4977 { 4185 {
4978 component.Win64 = Wix.YesNoType.no; 4186 xComponent.SetAttributeValue("Win64", "no");
4979 } 4187 }
4980 4188
4981 if (WindowsInstallerConstants.MsidbComponentAttributesDisableRegistryReflection == (attributes & WindowsInstallerConstants.MsidbComponentAttributesDisableRegistryReflection)) 4189 if (WindowsInstallerConstants.MsidbComponentAttributesDisableRegistryReflection == (attributes & WindowsInstallerConstants.MsidbComponentAttributesDisableRegistryReflection))
4982 { 4190 {
4983 component.DisableRegistryReflection = Wix.YesNoType.yes; 4191 xComponent.SetAttributeValue("DisableRegistryReflection", "yes");
4984 } 4192 }
4985 4193
4986 if (WindowsInstallerConstants.MsidbComponentAttributesUninstallOnSupersedence == (attributes & WindowsInstallerConstants.MsidbComponentAttributesUninstallOnSupersedence)) 4194 if (WindowsInstallerConstants.MsidbComponentAttributesUninstallOnSupersedence == (attributes & WindowsInstallerConstants.MsidbComponentAttributesUninstallOnSupersedence))
4987 { 4195 {
4988 component.UninstallWhenSuperseded = Wix.YesNoType.yes; 4196 xComponent.SetAttributeValue("UninstallWhenSuperseded", "yes");
4989 } 4197 }
4990 4198
4991 if (WindowsInstallerConstants.MsidbComponentAttributesShared == (attributes & WindowsInstallerConstants.MsidbComponentAttributesShared)) 4199 if (WindowsInstallerConstants.MsidbComponentAttributesShared == (attributes & WindowsInstallerConstants.MsidbComponentAttributesShared))
4992 { 4200 {
4993 component.Shared = Wix.YesNoType.yes; 4201 xComponent.SetAttributeValue("Shared", "yes");
4994 } 4202 }
4995 4203
4996 if (null != row[4]) 4204 if (!row.IsColumnNull(4))
4997 { 4205 {
4998 var condition = new Wix.Condition(); 4206 xComponent.SetAttributeValue("Condition", row.FieldAsString(4));
4999
5000 condition.Content = Convert.ToString(row[4]);
5001
5002 component.AddChild(condition);
5003 } 4207 }
5004 4208
5005 var directory = (Wix.Directory)this.core.GetIndexedElement("Directory", Convert.ToString(row[2])); 4209 this.AddChildToParent("Directory", xComponent, row, 2);
5006 if (null != directory) 4210 this.IndexElement(row, xComponent);
5007 {
5008 directory.AddChild(component);
5009 }
5010 else
5011 {
5012 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Directory_", Convert.ToString(row[2]), "Directory"));
5013 }
5014 this.core.IndexElement(row, component);
5015 } 4211 }
5016 } 4212 }
5017 4213
@@ -5023,23 +4219,17 @@ namespace WixToolset.Core.WindowsInstaller
5023 { 4219 {
5024 foreach (var row in table.Rows) 4220 foreach (var row in table.Rows)
5025 { 4221 {
5026 var condition = new Wix.Condition(); 4222 if (this.TryGetIndexedElement("Feature", out var xFeature, row.FieldAsString(0)))
5027
5028 condition.Level = Convert.ToInt32(row[1]);
5029
5030 if (null != row[2])
5031 { 4223 {
5032 condition.Content = Convert.ToString(row[2]); 4224 var xLevel = new XElement(Names.LevelElement,
5033 } 4225 row.IsColumnNull(2) ? null : new XAttribute("Condition", row.FieldAsString(2)),
4226 new XAttribute("Level", row.FieldAsInteger(1)));
5034 4227
5035 var feature = (Wix.Feature)this.core.GetIndexedElement("Feature", Convert.ToString(row[0])); 4228 xFeature.Add(xLevel);
5036 if (null != feature)
5037 {
5038 feature.AddChild(condition);
5039 } 4229 }
5040 else 4230 else
5041 { 4231 {
5042 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Feature_", Convert.ToString(row[0]), "Feature")); 4232 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Feature_", row.FieldAsString(0), "Feature"));
5043 } 4233 }
5044 } 4234 }
5045 } 4235 }
@@ -5052,85 +4242,28 @@ namespace WixToolset.Core.WindowsInstaller
5052 { 4242 {
5053 foreach (var row in table.Rows) 4243 foreach (var row in table.Rows)
5054 { 4244 {
5055 var dialog = new Wix.Dialog(); 4245 var attributes = row.FieldAsNullableInteger(5) ?? 0;
5056
5057 dialog.Id = Convert.ToString(row[0]);
5058
5059 dialog.X = Convert.ToInt32(row[1]);
5060
5061 dialog.Y = Convert.ToInt32(row[2]);
5062 4246
5063 dialog.Width = Convert.ToInt32(row[3]); 4247 var xDialog = new XElement(Names.DialogElement,
4248 new XAttribute("Id", row.FieldAsString(0)),
4249 new XAttribute("X", row.FieldAsString(1)),
4250 new XAttribute("Y", row.FieldAsString(2)),
4251 new XAttribute("Width", row.FieldAsString(3)),
4252 new XAttribute("Height", row.FieldAsString(4)),
4253 0 == (attributes & WindowsInstallerConstants.MsidbDialogAttributesVisible) ? new XAttribute("Hidden", "yes") : null,
4254 0 == (attributes & WindowsInstallerConstants.MsidbDialogAttributesModal) ? new XAttribute("Modeless", "yes") : null,
4255 0 == (attributes & WindowsInstallerConstants.MsidbDialogAttributesMinimize) ? new XAttribute("NoMinimize", "yes") : null,
4256 0 == (attributes & WindowsInstallerConstants.MsidbDialogAttributesMinimize) ? new XAttribute("NoMinimize", "yes") : null,
4257 WindowsInstallerConstants.MsidbDialogAttributesSysModal == (attributes & WindowsInstallerConstants.MsidbDialogAttributesSysModal) ? new XAttribute("SystemModal", "yes") : null,
4258 WindowsInstallerConstants.MsidbDialogAttributesKeepModeless == (attributes & WindowsInstallerConstants.MsidbDialogAttributesKeepModeless) ? new XAttribute("KeepModeless", "yes") : null,
4259 WindowsInstallerConstants.MsidbDialogAttributesTrackDiskSpace == (attributes & WindowsInstallerConstants.MsidbDialogAttributesTrackDiskSpace) ? new XAttribute("TrackDiskSpace", "yes") : null,
4260 WindowsInstallerConstants.MsidbDialogAttributesUseCustomPalette == (attributes & WindowsInstallerConstants.MsidbDialogAttributesUseCustomPalette) ? new XAttribute("CustomPalette", "yes") : null,
4261 WindowsInstallerConstants.MsidbDialogAttributesLeftScroll == (attributes & WindowsInstallerConstants.MsidbDialogAttributesLeftScroll) ? new XAttribute("LeftScroll", "yes") : null,
4262 WindowsInstallerConstants.MsidbDialogAttributesError == (attributes & WindowsInstallerConstants.MsidbDialogAttributesError) ? new XAttribute("ErrorDialog", "yes") : null,
4263 !row.IsColumnNull(6) ? new XAttribute("Title", row.FieldAsString(6)) : null);
5064 4264
5065 dialog.Height = Convert.ToInt32(row[4]); 4265 this.UIElement.Add(xDialog);
5066 4266 this.IndexElement(row, xDialog);
5067 if (null != row[5])
5068 {
5069 var attributes = Convert.ToInt32(row[5]);
5070
5071 if (0 == (attributes & WindowsInstallerConstants.MsidbDialogAttributesVisible))
5072 {
5073 dialog.Hidden = Wix.YesNoType.yes;
5074 }
5075
5076 if (0 == (attributes & WindowsInstallerConstants.MsidbDialogAttributesModal))
5077 {
5078 dialog.Modeless = Wix.YesNoType.yes;
5079 }
5080
5081 if (0 == (attributes & WindowsInstallerConstants.MsidbDialogAttributesMinimize))
5082 {
5083 dialog.NoMinimize = Wix.YesNoType.yes;
5084 }
5085
5086 if (WindowsInstallerConstants.MsidbDialogAttributesSysModal == (attributes & WindowsInstallerConstants.MsidbDialogAttributesSysModal))
5087 {
5088 dialog.SystemModal = Wix.YesNoType.yes;
5089 }
5090
5091 if (WindowsInstallerConstants.MsidbDialogAttributesKeepModeless == (attributes & WindowsInstallerConstants.MsidbDialogAttributesKeepModeless))
5092 {
5093 dialog.KeepModeless = Wix.YesNoType.yes;
5094 }
5095
5096 if (WindowsInstallerConstants.MsidbDialogAttributesTrackDiskSpace == (attributes & WindowsInstallerConstants.MsidbDialogAttributesTrackDiskSpace))
5097 {
5098 dialog.TrackDiskSpace = Wix.YesNoType.yes;
5099 }
5100
5101 if (WindowsInstallerConstants.MsidbDialogAttributesUseCustomPalette == (attributes & WindowsInstallerConstants.MsidbDialogAttributesUseCustomPalette))
5102 {
5103 dialog.CustomPalette = Wix.YesNoType.yes;
5104 }
5105
5106 if (WindowsInstallerConstants.MsidbDialogAttributesRTLRO == (attributes & WindowsInstallerConstants.MsidbDialogAttributesRTLRO))
5107 {
5108 dialog.RightToLeft = Wix.YesNoType.yes;
5109 }
5110
5111 if (WindowsInstallerConstants.MsidbDialogAttributesRightAligned == (attributes & WindowsInstallerConstants.MsidbDialogAttributesRightAligned))
5112 {
5113 dialog.RightAligned = Wix.YesNoType.yes;
5114 }
5115
5116 if (WindowsInstallerConstants.MsidbDialogAttributesLeftScroll == (attributes & WindowsInstallerConstants.MsidbDialogAttributesLeftScroll))
5117 {
5118 dialog.LeftScroll = Wix.YesNoType.yes;
5119 }
5120
5121 if (WindowsInstallerConstants.MsidbDialogAttributesError == (attributes & WindowsInstallerConstants.MsidbDialogAttributesError))
5122 {
5123 dialog.ErrorDialog = Wix.YesNoType.yes;
5124 }
5125 }
5126
5127 if (null != row[6])
5128 {
5129 dialog.Title = Convert.ToString(row[6]);
5130 }
5131
5132 this.core.UIElement.AddChild(dialog);
5133 this.core.IndexElement(row, dialog);
5134 } 4267 }
5135 } 4268 }
5136 4269
@@ -5142,16 +4275,16 @@ namespace WixToolset.Core.WindowsInstaller
5142 { 4275 {
5143 foreach (var row in table.Rows) 4276 foreach (var row in table.Rows)
5144 { 4277 {
5145 var directory = new Wix.Directory(); 4278 var id = row.FieldAsString(0);
4279 var xDirectory = new XElement(Names.DirectoryElement,
4280 new XAttribute("Id", id));
5146 4281
5147 directory.Id = Convert.ToString(row[0]); 4282 var names = Common.GetNames(row.FieldAsString(2));
5148 4283
5149 var names = Common.GetNames(Convert.ToString(row[2])); 4284 if (String.Equals(id, "TARGETDIR", StringComparison.Ordinal) && !String.Equals(names[0], "SourceDir", StringComparison.Ordinal))
5150
5151 if (String.Equals(directory.Id, "TARGETDIR", StringComparison.Ordinal) && !String.Equals(names[0], "SourceDir", StringComparison.Ordinal))
5152 { 4285 {
5153 this.Messaging.Write(WarningMessages.TargetDirCorrectedDefaultDir()); 4286 this.Messaging.Write(WarningMessages.TargetDirCorrectedDefaultDir());
5154 directory.Name = "SourceDir"; 4287 xDirectory.SetAttributeValue("Name", "SourceDir");
5155 } 4288 }
5156 else 4289 else
5157 { 4290 {
@@ -5159,17 +4292,17 @@ namespace WixToolset.Core.WindowsInstaller
5159 { 4292 {
5160 if (null != names[1]) 4293 if (null != names[1])
5161 { 4294 {
5162 directory.ShortName = names[0]; 4295 xDirectory.SetAttributeValue("ShortName", names[0]);
5163 } 4296 }
5164 else 4297 else
5165 { 4298 {
5166 directory.Name = names[0]; 4299 xDirectory.SetAttributeValue("Name", names[0]);
5167 } 4300 }
5168 } 4301 }
5169 4302
5170 if (null != names[1]) 4303 if (null != names[1])
5171 { 4304 {
5172 directory.Name = names[1]; 4305 xDirectory.SetAttributeValue("Name", names[1]);
5173 } 4306 }
5174 } 4307 }
5175 4308
@@ -5177,46 +4310,44 @@ namespace WixToolset.Core.WindowsInstaller
5177 { 4310 {
5178 if (null != names[3]) 4311 if (null != names[3])
5179 { 4312 {
5180 directory.ShortSourceName = names[2]; 4313 xDirectory.SetAttributeValue("ShortSourceName", names[2]);
5181 } 4314 }
5182 else 4315 else
5183 { 4316 {
5184 directory.SourceName = names[2]; 4317 xDirectory.SetAttributeValue("SourceName", names[2]);
5185 } 4318 }
5186 } 4319 }
5187 4320
5188 if (null != names[3]) 4321 if (null != names[3])
5189 { 4322 {
5190 directory.SourceName = names[3]; 4323 xDirectory.SetAttributeValue("SourceName", names[3]);
5191 } 4324 }
5192 4325
5193 this.core.IndexElement(row, directory); 4326 this.IndexElement(row, xDirectory);
5194 } 4327 }
5195 4328
5196 // nest the directories 4329 // nest the directories
5197 foreach (var row in table.Rows) 4330 foreach (var row in table.Rows)
5198 { 4331 {
5199 var directory = (Wix.Directory)this.core.GetIndexedElement(row); 4332 var xDirectory = this.GetIndexedElement(row);
5200 4333
5201 if (null == row[1]) 4334 if (row.IsColumnNull(1))
5202 { 4335 {
5203 this.core.RootElement.AddChild(directory); 4336 this.RootElement.Add(xDirectory);
5204 } 4337 }
5205 else 4338 else
5206 { 4339 {
5207 var parentDirectory = (Wix.Directory)this.core.GetIndexedElement("Directory", Convert.ToString(row[1])); 4340 if (!this.TryGetIndexedElement("Directory", out var xParentDirectory, row.FieldAsString(1)))
5208
5209 if (null == parentDirectory)
5210 { 4341 {
5211 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Directory_Parent", Convert.ToString(row[1]), "Directory")); 4342 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Directory_Parent", row.FieldAsString(1), "Directory"));
5212 } 4343 }
5213 else if (parentDirectory == directory) // another way to specify a root directory 4344 else if (xParentDirectory == xDirectory) // another way to specify a root directory
5214 { 4345 {
5215 this.core.RootElement.AddChild(directory); 4346 this.RootElement.Add(xDirectory);
5216 } 4347 }
5217 else 4348 else
5218 { 4349 {
5219 parentDirectory.AddChild(directory); 4350 xParentDirectory.Add(xDirectory);
5220 } 4351 }
5221 } 4352 }
5222 } 4353 }
@@ -5230,21 +4361,12 @@ namespace WixToolset.Core.WindowsInstaller
5230 { 4361 {
5231 foreach (var row in table.Rows) 4362 foreach (var row in table.Rows)
5232 { 4363 {
5233 var directorySearch = new Wix.DirectorySearch(); 4364 var xDirectorySearch = new XElement(Names.DirectorySearchElement,
5234 4365 new XAttribute("Id", row.FieldAsString(0)),
5235 directorySearch.Id = Convert.ToString(row[0]); 4366 XAttributeIfNotNull("Path", row, 2),
5236 4367 XAttributeIfNotNull("Depth", row, 3));
5237 if (null != row[2])
5238 {
5239 directorySearch.Path = Convert.ToString(row[2]);
5240 }
5241 4368
5242 if (null != row[3]) 4369 this.IndexElement(row, xDirectorySearch);
5243 {
5244 directorySearch.Depth = Convert.ToInt32(row[3]);
5245 }
5246
5247 this.core.IndexElement(row, directorySearch);
5248 } 4370 }
5249 } 4371 }
5250 4372
@@ -5256,38 +4378,28 @@ namespace WixToolset.Core.WindowsInstaller
5256 { 4378 {
5257 foreach (var row in table.Rows) 4379 foreach (var row in table.Rows)
5258 { 4380 {
5259 var copyFile = new Wix.CopyFile(); 4381 var xCopyFile = new XElement(Names.CopyFileElement,
5260 4382 new XAttribute("Id", row.FieldAsString(0)),
5261 copyFile.Id = Convert.ToString(row[0]); 4383 new XAttribute("FileId", row.FieldAsString(2)));
5262 4384
5263 copyFile.FileId = Convert.ToString(row[2]); 4385 if (!row.IsColumnNull(3))
5264
5265 if (null != row[3])
5266 { 4386 {
5267 var names = Common.GetNames(Convert.ToString(row[3])); 4387 var names = Common.GetNames(row.FieldAsString(3));
5268 if (null != names[0] && null != names[1]) 4388 if (null != names[0] && null != names[1])
5269 { 4389 {
5270 copyFile.DestinationShortName = names[0]; 4390 xCopyFile.SetAttributeValue("DestinationShortName", names[0]);
5271 copyFile.DestinationName = names[1]; 4391 xCopyFile.SetAttributeValue("DestinationName", names[1]);
5272 } 4392 }
5273 else if (null != names[0]) 4393 else if (null != names[0])
5274 { 4394 {
5275 copyFile.DestinationName = names[0]; 4395 xCopyFile.SetAttributeValue("DestinationName", names[0]);
5276 } 4396 }
5277 } 4397 }
5278 4398
5279 // destination directory/property is set in FinalizeDuplicateMoveFileTables 4399 // destination directory/property is set in FinalizeDuplicateMoveFileTables
5280 4400
5281 var component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[1])); 4401 this.AddChildToParent("Component", xCopyFile, row, 1);
5282 if (null != component) 4402 this.IndexElement(row, xCopyFile);
5283 {
5284 component.AddChild(copyFile);
5285 }
5286 else
5287 {
5288 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[1]), "Component"));
5289 }
5290 this.core.IndexElement(row, copyFile);
5291 } 4403 }
5292 } 4404 }
5293 4405
@@ -5299,83 +4411,74 @@ namespace WixToolset.Core.WindowsInstaller
5299 { 4411 {
5300 foreach (var row in table.Rows) 4412 foreach (var row in table.Rows)
5301 { 4413 {
5302 var environment = new Wix.Environment(); 4414 var xEnvironment = new XElement(Names.EnvironmentElement,
5303 4415 new XAttribute("Id", row.FieldAsString(0)));
5304 environment.Id = Convert.ToString(row[0]);
5305 4416
5306 var done = false; 4417 var done = false;
5307 var permanent = true; 4418 var permanent = true;
5308 var name = Convert.ToString(row[1]); 4419 var name = row.FieldAsString(1);
5309 for (var i = 0; i < name.Length && !done; i++) 4420 for (var i = 0; i < name.Length && !done; i++)
5310 { 4421 {
5311 switch (name[i]) 4422 switch (name[i])
5312 { 4423 {
5313 case '=': 4424 case '=':
5314 environment.Action = Wix.Environment.ActionType.set; 4425 xEnvironment.SetAttributeValue("Action", "set");
5315 break; 4426 break;
5316 case '+': 4427 case '+':
5317 environment.Action = Wix.Environment.ActionType.create; 4428 xEnvironment.SetAttributeValue("Action", "create");
5318 break; 4429 break;
5319 case '-': 4430 case '-':
5320 permanent = false; 4431 permanent = false;
5321 break; 4432 break;
5322 case '!': 4433 case '!':
5323 environment.Action = Wix.Environment.ActionType.remove; 4434 xEnvironment.SetAttributeValue("Action", "remove");
5324 break; 4435 break;
5325 case '*': 4436 case '*':
5326 environment.System = Wix.YesNoType.yes; 4437 xEnvironment.SetAttributeValue("System", "yes");
5327 break; 4438 break;
5328 default: 4439 default:
5329 environment.Name = name.Substring(i); 4440 xEnvironment.SetAttributeValue("Name", name.Substring(i));
5330 done = true; 4441 done = true;
5331 break; 4442 break;
5332 } 4443 }
5333 } 4444 }
5334 4445
5335 if (permanent) 4446 if (permanent)
5336 { 4447 {
5337 environment.Permanent = Wix.YesNoType.yes; 4448 xEnvironment.SetAttributeValue("Permanent", "yes");
5338 } 4449 }
5339 4450
5340 if (null != row[2]) 4451 if (!row.IsColumnNull(2))
5341 { 4452 {
5342 var value = Convert.ToString(row[2]); 4453 var value = row.FieldAsString(2);
5343 4454
5344 if (value.StartsWith("[~]", StringComparison.Ordinal)) 4455 if (value.StartsWith("[~]", StringComparison.Ordinal))
5345 { 4456 {
5346 environment.Part = Wix.Environment.PartType.last; 4457 xEnvironment.SetAttributeValue("Part", "last");
5347 4458
5348 if (3 < value.Length) 4459 if (3 < value.Length)
5349 { 4460 {
5350 environment.Separator = value.Substring(3, 1); 4461 xEnvironment.SetAttributeValue("Separator", value.Substring(3, 1));
5351 environment.Value = value.Substring(4); 4462 xEnvironment.SetAttributeValue("Value", value.Substring(4));
5352 } 4463 }
5353 } 4464 }
5354 else if (value.EndsWith("[~]", StringComparison.Ordinal)) 4465 else if (value.EndsWith("[~]", StringComparison.Ordinal))
5355 { 4466 {
5356 environment.Part = Wix.Environment.PartType.first; 4467 xEnvironment.SetAttributeValue("Part", "first");
5357 4468
5358 if (3 < value.Length) 4469 if (3 < value.Length)
5359 { 4470 {
5360 environment.Separator = value.Substring(value.Length - 4, 1); 4471 xEnvironment.SetAttributeValue("Separator", value.Substring(value.Length - 4, 1));
5361 environment.Value = value.Substring(0, value.Length - 4); 4472 xEnvironment.SetAttributeValue("Value", value.Substring(0, value.Length - 4));
5362 } 4473 }
5363 } 4474 }
5364 else 4475 else
5365 { 4476 {
5366 environment.Value = value; 4477 xEnvironment.SetAttributeValue("Value", value);
5367 } 4478 }
5368 } 4479 }
5369 4480
5370 var component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[3])); 4481 this.AddChildToParent("Component", xEnvironment, row, 3);
5371 if (null != component)
5372 {
5373 component.AddChild(environment);
5374 }
5375 else
5376 {
5377 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[3]), "Component"));
5378 }
5379 } 4482 }
5380 } 4483 }
5381 4484
@@ -5387,13 +4490,11 @@ namespace WixToolset.Core.WindowsInstaller
5387 { 4490 {
5388 foreach (var row in table.Rows) 4491 foreach (var row in table.Rows)
5389 { 4492 {
5390 var error = new Wix.Error(); 4493 var xError = new XElement(Names.ErrorElement,
4494 new XAttribute("Id", row.FieldAsString(0)),
4495 new XAttribute("Message", row.FieldAsString(1)));
5391 4496
5392 error.Id = Convert.ToInt32(row[0]); 4497 this.UIElement.Add(xError);
5393
5394 error.Content = Convert.ToString(row[1]);
5395
5396 this.core.UIElement.AddChild(error);
5397 } 4498 }
5398 } 4499 }
5399 4500
@@ -5405,20 +4506,17 @@ namespace WixToolset.Core.WindowsInstaller
5405 { 4506 {
5406 foreach (var row in table.Rows) 4507 foreach (var row in table.Rows)
5407 { 4508 {
5408 var subscribe = new Wix.Subscribe(); 4509 var xSubscribe = new XElement(Names.SubscribeElement,
5409 4510 new XAttribute("Event", row.FieldAsString(2)),
5410 subscribe.Event = Convert.ToString(row[2]); 4511 new XAttribute("Attribute", row.FieldAsString(3)));
5411 4512
5412 subscribe.Attribute = Convert.ToString(row[3]); 4513 if (this.TryGetIndexedElement("Control", out var xControl, row.FieldAsString(0), row.FieldAsString(1)))
5413
5414 var control = (Wix.Control)this.core.GetIndexedElement("Control", Convert.ToString(row[0]), Convert.ToString(row[1]));
5415 if (null != control)
5416 { 4514 {
5417 control.AddChild(subscribe); 4515 xControl.Add(xSubscribe);
5418 } 4516 }
5419 else 4517 else
5420 { 4518 {
5421 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Dialog_", Convert.ToString(row[0]), "Control_", Convert.ToString(row[1]), "Control")); 4519 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Dialog_", row.FieldAsString(0), "Control_", row.FieldAsString(1), "Control"));
5422 } 4520 }
5423 } 4521 }
5424 } 4522 }
@@ -5431,54 +4529,32 @@ namespace WixToolset.Core.WindowsInstaller
5431 { 4529 {
5432 foreach (var row in table.Rows) 4530 foreach (var row in table.Rows)
5433 { 4531 {
5434 var extension = new Wix.Extension(); 4532 var xExtension = new XElement(Names.ExtensionElement,
5435 4533 new XAttribute("Id", row.FieldAsString(0)),
5436 extension.Advertise = Wix.YesNoType.yes; 4534 new XAttribute("Advertise", "yes"));
5437 4535
5438 extension.Id = Convert.ToString(row[0]); 4536 if (!row.IsColumnNull(3))
5439
5440 if (null != row[3])
5441 { 4537 {
5442 var mime = (Wix.MIME)this.core.GetIndexedElement("MIME", Convert.ToString(row[3])); 4538 if (this.TryGetIndexedElement("MIME", out var xMime, row.FieldAsString(3)))
5443
5444 if (null != mime)
5445 { 4539 {
5446 mime.Default = Wix.YesNoType.yes; 4540 xMime.SetAttributeValue("Default", "yes");
5447 } 4541 }
5448 else 4542 else
5449 { 4543 {
5450 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "MIME_", Convert.ToString(row[3]), "MIME")); 4544 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "MIME_", row.FieldAsString(3), "MIME"));
5451 } 4545 }
5452 } 4546 }
5453 4547
5454 if (null != row[2]) 4548 if (!row.IsColumnNull(2))
5455 { 4549 {
5456 var progId = (Wix.ProgId)this.core.GetIndexedElement("ProgId", Convert.ToString(row[2])); 4550 this.AddChildToParent("ProgId", xExtension, row, 2);
5457
5458 if (null != progId)
5459 {
5460 progId.AddChild(extension);
5461 }
5462 else
5463 {
5464 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "ProgId_", Convert.ToString(row[2]), "ProgId"));
5465 }
5466 } 4551 }
5467 else 4552 else
5468 { 4553 {
5469 var component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[1])); 4554 this.AddChildToParent("Component", xExtension, row, 1);
5470
5471 if (null != component)
5472 {
5473 component.AddChild(extension);
5474 }
5475 else
5476 {
5477 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[1]), "Component"));
5478 }
5479 } 4555 }
5480 4556
5481 this.core.IndexElement(row, extension); 4557 this.IndexElement(row, xExtension);
5482 } 4558 }
5483 } 4559 }
5484 4560
@@ -5490,56 +4566,42 @@ namespace WixToolset.Core.WindowsInstaller
5490 { 4566 {
5491 foreach (var row in table.Rows) 4567 foreach (var row in table.Rows)
5492 { 4568 {
5493 var externalFile = new Wix.ExternalFile(); 4569 var xExternalFile = new XElement(Names.ExternalFileElement,
5494 4570 new XAttribute("File", row.FieldAsString(1)),
5495 externalFile.File = Convert.ToString(row[1]); 4571 new XAttribute("Source", row.FieldAsString(2)));
5496 4572
5497 externalFile.Source = Convert.ToString(row[2]); 4573 AddSymbolPaths(row, 3, xExternalFile);
5498 4574
5499 if (null != row[3]) 4575 if (!row.IsColumnNull(4) && !row.IsColumnNull(5))
5500 { 4576 {
5501 var symbolPaths = (Convert.ToString(row[3])).Split(';'); 4577 var ignoreOffsets = row.FieldAsString(4).Split(',');
5502 4578 var ignoreLengths = row.FieldAsString(5).Split(',');
5503 foreach (var symbolPathString in symbolPaths)
5504 {
5505 var symbolPath = new Wix.SymbolPath();
5506
5507 symbolPath.Path = symbolPathString;
5508
5509 externalFile.AddChild(symbolPath);
5510 }
5511 }
5512
5513 if (null != row[4] && null != row[5])
5514 {
5515 var ignoreOffsets = (Convert.ToString(row[4])).Split(',');
5516 var ignoreLengths = (Convert.ToString(row[5])).Split(',');
5517 4579
5518 if (ignoreOffsets.Length == ignoreLengths.Length) 4580 if (ignoreOffsets.Length == ignoreLengths.Length)
5519 { 4581 {
5520 for (var i = 0; i < ignoreOffsets.Length; i++) 4582 for (var i = 0; i < ignoreOffsets.Length; i++)
5521 { 4583 {
5522 var ignoreRange = new Wix.IgnoreRange(); 4584 var xIgnoreRange = new XElement(Names.IgnoreRangeElement);
5523 4585
5524 if (ignoreOffsets[i].StartsWith("0x", StringComparison.Ordinal)) 4586 if (ignoreOffsets[i].StartsWith("0x", StringComparison.Ordinal))
5525 { 4587 {
5526 ignoreRange.Offset = Convert.ToInt32(ignoreOffsets[i].Substring(2), 16); 4588 xIgnoreRange.SetAttributeValue("Offset", Convert.ToInt32(ignoreOffsets[i].Substring(2), 16));
5527 } 4589 }
5528 else 4590 else
5529 { 4591 {
5530 ignoreRange.Offset = Convert.ToInt32(ignoreOffsets[i], CultureInfo.InvariantCulture); 4592 xIgnoreRange.SetAttributeValue("Offset", Convert.ToInt32(ignoreOffsets[i], CultureInfo.InvariantCulture));
5531 } 4593 }
5532 4594
5533 if (ignoreLengths[i].StartsWith("0x", StringComparison.Ordinal)) 4595 if (ignoreLengths[i].StartsWith("0x", StringComparison.Ordinal))
5534 { 4596 {
5535 ignoreRange.Length = Convert.ToInt32(ignoreLengths[i].Substring(2), 16); 4597 xIgnoreRange.SetAttributeValue("Length", Convert.ToInt32(ignoreLengths[i].Substring(2), 16));
5536 } 4598 }
5537 else 4599 else
5538 { 4600 {
5539 ignoreRange.Length = Convert.ToInt32(ignoreLengths[i], CultureInfo.InvariantCulture); 4601 xIgnoreRange.SetAttributeValue("Length", Convert.ToInt32(ignoreLengths[i], CultureInfo.InvariantCulture));
5540 } 4602 }
5541 4603
5542 externalFile.AddChild(ignoreRange); 4604 xExternalFile.Add(xIgnoreRange);
5543 } 4605 }
5544 } 4606 }
5545 else 4607 else
@@ -5547,28 +4609,20 @@ namespace WixToolset.Core.WindowsInstaller
5547 // TODO: warn 4609 // TODO: warn
5548 } 4610 }
5549 } 4611 }
5550 else if (null != row[4] || null != row[5]) 4612 else if (!row.IsColumnNull(4) || !row.IsColumnNull(5))
5551 { 4613 {
5552 // TODO: warn about mismatch between columns 4614 // TODO: warn about mismatch between columns
5553 } 4615 }
5554 4616
5555 // the RetainOffsets column is handled in FinalizeFamilyFileRangesTable 4617 // the RetainOffsets column is handled in FinalizeFamilyFileRangesTable
5556 4618
5557 if (null != row[7]) 4619 if (!row.IsColumnNull(7))
5558 { 4620 {
5559 externalFile.Order = Convert.ToInt32(row[7]); 4621 xExternalFile.SetAttributeValue("Order", row.FieldAsInteger(7));
5560 } 4622 }
5561 4623
5562 var family = (Wix.Family)this.core.GetIndexedElement("ImageFamilies", Convert.ToString(row[0])); 4624 this.AddChildToParent("ImageFamilies", xExternalFile, row, 0);
5563 if (null != family) 4625 this.IndexElement(row, xExternalFile);
5564 {
5565 family.AddChild(externalFile);
5566 }
5567 else
5568 {
5569 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Family", Convert.ToString(row[0]), "ImageFamilies"));
5570 }
5571 this.core.IndexElement(row, externalFile);
5572 } 4626 }
5573 } 4627 }
5574 4628
@@ -5578,50 +4632,36 @@ namespace WixToolset.Core.WindowsInstaller
5578 /// <param name="table">The table to decompile.</param> 4632 /// <param name="table">The table to decompile.</param>
5579 private void DecompileFeatureTable(Table table) 4633 private void DecompileFeatureTable(Table table)
5580 { 4634 {
5581 var sortedFeatures = new SortedList(); 4635 var sortedFeatures = new SortedList<string, Row>();
5582 4636
5583 foreach (var row in table.Rows) 4637 foreach (var row in table.Rows)
5584 { 4638 {
5585 var feature = new Wix.Feature(); 4639 var feature = new XElement(Names.FeatureElement,
4640 new XAttribute("Id", row.FieldAsString(0)),
4641 row.IsColumnNull(2) ? null : new XAttribute("Title", row.FieldAsString(2)),
4642 row.IsColumnNull(3) ? null : new XAttribute("Description", row.FieldAsString(3)),
4643 new XAttribute("Level", row.FieldAsInteger(5)),
4644 row.IsColumnNull(6) ? null : new XAttribute("ConfigurableDirectory", row.FieldAsString(6)));
5586 4645
5587 feature.Id = Convert.ToString(row[0]); 4646 if (row.IsColumnNull(4))
5588
5589 if (null != row[2])
5590 { 4647 {
5591 feature.Title = Convert.ToString(row[2]); 4648 feature.SetAttributeValue("Display", "hidden");
5592 }
5593
5594 if (null != row[3])
5595 {
5596 feature.Description = Convert.ToString(row[3]);
5597 }
5598
5599 if (null == row[4])
5600 {
5601 feature.Display = "hidden";
5602 } 4649 }
5603 else 4650 else
5604 { 4651 {
5605 var display = Convert.ToInt32(row[4]); 4652 var display = row.FieldAsInteger(4);
5606 4653
5607 if (0 == display) 4654 if (0 == display)
5608 { 4655 {
5609 feature.Display = "hidden"; 4656 feature.SetAttributeValue("Display", "hidden");
5610 } 4657 }
5611 else if (1 == display % 2) 4658 else if (1 == display % 2)
5612 { 4659 {
5613 feature.Display = "expand"; 4660 feature.SetAttributeValue("Display", "expand");
5614 } 4661 }
5615 } 4662 }
5616 4663
5617 feature.Level = Convert.ToInt32(row[5]); 4664 var attributes = row.FieldAsInteger(7);
5618
5619 if (null != row[6])
5620 {
5621 feature.ConfigurableDirectory = Convert.ToString(row[6]);
5622 }
5623
5624 var attributes = Convert.ToInt32(row[7]);
5625 4665
5626 if (WindowsInstallerConstants.MsidbFeatureAttributesFavorSource == (attributes & WindowsInstallerConstants.MsidbFeatureAttributesFavorSource) && WindowsInstallerConstants.MsidbFeatureAttributesFollowParent == (attributes & WindowsInstallerConstants.MsidbFeatureAttributesFollowParent)) 4666 if (WindowsInstallerConstants.MsidbFeatureAttributesFavorSource == (attributes & WindowsInstallerConstants.MsidbFeatureAttributesFavorSource) && WindowsInstallerConstants.MsidbFeatureAttributesFollowParent == (attributes & WindowsInstallerConstants.MsidbFeatureAttributesFollowParent))
5627 { 4667 {
@@ -5629,68 +4669,69 @@ namespace WixToolset.Core.WindowsInstaller
5629 } 4669 }
5630 else if (WindowsInstallerConstants.MsidbFeatureAttributesFavorSource == (attributes & WindowsInstallerConstants.MsidbFeatureAttributesFavorSource)) 4670 else if (WindowsInstallerConstants.MsidbFeatureAttributesFavorSource == (attributes & WindowsInstallerConstants.MsidbFeatureAttributesFavorSource))
5631 { 4671 {
5632 feature.InstallDefault = Wix.Feature.InstallDefaultType.source; 4672 feature.SetAttributeValue("InstallDefault", "source");
5633 } 4673 }
5634 else if (WindowsInstallerConstants.MsidbFeatureAttributesFollowParent == (attributes & WindowsInstallerConstants.MsidbFeatureAttributesFollowParent)) 4674 else if (WindowsInstallerConstants.MsidbFeatureAttributesFollowParent == (attributes & WindowsInstallerConstants.MsidbFeatureAttributesFollowParent))
5635 { 4675 {
5636 feature.InstallDefault = Wix.Feature.InstallDefaultType.followParent; 4676 feature.SetAttributeValue("InstallDefault", "followParent");
5637 } 4677 }
5638 4678
5639 if (WindowsInstallerConstants.MsidbFeatureAttributesFavorAdvertise == (attributes & WindowsInstallerConstants.MsidbFeatureAttributesFavorAdvertise)) 4679 if (WindowsInstallerConstants.MsidbFeatureAttributesFavorAdvertise == (attributes & WindowsInstallerConstants.MsidbFeatureAttributesFavorAdvertise))
5640 { 4680 {
5641 feature.TypicalDefault = Wix.Feature.TypicalDefaultType.advertise; 4681 feature.SetAttributeValue("InstallDefault", "advertise");
5642 } 4682 }
5643 4683
5644 if (WindowsInstallerConstants.MsidbFeatureAttributesDisallowAdvertise == (attributes & WindowsInstallerConstants.MsidbFeatureAttributesDisallowAdvertise) && 4684 if (WindowsInstallerConstants.MsidbFeatureAttributesDisallowAdvertise == (attributes & WindowsInstallerConstants.MsidbFeatureAttributesDisallowAdvertise) &&
5645 WindowsInstallerConstants.MsidbFeatureAttributesNoUnsupportedAdvertise == (attributes & WindowsInstallerConstants.MsidbFeatureAttributesNoUnsupportedAdvertise)) 4685 WindowsInstallerConstants.MsidbFeatureAttributesNoUnsupportedAdvertise == (attributes & WindowsInstallerConstants.MsidbFeatureAttributesNoUnsupportedAdvertise))
5646 { 4686 {
5647 this.Messaging.Write(WarningMessages.InvalidAttributeCombination(row.SourceLineNumbers, "msidbFeatureAttributesDisallowAdvertise", "msidbFeatureAttributesNoUnsupportedAdvertise", "Feature.AllowAdvertiseType", "no")); 4687 this.Messaging.Write(WarningMessages.InvalidAttributeCombination(row.SourceLineNumbers, "msidbFeatureAttributesDisallowAdvertise", "msidbFeatureAttributesNoUnsupportedAdvertise", "Feature.AllowAdvertiseType", "no"));
5648 feature.AllowAdvertise = Wix.Feature.AllowAdvertiseType.no; 4688 feature.SetAttributeValue("AllowAdvertise", "no");
5649 } 4689 }
5650 else if (WindowsInstallerConstants.MsidbFeatureAttributesDisallowAdvertise == (attributes & WindowsInstallerConstants.MsidbFeatureAttributesDisallowAdvertise)) 4690 else if (WindowsInstallerConstants.MsidbFeatureAttributesDisallowAdvertise == (attributes & WindowsInstallerConstants.MsidbFeatureAttributesDisallowAdvertise))
5651 { 4691 {
5652 feature.AllowAdvertise = Wix.Feature.AllowAdvertiseType.no; 4692 feature.SetAttributeValue("AllowAdvertise", "no");
5653 } 4693 }
5654 else if (WindowsInstallerConstants.MsidbFeatureAttributesNoUnsupportedAdvertise == (attributes & WindowsInstallerConstants.MsidbFeatureAttributesNoUnsupportedAdvertise)) 4694 else if (WindowsInstallerConstants.MsidbFeatureAttributesNoUnsupportedAdvertise == (attributes & WindowsInstallerConstants.MsidbFeatureAttributesNoUnsupportedAdvertise))
5655 { 4695 {
5656 feature.AllowAdvertise = Wix.Feature.AllowAdvertiseType.system; 4696 feature.SetAttributeValue("AllowAdvertise", "system");
5657 } 4697 }
5658 4698
5659 if (WindowsInstallerConstants.MsidbFeatureAttributesUIDisallowAbsent == (attributes & WindowsInstallerConstants.MsidbFeatureAttributesUIDisallowAbsent)) 4699 if (WindowsInstallerConstants.MsidbFeatureAttributesUIDisallowAbsent == (attributes & WindowsInstallerConstants.MsidbFeatureAttributesUIDisallowAbsent))
5660 { 4700 {
5661 feature.Absent = Wix.Feature.AbsentType.disallow; 4701 feature.SetAttributeValue("Absent", "disallow");
5662 } 4702 }
5663 4703
5664 this.core.IndexElement(row, feature); 4704 this.IndexElement(row, feature);
5665 4705
5666 // sort the features by their display column (and append the identifier to ensure unique keys) 4706 // sort the features by their display column (and append the identifier to ensure unique keys)
5667 sortedFeatures.Add(String.Format(CultureInfo.InvariantCulture, "{0:00000}|{1}", Convert.ToInt32(row[4], CultureInfo.InvariantCulture), row[0]), row); 4707 sortedFeatures.Add(String.Format(CultureInfo.InvariantCulture, "{0:00000}|{1}", row.FieldAsInteger(4), row[0]), row);
5668 } 4708 }
5669 4709
5670 // nest the features 4710 // nest the features
5671 foreach (Row row in sortedFeatures.Values) 4711 foreach (var row in sortedFeatures.Values)
5672 { 4712 {
5673 var feature = (Wix.Feature)this.core.GetIndexedElement("Feature", Convert.ToString(row[0])); 4713 var xFeature = this.GetIndexedElement("Feature", row.FieldAsString(0));
5674 4714
5675 if (null == row[1]) 4715 if (row.IsColumnNull(1))
5676 { 4716 {
5677 this.core.RootElement.AddChild(feature); 4717 this.RootElement.Add(xFeature);
5678 } 4718 }
5679 else 4719 else
5680 { 4720 {
5681 var parentFeature = (Wix.Feature)this.core.GetIndexedElement("Feature", Convert.ToString(row[1])); 4721 if (this.TryGetIndexedElement("Feature", out var xParentFeature, row.FieldAsString(1)))
5682
5683 if (null == parentFeature)
5684 {
5685 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Feature_Parent", Convert.ToString(row[1]), "Feature"));
5686 }
5687 else if (parentFeature == feature)
5688 { 4722 {
5689 // TODO: display a warning about self-nesting 4723 if (xParentFeature == xFeature)
4724 {
4725 // TODO: display a warning about self-nesting
4726 }
4727 else
4728 {
4729 xParentFeature.Add(xFeature);
4730 }
5690 } 4731 }
5691 else 4732 else
5692 { 4733 {
5693 parentFeature.AddChild(feature); 4734 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Feature_Parent", row.FieldAsString(1), "Feature"));
5694 } 4735 }
5695 } 4736 }
5696 } 4737 }
@@ -5704,20 +4745,11 @@ namespace WixToolset.Core.WindowsInstaller
5704 { 4745 {
5705 foreach (var row in table.Rows) 4746 foreach (var row in table.Rows)
5706 { 4747 {
5707 var componentRef = new Wix.ComponentRef(); 4748 var xComponentRef = new XElement(Names.ComponentRefElement,
5708 4749 new XAttribute("Id", row.FieldAsString(1)));
5709 componentRef.Id = Convert.ToString(row[1]);
5710 4750
5711 var parentFeature = (Wix.Feature)this.core.GetIndexedElement("Feature", Convert.ToString(row[0])); 4751 this.AddChildToParent("Feature", xComponentRef, row, 0);
5712 if (null != parentFeature) 4752 this.IndexElement(row, xComponentRef);
5713 {
5714 parentFeature.AddChild(componentRef);
5715 }
5716 else
5717 {
5718 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Feature_", Convert.ToString(row[0]), "Feature"));
5719 }
5720 this.core.IndexElement(row, componentRef);
5721 } 4753 }
5722 } 4754 }
5723 4755
@@ -5729,52 +4761,24 @@ namespace WixToolset.Core.WindowsInstaller
5729 { 4761 {
5730 foreach (FileRow fileRow in table.Rows) 4762 foreach (FileRow fileRow in table.Rows)
5731 { 4763 {
5732 var file = new Wix.File(); 4764 var xFile = new XElement(Names.FileElement,
5733 4765 new XAttribute("Id", fileRow.File),
5734 file.Id = fileRow.File; 4766 WindowsInstallerConstants.MsidbFileAttributesReadOnly == (fileRow.Attributes & WindowsInstallerConstants.MsidbFileAttributesReadOnly) ? new XAttribute("ReadOnly", "yes") : null,
4767 WindowsInstallerConstants.MsidbFileAttributesHidden == (fileRow.Attributes & WindowsInstallerConstants.MsidbFileAttributesHidden) ? new XAttribute("Hidden", "yes") : null,
4768 WindowsInstallerConstants.MsidbFileAttributesSystem == (fileRow.Attributes & WindowsInstallerConstants.MsidbFileAttributesSystem) ? new XAttribute("System", "yes") : null,
4769 WindowsInstallerConstants.MsidbFileAttributesChecksum == (fileRow.Attributes & WindowsInstallerConstants.MsidbFileAttributesChecksum) ? new XAttribute("Checksum", "yes") : null,
4770 WindowsInstallerConstants.MsidbFileAttributesVital != (fileRow.Attributes & WindowsInstallerConstants.MsidbFileAttributesVital) ? new XAttribute("Vital", "no") : null,
4771 null != fileRow.Version && 0 < fileRow.Version.Length && !Char.IsDigit(fileRow.Version[0]) ? new XAttribute("CompanionFile", fileRow.Version) : null);
5735 4772
5736 var names = Common.GetNames(fileRow.FileName); 4773 var names = Common.GetNames(fileRow.FileName);
5737 if (null != names[0] && null != names[1]) 4774 if (null != names[0] && null != names[1])
5738 { 4775 {
5739 file.ShortName = names[0]; 4776 xFile.SetAttributeValue("ShortName", names[0]);
5740 file.Name = names[1]; 4777 xFile.SetAttributeValue("Name", names[1]);
5741 } 4778 }
5742 else if (null != names[0]) 4779 else if (null != names[0])
5743 { 4780 {
5744 file.Name = names[0]; 4781 xFile.SetAttributeValue("Name", names[0]);
5745 }
5746
5747 if (null != fileRow.Version && 0 < fileRow.Version.Length)
5748 {
5749 if (!Char.IsDigit(fileRow.Version[0]))
5750 {
5751 file.CompanionFile = fileRow.Version;
5752 }
5753 }
5754
5755 if (WindowsInstallerConstants.MsidbFileAttributesReadOnly == (fileRow.Attributes & WindowsInstallerConstants.MsidbFileAttributesReadOnly))
5756 {
5757 file.ReadOnly = Wix.YesNoType.yes;
5758 }
5759
5760 if (WindowsInstallerConstants.MsidbFileAttributesHidden == (fileRow.Attributes & WindowsInstallerConstants.MsidbFileAttributesHidden))
5761 {
5762 file.Hidden = Wix.YesNoType.yes;
5763 }
5764
5765 if (WindowsInstallerConstants.MsidbFileAttributesSystem == (fileRow.Attributes & WindowsInstallerConstants.MsidbFileAttributesSystem))
5766 {
5767 file.System = Wix.YesNoType.yes;
5768 }
5769
5770 if (WindowsInstallerConstants.MsidbFileAttributesVital != (fileRow.Attributes & WindowsInstallerConstants.MsidbFileAttributesVital))
5771 {
5772 file.Vital = Wix.YesNoType.no;
5773 }
5774
5775 if (WindowsInstallerConstants.MsidbFileAttributesChecksum == (fileRow.Attributes & WindowsInstallerConstants.MsidbFileAttributesChecksum))
5776 {
5777 file.Checksum = Wix.YesNoType.yes;
5778 } 4782 }
5779 4783
5780 if (WindowsInstallerConstants.MsidbFileAttributesNoncompressed == (fileRow.Attributes & WindowsInstallerConstants.MsidbFileAttributesNoncompressed) && 4784 if (WindowsInstallerConstants.MsidbFileAttributesNoncompressed == (fileRow.Attributes & WindowsInstallerConstants.MsidbFileAttributesNoncompressed) &&
@@ -5784,14 +4788,14 @@ namespace WixToolset.Core.WindowsInstaller
5784 } 4788 }
5785 else if (WindowsInstallerConstants.MsidbFileAttributesNoncompressed == (fileRow.Attributes & WindowsInstallerConstants.MsidbFileAttributesNoncompressed)) 4789 else if (WindowsInstallerConstants.MsidbFileAttributesNoncompressed == (fileRow.Attributes & WindowsInstallerConstants.MsidbFileAttributesNoncompressed))
5786 { 4790 {
5787 file.Compressed = Wix.YesNoDefaultType.no; 4791 xFile.SetAttributeValue("Compressed", "no");
5788 } 4792 }
5789 else if (WindowsInstallerConstants.MsidbFileAttributesCompressed == (fileRow.Attributes & WindowsInstallerConstants.MsidbFileAttributesCompressed)) 4793 else if (WindowsInstallerConstants.MsidbFileAttributesCompressed == (fileRow.Attributes & WindowsInstallerConstants.MsidbFileAttributesCompressed))
5790 { 4794 {
5791 file.Compressed = Wix.YesNoDefaultType.yes; 4795 xFile.SetAttributeValue("Compressed", "yes");
5792 } 4796 }
5793 4797
5794 this.core.IndexElement(fileRow, file); 4798 this.IndexElement(fileRow, xFile);
5795 } 4799 }
5796 } 4800 }
5797 4801
@@ -5803,19 +4807,10 @@ namespace WixToolset.Core.WindowsInstaller
5803 { 4807 {
5804 foreach (var row in table.Rows) 4808 foreach (var row in table.Rows)
5805 { 4809 {
5806 var sfpFile = new Wix.SFPFile(); 4810 var xSfpFile = new XElement(Names.SFPFileElement,
5807 4811 new XAttribute("Id", row.FieldAsString(0)));
5808 sfpFile.Id = Convert.ToString(row[0]);
5809 4812
5810 var sfpCatalog = (Wix.SFPCatalog)this.core.GetIndexedElement("SFPCatalog", Convert.ToString(row[1])); 4813 this.AddChildToParent("SFPCatalog", xSfpFile, row, 1);
5811 if (null != sfpCatalog)
5812 {
5813 sfpCatalog.AddChild(sfpFile);
5814 }
5815 else
5816 {
5817 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "SFPCatalog_", Convert.ToString(row[1]), "SFPCatalog"));
5818 }
5819 } 4814 }
5820 } 4815 }
5821 4816
@@ -5827,22 +4822,20 @@ namespace WixToolset.Core.WindowsInstaller
5827 { 4822 {
5828 foreach (var row in table.Rows) 4823 foreach (var row in table.Rows)
5829 { 4824 {
5830 var file = (Wix.File)this.core.GetIndexedElement("File", Convert.ToString(row[0])); 4825 if (this.TryGetIndexedElement("File", out var xFile, row.FieldAsString(0)))
5831
5832 if (null != file)
5833 { 4826 {
5834 if (null != row[1]) 4827 if (!row.IsColumnNull(1))
5835 { 4828 {
5836 file.FontTitle = Convert.ToString(row[1]); 4829 xFile.SetAttributeValue("FontTitle", row.FieldAsString(1));
5837 } 4830 }
5838 else 4831 else
5839 { 4832 {
5840 file.TrueType = Wix.YesNoType.yes; 4833 xFile.SetAttributeValue("TrueType", "yes");
5841 } 4834 }
5842 } 4835 }
5843 else 4836 else
5844 { 4837 {
5845 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "File_", Convert.ToString(row[0]), "File")); 4838 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "File_", row.FieldAsString(0), "File"));
5846 } 4839 }
5847 } 4840 }
5848 } 4841 }
@@ -5855,13 +4848,11 @@ namespace WixToolset.Core.WindowsInstaller
5855 { 4848 {
5856 foreach (var row in table.Rows) 4849 foreach (var row in table.Rows)
5857 { 4850 {
5858 var icon = new Wix.Icon(); 4851 var icon = new XElement(Names.IconElement,
5859 4852 new XAttribute("Id", row.FieldAsString(0)),
5860 icon.Id = Convert.ToString(row[0]); 4853 new XAttribute("SourceFile", row.FieldAsString(1)));
5861 4854
5862 icon.SourceFile = Convert.ToString(row[1]); 4855 this.RootElement.Add(icon);
5863
5864 this.core.RootElement.AddChild(icon);
5865 } 4856 }
5866 } 4857 }
5867 4858
@@ -5873,37 +4864,16 @@ namespace WixToolset.Core.WindowsInstaller
5873 { 4864 {
5874 foreach (var row in table.Rows) 4865 foreach (var row in table.Rows)
5875 { 4866 {
5876 var family = new Wix.Family(); 4867 var family = new XElement(Names.FamilyElement,
5877 4868 new XAttribute("Name", row.FieldAsString(0)),
5878 family.Name = Convert.ToString(row[0]); 4869 row.IsColumnNull(1) ? null : new XAttribute("MediaSrcProp", row.FieldAsString(1)),
5879 4870 row.IsColumnNull(2) ? null : new XAttribute("DiskId", row.FieldAsString(2)),
5880 if (null != row[1]) 4871 row.IsColumnNull(3) ? null : new XAttribute("SequenceStart", row.FieldAsString(3)),
5881 { 4872 row.IsColumnNull(4) ? null : new XAttribute("DiskPrompt", row.FieldAsString(4)),
5882 family.MediaSrcProp = Convert.ToString(row[1]); 4873 row.IsColumnNull(5) ? null : new XAttribute("VolumeLabel", row.FieldAsString(5)));
5883 }
5884 4874
5885 if (null != row[2]) 4875 this.RootElement.Add(family);
5886 { 4876 this.IndexElement(row, family);
5887 family.DiskId = Convert.ToString(Convert.ToInt32(row[2]));
5888 }
5889
5890 if (null != row[3])
5891 {
5892 family.SequenceStart = Convert.ToInt32(row[3]);
5893 }
5894
5895 if (null != row[4])
5896 {
5897 family.DiskPrompt = Convert.ToString(row[4]);
5898 }
5899
5900 if (null != row[5])
5901 {
5902 family.VolumeLabel = Convert.ToString(row[5]);
5903 }
5904
5905 this.core.RootElement.AddChild(family);
5906 this.core.IndexElement(row, family);
5907 } 4877 }
5908 } 4878 }
5909 4879
@@ -5915,65 +4885,49 @@ namespace WixToolset.Core.WindowsInstaller
5915 { 4885 {
5916 foreach (var row in table.Rows) 4886 foreach (var row in table.Rows)
5917 { 4887 {
5918 var iniFile = new Wix.IniFile(); 4888 var xIniFile = new XElement(Names.IniFileElement,
5919 4889 new XAttribute("Id", row.FieldAsString(0)),
5920 iniFile.Id = Convert.ToString(row[0]); 4890 new XAttribute("Section", row.FieldAsString(3)),
4891 new XAttribute("Key", row.FieldAsString(4)),
4892 new XAttribute("Value", row.FieldAsString(5)),
4893 row.IsColumnNull(2) ? null : new XAttribute("Directory", row.FieldAsString(2)));
5921 4894
5922 var names = Common.GetNames(Convert.ToString(row[1])); 4895 var names = Common.GetNames(row.FieldAsString(1));
5923 4896
5924 if (null != names[0]) 4897 if (null != names[0])
5925 { 4898 {
5926 if (null == names[1]) 4899 if (null == names[1])
5927 { 4900 {
5928 iniFile.Name = names[0]; 4901 xIniFile.SetAttributeValue("Name", names[0]);
5929 } 4902 }
5930 else 4903 else
5931 { 4904 {
5932 iniFile.ShortName = names[0]; 4905 xIniFile.SetAttributeValue("ShortName", names[0]);
5933 } 4906 }
5934 } 4907 }
5935 4908
5936 if (null != names[1]) 4909 if (null != names[1])
5937 { 4910 {
5938 iniFile.Name = names[1]; 4911 xIniFile.SetAttributeValue("Name", names[1]);
5939 }
5940
5941 if (null != row[2])
5942 {
5943 iniFile.Directory = Convert.ToString(row[2]);
5944 } 4912 }
5945 4913
5946 iniFile.Section = Convert.ToString(row[3]); 4914 switch (row.FieldAsInteger(6))
5947
5948 iniFile.Key = Convert.ToString(row[4]);
5949
5950 iniFile.Value = Convert.ToString(row[5]);
5951
5952 switch (Convert.ToInt32(row[6]))
5953 { 4915 {
5954 case WindowsInstallerConstants.MsidbIniFileActionAddLine: 4916 case WindowsInstallerConstants.MsidbIniFileActionAddLine:
5955 iniFile.Action = Wix.IniFile.ActionType.addLine; 4917 xIniFile.SetAttributeValue("Action", "addLine");
5956 break; 4918 break;
5957 case WindowsInstallerConstants.MsidbIniFileActionCreateLine: 4919 case WindowsInstallerConstants.MsidbIniFileActionCreateLine:
5958 iniFile.Action = Wix.IniFile.ActionType.createLine; 4920 xIniFile.SetAttributeValue("Action", "createLine");
5959 break; 4921 break;
5960 case WindowsInstallerConstants.MsidbIniFileActionAddTag: 4922 case WindowsInstallerConstants.MsidbIniFileActionAddTag:
5961 iniFile.Action = Wix.IniFile.ActionType.addTag; 4923 xIniFile.SetAttributeValue("Action", "addTag");
5962 break; 4924 break;
5963 default: 4925 default:
5964 this.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[6].Column.Name, row[6])); 4926 this.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[6].Column.Name, row[6]));
5965 break; 4927 break;
5966 } 4928 }
5967 4929
5968 var component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[7])); 4930 this.AddChildToParent("Component", xIniFile, row, 7);
5969 if (null != component)
5970 {
5971 component.AddChild(iniFile);
5972 }
5973 else
5974 {
5975 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[7]), "Component"));
5976 }
5977 } 4931 }
5978 } 4932 }
5979 4933
@@ -5985,55 +4939,43 @@ namespace WixToolset.Core.WindowsInstaller
5985 { 4939 {
5986 foreach (var row in table.Rows) 4940 foreach (var row in table.Rows)
5987 { 4941 {
5988 var iniFileSearch = new Wix.IniFileSearch(); 4942 var xIniFileSearch = new XElement(Names.IniFileSearchElement,
5989 4943 new XAttribute("Id", row.FieldAsString(0)),
5990 iniFileSearch.Id = Convert.ToString(row[0]); 4944 new XAttribute("Section", row.FieldAsString(2)),
4945 new XAttribute("Key", row.FieldAsString(3)),
4946 row.IsColumnNull(4) || row.FieldAsInteger(4) == 0 ? null : new XAttribute("Field", row.FieldAsInteger(4)));
5991 4947
5992 var names = Common.GetNames(Convert.ToString(row[1])); 4948 var names = Common.GetNames(row.FieldAsString(1));
5993 if (null != names[0] && null != names[1]) 4949 if (null != names[0] && null != names[1])
5994 { 4950 {
5995 iniFileSearch.ShortName = names[0]; 4951 xIniFileSearch.SetAttributeValue("ShortName", names[0]);
5996 iniFileSearch.Name = names[1]; 4952 xIniFileSearch.SetAttributeValue("Name", names[1]);
5997 } 4953 }
5998 else if (null != names[0]) 4954 else if (null != names[0])
5999 { 4955 {
6000 iniFileSearch.Name = names[0]; 4956 xIniFileSearch.SetAttributeValue("Name", names[0]);
6001 } 4957 }
6002 4958
6003 iniFileSearch.Section = Convert.ToString(row[2]); 4959 if (!row.IsColumnNull(5))
6004
6005 iniFileSearch.Key = Convert.ToString(row[3]);
6006
6007 if (null != row[4])
6008 { 4960 {
6009 var field = Convert.ToInt32(row[4]); 4961 switch (row.FieldAsInteger(5))
6010
6011 if (0 != field)
6012 { 4962 {
6013 iniFileSearch.Field = field; 4963 case WindowsInstallerConstants.MsidbLocatorTypeDirectory:
6014 } 4964 xIniFileSearch.SetAttributeValue("Type", "directory");
6015 } 4965 break;
6016 4966 case WindowsInstallerConstants.MsidbLocatorTypeFileName:
6017 if (null != row[5]) 4967 // this is the default value
6018 { 4968 break;
6019 switch (Convert.ToInt32(row[5])) 4969 case WindowsInstallerConstants.MsidbLocatorTypeRawValue:
6020 { 4970 xIniFileSearch.SetAttributeValue("Type", "raw");
6021 case WindowsInstallerConstants.MsidbLocatorTypeDirectory: 4971 break;
6022 iniFileSearch.Type = Wix.IniFileSearch.TypeType.directory; 4972 default:
6023 break; 4973 this.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[5].Column.Name, row[5]));
6024 case WindowsInstallerConstants.MsidbLocatorTypeFileName: 4974 break;
6025 // this is the default value
6026 break;
6027 case WindowsInstallerConstants.MsidbLocatorTypeRawValue:
6028 iniFileSearch.Type = Wix.IniFileSearch.TypeType.raw;
6029 break;
6030 default:
6031 this.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[5].Column.Name, row[5]));
6032 break;
6033 } 4975 }
6034 } 4976 }
6035 4977
6036 this.core.IndexElement(row, iniFileSearch); 4978 this.IndexElement(row, xIniFileSearch);
6037 } 4979 }
6038 } 4980 }
6039 4981
@@ -6045,19 +4987,10 @@ namespace WixToolset.Core.WindowsInstaller
6045 { 4987 {
6046 foreach (var row in table.Rows) 4988 foreach (var row in table.Rows)
6047 { 4989 {
6048 var isolateComponent = new Wix.IsolateComponent(); 4990 var xIsolateComponent = new XElement(Names.IsolateComponentElement,
4991 new XAttribute("Shared", row.FieldAsString(0)));
6049 4992
6050 isolateComponent.Shared = Convert.ToString(row[0]); 4993 this.AddChildToParent("Component", xIsolateComponent, row, 1);
6051
6052 var component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[1]));
6053 if (null != component)
6054 {
6055 component.AddChild(isolateComponent);
6056 }
6057 else
6058 {
6059 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[1]), "Component"));
6060 }
6061 } 4994 }
6062 } 4995 }
6063 4996
@@ -6069,18 +5002,16 @@ namespace WixToolset.Core.WindowsInstaller
6069 { 5002 {
6070 foreach (var row in table.Rows) 5003 foreach (var row in table.Rows)
6071 { 5004 {
6072 if (Common.DowngradePreventedCondition == Convert.ToString(row[0]) || Common.UpgradePreventedCondition == Convert.ToString(row[0])) 5005 if (Common.DowngradePreventedCondition == row.FieldAsString(0) || Common.UpgradePreventedCondition == row.FieldAsString(0))
6073 { 5006 {
6074 continue; // MajorUpgrade rows processed in FinalizeUpgradeTable 5007 continue; // MajorUpgrade rows processed in FinalizeUpgradeTable
6075 } 5008 }
6076 5009
6077 var condition = new Wix.Condition(); 5010 var condition = new XElement(Names.LaunchElement,
6078 5011 new XAttribute("Condition", row.FieldAsString(0)),
6079 condition.Content = Convert.ToString(row[0]); 5012 new XAttribute("Message", row.FieldAsString(1)));
6080
6081 condition.Message = Convert.ToString(row[1]);
6082 5013
6083 this.core.RootElement.AddChild(condition); 5014 this.RootElement.Add(condition);
6084 } 5015 }
6085 } 5016 }
6086 5017
@@ -6090,36 +5021,25 @@ namespace WixToolset.Core.WindowsInstaller
6090 /// <param name="table">The table to decompile.</param> 5021 /// <param name="table">The table to decompile.</param>
6091 private void DecompileListBoxTable(Table table) 5022 private void DecompileListBoxTable(Table table)
6092 { 5023 {
6093 Wix.ListBox listBox = null;
6094 var listBoxRows = new SortedList();
6095
6096 // sort the list boxes by their property and order 5024 // sort the list boxes by their property and order
6097 foreach (var row in table.Rows) 5025 var listBoxRows = table.Rows.OrderBy(row => row.FieldAsString(0)).ThenBy(row => row.FieldAsInteger(1)).ToList();
6098 {
6099 listBoxRows.Add(String.Concat("{0}|{1:0000000000}", row[0], row[1]), row);
6100 }
6101 5026
6102 foreach (Row row in listBoxRows.Values) 5027 XElement xListBox = null;
5028 foreach (Row row in listBoxRows)
6103 { 5029 {
6104 if (null == listBox || Convert.ToString(row[0]) != listBox.Property) 5030 if (null == xListBox || row.FieldAsString(0) != xListBox.Attribute("Property")?.Value)
6105 { 5031 {
6106 listBox = new Wix.ListBox(); 5032 xListBox = new XElement(Names.ListBoxElement,
6107 5033 new XAttribute("Property", row.FieldAsString(0)));
6108 listBox.Property = Convert.ToString(row[0]);
6109 5034
6110 this.core.UIElement.AddChild(listBox); 5035 this.UIElement.Add(xListBox);
6111 } 5036 }
6112 5037
6113 var listItem = new Wix.ListItem(); 5038 var listItem = new XElement(Names.ListItemElement,
6114 5039 new XAttribute("Value", row.FieldAsString(2)),
6115 listItem.Value = Convert.ToString(row[2]); 5040 row.IsColumnNull(3) ? null : new XAttribute("Text", row.FieldAsString(3)));
6116 5041
6117 if (null != row[3]) 5042 xListBox.Add(listItem);
6118 {
6119 listItem.Text = Convert.ToString(row[3]);
6120 }
6121
6122 listBox.AddChild(listItem);
6123 } 5043 }
6124 } 5044 }
6125 5045
@@ -6129,41 +5049,26 @@ namespace WixToolset.Core.WindowsInstaller
6129 /// <param name="table">The table to decompile.</param> 5049 /// <param name="table">The table to decompile.</param>
6130 private void DecompileListViewTable(Table table) 5050 private void DecompileListViewTable(Table table)
6131 { 5051 {
6132 Wix.ListView listView = null;
6133 var listViewRows = new SortedList();
6134
6135 // sort the list views by their property and order 5052 // sort the list views by their property and order
6136 foreach (var row in table.Rows) 5053 var listViewRows = table.Rows.OrderBy(row => row.FieldAsString(0)).ThenBy(row => row.FieldAsInteger(1)).ToList();
6137 {
6138 listViewRows.Add(String.Concat("{0}|{1:0000000000}", row[0], row[1]), row);
6139 }
6140 5054
6141 foreach (Row row in listViewRows.Values) 5055 XElement xListView = null;
5056 foreach (var row in listViewRows)
6142 { 5057 {
6143 if (null == listView || Convert.ToString(row[0]) != listView.Property) 5058 if (null == xListView || row.FieldAsString(0) != xListView.Attribute("Property")?.Value)
6144 { 5059 {
6145 listView = new Wix.ListView(); 5060 xListView = new XElement(Names.ListViewElement,
5061 new XAttribute("Property", row.FieldAsString(0)));
6146 5062
6147 listView.Property = Convert.ToString(row[0]); 5063 this.UIElement.Add(xListView);
6148
6149 this.core.UIElement.AddChild(listView);
6150 } 5064 }
6151 5065
6152 var listItem = new Wix.ListItem(); 5066 var listItem = new XElement(Names.ListItemElement,
6153 5067 new XAttribute("Value", row.FieldAsString(2)),
6154 listItem.Value = Convert.ToString(row[2]); 5068 row.IsColumnNull(3) ? null : new XAttribute("Text", row.FieldAsString(3)),
6155 5069 row.IsColumnNull(4) ? null : new XAttribute("Icon", row.FieldAsString(4)));
6156 if (null != row[3])
6157 {
6158 listItem.Text = Convert.ToString(row[3]);
6159 }
6160 5070
6161 if (null != row[4]) 5071 xListView.Add(listItem);
6162 {
6163 listItem.Icon = Convert.ToString(row[4]);
6164 }
6165
6166 listView.AddChild(listItem);
6167 } 5072 }
6168 } 5073 }
6169 5074
@@ -6175,26 +5080,29 @@ namespace WixToolset.Core.WindowsInstaller
6175 { 5080 {
6176 foreach (var row in table.Rows) 5081 foreach (var row in table.Rows)
6177 { 5082 {
6178 var permission = new Wix.Permission(); 5083 var xPermission = new XElement(Names.PermissionElement,
5084 row.IsColumnNull(2) ? null : new XAttribute("Domain", row.FieldAsString(2)),
5085 new XAttribute("User", row.FieldAsString(3)));
5086
6179 string[] specialPermissions; 5087 string[] specialPermissions;
6180 5088
6181 switch (Convert.ToString(row[1])) 5089 switch (row.FieldAsString(1))
6182 { 5090 {
6183 case "CreateFolder": 5091 case "CreateFolder":
6184 specialPermissions = Common.FolderPermissions; 5092 specialPermissions = Common.FolderPermissions;
6185 break; 5093 break;
6186 case "File": 5094 case "File":
6187 specialPermissions = Common.FilePermissions; 5095 specialPermissions = Common.FilePermissions;
6188 break; 5096 break;
6189 case "Registry": 5097 case "Registry":
6190 specialPermissions = Common.RegistryPermissions; 5098 specialPermissions = Common.RegistryPermissions;
6191 break; 5099 break;
6192 default: 5100 default:
6193 this.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, row.Table.Name, row.Fields[1].Column.Name, row[1])); 5101 this.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, row.Table.Name, row.Fields[1].Column.Name, row[1]));
6194 return; 5102 return;
6195 } 5103 }
6196 5104
6197 var permissionBits = Convert.ToInt32(row[4]); 5105 var permissionBits = row.FieldAsInteger(4);
6198 for (var i = 0; i < 32; i++) 5106 for (var i = 0; i < 32; i++)
6199 { 5107 {
6200 if (0 != ((permissionBits >> i) & 1)) 5108 if (0 != ((permissionBits >> i) & 1))
@@ -6226,102 +5134,43 @@ namespace WixToolset.Core.WindowsInstaller
6226 { 5134 {
6227 switch (name) 5135 switch (name)
6228 { 5136 {
6229 case "Append": 5137 case "Append":
6230 permission.Append = Wix.YesNoType.yes; 5138 case "ChangePermission":
6231 break; 5139 case "CreateChild":
6232 case "ChangePermission": 5140 case "CreateFile":
6233 permission.ChangePermission = Wix.YesNoType.yes; 5141 case "CreateLink":
6234 break; 5142 case "CreateSubkeys":
6235 case "CreateChild": 5143 case "Delete":
6236 permission.CreateChild = Wix.YesNoType.yes; 5144 case "DeleteChild":
6237 break; 5145 case "EnumerateSubkeys":
6238 case "CreateFile": 5146 case "Execute":
6239 permission.CreateFile = Wix.YesNoType.yes; 5147 case "FileAllRights":
6240 break; 5148 case "GenericAll":
6241 case "CreateLink": 5149 case "GenericExecute":
6242 permission.CreateLink = Wix.YesNoType.yes; 5150 case "GenericRead":
6243 break; 5151 case "GenericWrite":
6244 case "CreateSubkeys": 5152 case "Notify":
6245 permission.CreateSubkeys = Wix.YesNoType.yes; 5153 case "Read":
6246 break; 5154 case "ReadAttributes":
6247 case "Delete": 5155 case "ReadExtendedAttributes":
6248 permission.Delete = Wix.YesNoType.yes; 5156 case "ReadPermission":
6249 break; 5157 case "SpecificRightsAll":
6250 case "DeleteChild": 5158 case "Synchronize":
6251 permission.DeleteChild = Wix.YesNoType.yes; 5159 case "TakeOwnership":
6252 break; 5160 case "Traverse":
6253 case "EnumerateSubkeys": 5161 case "Write":
6254 permission.EnumerateSubkeys = Wix.YesNoType.yes; 5162 case "WriteAttributes":
6255 break; 5163 case "WriteExtendedAttributes":
6256 case "Execute": 5164 xPermission.SetAttributeValue(name, "yes");
6257 permission.Execute = Wix.YesNoType.yes; 5165 break;
6258 break; 5166 default:
6259 case "FileAllRights": 5167 throw new InvalidOperationException($"Unknown permission attribute '{name}'.");
6260 permission.FileAllRights = Wix.YesNoType.yes;
6261 break;
6262 case "GenericAll":
6263 permission.GenericAll = Wix.YesNoType.yes;
6264 break;
6265 case "GenericExecute":
6266 permission.GenericExecute = Wix.YesNoType.yes;
6267 break;
6268 case "GenericRead":
6269 permission.GenericRead = Wix.YesNoType.yes;
6270 break;
6271 case "GenericWrite":
6272 permission.GenericWrite = Wix.YesNoType.yes;
6273 break;
6274 case "Notify":
6275 permission.Notify = Wix.YesNoType.yes;
6276 break;
6277 case "Read":
6278 permission.Read = Wix.YesNoType.yes;
6279 break;
6280 case "ReadAttributes":
6281 permission.ReadAttributes = Wix.YesNoType.yes;
6282 break;
6283 case "ReadExtendedAttributes":
6284 permission.ReadExtendedAttributes = Wix.YesNoType.yes;
6285 break;
6286 case "ReadPermission":
6287 permission.ReadPermission = Wix.YesNoType.yes;
6288 break;
6289 case "SpecificRightsAll":
6290 permission.SpecificRightsAll = Wix.YesNoType.yes;
6291 break;
6292 case "Synchronize":
6293 permission.Synchronize = Wix.YesNoType.yes;
6294 break;
6295 case "TakeOwnership":
6296 permission.TakeOwnership = Wix.YesNoType.yes;
6297 break;
6298 case "Traverse":
6299 permission.Traverse = Wix.YesNoType.yes;
6300 break;
6301 case "Write":
6302 permission.Write = Wix.YesNoType.yes;
6303 break;
6304 case "WriteAttributes":
6305 permission.WriteAttributes = Wix.YesNoType.yes;
6306 break;
6307 case "WriteExtendedAttributes":
6308 permission.WriteExtendedAttributes = Wix.YesNoType.yes;
6309 break;
6310 default:
6311 throw new InvalidOperationException($"Unknown permission attribute '{name}'.");
6312 } 5168 }
6313 } 5169 }
6314 } 5170 }
6315 } 5171 }
6316 5172
6317 if (null != row[2]) 5173 this.IndexElement(row, xPermission);
6318 {
6319 permission.Domain = Convert.ToString(row[2]);
6320 }
6321
6322 permission.User = Convert.ToString(row[3]);
6323
6324 this.core.IndexElement(row, permission);
6325 } 5174 }
6326 } 5175 }
6327 5176
@@ -6333,14 +5182,10 @@ namespace WixToolset.Core.WindowsInstaller
6333 { 5182 {
6334 foreach (MediaRow mediaRow in table.Rows) 5183 foreach (MediaRow mediaRow in table.Rows)
6335 { 5184 {
6336 var media = new Wix.Media(); 5185 var xMedia = new XElement(Names.MediaElement,
6337 5186 new XAttribute("Id", mediaRow.DiskId),
6338 media.Id = Convert.ToString(mediaRow.DiskId); 5187 mediaRow.DiskPrompt == null ? null : new XAttribute("DiskPrompt", mediaRow.DiskPrompt),
6339 5188 mediaRow.VolumeLabel == null ? null : new XAttribute("VolumeLabel", mediaRow.VolumeLabel));
6340 if (null != mediaRow.DiskPrompt)
6341 {
6342 media.DiskPrompt = mediaRow.DiskPrompt;
6343 }
6344 5189
6345 if (null != mediaRow.Cabinet) 5190 if (null != mediaRow.Cabinet)
6346 { 5191 {
@@ -6348,20 +5193,15 @@ namespace WixToolset.Core.WindowsInstaller
6348 5193
6349 if (cabinet.StartsWith("#", StringComparison.Ordinal)) 5194 if (cabinet.StartsWith("#", StringComparison.Ordinal))
6350 { 5195 {
6351 media.EmbedCab = Wix.YesNoType.yes; 5196 xMedia.SetAttributeValue("EmbedCab", "yes");
6352 cabinet = cabinet.Substring(1); 5197 cabinet = cabinet.Substring(1);
6353 } 5198 }
6354 5199
6355 media.Cabinet = cabinet; 5200 xMedia.SetAttributeValue("Cabinet", cabinet);
6356 }
6357
6358 if (null != mediaRow.VolumeLabel)
6359 {
6360 media.VolumeLabel = mediaRow.VolumeLabel;
6361 } 5201 }
6362 5202
6363 this.core.RootElement.AddChild(media); 5203 this.RootElement.Add(xMedia);
6364 this.core.IndexElement(mediaRow, media); 5204 this.IndexElement(mediaRow, xMedia);
6365 } 5205 }
6366 } 5206 }
6367 5207
@@ -6373,16 +5213,11 @@ namespace WixToolset.Core.WindowsInstaller
6373 { 5213 {
6374 foreach (var row in table.Rows) 5214 foreach (var row in table.Rows)
6375 { 5215 {
6376 var mime = new Wix.MIME(); 5216 var mime = new XElement(Names.MIMEElement,
6377 5217 new XAttribute("ContentType", row.FieldAsString(0)),
6378 mime.ContentType = Convert.ToString(row[0]); 5218 row.IsColumnNull(2) ? null : new XAttribute("Class", row.FieldAsString(2)));
6379
6380 if (null != row[2])
6381 {
6382 mime.Class = Convert.ToString(row[2]);
6383 }
6384 5219
6385 this.core.IndexElement(row, mime); 5220 this.IndexElement(row, mime);
6386 } 5221 }
6387 } 5222 }
6388 5223
@@ -6394,56 +5229,47 @@ namespace WixToolset.Core.WindowsInstaller
6394 { 5229 {
6395 foreach (var row in table.Rows) 5230 foreach (var row in table.Rows)
6396 { 5231 {
6397 var configuration = new Wix.Configuration(); 5232 var configuration = new XElement(Names.ConfigurationElement,
6398 5233 new XAttribute("Name", row.FieldAsString(0)),
6399 configuration.Name = Convert.ToString(row[0]); 5234 XAttributeIfNotNull("Type", row, 2),
5235 XAttributeIfNotNull("ContextData", row, 3),
5236 XAttributeIfNotNull("DefaultValue", row, 4),
5237 XAttributeIfNotNull("DisplayName", row, 6),
5238 XAttributeIfNotNull("Description", row, 7),
5239 XAttributeIfNotNull("HelpLocation", row, 8),
5240 XAttributeIfNotNull("HelpKeyword", row, 9));
6400 5241
6401 switch (Convert.ToInt32(row[1])) 5242 switch (row.FieldAsInteger(1))
6402 { 5243 {
6403 case 0: 5244 case 0:
6404 configuration.Format = Wix.Configuration.FormatType.Text; 5245 configuration.SetAttributeValue("Format", "Text");
6405 break; 5246 break;
6406 case 1: 5247 case 1:
6407 configuration.Format = Wix.Configuration.FormatType.Key; 5248 configuration.SetAttributeValue("Format", "Key");
6408 break; 5249 break;
6409 case 2: 5250 case 2:
6410 configuration.Format = Wix.Configuration.FormatType.Integer; 5251 configuration.SetAttributeValue("Format", "Integer");
6411 break; 5252 break;
6412 case 3: 5253 case 3:
6413 configuration.Format = Wix.Configuration.FormatType.Bitfield; 5254 configuration.SetAttributeValue("Format", "Bitfield");
6414 break; 5255 break;
6415 default: 5256 default:
6416 this.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[1].Column.Name, row[1])); 5257 this.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[1].Column.Name, row[1]));
6417 break; 5258 break;
6418 }
6419
6420 if (null != row[2])
6421 {
6422 configuration.Type = Convert.ToString(row[2]);
6423 }
6424
6425 if (null != row[3])
6426 {
6427 configuration.ContextData = Convert.ToString(row[3]);
6428 }
6429
6430 if (null != row[4])
6431 {
6432 configuration.DefaultValue = Convert.ToString(row[4]);
6433 } 5259 }
6434 5260
6435 if (null != row[5]) 5261 if (!row.IsColumnNull(5))
6436 { 5262 {
6437 var attributes = Convert.ToInt32(row[5]); 5263 var attributes = row.FieldAsInteger(5);
6438 5264
6439 if (WindowsInstallerConstants.MsidbMsmConfigurableOptionKeyNoOrphan == (attributes & WindowsInstallerConstants.MsidbMsmConfigurableOptionKeyNoOrphan)) 5265 if (WindowsInstallerConstants.MsidbMsmConfigurableOptionKeyNoOrphan == (attributes & WindowsInstallerConstants.MsidbMsmConfigurableOptionKeyNoOrphan))
6440 { 5266 {
6441 configuration.KeyNoOrphan = Wix.YesNoType.yes; 5267 configuration.SetAttributeValue("KeyNoOrphan", "yes");
6442 } 5268 }
6443 5269
6444 if (WindowsInstallerConstants.MsidbMsmConfigurableOptionNonNullable == (attributes & WindowsInstallerConstants.MsidbMsmConfigurableOptionNonNullable)) 5270 if (WindowsInstallerConstants.MsidbMsmConfigurableOptionNonNullable == (attributes & WindowsInstallerConstants.MsidbMsmConfigurableOptionNonNullable))
6445 { 5271 {
6446 configuration.NonNullable = Wix.YesNoType.yes; 5272 configuration.SetAttributeValue("NonNullable", "yes");
6447 } 5273 }
6448 5274
6449 if (3 < attributes) 5275 if (3 < attributes)
@@ -6452,27 +5278,7 @@ namespace WixToolset.Core.WindowsInstaller
6452 } 5278 }
6453 } 5279 }
6454 5280
6455 if (null != row[6]) 5281 this.RootElement.Add(configuration);
6456 {
6457 configuration.DisplayName = Convert.ToString(row[6]);
6458 }
6459
6460 if (null != row[7])
6461 {
6462 configuration.Description = Convert.ToString(row[7]);
6463 }
6464
6465 if (null != row[8])
6466 {
6467 configuration.HelpLocation = Convert.ToString(row[8]);
6468 }
6469
6470 if (null != row[9])
6471 {
6472 configuration.HelpKeyword = Convert.ToString(row[9]);
6473 }
6474
6475 this.core.RootElement.AddChild(configuration);
6476 } 5282 }
6477 } 5283 }
6478 5284
@@ -6484,18 +5290,12 @@ namespace WixToolset.Core.WindowsInstaller
6484 { 5290 {
6485 foreach (var row in table.Rows) 5291 foreach (var row in table.Rows)
6486 { 5292 {
6487 var dependency = new Wix.Dependency(); 5293 var xDependency = new XElement(Names.DependencyElement,
6488 5294 new XAttribute("RequiredId", row.FieldAsString(2)),
6489 dependency.RequiredId = Convert.ToString(row[2]); 5295 new XAttribute("RequiredLanguage", row.FieldAsString(3)),
6490 5296 XAttributeIfNotNull("RequiredVersion", row, 4));
6491 dependency.RequiredLanguage = Convert.ToInt32(row[3], CultureInfo.InvariantCulture);
6492
6493 if (null != row[4])
6494 {
6495 dependency.RequiredVersion = Convert.ToString(row[4]);
6496 }
6497 5297
6498 this.core.RootElement.AddChild(dependency); 5298 this.RootElement.Add(xDependency);
6499 } 5299 }
6500 } 5300 }
6501 5301
@@ -6507,31 +5307,22 @@ namespace WixToolset.Core.WindowsInstaller
6507 { 5307 {
6508 foreach (var row in table.Rows) 5308 foreach (var row in table.Rows)
6509 { 5309 {
6510 var exclusion = new Wix.Exclusion(); 5310 var xExclusion = new XElement(Names.ExclusionElement,
6511 5311 new XAttribute("ExcludedId", row.FieldAsString(2)),
6512 exclusion.ExcludedId = Convert.ToString(row[2]); 5312 XAttributeIfNotNull("ExcludedMinVersion", row, 4),
5313 XAttributeIfNotNull("ExcludedMaxVersion", row, 5));
6513 5314
6514 var excludedLanguage = Convert.ToInt32(Convert.ToString(row[3]), CultureInfo.InvariantCulture); 5315 var excludedLanguage = row.FieldAsInteger(3);
6515 if (0 < excludedLanguage) 5316 if (0 < excludedLanguage)
6516 { 5317 {
6517 exclusion.ExcludeLanguage = excludedLanguage; 5318 xExclusion.SetAttributeValue("ExcludeLanguage", excludedLanguage);
6518 } 5319 }
6519 else if (0 > excludedLanguage) 5320 else if (0 > excludedLanguage)
6520 { 5321 {
6521 exclusion.ExcludeExceptLanguage = -excludedLanguage; 5322 xExclusion.SetAttributeValue("ExcludeExceptLanguage", -excludedLanguage);
6522 }
6523
6524 if (null != row[4])
6525 {
6526 exclusion.ExcludedMinVersion = Convert.ToString(row[4]);
6527 } 5323 }
6528 5324
6529 if (null != row[5]) 5325 this.RootElement.Add(xExclusion);
6530 {
6531 exclusion.ExcludedMinVersion = Convert.ToString(row[5]);
6532 }
6533
6534 this.core.RootElement.AddChild(exclusion);
6535 } 5326 }
6536 } 5327 }
6537 5328
@@ -6543,16 +5334,15 @@ namespace WixToolset.Core.WindowsInstaller
6543 { 5334 {
6544 foreach (var row in table.Rows) 5335 foreach (var row in table.Rows)
6545 { 5336 {
6546 var tableName = Convert.ToString(row[0]); 5337 var tableName = row.FieldAsString(0);
6547 5338
6548 // the linker automatically adds a ModuleIgnoreTable row for some tables 5339 // the linker automatically adds a ModuleIgnoreTable row for some tables
6549 if ("ModuleConfiguration" != tableName && "ModuleSubstitution" != tableName) 5340 if ("ModuleConfiguration" != tableName && "ModuleSubstitution" != tableName)
6550 { 5341 {
6551 var ignoreTable = new Wix.IgnoreTable(); 5342 var xIgnoreTable = new XElement(Names.IgnoreTableElement,
5343 new XAttribute("Id", tableName));
6552 5344
6553 ignoreTable.Id = tableName; 5345 this.RootElement.Add(xIgnoreTable);
6554
6555 this.core.RootElement.AddChild(ignoreTable);
6556 } 5346 }
6557 } 5347 }
6558 } 5348 }
@@ -6567,14 +5357,10 @@ namespace WixToolset.Core.WindowsInstaller
6567 { 5357 {
6568 var row = table.Rows[0]; 5358 var row = table.Rows[0];
6569 5359
6570 var module = (Wix.Module)this.core.RootElement; 5360 this.RootElement.SetAttributeValue("Id", row.FieldAsString(0));
6571
6572 module.Id = Convert.ToString(row[0]);
6573
6574 // support Language columns that are treated as integers as well as strings (the WiX default, to support localizability) 5361 // support Language columns that are treated as integers as well as strings (the WiX default, to support localizability)
6575 module.Language = Convert.ToString(row[1], CultureInfo.InvariantCulture); 5362 this.RootElement.SetAttributeValue("Language", row.FieldAsString(1));
6576 5363 this.RootElement.SetAttributeValue("Version", row.FieldAsString(2));
6577 module.Version = Convert.ToString(row[2]);
6578 } 5364 }
6579 else 5365 else
6580 { 5366 {
@@ -6590,20 +5376,13 @@ namespace WixToolset.Core.WindowsInstaller
6590 { 5376 {
6591 foreach (var row in table.Rows) 5377 foreach (var row in table.Rows)
6592 { 5378 {
6593 var substitution = new Wix.Substitution(); 5379 var xSubstitution = new XElement(Names.SubstitutionElement,
6594 5380 new XAttribute("Table", row.FieldAsString(0)),
6595 substitution.Table = Convert.ToString(row[0]); 5381 new XAttribute("Row", row.FieldAsString(1)),
6596 5382 new XAttribute("Column", row.FieldAsString(2)),
6597 substitution.Row = Convert.ToString(row[1]); 5383 XAttributeIfNotNull("Value", row, 3));
6598
6599 substitution.Column = Convert.ToString(row[2]);
6600 5384
6601 if (null != row[3]) 5385 this.RootElement.Add(xSubstitution);
6602 {
6603 substitution.Value = Convert.ToString(row[3]);
6604 }
6605
6606 this.core.RootElement.AddChild(substitution);
6607 } 5386 }
6608 } 5387 }
6609 5388
@@ -6615,53 +5394,40 @@ namespace WixToolset.Core.WindowsInstaller
6615 { 5394 {
6616 foreach (var row in table.Rows) 5395 foreach (var row in table.Rows)
6617 { 5396 {
6618 var copyFile = new Wix.CopyFile(); 5397 var xCopyFile = new XElement(Names.CopyFileElement,
6619 5398 new XAttribute("Id", row.FieldAsString(0)),
6620 copyFile.Id = Convert.ToString(row[0]); 5399 XAttributeIfNotNull("SourceName", row, 2));
6621
6622 if (null != row[2])
6623 {
6624 copyFile.SourceName = Convert.ToString(row[2]);
6625 }
6626 5400
6627 if (null != row[3]) 5401 if (!row.IsColumnNull(3))
6628 { 5402 {
6629 var names = Common.GetNames(Convert.ToString(row[3])); 5403 var names = Common.GetNames(row.FieldAsString(3));
6630 if (null != names[0] && null != names[1]) 5404 if (null != names[0] && null != names[1])
6631 { 5405 {
6632 copyFile.DestinationShortName = names[0]; 5406 xCopyFile.SetAttributeValue("DestinationShortName", names[0]);
6633 copyFile.DestinationName = names[1]; 5407 xCopyFile.SetAttributeValue("DestinationName", names[1]);
6634 } 5408 }
6635 else if (null != names[0]) 5409 else if (null != names[0])
6636 { 5410 {
6637 copyFile.DestinationName = names[0]; 5411 xCopyFile.SetAttributeValue("DestinationName", names[0]);
6638 } 5412 }
6639 } 5413 }
6640 5414
6641 // source/destination directory/property is set in FinalizeDuplicateMoveFileTables 5415 // source/destination directory/property is set in FinalizeDuplicateMoveFileTables
6642 5416
6643 switch (Convert.ToInt32(row[6])) 5417 switch (row.FieldAsInteger(6))
6644 { 5418 {
6645 case 0: 5419 case 0:
6646 break; 5420 break;
6647 case WindowsInstallerConstants.MsidbMoveFileOptionsMove: 5421 case WindowsInstallerConstants.MsidbMoveFileOptionsMove:
6648 copyFile.Delete = Wix.YesNoType.yes; 5422 xCopyFile.SetAttributeValue("Delete", "yes");
6649 break; 5423 break;
6650 default: 5424 default:
6651 this.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[6].Column.Name, row[6])); 5425 this.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[6].Column.Name, row[6]));
6652 break; 5426 break;
6653 } 5427 }
6654 5428
6655 var component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[1])); 5429 this.AddChildToParent("Component", xCopyFile, row, 1);
6656 if (null != component) 5430 this.IndexElement(row, xCopyFile);
6657 {
6658 component.AddChild(copyFile);
6659 }
6660 else
6661 {
6662 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[1]), "Component"));
6663 }
6664 this.core.IndexElement(row, copyFile);
6665 } 5431 }
6666 } 5432 }
6667 5433
@@ -6673,13 +5439,11 @@ namespace WixToolset.Core.WindowsInstaller
6673 { 5439 {
6674 foreach (var row in table.Rows) 5440 foreach (var row in table.Rows)
6675 { 5441 {
6676 var digitalCertificate = new Wix.DigitalCertificate(); 5442 var xDigitalCertificate = new XElement(Names.DigitalCertificateElement,
6677 5443 new XAttribute("Id", row.FieldAsString(0)),
6678 digitalCertificate.Id = Convert.ToString(row[0]); 5444 new XAttribute("SourceFile", row.FieldAsString(1)));
6679
6680 digitalCertificate.SourceFile = Convert.ToString(row[1]);
6681 5445
6682 this.core.IndexElement(row, digitalCertificate); 5446 this.IndexElement(row, xDigitalCertificate);
6683 } 5447 }
6684 } 5448 }
6685 5449
@@ -6691,31 +5455,18 @@ namespace WixToolset.Core.WindowsInstaller
6691 { 5455 {
6692 foreach (var row in table.Rows) 5456 foreach (var row in table.Rows)
6693 { 5457 {
6694 var digitalSignature = new Wix.DigitalSignature(); 5458 var xDigitalSignature = new XElement(Names.DigitalSignatureElement,
6695 5459 XAttributeIfNotNull("SourceFile", row, 3));
6696 if (null != row[3])
6697 {
6698 digitalSignature.SourceFile = Convert.ToString(row[3]);
6699 }
6700 5460
6701 var digitalCertificate = (Wix.DigitalCertificate)this.core.GetIndexedElement("MsiDigitalCertificate", Convert.ToString(row[2])); 5461 this.AddChildToParent("MsiDigitalCertificate", xDigitalSignature, row, 2);
6702 if (null != digitalCertificate)
6703 {
6704 digitalSignature.AddChild(digitalCertificate);
6705 }
6706 else
6707 {
6708 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "DigitalCertificate_", Convert.ToString(row[2]), "MsiDigitalCertificate"));
6709 }
6710 5462
6711 var parentElement = (Wix.IParentElement)this.core.GetIndexedElement(Convert.ToString(row[0]), Convert.ToString(row[1])); 5463 if (this.TryGetIndexedElement(row.FieldAsString(0), out var xParentElement, row.FieldAsString(1)))
6712 if (null != parentElement)
6713 { 5464 {
6714 parentElement.AddChild(digitalSignature); 5465 xParentElement.Add(xDigitalSignature);
6715 } 5466 }
6716 else 5467 else
6717 { 5468 {
6718 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "SignObject", Convert.ToString(row[1]), Convert.ToString(row[0]))); 5469 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "SignObject", row.FieldAsString(1), row.FieldAsString(0)));
6719 } 5470 }
6720 } 5471 }
6721 } 5472 }
@@ -6728,34 +5479,28 @@ namespace WixToolset.Core.WindowsInstaller
6728 { 5479 {
6729 foreach (var row in table.Rows) 5480 foreach (var row in table.Rows)
6730 { 5481 {
6731 var embeddedChainer = new Wix.EmbeddedChainer(); 5482 var xEmbeddedChainer = new XElement(Names.EmbeddedChainerElement,
6732 5483 new XAttribute("Id", row.FieldAsString(0)),
6733 embeddedChainer.Id = Convert.ToString(row[0]); 5484 new XAttribute("Condition", row.FieldAsString(1)),
6734 5485 XAttributeIfNotNull("CommandLine", row, 2));
6735 embeddedChainer.Content = Convert.ToString(row[1]);
6736
6737 if (null != row[2])
6738 {
6739 embeddedChainer.CommandLine = Convert.ToString(row[2]);
6740 }
6741 5486
6742 switch (Convert.ToInt32(row[4])) 5487 switch (row.FieldAsInteger(4))
6743 { 5488 {
6744 case WindowsInstallerConstants.MsidbCustomActionTypeExe + WindowsInstallerConstants.MsidbCustomActionTypeBinaryData: 5489 case WindowsInstallerConstants.MsidbCustomActionTypeExe + WindowsInstallerConstants.MsidbCustomActionTypeBinaryData:
6745 embeddedChainer.BinarySource = Convert.ToString(row[3]); 5490 xEmbeddedChainer.SetAttributeValue("BinarySource", row.FieldAsString(3));
6746 break; 5491 break;
6747 case WindowsInstallerConstants.MsidbCustomActionTypeExe + WindowsInstallerConstants.MsidbCustomActionTypeSourceFile: 5492 case WindowsInstallerConstants.MsidbCustomActionTypeExe + WindowsInstallerConstants.MsidbCustomActionTypeSourceFile:
6748 embeddedChainer.FileSource = Convert.ToString(row[3]); 5493 xEmbeddedChainer.SetAttributeValue("FileSource", row.FieldAsString(3));
6749 break; 5494 break;
6750 case WindowsInstallerConstants.MsidbCustomActionTypeExe + WindowsInstallerConstants.MsidbCustomActionTypeProperty: 5495 case WindowsInstallerConstants.MsidbCustomActionTypeExe + WindowsInstallerConstants.MsidbCustomActionTypeProperty:
6751 embeddedChainer.PropertySource = Convert.ToString(row[3]); 5496 xEmbeddedChainer.SetAttributeValue("PropertySource", row.FieldAsString(3));
6752 break; 5497 break;
6753 default: 5498 default:
6754 this.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[4].Column.Name, row[4])); 5499 this.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[4].Column.Name, row[4]));
6755 break; 5500 break;
6756 } 5501 }
6757 5502
6758 this.core.RootElement.AddChild(embeddedChainer); 5503 this.RootElement.Add(xEmbeddedChainer);
6759 } 5504 }
6760 } 5505 }
6761 5506
@@ -6765,13 +5510,14 @@ namespace WixToolset.Core.WindowsInstaller
6765 /// <param name="table">The table to decompile.</param> 5510 /// <param name="table">The table to decompile.</param>
6766 private void DecompileMsiEmbeddedUITable(Table table) 5511 private void DecompileMsiEmbeddedUITable(Table table)
6767 { 5512 {
6768 var embeddedUI = new Wix.EmbeddedUI(); 5513 var xEmbeddedUI = new XElement(Names.EmbeddedUIElement);
5514
6769 var foundEmbeddedUI = false; 5515 var foundEmbeddedUI = false;
6770 var foundEmbeddedResources = false; 5516 var foundEmbeddedResources = false;
6771 5517
6772 foreach (var row in table.Rows) 5518 foreach (var row in table.Rows)
6773 { 5519 {
6774 var attributes = Convert.ToInt32(row[2]); 5520 var attributes = row.FieldAsInteger(2);
6775 5521
6776 if (WindowsInstallerConstants.MsidbEmbeddedUI == (attributes & WindowsInstallerConstants.MsidbEmbeddedUI)) 5522 if (WindowsInstallerConstants.MsidbEmbeddedUI == (attributes & WindowsInstallerConstants.MsidbEmbeddedUI))
6777 { 5523 {
@@ -6781,120 +5527,119 @@ namespace WixToolset.Core.WindowsInstaller
6781 } 5527 }
6782 else 5528 else
6783 { 5529 {
6784 embeddedUI.Id = Convert.ToString(row[0]); 5530 xEmbeddedUI.SetAttributeValue("Id", row.FieldAsString(0));
6785 embeddedUI.Name = Convert.ToString(row[1]); 5531 xEmbeddedUI.SetAttributeValue("Name", row.FieldAsString(1));
6786 5532
6787 var messageFilter = Convert.ToInt32(row[3]); 5533 var messageFilter = row.FieldAsInteger(3);
6788 if (0 == (messageFilter & WindowsInstallerConstants.INSTALLLOGMODE_FATALEXIT)) 5534 if (0 == (messageFilter & WindowsInstallerConstants.INSTALLLOGMODE_FATALEXIT))
6789 { 5535 {
6790 embeddedUI.IgnoreFatalExit = Wix.YesNoType.yes; 5536 xEmbeddedUI.SetAttributeValue("IgnoreFatalExit", "yes");
6791 } 5537 }
6792 5538
6793 if (0 == (messageFilter & WindowsInstallerConstants.INSTALLLOGMODE_ERROR)) 5539 if (0 == (messageFilter & WindowsInstallerConstants.INSTALLLOGMODE_ERROR))
6794 { 5540 {
6795 embeddedUI.IgnoreError = Wix.YesNoType.yes; 5541 xEmbeddedUI.SetAttributeValue("IgnoreError", "yes");
6796 } 5542 }
6797 5543
6798 if (0 == (messageFilter & WindowsInstallerConstants.INSTALLLOGMODE_WARNING)) 5544 if (0 == (messageFilter & WindowsInstallerConstants.INSTALLLOGMODE_WARNING))
6799 { 5545 {
6800 embeddedUI.IgnoreWarning = Wix.YesNoType.yes; 5546 xEmbeddedUI.SetAttributeValue("IgnoreWarning", "yes");
6801 } 5547 }
6802 5548
6803 if (0 == (messageFilter & WindowsInstallerConstants.INSTALLLOGMODE_USER)) 5549 if (0 == (messageFilter & WindowsInstallerConstants.INSTALLLOGMODE_USER))
6804 { 5550 {
6805 embeddedUI.IgnoreUser = Wix.YesNoType.yes; 5551 xEmbeddedUI.SetAttributeValue("IgnoreUser", "yes");
6806 } 5552 }
6807 5553
6808 if (0 == (messageFilter & WindowsInstallerConstants.INSTALLLOGMODE_INFO)) 5554 if (0 == (messageFilter & WindowsInstallerConstants.INSTALLLOGMODE_INFO))
6809 { 5555 {
6810 embeddedUI.IgnoreInfo = Wix.YesNoType.yes; 5556 xEmbeddedUI.SetAttributeValue("IgnoreInfo", "yes");
6811 } 5557 }
6812 5558
6813 if (0 == (messageFilter & WindowsInstallerConstants.INSTALLLOGMODE_FILESINUSE)) 5559 if (0 == (messageFilter & WindowsInstallerConstants.INSTALLLOGMODE_FILESINUSE))
6814 { 5560 {
6815 embeddedUI.IgnoreFilesInUse = Wix.YesNoType.yes; 5561 xEmbeddedUI.SetAttributeValue("IgnoreFilesInUse", "yes");
6816 } 5562 }
6817 5563
6818 if (0 == (messageFilter & WindowsInstallerConstants.INSTALLLOGMODE_RESOLVESOURCE)) 5564 if (0 == (messageFilter & WindowsInstallerConstants.INSTALLLOGMODE_RESOLVESOURCE))
6819 { 5565 {
6820 embeddedUI.IgnoreResolveSource = Wix.YesNoType.yes; 5566 xEmbeddedUI.SetAttributeValue("IgnoreResolveSource", "yes");
6821 } 5567 }
6822 5568
6823 if (0 == (messageFilter & WindowsInstallerConstants.INSTALLLOGMODE_OUTOFDISKSPACE)) 5569 if (0 == (messageFilter & WindowsInstallerConstants.INSTALLLOGMODE_OUTOFDISKSPACE))
6824 { 5570 {
6825 embeddedUI.IgnoreOutOfDiskSpace = Wix.YesNoType.yes; 5571 xEmbeddedUI.SetAttributeValue("IgnoreOutOfDiskSpace", "yes");
6826 } 5572 }
6827 5573
6828 if (0 == (messageFilter & WindowsInstallerConstants.INSTALLLOGMODE_ACTIONSTART)) 5574 if (0 == (messageFilter & WindowsInstallerConstants.INSTALLLOGMODE_ACTIONSTART))
6829 { 5575 {
6830 embeddedUI.IgnoreActionStart = Wix.YesNoType.yes; 5576 xEmbeddedUI.SetAttributeValue("IgnoreActionStart", "yes");
6831 } 5577 }
6832 5578
6833 if (0 == (messageFilter & WindowsInstallerConstants.INSTALLLOGMODE_ACTIONDATA)) 5579 if (0 == (messageFilter & WindowsInstallerConstants.INSTALLLOGMODE_ACTIONDATA))
6834 { 5580 {
6835 embeddedUI.IgnoreActionData = Wix.YesNoType.yes; 5581 xEmbeddedUI.SetAttributeValue("IgnoreActionData", "yes");
6836 } 5582 }
6837 5583
6838 if (0 == (messageFilter & WindowsInstallerConstants.INSTALLLOGMODE_PROGRESS)) 5584 if (0 == (messageFilter & WindowsInstallerConstants.INSTALLLOGMODE_PROGRESS))
6839 { 5585 {
6840 embeddedUI.IgnoreProgress = Wix.YesNoType.yes; 5586 xEmbeddedUI.SetAttributeValue("IgnoreProgress", "yes");
6841 } 5587 }
6842 5588
6843 if (0 == (messageFilter & WindowsInstallerConstants.INSTALLLOGMODE_COMMONDATA)) 5589 if (0 == (messageFilter & WindowsInstallerConstants.INSTALLLOGMODE_COMMONDATA))
6844 { 5590 {
6845 embeddedUI.IgnoreCommonData = Wix.YesNoType.yes; 5591 xEmbeddedUI.SetAttributeValue("IgnoreCommonData", "yes");
6846 } 5592 }
6847 5593
6848 if (0 == (messageFilter & WindowsInstallerConstants.INSTALLLOGMODE_INITIALIZE)) 5594 if (0 == (messageFilter & WindowsInstallerConstants.INSTALLLOGMODE_INITIALIZE))
6849 { 5595 {
6850 embeddedUI.IgnoreInitialize = Wix.YesNoType.yes; 5596 xEmbeddedUI.SetAttributeValue("IgnoreInitialize", "yes");
6851 } 5597 }
6852 5598
6853 if (0 == (messageFilter & WindowsInstallerConstants.INSTALLLOGMODE_TERMINATE)) 5599 if (0 == (messageFilter & WindowsInstallerConstants.INSTALLLOGMODE_TERMINATE))
6854 { 5600 {
6855 embeddedUI.IgnoreTerminate = Wix.YesNoType.yes; 5601 xEmbeddedUI.SetAttributeValue("IgnoreTerminate", "yes");
6856 } 5602 }
6857 5603
6858 if (0 == (messageFilter & WindowsInstallerConstants.INSTALLLOGMODE_SHOWDIALOG)) 5604 if (0 == (messageFilter & WindowsInstallerConstants.INSTALLLOGMODE_SHOWDIALOG))
6859 { 5605 {
6860 embeddedUI.IgnoreShowDialog = Wix.YesNoType.yes; 5606 xEmbeddedUI.SetAttributeValue("IgnoreShowDialog", "yes");
6861 } 5607 }
6862 5608
6863 if (0 == (messageFilter & WindowsInstallerConstants.INSTALLLOGMODE_RMFILESINUSE)) 5609 if (0 == (messageFilter & WindowsInstallerConstants.INSTALLLOGMODE_RMFILESINUSE))
6864 { 5610 {
6865 embeddedUI.IgnoreRMFilesInUse = Wix.YesNoType.yes; 5611 xEmbeddedUI.SetAttributeValue("IgnoreRMFilesInUse", "yes");
6866 } 5612 }
6867 5613
6868 if (0 == (messageFilter & WindowsInstallerConstants.INSTALLLOGMODE_INSTALLSTART)) 5614 if (0 == (messageFilter & WindowsInstallerConstants.INSTALLLOGMODE_INSTALLSTART))
6869 { 5615 {
6870 embeddedUI.IgnoreInstallStart = Wix.YesNoType.yes; 5616 xEmbeddedUI.SetAttributeValue("IgnoreInstallStart", "yes");
6871 } 5617 }
6872 5618
6873 if (0 == (messageFilter & WindowsInstallerConstants.INSTALLLOGMODE_INSTALLEND)) 5619 if (0 == (messageFilter & WindowsInstallerConstants.INSTALLLOGMODE_INSTALLEND))
6874 { 5620 {
6875 embeddedUI.IgnoreInstallEnd = Wix.YesNoType.yes; 5621 xEmbeddedUI.SetAttributeValue("IgnoreInstallEnd", "yes");
6876 } 5622 }
6877 5623
6878 if (WindowsInstallerConstants.MsidbEmbeddedHandlesBasic == (attributes & WindowsInstallerConstants.MsidbEmbeddedHandlesBasic)) 5624 if (WindowsInstallerConstants.MsidbEmbeddedHandlesBasic == (attributes & WindowsInstallerConstants.MsidbEmbeddedHandlesBasic))
6879 { 5625 {
6880 embeddedUI.SupportBasicUI = Wix.YesNoType.yes; 5626 xEmbeddedUI.SetAttributeValue("SupportBasicUI", "yes");
6881 } 5627 }
6882 5628
6883 embeddedUI.SourceFile = Convert.ToString(row[4]); 5629 xEmbeddedUI.SetAttributeValue("SourceFile", row.FieldAsString(4));
6884 5630
6885 this.core.UIElement.AddChild(embeddedUI); 5631 this.UIElement.Add(xEmbeddedUI);
6886 foundEmbeddedUI = true; 5632 foundEmbeddedUI = true;
6887 } 5633 }
6888 } 5634 }
6889 else 5635 else
6890 { 5636 {
6891 var embeddedResource = new Wix.EmbeddedUIResource(); 5637 var xEmbeddedResource = new XElement(Names.EmbeddedUIResourceElement,
5638 new XAttribute("Id", row.FieldAsString(0)),
5639 new XAttribute("Name", row.FieldAsString(1)),
5640 new XAttribute("SourceFile", row.FieldAsString(4)));
6892 5641
6893 embeddedResource.Id = Convert.ToString(row[0]); 5642 xEmbeddedUI.Add(xEmbeddedResource);
6894 embeddedResource.Name = Convert.ToString(row[1]);
6895 embeddedResource.SourceFile = Convert.ToString(row[4]);
6896
6897 embeddedUI.AddChild(embeddedResource);
6898 foundEmbeddedResources = true; 5643 foundEmbeddedResources = true;
6899 } 5644 }
6900 } 5645 }
@@ -6913,30 +5658,24 @@ namespace WixToolset.Core.WindowsInstaller
6913 { 5658 {
6914 foreach (var row in table.Rows) 5659 foreach (var row in table.Rows)
6915 { 5660 {
6916 var permissionEx = new Wix.PermissionEx(); 5661 var xPermissionEx = new XElement(Names.PermissionExElement,
6917 permissionEx.Id = Convert.ToString(row[0]); 5662 new XAttribute("Id", row.FieldAsString(0)),
6918 permissionEx.Sddl = Convert.ToString(row[3]); 5663 new XAttribute("Sddl", row.FieldAsString(3)),
5664 XAttributeIfNotNull("Condition", row, 4));
6919 5665
6920 if (null != row[4]) 5666 switch (row.FieldAsString(2))
6921 { 5667 {
6922 var condition = new Wix.Condition(); 5668 case "CreateFolder":
6923 condition.Content = Convert.ToString(row[4]); 5669 case "File":
6924 permissionEx.AddChild(condition); 5670 case "Registry":
6925 } 5671 case "ServiceInstall":
6926 5672 break;
6927 switch (Convert.ToString(row[2])) 5673 default:
6928 { 5674 this.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, row.Table.Name, row.Fields[1].Column.Name, row[1]));
6929 case "CreateFolder": 5675 return;
6930 case "File":
6931 case "Registry":
6932 case "ServiceInstall":
6933 break;
6934 default:
6935 this.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, row.Table.Name, row.Fields[1].Column.Name, row[1]));
6936 return;
6937 } 5676 }
6938 5677
6939 this.core.IndexElement(row, permissionEx); 5678 this.IndexElement(row, xPermissionEx);
6940 } 5679 }
6941 } 5680 }
6942 5681
@@ -6948,9 +5687,9 @@ namespace WixToolset.Core.WindowsInstaller
6948 { 5687 {
6949 if (0 < table.Rows.Count) 5688 if (0 < table.Rows.Count)
6950 { 5689 {
6951 var packageCertificates = new Wix.PackageCertificates(); 5690 var xPackageCertificates = new XElement(Names.PatchCertificatesElement);
6952 this.core.RootElement.AddChild(packageCertificates); 5691 this.RootElement.Add(xPackageCertificates);
6953 this.AddCertificates(table, packageCertificates); 5692 this.AddCertificates(table, xPackageCertificates);
6954 } 5693 }
6955 } 5694 }
6956 5695
@@ -6962,9 +5701,9 @@ namespace WixToolset.Core.WindowsInstaller
6962 { 5701 {
6963 if (0 < table.Rows.Count) 5702 if (0 < table.Rows.Count)
6964 { 5703 {
6965 var patchCertificates = new Wix.PatchCertificates(); 5704 var xPatchCertificates = new XElement(Names.PatchCertificatesElement);
6966 this.core.RootElement.AddChild(patchCertificates); 5705 this.RootElement.Add(xPatchCertificates);
6967 this.AddCertificates(table, patchCertificates); 5706 this.AddCertificates(table, xPatchCertificates);
6968 } 5707 }
6969 } 5708 }
6970 5709
@@ -6973,19 +5712,17 @@ namespace WixToolset.Core.WindowsInstaller
6973 /// </summary> 5712 /// </summary>
6974 /// <param name="table">The table being decompiled.</param> 5713 /// <param name="table">The table being decompiled.</param>
6975 /// <param name="parent">DigitalCertificate parent</param> 5714 /// <param name="parent">DigitalCertificate parent</param>
6976 private void AddCertificates(Table table, Wix.IParentElement parent) 5715 private void AddCertificates(Table table, XElement parent)
6977 { 5716 {
6978 foreach (var row in table.Rows) 5717 foreach (var row in table.Rows)
6979 { 5718 {
6980 var digitalCertificate = (Wix.DigitalCertificate)this.core.GetIndexedElement("MsiDigitalCertificate", Convert.ToString(row[1])); 5719 if (this.TryGetIndexedElement("MsiDigitalCertificate", out var xDigitalCertificate, row.FieldAsString(1)))
6981
6982 if (null != digitalCertificate)
6983 { 5720 {
6984 parent.AddChild(digitalCertificate); 5721 parent.Add(xDigitalCertificate);
6985 } 5722 }
6986 else 5723 else
6987 { 5724 {
6988 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "DigitalCertificate_", Convert.ToString(row[1]), "MsiDigitalCertificate")); 5725 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "DigitalCertificate_", row.FieldAsString(1), "MsiDigitalCertificate"));
6989 } 5726 }
6990 } 5727 }
6991 } 5728 }
@@ -6998,20 +5735,12 @@ namespace WixToolset.Core.WindowsInstaller
6998 { 5735 {
6999 foreach (var row in table.Rows) 5736 foreach (var row in table.Rows)
7000 { 5737 {
7001 var property = new Wix.ShortcutProperty(); 5738 var xProperty = new XElement(Names.ShortcutPropertyElement,
7002 property.Id = Convert.ToString(row[0]); 5739 new XAttribute("Id", row.FieldAsString(0)),
7003 property.Key = Convert.ToString(row[2]); 5740 new XAttribute("Key", row.FieldAsString(2)),
7004 property.Value = Convert.ToString(row[3]); 5741 new XAttribute("Value", row.FieldAsString(3)));
7005 5742
7006 var shortcut = (Wix.Shortcut)this.core.GetIndexedElement("Shortcut", Convert.ToString(row[1])); 5743 this.AddChildToParent("Shortcut", xProperty, row, 1);
7007 if (null != shortcut)
7008 {
7009 shortcut.AddChild(property);
7010 }
7011 else
7012 {
7013 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Shortcut_", Convert.ToString(row[1]), "Shortcut"));
7014 }
7015 } 5744 }
7016 } 5745 }
7017 5746
@@ -7023,24 +5752,11 @@ namespace WixToolset.Core.WindowsInstaller
7023 { 5752 {
7024 foreach (var row in table.Rows) 5753 foreach (var row in table.Rows)
7025 { 5754 {
7026 var property = new Wix.Property(); 5755 var xProperty = new XElement(Names.PropertyElement,
7027 5756 new XAttribute("Id", row.FieldAsString(1)),
7028 property.Id = Convert.ToString(row[1]); 5757 row.IsColumnNull(2) ? null : new XAttribute("Value", row.FieldAsString(2)));
7029
7030 if (null != row[2])
7031 {
7032 property.Value = Convert.ToString(row[2]);
7033 }
7034 5758
7035 var odbcDriver = (Wix.ODBCDriver)this.core.GetIndexedElement("ODBCDriver", Convert.ToString(row[0])); 5759 this.AddChildToParent("ODBCDriver", xProperty, row, 0);
7036 if (null != odbcDriver)
7037 {
7038 odbcDriver.AddChild(property);
7039 }
7040 else
7041 {
7042 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Driver_", Convert.ToString(row[0]), "ODBCDriver"));
7043 }
7044 } 5760 }
7045 } 5761 }
7046 5762
@@ -7052,28 +5768,25 @@ namespace WixToolset.Core.WindowsInstaller
7052 { 5768 {
7053 foreach (var row in table.Rows) 5769 foreach (var row in table.Rows)
7054 { 5770 {
7055 var odbcDataSource = new Wix.ODBCDataSource(); 5771 var xOdbcDataSource = new XElement(Names.ODBCDataSourceElement,
7056 5772 new XAttribute("Id", row.FieldAsString(0)),
7057 odbcDataSource.Id = Convert.ToString(row[0]); 5773 new XAttribute("Name", row.FieldAsString(2)),
7058 5774 new XAttribute("DriverName", row.FieldAsString(3)));
7059 odbcDataSource.Name = Convert.ToString(row[2]);
7060 5775
7061 odbcDataSource.DriverName = Convert.ToString(row[3]); 5776 switch (row.FieldAsInteger(4))
7062
7063 switch (Convert.ToInt32(row[4]))
7064 { 5777 {
7065 case WindowsInstallerConstants.MsidbODBCDataSourceRegistrationPerMachine: 5778 case WindowsInstallerConstants.MsidbODBCDataSourceRegistrationPerMachine:
7066 odbcDataSource.Registration = Wix.ODBCDataSource.RegistrationType.machine; 5779 xOdbcDataSource.SetAttributeValue("Registration", "machine");
7067 break; 5780 break;
7068 case WindowsInstallerConstants.MsidbODBCDataSourceRegistrationPerUser: 5781 case WindowsInstallerConstants.MsidbODBCDataSourceRegistrationPerUser:
7069 odbcDataSource.Registration = Wix.ODBCDataSource.RegistrationType.user; 5782 xOdbcDataSource.SetAttributeValue("Registration", "user");
7070 break; 5783 break;
7071 default: 5784 default:
7072 this.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[4].Column.Name, row[4])); 5785 this.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[4].Column.Name, row[4]));
7073 break; 5786 break;
7074 } 5787 }
7075 5788
7076 this.core.IndexElement(row, odbcDataSource); 5789 this.IndexElement(row, xOdbcDataSource);
7077 } 5790 }
7078 } 5791 }
7079 5792
@@ -7085,29 +5798,14 @@ namespace WixToolset.Core.WindowsInstaller
7085 { 5798 {
7086 foreach (var row in table.Rows) 5799 foreach (var row in table.Rows)
7087 { 5800 {
7088 var odbcDriver = new Wix.ODBCDriver(); 5801 var xOdbcDriver = new XElement(Names.ODBCDriverElement,
7089 5802 new XAttribute("Id", row.FieldAsString(0)),
7090 odbcDriver.Id = Convert.ToString(row[0]); 5803 new XAttribute("Name", row.FieldAsString(2)),
7091 5804 new XAttribute("File", row.FieldAsString(3)),
7092 odbcDriver.Name = Convert.ToString(row[2]); 5805 XAttributeIfNotNull("SetupFile", row, 4));
7093 5806
7094 odbcDriver.File = Convert.ToString(row[3]); 5807 this.AddChildToParent("Component", xOdbcDriver, row, 1);
7095 5808 this.IndexElement(row, xOdbcDriver);
7096 if (null != row[4])
7097 {
7098 odbcDriver.SetupFile = Convert.ToString(row[4]);
7099 }
7100
7101 var component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[1]));
7102 if (null != component)
7103 {
7104 component.AddChild(odbcDriver);
7105 }
7106 else
7107 {
7108 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[1]), "Component"));
7109 }
7110 this.core.IndexElement(row, odbcDriver);
7111 } 5809 }
7112 } 5810 }
7113 5811
@@ -7119,24 +5817,11 @@ namespace WixToolset.Core.WindowsInstaller
7119 { 5817 {
7120 foreach (var row in table.Rows) 5818 foreach (var row in table.Rows)
7121 { 5819 {
7122 var property = new Wix.Property(); 5820 var xProperty = new XElement(Names.PropertyElement,
7123 5821 new XAttribute("Id", row.FieldAsString(1)),
7124 property.Id = Convert.ToString(row[1]); 5822 XAttributeIfNotNull("Value", row, 2));
7125 5823
7126 if (null != row[2]) 5824 this.AddChildToParent("ODBCDataSource", xProperty, row, 0);
7127 {
7128 property.Value = Convert.ToString(row[2]);
7129 }
7130
7131 var odbcDataSource = (Wix.ODBCDataSource)this.core.GetIndexedElement("ODBCDataSource", Convert.ToString(row[0]));
7132 if (null != odbcDataSource)
7133 {
7134 odbcDataSource.AddChild(property);
7135 }
7136 else
7137 {
7138 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "DataSource_", Convert.ToString(row[0]), "ODBCDataSource"));
7139 }
7140 } 5825 }
7141 } 5826 }
7142 5827
@@ -7148,28 +5833,13 @@ namespace WixToolset.Core.WindowsInstaller
7148 { 5833 {
7149 foreach (var row in table.Rows) 5834 foreach (var row in table.Rows)
7150 { 5835 {
7151 var odbcTranslator = new Wix.ODBCTranslator(); 5836 var xOdbcTranslator = new XElement(Names.ODBCTranslatorElement,
7152 5837 new XAttribute("Id", row.FieldAsString(0)),
7153 odbcTranslator.Id = Convert.ToString(row[0]); 5838 new XAttribute("Name", row.FieldAsString(2)),
7154 5839 new XAttribute("File", row.FieldAsString(3)),
7155 odbcTranslator.Name = Convert.ToString(row[2]); 5840 XAttributeIfNotNull("SetupFile", row, 4));
7156 5841
7157 odbcTranslator.File = Convert.ToString(row[3]); 5842 this.AddChildToParent("Component", xOdbcTranslator, row, 1);
7158
7159 if (null != row[4])
7160 {
7161 odbcTranslator.SetupFile = Convert.ToString(row[4]);
7162 }
7163
7164 var component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[1]));
7165 if (null != component)
7166 {
7167 component.AddChild(odbcTranslator);
7168 }
7169 else
7170 {
7171 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[1]), "Component"));
7172 }
7173 } 5843 }
7174 } 5844 }
7175 5845
@@ -7181,115 +5851,106 @@ namespace WixToolset.Core.WindowsInstaller
7181 { 5851 {
7182 if (0 < table.Rows.Count) 5852 if (0 < table.Rows.Count)
7183 { 5853 {
7184 var patchMetadata = new Wix.PatchMetadata(); 5854 var xPatchMetadata = new XElement(Names.PatchMetadataElement);
7185 5855
7186 foreach (var row in table.Rows) 5856 foreach (var row in table.Rows)
7187 { 5857 {
7188 var value = Convert.ToString(row[2]); 5858 var value = row.FieldAsString(2);
7189 5859
7190 switch (Convert.ToString(row[1])) 5860 switch (row.FieldAsString(1))
7191 { 5861 {
7192 case "AllowRemoval": 5862 case "AllowRemoval":
7193 if ("1" == value) 5863 if ("1" == value)
7194 { 5864 {
7195 patchMetadata.AllowRemoval = Wix.YesNoType.yes; 5865 xPatchMetadata.SetAttributeValue("AllowRemoval", "yes");
7196 } 5866 }
7197 break; 5867 break;
7198 case "Classification": 5868 case "Classification":
7199 if (null != value) 5869 if (null != value)
7200 { 5870 {
7201 patchMetadata.Classification = value; 5871 xPatchMetadata.SetAttributeValue("Classification", value);
7202 } 5872 }
7203 break; 5873 break;
7204 case "CreationTimeUTC": 5874 case "CreationTimeUTC":
7205 if (null != value) 5875 if (null != value)
7206 { 5876 {
7207 patchMetadata.CreationTimeUTC = value; 5877 xPatchMetadata.SetAttributeValue("CreationTimeUTC", value);
7208 } 5878 }
7209 break; 5879 break;
7210 case "Description": 5880 case "Description":
7211 if (null != value) 5881 if (null != value)
7212 { 5882 {
7213 patchMetadata.Description = value; 5883 xPatchMetadata.SetAttributeValue("Description", value);
7214 } 5884 }
7215 break; 5885 break;
7216 case "DisplayName": 5886 case "DisplayName":
7217 if (null != value) 5887 if (null != value)
7218 { 5888 {
7219 patchMetadata.DisplayName = value; 5889 xPatchMetadata.SetAttributeValue("DisplayName", value);
7220 } 5890 }
7221 break; 5891 break;
7222 case "ManufacturerName": 5892 case "ManufacturerName":
7223 if (null != value) 5893 if (null != value)
7224 { 5894 {
7225 patchMetadata.ManufacturerName = value; 5895 xPatchMetadata.SetAttributeValue("ManufacturerName", value);
7226 } 5896 }
7227 break; 5897 break;
7228 case "MinorUpdateTargetRTM": 5898 case "MinorUpdateTargetRTM":
7229 if (null != value) 5899 if (null != value)
7230 { 5900 {
7231 patchMetadata.MinorUpdateTargetRTM = value; 5901 xPatchMetadata.SetAttributeValue("MinorUpdateTargetRTM", value);
7232 } 5902 }
7233 break; 5903 break;
7234 case "MoreInfoURL": 5904 case "MoreInfoURL":
7235 if (null != value) 5905 if (null != value)
7236 { 5906 {
7237 patchMetadata.MoreInfoURL = value; 5907 xPatchMetadata.SetAttributeValue("MoreInfoURL", value);
7238 } 5908 }
7239 break; 5909 break;
7240 case "OptimizeCA": 5910 case "OptimizeCA":
7241 var optimizeCustomActions = new Wix.OptimizeCustomActions(); 5911 var xOptimizeCustomActions = new XElement(Names.OptimizeCustomActionsElement);
7242 var optimizeCA = Int32.Parse(value, CultureInfo.InvariantCulture); 5912 var optimizeCA = Int32.Parse(value, CultureInfo.InvariantCulture);
7243 if (0 != (Convert.ToInt32(OptimizeCA.SkipAssignment) & optimizeCA)) 5913 if (0 != (Convert.ToInt32(OptimizeCA.SkipAssignment) & optimizeCA))
7244 { 5914 {
7245 optimizeCustomActions.SkipAssignment = Wix.YesNoType.yes; 5915 xOptimizeCustomActions.SetAttributeValue("SkipAssignment", "yes");
7246 } 5916 }
7247
7248 if (0 != (Convert.ToInt32(OptimizeCA.SkipImmediate) & optimizeCA))
7249 {
7250 optimizeCustomActions.SkipImmediate = Wix.YesNoType.yes;
7251 }
7252
7253 if (0 != (Convert.ToInt32(OptimizeCA.SkipDeferred) & optimizeCA))
7254 {
7255 optimizeCustomActions.SkipDeferred = Wix.YesNoType.yes;
7256 }
7257
7258 patchMetadata.AddChild(optimizeCustomActions);
7259 break;
7260 case "OptimizedInstallMode":
7261 if ("1" == value)
7262 {
7263 patchMetadata.OptimizedInstallMode = Wix.YesNoType.yes;
7264 }
7265 break;
7266 case "TargetProductName":
7267 if (null != value)
7268 {
7269 patchMetadata.TargetProductName = value;
7270 }
7271 break;
7272 default:
7273 var customProperty = new Wix.CustomProperty();
7274 5917
7275 if (null != row[0]) 5918 if (0 != (Convert.ToInt32(OptimizeCA.SkipImmediate) & optimizeCA))
7276 { 5919 {
7277 customProperty.Company = Convert.ToString(row[0]); 5920 xOptimizeCustomActions.SetAttributeValue("SkipImmediate", "yes");
7278 } 5921 }
7279 5922
7280 customProperty.Property = Convert.ToString(row[1]); 5923 if (0 != (Convert.ToInt32(OptimizeCA.SkipDeferred) & optimizeCA))
5924 {
5925 xOptimizeCustomActions.SetAttributeValue("SkipDeferred", "yes");
5926 }
7281 5927
7282 if (null != row[2]) 5928 xPatchMetadata.Add(xOptimizeCustomActions);
7283 { 5929 break;
7284 customProperty.Value = Convert.ToString(row[2]); 5930 case "OptimizedInstallMode":
7285 } 5931 if ("1" == value)
5932 {
5933 xPatchMetadata.SetAttributeValue("OptimizedInstallMode", "yes");
5934 }
5935 break;
5936 case "TargetProductName":
5937 if (null != value)
5938 {
5939 xPatchMetadata.SetAttributeValue("TargetProductName", value);
5940 }
5941 break;
5942 default:
5943 var xCustomProperty = new XElement(Names.CustomPropertyElement,
5944 XAttributeIfNotNull("Company", row, 0),
5945 XAttributeIfNotNull("Property", row, 1),
5946 XAttributeIfNotNull("Value", row, 2));
7286 5947
7287 patchMetadata.AddChild(customProperty); 5948 xPatchMetadata.Add(xCustomProperty);
7288 break; 5949 break;
7289 } 5950 }
7290 } 5951 }
7291 5952
7292 this.core.RootElement.AddChild(patchMetadata); 5953 this.RootElement.Add(xPatchMetadata);
7293 } 5954 }
7294 } 5955 }
7295 5956
@@ -7301,35 +5962,34 @@ namespace WixToolset.Core.WindowsInstaller
7301 { 5962 {
7302 foreach (var row in table.Rows) 5963 foreach (var row in table.Rows)
7303 { 5964 {
7304 var patchSequence = new Wix.PatchSequence(); 5965 var patchSequence = new XElement(Names.PatchSequenceElement,
7305 5966 new XAttribute("PatchFamily", row.FieldAsString(0)));
7306 patchSequence.PatchFamily = Convert.ToString(row[0]);
7307 5967
7308 if (null != row[1]) 5968 if (!row.IsColumnNull(1))
7309 { 5969 {
7310 try 5970 try
7311 { 5971 {
7312 var guid = new Guid(Convert.ToString(row[1])); 5972 var guid = new Guid(row.FieldAsString(1));
7313 5973
7314 patchSequence.ProductCode = Convert.ToString(row[1]); 5974 patchSequence.SetAttributeValue("ProductCode", row.FieldAsString(1));
7315 } 5975 }
7316 catch // non-guid value 5976 catch // non-guid value
7317 { 5977 {
7318 patchSequence.TargetImage = Convert.ToString(row[1]); 5978 patchSequence.SetAttributeValue("TargetImage", row.FieldAsString(1));
7319 } 5979 }
7320 } 5980 }
7321 5981
7322 if (null != row[2]) 5982 if (!row.IsColumnNull(2))
7323 { 5983 {
7324 patchSequence.Sequence = Convert.ToString(row[2]); 5984 patchSequence.SetAttributeValue("Sequence", row.FieldAsString(2));
7325 } 5985 }
7326 5986
7327 if (null != row[3] && 0x1 == Convert.ToInt32(row[3])) 5987 if (!row.IsColumnNull(3) && 0x1 == row.FieldAsInteger(3))
7328 { 5988 {
7329 patchSequence.Supersede = Wix.YesNoType.yes; 5989 patchSequence.SetAttributeValue("Supersede", "yes");
7330 } 5990 }
7331 5991
7332 this.core.RootElement.AddChild(patchSequence); 5992 this.RootElement.Add(patchSequence);
7333 } 5993 }
7334 } 5994 }
7335 5995
@@ -7341,49 +6001,26 @@ namespace WixToolset.Core.WindowsInstaller
7341 { 6001 {
7342 foreach (var row in table.Rows) 6002 foreach (var row in table.Rows)
7343 { 6003 {
7344 var progId = new Wix.ProgId(); 6004 var xProgId = new XElement(Names.ProgIdElement,
7345 6005 new XAttribute("Advertise", "yes"),
7346 progId.Advertise = Wix.YesNoType.yes; 6006 new XAttribute("Id", row.FieldAsString(0)),
6007 XAttributeIfNotNull("Description", row, 3),
6008 XAttributeIfNotNull("Icon", row, 4),
6009 XAttributeIfNotNull("IconIndex", row, 5));
7347 6010
7348 progId.Id = Convert.ToString(row[0]); 6011 this.IndexElement(row, xProgId);
7349
7350 if (null != row[3])
7351 {
7352 progId.Description = Convert.ToString(row[3]);
7353 }
7354
7355 if (null != row[4])
7356 {
7357 progId.Icon = Convert.ToString(row[4]);
7358 }
7359
7360 if (null != row[5])
7361 {
7362 progId.IconIndex = Convert.ToInt32(row[5]);
7363 }
7364
7365 this.core.IndexElement(row, progId);
7366 } 6012 }
7367 6013
7368 // nest the ProgIds 6014 // nest the ProgIds
7369 foreach (var row in table.Rows) 6015 foreach (var row in table.Rows)
7370 { 6016 {
7371 var progId = (Wix.ProgId)this.core.GetIndexedElement(row); 6017 var xProgId = this.GetIndexedElement(row);
7372 6018
7373 if (null != row[1]) 6019 if (!row.IsColumnNull(1))
7374 { 6020 {
7375 var parentProgId = (Wix.ProgId)this.core.GetIndexedElement("ProgId", Convert.ToString(row[1])); 6021 this.AddChildToParent("ProgId", xProgId, row, 1);
7376
7377 if (null != parentProgId)
7378 {
7379 parentProgId.AddChild(progId);
7380 }
7381 else
7382 {
7383 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "ProgId_Parent", Convert.ToString(row[1]), "ProgId"));
7384 }
7385 } 6022 }
7386 else if (null != row[2]) 6023 else if (!row.IsColumnNull(2))
7387 { 6024 {
7388 // nesting is handled in FinalizeProgIdTable 6025 // nesting is handled in FinalizeProgIdTable
7389 } 6026 }
@@ -7400,107 +6037,101 @@ namespace WixToolset.Core.WindowsInstaller
7400 /// <param name="table">The table to decompile.</param> 6037 /// <param name="table">The table to decompile.</param>
7401 private void DecompilePropertiesTable(Table table) 6038 private void DecompilePropertiesTable(Table table)
7402 { 6039 {
7403 var patchCreation = (Wix.PatchCreation)this.core.RootElement;
7404
7405 foreach (var row in table.Rows) 6040 foreach (var row in table.Rows)
7406 { 6041 {
7407 var name = Convert.ToString(row[0]); 6042 var name = row.FieldAsString(0);
7408 var value = Convert.ToString(row[1]); 6043 var value = row.FieldAsString(1);
7409 6044
7410 switch (name) 6045 switch (name)
7411 { 6046 {
7412 case "AllowProductCodeMismatches": 6047 case "AllowProductCodeMismatches":
7413 if ("1" == value) 6048 if ("1" == value)
7414 { 6049 {
7415 patchCreation.AllowProductCodeMismatches = Wix.YesNoType.yes; 6050 this.RootElement.SetAttributeValue("AllowProductCodeMismatches", "yes");
7416 } 6051 }
7417 break; 6052 break;
7418 case "AllowProductVersionMajorMismatches": 6053 case "AllowProductVersionMajorMismatches":
7419 if ("1" == value) 6054 if ("1" == value)
7420 { 6055 {
7421 patchCreation.AllowMajorVersionMismatches = Wix.YesNoType.yes; 6056 this.RootElement.SetAttributeValue("AllowMajorVersionMismatches", "yes");
7422 } 6057 }
7423 break; 6058 break;
7424 case "ApiPatchingSymbolFlags": 6059 case "ApiPatchingSymbolFlags":
7425 if (null != value) 6060 if (null != value)
7426 {
7427 try
7428 { 6061 {
7429 // remove the leading "0x" if its present 6062 try
7430 if (value.StartsWith("0x", StringComparison.Ordinal))
7431 { 6063 {
7432 value = value.Substring(2); 6064 // remove the leading "0x" if its present
7433 } 6065 if (value.StartsWith("0x", StringComparison.Ordinal))
6066 {
6067 value = value.Substring(2);
6068 }
7434 6069
7435 patchCreation.SymbolFlags = Convert.ToInt32(value, 16); 6070 this.RootElement.SetAttributeValue("SymbolFlags", Convert.ToInt32(value, 16));
6071 }
6072 catch
6073 {
6074 this.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[1].Column.Name, row[1]));
6075 }
7436 } 6076 }
7437 catch 6077 break;
6078 case "DontRemoveTempFolderWhenFinished":
6079 if ("1" == value)
7438 { 6080 {
7439 this.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[1].Column.Name, row[1])); 6081 this.RootElement.SetAttributeValue("CleanWorkingFolder", "no");
7440 } 6082 }
7441 } 6083 break;
7442 break; 6084 case "IncludeWholeFilesOnly":
7443 case "DontRemoveTempFolderWhenFinished": 6085 if ("1" == value)
7444 if ("1" == value)
7445 {
7446 patchCreation.CleanWorkingFolder = Wix.YesNoType.no;
7447 }
7448 break;
7449 case "IncludeWholeFilesOnly":
7450 if ("1" == value)
7451 {
7452 patchCreation.WholeFilesOnly = Wix.YesNoType.yes;
7453 }
7454 break;
7455 case "ListOfPatchGUIDsToReplace":
7456 if (null != value)
7457 {
7458 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}\}");
7459 var guidMatches = guidRegex.Matches(value);
7460
7461 foreach (Match guidMatch in guidMatches)
7462 { 6086 {
7463 var replacePatch = new Wix.ReplacePatch(); 6087 this.RootElement.SetAttributeValue("WholeFilesOnly", "yes");
7464
7465 replacePatch.Id = guidMatch.Value;
7466
7467 this.core.RootElement.AddChild(replacePatch);
7468 } 6088 }
7469 } 6089 break;
7470 break; 6090 case "ListOfPatchGUIDsToReplace":
7471 case "ListOfTargetProductCodes": 6091 if (null != value)
7472 if (null != value)
7473 {
7474 var targetProductCodes = value.Split(';');
7475
7476 foreach (var targetProductCodeString in targetProductCodes)
7477 { 6092 {
7478 var targetProductCode = new Wix.TargetProductCode(); 6093 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}\}");
6094 var guidMatches = guidRegex.Matches(value);
7479 6095
7480 targetProductCode.Id = targetProductCodeString; 6096 foreach (Match guidMatch in guidMatches)
6097 {
6098 var xReplacePatch = new XElement(Names.ReplacePatchElement,
6099 new XAttribute("Id", guidMatch.Value));
7481 6100
7482 this.core.RootElement.AddChild(targetProductCode); 6101 this.RootElement.Add(xReplacePatch);
6102 }
7483 } 6103 }
7484 } 6104 break;
7485 break; 6105 case "ListOfTargetProductCodes":
7486 case "PatchGUID": 6106 if (null != value)
7487 patchCreation.Id = value; 6107 {
7488 break; 6108 var targetProductCodes = value.Split(';');
7489 case "PatchSourceList":
7490 patchCreation.SourceList = value;
7491 break;
7492 case "PatchOutputPath":
7493 patchCreation.OutputPath = value;
7494 break;
7495 default:
7496 var patchProperty = new Wix.PatchProperty();
7497 6109
7498 patchProperty.Name = name; 6110 foreach (var targetProductCodeString in targetProductCodes)
6111 {
6112 var xTargetProductCode = new XElement(Names.TargetProductCodeElement,
6113 new XAttribute("Id", targetProductCodeString));
7499 6114
7500 patchProperty.Value = value; 6115 this.RootElement.Add(xTargetProductCode);
6116 }
6117 }
6118 break;
6119 case "PatchGUID":
6120 this.RootElement.SetAttributeValue("Id", value);
6121 break;
6122 case "PatchSourceList":
6123 this.RootElement.SetAttributeValue("SourceList", value);
6124 break;
6125 case "PatchOutputPath":
6126 this.RootElement.SetAttributeValue("OutputPath", value);
6127 break;
6128 default:
6129 var patchProperty = new XElement(Names.PatchPropertyElement,
6130 new XAttribute("Name", name),
6131 new XAttribute("Value", value));
7501 6132
7502 this.core.RootElement.AddChild(patchProperty); 6133 this.RootElement.Add(patchProperty);
7503 break; 6134 break;
7504 } 6135 }
7505 } 6136 }
7506 } 6137 }
@@ -7513,8 +6144,8 @@ namespace WixToolset.Core.WindowsInstaller
7513 { 6144 {
7514 foreach (var row in table.Rows) 6145 foreach (var row in table.Rows)
7515 { 6146 {
7516 var id = Convert.ToString(row[0]); 6147 var id = row.FieldAsString(0);
7517 var value = Convert.ToString(row[1]); 6148 var value = row.FieldAsString(1);
7518 6149
7519 if ("AdminProperties" == id || "MsiHiddenProperties" == id || "SecureCustomProperties" == id) 6150 if ("AdminProperties" == id || "MsiHiddenProperties" == id || "SecureCustomProperties" == id)
7520 { 6151 {
@@ -7531,9 +6162,9 @@ namespace WixToolset.Core.WindowsInstaller
7531 var suppressModulularization = false; 6162 var suppressModulularization = false;
7532 if (OutputType.Module == this.OutputType) 6163 if (OutputType.Module == this.OutputType)
7533 { 6164 {
7534 if (propertyId.EndsWith(this.modularizationGuid.Substring(1, 36).Replace('-', '_'), StringComparison.Ordinal)) 6165 if (propertyId.EndsWith(this.ModularizationGuid.Substring(1, 36).Replace('-', '_'), StringComparison.Ordinal))
7535 { 6166 {
7536 property = propertyId.Substring(0, propertyId.Length - this.modularizationGuid.Length + 1); 6167 property = propertyId.Substring(0, propertyId.Length - this.ModularizationGuid.Length + 1);
7537 } 6168 }
7538 else 6169 else
7539 { 6170 {
@@ -7541,23 +6172,23 @@ namespace WixToolset.Core.WindowsInstaller
7541 } 6172 }
7542 } 6173 }
7543 6174
7544 var specialProperty = this.EnsureProperty(property); 6175 var xSpecialProperty = this.EnsureProperty(property);
7545 if (suppressModulularization) 6176 if (suppressModulularization)
7546 { 6177 {
7547 specialProperty.SuppressModularization = Wix.YesNoType.yes; 6178 xSpecialProperty.SetAttributeValue("SuppressModularization", "yes");
7548 } 6179 }
7549 6180
7550 switch (id) 6181 switch (id)
7551 { 6182 {
7552 case "AdminProperties": 6183 case "AdminProperties":
7553 specialProperty.Admin = Wix.YesNoType.yes; 6184 xSpecialProperty.SetAttributeValue("Admin", "yes");
7554 break; 6185 break;
7555 case "MsiHiddenProperties": 6186 case "MsiHiddenProperties":
7556 specialProperty.Hidden = Wix.YesNoType.yes; 6187 xSpecialProperty.SetAttributeValue("Hidden", "yes");
7557 break; 6188 break;
7558 case "SecureCustomProperties": 6189 case "SecureCustomProperties":
7559 specialProperty.Secure = Wix.YesNoType.yes; 6190 xSpecialProperty.SetAttributeValue("Secure", "yes");
7560 break; 6191 break;
7561 } 6192 }
7562 } 6193 }
7563 } 6194 }
@@ -7566,36 +6197,34 @@ namespace WixToolset.Core.WindowsInstaller
7566 } 6197 }
7567 else if (OutputType.Product == this.OutputType) 6198 else if (OutputType.Product == this.OutputType)
7568 { 6199 {
7569 var product = (Wix.Product)this.core.RootElement;
7570
7571 switch (id) 6200 switch (id)
7572 { 6201 {
7573 case "Manufacturer": 6202 case "Manufacturer":
7574 product.Manufacturer = value; 6203 this.RootElement.SetAttributeValue("Manufacturer", value);
7575 continue; 6204 continue;
7576 case "ProductCode": 6205 case "ProductCode":
7577 product.Id = value.ToUpper(CultureInfo.InvariantCulture); 6206 this.RootElement.SetAttributeValue("Id", value.ToUpper(CultureInfo.InvariantCulture));
7578 continue; 6207 continue;
7579 case "ProductLanguage": 6208 case "ProductLanguage":
7580 product.Language = value; 6209 this.RootElement.SetAttributeValue("Language", value);
7581 continue; 6210 continue;
7582 case "ProductName": 6211 case "ProductName":
7583 product.Name = value; 6212 this.RootElement.SetAttributeValue("Name", value);
7584 continue; 6213 continue;
7585 case "ProductVersion": 6214 case "ProductVersion":
7586 product.Version = value; 6215 this.RootElement.SetAttributeValue("Version", value);
7587 continue; 6216 continue;
7588 case "UpgradeCode": 6217 case "UpgradeCode":
7589 product.UpgradeCode = value; 6218 this.RootElement.SetAttributeValue("UpgradeCode", value);
7590 continue; 6219 continue;
7591 } 6220 }
7592 } 6221 }
7593 6222
7594 if (!this.SuppressUI || "ErrorDialog" != id) 6223 if (!this.SuppressUI || "ErrorDialog" != id)
7595 { 6224 {
7596 var property = this.EnsureProperty(id); 6225 var xProperty = this.EnsureProperty(id);
7597 6226
7598 property.Value = value; 6227 xProperty.SetAttributeValue("Value", value);
7599 } 6228 }
7600 } 6229 }
7601 } 6230 }
@@ -7608,26 +6237,12 @@ namespace WixToolset.Core.WindowsInstaller
7608 { 6237 {
7609 foreach (var row in table.Rows) 6238 foreach (var row in table.Rows)
7610 { 6239 {
7611 var category = new Wix.Category(); 6240 var category = new XElement(Names.CategoryElement,
7612 6241 new XAttribute("Id", row.FieldAsString(0)),
7613 category.Id = Convert.ToString(row[0]); 6242 new XAttribute("Qualifier", row.FieldAsString(1)),
7614 6243 XAttributeIfNotNull("AppData", row, 3));
7615 category.Qualifier = Convert.ToString(row[1]);
7616
7617 if (null != row[3])
7618 {
7619 category.AppData = Convert.ToString(row[3]);
7620 }
7621 6244
7622 var component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[2])); 6245 this.AddChildToParent("Component", category, row, 2);
7623 if (null != component)
7624 {
7625 component.AddChild(category);
7626 }
7627 else
7628 {
7629 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[2]), "Component"));
7630 }
7631 } 6246 }
7632 } 6247 }
7633 6248
@@ -7637,67 +6252,53 @@ namespace WixToolset.Core.WindowsInstaller
7637 /// <param name="table">The table to decompile.</param> 6252 /// <param name="table">The table to decompile.</param>
7638 private void DecompileRadioButtonTable(Table table) 6253 private void DecompileRadioButtonTable(Table table)
7639 { 6254 {
7640 var radioButtons = new SortedList();
7641 var radioButtonGroups = new Hashtable();
7642
7643 foreach (var row in table.Rows) 6255 foreach (var row in table.Rows)
7644 { 6256 {
7645 var radioButton = new Wix.RadioButton(); 6257 var radioButton = new XElement(Names.RadioButtonElement,
7646 6258 new XAttribute("Value", row.FieldAsString(2)),
7647 radioButton.Value = Convert.ToString(row[2]); 6259 new XAttribute("X", row.FieldAsInteger(3)),
7648 6260 new XAttribute("Y", row.FieldAsInteger(4)),
7649 radioButton.X = Convert.ToString(row[3], CultureInfo.InvariantCulture); 6261 new XAttribute("Width", row.FieldAsInteger(5)),
7650 6262 new XAttribute("Height", row.FieldAsInteger(6)),
7651 radioButton.Y = Convert.ToString(row[4], CultureInfo.InvariantCulture); 6263 XAttributeIfNotNull("Text", row, 7));
7652
7653 radioButton.Width = Convert.ToString(row[5], CultureInfo.InvariantCulture);
7654
7655 radioButton.Height = Convert.ToString(row[6], CultureInfo.InvariantCulture);
7656
7657 if (null != row[7])
7658 {
7659 radioButton.Text = Convert.ToString(row[7]);
7660 }
7661 6264
7662 if (null != row[8]) 6265 if (!row.IsColumnNull(8))
7663 { 6266 {
7664 var help = (Convert.ToString(row[8])).Split('|'); 6267 var help = (row.FieldAsString(8)).Split('|');
7665 6268
7666 if (2 == help.Length) 6269 if (2 == help.Length)
7667 { 6270 {
7668 if (0 < help[0].Length) 6271 if (0 < help[0].Length)
7669 { 6272 {
7670 radioButton.ToolTip = help[0]; 6273 radioButton.SetAttributeValue("ToolTip", help[0]);
7671 } 6274 }
7672 6275
7673 if (0 < help[1].Length) 6276 if (0 < help[1].Length)
7674 { 6277 {
7675 radioButton.Help = help[1]; 6278 radioButton.SetAttributeValue("Help", help[1]);
7676 } 6279 }
7677 } 6280 }
7678 } 6281 }
7679 6282
7680 radioButtons.Add(String.Format(CultureInfo.InvariantCulture, "{0}|{1:0000000000}", row[0], row[1]), row); 6283 this.IndexElement(row, radioButton);
7681 this.core.IndexElement(row, radioButton);
7682 } 6284 }
7683 6285
7684 // nest the radio buttons 6286 // nest the radio buttons
7685 foreach (Row row in radioButtons.Values) 6287 var xRadioButtonGroups = new Dictionary<string, XElement>();
6288 foreach (var row in table.Rows.OrderBy(row => row.FieldAsString(0)).ThenBy(row => row.FieldAsInteger(1)))
7686 { 6289 {
7687 var radioButton = (Wix.RadioButton)this.core.GetIndexedElement(row); 6290 var xRadioButton = this.GetIndexedElement(row);
7688 var radioButtonGroup = (Wix.RadioButtonGroup)radioButtonGroups[Convert.ToString(row[0])];
7689 6291
7690 if (null == radioButtonGroup) 6292 if (!xRadioButtonGroups.TryGetValue(row.FieldAsString(0), out var xRadioButtonGroup))
7691 { 6293 {
7692 radioButtonGroup = new Wix.RadioButtonGroup(); 6294 xRadioButtonGroup = new XElement(Names.RadioButtonGroupElement,
6295 new XAttribute("Property", row.FieldAsString(0)));
7693 6296
7694 radioButtonGroup.Property = Convert.ToString(row[0]); 6297 this.UIElement.Add(xRadioButtonGroup);
7695 6298 xRadioButtonGroups.Add(row.FieldAsString(0), xRadioButtonGroup);
7696 this.core.UIElement.AddChild(radioButtonGroup);
7697 radioButtonGroups.Add(Convert.ToString(row[0]), radioButtonGroup);
7698 } 6299 }
7699 6300
7700 radioButtonGroup.AddChild(radioButton); 6301 xRadioButtonGroup.Add(xRadioButton);
7701 } 6302 }
7702 } 6303 }
7703 6304
@@ -7709,71 +6310,63 @@ namespace WixToolset.Core.WindowsInstaller
7709 { 6310 {
7710 foreach (var row in table.Rows) 6311 foreach (var row in table.Rows)
7711 { 6312 {
7712 if (("-" == Convert.ToString(row[3]) || "+" == Convert.ToString(row[3]) || "*" == Convert.ToString(row[3])) && null == row[4]) 6313 if (("-" == row.FieldAsString(3) || "+" == row.FieldAsString(3) || "*" == row.FieldAsString(3)) && row.IsColumnNull(4))
7713 { 6314 {
7714 var registryKey = new Wix.RegistryKey(); 6315 var xRegistryKey = new XElement(Names.RegistryKeyElement,
7715 6316 new XAttribute("Id", row.FieldAsString(0)),
7716 registryKey.Id = Convert.ToString(row[0]); 6317 new XAttribute("Key", row.FieldAsString(2)));
7717 6318
7718 if (this.GetRegistryRootType(row.SourceLineNumbers, table.Name, row.Fields[1], out var registryRootType)) 6319 if (this.GetRegistryRootType(row.SourceLineNumbers, table.Name, row.Fields[1], out var registryRootType))
7719 { 6320 {
7720 registryKey.Root = registryRootType; 6321 xRegistryKey.SetAttributeValue("Root", registryRootType);
7721 } 6322 }
7722 6323
7723 registryKey.Key = Convert.ToString(row[2]); 6324 switch (row.FieldAsString(3))
7724
7725 switch (Convert.ToString(row[3]))
7726 { 6325 {
7727 case "+": 6326 case "+":
7728 registryKey.ForceCreateOnInstall = Wix.YesNoType.yes; 6327 xRegistryKey.SetAttributeValue("ForceCreateOnInstall", "yes");
7729 break; 6328 break;
7730 case "-": 6329 case "-":
7731 registryKey.ForceDeleteOnUninstall = Wix.YesNoType.yes; 6330 xRegistryKey.SetAttributeValue("ForceDeleteOnUninstall", "yes");
7732 break; 6331 break;
7733 case "*": 6332 case "*":
7734 registryKey.ForceDeleteOnUninstall = Wix.YesNoType.yes; 6333 xRegistryKey.SetAttributeValue("ForceCreateOnInstall", "yes");
7735 registryKey.ForceCreateOnInstall = Wix.YesNoType.yes; 6334 xRegistryKey.SetAttributeValue("ForceDeleteOnUninstall", "yes");
7736 break; 6335 break;
7737 } 6336 }
7738 6337
7739 this.core.IndexElement(row, registryKey); 6338 this.IndexElement(row, xRegistryKey);
7740 } 6339 }
7741 else 6340 else
7742 { 6341 {
7743 var registryValue = new Wix.RegistryValue(); 6342 var xRegistryValue = new XElement(Names.RegistryValueElement,
7744 6343 new XAttribute("Id", row.FieldAsString(0)),
7745 registryValue.Id = Convert.ToString(row[0]); 6344 new XAttribute("Key", row.FieldAsString(2)),
6345 XAttributeIfNotNull("Name", row, 3));
7746 6346
7747 if (this.GetRegistryRootType(row.SourceLineNumbers, table.Name, row.Fields[1], out var registryRootType)) 6347 if (this.GetRegistryRootType(row.SourceLineNumbers, table.Name, row.Fields[1], out var registryRootType))
7748 { 6348 {
7749 registryValue.Root = registryRootType; 6349 xRegistryValue.SetAttributeValue("Root", registryRootType);
7750 } 6350 }
7751 6351
7752 registryValue.Key = Convert.ToString(row[2]); 6352 if (!row.IsColumnNull(4))
7753
7754 if (null != row[3])
7755 { 6353 {
7756 registryValue.Name = Convert.ToString(row[3]); 6354 var value = row.FieldAsString(4);
7757 }
7758
7759 if (null != row[4])
7760 {
7761 var value = Convert.ToString(row[4]);
7762 6355
7763 if (value.StartsWith("#x", StringComparison.Ordinal)) 6356 if (value.StartsWith("#x", StringComparison.Ordinal))
7764 { 6357 {
7765 registryValue.Type = Wix.RegistryValue.TypeType.binary; 6358 xRegistryValue.SetAttributeValue("Type", "binary");
7766 registryValue.Value = value.Substring(2); 6359 xRegistryValue.SetAttributeValue("Value", value.Substring(2));
7767 } 6360 }
7768 else if (value.StartsWith("#%", StringComparison.Ordinal)) 6361 else if (value.StartsWith("#%", StringComparison.Ordinal))
7769 { 6362 {
7770 registryValue.Type = Wix.RegistryValue.TypeType.expandable; 6363 xRegistryValue.SetAttributeValue("Type", "expandable");
7771 registryValue.Value = value.Substring(2); 6364 xRegistryValue.SetAttributeValue("Value", value.Substring(2));
7772 } 6365 }
7773 else if (value.StartsWith("#", StringComparison.Ordinal) && !value.StartsWith("##", StringComparison.Ordinal)) 6366 else if (value.StartsWith("#", StringComparison.Ordinal) && !value.StartsWith("##", StringComparison.Ordinal))
7774 { 6367 {
7775 registryValue.Type = Wix.RegistryValue.TypeType.integer; 6368 xRegistryValue.SetAttributeValue("Type", "integer");
7776 registryValue.Value = value.Substring(1); 6369 xRegistryValue.SetAttributeValue("Value", value.Substring(1));
7777 } 6370 }
7778 else 6371 else
7779 { 6372 {
@@ -7784,7 +6377,7 @@ namespace WixToolset.Core.WindowsInstaller
7784 6377
7785 if (0 <= value.IndexOf("[~]", StringComparison.Ordinal)) 6378 if (0 <= value.IndexOf("[~]", StringComparison.Ordinal))
7786 { 6379 {
7787 registryValue.Type = Wix.RegistryValue.TypeType.multiString; 6380 xRegistryValue.SetAttributeValue("Type", "multiString");
7788 6381
7789 if ("[~]" == value) 6382 if ("[~]" == value)
7790 { 6383 {
@@ -7796,39 +6389,38 @@ namespace WixToolset.Core.WindowsInstaller
7796 } 6389 }
7797 else if (value.StartsWith("[~]", StringComparison.Ordinal)) 6390 else if (value.StartsWith("[~]", StringComparison.Ordinal))
7798 { 6391 {
7799 registryValue.Action = Wix.RegistryValue.ActionType.append; 6392 xRegistryValue.SetAttributeValue("Action", "append");
7800 value = value.Substring(3); 6393 value = value.Substring(3);
7801 } 6394 }
7802 else if (value.EndsWith("[~]", StringComparison.Ordinal)) 6395 else if (value.EndsWith("[~]", StringComparison.Ordinal))
7803 { 6396 {
7804 registryValue.Action = Wix.RegistryValue.ActionType.prepend; 6397 xRegistryValue.SetAttributeValue("Action", "prepend");
7805 value = value.Substring(0, value.Length - 3); 6398 value = value.Substring(0, value.Length - 3);
7806 } 6399 }
7807 6400
7808 var multiValues = NullSplitter.Split(value); 6401 var multiValues = NullSplitter.Split(value);
7809 foreach (var multiValue in multiValues) 6402 foreach (var multiValue in multiValues)
7810 { 6403 {
7811 var multiStringValue = new Wix.MultiStringValue(); 6404 var xMultiStringValue = new XElement(Names.MultiStringElement,
7812 6405 new XAttribute("Value", multiValue));
7813 multiStringValue.Content = multiValue;
7814 6406
7815 registryValue.AddChild(multiStringValue); 6407 xRegistryValue.Add(xMultiStringValue);
7816 } 6408 }
7817 } 6409 }
7818 else 6410 else
7819 { 6411 {
7820 registryValue.Type = Wix.RegistryValue.TypeType.@string; 6412 xRegistryValue.SetAttributeValue("Type", "string");
7821 registryValue.Value = value; 6413 xRegistryValue.SetAttributeValue("Value", value);
7822 } 6414 }
7823 } 6415 }
7824 } 6416 }
7825 else 6417 else
7826 { 6418 {
7827 registryValue.Type = Wix.RegistryValue.TypeType.@string; 6419 xRegistryValue.SetAttributeValue("Type", "string");
7828 registryValue.Value = String.Empty; 6420 xRegistryValue.SetAttributeValue("Value", String.Empty);
7829 } 6421 }
7830 6422
7831 this.core.IndexElement(row, registryValue); 6423 this.IndexElement(row, xRegistryValue);
7832 } 6424 }
7833 } 6425 }
7834 } 6426 }
@@ -7841,72 +6433,66 @@ namespace WixToolset.Core.WindowsInstaller
7841 { 6433 {
7842 foreach (var row in table.Rows) 6434 foreach (var row in table.Rows)
7843 { 6435 {
7844 var registrySearch = new Wix.RegistrySearch(); 6436 var xRegistrySearch = new XElement(Names.RegistrySearchElement,
7845 6437 new XAttribute("Id", row.FieldAsString(0)),
7846 registrySearch.Id = Convert.ToString(row[0]); 6438 new XAttribute("Key", row.FieldAsString(2)),
7847 6439 XAttributeIfNotNull("Name", row, 3));
7848 switch (Convert.ToInt32(row[1]))
7849 {
7850 case WindowsInstallerConstants.MsidbRegistryRootClassesRoot:
7851 registrySearch.Root = Wix.RegistrySearch.RootType.HKCR;
7852 break;
7853 case WindowsInstallerConstants.MsidbRegistryRootCurrentUser:
7854 registrySearch.Root = Wix.RegistrySearch.RootType.HKCU;
7855 break;
7856 case WindowsInstallerConstants.MsidbRegistryRootLocalMachine:
7857 registrySearch.Root = Wix.RegistrySearch.RootType.HKLM;
7858 break;
7859 case WindowsInstallerConstants.MsidbRegistryRootUsers:
7860 registrySearch.Root = Wix.RegistrySearch.RootType.HKU;
7861 break;
7862 default:
7863 this.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[1].Column.Name, row[1]));
7864 break;
7865 }
7866
7867 registrySearch.Key = Convert.ToString(row[2]);
7868 6440
7869 if (null != row[3]) 6441 switch (row.FieldAsInteger(1))
7870 { 6442 {
7871 registrySearch.Name = Convert.ToString(row[3]); 6443 case WindowsInstallerConstants.MsidbRegistryRootClassesRoot:
6444 xRegistrySearch.SetAttributeValue("Root", "HKCR");
6445 break;
6446 case WindowsInstallerConstants.MsidbRegistryRootCurrentUser:
6447 xRegistrySearch.SetAttributeValue("Root", "HKCU");
6448 break;
6449 case WindowsInstallerConstants.MsidbRegistryRootLocalMachine:
6450 xRegistrySearch.SetAttributeValue("Root", "HKLM");
6451 break;
6452 case WindowsInstallerConstants.MsidbRegistryRootUsers:
6453 xRegistrySearch.SetAttributeValue("Root", "HKU");
6454 break;
6455 default:
6456 this.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[1].Column.Name, row[1]));
6457 break;
7872 } 6458 }
7873 6459
7874 if (null == row[4]) 6460 if (row.IsColumnNull(4))
7875 { 6461 {
7876 registrySearch.Type = Wix.RegistrySearch.TypeType.file; 6462 xRegistrySearch.SetAttributeValue("Type", "file");
7877 } 6463 }
7878 else 6464 else
7879 { 6465 {
7880 var type = Convert.ToInt32(row[4]); 6466 var type = row.FieldAsInteger(4);
7881 6467
7882 if (WindowsInstallerConstants.MsidbLocatorType64bit == (type & WindowsInstallerConstants.MsidbLocatorType64bit)) 6468 if (WindowsInstallerConstants.MsidbLocatorType64bit == (type & WindowsInstallerConstants.MsidbLocatorType64bit))
7883 { 6469 {
7884 registrySearch.Win64 = Wix.YesNoType.yes; 6470 xRegistrySearch.SetAttributeValue("Win64", "yes");
7885 type &= ~WindowsInstallerConstants.MsidbLocatorType64bit; 6471 type &= ~WindowsInstallerConstants.MsidbLocatorType64bit;
7886 } 6472 }
7887 else 6473 else
7888 { 6474 {
7889 registrySearch.Win64 = Wix.YesNoType.no; 6475 xRegistrySearch.SetAttributeValue("Win64", "no");
7890 } 6476 }
7891 6477
7892 switch (type) 6478 switch (type)
7893 { 6479 {
7894 case WindowsInstallerConstants.MsidbLocatorTypeDirectory: 6480 case WindowsInstallerConstants.MsidbLocatorTypeDirectory:
7895 registrySearch.Type = Wix.RegistrySearch.TypeType.directory; 6481 xRegistrySearch.SetAttributeValue("Type", "directory");
7896 break; 6482 break;
7897 case WindowsInstallerConstants.MsidbLocatorTypeFileName: 6483 case WindowsInstallerConstants.MsidbLocatorTypeFileName:
7898 registrySearch.Type = Wix.RegistrySearch.TypeType.file; 6484 xRegistrySearch.SetAttributeValue("Type", "file");
7899 break; 6485 break;
7900 case WindowsInstallerConstants.MsidbLocatorTypeRawValue: 6486 case WindowsInstallerConstants.MsidbLocatorTypeRawValue:
7901 registrySearch.Type = Wix.RegistrySearch.TypeType.raw; 6487 xRegistrySearch.SetAttributeValue("Type", "raw");
7902 break; 6488 break;
7903 default: 6489 default:
7904 this.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[4].Column.Name, row[4])); 6490 this.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[4].Column.Name, row[4]));
7905 break; 6491 break;
7906 } 6492 }
7907 } 6493 }
7908 6494
7909 this.core.IndexElement(row, registrySearch); 6495 this.IndexElement(row, xRegistrySearch);
7910 } 6496 }
7911 } 6497 }
7912 6498
@@ -7918,86 +6504,68 @@ namespace WixToolset.Core.WindowsInstaller
7918 { 6504 {
7919 foreach (var row in table.Rows) 6505 foreach (var row in table.Rows)
7920 { 6506 {
7921 if (null == row[2]) 6507 if (row.IsColumnNull(2))
7922 { 6508 {
7923 var removeFolder = new Wix.RemoveFolder(); 6509 var xRemoveFolder = new XElement(Names.RemoveFolderElement,
7924 6510 new XAttribute("Id", row.FieldAsString(0)));
7925 removeFolder.Id = Convert.ToString(row[0]);
7926 6511
7927 // directory/property is set in FinalizeDecompile 6512 // directory/property is set in FinalizeDecompile
7928 6513
7929 switch (Convert.ToInt32(row[4])) 6514 switch (row.FieldAsInteger(4))
7930 { 6515 {
7931 case WindowsInstallerConstants.MsidbRemoveFileInstallModeOnInstall: 6516 case WindowsInstallerConstants.MsidbRemoveFileInstallModeOnInstall:
7932 removeFolder.On = Wix.InstallUninstallType.install; 6517 xRemoveFolder.SetAttributeValue("On", "install");
7933 break; 6518 break;
7934 case WindowsInstallerConstants.MsidbRemoveFileInstallModeOnRemove: 6519 case WindowsInstallerConstants.MsidbRemoveFileInstallModeOnRemove:
7935 removeFolder.On = Wix.InstallUninstallType.uninstall; 6520 xRemoveFolder.SetAttributeValue("On", "uninstall");
7936 break; 6521 break;
7937 case WindowsInstallerConstants.MsidbRemoveFileInstallModeOnBoth: 6522 case WindowsInstallerConstants.MsidbRemoveFileInstallModeOnBoth:
7938 removeFolder.On = Wix.InstallUninstallType.both; 6523 xRemoveFolder.SetAttributeValue("On", "both");
7939 break; 6524 break;
7940 default: 6525 default:
7941 this.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[4].Column.Name, row[4])); 6526 this.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[4].Column.Name, row[4]));
7942 break; 6527 break;
7943 } 6528 }
7944 6529
7945 var component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[1])); 6530 this.AddChildToParent("Component", xRemoveFolder, row, 1);
7946 if (null != component) 6531 this.IndexElement(row, xRemoveFolder);
7947 {
7948 component.AddChild(removeFolder);
7949 }
7950 else
7951 {
7952 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[1]), "Component"));
7953 }
7954 this.core.IndexElement(row, removeFolder);
7955 } 6532 }
7956 else 6533 else
7957 { 6534 {
7958 var removeFile = new Wix.RemoveFile(); 6535 var xRemoveFile = new XElement(Names.RemoveFileElement,
6536 new XAttribute("Id", row.FieldAsString(0)));
7959 6537
7960 removeFile.Id = Convert.ToString(row[0]); 6538 var names = Common.GetNames(row.FieldAsString(2));
7961
7962 var names = Common.GetNames(Convert.ToString(row[2]));
7963 if (null != names[0] && null != names[1]) 6539 if (null != names[0] && null != names[1])
7964 { 6540 {
7965 removeFile.ShortName = names[0]; 6541 xRemoveFile.SetAttributeValue("ShortName", names[0]);
7966 removeFile.Name = names[1]; 6542 xRemoveFile.SetAttributeValue("Name", names[1]);
7967 } 6543 }
7968 else if (null != names[0]) 6544 else if (null != names[0])
7969 { 6545 {
7970 removeFile.Name = names[0]; 6546 xRemoveFile.SetAttributeValue("Name", names[0]);
7971 } 6547 }
7972 6548
7973 // directory/property is set in FinalizeDecompile 6549 // directory/property is set in FinalizeDecompile
7974 6550
7975 switch (Convert.ToInt32(row[4])) 6551 switch (row.FieldAsInteger(4))
7976 { 6552 {
7977 case WindowsInstallerConstants.MsidbRemoveFileInstallModeOnInstall: 6553 case WindowsInstallerConstants.MsidbRemoveFileInstallModeOnInstall:
7978 removeFile.On = Wix.InstallUninstallType.install; 6554 xRemoveFile.SetAttributeValue("On", "install");
7979 break; 6555 break;
7980 case WindowsInstallerConstants.MsidbRemoveFileInstallModeOnRemove: 6556 case WindowsInstallerConstants.MsidbRemoveFileInstallModeOnRemove:
7981 removeFile.On = Wix.InstallUninstallType.uninstall; 6557 xRemoveFile.SetAttributeValue("On", "uninstall");
7982 break; 6558 break;
7983 case WindowsInstallerConstants.MsidbRemoveFileInstallModeOnBoth: 6559 case WindowsInstallerConstants.MsidbRemoveFileInstallModeOnBoth:
7984 removeFile.On = Wix.InstallUninstallType.both; 6560 xRemoveFile.SetAttributeValue("On", "both");
7985 break; 6561 break;
7986 default: 6562 default:
7987 this.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[4].Column.Name, row[4])); 6563 this.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[4].Column.Name, row[4]));
7988 break; 6564 break;
7989 } 6565 }
7990 6566
7991 var component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[1])); 6567 this.AddChildToParent("Component", xRemoveFile, row, 1);
7992 if (null != component) 6568 this.IndexElement(row, xRemoveFile);
7993 {
7994 component.AddChild(removeFile);
7995 }
7996 else
7997 {
7998 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[1]), "Component"));
7999 }
8000 this.core.IndexElement(row, removeFile);
8001 } 6569 }
8002 } 6570 }
8003 } 6571 }
@@ -8010,57 +6578,38 @@ namespace WixToolset.Core.WindowsInstaller
8010 { 6578 {
8011 foreach (var row in table.Rows) 6579 foreach (var row in table.Rows)
8012 { 6580 {
8013 var iniFile = new Wix.IniFile(); 6581 var xIniFile = new XElement(Names.IniFileElement,
8014 6582 new XAttribute("Id", row.FieldAsString(0)),
8015 iniFile.Id = Convert.ToString(row[0]); 6583 XAttributeIfNotNull("Directory", row, 2),
6584 new XAttribute("Section", row.FieldAsString(3)),
6585 new XAttribute("Key", row.FieldAsString(4)),
6586 XAttributeIfNotNull("Value", row, 5));
8016 6587
8017 var names = Common.GetNames(Convert.ToString(row[1])); 6588 var names = Common.GetNames(row.FieldAsString(1));
8018 if (null != names[0] && null != names[1]) 6589 if (null != names[0] && null != names[1])
8019 { 6590 {
8020 iniFile.ShortName = names[0]; 6591 xIniFile.SetAttributeValue("ShortName", names[0]);
8021 iniFile.Name = names[1]; 6592 xIniFile.SetAttributeValue("Name", names[1]);
8022 } 6593 }
8023 else if (null != names[0]) 6594 else if (null != names[0])
8024 { 6595 {
8025 iniFile.Name = names[0]; 6596 xIniFile.SetAttributeValue("Name", names[0]);
8026 } 6597 }
8027 6598
8028 if (null != row[2]) 6599 switch (row.FieldAsInteger(6))
8029 { 6600 {
8030 iniFile.Directory = Convert.ToString(row[2]); 6601 case WindowsInstallerConstants.MsidbIniFileActionRemoveLine:
8031 } 6602 xIniFile.SetAttributeValue("Action", "removeLine");
8032 6603 break;
8033 iniFile.Section = Convert.ToString(row[3]); 6604 case WindowsInstallerConstants.MsidbIniFileActionRemoveTag:
8034 6605 xIniFile.SetAttributeValue("Action", "removeTag");
8035 iniFile.Key = Convert.ToString(row[4]); 6606 break;
8036 6607 default:
8037 if (null != row[5]) 6608 this.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[6].Column.Name, row[6]));
8038 { 6609 break;
8039 iniFile.Value = Convert.ToString(row[5]);
8040 }
8041
8042 switch (Convert.ToInt32(row[6]))
8043 {
8044 case WindowsInstallerConstants.MsidbIniFileActionRemoveLine:
8045 iniFile.Action = Wix.IniFile.ActionType.removeLine;
8046 break;
8047 case WindowsInstallerConstants.MsidbIniFileActionRemoveTag:
8048 iniFile.Action = Wix.IniFile.ActionType.removeTag;
8049 break;
8050 default:
8051 this.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[6].Column.Name, row[6]));
8052 break;
8053 } 6610 }
8054 6611
8055 var component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[7])); 6612 this.AddChildToParent("Component", xIniFile, row, 7);
8056 if (null != component)
8057 {
8058 component.AddChild(iniFile);
8059 }
8060 else
8061 {
8062 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[7]), "Component"));
8063 }
8064 } 6613 }
8065 } 6614 }
8066 6615
@@ -8072,58 +6621,33 @@ namespace WixToolset.Core.WindowsInstaller
8072 { 6621 {
8073 foreach (var row in table.Rows) 6622 foreach (var row in table.Rows)
8074 { 6623 {
8075 if ("-" == Convert.ToString(row[3])) 6624 if ("-" == row.FieldAsString(3))
8076 { 6625 {
8077 var removeRegistryKey = new Wix.RemoveRegistryKey(); 6626 var xRemoveRegistryKey = new XElement(Names.RemoveRegistryKeyElement,
8078 6627 new XAttribute("Id", row.FieldAsString(0)),
8079 removeRegistryKey.Id = Convert.ToString(row[0]); 6628 new XAttribute("Key", row.FieldAsString(2)),
6629 new XAttribute("Action", "removeOnInstall"));
8080 6630
8081 if (this.GetRegistryRootType(row.SourceLineNumbers, table.Name, row.Fields[1], out var registryRootType)) 6631 if (this.GetRegistryRootType(row.SourceLineNumbers, table.Name, row.Fields[1], out var registryRootType))
8082 { 6632 {
8083 removeRegistryKey.Root = registryRootType; 6633 xRemoveRegistryKey.SetAttributeValue("Root", registryRootType);
8084 } 6634 }
8085 6635
8086 removeRegistryKey.Key = Convert.ToString(row[2]); 6636 this.AddChildToParent("Component", xRemoveRegistryKey, row, 4);
8087
8088 removeRegistryKey.Action = Wix.RemoveRegistryKey.ActionType.removeOnInstall;
8089
8090 var component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[4]));
8091 if (null != component)
8092 {
8093 component.AddChild(removeRegistryKey);
8094 }
8095 else
8096 {
8097 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[4]), "Component"));
8098 }
8099 } 6637 }
8100 else 6638 else
8101 { 6639 {
8102 var removeRegistryValue = new Wix.RemoveRegistryValue(); 6640 var xRemoveRegistryValue = new XElement(Names.RemoveRegistryValueElement,
8103 6641 new XAttribute("Id", row.FieldAsString(0)),
8104 removeRegistryValue.Id = Convert.ToString(row[0]); 6642 new XAttribute("Key", row.FieldAsString(2)),
6643 XAttributeIfNotNull("Name", row, 3));
8105 6644
8106 if (this.GetRegistryRootType(row.SourceLineNumbers, table.Name, row.Fields[1], out var registryRootType)) 6645 if (this.GetRegistryRootType(row.SourceLineNumbers, table.Name, row.Fields[1], out var registryRootType))
8107 { 6646 {
8108 removeRegistryValue.Root = registryRootType; 6647 xRemoveRegistryValue.SetAttributeValue("Root", registryRootType);
8109 }
8110
8111 removeRegistryValue.Key = Convert.ToString(row[2]);
8112
8113 if (null != row[3])
8114 {
8115 removeRegistryValue.Name = Convert.ToString(row[3]);
8116 } 6648 }
8117 6649
8118 var component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[4])); 6650 this.AddChildToParent("Component", xRemoveRegistryValue, row, 4);
8119 if (null != component)
8120 {
8121 component.AddChild(removeRegistryValue);
8122 }
8123 else
8124 {
8125 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[4]), "Component"));
8126 }
8127 } 6651 }
8128 } 6652 }
8129 } 6653 }
@@ -8136,28 +6660,13 @@ namespace WixToolset.Core.WindowsInstaller
8136 { 6660 {
8137 foreach (var row in table.Rows) 6661 foreach (var row in table.Rows)
8138 { 6662 {
8139 var reserveCost = new Wix.ReserveCost(); 6663 var xReserveCost = new XElement(Names.ReserveCostElement,
8140 6664 new XAttribute("Id", row.FieldAsString(0)),
8141 reserveCost.Id = Convert.ToString(row[0]); 6665 XAttributeIfNotNull("Directory", row, 2),
6666 new XAttribute("RunLocal", row.FieldAsString(3)),
6667 new XAttribute("RunFromSource", row.FieldAsString(4)));
8142 6668
8143 if (null != row[2]) 6669 this.AddChildToParent("Component", xReserveCost, row, 4);
8144 {
8145 reserveCost.Directory = Convert.ToString(row[2]);
8146 }
8147
8148 reserveCost.RunLocal = Convert.ToInt32(row[3]);
8149
8150 reserveCost.RunFromSource = Convert.ToInt32(row[4]);
8151
8152 var component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[1]));
8153 if (null != component)
8154 {
8155 component.AddChild(reserveCost);
8156 }
8157 else
8158 {
8159 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[1]), "Component"));
8160 }
8161 } 6670 }
8162 } 6671 }
8163 6672
@@ -8169,22 +6678,13 @@ namespace WixToolset.Core.WindowsInstaller
8169 { 6678 {
8170 foreach (var row in table.Rows) 6679 foreach (var row in table.Rows)
8171 { 6680 {
8172 var file = (Wix.File)this.core.GetIndexedElement("File", Convert.ToString(row[0])); 6681 if (this.TryGetIndexedElement("File", out var xFile, row.FieldAsString(0)))
8173
8174 if (null != file)
8175 { 6682 {
8176 if (null != row[1]) 6683 xFile.SetAttributeValue("SelfRegCost", row.IsColumnNull(1) ? 0 : row.FieldAsInteger(1));
8177 {
8178 file.SelfRegCost = Convert.ToInt32(row[1]);
8179 }
8180 else
8181 {
8182 file.SelfRegCost = 0;
8183 }
8184 } 6684 }
8185 else 6685 else
8186 { 6686 {
8187 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "File_", Convert.ToString(row[0]), "File")); 6687 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "File_", row.FieldAsString(0), "File"));
8188 } 6688 }
8189 } 6689 }
8190 } 6690 }
@@ -8197,90 +6697,72 @@ namespace WixToolset.Core.WindowsInstaller
8197 { 6697 {
8198 foreach (var row in table.Rows) 6698 foreach (var row in table.Rows)
8199 { 6699 {
8200 var serviceControl = new Wix.ServiceControl(); 6700 var xServiceControl = new XElement(Names.ServiceControlElement,
8201 6701 new XAttribute("Id", row.FieldAsString(0)),
8202 serviceControl.Id = Convert.ToString(row[0]); 6702 new XAttribute("Name", row.FieldAsString(1)));
8203
8204 serviceControl.Name = Convert.ToString(row[1]);
8205 6703
8206 var eventValue = Convert.ToInt32(row[2]); 6704 var eventValue = row.FieldAsInteger(2);
8207 if (WindowsInstallerConstants.MsidbServiceControlEventStart == (eventValue & WindowsInstallerConstants.MsidbServiceControlEventStart) && 6705 if (WindowsInstallerConstants.MsidbServiceControlEventStart == (eventValue & WindowsInstallerConstants.MsidbServiceControlEventStart) &&
8208 WindowsInstallerConstants.MsidbServiceControlEventUninstallStart == (eventValue & WindowsInstallerConstants.MsidbServiceControlEventUninstallStart)) 6706 WindowsInstallerConstants.MsidbServiceControlEventUninstallStart == (eventValue & WindowsInstallerConstants.MsidbServiceControlEventUninstallStart))
8209 { 6707 {
8210 serviceControl.Start = Wix.InstallUninstallType.both; 6708 xServiceControl.SetAttributeValue("Start", "both");
8211 } 6709 }
8212 else if (WindowsInstallerConstants.MsidbServiceControlEventStart == (eventValue & WindowsInstallerConstants.MsidbServiceControlEventStart)) 6710 else if (WindowsInstallerConstants.MsidbServiceControlEventStart == (eventValue & WindowsInstallerConstants.MsidbServiceControlEventStart))
8213 { 6711 {
8214 serviceControl.Start = Wix.InstallUninstallType.install; 6712 xServiceControl.SetAttributeValue("Start", "install");
8215 } 6713 }
8216 else if (WindowsInstallerConstants.MsidbServiceControlEventUninstallStart == (eventValue & WindowsInstallerConstants.MsidbServiceControlEventUninstallStart)) 6714 else if (WindowsInstallerConstants.MsidbServiceControlEventUninstallStart == (eventValue & WindowsInstallerConstants.MsidbServiceControlEventUninstallStart))
8217 { 6715 {
8218 serviceControl.Start = Wix.InstallUninstallType.uninstall; 6716 xServiceControl.SetAttributeValue("Start", "uninstall");
8219 } 6717 }
8220 6718
8221 if (WindowsInstallerConstants.MsidbServiceControlEventStop == (eventValue & WindowsInstallerConstants.MsidbServiceControlEventStop) && 6719 if (WindowsInstallerConstants.MsidbServiceControlEventStop == (eventValue & WindowsInstallerConstants.MsidbServiceControlEventStop) &&
8222 WindowsInstallerConstants.MsidbServiceControlEventUninstallStop == (eventValue & WindowsInstallerConstants.MsidbServiceControlEventUninstallStop)) 6720 WindowsInstallerConstants.MsidbServiceControlEventUninstallStop == (eventValue & WindowsInstallerConstants.MsidbServiceControlEventUninstallStop))
8223 { 6721 {
8224 serviceControl.Stop = Wix.InstallUninstallType.both; 6722 xServiceControl.SetAttributeValue("Stop", "both");
8225 } 6723 }
8226 else if (WindowsInstallerConstants.MsidbServiceControlEventStop == (eventValue & WindowsInstallerConstants.MsidbServiceControlEventStop)) 6724 else if (WindowsInstallerConstants.MsidbServiceControlEventStop == (eventValue & WindowsInstallerConstants.MsidbServiceControlEventStop))
8227 { 6725 {
8228 serviceControl.Stop = Wix.InstallUninstallType.install; 6726 xServiceControl.SetAttributeValue("Stop", "install");
8229 } 6727 }
8230 else if (WindowsInstallerConstants.MsidbServiceControlEventUninstallStop == (eventValue & WindowsInstallerConstants.MsidbServiceControlEventUninstallStop)) 6728 else if (WindowsInstallerConstants.MsidbServiceControlEventUninstallStop == (eventValue & WindowsInstallerConstants.MsidbServiceControlEventUninstallStop))
8231 { 6729 {
8232 serviceControl.Stop = Wix.InstallUninstallType.uninstall; 6730 xServiceControl.SetAttributeValue("Stop", "uninstall");
8233 } 6731 }
8234 6732
8235 if (WindowsInstallerConstants.MsidbServiceControlEventDelete == (eventValue & WindowsInstallerConstants.MsidbServiceControlEventDelete) && 6733 if (WindowsInstallerConstants.MsidbServiceControlEventDelete == (eventValue & WindowsInstallerConstants.MsidbServiceControlEventDelete) &&
8236 WindowsInstallerConstants.MsidbServiceControlEventUninstallDelete == (eventValue & WindowsInstallerConstants.MsidbServiceControlEventUninstallDelete)) 6734 WindowsInstallerConstants.MsidbServiceControlEventUninstallDelete == (eventValue & WindowsInstallerConstants.MsidbServiceControlEventUninstallDelete))
8237 { 6735 {
8238 serviceControl.Remove = Wix.InstallUninstallType.both; 6736 xServiceControl.SetAttributeValue("Remove", "both");
8239 } 6737 }
8240 else if (WindowsInstallerConstants.MsidbServiceControlEventDelete == (eventValue & WindowsInstallerConstants.MsidbServiceControlEventDelete)) 6738 else if (WindowsInstallerConstants.MsidbServiceControlEventDelete == (eventValue & WindowsInstallerConstants.MsidbServiceControlEventDelete))
8241 { 6739 {
8242 serviceControl.Remove = Wix.InstallUninstallType.install; 6740 xServiceControl.SetAttributeValue("Remove", "install");
8243 } 6741 }
8244 else if (WindowsInstallerConstants.MsidbServiceControlEventUninstallDelete == (eventValue & WindowsInstallerConstants.MsidbServiceControlEventUninstallDelete)) 6742 else if (WindowsInstallerConstants.MsidbServiceControlEventUninstallDelete == (eventValue & WindowsInstallerConstants.MsidbServiceControlEventUninstallDelete))
8245 { 6743 {
8246 serviceControl.Remove = Wix.InstallUninstallType.uninstall; 6744 xServiceControl.SetAttributeValue("Remove", "uninstall");
8247 } 6745 }
8248 6746
8249 if (null != row[3]) 6747 if (!row.IsColumnNull(3))
8250 { 6748 {
8251 var arguments = NullSplitter.Split(Convert.ToString(row[3])); 6749 var arguments = NullSplitter.Split(row.FieldAsString(3));
8252 6750
8253 foreach (var argument in arguments) 6751 foreach (var argument in arguments)
8254 { 6752 {
8255 var serviceArgument = new Wix.ServiceArgument(); 6753 var xServiceArgument = new XElement(Names.ServiceArgumentElement,
6754 new XAttribute("Value", argument));
8256 6755
8257 serviceArgument.Content = argument; 6756 xServiceControl.Add(xServiceArgument);
8258
8259 serviceControl.AddChild(serviceArgument);
8260 } 6757 }
8261 } 6758 }
8262 6759
8263 if (null != row[4]) 6760 if (!row.IsColumnNull(4))
8264 { 6761 {
8265 if (0 == Convert.ToInt32(row[4])) 6762 xServiceControl.SetAttributeValue("Wait", row.FieldAsInteger(4) == 0 ? "no" : "yes");
8266 {
8267 serviceControl.Wait = Wix.YesNoType.no;
8268 }
8269 else
8270 {
8271 serviceControl.Wait = Wix.YesNoType.yes;
8272 }
8273 } 6763 }
8274 6764
8275 var component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[5])); 6765 this.AddChildToParent("Component", xServiceControl, row, 5);
8276 if (null != component)
8277 {
8278 component.AddChild(serviceControl);
8279 }
8280 else
8281 {
8282 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[5]), "Component"));
8283 }
8284 } 6766 }
8285 } 6767 }
8286 6768
@@ -8292,21 +6774,20 @@ namespace WixToolset.Core.WindowsInstaller
8292 { 6774 {
8293 foreach (var row in table.Rows) 6775 foreach (var row in table.Rows)
8294 { 6776 {
8295 var serviceInstall = new Wix.ServiceInstall(); 6777 var xServiceInstall = new XElement(Names.ServiceInstallElement,
8296 6778 new XAttribute("Id", row.FieldAsString(0)),
8297 serviceInstall.Id = Convert.ToString(row[0]); 6779 new XAttribute("Name", row.FieldAsString(1)),
8298 6780 XAttributeIfNotNull("DisplayName", row, 2),
8299 serviceInstall.Name = Convert.ToString(row[1]); 6781 XAttributeIfNotNull("LoadOrderGroup", row, 6),
8300 6782 XAttributeIfNotNull("Account", row, 8),
8301 if (null != row[2]) 6783 XAttributeIfNotNull("Password", row, 9),
8302 { 6784 XAttributeIfNotNull("Arguments", row, 10),
8303 serviceInstall.DisplayName = Convert.ToString(row[2]); 6785 XAttributeIfNotNull("Description", row, 12));
8304 } 6786
8305 6787 var serviceType = row.FieldAsInteger(3);
8306 var serviceType = Convert.ToInt32(row[3]);
8307 if (WindowsInstallerConstants.MsidbServiceInstallInteractive == (serviceType & WindowsInstallerConstants.MsidbServiceInstallInteractive)) 6788 if (WindowsInstallerConstants.MsidbServiceInstallInteractive == (serviceType & WindowsInstallerConstants.MsidbServiceInstallInteractive))
8308 { 6789 {
8309 serviceInstall.Interactive = Wix.YesNoType.yes; 6790 xServiceInstall.SetAttributeValue("Interactive", "yes");
8310 } 6791 }
8311 6792
8312 if (WindowsInstallerConstants.MsidbServiceInstallOwnProcess == (serviceType & WindowsInstallerConstants.MsidbServiceInstallOwnProcess) && 6793 if (WindowsInstallerConstants.MsidbServiceInstallOwnProcess == (serviceType & WindowsInstallerConstants.MsidbServiceInstallOwnProcess) &&
@@ -8316,110 +6797,77 @@ namespace WixToolset.Core.WindowsInstaller
8316 } 6797 }
8317 else if (WindowsInstallerConstants.MsidbServiceInstallOwnProcess == (serviceType & WindowsInstallerConstants.MsidbServiceInstallOwnProcess)) 6798 else if (WindowsInstallerConstants.MsidbServiceInstallOwnProcess == (serviceType & WindowsInstallerConstants.MsidbServiceInstallOwnProcess))
8318 { 6799 {
8319 serviceInstall.Type = Wix.ServiceInstall.TypeType.ownProcess; 6800 xServiceInstall.SetAttributeValue("Type", "ownProcess");
8320 } 6801 }
8321 else if (WindowsInstallerConstants.MsidbServiceInstallShareProcess == (serviceType & WindowsInstallerConstants.MsidbServiceInstallShareProcess)) 6802 else if (WindowsInstallerConstants.MsidbServiceInstallShareProcess == (serviceType & WindowsInstallerConstants.MsidbServiceInstallShareProcess))
8322 { 6803 {
8323 serviceInstall.Type = Wix.ServiceInstall.TypeType.shareProcess; 6804 xServiceInstall.SetAttributeValue("Type", "shareProcess");
8324 } 6805 }
8325 6806
8326 var startType = Convert.ToInt32(row[4]); 6807 var startType = row.FieldAsInteger(4);
8327 if (WindowsInstallerConstants.MsidbServiceInstallDisabled == startType) 6808 if (WindowsInstallerConstants.MsidbServiceInstallDisabled == startType)
8328 { 6809 {
8329 serviceInstall.Start = Wix.ServiceInstall.StartType.disabled; 6810 xServiceInstall.SetAttributeValue("Start", "disabled");
8330 } 6811 }
8331 else if (WindowsInstallerConstants.MsidbServiceInstallDemandStart == startType) 6812 else if (WindowsInstallerConstants.MsidbServiceInstallDemandStart == startType)
8332 { 6813 {
8333 serviceInstall.Start = Wix.ServiceInstall.StartType.demand; 6814 xServiceInstall.SetAttributeValue("Start", "demand");
8334 } 6815 }
8335 else if (WindowsInstallerConstants.MsidbServiceInstallAutoStart == startType) 6816 else if (WindowsInstallerConstants.MsidbServiceInstallAutoStart == startType)
8336 { 6817 {
8337 serviceInstall.Start = Wix.ServiceInstall.StartType.auto; 6818 xServiceInstall.SetAttributeValue("Start", "auto");
8338 } 6819 }
8339 else 6820 else
8340 { 6821 {
8341 this.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[4].Column.Name, row[4])); 6822 this.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[4].Column.Name, row[4]));
8342 } 6823 }
8343 6824
8344 var errorControl = Convert.ToInt32(row[5]); 6825 var errorControl = row.FieldAsInteger(5);
8345 if (WindowsInstallerConstants.MsidbServiceInstallErrorCritical == (errorControl & WindowsInstallerConstants.MsidbServiceInstallErrorCritical)) 6826 if (WindowsInstallerConstants.MsidbServiceInstallErrorCritical == (errorControl & WindowsInstallerConstants.MsidbServiceInstallErrorCritical))
8346 { 6827 {
8347 serviceInstall.ErrorControl = Wix.ServiceInstall.ErrorControlType.critical; 6828 xServiceInstall.SetAttributeValue("ErrorControl", "critical");
8348 } 6829 }
8349 else if (WindowsInstallerConstants.MsidbServiceInstallErrorNormal == (errorControl & WindowsInstallerConstants.MsidbServiceInstallErrorNormal)) 6830 else if (WindowsInstallerConstants.MsidbServiceInstallErrorNormal == (errorControl & WindowsInstallerConstants.MsidbServiceInstallErrorNormal))
8350 { 6831 {
8351 serviceInstall.ErrorControl = Wix.ServiceInstall.ErrorControlType.normal; 6832 xServiceInstall.SetAttributeValue("ErrorControl", "normal");
8352 } 6833 }
8353 else 6834 else
8354 { 6835 {
8355 serviceInstall.ErrorControl = Wix.ServiceInstall.ErrorControlType.ignore; 6836 xServiceInstall.SetAttributeValue("ErrorControl", "ignore");
8356 } 6837 }
8357 6838
8358 if (WindowsInstallerConstants.MsidbServiceInstallErrorControlVital == (errorControl & WindowsInstallerConstants.MsidbServiceInstallErrorControlVital)) 6839 if (WindowsInstallerConstants.MsidbServiceInstallErrorControlVital == (errorControl & WindowsInstallerConstants.MsidbServiceInstallErrorControlVital))
8359 { 6840 {
8360 serviceInstall.Vital = Wix.YesNoType.yes; 6841 xServiceInstall.SetAttributeValue("Vital", "yes");
8361 } 6842 }
8362 6843
8363 if (null != row[6]) 6844 if (!row.IsColumnNull(7))
8364 { 6845 {
8365 serviceInstall.LoadOrderGroup = Convert.ToString(row[6]); 6846 var dependencies = NullSplitter.Split(row.FieldAsString(7));
8366 }
8367
8368 if (null != row[7])
8369 {
8370 var dependencies = NullSplitter.Split(Convert.ToString(row[7]));
8371 6847
8372 foreach (var dependency in dependencies) 6848 foreach (var dependency in dependencies)
8373 { 6849 {
8374 if (0 < dependency.Length) 6850 if (0 < dependency.Length)
8375 { 6851 {
8376 var serviceDependency = new Wix.ServiceDependency(); 6852 var xServiceDependency = new XElement(Names.ServiceDependencyElement);
8377 6853
8378 if (dependency.StartsWith("+", StringComparison.Ordinal)) 6854 if (dependency.StartsWith("+", StringComparison.Ordinal))
8379 { 6855 {
8380 serviceDependency.Group = Wix.YesNoType.yes; 6856 xServiceDependency.SetAttributeValue("Group", "yes");
8381 serviceDependency.Id = dependency.Substring(1); 6857 xServiceDependency.SetAttributeValue("Id", dependency.Substring(1));
8382 } 6858 }
8383 else 6859 else
8384 { 6860 {
8385 serviceDependency.Id = dependency; 6861 xServiceDependency.SetAttributeValue("Id", dependency);
8386 } 6862 }
8387 6863
8388 serviceInstall.AddChild(serviceDependency); 6864 xServiceInstall.Add(xServiceDependency);
8389 } 6865 }
8390 } 6866 }
8391 } 6867 }
8392 6868
8393 if (null != row[8]) 6869 this.AddChildToParent("Component", xServiceInstall, row, 11);
8394 { 6870 this.IndexElement(row, xServiceInstall);
8395 serviceInstall.Account = Convert.ToString(row[8]);
8396 }
8397
8398 if (null != row[9])
8399 {
8400 serviceInstall.Password = Convert.ToString(row[9]);
8401 }
8402
8403 if (null != row[10])
8404 {
8405 serviceInstall.Arguments = Convert.ToString(row[10]);
8406 }
8407
8408 if (null != row[12])
8409 {
8410 serviceInstall.Description = Convert.ToString(row[12]);
8411 }
8412
8413 var component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[11]));
8414 if (null != component)
8415 {
8416 component.AddChild(serviceInstall);
8417 }
8418 else
8419 {
8420 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[11]), "Component"));
8421 }
8422 this.core.IndexElement(row, serviceInstall);
8423 } 6871 }
8424 } 6872 }
8425 6873
@@ -8431,38 +6879,34 @@ namespace WixToolset.Core.WindowsInstaller
8431 { 6879 {
8432 foreach (var row in table.Rows) 6880 foreach (var row in table.Rows)
8433 { 6881 {
8434 var sfpCatalog = new Wix.SFPCatalog(); 6882 var xSfpCatalog = new XElement(Names.SFPCatalogElement,
8435 6883 new XAttribute("Name", row.FieldAsString(0)),
8436 sfpCatalog.Name = Convert.ToString(row[0]); 6884 new XAttribute("SourceFile", row.FieldAsString(1)));
8437 6885
8438 sfpCatalog.SourceFile = Convert.ToString(row[1]); 6886 this.IndexElement(row, xSfpCatalog);
8439
8440 this.core.IndexElement(row, sfpCatalog);
8441 } 6887 }
8442 6888
8443 // nest the SFPCatalog elements 6889 // nest the SFPCatalog elements
8444 foreach (var row in table.Rows) 6890 foreach (var row in table.Rows)
8445 { 6891 {
8446 var sfpCatalog = (Wix.SFPCatalog)this.core.GetIndexedElement(row); 6892 var xSfpCatalog = this.GetIndexedElement(row);
8447 6893
8448 if (null != row[2]) 6894 if (!row.IsColumnNull(2))
8449 { 6895 {
8450 var parentSFPCatalog = (Wix.SFPCatalog)this.core.GetIndexedElement("SFPCatalog", Convert.ToString(row[2])); 6896 if (this.TryGetIndexedElement("SFPCatalog", out var xParentSFPCatalog, row.FieldAsString(2)))
8451
8452 if (null != parentSFPCatalog)
8453 { 6897 {
8454 parentSFPCatalog.AddChild(sfpCatalog); 6898 xParentSFPCatalog.Add(xSfpCatalog);
8455 } 6899 }
8456 else 6900 else
8457 { 6901 {
8458 sfpCatalog.Dependency = Convert.ToString(row[2]); 6902 xSfpCatalog.SetAttributeValue("Dependency", row.FieldAsString(2));
8459 6903
8460 this.core.RootElement.AddChild(sfpCatalog); 6904 this.RootElement.Add(xSfpCatalog);
8461 } 6905 }
8462 } 6906 }
8463 else 6907 else
8464 { 6908 {
8465 this.core.RootElement.AddChild(sfpCatalog); 6909 this.RootElement.Add(xSfpCatalog);
8466 } 6910 }
8467 } 6911 }
8468 } 6912 }
@@ -8475,107 +6919,72 @@ namespace WixToolset.Core.WindowsInstaller
8475 { 6919 {
8476 foreach (var row in table.Rows) 6920 foreach (var row in table.Rows)
8477 { 6921 {
8478 var shortcut = new Wix.Shortcut(); 6922 var xShortcut = new XElement(Names.ShortcutElement,
8479 6923 new XAttribute("Id", row.FieldAsString(0)),
8480 shortcut.Id = Convert.ToString(row[0]); 6924 new XAttribute("Directory", row.FieldAsString(1)),
8481 6925 XAttributeIfNotNull("Arguments", row, 5),
8482 shortcut.Directory = Convert.ToString(row[1]); 6926 XAttributeIfNotNull("Description", row, 6),
8483 6927 XAttributeIfNotNull("Hotkey", row, 7),
8484 var names = Common.GetNames(Convert.ToString(row[2])); 6928 XAttributeIfNotNull("Icon", row, 8),
6929 XAttributeIfNotNull("IconIndex", row, 9),
6930 XAttributeIfNotNull("WorkingDirectory", row, 11));
6931
6932 var names = Common.GetNames(row.FieldAsString(2));
8485 if (null != names[0] && null != names[1]) 6933 if (null != names[0] && null != names[1])
8486 { 6934 {
8487 shortcut.ShortName = names[0]; 6935 xShortcut.SetAttributeValue("ShortName", names[0]);
8488 shortcut.Name = names[1]; 6936 xShortcut.SetAttributeValue("Name", names[1]);
8489 } 6937 }
8490 else if (null != names[0]) 6938 else if (null != names[0])
8491 { 6939 {
8492 shortcut.Name = names[0]; 6940 xShortcut.SetAttributeValue("Name", names[0]);
8493 } 6941 }
8494 6942
8495 if (null != row[5]) 6943 if (!row.IsColumnNull(10))
8496 { 6944 {
8497 shortcut.Arguments = Convert.ToString(row[5]); 6945 switch (row.FieldAsInteger(10))
8498 }
8499
8500 if (null != row[6])
8501 {
8502 shortcut.Description = Convert.ToString(row[6]);
8503 }
8504
8505 if (null != row[7])
8506 {
8507 shortcut.Hotkey = Convert.ToInt32(row[7]);
8508 }
8509
8510 if (null != row[8])
8511 {
8512 shortcut.Icon = Convert.ToString(row[8]);
8513 }
8514
8515 if (null != row[9])
8516 {
8517 shortcut.IconIndex = Convert.ToInt32(row[9]);
8518 }
8519
8520 if (null != row[10])
8521 {
8522 switch (Convert.ToInt32(row[10]))
8523 { 6946 {
8524 case 1: 6947 case 1:
8525 shortcut.Show = Wix.Shortcut.ShowType.normal; 6948 xShortcut.SetAttributeValue("Show", "normal");
8526 break; 6949 break;
8527 case 3: 6950 case 3:
8528 shortcut.Show = Wix.Shortcut.ShowType.maximized; 6951 xShortcut.SetAttributeValue("Show", "maximized");
8529 break; 6952 break;
8530 case 7: 6953 case 7:
8531 shortcut.Show = Wix.Shortcut.ShowType.minimized; 6954 xShortcut.SetAttributeValue("Show", "minimized");
8532 break; 6955 break;
8533 default: 6956 default:
8534 this.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[10].Column.Name, row[10])); 6957 this.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[10].Column.Name, row[10]));
8535 break; 6958 break;
8536 } 6959 }
8537 } 6960 }
8538 6961
8539 if (null != row[11])
8540 {
8541 shortcut.WorkingDirectory = Convert.ToString(row[11]);
8542 }
8543
8544 // Only try to read the MSI 4.0-specific columns if they actually exist 6962 // Only try to read the MSI 4.0-specific columns if they actually exist
8545 if (15 < row.Fields.Length) 6963 if (15 < row.Fields.Length)
8546 { 6964 {
8547 if (null != row[12]) 6965 if (!row.IsColumnNull(12))
8548 { 6966 {
8549 shortcut.DisplayResourceDll = Convert.ToString(row[12]); 6967 xShortcut.SetAttributeValue("DisplayResourceDll", row.FieldAsString(12));
8550 } 6968 }
8551 6969
8552 if (null != row[13]) 6970 if (null != row[13])
8553 { 6971 {
8554 shortcut.DisplayResourceId = Convert.ToInt32(row[13]); 6972 xShortcut.SetAttributeValue("DisplayResourceId", row.FieldAsInteger(13));
8555 } 6973 }
8556 6974
8557 if (null != row[14]) 6975 if (null != row[14])
8558 { 6976 {
8559 shortcut.DescriptionResourceDll = Convert.ToString(row[14]); 6977 xShortcut.SetAttributeValue("DescriptionResourceDll", row.FieldAsString(14));
8560 } 6978 }
8561 6979
8562 if (null != row[15]) 6980 if (null != row[15])
8563 { 6981 {
8564 shortcut.DescriptionResourceId = Convert.ToInt32(row[15]); 6982 xShortcut.SetAttributeValue("DescriptionResourceId", row.FieldAsInteger(15));
8565 } 6983 }
8566 } 6984 }
8567 6985
8568 var component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[3])); 6986 this.AddChildToParent("Component", xShortcut, row, 3);
8569 if (null != component) 6987 this.IndexElement(row, xShortcut);
8570 {
8571 component.AddChild(shortcut);
8572 }
8573 else
8574 {
8575 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[3]), "Component"));
8576 }
8577
8578 this.core.IndexElement(row, shortcut);
8579 } 6988 }
8580 } 6989 }
8581 6990
@@ -8587,65 +6996,44 @@ namespace WixToolset.Core.WindowsInstaller
8587 { 6996 {
8588 foreach (var row in table.Rows) 6997 foreach (var row in table.Rows)
8589 { 6998 {
8590 var fileSearch = new Wix.FileSearch(); 6999 var fileSearch = new XElement(Names.FileSearchElement,
7000 new XAttribute("Id", row.FieldAsString(0)),
7001 XAttributeIfNotNull("MinVersion", row, 2),
7002 XAttributeIfNotNull("MaxVersion", row, 3),
7003 XAttributeIfNotNull("MinSize", row, 4),
7004 XAttributeIfNotNull("MaxSize", row, 5),
7005 XAttributeIfNotNull("Languages", row, 8));
8591 7006
8592 fileSearch.Id = Convert.ToString(row[0]); 7007 var names = Common.GetNames(row.FieldAsString(1));
8593
8594 var names = Common.GetNames(Convert.ToString(row[1]));
8595 if (null != names[0]) 7008 if (null != names[0])
8596 { 7009 {
8597 // it is permissable to just have a long name 7010 // it is permissable to just have a long name
8598 if (!this.core.IsValidShortFilename(names[0], false) && null == names[1]) 7011 if (!Common.IsValidShortFilename(names[0], false) && null == names[1])
8599 { 7012 {
8600 fileSearch.Name = names[0]; 7013 fileSearch.SetAttributeValue("Name", names[0]);
8601 } 7014 }
8602 else 7015 else
8603 { 7016 {
8604 fileSearch.ShortName = names[0]; 7017 fileSearch.SetAttributeValue("ShortName", names[0]);
8605 } 7018 }
8606 } 7019 }
8607 7020
8608 if (null != names[1]) 7021 if (null != names[1])
8609 { 7022 {
8610 fileSearch.Name = names[1]; 7023 fileSearch.SetAttributeValue("Name", names[1]);
8611 }
8612
8613 if (null != row[2])
8614 {
8615 fileSearch.MinVersion = Convert.ToString(row[2]);
8616 }
8617
8618 if (null != row[3])
8619 {
8620 fileSearch.MaxVersion = Convert.ToString(row[3]);
8621 }
8622
8623 if (null != row[4])
8624 {
8625 fileSearch.MinSize = Convert.ToInt32(row[4]);
8626 }
8627
8628 if (null != row[5])
8629 {
8630 fileSearch.MaxSize = Convert.ToInt32(row[5]);
8631 }
8632
8633 if (null != row[6])
8634 {
8635 fileSearch.MinDate = this.core.ConvertIntegerToDateTime(Convert.ToInt32(row[6]));
8636 } 7024 }
8637 7025
8638 if (null != row[7]) 7026 if (!row.IsColumnNull(6))
8639 { 7027 {
8640 fileSearch.MaxDate = this.core.ConvertIntegerToDateTime(Convert.ToInt32(row[7])); 7028 fileSearch.SetAttributeValue("MinDate", ConvertIntegerToDateTime(row.FieldAsInteger(6)));
8641 } 7029 }
8642 7030
8643 if (null != row[8]) 7031 if (!row.IsColumnNull(7))
8644 { 7032 {
8645 fileSearch.Languages = Convert.ToString(row[8]); 7033 fileSearch.SetAttributeValue("MaxDate", ConvertIntegerToDateTime(row.FieldAsInteger(7)));
8646 } 7034 }
8647 7035
8648 this.core.IndexElement(row, fileSearch); 7036 this.IndexElement(row, fileSearch);
8649 } 7037 }
8650 } 7038 }
8651 7039
@@ -8657,69 +7045,55 @@ namespace WixToolset.Core.WindowsInstaller
8657 { 7045 {
8658 foreach (var row in table.Rows) 7046 foreach (var row in table.Rows)
8659 { 7047 {
8660 var targetFile = (Wix.TargetFile)this.patchTargetFiles[row[0]]; 7048 if (!this.PatchTargetFiles.TryGetValue(row.FieldAsString(0), out var xPatchTargetFile))
8661 if (null == targetFile)
8662 { 7049 {
8663 targetFile = new Wix.TargetFile(); 7050 xPatchTargetFile = new XElement(Names.TargetFileElement,
8664 7051 new XAttribute("Id", row.FieldAsString(1)));
8665 targetFile.Id = Convert.ToString(row[1]);
8666 7052
8667 var targetImage = (Wix.TargetImage)this.core.GetIndexedElement("TargetImages", Convert.ToString(row[0])); 7053 if (this.TryGetIndexedElement("TargetImages", out var xTargetImage, row.FieldAsString(0)))
8668 if (null != targetImage)
8669 { 7054 {
8670 targetImage.AddChild(targetFile); 7055 xTargetImage.Add(xPatchTargetFile);
8671 } 7056 }
8672 else 7057 else
8673 { 7058 {
8674 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Target", Convert.ToString(row[0]), "TargetImages")); 7059 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Target", row.FieldAsString(0), "TargetImages"));
8675 } 7060 }
8676 this.patchTargetFiles.Add(row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), targetFile);
8677 }
8678
8679 if (null != row[2])
8680 {
8681 var symbolPaths = (Convert.ToString(row[2])).Split(';');
8682
8683 foreach (var symbolPathString in symbolPaths)
8684 {
8685 var symbolPath = new Wix.SymbolPath();
8686
8687 symbolPath.Path = symbolPathString;
8688 7061
8689 targetFile.AddChild(symbolPath); 7062 this.PatchTargetFiles.Add(row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), xPatchTargetFile);
8690 }
8691 } 7063 }
8692 7064
8693 if (null != row[3] && null != row[4]) 7065 AddSymbolPaths(row, 2, xPatchTargetFile);
7066
7067 if (!row.IsColumnNull(3) && !row.IsColumnNull(4))
8694 { 7068 {
8695 var ignoreOffsets = (Convert.ToString(row[3])).Split(','); 7069 var ignoreOffsets = row.FieldAsString(3).Split(',');
8696 var ignoreLengths = (Convert.ToString(row[4])).Split(','); 7070 var ignoreLengths = row.FieldAsString(4).Split(',');
8697 7071
8698 if (ignoreOffsets.Length == ignoreLengths.Length) 7072 if (ignoreOffsets.Length == ignoreLengths.Length)
8699 { 7073 {
8700 for (var i = 0; i < ignoreOffsets.Length; i++) 7074 for (var i = 0; i < ignoreOffsets.Length; i++)
8701 { 7075 {
8702 var ignoreRange = new Wix.IgnoreRange(); 7076 var xIgnoreRange = new XElement(Names.IgnoreRangeElement);
8703 7077
8704 if (ignoreOffsets[i].StartsWith("0x", StringComparison.Ordinal)) 7078 if (ignoreOffsets[i].StartsWith("0x", StringComparison.Ordinal))
8705 { 7079 {
8706 ignoreRange.Offset = Convert.ToInt32(ignoreOffsets[i].Substring(2), 16); 7080 xIgnoreRange.SetAttributeValue("Offset", Convert.ToInt32(ignoreOffsets[i].Substring(2), 16));
8707 } 7081 }
8708 else 7082 else
8709 { 7083 {
8710 ignoreRange.Offset = Convert.ToInt32(ignoreOffsets[i], CultureInfo.InvariantCulture); 7084 xIgnoreRange.SetAttributeValue("Offset", Convert.ToInt32(ignoreOffsets[i], CultureInfo.InvariantCulture));
8711 } 7085 }
8712 7086
8713 if (ignoreLengths[i].StartsWith("0x", StringComparison.Ordinal)) 7087 if (ignoreLengths[i].StartsWith("0x", StringComparison.Ordinal))
8714 { 7088 {
8715 ignoreRange.Length = Convert.ToInt32(ignoreLengths[i].Substring(2), 16); 7089 xIgnoreRange.SetAttributeValue("Length", Convert.ToInt32(ignoreLengths[i].Substring(2), 16));
8716 } 7090 }
8717 else 7091 else
8718 { 7092 {
8719 ignoreRange.Length = Convert.ToInt32(ignoreLengths[i], CultureInfo.InvariantCulture); 7093 xIgnoreRange.SetAttributeValue("Length", Convert.ToInt32(ignoreLengths[i], CultureInfo.InvariantCulture));
8720 } 7094 }
8721 7095
8722 targetFile.AddChild(ignoreRange); 7096 xPatchTargetFile.Add(xIgnoreRange);
8723 } 7097 }
8724 } 7098 }
8725 else 7099 else
@@ -8727,7 +7101,7 @@ namespace WixToolset.Core.WindowsInstaller
8727 // TODO: warn 7101 // TODO: warn
8728 } 7102 }
8729 } 7103 }
8730 else if (null != row[3] || null != row[4]) 7104 else if (!row.IsColumnNull(3) || !row.IsColumnNull(4))
8731 { 7105 {
8732 // TODO: warn about mismatch between columns 7106 // TODO: warn about mismatch between columns
8733 } 7107 }
@@ -8744,48 +7118,21 @@ namespace WixToolset.Core.WindowsInstaller
8744 { 7118 {
8745 foreach (var row in table.Rows) 7119 foreach (var row in table.Rows)
8746 { 7120 {
8747 var targetImage = new Wix.TargetImage(); 7121 var xTargetImage = new XElement(Names.TargetImageElement,
8748 7122 new XAttribute("Id", row.FieldAsString(0)),
8749 targetImage.Id = Convert.ToString(row[0]); 7123 new XAttribute("SourceFile", row.FieldAsString(1)),
7124 new XAttribute("Order", row.FieldAsInteger(4)),
7125 XAttributeIfNotNull("Validation", row, 5));
8750 7126
8751 targetImage.SourceFile = Convert.ToString(row[1]); 7127 AddSymbolPaths(row, 2, xTargetImage);
8752 7128
8753 if (null != row[2]) 7129 if (0 != row.FieldAsInteger(6))
8754 { 7130 {
8755 var symbolPaths = (Convert.ToString(row[3])).Split(';'); 7131 xTargetImage.SetAttributeValue("IgnoreMissingFiles", "yes");
8756
8757 foreach (var symbolPathString in symbolPaths)
8758 {
8759 var symbolPath = new Wix.SymbolPath();
8760
8761 symbolPath.Path = symbolPathString;
8762
8763 targetImage.AddChild(symbolPath);
8764 }
8765 } 7132 }
8766 7133
8767 targetImage.Order = Convert.ToInt32(row[4]); 7134 this.AddChildToParent("UpgradedImages", xTargetImage, row, 3);
8768 7135 this.IndexElement(row, xTargetImage);
8769 if (null != row[5])
8770 {
8771 targetImage.Validation = Convert.ToString(row[5]);
8772 }
8773
8774 if (0 != Convert.ToInt32(row[6]))
8775 {
8776 targetImage.IgnoreMissingFiles = Wix.YesNoType.yes;
8777 }
8778
8779 var upgradeImage = (Wix.UpgradeImage)this.core.GetIndexedElement("UpgradedImages", Convert.ToString(row[3]));
8780 if (null != upgradeImage)
8781 {
8782 upgradeImage.AddChild(targetImage);
8783 }
8784 else
8785 {
8786 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Upgraded", Convert.ToString(row[3]), "UpgradedImages"));
8787 }
8788 this.core.IndexElement(row, targetImage);
8789 } 7136 }
8790 } 7137 }
8791 7138
@@ -8797,51 +7144,46 @@ namespace WixToolset.Core.WindowsInstaller
8797 { 7144 {
8798 foreach (var row in table.Rows) 7145 foreach (var row in table.Rows)
8799 { 7146 {
8800 var textStyle = new Wix.TextStyle(); 7147 var xTextStyle = new XElement(Names.TextStyleElement,
7148 new XAttribute("Id", row.FieldAsString(0)),
7149 new XAttribute("FaceName", row.FieldAsString(1)),
7150 new XAttribute("Size", row.FieldAsString(2)));
8801 7151
8802 textStyle.Id = Convert.ToString(row[0]); 7152 if (!row.IsColumnNull(3))
8803
8804 textStyle.FaceName = Convert.ToString(row[1]);
8805
8806 textStyle.Size = Convert.ToString(row[2]);
8807
8808 if (null != row[3])
8809 { 7153 {
8810 var color = Convert.ToInt32(row[3]); 7154 var color = row.FieldAsInteger(3);
8811
8812 textStyle.Red = color & 0xFF;
8813
8814 textStyle.Green = (color & 0xFF00) >> 8;
8815 7155
8816 textStyle.Blue = (color & 0xFF0000) >> 16; 7156 xTextStyle.SetAttributeValue("Red", color & 0xFF);
7157 xTextStyle.SetAttributeValue("Green", (color & 0xFF00) >> 8);
7158 xTextStyle.SetAttributeValue("Blue", (color & 0xFF0000) >> 16);
8817 } 7159 }
8818 7160
8819 if (null != row[4]) 7161 if (!row.IsColumnNull(4))
8820 { 7162 {
8821 var styleBits = Convert.ToInt32(row[4]); 7163 var styleBits = row.FieldAsInteger(4);
8822 7164
8823 if (WindowsInstallerConstants.MsidbTextStyleStyleBitsBold == (styleBits & WindowsInstallerConstants.MsidbTextStyleStyleBitsBold)) 7165 if (WindowsInstallerConstants.MsidbTextStyleStyleBitsBold == (styleBits & WindowsInstallerConstants.MsidbTextStyleStyleBitsBold))
8824 { 7166 {
8825 textStyle.Bold = Wix.YesNoType.yes; 7167 xTextStyle.SetAttributeValue("Bold", "yes");
8826 } 7168 }
8827 7169
8828 if (WindowsInstallerConstants.MsidbTextStyleStyleBitsItalic == (styleBits & WindowsInstallerConstants.MsidbTextStyleStyleBitsItalic)) 7170 if (WindowsInstallerConstants.MsidbTextStyleStyleBitsItalic == (styleBits & WindowsInstallerConstants.MsidbTextStyleStyleBitsItalic))
8829 { 7171 {
8830 textStyle.Italic = Wix.YesNoType.yes; 7172 xTextStyle.SetAttributeValue("Italic", "yes");
8831 } 7173 }
8832 7174
8833 if (WindowsInstallerConstants.MsidbTextStyleStyleBitsUnderline == (styleBits & WindowsInstallerConstants.MsidbTextStyleStyleBitsUnderline)) 7175 if (WindowsInstallerConstants.MsidbTextStyleStyleBitsUnderline == (styleBits & WindowsInstallerConstants.MsidbTextStyleStyleBitsUnderline))
8834 { 7176 {
8835 textStyle.Underline = Wix.YesNoType.yes; 7177 xTextStyle.SetAttributeValue("Underline", "yes");
8836 } 7178 }
8837 7179
8838 if (WindowsInstallerConstants.MsidbTextStyleStyleBitsStrike == (styleBits & WindowsInstallerConstants.MsidbTextStyleStyleBitsStrike)) 7180 if (WindowsInstallerConstants.MsidbTextStyleStyleBitsStrike == (styleBits & WindowsInstallerConstants.MsidbTextStyleStyleBitsStrike))
8839 { 7181 {
8840 textStyle.Strike = Wix.YesNoType.yes; 7182 xTextStyle.SetAttributeValue("Strike", "yes");
8841 } 7183 }
8842 } 7184 }
8843 7185
8844 this.core.UIElement.AddChild(textStyle); 7186 this.UIElement.Add(xTextStyle);
8845 } 7187 }
8846 } 7188 }
8847 7189
@@ -8853,44 +7195,34 @@ namespace WixToolset.Core.WindowsInstaller
8853 { 7195 {
8854 foreach (var row in table.Rows) 7196 foreach (var row in table.Rows)
8855 { 7197 {
8856 var typeLib = new Wix.TypeLib(); 7198 var id = row.FieldAsString(0);
7199 var xTypeLib = new XElement(Names.TypeLibElement,
7200 new XAttribute("Advertise", "yes"),
7201 new XAttribute("Id", id),
7202 new XAttribute("Language", row.FieldAsInteger(1)),
7203 XAttributeIfNotNull("Description", row, 4),
7204 XAttributeIfNotNull("HelpDirectory", row, 5));
8857 7205
8858 typeLib.Id = Convert.ToString(row[0]); 7206 if (!row.IsColumnNull(3))
8859
8860 typeLib.Advertise = Wix.YesNoType.yes;
8861
8862 typeLib.Language = Convert.ToInt32(row[1]);
8863
8864 if (null != row[3])
8865 { 7207 {
8866 var version = Convert.ToInt32(row[3]); 7208 var version = row.FieldAsInteger(3);
8867 7209
8868 if (65536 == version) 7210 if (65536 == version)
8869 { 7211 {
8870 this.Messaging.Write(WarningMessages.PossiblyIncorrectTypelibVersion(row.SourceLineNumbers, typeLib.Id)); 7212 this.Messaging.Write(WarningMessages.PossiblyIncorrectTypelibVersion(row.SourceLineNumbers, id));
8871 } 7213 }
8872 7214
8873 typeLib.MajorVersion = ((version & 0xFFFF00) >> 8); 7215 xTypeLib.SetAttributeValue("MajorVersion", (version & 0xFFFF00) >> 8);
8874 typeLib.MinorVersion = (version & 0xFF); 7216 xTypeLib.SetAttributeValue("MinorVersion", version & 0xFF);
8875 } 7217 }
8876 7218
8877 if (null != row[4]) 7219 if (!row.IsColumnNull(7))
8878 { 7220 {
8879 typeLib.Description = Convert.ToString(row[4]); 7221 xTypeLib.SetAttributeValue("Cost", row.FieldAsInteger(7));
8880 }
8881
8882 if (null != row[5])
8883 {
8884 typeLib.HelpDirectory = Convert.ToString(row[5]);
8885 }
8886
8887 if (null != row[7])
8888 {
8889 typeLib.Cost = Convert.ToInt32(row[7]);
8890 } 7222 }
8891 7223
8892 // nested under the appropriate File element in FinalizeFileTable 7224 // nested under the appropriate File element in FinalizeFileTable
8893 this.core.IndexElement(row, typeLib); 7225 this.IndexElement(row, xTypeLib);
8894 } 7226 }
8895 } 7227 }
8896 7228
@@ -8900,7 +7232,7 @@ namespace WixToolset.Core.WindowsInstaller
8900 /// <param name="table">The table to decompile.</param> 7232 /// <param name="table">The table to decompile.</param>
8901 private void DecompileUpgradeTable(Table table) 7233 private void DecompileUpgradeTable(Table table)
8902 { 7234 {
8903 var upgradeElements = new Hashtable(); 7235 var xUpgrades = new Dictionary<string, XElement>();
8904 7236
8905 foreach (UpgradeRow upgradeRow in table.Rows) 7237 foreach (UpgradeRow upgradeRow in table.Rows)
8906 { 7238 {
@@ -8909,74 +7241,70 @@ namespace WixToolset.Core.WindowsInstaller
8909 continue; // MajorUpgrade rows processed in FinalizeUpgradeTable 7241 continue; // MajorUpgrade rows processed in FinalizeUpgradeTable
8910 } 7242 }
8911 7243
8912 var upgrade = (Wix.Upgrade)upgradeElements[upgradeRow.UpgradeCode]; 7244 if (!xUpgrades.TryGetValue(upgradeRow.UpgradeCode, out var xUpgrade))
8913
8914 // create the parent Upgrade element if it doesn't already exist
8915 if (null == upgrade)
8916 { 7245 {
8917 upgrade = new Wix.Upgrade(); 7246 xUpgrade = new XElement(Names.UpgradeElement,
8918 7247 new XAttribute("Id", upgradeRow.UpgradeCode));
8919 upgrade.Id = upgradeRow.UpgradeCode;
8920 7248
8921 this.core.RootElement.AddChild(upgrade); 7249 this.RootElement.Add(xUpgrade);
8922 upgradeElements.Add(upgrade.Id, upgrade); 7250 xUpgrades.Add(upgradeRow.UpgradeCode, xUpgrade);
8923 } 7251 }
8924 7252
8925 var upgradeVersion = new Wix.UpgradeVersion(); 7253 var xUpgradeVersion = new XElement(Names.UpgradeVersionElement,
7254 new XAttribute("Id", upgradeRow.UpgradeCode),
7255 new XAttribute("Property", upgradeRow.ActionProperty));
8926 7256
8927 if (null != upgradeRow.VersionMin) 7257 if (null != upgradeRow.VersionMin)
8928 { 7258 {
8929 upgradeVersion.Minimum = upgradeRow.VersionMin; 7259 xUpgradeVersion.SetAttributeValue("Minimum", upgradeRow.VersionMin);
8930 } 7260 }
8931 7261
8932 if (null != upgradeRow.VersionMax) 7262 if (null != upgradeRow.VersionMax)
8933 { 7263 {
8934 upgradeVersion.Maximum = upgradeRow.VersionMax; 7264 xUpgradeVersion.SetAttributeValue("Maximum", upgradeRow.VersionMax);
8935 } 7265 }
8936 7266
8937 if (null != upgradeRow.Language) 7267 if (null != upgradeRow.Language)
8938 { 7268 {
8939 upgradeVersion.Language = upgradeRow.Language; 7269 xUpgradeVersion.SetAttributeValue("Language", upgradeRow.Language);
8940 } 7270 }
8941 7271
8942 if (WindowsInstallerConstants.MsidbUpgradeAttributesMigrateFeatures == (upgradeRow.Attributes & WindowsInstallerConstants.MsidbUpgradeAttributesMigrateFeatures)) 7272 if (WindowsInstallerConstants.MsidbUpgradeAttributesMigrateFeatures == (upgradeRow.Attributes & WindowsInstallerConstants.MsidbUpgradeAttributesMigrateFeatures))
8943 { 7273 {
8944 upgradeVersion.MigrateFeatures = Wix.YesNoType.yes; 7274 xUpgradeVersion.SetAttributeValue("MigrateFeatures", "yes");
8945 } 7275 }
8946 7276
8947 if (WindowsInstallerConstants.MsidbUpgradeAttributesOnlyDetect == (upgradeRow.Attributes & WindowsInstallerConstants.MsidbUpgradeAttributesOnlyDetect)) 7277 if (WindowsInstallerConstants.MsidbUpgradeAttributesOnlyDetect == (upgradeRow.Attributes & WindowsInstallerConstants.MsidbUpgradeAttributesOnlyDetect))
8948 { 7278 {
8949 upgradeVersion.OnlyDetect = Wix.YesNoType.yes; 7279 xUpgradeVersion.SetAttributeValue("OnlyDetect", "yes");
8950 } 7280 }
8951 7281
8952 if (WindowsInstallerConstants.MsidbUpgradeAttributesIgnoreRemoveFailure == (upgradeRow.Attributes & WindowsInstallerConstants.MsidbUpgradeAttributesIgnoreRemoveFailure)) 7282 if (WindowsInstallerConstants.MsidbUpgradeAttributesIgnoreRemoveFailure == (upgradeRow.Attributes & WindowsInstallerConstants.MsidbUpgradeAttributesIgnoreRemoveFailure))
8953 { 7283 {
8954 upgradeVersion.IgnoreRemoveFailure = Wix.YesNoType.yes; 7284 xUpgradeVersion.SetAttributeValue("IgnoreRemoveFailure", "yes");
8955 } 7285 }
8956 7286
8957 if (WindowsInstallerConstants.MsidbUpgradeAttributesVersionMinInclusive == (upgradeRow.Attributes & WindowsInstallerConstants.MsidbUpgradeAttributesVersionMinInclusive)) 7287 if (WindowsInstallerConstants.MsidbUpgradeAttributesVersionMinInclusive == (upgradeRow.Attributes & WindowsInstallerConstants.MsidbUpgradeAttributesVersionMinInclusive))
8958 { 7288 {
8959 upgradeVersion.IncludeMinimum = Wix.YesNoType.yes; 7289 xUpgradeVersion.SetAttributeValue("IncludeMinimum", "yes");
8960 } 7290 }
8961 7291
8962 if (WindowsInstallerConstants.MsidbUpgradeAttributesVersionMaxInclusive == (upgradeRow.Attributes & WindowsInstallerConstants.MsidbUpgradeAttributesVersionMaxInclusive)) 7292 if (WindowsInstallerConstants.MsidbUpgradeAttributesVersionMaxInclusive == (upgradeRow.Attributes & WindowsInstallerConstants.MsidbUpgradeAttributesVersionMaxInclusive))
8963 { 7293 {
8964 upgradeVersion.IncludeMaximum = Wix.YesNoType.yes; 7294 xUpgradeVersion.SetAttributeValue("IncludeMaximum", "yes");
8965 } 7295 }
8966 7296
8967 if (WindowsInstallerConstants.MsidbUpgradeAttributesLanguagesExclusive == (upgradeRow.Attributes & WindowsInstallerConstants.MsidbUpgradeAttributesLanguagesExclusive)) 7297 if (WindowsInstallerConstants.MsidbUpgradeAttributesLanguagesExclusive == (upgradeRow.Attributes & WindowsInstallerConstants.MsidbUpgradeAttributesLanguagesExclusive))
8968 { 7298 {
8969 upgradeVersion.ExcludeLanguages = Wix.YesNoType.yes; 7299 xUpgradeVersion.SetAttributeValue("ExcludeLanguages", "yes");
8970 } 7300 }
8971 7301
8972 if (null != upgradeRow.Remove) 7302 if (null != upgradeRow.Remove)
8973 { 7303 {
8974 upgradeVersion.RemoveFeatures = upgradeRow.Remove; 7304 xUpgradeVersion.SetAttributeValue("RemoveFeatures", upgradeRow.Remove);
8975 } 7305 }
8976 7306
8977 upgradeVersion.Property = upgradeRow.ActionProperty; 7307 xUpgrade.Add(xUpgradeVersion);
8978
8979 upgrade.AddChild(upgradeVersion);
8980 } 7308 }
8981 } 7309 }
8982 7310
@@ -8988,45 +7316,23 @@ namespace WixToolset.Core.WindowsInstaller
8988 { 7316 {
8989 foreach (var row in table.Rows) 7317 foreach (var row in table.Rows)
8990 { 7318 {
8991 var upgradeFile = new Wix.UpgradeFile(); 7319 var xUpgradeFile = new XElement(Names.UpgradeFileElement,
7320 new XAttribute("File", row.FieldAsString(1)),
7321 new XAttribute("Ignore", "no"));
8992 7322
8993 upgradeFile.File = Convert.ToString(row[1]); 7323 AddSymbolPaths(row, 2, xUpgradeFile);
8994 7324
8995 if (null != row[2]) 7325 if (!row.IsColumnNull(3) && 1 == row.FieldAsInteger(3))
8996 { 7326 {
8997 var symbolPaths = (Convert.ToString(row[2])).Split(';'); 7327 xUpgradeFile.SetAttributeValue("AllowIgnoreOnError", "yes");
8998
8999 foreach (var symbolPathString in symbolPaths)
9000 {
9001 var symbolPath = new Wix.SymbolPath();
9002
9003 symbolPath.Path = symbolPathString;
9004
9005 upgradeFile.AddChild(symbolPath);
9006 }
9007 } 7328 }
9008 7329
9009 if (null != row[3] && 1 == Convert.ToInt32(row[3])) 7330 if (!row.IsColumnNull(4) && 0 != row.FieldAsInteger(4))
9010 { 7331 {
9011 upgradeFile.AllowIgnoreOnError = Wix.YesNoType.yes; 7332 xUpgradeFile.SetAttributeValue("WholeFile", "yes");
9012 } 7333 }
9013 7334
9014 if (null != row[4] && 0 != Convert.ToInt32(row[4])) 7335 this.AddChildToParent("UpgradedImages", xUpgradeFile, row, 0);
9015 {
9016 upgradeFile.WholeFile = Wix.YesNoType.yes;
9017 }
9018
9019 upgradeFile.Ignore = Wix.YesNoType.no;
9020
9021 var upgradeImage = (Wix.UpgradeImage)this.core.GetIndexedElement("UpgradedImages", Convert.ToString(row[0]));
9022 if (null != upgradeImage)
9023 {
9024 upgradeImage.AddChild(upgradeFile);
9025 }
9026 else
9027 {
9028 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Upgraded", Convert.ToString(row[0]), "UpgradedImages"));
9029 }
9030 } 7336 }
9031 } 7337 }
9032 7338
@@ -9038,23 +7344,13 @@ namespace WixToolset.Core.WindowsInstaller
9038 { 7344 {
9039 foreach (var row in table.Rows) 7345 foreach (var row in table.Rows)
9040 { 7346 {
9041 if ("*" != Convert.ToString(row[0])) 7347 if ("*" != row.FieldAsString(0))
9042 { 7348 {
9043 var upgradeFile = new Wix.UpgradeFile(); 7349 var xUpgradeFile = new XElement(Names.UpgradeFileElement,
7350 new XAttribute("File", row.FieldAsString(1)),
7351 new XAttribute("Ignore", "yes"));
9044 7352
9045 upgradeFile.File = Convert.ToString(row[1]); 7353 this.AddChildToParent("UpgradedImages", xUpgradeFile, row, 0);
9046
9047 upgradeFile.Ignore = Wix.YesNoType.yes;
9048
9049 var upgradeImage = (Wix.UpgradeImage)this.core.GetIndexedElement("UpgradedImages", Convert.ToString(row[0]));
9050 if (null != upgradeImage)
9051 {
9052 upgradeImage.AddChild(upgradeFile);
9053 }
9054 else
9055 {
9056 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Upgraded", Convert.ToString(row[0]), "UpgradedImages"));
9057 }
9058 } 7354 }
9059 else 7355 else
9060 { 7356 {
@@ -9071,41 +7367,31 @@ namespace WixToolset.Core.WindowsInstaller
9071 { 7367 {
9072 foreach (var row in table.Rows) 7368 foreach (var row in table.Rows)
9073 { 7369 {
9074 var upgradeImage = new Wix.UpgradeImage(); 7370 var xUpgradeImage = new XElement(Names.UpgradeImageElement,
7371 new XAttribute("Id", row.FieldAsString(0)),
7372 new XAttribute("SourceFile", row.FieldAsString(1)),
7373 XAttributeIfNotNull("SourcePatch", row, 2));
9075 7374
9076 upgradeImage.Id = Convert.ToString(row[0]); 7375 AddSymbolPaths(row, 3, xUpgradeImage);
9077 7376
9078 upgradeImage.SourceFile = Convert.ToString(row[1]); 7377 this.AddChildToParent("ImageFamilies", xUpgradeImage, row, 4);
7378 this.IndexElement(row, xUpgradeImage);
7379 }
7380 }
9079 7381
9080 if (null != row[2]) 7382 private static void AddSymbolPaths(Row row, int column, XElement xParent)
9081 { 7383 {
9082 upgradeImage.SourcePatch = Convert.ToString(row[2]); 7384 if (!row.IsColumnNull(column))
9083 } 7385 {
7386 var symbolPaths = row.FieldAsString(column).Split(';');
9084 7387
9085 if (null != row[3]) 7388 foreach (var symbolPath in symbolPaths)
9086 { 7389 {
9087 var symbolPaths = (Convert.ToString(row[3])).Split(';'); 7390 var xSymbolPath = new XElement(Names.SymbolPathElement,
9088 7391 new XAttribute("Path", symbolPath));
9089 foreach (var symbolPathString in symbolPaths)
9090 {
9091 var symbolPath = new Wix.SymbolPath();
9092 7392
9093 symbolPath.Path = symbolPathString; 7393 xParent.Add(xSymbolPath);
9094
9095 upgradeImage.AddChild(symbolPath);
9096 }
9097 }
9098
9099 var family = (Wix.Family)this.core.GetIndexedElement("ImageFamilies", Convert.ToString(row[4]));
9100 if (null != family)
9101 {
9102 family.AddChild(upgradeImage);
9103 } 7394 }
9104 else
9105 {
9106 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Family", Convert.ToString(row[4]), "ImageFamilies"));
9107 }
9108 this.core.IndexElement(row, upgradeImage);
9109 } 7395 }
9110 } 7396 }
9111 7397
@@ -9117,13 +7403,11 @@ namespace WixToolset.Core.WindowsInstaller
9117 { 7403 {
9118 foreach (var row in table.Rows) 7404 foreach (var row in table.Rows)
9119 { 7405 {
9120 var uiText = new Wix.UIText(); 7406 var xUiText = new XElement(Names.UITextElement,
9121 7407 new XAttribute("Id", row.FieldAsString(0)),
9122 uiText.Id = Convert.ToString(row[0]); 7408 new XAttribute("Value", row.FieldAsString(1)));
9123
9124 uiText.Content = Convert.ToString(row[1]);
9125 7409
9126 this.core.UIElement.AddChild(uiText); 7410 this.UIElement.Add(xUiText);
9127 } 7411 }
9128 } 7412 }
9129 7413
@@ -9135,26 +7419,13 @@ namespace WixToolset.Core.WindowsInstaller
9135 { 7419 {
9136 foreach (var row in table.Rows) 7420 foreach (var row in table.Rows)
9137 { 7421 {
9138 var verb = new Wix.Verb(); 7422 var verb = new XElement(Names.VerbElement,
9139 7423 new XAttribute("Id", row.FieldAsString(1)),
9140 verb.Id = Convert.ToString(row[1]); 7424 XAttributeIfNotNull("Sequence", row, 2),
9141 7425 XAttributeIfNotNull("Command", row, 3),
9142 if (null != row[2]) 7426 XAttributeIfNotNull("Argument", row, 4));
9143 {
9144 verb.Sequence = Convert.ToInt32(row[2]);
9145 }
9146
9147 if (null != row[3])
9148 {
9149 verb.Command = Convert.ToString(row[3]);
9150 }
9151
9152 if (null != row[4])
9153 {
9154 verb.Argument = Convert.ToString(row[4]);
9155 }
9156 7427
9157 this.core.IndexElement(row, verb); 7428 this.IndexElement(row, verb);
9158 } 7429 }
9159 } 7430 }
9160 7431
@@ -9166,29 +7437,29 @@ namespace WixToolset.Core.WindowsInstaller
9166 /// <param name="field">The field containing the root value.</param> 7437 /// <param name="field">The field containing the root value.</param>
9167 /// <param name="registryRootType">The strongly-typed representation of the root.</param> 7438 /// <param name="registryRootType">The strongly-typed representation of the root.</param>
9168 /// <returns>true if the value could be converted; false otherwise.</returns> 7439 /// <returns>true if the value could be converted; false otherwise.</returns>
9169 private bool GetRegistryRootType(SourceLineNumber sourceLineNumbers, string tableName, Field field, out Wix.RegistryRootType registryRootType) 7440 private bool GetRegistryRootType(SourceLineNumber sourceLineNumbers, string tableName, Field field, out string registryRootType)
9170 { 7441 {
9171 switch (Convert.ToInt32(field.Data)) 7442 switch (Convert.ToInt32(field.Data))
9172 { 7443 {
9173 case (-1): 7444 case (-1):
9174 registryRootType = Wix.RegistryRootType.HKMU; 7445 registryRootType = "HKMU";
9175 return true; 7446 return true;
9176 case WindowsInstallerConstants.MsidbRegistryRootClassesRoot: 7447 case WindowsInstallerConstants.MsidbRegistryRootClassesRoot:
9177 registryRootType = Wix.RegistryRootType.HKCR; 7448 registryRootType = "HKCR";
9178 return true; 7449 return true;
9179 case WindowsInstallerConstants.MsidbRegistryRootCurrentUser: 7450 case WindowsInstallerConstants.MsidbRegistryRootCurrentUser:
9180 registryRootType = Wix.RegistryRootType.HKCU; 7451 registryRootType = "HKCU";
9181 return true; 7452 return true;
9182 case WindowsInstallerConstants.MsidbRegistryRootLocalMachine: 7453 case WindowsInstallerConstants.MsidbRegistryRootLocalMachine:
9183 registryRootType = Wix.RegistryRootType.HKLM; 7454 registryRootType = "HKLM";
9184 return true; 7455 return true;
9185 case WindowsInstallerConstants.MsidbRegistryRootUsers: 7456 case WindowsInstallerConstants.MsidbRegistryRootUsers:
9186 registryRootType = Wix.RegistryRootType.HKU; 7457 registryRootType = "HKU";
9187 return true; 7458 return true;
9188 default: 7459 default:
9189 this.Messaging.Write(WarningMessages.IllegalColumnValue(sourceLineNumbers, tableName, field.Column.Name, field.Data)); 7460 this.Messaging.Write(WarningMessages.IllegalColumnValue(sourceLineNumbers, tableName, field.Column.Name, field.Data));
9190 registryRootType = Wix.RegistryRootType.HKCR; // assign anything to satisfy the out parameter 7461 registryRootType = null; // assign anything to satisfy the out parameter
9191 return false; 7462 return false;
9192 } 7463 }
9193 } 7464 }
9194 7465
@@ -9206,11 +7477,9 @@ namespace WixToolset.Core.WindowsInstaller
9206 var featureField = row.Fields[featureColumnIndex]; 7477 var featureField = row.Fields[featureColumnIndex];
9207 var componentField = row.Fields[componentColumnIndex]; 7478 var componentField = row.Fields[componentColumnIndex];
9208 7479
9209 var componentRef = (Wix.ComponentRef)this.core.GetIndexedElement("FeatureComponents", Convert.ToString(featureField.Data), Convert.ToString(componentField.Data)); 7480 if (this.TryGetIndexedElement("FeatureComponents", out var xComponentRef, Convert.ToString(featureField.Data), Convert.ToString(componentField.Data)))
9210
9211 if (null != componentRef)
9212 { 7481 {
9213 componentRef.Primary = Wix.YesNoType.yes; 7482 xComponentRef.SetAttributeValue("Primary", "yes");
9214 } 7483 }
9215 else 7484 else
9216 { 7485 {
@@ -9223,7 +7492,7 @@ namespace WixToolset.Core.WindowsInstaller
9223 /// Checks the InstallExecuteSequence table to determine where RemoveExistingProducts is scheduled and removes it. 7492 /// Checks the InstallExecuteSequence table to determine where RemoveExistingProducts is scheduled and removes it.
9224 /// </summary> 7493 /// </summary>
9225 /// <param name="tables">The collection of all tables.</param> 7494 /// <param name="tables">The collection of all tables.</param>
9226 private static Wix.MajorUpgrade.ScheduleType DetermineMajorUpgradeScheduling(TableIndexedCollection tables) 7495 private static string DetermineMajorUpgradeScheduling(TableIndexedCollection tables)
9227 { 7496 {
9228 var sequenceRemoveExistingProducts = 0; 7497 var sequenceRemoveExistingProducts = 0;
9229 var sequenceInstallValidate = 0; 7498 var sequenceInstallValidate = 0;
@@ -9239,30 +7508,30 @@ namespace WixToolset.Core.WindowsInstaller
9239 for (var i = 0; i < installExecuteSequenceTable.Rows.Count; i++) 7508 for (var i = 0; i < installExecuteSequenceTable.Rows.Count; i++)
9240 { 7509 {
9241 var row = installExecuteSequenceTable.Rows[i]; 7510 var row = installExecuteSequenceTable.Rows[i];
9242 var action = Convert.ToString(row[0]); 7511 var action = row.FieldAsString(0);
9243 var sequence = Convert.ToInt32(row[2]); 7512 var sequence = row.FieldAsInteger(2);
9244 7513
9245 switch (action) 7514 switch (action)
9246 { 7515 {
9247 case "RemoveExistingProducts": 7516 case "RemoveExistingProducts":
9248 sequenceRemoveExistingProducts = sequence; 7517 sequenceRemoveExistingProducts = sequence;
9249 removeExistingProductsRow = i; 7518 removeExistingProductsRow = i;
9250 break; 7519 break;
9251 case "InstallValidate": 7520 case "InstallValidate":
9252 sequenceInstallValidate = sequence; 7521 sequenceInstallValidate = sequence;
9253 break; 7522 break;
9254 case "InstallInitialize": 7523 case "InstallInitialize":
9255 sequenceInstallInitialize = sequence; 7524 sequenceInstallInitialize = sequence;
9256 break; 7525 break;
9257 case "InstallExecute": 7526 case "InstallExecute":
9258 sequenceInstallExecute = sequence; 7527 sequenceInstallExecute = sequence;
9259 break; 7528 break;
9260 case "InstallExecuteAgain": 7529 case "InstallExecuteAgain":
9261 sequenceInstallExecuteAgain = sequence; 7530 sequenceInstallExecuteAgain = sequence;
9262 break; 7531 break;
9263 case "InstallFinalize": 7532 case "InstallFinalize":
9264 sequenceInstallFinalize = sequence; 7533 sequenceInstallFinalize = sequence;
9265 break; 7534 break;
9266 } 7535 }
9267 } 7536 }
9268 7537
@@ -9271,23 +7540,23 @@ namespace WixToolset.Core.WindowsInstaller
9271 7540
9272 if (0 != sequenceInstallValidate && sequenceInstallValidate < sequenceRemoveExistingProducts && sequenceRemoveExistingProducts < sequenceInstallInitialize) 7541 if (0 != sequenceInstallValidate && sequenceInstallValidate < sequenceRemoveExistingProducts && sequenceRemoveExistingProducts < sequenceInstallInitialize)
9273 { 7542 {
9274 return Wix.MajorUpgrade.ScheduleType.afterInstallValidate; 7543 return "afterInstallValidate";
9275 } 7544 }
9276 else if (0 != sequenceInstallInitialize && sequenceInstallInitialize < sequenceRemoveExistingProducts && sequenceRemoveExistingProducts < sequenceInstallExecute) 7545 else if (0 != sequenceInstallInitialize && sequenceInstallInitialize < sequenceRemoveExistingProducts && sequenceRemoveExistingProducts < sequenceInstallExecute)
9277 { 7546 {
9278 return Wix.MajorUpgrade.ScheduleType.afterInstallInitialize; 7547 return "afterInstallInitialize";
9279 } 7548 }
9280 else if (0 != sequenceInstallExecute && sequenceInstallExecute < sequenceRemoveExistingProducts && sequenceRemoveExistingProducts < sequenceInstallExecuteAgain) 7549 else if (0 != sequenceInstallExecute && sequenceInstallExecute < sequenceRemoveExistingProducts && sequenceRemoveExistingProducts < sequenceInstallExecuteAgain)
9281 { 7550 {
9282 return Wix.MajorUpgrade.ScheduleType.afterInstallExecute; 7551 return "afterInstallExecute";
9283 } 7552 }
9284 else if (0 != sequenceInstallExecuteAgain && sequenceInstallExecuteAgain < sequenceRemoveExistingProducts && sequenceRemoveExistingProducts < sequenceInstallFinalize) 7553 else if (0 != sequenceInstallExecuteAgain && sequenceInstallExecuteAgain < sequenceRemoveExistingProducts && sequenceRemoveExistingProducts < sequenceInstallFinalize)
9285 { 7554 {
9286 return Wix.MajorUpgrade.ScheduleType.afterInstallExecuteAgain; 7555 return "afterInstallExecuteAgain";
9287 } 7556 }
9288 else 7557 else
9289 { 7558 {
9290 return Wix.MajorUpgrade.ScheduleType.afterInstallFinalize; 7559 return "afterInstallFinalize";
9291 } 7560 }
9292 } 7561 }
9293 } 7562 }
diff --git a/src/WixToolset.Core.WindowsInstaller/Decompile/DecompilerCore.cs b/src/WixToolset.Core.WindowsInstaller/Decompile/DecompilerCore.cs
deleted file mode 100644
index 17c97e09..00000000
--- a/src/WixToolset.Core.WindowsInstaller/Decompile/DecompilerCore.cs
+++ /dev/null
@@ -1,110 +0,0 @@
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}
diff --git a/src/WixToolset.Core.WindowsInstaller/Decompile/Names.cs b/src/WixToolset.Core.WindowsInstaller/Decompile/Names.cs
new file mode 100644
index 00000000..63ab5cd3
--- /dev/null
+++ b/src/WixToolset.Core.WindowsInstaller/Decompile/Names.cs
@@ -0,0 +1,158 @@
1namespace WixToolset.Core.WindowsInstaller.Decompile
2{
3 using System.Xml.Linq;
4
5 internal static class Names
6 {
7 public static readonly XNamespace WxsNamespace = "http://wixtoolset.org/schemas/v4/wxs";
8
9 public static readonly XName WixElement = WxsNamespace + "Wix";
10
11 public static readonly XName ProductElement = WxsNamespace + "Product";
12 public static readonly XName ModuleElement = WxsNamespace + "Module";
13 public static readonly XName PatchCreationElement = WxsNamespace + "PatchCreation";
14
15 public static readonly XName CustomElement = WxsNamespace + "Custom";
16
17 public static readonly XName AdminExecuteSequenceElement = WxsNamespace + "AdminExecuteSequence";
18 public static readonly XName AdminUISequenceElement = WxsNamespace + "AdminUISequence";
19 public static readonly XName AdvertiseExecuteSequenceElement = WxsNamespace + "AdvertiseExecuteSequence";
20 public static readonly XName InstallExecuteSequenceElement = WxsNamespace + "InstallExecuteSequence";
21 public static readonly XName InstallUISequenceElement = WxsNamespace + "InstallUISequence";
22
23 public static readonly XName AppSearchElement = WxsNamespace + "AppSearch";
24
25 public static readonly XName PropertyElement = WxsNamespace + "Property";
26
27 public static readonly XName ProtectRangeElement = WxsNamespace + "ProtectRange";
28 public static readonly XName ProtectFileElement = WxsNamespace + "ProtectFile";
29
30 public static readonly XName FileElement = WxsNamespace + "File";
31
32 public static readonly XName EnsureTableElement = WxsNamespace + "EnsureTable";
33 public static readonly XName PackageElement = WxsNamespace + "Package";
34 public static readonly XName PatchInformationElement = WxsNamespace + "PatchInformation";
35
36 public static readonly XName ProgressTextElement = WxsNamespace + "ProgressText";
37 public static readonly XName UIElement = WxsNamespace + "UI";
38
39 public static readonly XName AppIdElement = WxsNamespace + "AppId";
40
41 public static readonly XName ControlElement = WxsNamespace + "Control";
42
43 public static readonly XName BillboardElement = WxsNamespace + "Billboard";
44 public static readonly XName BillboardActionElement = WxsNamespace + "BillboardAction";
45
46 public static readonly XName BinaryElement = WxsNamespace + "Binary";
47
48 public static readonly XName ClassElement = WxsNamespace + "Class";
49
50 public static readonly XName FileTypeMaskElement = WxsNamespace + "FileTypeMask";
51
52 public static readonly XName ComboBoxElement = WxsNamespace + "ComboBox";
53
54 public static readonly XName ListItemElement = WxsNamespace + "ListItem";
55
56 public static readonly XName ConditionElement = WxsNamespace + "Condition";
57 public static readonly XName PublishElement = WxsNamespace + "Publish";
58 public static readonly XName CustomTableElement = WxsNamespace + "CustomTable";
59 public static readonly XName ColumnElement = WxsNamespace + "Column";
60 public static readonly XName RowElement = WxsNamespace + "Row";
61 public static readonly XName DataElement = WxsNamespace + "Data";
62 public static readonly XName CreateFolderElement = WxsNamespace + "CreateFolder";
63
64 public static readonly XName CustomActionElement = WxsNamespace + "CustomAction";
65
66 public static readonly XName ComponentSearchElement = WxsNamespace + "ComponentSearch";
67 public static readonly XName ComponentElement = WxsNamespace + "Component";
68
69 public static readonly XName LevelElement = WxsNamespace + "Level";
70 public static readonly XName DialogElement = WxsNamespace + "Dialog";
71 public static readonly XName DirectoryElement = WxsNamespace + "Directory";
72 public static readonly XName DirectorySearchElement = WxsNamespace + "DirectorySearch";
73 public static readonly XName CopyFileElement = WxsNamespace + "CopyFile";
74 public static readonly XName EnvironmentElement = WxsNamespace + "Environment";
75 public static readonly XName ErrorElement = WxsNamespace + "Error";
76 public static readonly XName SubscribeElement = WxsNamespace + "Subscribe";
77 public static readonly XName ExtensionElement = WxsNamespace + "Extension";
78 public static readonly XName ExternalFileElement = WxsNamespace + "ExternalFile";
79 public static readonly XName SymbolPathElement = WxsNamespace + "SymbolPath";
80 public static readonly XName IgnoreRangeElement = WxsNamespace + "IgnoreRange";
81
82 public static readonly XName FeatureElement = WxsNamespace + "Feature";
83 public static readonly XName ComponentRefElement = WxsNamespace + "ComponentRef";
84 public static readonly XName SFPFileElement = WxsNamespace + "SFPFile";
85 public static readonly XName IconElement = WxsNamespace + "Icon";
86 public static readonly XName FamilyElement = WxsNamespace + "Family";
87 public static readonly XName IniFileElement = WxsNamespace + "IniFile";
88 public static readonly XName IniFileSearchElement = WxsNamespace + "IniFileSearch";
89 public static readonly XName IsolateComponentElement = WxsNamespace + "IsolateComponent";
90 public static readonly XName LaunchElement = WxsNamespace + "Launch";
91 public static readonly XName ListBoxElement = WxsNamespace + "ListBox";
92 public static readonly XName ListViewElement = WxsNamespace + "ListView";
93 public static readonly XName PermissionElement = WxsNamespace + "Permission";
94 public static readonly XName MediaElement = WxsNamespace + "Media";
95 public static readonly XName MIMEElement = WxsNamespace + "MIME";
96 public static readonly XName ConfigurationElement = WxsNamespace + "Configuration";
97 public static readonly XName DependencyElement = WxsNamespace + "Dependency";
98 public static readonly XName ExclusionElement = WxsNamespace + "Exclusion";
99 public static readonly XName IgnoreTableElement = WxsNamespace + "IgnoreTable";
100 public static readonly XName SubstitutionElement = WxsNamespace + "Substitution";
101 public static readonly XName DigitalCertificateElement = WxsNamespace + "DigitalCertificate";
102 public static readonly XName DigitalSignatureElement = WxsNamespace + "DigitalSignature";
103 public static readonly XName EmbeddedChainerElement = WxsNamespace + "EmbeddedChainer";
104 public static readonly XName EmbeddedUIElement = WxsNamespace + "EmbeddedUI";
105 public static readonly XName EmbeddedUIResourceElement = WxsNamespace + "EmbeddedUIResource";
106 public static readonly XName PermissionExElement = WxsNamespace + "PermissionEx";
107 public static readonly XName PackageCertificatesElement = WxsNamespace + "PackageCertificates";
108 public static readonly XName PatchCertificatesElement = WxsNamespace + "PatchCertificates";
109 public static readonly XName ShortcutPropertyElement = WxsNamespace + "ShortcutProperty";
110 public static readonly XName ODBCDataSourceElement = WxsNamespace + "ODBCDataSource";
111 public static readonly XName ODBCDriverElement = WxsNamespace + "ODBCDriver";
112 public static readonly XName ODBCTranslatorElement = WxsNamespace + "ODBCTranslator";
113 public static readonly XName PatchMetadataElement = WxsNamespace + "PatchMetadata";
114 public static readonly XName OptimizeCustomActionsElement = WxsNamespace + "OptimizeCustomActions";
115 public static readonly XName CustomPropertyElement = WxsNamespace + "CustomProperty";
116 public static readonly XName PatchSequenceElement = WxsNamespace + "PatchSequence";
117 public static readonly XName ProgIdElement = WxsNamespace + "ProgId";
118 public static readonly XName ReplacePatchElement = WxsNamespace + "ReplacePatch";
119 public static readonly XName TargetProductCodeElement = WxsNamespace + "TargetProductCode";
120 public static readonly XName PatchPropertyElement = WxsNamespace + "PatchProperty";
121 public static readonly XName CategoryElement = WxsNamespace + "Category";
122 public static readonly XName RadioButtonElement = WxsNamespace + "RadioButton";
123 public static readonly XName RadioButtonGroupElement = WxsNamespace + "RadioButtonGroup";
124 public static readonly XName RegistryKeyElement = WxsNamespace + "RegistryKey";
125 public static readonly XName RegistryValueElement = WxsNamespace + "RegistryValue";
126 public static readonly XName MultiStringElement = WxsNamespace + "MultiString";
127 public static readonly XName RegistrySearchElement = WxsNamespace + "RegistrySearch";
128 public static readonly XName RemoveFolderElement = WxsNamespace + "RemoveFolder";
129 public static readonly XName RemoveFileElement = WxsNamespace + "RemoveFile";
130 public static readonly XName RemoveRegistryKeyElement = WxsNamespace + "RemoveRegistryKey";
131 public static readonly XName RemoveRegistryValueElement = WxsNamespace + "RemoveRegistryValue";
132 public static readonly XName ReserveCostElement = WxsNamespace + "ReserveCost";
133 public static readonly XName ServiceControlElement = WxsNamespace + "ServiceControl";
134 public static readonly XName ServiceArgumentElement = WxsNamespace + "ServiceArgument";
135 public static readonly XName ServiceInstallElement = WxsNamespace + "ServiceInstall";
136 public static readonly XName ServiceDependencyElement = WxsNamespace + "ServiceDependency";
137 public static readonly XName SFPCatalogElement = WxsNamespace + "SFPCatalog";
138 public static readonly XName ShortcutElement = WxsNamespace + "Shortcut";
139 public static readonly XName FileSearchElement = WxsNamespace + "FileSearch";
140 public static readonly XName TargetFileElement = WxsNamespace + "TargetFile";
141 public static readonly XName TargetImageElement = WxsNamespace + "TargetImage";
142 public static readonly XName TextStyleElement = WxsNamespace + "TextStyle";
143 public static readonly XName TypeLibElement = WxsNamespace + "TypeLib";
144 public static readonly XName UpgradeElement = WxsNamespace + "Upgrade";
145 public static readonly XName UpgradeVersionElement = WxsNamespace + "UpgradeVersion";
146 public static readonly XName UpgradeFileElement = WxsNamespace + "UpgradeFile";
147 public static readonly XName UpgradeImageElement = WxsNamespace + "UpgradeImage";
148 public static readonly XName UITextElement = WxsNamespace + "UIText";
149 public static readonly XName VerbElement = WxsNamespace + "Verb";
150 public static readonly XName ComplianceCheckElement = WxsNamespace + "ComplianceCheck";
151 public static readonly XName FileSearchRefElement = WxsNamespace + "FileSearchRef";
152 public static readonly XName ComplianceDriveElement = WxsNamespace + "ComplianceDrive";
153 public static readonly XName DirectorySearchRefElement = WxsNamespace + "DirectorySearchRef";
154 public static readonly XName RegistrySearchRefElement = WxsNamespace + "RegistrySearchRef";
155 public static readonly XName MajorUpgradeElement = WxsNamespace + "MajorUpgrade";
156 //public static readonly XName Element = WxsNamespace + "";
157 }
158}
diff --git a/src/WixToolset.Core.WindowsInstaller/Melter.cs b/src/WixToolset.Core.WindowsInstaller/Melter.cs
index a57f73a5..4e4d9e4e 100644
--- a/src/WixToolset.Core.WindowsInstaller/Melter.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Melter.cs
@@ -12,7 +12,6 @@ namespace WixToolset
12 using System.Text; 12 using System.Text;
13 using System.Text.RegularExpressions; 13 using System.Text.RegularExpressions;
14 using WixToolset.Data; 14 using WixToolset.Data;
15 using Wix = WixToolset.Data.Serialize;
16 15
17 /// <summary> 16 /// <summary>
18 /// Converts a wixout representation of an MSM database into a ComponentGroup the form of WiX source. 17 /// Converts a wixout representation of an MSM database into a ComponentGroup the form of WiX source.
diff --git a/src/WixToolset.Core/CommandLine/DecompileCommand.cs b/src/WixToolset.Core/CommandLine/DecompileCommand.cs
index 1e11ae52..fc77a7b4 100644
--- a/src/WixToolset.Core/CommandLine/DecompileCommand.cs
+++ b/src/WixToolset.Core/CommandLine/DecompileCommand.cs
@@ -33,7 +33,7 @@ namespace WixToolset.Core.CommandLine
33 33
34 public Task<int> ExecuteAsync(CancellationToken _) 34 public Task<int> ExecuteAsync(CancellationToken _)
35 { 35 {
36 if (this.commandLine.ShowHelp) 36 if (this.commandLine.ShowHelp || String.IsNullOrEmpty(this.commandLine.DecompileFilePath))
37 { 37 {
38 Console.WriteLine("TODO: Show decompile command help"); 38 Console.WriteLine("TODO: Show decompile command help");
39 return Task.FromResult(-1); 39 return Task.FromResult(-1);
diff --git a/src/WixToolset.Core/Compiler.cs b/src/WixToolset.Core/Compiler.cs
index c641bceb..6cc3a2e8 100644
--- a/src/WixToolset.Core/Compiler.cs
+++ b/src/WixToolset.Core/Compiler.cs
@@ -3331,7 +3331,7 @@ namespace WixToolset.Core
3331 break; 3331 break;
3332 } 3332 }
3333 break; 3333 break;
3334 case "ScriptFile": 3334 case "ScriptSourceFile":
3335 scriptFile = this.Core.GetAttributeValue(sourceLineNumbers, attrib); 3335 scriptFile = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
3336 break; 3336 break;
3337 case "SuppressModularization": 3337 case "SuppressModularization":
@@ -3387,7 +3387,7 @@ namespace WixToolset.Core
3387 { 3387 {
3388 if (String.IsNullOrEmpty(scriptFile)) 3388 if (String.IsNullOrEmpty(scriptFile))
3389 { 3389 {
3390 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "ScriptFile", "Script")); 3390 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "ScriptSourceFile", "Script"));
3391 } 3391 }
3392 } 3392 }
3393 else if (CustomActionTargetType.VBScript == targetType) // non-inline vbscript 3393 else if (CustomActionTargetType.VBScript == targetType) // non-inline vbscript
@@ -3426,7 +3426,7 @@ namespace WixToolset.Core
3426 3426
3427 if (!inlineScript && !String.IsNullOrEmpty(scriptFile)) 3427 if (!inlineScript && !String.IsNullOrEmpty(scriptFile))
3428 { 3428 {
3429 this.Core.Write(ErrorMessages.IllegalAttributeWithoutOtherAttributes(sourceLineNumbers, node.Name.LocalName, "ScriptFile", "Script")); 3429 this.Core.Write(ErrorMessages.IllegalAttributeWithoutOtherAttributes(sourceLineNumbers, node.Name.LocalName, "ScriptSourceFile", "Script"));
3430 } 3430 }
3431 3431
3432 if (win64 && CustomActionTargetType.VBScript != targetType && CustomActionTargetType.JScript != targetType) 3432 if (win64 && CustomActionTargetType.VBScript != targetType && CustomActionTargetType.JScript != targetType)
diff --git a/src/test/WixToolsetTest.CoreIntegration/CustomTableFixture.cs b/src/test/WixToolsetTest.CoreIntegration/CustomTableFixture.cs
index 0a45c914..4a5cf544 100644
--- a/src/test/WixToolsetTest.CoreIntegration/CustomTableFixture.cs
+++ b/src/test/WixToolsetTest.CoreIntegration/CustomTableFixture.cs
@@ -3,6 +3,7 @@
3namespace WixToolsetTest.CoreIntegration 3namespace WixToolsetTest.CoreIntegration
4{ 4{
5 using System.IO; 5 using System.IO;
6 using System.Xml.Linq;
6 using WixBuildTools.TestSupport; 7 using WixBuildTools.TestSupport;
7 using WixToolset.Core.TestPackage; 8 using WixToolset.Core.TestPackage;
8 using Xunit; 9 using Xunit;
@@ -224,20 +225,8 @@ namespace WixToolsetTest.CoreIntegration
224 225
225 result.AssertSuccess(); 226 result.AssertSuccess();
226 227
227 CompareLineByLine(expectedFile, decompiledWxsPath); 228 WixAssert.CompareXml(expectedFile, decompiledWxsPath);
228 } 229 }
229 } 230 }
230
231 private static void CompareLineByLine(string expectedFile, string actualFile)
232 {
233 var expectedLines = File.ReadAllLines(expectedFile);
234 var actualLines = File.ReadAllLines(actualFile);
235 for (var i = 0; i < expectedLines.Length; ++i)
236 {
237 Assert.True(actualLines.Length > i, $"{i}: Expected file longer than actual file");
238 Assert.Equal($"{i}: {expectedLines[i]}", $"{i}: {actualLines[i]}");
239 }
240 Assert.True(expectedLines.Length == actualLines.Length, "Actual file longer than expected file");
241 }
242 } 231 }
243} 232}
diff --git a/src/test/WixToolsetTest.CoreIntegration/DecompileFixture.cs b/src/test/WixToolsetTest.CoreIntegration/DecompileFixture.cs
index 9893a525..15082f2b 100644
--- a/src/test/WixToolsetTest.CoreIntegration/DecompileFixture.cs
+++ b/src/test/WixToolsetTest.CoreIntegration/DecompileFixture.cs
@@ -6,14 +6,14 @@ namespace WixToolsetTest.CoreIntegration
6 using System.Xml.Linq; 6 using System.Xml.Linq;
7 using WixBuildTools.TestSupport; 7 using WixBuildTools.TestSupport;
8 using WixToolset.Core.TestPackage; 8 using WixToolset.Core.TestPackage;
9 using WixToolset.Extensibility.Services;
9 using Xunit; 10 using Xunit;
10 11
11 public class DecompileFixture 12 public class DecompileFixture
12 { 13 {
13 [Fact] 14 private static void DecompileAndCompare(string sourceFolder, string msiName, string expectedWxsName)
14 public void CanDecompileSingleFileCompressed()
15 { 15 {
16 var folder = TestData.Get(@"TestData\DecompileSingleFileCompressed"); 16 var folder = TestData.Get(sourceFolder);
17 17
18 using (var fs = new DisposableFileSystem()) 18 using (var fs = new DisposableFileSystem())
19 { 19 {
@@ -23,75 +23,33 @@ namespace WixToolsetTest.CoreIntegration
23 var result = WixRunner.Execute(new[] 23 var result = WixRunner.Execute(new[]
24 { 24 {
25 "decompile", 25 "decompile",
26 Path.Combine(folder, "example.msi"), 26 Path.Combine(folder, msiName),
27 "-intermediateFolder", intermediateFolder, 27 "-intermediateFolder", intermediateFolder,
28 "-o", outputPath 28 "-o", outputPath
29 }); 29 });
30 30
31 result.AssertSuccess(); 31 result.AssertSuccess();
32 32
33 var actual = File.ReadAllText(outputPath); 33 WixAssert.CompareXml(Path.Combine(folder, expectedWxsName), outputPath);
34 var actualFormatted = XDocument.Parse(actual, LoadOptions.PreserveWhitespace | LoadOptions.SetBaseUri | LoadOptions.SetLineInfo).ToString();
35 var expected = XDocument.Load(Path.Combine(folder, "Expected.wxs"), LoadOptions.PreserveWhitespace | LoadOptions.SetBaseUri | LoadOptions.SetLineInfo).ToString();
36
37 Assert.Equal(expected, actualFormatted);
38 } 34 }
39 } 35 }
40 36
41 [Fact] 37 [Fact]
42 public void CanDecompile64BitSingleFileCompressed() 38 public void CanDecompileSingleFileCompressed()
43 { 39 {
44 var folder = TestData.Get(@"TestData\DecompileSingleFileCompressed64"); 40 DecompileAndCompare(@"TestData\DecompileSingleFileCompressed", "example.msi", "Expected.wxs");
45 41 }
46 using (var fs = new DisposableFileSystem())
47 {
48 var intermediateFolder = fs.GetFolder();
49 var outputPath = Path.Combine(intermediateFolder, @"Actual.wxs");
50
51 var result = WixRunner.Execute(new[]
52 {
53 "decompile",
54 Path.Combine(folder, "example.msi"),
55 "-intermediateFolder", intermediateFolder,
56 "-o", outputPath
57 });
58
59 result.AssertSuccess();
60
61 var actual = File.ReadAllText(outputPath);
62 var actualFormatted = XDocument.Parse(actual, LoadOptions.PreserveWhitespace | LoadOptions.SetBaseUri | LoadOptions.SetLineInfo).ToString();
63 var expected = XDocument.Load(Path.Combine(folder, "Expected.wxs"), LoadOptions.PreserveWhitespace | LoadOptions.SetBaseUri | LoadOptions.SetLineInfo).ToString();
64 42
65 Assert.Equal(expected, actualFormatted); 43 [Fact]
66 } 44 public void CanDecompile64BitSingleFileCompressed()
45 {
46 DecompileAndCompare(@"TestData\DecompileSingleFileCompressed64", "example.msi", "Expected.wxs");
67 } 47 }
68 48
69 [Fact] 49 [Fact]
70 public void CanDecompileNestedDirSearchUnderRegSearch() 50 public void CanDecompileNestedDirSearchUnderRegSearch()
71 { 51 {
72 var folder = TestData.Get(@"TestData\AppSearch"); 52 DecompileAndCompare(@"TestData\AppSearch", "NestedDirSearchUnderRegSearch.msi", "DecompiledNestedDirSearchUnderRegSearch.wxs");
73
74 using (var fs = new DisposableFileSystem())
75 {
76 var intermediateFolder = fs.GetFolder();
77 var outputPath = Path.Combine(intermediateFolder, @"Actual.wxs");
78
79 var result = WixRunner.Execute(new[]
80 {
81 "decompile",
82 Path.Combine(folder, "NestedDirSearchUnderRegSearch.msi"),
83 "-intermediateFolder", intermediateFolder,
84 "-o", outputPath
85 });
86
87 result.AssertSuccess();
88
89 var actual = File.ReadAllText(outputPath);
90 var actualFormatted = XDocument.Parse(actual, LoadOptions.PreserveWhitespace | LoadOptions.SetBaseUri | LoadOptions.SetLineInfo).ToString();
91 var expected = XDocument.Load(Path.Combine(folder, "DecompiledNestedDirSearchUnderRegSearch.wxs"), LoadOptions.PreserveWhitespace | LoadOptions.SetBaseUri | LoadOptions.SetLineInfo).ToString();
92
93 Assert.Equal(expected, actualFormatted);
94 }
95 } 53 }
96 54
97 [Fact] 55 [Fact]
@@ -100,85 +58,19 @@ namespace WixToolsetTest.CoreIntegration
100 // The input MSI was not created using standard methods, it is an example of a real world database that needs to be decompiled. 58 // The input MSI was not created using standard methods, it is an example of a real world database that needs to be decompiled.
101 // The Class/@Feature_ column has length of 32, the File/@Attributes has length of 2, 59 // The Class/@Feature_ column has length of 32, the File/@Attributes has length of 2,
102 // and numerous foreign key relationships are missing. 60 // and numerous foreign key relationships are missing.
103 var folder = TestData.Get(@"TestData\Class"); 61 DecompileAndCompare(@"TestData\Class", "OldClassTableDef.msi", "DecompiledOldClassTableDef.wxs");
104
105 using (var fs = new DisposableFileSystem())
106 {
107 var intermediateFolder = fs.GetFolder();
108 var outputPath = Path.Combine(intermediateFolder, @"Actual.wxs");
109
110 var result = WixRunner.Execute(new[]
111 {
112 "decompile",
113 Path.Combine(folder, "OldClassTableDef.msi"),
114 "-intermediateFolder", intermediateFolder,
115 "-o", outputPath
116 });
117
118 result.AssertSuccess();
119
120 var actual = File.ReadAllText(outputPath);
121 var actualFormatted = XDocument.Parse(actual, LoadOptions.PreserveWhitespace | LoadOptions.SetBaseUri | LoadOptions.SetLineInfo).ToString();
122 var expected = XDocument.Load(Path.Combine(folder, "DecompiledOldClassTableDef.wxs"), LoadOptions.PreserveWhitespace | LoadOptions.SetBaseUri | LoadOptions.SetLineInfo).ToString();
123
124 Assert.Equal(expected, actualFormatted);
125 }
126 } 62 }
127 63
128 [Fact] 64 [Fact]
129 public void CanDecompileSequenceTables() 65 public void CanDecompileSequenceTables()
130 { 66 {
131 var folder = TestData.Get(@"TestData\SequenceTables"); 67 DecompileAndCompare(@"TestData\SequenceTables", "SequenceTables.msi", "DecompiledSequenceTables.wxs");
132
133 using (var fs = new DisposableFileSystem())
134 {
135 var intermediateFolder = fs.GetFolder();
136 var outputPath = Path.Combine(intermediateFolder, @"Actual.wxs");
137
138 var result = WixRunner.Execute(new[]
139 {
140 "decompile",
141 Path.Combine(folder, "SequenceTables.msi"),
142 "-intermediateFolder", intermediateFolder,
143 "-o", outputPath
144 });
145
146 result.AssertSuccess();
147
148 var actual = File.ReadAllText(outputPath);
149 var actualFormatted = XDocument.Parse(actual, LoadOptions.PreserveWhitespace | LoadOptions.SetBaseUri | LoadOptions.SetLineInfo).ToString();
150 var expected = XDocument.Load(Path.Combine(folder, "DecompiledSequenceTables.wxs"), LoadOptions.PreserveWhitespace | LoadOptions.SetBaseUri | LoadOptions.SetLineInfo).ToString();
151
152 Assert.Equal(expected, actualFormatted);
153 }
154 } 68 }
155 69
156 [Fact] 70 [Fact]
157 public void CanDecompileShortcuts() 71 public void CanDecompileShortcuts()
158 { 72 {
159 var folder = TestData.Get(@"TestData\Shortcut"); 73 DecompileAndCompare(@"TestData\Shortcut", "shortcuts.msi", "DecompiledShortcuts.wxs");
160
161 using (var fs = new DisposableFileSystem())
162 {
163 var intermediateFolder = fs.GetFolder();
164 var outputPath = Path.Combine(intermediateFolder, @"Actual.wxs");
165
166 var result = WixRunner.Execute(new[]
167 {
168 "decompile",
169 Path.Combine(folder, "shortcuts.msi"),
170 "-intermediateFolder", intermediateFolder,
171 "-o", outputPath
172 });
173
174 result.AssertSuccess();
175
176 var actual = File.ReadAllText(outputPath);
177 var actualFormatted = XDocument.Parse(actual, LoadOptions.PreserveWhitespace | LoadOptions.SetBaseUri | LoadOptions.SetLineInfo).ToString();
178 var expected = XDocument.Load(Path.Combine(folder, "DecompiledShortcuts.wxs"), LoadOptions.PreserveWhitespace | LoadOptions.SetBaseUri | LoadOptions.SetLineInfo).ToString();
179
180 Assert.Equal(expected, actualFormatted);
181 }
182 } 74 }
183 } 75 }
184} 76}
diff --git a/src/test/WixToolsetTest.CoreIntegration/TestData/CustomTable/CustomTable-Expected.wxs b/src/test/WixToolsetTest.CoreIntegration/TestData/CustomTable/CustomTable-Expected.wxs
index c55f4ed0..22036ae5 100644
--- a/src/test/WixToolsetTest.CoreIntegration/TestData/CustomTable/CustomTable-Expected.wxs
+++ b/src/test/WixToolsetTest.CoreIntegration/TestData/CustomTable/CustomTable-Expected.wxs
@@ -6,12 +6,12 @@
6 <Column Id="Column1" PrimaryKey="yes" Type="string" Width="0" Category="text" Description="The first custom column." /> 6 <Column Id="Column1" PrimaryKey="yes" Type="string" Width="0" Category="text" Description="The first custom column." />
7 <Column Id="Component_" Type="string" Width="72" KeyTable="Component" KeyColumn="1" Description="The custom table's Component reference" /> 7 <Column Id="Component_" Type="string" Width="72" KeyTable="Component" KeyColumn="1" Description="The custom table's Component reference" />
8 <Row> 8 <Row>
9 <Data Column="Column1">Row1</Data> 9 <Data Column="Column1" Value="Row1" />
10 <Data Column="Component_">test.txt</Data> 10 <Data Column="Component_" Value="test.txt" />
11 </Row> 11 </Row>
12 <Row> 12 <Row>
13 <Data Column="Column1">Row2</Data> 13 <Data Column="Column1" Value="Row2" />
14 <Data Column="Component_">test.txt</Data> 14 <Data Column="Component_" Value="test.txt" />
15 </Row> 15 </Row>
16 </CustomTable> 16 </CustomTable>
17 <Directory Id="TARGETDIR" Name="SourceDir"> 17 <Directory Id="TARGETDIR" Name="SourceDir">