diff options
Diffstat (limited to 'src')
28 files changed, 468 insertions, 445 deletions
diff --git a/src/api/wix/WixToolset.Extensibility/Data/IDecompileContext.cs b/src/api/wix/WixToolset.Extensibility/Data/IWindowsInstallerDecompileContext.cs index fe7d0465..f744121a 100644 --- a/src/api/wix/WixToolset.Extensibility/Data/IDecompileContext.cs +++ b/src/api/wix/WixToolset.Extensibility/Data/IWindowsInstallerDecompileContext.cs | |||
| @@ -5,21 +5,40 @@ namespace WixToolset.Extensibility.Data | |||
| 5 | using System; | 5 | using System; |
| 6 | using System.Collections.Generic; | 6 | using System.Collections.Generic; |
| 7 | using WixToolset.Data; | 7 | using WixToolset.Data; |
| 8 | using WixToolset.Extensibility.Services; | ||
| 9 | 8 | ||
| 10 | #pragma warning disable 1591 // TODO: add documentation | 9 | /// <summary> |
| 11 | public interface IDecompileContext | 10 | /// The context used to decompile Windows Installer packages. |
| 11 | /// </summary> | ||
| 12 | public interface IWindowsInstallerDecompileContext | ||
| 12 | { | 13 | { |
| 14 | /// <summary> | ||
| 15 | /// Gets or sets the service provider. | ||
| 16 | /// </summary> | ||
| 13 | IServiceProvider ServiceProvider { get; } | 17 | IServiceProvider ServiceProvider { get; } |
| 14 | 18 | ||
| 19 | /// <summary> | ||
| 20 | /// Gets or sets the path to the file to decompile. | ||
| 21 | /// </summary> | ||
| 15 | string DecompilePath { get; set; } | 22 | string DecompilePath { get; set; } |
| 16 | 23 | ||
| 24 | /// <summary> | ||
| 25 | /// Gets or sets the type to decompile. | ||
| 26 | /// </summary> | ||
| 17 | OutputType DecompileType { get; set; } | 27 | OutputType DecompileType { get; set; } |
| 18 | 28 | ||
| 19 | IReadOnlyCollection<IDecompilerExtension> Extensions { get; set; } | 29 | /// <summary> |
| 30 | /// Gets or sets the decompiler extensions. | ||
| 31 | /// </summary> | ||
| 32 | IReadOnlyCollection<IWindowsInstallerDecompilerExtension> Extensions { get; set; } | ||
| 20 | 33 | ||
| 34 | /// <summary> | ||
| 35 | /// Gets or sets the folder where content is extracted. | ||
| 36 | /// </summary> | ||
| 21 | string ExtractFolder { get; set; } | 37 | string ExtractFolder { get; set; } |
| 22 | 38 | ||
| 39 | /// <summary> | ||
| 40 | /// Gets or sets the folder where files are extracted. | ||
| 41 | /// </summary> | ||
| 23 | string CabinetExtractFolder { get; set; } | 42 | string CabinetExtractFolder { get; set; } |
| 24 | 43 | ||
| 25 | /// <summary> | 44 | /// <summary> |
| @@ -28,10 +47,19 @@ namespace WixToolset.Extensibility.Data | |||
| 28 | /// <remarks>Default value is "SourceDir" to enable use of BindPaths.</remarks> | 47 | /// <remarks>Default value is "SourceDir" to enable use of BindPaths.</remarks> |
| 29 | string BaseSourcePath { get; set; } | 48 | string BaseSourcePath { get; set; } |
| 30 | 49 | ||
| 50 | /// <summary> | ||
| 51 | /// Gets or sets the intermediate folder. | ||
| 52 | /// </summary> | ||
| 31 | string IntermediateFolder { get; set; } | 53 | string IntermediateFolder { get; set; } |
| 32 | 54 | ||
| 55 | /// <summary> | ||
| 56 | /// Gets or sets whether the decompiler admin image. | ||
| 57 | /// </summary> | ||
| 33 | bool IsAdminImage { get; set; } | 58 | bool IsAdminImage { get; set; } |
| 34 | 59 | ||
| 60 | /// <summary> | ||
| 61 | /// Gets or sets where to output the result. | ||
| 62 | /// </summary> | ||
| 35 | string OutputPath { get; set; } | 63 | string OutputPath { get; set; } |
| 36 | 64 | ||
| 37 | /// <summary> | 65 | /// <summary> |
| @@ -44,9 +72,17 @@ namespace WixToolset.Extensibility.Data | |||
| 44 | /// </summary> | 72 | /// </summary> |
| 45 | bool SuppressDroppingEmptyTables { get; set; } | 73 | bool SuppressDroppingEmptyTables { get; set; } |
| 46 | 74 | ||
| 75 | /// <summary> | ||
| 76 | /// Gets or sets whether to prevent extract cabinets. | ||
| 77 | /// </summary> | ||
| 47 | bool SuppressExtractCabinets { get; set; } | 78 | bool SuppressExtractCabinets { get; set; } |
| 48 | 79 | ||
| 49 | /// <summary> | 80 | /// <summary> |
| 81 | /// Gets or sets whether to suppress relative action sequencing. | ||
| 82 | /// </summary> | ||
| 83 | bool SuppressRelativeActionSequencing { get; set; } | ||
| 84 | |||
| 85 | /// <summary> | ||
| 50 | /// Gets or sets the option to suppress decompiling UI-related tables. | 86 | /// Gets or sets the option to suppress decompiling UI-related tables. |
| 51 | /// </summary> | 87 | /// </summary> |
| 52 | bool SuppressUI { get; set; } | 88 | bool SuppressUI { get; set; } |
diff --git a/src/api/wix/WixToolset.Extensibility/Data/IDecompileResult.cs b/src/api/wix/WixToolset.Extensibility/Data/IWindowsInstallerDecompileResult.cs index cffd0976..3b1dd815 100644 --- a/src/api/wix/WixToolset.Extensibility/Data/IDecompileResult.cs +++ b/src/api/wix/WixToolset.Extensibility/Data/IWindowsInstallerDecompileResult.cs | |||
| @@ -7,7 +7,7 @@ namespace WixToolset.Extensibility.Data | |||
| 7 | using WixToolset.Data; | 7 | using WixToolset.Data; |
| 8 | 8 | ||
| 9 | #pragma warning disable 1591 // TODO: add documentation | 9 | #pragma warning disable 1591 // TODO: add documentation |
| 10 | public interface IDecompileResult | 10 | public interface IWindowsInstallerDecompileResult |
| 11 | { | 11 | { |
| 12 | XDocument Document { get; set; } | 12 | XDocument Document { get; set; } |
| 13 | 13 | ||
diff --git a/src/api/wix/WixToolset.Extensibility/IBackend.cs b/src/api/wix/WixToolset.Extensibility/IBackend.cs index cb151e05..720abe15 100644 --- a/src/api/wix/WixToolset.Extensibility/IBackend.cs +++ b/src/api/wix/WixToolset.Extensibility/IBackend.cs | |||
| @@ -15,8 +15,5 @@ namespace WixToolset.Extensibility | |||
| 15 | /// <param name="context">Bind context.</param> | 15 | /// <param name="context">Bind context.</param> |
| 16 | /// <returns>Result of the bind operation.</returns> | 16 | /// <returns>Result of the bind operation.</returns> |
| 17 | IBindResult Bind(IBindContext context); | 17 | IBindResult Bind(IBindContext context); |
| 18 | |||
| 19 | #pragma warning disable 1591 // TODO: add documentation | ||
| 20 | IDecompileResult Decompile(IDecompileContext context); | ||
| 21 | } | 18 | } |
| 22 | } | 19 | } |
diff --git a/src/api/wix/WixToolset.Extensibility/IBackendFactory.cs b/src/api/wix/WixToolset.Extensibility/IBackendFactory.cs index 7f9ef62d..8e84f5b6 100644 --- a/src/api/wix/WixToolset.Extensibility/IBackendFactory.cs +++ b/src/api/wix/WixToolset.Extensibility/IBackendFactory.cs | |||
| @@ -3,7 +3,7 @@ | |||
| 3 | namespace WixToolset.Extensibility | 3 | namespace WixToolset.Extensibility |
| 4 | { | 4 | { |
| 5 | /// <summary> | 5 | /// <summary> |
| 6 | /// Implemented by extensions to create backends. | 6 | /// Implemented by extensions that are backends. |
| 7 | /// </summary> | 7 | /// </summary> |
| 8 | public interface IBackendFactory | 8 | public interface IBackendFactory |
| 9 | { | 9 | { |
| @@ -12,8 +12,8 @@ namespace WixToolset.Extensibility | |||
| 12 | /// </summary> | 12 | /// </summary> |
| 13 | /// <param name="outputType">Type of output being created.</param> | 13 | /// <param name="outputType">Type of output being created.</param> |
| 14 | /// <param name="outputPath">Path to the output to create.</param> | 14 | /// <param name="outputPath">Path to the output to create.</param> |
| 15 | /// <param name="backend">The backend for the output.</param> | 15 | /// <param name="binder">The backend for the output.</param> |
| 16 | /// <returns>True if the backend was created, otherwise false.</returns> | 16 | /// <returns>True if the backend was created, otherwise false.</returns> |
| 17 | bool TryCreateBackend(string outputType, string outputPath, out IBackend backend); | 17 | bool TryCreateBackend(string outputType, string outputPath, out IBackend binder); |
| 18 | } | 18 | } |
| 19 | } | 19 | } |
diff --git a/src/api/wix/WixToolset.Extensibility/IDecompilerExtension.cs b/src/api/wix/WixToolset.Extensibility/IDecompilerExtension.cs deleted file mode 100644 index 24ef3bff..00000000 --- a/src/api/wix/WixToolset.Extensibility/IDecompilerExtension.cs +++ /dev/null | |||
| @@ -1,22 +0,0 @@ | |||
| 1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. | ||
| 2 | |||
| 3 | namespace WixToolset.Extensibility | ||
| 4 | { | ||
| 5 | using WixToolset.Extensibility.Data; | ||
| 6 | |||
| 7 | /// <summary> | ||
| 8 | /// Base class for creating a decompiler extension. | ||
| 9 | /// </summary> | ||
| 10 | public interface IDecompilerExtension | ||
| 11 | { | ||
| 12 | /// <summary> | ||
| 13 | /// Called before decompiling occurs. | ||
| 14 | /// </summary> | ||
| 15 | void PreDecompile(IDecompileContext context); | ||
| 16 | |||
| 17 | /// <summary> | ||
| 18 | /// Called after all decompiling occurs. | ||
| 19 | /// </summary> | ||
| 20 | void PostDecompile(IDecompileResult result); | ||
| 21 | } | ||
| 22 | } | ||
diff --git a/src/api/wix/WixToolset.Extensibility/IWindowsInstallerBackendDecompilerExtension.cs b/src/api/wix/WixToolset.Extensibility/IWindowsInstallerDecompilerExtension.cs index a56b63c3..add5f886 100644 --- a/src/api/wix/WixToolset.Extensibility/IWindowsInstallerBackendDecompilerExtension.cs +++ b/src/api/wix/WixToolset.Extensibility/IWindowsInstallerDecompilerExtension.cs | |||
| @@ -9,18 +9,18 @@ namespace WixToolset.Extensibility | |||
| 9 | /// <summary> | 9 | /// <summary> |
| 10 | /// Interface all binder extensions implement. | 10 | /// Interface all binder extensions implement. |
| 11 | /// </summary> | 11 | /// </summary> |
| 12 | public interface IWindowsInstallerBackendDecompilerExtension | 12 | public interface IWindowsInstallerDecompilerExtension |
| 13 | { | 13 | { |
| 14 | /// <summary> | 14 | /// <summary> |
| 15 | /// Called before decompiling occurs. | 15 | /// Called before decompiling occurs. |
| 16 | /// </summary> | 16 | /// </summary> |
| 17 | void PreBackendDecompile(IDecompileContext context); | 17 | void PreDecompile(IWindowsInstallerDecompileContext context); |
| 18 | 18 | ||
| 19 | // TODO: Redesign this interface to be useful. | 19 | // TODO: Redesign this interface to be useful. |
| 20 | 20 | ||
| 21 | /// <summary> | 21 | /// <summary> |
| 22 | /// Called after all output changes occur and right before the output is bound into its final format. | 22 | /// Called after all output changes occur and right before the output is bound into its final format. |
| 23 | /// </summary> | 23 | /// </summary> |
| 24 | void PostBackendDecompile(IDecompileResult result); | 24 | void PostDecompile(IWindowsInstallerDecompileResult result); |
| 25 | } | 25 | } |
| 26 | } | 26 | } |
diff --git a/src/api/wix/WixToolset.Extensibility/Services/ICommandLineParser.cs b/src/api/wix/WixToolset.Extensibility/Services/ICommandLineParser.cs index cd17f100..efd6600d 100644 --- a/src/api/wix/WixToolset.Extensibility/Services/ICommandLineParser.cs +++ b/src/api/wix/WixToolset.Extensibility/Services/ICommandLineParser.cs | |||
| @@ -5,36 +5,111 @@ namespace WixToolset.Extensibility.Services | |||
| 5 | using System.Collections.Generic; | 5 | using System.Collections.Generic; |
| 6 | using WixToolset.Data; | 6 | using WixToolset.Data; |
| 7 | 7 | ||
| 8 | #pragma warning disable 1591 // TODO: add documentation | 8 | /// <summary> |
| 9 | /// Provides the command-line arguments. | ||
| 10 | /// </summary> | ||
| 9 | public interface ICommandLineParser | 11 | public interface ICommandLineParser |
| 10 | { | 12 | { |
| 13 | /// <summary> | ||
| 14 | /// Gets the argument that caused the error. | ||
| 15 | /// </summary> | ||
| 11 | string ErrorArgument { get; } | 16 | string ErrorArgument { get; } |
| 12 | 17 | ||
| 13 | /// <summary> | 18 | /// <summary> |
| 14 | /// Validates that a valid switch (starts with "/" or "-"), and returns a bool indicating its validity | 19 | /// Validates that a valid switch (starts with "/" or "-"), and returns a bool indicating its validity |
| 15 | /// </summary> | 20 | /// </summary> |
| 16 | /// <param name="arg">The string check.</param> | 21 | /// <param name="argument">The string check.</param> |
| 17 | /// <returns>True if a valid switch, otherwise false.</returns> | 22 | /// <returns>True if a valid switch, otherwise false.</returns> |
| 18 | bool IsSwitch(string arg); | 23 | bool IsSwitch(string argument); |
| 19 | 24 | ||
| 25 | /// <summary> | ||
| 26 | /// Gets the current argument as a file or displays an error. | ||
| 27 | /// </summary> | ||
| 28 | /// <param name="argument">Current argument used in the error message if necessary.</param> | ||
| 29 | /// <param name="fileType">Type of file displayed in the error message if necessary.</param> | ||
| 30 | /// <returns>The fully expanded path if the argument is a file path, otherwise null.</returns> | ||
| 20 | string GetArgumentAsFilePathOrError(string argument, string fileType); | 31 | string GetArgumentAsFilePathOrError(string argument, string fileType); |
| 21 | 32 | ||
| 22 | void GetArgumentAsFilePathOrError(string argument, string fileType, IList<string> paths); | 33 | /// <summary> |
| 34 | /// Adds the current argument as a file to the list or displays an error. | ||
| 35 | /// </summary> | ||
| 36 | /// <param name="argument">Current argument used in the error message if necessary.</param> | ||
| 37 | /// <param name="fileType">Type of file displayed in the error message if necessary.</param> | ||
| 38 | /// <param name="paths">List to add the fully expanded path if the argument is a file path.</param> | ||
| 39 | /// <returns>True if the argument is a file path, otherwise false.</returns> | ||
| 40 | bool GetArgumentAsFilePathOrError(string argument, string fileType, IList<string> paths); | ||
| 23 | 41 | ||
| 24 | string GetNextArgumentOrError(string commandLineSwitch); | 42 | /// <summary> |
| 43 | /// Gets the next argument or displays error if no argument is available. | ||
| 44 | /// </summary> | ||
| 45 | /// <param name="argument">Current argument used in the error message if necessary.</param> | ||
| 46 | /// <returns>The next argument if present or null</returns> | ||
| 47 | string GetNextArgumentOrError(string argument); | ||
| 25 | 48 | ||
| 26 | bool GetNextArgumentOrError(string commandLineSwitch, IList<string> argument); | 49 | /// <summary> |
| 50 | /// Adds the next argument to a list or displays error if no argument is available. | ||
| 51 | /// </summary> | ||
| 52 | /// <param name="argument">Current argument used in the error message if necessary.</param> | ||
| 53 | /// <param name="arguments">List to add the argument to.</param> | ||
| 54 | /// <returns>True if an argument is available, otherwise false.</returns> | ||
| 55 | bool GetNextArgumentOrError(string argument, IList<string> arguments); | ||
| 27 | 56 | ||
| 28 | string GetNextArgumentAsDirectoryOrError(string commandLineSwitch); | 57 | /// <summary> |
| 58 | /// Gets the next argument as a directory or displays an error. | ||
| 59 | /// </summary> | ||
| 60 | /// <param name="argument">Current argument used in the error message if necessary.</param> | ||
| 61 | /// <returns>The fully expanded path if the argument is a directory, otherwise null.</returns> | ||
| 62 | string GetNextArgumentAsDirectoryOrError(string argument); | ||
| 29 | 63 | ||
| 30 | bool GetNextArgumentAsDirectoryOrError(string commandLineSwitch, IList<string> directories); | 64 | /// <summary> |
| 65 | /// Adds the next argument as a directory to the list or displays an error. | ||
| 66 | /// </summary> | ||
| 67 | /// <param name="argument">Current argument used in the error message if necessary.</param> | ||
| 68 | /// <param name="directories">List to add the fully expanded directory if the argument is a file path.</param> | ||
| 69 | /// <returns>True if the argument is a directory, otherwise false.</returns> | ||
| 70 | bool GetNextArgumentAsDirectoryOrError(string argument, IList<string> directories); | ||
| 31 | 71 | ||
| 32 | string GetNextArgumentAsFilePathOrError(string commandLineSwitch); | 72 | /// <summary> |
| 73 | /// Gets the next argument as a file or displays an error. | ||
| 74 | /// </summary> | ||
| 75 | /// <param name="argument">Current argument used in the error message if necessary.</param> | ||
| 76 | /// <returns>The fully expanded path if the argument is a file path, otherwise null.</returns> | ||
| 77 | string GetNextArgumentAsFilePathOrError(string argument); | ||
| 33 | 78 | ||
| 34 | bool GetNextArgumentAsFilePathOrError(string commandLineSwitch, string fileType, IList<string> paths); | 79 | /// <summary> |
| 80 | /// Adds the next argument as a file to the list or displays an error. | ||
| 81 | /// </summary> | ||
| 82 | /// <param name="argument">Current argument used in the error message if necessary.</param> | ||
| 83 | /// <param name="fileType">Type of file displayed in the error message if necessary.</param> | ||
| 84 | /// <param name="paths">List to add the fully expanded path if the argument is a file path.</param> | ||
| 85 | /// <returns>True if the argument is a file path, otherwise false.</returns> | ||
| 86 | bool GetNextArgumentAsFilePathOrError(string argument, string fileType, IList<string> paths); | ||
| 35 | 87 | ||
| 88 | /// <summary> | ||
| 89 | /// Reports a command line error for the provided argument. | ||
| 90 | /// </summary> | ||
| 91 | /// <param name="argument">Argument that caused the error.</param> | ||
| 92 | /// <param name="message">Message to report.</param> | ||
| 36 | void ReportErrorArgument(string argument, Message message = null); | 93 | void ReportErrorArgument(string argument, Message message = null); |
| 37 | 94 | ||
| 38 | bool TryGetNextSwitchOrArgument(out string arg); | 95 | /// <summary> |
| 96 | /// Tries to get the next argument. | ||
| 97 | /// </summary> | ||
| 98 | /// <param name="argument">Next argument if available.</param> | ||
| 99 | /// <returns>True if argument is available, otherwise false.</returns> | ||
| 100 | bool TryGetNextSwitchOrArgument(out string argument); | ||
| 101 | |||
| 102 | /// <summary> | ||
| 103 | /// Looks ahead to the next argument without moving to the next argument. | ||
| 104 | /// </summary> | ||
| 105 | /// <returns>Next argument if available, otherwise null.</returns> | ||
| 106 | string PeekNextArgument(); | ||
| 107 | |||
| 108 | /// <summary> | ||
| 109 | /// Tries to looks ahead to the next argument without moving to the next argument. | ||
| 110 | /// </summary> | ||
| 111 | /// <param name="argument">Argument found if present.</param> | ||
| 112 | /// <returns>True if argument is found, otherwise false.</returns> | ||
| 113 | bool TryPeekNextArgument(out string argument); | ||
| 39 | } | 114 | } |
| 40 | } | 115 | } |
diff --git a/src/wix/WixToolset.Core.Burn/BundleBackend.cs b/src/wix/WixToolset.Core.Burn/BundleBackend.cs index a2003989..cf1971f6 100644 --- a/src/wix/WixToolset.Core.Burn/BundleBackend.cs +++ b/src/wix/WixToolset.Core.Burn/BundleBackend.cs | |||
| @@ -2,7 +2,6 @@ | |||
| 2 | 2 | ||
| 3 | namespace WixToolset.Core.Burn | 3 | namespace WixToolset.Core.Burn |
| 4 | { | 4 | { |
| 5 | using System; | ||
| 6 | using WixToolset.Extensibility; | 5 | using WixToolset.Extensibility; |
| 7 | using WixToolset.Extensibility.Data; | 6 | using WixToolset.Extensibility.Data; |
| 8 | using WixToolset.Extensibility.Services; | 7 | using WixToolset.Extensibility.Services; |
| @@ -35,10 +34,5 @@ namespace WixToolset.Core.Burn | |||
| 35 | 34 | ||
| 36 | return result; | 35 | return result; |
| 37 | } | 36 | } |
| 38 | |||
| 39 | public IDecompileResult Decompile(IDecompileContext context) | ||
| 40 | { | ||
| 41 | throw new NotImplementedException(); | ||
| 42 | } | ||
| 43 | } | 37 | } |
| 44 | } | 38 | } |
diff --git a/src/wix/WixToolset.Core.WindowsInstaller/CommandLine/DecompilerSubcommand.cs b/src/wix/WixToolset.Core.WindowsInstaller/CommandLine/DecompilerSubcommand.cs new file mode 100644 index 00000000..19d1c738 --- /dev/null +++ b/src/wix/WixToolset.Core.WindowsInstaller/CommandLine/DecompilerSubcommand.cs | |||
| @@ -0,0 +1,185 @@ | |||
| 1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. | ||
| 2 | |||
| 3 | namespace WixToolset.Core.WindowsInstaller.CommandLine | ||
| 4 | { | ||
| 5 | using System; | ||
| 6 | using System.IO; | ||
| 7 | using System.Threading; | ||
| 8 | using System.Threading.Tasks; | ||
| 9 | using System.Xml.Linq; | ||
| 10 | using WixToolset.Data; | ||
| 11 | using WixToolset.Extensibility; | ||
| 12 | using WixToolset.Extensibility.Data; | ||
| 13 | using WixToolset.Extensibility.Services; | ||
| 14 | |||
| 15 | internal class DecompilerSubcommand : WindowsInstallerSubcommandBase | ||
| 16 | { | ||
| 17 | public DecompilerSubcommand(IServiceProvider serviceProvider) | ||
| 18 | { | ||
| 19 | this.ServiceProvider = serviceProvider; | ||
| 20 | this.Messaging = serviceProvider.GetService<IMessaging>(); | ||
| 21 | } | ||
| 22 | |||
| 23 | private IServiceProvider ServiceProvider { get; } | ||
| 24 | |||
| 25 | private IMessaging Messaging { get; } | ||
| 26 | |||
| 27 | private string InputPath { get; set; } | ||
| 28 | |||
| 29 | private string DecompileType { get; set; } | ||
| 30 | |||
| 31 | private string IntermediateFolder { get; set; } | ||
| 32 | |||
| 33 | private string OutputPath { get; set; } | ||
| 34 | |||
| 35 | private string ExportBasePath { get; set; } | ||
| 36 | |||
| 37 | private bool SuppressCustomTables { get; set; } | ||
| 38 | |||
| 39 | private bool SuppressDroppingEmptyTables { get; set; } | ||
| 40 | |||
| 41 | private bool SuppressRelativeActionSequencing { get; set; } | ||
| 42 | |||
| 43 | private bool SuppressUI { get; set; } | ||
| 44 | |||
| 45 | public override Task<int> ExecuteAsync(CancellationToken cancellationToken) | ||
| 46 | { | ||
| 47 | if (String.IsNullOrEmpty(this.InputPath)) | ||
| 48 | { | ||
| 49 | Console.Error.WriteLine("Input MSI or MSM database is required"); | ||
| 50 | return Task.FromResult(-1); | ||
| 51 | } | ||
| 52 | |||
| 53 | if (!this.TryCalculateDecompileType(out var decompileType)) | ||
| 54 | { | ||
| 55 | Console.Error.WriteLine("Unknown output type '{0}' from input: {1}", decompileType, this.InputPath); | ||
| 56 | return Task.FromResult(-1); | ||
| 57 | } | ||
| 58 | |||
| 59 | if (String.IsNullOrEmpty(this.IntermediateFolder)) | ||
| 60 | { | ||
| 61 | this.IntermediateFolder = Path.GetTempPath(); | ||
| 62 | } | ||
| 63 | |||
| 64 | if (String.IsNullOrEmpty(this.OutputPath)) | ||
| 65 | { | ||
| 66 | this.OutputPath = Path.ChangeExtension(this.InputPath, ".wxs"); | ||
| 67 | } | ||
| 68 | |||
| 69 | var context = this.ServiceProvider.GetService<IWindowsInstallerDecompileContext>(); | ||
| 70 | context.Extensions = this.ServiceProvider.GetService<IExtensionManager>().GetServices<IWindowsInstallerDecompilerExtension>(); | ||
| 71 | context.DecompilePath = this.InputPath; | ||
| 72 | context.DecompileType = decompileType; | ||
| 73 | context.IntermediateFolder = this.IntermediateFolder; | ||
| 74 | context.OutputPath = this.OutputPath; | ||
| 75 | |||
| 76 | context.ExtractFolder = this.ExportBasePath ?? this.IntermediateFolder; | ||
| 77 | context.SuppressCustomTables = this.SuppressCustomTables; | ||
| 78 | context.SuppressDroppingEmptyTables = this.SuppressDroppingEmptyTables; | ||
| 79 | context.SuppressRelativeActionSequencing = this.SuppressRelativeActionSequencing; | ||
| 80 | context.SuppressUI = this.SuppressUI; | ||
| 81 | |||
| 82 | try | ||
| 83 | { | ||
| 84 | var decompiler = this.ServiceProvider.GetService<IWindowsInstallerDecompiler>(); | ||
| 85 | var result = decompiler.Decompile(context); | ||
| 86 | |||
| 87 | if (!this.Messaging.EncounteredError) | ||
| 88 | { | ||
| 89 | Directory.CreateDirectory(Path.GetDirectoryName(Path.GetFullPath(context.OutputPath))); | ||
| 90 | result.Document.Save(context.OutputPath, SaveOptions.OmitDuplicateNamespaces); | ||
| 91 | } | ||
| 92 | } | ||
| 93 | catch (WixException e) | ||
| 94 | { | ||
| 95 | this.Messaging.Write(e.Error); | ||
| 96 | } | ||
| 97 | |||
| 98 | return Task.FromResult(this.Messaging.LastErrorNumber); | ||
| 99 | } | ||
| 100 | |||
| 101 | public override bool TryParseArgument(ICommandLineParser parser, string argument) | ||
| 102 | { | ||
| 103 | if (parser.IsSwitch(argument)) | ||
| 104 | { | ||
| 105 | var parameter = argument.Substring(1); | ||
| 106 | switch (parameter.ToLowerInvariant()) | ||
| 107 | { | ||
| 108 | case "intermediatefolder": | ||
| 109 | this.IntermediateFolder = parser.GetNextArgumentAsDirectoryOrError(argument); | ||
| 110 | return true; | ||
| 111 | |||
| 112 | case "o": | ||
| 113 | case "out": | ||
| 114 | this.OutputPath = parser.GetNextArgumentAsFilePathOrError(argument); | ||
| 115 | return true; | ||
| 116 | |||
| 117 | case "sct": | ||
| 118 | this.SuppressCustomTables = true; | ||
| 119 | return true; | ||
| 120 | |||
| 121 | case "sdet": | ||
| 122 | this.SuppressDroppingEmptyTables = true; | ||
| 123 | return true; | ||
| 124 | |||
| 125 | case "sras": | ||
| 126 | this.SuppressRelativeActionSequencing = true; | ||
| 127 | return true; | ||
| 128 | |||
| 129 | case "sui": | ||
| 130 | this.SuppressUI = true; | ||
| 131 | return true; | ||
| 132 | |||
| 133 | case "type": | ||
| 134 | this.DecompileType = parser.GetNextArgumentOrError(argument); | ||
| 135 | return true; | ||
| 136 | |||
| 137 | case "x": | ||
| 138 | // Peek ahead to get the actual value provided on the command-line so the authoring | ||
| 139 | // matches what they typed on the command-line. | ||
| 140 | var originalExportBasePath = parser.PeekNextArgument(); | ||
| 141 | parser.GetNextArgumentAsDirectoryOrError(argument); // ensure we actually got a directory. | ||
| 142 | |||
| 143 | this.ExportBasePath = originalExportBasePath; | ||
| 144 | return true; | ||
| 145 | } | ||
| 146 | } | ||
| 147 | else if (String.IsNullOrEmpty(this.InputPath)) | ||
| 148 | { | ||
| 149 | this.InputPath = argument; | ||
| 150 | return true; | ||
| 151 | } | ||
| 152 | |||
| 153 | return false; | ||
| 154 | } | ||
| 155 | |||
| 156 | private bool TryCalculateDecompileType(out OutputType decompileType) | ||
| 157 | { | ||
| 158 | decompileType = OutputType.Unknown; | ||
| 159 | |||
| 160 | if (String.IsNullOrEmpty(this.DecompileType)) | ||
| 161 | { | ||
| 162 | this.DecompileType = Path.GetExtension(this.InputPath); | ||
| 163 | } | ||
| 164 | |||
| 165 | switch (this.DecompileType.ToLowerInvariant()) | ||
| 166 | { | ||
| 167 | case "product": | ||
| 168 | case "package": | ||
| 169 | case "msi": | ||
| 170 | case ".msi": | ||
| 171 | decompileType = OutputType.Product; | ||
| 172 | break; | ||
| 173 | |||
| 174 | case "mergemodule": | ||
| 175 | case "module": | ||
| 176 | case "msm": | ||
| 177 | case ".msm": | ||
| 178 | decompileType = OutputType.Module; | ||
| 179 | break; | ||
| 180 | } | ||
| 181 | |||
| 182 | return decompileType != OutputType.Unknown; | ||
| 183 | } | ||
| 184 | } | ||
| 185 | } | ||
diff --git a/src/wix/WixToolset.Core.WindowsInstaller/CommandLine/WindowsInstallerCommand.cs b/src/wix/WixToolset.Core.WindowsInstaller/CommandLine/WindowsInstallerCommand.cs index ed0c0658..f11020c8 100644 --- a/src/wix/WixToolset.Core.WindowsInstaller/CommandLine/WindowsInstallerCommand.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/CommandLine/WindowsInstallerCommand.cs | |||
| @@ -45,6 +45,10 @@ namespace WixToolset.Core.WindowsInstaller.CommandLine | |||
| 45 | { | 45 | { |
| 46 | switch (argument.ToLowerInvariant()) | 46 | switch (argument.ToLowerInvariant()) |
| 47 | { | 47 | { |
| 48 | case "decompile": | ||
| 49 | this.Subcommand = new DecompilerSubcommand(this.ServiceProvider); | ||
| 50 | return true; | ||
| 51 | |||
| 48 | case "inscribe": | 52 | case "inscribe": |
| 49 | this.Subcommand = new InscribeSubcommand(this.ServiceProvider); | 53 | this.Subcommand = new InscribeSubcommand(this.ServiceProvider); |
| 50 | return true; | 54 | return true; |
diff --git a/src/wix/WixToolset.Core.WindowsInstaller/Decompile/DecompileMsiOrMsmCommand.cs b/src/wix/WixToolset.Core.WindowsInstaller/Decompile/DecompileMsiOrMsmCommand.cs index aeda4443..5001828d 100644 --- a/src/wix/WixToolset.Core.WindowsInstaller/Decompile/DecompileMsiOrMsmCommand.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/Decompile/DecompileMsiOrMsmCommand.cs | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. | 1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. |
| 2 | 2 | ||
| 3 | namespace WixToolset.Core.WindowsInstaller.Decompile | 3 | namespace WixToolset.Core.WindowsInstaller.Decompile |
| 4 | { | 4 | { |
| @@ -11,28 +11,24 @@ namespace WixToolset.Core.WindowsInstaller.Decompile | |||
| 11 | using WixToolset.Core.WindowsInstaller.Unbind; | 11 | using WixToolset.Core.WindowsInstaller.Unbind; |
| 12 | using WixToolset.Data; | 12 | using WixToolset.Data; |
| 13 | using WixToolset.Data.WindowsInstaller; | 13 | using WixToolset.Data.WindowsInstaller; |
| 14 | using WixToolset.Extensibility; | ||
| 15 | using WixToolset.Extensibility.Data; | 14 | using WixToolset.Extensibility.Data; |
| 16 | using WixToolset.Extensibility.Services; | 15 | using WixToolset.Extensibility.Services; |
| 17 | 16 | ||
| 18 | internal class DecompileMsiOrMsmCommand | 17 | internal class DecompileMsiOrMsmCommand |
| 19 | { | 18 | { |
| 20 | public DecompileMsiOrMsmCommand(IDecompileContext context, IEnumerable<IWindowsInstallerBackendDecompilerExtension> backendExtensions) | 19 | public DecompileMsiOrMsmCommand(IWindowsInstallerDecompileContext context) |
| 21 | { | 20 | { |
| 22 | this.Context = context; | 21 | this.Context = context; |
| 23 | this.Extensions = backendExtensions; | ||
| 24 | this.Messaging = context.ServiceProvider.GetService<IMessaging>(); | 22 | this.Messaging = context.ServiceProvider.GetService<IMessaging>(); |
| 25 | } | 23 | } |
| 26 | 24 | ||
| 27 | private IDecompileContext Context { get; } | 25 | private IWindowsInstallerDecompileContext Context { get; } |
| 28 | |||
| 29 | private IEnumerable<IWindowsInstallerBackendDecompilerExtension> Extensions { get; } | ||
| 30 | 26 | ||
| 31 | private IMessaging Messaging { get; } | 27 | private IMessaging Messaging { get; } |
| 32 | 28 | ||
| 33 | public IDecompileResult Execute() | 29 | public IWindowsInstallerDecompileResult Execute() |
| 34 | { | 30 | { |
| 35 | var result = this.Context.ServiceProvider.GetService<IDecompileResult>(); | 31 | var result = this.Context.ServiceProvider.GetService<IWindowsInstallerDecompileResult>(); |
| 36 | 32 | ||
| 37 | try | 33 | try |
| 38 | { | 34 | { |
| @@ -50,7 +46,7 @@ namespace WixToolset.Core.WindowsInstaller.Decompile | |||
| 50 | var output = unbindCommand.Execute(); | 46 | var output = unbindCommand.Execute(); |
| 51 | var extractedFilePaths = new List<string>(unbindCommand.ExportedFiles); | 47 | var extractedFilePaths = new List<string>(unbindCommand.ExportedFiles); |
| 52 | 48 | ||
| 53 | var decompiler = new Decompiler(this.Messaging, backendHelper, this.Extensions, this.Context.BaseSourcePath, this.Context.SuppressCustomTables, this.Context.SuppressDroppingEmptyTables, this.Context.SuppressUI, this.Context.TreatProductAsModule); | 49 | var decompiler = new Decompiler(this.Messaging, backendHelper, this.Context.Extensions, this.Context.BaseSourcePath, this.Context.SuppressCustomTables, this.Context.SuppressDroppingEmptyTables, this.Context.SuppressRelativeActionSequencing, this.Context.SuppressUI, this.Context.TreatProductAsModule); |
| 54 | result.Document = decompiler.Decompile(output); | 50 | result.Document = decompiler.Decompile(output); |
| 55 | 51 | ||
| 56 | result.Platform = GetPlatformFromOutput(output); | 52 | result.Platform = GetPlatformFromOutput(output); |
| @@ -90,7 +86,6 @@ namespace WixToolset.Core.WindowsInstaller.Decompile | |||
| 90 | var template = output.Tables["_SummaryInformation"]?.Rows.SingleOrDefault(row => row.FieldAsInteger(0) == 7)?.FieldAsString(1); | 86 | var template = output.Tables["_SummaryInformation"]?.Rows.SingleOrDefault(row => row.FieldAsInteger(0) == 7)?.FieldAsString(1); |
| 91 | 87 | ||
| 92 | return Decompiler.GetPlatformFromTemplateSummaryInformation(template?.Split(';')); | 88 | return Decompiler.GetPlatformFromTemplateSummaryInformation(template?.Split(';')); |
| 93 | |||
| 94 | } | 89 | } |
| 95 | } | 90 | } |
| 96 | } | 91 | } |
diff --git a/src/wix/WixToolset.Core.WindowsInstaller/Decompile/Decompiler.cs b/src/wix/WixToolset.Core.WindowsInstaller/Decompile/Decompiler.cs index 9c338293..4ccfaaa5 100644 --- a/src/wix/WixToolset.Core.WindowsInstaller/Decompile/Decompiler.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/Decompile/Decompiler.cs | |||
| @@ -43,7 +43,7 @@ namespace WixToolset.Core.WindowsInstaller.Decompile | |||
| 43 | /// <summary> | 43 | /// <summary> |
| 44 | /// Creates a new decompiler object with a default set of table definitions. | 44 | /// Creates a new decompiler object with a default set of table definitions. |
| 45 | /// </summary> | 45 | /// </summary> |
| 46 | public Decompiler(IMessaging messaging, IBackendHelper backendHelper, IEnumerable<IWindowsInstallerBackendDecompilerExtension> extensions, string baseSourcePath, bool suppressCustomTables, bool suppressDroppingEmptyTables, bool suppressUI, bool treatProductAsModule) | 46 | public Decompiler(IMessaging messaging, IBackendHelper backendHelper, IEnumerable<IWindowsInstallerDecompilerExtension> extensions, string baseSourcePath, bool suppressCustomTables, bool suppressDroppingEmptyTables, bool suppressRelativeActionSequencing, bool suppressUI, bool treatProductAsModule) |
| 47 | { | 47 | { |
| 48 | this.Messaging = messaging; | 48 | this.Messaging = messaging; |
| 49 | this.BackendHelper = backendHelper; | 49 | this.BackendHelper = backendHelper; |
| @@ -51,10 +51,11 @@ namespace WixToolset.Core.WindowsInstaller.Decompile | |||
| 51 | this.BaseSourcePath = baseSourcePath ?? "SourceDir"; | 51 | this.BaseSourcePath = baseSourcePath ?? "SourceDir"; |
| 52 | this.SuppressCustomTables = suppressCustomTables; | 52 | this.SuppressCustomTables = suppressCustomTables; |
| 53 | this.SuppressDroppingEmptyTables = suppressDroppingEmptyTables; | 53 | this.SuppressDroppingEmptyTables = suppressDroppingEmptyTables; |
| 54 | this.SuppressRelativeActionSequencing = suppressRelativeActionSequencing; | ||
| 54 | this.SuppressUI = suppressUI; | 55 | this.SuppressUI = suppressUI; |
| 55 | this.TreatProductAsModule = treatProductAsModule; | 56 | this.TreatProductAsModule = treatProductAsModule; |
| 56 | 57 | ||
| 57 | this.ExtensionsByTableName = new Dictionary<string, IWindowsInstallerBackendDecompilerExtension>(); | 58 | this.ExtensionsByTableName = new Dictionary<string, IWindowsInstallerDecompilerExtension>(); |
| 58 | this.StandardActions = WindowsInstallerStandard.StandardActions().ToDictionary(a => a.Id.Id); | 59 | this.StandardActions = WindowsInstallerStandard.StandardActions().ToDictionary(a => a.Id.Id); |
| 59 | 60 | ||
| 60 | this.TableDefinitions = new TableDefinitionCollection(); | 61 | this.TableDefinitions = new TableDefinitionCollection(); |
| @@ -64,9 +65,9 @@ namespace WixToolset.Core.WindowsInstaller.Decompile | |||
| 64 | 65 | ||
| 65 | private IBackendHelper BackendHelper { get; } | 66 | private IBackendHelper BackendHelper { get; } |
| 66 | 67 | ||
| 67 | private IEnumerable<IWindowsInstallerBackendDecompilerExtension> Extensions { get; } | 68 | private IEnumerable<IWindowsInstallerDecompilerExtension> Extensions { get; } |
| 68 | 69 | ||
| 69 | private Dictionary<string, IWindowsInstallerBackendDecompilerExtension> ExtensionsByTableName { get; } | 70 | private Dictionary<string, IWindowsInstallerDecompilerExtension> ExtensionsByTableName { get; } |
| 70 | 71 | ||
| 71 | private string BaseSourcePath { get; } | 72 | private string BaseSourcePath { get; } |
| 72 | 73 | ||
| @@ -238,7 +239,10 @@ namespace WixToolset.Core.WindowsInstaller.Decompile | |||
| 238 | /// </summary> | 239 | /// </summary> |
| 239 | /// <param name="row">The row corresponding to the element.</param> | 240 | /// <param name="row">The row corresponding to the element.</param> |
| 240 | /// <returns>The indexed element.</returns> | 241 | /// <returns>The indexed element.</returns> |
| 241 | private XElement GetIndexedElement(WixToolset.Data.WindowsInstaller.Row row) => this.GetIndexedElement(row.TableDefinition.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter)); | 242 | private XElement GetIndexedElement(Row row) |
| 243 | { | ||
| 244 | return this.GetIndexedElement(row.TableDefinition.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter)); | ||
| 245 | } | ||
| 242 | 246 | ||
| 243 | /// <summary> | 247 | /// <summary> |
| 244 | /// Gets the element corresponding to the primary key of the given table. | 248 | /// Gets the element corresponding to the primary key of the given table. |
| @@ -246,7 +250,10 @@ namespace WixToolset.Core.WindowsInstaller.Decompile | |||
| 246 | /// <param name="table">The table corresponding to the element.</param> | 250 | /// <param name="table">The table corresponding to the element.</param> |
| 247 | /// <param name="primaryKey">The primary key corresponding to the element.</param> | 251 | /// <param name="primaryKey">The primary key corresponding to the element.</param> |
| 248 | /// <returns>The indexed element.</returns> | 252 | /// <returns>The indexed element.</returns> |
| 249 | private XElement GetIndexedElement(string table, params string[] primaryKey) => this.IndexedElements[String.Concat(table, ':', String.Join(DecompilerConstants.PrimaryKeyDelimiterString, primaryKey))]; | 253 | private XElement GetIndexedElement(string table, params string[] primaryKey) |
| 254 | { | ||
| 255 | return this.TryGetIndexedElement(table, out var element, primaryKey) ? element : null; | ||
| 256 | } | ||
| 250 | 257 | ||
| 251 | /// <summary> | 258 | /// <summary> |
| 252 | /// Tries to get the element corresponding to the primary key of the given table. | 259 | /// Tries to get the element corresponding to the primary key of the given table. |
| @@ -254,7 +261,10 @@ namespace WixToolset.Core.WindowsInstaller.Decompile | |||
| 254 | /// <param name="row">The table corresponding to the element.</param> | 261 | /// <param name="row">The table corresponding to the element.</param> |
| 255 | /// <param name="xElement">The indexed element.</param> | 262 | /// <param name="xElement">The indexed element.</param> |
| 256 | /// <returns>Whether the element was found.</returns> | 263 | /// <returns>Whether the element was found.</returns> |
| 257 | private bool TryGetIndexedElement(WixToolset.Data.WindowsInstaller.Row row, out XElement xElement) => this.TryGetIndexedElement(row.TableDefinition.Name, out xElement, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter)); | 264 | private bool TryGetIndexedElement(Row row, out XElement xElement) |
| 265 | { | ||
| 266 | return this.TryGetIndexedElement(row.TableDefinition.Name, out xElement, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter)); | ||
| 267 | } | ||
| 258 | 268 | ||
| 259 | /// <summary> | 269 | /// <summary> |
| 260 | /// Tries to get the element corresponding to the primary key of the given table. | 270 | /// Tries to get the element corresponding to the primary key of the given table. |
| @@ -263,14 +273,17 @@ namespace WixToolset.Core.WindowsInstaller.Decompile | |||
| 263 | /// <param name="xElement">The indexed element.</param> | 273 | /// <param name="xElement">The indexed element.</param> |
| 264 | /// <param name="primaryKey">The primary key corresponding to the element.</param> | 274 | /// <param name="primaryKey">The primary key corresponding to the element.</param> |
| 265 | /// <returns>Whether the element was found.</returns> | 275 | /// <returns>Whether the element was found.</returns> |
| 266 | private bool TryGetIndexedElement(string table, out XElement xElement, params string[] primaryKey) => this.IndexedElements.TryGetValue(String.Concat(table, ':', String.Join(DecompilerConstants.PrimaryKeyDelimiterString, primaryKey)), out xElement); | 276 | private bool TryGetIndexedElement(string table, out XElement xElement, params string[] primaryKey) |
| 277 | { | ||
| 278 | return this.IndexedElements.TryGetValue(String.Concat(table, ':', String.Join(DecompilerConstants.PrimaryKeyDelimiterString, primaryKey)), out xElement); | ||
| 279 | } | ||
| 267 | 280 | ||
| 268 | /// <summary> | 281 | /// <summary> |
| 269 | /// Index an element by its corresponding row. | 282 | /// Index an element by its corresponding row. |
| 270 | /// </summary> | 283 | /// </summary> |
| 271 | /// <param name="row">The row corresponding to the element.</param> | 284 | /// <param name="row">The row corresponding to the element.</param> |
| 272 | /// <param name="element">The element to index.</param> | 285 | /// <param name="element">The element to index.</param> |
| 273 | private void IndexElement(WixToolset.Data.WindowsInstaller.Row row, XElement element) | 286 | private void IndexElement(Row row, XElement element) |
| 274 | { | 287 | { |
| 275 | this.IndexedElements.Add(String.Concat(row.TableDefinition.Name, ':', row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter)), element); | 288 | this.IndexedElements.Add(String.Concat(row.TableDefinition.Name, ':', row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter)), element); |
| 276 | } | 289 | } |
| @@ -293,9 +306,15 @@ namespace WixToolset.Core.WindowsInstaller.Decompile | |||
| 293 | .ToDictionary(lookup => lookup.Key, lookup => lookup.ToList()); | 306 | .ToDictionary(lookup => lookup.Key, lookup => lookup.ToList()); |
| 294 | } | 307 | } |
| 295 | 308 | ||
| 296 | private Dictionary<string, List<XElement>> IndexTableOneToMany(TableIndexedCollection tables, string tableName, int column = 0) => this.IndexTableOneToMany(tables[tableName]?.Rows ?? Enumerable.Empty<Row>(), column); | 309 | private Dictionary<string, List<XElement>> IndexTableOneToMany(TableIndexedCollection tables, string tableName, int column = 0) |
| 310 | { | ||
| 311 | return this.IndexTableOneToMany(tables[tableName]?.Rows ?? Enumerable.Empty<Row>(), column); | ||
| 312 | } | ||
| 297 | 313 | ||
| 298 | private Dictionary<string, List<XElement>> IndexTableOneToMany(Table table, int column = 0) => this.IndexTableOneToMany(table?.Rows ?? Enumerable.Empty<Row>(), column); | 314 | private Dictionary<string, List<XElement>> IndexTableOneToMany(Table table, int column = 0) |
| 315 | { | ||
| 316 | return this.IndexTableOneToMany(table?.Rows ?? Enumerable.Empty<Row>(), column); | ||
| 317 | } | ||
| 299 | 318 | ||
| 300 | private void AddChildToParent(string parentName, XElement xChild, Row row, int column) | 319 | private void AddChildToParent(string parentName, XElement xChild, Row row, int column) |
| 301 | { | 320 | { |
| @@ -310,7 +329,10 @@ namespace WixToolset.Core.WindowsInstaller.Decompile | |||
| 310 | } | 329 | } |
| 311 | } | 330 | } |
| 312 | 331 | ||
| 313 | private static XAttribute XAttributeIfNotNull(string attributeName, Row row, int column) => row.IsColumnNull(column) ? null : new XAttribute(attributeName, row.FieldAsString(column)); | 332 | private static XAttribute XAttributeIfNotNull(string attributeName, Row row, int column) |
| 333 | { | ||
| 334 | return row.IsColumnNull(column) ? null : new XAttribute(attributeName, row.FieldAsString(column)); | ||
| 335 | } | ||
| 314 | 336 | ||
| 315 | private static void SetAttributeIfNotNull(XElement xElement, string attributeName, string value) | 337 | private static void SetAttributeIfNotNull(XElement xElement, string attributeName, string value) |
| 316 | { | 338 | { |
| @@ -1578,7 +1600,10 @@ namespace WixToolset.Core.WindowsInstaller.Decompile | |||
| 1578 | /// Nests the Permission elements below their parent elements. There are no declared foreign | 1600 | /// Nests the Permission elements below their parent elements. There are no declared foreign |
| 1579 | /// keys for the parents of the LockPermissions table. | 1601 | /// keys for the parents of the LockPermissions table. |
| 1580 | /// </remarks> | 1602 | /// </remarks> |
| 1581 | private void FinalizeLockPermissionsTable(TableIndexedCollection tables) => this.FinalizePermissionsTable(tables, "LockPermissions"); | 1603 | private void FinalizeLockPermissionsTable(TableIndexedCollection tables) |
| 1604 | { | ||
| 1605 | this.FinalizePermissionsTable(tables, "LockPermissions"); | ||
| 1606 | } | ||
| 1582 | 1607 | ||
| 1583 | /// <summary> | 1608 | /// <summary> |
| 1584 | /// Finalize the MsiLockPermissionsEx table. | 1609 | /// Finalize the MsiLockPermissionsEx table. |
| @@ -1588,7 +1613,10 @@ namespace WixToolset.Core.WindowsInstaller.Decompile | |||
| 1588 | /// Nests the PermissionEx elements below their parent elements. There are no declared foreign | 1613 | /// Nests the PermissionEx elements below their parent elements. There are no declared foreign |
| 1589 | /// keys for the parents of the MsiLockPermissionsEx table. | 1614 | /// keys for the parents of the MsiLockPermissionsEx table. |
| 1590 | /// </remarks> | 1615 | /// </remarks> |
| 1591 | private void FinalizeMsiLockPermissionsExTable(TableIndexedCollection tables) => this.FinalizePermissionsTable(tables, "MsiLockPermissionsEx"); | 1616 | private void FinalizeMsiLockPermissionsExTable(TableIndexedCollection tables) |
| 1617 | { | ||
| 1618 | this.FinalizePermissionsTable(tables, "MsiLockPermissionsEx"); | ||
| 1619 | } | ||
| 1592 | 1620 | ||
| 1593 | private static Dictionary<string, List<string>> IndexTable(Table table, int keyColumn, int? dataColumn) | 1621 | private static Dictionary<string, List<string>> IndexTable(Table table, int keyColumn, int? dataColumn) |
| 1594 | { | 1622 | { |
| @@ -2462,53 +2490,44 @@ namespace WixToolset.Core.WindowsInstaller.Decompile | |||
| 2462 | // index the rows from the extension libraries | 2490 | // index the rows from the extension libraries |
| 2463 | var indexedExtensionTables = new Dictionary<string, HashSet<string>>(); | 2491 | var indexedExtensionTables = new Dictionary<string, HashSet<string>>(); |
| 2464 | #if TODO_DECOMPILER_EXTENSIONS | 2492 | #if TODO_DECOMPILER_EXTENSIONS |
| 2465 | foreach (IDecompilerExtension extension in this.extensions) | 2493 | foreach (var extension in this.Extensions) |
| 2466 | { | 2494 | { |
| 2467 | // Get the optional library from the extension with the rows to be removed. | 2495 | // Get the optional library from the extension with the rows to be removed. |
| 2468 | Library library = extension.GetLibraryToRemove(this.tableDefinitions); | 2496 | var library = extension.GetLibraryToRemove(this.tableDefinitions); |
| 2469 | if (null != library) | 2497 | if (library != null) |
| 2470 | { | 2498 | { |
| 2471 | foreach (var section in library.Sections) | 2499 | foreach (var row in library.Sections.SelectMany(s => s.Tables).SelectMany(t => t.Rows)) |
| 2472 | { | 2500 | { |
| 2473 | foreach (Table table in section.Tables) | 2501 | string primaryKey; |
| 2474 | { | 2502 | string tableName; |
| 2475 | foreach (Row row in table.Rows) | ||
| 2476 | { | ||
| 2477 | string primaryKey; | ||
| 2478 | string tableName; | ||
| 2479 | |||
| 2480 | // the Actions table needs to be handled specially | ||
| 2481 | if ("WixAction" == table.Name) | ||
| 2482 | { | ||
| 2483 | primaryKey = row.FieldAsString(1); | ||
| 2484 | 2503 | ||
| 2485 | if (OutputType.Module == this.outputType) | 2504 | // the Actions table needs to be handled specially |
| 2486 | { | 2505 | if (table.Name == "WixAction") |
| 2487 | tableName = String.Concat("Module", row.FieldAsString(0)); | 2506 | { |
| 2488 | } | 2507 | primaryKey = row.FieldAsString(1); |
| 2489 | else | 2508 | tableName = row.FieldAsString(0); |
| 2490 | { | ||
| 2491 | tableName = row.FieldAsString(0); | ||
| 2492 | } | ||
| 2493 | } | ||
| 2494 | else | ||
| 2495 | { | ||
| 2496 | primaryKey = row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter); | ||
| 2497 | tableName = table.Name; | ||
| 2498 | } | ||
| 2499 | 2509 | ||
| 2500 | if (null != primaryKey) | 2510 | if (this.outputType == OutputType.Module) |
| 2501 | { | 2511 | { |
| 2502 | HashSet<string> indexedExtensionRows; | 2512 | tableName = "Module" + tableName; |
| 2503 | if (!indexedExtensionTables.TryGetValue(tableName, out indexedExtensionRows)) | 2513 | } |
| 2504 | { | 2514 | } |
| 2505 | indexedExtensionRows = new HashSet<string>(); | 2515 | else |
| 2506 | indexedExtensionTables.Add(tableName, indexedExtensionRows); | 2516 | { |
| 2507 | } | 2517 | primaryKey = row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter); |
| 2518 | tableName = table.Name; | ||
| 2519 | } | ||
| 2508 | 2520 | ||
| 2509 | indexedExtensionRows.Add(primaryKey); | 2521 | if (primaryKey != null) |
| 2510 | } | 2522 | { |
| 2523 | HashSet<string> indexedExtensionRows; | ||
| 2524 | if (!indexedExtensionTables.TryGetValue(tableName, out indexedExtensionRows)) | ||
| 2525 | { | ||
| 2526 | indexedExtensionRows = new HashSet<string>(); | ||
| 2527 | indexedExtensionTables.Add(tableName, indexedExtensionRows); | ||
| 2511 | } | 2528 | } |
| 2529 | |||
| 2530 | indexedExtensionRows.Add(primaryKey); | ||
| 2512 | } | 2531 | } |
| 2513 | } | 2532 | } |
| 2514 | } | 2533 | } |
diff --git a/src/wix/WixToolset.Core.WindowsInstaller/IWindowsInstallerDecompiler.cs b/src/wix/WixToolset.Core.WindowsInstaller/IWindowsInstallerDecompiler.cs new file mode 100644 index 00000000..5bcda36c --- /dev/null +++ b/src/wix/WixToolset.Core.WindowsInstaller/IWindowsInstallerDecompiler.cs | |||
| @@ -0,0 +1,19 @@ | |||
| 1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. | ||
| 2 | |||
| 3 | namespace WixToolset.Core | ||
| 4 | { | ||
| 5 | using WixToolset.Extensibility.Data; | ||
| 6 | |||
| 7 | /// <summary> | ||
| 8 | /// Supports converting Windows Installer databases to source code. | ||
| 9 | /// </summary> | ||
| 10 | public interface IWindowsInstallerDecompiler | ||
| 11 | { | ||
| 12 | /// <summary> | ||
| 13 | /// Converts Windows Installer database back to source code. | ||
| 14 | /// </summary> | ||
| 15 | /// <param name="context">Context for decompiling.</param> | ||
| 16 | /// <returns>Result of decompilation.</returns> | ||
| 17 | IWindowsInstallerDecompileResult Decompile(IWindowsInstallerDecompileContext context); | ||
| 18 | } | ||
| 19 | } | ||
diff --git a/src/wix/WixToolset.Core.WindowsInstaller/MsiBackend.cs b/src/wix/WixToolset.Core.WindowsInstaller/MsiBackend.cs index d1c1d3a6..f73791aa 100644 --- a/src/wix/WixToolset.Core.WindowsInstaller/MsiBackend.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/MsiBackend.cs | |||
| @@ -47,27 +47,5 @@ namespace WixToolset.Core.WindowsInstaller | |||
| 47 | } | 47 | } |
| 48 | } | 48 | } |
| 49 | } | 49 | } |
| 50 | |||
| 51 | public IDecompileResult Decompile(IDecompileContext context) | ||
| 52 | { | ||
| 53 | var extensionManager = context.ServiceProvider.GetService<IExtensionManager>(); | ||
| 54 | |||
| 55 | var backendExtensions = extensionManager.GetServices<IWindowsInstallerBackendDecompilerExtension>(); | ||
| 56 | |||
| 57 | foreach (var extension in backendExtensions) | ||
| 58 | { | ||
| 59 | extension.PreBackendDecompile(context); | ||
| 60 | } | ||
| 61 | |||
| 62 | var command = new DecompileMsiOrMsmCommand(context, backendExtensions); | ||
| 63 | var result = command.Execute(); | ||
| 64 | |||
| 65 | foreach (var extension in backendExtensions) | ||
| 66 | { | ||
| 67 | extension.PostBackendDecompile(result); | ||
| 68 | } | ||
| 69 | |||
| 70 | return result; | ||
| 71 | } | ||
| 72 | } | 50 | } |
| 73 | } | 51 | } |
diff --git a/src/wix/WixToolset.Core.WindowsInstaller/MsmBackend.cs b/src/wix/WixToolset.Core.WindowsInstaller/MsmBackend.cs index ea008c39..fa24745a 100644 --- a/src/wix/WixToolset.Core.WindowsInstaller/MsmBackend.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/MsmBackend.cs | |||
| @@ -2,11 +2,7 @@ | |||
| 2 | 2 | ||
| 3 | namespace WixToolset.Core.WindowsInstaller | 3 | namespace WixToolset.Core.WindowsInstaller |
| 4 | { | 4 | { |
| 5 | using System; | ||
| 6 | using WixToolset.Core.WindowsInstaller.Bind; | 5 | using WixToolset.Core.WindowsInstaller.Bind; |
| 7 | using WixToolset.Core.WindowsInstaller.Decompile; | ||
| 8 | using WixToolset.Core.WindowsInstaller.Unbind; | ||
| 9 | using WixToolset.Data; | ||
| 10 | using WixToolset.Extensibility; | 6 | using WixToolset.Extensibility; |
| 11 | using WixToolset.Extensibility.Data; | 7 | using WixToolset.Extensibility.Data; |
| 12 | using WixToolset.Extensibility.Services; | 8 | using WixToolset.Extensibility.Services; |
| @@ -43,27 +39,5 @@ namespace WixToolset.Core.WindowsInstaller | |||
| 43 | throw; | 39 | throw; |
| 44 | } | 40 | } |
| 45 | } | 41 | } |
| 46 | |||
| 47 | public IDecompileResult Decompile(IDecompileContext context) | ||
| 48 | { | ||
| 49 | var extensionManager = context.ServiceProvider.GetService<IExtensionManager>(); | ||
| 50 | |||
| 51 | var backendExtensions = extensionManager.GetServices<IWindowsInstallerBackendDecompilerExtension>(); | ||
| 52 | |||
| 53 | foreach (var extension in backendExtensions) | ||
| 54 | { | ||
| 55 | extension.PreBackendDecompile(context); | ||
| 56 | } | ||
| 57 | |||
| 58 | var command = new DecompileMsiOrMsmCommand(context, backendExtensions); | ||
| 59 | var result = command.Execute(); | ||
| 60 | |||
| 61 | foreach (var extension in backendExtensions) | ||
| 62 | { | ||
| 63 | extension.PostBackendDecompile(result); | ||
| 64 | } | ||
| 65 | |||
| 66 | return result; | ||
| 67 | } | ||
| 68 | } | 42 | } |
| 69 | } | 43 | } |
diff --git a/src/wix/WixToolset.Core.WindowsInstaller/MspBackend.cs b/src/wix/WixToolset.Core.WindowsInstaller/MspBackend.cs index 398fc780..38a4ab34 100644 --- a/src/wix/WixToolset.Core.WindowsInstaller/MspBackend.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/MspBackend.cs | |||
| @@ -63,11 +63,6 @@ namespace WixToolset.Core.WindowsInstaller | |||
| 63 | } | 63 | } |
| 64 | } | 64 | } |
| 65 | 65 | ||
| 66 | public IDecompileResult Decompile(IDecompileContext context) | ||
| 67 | { | ||
| 68 | throw new NotImplementedException(); | ||
| 69 | } | ||
| 70 | |||
| 71 | #if TODO_PATCHING | 66 | #if TODO_PATCHING |
| 72 | public Intermediate Unbind(IUnbindContext context) | 67 | public Intermediate Unbind(IUnbindContext context) |
| 73 | { | 68 | { |
diff --git a/src/wix/WixToolset.Core/DecompileContext.cs b/src/wix/WixToolset.Core.WindowsInstaller/WindowsInstallerDecompileContext.cs index a7ec03fd..1428a469 100644 --- a/src/wix/WixToolset.Core/DecompileContext.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/WindowsInstallerDecompileContext.cs | |||
| @@ -1,17 +1,16 @@ | |||
| 1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. | 1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. |
| 2 | 2 | ||
| 3 | namespace WixToolset.Core | 3 | namespace WixToolset.Core.WindowsInstaller |
| 4 | { | 4 | { |
| 5 | using System; | 5 | using System; |
| 6 | using System.Collections.Generic; | 6 | using System.Collections.Generic; |
| 7 | using WixToolset.Data; | 7 | using WixToolset.Data; |
| 8 | using WixToolset.Extensibility; | 8 | using WixToolset.Extensibility; |
| 9 | using WixToolset.Extensibility.Data; | 9 | using WixToolset.Extensibility.Data; |
| 10 | using WixToolset.Extensibility.Services; | ||
| 11 | 10 | ||
| 12 | internal class DecompileContext : IDecompileContext | 11 | internal class WindowsInstallerDecompileContext : IWindowsInstallerDecompileContext |
| 13 | { | 12 | { |
| 14 | internal DecompileContext(IServiceProvider serviceProvider) | 13 | internal WindowsInstallerDecompileContext(IServiceProvider serviceProvider) |
| 15 | { | 14 | { |
| 16 | this.ServiceProvider = serviceProvider; | 15 | this.ServiceProvider = serviceProvider; |
| 17 | } | 16 | } |
| @@ -22,7 +21,7 @@ namespace WixToolset.Core | |||
| 22 | 21 | ||
| 23 | public OutputType DecompileType { get; set; } | 22 | public OutputType DecompileType { get; set; } |
| 24 | 23 | ||
| 25 | public IReadOnlyCollection<IDecompilerExtension> Extensions { get; set; } | 24 | public IReadOnlyCollection<IWindowsInstallerDecompilerExtension> Extensions { get; set; } |
| 26 | 25 | ||
| 27 | public string ExtractFolder { get; set; } | 26 | public string ExtractFolder { get; set; } |
| 28 | 27 | ||
| @@ -40,6 +39,8 @@ namespace WixToolset.Core | |||
| 40 | 39 | ||
| 41 | public bool SuppressDroppingEmptyTables { get; set; } | 40 | public bool SuppressDroppingEmptyTables { get; set; } |
| 42 | 41 | ||
| 42 | public bool SuppressRelativeActionSequencing { get; set; } | ||
| 43 | |||
| 43 | public bool SuppressExtractCabinets { get; set; } | 44 | public bool SuppressExtractCabinets { get; set; } |
| 44 | 45 | ||
| 45 | public bool SuppressUI { get; set; } | 46 | public bool SuppressUI { get; set; } |
diff --git a/src/wix/WixToolset.Core/DecompileResult.cs b/src/wix/WixToolset.Core.WindowsInstaller/WindowsInstallerDecompileResult.cs index fc24cab7..69363286 100644 --- a/src/wix/WixToolset.Core/DecompileResult.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/WindowsInstallerDecompileResult.cs | |||
| @@ -1,13 +1,13 @@ | |||
| 1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. | 1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. |
| 2 | 2 | ||
| 3 | namespace WixToolset.Core | 3 | namespace WixToolset.Core.WindowsInstaller |
| 4 | { | 4 | { |
| 5 | using System.Collections.Generic; | 5 | using System.Collections.Generic; |
| 6 | using System.Xml.Linq; | 6 | using System.Xml.Linq; |
| 7 | using WixToolset.Data; | 7 | using WixToolset.Data; |
| 8 | using WixToolset.Extensibility.Data; | 8 | using WixToolset.Extensibility.Data; |
| 9 | 9 | ||
| 10 | internal class DecompileResult : IDecompileResult | 10 | internal class WindowsInstallerDecompileResult : IWindowsInstallerDecompileResult |
| 11 | { | 11 | { |
| 12 | public XDocument Document { get; set; } | 12 | public XDocument Document { get; set; } |
| 13 | 13 | ||
diff --git a/src/wix/WixToolset.Core/Decompiler.cs b/src/wix/WixToolset.Core.WindowsInstaller/WindowsInstallerDecompiler.cs index 859f582b..10420010 100644 --- a/src/wix/WixToolset.Core/Decompiler.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/WindowsInstallerDecompiler.cs | |||
| @@ -1,8 +1,9 @@ | |||
| 1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. | 1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. |
| 2 | 2 | ||
| 3 | namespace WixToolset.Core | 3 | namespace WixToolset.Core.WindowsInstaller |
| 4 | { | 4 | { |
| 5 | using System; | 5 | using System; |
| 6 | using WixToolset.Core.WindowsInstaller.Decompile; | ||
| 6 | using WixToolset.Extensibility; | 7 | using WixToolset.Extensibility; |
| 7 | using WixToolset.Extensibility.Data; | 8 | using WixToolset.Extensibility.Data; |
| 8 | using WixToolset.Extensibility.Services; | 9 | using WixToolset.Extensibility.Services; |
| @@ -10,16 +11,16 @@ namespace WixToolset.Core | |||
| 10 | /// <summary> | 11 | /// <summary> |
| 11 | /// Decompiler of the WiX toolset. | 12 | /// Decompiler of the WiX toolset. |
| 12 | /// </summary> | 13 | /// </summary> |
| 13 | internal class Decompiler : IDecompiler | 14 | internal class WindowsInstallerDecompiler : IWindowsInstallerDecompiler |
| 14 | { | 15 | { |
| 15 | internal Decompiler(IServiceProvider serviceProvider) | 16 | internal WindowsInstallerDecompiler(IServiceProvider serviceProvider) |
| 16 | { | 17 | { |
| 17 | this.ServiceProvider = serviceProvider; | 18 | this.ServiceProvider = serviceProvider; |
| 18 | } | 19 | } |
| 19 | 20 | ||
| 20 | public IServiceProvider ServiceProvider { get; } | 21 | public IServiceProvider ServiceProvider { get; } |
| 21 | 22 | ||
| 22 | public IDecompileResult Decompile(IDecompileContext context) | 23 | public IWindowsInstallerDecompileResult Decompile(IWindowsInstallerDecompileContext context) |
| 23 | { | 24 | { |
| 24 | // Pre-decompile. | 25 | // Pre-decompile. |
| 25 | // | 26 | // |
| @@ -30,7 +31,8 @@ namespace WixToolset.Core | |||
| 30 | 31 | ||
| 31 | // Decompile. | 32 | // Decompile. |
| 32 | // | 33 | // |
| 33 | var result = this.BackendDecompile(context); | 34 | var command = new DecompileMsiOrMsmCommand(context); |
| 35 | var result = command.Execute(); | ||
| 34 | 36 | ||
| 35 | if (result != null) | 37 | if (result != null) |
| 36 | { | 38 | { |
| @@ -44,25 +46,5 @@ namespace WixToolset.Core | |||
| 44 | 46 | ||
| 45 | return result; | 47 | return result; |
| 46 | } | 48 | } |
| 47 | |||
| 48 | private IDecompileResult BackendDecompile(IDecompileContext context) | ||
| 49 | { | ||
| 50 | var extensionManager = context.ServiceProvider.GetService<IExtensionManager>(); | ||
| 51 | |||
| 52 | var backendFactories = extensionManager.GetServices<IBackendFactory>(); | ||
| 53 | |||
| 54 | foreach (var factory in backendFactories) | ||
| 55 | { | ||
| 56 | if (factory.TryCreateBackend(context.DecompileType.ToString(), context.OutputPath, out var backend)) | ||
| 57 | { | ||
| 58 | var result = backend.Decompile(context); | ||
| 59 | return result; | ||
| 60 | } | ||
| 61 | } | ||
| 62 | |||
| 63 | // TODO: messaging that a backend could not be found to decompile the decompile type? | ||
| 64 | |||
| 65 | return null; | ||
| 66 | } | ||
| 67 | } | 49 | } |
| 68 | } | 50 | } |
diff --git a/src/wix/WixToolset.Core.WindowsInstaller/WixToolsetCoreServiceProviderExtensions.cs b/src/wix/WixToolset.Core.WindowsInstaller/WixToolsetCoreServiceProviderExtensions.cs index e686fa49..d064aed1 100644 --- a/src/wix/WixToolset.Core.WindowsInstaller/WixToolsetCoreServiceProviderExtensions.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/WixToolsetCoreServiceProviderExtensions.cs | |||
| @@ -5,6 +5,7 @@ namespace WixToolset.Core.WindowsInstaller | |||
| 5 | using System; | 5 | using System; |
| 6 | using System.Collections.Generic; | 6 | using System.Collections.Generic; |
| 7 | using WixToolset.Core.WindowsInstaller.ExtensibilityServices; | 7 | using WixToolset.Core.WindowsInstaller.ExtensibilityServices; |
| 8 | using WixToolset.Extensibility.Data; | ||
| 8 | using WixToolset.Extensibility.Services; | 9 | using WixToolset.Extensibility.Services; |
| 9 | 10 | ||
| 10 | /// <summary> | 11 | /// <summary> |
| @@ -31,6 +32,11 @@ namespace WixToolset.Core.WindowsInstaller | |||
| 31 | { | 32 | { |
| 32 | // Singletons. | 33 | // Singletons. |
| 33 | coreProvider.AddService((provider, singletons) => AddSingleton<IWindowsInstallerBackendHelper>(singletons, new WindowsInstallerBackendHelper(provider))); | 34 | coreProvider.AddService((provider, singletons) => AddSingleton<IWindowsInstallerBackendHelper>(singletons, new WindowsInstallerBackendHelper(provider))); |
| 35 | |||
| 36 | // Transients. | ||
| 37 | coreProvider.AddService<IWindowsInstallerDecompiler>((provider, singletons) => new WindowsInstallerDecompiler(provider)); | ||
| 38 | coreProvider.AddService<IWindowsInstallerDecompileContext>((provider, singletons) => new WindowsInstallerDecompileContext(provider)); | ||
| 39 | coreProvider.AddService<IWindowsInstallerDecompileResult>((provider, singletons) => new WindowsInstallerDecompileResult()); | ||
| 34 | } | 40 | } |
| 35 | 41 | ||
| 36 | private static T AddSingleton<T>(Dictionary<Type, object> singletons, T service) where T : class | 42 | private static T AddSingleton<T>(Dictionary<Type, object> singletons, T service) where T : class |
diff --git a/src/wix/WixToolset.Core/CommandLine/CommandLine.cs b/src/wix/WixToolset.Core/CommandLine/CommandLine.cs index cd3b2fe4..0921f9ff 100644 --- a/src/wix/WixToolset.Core/CommandLine/CommandLine.cs +++ b/src/wix/WixToolset.Core/CommandLine/CommandLine.cs | |||
| @@ -9,14 +9,6 @@ namespace WixToolset.Core.CommandLine | |||
| 9 | using WixToolset.Extensibility.Data; | 9 | using WixToolset.Extensibility.Data; |
| 10 | using WixToolset.Extensibility.Services; | 10 | using WixToolset.Extensibility.Services; |
| 11 | 11 | ||
| 12 | internal enum CommandTypes | ||
| 13 | { | ||
| 14 | Unknown, | ||
| 15 | Build, | ||
| 16 | Preprocess, | ||
| 17 | Decompile, | ||
| 18 | } | ||
| 19 | |||
| 20 | internal class CommandLine : ICommandLine | 12 | internal class CommandLine : ICommandLine |
| 21 | { | 13 | { |
| 22 | public CommandLine(IServiceProvider serviceProvider) | 14 | public CommandLine(IServiceProvider serviceProvider) |
| @@ -154,18 +146,9 @@ namespace WixToolset.Core.CommandLine | |||
| 154 | } | 146 | } |
| 155 | else | 147 | else |
| 156 | { | 148 | { |
| 157 | if (Enum.TryParse(arg, true, out CommandTypes commandType)) | 149 | if ("build".Equals(arg, StringComparison.OrdinalIgnoreCase)) |
| 158 | { | 150 | { |
| 159 | switch (commandType) | 151 | command = new BuildCommand(this.ServiceProvider); |
| 160 | { | ||
| 161 | case CommandTypes.Build: | ||
| 162 | command = new BuildCommand(this.ServiceProvider); | ||
| 163 | break; | ||
| 164 | |||
| 165 | case CommandTypes.Decompile: | ||
| 166 | command = new DecompileCommand(this.ServiceProvider); | ||
| 167 | break; | ||
| 168 | } | ||
| 169 | } | 152 | } |
| 170 | else | 153 | else |
| 171 | { | 154 | { |
| @@ -175,8 +158,6 @@ namespace WixToolset.Core.CommandLine | |||
| 175 | { | 158 | { |
| 176 | break; | 159 | break; |
| 177 | } | 160 | } |
| 178 | |||
| 179 | command = null; | ||
| 180 | } | 161 | } |
| 181 | } | 162 | } |
| 182 | } | 163 | } |
diff --git a/src/wix/WixToolset.Core/CommandLine/CommandLineParser.cs b/src/wix/WixToolset.Core/CommandLine/CommandLineParser.cs index 015d3e62..7e6e7cac 100644 --- a/src/wix/WixToolset.Core/CommandLine/CommandLineParser.cs +++ b/src/wix/WixToolset.Core/CommandLine/CommandLineParser.cs | |||
| @@ -41,12 +41,16 @@ namespace WixToolset.Core.CommandLine | |||
| 41 | return argument; | 41 | return argument; |
| 42 | } | 42 | } |
| 43 | 43 | ||
| 44 | public void GetArgumentAsFilePathOrError(string argument, string fileType, IList<string> paths) | 44 | public bool GetArgumentAsFilePathOrError(string argument, string fileType, IList<string> paths) |
| 45 | { | 45 | { |
| 46 | foreach (var path in this.GetFiles(argument, fileType)) | 46 | var files = this.GetFiles(argument, fileType); |
| 47 | |||
| 48 | foreach (var path in files) | ||
| 47 | { | 49 | { |
| 48 | paths.Add(path); | 50 | paths.Add(path); |
| 49 | } | 51 | } |
| 52 | |||
| 53 | return files.Length > 0; | ||
| 50 | } | 54 | } |
| 51 | 55 | ||
| 52 | public string GetNextArgumentOrError(string commandLineSwitch) | 56 | public string GetNextArgumentOrError(string commandLineSwitch) |
| @@ -140,6 +144,23 @@ namespace WixToolset.Core.CommandLine | |||
| 140 | return false; | 144 | return false; |
| 141 | } | 145 | } |
| 142 | 146 | ||
| 147 | public string PeekNextArgument() | ||
| 148 | { | ||
| 149 | return this.TryPeekNextArgument(out var argument) ? argument : null; | ||
| 150 | } | ||
| 151 | |||
| 152 | public bool TryPeekNextArgument(out string argument) | ||
| 153 | { | ||
| 154 | if (this.RemainingArguments.Count > 0) | ||
| 155 | { | ||
| 156 | argument = this.RemainingArguments.Peek(); | ||
| 157 | return true; | ||
| 158 | } | ||
| 159 | |||
| 160 | argument = null; | ||
| 161 | return false; | ||
| 162 | } | ||
| 163 | |||
| 143 | private bool TryGetNextNonSwitchArgumentOrError(out string arg) | 164 | private bool TryGetNextNonSwitchArgumentOrError(out string arg) |
| 144 | { | 165 | { |
| 145 | var result = this.TryGetNextSwitchOrArgument(out arg); | 166 | var result = this.TryGetNextSwitchOrArgument(out arg); |
diff --git a/src/wix/WixToolset.Core/CommandLine/DecompileCommand.cs b/src/wix/WixToolset.Core/CommandLine/DecompileCommand.cs deleted file mode 100644 index 22853f86..00000000 --- a/src/wix/WixToolset.Core/CommandLine/DecompileCommand.cs +++ /dev/null | |||
| @@ -1,202 +0,0 @@ | |||
| 1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. | ||
| 2 | |||
| 3 | namespace WixToolset.Core.CommandLine | ||
| 4 | { | ||
| 5 | using System; | ||
| 6 | using System.IO; | ||
| 7 | using System.Threading; | ||
| 8 | using System.Threading.Tasks; | ||
| 9 | using System.Xml.Linq; | ||
| 10 | using WixToolset.Data; | ||
| 11 | using WixToolset.Extensibility; | ||
| 12 | using WixToolset.Extensibility.Data; | ||
| 13 | using WixToolset.Extensibility.Services; | ||
| 14 | |||
| 15 | internal class DecompileCommand : ICommandLineCommand | ||
| 16 | { | ||
| 17 | private readonly CommandLine commandLine; | ||
| 18 | |||
| 19 | public DecompileCommand(IServiceProvider serviceProvider) | ||
| 20 | { | ||
| 21 | this.ServiceProvider = serviceProvider; | ||
| 22 | this.Messaging = serviceProvider.GetService<IMessaging>(); | ||
| 23 | this.commandLine = new CommandLine(this.Messaging); | ||
| 24 | } | ||
| 25 | |||
| 26 | public bool ShowHelp | ||
| 27 | { | ||
| 28 | get { return this.commandLine.ShowHelp; } | ||
| 29 | set { this.commandLine.ShowHelp = value; } | ||
| 30 | } | ||
| 31 | |||
| 32 | public bool ShowLogo | ||
| 33 | { | ||
| 34 | get { return this.commandLine.ShowLogo; } | ||
| 35 | set { this.commandLine.ShowLogo = value; } | ||
| 36 | } | ||
| 37 | |||
| 38 | // Stop parsing when we've decided to show help. | ||
| 39 | public bool StopParsing => this.commandLine.ShowHelp; | ||
| 40 | |||
| 41 | private IServiceProvider ServiceProvider { get; } | ||
| 42 | |||
| 43 | public IMessaging Messaging { get; } | ||
| 44 | |||
| 45 | public Task<int> ExecuteAsync(CancellationToken _) | ||
| 46 | { | ||
| 47 | if (this.commandLine.ShowHelp || String.IsNullOrEmpty(this.commandLine.DecompileFilePath)) | ||
| 48 | { | ||
| 49 | Console.WriteLine("TODO: Show decompile command help"); | ||
| 50 | return Task.FromResult(-1); | ||
| 51 | } | ||
| 52 | |||
| 53 | var context = this.ServiceProvider.GetService<IDecompileContext>(); | ||
| 54 | context.Extensions = this.ServiceProvider.GetService<IExtensionManager>().GetServices<IDecompilerExtension>(); | ||
| 55 | context.DecompilePath = this.commandLine.DecompileFilePath; | ||
| 56 | context.DecompileType = this.commandLine.CalculateDecompileType(); | ||
| 57 | context.IntermediateFolder = this.commandLine.CalculateIntermedateFolder(); | ||
| 58 | context.OutputPath = this.commandLine.CalculateOutputPath(); | ||
| 59 | |||
| 60 | try | ||
| 61 | { | ||
| 62 | var decompiler = this.ServiceProvider.GetService<IDecompiler>(); | ||
| 63 | var result = decompiler.Decompile(context); | ||
| 64 | |||
| 65 | if (!this.Messaging.EncounteredError) | ||
| 66 | { | ||
| 67 | Directory.CreateDirectory(Path.GetDirectoryName(Path.GetFullPath(context.OutputPath))); | ||
| 68 | result.Document.Save(context.OutputPath, SaveOptions.OmitDuplicateNamespaces); | ||
| 69 | } | ||
| 70 | } | ||
| 71 | catch (WixException e) | ||
| 72 | { | ||
| 73 | this.Messaging.Write(e.Error); | ||
| 74 | } | ||
| 75 | |||
| 76 | if (this.Messaging.EncounteredError) | ||
| 77 | { | ||
| 78 | return Task.FromResult(1); | ||
| 79 | } | ||
| 80 | |||
| 81 | return Task.FromResult(0); | ||
| 82 | } | ||
| 83 | |||
| 84 | public bool TryParseArgument(ICommandLineParser parser, string argument) | ||
| 85 | { | ||
| 86 | return this.commandLine.TryParseArgument(argument, parser); | ||
| 87 | } | ||
| 88 | |||
| 89 | private class CommandLine | ||
| 90 | { | ||
| 91 | public CommandLine(IMessaging messaging) | ||
| 92 | { | ||
| 93 | this.Messaging = messaging; | ||
| 94 | } | ||
| 95 | |||
| 96 | private IMessaging Messaging { get; } | ||
| 97 | |||
| 98 | public string DecompileFilePath { get; private set; } | ||
| 99 | |||
| 100 | public string DecompileType { get; private set; } | ||
| 101 | |||
| 102 | public Platform Platform { get; private set; } | ||
| 103 | |||
| 104 | public bool ShowLogo { get; set; } | ||
| 105 | |||
| 106 | public bool ShowHelp { get; set; } | ||
| 107 | |||
| 108 | public string IntermediateFolder { get; private set; } | ||
| 109 | |||
| 110 | public string OutputFile { get; private set; } | ||
| 111 | |||
| 112 | public bool TryParseArgument(string arg, ICommandLineParser parser) | ||
| 113 | { | ||
| 114 | if (parser.IsSwitch(arg)) | ||
| 115 | { | ||
| 116 | var parameter = arg.Substring(1); | ||
| 117 | switch (parameter.ToLowerInvariant()) | ||
| 118 | { | ||
| 119 | case "intermediatefolder": | ||
| 120 | this.IntermediateFolder = parser.GetNextArgumentAsDirectoryOrError(arg); | ||
| 121 | return true; | ||
| 122 | |||
| 123 | case "o": | ||
| 124 | case "out": | ||
| 125 | this.OutputFile = parser.GetNextArgumentAsFilePathOrError(arg); | ||
| 126 | return true; | ||
| 127 | } | ||
| 128 | } | ||
| 129 | else | ||
| 130 | { | ||
| 131 | if (String.IsNullOrEmpty(this.DecompileFilePath)) | ||
| 132 | { | ||
| 133 | this.DecompileFilePath = parser.GetArgumentAsFilePathOrError(arg, "decompile file"); | ||
| 134 | return true; | ||
| 135 | } | ||
| 136 | else if (String.IsNullOrEmpty(this.OutputFile)) | ||
| 137 | { | ||
| 138 | this.OutputFile = parser.GetArgumentAsFilePathOrError(arg, "output file"); | ||
| 139 | return true; | ||
| 140 | } | ||
| 141 | } | ||
| 142 | |||
| 143 | return false; | ||
| 144 | } | ||
| 145 | |||
| 146 | public OutputType CalculateDecompileType() | ||
| 147 | { | ||
| 148 | if (String.IsNullOrEmpty(this.DecompileType)) | ||
| 149 | { | ||
| 150 | this.DecompileType = Path.GetExtension(this.DecompileFilePath); | ||
| 151 | } | ||
| 152 | |||
| 153 | switch (this.DecompileType.ToLowerInvariant()) | ||
| 154 | { | ||
| 155 | case "bundle": | ||
| 156 | case ".exe": | ||
| 157 | return OutputType.Bundle; | ||
| 158 | |||
| 159 | case "library": | ||
| 160 | case ".wixlib": | ||
| 161 | return OutputType.Library; | ||
| 162 | |||
| 163 | case "module": | ||
| 164 | case ".msm": | ||
| 165 | return OutputType.Module; | ||
| 166 | |||
| 167 | case "patch": | ||
| 168 | case ".msp": | ||
| 169 | return OutputType.Patch; | ||
| 170 | |||
| 171 | case ".pcp": | ||
| 172 | return OutputType.PatchCreation; | ||
| 173 | |||
| 174 | case "product": | ||
| 175 | case "package": | ||
| 176 | case ".msi": | ||
| 177 | return OutputType.Product; | ||
| 178 | |||
| 179 | case "transform": | ||
| 180 | case ".mst": | ||
| 181 | return OutputType.Transform; | ||
| 182 | |||
| 183 | case "intermediatepostlink": | ||
| 184 | case ".wixipl": | ||
| 185 | return OutputType.IntermediatePostLink; | ||
| 186 | } | ||
| 187 | |||
| 188 | return OutputType.Unknown; | ||
| 189 | } | ||
| 190 | |||
| 191 | public string CalculateIntermedateFolder() | ||
| 192 | { | ||
| 193 | return String.IsNullOrEmpty(this.IntermediateFolder) ? Path.GetTempPath() : this.IntermediateFolder; | ||
| 194 | } | ||
| 195 | |||
| 196 | public string CalculateOutputPath() | ||
| 197 | { | ||
| 198 | return String.IsNullOrEmpty(this.OutputFile) ? Path.ChangeExtension(this.DecompileFilePath, ".wxs") : this.OutputFile; | ||
| 199 | } | ||
| 200 | } | ||
| 201 | } | ||
| 202 | } | ||
diff --git a/src/wix/WixToolset.Core/IDecompiler.cs b/src/wix/WixToolset.Core/IDecompiler.cs deleted file mode 100644 index 74ec26de..00000000 --- a/src/wix/WixToolset.Core/IDecompiler.cs +++ /dev/null | |||
| @@ -1,12 +0,0 @@ | |||
| 1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. | ||
| 2 | |||
| 3 | namespace WixToolset.Core | ||
| 4 | { | ||
| 5 | using WixToolset.Extensibility.Data; | ||
| 6 | |||
| 7 | #pragma warning disable 1591 // TODO: add documentation | ||
| 8 | public interface IDecompiler | ||
| 9 | { | ||
| 10 | IDecompileResult Decompile(IDecompileContext context); | ||
| 11 | } | ||
| 12 | } | ||
diff --git a/src/wix/WixToolset.Core/WixToolsetServiceProvider.cs b/src/wix/WixToolset.Core/WixToolsetServiceProvider.cs index 9fbf6717..525b9dd9 100644 --- a/src/wix/WixToolset.Core/WixToolsetServiceProvider.cs +++ b/src/wix/WixToolset.Core/WixToolsetServiceProvider.cs | |||
| @@ -40,14 +40,12 @@ namespace WixToolset.Core | |||
| 40 | this.AddService<ILinkContext>((provider, singletons) => new LinkContext(provider)); | 40 | this.AddService<ILinkContext>((provider, singletons) => new LinkContext(provider)); |
| 41 | this.AddService<IResolveContext>((provider, singletons) => new ResolveContext(provider)); | 41 | this.AddService<IResolveContext>((provider, singletons) => new ResolveContext(provider)); |
| 42 | this.AddService<IBindContext>((provider, singletons) => new BindContext(provider)); | 42 | this.AddService<IBindContext>((provider, singletons) => new BindContext(provider)); |
| 43 | this.AddService<IDecompileContext>((provider, singletons) => new DecompileContext(provider)); | ||
| 44 | this.AddService<ILayoutContext>((provider, singletons) => new LayoutContext(provider)); | 43 | this.AddService<ILayoutContext>((provider, singletons) => new LayoutContext(provider)); |
| 45 | 44 | ||
| 46 | this.AddService<IBindFileWithPath>((provider, singletons) => new BindFileWithPath()); | 45 | this.AddService<IBindFileWithPath>((provider, singletons) => new BindFileWithPath()); |
| 47 | this.AddService<IBindPath>((provider, singletons) => new BindPath()); | 46 | this.AddService<IBindPath>((provider, singletons) => new BindPath()); |
| 48 | this.AddService<IBindResult>((provider, singletons) => new BindResult()); | 47 | this.AddService<IBindResult>((provider, singletons) => new BindResult()); |
| 49 | this.AddService<IComponentKeyPath>((provider, singletons) => new ComponentKeyPath()); | 48 | this.AddService<IComponentKeyPath>((provider, singletons) => new ComponentKeyPath()); |
| 50 | this.AddService<IDecompileResult>((provider, singletons) => new DecompileResult()); | ||
| 51 | this.AddService<IIncludedFile>((provider, singletons) => new IncludedFile()); | 49 | this.AddService<IIncludedFile>((provider, singletons) => new IncludedFile()); |
| 52 | this.AddService<IPreprocessResult>((provider, singletons) => new PreprocessResult()); | 50 | this.AddService<IPreprocessResult>((provider, singletons) => new PreprocessResult()); |
| 53 | this.AddService<IResolvedDirectory>((provider, singletons) => new ResolvedDirectory()); | 51 | this.AddService<IResolvedDirectory>((provider, singletons) => new ResolvedDirectory()); |
| @@ -58,7 +56,6 @@ namespace WixToolset.Core | |||
| 58 | 56 | ||
| 59 | this.AddService<IBinder>((provider, singletons) => new Binder(provider)); | 57 | this.AddService<IBinder>((provider, singletons) => new Binder(provider)); |
| 60 | this.AddService<ICompiler>((provider, singletons) => new Compiler(provider)); | 58 | this.AddService<ICompiler>((provider, singletons) => new Compiler(provider)); |
| 61 | this.AddService<IDecompiler>((provider, singletons) => new Decompiler(provider)); | ||
| 62 | this.AddService<ILayoutCreator>((provider, singletons) => new LayoutCreator(provider)); | 59 | this.AddService<ILayoutCreator>((provider, singletons) => new LayoutCreator(provider)); |
| 63 | this.AddService<IPreprocessor>((provider, singletons) => new Preprocessor(provider)); | 60 | this.AddService<IPreprocessor>((provider, singletons) => new Preprocessor(provider)); |
| 64 | this.AddService<ILibrarian>((provider, singletons) => new Librarian(provider)); | 61 | this.AddService<ILibrarian>((provider, singletons) => new Librarian(provider)); |
diff --git a/src/wix/test/WixToolsetTest.Converters/ProductPackageFixture.cs b/src/wix/test/WixToolsetTest.Converters/ProductPackageFixture.cs index e01b9789..5ad7ef6f 100644 --- a/src/wix/test/WixToolsetTest.Converters/ProductPackageFixture.cs +++ b/src/wix/test/WixToolsetTest.Converters/ProductPackageFixture.cs | |||
| @@ -249,7 +249,7 @@ namespace WixToolsetTest.Converters | |||
| 249 | var v3msiPath = Path.Combine(folder, "TypicalV3.msi"); | 249 | var v3msiPath = Path.Combine(folder, "TypicalV3.msi"); |
| 250 | var result = WixRunner.Execute(new[] | 250 | var result = WixRunner.Execute(new[] |
| 251 | { | 251 | { |
| 252 | "decompile", v3msiPath, | 252 | "msi", "decompile", v3msiPath, |
| 253 | "-intermediateFolder", intermediateFolder, | 253 | "-intermediateFolder", intermediateFolder, |
| 254 | "-o", decompiledWxsPath | 254 | "-o", decompiledWxsPath |
| 255 | }); | 255 | }); |
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/CustomTableFixture.cs b/src/wix/test/WixToolsetTest.CoreIntegration/CustomTableFixture.cs index b9a6185d..1be7d9ab 100644 --- a/src/wix/test/WixToolsetTest.CoreIntegration/CustomTableFixture.cs +++ b/src/wix/test/WixToolsetTest.CoreIntegration/CustomTableFixture.cs | |||
| @@ -219,7 +219,7 @@ namespace WixToolsetTest.CoreIntegration | |||
| 219 | 219 | ||
| 220 | result = WixRunner.Execute(new[] | 220 | result = WixRunner.Execute(new[] |
| 221 | { | 221 | { |
| 222 | "decompile", msiPath, | 222 | "msi", "decompile", msiPath, |
| 223 | "-sw1060", | 223 | "-sw1060", |
| 224 | "-intermediateFolder", intermediateFolder, | 224 | "-intermediateFolder", intermediateFolder, |
| 225 | "-o", decompiledWxsPath | 225 | "-o", decompiledWxsPath |
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/DecompileFixture.cs b/src/wix/test/WixToolsetTest.CoreIntegration/DecompileFixture.cs index e87bbfee..b43d2033 100644 --- a/src/wix/test/WixToolsetTest.CoreIntegration/DecompileFixture.cs +++ b/src/wix/test/WixToolsetTest.CoreIntegration/DecompileFixture.cs | |||
| @@ -20,7 +20,7 @@ namespace WixToolsetTest.CoreIntegration | |||
| 20 | 20 | ||
| 21 | var result = WixRunner.Execute(new[] | 21 | var result = WixRunner.Execute(new[] |
| 22 | { | 22 | { |
| 23 | "decompile", | 23 | "msi", "decompile", |
| 24 | Path.Combine(folder, msiName), | 24 | Path.Combine(folder, msiName), |
| 25 | "-intermediateFolder", intermediateFolder, | 25 | "-intermediateFolder", intermediateFolder, |
| 26 | "-o", outputPath | 26 | "-o", outputPath |
