From 2bb37beda887d120a0ddabf874ad25357101faa1 Mon Sep 17 00:00:00 2001 From: Rob Mensching Date: Wed, 1 Nov 2017 10:59:45 -0700 Subject: Update to WiX Intermediate Representation --- src/WixToolset.Core.WindowsInstaller/Decompiler.cs | 9357 ++++++++++++++++++++ 1 file changed, 9357 insertions(+) create mode 100644 src/WixToolset.Core.WindowsInstaller/Decompiler.cs (limited to 'src/WixToolset.Core.WindowsInstaller/Decompiler.cs') diff --git a/src/WixToolset.Core.WindowsInstaller/Decompiler.cs b/src/WixToolset.Core.WindowsInstaller/Decompiler.cs new file mode 100644 index 00000000..d353cc16 --- /dev/null +++ b/src/WixToolset.Core.WindowsInstaller/Decompiler.cs @@ -0,0 +1,9357 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset +{ + using System; + using System.Collections; + using System.Collections.Generic; + using System.Collections.Specialized; + using System.Diagnostics.CodeAnalysis; + using System.Globalization; + using System.IO; + using System.Text; + using System.Text.RegularExpressions; + using WixToolset.Data; + using WixToolset.Data.Rows; + using WixToolset.Extensibility; + using WixToolset.Core.Native; + using Wix = WixToolset.Data.Serialize; + using WixToolset.Core; + + /// + /// Decompiles an msi database into WiX source. + /// + public class Decompiler + { + private static readonly Regex NullSplitter = new Regex(@"\[~]"); +#if TODO + private int codepage; + private bool compressed; + private bool shortNames; + private DecompilerCore core; + private string exportFilePath; + private List extensions; + private Dictionary extensionsByTableName; + private string modularizationGuid; + private OutputType outputType; + private Hashtable patchTargetFiles; + private Hashtable sequenceElements; + private bool showPedanticMessages; + private WixActionRowCollection standardActions; + private bool suppressCustomTables; + private bool suppressDroppingEmptyTables; + private bool suppressRelativeActionSequencing; + private bool suppressUI; + private TableDefinitionCollection tableDefinitions; + // private TempFileCollection tempFiles; + private bool treatProductAsModule; + + /// + /// Creates a new decompiler object with a default set of table definitions. + /// + public Decompiler() + { + this.standardActions = WindowsInstallerStandard.GetStandardActions(); + + this.extensions = new List(); + this.extensionsByTableName = new Dictionary(); + this.patchTargetFiles = new Hashtable(); + this.sequenceElements = new Hashtable(); + this.tableDefinitions = new TableDefinitionCollection(); + this.exportFilePath = "SourceDir"; + } + + /// + /// Gets or sets the base source file path. + /// + /// Base source file path. + public string ExportFilePath + { + get { return this.exportFilePath; } + set { this.exportFilePath = value; } + } + + /// + /// Gets or sets the option to show pedantic messages. + /// + /// The option to show pedantic messages. + public bool ShowPedanticMessages + { + get { return this.showPedanticMessages; } + set { this.showPedanticMessages = value; } + } + + /// + /// Gets or sets the option to suppress custom tables. + /// + /// The option to suppress dropping empty tables. + public bool SuppressCustomTables + { + get { return this.suppressCustomTables; } + set { this.suppressCustomTables = value; } + } + + /// + /// Gets or sets the option to suppress dropping empty tables. + /// + /// The option to suppress dropping empty tables. + public bool SuppressDroppingEmptyTables + { + get { return this.suppressDroppingEmptyTables; } + set { this.suppressDroppingEmptyTables = value; } + } + + /// + /// Gets or sets the option to suppress decompiling with relative action sequencing (uses sequence numbers). + /// + /// The option to suppress decompiling with relative action sequencing (uses sequence numbers). + public bool SuppressRelativeActionSequencing + { + get { return this.suppressRelativeActionSequencing; } + set { this.suppressRelativeActionSequencing = value; } + } + + /// + /// Gets or sets the option to suppress decompiling UI-related tables. + /// + /// The option to suppress decompiling UI-related tables. + public bool SuppressUI + { + get { return this.suppressUI; } + set { this.suppressUI = value; } + } + + /// + /// Gets or sets the temporary path for the Decompiler. If left null, the decompiler + /// will use %TEMP% environment variable. + /// + /// Path to temp files. + public string TempFilesLocation + { + get + { + // return null == this.tempFiles ? String.Empty : this.tempFiles.BasePath; + return Path.GetTempPath(); + } + + // set + // { + // if (null == value) + // { + // this.tempFiles = new TempFileCollection(); + // } + // else + // { + // this.tempFiles = new TempFileCollection(value); + // } + // } + } + + /// + /// Gets or sets whether the decompiler should use module logic on a product output. + /// + /// The option to treat a product like a module + public bool TreatProductAsModule + { + get { return this.treatProductAsModule; } + set { this.treatProductAsModule = value; } + } + + /// + /// Decompile the database file. + /// + /// The output to decompile. + /// The serialized WiX source code. + [SuppressMessage("Microsoft.Globalization", "CA1303:DoNotPassLiteralsAsLocalizedParameters", MessageId = "System.InvalidOperationException.#ctor(System.String)")] + public Wix.Wix Decompile(Output output) + { + if (null == output) + { + throw new ArgumentNullException("output"); + } + + this.codepage = output.Codepage; + this.outputType = output.Type; + + // collect the table definitions from the output + this.tableDefinitions.Clear(); + foreach (Table table in output.Tables) + { + this.tableDefinitions.Add(table.Definition); + } + + // add any missing standard and wix-specific table definitions + foreach (TableDefinition tableDefinition in WindowsInstallerStandard.GetTableDefinitions()) + { + if (!this.tableDefinitions.Contains(tableDefinition.Name)) + { + this.tableDefinitions.Add(tableDefinition); + } + } + + // add any missing extension table definitions + foreach (IDecompilerExtension extension in this.extensions) + { + if (null != extension.TableDefinitions) + { + foreach (TableDefinition tableDefinition in extension.TableDefinitions) + { + if (!this.tableDefinitions.Contains(tableDefinition.Name)) + { + this.tableDefinitions.Add(tableDefinition); + } + } + } + } + + // if we don't have the temporary files object yet, get one +#if REDO_IN_NETCORE + if (null == this.tempFiles) + { + this.TempFilesLocation = null; + } +#endif + Directory.CreateDirectory(this.TempFilesLocation); // ensure the base path is there + + bool encounteredError = false; + Wix.IParentElement rootElement; + Wix.Wix wixElement = new Wix.Wix(); + + switch (this.outputType) + { + case OutputType.Module: + rootElement = new Wix.Module(); + break; + case OutputType.PatchCreation: + rootElement = new Wix.PatchCreation(); + break; + case OutputType.Product: + rootElement = new Wix.Product(); + break; + default: + throw new InvalidOperationException(WixStrings.EXP_UnknownOutputType); + } + wixElement.AddChild((Wix.ISchemaElement)rootElement); + + // try to decompile the database file + try + { + this.core = new DecompilerCore(rootElement); + this.core.ShowPedanticMessages = this.showPedanticMessages; + + // stop processing if an error previously occurred + if (this.core.EncounteredError) + { + return null; + } + + // initialize the decompiler and its extensions + foreach (IDecompilerExtension extension in this.extensions) + { + extension.Core = this.core; + extension.Initialize(output.Tables); + } + this.InitializeDecompile(output.Tables); + + // stop processing if an error previously occurred + if (this.core.EncounteredError) + { + return null; + } + + // decompile the tables + this.DecompileTables(output); + + // finalize the decompiler and its extensions + this.FinalizeDecompile(output.Tables); + foreach (IDecompilerExtension extension in this.extensions) + { + extension.Finish(output.Tables); + } + } + finally + { + encounteredError = this.core.EncounteredError; + + this.core = null; + foreach (IDecompilerExtension extension in this.extensions) + { + extension.Core = null; + } + } + + // return the root element only if decompilation completed successfully + return (encounteredError ? null : wixElement); + } + + /// + /// Adds an extension. + /// + /// The extension to add. + public void AddExtension(IDecompilerExtension extension) + { + this.extensions.Add(extension); + + if (null != extension.TableDefinitions) + { + foreach (TableDefinition tableDefinition in extension.TableDefinitions) + { + if (!this.extensionsByTableName.ContainsKey(tableDefinition.Name)) + { + this.extensionsByTableName.Add(tableDefinition.Name, extension); + } + else + { + Messaging.Instance.OnMessage(WixErrors.DuplicateExtensionTable(extension.GetType().ToString(), tableDefinition.Name)); + } + } + } + } + + /// + /// Cleans up the temp files used by the Decompiler. + /// + /// True if all files were deleted, false otherwise. + /// + /// This should be called after every call to Decompile to ensure there + /// are no conflicts between each decompiled database. + /// + public bool DeleteTempFiles() + { +#if REDO_IN_NETCORE + if (null == this.tempFiles) + { + return true; // no work to do + } + else + { + bool deleted = Common.DeleteTempFiles(this.tempFiles.BasePath, this.core); + + if (deleted) + { + this.tempFiles = null; // temp files have been deleted, no need to remember this now + } + + return deleted; + } +#endif + return true; + } + + /// + /// Set the common control attributes in a control element. + /// + /// The control attributes. + /// The control element. + private static void SetControlAttributes(int attributes, Wix.Control control) + { + if (0 == (attributes & MsiInterop.MsidbControlAttributesEnabled)) + { + control.Disabled = Wix.YesNoType.yes; + } + + if (MsiInterop.MsidbControlAttributesIndirect == (attributes & MsiInterop.MsidbControlAttributesIndirect)) + { + control.Indirect = Wix.YesNoType.yes; + } + + if (MsiInterop.MsidbControlAttributesInteger == (attributes & MsiInterop.MsidbControlAttributesInteger)) + { + control.Integer = Wix.YesNoType.yes; + } + + if (MsiInterop.MsidbControlAttributesLeftScroll == (attributes & MsiInterop.MsidbControlAttributesLeftScroll)) + { + control.LeftScroll = Wix.YesNoType.yes; + } + + if (MsiInterop.MsidbControlAttributesRightAligned == (attributes & MsiInterop.MsidbControlAttributesRightAligned)) + { + control.RightAligned = Wix.YesNoType.yes; + } + + if (MsiInterop.MsidbControlAttributesRTLRO == (attributes & MsiInterop.MsidbControlAttributesRTLRO)) + { + control.RightToLeft = Wix.YesNoType.yes; + } + + if (MsiInterop.MsidbControlAttributesSunken == (attributes & MsiInterop.MsidbControlAttributesSunken)) + { + control.Sunken = Wix.YesNoType.yes; + } + + if (0 == (attributes & MsiInterop.MsidbControlAttributesVisible)) + { + control.Hidden = Wix.YesNoType.yes; + } + } + + /// + /// Creates an action element. + /// + /// The action row from which the element should be created. + private void CreateActionElement(WixActionRow actionRow) + { + Wix.ISchemaElement actionElement = null; + + if (null != this.core.GetIndexedElement("CustomAction", actionRow.Action)) // custom action + { + Wix.Custom custom = new Wix.Custom(); + + custom.Action = actionRow.Action; + + if (null != actionRow.Condition) + { + custom.Content = actionRow.Condition; + } + + switch (actionRow.Sequence) + { + case (-4): + custom.OnExit = Wix.ExitType.suspend; + break; + case (-3): + custom.OnExit = Wix.ExitType.error; + break; + case (-2): + custom.OnExit = Wix.ExitType.cancel; + break; + case (-1): + custom.OnExit = Wix.ExitType.success; + break; + default: + if (null != actionRow.Before) + { + custom.Before = actionRow.Before; + } + else if (null != actionRow.After) + { + custom.After = actionRow.After; + } + else if (0 < actionRow.Sequence) + { + custom.Sequence = actionRow.Sequence; + } + break; + } + + actionElement = custom; + } + else if (null != this.core.GetIndexedElement("Dialog", actionRow.Action)) // dialog + { + Wix.Show show = new Wix.Show(); + + show.Dialog = actionRow.Action; + + if (null != actionRow.Condition) + { + show.Content = actionRow.Condition; + } + + switch (actionRow.Sequence) + { + case (-4): + show.OnExit = Wix.ExitType.suspend; + break; + case (-3): + show.OnExit = Wix.ExitType.error; + break; + case (-2): + show.OnExit = Wix.ExitType.cancel; + break; + case (-1): + show.OnExit = Wix.ExitType.success; + break; + default: + if (null != actionRow.Before) + { + show.Before = actionRow.Before; + } + else if (null != actionRow.After) + { + show.After = actionRow.After; + } + else if (0 < actionRow.Sequence) + { + show.Sequence = actionRow.Sequence; + } + break; + } + + actionElement = show; + } + else // possibly a standard action without suggested sequence information + { + actionElement = this.CreateStandardActionElement(actionRow); + } + + // add the action element to the appropriate sequence element + if (null != actionElement) + { + string sequenceTable = actionRow.SequenceTable.ToString(); + Wix.IParentElement sequenceElement = (Wix.IParentElement)this.sequenceElements[sequenceTable]; + + if (null == sequenceElement) + { + switch (actionRow.SequenceTable) + { + case SequenceTable.AdminExecuteSequence: + sequenceElement = new Wix.AdminExecuteSequence(); + break; + case SequenceTable.AdminUISequence: + sequenceElement = new Wix.AdminUISequence(); + break; + case SequenceTable.AdvtExecuteSequence: + sequenceElement = new Wix.AdvertiseExecuteSequence(); + break; + case SequenceTable.InstallExecuteSequence: + sequenceElement = new Wix.InstallExecuteSequence(); + break; + case SequenceTable.InstallUISequence: + sequenceElement = new Wix.InstallUISequence(); + break; + default: + throw new InvalidOperationException(WixStrings.EXP_UnknowSequenceTable); + } + + this.core.RootElement.AddChild((Wix.ISchemaElement)sequenceElement); + this.sequenceElements.Add(sequenceTable, sequenceElement); + } + + try + { + sequenceElement.AddChild(actionElement); + } + catch (System.ArgumentException) // action/dialog is not valid for this sequence + { + this.core.OnMessage(WixWarnings.IllegalActionInSequence(actionRow.SourceLineNumbers, actionRow.SequenceTable.ToString(), actionRow.Action)); + } + } + } + + /// + /// Creates a standard action element. + /// + /// The action row from which the element should be created. + /// The created element. + private Wix.ISchemaElement CreateStandardActionElement(WixActionRow actionRow) + { + Wix.ActionSequenceType actionElement = null; + + switch (actionRow.Action) + { + case "AllocateRegistrySpace": + actionElement = new Wix.AllocateRegistrySpace(); + break; + case "AppSearch": + WixActionRow appSearchActionRow = this.standardActions[actionRow.SequenceTable, actionRow.Action]; + + if (null != actionRow.Before || null != actionRow.After || (null != appSearchActionRow && actionRow.Sequence != appSearchActionRow.Sequence)) + { + Wix.AppSearch appSearch = new Wix.AppSearch(); + + if (null != actionRow.Condition) + { + appSearch.Content = actionRow.Condition; + } + + if (null != actionRow.Before) + { + appSearch.Before = actionRow.Before; + } + else if (null != actionRow.After) + { + appSearch.After = actionRow.After; + } + else if (0 < actionRow.Sequence) + { + appSearch.Sequence = actionRow.Sequence; + } + + return appSearch; + } + break; + case "BindImage": + actionElement = new Wix.BindImage(); + break; + case "CCPSearch": + Wix.CCPSearch ccpSearch = new Wix.CCPSearch(); + Decompiler.SequenceRelativeAction(actionRow, ccpSearch); + return ccpSearch; + case "CostFinalize": + actionElement = new Wix.CostFinalize(); + break; + case "CostInitialize": + actionElement = new Wix.CostInitialize(); + break; + case "CreateFolders": + actionElement = new Wix.CreateFolders(); + break; + case "CreateShortcuts": + actionElement = new Wix.CreateShortcuts(); + break; + case "DeleteServices": + actionElement = new Wix.DeleteServices(); + break; + case "DisableRollback": + Wix.DisableRollback disableRollback = new Wix.DisableRollback(); + Decompiler.SequenceRelativeAction(actionRow, disableRollback); + return disableRollback; + case "DuplicateFiles": + actionElement = new Wix.DuplicateFiles(); + break; + case "ExecuteAction": + actionElement = new Wix.ExecuteAction(); + break; + case "FileCost": + actionElement = new Wix.FileCost(); + break; + case "FindRelatedProducts": + Wix.FindRelatedProducts findRelatedProducts = new Wix.FindRelatedProducts(); + Decompiler.SequenceRelativeAction(actionRow, findRelatedProducts); + return findRelatedProducts; + case "ForceReboot": + Wix.ForceReboot forceReboot = new Wix.ForceReboot(); + Decompiler.SequenceRelativeAction(actionRow, forceReboot); + return forceReboot; + case "InstallAdminPackage": + actionElement = new Wix.InstallAdminPackage(); + break; + case "InstallExecute": + Wix.InstallExecute installExecute = new Wix.InstallExecute(); + Decompiler.SequenceRelativeAction(actionRow, installExecute); + return installExecute; + case "InstallExecuteAgain": + Wix.InstallExecuteAgain installExecuteAgain = new Wix.InstallExecuteAgain(); + Decompiler.SequenceRelativeAction(actionRow, installExecuteAgain); + return installExecuteAgain; + case "InstallFiles": + actionElement = new Wix.InstallFiles(); + break; + case "InstallFinalize": + actionElement = new Wix.InstallFinalize(); + break; + case "InstallInitialize": + actionElement = new Wix.InstallInitialize(); + break; + case "InstallODBC": + actionElement = new Wix.InstallODBC(); + break; + case "InstallServices": + actionElement = new Wix.InstallServices(); + break; + case "InstallValidate": + actionElement = new Wix.InstallValidate(); + break; + case "IsolateComponents": + actionElement = new Wix.IsolateComponents(); + break; + case "LaunchConditions": + Wix.LaunchConditions launchConditions = new Wix.LaunchConditions(); + Decompiler.SequenceRelativeAction(actionRow, launchConditions); + return launchConditions; + case "MigrateFeatureStates": + actionElement = new Wix.MigrateFeatureStates(); + break; + case "MoveFiles": + actionElement = new Wix.MoveFiles(); + break; + case "MsiPublishAssemblies": + actionElement = new Wix.MsiPublishAssemblies(); + break; + case "MsiUnpublishAssemblies": + actionElement = new Wix.MsiUnpublishAssemblies(); + break; + case "PatchFiles": + actionElement = new Wix.PatchFiles(); + break; + case "ProcessComponents": + actionElement = new Wix.ProcessComponents(); + break; + case "PublishComponents": + actionElement = new Wix.PublishComponents(); + break; + case "PublishFeatures": + actionElement = new Wix.PublishFeatures(); + break; + case "PublishProduct": + actionElement = new Wix.PublishProduct(); + break; + case "RegisterClassInfo": + actionElement = new Wix.RegisterClassInfo(); + break; + case "RegisterComPlus": + actionElement = new Wix.RegisterComPlus(); + break; + case "RegisterExtensionInfo": + actionElement = new Wix.RegisterExtensionInfo(); + break; + case "RegisterFonts": + actionElement = new Wix.RegisterFonts(); + break; + case "RegisterMIMEInfo": + actionElement = new Wix.RegisterMIMEInfo(); + break; + case "RegisterProduct": + actionElement = new Wix.RegisterProduct(); + break; + case "RegisterProgIdInfo": + actionElement = new Wix.RegisterProgIdInfo(); + break; + case "RegisterTypeLibraries": + actionElement = new Wix.RegisterTypeLibraries(); + break; + case "RegisterUser": + actionElement = new Wix.RegisterUser(); + break; + case "RemoveDuplicateFiles": + actionElement = new Wix.RemoveDuplicateFiles(); + break; + case "RemoveEnvironmentStrings": + actionElement = new Wix.RemoveEnvironmentStrings(); + break; + case "RemoveExistingProducts": + Wix.RemoveExistingProducts removeExistingProducts = new Wix.RemoveExistingProducts(); + Decompiler.SequenceRelativeAction(actionRow, removeExistingProducts); + return removeExistingProducts; + case "RemoveFiles": + actionElement = new Wix.RemoveFiles(); + break; + case "RemoveFolders": + actionElement = new Wix.RemoveFolders(); + break; + case "RemoveIniValues": + actionElement = new Wix.RemoveIniValues(); + break; + case "RemoveODBC": + actionElement = new Wix.RemoveODBC(); + break; + case "RemoveRegistryValues": + actionElement = new Wix.RemoveRegistryValues(); + break; + case "RemoveShortcuts": + actionElement = new Wix.RemoveShortcuts(); + break; + case "ResolveSource": + Wix.ResolveSource resolveSource = new Wix.ResolveSource(); + Decompiler.SequenceRelativeAction(actionRow, resolveSource); + return resolveSource; + case "RMCCPSearch": + Wix.RMCCPSearch rmccpSearch = new Wix.RMCCPSearch(); + Decompiler.SequenceRelativeAction(actionRow, rmccpSearch); + return rmccpSearch; + case "ScheduleReboot": + Wix.ScheduleReboot scheduleReboot = new Wix.ScheduleReboot(); + Decompiler.SequenceRelativeAction(actionRow, scheduleReboot); + return scheduleReboot; + case "SelfRegModules": + actionElement = new Wix.SelfRegModules(); + break; + case "SelfUnregModules": + actionElement = new Wix.SelfUnregModules(); + break; + case "SetODBCFolders": + actionElement = new Wix.SetODBCFolders(); + break; + case "StartServices": + actionElement = new Wix.StartServices(); + break; + case "StopServices": + actionElement = new Wix.StopServices(); + break; + case "UnpublishComponents": + actionElement = new Wix.UnpublishComponents(); + break; + case "UnpublishFeatures": + actionElement = new Wix.UnpublishFeatures(); + break; + case "UnregisterClassInfo": + actionElement = new Wix.UnregisterClassInfo(); + break; + case "UnregisterComPlus": + actionElement = new Wix.UnregisterComPlus(); + break; + case "UnregisterExtensionInfo": + actionElement = new Wix.UnregisterExtensionInfo(); + break; + case "UnregisterFonts": + actionElement = new Wix.UnregisterFonts(); + break; + case "UnregisterMIMEInfo": + actionElement = new Wix.UnregisterMIMEInfo(); + break; + case "UnregisterProgIdInfo": + actionElement = new Wix.UnregisterProgIdInfo(); + break; + case "UnregisterTypeLibraries": + actionElement = new Wix.UnregisterTypeLibraries(); + break; + case "ValidateProductID": + actionElement = new Wix.ValidateProductID(); + break; + case "WriteEnvironmentStrings": + actionElement = new Wix.WriteEnvironmentStrings(); + break; + case "WriteIniValues": + actionElement = new Wix.WriteIniValues(); + break; + case "WriteRegistryValues": + actionElement = new Wix.WriteRegistryValues(); + break; + default: + this.core.OnMessage(WixWarnings.UnknownAction(actionRow.SourceLineNumbers, actionRow.SequenceTable.ToString(), actionRow.Action)); + return null; + } + + if (actionElement != null) + { + this.SequenceStandardAction(actionRow, actionElement); + } + + return actionElement; + } + + /// + /// Applies the condition and sequence to a standard action element based on the action row data. + /// + /// Action row data from the database. + /// Element to be sequenced. + private void SequenceStandardAction(WixActionRow actionRow, Wix.ActionSequenceType actionElement) + { + if (null != actionRow.Condition) + { + actionElement.Content = actionRow.Condition; + } + + if ((null != actionRow.Before || null != actionRow.After) && 0 == actionRow.Sequence) + { + this.core.OnMessage(WixWarnings.DecompiledStandardActionRelativelyScheduledInModule(actionRow.SourceLineNumbers, actionRow.SequenceTable.ToString(), actionRow.Action)); + } + else if (0 < actionRow.Sequence) + { + actionElement.Sequence = actionRow.Sequence; + } + } + + /// + /// Applies the condition and relative sequence to an action element based on the action row data. + /// + /// Action row data from the database. + /// Element to be sequenced. + private static void SequenceRelativeAction(WixActionRow actionRow, Wix.ActionModuleSequenceType actionElement) + { + if (null != actionRow.Condition) + { + actionElement.Content = actionRow.Condition; + } + + if (null != actionRow.Before) + { + actionElement.Before = actionRow.Before; + } + else if (null != actionRow.After) + { + actionElement.After = actionRow.After; + } + else if (0 < actionRow.Sequence) + { + actionElement.Sequence = actionRow.Sequence; + } + } + + /// + /// Ensure that a particular property exists in the decompiled output. + /// + /// The identifier of the property. + /// The property element. + private Wix.Property EnsureProperty(string id) + { + Wix.Property property = (Wix.Property)this.core.GetIndexedElement("Property", id); + + if (null == property) + { + property = new Wix.Property(); + property.Id = id; + + // create a dummy row for indexing + Row row = new Row(null, this.tableDefinitions["Property"]); + row[0] = id; + + this.core.RootElement.AddChild(property); + this.core.IndexElement(row, property); + } + + return property; + } + + /// + /// Finalize decompilation. + /// + /// The collection of all tables. + private void FinalizeDecompile(TableIndexedCollection tables) + { + if (OutputType.PatchCreation == this.outputType) + { + this.FinalizeFamilyFileRangesTable(tables); + } + else + { + this.FinalizeCheckBoxTable(tables); + this.FinalizeComponentTable(tables); + this.FinalizeDialogTable(tables); + this.FinalizeDuplicateMoveFileTables(tables); + this.FinalizeFeatureComponentsTable(tables); + this.FinalizeFileTable(tables); + this.FinalizeMIMETable(tables); + this.FinalizeMsiLockPermissionsExTable(tables); + this.FinalizeLockPermissionsTable(tables); + this.FinalizeProgIdTable(tables); + this.FinalizePropertyTable(tables); + this.FinalizeRemoveFileTable(tables); + this.FinalizeSearchTables(tables); + this.FinalizeUpgradeTable(tables); + this.FinalizeSequenceTables(tables); + this.FinalizeVerbTable(tables); + } + } + + /// + /// Finalize the CheckBox table. + /// + /// The collection of all tables. + /// + /// Enumerates through all the Control rows, looking for controls of type "CheckBox" with + /// a value in the Property column. This is then possibly matched up with a CheckBox row + /// to retrieve a CheckBoxValue. There is no foreign key from the Control to CheckBox table. + /// + private void FinalizeCheckBoxTable(TableIndexedCollection tables) + { + // if the user has requested to suppress the UI elements, we have nothing to do + if (this.suppressUI) + { + return; + } + + Table checkBoxTable = tables["CheckBox"]; + Table controlTable = tables["Control"]; + + Hashtable checkBoxes = new Hashtable(); + Hashtable checkBoxProperties = new Hashtable(); + + // index the CheckBox table + if (null != checkBoxTable) + { + foreach (Row row in checkBoxTable.Rows) + { + checkBoxes.Add(row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), row); + checkBoxProperties.Add(row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), false); + } + } + + // enumerate through the Control table, adding CheckBox values where appropriate + if (null != controlTable) + { + foreach (Row row in controlTable.Rows) + { + Wix.Control control = (Wix.Control)this.core.GetIndexedElement(row); + + if ("CheckBox" == Convert.ToString(row[2]) && null != row[8]) + { + Row checkBoxRow = (Row)checkBoxes[row[8]]; + + if (null == checkBoxRow) + { + this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, "Control", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Property", Convert.ToString(row[8]), "CheckBox")); + } + else + { + // if we've seen this property already, create a reference to it + if (Convert.ToBoolean(checkBoxProperties[row[8]])) + { + control.CheckBoxPropertyRef = Convert.ToString(row[8]); + } + else + { + control.Property = Convert.ToString(row[8]); + checkBoxProperties[row[8]] = true; + } + + if (null != checkBoxRow[1]) + { + control.CheckBoxValue = Convert.ToString(checkBoxRow[1]); + } + } + } + } + } + } + + /// + /// Finalize the Component table. + /// + /// The collection of all tables. + /// + /// Set the keypaths for each component. + /// + private void FinalizeComponentTable(TableIndexedCollection tables) + { + Table componentTable = tables["Component"]; + Table fileTable = tables["File"]; + Table odbcDataSourceTable = tables["ODBCDataSource"]; + Table registryTable = tables["Registry"]; + + // set the component keypaths + if (null != componentTable) + { + foreach (Row row in componentTable.Rows) + { + int attributes = Convert.ToInt32(row[3]); + + if (null == row[5]) + { + Wix.Component component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[0])); + + component.KeyPath = Wix.YesNoType.yes; + } + else if (MsiInterop.MsidbComponentAttributesRegistryKeyPath == (attributes & MsiInterop.MsidbComponentAttributesRegistryKeyPath)) + { + object registryObject = this.core.GetIndexedElement("Registry", Convert.ToString(row[5])); + + if (null != registryObject) + { + Wix.RegistryValue registryValue = registryObject as Wix.RegistryValue; + + if (null != registryValue) + { + registryValue.KeyPath = Wix.YesNoType.yes; + } + else + { + this.core.OnMessage(WixWarnings.IllegalRegistryKeyPath(row.SourceLineNumbers, "Component", Convert.ToString(row[5]))); + } + } + else + { + this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, "Component", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "KeyPath", Convert.ToString(row[5]), "Registry")); + } + } + else if (MsiInterop.MsidbComponentAttributesODBCDataSource == (attributes & MsiInterop.MsidbComponentAttributesODBCDataSource)) + { + Wix.ODBCDataSource odbcDataSource = (Wix.ODBCDataSource)this.core.GetIndexedElement("ODBCDataSource", Convert.ToString(row[5])); + + if (null != odbcDataSource) + { + odbcDataSource.KeyPath = Wix.YesNoType.yes; + } + else + { + this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, "Component", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "KeyPath", Convert.ToString(row[5]), "ODBCDataSource")); + } + } + else + { + Wix.File file = (Wix.File)this.core.GetIndexedElement("File", Convert.ToString(row[5])); + + if (null != file) + { + file.KeyPath = Wix.YesNoType.yes; + } + else + { + this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, "Component", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "KeyPath", Convert.ToString(row[5]), "File")); + } + } + } + } + + // add the File children elements + if (null != fileTable) + { + foreach (FileRow fileRow in fileTable.Rows) + { + Wix.Component component = (Wix.Component)this.core.GetIndexedElement("Component", fileRow.Component); + Wix.File file = (Wix.File)this.core.GetIndexedElement(fileRow); + + if (null != component) + { + component.AddChild(file); + } + else + { + this.core.OnMessage(WixWarnings.ExpectedForeignRow(fileRow.SourceLineNumbers, "File", fileRow.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", fileRow.Component, "Component")); + } + } + } + + // add the ODBCDataSource children elements + if (null != odbcDataSourceTable) + { + foreach (Row row in odbcDataSourceTable.Rows) + { + Wix.Component component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[1])); + Wix.ODBCDataSource odbcDataSource = (Wix.ODBCDataSource)this.core.GetIndexedElement(row); + + if (null != component) + { + component.AddChild(odbcDataSource); + } + else + { + this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, "ODBCDataSource", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[1]), "Component")); + } + } + } + + // add the Registry children elements + if (null != registryTable) + { + foreach (Row row in registryTable.Rows) + { + Wix.Component component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[5])); + Wix.ISchemaElement registryElement = (Wix.ISchemaElement)this.core.GetIndexedElement(row); + + if (null != component) + { + component.AddChild(registryElement); + } + else + { + this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, "Registry", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[5]), "Component")); + } + } + } + } + + /// + /// Finalize the Dialog table. + /// + /// The collection of all tables. + /// + /// Sets the first, default, and cancel control for each dialog and adds all child control + /// elements to the dialog. + /// + private void FinalizeDialogTable(TableIndexedCollection tables) + { + // if the user has requested to suppress the UI elements, we have nothing to do + if (this.suppressUI) + { + return; + } + + Table controlTable = tables["Control"]; + Table dialogTable = tables["Dialog"]; + + Hashtable addedControls = new Hashtable(); + Hashtable controlRows = new Hashtable(); + + // index the rows in the control rows (because we need the Control_Next value) + if (null != controlTable) + { + foreach (Row row in controlTable.Rows) + { + controlRows.Add(row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), row); + } + } + + if (null != dialogTable) + { + foreach (Row row in dialogTable.Rows) + { + Wix.Dialog dialog = (Wix.Dialog)this.core.GetIndexedElement(row); + string dialogId = Convert.ToString(row[0]); + + Wix.Control control = (Wix.Control)this.core.GetIndexedElement("Control", dialogId, Convert.ToString(row[7])); + if (null == control) + { + this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, "Dialog", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Dialog", dialogId, "Control_First", Convert.ToString(row[7]), "Control")); + } + + // add tabbable controls + while (null != control) + { + Row controlRow = (Row)controlRows[String.Concat(dialogId, DecompilerConstants.PrimaryKeyDelimiter, control.Id)]; + + control.TabSkip = Wix.YesNoType.no; + dialog.AddChild(control); + addedControls.Add(control, null); + + if (null != controlRow[10]) + { + control = (Wix.Control)this.core.GetIndexedElement("Control", dialogId, Convert.ToString(controlRow[10])); + if (null != control) + { + // looped back to the first control in the dialog + if (addedControls.Contains(control)) + { + control = null; + } + } + else + { + this.core.OnMessage(WixWarnings.ExpectedForeignRow(controlRow.SourceLineNumbers, "Control", controlRow.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Dialog_", dialogId, "Control_Next", Convert.ToString(controlRow[10]), "Control")); + } + } + else + { + control = null; + } + } + + // set default control + if (null != row[8]) + { + Wix.Control defaultControl = (Wix.Control)this.core.GetIndexedElement("Control", dialogId, Convert.ToString(row[8])); + + if (null != defaultControl) + { + defaultControl.Default = Wix.YesNoType.yes; + } + else + { + this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, "Dialog", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Dialog", dialogId, "Control_Default", Convert.ToString(row[8]), "Control")); + } + } + + // set cancel control + if (null != row[9]) + { + Wix.Control cancelControl = (Wix.Control)this.core.GetIndexedElement("Control", dialogId, Convert.ToString(row[9])); + + if (null != cancelControl) + { + cancelControl.Cancel = Wix.YesNoType.yes; + } + else + { + this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, "Dialog", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Dialog", dialogId, "Control_Cancel", Convert.ToString(row[9]), "Control")); + } + } + } + } + + // add the non-tabbable controls to the dialog + if (null != controlTable) + { + foreach (Row row in controlTable.Rows) + { + Wix.Control control = (Wix.Control)this.core.GetIndexedElement(row); + Wix.Dialog dialog = (Wix.Dialog)this.core.GetIndexedElement("Dialog", Convert.ToString(row[0])); + + if (null == dialog) + { + this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, "Control", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Dialog_", Convert.ToString(row[0]), "Dialog")); + continue; + } + + if (!addedControls.Contains(control)) + { + control.TabSkip = Wix.YesNoType.yes; + dialog.AddChild(control); + } + } + } + } + + /// + /// Finalize the DuplicateFile and MoveFile tables. + /// + /// The collection of all tables. + /// + /// Sets the source/destination property/directory for each DuplicateFile or + /// MoveFile row. + /// + private void FinalizeDuplicateMoveFileTables(TableIndexedCollection tables) + { + Table duplicateFileTable = tables["DuplicateFile"]; + Table moveFileTable = tables["MoveFile"]; + + if (null != duplicateFileTable) + { + foreach (Row row in duplicateFileTable.Rows) + { + Wix.CopyFile copyFile = (Wix.CopyFile)this.core.GetIndexedElement(row); + + if (null != row[4]) + { + if (null != this.core.GetIndexedElement("Directory", Convert.ToString(row[4]))) + { + copyFile.DestinationDirectory = Convert.ToString(row[4]); + } + else + { + copyFile.DestinationProperty = Convert.ToString(row[4]); + } + } + } + } + + if (null != moveFileTable) + { + foreach (Row row in moveFileTable.Rows) + { + Wix.CopyFile copyFile = (Wix.CopyFile)this.core.GetIndexedElement(row); + + if (null != row[4]) + { + if (null != this.core.GetIndexedElement("Directory", Convert.ToString(row[4]))) + { + copyFile.SourceDirectory = Convert.ToString(row[4]); + } + else + { + copyFile.SourceProperty = Convert.ToString(row[4]); + } + } + + if (null != this.core.GetIndexedElement("Directory", Convert.ToString(row[5]))) + { + copyFile.DestinationDirectory = Convert.ToString(row[5]); + } + else + { + copyFile.DestinationProperty = Convert.ToString(row[5]); + } + } + } + } + + /// + /// Finalize the FamilyFileRanges table. + /// + /// The collection of all tables. + private void FinalizeFamilyFileRangesTable(TableIndexedCollection tables) + { + Table externalFilesTable = tables["ExternalFiles"]; + Table familyFileRangesTable = tables["FamilyFileRanges"]; + Table targetFiles_OptionalDataTable = tables["TargetFiles_OptionalData"]; + + Hashtable usedProtectRanges = new Hashtable(); + + if (null != familyFileRangesTable) + { + foreach (Row row in familyFileRangesTable.Rows) + { + Wix.ProtectRange protectRange = new Wix.ProtectRange(); + + if (null != row[2] && null != row[3]) + { + string[] retainOffsets = (Convert.ToString(row[2])).Split(','); + string[] retainLengths = (Convert.ToString(row[3])).Split(','); + + if (retainOffsets.Length == retainLengths.Length) + { + for (int i = 0; i < retainOffsets.Length; i++) + { + if (retainOffsets[i].StartsWith("0x", StringComparison.Ordinal)) + { + protectRange.Offset = Convert.ToInt32(retainOffsets[i].Substring(2), 16); + } + else + { + protectRange.Offset = Convert.ToInt32(retainOffsets[i], CultureInfo.InvariantCulture); + } + + if (retainLengths[i].StartsWith("0x", StringComparison.Ordinal)) + { + protectRange.Length = Convert.ToInt32(retainLengths[i].Substring(2), 16); + } + else + { + protectRange.Length = Convert.ToInt32(retainLengths[i], CultureInfo.InvariantCulture); + } + } + } + else + { + // TODO: warn + } + } + else if (null != row[2] || null != row[3]) + { + // TODO: warn about mismatch between columns + } + + this.core.IndexElement(row, protectRange); + } + } + + if (null != externalFilesTable) + { + foreach (Row row in externalFilesTable.Rows) + { + Wix.ExternalFile externalFile = (Wix.ExternalFile)this.core.GetIndexedElement(row); + + Wix.ProtectRange protectRange = (Wix.ProtectRange)this.core.GetIndexedElement("FamilyFileRanges", Convert.ToString(row[0]), Convert.ToString(row[1])); + if (null != protectRange) + { + externalFile.AddChild(protectRange); + usedProtectRanges[protectRange] = null; + } + } + } + + if (null != targetFiles_OptionalDataTable) + { + Table targetImagesTable = tables["TargetImages"]; + Table upgradedImagesTable = tables["UpgradedImages"]; + + Hashtable targetImageRows = new Hashtable(); + Hashtable upgradedImagesRows = new Hashtable(); + + // index the TargetImages table + if (null != targetImagesTable) + { + foreach (Row row in targetImagesTable.Rows) + { + targetImageRows.Add(row[0], row); + } + } + + // index the UpgradedImages table + if (null != upgradedImagesTable) + { + foreach (Row row in upgradedImagesTable.Rows) + { + upgradedImagesRows.Add(row[0], row); + } + } + + foreach (Row row in targetFiles_OptionalDataTable.Rows) + { + Wix.TargetFile targetFile = (Wix.TargetFile)this.patchTargetFiles[row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter)]; + + Row targetImageRow = (Row)targetImageRows[row[0]]; + if (null == targetImageRow) + { + this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, targetFiles_OptionalDataTable.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Target", Convert.ToString(row[0]), "TargetImages")); + continue; + } + + Row upgradedImagesRow = (Row)upgradedImagesRows[targetImageRow[3]]; + if (null == upgradedImagesRow) + { + this.core.OnMessage(WixWarnings.ExpectedForeignRow(targetImageRow.SourceLineNumbers, targetImageRow.Table.Name, targetImageRow.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Upgraded", Convert.ToString(row[3]), "UpgradedImages")); + continue; + } + + Wix.ProtectRange protectRange = (Wix.ProtectRange)this.core.GetIndexedElement("FamilyFileRanges", Convert.ToString(upgradedImagesRow[4]), Convert.ToString(row[1])); + if (null != protectRange) + { + targetFile.AddChild(protectRange); + usedProtectRanges[protectRange] = null; + } + } + } + + if (null != familyFileRangesTable) + { + foreach (Row row in familyFileRangesTable.Rows) + { + Wix.ProtectRange protectRange = (Wix.ProtectRange)this.core.GetIndexedElement(row); + + if (!usedProtectRanges.Contains(protectRange)) + { + Wix.ProtectFile protectFile = new Wix.ProtectFile(); + + protectFile.File = Convert.ToString(row[1]); + + protectFile.AddChild(protectRange); + + Wix.Family family = (Wix.Family)this.core.GetIndexedElement("ImageFamilies", Convert.ToString(row[0])); + if (null != family) + { + family.AddChild(protectFile); + } + else + { + this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, familyFileRangesTable.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Family", Convert.ToString(row[0]), "ImageFamilies")); + } + } + } + } + } + + /// + /// Finalize the FeatureComponents table. + /// + /// The collection of all tables. + /// + /// Since tables specifying references to the FeatureComponents table have references to + /// the Feature and Component table separately, but not the FeatureComponents table specifically, + /// the FeatureComponents table and primary features must be decompiled during finalization. + /// + private void FinalizeFeatureComponentsTable(TableIndexedCollection tables) + { + Table classTable = tables["Class"]; + Table extensionTable = tables["Extension"]; + Table msiAssemblyTable = tables["MsiAssembly"]; + Table publishComponentTable = tables["PublishComponent"]; + Table shortcutTable = tables["Shortcut"]; + Table typeLibTable = tables["TypeLib"]; + + if (null != classTable) + { + foreach (Row row in classTable.Rows) + { + this.SetPrimaryFeature(row, 11, 2); + } + } + + if (null != extensionTable) + { + foreach (Row row in extensionTable.Rows) + { + this.SetPrimaryFeature(row, 4, 1); + } + } + + if (null != msiAssemblyTable) + { + foreach (Row row in msiAssemblyTable.Rows) + { + this.SetPrimaryFeature(row, 1, 0); + } + } + + if (null != publishComponentTable) + { + foreach (Row row in publishComponentTable.Rows) + { + this.SetPrimaryFeature(row, 4, 2); + } + } + + if (null != shortcutTable) + { + foreach (Row row in shortcutTable.Rows) + { + string target = Convert.ToString(row[4]); + + if (!target.StartsWith("[", StringComparison.Ordinal) && !target.EndsWith("]", StringComparison.Ordinal)) + { + this.SetPrimaryFeature(row, 4, 3); + } + } + } + + if (null != typeLibTable) + { + foreach (Row row in typeLibTable.Rows) + { + this.SetPrimaryFeature(row, 6, 2); + } + } + } + + /// + /// Finalize the File table. + /// + /// The collection of all tables. + /// + /// Sets the source, diskId, and assembly information for each file. + /// + private void FinalizeFileTable(TableIndexedCollection tables) + { + Table fileTable = tables["File"]; + Table mediaTable = tables["Media"]; + Table msiAssemblyTable = tables["MsiAssembly"]; + Table typeLibTable = tables["TypeLib"]; + + // index the media table by media id + RowDictionary mediaRows; + if (null != mediaTable) + { + mediaRows = new RowDictionary(mediaTable); + } + + // set the disk identifiers and sources for files + if (null != fileTable) + { + foreach (FileRow fileRow in fileTable.Rows) + { + Wix.File file = (Wix.File)this.core.GetIndexedElement("File", fileRow.File); + + // Don't bother processing files that are orphaned (and won't show up in the output anyway) + if (null != file.ParentElement) + { + // set the diskid + if (null != mediaTable) + { + foreach (MediaRow mediaRow in mediaTable.Rows) + { + if (fileRow.Sequence <= mediaRow.LastSequence) + { + file.DiskId = Convert.ToString(mediaRow.DiskId); + break; + } + } + } + + // set the source (done here because it requires information from the Directory table) + if (OutputType.Module == this.outputType) + { + file.Source = String.Concat(this.exportFilePath, Path.DirectorySeparatorChar, "File", Path.DirectorySeparatorChar, file.Id, '.', this.modularizationGuid.Substring(1, 36).Replace('-', '_')); + } + else if (Wix.YesNoDefaultType.yes == file.Compressed || (Wix.YesNoDefaultType.no != file.Compressed && this.compressed)) + { + file.Source = String.Concat(this.exportFilePath, Path.DirectorySeparatorChar, "File", Path.DirectorySeparatorChar, file.Id); + } + else // uncompressed + { + string fileName = (null != file.ShortName ? file.ShortName : file.Name); + + if (!this.shortNames && null != file.Name) + { + fileName = file.Name; + } + + if (this.compressed) // uncompressed at the root of the source image + { + file.Source = String.Concat("SourceDir", Path.DirectorySeparatorChar, fileName); + } + else + { + string sourcePath = this.GetSourcePath(file); + + file.Source = Path.Combine(sourcePath, fileName); + } + } + } + } + } + + // set the file assemblies and manifests + if (null != msiAssemblyTable) + { + foreach (Row row in msiAssemblyTable.Rows) + { + Wix.Component component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[0])); + + if (null == component) + { + this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, "MsiAssembly", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[0]), "Component")); + } + else + { + foreach (Wix.ISchemaElement element in component.Children) + { + Wix.File file = element as Wix.File; + + if (null != file && Wix.YesNoType.yes == file.KeyPath) + { + if (null != row[2]) + { + file.AssemblyManifest = Convert.ToString(row[2]); + } + + if (null != row[3]) + { + file.AssemblyApplication = Convert.ToString(row[3]); + } + + if (null == row[4] || 0 == Convert.ToInt32(row[4])) + { + file.Assembly = Wix.File.AssemblyType.net; + } + else + { + file.Assembly = Wix.File.AssemblyType.win32; + } + } + } + } + } + } + + // nest the TypeLib elements + if (null != typeLibTable) + { + foreach (Row row in typeLibTable.Rows) + { + Wix.Component component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[2])); + Wix.TypeLib typeLib = (Wix.TypeLib)this.core.GetIndexedElement(row); + + foreach (Wix.ISchemaElement element in component.Children) + { + Wix.File file = element as Wix.File; + + if (null != file && Wix.YesNoType.yes == file.KeyPath) + { + file.AddChild(typeLib); + } + } + } + } + } + + /// + /// Finalize the MIME table. + /// + /// The collection of all tables. + /// + /// There is a foreign key shared between the MIME and Extension + /// tables so either one would be valid to be decompiled first, so + /// the only safe way to nest the MIME elements is to do it during finalize. + /// + private void FinalizeMIMETable(TableIndexedCollection tables) + { + Table extensionTable = tables["Extension"]; + Table mimeTable = tables["MIME"]; + + Hashtable comExtensions = new Hashtable(); + + if (null != extensionTable) + { + foreach (Row row in extensionTable.Rows) + { + Wix.Extension extension = (Wix.Extension)this.core.GetIndexedElement(row); + + // index the extension + if (!comExtensions.Contains(row[0])) + { + comExtensions.Add(row[0], new ArrayList()); + } + ((ArrayList)comExtensions[row[0]]).Add(extension); + + // set the default MIME element for this extension + if (null != row[3]) + { + Wix.MIME mime = (Wix.MIME)this.core.GetIndexedElement("MIME", Convert.ToString(row[3])); + + if (null != mime) + { + mime.Default = Wix.YesNoType.yes; + } + else + { + this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, "Extension", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "MIME_", Convert.ToString(row[3]), "MIME")); + } + } + } + } + + if (null != mimeTable) + { + foreach (Row row in mimeTable.Rows) + { + Wix.MIME mime = (Wix.MIME)this.core.GetIndexedElement(row); + + if (comExtensions.Contains(row[1])) + { + ArrayList extensionElements = (ArrayList)comExtensions[row[1]]; + + foreach (Wix.Extension extension in extensionElements) + { + extension.AddChild(mime); + } + } + else + { + this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, "MIME", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Extension_", Convert.ToString(row[1]), "Extension")); + } + } + } + } + + /// + /// Finalize the ProgId table. + /// + /// The collection of all tables. + /// + /// Enumerates through all the Class rows, looking for child ProgIds (these are the + /// default ProgIds for a given Class). Then go through the ProgId table and add any + /// remaining ProgIds for each Class. This happens during finalize because there is + /// a circular dependency between the Class and ProgId tables. + /// + private void FinalizeProgIdTable(TableIndexedCollection tables) + { + Table classTable = tables["Class"]; + Table progIdTable = tables["ProgId"]; + Table extensionTable = tables["Extension"]; + Table componentTable = tables["Component"]; + + Hashtable addedProgIds = new Hashtable(); + Hashtable classes = new Hashtable(); + Hashtable components = new Hashtable(); + + // add the default ProgIds for each class (and index the class table) + if (null != classTable) + { + foreach (Row row in classTable.Rows) + { + Wix.Class wixClass = (Wix.Class)this.core.GetIndexedElement(row); + + if (null != row[3]) + { + Wix.ProgId progId = (Wix.ProgId)this.core.GetIndexedElement("ProgId", Convert.ToString(row[3])); + + if (null != progId) + { + if (addedProgIds.Contains(progId)) + { + this.core.OnMessage(WixWarnings.TooManyProgIds(row.SourceLineNumbers, Convert.ToString(row[0]), Convert.ToString(row[3]), Convert.ToString(addedProgIds[progId]))); + } + else + { + wixClass.AddChild(progId); + addedProgIds.Add(progId, wixClass.Id); + } + } + else + { + this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, "Class", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "ProgId_Default", Convert.ToString(row[3]), "ProgId")); + } + } + + // index the Class elements for nesting of ProgId elements (which don't use the full Class primary key) + if (!classes.Contains(wixClass.Id)) + { + classes.Add(wixClass.Id, new ArrayList()); + } + ((ArrayList)classes[wixClass.Id]).Add(wixClass); + } + } + + // add the remaining non-default ProgId entries for each class + if (null != progIdTable) + { + foreach (Row row in progIdTable.Rows) + { + Wix.ProgId progId = (Wix.ProgId)this.core.GetIndexedElement(row); + + if (!addedProgIds.Contains(progId) && null != row[2] && null == progId.ParentElement) + { + ArrayList classElements = (ArrayList)classes[row[2]]; + + if (null != classElements) + { + foreach (Wix.Class wixClass in classElements) + { + wixClass.AddChild(progId); + addedProgIds.Add(progId, wixClass.Id); + } + } + else + { + this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, "ProgId", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Class_", Convert.ToString(row[2]), "Class")); + } + } + } + } + + if (null != componentTable) + { + foreach (Row row in componentTable.Rows) + { + Wix.Component wixComponent = (Wix.Component)this.core.GetIndexedElement(row); + + // index the Class elements for nesting of ProgId elements (which don't use the full Class primary key) + if (!components.Contains(wixComponent.Id)) + { + components.Add(wixComponent.Id, new ArrayList()); + } + ((ArrayList)components[wixComponent.Id]).Add(wixComponent); + } + } + + // Check for any progIds that are not hooked up to a class and hook them up to the component specified by the extension + if (null != extensionTable) + { + foreach (Row row in extensionTable.Rows) + { + // ignore the extension if it isn't associated with a progId + if (null == row[2]) + { + continue; + } + + Wix.ProgId progId = (Wix.ProgId)this.core.GetIndexedElement("ProgId", Convert.ToString(row[2])); + + // Haven't added the progId yet and it doesn't have a parent progId + if (!addedProgIds.Contains(progId) && null == progId.ParentElement) + { + ArrayList componentElements = (ArrayList)components[row[1]]; + + if (null != componentElements) + { + foreach (Wix.Component wixComponent in componentElements) + { + wixComponent.AddChild(progId); + } + } + else + { + this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, "Extension", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[1]), "Component")); + } + } + } + } + } + + /// + /// Finalize the Property table. + /// + /// The collection of all tables. + /// + /// Removes properties that are generated from other entries. + /// + private void FinalizePropertyTable(TableIndexedCollection tables) + { + Table propertyTable = tables["Property"]; + Table customActionTable = tables["CustomAction"]; + + if (null != propertyTable && null != customActionTable) + { + foreach (Row row in customActionTable.Rows) + { + int bits = Convert.ToInt32(row[1]); + if (MsiInterop.MsidbCustomActionTypeHideTarget == (bits & MsiInterop.MsidbCustomActionTypeHideTarget) && + MsiInterop.MsidbCustomActionTypeInScript == (bits & MsiInterop.MsidbCustomActionTypeInScript)) + { + Wix.Property property = (Wix.Property)this.core.GetIndexedElement("Property", Convert.ToString(row[0])); + + // If no other fields on the property are set we must have created it during link + if (null != property && null == property.Value && Wix.YesNoType.yes != property.Secure && Wix.YesNoType.yes != property.SuppressModularization) + { + this.core.RootElement.RemoveChild(property); + } + } + } + } + } + + /// + /// Finalize the RemoveFile table. + /// + /// The collection of all tables. + /// + /// Sets the directory/property for each RemoveFile row. + /// + private void FinalizeRemoveFileTable(TableIndexedCollection tables) + { + Table removeFileTable = tables["RemoveFile"]; + + if (null != removeFileTable) + { + foreach (Row row in removeFileTable.Rows) + { + bool isDirectory = false; + string property = Convert.ToString(row[3]); + + // determine if the property is actually authored as a directory + if (null != this.core.GetIndexedElement("Directory", property)) + { + isDirectory = true; + } + + Wix.ISchemaElement element = this.core.GetIndexedElement(row); + + Wix.RemoveFile removeFile = element as Wix.RemoveFile; + if (null != removeFile) + { + if (isDirectory) + { + removeFile.Directory = property; + } + else + { + removeFile.Property = property; + } + } + else + { + Wix.RemoveFolder removeFolder = (Wix.RemoveFolder)element; + + if (isDirectory) + { + removeFolder.Directory = property; + } + else + { + removeFolder.Property = property; + } + } + } + } + } + + /// + /// Finalize the LockPermissions table. + /// + /// The collection of all tables. + /// + /// Nests the Permission elements below their parent elements. There are no declared foreign + /// keys for the parents of the LockPermissions table. + /// + private void FinalizeLockPermissionsTable(TableIndexedCollection tables) + { + Table createFolderTable = tables["CreateFolder"]; + Table lockPermissionsTable = tables["LockPermissions"]; + + Hashtable createFolders = new Hashtable(); + + // index the CreateFolder table because the foreign key to this table from the + // LockPermissions table is only part of the primary key of this table + if (null != createFolderTable) + { + foreach (Row row in createFolderTable.Rows) + { + Wix.CreateFolder createFolder = (Wix.CreateFolder)this.core.GetIndexedElement(row); + string directoryId = Convert.ToString(row[0]); + + if (!createFolders.Contains(directoryId)) + { + createFolders.Add(directoryId, new ArrayList()); + } + ((ArrayList)createFolders[directoryId]).Add(createFolder); + } + } + + if (null != lockPermissionsTable) + { + foreach (Row row in lockPermissionsTable.Rows) + { + string id = Convert.ToString(row[0]); + string table = Convert.ToString(row[1]); + + Wix.Permission permission = (Wix.Permission)this.core.GetIndexedElement(row); + + if ("CreateFolder" == table) + { + ArrayList createFolderElements = (ArrayList)createFolders[id]; + + if (null != createFolderElements) + { + foreach (Wix.CreateFolder createFolder in createFolderElements) + { + createFolder.AddChild(permission); + } + } + else + { + this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, "LockPermissions", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "LockObject", id, table)); + } + } + else + { + Wix.IParentElement parentElement = (Wix.IParentElement)this.core.GetIndexedElement(table, id); + + if (null != parentElement) + { + parentElement.AddChild(permission); + } + else + { + this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, "LockPermissions", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "LockObject", id, table)); + } + } + } + } + } + + /// + /// Finalize the MsiLockPermissionsEx table. + /// + /// The collection of all tables. + /// + /// Nests the PermissionEx elements below their parent elements. There are no declared foreign + /// keys for the parents of the MsiLockPermissionsEx table. + /// + private void FinalizeMsiLockPermissionsExTable(TableIndexedCollection tables) + { + Table createFolderTable = tables["CreateFolder"]; + Table msiLockPermissionsExTable = tables["MsiLockPermissionsEx"]; + + Hashtable createFolders = new Hashtable(); + + // index the CreateFolder table because the foreign key to this table from the + // MsiLockPermissionsEx table is only part of the primary key of this table + if (null != createFolderTable) + { + foreach (Row row in createFolderTable.Rows) + { + Wix.CreateFolder createFolder = (Wix.CreateFolder)this.core.GetIndexedElement(row); + string directoryId = Convert.ToString(row[0]); + + if (!createFolders.Contains(directoryId)) + { + createFolders.Add(directoryId, new ArrayList()); + } + ((ArrayList)createFolders[directoryId]).Add(createFolder); + } + } + + if (null != msiLockPermissionsExTable) + { + foreach (Row row in msiLockPermissionsExTable.Rows) + { + string id = Convert.ToString(row[1]); + string table = Convert.ToString(row[2]); + + Wix.PermissionEx permissionEx = (Wix.PermissionEx)this.core.GetIndexedElement(row); + + if ("CreateFolder" == table) + { + ArrayList createFolderElements = (ArrayList)createFolders[id]; + + if (null != createFolderElements) + { + foreach (Wix.CreateFolder createFolder in createFolderElements) + { + createFolder.AddChild(permissionEx); + } + } + else + { + this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, "MsiLockPermissionsEx", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "LockObject", id, table)); + } + } + else + { + Wix.IParentElement parentElement = (Wix.IParentElement)this.core.GetIndexedElement(table, id); + + if (null != parentElement) + { + parentElement.AddChild(permissionEx); + } + else + { + this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, "MsiLockPermissionsEx", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "LockObject", id, table)); + } + } + } + } + } + + /// + /// Finalize the search tables. + /// + /// The collection of all tables. + /// Does all the complex linking required for the search tables. + private void FinalizeSearchTables(TableIndexedCollection tables) + { + Table appSearchTable = tables["AppSearch"]; + Table ccpSearchTable = tables["CCPSearch"]; + Table drLocatorTable = tables["DrLocator"]; + + Hashtable appSearches = new Hashtable(); + Hashtable ccpSearches = new Hashtable(); + Hashtable drLocators = new Hashtable(); + Hashtable locators = new Hashtable(); + Hashtable usedSearchElements = new Hashtable(); + ArrayList unusedSearchElements = new ArrayList(); + + Wix.ComplianceCheck complianceCheck = null; + + // index the AppSearch table by signatures + if (null != appSearchTable) + { + foreach (Row row in appSearchTable.Rows) + { + string property = Convert.ToString(row[0]); + string signature = Convert.ToString(row[1]); + + if (!appSearches.Contains(signature)) + { + appSearches.Add(signature, new StringCollection()); + } + + ((StringCollection)appSearches[signature]).Add(property); + } + } + + // index the CCPSearch table by signatures + if (null != ccpSearchTable) + { + foreach (Row row in ccpSearchTable.Rows) + { + string signature = Convert.ToString(row[0]); + + if (!ccpSearches.Contains(signature)) + { + ccpSearches.Add(signature, new StringCollection()); + } + + ((StringCollection)ccpSearches[signature]).Add(null); + + if (null == complianceCheck && !appSearches.Contains(signature)) + { + complianceCheck = new Wix.ComplianceCheck(); + this.core.RootElement.AddChild(complianceCheck); + } + } + } + + // index the directory searches by their search elements (to get back the original row) + if (null != drLocatorTable) + { + foreach (Row row in drLocatorTable.Rows) + { + drLocators.Add(this.core.GetIndexedElement(row), row); + } + } + + // index the locator tables by their signatures + string[] locatorTableNames = new string[] { "CompLocator", "RegLocator", "IniLocator", "DrLocator", "Signature" }; + foreach (string locatorTableName in locatorTableNames) + { + Table locatorTable = tables[locatorTableName]; + + if (null != locatorTable) + { + foreach (Row row in locatorTable.Rows) + { + string signature = Convert.ToString(row[0]); + + if (!locators.Contains(signature)) + { + locators.Add(signature, new ArrayList()); + } + + ((ArrayList)locators[signature]).Add(row); + } + } + } + + // move the DrLocator rows with a parent of CCP_DRIVE first to ensure they get FileSearch children (not FileSearchRef) + foreach (ArrayList locatorRows in locators.Values) + { + int firstDrLocator = -1; + + for (int i = 0; i < locatorRows.Count; i++) + { + Row locatorRow = (Row)locatorRows[i]; + + if ("DrLocator" == locatorRow.TableDefinition.Name) + { + if (-1 == firstDrLocator) + { + firstDrLocator = i; + } + + if ("CCP_DRIVE" == Convert.ToString(locatorRow[1])) + { + locatorRows.RemoveAt(i); + locatorRows.Insert(firstDrLocator, locatorRow); + break; + } + } + } + } + + foreach (string signature in locators.Keys) + { + ArrayList locatorRows = (ArrayList)locators[signature]; + ArrayList signatureSearchElements = new ArrayList(); + + foreach (Row locatorRow in locatorRows) + { + bool used = true; + Wix.ISchemaElement searchElement = this.core.GetIndexedElement(locatorRow); + + if ("Signature" == locatorRow.TableDefinition.Name && 0 < signatureSearchElements.Count) + { + foreach (Wix.IParentElement searchParentElement in signatureSearchElements) + { + if (!usedSearchElements.Contains(searchElement)) + { + searchParentElement.AddChild(searchElement); + usedSearchElements[searchElement] = null; + } + else + { + Wix.FileSearchRef fileSearchRef = new Wix.FileSearchRef(); + + fileSearchRef.Id = signature; + + searchParentElement.AddChild(fileSearchRef); + } + } + } + else if ("DrLocator" == locatorRow.TableDefinition.Name && null != locatorRow[1]) + { + string parentSignature = Convert.ToString(locatorRow[1]); + + if ("CCP_DRIVE" == parentSignature) + { + if (appSearches.Contains(signature)) + { + StringCollection appSearchPropertyIds = (StringCollection)appSearches[signature]; + + foreach (string propertyId in appSearchPropertyIds) + { + Wix.Property property = this.EnsureProperty(propertyId); + Wix.ComplianceDrive complianceDrive = null; + + if (ccpSearches.Contains(signature)) + { + property.ComplianceCheck = Wix.YesNoType.yes; + } + + foreach (Wix.ISchemaElement element in property.Children) + { + complianceDrive = element as Wix.ComplianceDrive; + if (null != complianceDrive) + { + break; + } + } + + if (null == complianceDrive) + { + complianceDrive = new Wix.ComplianceDrive(); + property.AddChild(complianceDrive); + } + + if (!usedSearchElements.Contains(searchElement)) + { + complianceDrive.AddChild(searchElement); + usedSearchElements[searchElement] = null; + } + else + { + Wix.DirectorySearchRef directorySearchRef = new Wix.DirectorySearchRef(); + + directorySearchRef.Id = signature; + + if (null != locatorRow[1]) + { + directorySearchRef.Parent = Convert.ToString(locatorRow[1]); + } + + if (null != locatorRow[2]) + { + directorySearchRef.Path = Convert.ToString(locatorRow[2]); + } + + complianceDrive.AddChild(directorySearchRef); + signatureSearchElements.Add(directorySearchRef); + } + } + } + else if (ccpSearches.Contains(signature)) + { + Wix.ComplianceDrive complianceDrive = null; + + foreach (Wix.ISchemaElement element in complianceCheck.Children) + { + complianceDrive = element as Wix.ComplianceDrive; + if (null != complianceDrive) + { + break; + } + } + + if (null == complianceDrive) + { + complianceDrive = new Wix.ComplianceDrive(); + complianceCheck.AddChild(complianceDrive); + } + + if (!usedSearchElements.Contains(searchElement)) + { + complianceDrive.AddChild(searchElement); + usedSearchElements[searchElement] = null; + } + else + { + Wix.DirectorySearchRef directorySearchRef = new Wix.DirectorySearchRef(); + + directorySearchRef.Id = signature; + + if (null != locatorRow[1]) + { + directorySearchRef.Parent = Convert.ToString(locatorRow[1]); + } + + if (null != locatorRow[2]) + { + directorySearchRef.Path = Convert.ToString(locatorRow[2]); + } + + complianceDrive.AddChild(directorySearchRef); + signatureSearchElements.Add(directorySearchRef); + } + } + } + else + { + bool usedDrLocator = false; + ArrayList parentLocatorRows = (ArrayList)locators[parentSignature]; + + if (null != parentLocatorRows) + { + foreach (Row parentLocatorRow in parentLocatorRows) + { + if ("DrLocator" == parentLocatorRow.TableDefinition.Name) + { + Wix.IParentElement parentSearchElement = (Wix.IParentElement)this.core.GetIndexedElement(parentLocatorRow); + + if (parentSearchElement.Children.GetEnumerator().MoveNext()) + { + Row parentDrLocatorRow = (Row)drLocators[parentSearchElement]; + Wix.DirectorySearchRef directorySeachRef = new Wix.DirectorySearchRef(); + + directorySeachRef.Id = parentSignature; + + if (null != parentDrLocatorRow[1]) + { + directorySeachRef.Parent = Convert.ToString(parentDrLocatorRow[1]); + } + + if (null != parentDrLocatorRow[2]) + { + directorySeachRef.Path = Convert.ToString(parentDrLocatorRow[2]); + } + + parentSearchElement = directorySeachRef; + unusedSearchElements.Add(directorySeachRef); + } + + if (!usedSearchElements.Contains(searchElement)) + { + parentSearchElement.AddChild(searchElement); + usedSearchElements[searchElement] = null; + usedDrLocator = true; + } + else + { + Wix.DirectorySearchRef directorySearchRef = new Wix.DirectorySearchRef(); + + directorySearchRef.Id = signature; + + directorySearchRef.Parent = parentSignature; + + if (null != locatorRow[2]) + { + directorySearchRef.Path = Convert.ToString(locatorRow[2]); + } + + parentSearchElement.AddChild(searchElement); + usedDrLocator = true; + } + } + } + + // keep track of unused DrLocator rows + if (!usedDrLocator) + { + unusedSearchElements.Add(searchElement); + } + } + else + { + // TODO: warn + } + } + } + else if (appSearches.Contains(signature)) + { + StringCollection appSearchPropertyIds = (StringCollection)appSearches[signature]; + + foreach (string propertyId in appSearchPropertyIds) + { + Wix.Property property = this.EnsureProperty(propertyId); + + if (ccpSearches.Contains(signature)) + { + property.ComplianceCheck = Wix.YesNoType.yes; + } + + if (!usedSearchElements.Contains(searchElement)) + { + property.AddChild(searchElement); + usedSearchElements[searchElement] = null; + } + else if ("RegLocator" == locatorRow.TableDefinition.Name) + { + Wix.RegistrySearchRef registrySearchRef = new Wix.RegistrySearchRef(); + + registrySearchRef.Id = signature; + + property.AddChild(registrySearchRef); + signatureSearchElements.Add(registrySearchRef); + } + else + { + // TODO: warn about unavailable Ref element + } + } + } + else if (ccpSearches.Contains(signature)) + { + if (!usedSearchElements.Contains(searchElement)) + { + complianceCheck.AddChild(searchElement); + usedSearchElements[searchElement] = null; + } + else if ("RegLocator" == locatorRow.TableDefinition.Name) + { + Wix.RegistrySearchRef registrySearchRef = new Wix.RegistrySearchRef(); + + registrySearchRef.Id = signature; + + complianceCheck.AddChild(registrySearchRef); + signatureSearchElements.Add(registrySearchRef); + } + else + { + // TODO: warn about unavailable Ref element + } + } + else + { + if ("DrLocator" == locatorRow.TableDefinition.Name) + { + unusedSearchElements.Add(searchElement); + } + else + { + // TODO: warn + used = false; + } + } + + // keep track of the search elements for this signature so that nested searches go in the proper parents + if (used) + { + signatureSearchElements.Add(searchElement); + } + } + } + + foreach (Wix.IParentElement unusedSearchElement in unusedSearchElements) + { + bool used = false; + + foreach (Wix.ISchemaElement schemaElement in unusedSearchElement.Children) + { + Wix.DirectorySearch directorySearch = schemaElement as Wix.DirectorySearch; + if (null != directorySearch) + { + StringCollection appSearchProperties = (StringCollection)appSearches[directorySearch.Id]; + + Wix.ISchemaElement unusedSearchSchemaElement = unusedSearchElement as Wix.ISchemaElement; + if (null != appSearchProperties) + { + Wix.Property property = this.EnsureProperty(appSearchProperties[0]); + + property.AddChild(unusedSearchSchemaElement); + used = true; + break; + } + else if (ccpSearches.Contains(directorySearch.Id)) + { + complianceCheck.AddChild(unusedSearchSchemaElement); + used = true; + break; + } + else + { + // TODO: warn + } + } + } + + if (!used) + { + // TODO: warn + } + } + } + + /// + /// Finalize the sequence tables. + /// + /// The collection of all tables. + /// + /// Creates the sequence elements. Occurs during finalization because its + /// not known if sequences refer to custom actions or dialogs during decompilation. + /// + private void FinalizeSequenceTables(TableIndexedCollection tables) + { + // finalize the normal sequence tables + if (OutputType.Product == this.outputType && !this.treatProductAsModule) + { + foreach (SequenceTable sequenceTable in Enum.GetValues(typeof(SequenceTable))) + { + // if suppressing UI elements, skip UI-related sequence tables + if (this.suppressUI && ("AdminUISequence" == sequenceTable.ToString() || "InstallUISequence" == sequenceTable.ToString())) + { + continue; + } + + Table actionsTable = new Table(null, this.tableDefinitions["WixAction"]); + Table table = tables[sequenceTable.ToString()]; + + if (null != table) + { + ArrayList actionRows = new ArrayList(); + bool needAbsoluteScheduling = this.suppressRelativeActionSequencing; + WixActionRowCollection nonSequencedActionRows = new WixActionRowCollection(); + WixActionRowCollection suppressedRelativeActionRows = new WixActionRowCollection(); + + // create a sorted array of actions in this table + foreach (Row row in table.Rows) + { + WixActionRow actionRow = (WixActionRow)actionsTable.CreateRow(null); + + actionRow.Action = Convert.ToString(row[0]); + + if (null != row[1]) + { + actionRow.Condition = Convert.ToString(row[1]); + } + + actionRow.Sequence = Convert.ToInt32(row[2]); + + actionRow.SequenceTable = sequenceTable; + + actionRows.Add(actionRow); + } + actionRows.Sort(); + + for (int i = 0; i < actionRows.Count && !needAbsoluteScheduling; i++) + { + WixActionRow actionRow = (WixActionRow)actionRows[i]; + WixActionRow standardActionRow = this.standardActions[actionRow.SequenceTable, actionRow.Action]; + + // create actions for custom actions, dialogs, AppSearch when its moved, and standard actions with non-standard conditions + if ("AppSearch" == actionRow.Action || null == standardActionRow || actionRow.Condition != standardActionRow.Condition) + { + WixActionRow previousActionRow = null; + WixActionRow nextActionRow = null; + + // find the previous action row if there is one + if (0 <= i - 1) + { + previousActionRow = (WixActionRow)actionRows[i - 1]; + } + + // find the next action row if there is one + if (actionRows.Count > i + 1) + { + nextActionRow = (WixActionRow)actionRows[i + 1]; + } + + // the logic for setting the before or after attribute for an action: + // 1. If more than one action shares the same sequence number, everything must be absolutely sequenced. + // 2. If the next action is a standard action and is 1 sequence number higher, this action occurs before it. + // 3. If the previous action is a standard action and is 1 sequence number lower, this action occurs after it. + // 4. If this action is not standard and the previous action is 1 sequence number lower and does not occur before this action, this action occurs after it. + // 5. If this action is not standard and the previous action does not have the same sequence number and the next action is 1 sequence number higher, this action occurs before it. + // 6. If this action is AppSearch and has all standard information, ignore it. + // 7. If this action is standard and has a non-standard condition, create the action without any scheduling information. + // 8. Everything must be absolutely sequenced. + if ((null != previousActionRow && actionRow.Sequence == previousActionRow.Sequence) || (null != nextActionRow && actionRow.Sequence == nextActionRow.Sequence)) + { + needAbsoluteScheduling = true; + } + else if (null != nextActionRow && null != this.standardActions[sequenceTable, nextActionRow.Action] && actionRow.Sequence + 1 == nextActionRow.Sequence) + { + actionRow.Before = nextActionRow.Action; + } + else if (null != previousActionRow && null != this.standardActions[sequenceTable, previousActionRow.Action] && actionRow.Sequence - 1 == previousActionRow.Sequence) + { + actionRow.After = previousActionRow.Action; + } + else if (null == standardActionRow && null != previousActionRow && actionRow.Sequence - 1 == previousActionRow.Sequence && previousActionRow.Before != actionRow.Action) + { + actionRow.After = previousActionRow.Action; + } + else if (null == standardActionRow && null != previousActionRow && actionRow.Sequence != previousActionRow.Sequence && null != nextActionRow && actionRow.Sequence + 1 == nextActionRow.Sequence) + { + actionRow.Before = nextActionRow.Action; + } + else if ("AppSearch" == actionRow.Action && null != standardActionRow && actionRow.Sequence == standardActionRow.Sequence && actionRow.Condition == standardActionRow.Condition) + { + // ignore an AppSearch row which has the WiX standard sequence and a standard condition + } + else if (null != standardActionRow && actionRow.Condition != standardActionRow.Condition) // standard actions get their standard sequence numbers + { + nonSequencedActionRows.Add(actionRow); + } + else if (0 < actionRow.Sequence) + { + needAbsoluteScheduling = true; + } + } + else + { + suppressedRelativeActionRows.Add(actionRow); + } + } + + // create the actions now that we know if they must be absolutely or relatively scheduled + foreach (WixActionRow actionRow in actionRows) + { + if (needAbsoluteScheduling) + { + // remove any before/after information to ensure this is absolutely sequenced + actionRow.Before = null; + actionRow.After = null; + } + else if (nonSequencedActionRows.Contains(actionRow.SequenceTable, actionRow.Action)) + { + // clear the sequence attribute to ensure this action is scheduled without a sequence number (or before/after) + actionRow.Sequence = 0; + } + else if (suppressedRelativeActionRows.Contains(actionRow.SequenceTable, actionRow.Action)) + { + // skip the suppressed relatively scheduled action rows + continue; + } + + // create the action element + this.CreateActionElement(actionRow); + } + } + } + } + else if (OutputType.Module == this.outputType || this.treatProductAsModule) // finalize the Module sequence tables + { + foreach (SequenceTable sequenceTable in Enum.GetValues(typeof(SequenceTable))) + { + // if suppressing UI elements, skip UI-related sequence tables + if (this.suppressUI && ("AdminUISequence" == sequenceTable.ToString() || "InstallUISequence" == sequenceTable.ToString())) + { + continue; + } + + Table actionsTable = new Table(null, this.tableDefinitions["WixAction"]); + Table table = tables[String.Concat("Module", sequenceTable.ToString())]; + + if (null != table) + { + foreach (Row row in table.Rows) + { + WixActionRow actionRow = (WixActionRow)actionsTable.CreateRow(null); + + actionRow.Action = Convert.ToString(row[0]); + + if (null != row[1]) + { + actionRow.Sequence = Convert.ToInt32(row[1]); + } + + if (null != row[2] && null != row[3]) + { + switch (Convert.ToInt32(row[3])) + { + case 0: + actionRow.Before = Convert.ToString(row[2]); + break; + case 1: + actionRow.After = Convert.ToString(row[2]); + break; + default: + this.core.OnMessage(WixWarnings.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[3].Column.Name, row[3])); + break; + } + } + + if (null != row[4]) + { + actionRow.Condition = Convert.ToString(row[4]); + } + + actionRow.SequenceTable = sequenceTable; + + // create action elements for non-standard actions + if (null == this.standardActions[actionRow.SequenceTable, actionRow.Action] || null != actionRow.After || null != actionRow.Before) + { + this.CreateActionElement(actionRow); + } + } + } + } + } + } + + /// + /// Finalize the Upgrade table. + /// + /// The collection of all tables. + /// + /// Decompile the rows from the Upgrade and LaunchCondition tables + /// created by the MajorUpgrade element. + /// + private void FinalizeUpgradeTable(TableIndexedCollection tables) + { + Table launchConditionTable = tables["LaunchCondition"]; + Table upgradeTable = tables["Upgrade"]; + string downgradeErrorMessage = null; + string disallowUpgradeErrorMessage = null; + Wix.MajorUpgrade majorUpgrade = new Wix.MajorUpgrade(); + + // find the DowngradePreventedCondition launch condition message + if (null != launchConditionTable && 0 < launchConditionTable.Rows.Count) + { + foreach (Row launchRow in launchConditionTable.Rows) + { + if (Compiler.DowngradePreventedCondition == Convert.ToString(launchRow[0])) + { + downgradeErrorMessage = Convert.ToString(launchRow[1]); + } + else if (Compiler.UpgradePreventedCondition == Convert.ToString(launchRow[0])) + { + disallowUpgradeErrorMessage = Convert.ToString(launchRow[1]); + } + } + } + + if (null != upgradeTable && 0 < upgradeTable.Rows.Count) + { + bool hasMajorUpgrade = false; + + foreach (Row row in upgradeTable.Rows) + { + UpgradeRow upgradeRow = (UpgradeRow)row; + + if (Compiler.UpgradeDetectedProperty == upgradeRow.ActionProperty) + { + hasMajorUpgrade = true; + int attr = upgradeRow.Attributes; + string removeFeatures = upgradeRow.Remove; + + if (MsiInterop.MsidbUpgradeAttributesVersionMaxInclusive == (attr & MsiInterop.MsidbUpgradeAttributesVersionMaxInclusive)) + { + majorUpgrade.AllowSameVersionUpgrades = Wix.YesNoType.yes; + } + + if (MsiInterop.MsidbUpgradeAttributesMigrateFeatures != (attr & MsiInterop.MsidbUpgradeAttributesMigrateFeatures)) + { + majorUpgrade.MigrateFeatures = Wix.YesNoType.no; + } + + if (MsiInterop.MsidbUpgradeAttributesIgnoreRemoveFailure == (attr & MsiInterop.MsidbUpgradeAttributesIgnoreRemoveFailure)) + { + majorUpgrade.IgnoreRemoveFailure = Wix.YesNoType.yes; + } + + if (!String.IsNullOrEmpty(removeFeatures)) + { + majorUpgrade.RemoveFeatures = removeFeatures; + } + } + else if (Compiler.DowngradeDetectedProperty == upgradeRow.ActionProperty) + { + hasMajorUpgrade = true; + majorUpgrade.DowngradeErrorMessage = downgradeErrorMessage; + } + } + + if (hasMajorUpgrade) + { + if (String.IsNullOrEmpty(downgradeErrorMessage)) + { + majorUpgrade.AllowDowngrades = Wix.YesNoType.yes; + } + + if (!String.IsNullOrEmpty(disallowUpgradeErrorMessage)) + { + majorUpgrade.Disallow = Wix.YesNoType.yes; + majorUpgrade.DisallowUpgradeErrorMessage = disallowUpgradeErrorMessage; + } + + majorUpgrade.Schedule = DetermineMajorUpgradeScheduling(tables); + this.core.RootElement.AddChild(majorUpgrade); + } + } + } + + /// + /// Finalize the Verb table. + /// + /// The collection of all tables. + /// + /// The Extension table is a foreign table for the Verb table, but the + /// foreign key is only part of the primary key of the Extension table, + /// so it needs special logic to be nested properly. + /// + private void FinalizeVerbTable(TableIndexedCollection tables) + { + Table extensionTable = tables["Extension"]; + Table verbTable = tables["Verb"]; + + Hashtable extensionElements = new Hashtable(); + + if (null != extensionTable) + { + foreach (Row row in extensionTable.Rows) + { + Wix.Extension extension = (Wix.Extension)this.core.GetIndexedElement(row); + + if (!extensionElements.Contains(row[0])) + { + extensionElements.Add(row[0], new ArrayList()); + } + + ((ArrayList)extensionElements[row[0]]).Add(extension); + } + } + + if (null != verbTable) + { + foreach (Row row in verbTable.Rows) + { + Wix.Verb verb = (Wix.Verb)this.core.GetIndexedElement(row); + + ArrayList extensionsArray = (ArrayList)extensionElements[row[0]]; + if (null != extensionsArray) + { + foreach (Wix.Extension extension in extensionsArray) + { + extension.AddChild(verb); + } + } + else + { + this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, verbTable.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Extension_", Convert.ToString(row[0]), "Extension")); + } + } + } + } + + /// + /// Get the path to a file in the source image. + /// + /// The file. + /// The path to the file in the source image. + private string GetSourcePath(Wix.File file) + { + StringBuilder sourcePath = new StringBuilder(); + + Wix.Component component = (Wix.Component)file.ParentElement; + + for (Wix.Directory directory = (Wix.Directory)component.ParentElement; null != directory; directory = directory.ParentElement as Wix.Directory) + { + string name; + + if (!this.shortNames && null != directory.SourceName) + { + name = directory.SourceName; + } + else if (null != directory.ShortSourceName) + { + name = directory.ShortSourceName; + } + else if (!this.shortNames || null == directory.ShortName) + { + name = directory.Name; + } + else + { + name = directory.ShortName; + } + + if (0 == sourcePath.Length) + { + sourcePath.Append(name); + } + else + { + sourcePath.Insert(0, Path.DirectorySeparatorChar); + sourcePath.Insert(0, name); + } + } + + return sourcePath.ToString(); + } + + /// + /// Resolve the dependencies for a table (this is a helper method for GetSortedTableNames). + /// + /// The name of the table to resolve. + /// The unsorted table names. + /// The sorted table names. + private void ResolveTableDependencies(string tableName, SortedList unsortedTableNames, StringCollection sortedTableNames) + { + unsortedTableNames.Remove(tableName); + + foreach (ColumnDefinition columnDefinition in this.tableDefinitions[tableName].Columns) + { + // no dependency to resolve because this column doesn't reference another table + if (null == columnDefinition.KeyTable) + { + continue; + } + + foreach (string keyTable in columnDefinition.KeyTable.Split(';')) + { + if (tableName == keyTable) + { + continue; // self-referencing dependency + } + else if (sortedTableNames.Contains(keyTable)) + { + continue; // dependent table has already been sorted + } + else if (!this.tableDefinitions.Contains(keyTable)) + { + this.core.OnMessage(WixErrors.MissingTableDefinition(keyTable)); + } + else if (unsortedTableNames.Contains(keyTable)) + { + this.ResolveTableDependencies(keyTable, unsortedTableNames, sortedTableNames); + } + else + { + // found a circular dependency, so ignore it (this assumes that the tables will + // use a finalize method to nest their elements since the ordering will not be + // deterministic + } + } + } + + sortedTableNames.Add(tableName); + } + + /// + /// Get the names of the tables to process in the order they should be processed, according to their dependencies. + /// + /// A StringCollection containing the ordered table names. + private StringCollection GetSortedTableNames() + { + StringCollection sortedTableNames = new StringCollection(); + SortedList unsortedTableNames = new SortedList(); + + // index the table names + foreach (TableDefinition tableDefinition in this.tableDefinitions) + { + unsortedTableNames.Add(tableDefinition.Name, tableDefinition.Name); + } + + // resolve the dependencies for each table + while (0 < unsortedTableNames.Count) + { + this.ResolveTableDependencies(Convert.ToString(unsortedTableNames.GetByIndex(0)), unsortedTableNames, sortedTableNames); + } + + return sortedTableNames; + } + + /// + /// Initialize decompilation. + /// + /// The collection of all tables. + private void InitializeDecompile(TableIndexedCollection tables) + { + // reset all the state information + this.compressed = false; + this.patchTargetFiles.Clear(); + this.sequenceElements.Clear(); + this.shortNames = false; + + // set the codepage if its not neutral (0) + if (0 != this.codepage) + { + switch (this.outputType) + { + case OutputType.Module: + ((Wix.Module)this.core.RootElement).Codepage = this.codepage.ToString(CultureInfo.InvariantCulture); + break; + case OutputType.PatchCreation: + ((Wix.PatchCreation)this.core.RootElement).Codepage = this.codepage.ToString(CultureInfo.InvariantCulture); + break; + case OutputType.Product: + ((Wix.Product)this.core.RootElement).Codepage = this.codepage.ToString(CultureInfo.InvariantCulture); + break; + } + } + + // index the rows from the extension libraries + Dictionary> indexedExtensionTables = new Dictionary>(); + foreach (IDecompilerExtension extension in this.extensions) + { + // Get the optional library from the extension with the rows to be removed. + Library library = extension.GetLibraryToRemove(this.tableDefinitions); + if (null != library) + { + foreach (Section section in library.Sections) + { + foreach (Table table in section.Tables) + { + foreach (Row row in table.Rows) + { + string primaryKey; + string tableName; + + // the Actions table needs to be handled specially + if ("WixAction" == table.Name) + { + primaryKey = Convert.ToString(row[1]); + + if (OutputType.Module == this.outputType) + { + tableName = String.Concat("Module", Convert.ToString(row[0])); + } + else + { + tableName = Convert.ToString(row[0]); + } + } + else + { + primaryKey = row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter); + tableName = table.Name; + } + + if (null != primaryKey) + { + HashSet indexedExtensionRows; + if (!indexedExtensionTables.TryGetValue(tableName, out indexedExtensionRows)) + { + indexedExtensionRows = new HashSet(); + indexedExtensionTables.Add(tableName, indexedExtensionRows); + } + + indexedExtensionRows.Add(primaryKey); + } + } + } + } + } + } + + // remove the rows from the extension libraries (to allow full round-tripping) + foreach (var kvp in indexedExtensionTables) + { + string tableName = kvp.Key; + HashSet indexedExtensionRows = kvp.Value; + + Table table = tables[tableName]; + if (null != table) + { + RowDictionary originalRows = new RowDictionary(table); + + // remove the original rows so that they can be added back if they should remain + table.Rows.Clear(); + + foreach (Row row in originalRows.Values) + { + if (!indexedExtensionRows.Contains(row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter))) + { + table.Rows.Add(row); + } + } + } + } + } + + /// + /// Decompile the tables. + /// + /// The output being decompiled. + private void DecompileTables(Output output) + { + StringCollection sortedTableNames = this.GetSortedTableNames(); + + foreach (string tableName in sortedTableNames) + { + Table table = output.Tables[tableName]; + + // table does not exist in this database or should not be decompiled + if (null == table || !this.DecompilableTable(output, tableName)) + { + continue; + } + + this.core.OnMessage(WixVerboses.DecompilingTable(table.Name)); + + // empty tables may be kept with EnsureTable if the user set the proper option + if (0 == table.Rows.Count && this.suppressDroppingEmptyTables) + { + Wix.EnsureTable ensureTable = new Wix.EnsureTable(); + ensureTable.Id = table.Name; + this.core.RootElement.AddChild(ensureTable); + } + + switch (table.Name) + { + case "_SummaryInformation": + this.Decompile_SummaryInformationTable(table); + break; + case "AdminExecuteSequence": + case "AdminUISequence": + case "AdvtExecuteSequence": + case "InstallExecuteSequence": + case "InstallUISequence": + case "ModuleAdminExecuteSequence": + case "ModuleAdminUISequence": + case "ModuleAdvtExecuteSequence": + case "ModuleInstallExecuteSequence": + case "ModuleInstallUISequence": + // handled in FinalizeSequenceTables + break; + case "ActionText": + this.DecompileActionTextTable(table); + break; + case "AdvtUISequence": + this.core.OnMessage(WixWarnings.DeprecatedTable(table.Name)); + break; + case "AppId": + this.DecompileAppIdTable(table); + break; + case "AppSearch": + // handled in FinalizeSearchTables + break; + case "BBControl": + this.DecompileBBControlTable(table); + break; + case "Billboard": + this.DecompileBillboardTable(table); + break; + case "Binary": + this.DecompileBinaryTable(table); + break; + case "BindImage": + this.DecompileBindImageTable(table); + break; + case "CCPSearch": + // handled in FinalizeSearchTables + break; + case "CheckBox": + // handled in FinalizeCheckBoxTable + break; + case "Class": + this.DecompileClassTable(table); + break; + case "ComboBox": + this.DecompileComboBoxTable(table); + break; + case "Control": + this.DecompileControlTable(table); + break; + case "ControlCondition": + this.DecompileControlConditionTable(table); + break; + case "ControlEvent": + this.DecompileControlEventTable(table); + break; + case "CreateFolder": + this.DecompileCreateFolderTable(table); + break; + case "CustomAction": + this.DecompileCustomActionTable(table); + break; + case "CompLocator": + this.DecompileCompLocatorTable(table); + break; + case "Complus": + this.DecompileComplusTable(table); + break; + case "Component": + this.DecompileComponentTable(table); + break; + case "Condition": + this.DecompileConditionTable(table); + break; + case "Dialog": + this.DecompileDialogTable(table); + break; + case "Directory": + this.DecompileDirectoryTable(table); + break; + case "DrLocator": + this.DecompileDrLocatorTable(table); + break; + case "DuplicateFile": + this.DecompileDuplicateFileTable(table); + break; + case "Environment": + this.DecompileEnvironmentTable(table); + break; + case "Error": + this.DecompileErrorTable(table); + break; + case "EventMapping": + this.DecompileEventMappingTable(table); + break; + case "Extension": + this.DecompileExtensionTable(table); + break; + case "ExternalFiles": + this.DecompileExternalFilesTable(table); + break; + case "FamilyFileRanges": + // handled in FinalizeFamilyFileRangesTable + break; + case "Feature": + this.DecompileFeatureTable(table); + break; + case "FeatureComponents": + this.DecompileFeatureComponentsTable(table); + break; + case "File": + this.DecompileFileTable(table); + break; + case "FileSFPCatalog": + this.DecompileFileSFPCatalogTable(table); + break; + case "Font": + this.DecompileFontTable(table); + break; + case "Icon": + this.DecompileIconTable(table); + break; + case "ImageFamilies": + this.DecompileImageFamiliesTable(table); + break; + case "IniFile": + this.DecompileIniFileTable(table); + break; + case "IniLocator": + this.DecompileIniLocatorTable(table); + break; + case "IsolatedComponent": + this.DecompileIsolatedComponentTable(table); + break; + case "LaunchCondition": + this.DecompileLaunchConditionTable(table); + break; + case "ListBox": + this.DecompileListBoxTable(table); + break; + case "ListView": + this.DecompileListViewTable(table); + break; + case "LockPermissions": + this.DecompileLockPermissionsTable(table); + break; + case "Media": + this.DecompileMediaTable(table); + break; + case "MIME": + this.DecompileMIMETable(table); + break; + case "ModuleAdvtUISequence": + this.core.OnMessage(WixWarnings.DeprecatedTable(table.Name)); + break; + case "ModuleComponents": + // handled by DecompileComponentTable (since the ModuleComponents table + // rows are created by nesting components under the Module element) + break; + case "ModuleConfiguration": + this.DecompileModuleConfigurationTable(table); + break; + case "ModuleDependency": + this.DecompileModuleDependencyTable(table); + break; + case "ModuleExclusion": + this.DecompileModuleExclusionTable(table); + break; + case "ModuleIgnoreTable": + this.DecompileModuleIgnoreTableTable(table); + break; + case "ModuleSignature": + this.DecompileModuleSignatureTable(table); + break; + case "ModuleSubstitution": + this.DecompileModuleSubstitutionTable(table); + break; + case "MoveFile": + this.DecompileMoveFileTable(table); + break; + case "MsiAssembly": + // handled in FinalizeFileTable + break; + case "MsiDigitalCertificate": + this.DecompileMsiDigitalCertificateTable(table); + break; + case "MsiDigitalSignature": + this.DecompileMsiDigitalSignatureTable(table); + break; + case "MsiEmbeddedChainer": + this.DecompileMsiEmbeddedChainerTable(table); + break; + case "MsiEmbeddedUI": + this.DecompileMsiEmbeddedUITable(table); + break; + case "MsiLockPermissionsEx": + this.DecompileMsiLockPermissionsExTable(table); + break; + case "MsiPackageCertificate": + this.DecompileMsiPackageCertificateTable(table); + break; + case "MsiPatchCertificate": + this.DecompileMsiPatchCertificateTable(table); + break; + case "MsiShortcutProperty": + this.DecompileMsiShortcutPropertyTable(table); + break; + case "ODBCAttribute": + this.DecompileODBCAttributeTable(table); + break; + case "ODBCDataSource": + this.DecompileODBCDataSourceTable(table); + break; + case "ODBCDriver": + this.DecompileODBCDriverTable(table); + break; + case "ODBCSourceAttribute": + this.DecompileODBCSourceAttributeTable(table); + break; + case "ODBCTranslator": + this.DecompileODBCTranslatorTable(table); + break; + case "PatchMetadata": + this.DecompilePatchMetadataTable(table); + break; + case "PatchSequence": + this.DecompilePatchSequenceTable(table); + break; + case "ProgId": + this.DecompileProgIdTable(table); + break; + case "Properties": + this.DecompilePropertiesTable(table); + break; + case "Property": + this.DecompilePropertyTable(table); + break; + case "PublishComponent": + this.DecompilePublishComponentTable(table); + break; + case "RadioButton": + this.DecompileRadioButtonTable(table); + break; + case "Registry": + this.DecompileRegistryTable(table); + break; + case "RegLocator": + this.DecompileRegLocatorTable(table); + break; + case "RemoveFile": + this.DecompileRemoveFileTable(table); + break; + case "RemoveIniFile": + this.DecompileRemoveIniFileTable(table); + break; + case "RemoveRegistry": + this.DecompileRemoveRegistryTable(table); + break; + case "ReserveCost": + this.DecompileReserveCostTable(table); + break; + case "SelfReg": + this.DecompileSelfRegTable(table); + break; + case "ServiceControl": + this.DecompileServiceControlTable(table); + break; + case "ServiceInstall": + this.DecompileServiceInstallTable(table); + break; + case "SFPCatalog": + this.DecompileSFPCatalogTable(table); + break; + case "Shortcut": + this.DecompileShortcutTable(table); + break; + case "Signature": + this.DecompileSignatureTable(table); + break; + case "TargetFiles_OptionalData": + this.DecompileTargetFiles_OptionalDataTable(table); + break; + case "TargetImages": + this.DecompileTargetImagesTable(table); + break; + case "TextStyle": + this.DecompileTextStyleTable(table); + break; + case "TypeLib": + this.DecompileTypeLibTable(table); + break; + case "Upgrade": + this.DecompileUpgradeTable(table); + break; + case "UpgradedFiles_OptionalData": + this.DecompileUpgradedFiles_OptionalDataTable(table); + break; + case "UpgradedFilesToIgnore": + this.DecompileUpgradedFilesToIgnoreTable(table); + break; + case "UpgradedImages": + this.DecompileUpgradedImagesTable(table); + break; + case "UIText": + this.DecompileUITextTable(table); + break; + case "Verb": + this.DecompileVerbTable(table); + break; + default: + DecompilerExtension extension = (DecompilerExtension)this.extensionsByTableName[table.Name]; + + if (null != extension) + { + extension.DecompileTable(table); + } + else if (!this.suppressCustomTables) + { + this.DecompileCustomTable(table); + } + break; + } + } + } + + /// + /// Determine if a particular table should be decompiled with the current settings. + /// + /// The output being decompiled. + /// The name of a table. + /// true if the table should be decompiled; false otherwise. + private bool DecompilableTable(Output output, string tableName) + { + switch (tableName) + { + case "ActionText": + case "BBControl": + case "Billboard": + case "CheckBox": + case "Control": + case "ControlCondition": + case "ControlEvent": + case "Dialog": + case "Error": + case "EventMapping": + case "RadioButton": + case "TextStyle": + case "UIText": + return !this.suppressUI; + case "ModuleAdminExecuteSequence": + case "ModuleAdminUISequence": + case "ModuleAdvtExecuteSequence": + case "ModuleAdvtUISequence": + case "ModuleComponents": + case "ModuleConfiguration": + case "ModuleDependency": + case "ModuleIgnoreTable": + case "ModuleInstallExecuteSequence": + case "ModuleInstallUISequence": + case "ModuleExclusion": + case "ModuleSignature": + case "ModuleSubstitution": + if (OutputType.Module != output.Type) + { + this.core.OnMessage(WixWarnings.SkippingMergeModuleTable(output.SourceLineNumbers, tableName)); + return false; + } + else + { + return true; + } + case "ExternalFiles": + case "FamilyFileRanges": + case "ImageFamilies": + case "PatchMetadata": + case "PatchSequence": + case "Properties": + case "TargetFiles_OptionalData": + case "TargetImages": + case "UpgradedFiles_OptionalData": + case "UpgradedFilesToIgnore": + case "UpgradedImages": + if (OutputType.PatchCreation != output.Type) + { + this.core.OnMessage(WixWarnings.SkippingPatchCreationTable(output.SourceLineNumbers, tableName)); + return false; + } + else + { + return true; + } + case "MsiPatchHeaders": + case "MsiPatchMetadata": + case "MsiPatchOldAssemblyName": + case "MsiPatchOldAssemblyFile": + case "MsiPatchSequence": + case "Patch": + case "PatchPackage": + this.core.OnMessage(WixWarnings.PatchTable(output.SourceLineNumbers, tableName)); + return false; + case "_SummaryInformation": + return true; + case "_Validation": + case "MsiAssemblyName": + case "MsiFileHash": + return false; + default: // all other tables are allowed in any output except for a patch creation package + if (OutputType.PatchCreation == output.Type) + { + this.core.OnMessage(WixWarnings.IllegalPatchCreationTable(output.SourceLineNumbers, tableName)); + return false; + } + else + { + return true; + } + } + } + + /// + /// Decompile the _SummaryInformation table. + /// + /// The table to decompile. + private void Decompile_SummaryInformationTable(Table table) + { + if (OutputType.Module == this.outputType || OutputType.Product == this.outputType) + { + Wix.Package package = new Wix.Package(); + + foreach (Row row in table.Rows) + { + string value = Convert.ToString(row[1]); + + if (null != value && 0 < value.Length) + { + switch (Convert.ToInt32(row[0])) + { + case 1: + if ("1252" != value) + { + package.SummaryCodepage = value; + } + break; + case 3: + package.Description = value; + break; + case 4: + package.Manufacturer = value; + break; + case 5: + if ("Installer" != value) + { + package.Keywords = value; + } + break; + case 6: + package.Comments = value; + break; + case 7: + string[] template = value.Split(';'); + if (0 < template.Length && 0 < template[template.Length - 1].Length) + { + package.Languages = template[template.Length - 1]; + } + + if (1 < template.Length && null != template[0] && 0 < template[0].Length) + { + switch (template[0]) + { + case "Intel": + package.Platform = WixToolset.Data.Serialize.Package.PlatformType.x86; + break; + case "Intel64": + package.Platform = WixToolset.Data.Serialize.Package.PlatformType.ia64; + break; + case "x64": + package.Platform = WixToolset.Data.Serialize.Package.PlatformType.x64; + break; + } + } + break; + case 9: + if (OutputType.Module == this.outputType) + { + this.modularizationGuid = value; + package.Id = value; + } + break; + case 14: + package.InstallerVersion = Convert.ToInt32(row[1], CultureInfo.InvariantCulture); + break; + case 15: + int wordCount = Convert.ToInt32(row[1], CultureInfo.InvariantCulture); + if (0x1 == (wordCount & 0x1)) + { + this.shortNames = true; + package.ShortNames = Wix.YesNoType.yes; + } + + if (0x2 == (wordCount & 0x2)) + { + this.compressed = true; + + if (OutputType.Product == this.outputType) + { + package.Compressed = Wix.YesNoType.yes; + } + } + + if (0x4 == (wordCount & 0x4)) + { + package.AdminImage = Wix.YesNoType.yes; + } + + if (0x8 == (wordCount & 0x8)) + { + package.InstallPrivileges = Wix.Package.InstallPrivilegesType.limited; + } + + break; + case 19: + int security = Convert.ToInt32(row[1], CultureInfo.InvariantCulture); + switch (security) + { + case 0: + package.ReadOnly = Wix.YesNoDefaultType.no; + break; + case 4: + package.ReadOnly = Wix.YesNoDefaultType.yes; + break; + } + break; + } + } + } + + this.core.RootElement.AddChild(package); + } + else + { + Wix.PatchInformation patchInformation = new Wix.PatchInformation(); + + foreach (Row row in table.Rows) + { + int propertyId = Convert.ToInt32(row[0]); + string value = Convert.ToString(row[1]); + + if (null != row[1] && 0 < value.Length) + { + switch (propertyId) + { + case 1: + if ("1252" != value) + { + patchInformation.SummaryCodepage = value; + } + break; + case 3: + patchInformation.Description = value; + break; + case 4: + patchInformation.Manufacturer = value; + break; + case 5: + if ("Installer,Patching,PCP,Database" != value) + { + patchInformation.Keywords = value; + } + break; + case 6: + patchInformation.Comments = value; + break; + case 7: + string[] template = value.Split(';'); + if (0 < template.Length && 0 < template[template.Length - 1].Length) + { + patchInformation.Languages = template[template.Length - 1]; + } + + if (1 < template.Length && null != template[0] && 0 < template[0].Length) + { + patchInformation.Platforms = template[0]; + } + break; + case 15: + int wordCount = Convert.ToInt32(value, CultureInfo.InvariantCulture); + if (0x1 == (wordCount & 0x1)) + { + patchInformation.ShortNames = Wix.YesNoType.yes; + } + + if (0x2 == (wordCount & 0x2)) + { + patchInformation.Compressed = Wix.YesNoType.yes; + } + + if (0x4 == (wordCount & 0x4)) + { + patchInformation.AdminImage = Wix.YesNoType.yes; + } + break; + case 19: + int security = Convert.ToInt32(value, CultureInfo.InvariantCulture); + switch (security) + { + case 0: + patchInformation.ReadOnly = Wix.YesNoDefaultType.no; + break; + case 4: + patchInformation.ReadOnly = Wix.YesNoDefaultType.yes; + break; + } + break; + } + } + } + + this.core.RootElement.AddChild(patchInformation); + } + } + + /// + /// Decompile the ActionText table. + /// + /// The table to decompile. + private void DecompileActionTextTable(Table table) + { + foreach (Row row in table.Rows) + { + Wix.ProgressText progressText = new Wix.ProgressText(); + + progressText.Action = Convert.ToString(row[0]); + + if (null != row[1]) + { + progressText.Content = Convert.ToString(row[1]); + } + + if (null != row[2]) + { + progressText.Template = Convert.ToString(row[2]); + } + + this.core.UIElement.AddChild(progressText); + } + } + + /// + /// Decompile the AppId table. + /// + /// The table to decompile. + private void DecompileAppIdTable(Table table) + { + foreach (Row row in table.Rows) + { + Wix.AppId appId = new Wix.AppId(); + + appId.Advertise = Wix.YesNoType.yes; + + appId.Id = Convert.ToString(row[0]); + + if (null != row[1]) + { + appId.RemoteServerName = Convert.ToString(row[1]); + } + + if (null != row[2]) + { + appId.LocalService = Convert.ToString(row[2]); + } + + if (null != row[3]) + { + appId.ServiceParameters = Convert.ToString(row[3]); + } + + if (null != row[4]) + { + appId.DllSurrogate = Convert.ToString(row[4]); + } + + if (null != row[5] && Int32.Equals(row[5], 1)) + { + appId.ActivateAtStorage = Wix.YesNoType.yes; + } + + if (null != row[6] && Int32.Equals(row[6], 1)) + { + appId.RunAsInteractiveUser = Wix.YesNoType.yes; + } + + this.core.RootElement.AddChild(appId); + this.core.IndexElement(row, appId); + } + } + + /// + /// Decompile the BBControl table. + /// + /// The table to decompile. + private void DecompileBBControlTable(Table table) + { + foreach (BBControlRow bbControlRow in table.Rows) + { + Wix.Control control = new Wix.Control(); + + control.Id = bbControlRow.BBControl; + + control.Type = bbControlRow.Type; + + control.X = bbControlRow.X; + + control.Y = bbControlRow.Y; + + control.Width = bbControlRow.Width; + + control.Height = bbControlRow.Height; + + if (null != bbControlRow[7]) + { + SetControlAttributes(bbControlRow.Attributes, control); + } + + if (null != bbControlRow.Text) + { + control.Text = bbControlRow.Text; + } + + Wix.Billboard billboard = (Wix.Billboard)this.core.GetIndexedElement("Billboard", bbControlRow.Billboard); + if (null != billboard) + { + billboard.AddChild(control); + } + else + { + this.core.OnMessage(WixWarnings.ExpectedForeignRow(bbControlRow.SourceLineNumbers, table.Name, bbControlRow.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Billboard_", bbControlRow.Billboard, "Billboard")); + } + } + } + + /// + /// Decompile the Billboard table. + /// + /// The table to decompile. + private void DecompileBillboardTable(Table table) + { + Hashtable billboardActions = new Hashtable(); + SortedList billboards = new SortedList(); + + foreach (Row row in table.Rows) + { + Wix.Billboard billboard = new Wix.Billboard(); + + billboard.Id = Convert.ToString(row[0]); + + billboard.Feature = Convert.ToString(row[1]); + + this.core.IndexElement(row, billboard); + billboards.Add(String.Format(CultureInfo.InvariantCulture, "{0}|{1:0000000000}", row[0], row[3]), row); + } + + foreach (Row row in billboards.Values) + { + Wix.Billboard billboard = (Wix.Billboard)this.core.GetIndexedElement(row); + Wix.BillboardAction billboardAction = (Wix.BillboardAction)billboardActions[row[2]]; + + if (null == billboardAction) + { + billboardAction = new Wix.BillboardAction(); + + billboardAction.Id = Convert.ToString(row[2]); + + this.core.UIElement.AddChild(billboardAction); + billboardActions.Add(row[2], billboardAction); + } + + billboardAction.AddChild(billboard); + } + } + + /// + /// Decompile the Binary table. + /// + /// The table to decompile. + private void DecompileBinaryTable(Table table) + { + foreach (Row row in table.Rows) + { + Wix.Binary binary = new Wix.Binary(); + + binary.Id = Convert.ToString(row[0]); + + binary.SourceFile = Convert.ToString(row[1]); + + this.core.RootElement.AddChild(binary); + } + } + + /// + /// Decompile the BindImage table. + /// + /// The table to decompile. + private void DecompileBindImageTable(Table table) + { + foreach (Row row in table.Rows) + { + Wix.File file = (Wix.File)this.core.GetIndexedElement("File", Convert.ToString(row[0])); + + if (null != file) + { + file.BindPath = Convert.ToString(row[1]); + } + else + { + this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "File_", Convert.ToString(row[0]), "File")); + } + } + } + + /// + /// Decompile the Class table. + /// + /// The table to decompile. + private void DecompileClassTable(Table table) + { + foreach (Row row in table.Rows) + { + Wix.Class wixClass = new Wix.Class(); + + wixClass.Advertise = Wix.YesNoType.yes; + + wixClass.Id = Convert.ToString(row[0]); + + switch (Convert.ToString(row[1])) + { + case "LocalServer": + wixClass.Context = Wix.Class.ContextType.LocalServer; + break; + case "LocalServer32": + wixClass.Context = Wix.Class.ContextType.LocalServer32; + break; + case "InprocServer": + wixClass.Context = Wix.Class.ContextType.InprocServer; + break; + case "InprocServer32": + wixClass.Context = Wix.Class.ContextType.InprocServer32; + break; + default: + this.core.OnMessage(WixWarnings.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[1].Column.Name, row[1])); + break; + } + + // ProgId children are handled in FinalizeProgIdTable + + if (null != row[4]) + { + wixClass.Description = Convert.ToString(row[4]); + } + + if (null != row[5]) + { + wixClass.AppId = Convert.ToString(row[5]); + } + + if (null != row[6]) + { + string[] fileTypeMaskStrings = (Convert.ToString(row[6])).Split(';'); + + try + { + foreach (string fileTypeMaskString in fileTypeMaskStrings) + { + string[] fileTypeMaskParts = fileTypeMaskString.Split(','); + + if (4 == fileTypeMaskParts.Length) + { + Wix.FileTypeMask fileTypeMask = new Wix.FileTypeMask(); + + fileTypeMask.Offset = Convert.ToInt32(fileTypeMaskParts[0], CultureInfo.InvariantCulture); + + fileTypeMask.Mask = fileTypeMaskParts[2]; + + fileTypeMask.Value = fileTypeMaskParts[3]; + + wixClass.AddChild(fileTypeMask); + } + else + { + // TODO: warn + } + } + } + catch (FormatException) + { + this.core.OnMessage(WixWarnings.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[6].Column.Name, row[6])); + } + catch (OverflowException) + { + this.core.OnMessage(WixWarnings.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[6].Column.Name, row[6])); + } + } + + if (null != row[7]) + { + wixClass.Icon = Convert.ToString(row[7]); + } + + if (null != row[8]) + { + wixClass.IconIndex = Convert.ToInt32(row[8]); + } + + if (null != row[9]) + { + wixClass.Handler = Convert.ToString(row[9]); + } + + if (null != row[10]) + { + wixClass.Argument = Convert.ToString(row[10]); + } + + if (null != row[12]) + { + if (1 == Convert.ToInt32(row[12])) + { + wixClass.RelativePath = Wix.YesNoType.yes; + } + else + { + this.core.OnMessage(WixWarnings.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[12].Column.Name, row[12])); + } + } + + Wix.Component component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[2])); + if (null != component) + { + component.AddChild(wixClass); + } + else + { + this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[2]), "Component")); + } + + this.core.IndexElement(row, wixClass); + } + } + + /// + /// Decompile the ComboBox table. + /// + /// The table to decompile. + private void DecompileComboBoxTable(Table table) + { + Wix.ComboBox comboBox = null; + SortedList comboBoxRows = new SortedList(); + + // sort the combo boxes by their property and order + foreach (Row row in table.Rows) + { + comboBoxRows.Add(String.Concat("{0}|{1:0000000000}", row[0], row[1]), row); + } + + foreach (Row row in comboBoxRows.Values) + { + if (null == comboBox || Convert.ToString(row[0]) != comboBox.Property) + { + comboBox = new Wix.ComboBox(); + + comboBox.Property = Convert.ToString(row[0]); + + this.core.UIElement.AddChild(comboBox); + } + + Wix.ListItem listItem = new Wix.ListItem(); + + listItem.Value = Convert.ToString(row[2]); + + if (null != row[3]) + { + listItem.Text = Convert.ToString(row[3]); + } + + comboBox.AddChild(listItem); + } + } + + /// + /// Decompile the Control table. + /// + /// The table to decompile. + private void DecompileControlTable(Table table) + { + foreach (ControlRow controlRow in table.Rows) + { + Wix.Control control = new Wix.Control(); + + control.Id = controlRow.Control; + + control.Type = controlRow.Type; + + control.X = controlRow.X; + + control.Y = controlRow.Y; + + control.Width = controlRow.Width; + + control.Height = controlRow.Height; + + if (null != controlRow[7]) + { + string[] specialAttributes; + + // sets various common attributes like Disabled, Indirect, Integer, ... + SetControlAttributes(controlRow.Attributes, control); + + switch (control.Type) + { + case "Bitmap": + specialAttributes = MsiInterop.BitmapControlAttributes; + break; + case "CheckBox": + specialAttributes = MsiInterop.CheckboxControlAttributes; + break; + case "ComboBox": + specialAttributes = MsiInterop.ComboboxControlAttributes; + break; + case "DirectoryCombo": + specialAttributes = MsiInterop.VolumeControlAttributes; + break; + case "Edit": + specialAttributes = MsiInterop.EditControlAttributes; + break; + case "Icon": + specialAttributes = MsiInterop.IconControlAttributes; + break; + case "ListBox": + specialAttributes = MsiInterop.ListboxControlAttributes; + break; + case "ListView": + specialAttributes = MsiInterop.ListviewControlAttributes; + break; + case "MaskedEdit": + specialAttributes = MsiInterop.EditControlAttributes; + break; + case "PathEdit": + specialAttributes = MsiInterop.EditControlAttributes; + break; + case "ProgressBar": + specialAttributes = MsiInterop.ProgressControlAttributes; + break; + case "PushButton": + specialAttributes = MsiInterop.ButtonControlAttributes; + break; + case "RadioButtonGroup": + specialAttributes = MsiInterop.RadioControlAttributes; + break; + case "Text": + specialAttributes = MsiInterop.TextControlAttributes; + break; + case "VolumeCostList": + specialAttributes = MsiInterop.VolumeControlAttributes; + break; + case "VolumeSelectCombo": + specialAttributes = MsiInterop.VolumeControlAttributes; + break; + default: + specialAttributes = null; + break; + } + + if (null != specialAttributes) + { + bool iconSizeSet = false; + + for (int i = 16; 32 > i; i++) + { + if (1 == ((controlRow.Attributes >> i) & 1)) + { + string attribute = null; + + if (specialAttributes.Length > (i - 16)) + { + attribute = specialAttributes[i - 16]; + } + + // unknown attribute + if (null == attribute) + { + this.core.OnMessage(WixWarnings.IllegalColumnValue(controlRow.SourceLineNumbers, table.Name, controlRow.Fields[7].Column.Name, controlRow.Attributes)); + continue; + } + + switch (attribute) + { + case "Bitmap": + control.Bitmap = Wix.YesNoType.yes; + break; + case "CDROM": + control.CDROM = Wix.YesNoType.yes; + break; + case "ComboList": + control.ComboList = Wix.YesNoType.yes; + break; + case "ElevationShield": + control.ElevationShield = Wix.YesNoType.yes; + break; + case "Fixed": + control.Fixed = Wix.YesNoType.yes; + break; + case "FixedSize": + control.FixedSize = Wix.YesNoType.yes; + break; + case "Floppy": + control.Floppy = Wix.YesNoType.yes; + break; + case "FormatSize": + control.FormatSize = Wix.YesNoType.yes; + break; + case "HasBorder": + control.HasBorder = Wix.YesNoType.yes; + break; + case "Icon": + control.Icon = Wix.YesNoType.yes; + break; + case "Icon16": + if (iconSizeSet) + { + control.IconSize = Wix.Control.IconSizeType.Item48; + } + else + { + iconSizeSet = true; + control.IconSize = Wix.Control.IconSizeType.Item16; + } + break; + case "Icon32": + if (iconSizeSet) + { + control.IconSize = Wix.Control.IconSizeType.Item48; + } + else + { + iconSizeSet = true; + control.IconSize = Wix.Control.IconSizeType.Item32; + } + break; + case "Image": + control.Image = Wix.YesNoType.yes; + break; + case "Multiline": + control.Multiline = Wix.YesNoType.yes; + break; + case "NoPrefix": + control.NoPrefix = Wix.YesNoType.yes; + break; + case "NoWrap": + control.NoWrap = Wix.YesNoType.yes; + break; + case "Password": + control.Password = Wix.YesNoType.yes; + break; + case "ProgressBlocks": + control.ProgressBlocks = Wix.YesNoType.yes; + break; + case "PushLike": + control.PushLike = Wix.YesNoType.yes; + break; + case "RAMDisk": + control.RAMDisk = Wix.YesNoType.yes; + break; + case "Remote": + control.Remote = Wix.YesNoType.yes; + break; + case "Removable": + control.Removable = Wix.YesNoType.yes; + break; + case "ShowRollbackCost": + control.ShowRollbackCost = Wix.YesNoType.yes; + break; + case "Sorted": + control.Sorted = Wix.YesNoType.yes; + break; + case "Transparent": + control.Transparent = Wix.YesNoType.yes; + break; + case "UserLanguage": + control.UserLanguage = Wix.YesNoType.yes; + break; + default: + throw new InvalidOperationException(String.Format(CultureInfo.CurrentUICulture, WixStrings.EXP_UnknowControlAttribute, attribute)); + } + } + } + } + else if (0 < (controlRow.Attributes & 0xFFFF0000)) + { + this.core.OnMessage(WixWarnings.IllegalColumnValue(controlRow.SourceLineNumbers, table.Name, controlRow.Fields[7].Column.Name, controlRow.Attributes)); + } + } + + // FinalizeCheckBoxTable adds Control/@Property|@CheckBoxPropertyRef + if (null != controlRow.Property && 0 != String.CompareOrdinal("CheckBox", control.Type)) + { + control.Property = controlRow.Property; + } + + if (null != controlRow.Text) + { + control.Text = controlRow.Text; + } + + if (null != controlRow.Help) + { + string[] help = controlRow.Help.Split('|'); + + if (2 == help.Length) + { + if (0 < help[0].Length) + { + control.ToolTip = help[0]; + } + + if (0 < help[1].Length) + { + control.Help = help[1]; + } + } + } + + this.core.IndexElement(controlRow, control); + } + } + + /// + /// Decompile the ControlCondition table. + /// + /// The table to decompile. + private void DecompileControlConditionTable(Table table) + { + foreach (Row row in table.Rows) + { + Wix.Condition condition = new Wix.Condition(); + + switch (Convert.ToString(row[2])) + { + case "Default": + condition.Action = Wix.Condition.ActionType.@default; + break; + case "Disable": + condition.Action = Wix.Condition.ActionType.disable; + break; + case "Enable": + condition.Action = Wix.Condition.ActionType.enable; + break; + case "Hide": + condition.Action = Wix.Condition.ActionType.hide; + break; + case "Show": + condition.Action = Wix.Condition.ActionType.show; + break; + default: + this.core.OnMessage(WixWarnings.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[2].Column.Name, row[2])); + break; + } + + condition.Content = Convert.ToString(row[3]); + + Wix.Control control = (Wix.Control)this.core.GetIndexedElement("Control", Convert.ToString(row[0]), Convert.ToString(row[1])); + if (null != control) + { + control.AddChild(condition); + } + else + { + this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Dialog_", Convert.ToString(row[0]), "Control_", Convert.ToString(row[1]), "Control")); + } + } + } + + /// + /// Decompile the ControlEvent table. + /// + /// The table to decompile. + private void DecompileControlEventTable(Table table) + { + SortedList controlEvents = new SortedList(); + + foreach (Row row in table.Rows) + { + Wix.Publish publish = new Wix.Publish(); + + string publishEvent = Convert.ToString(row[2]); + if (publishEvent.StartsWith("[", StringComparison.Ordinal) && publishEvent.EndsWith("]", StringComparison.Ordinal)) + { + publish.Property = publishEvent.Substring(1, publishEvent.Length - 2); + + if ("{}" != Convert.ToString(row[3])) + { + publish.Value = Convert.ToString(row[3]); + } + } + else + { + publish.Event = publishEvent; + publish.Value = Convert.ToString(row[3]); + } + + if (null != row[4]) + { + publish.Content = Convert.ToString(row[4]); + } + + 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); + + this.core.IndexElement(row, publish); + } + + foreach (Row row in controlEvents.Values) + { + Wix.Control control = (Wix.Control)this.core.GetIndexedElement("Control", Convert.ToString(row[0]), Convert.ToString(row[1])); + Wix.Publish publish = (Wix.Publish)this.core.GetIndexedElement(row); + + if (null != control) + { + control.AddChild(publish); + } + else + { + this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Dialog_", Convert.ToString(row[0]), "Control_", Convert.ToString(row[1]), "Control")); + } + } + } + + /// + /// Decompile a custom table. + /// + /// The table to decompile. + private void DecompileCustomTable(Table table) + { + if (0 < table.Rows.Count || this.suppressDroppingEmptyTables) + { + Wix.CustomTable customTable = new Wix.CustomTable(); + + this.core.OnMessage(WixWarnings.DecompilingAsCustomTable(table.Rows[0].SourceLineNumbers, table.Name)); + + customTable.Id = table.Name; + + foreach (ColumnDefinition columnDefinition in table.Definition.Columns) + { + Wix.Column column = new Wix.Column(); + + column.Id = columnDefinition.Name; + + if (ColumnCategory.Unknown != columnDefinition.Category) + { + switch (columnDefinition.Category) + { + case ColumnCategory.Text: + column.Category = Wix.Column.CategoryType.Text; + break; + case ColumnCategory.UpperCase: + column.Category = Wix.Column.CategoryType.UpperCase; + break; + case ColumnCategory.LowerCase: + column.Category = Wix.Column.CategoryType.LowerCase; + break; + case ColumnCategory.Integer: + column.Category = Wix.Column.CategoryType.Integer; + break; + case ColumnCategory.DoubleInteger: + column.Category = Wix.Column.CategoryType.DoubleInteger; + break; + case ColumnCategory.TimeDate: + column.Category = Wix.Column.CategoryType.TimeDate; + break; + case ColumnCategory.Identifier: + column.Category = Wix.Column.CategoryType.Identifier; + break; + case ColumnCategory.Property: + column.Category = Wix.Column.CategoryType.Property; + break; + case ColumnCategory.Filename: + column.Category = Wix.Column.CategoryType.Filename; + break; + case ColumnCategory.WildCardFilename: + column.Category = Wix.Column.CategoryType.WildCardFilename; + break; + case ColumnCategory.Path: + column.Category = Wix.Column.CategoryType.Path; + break; + case ColumnCategory.Paths: + column.Category = Wix.Column.CategoryType.Paths; + break; + case ColumnCategory.AnyPath: + column.Category = Wix.Column.CategoryType.AnyPath; + break; + case ColumnCategory.DefaultDir: + column.Category = Wix.Column.CategoryType.DefaultDir; + break; + case ColumnCategory.RegPath: + column.Category = Wix.Column.CategoryType.RegPath; + break; + case ColumnCategory.Formatted: + column.Category = Wix.Column.CategoryType.Formatted; + break; + case ColumnCategory.FormattedSDDLText: + column.Category = Wix.Column.CategoryType.FormattedSddl; + break; + case ColumnCategory.Template: + column.Category = Wix.Column.CategoryType.Template; + break; + case ColumnCategory.Condition: + column.Category = Wix.Column.CategoryType.Condition; + break; + case ColumnCategory.Guid: + column.Category = Wix.Column.CategoryType.Guid; + break; + case ColumnCategory.Version: + column.Category = Wix.Column.CategoryType.Version; + break; + case ColumnCategory.Language: + column.Category = Wix.Column.CategoryType.Language; + break; + case ColumnCategory.Binary: + column.Category = Wix.Column.CategoryType.Binary; + break; + case ColumnCategory.CustomSource: + column.Category = Wix.Column.CategoryType.CustomSource; + break; + case ColumnCategory.Cabinet: + column.Category = Wix.Column.CategoryType.Cabinet; + break; + case ColumnCategory.Shortcut: + column.Category = Wix.Column.CategoryType.Shortcut; + break; + default: + throw new InvalidOperationException(String.Format(CultureInfo.CurrentUICulture, WixStrings.EXP_UnknownCustomColumnCategory, columnDefinition.Category.ToString())); + } + } + + if (null != columnDefinition.Description) + { + column.Description = columnDefinition.Description; + } + + if (columnDefinition.IsKeyColumnSet) + { + column.KeyColumn = columnDefinition.KeyColumn; + } + + if (null != columnDefinition.KeyTable) + { + column.KeyTable = columnDefinition.KeyTable; + } + + if (columnDefinition.IsLocalizable) + { + column.Localizable = Wix.YesNoType.yes; + } + + if (columnDefinition.IsMaxValueSet) + { + column.MaxValue = columnDefinition.MaxValue; + } + + if (columnDefinition.IsMinValueSet) + { + column.MinValue = columnDefinition.MinValue; + } + + if (ColumnModularizeType.None != columnDefinition.ModularizeType) + { + switch (columnDefinition.ModularizeType) + { + case ColumnModularizeType.Column: + column.Modularize = Wix.Column.ModularizeType.Column; + break; + case ColumnModularizeType.Condition: + column.Modularize = Wix.Column.ModularizeType.Condition; + break; + case ColumnModularizeType.Icon: + column.Modularize = Wix.Column.ModularizeType.Icon; + break; + case ColumnModularizeType.Property: + column.Modularize = Wix.Column.ModularizeType.Property; + break; + case ColumnModularizeType.SemicolonDelimited: + column.Modularize = Wix.Column.ModularizeType.SemicolonDelimited; + break; + default: + throw new InvalidOperationException(String.Format(CultureInfo.CurrentUICulture, WixStrings.EXP_UnknownCustomColumnModularizationType, columnDefinition.ModularizeType.ToString())); + } + } + + if (columnDefinition.Nullable) + { + column.Nullable = Wix.YesNoType.yes; + } + + if (columnDefinition.PrimaryKey) + { + column.PrimaryKey = Wix.YesNoType.yes; + } + + if (null != columnDefinition.Possibilities) + { + column.Set = columnDefinition.Possibilities; + } + + if (ColumnType.Unknown != columnDefinition.Type) + { + switch (columnDefinition.Type) + { + case ColumnType.Localized: + column.Localizable = Wix.YesNoType.yes; + column.Type = Wix.Column.TypeType.@string; + break; + case ColumnType.Number: + column.Type = Wix.Column.TypeType.@int; + break; + case ColumnType.Object: + column.Type = Wix.Column.TypeType.binary; + break; + case ColumnType.Preserved: + case ColumnType.String: + column.Type = Wix.Column.TypeType.@string; + break; + default: + throw new InvalidOperationException(String.Format(CultureInfo.CurrentUICulture, WixStrings.EXP_UnknownCustomColumnType, columnDefinition.Type.ToString())); + } + } + + column.Width = columnDefinition.Length; + + customTable.AddChild(column); + } + + foreach (Row row in table.Rows) + { + Wix.Row wixRow = new Wix.Row(); + + foreach (Field field in row.Fields) + { + Wix.Data data = new Wix.Data(); + + data.Column = field.Column.Name; + + data.Content = Convert.ToString(field.Data, CultureInfo.InvariantCulture); + + wixRow.AddChild(data); + } + + customTable.AddChild(wixRow); + } + + this.core.RootElement.AddChild(customTable); + } + } + + /// + /// Decompile the CreateFolder table. + /// + /// The table to decompile. + private void DecompileCreateFolderTable(Table table) + { + foreach (Row row in table.Rows) + { + Wix.CreateFolder createFolder = new Wix.CreateFolder(); + + createFolder.Directory = Convert.ToString(row[0]); + + Wix.Component component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[1])); + if (null != component) + { + component.AddChild(createFolder); + } + else + { + this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[1]), "Component")); + } + this.core.IndexElement(row, createFolder); + } + } + + /// + /// Decompile the CustomAction table. + /// + /// The table to decompile. + private void DecompileCustomActionTable(Table table) + { + foreach (Row row in table.Rows) + { + Wix.CustomAction customAction = new Wix.CustomAction(); + + customAction.Id = Convert.ToString(row[0]); + + int type = Convert.ToInt32(row[1]); + + if (MsiInterop.MsidbCustomActionTypeHideTarget == (type & MsiInterop.MsidbCustomActionTypeHideTarget)) + { + customAction.HideTarget = Wix.YesNoType.yes; + } + + if (MsiInterop.MsidbCustomActionTypeNoImpersonate == (type & MsiInterop.MsidbCustomActionTypeNoImpersonate)) + { + customAction.Impersonate = Wix.YesNoType.no; + } + + if (MsiInterop.MsidbCustomActionTypeTSAware == (type & MsiInterop.MsidbCustomActionTypeTSAware)) + { + customAction.TerminalServerAware = Wix.YesNoType.yes; + } + + if (MsiInterop.MsidbCustomActionType64BitScript == (type & MsiInterop.MsidbCustomActionType64BitScript)) + { + customAction.Win64 = Wix.YesNoType.yes; + } + + switch (type & MsiInterop.MsidbCustomActionTypeExecuteBits) + { + case 0: + // this is the default value + break; + case MsiInterop.MsidbCustomActionTypeFirstSequence: + customAction.Execute = Wix.CustomAction.ExecuteType.firstSequence; + break; + case MsiInterop.MsidbCustomActionTypeOncePerProcess: + customAction.Execute = Wix.CustomAction.ExecuteType.oncePerProcess; + break; + case MsiInterop.MsidbCustomActionTypeClientRepeat: + customAction.Execute = Wix.CustomAction.ExecuteType.secondSequence; + break; + case MsiInterop.MsidbCustomActionTypeInScript: + customAction.Execute = Wix.CustomAction.ExecuteType.deferred; + break; + case MsiInterop.MsidbCustomActionTypeInScript + MsiInterop.MsidbCustomActionTypeRollback: + customAction.Execute = Wix.CustomAction.ExecuteType.rollback; + break; + case MsiInterop.MsidbCustomActionTypeInScript + MsiInterop.MsidbCustomActionTypeCommit: + customAction.Execute = Wix.CustomAction.ExecuteType.commit; + break; + default: + this.core.OnMessage(WixWarnings.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[1].Column.Name, row[1])); + break; + } + + switch (type & MsiInterop.MsidbCustomActionTypeReturnBits) + { + case 0: + // this is the default value + break; + case MsiInterop.MsidbCustomActionTypeContinue: + customAction.Return = Wix.CustomAction.ReturnType.ignore; + break; + case MsiInterop.MsidbCustomActionTypeAsync: + customAction.Return = Wix.CustomAction.ReturnType.asyncWait; + break; + case MsiInterop.MsidbCustomActionTypeAsync + MsiInterop.MsidbCustomActionTypeContinue: + customAction.Return = Wix.CustomAction.ReturnType.asyncNoWait; + break; + default: + this.core.OnMessage(WixWarnings.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[1].Column.Name, row[1])); + break; + } + + int source = type & MsiInterop.MsidbCustomActionTypeSourceBits; + switch (source) + { + case MsiInterop.MsidbCustomActionTypeBinaryData: + customAction.BinaryKey = Convert.ToString(row[2]); + break; + case MsiInterop.MsidbCustomActionTypeSourceFile: + if (null != row[2]) + { + customAction.FileKey = Convert.ToString(row[2]); + } + break; + case MsiInterop.MsidbCustomActionTypeDirectory: + if (null != row[2]) + { + customAction.Directory = Convert.ToString(row[2]); + } + break; + case MsiInterop.MsidbCustomActionTypeProperty: + customAction.Property = Convert.ToString(row[2]); + break; + default: + this.core.OnMessage(WixWarnings.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[1].Column.Name, row[1])); + break; + } + + switch (type & MsiInterop.MsidbCustomActionTypeTargetBits) + { + case MsiInterop.MsidbCustomActionTypeDll: + customAction.DllEntry = Convert.ToString(row[3]); + break; + case MsiInterop.MsidbCustomActionTypeExe: + customAction.ExeCommand = Convert.ToString(row[3]); + break; + case MsiInterop.MsidbCustomActionTypeTextData: + if (MsiInterop.MsidbCustomActionTypeSourceFile == source) + { + customAction.Error = Convert.ToString(row[3]); + } + else + { + customAction.Value = Convert.ToString(row[3]); + } + break; + case MsiInterop.MsidbCustomActionTypeJScript: + if (MsiInterop.MsidbCustomActionTypeDirectory == source) + { + customAction.Script = Wix.CustomAction.ScriptType.jscript; + customAction.Content = Convert.ToString(row[3]); + } + else + { + customAction.JScriptCall = Convert.ToString(row[3]); + } + break; + case MsiInterop.MsidbCustomActionTypeVBScript: + if (MsiInterop.MsidbCustomActionTypeDirectory == source) + { + customAction.Script = Wix.CustomAction.ScriptType.vbscript; + customAction.Content = Convert.ToString(row[3]); + } + else + { + customAction.VBScriptCall = Convert.ToString(row[3]); + } + break; + case MsiInterop.MsidbCustomActionTypeInstall: + this.core.OnMessage(WixWarnings.NestedInstall(row.SourceLineNumbers, table.Name, row.Fields[1].Column.Name, row[1])); + continue; + default: + this.core.OnMessage(WixWarnings.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[1].Column.Name, row[1])); + break; + } + + int extype = 4 < row.Fields.Length && null != row[4] ? Convert.ToInt32(row[4]) : 0; + if (MsiInterop.MsidbCustomActionTypePatchUninstall == (extype & MsiInterop.MsidbCustomActionTypePatchUninstall)) + { + customAction.PatchUninstall = Wix.YesNoType.yes; + } + + this.core.RootElement.AddChild(customAction); + this.core.IndexElement(row, customAction); + } + } + + /// + /// Decompile the CompLocator table. + /// + /// The table to decompile. + private void DecompileCompLocatorTable(Table table) + { + foreach (Row row in table.Rows) + { + Wix.ComponentSearch componentSearch = new Wix.ComponentSearch(); + + componentSearch.Id = Convert.ToString(row[0]); + + componentSearch.Guid = Convert.ToString(row[1]); + + if (null != row[2]) + { + switch (Convert.ToInt32(row[2])) + { + case MsiInterop.MsidbLocatorTypeDirectory: + componentSearch.Type = Wix.ComponentSearch.TypeType.directory; + break; + case MsiInterop.MsidbLocatorTypeFileName: + // this is the default value + break; + default: + this.core.OnMessage(WixWarnings.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[2].Column.Name, row[2])); + break; + } + } + + this.core.IndexElement(row, componentSearch); + } + } + + /// + /// Decompile the Complus table. + /// + /// The table to decompile. + private void DecompileComplusTable(Table table) + { + foreach (Row row in table.Rows) + { + if (null != row[1]) + { + Wix.Component component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[0])); + + if (null != component) + { + component.ComPlusFlags = Convert.ToInt32(row[1]); + } + else + { + this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[0]), "Component")); + } + } + } + } + + /// + /// Decompile the Component table. + /// + /// The table to decompile. + private void DecompileComponentTable(Table table) + { + foreach (Row row in table.Rows) + { + Wix.Component component = new Wix.Component(); + + component.Id = Convert.ToString(row[0]); + + component.Guid = Convert.ToString(row[1]); + + int attributes = Convert.ToInt32(row[3]); + + if (MsiInterop.MsidbComponentAttributesSourceOnly == (attributes & MsiInterop.MsidbComponentAttributesSourceOnly)) + { + component.Location = Wix.Component.LocationType.source; + } + else if (MsiInterop.MsidbComponentAttributesOptional == (attributes & MsiInterop.MsidbComponentAttributesOptional)) + { + component.Location = Wix.Component.LocationType.either; + } + + if (MsiInterop.MsidbComponentAttributesSharedDllRefCount == (attributes & MsiInterop.MsidbComponentAttributesSharedDllRefCount)) + { + component.SharedDllRefCount = Wix.YesNoType.yes; + } + + if (MsiInterop.MsidbComponentAttributesPermanent == (attributes & MsiInterop.MsidbComponentAttributesPermanent)) + { + component.Permanent = Wix.YesNoType.yes; + } + + if (MsiInterop.MsidbComponentAttributesTransitive == (attributes & MsiInterop.MsidbComponentAttributesTransitive)) + { + component.Transitive = Wix.YesNoType.yes; + } + + if (MsiInterop.MsidbComponentAttributesNeverOverwrite == (attributes & MsiInterop.MsidbComponentAttributesNeverOverwrite)) + { + component.NeverOverwrite = Wix.YesNoType.yes; + } + + if (MsiInterop.MsidbComponentAttributes64bit == (attributes & MsiInterop.MsidbComponentAttributes64bit)) + { + component.Win64 = Wix.YesNoType.yes; + } + + if (MsiInterop.MsidbComponentAttributesDisableRegistryReflection == (attributes & MsiInterop.MsidbComponentAttributesDisableRegistryReflection)) + { + component.DisableRegistryReflection = Wix.YesNoType.yes; + } + + if (MsiInterop.MsidbComponentAttributesUninstallOnSupersedence == (attributes & MsiInterop.MsidbComponentAttributesUninstallOnSupersedence)) + { + component.UninstallWhenSuperseded = Wix.YesNoType.yes; + } + + if (MsiInterop.MsidbComponentAttributesShared == (attributes & MsiInterop.MsidbComponentAttributesShared)) + { + component.Shared = Wix.YesNoType.yes; + } + + if (null != row[4]) + { + Wix.Condition condition = new Wix.Condition(); + + condition.Content = Convert.ToString(row[4]); + + component.AddChild(condition); + } + + Wix.Directory directory = (Wix.Directory)this.core.GetIndexedElement("Directory", Convert.ToString(row[2])); + if (null != directory) + { + directory.AddChild(component); + } + else + { + this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Directory_", Convert.ToString(row[2]), "Directory")); + } + this.core.IndexElement(row, component); + } + } + + /// + /// Decompile the Condition table. + /// + /// The table to decompile. + private void DecompileConditionTable(Table table) + { + foreach (Row row in table.Rows) + { + Wix.Condition condition = new Wix.Condition(); + + condition.Level = Convert.ToInt32(row[1]); + + if (null != row[2]) + { + condition.Content = Convert.ToString(row[2]); + } + + Wix.Feature feature = (Wix.Feature)this.core.GetIndexedElement("Feature", Convert.ToString(row[0])); + if (null != feature) + { + feature.AddChild(condition); + } + else + { + this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Feature_", Convert.ToString(row[0]), "Feature")); + } + } + } + + /// + /// Decompile the Dialog table. + /// + /// The table to decompile. + private void DecompileDialogTable(Table table) + { + foreach (Row row in table.Rows) + { + Wix.Dialog dialog = new Wix.Dialog(); + + dialog.Id = Convert.ToString(row[0]); + + dialog.X = Convert.ToInt32(row[1]); + + dialog.Y = Convert.ToInt32(row[2]); + + dialog.Width = Convert.ToInt32(row[3]); + + dialog.Height = Convert.ToInt32(row[4]); + + if (null != row[5]) + { + int attributes = Convert.ToInt32(row[5]); + + if (0 == (attributes & MsiInterop.MsidbDialogAttributesVisible)) + { + dialog.Hidden = Wix.YesNoType.yes; + } + + if (0 == (attributes & MsiInterop.MsidbDialogAttributesModal)) + { + dialog.Modeless = Wix.YesNoType.yes; + } + + if (0 == (attributes & MsiInterop.MsidbDialogAttributesMinimize)) + { + dialog.NoMinimize = Wix.YesNoType.yes; + } + + if (MsiInterop.MsidbDialogAttributesSysModal == (attributes & MsiInterop.MsidbDialogAttributesSysModal)) + { + dialog.SystemModal = Wix.YesNoType.yes; + } + + if (MsiInterop.MsidbDialogAttributesKeepModeless == (attributes & MsiInterop.MsidbDialogAttributesKeepModeless)) + { + dialog.KeepModeless = Wix.YesNoType.yes; + } + + if (MsiInterop.MsidbDialogAttributesTrackDiskSpace == (attributes & MsiInterop.MsidbDialogAttributesTrackDiskSpace)) + { + dialog.TrackDiskSpace = Wix.YesNoType.yes; + } + + if (MsiInterop.MsidbDialogAttributesUseCustomPalette == (attributes & MsiInterop.MsidbDialogAttributesUseCustomPalette)) + { + dialog.CustomPalette = Wix.YesNoType.yes; + } + + if (MsiInterop.MsidbDialogAttributesRTLRO == (attributes & MsiInterop.MsidbDialogAttributesRTLRO)) + { + dialog.RightToLeft = Wix.YesNoType.yes; + } + + if (MsiInterop.MsidbDialogAttributesRightAligned == (attributes & MsiInterop.MsidbDialogAttributesRightAligned)) + { + dialog.RightAligned = Wix.YesNoType.yes; + } + + if (MsiInterop.MsidbDialogAttributesLeftScroll == (attributes & MsiInterop.MsidbDialogAttributesLeftScroll)) + { + dialog.LeftScroll = Wix.YesNoType.yes; + } + + if (MsiInterop.MsidbDialogAttributesError == (attributes & MsiInterop.MsidbDialogAttributesError)) + { + dialog.ErrorDialog = Wix.YesNoType.yes; + } + } + + if (null != row[6]) + { + dialog.Title = Convert.ToString(row[6]); + } + + this.core.UIElement.AddChild(dialog); + this.core.IndexElement(row, dialog); + } + } + + /// + /// Decompile the Directory table. + /// + /// The table to decompile. + private void DecompileDirectoryTable(Table table) + { + foreach (Row row in table.Rows) + { + Wix.Directory directory = new Wix.Directory(); + + directory.Id = Convert.ToString(row[0]); + + string[] names = Common.GetNames(Convert.ToString(row[2])); + + if (String.Equals(directory.Id, "TARGETDIR", StringComparison.Ordinal) && !String.Equals(names[0], "SourceDir", StringComparison.Ordinal)) + { + this.core.OnMessage(WixWarnings.TargetDirCorrectedDefaultDir()); + directory.Name = "SourceDir"; + } + else + { + if (null != names[0] && "." != names[0]) + { + if (null != names[1]) + { + directory.ShortName = names[0]; + } + else + { + directory.Name = names[0]; + } + } + + if (null != names[1]) + { + directory.Name = names[1]; + } + } + + if (null != names[2]) + { + if (null != names[3]) + { + directory.ShortSourceName = names[2]; + } + else + { + directory.SourceName = names[2]; + } + } + + if (null != names[3]) + { + directory.SourceName = names[3]; + } + + this.core.IndexElement(row, directory); + } + + // nest the directories + foreach (Row row in table.Rows) + { + Wix.Directory directory = (Wix.Directory)this.core.GetIndexedElement(row); + + if (null == row[1]) + { + this.core.RootElement.AddChild(directory); + } + else + { + Wix.Directory parentDirectory = (Wix.Directory)this.core.GetIndexedElement("Directory", Convert.ToString(row[1])); + + if (null == parentDirectory) + { + this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Directory_Parent", Convert.ToString(row[1]), "Directory")); + } + else if (parentDirectory == directory) // another way to specify a root directory + { + this.core.RootElement.AddChild(directory); + } + else + { + parentDirectory.AddChild(directory); + } + } + } + } + + /// + /// Decompile the DrLocator table. + /// + /// The table to decompile. + private void DecompileDrLocatorTable(Table table) + { + foreach (Row row in table.Rows) + { + Wix.DirectorySearch directorySearch = new Wix.DirectorySearch(); + + directorySearch.Id = Convert.ToString(row[0]); + + if (null != row[2]) + { + directorySearch.Path = Convert.ToString(row[2]); + } + + if (null != row[3]) + { + directorySearch.Depth = Convert.ToInt32(row[3]); + } + + this.core.IndexElement(row, directorySearch); + } + } + + /// + /// Decompile the DuplicateFile table. + /// + /// The table to decompile. + private void DecompileDuplicateFileTable(Table table) + { + foreach (Row row in table.Rows) + { + Wix.CopyFile copyFile = new Wix.CopyFile(); + + copyFile.Id = Convert.ToString(row[0]); + + copyFile.FileId = Convert.ToString(row[2]); + + if (null != row[3]) + { + string[] names = Common.GetNames(Convert.ToString(row[3])); + if (null != names[0] && null != names[1]) + { + copyFile.DestinationShortName = names[0]; + copyFile.DestinationName = names[1]; + } + else if (null != names[0]) + { + copyFile.DestinationName = names[0]; + } + } + + // destination directory/property is set in FinalizeDuplicateMoveFileTables + + Wix.Component component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[1])); + if (null != component) + { + component.AddChild(copyFile); + } + else + { + this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[1]), "Component")); + } + this.core.IndexElement(row, copyFile); + } + } + + /// + /// Decompile the Environment table. + /// + /// The table to decompile. + private void DecompileEnvironmentTable(Table table) + { + foreach (Row row in table.Rows) + { + Wix.Environment environment = new Wix.Environment(); + + environment.Id = Convert.ToString(row[0]); + + bool done = false; + bool permanent = true; + string name = Convert.ToString(row[1]); + for (int i = 0; i < name.Length && !done; i++) + { + switch (name[i]) + { + case '=': + environment.Action = Wix.Environment.ActionType.set; + break; + case '+': + environment.Action = Wix.Environment.ActionType.create; + break; + case '-': + permanent = false; + break; + case '!': + environment.Action = Wix.Environment.ActionType.remove; + break; + case '*': + environment.System = Wix.YesNoType.yes; + break; + default: + environment.Name = name.Substring(i); + done = true; + break; + } + } + + if (permanent) + { + environment.Permanent = Wix.YesNoType.yes; + } + + if (null != row[2]) + { + string value = Convert.ToString(row[2]); + + if (value.StartsWith("[~]", StringComparison.Ordinal)) + { + environment.Part = Wix.Environment.PartType.last; + + if (3 < value.Length) + { + environment.Separator = value.Substring(3, 1); + environment.Value = value.Substring(4); + } + } + else if (value.EndsWith("[~]", StringComparison.Ordinal)) + { + environment.Part = Wix.Environment.PartType.first; + + if (3 < value.Length) + { + environment.Separator = value.Substring(value.Length - 4, 1); + environment.Value = value.Substring(0, value.Length - 4); + } + } + else + { + environment.Value = value; + } + } + + Wix.Component component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[3])); + if (null != component) + { + component.AddChild(environment); + } + else + { + this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[3]), "Component")); + } + } + } + + /// + /// Decompile the Error table. + /// + /// The table to decompile. + private void DecompileErrorTable(Table table) + { + foreach (Row row in table.Rows) + { + Wix.Error error = new Wix.Error(); + + error.Id = Convert.ToInt32(row[0]); + + error.Content = Convert.ToString(row[1]); + + this.core.UIElement.AddChild(error); + } + } + + /// + /// Decompile the EventMapping table. + /// + /// The table to decompile. + private void DecompileEventMappingTable(Table table) + { + foreach (Row row in table.Rows) + { + Wix.Subscribe subscribe = new Wix.Subscribe(); + + subscribe.Event = Convert.ToString(row[2]); + + subscribe.Attribute = Convert.ToString(row[3]); + + Wix.Control control = (Wix.Control)this.core.GetIndexedElement("Control", Convert.ToString(row[0]), Convert.ToString(row[1])); + if (null != control) + { + control.AddChild(subscribe); + } + else + { + this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Dialog_", Convert.ToString(row[0]), "Control_", Convert.ToString(row[1]), "Control")); + } + } + } + + /// + /// Decompile the Extension table. + /// + /// The table to decompile. + private void DecompileExtensionTable(Table table) + { + foreach (Row row in table.Rows) + { + Wix.Extension extension = new Wix.Extension(); + + extension.Advertise = Wix.YesNoType.yes; + + extension.Id = Convert.ToString(row[0]); + + if (null != row[3]) + { + Wix.MIME mime = (Wix.MIME)this.core.GetIndexedElement("MIME", Convert.ToString(row[3])); + + if (null != mime) + { + mime.Default = Wix.YesNoType.yes; + } + else + { + this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "MIME_", Convert.ToString(row[3]), "MIME")); + } + } + + if (null != row[2]) + { + Wix.ProgId progId = (Wix.ProgId)this.core.GetIndexedElement("ProgId", Convert.ToString(row[2])); + + if (null != progId) + { + progId.AddChild(extension); + } + else + { + this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "ProgId_", Convert.ToString(row[2]), "ProgId")); + } + } + else + { + Wix.Component component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[1])); + + if (null != component) + { + component.AddChild(extension); + } + else + { + this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[1]), "Component")); + } + } + + this.core.IndexElement(row, extension); + } + } + + /// + /// Decompile the ExternalFiles table. + /// + /// The table to decompile. + private void DecompileExternalFilesTable(Table table) + { + foreach (Row row in table.Rows) + { + Wix.ExternalFile externalFile = new Wix.ExternalFile(); + + externalFile.File = Convert.ToString(row[1]); + + externalFile.Source = Convert.ToString(row[2]); + + if (null != row[3]) + { + string[] symbolPaths = (Convert.ToString(row[3])).Split(';'); + + foreach (string symbolPathString in symbolPaths) + { + Wix.SymbolPath symbolPath = new Wix.SymbolPath(); + + symbolPath.Path = symbolPathString; + + externalFile.AddChild(symbolPath); + } + } + + if (null != row[4] && null != row[5]) + { + string[] ignoreOffsets = (Convert.ToString(row[4])).Split(','); + string[] ignoreLengths = (Convert.ToString(row[5])).Split(','); + + if (ignoreOffsets.Length == ignoreLengths.Length) + { + for (int i = 0; i < ignoreOffsets.Length; i++) + { + Wix.IgnoreRange ignoreRange = new Wix.IgnoreRange(); + + if (ignoreOffsets[i].StartsWith("0x", StringComparison.Ordinal)) + { + ignoreRange.Offset = Convert.ToInt32(ignoreOffsets[i].Substring(2), 16); + } + else + { + ignoreRange.Offset = Convert.ToInt32(ignoreOffsets[i], CultureInfo.InvariantCulture); + } + + if (ignoreLengths[i].StartsWith("0x", StringComparison.Ordinal)) + { + ignoreRange.Length = Convert.ToInt32(ignoreLengths[i].Substring(2), 16); + } + else + { + ignoreRange.Length = Convert.ToInt32(ignoreLengths[i], CultureInfo.InvariantCulture); + } + + externalFile.AddChild(ignoreRange); + } + } + else + { + // TODO: warn + } + } + else if (null != row[4] || null != row[5]) + { + // TODO: warn about mismatch between columns + } + + // the RetainOffsets column is handled in FinalizeFamilyFileRangesTable + + if (null != row[7]) + { + externalFile.Order = Convert.ToInt32(row[7]); + } + + Wix.Family family = (Wix.Family)this.core.GetIndexedElement("ImageFamilies", Convert.ToString(row[0])); + if (null != family) + { + family.AddChild(externalFile); + } + else + { + this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Family", Convert.ToString(row[0]), "ImageFamilies")); + } + this.core.IndexElement(row, externalFile); + } + } + + /// + /// Decompile the Feature table. + /// + /// The table to decompile. + private void DecompileFeatureTable(Table table) + { + SortedList sortedFeatures = new SortedList(); + + foreach (Row row in table.Rows) + { + Wix.Feature feature = new Wix.Feature(); + + feature.Id = Convert.ToString(row[0]); + + if (null != row[2]) + { + feature.Title = Convert.ToString(row[2]); + } + + if (null != row[3]) + { + feature.Description = Convert.ToString(row[3]); + } + + if (null == row[4]) + { + feature.Display = "hidden"; + } + else + { + int display = Convert.ToInt32(row[4]); + + if (0 == display) + { + feature.Display = "hidden"; + } + else if (1 == display % 2) + { + feature.Display = "expand"; + } + } + + feature.Level = Convert.ToInt32(row[5]); + + if (null != row[6]) + { + feature.ConfigurableDirectory = Convert.ToString(row[6]); + } + + int attributes = Convert.ToInt32(row[7]); + + if (MsiInterop.MsidbFeatureAttributesFavorSource == (attributes & MsiInterop.MsidbFeatureAttributesFavorSource) && MsiInterop.MsidbFeatureAttributesFollowParent == (attributes & MsiInterop.MsidbFeatureAttributesFollowParent)) + { + // TODO: display a warning for setting favor local and follow parent together + } + else if (MsiInterop.MsidbFeatureAttributesFavorSource == (attributes & MsiInterop.MsidbFeatureAttributesFavorSource)) + { + feature.InstallDefault = Wix.Feature.InstallDefaultType.source; + } + else if (MsiInterop.MsidbFeatureAttributesFollowParent == (attributes & MsiInterop.MsidbFeatureAttributesFollowParent)) + { + feature.InstallDefault = Wix.Feature.InstallDefaultType.followParent; + } + + if (MsiInterop.MsidbFeatureAttributesFavorAdvertise == (attributes & MsiInterop.MsidbFeatureAttributesFavorAdvertise)) + { + feature.TypicalDefault = Wix.Feature.TypicalDefaultType.advertise; + } + + if (MsiInterop.MsidbFeatureAttributesDisallowAdvertise == (attributes & MsiInterop.MsidbFeatureAttributesDisallowAdvertise) && + MsiInterop.MsidbFeatureAttributesNoUnsupportedAdvertise == (attributes & MsiInterop.MsidbFeatureAttributesNoUnsupportedAdvertise)) + { + this.core.OnMessage(WixWarnings.InvalidAttributeCombination(row.SourceLineNumbers, "msidbFeatureAttributesDisallowAdvertise", "msidbFeatureAttributesNoUnsupportedAdvertise", "Feature.AllowAdvertiseType", "no")); + feature.AllowAdvertise = Wix.Feature.AllowAdvertiseType.no; + } + else if (MsiInterop.MsidbFeatureAttributesDisallowAdvertise == (attributes & MsiInterop.MsidbFeatureAttributesDisallowAdvertise)) + { + feature.AllowAdvertise = Wix.Feature.AllowAdvertiseType.no; + } + else if (MsiInterop.MsidbFeatureAttributesNoUnsupportedAdvertise == (attributes & MsiInterop.MsidbFeatureAttributesNoUnsupportedAdvertise)) + { + feature.AllowAdvertise = Wix.Feature.AllowAdvertiseType.system; + } + + if (MsiInterop.MsidbFeatureAttributesUIDisallowAbsent == (attributes & MsiInterop.MsidbFeatureAttributesUIDisallowAbsent)) + { + feature.Absent = Wix.Feature.AbsentType.disallow; + } + + this.core.IndexElement(row, feature); + + // sort the features by their display column (and append the identifier to ensure unique keys) + sortedFeatures.Add(String.Format(CultureInfo.InvariantCulture, "{0:00000}|{1}", Convert.ToInt32(row[4], CultureInfo.InvariantCulture), row[0]), row); + } + + // nest the features + foreach (Row row in sortedFeatures.Values) + { + Wix.Feature feature = (Wix.Feature)this.core.GetIndexedElement("Feature", Convert.ToString(row[0])); + + if (null == row[1]) + { + this.core.RootElement.AddChild(feature); + } + else + { + Wix.Feature parentFeature = (Wix.Feature)this.core.GetIndexedElement("Feature", Convert.ToString(row[1])); + + if (null == parentFeature) + { + this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Feature_Parent", Convert.ToString(row[1]), "Feature")); + } + else if (parentFeature == feature) + { + // TODO: display a warning about self-nesting + } + else + { + parentFeature.AddChild(feature); + } + } + } + } + + /// + /// Decompile the FeatureComponents table. + /// + /// The table to decompile. + private void DecompileFeatureComponentsTable(Table table) + { + foreach (Row row in table.Rows) + { + Wix.ComponentRef componentRef = new Wix.ComponentRef(); + + componentRef.Id = Convert.ToString(row[1]); + + Wix.Feature parentFeature = (Wix.Feature)this.core.GetIndexedElement("Feature", Convert.ToString(row[0])); + if (null != parentFeature) + { + parentFeature.AddChild(componentRef); + } + else + { + this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Feature_", Convert.ToString(row[0]), "Feature")); + } + this.core.IndexElement(row, componentRef); + } + } + + /// + /// Decompile the File table. + /// + /// The table to decompile. + private void DecompileFileTable(Table table) + { + foreach (FileRow fileRow in table.Rows) + { + Wix.File file = new Wix.File(); + + file.Id = fileRow.File; + + string[] names = Common.GetNames(fileRow.FileName); + if (null != names[0] && null != names[1]) + { + file.ShortName = names[0]; + file.Name = names[1]; + } + else if (null != names[0]) + { + file.Name = names[0]; + } + + if (null != fileRow.Version && 0 < fileRow.Version.Length) + { + if (!Char.IsDigit(fileRow.Version[0])) + { + file.CompanionFile = fileRow.Version; + } + } + + if (MsiInterop.MsidbFileAttributesReadOnly == (fileRow.Attributes & MsiInterop.MsidbFileAttributesReadOnly)) + { + file.ReadOnly = Wix.YesNoType.yes; + } + + if (MsiInterop.MsidbFileAttributesHidden == (fileRow.Attributes & MsiInterop.MsidbFileAttributesHidden)) + { + file.Hidden = Wix.YesNoType.yes; + } + + if (MsiInterop.MsidbFileAttributesSystem == (fileRow.Attributes & MsiInterop.MsidbFileAttributesSystem)) + { + file.System = Wix.YesNoType.yes; + } + + if (MsiInterop.MsidbFileAttributesVital != (fileRow.Attributes & MsiInterop.MsidbFileAttributesVital)) + { + file.Vital = Wix.YesNoType.no; + } + + if (MsiInterop.MsidbFileAttributesChecksum == (fileRow.Attributes & MsiInterop.MsidbFileAttributesChecksum)) + { + file.Checksum = Wix.YesNoType.yes; + } + + if (MsiInterop.MsidbFileAttributesNoncompressed == (fileRow.Attributes & MsiInterop.MsidbFileAttributesNoncompressed) && + MsiInterop.MsidbFileAttributesCompressed == (fileRow.Attributes & MsiInterop.MsidbFileAttributesCompressed)) + { + // TODO: error + } + else if (MsiInterop.MsidbFileAttributesNoncompressed == (fileRow.Attributes & MsiInterop.MsidbFileAttributesNoncompressed)) + { + file.Compressed = Wix.YesNoDefaultType.no; + } + else if (MsiInterop.MsidbFileAttributesCompressed == (fileRow.Attributes & MsiInterop.MsidbFileAttributesCompressed)) + { + file.Compressed = Wix.YesNoDefaultType.yes; + } + + this.core.IndexElement(fileRow, file); + } + } + + /// + /// Decompile the FileSFPCatalog table. + /// + /// The table to decompile. + private void DecompileFileSFPCatalogTable(Table table) + { + foreach (Row row in table.Rows) + { + Wix.SFPFile sfpFile = new Wix.SFPFile(); + + sfpFile.Id = Convert.ToString(row[0]); + + Wix.SFPCatalog sfpCatalog = (Wix.SFPCatalog)this.core.GetIndexedElement("SFPCatalog", Convert.ToString(row[1])); + if (null != sfpCatalog) + { + sfpCatalog.AddChild(sfpFile); + } + else + { + this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "SFPCatalog_", Convert.ToString(row[1]), "SFPCatalog")); + } + } + } + + /// + /// Decompile the Font table. + /// + /// The table to decompile. + private void DecompileFontTable(Table table) + { + foreach (Row row in table.Rows) + { + Wix.File file = (Wix.File)this.core.GetIndexedElement("File", Convert.ToString(row[0])); + + if (null != file) + { + if (null != row[1]) + { + file.FontTitle = Convert.ToString(row[1]); + } + else + { + file.TrueType = Wix.YesNoType.yes; + } + } + else + { + this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "File_", Convert.ToString(row[0]), "File")); + } + } + } + + /// + /// Decompile the Icon table. + /// + /// The table to decompile. + private void DecompileIconTable(Table table) + { + foreach (Row row in table.Rows) + { + Wix.Icon icon = new Wix.Icon(); + + icon.Id = Convert.ToString(row[0]); + + icon.SourceFile = Convert.ToString(row[1]); + + this.core.RootElement.AddChild(icon); + } + } + + /// + /// Decompile the ImageFamilies table. + /// + /// The table to decompile. + private void DecompileImageFamiliesTable(Table table) + { + foreach (Row row in table.Rows) + { + Wix.Family family = new Wix.Family(); + + family.Name = Convert.ToString(row[0]); + + if (null != row[1]) + { + family.MediaSrcProp = Convert.ToString(row[1]); + } + + if (null != row[2]) + { + family.DiskId = Convert.ToString(Convert.ToInt32(row[2])); + } + + if (null != row[3]) + { + family.SequenceStart = Convert.ToInt32(row[3]); + } + + if (null != row[4]) + { + family.DiskPrompt = Convert.ToString(row[4]); + } + + if (null != row[5]) + { + family.VolumeLabel = Convert.ToString(row[5]); + } + + this.core.RootElement.AddChild(family); + this.core.IndexElement(row, family); + } + } + + /// + /// Decompile the IniFile table. + /// + /// The table to decompile. + private void DecompileIniFileTable(Table table) + { + foreach (Row row in table.Rows) + { + Wix.IniFile iniFile = new Wix.IniFile(); + + iniFile.Id = Convert.ToString(row[0]); + + string[] names = Common.GetNames(Convert.ToString(row[1])); + + if (null != names[0]) + { + if (null == names[1]) + { + iniFile.Name = names[0]; + } + else + { + iniFile.ShortName = names[0]; + } + } + + if (null != names[1]) + { + iniFile.Name = names[1]; + } + + if (null != row[2]) + { + iniFile.Directory = Convert.ToString(row[2]); + } + + iniFile.Section = Convert.ToString(row[3]); + + iniFile.Key = Convert.ToString(row[4]); + + iniFile.Value = Convert.ToString(row[5]); + + switch (Convert.ToInt32(row[6])) + { + case MsiInterop.MsidbIniFileActionAddLine: + iniFile.Action = Wix.IniFile.ActionType.addLine; + break; + case MsiInterop.MsidbIniFileActionCreateLine: + iniFile.Action = Wix.IniFile.ActionType.createLine; + break; + case MsiInterop.MsidbIniFileActionAddTag: + iniFile.Action = Wix.IniFile.ActionType.addTag; + break; + default: + this.core.OnMessage(WixWarnings.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[6].Column.Name, row[6])); + break; + } + + Wix.Component component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[7])); + if (null != component) + { + component.AddChild(iniFile); + } + else + { + this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[7]), "Component")); + } + } + } + + /// + /// Decompile the IniLocator table. + /// + /// The table to decompile. + private void DecompileIniLocatorTable(Table table) + { + foreach (Row row in table.Rows) + { + Wix.IniFileSearch iniFileSearch = new Wix.IniFileSearch(); + + iniFileSearch.Id = Convert.ToString(row[0]); + + string[] names = Common.GetNames(Convert.ToString(row[1])); + if (null != names[0] && null != names[1]) + { + iniFileSearch.ShortName = names[0]; + iniFileSearch.Name = names[1]; + } + else if (null != names[0]) + { + iniFileSearch.Name = names[0]; + } + + iniFileSearch.Section = Convert.ToString(row[2]); + + iniFileSearch.Key = Convert.ToString(row[3]); + + if (null != row[4]) + { + int field = Convert.ToInt32(row[4]); + + if (0 != field) + { + iniFileSearch.Field = field; + } + } + + if (null != row[5]) + { + switch (Convert.ToInt32(row[5])) + { + case MsiInterop.MsidbLocatorTypeDirectory: + iniFileSearch.Type = Wix.IniFileSearch.TypeType.directory; + break; + case MsiInterop.MsidbLocatorTypeFileName: + // this is the default value + break; + case MsiInterop.MsidbLocatorTypeRawValue: + iniFileSearch.Type = Wix.IniFileSearch.TypeType.raw; + break; + default: + this.core.OnMessage(WixWarnings.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[5].Column.Name, row[5])); + break; + } + } + + this.core.IndexElement(row, iniFileSearch); + } + } + + /// + /// Decompile the IsolatedComponent table. + /// + /// The table to decompile. + private void DecompileIsolatedComponentTable(Table table) + { + foreach (Row row in table.Rows) + { + Wix.IsolateComponent isolateComponent = new Wix.IsolateComponent(); + + isolateComponent.Shared = Convert.ToString(row[0]); + + Wix.Component component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[1])); + if (null != component) + { + component.AddChild(isolateComponent); + } + else + { + this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[1]), "Component")); + } + } + } + + /// + /// Decompile the LaunchCondition table. + /// + /// The table to decompile. + private void DecompileLaunchConditionTable(Table table) + { + foreach (Row row in table.Rows) + { + if (Compiler.DowngradePreventedCondition == Convert.ToString(row[0]) || Compiler.UpgradePreventedCondition == Convert.ToString(row[0])) + { + continue; // MajorUpgrade rows processed in FinalizeUpgradeTable + } + + Wix.Condition condition = new Wix.Condition(); + + condition.Content = Convert.ToString(row[0]); + + condition.Message = Convert.ToString(row[1]); + + this.core.RootElement.AddChild(condition); + } + } + + /// + /// Decompile the ListBox table. + /// + /// The table to decompile. + private void DecompileListBoxTable(Table table) + { + Wix.ListBox listBox = null; + SortedList listBoxRows = new SortedList(); + + // sort the list boxes by their property and order + foreach (Row row in table.Rows) + { + listBoxRows.Add(String.Concat("{0}|{1:0000000000}", row[0], row[1]), row); + } + + foreach (Row row in listBoxRows.Values) + { + if (null == listBox || Convert.ToString(row[0]) != listBox.Property) + { + listBox = new Wix.ListBox(); + + listBox.Property = Convert.ToString(row[0]); + + this.core.UIElement.AddChild(listBox); + } + + Wix.ListItem listItem = new Wix.ListItem(); + + listItem.Value = Convert.ToString(row[2]); + + if (null != row[3]) + { + listItem.Text = Convert.ToString(row[3]); + } + + listBox.AddChild(listItem); + } + } + + /// + /// Decompile the ListView table. + /// + /// The table to decompile. + private void DecompileListViewTable(Table table) + { + Wix.ListView listView = null; + SortedList listViewRows = new SortedList(); + + // sort the list views by their property and order + foreach (Row row in table.Rows) + { + listViewRows.Add(String.Concat("{0}|{1:0000000000}", row[0], row[1]), row); + } + + foreach (Row row in listViewRows.Values) + { + if (null == listView || Convert.ToString(row[0]) != listView.Property) + { + listView = new Wix.ListView(); + + listView.Property = Convert.ToString(row[0]); + + this.core.UIElement.AddChild(listView); + } + + Wix.ListItem listItem = new Wix.ListItem(); + + listItem.Value = Convert.ToString(row[2]); + + if (null != row[3]) + { + listItem.Text = Convert.ToString(row[3]); + } + + if (null != row[4]) + { + listItem.Icon = Convert.ToString(row[4]); + } + + listView.AddChild(listItem); + } + } + + /// + /// Decompile the LockPermissions table. + /// + /// The table to decompile. + private void DecompileLockPermissionsTable(Table table) + { + foreach (Row row in table.Rows) + { + Wix.Permission permission = new Wix.Permission(); + string[] specialPermissions; + + switch (Convert.ToString(row[1])) + { + case "CreateFolder": + specialPermissions = Common.FolderPermissions; + break; + case "File": + specialPermissions = Common.FilePermissions; + break; + case "Registry": + specialPermissions = Common.RegistryPermissions; + break; + default: + this.core.OnMessage(WixWarnings.IllegalColumnValue(row.SourceLineNumbers, row.Table.Name, row.Fields[1].Column.Name, row[1])); + return; + } + + int permissionBits = Convert.ToInt32(row[4]); + for (int i = 0; i < 32; i++) + { + if (0 != ((permissionBits >> i) & 1)) + { + string name = null; + + if (specialPermissions.Length > i) + { + name = specialPermissions[i]; + } + else if (16 > i && specialPermissions.Length <= i) + { + name = "SpecificRightsAll"; + } + else if (28 > i && Common.StandardPermissions.Length > (i - 16)) + { + name = Common.StandardPermissions[i - 16]; + } + else if (0 <= (i - 28) && Common.GenericPermissions.Length > (i - 28)) + { + name = Common.GenericPermissions[i - 28]; + } + + if (null == name) + { + this.core.OnMessage(WixWarnings.UnknownPermission(row.SourceLineNumbers, row.Table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), i)); + } + else + { + switch (name) + { + case "Append": + permission.Append = Wix.YesNoType.yes; + break; + case "ChangePermission": + permission.ChangePermission = Wix.YesNoType.yes; + break; + case "CreateChild": + permission.CreateChild = Wix.YesNoType.yes; + break; + case "CreateFile": + permission.CreateFile = Wix.YesNoType.yes; + break; + case "CreateLink": + permission.CreateLink = Wix.YesNoType.yes; + break; + case "CreateSubkeys": + permission.CreateSubkeys = Wix.YesNoType.yes; + break; + case "Delete": + permission.Delete = Wix.YesNoType.yes; + break; + case "DeleteChild": + permission.DeleteChild = Wix.YesNoType.yes; + break; + case "EnumerateSubkeys": + permission.EnumerateSubkeys = Wix.YesNoType.yes; + break; + case "Execute": + permission.Execute = Wix.YesNoType.yes; + break; + case "FileAllRights": + permission.FileAllRights = Wix.YesNoType.yes; + break; + case "GenericAll": + permission.GenericAll = Wix.YesNoType.yes; + break; + case "GenericExecute": + permission.GenericExecute = Wix.YesNoType.yes; + break; + case "GenericRead": + permission.GenericRead = Wix.YesNoType.yes; + break; + case "GenericWrite": + permission.GenericWrite = Wix.YesNoType.yes; + break; + case "Notify": + permission.Notify = Wix.YesNoType.yes; + break; + case "Read": + permission.Read = Wix.YesNoType.yes; + break; + case "ReadAttributes": + permission.ReadAttributes = Wix.YesNoType.yes; + break; + case "ReadExtendedAttributes": + permission.ReadExtendedAttributes = Wix.YesNoType.yes; + break; + case "ReadPermission": + permission.ReadPermission = Wix.YesNoType.yes; + break; + case "SpecificRightsAll": + permission.SpecificRightsAll = Wix.YesNoType.yes; + break; + case "Synchronize": + permission.Synchronize = Wix.YesNoType.yes; + break; + case "TakeOwnership": + permission.TakeOwnership = Wix.YesNoType.yes; + break; + case "Traverse": + permission.Traverse = Wix.YesNoType.yes; + break; + case "Write": + permission.Write = Wix.YesNoType.yes; + break; + case "WriteAttributes": + permission.WriteAttributes = Wix.YesNoType.yes; + break; + case "WriteExtendedAttributes": + permission.WriteExtendedAttributes = Wix.YesNoType.yes; + break; + default: + throw new InvalidOperationException(String.Format(CultureInfo.CurrentUICulture, WixStrings.EXP_UnknownPermissionAttribute, name)); + } + } + } + } + + if (null != row[2]) + { + permission.Domain = Convert.ToString(row[2]); + } + + permission.User = Convert.ToString(row[3]); + + this.core.IndexElement(row, permission); + } + } + + /// + /// Decompile the Media table. + /// + /// The table to decompile. + private void DecompileMediaTable(Table table) + { + foreach (MediaRow mediaRow in table.Rows) + { + Wix.Media media = new Wix.Media(); + + media.Id = Convert.ToString(mediaRow.DiskId); + + if (null != mediaRow.DiskPrompt) + { + media.DiskPrompt = mediaRow.DiskPrompt; + } + + if (null != mediaRow.Cabinet) + { + string cabinet = mediaRow.Cabinet; + + if (cabinet.StartsWith("#", StringComparison.Ordinal)) + { + media.EmbedCab = Wix.YesNoType.yes; + cabinet = cabinet.Substring(1); + } + + media.Cabinet = cabinet; + } + + if (null != mediaRow.VolumeLabel) + { + media.VolumeLabel = mediaRow.VolumeLabel; + } + + this.core.RootElement.AddChild(media); + this.core.IndexElement(mediaRow, media); + } + } + + /// + /// Decompile the MIME table. + /// + /// The table to decompile. + private void DecompileMIMETable(Table table) + { + foreach (Row row in table.Rows) + { + Wix.MIME mime = new Wix.MIME(); + + mime.ContentType = Convert.ToString(row[0]); + + if (null != row[2]) + { + mime.Class = Convert.ToString(row[2]); + } + + this.core.IndexElement(row, mime); + } + } + + /// + /// Decompile the ModuleConfiguration table. + /// + /// The table to decompile. + private void DecompileModuleConfigurationTable(Table table) + { + foreach (Row row in table.Rows) + { + Wix.Configuration configuration = new Wix.Configuration(); + + configuration.Name = Convert.ToString(row[0]); + + switch (Convert.ToInt32(row[1])) + { + case 0: + configuration.Format = Wix.Configuration.FormatType.Text; + break; + case 1: + configuration.Format = Wix.Configuration.FormatType.Key; + break; + case 2: + configuration.Format = Wix.Configuration.FormatType.Integer; + break; + case 3: + configuration.Format = Wix.Configuration.FormatType.Bitfield; + break; + default: + this.core.OnMessage(WixWarnings.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[1].Column.Name, row[1])); + break; + } + + if (null != row[2]) + { + configuration.Type = Convert.ToString(row[2]); + } + + if (null != row[3]) + { + configuration.ContextData = Convert.ToString(row[3]); + } + + if (null != row[4]) + { + configuration.DefaultValue = Convert.ToString(row[4]); + } + + if (null != row[5]) + { + int attributes = Convert.ToInt32(row[5]); + + if (MsiInterop.MsidbMsmConfigurableOptionKeyNoOrphan == (attributes & MsiInterop.MsidbMsmConfigurableOptionKeyNoOrphan)) + { + configuration.KeyNoOrphan = Wix.YesNoType.yes; + } + + if (MsiInterop.MsidbMsmConfigurableOptionNonNullable == (attributes & MsiInterop.MsidbMsmConfigurableOptionNonNullable)) + { + configuration.NonNullable = Wix.YesNoType.yes; + } + + if (3 < attributes) + { + this.core.OnMessage(WixWarnings.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[5].Column.Name, row[5])); + } + } + + if (null != row[6]) + { + configuration.DisplayName = Convert.ToString(row[6]); + } + + if (null != row[7]) + { + configuration.Description = Convert.ToString(row[7]); + } + + if (null != row[8]) + { + configuration.HelpLocation = Convert.ToString(row[8]); + } + + if (null != row[9]) + { + configuration.HelpKeyword = Convert.ToString(row[9]); + } + + this.core.RootElement.AddChild(configuration); + } + } + + /// + /// Decompile the ModuleDependency table. + /// + /// The table to decompile. + private void DecompileModuleDependencyTable(Table table) + { + foreach (Row row in table.Rows) + { + Wix.Dependency dependency = new Wix.Dependency(); + + dependency.RequiredId = Convert.ToString(row[2]); + + dependency.RequiredLanguage = Convert.ToInt32(row[3], CultureInfo.InvariantCulture); + + if (null != row[4]) + { + dependency.RequiredVersion = Convert.ToString(row[4]); + } + + this.core.RootElement.AddChild(dependency); + } + } + + /// + /// Decompile the ModuleExclusion table. + /// + /// The table to decompile. + private void DecompileModuleExclusionTable(Table table) + { + foreach (Row row in table.Rows) + { + Wix.Exclusion exclusion = new Wix.Exclusion(); + + exclusion.ExcludedId = Convert.ToString(row[2]); + + int excludedLanguage = Convert.ToInt32(Convert.ToString(row[3]), CultureInfo.InvariantCulture); + if (0 < excludedLanguage) + { + exclusion.ExcludeLanguage = excludedLanguage; + } + else if (0 > excludedLanguage) + { + exclusion.ExcludeExceptLanguage = -excludedLanguage; + } + + if (null != row[4]) + { + exclusion.ExcludedMinVersion = Convert.ToString(row[4]); + } + + if (null != row[5]) + { + exclusion.ExcludedMinVersion = Convert.ToString(row[5]); + } + + this.core.RootElement.AddChild(exclusion); + } + } + + /// + /// Decompile the ModuleIgnoreTable table. + /// + /// The table to decompile. + private void DecompileModuleIgnoreTableTable(Table table) + { + foreach (Row row in table.Rows) + { + string tableName = Convert.ToString(row[0]); + + // the linker automatically adds a ModuleIgnoreTable row for some tables + if ("ModuleConfiguration" != tableName && "ModuleSubstitution" != tableName) + { + Wix.IgnoreTable ignoreTable = new Wix.IgnoreTable(); + + ignoreTable.Id = tableName; + + this.core.RootElement.AddChild(ignoreTable); + } + } + } + + /// + /// Decompile the ModuleSignature table. + /// + /// The table to decompile. + private void DecompileModuleSignatureTable(Table table) + { + if (1 == table.Rows.Count) + { + Row row = table.Rows[0]; + + Wix.Module module = (Wix.Module)this.core.RootElement; + + module.Id = Convert.ToString(row[0]); + + // support Language columns that are treated as integers as well as strings (the WiX default, to support localizability) + module.Language = Convert.ToString(row[1], CultureInfo.InvariantCulture); + + module.Version = Convert.ToString(row[2]); + } + else + { + // TODO: warn + } + } + + /// + /// Decompile the ModuleSubstitution table. + /// + /// The table to decompile. + private void DecompileModuleSubstitutionTable(Table table) + { + foreach (Row row in table.Rows) + { + Wix.Substitution substitution = new Wix.Substitution(); + + substitution.Table = Convert.ToString(row[0]); + + substitution.Row = Convert.ToString(row[1]); + + substitution.Column = Convert.ToString(row[2]); + + if (null != row[3]) + { + substitution.Value = Convert.ToString(row[3]); + } + + this.core.RootElement.AddChild(substitution); + } + } + + /// + /// Decompile the MoveFile table. + /// + /// The table to decompile. + private void DecompileMoveFileTable(Table table) + { + foreach (Row row in table.Rows) + { + Wix.CopyFile copyFile = new Wix.CopyFile(); + + copyFile.Id = Convert.ToString(row[0]); + + if (null != row[2]) + { + copyFile.SourceName = Convert.ToString(row[2]); + } + + if (null != row[3]) + { + string[] names = Common.GetNames(Convert.ToString(row[3])); + if (null != names[0] && null != names[1]) + { + copyFile.DestinationShortName = names[0]; + copyFile.DestinationName = names[1]; + } + else if (null != names[0]) + { + copyFile.DestinationName = names[0]; + } + } + + // source/destination directory/property is set in FinalizeDuplicateMoveFileTables + + switch (Convert.ToInt32(row[6])) + { + case 0: + break; + case MsiInterop.MsidbMoveFileOptionsMove: + copyFile.Delete = Wix.YesNoType.yes; + break; + default: + this.core.OnMessage(WixWarnings.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[6].Column.Name, row[6])); + break; + } + + Wix.Component component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[1])); + if (null != component) + { + component.AddChild(copyFile); + } + else + { + this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[1]), "Component")); + } + this.core.IndexElement(row, copyFile); + } + } + + /// + /// Decompile the MsiDigitalCertificate table. + /// + /// The table to decompile. + private void DecompileMsiDigitalCertificateTable(Table table) + { + foreach (Row row in table.Rows) + { + Wix.DigitalCertificate digitalCertificate = new Wix.DigitalCertificate(); + + digitalCertificate.Id = Convert.ToString(row[0]); + + digitalCertificate.SourceFile = Convert.ToString(row[1]); + + this.core.IndexElement(row, digitalCertificate); + } + } + + /// + /// Decompile the MsiDigitalSignature table. + /// + /// The table to decompile. + private void DecompileMsiDigitalSignatureTable(Table table) + { + foreach (Row row in table.Rows) + { + Wix.DigitalSignature digitalSignature = new Wix.DigitalSignature(); + + if (null != row[3]) + { + digitalSignature.SourceFile = Convert.ToString(row[3]); + } + + Wix.DigitalCertificate digitalCertificate = (Wix.DigitalCertificate)this.core.GetIndexedElement("MsiDigitalCertificate", Convert.ToString(row[2])); + if (null != digitalCertificate) + { + digitalSignature.AddChild(digitalCertificate); + } + else + { + this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "DigitalCertificate_", Convert.ToString(row[2]), "MsiDigitalCertificate")); + } + + Wix.IParentElement parentElement = (Wix.IParentElement)this.core.GetIndexedElement(Convert.ToString(row[0]), Convert.ToString(row[1])); + if (null != parentElement) + { + parentElement.AddChild(digitalSignature); + } + else + { + this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "SignObject", Convert.ToString(row[1]), Convert.ToString(row[0]))); + } + } + } + + /// + /// Decompile the MsiEmbeddedChainer table. + /// + /// The table to decompile. + private void DecompileMsiEmbeddedChainerTable(Table table) + { + foreach (Row row in table.Rows) + { + Wix.EmbeddedChainer embeddedChainer = new Wix.EmbeddedChainer(); + + embeddedChainer.Id = Convert.ToString(row[0]); + + embeddedChainer.Content = Convert.ToString(row[1]); + + if (null != row[2]) + { + embeddedChainer.CommandLine = Convert.ToString(row[2]); + } + + switch (Convert.ToInt32(row[4])) + { + case MsiInterop.MsidbCustomActionTypeExe + MsiInterop.MsidbCustomActionTypeBinaryData: + embeddedChainer.BinarySource = Convert.ToString(row[3]); + break; + case MsiInterop.MsidbCustomActionTypeExe + MsiInterop.MsidbCustomActionTypeSourceFile: + embeddedChainer.FileSource = Convert.ToString(row[3]); + break; + case MsiInterop.MsidbCustomActionTypeExe + MsiInterop.MsidbCustomActionTypeProperty: + embeddedChainer.PropertySource = Convert.ToString(row[3]); + break; + default: + this.core.OnMessage(WixWarnings.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[4].Column.Name, row[4])); + break; + } + + this.core.RootElement.AddChild(embeddedChainer); + } + } + + /// + /// Decompile the MsiEmbeddedUI table. + /// + /// The table to decompile. + private void DecompileMsiEmbeddedUITable(Table table) + { + Wix.EmbeddedUI embeddedUI = new Wix.EmbeddedUI(); + bool foundEmbeddedUI = false; + bool foundEmbeddedResources = false; + + foreach (Row row in table.Rows) + { + int attributes = Convert.ToInt32(row[2]); + + if (MsiInterop.MsidbEmbeddedUI == (attributes & MsiInterop.MsidbEmbeddedUI)) + { + if (foundEmbeddedUI) + { + this.core.OnMessage(WixWarnings.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[2].Column.Name, row[2])); + } + else + { + embeddedUI.Id = Convert.ToString(row[0]); + embeddedUI.Name = Convert.ToString(row[1]); + + int messageFilter = Convert.ToInt32(row[3]); + if (0 == (messageFilter & MsiInterop.INSTALLLOGMODE_FATALEXIT)) + { + embeddedUI.IgnoreFatalExit = Wix.YesNoType.yes; + } + + if (0 == (messageFilter & MsiInterop.INSTALLLOGMODE_ERROR)) + { + embeddedUI.IgnoreError = Wix.YesNoType.yes; + } + + if (0 == (messageFilter & MsiInterop.INSTALLLOGMODE_WARNING)) + { + embeddedUI.IgnoreWarning = Wix.YesNoType.yes; + } + + if (0 == (messageFilter & MsiInterop.INSTALLLOGMODE_USER)) + { + embeddedUI.IgnoreUser = Wix.YesNoType.yes; + } + + if (0 == (messageFilter & MsiInterop.INSTALLLOGMODE_INFO)) + { + embeddedUI.IgnoreInfo = Wix.YesNoType.yes; + } + + if (0 == (messageFilter & MsiInterop.INSTALLLOGMODE_FILESINUSE)) + { + embeddedUI.IgnoreFilesInUse = Wix.YesNoType.yes; + } + + if (0 == (messageFilter & MsiInterop.INSTALLLOGMODE_RESOLVESOURCE)) + { + embeddedUI.IgnoreResolveSource = Wix.YesNoType.yes; + } + + if (0 == (messageFilter & MsiInterop.INSTALLLOGMODE_OUTOFDISKSPACE)) + { + embeddedUI.IgnoreOutOfDiskSpace = Wix.YesNoType.yes; + } + + if (0 == (messageFilter & MsiInterop.INSTALLLOGMODE_ACTIONSTART)) + { + embeddedUI.IgnoreActionStart = Wix.YesNoType.yes; + } + + if (0 == (messageFilter & MsiInterop.INSTALLLOGMODE_ACTIONDATA)) + { + embeddedUI.IgnoreActionData = Wix.YesNoType.yes; + } + + if (0 == (messageFilter & MsiInterop.INSTALLLOGMODE_PROGRESS)) + { + embeddedUI.IgnoreProgress = Wix.YesNoType.yes; + } + + if (0 == (messageFilter & MsiInterop.INSTALLLOGMODE_COMMONDATA)) + { + embeddedUI.IgnoreCommonData = Wix.YesNoType.yes; + } + + if (0 == (messageFilter & MsiInterop.INSTALLLOGMODE_INITIALIZE)) + { + embeddedUI.IgnoreInitialize = Wix.YesNoType.yes; + } + + if (0 == (messageFilter & MsiInterop.INSTALLLOGMODE_TERMINATE)) + { + embeddedUI.IgnoreTerminate = Wix.YesNoType.yes; + } + + if (0 == (messageFilter & MsiInterop.INSTALLLOGMODE_SHOWDIALOG)) + { + embeddedUI.IgnoreShowDialog = Wix.YesNoType.yes; + } + + if (0 == (messageFilter & MsiInterop.INSTALLLOGMODE_RMFILESINUSE)) + { + embeddedUI.IgnoreRMFilesInUse = Wix.YesNoType.yes; + } + + if (0 == (messageFilter & MsiInterop.INSTALLLOGMODE_INSTALLSTART)) + { + embeddedUI.IgnoreInstallStart = Wix.YesNoType.yes; + } + + if (0 == (messageFilter & MsiInterop.INSTALLLOGMODE_INSTALLEND)) + { + embeddedUI.IgnoreInstallEnd = Wix.YesNoType.yes; + } + + if (MsiInterop.MsidbEmbeddedHandlesBasic == (attributes & MsiInterop.MsidbEmbeddedHandlesBasic)) + { + embeddedUI.SupportBasicUI = Wix.YesNoType.yes; + } + + embeddedUI.SourceFile = Convert.ToString(row[4]); + + this.core.UIElement.AddChild(embeddedUI); + foundEmbeddedUI = true; + } + } + else + { + Wix.EmbeddedUIResource embeddedResource = new Wix.EmbeddedUIResource(); + + embeddedResource.Id = Convert.ToString(row[0]); + embeddedResource.Name = Convert.ToString(row[1]); + embeddedResource.SourceFile = Convert.ToString(row[4]); + + embeddedUI.AddChild(embeddedResource); + foundEmbeddedResources = true; + } + } + + if (!foundEmbeddedUI && foundEmbeddedResources) + { + // TODO: warn + } + } + + /// + /// Decompile the MsiLockPermissionsEx table. + /// + /// The table to decompile. + private void DecompileMsiLockPermissionsExTable(Table table) + { + foreach (Row row in table.Rows) + { + Wix.PermissionEx permissionEx = new Wix.PermissionEx(); + permissionEx.Id = Convert.ToString(row[0]); + permissionEx.Sddl = Convert.ToString(row[3]); + + if (null != row[4]) + { + Wix.Condition condition = new Wix.Condition(); + condition.Content = Convert.ToString(row[4]); + permissionEx.AddChild(condition); + } + + switch (Convert.ToString(row[2])) + { + case "CreateFolder": + case "File": + case "Registry": + case "ServiceInstall": + break; + default: + this.core.OnMessage(WixWarnings.IllegalColumnValue(row.SourceLineNumbers, row.Table.Name, row.Fields[1].Column.Name, row[1])); + return; + } + + this.core.IndexElement(row, permissionEx); + } + } + + /// + /// Decompile the MsiPackageCertificate table. + /// + /// The table to decompile. + private void DecompileMsiPackageCertificateTable(Table table) + { + if (0 < table.Rows.Count) + { + Wix.PackageCertificates packageCertificates = new Wix.PackageCertificates(); + this.core.RootElement.AddChild(packageCertificates); + AddCertificates(table, packageCertificates); + } + } + + /// + /// Decompile the MsiPatchCertificate table. + /// + /// The table to decompile. + private void DecompileMsiPatchCertificateTable(Table table) + { + if (0 < table.Rows.Count) + { + Wix.PatchCertificates patchCertificates = new Wix.PatchCertificates(); + this.core.RootElement.AddChild(patchCertificates); + AddCertificates(table, patchCertificates); + } + } + + /// + /// Insert DigitalCertificate records associated with passed msiPackageCertificate or msiPatchCertificate table. + /// + /// The table being decompiled. + /// DigitalCertificate parent + private void AddCertificates(Table table, Wix.IParentElement parent) + { + foreach (Row row in table.Rows) + { + Wix.DigitalCertificate digitalCertificate = (Wix.DigitalCertificate)this.core.GetIndexedElement("MsiDigitalCertificate", Convert.ToString(row[1])); + + if (null != digitalCertificate) + { + parent.AddChild(digitalCertificate); + } + else + { + this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "DigitalCertificate_", Convert.ToString(row[1]), "MsiDigitalCertificate")); + } + } + } + + /// + /// Decompile the MsiShortcutProperty table. + /// + /// The table to decompile. + private void DecompileMsiShortcutPropertyTable(Table table) + { + foreach (Row row in table.Rows) + { + Wix.ShortcutProperty property = new Wix.ShortcutProperty(); + property.Id = Convert.ToString(row[0]); + property.Key = Convert.ToString(row[2]); + property.Value = Convert.ToString(row[3]); + + Wix.Shortcut shortcut = (Wix.Shortcut)this.core.GetIndexedElement("Shortcut", Convert.ToString(row[1])); + if (null != shortcut) + { + shortcut.AddChild(property); + } + else + { + this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Shortcut_", Convert.ToString(row[1]), "Shortcut")); + } + } + } + + /// + /// Decompile the ODBCAttribute table. + /// + /// The table to decompile. + private void DecompileODBCAttributeTable(Table table) + { + foreach (Row row in table.Rows) + { + Wix.Property property = new Wix.Property(); + + property.Id = Convert.ToString(row[1]); + + if (null != row[2]) + { + property.Value = Convert.ToString(row[2]); + } + + Wix.ODBCDriver odbcDriver = (Wix.ODBCDriver)this.core.GetIndexedElement("ODBCDriver", Convert.ToString(row[0])); + if (null != odbcDriver) + { + odbcDriver.AddChild(property); + } + else + { + this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Driver_", Convert.ToString(row[0]), "ODBCDriver")); + } + } + } + + /// + /// Decompile the ODBCDataSource table. + /// + /// The table to decompile. + private void DecompileODBCDataSourceTable(Table table) + { + foreach (Row row in table.Rows) + { + Wix.ODBCDataSource odbcDataSource = new Wix.ODBCDataSource(); + + odbcDataSource.Id = Convert.ToString(row[0]); + + odbcDataSource.Name = Convert.ToString(row[2]); + + odbcDataSource.DriverName = Convert.ToString(row[3]); + + switch (Convert.ToInt32(row[4])) + { + case MsiInterop.MsidbODBCDataSourceRegistrationPerMachine: + odbcDataSource.Registration = Wix.ODBCDataSource.RegistrationType.machine; + break; + case MsiInterop.MsidbODBCDataSourceRegistrationPerUser: + odbcDataSource.Registration = Wix.ODBCDataSource.RegistrationType.user; + break; + default: + this.core.OnMessage(WixWarnings.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[4].Column.Name, row[4])); + break; + } + + this.core.IndexElement(row, odbcDataSource); + } + } + + /// + /// Decompile the ODBCDriver table. + /// + /// The table to decompile. + private void DecompileODBCDriverTable(Table table) + { + foreach (Row row in table.Rows) + { + Wix.ODBCDriver odbcDriver = new Wix.ODBCDriver(); + + odbcDriver.Id = Convert.ToString(row[0]); + + odbcDriver.Name = Convert.ToString(row[2]); + + odbcDriver.File = Convert.ToString(row[3]); + + if (null != row[4]) + { + odbcDriver.SetupFile = Convert.ToString(row[4]); + } + + Wix.Component component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[1])); + if (null != component) + { + component.AddChild(odbcDriver); + } + else + { + this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[1]), "Component")); + } + this.core.IndexElement(row, odbcDriver); + } + } + + /// + /// Decompile the ODBCSourceAttribute table. + /// + /// The table to decompile. + private void DecompileODBCSourceAttributeTable(Table table) + { + foreach (Row row in table.Rows) + { + Wix.Property property = new Wix.Property(); + + property.Id = Convert.ToString(row[1]); + + if (null != row[2]) + { + property.Value = Convert.ToString(row[2]); + } + + Wix.ODBCDataSource odbcDataSource = (Wix.ODBCDataSource)this.core.GetIndexedElement("ODBCDataSource", Convert.ToString(row[0])); + if (null != odbcDataSource) + { + odbcDataSource.AddChild(property); + } + else + { + this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "DataSource_", Convert.ToString(row[0]), "ODBCDataSource")); + } + } + } + + /// + /// Decompile the ODBCTranslator table. + /// + /// The table to decompile. + private void DecompileODBCTranslatorTable(Table table) + { + foreach (Row row in table.Rows) + { + Wix.ODBCTranslator odbcTranslator = new Wix.ODBCTranslator(); + + odbcTranslator.Id = Convert.ToString(row[0]); + + odbcTranslator.Name = Convert.ToString(row[2]); + + odbcTranslator.File = Convert.ToString(row[3]); + + if (null != row[4]) + { + odbcTranslator.SetupFile = Convert.ToString(row[4]); + } + + Wix.Component component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[1])); + if (null != component) + { + component.AddChild(odbcTranslator); + } + else + { + this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[1]), "Component")); + } + } + } + + /// + /// Decompile the PatchMetadata table. + /// + /// The table to decompile. + private void DecompilePatchMetadataTable(Table table) + { + if (0 < table.Rows.Count) + { + Wix.PatchMetadata patchMetadata = new Wix.PatchMetadata(); + + foreach (Row row in table.Rows) + { + string value = Convert.ToString(row[2]); + + switch (Convert.ToString(row[1])) + { + case "AllowRemoval": + if ("1" == value) + { + patchMetadata.AllowRemoval = Wix.YesNoType.yes; + } + break; + case "Classification": + if (null != value) + { + patchMetadata.Classification = value; + } + break; + case "CreationTimeUTC": + if (null != value) + { + patchMetadata.CreationTimeUTC = value; + } + break; + case "Description": + if (null != value) + { + patchMetadata.Description = value; + } + break; + case "DisplayName": + if (null != value) + { + patchMetadata.DisplayName = value; + } + break; + case "ManufacturerName": + if (null != value) + { + patchMetadata.ManufacturerName = value; + } + break; + case "MinorUpdateTargetRTM": + if (null != value) + { + patchMetadata.MinorUpdateTargetRTM = value; + } + break; + case "MoreInfoURL": + if (null != value) + { + patchMetadata.MoreInfoURL = value; + } + break; + case "OptimizeCA": + Wix.OptimizeCustomActions optimizeCustomActions = new Wix.OptimizeCustomActions(); + int optimizeCA = Int32.Parse(value, CultureInfo.InvariantCulture); + if (0 != (Convert.ToInt32(OptimizeCA.SkipAssignment) & optimizeCA)) + { + optimizeCustomActions.SkipAssignment = Wix.YesNoType.yes; + } + + if (0 != (Convert.ToInt32(OptimizeCA.SkipImmediate) & optimizeCA)) + { + optimizeCustomActions.SkipImmediate = Wix.YesNoType.yes; + } + + if (0 != (Convert.ToInt32(OptimizeCA.SkipDeferred) & optimizeCA)) + { + optimizeCustomActions.SkipDeferred = Wix.YesNoType.yes; + } + + patchMetadata.AddChild(optimizeCustomActions); + break; + case "OptimizedInstallMode": + if ("1" == value) + { + patchMetadata.OptimizedInstallMode = Wix.YesNoType.yes; + } + break; + case "TargetProductName": + if (null != value) + { + patchMetadata.TargetProductName = value; + } + break; + default: + Wix.CustomProperty customProperty = new Wix.CustomProperty(); + + if (null != row[0]) + { + customProperty.Company = Convert.ToString(row[0]); + } + + customProperty.Property = Convert.ToString(row[1]); + + if (null != row[2]) + { + customProperty.Value = Convert.ToString(row[2]); + } + + patchMetadata.AddChild(customProperty); + break; + } + } + + this.core.RootElement.AddChild(patchMetadata); + } + } + + /// + /// Decompile the PatchSequence table. + /// + /// The table to decompile. + private void DecompilePatchSequenceTable(Table table) + { + foreach (Row row in table.Rows) + { + Wix.PatchSequence patchSequence = new Wix.PatchSequence(); + + patchSequence.PatchFamily = Convert.ToString(row[0]); + + if (null != row[1]) + { + try + { + Guid guid = new Guid(Convert.ToString(row[1])); + + patchSequence.ProductCode = Convert.ToString(row[1]); + } + catch // non-guid value + { + patchSequence.TargetImage = Convert.ToString(row[1]); + } + } + + if (null != row[2]) + { + patchSequence.Sequence = Convert.ToString(row[2]); + } + + if (null != row[3] && 0x1 == Convert.ToInt32(row[3])) + { + patchSequence.Supersede = Wix.YesNoType.yes; + } + + this.core.RootElement.AddChild(patchSequence); + } + } + + /// + /// Decompile the ProgId table. + /// + /// The table to decompile. + private void DecompileProgIdTable(Table table) + { + foreach (Row row in table.Rows) + { + Wix.ProgId progId = new Wix.ProgId(); + + progId.Advertise = Wix.YesNoType.yes; + + progId.Id = Convert.ToString(row[0]); + + if (null != row[3]) + { + progId.Description = Convert.ToString(row[3]); + } + + if (null != row[4]) + { + progId.Icon = Convert.ToString(row[4]); + } + + if (null != row[5]) + { + progId.IconIndex = Convert.ToInt32(row[5]); + } + + this.core.IndexElement(row, progId); + } + + // nest the ProgIds + foreach (Row row in table.Rows) + { + Wix.ProgId progId = (Wix.ProgId)this.core.GetIndexedElement(row); + + if (null != row[1]) + { + Wix.ProgId parentProgId = (Wix.ProgId)this.core.GetIndexedElement("ProgId", Convert.ToString(row[1])); + + if (null != parentProgId) + { + parentProgId.AddChild(progId); + } + else + { + this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "ProgId_Parent", Convert.ToString(row[1]), "ProgId")); + } + } + else if (null != row[2]) + { + // nesting is handled in FinalizeProgIdTable + } + else + { + // TODO: warn for orphaned ProgId + } + } + } + + /// + /// Decompile the Properties table. + /// + /// The table to decompile. + private void DecompilePropertiesTable(Table table) + { + Wix.PatchCreation patchCreation = (Wix.PatchCreation)this.core.RootElement; + + foreach (Row row in table.Rows) + { + string name = Convert.ToString(row[0]); + string value = Convert.ToString(row[1]); + + switch (name) + { + case "AllowProductCodeMismatches": + if ("1" == value) + { + patchCreation.AllowProductCodeMismatches = Wix.YesNoType.yes; + } + break; + case "AllowProductVersionMajorMismatches": + if ("1" == value) + { + patchCreation.AllowMajorVersionMismatches = Wix.YesNoType.yes; + } + break; + case "ApiPatchingSymbolFlags": + if (null != value) + { + try + { + // remove the leading "0x" if its present + if (value.StartsWith("0x", StringComparison.Ordinal)) + { + value = value.Substring(2); + } + + patchCreation.SymbolFlags = Convert.ToInt32(value, 16); + } + catch + { + this.core.OnMessage(WixWarnings.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[1].Column.Name, row[1])); + } + } + break; + case "DontRemoveTempFolderWhenFinished": + if ("1" == value) + { + patchCreation.CleanWorkingFolder = Wix.YesNoType.no; + } + break; + case "IncludeWholeFilesOnly": + if ("1" == value) + { + patchCreation.WholeFilesOnly = Wix.YesNoType.yes; + } + break; + case "ListOfPatchGUIDsToReplace": + if (null != value) + { + Regex 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}\}"); + MatchCollection guidMatches = guidRegex.Matches(value); + + foreach (Match guidMatch in guidMatches) + { + Wix.ReplacePatch replacePatch = new Wix.ReplacePatch(); + + replacePatch.Id = guidMatch.Value; + + this.core.RootElement.AddChild(replacePatch); + } + } + break; + case "ListOfTargetProductCodes": + if (null != value) + { + string[] targetProductCodes = value.Split(';'); + + foreach (string targetProductCodeString in targetProductCodes) + { + Wix.TargetProductCode targetProductCode = new Wix.TargetProductCode(); + + targetProductCode.Id = targetProductCodeString; + + this.core.RootElement.AddChild(targetProductCode); + } + } + break; + case "PatchGUID": + patchCreation.Id = value; + break; + case "PatchSourceList": + patchCreation.SourceList = value; + break; + case "PatchOutputPath": + patchCreation.OutputPath = value; + break; + default: + Wix.PatchProperty patchProperty = new Wix.PatchProperty(); + + patchProperty.Name = name; + + patchProperty.Value = value; + + this.core.RootElement.AddChild(patchProperty); + break; + } + } + } + + /// + /// Decompile the Property table. + /// + /// The table to decompile. + private void DecompilePropertyTable(Table table) + { + foreach (Row row in table.Rows) + { + string id = Convert.ToString(row[0]); + string value = Convert.ToString(row[1]); + + if ("AdminProperties" == id || "MsiHiddenProperties" == id || "SecureCustomProperties" == id) + { + if (0 < value.Length) + { + foreach (string propertyId in value.Split(';')) + { + string property = propertyId; + bool suppressModulularization = false; + if (OutputType.Module == this.outputType) + { + if (propertyId.EndsWith(this.modularizationGuid.Substring(1, 36).Replace('-', '_'), StringComparison.Ordinal)) + { + property = propertyId.Substring(0, propertyId.Length - this.modularizationGuid.Length + 1); + } + else + { + suppressModulularization = true; + } + } + + Wix.Property specialProperty = this.EnsureProperty(property); + if (suppressModulularization) + { + specialProperty.SuppressModularization = Wix.YesNoType.yes; + } + + switch (id) + { + case "AdminProperties": + specialProperty.Admin = Wix.YesNoType.yes; + break; + case "MsiHiddenProperties": + specialProperty.Hidden = Wix.YesNoType.yes; + break; + case "SecureCustomProperties": + specialProperty.Secure = Wix.YesNoType.yes; + break; + } + } + } + + continue; + } + else if (OutputType.Product == this.outputType) + { + Wix.Product product = (Wix.Product)this.core.RootElement; + + switch (id) + { + case "Manufacturer": + product.Manufacturer = value; + continue; + case "ProductCode": + product.Id = value.ToUpper(CultureInfo.InvariantCulture); + continue; + case "ProductLanguage": + product.Language = value; + continue; + case "ProductName": + product.Name = value; + continue; + case "ProductVersion": + product.Version = value; + continue; + case "UpgradeCode": + product.UpgradeCode = value; + continue; + } + } + + if (!this.suppressUI || "ErrorDialog" != id) + { + Wix.Property property = this.EnsureProperty(id); + + property.Value = value; + } + } + } + + /// + /// Decompile the PublishComponent table. + /// + /// The table to decompile. + private void DecompilePublishComponentTable(Table table) + { + foreach (Row row in table.Rows) + { + Wix.Category category = new Wix.Category(); + + category.Id = Convert.ToString(row[0]); + + category.Qualifier = Convert.ToString(row[1]); + + if (null != row[3]) + { + category.AppData = Convert.ToString(row[3]); + } + + Wix.Component component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[2])); + if (null != component) + { + component.AddChild(category); + } + else + { + this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[2]), "Component")); + } + } + } + + /// + /// Decompile the RadioButton table. + /// + /// The table to decompile. + private void DecompileRadioButtonTable(Table table) + { + SortedList radioButtons = new SortedList(); + Hashtable radioButtonGroups = new Hashtable(); + + foreach (Row row in table.Rows) + { + Wix.RadioButton radioButton = new Wix.RadioButton(); + + radioButton.Value = Convert.ToString(row[2]); + + radioButton.X = Convert.ToString(row[3], CultureInfo.InvariantCulture); + + radioButton.Y = Convert.ToString(row[4], CultureInfo.InvariantCulture); + + radioButton.Width = Convert.ToString(row[5], CultureInfo.InvariantCulture); + + radioButton.Height = Convert.ToString(row[6], CultureInfo.InvariantCulture); + + if (null != row[7]) + { + radioButton.Text = Convert.ToString(row[7]); + } + + if (null != row[8]) + { + string[] help = (Convert.ToString(row[8])).Split('|'); + + if (2 == help.Length) + { + if (0 < help[0].Length) + { + radioButton.ToolTip = help[0]; + } + + if (0 < help[1].Length) + { + radioButton.Help = help[1]; + } + } + } + + radioButtons.Add(String.Format(CultureInfo.InvariantCulture, "{0}|{1:0000000000}", row[0], row[1]), row); + this.core.IndexElement(row, radioButton); + } + + // nest the radio buttons + foreach (Row row in radioButtons.Values) + { + Wix.RadioButton radioButton = (Wix.RadioButton)this.core.GetIndexedElement(row); + Wix.RadioButtonGroup radioButtonGroup = (Wix.RadioButtonGroup)radioButtonGroups[Convert.ToString(row[0])]; + + if (null == radioButtonGroup) + { + radioButtonGroup = new Wix.RadioButtonGroup(); + + radioButtonGroup.Property = Convert.ToString(row[0]); + + this.core.UIElement.AddChild(radioButtonGroup); + radioButtonGroups.Add(Convert.ToString(row[0]), radioButtonGroup); + } + + radioButtonGroup.AddChild(radioButton); + } + } + + /// + /// Decompile the Registry table. + /// + /// The table to decompile. + private void DecompileRegistryTable(Table table) + { + foreach (Row row in table.Rows) + { + if (("-" == Convert.ToString(row[3]) || "+" == Convert.ToString(row[3]) || "*" == Convert.ToString(row[3])) && null == row[4]) + { + Wix.RegistryKey registryKey = new Wix.RegistryKey(); + + registryKey.Id = Convert.ToString(row[0]); + + Wix.RegistryRootType registryRootType; + if (this.GetRegistryRootType(row.SourceLineNumbers, table.Name, row.Fields[1], out registryRootType)) + { + registryKey.Root = registryRootType; + } + + registryKey.Key = Convert.ToString(row[2]); + + switch (Convert.ToString(row[3])) + { + case "+": + registryKey.ForceCreateOnInstall = Wix.YesNoType.yes; + break; + case "-": + registryKey.ForceDeleteOnUninstall = Wix.YesNoType.yes; + break; + case "*": + registryKey.ForceDeleteOnUninstall = Wix.YesNoType.yes; + registryKey.ForceCreateOnInstall = Wix.YesNoType.yes; + break; + } + + this.core.IndexElement(row, registryKey); + } + else + { + Wix.RegistryValue registryValue = new Wix.RegistryValue(); + + registryValue.Id = Convert.ToString(row[0]); + + Wix.RegistryRootType registryRootType; + if (this.GetRegistryRootType(row.SourceLineNumbers, table.Name, row.Fields[1], out registryRootType)) + { + registryValue.Root = registryRootType; + } + + registryValue.Key = Convert.ToString(row[2]); + + if (null != row[3]) + { + registryValue.Name = Convert.ToString(row[3]); + } + + if (null != row[4]) + { + string value = Convert.ToString(row[4]); + + if (value.StartsWith("#x", StringComparison.Ordinal)) + { + registryValue.Type = Wix.RegistryValue.TypeType.binary; + registryValue.Value = value.Substring(2); + } + else if (value.StartsWith("#%", StringComparison.Ordinal)) + { + registryValue.Type = Wix.RegistryValue.TypeType.expandable; + registryValue.Value = value.Substring(2); + } + else if (value.StartsWith("#", StringComparison.Ordinal) && !value.StartsWith("##", StringComparison.Ordinal)) + { + registryValue.Type = Wix.RegistryValue.TypeType.integer; + registryValue.Value = value.Substring(1); + } + else + { + if (value.StartsWith("##", StringComparison.Ordinal)) + { + value = value.Substring(1); + } + + if (0 <= value.IndexOf("[~]", StringComparison.Ordinal)) + { + registryValue.Type = Wix.RegistryValue.TypeType.multiString; + + if ("[~]" == value) + { + value = string.Empty; + } + else if (value.StartsWith("[~]", StringComparison.Ordinal) && value.EndsWith("[~]", StringComparison.Ordinal)) + { + value = value.Substring(3, value.Length - 6); + } + else if (value.StartsWith("[~]", StringComparison.Ordinal)) + { + registryValue.Action = Wix.RegistryValue.ActionType.append; + value = value.Substring(3); + } + else if (value.EndsWith("[~]", StringComparison.Ordinal)) + { + registryValue.Action = Wix.RegistryValue.ActionType.prepend; + value = value.Substring(0, value.Length - 3); + } + + string[] multiValues = NullSplitter.Split(value); + foreach (string multiValue in multiValues) + { + Wix.MultiStringValue multiStringValue = new Wix.MultiStringValue(); + + multiStringValue.Content = multiValue; + + registryValue.AddChild(multiStringValue); + } + } + else + { + registryValue.Type = Wix.RegistryValue.TypeType.@string; + registryValue.Value = value; + } + } + } + else + { + registryValue.Type = Wix.RegistryValue.TypeType.@string; + registryValue.Value = String.Empty; + } + + this.core.IndexElement(row, registryValue); + } + } + } + + /// + /// Decompile the RegLocator table. + /// + /// The table to decompile. + private void DecompileRegLocatorTable(Table table) + { + foreach (Row row in table.Rows) + { + Wix.RegistrySearch registrySearch = new Wix.RegistrySearch(); + + registrySearch.Id = Convert.ToString(row[0]); + + switch (Convert.ToInt32(row[1])) + { + case MsiInterop.MsidbRegistryRootClassesRoot: + registrySearch.Root = Wix.RegistrySearch.RootType.HKCR; + break; + case MsiInterop.MsidbRegistryRootCurrentUser: + registrySearch.Root = Wix.RegistrySearch.RootType.HKCU; + break; + case MsiInterop.MsidbRegistryRootLocalMachine: + registrySearch.Root = Wix.RegistrySearch.RootType.HKLM; + break; + case MsiInterop.MsidbRegistryRootUsers: + registrySearch.Root = Wix.RegistrySearch.RootType.HKU; + break; + default: + this.core.OnMessage(WixWarnings.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[1].Column.Name, row[1])); + break; + } + + registrySearch.Key = Convert.ToString(row[2]); + + if (null != row[3]) + { + registrySearch.Name = Convert.ToString(row[3]); + } + + if (null == row[4]) + { + registrySearch.Type = Wix.RegistrySearch.TypeType.file; + } + else + { + int type = Convert.ToInt32(row[4]); + + if (MsiInterop.MsidbLocatorType64bit == (type & MsiInterop.MsidbLocatorType64bit)) + { + registrySearch.Win64 = Wix.YesNoType.yes; + type &= ~MsiInterop.MsidbLocatorType64bit; + } + + switch (type) + { + case MsiInterop.MsidbLocatorTypeDirectory: + registrySearch.Type = Wix.RegistrySearch.TypeType.directory; + break; + case MsiInterop.MsidbLocatorTypeFileName: + registrySearch.Type = Wix.RegistrySearch.TypeType.file; + break; + case MsiInterop.MsidbLocatorTypeRawValue: + registrySearch.Type = Wix.RegistrySearch.TypeType.raw; + break; + default: + this.core.OnMessage(WixWarnings.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[4].Column.Name, row[4])); + break; + } + } + + this.core.IndexElement(row, registrySearch); + } + } + + /// + /// Decompile the RemoveFile table. + /// + /// The table to decompile. + private void DecompileRemoveFileTable(Table table) + { + foreach (Row row in table.Rows) + { + if (null == row[2]) + { + Wix.RemoveFolder removeFolder = new Wix.RemoveFolder(); + + removeFolder.Id = Convert.ToString(row[0]); + + // directory/property is set in FinalizeDecompile + + switch (Convert.ToInt32(row[4])) + { + case MsiInterop.MsidbRemoveFileInstallModeOnInstall: + removeFolder.On = Wix.InstallUninstallType.install; + break; + case MsiInterop.MsidbRemoveFileInstallModeOnRemove: + removeFolder.On = Wix.InstallUninstallType.uninstall; + break; + case MsiInterop.MsidbRemoveFileInstallModeOnBoth: + removeFolder.On = Wix.InstallUninstallType.both; + break; + default: + this.core.OnMessage(WixWarnings.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[4].Column.Name, row[4])); + break; + } + + Wix.Component component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[1])); + if (null != component) + { + component.AddChild(removeFolder); + } + else + { + this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[1]), "Component")); + } + this.core.IndexElement(row, removeFolder); + } + else + { + Wix.RemoveFile removeFile = new Wix.RemoveFile(); + + removeFile.Id = Convert.ToString(row[0]); + + string[] names = Common.GetNames(Convert.ToString(row[2])); + if (null != names[0] && null != names[1]) + { + removeFile.ShortName = names[0]; + removeFile.Name = names[1]; + } + else if (null != names[0]) + { + removeFile.Name = names[0]; + } + + // directory/property is set in FinalizeDecompile + + switch (Convert.ToInt32(row[4])) + { + case MsiInterop.MsidbRemoveFileInstallModeOnInstall: + removeFile.On = Wix.InstallUninstallType.install; + break; + case MsiInterop.MsidbRemoveFileInstallModeOnRemove: + removeFile.On = Wix.InstallUninstallType.uninstall; + break; + case MsiInterop.MsidbRemoveFileInstallModeOnBoth: + removeFile.On = Wix.InstallUninstallType.both; + break; + default: + this.core.OnMessage(WixWarnings.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[4].Column.Name, row[4])); + break; + } + + Wix.Component component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[1])); + if (null != component) + { + component.AddChild(removeFile); + } + else + { + this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[1]), "Component")); + } + this.core.IndexElement(row, removeFile); + } + } + } + + /// + /// Decompile the RemoveIniFile table. + /// + /// The table to decompile. + private void DecompileRemoveIniFileTable(Table table) + { + foreach (Row row in table.Rows) + { + Wix.IniFile iniFile = new Wix.IniFile(); + + iniFile.Id = Convert.ToString(row[0]); + + string[] names = Common.GetNames(Convert.ToString(row[1])); + if (null != names[0] && null != names[1]) + { + iniFile.ShortName = names[0]; + iniFile.Name = names[1]; + } + else if (null != names[0]) + { + iniFile.Name = names[0]; + } + + if (null != row[2]) + { + iniFile.Directory = Convert.ToString(row[2]); + } + + iniFile.Section = Convert.ToString(row[3]); + + iniFile.Key = Convert.ToString(row[4]); + + if (null != row[5]) + { + iniFile.Value = Convert.ToString(row[5]); + } + + switch (Convert.ToInt32(row[6])) + { + case MsiInterop.MsidbIniFileActionRemoveLine: + iniFile.Action = Wix.IniFile.ActionType.removeLine; + break; + case MsiInterop.MsidbIniFileActionRemoveTag: + iniFile.Action = Wix.IniFile.ActionType.removeTag; + break; + default: + this.core.OnMessage(WixWarnings.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[6].Column.Name, row[6])); + break; + } + + Wix.Component component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[7])); + if (null != component) + { + component.AddChild(iniFile); + } + else + { + this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[7]), "Component")); + } + } + } + + /// + /// Decompile the RemoveRegistry table. + /// + /// The table to decompile. + private void DecompileRemoveRegistryTable(Table table) + { + foreach (Row row in table.Rows) + { + if ("-" == Convert.ToString(row[3])) + { + Wix.RemoveRegistryKey removeRegistryKey = new Wix.RemoveRegistryKey(); + + removeRegistryKey.Id = Convert.ToString(row[0]); + + Wix.RegistryRootType registryRootType; + if (this.GetRegistryRootType(row.SourceLineNumbers, table.Name, row.Fields[1], out registryRootType)) + { + removeRegistryKey.Root = registryRootType; + } + + removeRegistryKey.Key = Convert.ToString(row[2]); + + removeRegistryKey.Action = Wix.RemoveRegistryKey.ActionType.removeOnInstall; + + Wix.Component component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[4])); + if (null != component) + { + component.AddChild(removeRegistryKey); + } + else + { + this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[4]), "Component")); + } + } + else + { + Wix.RemoveRegistryValue removeRegistryValue = new Wix.RemoveRegistryValue(); + + removeRegistryValue.Id = Convert.ToString(row[0]); + + Wix.RegistryRootType registryRootType; + if (this.GetRegistryRootType(row.SourceLineNumbers, table.Name, row.Fields[1], out registryRootType)) + { + removeRegistryValue.Root = registryRootType; + } + + removeRegistryValue.Key = Convert.ToString(row[2]); + + if (null != row[3]) + { + removeRegistryValue.Name = Convert.ToString(row[3]); + } + + Wix.Component component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[4])); + if (null != component) + { + component.AddChild(removeRegistryValue); + } + else + { + this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[4]), "Component")); + } + } + } + } + + /// + /// Decompile the ReserveCost table. + /// + /// The table to decompile. + private void DecompileReserveCostTable(Table table) + { + foreach (Row row in table.Rows) + { + Wix.ReserveCost reserveCost = new Wix.ReserveCost(); + + reserveCost.Id = Convert.ToString(row[0]); + + if (null != row[2]) + { + reserveCost.Directory = Convert.ToString(row[2]); + } + + reserveCost.RunLocal = Convert.ToInt32(row[3]); + + reserveCost.RunFromSource = Convert.ToInt32(row[4]); + + Wix.Component component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[1])); + if (null != component) + { + component.AddChild(reserveCost); + } + else + { + this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[1]), "Component")); + } + } + } + + /// + /// Decompile the SelfReg table. + /// + /// The table to decompile. + private void DecompileSelfRegTable(Table table) + { + foreach (Row row in table.Rows) + { + Wix.File file = (Wix.File)this.core.GetIndexedElement("File", Convert.ToString(row[0])); + + if (null != file) + { + if (null != row[1]) + { + file.SelfRegCost = Convert.ToInt32(row[1]); + } + else + { + file.SelfRegCost = 0; + } + } + else + { + this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "File_", Convert.ToString(row[0]), "File")); + } + } + } + + /// + /// Decompile the ServiceControl table. + /// + /// The table to decompile. + private void DecompileServiceControlTable(Table table) + { + foreach (Row row in table.Rows) + { + Wix.ServiceControl serviceControl = new Wix.ServiceControl(); + + serviceControl.Id = Convert.ToString(row[0]); + + serviceControl.Name = Convert.ToString(row[1]); + + int eventValue = Convert.ToInt32(row[2]); + if (MsiInterop.MsidbServiceControlEventStart == (eventValue & MsiInterop.MsidbServiceControlEventStart) && + MsiInterop.MsidbServiceControlEventUninstallStart == (eventValue & MsiInterop.MsidbServiceControlEventUninstallStart)) + { + serviceControl.Start = Wix.InstallUninstallType.both; + } + else if (MsiInterop.MsidbServiceControlEventStart == (eventValue & MsiInterop.MsidbServiceControlEventStart)) + { + serviceControl.Start = Wix.InstallUninstallType.install; + } + else if (MsiInterop.MsidbServiceControlEventUninstallStart == (eventValue & MsiInterop.MsidbServiceControlEventUninstallStart)) + { + serviceControl.Start = Wix.InstallUninstallType.uninstall; + } + + if (MsiInterop.MsidbServiceControlEventStop == (eventValue & MsiInterop.MsidbServiceControlEventStop) && + MsiInterop.MsidbServiceControlEventUninstallStop == (eventValue & MsiInterop.MsidbServiceControlEventUninstallStop)) + { + serviceControl.Stop = Wix.InstallUninstallType.both; + } + else if (MsiInterop.MsidbServiceControlEventStop == (eventValue & MsiInterop.MsidbServiceControlEventStop)) + { + serviceControl.Stop = Wix.InstallUninstallType.install; + } + else if (MsiInterop.MsidbServiceControlEventUninstallStop == (eventValue & MsiInterop.MsidbServiceControlEventUninstallStop)) + { + serviceControl.Stop = Wix.InstallUninstallType.uninstall; + } + + if (MsiInterop.MsidbServiceControlEventDelete == (eventValue & MsiInterop.MsidbServiceControlEventDelete) && + MsiInterop.MsidbServiceControlEventUninstallDelete == (eventValue & MsiInterop.MsidbServiceControlEventUninstallDelete)) + { + serviceControl.Remove = Wix.InstallUninstallType.both; + } + else if (MsiInterop.MsidbServiceControlEventDelete == (eventValue & MsiInterop.MsidbServiceControlEventDelete)) + { + serviceControl.Remove = Wix.InstallUninstallType.install; + } + else if (MsiInterop.MsidbServiceControlEventUninstallDelete == (eventValue & MsiInterop.MsidbServiceControlEventUninstallDelete)) + { + serviceControl.Remove = Wix.InstallUninstallType.uninstall; + } + + if (null != row[3]) + { + string[] arguments = NullSplitter.Split(Convert.ToString(row[3])); + + foreach (string argument in arguments) + { + Wix.ServiceArgument serviceArgument = new Wix.ServiceArgument(); + + serviceArgument.Content = argument; + + serviceControl.AddChild(serviceArgument); + } + } + + if (null != row[4]) + { + if (0 == Convert.ToInt32(row[4])) + { + serviceControl.Wait = Wix.YesNoType.no; + } + else + { + serviceControl.Wait = Wix.YesNoType.yes; + } + } + + Wix.Component component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[5])); + if (null != component) + { + component.AddChild(serviceControl); + } + else + { + this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[5]), "Component")); + } + } + } + + /// + /// Decompile the ServiceInstall table. + /// + /// The table to decompile. + private void DecompileServiceInstallTable(Table table) + { + foreach (Row row in table.Rows) + { + Wix.ServiceInstall serviceInstall = new Wix.ServiceInstall(); + + serviceInstall.Id = Convert.ToString(row[0]); + + serviceInstall.Name = Convert.ToString(row[1]); + + if (null != row[2]) + { + serviceInstall.DisplayName = Convert.ToString(row[2]); + } + + int serviceType = Convert.ToInt32(row[3]); + if (MsiInterop.MsidbServiceInstallInteractive == (serviceType & MsiInterop.MsidbServiceInstallInteractive)) + { + serviceInstall.Interactive = Wix.YesNoType.yes; + } + + if (MsiInterop.MsidbServiceInstallOwnProcess == (serviceType & MsiInterop.MsidbServiceInstallOwnProcess) && + MsiInterop.MsidbServiceInstallShareProcess == (serviceType & MsiInterop.MsidbServiceInstallShareProcess)) + { + // TODO: warn + } + else if (MsiInterop.MsidbServiceInstallOwnProcess == (serviceType & MsiInterop.MsidbServiceInstallOwnProcess)) + { + serviceInstall.Type = Wix.ServiceInstall.TypeType.ownProcess; + } + else if (MsiInterop.MsidbServiceInstallShareProcess == (serviceType & MsiInterop.MsidbServiceInstallShareProcess)) + { + serviceInstall.Type = Wix.ServiceInstall.TypeType.shareProcess; + } + + int startType = Convert.ToInt32(row[4]); + if (MsiInterop.MsidbServiceInstallDisabled == startType) + { + serviceInstall.Start = Wix.ServiceInstall.StartType.disabled; + } + else if (MsiInterop.MsidbServiceInstallDemandStart == startType) + { + serviceInstall.Start = Wix.ServiceInstall.StartType.demand; + } + else if (MsiInterop.MsidbServiceInstallAutoStart == startType) + { + serviceInstall.Start = Wix.ServiceInstall.StartType.auto; + } + else + { + this.core.OnMessage(WixWarnings.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[4].Column.Name, row[4])); + } + + int errorControl = Convert.ToInt32(row[5]); + if (MsiInterop.MsidbServiceInstallErrorCritical == (errorControl & MsiInterop.MsidbServiceInstallErrorCritical)) + { + serviceInstall.ErrorControl = Wix.ServiceInstall.ErrorControlType.critical; + } + else if (MsiInterop.MsidbServiceInstallErrorNormal == (errorControl & MsiInterop.MsidbServiceInstallErrorNormal)) + { + serviceInstall.ErrorControl = Wix.ServiceInstall.ErrorControlType.normal; + } + else + { + serviceInstall.ErrorControl = Wix.ServiceInstall.ErrorControlType.ignore; + } + + if (MsiInterop.MsidbServiceInstallErrorControlVital == (errorControl & MsiInterop.MsidbServiceInstallErrorControlVital)) + { + serviceInstall.Vital = Wix.YesNoType.yes; + } + + if (null != row[6]) + { + serviceInstall.LoadOrderGroup = Convert.ToString(row[6]); + } + + if (null != row[7]) + { + string[] dependencies = NullSplitter.Split(Convert.ToString(row[7])); + + foreach (string dependency in dependencies) + { + if (0 < dependency.Length) + { + Wix.ServiceDependency serviceDependency = new Wix.ServiceDependency(); + + if (dependency.StartsWith("+", StringComparison.Ordinal)) + { + serviceDependency.Group = Wix.YesNoType.yes; + serviceDependency.Id = dependency.Substring(1); + } + else + { + serviceDependency.Id = dependency; + } + + serviceInstall.AddChild(serviceDependency); + } + } + } + + if (null != row[8]) + { + serviceInstall.Account = Convert.ToString(row[8]); + } + + if (null != row[9]) + { + serviceInstall.Password = Convert.ToString(row[9]); + } + + if (null != row[10]) + { + serviceInstall.Arguments = Convert.ToString(row[10]); + } + + if (null != row[12]) + { + serviceInstall.Description = Convert.ToString(row[12]); + } + + Wix.Component component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[11])); + if (null != component) + { + component.AddChild(serviceInstall); + } + else + { + this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[11]), "Component")); + } + this.core.IndexElement(row, serviceInstall); + } + } + + /// + /// Decompile the SFPCatalog table. + /// + /// The table to decompile. + private void DecompileSFPCatalogTable(Table table) + { + foreach (Row row in table.Rows) + { + Wix.SFPCatalog sfpCatalog = new Wix.SFPCatalog(); + + sfpCatalog.Name = Convert.ToString(row[0]); + + sfpCatalog.SourceFile = Convert.ToString(row[1]); + + this.core.IndexElement(row, sfpCatalog); + } + + // nest the SFPCatalog elements + foreach (Row row in table.Rows) + { + Wix.SFPCatalog sfpCatalog = (Wix.SFPCatalog)this.core.GetIndexedElement(row); + + if (null != row[2]) + { + Wix.SFPCatalog parentSFPCatalog = (Wix.SFPCatalog)this.core.GetIndexedElement("SFPCatalog", Convert.ToString(row[2])); + + if (null != parentSFPCatalog) + { + parentSFPCatalog.AddChild(sfpCatalog); + } + else + { + sfpCatalog.Dependency = Convert.ToString(row[2]); + + this.core.RootElement.AddChild(sfpCatalog); + } + } + else + { + this.core.RootElement.AddChild(sfpCatalog); + } + } + } + + /// + /// Decompile the Shortcut table. + /// + /// The table to decompile. + private void DecompileShortcutTable(Table table) + { + foreach (Row row in table.Rows) + { + Wix.Shortcut shortcut = new Wix.Shortcut(); + + shortcut.Id = Convert.ToString(row[0]); + + shortcut.Directory = Convert.ToString(row[1]); + + string[] names = Common.GetNames(Convert.ToString(row[2])); + if (null != names[0] && null != names[1]) + { + shortcut.ShortName = names[0]; + shortcut.Name = names[1]; + } + else if (null != names[0]) + { + shortcut.Name = names[0]; + } + + string target = Convert.ToString(row[4]); + if (target.StartsWith("[", StringComparison.Ordinal) && target.EndsWith("]", StringComparison.Ordinal)) + { + // TODO: use this value to do a "more-correct" nesting under the indicated File or CreateDirectory element + shortcut.Target = target; + } + else + { + shortcut.Advertise = Wix.YesNoType.yes; + + // primary feature is set in FinalizeFeatureComponentsTable + } + + if (null != row[5]) + { + shortcut.Arguments = Convert.ToString(row[5]); + } + + if (null != row[6]) + { + shortcut.Description = Convert.ToString(row[6]); + } + + if (null != row[7]) + { + shortcut.Hotkey = Convert.ToInt32(row[7]); + } + + if (null != row[8]) + { + shortcut.Icon = Convert.ToString(row[8]); + } + + if (null != row[9]) + { + shortcut.IconIndex = Convert.ToInt32(row[9]); + } + + if (null != row[10]) + { + switch (Convert.ToInt32(row[10])) + { + case 1: + shortcut.Show = Wix.Shortcut.ShowType.normal; + break; + case 3: + shortcut.Show = Wix.Shortcut.ShowType.maximized; + break; + case 7: + shortcut.Show = Wix.Shortcut.ShowType.minimized; + break; + default: + this.core.OnMessage(WixWarnings.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[10].Column.Name, row[10])); + break; + } + } + + if (null != row[11]) + { + shortcut.WorkingDirectory = Convert.ToString(row[11]); + } + + // Only try to read the MSI 4.0-specific columns if they actually exist + if (15 < row.Fields.Length) + { + if (null != row[12]) + { + shortcut.DisplayResourceDll = Convert.ToString(row[12]); + } + + if (null != row[13]) + { + shortcut.DisplayResourceId = Convert.ToInt32(row[13]); + } + + if (null != row[14]) + { + shortcut.DescriptionResourceDll = Convert.ToString(row[14]); + } + + if (null != row[15]) + { + shortcut.DescriptionResourceId = Convert.ToInt32(row[15]); + } + } + + Wix.Component component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[3])); + if (null != component) + { + component.AddChild(shortcut); + } + else + { + this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[3]), "Component")); + } + + this.core.IndexElement(row, shortcut); + } + } + + /// + /// Decompile the Signature table. + /// + /// The table to decompile. + private void DecompileSignatureTable(Table table) + { + foreach (Row row in table.Rows) + { + Wix.FileSearch fileSearch = new Wix.FileSearch(); + + fileSearch.Id = Convert.ToString(row[0]); + + string[] names = Common.GetNames(Convert.ToString(row[1])); + if (null != names[0]) + { + // it is permissable to just have a long name + if (!this.core.IsValidShortFilename(names[0], false) && null == names[1]) + { + fileSearch.Name = names[0]; + } + else + { + fileSearch.ShortName = names[0]; + } + } + + if (null != names[1]) + { + fileSearch.Name = names[1]; + } + + if (null != row[2]) + { + fileSearch.MinVersion = Convert.ToString(row[2]); + } + + if (null != row[3]) + { + fileSearch.MaxVersion = Convert.ToString(row[3]); + } + + if (null != row[4]) + { + fileSearch.MinSize = Convert.ToInt32(row[4]); + } + + if (null != row[5]) + { + fileSearch.MaxSize = Convert.ToInt32(row[5]); + } + + if (null != row[6]) + { + fileSearch.MinDate = this.core.ConvertIntegerToDateTime(Convert.ToInt32(row[6])); + } + + if (null != row[7]) + { + fileSearch.MaxDate = this.core.ConvertIntegerToDateTime(Convert.ToInt32(row[7])); + } + + if (null != row[8]) + { + fileSearch.Languages = Convert.ToString(row[8]); + } + + this.core.IndexElement(row, fileSearch); + } + } + + /// + /// Decompile the TargetFiles_OptionalData table. + /// + /// The table to decompile. + private void DecompileTargetFiles_OptionalDataTable(Table table) + { + foreach (Row row in table.Rows) + { + Wix.TargetFile targetFile = (Wix.TargetFile)this.patchTargetFiles[row[0]]; + if (null == targetFile) + { + targetFile = new Wix.TargetFile(); + + targetFile.Id = Convert.ToString(row[1]); + + Wix.TargetImage targetImage = (Wix.TargetImage)this.core.GetIndexedElement("TargetImages", Convert.ToString(row[0])); + if (null != targetImage) + { + targetImage.AddChild(targetFile); + } + else + { + this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Target", Convert.ToString(row[0]), "TargetImages")); + } + this.patchTargetFiles.Add(row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), targetFile); + } + + if (null != row[2]) + { + string[] symbolPaths = (Convert.ToString(row[2])).Split(';'); + + foreach (string symbolPathString in symbolPaths) + { + Wix.SymbolPath symbolPath = new Wix.SymbolPath(); + + symbolPath.Path = symbolPathString; + + targetFile.AddChild(symbolPath); + } + } + + if (null != row[3] && null != row[4]) + { + string[] ignoreOffsets = (Convert.ToString(row[3])).Split(','); + string[] ignoreLengths = (Convert.ToString(row[4])).Split(','); + + if (ignoreOffsets.Length == ignoreLengths.Length) + { + for (int i = 0; i < ignoreOffsets.Length; i++) + { + Wix.IgnoreRange ignoreRange = new Wix.IgnoreRange(); + + if (ignoreOffsets[i].StartsWith("0x", StringComparison.Ordinal)) + { + ignoreRange.Offset = Convert.ToInt32(ignoreOffsets[i].Substring(2), 16); + } + else + { + ignoreRange.Offset = Convert.ToInt32(ignoreOffsets[i], CultureInfo.InvariantCulture); + } + + if (ignoreLengths[i].StartsWith("0x", StringComparison.Ordinal)) + { + ignoreRange.Length = Convert.ToInt32(ignoreLengths[i].Substring(2), 16); + } + else + { + ignoreRange.Length = Convert.ToInt32(ignoreLengths[i], CultureInfo.InvariantCulture); + } + + targetFile.AddChild(ignoreRange); + } + } + else + { + // TODO: warn + } + } + else if (null != row[3] || null != row[4]) + { + // TODO: warn about mismatch between columns + } + + // the RetainOffsets column is handled in FinalizeFamilyFileRangesTable + } + } + + /// + /// Decompile the TargetImages table. + /// + /// The table to decompile. + private void DecompileTargetImagesTable(Table table) + { + foreach (Row row in table.Rows) + { + Wix.TargetImage targetImage = new Wix.TargetImage(); + + targetImage.Id = Convert.ToString(row[0]); + + targetImage.SourceFile = Convert.ToString(row[1]); + + if (null != row[2]) + { + string[] symbolPaths = (Convert.ToString(row[3])).Split(';'); + + foreach (string symbolPathString in symbolPaths) + { + Wix.SymbolPath symbolPath = new Wix.SymbolPath(); + + symbolPath.Path = symbolPathString; + + targetImage.AddChild(symbolPath); + } + } + + targetImage.Order = Convert.ToInt32(row[4]); + + if (null != row[5]) + { + targetImage.Validation = Convert.ToString(row[5]); + } + + if (0 != Convert.ToInt32(row[6])) + { + targetImage.IgnoreMissingFiles = Wix.YesNoType.yes; + } + + Wix.UpgradeImage upgradeImage = (Wix.UpgradeImage)this.core.GetIndexedElement("UpgradedImages", Convert.ToString(row[3])); + if (null != upgradeImage) + { + upgradeImage.AddChild(targetImage); + } + else + { + this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Upgraded", Convert.ToString(row[3]), "UpgradedImages")); + } + this.core.IndexElement(row, targetImage); + } + } + + /// + /// Decompile the TextStyle table. + /// + /// The table to decompile. + private void DecompileTextStyleTable(Table table) + { + foreach (Row row in table.Rows) + { + Wix.TextStyle textStyle = new Wix.TextStyle(); + + textStyle.Id = Convert.ToString(row[0]); + + textStyle.FaceName = Convert.ToString(row[1]); + + textStyle.Size = Convert.ToString(row[2]); + + if (null != row[3]) + { + int color = Convert.ToInt32(row[3]); + + textStyle.Red = color & 0xFF; + + textStyle.Green = (color & 0xFF00) >> 8; + + textStyle.Blue = (color & 0xFF0000) >> 16; + } + + if (null != row[4]) + { + int styleBits = Convert.ToInt32(row[4]); + + if (MsiInterop.MsidbTextStyleStyleBitsBold == (styleBits & MsiInterop.MsidbTextStyleStyleBitsBold)) + { + textStyle.Bold = Wix.YesNoType.yes; + } + + if (MsiInterop.MsidbTextStyleStyleBitsItalic == (styleBits & MsiInterop.MsidbTextStyleStyleBitsItalic)) + { + textStyle.Italic = Wix.YesNoType.yes; + } + + if (MsiInterop.MsidbTextStyleStyleBitsUnderline == (styleBits & MsiInterop.MsidbTextStyleStyleBitsUnderline)) + { + textStyle.Underline = Wix.YesNoType.yes; + } + + if (MsiInterop.MsidbTextStyleStyleBitsStrike == (styleBits & MsiInterop.MsidbTextStyleStyleBitsStrike)) + { + textStyle.Strike = Wix.YesNoType.yes; + } + } + + this.core.UIElement.AddChild(textStyle); + } + } + + /// + /// Decompile the TypeLib table. + /// + /// The table to decompile. + private void DecompileTypeLibTable(Table table) + { + foreach (Row row in table.Rows) + { + Wix.TypeLib typeLib = new Wix.TypeLib(); + + typeLib.Id = Convert.ToString(row[0]); + + typeLib.Advertise = Wix.YesNoType.yes; + + typeLib.Language = Convert.ToInt32(row[1]); + + if (null != row[3]) + { + int version = Convert.ToInt32(row[3]); + + if (65536 == version) + { + this.core.OnMessage(WixWarnings.PossiblyIncorrectTypelibVersion(row.SourceLineNumbers, typeLib.Id)); + } + + typeLib.MajorVersion = ((version & 0xFFFF00) >> 8); + typeLib.MinorVersion = (version & 0xFF); + } + + if (null != row[4]) + { + typeLib.Description = Convert.ToString(row[4]); + } + + if (null != row[5]) + { + typeLib.HelpDirectory = Convert.ToString(row[5]); + } + + if (null != row[7]) + { + typeLib.Cost = Convert.ToInt32(row[7]); + } + + // nested under the appropriate File element in FinalizeFileTable + this.core.IndexElement(row, typeLib); + } + } + + /// + /// Decompile the Upgrade table. + /// + /// The table to decompile. + private void DecompileUpgradeTable(Table table) + { + Hashtable upgradeElements = new Hashtable(); + + foreach (UpgradeRow upgradeRow in table.Rows) + { + if (Compiler.UpgradeDetectedProperty == upgradeRow.ActionProperty || Compiler.DowngradeDetectedProperty == upgradeRow.ActionProperty) + { + continue; // MajorUpgrade rows processed in FinalizeUpgradeTable + } + + Wix.Upgrade upgrade = (Wix.Upgrade)upgradeElements[upgradeRow.UpgradeCode]; + + // create the parent Upgrade element if it doesn't already exist + if (null == upgrade) + { + upgrade = new Wix.Upgrade(); + + upgrade.Id = upgradeRow.UpgradeCode; + + this.core.RootElement.AddChild(upgrade); + upgradeElements.Add(upgrade.Id, upgrade); + } + + Wix.UpgradeVersion upgradeVersion = new Wix.UpgradeVersion(); + + if (null != upgradeRow.VersionMin) + { + upgradeVersion.Minimum = upgradeRow.VersionMin; + } + + if (null != upgradeRow.VersionMax) + { + upgradeVersion.Maximum = upgradeRow.VersionMax; + } + + if (null != upgradeRow.Language) + { + upgradeVersion.Language = upgradeRow.Language; + } + + if (MsiInterop.MsidbUpgradeAttributesMigrateFeatures == (upgradeRow.Attributes & MsiInterop.MsidbUpgradeAttributesMigrateFeatures)) + { + upgradeVersion.MigrateFeatures = Wix.YesNoType.yes; + } + + if (MsiInterop.MsidbUpgradeAttributesOnlyDetect == (upgradeRow.Attributes & MsiInterop.MsidbUpgradeAttributesOnlyDetect)) + { + upgradeVersion.OnlyDetect = Wix.YesNoType.yes; + } + + if (MsiInterop.MsidbUpgradeAttributesIgnoreRemoveFailure == (upgradeRow.Attributes & MsiInterop.MsidbUpgradeAttributesIgnoreRemoveFailure)) + { + upgradeVersion.IgnoreRemoveFailure = Wix.YesNoType.yes; + } + + if (MsiInterop.MsidbUpgradeAttributesVersionMinInclusive == (upgradeRow.Attributes & MsiInterop.MsidbUpgradeAttributesVersionMinInclusive)) + { + upgradeVersion.IncludeMinimum = Wix.YesNoType.yes; + } + + if (MsiInterop.MsidbUpgradeAttributesVersionMaxInclusive == (upgradeRow.Attributes & MsiInterop.MsidbUpgradeAttributesVersionMaxInclusive)) + { + upgradeVersion.IncludeMaximum = Wix.YesNoType.yes; + } + + if (MsiInterop.MsidbUpgradeAttributesLanguagesExclusive == (upgradeRow.Attributes & MsiInterop.MsidbUpgradeAttributesLanguagesExclusive)) + { + upgradeVersion.ExcludeLanguages = Wix.YesNoType.yes; + } + + if (null != upgradeRow.Remove) + { + upgradeVersion.RemoveFeatures = upgradeRow.Remove; + } + + upgradeVersion.Property = upgradeRow.ActionProperty; + + upgrade.AddChild(upgradeVersion); + } + } + + /// + /// Decompile the UpgradedFiles_OptionalData table. + /// + /// The table to decompile. + private void DecompileUpgradedFiles_OptionalDataTable(Table table) + { + foreach (Row row in table.Rows) + { + Wix.UpgradeFile upgradeFile = new Wix.UpgradeFile(); + + upgradeFile.File = Convert.ToString(row[1]); + + if (null != row[2]) + { + string[] symbolPaths = (Convert.ToString(row[2])).Split(';'); + + foreach (string symbolPathString in symbolPaths) + { + Wix.SymbolPath symbolPath = new Wix.SymbolPath(); + + symbolPath.Path = symbolPathString; + + upgradeFile.AddChild(symbolPath); + } + } + + if (null != row[3] && 1 == Convert.ToInt32(row[3])) + { + upgradeFile.AllowIgnoreOnError = Wix.YesNoType.yes; + } + + if (null != row[4] && 0 != Convert.ToInt32(row[4])) + { + upgradeFile.WholeFile = Wix.YesNoType.yes; + } + + upgradeFile.Ignore = Wix.YesNoType.no; + + Wix.UpgradeImage upgradeImage = (Wix.UpgradeImage)this.core.GetIndexedElement("UpgradedImages", Convert.ToString(row[0])); + if (null != upgradeImage) + { + upgradeImage.AddChild(upgradeFile); + } + else + { + this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Upgraded", Convert.ToString(row[0]), "UpgradedImages")); + } + } + } + + /// + /// Decompile the UpgradedFilesToIgnore table. + /// + /// The table to decompile. + private void DecompileUpgradedFilesToIgnoreTable(Table table) + { + foreach (Row row in table.Rows) + { + if ("*" != Convert.ToString(row[0])) + { + Wix.UpgradeFile upgradeFile = new Wix.UpgradeFile(); + + upgradeFile.File = Convert.ToString(row[1]); + + upgradeFile.Ignore = Wix.YesNoType.yes; + + Wix.UpgradeImage upgradeImage = (Wix.UpgradeImage)this.core.GetIndexedElement("UpgradedImages", Convert.ToString(row[0])); + if (null != upgradeImage) + { + upgradeImage.AddChild(upgradeFile); + } + else + { + this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Upgraded", Convert.ToString(row[0]), "UpgradedImages")); + } + } + else + { + this.core.OnMessage(WixWarnings.UnrepresentableColumnValue(row.SourceLineNumbers, table.Name, row.Fields[0].Column.Name, row[0])); + } + } + } + + /// + /// Decompile the UpgradedImages table. + /// + /// The table to decompile. + private void DecompileUpgradedImagesTable(Table table) + { + foreach (Row row in table.Rows) + { + Wix.UpgradeImage upgradeImage = new Wix.UpgradeImage(); + + upgradeImage.Id = Convert.ToString(row[0]); + + upgradeImage.SourceFile = Convert.ToString(row[1]); + + if (null != row[2]) + { + upgradeImage.SourcePatch = Convert.ToString(row[2]); + } + + if (null != row[3]) + { + string[] symbolPaths = (Convert.ToString(row[3])).Split(';'); + + foreach (string symbolPathString in symbolPaths) + { + Wix.SymbolPath symbolPath = new Wix.SymbolPath(); + + symbolPath.Path = symbolPathString; + + upgradeImage.AddChild(symbolPath); + } + } + + Wix.Family family = (Wix.Family)this.core.GetIndexedElement("ImageFamilies", Convert.ToString(row[4])); + if (null != family) + { + family.AddChild(upgradeImage); + } + else + { + this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Family", Convert.ToString(row[4]), "ImageFamilies")); + } + this.core.IndexElement(row, upgradeImage); + } + } + + /// + /// Decompile the UIText table. + /// + /// The table to decompile. + private void DecompileUITextTable(Table table) + { + foreach (Row row in table.Rows) + { + Wix.UIText uiText = new Wix.UIText(); + + uiText.Id = Convert.ToString(row[0]); + + uiText.Content = Convert.ToString(row[1]); + + this.core.UIElement.AddChild(uiText); + } + } + + /// + /// Decompile the Verb table. + /// + /// The table to decompile. + private void DecompileVerbTable(Table table) + { + foreach (Row row in table.Rows) + { + Wix.Verb verb = new Wix.Verb(); + + verb.Id = Convert.ToString(row[1]); + + if (null != row[2]) + { + verb.Sequence = Convert.ToInt32(row[2]); + } + + if (null != row[3]) + { + verb.Command = Convert.ToString(row[3]); + } + + if (null != row[4]) + { + verb.Argument = Convert.ToString(row[4]); + } + + this.core.IndexElement(row, verb); + } + } + + /// + /// Gets the RegistryRootType from an integer representation of the root. + /// + /// The source line information for the root. + /// The name of the table containing the field. + /// The field containing the root value. + /// The strongly-typed representation of the root. + /// true if the value could be converted; false otherwise. + private bool GetRegistryRootType(SourceLineNumber sourceLineNumbers, string tableName, Field field, out Wix.RegistryRootType registryRootType) + { + switch (Convert.ToInt32(field.Data)) + { + case (-1): + registryRootType = Wix.RegistryRootType.HKMU; + return true; + case MsiInterop.MsidbRegistryRootClassesRoot: + registryRootType = Wix.RegistryRootType.HKCR; + return true; + case MsiInterop.MsidbRegistryRootCurrentUser: + registryRootType = Wix.RegistryRootType.HKCU; + return true; + case MsiInterop.MsidbRegistryRootLocalMachine: + registryRootType = Wix.RegistryRootType.HKLM; + return true; + case MsiInterop.MsidbRegistryRootUsers: + registryRootType = Wix.RegistryRootType.HKU; + return true; + default: + this.core.OnMessage(WixWarnings.IllegalColumnValue(sourceLineNumbers, tableName, field.Column.Name, field.Data)); + registryRootType = Wix.RegistryRootType.HKCR; // assign anything to satisfy the out parameter + return false; + } + } + + /// + /// Set the primary feature for a component. + /// + /// The row which specifies a primary feature. + /// The index of the column contaning the feature identifier. + /// The index of the column containing the component identifier. + private void SetPrimaryFeature(Row row, int featureColumnIndex, int componentColumnIndex) + { + // only products contain primary features + if (OutputType.Product == this.outputType) + { + Field featureField = row.Fields[featureColumnIndex]; + Field componentField = row.Fields[componentColumnIndex]; + + Wix.ComponentRef componentRef = (Wix.ComponentRef)this.core.GetIndexedElement("FeatureComponents", Convert.ToString(featureField.Data), Convert.ToString(componentField.Data)); + + if (null != componentRef) + { + componentRef.Primary = Wix.YesNoType.yes; + } + else + { + this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, row.TableDefinition.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), featureField.Column.Name, Convert.ToString(featureField.Data), componentField.Column.Name, Convert.ToString(componentField.Data), "FeatureComponents")); + } + } + } + + /// + /// Checks the InstallExecuteSequence table to determine where RemoveExistingProducts is scheduled and removes it. + /// + /// The collection of all tables. + private static Wix.MajorUpgrade.ScheduleType DetermineMajorUpgradeScheduling(TableIndexedCollection tables) + { + int sequenceRemoveExistingProducts = 0; + int sequenceInstallValidate = 0; + int sequenceInstallInitialize = 0; + int sequenceInstallFinalize = 0; + int sequenceInstallExecute = 0; + int sequenceInstallExecuteAgain = 0; + + Table installExecuteSequenceTable = tables["InstallExecuteSequence"]; + if (null != installExecuteSequenceTable) + { + int removeExistingProductsRow = -1; + for (int i = 0; i < installExecuteSequenceTable.Rows.Count; i++) + { + Row row = installExecuteSequenceTable.Rows[i]; + string action = Convert.ToString(row[0]); + int sequence = Convert.ToInt32(row[2]); + + switch (action) + { + case "RemoveExistingProducts": + sequenceRemoveExistingProducts = sequence; + removeExistingProductsRow = i; + break; + case "InstallValidate": + sequenceInstallValidate = sequence; + break; + case "InstallInitialize": + sequenceInstallInitialize = sequence; + break; + case "InstallExecute": + sequenceInstallExecute = sequence; + break; + case "InstallExecuteAgain": + sequenceInstallExecuteAgain = sequence; + break; + case "InstallFinalize": + sequenceInstallFinalize = sequence; + break; + } + } + + installExecuteSequenceTable.Rows.RemoveAt(removeExistingProductsRow); + } + + if (0 != sequenceInstallValidate && sequenceInstallValidate < sequenceRemoveExistingProducts && sequenceRemoveExistingProducts < sequenceInstallInitialize) + { + return Wix.MajorUpgrade.ScheduleType.afterInstallValidate; + } + else if (0 != sequenceInstallInitialize && sequenceInstallInitialize < sequenceRemoveExistingProducts && sequenceRemoveExistingProducts < sequenceInstallExecute) + { + return Wix.MajorUpgrade.ScheduleType.afterInstallInitialize; + } + else if (0 != sequenceInstallExecute && sequenceInstallExecute < sequenceRemoveExistingProducts && sequenceRemoveExistingProducts < sequenceInstallExecuteAgain) + { + return Wix.MajorUpgrade.ScheduleType.afterInstallExecute; + } + else if (0 != sequenceInstallExecuteAgain && sequenceInstallExecuteAgain < sequenceRemoveExistingProducts && sequenceRemoveExistingProducts < sequenceInstallFinalize) + { + return Wix.MajorUpgrade.ScheduleType.afterInstallExecuteAgain; + } + else + { + return Wix.MajorUpgrade.ScheduleType.afterInstallFinalize; + } + } +#endif + } +} -- cgit v1.2.3-55-g6feb