diff options
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 |