diff options
author | Rob Mensching <rob@firegiant.com> | 2022-03-23 10:25:49 -0700 |
---|---|---|
committer | Rob Mensching <rob@firegiant.com> | 2022-03-30 14:12:12 -0700 |
commit | c86a2148f6dd7bfcd6637b6e1c9e7b5a9b53a996 (patch) | |
tree | 547736274aca4871f71578222e74d9972609c0c6 | |
parent | eedde7ee47ab7b3bef417f2d631814b586cdb011 (diff) | |
download | wix-c86a2148f6dd7bfcd6637b6e1c9e7b5a9b53a996.tar.gz wix-c86a2148f6dd7bfcd6637b6e1c9e7b5a9b53a996.tar.bz2 wix-c86a2148f6dd7bfcd6637b6e1c9e7b5a9b53a996.zip |
Make "decompile" an MSI-only command instead of a backend requirement
As much as I'd like decompiling to be global functionality provided
by all backends there are only two output types that support
decompiling: MSI and MSM. In the future, perhaps we can invest in a
generic symbols to source code converter that would reduce the
redundant work backends need to do today. Until then, make
decompile an MSI specific command
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 |