From 822d917960cbd35f506598af4baa6a20ad4b447e Mon Sep 17 00:00:00 2001 From: Rob Mensching Date: Wed, 24 Oct 2018 21:06:51 -0700 Subject: Re-introduce "decompile" to backend --- src/WixToolset.Core.Burn/BundleBackend.cs | 4 +- .../Decompile/DecompileMsiOrMsmCommand.cs | 75 + .../Decompile/Decompiler.cs | 9229 +++++++++++++++++++ .../Decompile/DecompilerCore.cs | 110 + src/WixToolset.Core.WindowsInstaller/Decompiler.cs | 9356 -------------------- .../DecompilerCore.cs | 154 - src/WixToolset.Core.WindowsInstaller/MsiBackend.cs | 23 +- src/WixToolset.Core.WindowsInstaller/MsmBackend.cs | 23 +- src/WixToolset.Core.WindowsInstaller/MspBackend.cs | 4 +- src/WixToolset.Core.WindowsInstaller/MstBackend.cs | 4 +- .../CommandLine/DecompileCommand.cs | 212 + src/WixToolset.Core/DecompileContext.cs | 20 +- src/WixToolset.Core/Decompiler.cs | 12 +- src/WixToolset.Core/IDecompiler.cs | 4 +- src/WixToolset.Core/OptimizeCA.cs | 4 +- .../DecompileFixture.cs | 41 + .../DecompileSingleFileCompressed/Expected.wxs | 21 + .../DecompileSingleFileCompressed/example.cab | Bin 0 -> 137 bytes .../DecompileSingleFileCompressed/example.msi | Bin 0 -> 32768 bytes .../WixToolsetTest.CoreIntegration.csproj | 3 + 20 files changed, 9766 insertions(+), 9533 deletions(-) create mode 100644 src/WixToolset.Core.WindowsInstaller/Decompile/DecompileMsiOrMsmCommand.cs create mode 100644 src/WixToolset.Core.WindowsInstaller/Decompile/Decompiler.cs create mode 100644 src/WixToolset.Core.WindowsInstaller/Decompile/DecompilerCore.cs delete mode 100644 src/WixToolset.Core.WindowsInstaller/Decompiler.cs delete mode 100644 src/WixToolset.Core.WindowsInstaller/DecompilerCore.cs create mode 100644 src/WixToolset.Core/CommandLine/DecompileCommand.cs create mode 100644 src/test/WixToolsetTest.CoreIntegration/DecompileFixture.cs create mode 100644 src/test/WixToolsetTest.CoreIntegration/TestData/DecompileSingleFileCompressed/Expected.wxs create mode 100644 src/test/WixToolsetTest.CoreIntegration/TestData/DecompileSingleFileCompressed/example.cab create mode 100644 src/test/WixToolsetTest.CoreIntegration/TestData/DecompileSingleFileCompressed/example.msi diff --git a/src/WixToolset.Core.Burn/BundleBackend.cs b/src/WixToolset.Core.Burn/BundleBackend.cs index 3baa526e..1d833b93 100644 --- a/src/WixToolset.Core.Burn/BundleBackend.cs +++ b/src/WixToolset.Core.Burn/BundleBackend.cs @@ -1,4 +1,4 @@ -// 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. +// 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.Core.Burn { @@ -27,7 +27,7 @@ namespace WixToolset.Core.Burn return new BindResult { FileTransfers = command.FileTransfers, TrackedFiles = command.TrackedFiles }; } - public BindResult Decompile(IDecompileContext context) + public DecompileResult Decompile(IDecompileContext context) { throw new NotImplementedException(); } diff --git a/src/WixToolset.Core.WindowsInstaller/Decompile/DecompileMsiOrMsmCommand.cs b/src/WixToolset.Core.WindowsInstaller/Decompile/DecompileMsiOrMsmCommand.cs new file mode 100644 index 00000000..130f5ea8 --- /dev/null +++ b/src/WixToolset.Core.WindowsInstaller/Decompile/DecompileMsiOrMsmCommand.cs @@ -0,0 +1,75 @@ +// 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.Core.WindowsInstaller.Unbind +{ + using System; + using System.Collections.Generic; + using System.ComponentModel; + using System.Xml.Linq; + using WixToolset.Core.Native; + using WixToolset.Data; + using WixToolset.Extensibility; + using WixToolset.Extensibility.Data; + using WixToolset.Extensibility.Services; + using WixToolset.Msi; + + internal class DecompileMsiOrMsmCommand + { + public DecompileMsiOrMsmCommand(IDecompileContext context, IEnumerable backendExtensions) + { + this.Context = context; + this.Extensions = backendExtensions; + this.Messaging = context.ServiceProvider.GetService(); + } + + private IDecompileContext Context { get; } + + private IEnumerable Extensions { get; } + + private IMessaging Messaging { get; } + + public DecompileResult Execute() + { + var result = new DecompileResult(); + + try + { + using (var database = new Database(this.Context.DecompilePath, OpenDatabase.ReadOnly)) + { + var unbindCommand = new UnbindDatabaseCommand(this.Messaging, database, this.Context.DecompilePath, this.Context.DecompileType, this.Context.ExtractFolder, this.Context.IntermediateFolder, this.Context.IsAdminImage, false, skipSummaryInfo: false); + var output = unbindCommand.Execute(); + + var decompiler = new Decompiler(this.Messaging, this.Extensions, this.Context.BaseSourcePath, this.Context.SuppressCustomTables, this.Context.SuppressDroppingEmptyTables, this.Context.SuppressUI, this.Context.TreatProductAsModule); + var wxs = decompiler.Decompile(output); + + wxs.Save(this.Context.OutputPath, SaveOptions.OmitDuplicateNamespaces); + result.SourceDocumentPath = this.Context.OutputPath; + + // extract the files from the cabinets + if (!String.IsNullOrEmpty(this.Context.ExtractFolder) && !this.Context.SuppressExtractCabinets) + { + var extractCommand = new ExtractCabinetsCommand(output, database, this.Context.DecompilePath, this.Context.ExtractFolder, this.Context.IntermediateFolder); + extractCommand.Execute(); + + result.ExtractedFilePaths = extractCommand.ExtractedFiles; + } + else + { + result.ExtractedFilePaths = new string[0]; + } + } + } + catch (Win32Exception e) + { + if (0x6E == e.NativeErrorCode) // ERROR_OPEN_FAILED + { + throw new WixException(ErrorMessages.OpenDatabaseFailed(this.Context.DecompilePath)); + } + + throw; + } + + return result; + } + } +} diff --git a/src/WixToolset.Core.WindowsInstaller/Decompile/Decompiler.cs b/src/WixToolset.Core.WindowsInstaller/Decompile/Decompiler.cs new file mode 100644 index 00000000..26e1f399 --- /dev/null +++ b/src/WixToolset.Core.WindowsInstaller/Decompile/Decompiler.cs @@ -0,0 +1,9229 @@ +// 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.Core.WindowsInstaller +{ + using System; + using System.Collections; + using System.Collections.Generic; + using System.Collections.Specialized; + using System.Globalization; + using System.IO; + using System.Linq; + using System.Text; + using System.Text.RegularExpressions; + using System.Xml.Linq; + using WixToolset.Core; + using WixToolset.Core.Native; + using WixToolset.Core.WindowsInstaller.Rows; + using WixToolset.Data; + using WixToolset.Data.Tuples; + using WixToolset.Data.WindowsInstaller; + using WixToolset.Data.WindowsInstaller.Rows; + using WixToolset.Extensibility; + using WixToolset.Extensibility.Services; + using Wix = WixToolset.Data.Serialize; + + /// + /// Decompiles an msi database into WiX source. + /// + internal class Decompiler + { + private static readonly Regex NullSplitter = new Regex(@"\[~]"); + + private bool compressed; + private bool shortNames; + private DecompilerCore core; + private string modularizationGuid; + private readonly Hashtable patchTargetFiles; + private readonly Hashtable sequenceElements; + private readonly TableDefinitionCollection tableDefinitions; + + /// + /// Creates a new decompiler object with a default set of table definitions. + /// + public Decompiler(IMessaging messaging, IEnumerable extensions, string baseSourcePath, bool suppressCustomTables, bool suppressDroppingEmptyTables, bool suppressUI, bool treatProductAsModule) + { + this.Messaging = messaging; + this.Extensions = extensions; + this.BaseSourcePath = String.IsNullOrEmpty(baseSourcePath) ? "SourceDir" : baseSourcePath; + this.SuppressCustomTables = suppressCustomTables; + this.SuppressDroppingEmptyTables = suppressDroppingEmptyTables; + this.SuppressUI = suppressUI; + this.TreatProductAsModule = treatProductAsModule; + + this.ExtensionsByTableName = new Dictionary(); + this.StandardActions = WindowsInstallerStandard.StandardActions().ToDictionary(a => a.Id.Id); + + this.patchTargetFiles = new Hashtable(); + this.sequenceElements = new Hashtable(); + this.tableDefinitions = new TableDefinitionCollection(); + } + + private IMessaging Messaging { get; } + + private IEnumerable Extensions { get; } + + private Dictionary ExtensionsByTableName { get; } + + private string BaseSourcePath { get; } + + private bool SuppressCustomTables { get; } + + private bool SuppressDroppingEmptyTables { get; } + + private bool SuppressRelativeActionSequencing { get; } + + private bool SuppressUI { get; } + + private bool TreatProductAsModule { get; } + + private OutputType OutputType { get; set; } + + private Dictionary StandardActions { get; } + + /// + /// Decompile the database file. + /// + /// The output to decompile. + /// The serialized WiX source code. + public XDocument Decompile(Output output) + { + if (null == output) + { + throw new ArgumentNullException("output"); + } + + this.OutputType = output.Type; + + // collect the table definitions from the output + this.tableDefinitions.Clear(); + foreach (var table in output.Tables) + { + this.tableDefinitions.Add(table.Definition); + } + + // add any missing standard and wix-specific table definitions + foreach (var tableDefinition in WindowsInstallerStandardInternal.GetTableDefinitions()) + { + if (!this.tableDefinitions.Contains(tableDefinition.Name)) + { + this.tableDefinitions.Add(tableDefinition); + } + } + + // add any missing extension table definitions +#if TODO_DECOMPILER_EXTENSIONS + foreach (var extension in this.Extensions) + { + this.AddExtension(extension); + } +#endif + + var wixElement = new Wix.Wix(); + Wix.IParentElement rootElement; + + 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("Unknown output type."); + } + wixElement.AddChild((Wix.ISchemaElement)rootElement); + + // try to decompile the database file + try + { + this.core = new DecompilerCore(rootElement); + + // stop processing if an error previously occurred + if (this.Messaging.EncounteredError) + { + return null; + } + + this.InitializeDecompile(output.Tables, output.Codepage); + + // stop processing if an error previously occurred + if (this.Messaging.EncounteredError) + { + return null; + } + + // decompile the tables + this.DecompileTables(output); + + // finalize the decompiler and its extensions + this.FinalizeDecompile(output.Tables); + } + finally + { + this.core = null; + } + + var document = new XDocument(); + using (var writer = document.CreateWriter()) + { + wixElement.OutputXml(writer); + } + + // return the XML document only if decompilation completed successfully + return this.Messaging.EncounteredError ? null : document; + } + +#if TODO_DECOMPILER_EXTENSIONS + private void AddExtension(IWindowsInstallerBackendDecompilerExtension extension) + { + if (null != extension.TableDefinitions) + { + foreach (TableDefinition tableDefinition in extension.TableDefinitions) + { + if (!this.ExtensionsByTableName.ContainsKey(tableDefinition.Name)) + { + this.ExtensionsByTableName.Add(tableDefinition.Name, extension); + } + else + { + this.Messaging.Write(ErrorMessages.DuplicateExtensionTable(extension.GetType().ToString(), tableDefinition.Name)); + } + } + } + } +#endif + + /// + /// 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 + { + var 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 + { + var 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) + { + var sequenceTable = actionRow.SequenceTable.ToString(); + var 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("Unknown sequence table."); + } + + 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.Messaging.Write(WarningMessages.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": + this.StandardActions.TryGetValue(actionRow.GetPrimaryKey(), out var appSearchActionRow); + + if (null != actionRow.Before || null != actionRow.After || (null != appSearchActionRow && actionRow.Sequence != appSearchActionRow.Sequence)) + { + var 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": + var 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": + var 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": + var findRelatedProducts = new Wix.FindRelatedProducts(); + Decompiler.SequenceRelativeAction(actionRow, findRelatedProducts); + return findRelatedProducts; + case "ForceReboot": + var forceReboot = new Wix.ForceReboot(); + Decompiler.SequenceRelativeAction(actionRow, forceReboot); + return forceReboot; + case "InstallAdminPackage": + actionElement = new Wix.InstallAdminPackage(); + break; + case "InstallExecute": + var installExecute = new Wix.InstallExecute(); + Decompiler.SequenceRelativeAction(actionRow, installExecute); + return installExecute; + case "InstallExecuteAgain": + var 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": + var 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": + var 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": + var resolveSource = new Wix.ResolveSource(); + Decompiler.SequenceRelativeAction(actionRow, resolveSource); + return resolveSource; + case "RMCCPSearch": + var rmccpSearch = new Wix.RMCCPSearch(); + Decompiler.SequenceRelativeAction(actionRow, rmccpSearch); + return rmccpSearch; + case "ScheduleReboot": + var 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.Messaging.Write(WarningMessages.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.Messaging.Write(WarningMessages.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) + { + var property = (Wix.Property)this.core.GetIndexedElement("Property", id); + + if (null == property) + { + property = new Wix.Property(); + property.Id = id; + + // create a dummy row for indexing + var 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; + } + + var checkBoxTable = tables["CheckBox"]; + var controlTable = tables["Control"]; + + var checkBoxes = new Hashtable(); + var checkBoxProperties = new Hashtable(); + + // index the CheckBox table + if (null != checkBoxTable) + { + foreach (var 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 (var row in controlTable.Rows) + { + var control = (Wix.Control)this.core.GetIndexedElement(row); + + if ("CheckBox" == Convert.ToString(row[2]) && null != row[8]) + { + var checkBoxRow = (Row)checkBoxes[row[8]]; + + if (null == checkBoxRow) + { + this.Messaging.Write(WarningMessages.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) + { + var componentTable = tables["Component"]; + var fileTable = tables["File"]; + var odbcDataSourceTable = tables["ODBCDataSource"]; + var registryTable = tables["Registry"]; + + // set the component keypaths + if (null != componentTable) + { + foreach (var row in componentTable.Rows) + { + var attributes = Convert.ToInt32(row[3]); + + if (null == row[5]) + { + var 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) + { + var registryValue = registryObject as Wix.RegistryValue; + + if (null != registryValue) + { + registryValue.KeyPath = Wix.YesNoType.yes; + } + else + { + this.Messaging.Write(WarningMessages.IllegalRegistryKeyPath(row.SourceLineNumbers, "Component", Convert.ToString(row[5]))); + } + } + else + { + this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, "Component", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "KeyPath", Convert.ToString(row[5]), "Registry")); + } + } + else if (MsiInterop.MsidbComponentAttributesODBCDataSource == (attributes & MsiInterop.MsidbComponentAttributesODBCDataSource)) + { + var odbcDataSource = (Wix.ODBCDataSource)this.core.GetIndexedElement("ODBCDataSource", Convert.ToString(row[5])); + + if (null != odbcDataSource) + { + odbcDataSource.KeyPath = Wix.YesNoType.yes; + } + else + { + this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, "Component", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "KeyPath", Convert.ToString(row[5]), "ODBCDataSource")); + } + } + else + { + var file = (Wix.File)this.core.GetIndexedElement("File", Convert.ToString(row[5])); + + if (null != file) + { + file.KeyPath = Wix.YesNoType.yes; + } + else + { + this.Messaging.Write(WarningMessages.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) + { + var component = (Wix.Component)this.core.GetIndexedElement("Component", fileRow.Component); + var file = (Wix.File)this.core.GetIndexedElement(fileRow); + + if (null != component) + { + component.AddChild(file); + } + else + { + this.Messaging.Write(WarningMessages.ExpectedForeignRow(fileRow.SourceLineNumbers, "File", fileRow.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", fileRow.Component, "Component")); + } + } + } + + // add the ODBCDataSource children elements + if (null != odbcDataSourceTable) + { + foreach (var row in odbcDataSourceTable.Rows) + { + var component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[1])); + var odbcDataSource = (Wix.ODBCDataSource)this.core.GetIndexedElement(row); + + if (null != component) + { + component.AddChild(odbcDataSource); + } + else + { + this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, "ODBCDataSource", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[1]), "Component")); + } + } + } + + // add the Registry children elements + if (null != registryTable) + { + foreach (var row in registryTable.Rows) + { + var component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[5])); + var registryElement = this.core.GetIndexedElement(row); + + if (null != component) + { + component.AddChild(registryElement); + } + else + { + this.Messaging.Write(WarningMessages.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; + } + + var controlTable = tables["Control"]; + var dialogTable = tables["Dialog"]; + + var addedControls = new Hashtable(); + var controlRows = new Hashtable(); + + // index the rows in the control rows (because we need the Control_Next value) + if (null != controlTable) + { + foreach (var row in controlTable.Rows) + { + controlRows.Add(row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), row); + } + } + + if (null != dialogTable) + { + foreach (var row in dialogTable.Rows) + { + var dialog = (Wix.Dialog)this.core.GetIndexedElement(row); + var dialogId = Convert.ToString(row[0]); + + var control = (Wix.Control)this.core.GetIndexedElement("Control", dialogId, Convert.ToString(row[7])); + if (null == control) + { + this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, "Dialog", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Dialog", dialogId, "Control_First", Convert.ToString(row[7]), "Control")); + } + + // add tabbable controls + while (null != control) + { + var 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.Messaging.Write(WarningMessages.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]) + { + var defaultControl = (Wix.Control)this.core.GetIndexedElement("Control", dialogId, Convert.ToString(row[8])); + + if (null != defaultControl) + { + defaultControl.Default = Wix.YesNoType.yes; + } + else + { + this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, "Dialog", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Dialog", dialogId, "Control_Default", Convert.ToString(row[8]), "Control")); + } + } + + // set cancel control + if (null != row[9]) + { + var cancelControl = (Wix.Control)this.core.GetIndexedElement("Control", dialogId, Convert.ToString(row[9])); + + if (null != cancelControl) + { + cancelControl.Cancel = Wix.YesNoType.yes; + } + else + { + this.Messaging.Write(WarningMessages.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 (var row in controlTable.Rows) + { + var control = (Wix.Control)this.core.GetIndexedElement(row); + var dialog = (Wix.Dialog)this.core.GetIndexedElement("Dialog", Convert.ToString(row[0])); + + if (null == dialog) + { + this.Messaging.Write(WarningMessages.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) + { + var duplicateFileTable = tables["DuplicateFile"]; + var moveFileTable = tables["MoveFile"]; + + if (null != duplicateFileTable) + { + foreach (var row in duplicateFileTable.Rows) + { + var 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 (var row in moveFileTable.Rows) + { + var 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) + { + var externalFilesTable = tables["ExternalFiles"]; + var familyFileRangesTable = tables["FamilyFileRanges"]; + var targetFiles_OptionalDataTable = tables["TargetFiles_OptionalData"]; + + var usedProtectRanges = new Hashtable(); + + if (null != familyFileRangesTable) + { + foreach (var row in familyFileRangesTable.Rows) + { + var protectRange = new Wix.ProtectRange(); + + if (null != row[2] && null != row[3]) + { + var retainOffsets = (Convert.ToString(row[2])).Split(','); + var retainLengths = (Convert.ToString(row[3])).Split(','); + + if (retainOffsets.Length == retainLengths.Length) + { + for (var 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 (var row in externalFilesTable.Rows) + { + var externalFile = (Wix.ExternalFile)this.core.GetIndexedElement(row); + + var 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) + { + var targetImagesTable = tables["TargetImages"]; + var upgradedImagesTable = tables["UpgradedImages"]; + + var targetImageRows = new Hashtable(); + var upgradedImagesRows = new Hashtable(); + + // index the TargetImages table + if (null != targetImagesTable) + { + foreach (var row in targetImagesTable.Rows) + { + targetImageRows.Add(row[0], row); + } + } + + // index the UpgradedImages table + if (null != upgradedImagesTable) + { + foreach (var row in upgradedImagesTable.Rows) + { + upgradedImagesRows.Add(row[0], row); + } + } + + foreach (var row in targetFiles_OptionalDataTable.Rows) + { + var targetFile = (Wix.TargetFile)this.patchTargetFiles[row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter)]; + + var targetImageRow = (Row)targetImageRows[row[0]]; + if (null == targetImageRow) + { + this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, targetFiles_OptionalDataTable.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Target", Convert.ToString(row[0]), "TargetImages")); + continue; + } + + var upgradedImagesRow = (Row)upgradedImagesRows[targetImageRow[3]]; + if (null == upgradedImagesRow) + { + this.Messaging.Write(WarningMessages.ExpectedForeignRow(targetImageRow.SourceLineNumbers, targetImageRow.Table.Name, targetImageRow.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Upgraded", Convert.ToString(row[3]), "UpgradedImages")); + continue; + } + + var 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 (var row in familyFileRangesTable.Rows) + { + var protectRange = (Wix.ProtectRange)this.core.GetIndexedElement(row); + + if (!usedProtectRanges.Contains(protectRange)) + { + var protectFile = new Wix.ProtectFile(); + + protectFile.File = Convert.ToString(row[1]); + + protectFile.AddChild(protectRange); + + var family = (Wix.Family)this.core.GetIndexedElement("ImageFamilies", Convert.ToString(row[0])); + if (null != family) + { + family.AddChild(protectFile); + } + else + { + this.Messaging.Write(WarningMessages.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) + { + var classTable = tables["Class"]; + var extensionTable = tables["Extension"]; + var msiAssemblyTable = tables["MsiAssembly"]; + var publishComponentTable = tables["PublishComponent"]; + var shortcutTable = tables["Shortcut"]; + var typeLibTable = tables["TypeLib"]; + + if (null != classTable) + { + foreach (var row in classTable.Rows) + { + this.SetPrimaryFeature(row, 11, 2); + } + } + + if (null != extensionTable) + { + foreach (var row in extensionTable.Rows) + { + this.SetPrimaryFeature(row, 4, 1); + } + } + + if (null != msiAssemblyTable) + { + foreach (var row in msiAssemblyTable.Rows) + { + this.SetPrimaryFeature(row, 1, 0); + } + } + + if (null != publishComponentTable) + { + foreach (var row in publishComponentTable.Rows) + { + this.SetPrimaryFeature(row, 4, 2); + } + } + + if (null != shortcutTable) + { + foreach (var row in shortcutTable.Rows) + { + var target = Convert.ToString(row[4]); + + if (!target.StartsWith("[", StringComparison.Ordinal) && !target.EndsWith("]", StringComparison.Ordinal)) + { + this.SetPrimaryFeature(row, 4, 3); + } + } + } + + if (null != typeLibTable) + { + foreach (var 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) + { + var fileTable = tables["File"]; + var mediaTable = tables["Media"]; + var msiAssemblyTable = tables["MsiAssembly"]; + var 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) + { + var 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 && mediaRow.DiskId != 1) + { + 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.BaseSourcePath, 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.BaseSourcePath, Path.DirectorySeparatorChar, "File", Path.DirectorySeparatorChar, file.Id); + } + else // uncompressed + { + var 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 + { + var sourcePath = this.GetSourcePath(file); + + file.Source = Path.Combine(sourcePath, fileName); + } + } + } + } + } + + // set the file assemblies and manifests + if (null != msiAssemblyTable) + { + foreach (var row in msiAssemblyTable.Rows) + { + var component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[0])); + + if (null == component) + { + this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, "MsiAssembly", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[0]), "Component")); + } + else + { + foreach (Wix.ISchemaElement element in component.Children) + { + var 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 (var row in typeLibTable.Rows) + { + var component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[2])); + var typeLib = (Wix.TypeLib)this.core.GetIndexedElement(row); + + foreach (Wix.ISchemaElement element in component.Children) + { + var 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) + { + var extensionTable = tables["Extension"]; + var mimeTable = tables["MIME"]; + + var comExtensions = new Hashtable(); + + if (null != extensionTable) + { + foreach (var row in extensionTable.Rows) + { + var 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]) + { + var mime = (Wix.MIME)this.core.GetIndexedElement("MIME", Convert.ToString(row[3])); + + if (null != mime) + { + mime.Default = Wix.YesNoType.yes; + } + else + { + this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, "Extension", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "MIME_", Convert.ToString(row[3]), "MIME")); + } + } + } + } + + if (null != mimeTable) + { + foreach (var row in mimeTable.Rows) + { + var mime = (Wix.MIME)this.core.GetIndexedElement(row); + + if (comExtensions.Contains(row[1])) + { + var extensionElements = (ArrayList)comExtensions[row[1]]; + + foreach (Wix.Extension extension in extensionElements) + { + extension.AddChild(mime); + } + } + else + { + this.Messaging.Write(WarningMessages.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) + { + var classTable = tables["Class"]; + var progIdTable = tables["ProgId"]; + var extensionTable = tables["Extension"]; + var componentTable = tables["Component"]; + + var addedProgIds = new Hashtable(); + var classes = new Hashtable(); + var components = new Hashtable(); + + // add the default ProgIds for each class (and index the class table) + if (null != classTable) + { + foreach (var row in classTable.Rows) + { + var wixClass = (Wix.Class)this.core.GetIndexedElement(row); + + if (null != row[3]) + { + var progId = (Wix.ProgId)this.core.GetIndexedElement("ProgId", Convert.ToString(row[3])); + + if (null != progId) + { + if (addedProgIds.Contains(progId)) + { + this.Messaging.Write(WarningMessages.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.Messaging.Write(WarningMessages.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 (var row in progIdTable.Rows) + { + var progId = (Wix.ProgId)this.core.GetIndexedElement(row); + + if (!addedProgIds.Contains(progId) && null != row[2] && null == progId.ParentElement) + { + var classElements = (ArrayList)classes[row[2]]; + + if (null != classElements) + { + foreach (Wix.Class wixClass in classElements) + { + wixClass.AddChild(progId); + addedProgIds.Add(progId, wixClass.Id); + } + } + else + { + this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, "ProgId", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Class_", Convert.ToString(row[2]), "Class")); + } + } + } + } + + if (null != componentTable) + { + foreach (var row in componentTable.Rows) + { + var 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 (var row in extensionTable.Rows) + { + // ignore the extension if it isn't associated with a progId + if (null == row[2]) + { + continue; + } + + var 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) + { + var componentElements = (ArrayList)components[row[1]]; + + if (null != componentElements) + { + foreach (Wix.Component wixComponent in componentElements) + { + wixComponent.AddChild(progId); + } + } + else + { + this.Messaging.Write(WarningMessages.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) + { + var propertyTable = tables["Property"]; + var customActionTable = tables["CustomAction"]; + + if (null != propertyTable && null != customActionTable) + { + foreach (var row in customActionTable.Rows) + { + var bits = Convert.ToInt32(row[1]); + if (MsiInterop.MsidbCustomActionTypeHideTarget == (bits & MsiInterop.MsidbCustomActionTypeHideTarget) && + MsiInterop.MsidbCustomActionTypeInScript == (bits & MsiInterop.MsidbCustomActionTypeInScript)) + { + var 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) + { + var removeFileTable = tables["RemoveFile"]; + + if (null != removeFileTable) + { + foreach (var row in removeFileTable.Rows) + { + var isDirectory = false; + var property = Convert.ToString(row[3]); + + // determine if the property is actually authored as a directory + if (null != this.core.GetIndexedElement("Directory", property)) + { + isDirectory = true; + } + + var element = this.core.GetIndexedElement(row); + + var removeFile = element as Wix.RemoveFile; + if (null != removeFile) + { + if (isDirectory) + { + removeFile.Directory = property; + } + else + { + removeFile.Property = property; + } + } + else + { + var 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) + { + var createFolderTable = tables["CreateFolder"]; + var lockPermissionsTable = tables["LockPermissions"]; + + var 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 (var row in createFolderTable.Rows) + { + var createFolder = (Wix.CreateFolder)this.core.GetIndexedElement(row); + var directoryId = Convert.ToString(row[0]); + + if (!createFolders.Contains(directoryId)) + { + createFolders.Add(directoryId, new ArrayList()); + } + ((ArrayList)createFolders[directoryId]).Add(createFolder); + } + } + + if (null != lockPermissionsTable) + { + foreach (var row in lockPermissionsTable.Rows) + { + var id = Convert.ToString(row[0]); + var table = Convert.ToString(row[1]); + + var permission = (Wix.Permission)this.core.GetIndexedElement(row); + + if ("CreateFolder" == table) + { + var createFolderElements = (ArrayList)createFolders[id]; + + if (null != createFolderElements) + { + foreach (Wix.CreateFolder createFolder in createFolderElements) + { + createFolder.AddChild(permission); + } + } + else + { + this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, "LockPermissions", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "LockObject", id, table)); + } + } + else + { + var parentElement = (Wix.IParentElement)this.core.GetIndexedElement(table, id); + + if (null != parentElement) + { + parentElement.AddChild(permission); + } + else + { + this.Messaging.Write(WarningMessages.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) + { + var createFolderTable = tables["CreateFolder"]; + var msiLockPermissionsExTable = tables["MsiLockPermissionsEx"]; + + var 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 (var row in createFolderTable.Rows) + { + var createFolder = (Wix.CreateFolder)this.core.GetIndexedElement(row); + var directoryId = Convert.ToString(row[0]); + + if (!createFolders.Contains(directoryId)) + { + createFolders.Add(directoryId, new ArrayList()); + } + ((ArrayList)createFolders[directoryId]).Add(createFolder); + } + } + + if (null != msiLockPermissionsExTable) + { + foreach (var row in msiLockPermissionsExTable.Rows) + { + var id = Convert.ToString(row[1]); + var table = Convert.ToString(row[2]); + + var permissionEx = (Wix.PermissionEx)this.core.GetIndexedElement(row); + + if ("CreateFolder" == table) + { + var createFolderElements = (ArrayList)createFolders[id]; + + if (null != createFolderElements) + { + foreach (Wix.CreateFolder createFolder in createFolderElements) + { + createFolder.AddChild(permissionEx); + } + } + else + { + this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, "MsiLockPermissionsEx", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "LockObject", id, table)); + } + } + else + { + var parentElement = (Wix.IParentElement)this.core.GetIndexedElement(table, id); + + if (null != parentElement) + { + parentElement.AddChild(permissionEx); + } + else + { + this.Messaging.Write(WarningMessages.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) + { + var appSearchTable = tables["AppSearch"]; + var ccpSearchTable = tables["CCPSearch"]; + var drLocatorTable = tables["DrLocator"]; + + var appSearches = new Hashtable(); + var ccpSearches = new Hashtable(); + var drLocators = new Hashtable(); + var locators = new Hashtable(); + var usedSearchElements = new Hashtable(); + var unusedSearchElements = new ArrayList(); + + Wix.ComplianceCheck complianceCheck = null; + + // index the AppSearch table by signatures + if (null != appSearchTable) + { + foreach (var row in appSearchTable.Rows) + { + var property = Convert.ToString(row[0]); + var 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 (var row in ccpSearchTable.Rows) + { + var 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 (var row in drLocatorTable.Rows) + { + drLocators.Add(this.core.GetIndexedElement(row), row); + } + } + + // index the locator tables by their signatures + var locatorTableNames = new string[] { "CompLocator", "RegLocator", "IniLocator", "DrLocator", "Signature" }; + foreach (var locatorTableName in locatorTableNames) + { + var locatorTable = tables[locatorTableName]; + + if (null != locatorTable) + { + foreach (var row in locatorTable.Rows) + { + var 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) + { + var firstDrLocator = -1; + + for (var i = 0; i < locatorRows.Count; i++) + { + var 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) + { + var locatorRows = (ArrayList)locators[signature]; + var signatureSearchElements = new ArrayList(); + + foreach (Row locatorRow in locatorRows) + { + var used = true; + var 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 + { + var fileSearchRef = new Wix.FileSearchRef(); + + fileSearchRef.Id = signature; + + searchParentElement.AddChild(fileSearchRef); + } + } + } + else if ("DrLocator" == locatorRow.TableDefinition.Name && null != locatorRow[1]) + { + var parentSignature = Convert.ToString(locatorRow[1]); + + if ("CCP_DRIVE" == parentSignature) + { + if (appSearches.Contains(signature)) + { + var appSearchPropertyIds = (StringCollection)appSearches[signature]; + + foreach (var propertyId in appSearchPropertyIds) + { + var 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 + { + var 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 + { + var 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 + { + var usedDrLocator = false; + var parentLocatorRows = (ArrayList)locators[parentSignature]; + + if (null != parentLocatorRows) + { + foreach (Row parentLocatorRow in parentLocatorRows) + { + if ("DrLocator" == parentLocatorRow.TableDefinition.Name) + { + var parentSearchElement = (Wix.IParentElement)this.core.GetIndexedElement(parentLocatorRow); + + if (parentSearchElement.Children.GetEnumerator().MoveNext()) + { + var parentDrLocatorRow = (Row)drLocators[parentSearchElement]; + var 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 + { + var 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)) + { + var appSearchPropertyIds = (StringCollection)appSearches[signature]; + + foreach (var propertyId in appSearchPropertyIds) + { + var 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) + { + var 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) + { + var 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) + { + var used = false; + + foreach (Wix.ISchemaElement schemaElement in unusedSearchElement.Children) + { + var directorySearch = schemaElement as Wix.DirectorySearch; + if (null != directorySearch) + { + var appSearchProperties = (StringCollection)appSearches[directorySearch.Id]; + + var unusedSearchSchemaElement = unusedSearchElement as Wix.ISchemaElement; + if (null != appSearchProperties) + { + var 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; + } + + var actionsTable = new Table(this.tableDefinitions["WixAction"]); + var table = tables[sequenceTable.ToString()]; + + if (null != table) + { + var actionRows = new ArrayList(); + var needAbsoluteScheduling = this.SuppressRelativeActionSequencing; + var nonSequencedActionRows = new WixActionRowCollection(); + var suppressedRelativeActionRows = new WixActionRowCollection(); + + // create a sorted array of actions in this table + foreach (var row in table.Rows) + { + var 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 (var i = 0; i < actionRows.Count && !needAbsoluteScheduling; i++) + { + var actionRow = (WixActionRow)actionRows[i]; + this.StandardActions.TryGetValue(actionRow.GetPrimaryKey(), out var standardActionRow); + + // 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 && this.StandardActions.ContainsKey(nextActionRow.GetPrimaryKey()) && actionRow.Sequence + 1 == nextActionRow.Sequence) + { + actionRow.Before = nextActionRow.Action; + } + else if (null != previousActionRow && this.StandardActions.ContainsKey(previousActionRow.GetPrimaryKey()) && 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; + } + + var actionsTable = new Table(this.tableDefinitions["WixAction"]); + var table = tables[String.Concat("Module", sequenceTable.ToString())]; + + if (null != table) + { + foreach (var row in table.Rows) + { + var 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.Messaging.Write(WarningMessages.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 (!this.StandardActions.ContainsKey(actionRow.GetPrimaryKey()) || 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) + { + var launchConditionTable = tables["LaunchCondition"]; + var upgradeTable = tables["Upgrade"]; + string downgradeErrorMessage = null; + string disallowUpgradeErrorMessage = null; + var majorUpgrade = new Wix.MajorUpgrade(); + + // find the DowngradePreventedCondition launch condition message + if (null != launchConditionTable && 0 < launchConditionTable.Rows.Count) + { + foreach (var launchRow in launchConditionTable.Rows) + { + if (Common.DowngradePreventedCondition == Convert.ToString(launchRow[0])) + { + downgradeErrorMessage = Convert.ToString(launchRow[1]); + } + else if (Common.UpgradePreventedCondition == Convert.ToString(launchRow[0])) + { + disallowUpgradeErrorMessage = Convert.ToString(launchRow[1]); + } + } + } + + if (null != upgradeTable && 0 < upgradeTable.Rows.Count) + { + var hasMajorUpgrade = false; + + foreach (var row in upgradeTable.Rows) + { + var upgradeRow = (UpgradeRow)row; + + if (Common.UpgradeDetectedProperty == upgradeRow.ActionProperty) + { + hasMajorUpgrade = true; + var attr = upgradeRow.Attributes; + var 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 (Common.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; + } + + var scheduledType = DetermineMajorUpgradeScheduling(tables); + if (Wix.MajorUpgrade.ScheduleType.afterInstallValidate != scheduledType) + { + majorUpgrade.Schedule = scheduledType; + } + + 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) + { + var extensionTable = tables["Extension"]; + var verbTable = tables["Verb"]; + + var extensionElements = new Hashtable(); + + if (null != extensionTable) + { + foreach (var row in extensionTable.Rows) + { + var 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 (var row in verbTable.Rows) + { + var verb = (Wix.Verb)this.core.GetIndexedElement(row); + + var extensionsArray = (ArrayList)extensionElements[row[0]]; + if (null != extensionsArray) + { + foreach (Wix.Extension extension in extensionsArray) + { + extension.AddChild(verb); + } + } + else + { + this.Messaging.Write(WarningMessages.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) + { + var sourcePath = new StringBuilder(); + + var component = (Wix.Component)file.ParentElement; + + for (var 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 (var columnDefinition in this.tableDefinitions[tableName].Columns) + { + // no dependency to resolve because this column doesn't reference another table + if (null == columnDefinition.KeyTable) + { + continue; + } + + foreach (var 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.Messaging.Write(ErrorMessages.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() + { + var sortedTableNames = new StringCollection(); + var unsortedTableNames = new SortedList(); + + // index the table names + foreach (var 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, int codepage) + { + // 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 != codepage) + { + switch (this.OutputType) + { + case OutputType.Module: + ((Wix.Module)this.core.RootElement).Codepage = codepage.ToString(CultureInfo.InvariantCulture); + break; + case OutputType.PatchCreation: + ((Wix.PatchCreation)this.core.RootElement).Codepage = codepage.ToString(CultureInfo.InvariantCulture); + break; + case OutputType.Product: + ((Wix.Product)this.core.RootElement).Codepage = codepage.ToString(CultureInfo.InvariantCulture); + break; + } + } + + // index the rows from the extension libraries + var indexedExtensionTables = new Dictionary>(); +#if TODO_DECOMPILER_EXTENSIONS + 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 (var 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); + } + } + } + } + } + } +#endif + + // remove the rows from the extension libraries (to allow full round-tripping) + foreach (var kvp in indexedExtensionTables) + { + var tableName = kvp.Key; + var indexedExtensionRows = kvp.Value; + + var table = tables[tableName]; + if (null != table) + { + var originalRows = new RowDictionary(table); + + // remove the original rows so that they can be added back if they should remain + table.Rows.Clear(); + + foreach (var 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) + { + var sortedTableNames = this.GetSortedTableNames(); + + foreach (var tableName in sortedTableNames) + { + var 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.Messaging.Write(VerboseMessages.DecompilingTable(table.Name)); + + // empty tables may be kept with EnsureTable if the user set the proper option + if (0 == table.Rows.Count && this.SuppressDroppingEmptyTables) + { + var 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.Messaging.Write(WarningMessages.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.Messaging.Write(WarningMessages.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: +#if TODO_DECOMPILER_EXTENSIONS + if (this.ExtensionsByTableName.TryGetValue(table.Name, out var extension) + { + extension.DecompileTable(table); + } + else +#endif + 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.Messaging.Write(WarningMessages.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.Messaging.Write(WarningMessages.SkippingPatchCreationTable(output.SourceLineNumbers, tableName)); + return false; + } + else + { + return true; + } + case "MsiPatchHeaders": + case "MsiPatchMetadata": + case "MsiPatchOldAssemblyName": + case "MsiPatchOldAssemblyFile": + case "MsiPatchSequence": + case "Patch": + case "PatchPackage": + this.Messaging.Write(WarningMessages.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.Messaging.Write(WarningMessages.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) + { + var package = new Wix.Package(); + + foreach (var row in table.Rows) + { + var 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: + if (!value.StartsWith("This installer database contains the logic and data required to install ")) + { + package.Comments = value; + } + break; + case 7: + var 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: + var 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: + var 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 + { + var patchInformation = new Wix.PatchInformation(); + + foreach (var row in table.Rows) + { + var propertyId = Convert.ToInt32(row[0]); + var 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: + var 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: + var 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: + var 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 (var row in table.Rows) + { + var 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 (var row in table.Rows) + { + var 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) + { + var 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; + } + + var billboard = (Wix.Billboard)this.core.GetIndexedElement("Billboard", bbControlRow.Billboard); + if (null != billboard) + { + billboard.AddChild(control); + } + else + { + this.Messaging.Write(WarningMessages.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) + { + var billboardActions = new Hashtable(); + var billboards = new SortedList(); + + foreach (var row in table.Rows) + { + var 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) + { + var billboard = (Wix.Billboard)this.core.GetIndexedElement(row); + var 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 (var row in table.Rows) + { + var 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 (var row in table.Rows) + { + var file = (Wix.File)this.core.GetIndexedElement("File", Convert.ToString(row[0])); + + if (null != file) + { + file.BindPath = Convert.ToString(row[1]); + } + else + { + this.Messaging.Write(WarningMessages.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 (var row in table.Rows) + { + var 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.Messaging.Write(WarningMessages.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]) + { + var fileTypeMaskStrings = (Convert.ToString(row[6])).Split(';'); + + try + { + foreach (var fileTypeMaskString in fileTypeMaskStrings) + { + var fileTypeMaskParts = fileTypeMaskString.Split(','); + + if (4 == fileTypeMaskParts.Length) + { + var 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.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[6].Column.Name, row[6])); + } + catch (OverflowException) + { + this.Messaging.Write(WarningMessages.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.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[12].Column.Name, row[12])); + } + } + + var component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[2])); + if (null != component) + { + component.AddChild(wixClass); + } + else + { + this.Messaging.Write(WarningMessages.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; + var comboBoxRows = new SortedList(); + + // sort the combo boxes by their property and order + foreach (var 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); + } + + var 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) + { + var 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) + { + var iconSizeSet = false; + + for (var 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.Messaging.Write(WarningMessages.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($"Unknown control attribute: '{attribute}'."); + } + } + } + } + else if (0 < (controlRow.Attributes & 0xFFFF0000)) + { + this.Messaging.Write(WarningMessages.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) + { + var 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 (var row in table.Rows) + { + var 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.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[2].Column.Name, row[2])); + break; + } + + condition.Content = Convert.ToString(row[3]); + + var control = (Wix.Control)this.core.GetIndexedElement("Control", Convert.ToString(row[0]), Convert.ToString(row[1])); + if (null != control) + { + control.AddChild(condition); + } + else + { + this.Messaging.Write(WarningMessages.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) + { + var controlEvents = new SortedList(); + + foreach (var row in table.Rows) + { + var publish = new Wix.Publish(); + + var 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) + { + var control = (Wix.Control)this.core.GetIndexedElement("Control", Convert.ToString(row[0]), Convert.ToString(row[1])); + var publish = (Wix.Publish)this.core.GetIndexedElement(row); + + if (null != control) + { + control.AddChild(publish); + } + else + { + this.Messaging.Write(WarningMessages.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) + { + var customTable = new Wix.CustomTable(); + + this.Messaging.Write(WarningMessages.DecompilingAsCustomTable(table.Rows[0].SourceLineNumbers, table.Name)); + + customTable.Id = table.Name; + + foreach (var columnDefinition in table.Definition.Columns) + { + var 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($"Unknown custom column category '{columnDefinition.Category.ToString()}'."); + } + } + + if (null != columnDefinition.Description) + { + column.Description = columnDefinition.Description; + } + + if (columnDefinition.KeyColumn.HasValue) + { + column.KeyColumn = columnDefinition.KeyColumn.Value; + } + + if (null != columnDefinition.KeyTable) + { + column.KeyTable = columnDefinition.KeyTable; + } + + if (columnDefinition.IsLocalizable) + { + column.Localizable = Wix.YesNoType.yes; + } + + if (columnDefinition.MaxValue.HasValue) + { + column.MaxValue = columnDefinition.MaxValue.Value; + } + + if (columnDefinition.MinValue.HasValue) + { + column.MinValue = columnDefinition.MinValue.Value; + } + + 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($"Unknown custom column modularization type '{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($"Unknown custom column type '{columnDefinition.Type.ToString()}'."); + } + } + + column.Width = columnDefinition.Length; + + customTable.AddChild(column); + } + + foreach (var row in table.Rows) + { + var wixRow = new Wix.Row(); + + foreach (var field in row.Fields) + { + var 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 (var row in table.Rows) + { + var createFolder = new Wix.CreateFolder(); + + createFolder.Directory = Convert.ToString(row[0]); + + var component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[1])); + if (null != component) + { + component.AddChild(createFolder); + } + else + { + this.Messaging.Write(WarningMessages.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 (var row in table.Rows) + { + var customAction = new Wix.CustomAction(); + + customAction.Id = Convert.ToString(row[0]); + + var 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.Messaging.Write(WarningMessages.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.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[1].Column.Name, row[1])); + break; + } + + var 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.Messaging.Write(WarningMessages.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.Messaging.Write(WarningMessages.NestedInstall(row.SourceLineNumbers, table.Name, row.Fields[1].Column.Name, row[1])); + continue; + default: + this.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[1].Column.Name, row[1])); + break; + } + + var 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 (var row in table.Rows) + { + var 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.Messaging.Write(WarningMessages.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 (var row in table.Rows) + { + if (null != row[1]) + { + var component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[0])); + + if (null != component) + { + component.ComPlusFlags = Convert.ToInt32(row[1]); + } + else + { + this.Messaging.Write(WarningMessages.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 (var row in table.Rows) + { + var component = new Wix.Component(); + + component.Id = Convert.ToString(row[0]); + + component.Guid = Convert.ToString(row[1]); + + var 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]) + { + var condition = new Wix.Condition(); + + condition.Content = Convert.ToString(row[4]); + + component.AddChild(condition); + } + + var directory = (Wix.Directory)this.core.GetIndexedElement("Directory", Convert.ToString(row[2])); + if (null != directory) + { + directory.AddChild(component); + } + else + { + this.Messaging.Write(WarningMessages.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 (var row in table.Rows) + { + var condition = new Wix.Condition(); + + condition.Level = Convert.ToInt32(row[1]); + + if (null != row[2]) + { + condition.Content = Convert.ToString(row[2]); + } + + var feature = (Wix.Feature)this.core.GetIndexedElement("Feature", Convert.ToString(row[0])); + if (null != feature) + { + feature.AddChild(condition); + } + else + { + this.Messaging.Write(WarningMessages.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 (var row in table.Rows) + { + var 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]) + { + var 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 (var row in table.Rows) + { + var directory = new Wix.Directory(); + + directory.Id = Convert.ToString(row[0]); + + var names = Common.GetNames(Convert.ToString(row[2])); + + if (String.Equals(directory.Id, "TARGETDIR", StringComparison.Ordinal) && !String.Equals(names[0], "SourceDir", StringComparison.Ordinal)) + { + this.Messaging.Write(WarningMessages.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 (var row in table.Rows) + { + var directory = (Wix.Directory)this.core.GetIndexedElement(row); + + if (null == row[1]) + { + this.core.RootElement.AddChild(directory); + } + else + { + var parentDirectory = (Wix.Directory)this.core.GetIndexedElement("Directory", Convert.ToString(row[1])); + + if (null == parentDirectory) + { + this.Messaging.Write(WarningMessages.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 (var row in table.Rows) + { + var 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 (var row in table.Rows) + { + var copyFile = new Wix.CopyFile(); + + copyFile.Id = Convert.ToString(row[0]); + + copyFile.FileId = Convert.ToString(row[2]); + + if (null != row[3]) + { + var 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 + + var component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[1])); + if (null != component) + { + component.AddChild(copyFile); + } + else + { + this.Messaging.Write(WarningMessages.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 (var row in table.Rows) + { + var environment = new Wix.Environment(); + + environment.Id = Convert.ToString(row[0]); + + var done = false; + var permanent = true; + var name = Convert.ToString(row[1]); + for (var 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]) + { + var 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; + } + } + + var component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[3])); + if (null != component) + { + component.AddChild(environment); + } + else + { + this.Messaging.Write(WarningMessages.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 (var row in table.Rows) + { + var 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 (var row in table.Rows) + { + var subscribe = new Wix.Subscribe(); + + subscribe.Event = Convert.ToString(row[2]); + + subscribe.Attribute = Convert.ToString(row[3]); + + var control = (Wix.Control)this.core.GetIndexedElement("Control", Convert.ToString(row[0]), Convert.ToString(row[1])); + if (null != control) + { + control.AddChild(subscribe); + } + else + { + this.Messaging.Write(WarningMessages.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 (var row in table.Rows) + { + var extension = new Wix.Extension(); + + extension.Advertise = Wix.YesNoType.yes; + + extension.Id = Convert.ToString(row[0]); + + if (null != row[3]) + { + var mime = (Wix.MIME)this.core.GetIndexedElement("MIME", Convert.ToString(row[3])); + + if (null != mime) + { + mime.Default = Wix.YesNoType.yes; + } + else + { + this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "MIME_", Convert.ToString(row[3]), "MIME")); + } + } + + if (null != row[2]) + { + var progId = (Wix.ProgId)this.core.GetIndexedElement("ProgId", Convert.ToString(row[2])); + + if (null != progId) + { + progId.AddChild(extension); + } + else + { + this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "ProgId_", Convert.ToString(row[2]), "ProgId")); + } + } + else + { + var component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[1])); + + if (null != component) + { + component.AddChild(extension); + } + else + { + this.Messaging.Write(WarningMessages.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 (var row in table.Rows) + { + var externalFile = new Wix.ExternalFile(); + + externalFile.File = Convert.ToString(row[1]); + + externalFile.Source = Convert.ToString(row[2]); + + if (null != row[3]) + { + var symbolPaths = (Convert.ToString(row[3])).Split(';'); + + foreach (var symbolPathString in symbolPaths) + { + var symbolPath = new Wix.SymbolPath(); + + symbolPath.Path = symbolPathString; + + externalFile.AddChild(symbolPath); + } + } + + if (null != row[4] && null != row[5]) + { + var ignoreOffsets = (Convert.ToString(row[4])).Split(','); + var ignoreLengths = (Convert.ToString(row[5])).Split(','); + + if (ignoreOffsets.Length == ignoreLengths.Length) + { + for (var i = 0; i < ignoreOffsets.Length; i++) + { + var 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]); + } + + var family = (Wix.Family)this.core.GetIndexedElement("ImageFamilies", Convert.ToString(row[0])); + if (null != family) + { + family.AddChild(externalFile); + } + else + { + this.Messaging.Write(WarningMessages.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) + { + var sortedFeatures = new SortedList(); + + foreach (var row in table.Rows) + { + var 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 + { + var 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]); + } + + var 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.Messaging.Write(WarningMessages.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) + { + var feature = (Wix.Feature)this.core.GetIndexedElement("Feature", Convert.ToString(row[0])); + + if (null == row[1]) + { + this.core.RootElement.AddChild(feature); + } + else + { + var parentFeature = (Wix.Feature)this.core.GetIndexedElement("Feature", Convert.ToString(row[1])); + + if (null == parentFeature) + { + this.Messaging.Write(WarningMessages.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 (var row in table.Rows) + { + var componentRef = new Wix.ComponentRef(); + + componentRef.Id = Convert.ToString(row[1]); + + var parentFeature = (Wix.Feature)this.core.GetIndexedElement("Feature", Convert.ToString(row[0])); + if (null != parentFeature) + { + parentFeature.AddChild(componentRef); + } + else + { + this.Messaging.Write(WarningMessages.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) + { + var file = new Wix.File(); + + file.Id = fileRow.File; + + var 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 (var row in table.Rows) + { + var sfpFile = new Wix.SFPFile(); + + sfpFile.Id = Convert.ToString(row[0]); + + var sfpCatalog = (Wix.SFPCatalog)this.core.GetIndexedElement("SFPCatalog", Convert.ToString(row[1])); + if (null != sfpCatalog) + { + sfpCatalog.AddChild(sfpFile); + } + else + { + this.Messaging.Write(WarningMessages.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 (var row in table.Rows) + { + var 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.Messaging.Write(WarningMessages.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 (var row in table.Rows) + { + var 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 (var row in table.Rows) + { + var 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 (var row in table.Rows) + { + var iniFile = new Wix.IniFile(); + + iniFile.Id = Convert.ToString(row[0]); + + var 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.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[6].Column.Name, row[6])); + break; + } + + var component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[7])); + if (null != component) + { + component.AddChild(iniFile); + } + else + { + this.Messaging.Write(WarningMessages.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 (var row in table.Rows) + { + var iniFileSearch = new Wix.IniFileSearch(); + + iniFileSearch.Id = Convert.ToString(row[0]); + + var 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]) + { + var 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.Messaging.Write(WarningMessages.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 (var row in table.Rows) + { + var isolateComponent = new Wix.IsolateComponent(); + + isolateComponent.Shared = Convert.ToString(row[0]); + + var component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[1])); + if (null != component) + { + component.AddChild(isolateComponent); + } + else + { + this.Messaging.Write(WarningMessages.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 (var row in table.Rows) + { + if (Common.DowngradePreventedCondition == Convert.ToString(row[0]) || Common.UpgradePreventedCondition == Convert.ToString(row[0])) + { + continue; // MajorUpgrade rows processed in FinalizeUpgradeTable + } + + var 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; + var listBoxRows = new SortedList(); + + // sort the list boxes by their property and order + foreach (var 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); + } + + var 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; + var listViewRows = new SortedList(); + + // sort the list views by their property and order + foreach (var 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); + } + + var 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 (var row in table.Rows) + { + var 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.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, row.Table.Name, row.Fields[1].Column.Name, row[1])); + return; + } + + var permissionBits = Convert.ToInt32(row[4]); + for (var 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.Messaging.Write(WarningMessages.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($"Unknown permission attribute '{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) + { + var media = new Wix.Media(); + + media.Id = Convert.ToString(mediaRow.DiskId); + + if (null != mediaRow.DiskPrompt) + { + media.DiskPrompt = mediaRow.DiskPrompt; + } + + if (null != mediaRow.Cabinet) + { + var 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 (var row in table.Rows) + { + var 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 (var row in table.Rows) + { + var 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.Messaging.Write(WarningMessages.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]) + { + var 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.Messaging.Write(WarningMessages.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 (var row in table.Rows) + { + var 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 (var row in table.Rows) + { + var exclusion = new Wix.Exclusion(); + + exclusion.ExcludedId = Convert.ToString(row[2]); + + var 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 (var row in table.Rows) + { + var tableName = Convert.ToString(row[0]); + + // the linker automatically adds a ModuleIgnoreTable row for some tables + if ("ModuleConfiguration" != tableName && "ModuleSubstitution" != tableName) + { + var 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) + { + var row = table.Rows[0]; + + var 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 (var row in table.Rows) + { + var 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 (var row in table.Rows) + { + var copyFile = new Wix.CopyFile(); + + copyFile.Id = Convert.ToString(row[0]); + + if (null != row[2]) + { + copyFile.SourceName = Convert.ToString(row[2]); + } + + if (null != row[3]) + { + var 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.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[6].Column.Name, row[6])); + break; + } + + var component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[1])); + if (null != component) + { + component.AddChild(copyFile); + } + else + { + this.Messaging.Write(WarningMessages.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 (var row in table.Rows) + { + var 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 (var row in table.Rows) + { + var digitalSignature = new Wix.DigitalSignature(); + + if (null != row[3]) + { + digitalSignature.SourceFile = Convert.ToString(row[3]); + } + + var digitalCertificate = (Wix.DigitalCertificate)this.core.GetIndexedElement("MsiDigitalCertificate", Convert.ToString(row[2])); + if (null != digitalCertificate) + { + digitalSignature.AddChild(digitalCertificate); + } + else + { + this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "DigitalCertificate_", Convert.ToString(row[2]), "MsiDigitalCertificate")); + } + + var parentElement = (Wix.IParentElement)this.core.GetIndexedElement(Convert.ToString(row[0]), Convert.ToString(row[1])); + if (null != parentElement) + { + parentElement.AddChild(digitalSignature); + } + else + { + this.Messaging.Write(WarningMessages.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 (var row in table.Rows) + { + var 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.Messaging.Write(WarningMessages.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) + { + var embeddedUI = new Wix.EmbeddedUI(); + var foundEmbeddedUI = false; + var foundEmbeddedResources = false; + + foreach (var row in table.Rows) + { + var attributes = Convert.ToInt32(row[2]); + + if (MsiInterop.MsidbEmbeddedUI == (attributes & MsiInterop.MsidbEmbeddedUI)) + { + if (foundEmbeddedUI) + { + this.Messaging.Write(WarningMessages.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]); + + var 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 + { + var 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 (var row in table.Rows) + { + var permissionEx = new Wix.PermissionEx(); + permissionEx.Id = Convert.ToString(row[0]); + permissionEx.Sddl = Convert.ToString(row[3]); + + if (null != row[4]) + { + var 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.Messaging.Write(WarningMessages.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) + { + var packageCertificates = new Wix.PackageCertificates(); + this.core.RootElement.AddChild(packageCertificates); + this.AddCertificates(table, packageCertificates); + } + } + + /// + /// Decompile the MsiPatchCertificate table. + /// + /// The table to decompile. + private void DecompileMsiPatchCertificateTable(Table table) + { + if (0 < table.Rows.Count) + { + var patchCertificates = new Wix.PatchCertificates(); + this.core.RootElement.AddChild(patchCertificates); + this.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 (var row in table.Rows) + { + var digitalCertificate = (Wix.DigitalCertificate)this.core.GetIndexedElement("MsiDigitalCertificate", Convert.ToString(row[1])); + + if (null != digitalCertificate) + { + parent.AddChild(digitalCertificate); + } + else + { + this.Messaging.Write(WarningMessages.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 (var row in table.Rows) + { + var property = new Wix.ShortcutProperty(); + property.Id = Convert.ToString(row[0]); + property.Key = Convert.ToString(row[2]); + property.Value = Convert.ToString(row[3]); + + var shortcut = (Wix.Shortcut)this.core.GetIndexedElement("Shortcut", Convert.ToString(row[1])); + if (null != shortcut) + { + shortcut.AddChild(property); + } + else + { + this.Messaging.Write(WarningMessages.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 (var row in table.Rows) + { + var property = new Wix.Property(); + + property.Id = Convert.ToString(row[1]); + + if (null != row[2]) + { + property.Value = Convert.ToString(row[2]); + } + + var odbcDriver = (Wix.ODBCDriver)this.core.GetIndexedElement("ODBCDriver", Convert.ToString(row[0])); + if (null != odbcDriver) + { + odbcDriver.AddChild(property); + } + else + { + this.Messaging.Write(WarningMessages.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 (var row in table.Rows) + { + var 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.Messaging.Write(WarningMessages.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 (var row in table.Rows) + { + var 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]); + } + + var component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[1])); + if (null != component) + { + component.AddChild(odbcDriver); + } + else + { + this.Messaging.Write(WarningMessages.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 (var row in table.Rows) + { + var property = new Wix.Property(); + + property.Id = Convert.ToString(row[1]); + + if (null != row[2]) + { + property.Value = Convert.ToString(row[2]); + } + + var odbcDataSource = (Wix.ODBCDataSource)this.core.GetIndexedElement("ODBCDataSource", Convert.ToString(row[0])); + if (null != odbcDataSource) + { + odbcDataSource.AddChild(property); + } + else + { + this.Messaging.Write(WarningMessages.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 (var row in table.Rows) + { + var 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]); + } + + var component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[1])); + if (null != component) + { + component.AddChild(odbcTranslator); + } + else + { + this.Messaging.Write(WarningMessages.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) + { + var patchMetadata = new Wix.PatchMetadata(); + + foreach (var row in table.Rows) + { + var 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": + var optimizeCustomActions = new Wix.OptimizeCustomActions(); + var 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: + var 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 (var row in table.Rows) + { + var patchSequence = new Wix.PatchSequence(); + + patchSequence.PatchFamily = Convert.ToString(row[0]); + + if (null != row[1]) + { + try + { + var 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 (var row in table.Rows) + { + var 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 (var row in table.Rows) + { + var progId = (Wix.ProgId)this.core.GetIndexedElement(row); + + if (null != row[1]) + { + var parentProgId = (Wix.ProgId)this.core.GetIndexedElement("ProgId", Convert.ToString(row[1])); + + if (null != parentProgId) + { + parentProgId.AddChild(progId); + } + else + { + this.Messaging.Write(WarningMessages.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) + { + var patchCreation = (Wix.PatchCreation)this.core.RootElement; + + foreach (var row in table.Rows) + { + var name = Convert.ToString(row[0]); + var 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.Messaging.Write(WarningMessages.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) + { + var guidRegex = new Regex(@"\{[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}\}"); + var guidMatches = guidRegex.Matches(value); + + foreach (Match guidMatch in guidMatches) + { + var replacePatch = new Wix.ReplacePatch(); + + replacePatch.Id = guidMatch.Value; + + this.core.RootElement.AddChild(replacePatch); + } + } + break; + case "ListOfTargetProductCodes": + if (null != value) + { + var targetProductCodes = value.Split(';'); + + foreach (var targetProductCodeString in targetProductCodes) + { + var 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: + var 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 (var row in table.Rows) + { + var id = Convert.ToString(row[0]); + var value = Convert.ToString(row[1]); + + if ("AdminProperties" == id || "MsiHiddenProperties" == id || "SecureCustomProperties" == id) + { + if (0 < value.Length) + { + foreach (var propertyId in value.Split(';')) + { + if (Common.DowngradeDetectedProperty == propertyId || Common.UpgradeDetectedProperty == propertyId) + { + continue; + } + + var property = propertyId; + var 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; + } + } + + var 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) + { + var 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) + { + var property = this.EnsureProperty(id); + + property.Value = value; + } + } + } + + /// + /// Decompile the PublishComponent table. + /// + /// The table to decompile. + private void DecompilePublishComponentTable(Table table) + { + foreach (var row in table.Rows) + { + var 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]); + } + + var component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[2])); + if (null != component) + { + component.AddChild(category); + } + else + { + this.Messaging.Write(WarningMessages.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) + { + var radioButtons = new SortedList(); + var radioButtonGroups = new Hashtable(); + + foreach (var row in table.Rows) + { + var 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]) + { + var 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) + { + var radioButton = (Wix.RadioButton)this.core.GetIndexedElement(row); + var 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 (var row in table.Rows) + { + if (("-" == Convert.ToString(row[3]) || "+" == Convert.ToString(row[3]) || "*" == Convert.ToString(row[3])) && null == row[4]) + { + var registryKey = new Wix.RegistryKey(); + + registryKey.Id = Convert.ToString(row[0]); + + if (this.GetRegistryRootType(row.SourceLineNumbers, table.Name, row.Fields[1], out var 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 + { + var registryValue = new Wix.RegistryValue(); + + registryValue.Id = Convert.ToString(row[0]); + + if (this.GetRegistryRootType(row.SourceLineNumbers, table.Name, row.Fields[1], out var registryRootType)) + { + registryValue.Root = registryRootType; + } + + registryValue.Key = Convert.ToString(row[2]); + + if (null != row[3]) + { + registryValue.Name = Convert.ToString(row[3]); + } + + if (null != row[4]) + { + var 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); + } + + var multiValues = NullSplitter.Split(value); + foreach (var multiValue in multiValues) + { + var 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 (var row in table.Rows) + { + var 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.Messaging.Write(WarningMessages.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 + { + var 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.Messaging.Write(WarningMessages.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 (var row in table.Rows) + { + if (null == row[2]) + { + var 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.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[4].Column.Name, row[4])); + break; + } + + var component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[1])); + if (null != component) + { + component.AddChild(removeFolder); + } + else + { + this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[1]), "Component")); + } + this.core.IndexElement(row, removeFolder); + } + else + { + var removeFile = new Wix.RemoveFile(); + + removeFile.Id = Convert.ToString(row[0]); + + var 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.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[4].Column.Name, row[4])); + break; + } + + var component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[1])); + if (null != component) + { + component.AddChild(removeFile); + } + else + { + this.Messaging.Write(WarningMessages.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 (var row in table.Rows) + { + var iniFile = new Wix.IniFile(); + + iniFile.Id = Convert.ToString(row[0]); + + var 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.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[6].Column.Name, row[6])); + break; + } + + var component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[7])); + if (null != component) + { + component.AddChild(iniFile); + } + else + { + this.Messaging.Write(WarningMessages.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 (var row in table.Rows) + { + if ("-" == Convert.ToString(row[3])) + { + var removeRegistryKey = new Wix.RemoveRegistryKey(); + + removeRegistryKey.Id = Convert.ToString(row[0]); + + if (this.GetRegistryRootType(row.SourceLineNumbers, table.Name, row.Fields[1], out var registryRootType)) + { + removeRegistryKey.Root = registryRootType; + } + + removeRegistryKey.Key = Convert.ToString(row[2]); + + removeRegistryKey.Action = Wix.RemoveRegistryKey.ActionType.removeOnInstall; + + var component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[4])); + if (null != component) + { + component.AddChild(removeRegistryKey); + } + else + { + this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[4]), "Component")); + } + } + else + { + var removeRegistryValue = new Wix.RemoveRegistryValue(); + + removeRegistryValue.Id = Convert.ToString(row[0]); + + if (this.GetRegistryRootType(row.SourceLineNumbers, table.Name, row.Fields[1], out var registryRootType)) + { + removeRegistryValue.Root = registryRootType; + } + + removeRegistryValue.Key = Convert.ToString(row[2]); + + if (null != row[3]) + { + removeRegistryValue.Name = Convert.ToString(row[3]); + } + + var component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[4])); + if (null != component) + { + component.AddChild(removeRegistryValue); + } + else + { + this.Messaging.Write(WarningMessages.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 (var row in table.Rows) + { + var 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]); + + var component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[1])); + if (null != component) + { + component.AddChild(reserveCost); + } + else + { + this.Messaging.Write(WarningMessages.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 (var row in table.Rows) + { + var 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.Messaging.Write(WarningMessages.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 (var row in table.Rows) + { + var serviceControl = new Wix.ServiceControl(); + + serviceControl.Id = Convert.ToString(row[0]); + + serviceControl.Name = Convert.ToString(row[1]); + + var 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]) + { + var arguments = NullSplitter.Split(Convert.ToString(row[3])); + + foreach (var argument in arguments) + { + var 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; + } + } + + var component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[5])); + if (null != component) + { + component.AddChild(serviceControl); + } + else + { + this.Messaging.Write(WarningMessages.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 (var row in table.Rows) + { + var 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]); + } + + var 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; + } + + var 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.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[4].Column.Name, row[4])); + } + + var 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]) + { + var dependencies = NullSplitter.Split(Convert.ToString(row[7])); + + foreach (var dependency in dependencies) + { + if (0 < dependency.Length) + { + var 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]); + } + + var component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[11])); + if (null != component) + { + component.AddChild(serviceInstall); + } + else + { + this.Messaging.Write(WarningMessages.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 (var row in table.Rows) + { + var 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 (var row in table.Rows) + { + var sfpCatalog = (Wix.SFPCatalog)this.core.GetIndexedElement(row); + + if (null != row[2]) + { + var 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 (var row in table.Rows) + { + var shortcut = new Wix.Shortcut(); + + shortcut.Id = Convert.ToString(row[0]); + + shortcut.Directory = Convert.ToString(row[1]); + + var 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]; + } + + var 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.Messaging.Write(WarningMessages.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]); + } + } + + var component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[3])); + if (null != component) + { + component.AddChild(shortcut); + } + else + { + this.Messaging.Write(WarningMessages.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 (var row in table.Rows) + { + var fileSearch = new Wix.FileSearch(); + + fileSearch.Id = Convert.ToString(row[0]); + + var 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 (var row in table.Rows) + { + var targetFile = (Wix.TargetFile)this.patchTargetFiles[row[0]]; + if (null == targetFile) + { + targetFile = new Wix.TargetFile(); + + targetFile.Id = Convert.ToString(row[1]); + + var targetImage = (Wix.TargetImage)this.core.GetIndexedElement("TargetImages", Convert.ToString(row[0])); + if (null != targetImage) + { + targetImage.AddChild(targetFile); + } + else + { + this.Messaging.Write(WarningMessages.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]) + { + var symbolPaths = (Convert.ToString(row[2])).Split(';'); + + foreach (var symbolPathString in symbolPaths) + { + var symbolPath = new Wix.SymbolPath(); + + symbolPath.Path = symbolPathString; + + targetFile.AddChild(symbolPath); + } + } + + if (null != row[3] && null != row[4]) + { + var ignoreOffsets = (Convert.ToString(row[3])).Split(','); + var ignoreLengths = (Convert.ToString(row[4])).Split(','); + + if (ignoreOffsets.Length == ignoreLengths.Length) + { + for (var i = 0; i < ignoreOffsets.Length; i++) + { + var 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 (var row in table.Rows) + { + var targetImage = new Wix.TargetImage(); + + targetImage.Id = Convert.ToString(row[0]); + + targetImage.SourceFile = Convert.ToString(row[1]); + + if (null != row[2]) + { + var symbolPaths = (Convert.ToString(row[3])).Split(';'); + + foreach (var symbolPathString in symbolPaths) + { + var 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; + } + + var upgradeImage = (Wix.UpgradeImage)this.core.GetIndexedElement("UpgradedImages", Convert.ToString(row[3])); + if (null != upgradeImage) + { + upgradeImage.AddChild(targetImage); + } + else + { + this.Messaging.Write(WarningMessages.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 (var row in table.Rows) + { + var 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]) + { + var color = Convert.ToInt32(row[3]); + + textStyle.Red = color & 0xFF; + + textStyle.Green = (color & 0xFF00) >> 8; + + textStyle.Blue = (color & 0xFF0000) >> 16; + } + + if (null != row[4]) + { + var 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 (var row in table.Rows) + { + var 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]) + { + var version = Convert.ToInt32(row[3]); + + if (65536 == version) + { + this.Messaging.Write(WarningMessages.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) + { + var upgradeElements = new Hashtable(); + + foreach (UpgradeRow upgradeRow in table.Rows) + { + if (Common.UpgradeDetectedProperty == upgradeRow.ActionProperty || Common.DowngradeDetectedProperty == upgradeRow.ActionProperty) + { + continue; // MajorUpgrade rows processed in FinalizeUpgradeTable + } + + var 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); + } + + var 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 (var row in table.Rows) + { + var upgradeFile = new Wix.UpgradeFile(); + + upgradeFile.File = Convert.ToString(row[1]); + + if (null != row[2]) + { + var symbolPaths = (Convert.ToString(row[2])).Split(';'); + + foreach (var symbolPathString in symbolPaths) + { + var 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; + + var upgradeImage = (Wix.UpgradeImage)this.core.GetIndexedElement("UpgradedImages", Convert.ToString(row[0])); + if (null != upgradeImage) + { + upgradeImage.AddChild(upgradeFile); + } + else + { + this.Messaging.Write(WarningMessages.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 (var row in table.Rows) + { + if ("*" != Convert.ToString(row[0])) + { + var upgradeFile = new Wix.UpgradeFile(); + + upgradeFile.File = Convert.ToString(row[1]); + + upgradeFile.Ignore = Wix.YesNoType.yes; + + var upgradeImage = (Wix.UpgradeImage)this.core.GetIndexedElement("UpgradedImages", Convert.ToString(row[0])); + if (null != upgradeImage) + { + upgradeImage.AddChild(upgradeFile); + } + else + { + this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Upgraded", Convert.ToString(row[0]), "UpgradedImages")); + } + } + else + { + this.Messaging.Write(WarningMessages.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 (var row in table.Rows) + { + var 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]) + { + var symbolPaths = (Convert.ToString(row[3])).Split(';'); + + foreach (var symbolPathString in symbolPaths) + { + var symbolPath = new Wix.SymbolPath(); + + symbolPath.Path = symbolPathString; + + upgradeImage.AddChild(symbolPath); + } + } + + var family = (Wix.Family)this.core.GetIndexedElement("ImageFamilies", Convert.ToString(row[4])); + if (null != family) + { + family.AddChild(upgradeImage); + } + else + { + this.Messaging.Write(WarningMessages.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 (var row in table.Rows) + { + var 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 (var row in table.Rows) + { + var 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.Messaging.Write(WarningMessages.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) + { + var featureField = row.Fields[featureColumnIndex]; + var componentField = row.Fields[componentColumnIndex]; + + var 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.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, row.TableDefinition.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), featureField.Column.Name, Convert.ToString(featureField.Data), componentField.Column.Name, Convert.ToString(componentField.Data), "FeatureComponents")); + } + } + } + + /// + /// 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) + { + var sequenceRemoveExistingProducts = 0; + var sequenceInstallValidate = 0; + var sequenceInstallInitialize = 0; + var sequenceInstallFinalize = 0; + var sequenceInstallExecute = 0; + var sequenceInstallExecuteAgain = 0; + + var installExecuteSequenceTable = tables["InstallExecuteSequence"]; + if (null != installExecuteSequenceTable) + { + var removeExistingProductsRow = -1; + for (var i = 0; i < installExecuteSequenceTable.Rows.Count; i++) + { + var row = installExecuteSequenceTable.Rows[i]; + var action = Convert.ToString(row[0]); + var 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; + } + } + } +} diff --git a/src/WixToolset.Core.WindowsInstaller/Decompile/DecompilerCore.cs b/src/WixToolset.Core.WindowsInstaller/Decompile/DecompilerCore.cs new file mode 100644 index 00000000..17c97e09 --- /dev/null +++ b/src/WixToolset.Core.WindowsInstaller/Decompile/DecompilerCore.cs @@ -0,0 +1,110 @@ +// 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 WixToolset.Data.WindowsInstaller; + using WixToolset.Extensibility; + using Wix = WixToolset.Data.Serialize; + + /// + /// The base of the decompiler. Holds some variables used by the decompiler and extensions, + /// as well as some utility methods. + /// + internal class DecompilerCore + { + private readonly Hashtable elements; + private Wix.UI uiElement; + + /// + /// Instantiate a new decompiler core. + /// + /// The root element of the decompiled database. + /// The message handler. + internal DecompilerCore(Wix.IParentElement rootElement) + { + this.elements = new Hashtable(); + this.RootElement = rootElement; + } + + /// + /// Gets the root element of the decompiled output. + /// + /// The root element of the decompiled output. + public Wix.IParentElement RootElement { get; } + + /// + /// Gets the UI element. + /// + /// The UI element. + public Wix.UI UIElement + { + get + { + if (null == this.uiElement) + { + this.uiElement = new Wix.UI(); + this.RootElement.AddChild(this.uiElement); + } + + return this.uiElement; + } + } + + /// + /// Verifies if a filename is a valid short filename. + /// + /// Filename to verify. + /// true if wildcards are allowed in the filename. + /// True if the filename is a valid short filename + public virtual bool IsValidShortFilename(string filename, bool allowWildcards) + { + return false; + } + + /// + /// Convert an Int32 into a DateTime. + /// + /// The Int32 value. + /// The DateTime. + public DateTime ConvertIntegerToDateTime(int value) + { + var date = value / 65536; + var time = value % 65536; + + return new DateTime(1980 + (date / 512), (date % 512) / 32, date % 32, time / 2048, (time % 2048) / 32, (time % 32) * 2); + } + + /// + /// Gets the element corresponding to the row it came from. + /// + /// The row corresponding to the element. + /// The indexed element. + public Wix.ISchemaElement GetIndexedElement(Row row) + { + return this.GetIndexedElement(row.TableDefinition.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter)); + } + + /// + /// Gets the element corresponding to the primary key of the given table. + /// + /// The table corresponding to the element. + /// The primary key corresponding to the element. + /// The indexed element. + public Wix.ISchemaElement GetIndexedElement(string table, params string[] primaryKey) + { + return (Wix.ISchemaElement)this.elements[String.Concat(table, ':', String.Join(DecompilerConstants.PrimaryKeyDelimiterString, primaryKey))]; + } + + /// + /// Index an element by its corresponding row. + /// + /// The row corresponding to the element. + /// The element to index. + public void IndexElement(Row row, Wix.ISchemaElement element) + { + this.elements.Add(String.Concat(row.TableDefinition.Name, ':', row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter)), element); + } + } +} diff --git a/src/WixToolset.Core.WindowsInstaller/Decompiler.cs b/src/WixToolset.Core.WindowsInstaller/Decompiler.cs deleted file mode 100644 index c5d68db3..00000000 --- a/src/WixToolset.Core.WindowsInstaller/Decompiler.cs +++ /dev/null @@ -1,9356 +0,0 @@ -// 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.Core.WindowsInstaller -{ - 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.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 - } -} diff --git a/src/WixToolset.Core.WindowsInstaller/DecompilerCore.cs b/src/WixToolset.Core.WindowsInstaller/DecompilerCore.cs deleted file mode 100644 index 2be986fc..00000000 --- a/src/WixToolset.Core.WindowsInstaller/DecompilerCore.cs +++ /dev/null @@ -1,154 +0,0 @@ -// 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 WixToolset.Data; - using WixToolset.Extensibility; - using Wix = WixToolset.Data.Serialize; - -#if TODO - /// - /// The base of the decompiler. Holds some variables used by the decompiler and extensions, - /// as well as some utility methods. - /// - internal class DecompilerCore : IDecompilerCore - { - private Hashtable elements; - private Wix.IParentElement rootElement; - private bool showPedanticMessages; - private Wix.UI uiElement; - - /// - /// Instantiate a new decompiler core. - /// - /// The root element of the decompiled database. - /// The message handler. - internal DecompilerCore(Wix.IParentElement rootElement) - { - this.elements = new Hashtable(); - this.rootElement = rootElement; - } - - /// - /// Gets whether the decompiler core encountered an error while processing. - /// - /// Flag if core encountered an error during processing. - public bool EncounteredError - { - get { return Messaging.Instance.EncounteredError; } - } - - /// - /// Gets the root element of the decompiled output. - /// - /// The root element of the decompiled output. - public Wix.IParentElement RootElement - { - get { return this.rootElement; } - } - - /// - /// 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 the UI element. - /// - /// The UI element. - public Wix.UI UIElement - { - get - { - if (null == this.uiElement) - { - this.uiElement = new Wix.UI(); - this.rootElement.AddChild(this.uiElement); - } - - return this.uiElement; - } - } - - /// - /// Verifies if a filename is a valid short filename. - /// - /// Filename to verify. - /// true if wildcards are allowed in the filename. - /// True if the filename is a valid short filename - public virtual bool IsValidShortFilename(string filename, bool allowWildcards) - { - return false; - } - - /// - /// Convert an Int32 into a DateTime. - /// - /// The Int32 value. - /// The DateTime. - public DateTime ConvertIntegerToDateTime(int value) - { - int date = value / 65536; - int time = value % 65536; - - return new DateTime(1980 + (date / 512), (date % 512) / 32, date % 32, time / 2048, (time % 2048) / 32, (time % 32) * 2); - } - - /// - /// Gets the element corresponding to the row it came from. - /// - /// The row corresponding to the element. - /// The indexed element. - public Wix.ISchemaElement GetIndexedElement(Row row) - { - return this.GetIndexedElement(row.TableDefinition.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter)); - } - - /// - /// Gets the element corresponding to the primary key of the given table. - /// - /// The table corresponding to the element. - /// The primary key corresponding to the element. - /// The indexed element. - public Wix.ISchemaElement GetIndexedElement(string table, params string[] primaryKey) - { - return (Wix.ISchemaElement)this.elements[String.Concat(table, ':', String.Join(DecompilerConstants.PrimaryKeyDelimiterString, primaryKey))]; - } - - /// - /// Index an element by its corresponding row. - /// - /// The row corresponding to the element. - /// The element to index. - public void IndexElement(Row row, Wix.ISchemaElement element) - { - this.elements.Add(String.Concat(row.TableDefinition.Name, ':', row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter)), element); - } - - /// - /// Indicates the decompiler encountered and unexpected table to decompile. - /// - /// Unknown decompiled table. - public void UnexpectedTable(Table table) - { - this.OnMessage(WixErrors.TableDecompilationUnimplemented(table.Name)); - } - - /// - /// Sends a message to the message delegate if there is one. - /// - /// Message event arguments. - public void OnMessage(MessageEventArgs e) - { - Messaging.Instance.OnMessage(e); - } - } -#endif -} diff --git a/src/WixToolset.Core.WindowsInstaller/MsiBackend.cs b/src/WixToolset.Core.WindowsInstaller/MsiBackend.cs index 579977fe..b633ea31 100644 --- a/src/WixToolset.Core.WindowsInstaller/MsiBackend.cs +++ b/src/WixToolset.Core.WindowsInstaller/MsiBackend.cs @@ -1,4 +1,4 @@ -// 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. +// 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.Core.WindowsInstaller { @@ -38,9 +38,26 @@ namespace WixToolset.Core.WindowsInstaller return result; } - public BindResult Decompile(IDecompileContext context) + public DecompileResult Decompile(IDecompileContext context) { - throw new NotImplementedException(); + var extensionManager = context.ServiceProvider.GetService(); + + var backendExtensions = extensionManager.Create(); + + foreach (var extension in backendExtensions) + { + extension.PreBackendDecompile(context); + } + + var command = new DecompileMsiOrMsmCommand(context, backendExtensions); + var result = command.Execute(); + + foreach (var extension in backendExtensions) + { + extension.PostBackendDecompile(result); + } + + return result; } public bool Inscribe(IInscribeContext context) diff --git a/src/WixToolset.Core.WindowsInstaller/MsmBackend.cs b/src/WixToolset.Core.WindowsInstaller/MsmBackend.cs index de9c4162..84588572 100644 --- a/src/WixToolset.Core.WindowsInstaller/MsmBackend.cs +++ b/src/WixToolset.Core.WindowsInstaller/MsmBackend.cs @@ -1,4 +1,4 @@ -// 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. +// 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.Core.WindowsInstaller { @@ -43,9 +43,26 @@ namespace WixToolset.Core.WindowsInstaller return result; } - public BindResult Decompile(IDecompileContext context) + public DecompileResult Decompile(IDecompileContext context) { - throw new NotImplementedException(); + var extensionManager = context.ServiceProvider.GetService(); + + var backendExtensions = extensionManager.Create(); + + foreach (var extension in backendExtensions) + { + extension.PreBackendDecompile(context); + } + + var command = new DecompileMsiOrMsmCommand(context, backendExtensions); + var result = command.Execute(); + + foreach (var extension in backendExtensions) + { + extension.PostBackendDecompile(result); + } + + return result; } public bool Inscribe(IInscribeContext context) diff --git a/src/WixToolset.Core.WindowsInstaller/MspBackend.cs b/src/WixToolset.Core.WindowsInstaller/MspBackend.cs index c6a05b20..df4eb44c 100644 --- a/src/WixToolset.Core.WindowsInstaller/MspBackend.cs +++ b/src/WixToolset.Core.WindowsInstaller/MspBackend.cs @@ -1,4 +1,4 @@ -// 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. +// 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.Core.WindowsInstaller { @@ -21,7 +21,7 @@ namespace WixToolset.Core.WindowsInstaller throw new NotImplementedException(); } - public BindResult Decompile(IDecompileContext context) + public DecompileResult Decompile(IDecompileContext context) { throw new NotImplementedException(); } diff --git a/src/WixToolset.Core.WindowsInstaller/MstBackend.cs b/src/WixToolset.Core.WindowsInstaller/MstBackend.cs index 3e105963..6460821a 100644 --- a/src/WixToolset.Core.WindowsInstaller/MstBackend.cs +++ b/src/WixToolset.Core.WindowsInstaller/MstBackend.cs @@ -1,4 +1,4 @@ -// 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. +// 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.Core.WindowsInstaller { @@ -25,7 +25,7 @@ namespace WixToolset.Core.WindowsInstaller throw new NotImplementedException(); } - public BindResult Decompile(IDecompileContext context) + public DecompileResult Decompile(IDecompileContext context) { throw new NotImplementedException(); } diff --git a/src/WixToolset.Core/CommandLine/DecompileCommand.cs b/src/WixToolset.Core/CommandLine/DecompileCommand.cs new file mode 100644 index 00000000..87cead80 --- /dev/null +++ b/src/WixToolset.Core/CommandLine/DecompileCommand.cs @@ -0,0 +1,212 @@ +// 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.Core.CommandLine +{ + using System; + using System.Collections.Generic; + using System.IO; + using WixToolset.Data; + using WixToolset.Extensibility; + using WixToolset.Extensibility.Data; + using WixToolset.Extensibility.Services; + + internal class DecompileCommand : ICommandLineCommand + { + private readonly CommandLine commandLine; + + public DecompileCommand(IServiceProvider serviceProvider) + { + this.ServiceProvider = serviceProvider; + this.Messaging = serviceProvider.GetService(); + this.commandLine = new CommandLine(this.Messaging); + } + + public bool ShowLogo => this.commandLine.ShowLogo; + + public bool StopParsing => this.commandLine.ShowHelp; + + private IServiceProvider ServiceProvider { get; } + + public IMessaging Messaging { get; } + + private IEnumerable SourceFiles { get; } + + private string OutputPath { get; } + + public int Execute() + { + if (this.commandLine.ShowHelp) + { + Console.WriteLine("TODO: Show decompile command help"); + return -1; + } + + var context = this.ServiceProvider.GetService(); + context.Extensions = this.ServiceProvider.GetService().Create(); + context.DecompilePath = this.commandLine.DecompileFilePath; + context.DecompileType = this.commandLine.CalculateDecompileType(); + context.IntermediateFolder = this.commandLine.CalculateIntermedateFolder(); + context.OutputPath = this.commandLine.CalculateOutputPath(); + + try + { + var decompiler = this.ServiceProvider.GetService(); + var result = decompiler.Decompile(context); + } + catch (WixException e) + { + this.Messaging.Write(e.Error); + } + + if (this.Messaging.EncounteredError) + { + return 1; + } + + return 0; + } + + public bool TryParseArgument(ICommandLineParser parser, string argument) + { + return this.commandLine.TryParseArgument(argument, parser); + } + + private class CommandLine + { + public CommandLine(IMessaging messaging) + { + this.Messaging = messaging; + } + + private IMessaging Messaging { get; } + + public string DecompileFilePath { get; private set; } + + public string DecompileType { get; private set; } + + public Platform Platform { get; private set; } + + public bool ShowLogo { get; private set; } + + public bool ShowHelp { get; private set; } + + public string IntermediateFolder { get; private set; } + + public string OutputFile { get; private set; } + + public bool TryParseArgument(string arg, ICommandLineParser parser) + { + if (parser.IsSwitch(arg)) + { + var parameter = arg.Substring(1); + switch (parameter.ToLowerInvariant()) + { + case "?": + case "h": + case "help": + this.ShowHelp = true; + return true; + + case "intermediatefolder": + this.IntermediateFolder = parser.GetNextArgumentAsDirectoryOrError(arg); + return true; + + case "o": + case "out": + this.OutputFile = parser.GetNextArgumentAsFilePathOrError(arg); + return true; + + case "nologo": + this.ShowLogo = false; + return true; + + case "v": + case "verbose": + this.Messaging.ShowVerboseMessages = true; + return true; + + case "sw": + case "suppresswarning": + var warning = parser.GetNextArgumentOrError(arg); + if (!String.IsNullOrEmpty(warning)) + { + var warningNumber = Convert.ToInt32(warning); + this.Messaging.SuppressWarningMessage(warningNumber); + } + return true; + } + } + else + { + if (String.IsNullOrEmpty(this.DecompileFilePath)) + { + this.DecompileFilePath = parser.GetArgumentAsFilePathOrError(arg, "decompile file"); + return true; + } + else if (String.IsNullOrEmpty(this.OutputFile)) + { + this.OutputFile = parser.GetArgumentAsFilePathOrError(arg, "output file"); + return true; + } + } + + return false; + } + + public OutputType CalculateDecompileType() + { + if (String.IsNullOrEmpty(this.DecompileType)) + { + this.DecompileType = Path.GetExtension(this.DecompileFilePath); + } + + switch (this.DecompileType.ToLowerInvariant()) + { + case "bundle": + case ".exe": + return OutputType.Bundle; + + case "library": + case ".wixlib": + return OutputType.Library; + + case "module": + case ".msm": + return OutputType.Module; + + case "patch": + case ".msp": + return OutputType.Patch; + + case ".pcp": + return OutputType.PatchCreation; + + case "product": + case "package": + case ".msi": + return OutputType.Product; + + case "transform": + case ".mst": + return OutputType.Transform; + + case "intermediatepostlink": + case ".wixipl": + return OutputType.IntermediatePostLink; + } + + return OutputType.Unknown; + } + + public string CalculateIntermedateFolder() + { + return String.IsNullOrEmpty(this.IntermediateFolder) ? Path.GetTempPath() : this.IntermediateFolder; + } + + public string CalculateOutputPath() + { + return String.IsNullOrEmpty(this.OutputFile) ? Path.ChangeExtension(this.DecompileFilePath, ".wxs") : this.OutputFile; + } + } + } +} diff --git a/src/WixToolset.Core/DecompileContext.cs b/src/WixToolset.Core/DecompileContext.cs index a9f0640a..b697c3cf 100644 --- a/src/WixToolset.Core/DecompileContext.cs +++ b/src/WixToolset.Core/DecompileContext.cs @@ -1,4 +1,4 @@ -// 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. +// 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.Core { @@ -17,12 +17,30 @@ namespace WixToolset.Core public IServiceProvider ServiceProvider { get; } + public string DecompilePath { get; set; } + public OutputType DecompileType { get; set; } public IEnumerable Extensions { get; set; } + public string ExtractFolder { get; set; } + + public string BaseSourcePath { get; set; } + public string IntermediateFolder { get; set; } + public bool IsAdminImage { get; set; } + public string OutputPath { get; set; } + + public bool SuppressCustomTables { get; set; } + + public bool SuppressDroppingEmptyTables { get; set; } + + public bool SuppressExtractCabinets { get; set; } + + public bool SuppressUI { get; set; } + + public bool TreatProductAsModule { get; set; } } } diff --git a/src/WixToolset.Core/Decompiler.cs b/src/WixToolset.Core/Decompiler.cs index 45cfbea0..685722a8 100644 --- a/src/WixToolset.Core/Decompiler.cs +++ b/src/WixToolset.Core/Decompiler.cs @@ -19,7 +19,7 @@ namespace WixToolset.Core public IServiceProvider ServiceProvider { get; } - public BindResult Decompile(IDecompileContext context) + public DecompileResult Decompile(IDecompileContext context) { // Pre-decompile. // @@ -30,22 +30,22 @@ namespace WixToolset.Core // Decompile. // - var bindResult = this.BackendDecompile(context); + var result = this.BackendDecompile(context); - if (bindResult != null) + if (result != null) { // Post-decompile. // foreach (var extension in context.Extensions) { - extension.PostDecompile(bindResult); + extension.PostDecompile(result); } } - return bindResult; + return result; } - private BindResult BackendDecompile(IDecompileContext context) + private DecompileResult BackendDecompile(IDecompileContext context) { var extensionManager = context.ServiceProvider.GetService(); diff --git a/src/WixToolset.Core/IDecompiler.cs b/src/WixToolset.Core/IDecompiler.cs index b9bb7ed8..82b02943 100644 --- a/src/WixToolset.Core/IDecompiler.cs +++ b/src/WixToolset.Core/IDecompiler.cs @@ -1,4 +1,4 @@ -// 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. +// 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.Core { @@ -6,6 +6,6 @@ namespace WixToolset.Core public interface IDecompiler { - BindResult Decompile(IDecompileContext context); + DecompileResult Decompile(IDecompileContext context); } } diff --git a/src/WixToolset.Core/OptimizeCA.cs b/src/WixToolset.Core/OptimizeCA.cs index ba17604d..0d7b5e1a 100644 --- a/src/WixToolset.Core/OptimizeCA.cs +++ b/src/WixToolset.Core/OptimizeCA.cs @@ -1,4 +1,4 @@ -// 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. +// 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.Core { @@ -8,7 +8,7 @@ namespace WixToolset.Core /// Values for the OptimizeCA MsiPatchMetdata property, which indicates whether custom actions can be skipped when applying the patch. /// [Flags] - internal enum OptimizeCA + public enum OptimizeCA // TODO: review where to place this data so it can not be exposed by WixToolset.Core { /// /// No custom actions are skipped. diff --git a/src/test/WixToolsetTest.CoreIntegration/DecompileFixture.cs b/src/test/WixToolsetTest.CoreIntegration/DecompileFixture.cs new file mode 100644 index 00000000..66ce98c0 --- /dev/null +++ b/src/test/WixToolsetTest.CoreIntegration/DecompileFixture.cs @@ -0,0 +1,41 @@ +// 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 WixToolsetTest.CoreIntegration +{ + using System.IO; + using System.Xml.Linq; + using WixBuildTools.TestSupport; + using WixToolset.Core.TestPackage; + using Xunit; + + public class DecompileFixture + { + [Fact] + public void CanDecompileSingleFileCompressed() + { + var folder = TestData.Get(@"TestData\DecompileSingleFileCompressed"); + + using (var fs = new DisposableFileSystem()) + { + var intermediateFolder = fs.GetFolder(); + var outputPath = Path.Combine(intermediateFolder, @"Actual.wxs"); + + var result = WixRunner.Execute(new[] + { + "decompile", + Path.Combine(folder, "example.msi"), + "-intermediateFolder", intermediateFolder, + "-o", outputPath + }); + + result.AssertSuccess(); + + var actual = File.ReadAllText(outputPath); + var actualFormatted = XDocument.Parse(actual, LoadOptions.PreserveWhitespace | LoadOptions.SetBaseUri | LoadOptions.SetLineInfo).ToString(); + var expected = XDocument.Load(Path.Combine(folder, "Expected.wxs"), LoadOptions.PreserveWhitespace | LoadOptions.SetBaseUri | LoadOptions.SetLineInfo).ToString(); + + Assert.Equal(expected, actualFormatted); + } + } + } +} diff --git a/src/test/WixToolsetTest.CoreIntegration/TestData/DecompileSingleFileCompressed/Expected.wxs b/src/test/WixToolsetTest.CoreIntegration/TestData/DecompileSingleFileCompressed/Expected.wxs new file mode 100644 index 00000000..b2bb6050 --- /dev/null +++ b/src/test/WixToolsetTest.CoreIntegration/TestData/DecompileSingleFileCompressed/Expected.wxs @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/WixToolsetTest.CoreIntegration/TestData/DecompileSingleFileCompressed/example.cab b/src/test/WixToolsetTest.CoreIntegration/TestData/DecompileSingleFileCompressed/example.cab new file mode 100644 index 00000000..125eeb2c Binary files /dev/null and b/src/test/WixToolsetTest.CoreIntegration/TestData/DecompileSingleFileCompressed/example.cab differ diff --git a/src/test/WixToolsetTest.CoreIntegration/TestData/DecompileSingleFileCompressed/example.msi b/src/test/WixToolsetTest.CoreIntegration/TestData/DecompileSingleFileCompressed/example.msi new file mode 100644 index 00000000..9cb6d6bc Binary files /dev/null and b/src/test/WixToolsetTest.CoreIntegration/TestData/DecompileSingleFileCompressed/example.msi differ diff --git a/src/test/WixToolsetTest.CoreIntegration/WixToolsetTest.CoreIntegration.csproj b/src/test/WixToolsetTest.CoreIntegration/WixToolsetTest.CoreIntegration.csproj index 38b7dc81..7f1337e0 100644 --- a/src/test/WixToolsetTest.CoreIntegration/WixToolsetTest.CoreIntegration.csproj +++ b/src/test/WixToolsetTest.CoreIntegration/WixToolsetTest.CoreIntegration.csproj @@ -20,6 +20,9 @@ + + + -- cgit v1.2.3-55-g6feb