diff options
128 files changed, 4326 insertions, 2918 deletions
diff --git a/WixToolset.Core.sln b/WixToolset.Core.sln index b94c31b6..8771dc4c 100644 --- a/WixToolset.Core.sln +++ b/WixToolset.Core.sln | |||
@@ -1,6 +1,6 @@ | |||
1 | Microsoft Visual Studio Solution File, Format Version 12.00 | 1 | Microsoft Visual Studio Solution File, Format Version 12.00 |
2 | # Visual Studio 15 | 2 | # Visual Studio 15 |
3 | VisualStudioVersion = 15.0.26730.12 | 3 | VisualStudioVersion = 15.0.26730.16 |
4 | MinimumVisualStudioVersion = 15.0.26124.0 | 4 | MinimumVisualStudioVersion = 15.0.26124.0 |
5 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WixToolset.Core", "src\WixToolset.Core\WixToolset.Core.csproj", "{0B524850-5B9A-472B-85CC-D25920A1DFE1}" | 5 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WixToolset.Core", "src\WixToolset.Core\WixToolset.Core.csproj", "{0B524850-5B9A-472B-85CC-D25920A1DFE1}" |
6 | EndProject | 6 | EndProject |
@@ -8,24 +8,80 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "wix", "src\wix\wix.csproj", | |||
8 | EndProject | 8 | EndProject |
9 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WixToolset.BuildTasks", "src\WixToolset.BuildTasks\WixToolset.BuildTasks.csproj", "{C199C723-73E1-4E79-AF86-898DBA007FC3}" | 9 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WixToolset.BuildTasks", "src\WixToolset.BuildTasks\WixToolset.BuildTasks.csproj", "{C199C723-73E1-4E79-AF86-898DBA007FC3}" |
10 | EndProject | 10 | EndProject |
11 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WixToolset.Core.WindowsInstaller", "src\WixToolset.Core.WindowsInstaller\WixToolset.Core.WindowsInstaller.csproj", "{5617F2A7-46A0-4D07-B9E0-E982D15641E4}" | ||
12 | EndProject | ||
13 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WixToolset.Core.Burn", "src\WixToolset.Core.Burn\WixToolset.Core.Burn.csproj", "{BC19D30D-C1B6-46DF-95B3-8EDF688E0FEC}" | ||
14 | EndProject | ||
11 | Global | 15 | Global |
12 | GlobalSection(SolutionConfigurationPlatforms) = preSolution | 16 | GlobalSection(SolutionConfigurationPlatforms) = preSolution |
13 | Debug|Any CPU = Debug|Any CPU | 17 | Debug|Any CPU = Debug|Any CPU |
18 | Debug|x64 = Debug|x64 | ||
19 | Debug|x86 = Debug|x86 | ||
14 | Release|Any CPU = Release|Any CPU | 20 | Release|Any CPU = Release|Any CPU |
21 | Release|x64 = Release|x64 | ||
22 | Release|x86 = Release|x86 | ||
15 | EndGlobalSection | 23 | EndGlobalSection |
16 | GlobalSection(ProjectConfigurationPlatforms) = postSolution | 24 | GlobalSection(ProjectConfigurationPlatforms) = postSolution |
17 | {0B524850-5B9A-472B-85CC-D25920A1DFE1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | 25 | {0B524850-5B9A-472B-85CC-D25920A1DFE1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU |
18 | {0B524850-5B9A-472B-85CC-D25920A1DFE1}.Debug|Any CPU.Build.0 = Debug|Any CPU | 26 | {0B524850-5B9A-472B-85CC-D25920A1DFE1}.Debug|Any CPU.Build.0 = Debug|Any CPU |
27 | {0B524850-5B9A-472B-85CC-D25920A1DFE1}.Debug|x64.ActiveCfg = Debug|Any CPU | ||
28 | {0B524850-5B9A-472B-85CC-D25920A1DFE1}.Debug|x64.Build.0 = Debug|Any CPU | ||
29 | {0B524850-5B9A-472B-85CC-D25920A1DFE1}.Debug|x86.ActiveCfg = Debug|Any CPU | ||
30 | {0B524850-5B9A-472B-85CC-D25920A1DFE1}.Debug|x86.Build.0 = Debug|Any CPU | ||
19 | {0B524850-5B9A-472B-85CC-D25920A1DFE1}.Release|Any CPU.ActiveCfg = Release|Any CPU | 31 | {0B524850-5B9A-472B-85CC-D25920A1DFE1}.Release|Any CPU.ActiveCfg = Release|Any CPU |
20 | {0B524850-5B9A-472B-85CC-D25920A1DFE1}.Release|Any CPU.Build.0 = Release|Any CPU | 32 | {0B524850-5B9A-472B-85CC-D25920A1DFE1}.Release|Any CPU.Build.0 = Release|Any CPU |
33 | {0B524850-5B9A-472B-85CC-D25920A1DFE1}.Release|x64.ActiveCfg = Release|Any CPU | ||
34 | {0B524850-5B9A-472B-85CC-D25920A1DFE1}.Release|x64.Build.0 = Release|Any CPU | ||
35 | {0B524850-5B9A-472B-85CC-D25920A1DFE1}.Release|x86.ActiveCfg = Release|Any CPU | ||
36 | {0B524850-5B9A-472B-85CC-D25920A1DFE1}.Release|x86.Build.0 = Release|Any CPU | ||
21 | {A948BD6C-A430-4927-B7A5-F6FFAE7B01B1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | 37 | {A948BD6C-A430-4927-B7A5-F6FFAE7B01B1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU |
22 | {A948BD6C-A430-4927-B7A5-F6FFAE7B01B1}.Debug|Any CPU.Build.0 = Debug|Any CPU | 38 | {A948BD6C-A430-4927-B7A5-F6FFAE7B01B1}.Debug|Any CPU.Build.0 = Debug|Any CPU |
39 | {A948BD6C-A430-4927-B7A5-F6FFAE7B01B1}.Debug|x64.ActiveCfg = Debug|Any CPU | ||
40 | {A948BD6C-A430-4927-B7A5-F6FFAE7B01B1}.Debug|x64.Build.0 = Debug|Any CPU | ||
41 | {A948BD6C-A430-4927-B7A5-F6FFAE7B01B1}.Debug|x86.ActiveCfg = Debug|Any CPU | ||
42 | {A948BD6C-A430-4927-B7A5-F6FFAE7B01B1}.Debug|x86.Build.0 = Debug|Any CPU | ||
23 | {A948BD6C-A430-4927-B7A5-F6FFAE7B01B1}.Release|Any CPU.ActiveCfg = Release|Any CPU | 43 | {A948BD6C-A430-4927-B7A5-F6FFAE7B01B1}.Release|Any CPU.ActiveCfg = Release|Any CPU |
24 | {A948BD6C-A430-4927-B7A5-F6FFAE7B01B1}.Release|Any CPU.Build.0 = Release|Any CPU | 44 | {A948BD6C-A430-4927-B7A5-F6FFAE7B01B1}.Release|Any CPU.Build.0 = Release|Any CPU |
45 | {A948BD6C-A430-4927-B7A5-F6FFAE7B01B1}.Release|x64.ActiveCfg = Release|Any CPU | ||
46 | {A948BD6C-A430-4927-B7A5-F6FFAE7B01B1}.Release|x64.Build.0 = Release|Any CPU | ||
47 | {A948BD6C-A430-4927-B7A5-F6FFAE7B01B1}.Release|x86.ActiveCfg = Release|Any CPU | ||
48 | {A948BD6C-A430-4927-B7A5-F6FFAE7B01B1}.Release|x86.Build.0 = Release|Any CPU | ||
25 | {C199C723-73E1-4E79-AF86-898DBA007FC3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | 49 | {C199C723-73E1-4E79-AF86-898DBA007FC3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU |
26 | {C199C723-73E1-4E79-AF86-898DBA007FC3}.Debug|Any CPU.Build.0 = Debug|Any CPU | 50 | {C199C723-73E1-4E79-AF86-898DBA007FC3}.Debug|Any CPU.Build.0 = Debug|Any CPU |
51 | {C199C723-73E1-4E79-AF86-898DBA007FC3}.Debug|x64.ActiveCfg = Debug|Any CPU | ||
52 | {C199C723-73E1-4E79-AF86-898DBA007FC3}.Debug|x64.Build.0 = Debug|Any CPU | ||
53 | {C199C723-73E1-4E79-AF86-898DBA007FC3}.Debug|x86.ActiveCfg = Debug|Any CPU | ||
54 | {C199C723-73E1-4E79-AF86-898DBA007FC3}.Debug|x86.Build.0 = Debug|Any CPU | ||
27 | {C199C723-73E1-4E79-AF86-898DBA007FC3}.Release|Any CPU.ActiveCfg = Release|Any CPU | 55 | {C199C723-73E1-4E79-AF86-898DBA007FC3}.Release|Any CPU.ActiveCfg = Release|Any CPU |
28 | {C199C723-73E1-4E79-AF86-898DBA007FC3}.Release|Any CPU.Build.0 = Release|Any CPU | 56 | {C199C723-73E1-4E79-AF86-898DBA007FC3}.Release|Any CPU.Build.0 = Release|Any CPU |
57 | {C199C723-73E1-4E79-AF86-898DBA007FC3}.Release|x64.ActiveCfg = Release|Any CPU | ||
58 | {C199C723-73E1-4E79-AF86-898DBA007FC3}.Release|x64.Build.0 = Release|Any CPU | ||
59 | {C199C723-73E1-4E79-AF86-898DBA007FC3}.Release|x86.ActiveCfg = Release|Any CPU | ||
60 | {C199C723-73E1-4E79-AF86-898DBA007FC3}.Release|x86.Build.0 = Release|Any CPU | ||
61 | {5617F2A7-46A0-4D07-B9E0-E982D15641E4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||
62 | {5617F2A7-46A0-4D07-B9E0-E982D15641E4}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||
63 | {5617F2A7-46A0-4D07-B9E0-E982D15641E4}.Debug|x64.ActiveCfg = Debug|Any CPU | ||
64 | {5617F2A7-46A0-4D07-B9E0-E982D15641E4}.Debug|x64.Build.0 = Debug|Any CPU | ||
65 | {5617F2A7-46A0-4D07-B9E0-E982D15641E4}.Debug|x86.ActiveCfg = Debug|Any CPU | ||
66 | {5617F2A7-46A0-4D07-B9E0-E982D15641E4}.Debug|x86.Build.0 = Debug|Any CPU | ||
67 | {5617F2A7-46A0-4D07-B9E0-E982D15641E4}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||
68 | {5617F2A7-46A0-4D07-B9E0-E982D15641E4}.Release|Any CPU.Build.0 = Release|Any CPU | ||
69 | {5617F2A7-46A0-4D07-B9E0-E982D15641E4}.Release|x64.ActiveCfg = Release|Any CPU | ||
70 | {5617F2A7-46A0-4D07-B9E0-E982D15641E4}.Release|x64.Build.0 = Release|Any CPU | ||
71 | {5617F2A7-46A0-4D07-B9E0-E982D15641E4}.Release|x86.ActiveCfg = Release|Any CPU | ||
72 | {5617F2A7-46A0-4D07-B9E0-E982D15641E4}.Release|x86.Build.0 = Release|Any CPU | ||
73 | {BC19D30D-C1B6-46DF-95B3-8EDF688E0FEC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||
74 | {BC19D30D-C1B6-46DF-95B3-8EDF688E0FEC}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||
75 | {BC19D30D-C1B6-46DF-95B3-8EDF688E0FEC}.Debug|x64.ActiveCfg = Debug|Any CPU | ||
76 | {BC19D30D-C1B6-46DF-95B3-8EDF688E0FEC}.Debug|x64.Build.0 = Debug|Any CPU | ||
77 | {BC19D30D-C1B6-46DF-95B3-8EDF688E0FEC}.Debug|x86.ActiveCfg = Debug|Any CPU | ||
78 | {BC19D30D-C1B6-46DF-95B3-8EDF688E0FEC}.Debug|x86.Build.0 = Debug|Any CPU | ||
79 | {BC19D30D-C1B6-46DF-95B3-8EDF688E0FEC}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||
80 | {BC19D30D-C1B6-46DF-95B3-8EDF688E0FEC}.Release|Any CPU.Build.0 = Release|Any CPU | ||
81 | {BC19D30D-C1B6-46DF-95B3-8EDF688E0FEC}.Release|x64.ActiveCfg = Release|Any CPU | ||
82 | {BC19D30D-C1B6-46DF-95B3-8EDF688E0FEC}.Release|x64.Build.0 = Release|Any CPU | ||
83 | {BC19D30D-C1B6-46DF-95B3-8EDF688E0FEC}.Release|x86.ActiveCfg = Release|Any CPU | ||
84 | {BC19D30D-C1B6-46DF-95B3-8EDF688E0FEC}.Release|x86.Build.0 = Release|Any CPU | ||
29 | EndGlobalSection | 85 | EndGlobalSection |
30 | GlobalSection(SolutionProperties) = preSolution | 86 | GlobalSection(SolutionProperties) = preSolution |
31 | HideSolutionNode = FALSE | 87 | HideSolutionNode = FALSE |
diff --git a/src/WixToolset.BuildTasks/WixToolset.BuildTasks.csproj b/src/WixToolset.BuildTasks/WixToolset.BuildTasks.csproj index 10dce157..c34b3bca 100644 --- a/src/WixToolset.BuildTasks/WixToolset.BuildTasks.csproj +++ b/src/WixToolset.BuildTasks/WixToolset.BuildTasks.csproj | |||
@@ -24,6 +24,8 @@ | |||
24 | 24 | ||
25 | <ItemGroup> | 25 | <ItemGroup> |
26 | <ProjectReference Include="..\WixToolset.Core\WixToolset.Core.csproj" /> | 26 | <ProjectReference Include="..\WixToolset.Core\WixToolset.Core.csproj" /> |
27 | <ProjectReference Include="..\WixToolset.Core.Burn\WixToolset.Core.Burn.csproj" /> | ||
28 | <ProjectReference Include="..\WixToolset.Core.WindowsInstaller\WixToolset.Core.WindowsInstaller.csproj" /> | ||
27 | </ItemGroup> | 29 | </ItemGroup> |
28 | 30 | ||
29 | <ItemGroup> | 31 | <ItemGroup> |
diff --git a/src/WixToolset.Core.Burn/BackendFactory.cs b/src/WixToolset.Core.Burn/BackendFactory.cs new file mode 100644 index 00000000..042fa254 --- /dev/null +++ b/src/WixToolset.Core.Burn/BackendFactory.cs | |||
@@ -0,0 +1,30 @@ | |||
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.Burn | ||
4 | { | ||
5 | using System; | ||
6 | using System.IO; | ||
7 | using WixToolset.Extensibility; | ||
8 | |||
9 | internal class BackendFactory : IBackendFactory | ||
10 | { | ||
11 | public bool TryCreateBackend(string outputType, string outputFile, IBindContext context, out IBackend backend) | ||
12 | { | ||
13 | if (String.IsNullOrEmpty(outputType)) | ||
14 | { | ||
15 | outputType = Path.GetExtension(outputFile); | ||
16 | } | ||
17 | |||
18 | switch (outputType.ToLowerInvariant()) | ||
19 | { | ||
20 | case "bundle": | ||
21 | case ".exe": | ||
22 | backend = new BundleBackend(); | ||
23 | return true; | ||
24 | } | ||
25 | |||
26 | backend = null; | ||
27 | return false; | ||
28 | } | ||
29 | } | ||
30 | } | ||
diff --git a/src/WixToolset.Core/Bind/BindBundleCommand.cs b/src/WixToolset.Core.Burn/Bind/BindBundleCommand.cs index 7ea0c830..212b1e81 100644 --- a/src/WixToolset.Core/Bind/BindBundleCommand.cs +++ b/src/WixToolset.Core.Burn/Bind/BindBundleCommand.cs | |||
@@ -1,6 +1,6 @@ | |||
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.Bind | 3 | namespace WixToolset.Core.Burn |
4 | { | 4 | { |
5 | using System; | 5 | using System; |
6 | using System.Collections.Generic; | 6 | using System.Collections.Generic; |
@@ -9,23 +9,83 @@ namespace WixToolset.Bind | |||
9 | using System.IO; | 9 | using System.IO; |
10 | using System.Linq; | 10 | using System.Linq; |
11 | using System.Reflection; | 11 | using System.Reflection; |
12 | using WixToolset.Bind.Bundles; | 12 | using WixToolset.Bind; |
13 | using WixToolset.Core.Bind; | ||
14 | using WixToolset.Core.Burn.Bundles; | ||
13 | using WixToolset.Data; | 15 | using WixToolset.Data; |
16 | using WixToolset.Data.Bind; | ||
14 | using WixToolset.Data.Rows; | 17 | using WixToolset.Data.Rows; |
15 | using WixToolset.Extensibility; | 18 | using WixToolset.Extensibility; |
16 | 19 | ||
20 | // TODO: (4.0) Refactor so that these don't need to be copied. | ||
21 | // Copied verbatim from ext\UtilExtension\wixext\UtilCompiler.cs | ||
22 | [Flags] | ||
23 | internal enum WixFileSearchAttributes | ||
24 | { | ||
25 | Default = 0x001, | ||
26 | MinVersionInclusive = 0x002, | ||
27 | MaxVersionInclusive = 0x004, | ||
28 | MinSizeInclusive = 0x008, | ||
29 | MaxSizeInclusive = 0x010, | ||
30 | MinDateInclusive = 0x020, | ||
31 | MaxDateInclusive = 0x040, | ||
32 | WantVersion = 0x080, | ||
33 | WantExists = 0x100, | ||
34 | IsDirectory = 0x200, | ||
35 | } | ||
36 | |||
37 | [Flags] | ||
38 | internal enum WixRegistrySearchAttributes | ||
39 | { | ||
40 | Raw = 0x01, | ||
41 | Compatible = 0x02, | ||
42 | ExpandEnvironmentVariables = 0x04, | ||
43 | WantValue = 0x08, | ||
44 | WantExists = 0x10, | ||
45 | Win64 = 0x20, | ||
46 | } | ||
47 | |||
48 | internal enum WixComponentSearchAttributes | ||
49 | { | ||
50 | KeyPath = 0x1, | ||
51 | State = 0x2, | ||
52 | WantDirectory = 0x4, | ||
53 | } | ||
54 | |||
55 | [Flags] | ||
56 | internal enum WixProductSearchAttributes | ||
57 | { | ||
58 | Version = 0x1, | ||
59 | Language = 0x2, | ||
60 | State = 0x4, | ||
61 | Assignment = 0x8, | ||
62 | UpgradeCode = 0x10, | ||
63 | } | ||
64 | |||
17 | /// <summary> | 65 | /// <summary> |
18 | /// Binds a this.bundle. | 66 | /// Binds a this.bundle. |
19 | /// </summary> | 67 | /// </summary> |
20 | internal class BindBundleCommand : ICommand | 68 | internal class BindBundleCommand |
21 | { | 69 | { |
70 | public BindBundleCommand(IBindContext context) | ||
71 | { | ||
72 | this.TableDefinitions = WindowsInstallerStandard.GetTableDefinitions(); | ||
73 | |||
74 | this.DelayedFields = context.DelayedFields; | ||
75 | this.ExpectedEmbeddedFiles = context.ExpectedEmbeddedFiles; | ||
76 | |||
77 | this.BackendExtensions = context.ExtensionManager.Create<IBurnBackendExtension>(); | ||
78 | } | ||
79 | |||
22 | public CompressionLevel DefaultCompressionLevel { private get; set; } | 80 | public CompressionLevel DefaultCompressionLevel { private get; set; } |
23 | 81 | ||
24 | public IEnumerable<IBinderExtension> Extensions { private get; set; } | 82 | public IEnumerable<IDelayedField> DelayedFields { get; } |
83 | |||
84 | public IEnumerable<IExpectedExtractFile> ExpectedEmbeddedFiles { get; } | ||
25 | 85 | ||
26 | public BinderFileManagerCore FileManagerCore { private get; set; } | 86 | private IEnumerable<IBurnBackendExtension> BackendExtensions { get; } |
27 | 87 | ||
28 | public IEnumerable<IBinderFileManager> FileManagers { private get; set; } | 88 | public IEnumerable<IBinderExtension> Extensions { private get; set; } |
29 | 89 | ||
30 | public Output Output { private get; set; } | 90 | public Output Output { private get; set; } |
31 | 91 | ||
@@ -35,9 +95,9 @@ namespace WixToolset.Bind | |||
35 | 95 | ||
36 | public TableDefinitionCollection TableDefinitions { private get; set; } | 96 | public TableDefinitionCollection TableDefinitions { private get; set; } |
37 | 97 | ||
38 | public string TempFilesLocation { private get; set; } | 98 | public string IntermediateFolder { private get; set; } |
39 | 99 | ||
40 | public WixVariableResolver WixVariableResolver { private get; set; } | 100 | public IBindVariableResolver WixVariableResolver { private get; set; } |
41 | 101 | ||
42 | public IEnumerable<FileTransfer> FileTransfers { get; private set; } | 102 | public IEnumerable<FileTransfer> FileTransfers { get; private set; } |
43 | 103 | ||
@@ -79,32 +139,9 @@ namespace WixToolset.Bind | |||
79 | return; | 139 | return; |
80 | } | 140 | } |
81 | 141 | ||
82 | // Localize fields, resolve wix variables, and resolve file paths. | ||
83 | ExtractEmbeddedFiles filesWithEmbeddedFiles = new ExtractEmbeddedFiles(); | ||
84 | |||
85 | IEnumerable<DelayedField> delayedFields; | ||
86 | { | ||
87 | ResolveFieldsCommand command = new ResolveFieldsCommand(); | ||
88 | command.Tables = this.Output.Tables; | ||
89 | command.FilesWithEmbeddedFiles = filesWithEmbeddedFiles; | ||
90 | command.FileManagerCore = this.FileManagerCore; | ||
91 | command.FileManagers = this.FileManagers; | ||
92 | command.SupportDelayedResolution = true; | ||
93 | command.TempFilesLocation = this.TempFilesLocation; | ||
94 | command.WixVariableResolver = this.WixVariableResolver; | ||
95 | command.Execute(); | ||
96 | |||
97 | delayedFields = command.DelayedFields; | ||
98 | } | ||
99 | |||
100 | if (Messaging.Instance.EncounteredError) | ||
101 | { | ||
102 | return; | ||
103 | } | ||
104 | |||
105 | // If there are any fields to resolve later, create the cache to populate during bind. | 142 | // If there are any fields to resolve later, create the cache to populate during bind. |
106 | IDictionary<string, string> variableCache = null; | 143 | IDictionary<string, string> variableCache = null; |
107 | if (delayedFields.Any()) | 144 | if (this.DelayedFields.Any()) |
108 | { | 145 | { |
109 | variableCache = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase); | 146 | variableCache = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase); |
110 | } | 147 | } |
@@ -116,8 +153,8 @@ namespace WixToolset.Bind | |||
116 | 153 | ||
117 | // Extract files that come from cabinet files (this does not extract files from merge modules). | 154 | // Extract files that come from cabinet files (this does not extract files from merge modules). |
118 | { | 155 | { |
119 | ExtractEmbeddedFilesCommand extractEmbeddedFilesCommand = new ExtractEmbeddedFilesCommand(); | 156 | var extractEmbeddedFilesCommand = new ExtractEmbeddedFilesCommand(); |
120 | extractEmbeddedFilesCommand.FilesWithEmbeddedFiles = filesWithEmbeddedFiles; | 157 | extractEmbeddedFilesCommand.FilesWithEmbeddedFiles = ExpectedEmbeddedFiles; |
121 | extractEmbeddedFilesCommand.Execute(); | 158 | extractEmbeddedFilesCommand.Execute(); |
122 | } | 159 | } |
123 | 160 | ||
@@ -198,10 +235,10 @@ namespace WixToolset.Bind | |||
198 | 235 | ||
199 | case WixBundlePackageType.Msi: | 236 | case WixBundlePackageType.Msi: |
200 | { | 237 | { |
201 | ProcessMsiPackageCommand command = new ProcessMsiPackageCommand(); | 238 | var command = new ProcessMsiPackageCommand(); |
202 | command.AuthoredPayloads = payloads; | 239 | command.AuthoredPayloads = payloads; |
203 | command.Facade = facade; | 240 | command.Facade = facade; |
204 | command.FileManager = this.FileManagers.First(); | 241 | command.BackendExtensions = this.BackendExtensions; |
205 | command.MsiFeatureTable = this.Output.EnsureTable(this.TableDefinitions["WixBundleMsiFeature"]); | 242 | command.MsiFeatureTable = this.Output.EnsureTable(this.TableDefinitions["WixBundleMsiFeature"]); |
206 | command.MsiPropertyTable = this.Output.EnsureTable(this.TableDefinitions["WixBundleMsiProperty"]); | 243 | command.MsiPropertyTable = this.Output.EnsureTable(this.TableDefinitions["WixBundleMsiProperty"]); |
207 | command.PayloadTable = this.Output.Tables["WixBundlePayload"]; | 244 | command.PayloadTable = this.Output.Tables["WixBundlePayload"]; |
@@ -377,11 +414,11 @@ namespace WixToolset.Bind | |||
377 | } | 414 | } |
378 | 415 | ||
379 | // Resolve any delayed fields before generating the manifest. | 416 | // Resolve any delayed fields before generating the manifest. |
380 | if (delayedFields.Any()) | 417 | if (this.DelayedFields.Any()) |
381 | { | 418 | { |
382 | ResolveDelayedFieldsCommand resolveDelayedFieldsCommand = new ResolveDelayedFieldsCommand(); | 419 | var resolveDelayedFieldsCommand = new ResolveDelayedFieldsCommand(); |
383 | resolveDelayedFieldsCommand.OutputType = this.Output.Type; | 420 | resolveDelayedFieldsCommand.OutputType = this.Output.Type; |
384 | resolveDelayedFieldsCommand.DelayedFields = delayedFields; | 421 | resolveDelayedFieldsCommand.DelayedFields = this.DelayedFields; |
385 | resolveDelayedFieldsCommand.ModularizationGuid = null; | 422 | resolveDelayedFieldsCommand.ModularizationGuid = null; |
386 | resolveDelayedFieldsCommand.VariableCache = variableCache; | 423 | resolveDelayedFieldsCommand.VariableCache = variableCache; |
387 | resolveDelayedFieldsCommand.Execute(); | 424 | resolveDelayedFieldsCommand.Execute(); |
@@ -406,17 +443,17 @@ namespace WixToolset.Bind | |||
406 | command.Output = this.Output; | 443 | command.Output = this.Output; |
407 | command.Payloads = payloads; | 444 | command.Payloads = payloads; |
408 | command.TableDefinitions = this.TableDefinitions; | 445 | command.TableDefinitions = this.TableDefinitions; |
409 | command.TempFilesLocation = this.TempFilesLocation; | 446 | command.TempFilesLocation = this.IntermediateFolder; |
410 | command.Execute(); | 447 | command.Execute(); |
411 | 448 | ||
412 | WixBundlePayloadRow baManifestPayload = command.BootstrapperApplicationManifestPayloadRow; | 449 | WixBundlePayloadRow baManifestPayload = command.BootstrapperApplicationManifestPayloadRow; |
413 | payloads.Add(baManifestPayload); | 450 | payloads.Add(baManifestPayload); |
414 | } | 451 | } |
415 | 452 | ||
416 | foreach (BinderExtension extension in this.Extensions) | 453 | //foreach (BinderExtension extension in this.Extensions) |
417 | { | 454 | //{ |
418 | extension.Finish(Output); | 455 | // extension.PostBind(this.Context); |
419 | } | 456 | //} |
420 | 457 | ||
421 | // Create all the containers except the UX container first so the manifest (that goes in the UX container) | 458 | // Create all the containers except the UX container first so the manifest (that goes in the UX container) |
422 | // can contain all size and hash information about the non-UX containers. | 459 | // can contain all size and hash information about the non-UX containers. |
@@ -441,7 +478,7 @@ namespace WixToolset.Bind | |||
441 | } | 478 | } |
442 | else if (Compiler.BurnUXContainerId == container.Id) | 479 | else if (Compiler.BurnUXContainerId == container.Id) |
443 | { | 480 | { |
444 | container.WorkingPath = Path.Combine(this.TempFilesLocation, container.Name); | 481 | container.WorkingPath = Path.Combine(this.IntermediateFolder, container.Name); |
445 | container.AttachedContainerIndex = 0; | 482 | container.AttachedContainerIndex = 0; |
446 | 483 | ||
447 | // Gather the list of UX payloads but ensure the BootstrapperApplication Payload is the first | 484 | // Gather the list of UX payloads but ensure the BootstrapperApplication Payload is the first |
@@ -466,7 +503,7 @@ namespace WixToolset.Bind | |||
466 | } | 503 | } |
467 | else | 504 | else |
468 | { | 505 | { |
469 | container.WorkingPath = Path.Combine(this.TempFilesLocation, container.Name); | 506 | container.WorkingPath = Path.Combine(this.IntermediateFolder, container.Name); |
470 | 507 | ||
471 | // Add detached containers to the list of file transfers. | 508 | // Add detached containers to the list of file transfers. |
472 | if (ContainerType.Detached == container.Type) | 509 | if (ContainerType.Detached == container.Type) |
@@ -491,10 +528,10 @@ namespace WixToolset.Bind | |||
491 | } | 528 | } |
492 | 529 | ||
493 | // Create the bundle manifest then UX container. | 530 | // Create the bundle manifest then UX container. |
494 | string manifestPath = Path.Combine(this.TempFilesLocation, "bundle-manifest.xml"); | 531 | string manifestPath = Path.Combine(this.IntermediateFolder, "bundle-manifest.xml"); |
495 | { | 532 | { |
496 | CreateBurnManifestCommand command = new CreateBurnManifestCommand(); | 533 | var command = new CreateBurnManifestCommand(); |
497 | command.FileManagers = this.FileManagers; | 534 | command.BackendExtensions = this.BackendExtensions; |
498 | command.Output = this.Output; | 535 | command.Output = this.Output; |
499 | 536 | ||
500 | command.BundleInfo = bundleRow; | 537 | command.BundleInfo = bundleRow; |
@@ -519,7 +556,7 @@ namespace WixToolset.Bind | |||
519 | string stubPlatform = (Platform.X64 == bundleRow.Platform) ? "x86" : bundleRow.Platform.ToString(); | 556 | string stubPlatform = (Platform.X64 == bundleRow.Platform) ? "x86" : bundleRow.Platform.ToString(); |
520 | 557 | ||
521 | string stubFile = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), stubPlatform, "burn.exe"); | 558 | string stubFile = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), stubPlatform, "burn.exe"); |
522 | string bundleTempPath = Path.Combine(this.TempFilesLocation, Path.GetFileName(this.OutputPath)); | 559 | string bundleTempPath = Path.Combine(this.IntermediateFolder, Path.GetFileName(this.OutputPath)); |
523 | 560 | ||
524 | Messaging.Instance.OnMessage(WixVerboses.GeneratingBundle(bundleTempPath, stubFile)); | 561 | Messaging.Instance.OnMessage(WixVerboses.GeneratingBundle(bundleTempPath, stubFile)); |
525 | 562 | ||
diff --git a/src/WixToolset.Core/ProvidesDependency.cs b/src/WixToolset.Core.Burn/Bind/ProvidesDependency.cs index ea96b5c8..e64773b4 100644 --- a/src/WixToolset.Core/ProvidesDependency.cs +++ b/src/WixToolset.Core.Burn/Bind/ProvidesDependency.cs | |||
@@ -1,6 +1,6 @@ | |||
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 | 3 | namespace WixToolset.Core.Burn |
4 | { | 4 | { |
5 | using System; | 5 | using System; |
6 | using System.Xml; | 6 | using System.Xml; |
diff --git a/src/WixToolset.Core/ProvidesDependencyCollection.cs b/src/WixToolset.Core.Burn/Bind/ProvidesDependencyCollection.cs index a777afb0..668b81d3 100644 --- a/src/WixToolset.Core/ProvidesDependencyCollection.cs +++ b/src/WixToolset.Core.Burn/Bind/ProvidesDependencyCollection.cs | |||
@@ -1,6 +1,6 @@ | |||
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 | 3 | namespace WixToolset.Core.Burn |
4 | { | 4 | { |
5 | using System; | 5 | using System; |
6 | using System.Collections.ObjectModel; | 6 | using System.Collections.ObjectModel; |
diff --git a/src/WixToolset.Core/WixComponentSearchInfo.cs b/src/WixToolset.Core.Burn/Bind/WixComponentSearchInfo.cs index dfd5d8ba..f605d7c7 100644 --- a/src/WixToolset.Core/WixComponentSearchInfo.cs +++ b/src/WixToolset.Core.Burn/Bind/WixComponentSearchInfo.cs | |||
@@ -1,6 +1,6 @@ | |||
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 | 3 | namespace WixToolset.Core.Burn |
4 | { | 4 | { |
5 | using System; | 5 | using System; |
6 | using System.Xml; | 6 | using System.Xml; |
diff --git a/src/WixToolset.Core/WixFileSearchInfo.cs b/src/WixToolset.Core.Burn/Bind/WixFileSearchInfo.cs index e53f7bf7..ea955db4 100644 --- a/src/WixToolset.Core/WixFileSearchInfo.cs +++ b/src/WixToolset.Core.Burn/Bind/WixFileSearchInfo.cs | |||
@@ -1,6 +1,6 @@ | |||
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 | 3 | namespace WixToolset.Core.Burn |
4 | { | 4 | { |
5 | using System; | 5 | using System; |
6 | using System.Xml; | 6 | using System.Xml; |
diff --git a/src/WixToolset.Core/WixProductSearchInfo.cs b/src/WixToolset.Core.Burn/Bind/WixProductSearchInfo.cs index 4c57d8be..b3bf5fee 100644 --- a/src/WixToolset.Core/WixProductSearchInfo.cs +++ b/src/WixToolset.Core.Burn/Bind/WixProductSearchInfo.cs | |||
@@ -1,6 +1,6 @@ | |||
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 | 3 | namespace WixToolset.Core.Burn |
4 | { | 4 | { |
5 | using System; | 5 | using System; |
6 | using System.Xml; | 6 | using System.Xml; |
diff --git a/src/WixToolset.Core/WixRegistrySearchInfo.cs b/src/WixToolset.Core.Burn/Bind/WixRegistrySearchInfo.cs index e8d7ce9b..e25f25f4 100644 --- a/src/WixToolset.Core/WixRegistrySearchInfo.cs +++ b/src/WixToolset.Core.Burn/Bind/WixRegistrySearchInfo.cs | |||
@@ -1,6 +1,6 @@ | |||
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 | 3 | namespace WixToolset.Core.Burn |
4 | { | 4 | { |
5 | using System; | 5 | using System; |
6 | using System.Xml; | 6 | using System.Xml; |
diff --git a/src/WixToolset.Core/WixSearchInfo.cs b/src/WixToolset.Core.Burn/Bind/WixSearchInfo.cs index 906365a2..9ebca4ae 100644 --- a/src/WixToolset.Core/WixSearchInfo.cs +++ b/src/WixToolset.Core.Burn/Bind/WixSearchInfo.cs | |||
@@ -1,6 +1,6 @@ | |||
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 | 3 | namespace WixToolset.Core.Burn |
4 | { | 4 | { |
5 | using System; | 5 | using System; |
6 | using System.Diagnostics; | 6 | using System.Diagnostics; |
diff --git a/src/WixToolset.Core.Burn/BundleBackend.cs b/src/WixToolset.Core.Burn/BundleBackend.cs new file mode 100644 index 00000000..ef4d362c --- /dev/null +++ b/src/WixToolset.Core.Burn/BundleBackend.cs | |||
@@ -0,0 +1,58 @@ | |||
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.Burn | ||
4 | { | ||
5 | using System; | ||
6 | using System.IO; | ||
7 | using WixToolset.Core.Burn.Bundles; | ||
8 | using WixToolset.Core.Burn.Inscribe; | ||
9 | using WixToolset.Data; | ||
10 | using WixToolset.Data.Bind; | ||
11 | using WixToolset.Extensibility; | ||
12 | |||
13 | internal class BundleBackend : IBackend | ||
14 | { | ||
15 | public BindResult Bind(IBindContext context) | ||
16 | { | ||
17 | BindBundleCommand command = new BindBundleCommand(context); | ||
18 | //command.DefaultCompressionLevel = context.DefaultCompressionLevel; | ||
19 | //command.Extensions = context.Extensions; | ||
20 | //command.IntermediateFolder = context.IntermediateFolder; | ||
21 | //command.Output = context.IntermediateRepresentation; | ||
22 | //command.OutputPath = context.OutputPath; | ||
23 | //command.PdbFile = context.OutputPdbPath; | ||
24 | //command.WixVariableResolver = context.WixVariableResolver; | ||
25 | command.Execute(); | ||
26 | |||
27 | return new BindResult(command.FileTransfers, command.ContentFilePaths); | ||
28 | } | ||
29 | |||
30 | public bool Inscribe(IInscribeContext context) | ||
31 | { | ||
32 | if (String.IsNullOrEmpty(context.SignedEngineFile)) | ||
33 | { | ||
34 | var command = new InscribeBundleCommand(context); | ||
35 | return command.Execute(); | ||
36 | } | ||
37 | else | ||
38 | { | ||
39 | var command = new InscribeBundleEngineCommand(context); | ||
40 | return command.Execute(); | ||
41 | } | ||
42 | } | ||
43 | |||
44 | public Output Unbind(IUnbindContext context) | ||
45 | { | ||
46 | string uxExtractPath = Path.Combine(context.ExportBasePath, "UX"); | ||
47 | string acExtractPath = Path.Combine(context.ExportBasePath, "AttachedContainer"); | ||
48 | |||
49 | using (BurnReader reader = BurnReader.Open(context.InputFilePath)) | ||
50 | { | ||
51 | reader.ExtractUXContainer(uxExtractPath, context.IntermediateFolder); | ||
52 | reader.ExtractAttachedContainer(acExtractPath, context.IntermediateFolder); | ||
53 | } | ||
54 | |||
55 | return null; | ||
56 | } | ||
57 | } | ||
58 | } | ||
diff --git a/src/WixToolset.Core/Bind/Bundles/AutomaticallySlipstreamPatchesCommand.cs b/src/WixToolset.Core.Burn/Bundles/AutomaticallySlipstreamPatchesCommand.cs index eb02a983..bac8633b 100644 --- a/src/WixToolset.Core/Bind/Bundles/AutomaticallySlipstreamPatchesCommand.cs +++ b/src/WixToolset.Core.Burn/Bundles/AutomaticallySlipstreamPatchesCommand.cs | |||
@@ -1,6 +1,6 @@ | |||
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.Bind.Bundles | 3 | namespace WixToolset.Core.Burn.Bundles |
4 | { | 4 | { |
5 | using System; | 5 | using System; |
6 | using System.Collections.Generic; | 6 | using System.Collections.Generic; |
@@ -9,7 +9,7 @@ namespace WixToolset.Bind.Bundles | |||
9 | using WixToolset.Data; | 9 | using WixToolset.Data; |
10 | using WixToolset.Data.Rows; | 10 | using WixToolset.Data.Rows; |
11 | 11 | ||
12 | internal class AutomaticallySlipstreamPatchesCommand : ICommand | 12 | internal class AutomaticallySlipstreamPatchesCommand |
13 | { | 13 | { |
14 | public IEnumerable<PackageFacade> PackageFacades { private get; set; } | 14 | public IEnumerable<PackageFacade> PackageFacades { private get; set; } |
15 | 15 | ||
diff --git a/src/WixToolset.Core/Bind/Bundles/BurnCommon.cs b/src/WixToolset.Core.Burn/Bundles/BurnCommon.cs index 8cb07791..0baa6094 100644 --- a/src/WixToolset.Core/Bind/Bundles/BurnCommon.cs +++ b/src/WixToolset.Core.Burn/Bundles/BurnCommon.cs | |||
@@ -1,6 +1,6 @@ | |||
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.Bind.Bundles | 3 | namespace WixToolset.Core.Burn.Bundles |
4 | { | 4 | { |
5 | using System; | 5 | using System; |
6 | using System.Diagnostics; | 6 | using System.Diagnostics; |
diff --git a/src/WixToolset.Core/Bind/Bundles/BurnReader.cs b/src/WixToolset.Core.Burn/Bundles/BurnReader.cs index f6d7a197..261ef7b4 100644 --- a/src/WixToolset.Core/Bind/Bundles/BurnReader.cs +++ b/src/WixToolset.Core.Burn/Bundles/BurnReader.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.Bind.Bundles | 3 | namespace WixToolset.Core.Burn.Bundles |
4 | { | 4 | { |
5 | using System; | 5 | using System; |
6 | using System.Collections; | 6 | using System.Collections; |
7 | using System.Collections.Generic; | 7 | using System.Collections.Generic; |
8 | using System.IO; | 8 | using System.IO; |
9 | using System.Xml; | 9 | using System.Xml; |
10 | using WixToolset.Cab; | 10 | using WixToolset.Core.Cab; |
11 | 11 | ||
12 | /// <summary> | 12 | /// <summary> |
13 | /// Burn PE reader for the WiX toolset. | 13 | /// Burn PE reader for the WiX toolset. |
@@ -49,6 +49,11 @@ namespace WixToolset.Bind.Bundles | |||
49 | } | 49 | } |
50 | } | 50 | } |
51 | 51 | ||
52 | internal static BurnReader Open(object inputFilePath) | ||
53 | { | ||
54 | throw new NotImplementedException(); | ||
55 | } | ||
56 | |||
52 | /// <summary> | 57 | /// <summary> |
53 | /// Opens a Burn reader. | 58 | /// Opens a Burn reader. |
54 | /// </summary> | 59 | /// </summary> |
@@ -96,7 +101,7 @@ namespace WixToolset.Bind.Bundles | |||
96 | BurnCommon.CopyStream(this.binaryReader.BaseStream, tempCab, (int)this.UXSize); | 101 | BurnCommon.CopyStream(this.binaryReader.BaseStream, tempCab, (int)this.UXSize); |
97 | } | 102 | } |
98 | 103 | ||
99 | using (WixExtractCab extract = new WixExtractCab()) | 104 | using (var extract = new WixExtractCab()) |
100 | { | 105 | { |
101 | extract.Extract(tempCabPath, outputDirectory); | 106 | extract.Extract(tempCabPath, outputDirectory); |
102 | } | 107 | } |
@@ -144,6 +149,11 @@ namespace WixToolset.Bind.Bundles | |||
144 | return true; | 149 | return true; |
145 | } | 150 | } |
146 | 151 | ||
152 | internal void ExtractUXContainer(string uxExtractPath, object intermediateFolder) | ||
153 | { | ||
154 | throw new NotImplementedException(); | ||
155 | } | ||
156 | |||
147 | /// <summary> | 157 | /// <summary> |
148 | /// Gets the attached container from the exe and extracts its contents to the output directory. | 158 | /// Gets the attached container from the exe and extracts its contents to the output directory. |
149 | /// </summary> | 159 | /// </summary> |
diff --git a/src/WixToolset.Core/Bind/Bundles/BurnWriter.cs b/src/WixToolset.Core.Burn/Bundles/BurnWriter.cs index bc0baf46..e7365212 100644 --- a/src/WixToolset.Core/Bind/Bundles/BurnWriter.cs +++ b/src/WixToolset.Core.Burn/Bundles/BurnWriter.cs | |||
@@ -1,6 +1,6 @@ | |||
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.Bind.Bundles | 3 | namespace WixToolset.Core.Burn.Bundles |
4 | { | 4 | { |
5 | using System; | 5 | using System; |
6 | using System.Diagnostics; | 6 | using System.Diagnostics; |
diff --git a/src/WixToolset.Core/Bind/Bundles/CreateBootstrapperApplicationManifestCommand.cs b/src/WixToolset.Core.Burn/Bundles/CreateBootstrapperApplicationManifestCommand.cs index 1040b394..58814efc 100644 --- a/src/WixToolset.Core/Bind/Bundles/CreateBootstrapperApplicationManifestCommand.cs +++ b/src/WixToolset.Core.Burn/Bundles/CreateBootstrapperApplicationManifestCommand.cs | |||
@@ -1,6 +1,6 @@ | |||
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.Bind.Bundles | 3 | namespace WixToolset.Core.Burn.Bundles |
4 | { | 4 | { |
5 | using System; | 5 | using System; |
6 | using System.Collections.Generic; | 6 | using System.Collections.Generic; |
@@ -12,7 +12,7 @@ namespace WixToolset.Bind.Bundles | |||
12 | using WixToolset.Data; | 12 | using WixToolset.Data; |
13 | using WixToolset.Data.Rows; | 13 | using WixToolset.Data.Rows; |
14 | 14 | ||
15 | internal class CreateBootstrapperApplicationManifestCommand : ICommand | 15 | internal class CreateBootstrapperApplicationManifestCommand |
16 | { | 16 | { |
17 | public WixBundleRow BundleRow { private get; set; } | 17 | public WixBundleRow BundleRow { private get; set; } |
18 | 18 | ||
diff --git a/src/WixToolset.Core/Bind/Bundles/CreateBurnManifestCommand.cs b/src/WixToolset.Core.Burn/Bundles/CreateBurnManifestCommand.cs index 7bc708a3..772265a0 100644 --- a/src/WixToolset.Core/Bind/Bundles/CreateBurnManifestCommand.cs +++ b/src/WixToolset.Core.Burn/Bundles/CreateBurnManifestCommand.cs | |||
@@ -1,6 +1,6 @@ | |||
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.Bind.Bundles | 3 | namespace WixToolset.Core.Burn.Bundles |
4 | { | 4 | { |
5 | using System; | 5 | using System; |
6 | using System.Collections.Generic; | 6 | using System.Collections.Generic; |
@@ -13,9 +13,9 @@ namespace WixToolset.Bind.Bundles | |||
13 | using WixToolset.Data.Rows; | 13 | using WixToolset.Data.Rows; |
14 | using WixToolset.Extensibility; | 14 | using WixToolset.Extensibility; |
15 | 15 | ||
16 | internal class CreateBurnManifestCommand : ICommand | 16 | internal class CreateBurnManifestCommand |
17 | { | 17 | { |
18 | public IEnumerable<IBinderFileManager> FileManagers { private get; set; } | 18 | public IEnumerable<IBurnBackendExtension> BackendExtensions { private get; set; } |
19 | 19 | ||
20 | public Output Output { private get; set; } | 20 | public Output Output { private get; set; } |
21 | 21 | ||
@@ -671,9 +671,9 @@ namespace WixToolset.Bind.Bundles | |||
671 | private string ResolveUrl(string url, string fallbackUrl, string packageId, string payloadId, string fileName) | 671 | private string ResolveUrl(string url, string fallbackUrl, string packageId, string payloadId, string fileName) |
672 | { | 672 | { |
673 | string resolved = null; | 673 | string resolved = null; |
674 | foreach (IBinderFileManager fileManager in this.FileManagers) | 674 | foreach (var extension in this.BackendExtensions) |
675 | { | 675 | { |
676 | resolved = fileManager.ResolveUrl(url, fallbackUrl, packageId, payloadId, fileName); | 676 | resolved = extension.ResolveUrl(url, fallbackUrl, packageId, payloadId, fileName); |
677 | if (!String.IsNullOrEmpty(resolved)) | 677 | if (!String.IsNullOrEmpty(resolved)) |
678 | { | 678 | { |
679 | break; | 679 | break; |
diff --git a/src/WixToolset.Core/Bind/Bundles/CreateContainerCommand.cs b/src/WixToolset.Core.Burn/Bundles/CreateContainerCommand.cs index 1bf987e3..75379713 100644 --- a/src/WixToolset.Core/Bind/Bundles/CreateContainerCommand.cs +++ b/src/WixToolset.Core.Burn/Bundles/CreateContainerCommand.cs | |||
@@ -1,20 +1,20 @@ | |||
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.Bind.Bundles | 3 | namespace WixToolset.Core.Burn.Bundles |
4 | { | 4 | { |
5 | using System; | 5 | using System; |
6 | using System.Collections.Generic; | 6 | using System.Collections.Generic; |
7 | using System.Diagnostics; | 7 | using System.Diagnostics; |
8 | using System.IO; | 8 | using System.IO; |
9 | using System.Linq; | 9 | using System.Linq; |
10 | using WixToolset.Cab; | 10 | using WixToolset.Core.Cab; |
11 | using WixToolset.Data; | 11 | using WixToolset.Data; |
12 | using WixToolset.Data.Rows; | 12 | using WixToolset.Data.Rows; |
13 | 13 | ||
14 | /// <summary> | 14 | /// <summary> |
15 | /// Creates cabinet files. | 15 | /// Creates cabinet files. |
16 | /// </summary> | 16 | /// </summary> |
17 | internal class CreateContainerCommand : ICommand | 17 | internal class CreateContainerCommand |
18 | { | 18 | { |
19 | public CompressionLevel DefaultCompressionLevel { private get; set; } | 19 | public CompressionLevel DefaultCompressionLevel { private get; set; } |
20 | 20 | ||
@@ -37,7 +37,7 @@ namespace WixToolset.Bind.Bundles | |||
37 | ++payloadCount; | 37 | ++payloadCount; |
38 | } | 38 | } |
39 | 39 | ||
40 | using (WixCreateCab cab = new WixCreateCab(Path.GetFileName(this.OutputPath), Path.GetDirectoryName(this.OutputPath), payloadCount, 0, 0, this.DefaultCompressionLevel)) | 40 | using (var cab = new WixCreateCab(Path.GetFileName(this.OutputPath), Path.GetDirectoryName(this.OutputPath), payloadCount, 0, 0, this.DefaultCompressionLevel)) |
41 | { | 41 | { |
42 | // If a manifest was provided always add it as "payload 0" to the container. | 42 | // If a manifest was provided always add it as "payload 0" to the container. |
43 | if (!String.IsNullOrEmpty(this.ManifestFile)) | 43 | if (!String.IsNullOrEmpty(this.ManifestFile)) |
diff --git a/src/WixToolset.Core/Bind/Bundles/GetPackageFacadesCommand.cs b/src/WixToolset.Core.Burn/Bundles/GetPackageFacadesCommand.cs index dc19e380..7485758c 100644 --- a/src/WixToolset.Core/Bind/Bundles/GetPackageFacadesCommand.cs +++ b/src/WixToolset.Core.Burn/Bundles/GetPackageFacadesCommand.cs | |||
@@ -1,12 +1,12 @@ | |||
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.Bind.Bundles | 3 | namespace WixToolset.Core.Burn.Bundles |
4 | { | 4 | { |
5 | using System.Collections.Generic; | 5 | using System.Collections.Generic; |
6 | using WixToolset.Data; | 6 | using WixToolset.Data; |
7 | using WixToolset.Data.Rows; | 7 | using WixToolset.Data.Rows; |
8 | 8 | ||
9 | internal class GetPackageFacadesCommand : ICommand | 9 | internal class GetPackageFacadesCommand |
10 | { | 10 | { |
11 | public Table PackageTable { private get; set; } | 11 | public Table PackageTable { private get; set; } |
12 | 12 | ||
diff --git a/src/WixToolset.Core/Bind/Bundles/OrderPackagesAndRollbackBoundariesCommand.cs b/src/WixToolset.Core.Burn/Bundles/OrderPackagesAndRollbackBoundariesCommand.cs index ac3a301d..cb6e2748 100644 --- a/src/WixToolset.Core/Bind/Bundles/OrderPackagesAndRollbackBoundariesCommand.cs +++ b/src/WixToolset.Core.Burn/Bundles/OrderPackagesAndRollbackBoundariesCommand.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.Bind.Bundles | 3 | namespace WixToolset.Core.Burn.Bundles |
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.Data.Rows; | 8 | using WixToolset.Data.Rows; |
9 | 9 | ||
10 | internal class OrderPackagesAndRollbackBoundariesCommand : ICommand | 10 | internal class OrderPackagesAndRollbackBoundariesCommand |
11 | { | 11 | { |
12 | public Table WixGroupTable { private get; set; } | 12 | public Table WixGroupTable { private get; set; } |
13 | 13 | ||
diff --git a/src/WixToolset.Core/Bind/Bundles/PackageFacade.cs b/src/WixToolset.Core.Burn/Bundles/PackageFacade.cs index f7e6410f..3f2e184d 100644 --- a/src/WixToolset.Core/Bind/Bundles/PackageFacade.cs +++ b/src/WixToolset.Core.Burn/Bundles/PackageFacade.cs | |||
@@ -1,6 +1,6 @@ | |||
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.Bind.Bundles | 3 | namespace WixToolset.Core.Burn.Bundles |
4 | { | 4 | { |
5 | using WixToolset.Data.Rows; | 5 | using WixToolset.Data.Rows; |
6 | 6 | ||
diff --git a/src/WixToolset.Core/Bind/Bundles/ProcessExePackageCommand.cs b/src/WixToolset.Core.Burn/Bundles/ProcessExePackageCommand.cs index a1e7c271..11512c39 100644 --- a/src/WixToolset.Core/Bind/Bundles/ProcessExePackageCommand.cs +++ b/src/WixToolset.Core.Burn/Bundles/ProcessExePackageCommand.cs | |||
@@ -1,6 +1,6 @@ | |||
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.Bind.Bundles | 3 | namespace WixToolset.Core.Burn.Bundles |
4 | { | 4 | { |
5 | using System; | 5 | using System; |
6 | using WixToolset.Data; | 6 | using WixToolset.Data; |
@@ -9,7 +9,7 @@ namespace WixToolset.Bind.Bundles | |||
9 | /// <summary> | 9 | /// <summary> |
10 | /// Initializes package state from the Exe contents. | 10 | /// Initializes package state from the Exe contents. |
11 | /// </summary> | 11 | /// </summary> |
12 | internal class ProcessExePackageCommand : ICommand | 12 | internal class ProcessExePackageCommand |
13 | { | 13 | { |
14 | public RowDictionary<WixBundlePayloadRow> AuthoredPayloads { private get; set; } | 14 | public RowDictionary<WixBundlePayloadRow> AuthoredPayloads { private get; set; } |
15 | 15 | ||
diff --git a/src/WixToolset.Core/Bind/Bundles/ProcessMsiPackageCommand.cs b/src/WixToolset.Core.Burn/Bundles/ProcessMsiPackageCommand.cs index f73776c0..322187f9 100644 --- a/src/WixToolset.Core/Bind/Bundles/ProcessMsiPackageCommand.cs +++ b/src/WixToolset.Core.Burn/Bundles/ProcessMsiPackageCommand.cs | |||
@@ -1,6 +1,6 @@ | |||
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.Bind.Bundles | 3 | namespace WixToolset.Core.Burn.Bundles |
4 | { | 4 | { |
5 | using System; | 5 | using System; |
6 | using System.Collections; | 6 | using System.Collections; |
@@ -12,14 +12,15 @@ namespace WixToolset.Bind.Bundles | |||
12 | using WixToolset.Data; | 12 | using WixToolset.Data; |
13 | using WixToolset.Data.Rows; | 13 | using WixToolset.Data.Rows; |
14 | using WixToolset.Extensibility; | 14 | using WixToolset.Extensibility; |
15 | using WixToolset.Msi; | ||
16 | using WixToolset.Core.Native; | 15 | using WixToolset.Core.Native; |
17 | using Dtf = WixToolset.Dtf.WindowsInstaller; | 16 | using Dtf = WixToolset.Dtf.WindowsInstaller; |
17 | using WixToolset.Bind; | ||
18 | using WixToolset.Data.Bind; | ||
18 | 19 | ||
19 | /// <summary> | 20 | /// <summary> |
20 | /// Initializes package state from the MSI contents. | 21 | /// Initializes package state from the MSI contents. |
21 | /// </summary> | 22 | /// </summary> |
22 | internal class ProcessMsiPackageCommand : ICommand | 23 | internal class ProcessMsiPackageCommand |
23 | { | 24 | { |
24 | private const string PropertySqlFormat = "SELECT `Value` FROM `Property` WHERE `Property` = '{0}'"; | 25 | private const string PropertySqlFormat = "SELECT `Value` FROM `Property` WHERE `Property` = '{0}'"; |
25 | 26 | ||
@@ -27,7 +28,7 @@ namespace WixToolset.Bind.Bundles | |||
27 | 28 | ||
28 | public PackageFacade Facade { private get; set; } | 29 | public PackageFacade Facade { private get; set; } |
29 | 30 | ||
30 | public IBinderFileManager FileManager { private get; set; } | 31 | public IEnumerable<IBurnBackendExtension> BackendExtensions { private get; set; } |
31 | 32 | ||
32 | public Table MsiFeatureTable { private get; set; } | 33 | public Table MsiFeatureTable { private get; set; } |
33 | 34 | ||
@@ -365,7 +366,7 @@ namespace WixToolset.Bind.Bundles | |||
365 | if (!payloadNames.Contains(cabinetName)) | 366 | if (!payloadNames.Contains(cabinetName)) |
366 | { | 367 | { |
367 | string generatedId = Common.GenerateIdentifier("cab", packagePayload.Id, cabinet); | 368 | string generatedId = Common.GenerateIdentifier("cab", packagePayload.Id, cabinet); |
368 | string payloadSourceFile = FileManager.ResolveRelatedFile(packagePayload.UnresolvedSourceFile, cabinet, "Cabinet", this.Facade.Package.SourceLineNumbers, BindStage.Normal); | 369 | string payloadSourceFile = this.ResolveRelatedFile(packagePayload.UnresolvedSourceFile, cabinet, "Cabinet", this.Facade.Package.SourceLineNumbers, BindStage.Normal); |
369 | 370 | ||
370 | WixBundlePayloadRow payload = (WixBundlePayloadRow)this.PayloadTable.CreateRow(this.Facade.Package.SourceLineNumbers); | 371 | WixBundlePayloadRow payload = (WixBundlePayloadRow)this.PayloadTable.CreateRow(this.Facade.Package.SourceLineNumbers); |
371 | payload.Id = generatedId; | 372 | payload.Id = generatedId; |
@@ -407,7 +408,7 @@ namespace WixToolset.Bind.Bundles | |||
407 | break; | 408 | break; |
408 | } | 409 | } |
409 | 410 | ||
410 | string sourceName = Installer.GetName(record.GetString(3), true, longNamesInImage); | 411 | string sourceName = Common.GetName(record.GetString(3), true, longNamesInImage); |
411 | directories.Add(record.GetString(1), new ResolvedDirectory(record.GetString(2), sourceName)); | 412 | directories.Add(record.GetString(1), new ResolvedDirectory(record.GetString(2), sourceName)); |
412 | } | 413 | } |
413 | } | 414 | } |
@@ -441,7 +442,7 @@ namespace WixToolset.Bind.Bundles | |||
441 | if (!payloadNames.Contains(name)) | 442 | if (!payloadNames.Contains(name)) |
442 | { | 443 | { |
443 | string generatedId = Common.GenerateIdentifier("f", packagePayload.Id, record.GetString(2)); | 444 | string generatedId = Common.GenerateIdentifier("f", packagePayload.Id, record.GetString(2)); |
444 | string payloadSourceFile = FileManager.ResolveRelatedFile(packagePayload.UnresolvedSourceFile, fileSourcePath, "File", this.Facade.Package.SourceLineNumbers, BindStage.Normal); | 445 | string payloadSourceFile = this.ResolveRelatedFile(packagePayload.UnresolvedSourceFile, fileSourcePath, "File", this.Facade.Package.SourceLineNumbers, BindStage.Normal); |
445 | 446 | ||
446 | WixBundlePayloadRow payload = (WixBundlePayloadRow)this.PayloadTable.CreateRow(this.Facade.Package.SourceLineNumbers); | 447 | WixBundlePayloadRow payload = (WixBundlePayloadRow)this.PayloadTable.CreateRow(this.Facade.Package.SourceLineNumbers); |
447 | payload.Id = generatedId; | 448 | payload.Id = generatedId; |
@@ -510,6 +511,21 @@ namespace WixToolset.Bind.Bundles | |||
510 | } | 511 | } |
511 | } | 512 | } |
512 | 513 | ||
514 | private string ResolveRelatedFile(string sourceFile, string relatedSource, string type, SourceLineNumber sourceLineNumbers, BindStage stage) | ||
515 | { | ||
516 | foreach (var extension in this.BackendExtensions) | ||
517 | { | ||
518 | var relatedFile = extension.ResolveRelatedFile(sourceFile, relatedSource, type, sourceLineNumbers, stage); | ||
519 | |||
520 | if (!String.IsNullOrEmpty(relatedFile)) | ||
521 | { | ||
522 | return relatedFile; | ||
523 | } | ||
524 | } | ||
525 | |||
526 | return null; | ||
527 | } | ||
528 | |||
513 | /// <summary> | 529 | /// <summary> |
514 | /// Queries a Windows Installer database for a Property value. | 530 | /// Queries a Windows Installer database for a Property value. |
515 | /// </summary> | 531 | /// </summary> |
diff --git a/src/WixToolset.Core/Bind/Bundles/ProcessMspPackageCommand.cs b/src/WixToolset.Core.Burn/Bundles/ProcessMspPackageCommand.cs index 24063221..2d849d03 100644 --- a/src/WixToolset.Core/Bind/Bundles/ProcessMspPackageCommand.cs +++ b/src/WixToolset.Core.Burn/Bundles/ProcessMspPackageCommand.cs | |||
@@ -1,6 +1,6 @@ | |||
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.Bind.Bundles | 3 | namespace WixToolset.Core.Burn.Bundles |
4 | { | 4 | { |
5 | using System; | 5 | using System; |
6 | using System.Collections.Generic; | 6 | using System.Collections.Generic; |
@@ -16,7 +16,7 @@ namespace WixToolset.Bind.Bundles | |||
16 | /// <summary> | 16 | /// <summary> |
17 | /// Initializes package state from the Msp contents. | 17 | /// Initializes package state from the Msp contents. |
18 | /// </summary> | 18 | /// </summary> |
19 | internal class ProcessMspPackageCommand : ICommand | 19 | internal class ProcessMspPackageCommand |
20 | { | 20 | { |
21 | private const string PatchMetadataFormat = "SELECT `Value` FROM `MsiPatchMetadata` WHERE `Property` = '{0}'"; | 21 | private const string PatchMetadataFormat = "SELECT `Value` FROM `MsiPatchMetadata` WHERE `Property` = '{0}'"; |
22 | private static readonly Encoding XmlOutputEncoding = new UTF8Encoding(false); | 22 | private static readonly Encoding XmlOutputEncoding = new UTF8Encoding(false); |
diff --git a/src/WixToolset.Core/Bind/Bundles/ProcessMsuPackageCommand.cs b/src/WixToolset.Core.Burn/Bundles/ProcessMsuPackageCommand.cs index ba59f5f5..fcfc780c 100644 --- a/src/WixToolset.Core/Bind/Bundles/ProcessMsuPackageCommand.cs +++ b/src/WixToolset.Core.Burn/Bundles/ProcessMsuPackageCommand.cs | |||
@@ -1,6 +1,6 @@ | |||
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.Bind.Bundles | 3 | namespace WixToolset.Core.Burn.Bundles |
4 | { | 4 | { |
5 | using System; | 5 | using System; |
6 | using WixToolset.Data; | 6 | using WixToolset.Data; |
@@ -9,7 +9,7 @@ namespace WixToolset.Bind.Bundles | |||
9 | /// <summary> | 9 | /// <summary> |
10 | /// Processes the Msu packages to add properties and payloads from the Msu packages. | 10 | /// Processes the Msu packages to add properties and payloads from the Msu packages. |
11 | /// </summary> | 11 | /// </summary> |
12 | internal class ProcessMsuPackageCommand : ICommand | 12 | internal class ProcessMsuPackageCommand |
13 | { | 13 | { |
14 | public RowDictionary<WixBundlePayloadRow> AuthoredPayloads { private get; set; } | 14 | public RowDictionary<WixBundlePayloadRow> AuthoredPayloads { private get; set; } |
15 | 15 | ||
diff --git a/src/WixToolset.Core/Bind/Bundles/ProcessPayloadsCommand.cs b/src/WixToolset.Core.Burn/Bundles/ProcessPayloadsCommand.cs index a83a7a4a..5dbd6aaa 100644 --- a/src/WixToolset.Core/Bind/Bundles/ProcessPayloadsCommand.cs +++ b/src/WixToolset.Core.Burn/Bundles/ProcessPayloadsCommand.cs | |||
@@ -1,6 +1,6 @@ | |||
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.Bind.Bundles | 3 | namespace WixToolset.Core.Burn.Bundles |
4 | { | 4 | { |
5 | using System; | 5 | using System; |
6 | using System.Collections.Generic; | 6 | using System.Collections.Generic; |
@@ -9,10 +9,12 @@ namespace WixToolset.Bind.Bundles | |||
9 | using System.Security.Cryptography; | 9 | using System.Security.Cryptography; |
10 | using System.Security.Cryptography.X509Certificates; | 10 | using System.Security.Cryptography.X509Certificates; |
11 | using System.Text; | 11 | using System.Text; |
12 | using WixToolset.Bind; | ||
12 | using WixToolset.Data; | 13 | using WixToolset.Data; |
14 | using WixToolset.Data.Bind; | ||
13 | using WixToolset.Data.Rows; | 15 | using WixToolset.Data.Rows; |
14 | 16 | ||
15 | internal class ProcessPayloadsCommand : ICommand | 17 | internal class ProcessPayloadsCommand |
16 | { | 18 | { |
17 | private static readonly Version EmptyVersion = new Version(0, 0, 0, 0); | 19 | private static readonly Version EmptyVersion = new Version(0, 0, 0, 0); |
18 | 20 | ||
diff --git a/src/WixToolset.Core/Bind/Bundles/VerifyPayloadsWithCatalogCommand.cs b/src/WixToolset.Core.Burn/Bundles/VerifyPayloadsWithCatalogCommand.cs index 9c614c26..9919f777 100644 --- a/src/WixToolset.Core/Bind/Bundles/VerifyPayloadsWithCatalogCommand.cs +++ b/src/WixToolset.Core.Burn/Bundles/VerifyPayloadsWithCatalogCommand.cs | |||
@@ -1,6 +1,6 @@ | |||
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.Bind.Bundles | 3 | namespace WixToolset.Core.Burn.Bundles |
4 | { | 4 | { |
5 | using System; | 5 | using System; |
6 | using System.Collections.Generic; | 6 | using System.Collections.Generic; |
@@ -11,7 +11,7 @@ namespace WixToolset.Bind.Bundles | |||
11 | using WixToolset.Data; | 11 | using WixToolset.Data; |
12 | using WixToolset.Data.Rows; | 12 | using WixToolset.Data.Rows; |
13 | 13 | ||
14 | internal class VerifyPayloadsWithCatalogCommand : ICommand | 14 | internal class VerifyPayloadsWithCatalogCommand |
15 | { | 15 | { |
16 | public IEnumerable<WixBundleCatalogRow> Catalogs { private get; set; } | 16 | public IEnumerable<WixBundleCatalogRow> Catalogs { private get; set; } |
17 | 17 | ||
diff --git a/src/WixToolset.Core.Burn/Inscribe/InscribeBundleCommand.cs b/src/WixToolset.Core.Burn/Inscribe/InscribeBundleCommand.cs new file mode 100644 index 00000000..5eb76479 --- /dev/null +++ b/src/WixToolset.Core.Burn/Inscribe/InscribeBundleCommand.cs | |||
@@ -0,0 +1,53 @@ | |||
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.Burn.Inscribe | ||
4 | { | ||
5 | using System.IO; | ||
6 | using WixToolset.Core.Burn.Bundles; | ||
7 | using WixToolset.Extensibility; | ||
8 | |||
9 | internal class InscribeBundleCommand | ||
10 | { | ||
11 | public InscribeBundleCommand(IInscribeContext context) | ||
12 | { | ||
13 | this.Context = context; | ||
14 | } | ||
15 | |||
16 | private IInscribeContext Context { get; } | ||
17 | |||
18 | public bool Execute() | ||
19 | { | ||
20 | bool inscribed = false; | ||
21 | string tempFile = Path.Combine(this.Context.IntermediateFolder, "bundle_engine_signed.exe"); | ||
22 | |||
23 | using (BurnReader reader = BurnReader.Open(this.Context.InputFilePath)) | ||
24 | { | ||
25 | File.Copy(this.Context.SignedEngineFile, tempFile, true); | ||
26 | |||
27 | // If there was an attached container on the original (unsigned) bundle, put it back. | ||
28 | if (reader.AttachedContainerSize > 0) | ||
29 | { | ||
30 | reader.Stream.Seek(reader.AttachedContainerAddress, SeekOrigin.Begin); | ||
31 | |||
32 | using (BurnWriter writer = BurnWriter.Open(tempFile)) | ||
33 | { | ||
34 | writer.RememberThenResetSignature(); | ||
35 | writer.AppendContainer(reader.Stream, reader.AttachedContainerSize, BurnCommon.Container.Attached); | ||
36 | inscribed = true; | ||
37 | } | ||
38 | } | ||
39 | } | ||
40 | |||
41 | Directory.CreateDirectory(Path.GetDirectoryName(this.Context.OutputFile)); | ||
42 | if (File.Exists(this.Context.OutputFile)) | ||
43 | { | ||
44 | File.Delete(this.Context.OutputFile); | ||
45 | } | ||
46 | |||
47 | File.Move(tempFile, this.Context.OutputFile); | ||
48 | WixToolset.Core.Native.NativeMethods.ResetAcls(new string[] { this.Context.OutputFile }, 1); | ||
49 | |||
50 | return inscribed; | ||
51 | } | ||
52 | } | ||
53 | } | ||
diff --git a/src/WixToolset.Core.Burn/Inscribe/InscribeBundleEngineCommand.cs b/src/WixToolset.Core.Burn/Inscribe/InscribeBundleEngineCommand.cs new file mode 100644 index 00000000..26af056b --- /dev/null +++ b/src/WixToolset.Core.Burn/Inscribe/InscribeBundleEngineCommand.cs | |||
@@ -0,0 +1,61 @@ | |||
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.Burn.Inscribe | ||
4 | { | ||
5 | using System; | ||
6 | using System.IO; | ||
7 | using WixToolset.Core.Burn.Bundles; | ||
8 | using WixToolset.Extensibility; | ||
9 | |||
10 | internal class InscribeBundleEngineCommand | ||
11 | { | ||
12 | public InscribeBundleEngineCommand(IInscribeContext context) | ||
13 | { | ||
14 | this.Context = context; | ||
15 | } | ||
16 | |||
17 | private IInscribeContext Context { get; } | ||
18 | |||
19 | public bool Execute() | ||
20 | { | ||
21 | string tempFile = Path.Combine(this.Context.IntermediateFolder, "bundle_engine_unsigned.exe"); | ||
22 | |||
23 | using (BurnReader reader = BurnReader.Open(this.Context.InputFilePath)) | ||
24 | using (FileStream writer = File.Open(tempFile, FileMode.Create, FileAccess.Write, FileShare.Read | FileShare.Delete)) | ||
25 | { | ||
26 | reader.Stream.Seek(0, SeekOrigin.Begin); | ||
27 | |||
28 | byte[] buffer = new byte[4 * 1024]; | ||
29 | int total = 0; | ||
30 | int read = 0; | ||
31 | do | ||
32 | { | ||
33 | read = Math.Min(buffer.Length, (int)reader.EngineSize - total); | ||
34 | |||
35 | read = reader.Stream.Read(buffer, 0, read); | ||
36 | writer.Write(buffer, 0, read); | ||
37 | |||
38 | total += read; | ||
39 | } while (total < reader.EngineSize && 0 < read); | ||
40 | |||
41 | if (total != reader.EngineSize) | ||
42 | { | ||
43 | throw new InvalidOperationException("Failed to copy engine out of bundle."); | ||
44 | } | ||
45 | |||
46 | // TODO: update writer with detached container signatures. | ||
47 | } | ||
48 | |||
49 | Directory.CreateDirectory(Path.GetDirectoryName(this.Context.OutputFile)); | ||
50 | if (File.Exists(this.Context.OutputFile)) | ||
51 | { | ||
52 | File.Delete(this.Context.OutputFile); | ||
53 | } | ||
54 | |||
55 | File.Move(tempFile, this.Context.OutputFile); | ||
56 | WixToolset.Core.Native.NativeMethods.ResetAcls(new string[] { this.Context.OutputFile }, 1); | ||
57 | |||
58 | return true; | ||
59 | } | ||
60 | } | ||
61 | } | ||
diff --git a/src/WixToolset.Core/VerifyInterop.cs b/src/WixToolset.Core.Burn/VerifyInterop.cs index 81fbec65..81fbec65 100644 --- a/src/WixToolset.Core/VerifyInterop.cs +++ b/src/WixToolset.Core.Burn/VerifyInterop.cs | |||
diff --git a/src/WixToolset.Core.Burn/WixToolset.Core.Burn.csproj b/src/WixToolset.Core.Burn/WixToolset.Core.Burn.csproj new file mode 100644 index 00000000..878ac200 --- /dev/null +++ b/src/WixToolset.Core.Burn/WixToolset.Core.Burn.csproj | |||
@@ -0,0 +1,36 @@ | |||
1 | <?xml version="1.0" encoding="utf-8"?> | ||
2 | <!-- 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. --> | ||
3 | |||
4 | <Project Sdk="Microsoft.NET.Sdk"> | ||
5 | <PropertyGroup> | ||
6 | <TargetFramework>netstandard2.0</TargetFramework> | ||
7 | <Description>Core Burn</Description> | ||
8 | <Title>WiX Toolset Core Burn</Title> | ||
9 | </PropertyGroup> | ||
10 | |||
11 | <PropertyGroup> | ||
12 | <NoWarn>NU1701</NoWarn> | ||
13 | </PropertyGroup> | ||
14 | |||
15 | <ItemGroup> | ||
16 | <ProjectReference Include="$(WixToolsetRootFolder)\Data\src\WixToolset.Data\WixToolset.Data.csproj" Condition=" '$(Configuration)' == 'Debug' And Exists('$(WixToolsetRootFolder)\Data\src\WixToolset.Data\WixToolset.Data.csproj') " /> | ||
17 | <PackageReference Include="WixToolset.Data" Version="4.0.*" Condition=" '$(Configuration)' == 'Release' Or !Exists('$(WixToolsetRootFolder)\Data\src\WixToolset.Data\WixToolset.Data.csproj') " /> | ||
18 | |||
19 | <ProjectReference Include="$(WixToolsetRootFolder)\Extensibility\src\WixToolset.Extensibility\WixToolset.Extensibility.csproj" Condition=" '$(Configuration)' == 'Debug' And Exists('$(WixToolsetRootFolder)\Extensibility\src\WixToolset.Extensibility\WixToolset.Extensibility.csproj') " /> | ||
20 | <PackageReference Include="WixToolset.Extensibility" Version="4.0.*" Condition=" '$(Configuration)' == 'Release' Or !Exists('$(WixToolsetRootFolder)\Extensibility\src\WixToolset.Extensibility\WixToolset.Extensibility.csproj') " /> | ||
21 | |||
22 | <ProjectReference Include="$(WixToolsetRootFolder)\Core.Native\src\WixToolset.Core.Native\WixToolset.Core.Native.csproj" Condition=" '$(Configuration)' == 'Debug' And Exists('$(WixToolsetRootFolder)\Core.Native\src\WixToolset.Core.Native\WixToolset.Core.Native.csproj') " /> | ||
23 | |||
24 | <ProjectReference Include="..\WixToolset.Core\WixToolset.Core.csproj" /> | ||
25 | <PackageReference Include="WixToolset.Core.Native" Version="4.0.*" Condition=" '$(Configuration)' == 'Release' Or !Exists('$(WixToolsetRootFolder)\Core.Native\src\WixToolset.Core.Native\WixToolset.Core.Native.csproj') " /> | ||
26 | </ItemGroup> | ||
27 | |||
28 | <ItemGroup> | ||
29 | <PackageReference Include="WixToolset.Dtf.Resources" Version="4.0.*" /> | ||
30 | <PackageReference Include="WixToolset.Dtf.WindowsInstaller" Version="4.0.*" /> | ||
31 | </ItemGroup> | ||
32 | |||
33 | <ItemGroup> | ||
34 | <PackageReference Include="Nerdbank.GitVersioning" Version="2.0.41" PrivateAssets="all" /> | ||
35 | </ItemGroup> | ||
36 | </Project> | ||
diff --git a/src/WixToolset.Core/Bind/Databases/AssignMediaCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/AssignMediaCommand.cs index 5e2650e9..23c481b7 100644 --- a/src/WixToolset.Core/Bind/Databases/AssignMediaCommand.cs +++ b/src/WixToolset.Core.WindowsInstaller/Bind/AssignMediaCommand.cs | |||
@@ -1,18 +1,18 @@ | |||
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.Bind.Databases | 3 | namespace WixToolset.Core.WindowsInstaller.Databases |
4 | { | 4 | { |
5 | using System; | 5 | using System; |
6 | using System.Collections.Generic; | 6 | using System.Collections.Generic; |
7 | using System.Globalization; | 7 | using System.Globalization; |
8 | using System.IO; | 8 | using WixToolset.Core.Bind; |
9 | using WixToolset.Data; | 9 | using WixToolset.Data; |
10 | using WixToolset.Data.Rows; | 10 | using WixToolset.Data.Rows; |
11 | 11 | ||
12 | /// <summary> | 12 | /// <summary> |
13 | /// AssignMediaCommand assigns files to cabs based on Media or MediaTemplate rows. | 13 | /// AssignMediaCommand assigns files to cabs based on Media or MediaTemplate rows. |
14 | /// </summary> | 14 | /// </summary> |
15 | public class AssignMediaCommand : ICommand | 15 | public class AssignMediaCommand |
16 | { | 16 | { |
17 | public AssignMediaCommand() | 17 | public AssignMediaCommand() |
18 | { | 18 | { |
diff --git a/src/WixToolset.Core/Bind/BindDatabaseCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs index 93af2e9a..2e2c5417 100644 --- a/src/WixToolset.Core/Bind/BindDatabaseCommand.cs +++ b/src/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs | |||
@@ -1,6 +1,6 @@ | |||
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.Bind | 3 | namespace WixToolset.Core.WindowsInstaller.Bind |
4 | { | 4 | { |
5 | using System; | 5 | using System; |
6 | using System.Collections; | 6 | using System.Collections; |
@@ -9,8 +9,11 @@ namespace WixToolset.Bind | |||
9 | using System.Globalization; | 9 | using System.Globalization; |
10 | using System.IO; | 10 | using System.IO; |
11 | using System.Linq; | 11 | using System.Linq; |
12 | using WixToolset.Bind.Databases; | 12 | using WixToolset.Bind; |
13 | using WixToolset.Core.Bind; | ||
14 | using WixToolset.Core.WindowsInstaller.Databases; | ||
13 | using WixToolset.Data; | 15 | using WixToolset.Data; |
16 | using WixToolset.Data.Bind; | ||
14 | using WixToolset.Data.Rows; | 17 | using WixToolset.Data.Rows; |
15 | using WixToolset.Extensibility; | 18 | using WixToolset.Extensibility; |
16 | using WixToolset.Msi; | 19 | using WixToolset.Msi; |
@@ -18,46 +21,72 @@ namespace WixToolset.Bind | |||
18 | /// <summary> | 21 | /// <summary> |
19 | /// Binds a databse. | 22 | /// Binds a databse. |
20 | /// </summary> | 23 | /// </summary> |
21 | internal class BindDatabaseCommand : ICommand | 24 | internal class BindDatabaseCommand |
22 | { | 25 | { |
23 | // As outlined in RFC 4122, this is our namespace for generating name-based (version 3) UUIDs. | 26 | // As outlined in RFC 4122, this is our namespace for generating name-based (version 3) UUIDs. |
24 | private static readonly Guid WixComponentGuidNamespace = new Guid("{3064E5C6-FB63-4FE9-AC49-E446A792EFA5}"); | 27 | private static readonly Guid WixComponentGuidNamespace = new Guid("{3064E5C6-FB63-4FE9-AC49-E446A792EFA5}"); |
25 | 28 | ||
26 | public int Codepage { private get; set; } | 29 | public BindDatabaseCommand(IBindContext context, Validator validator) |
30 | { | ||
31 | this.TableDefinitions = WindowsInstallerStandard.GetTableDefinitions(); | ||
32 | |||
33 | this.BindPaths = context.BindPaths; | ||
34 | this.CabbingThreadCount = context.CabbingThreadCount; | ||
35 | this.CabCachePath = context.CabCachePath; | ||
36 | this.Codepage = context.Codepage; | ||
37 | this.DefaultCompressionLevel = context.DefaultCompressionLevel; | ||
38 | this.DelayedFields = context.DelayedFields; | ||
39 | this.ExpectedEmbeddedFiles = context.ExpectedEmbeddedFiles; | ||
40 | this.Extensions = context.Extensions; | ||
41 | this.Output = context.IntermediateRepresentation; | ||
42 | this.OutputPath = context.OutputPath; | ||
43 | this.PdbFile = context.OutputPdbPath; | ||
44 | this.IntermediateFolder = context.IntermediateFolder; | ||
45 | this.Validator = validator; | ||
46 | this.WixVariableResolver = context.WixVariableResolver; | ||
47 | |||
48 | this.BackendExtensions = context.ExtensionManager.Create<IWindowsInstallerBackendExtension>(); | ||
49 | } | ||
27 | 50 | ||
28 | public int CabbingThreadCount { private get; set; } | 51 | private IEnumerable<BindPath> BindPaths { get; } |
29 | 52 | ||
30 | public CompressionLevel DefaultCompressionLevel { private get; set; } | 53 | private int Codepage { get; } |
31 | 54 | ||
32 | public bool DeltaBinaryPatch { get; set; } | 55 | private int CabbingThreadCount { get; } |
33 | 56 | ||
34 | public IEnumerable<IBinderExtension> Extensions { private get; set; } | 57 | private string CabCachePath { get; } |
35 | 58 | ||
36 | public BinderFileManagerCore FileManagerCore { private get; set; } | 59 | private CompressionLevel DefaultCompressionLevel { get; } |
37 | 60 | ||
38 | public IEnumerable<IBinderFileManager> FileManagers { private get; set; } | 61 | public IEnumerable<IDelayedField> DelayedFields { get; } |
39 | 62 | ||
40 | public IEnumerable<InspectorExtension> InspectorExtensions { private get; set; } | 63 | public IEnumerable<IExpectedExtractFile> ExpectedEmbeddedFiles { get; } |
64 | |||
65 | public bool DeltaBinaryPatch { get; set; } | ||
41 | 66 | ||
42 | public Localizer Localizer { private get; set; } | 67 | private IEnumerable<IWindowsInstallerBackendExtension> BackendExtensions { get; } |
43 | 68 | ||
44 | public string PdbFile { private get; set; } | 69 | private IEnumerable<IBinderExtension> Extensions { get; } |
45 | 70 | ||
46 | public Output Output { private get; set; } | 71 | private IEnumerable<InspectorExtension> InspectorExtensions { get; } |
47 | 72 | ||
48 | public string OutputPath { private get; set; } | 73 | private string PdbFile { get; } |
49 | 74 | ||
50 | public bool SuppressAddingValidationRows { private get; set; } | 75 | private Output Output { get; } |
51 | 76 | ||
52 | public bool SuppressLayout { private get; set; } | 77 | private string OutputPath { get; } |
53 | 78 | ||
54 | public TableDefinitionCollection TableDefinitions { private get; set; } | 79 | private bool SuppressAddingValidationRows { get; } |
55 | 80 | ||
56 | public string TempFilesLocation { private get; set; } | 81 | private bool SuppressLayout { get; } |
57 | 82 | ||
58 | public Validator Validator { private get; set; } | 83 | private TableDefinitionCollection TableDefinitions { get; } |
59 | 84 | ||
60 | public WixVariableResolver WixVariableResolver { private get; set; } | 85 | private string IntermediateFolder { get; } |
86 | |||
87 | private Validator Validator { get; } | ||
88 | |||
89 | private IBindVariableResolver WixVariableResolver { get; } | ||
61 | 90 | ||
62 | public IEnumerable<FileTransfer> FileTransfers { get; private set; } | 91 | public IEnumerable<FileTransfer> FileTransfers { get; private set; } |
63 | 92 | ||
@@ -69,43 +98,9 @@ namespace WixToolset.Bind | |||
69 | 98 | ||
70 | HashSet<string> suppressedTableNames = new HashSet<string>(); | 99 | HashSet<string> suppressedTableNames = new HashSet<string>(); |
71 | 100 | ||
72 | // Localize fields, resolve wix variables, and resolve file paths. | ||
73 | ExtractEmbeddedFiles filesWithEmbeddedFiles = new ExtractEmbeddedFiles(); | ||
74 | |||
75 | IEnumerable<DelayedField> delayedFields; | ||
76 | { | ||
77 | ResolveFieldsCommand command = new ResolveFieldsCommand(); | ||
78 | command.Tables = this.Output.Tables; | ||
79 | command.FilesWithEmbeddedFiles = filesWithEmbeddedFiles; | ||
80 | command.FileManagerCore = this.FileManagerCore; | ||
81 | command.FileManagers = this.FileManagers; | ||
82 | command.SupportDelayedResolution = true; | ||
83 | command.TempFilesLocation = this.TempFilesLocation; | ||
84 | command.WixVariableResolver = this.WixVariableResolver; | ||
85 | command.Execute(); | ||
86 | |||
87 | delayedFields = command.DelayedFields; | ||
88 | } | ||
89 | |||
90 | if (OutputType.Patch == this.Output.Type) | ||
91 | { | ||
92 | foreach (SubStorage transform in this.Output.SubStorages) | ||
93 | { | ||
94 | ResolveFieldsCommand command = new ResolveFieldsCommand(); | ||
95 | command.Tables = transform.Data.Tables; | ||
96 | command.FilesWithEmbeddedFiles = filesWithEmbeddedFiles; | ||
97 | command.FileManagerCore = this.FileManagerCore; | ||
98 | command.FileManagers = this.FileManagers; | ||
99 | command.SupportDelayedResolution = false; | ||
100 | command.TempFilesLocation = this.TempFilesLocation; | ||
101 | command.WixVariableResolver = this.WixVariableResolver; | ||
102 | command.Execute(); | ||
103 | } | ||
104 | } | ||
105 | |||
106 | // If there are any fields to resolve later, create the cache to populate during bind. | 101 | // If there are any fields to resolve later, create the cache to populate during bind. |
107 | IDictionary<string, string> variableCache = null; | 102 | IDictionary<string, string> variableCache = null; |
108 | if (delayedFields.Any()) | 103 | if (this.DelayedFields.Any()) |
109 | { | 104 | { |
110 | variableCache = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase); | 105 | variableCache = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase); |
111 | } | 106 | } |
@@ -231,7 +226,7 @@ namespace WixToolset.Bind | |||
231 | // Add the property name and value to the variableCache. | 226 | // Add the property name and value to the variableCache. |
232 | if (null != variableCache) | 227 | if (null != variableCache) |
233 | { | 228 | { |
234 | string key = String.Concat("property.", Demodularize(this.Output.Type, modularizationGuid, propertyRow.Property)); | 229 | string key = String.Concat("property.", Common.Demodularize(this.Output.Type, modularizationGuid, propertyRow.Property)); |
235 | variableCache[key] = propertyRow.Value; | 230 | variableCache[key] = propertyRow.Value; |
236 | } | 231 | } |
237 | } | 232 | } |
@@ -240,7 +235,7 @@ namespace WixToolset.Bind | |||
240 | // Extract files that come from cabinet files (this does not extract files from merge modules). | 235 | // Extract files that come from cabinet files (this does not extract files from merge modules). |
241 | { | 236 | { |
242 | ExtractEmbeddedFilesCommand command = new ExtractEmbeddedFilesCommand(); | 237 | ExtractEmbeddedFilesCommand command = new ExtractEmbeddedFilesCommand(); |
243 | command.FilesWithEmbeddedFiles = filesWithEmbeddedFiles; | 238 | command.FilesWithEmbeddedFiles = this.ExpectedEmbeddedFiles; |
244 | command.Execute(); | 239 | command.Execute(); |
245 | } | 240 | } |
246 | 241 | ||
@@ -258,7 +253,7 @@ namespace WixToolset.Bind | |||
258 | command.WixMergeTable = wixMergeTable; | 253 | command.WixMergeTable = wixMergeTable; |
259 | command.OutputInstallerVersion = installerVersion; | 254 | command.OutputInstallerVersion = installerVersion; |
260 | command.SuppressLayout = this.SuppressLayout; | 255 | command.SuppressLayout = this.SuppressLayout; |
261 | command.TempFilesLocation = this.TempFilesLocation; | 256 | command.TempFilesLocation = this.IntermediateFolder; |
262 | command.Execute(); | 257 | command.Execute(); |
263 | 258 | ||
264 | fileFacades.AddRange(command.MergeModulesFileFacades); | 259 | fileFacades.AddRange(command.MergeModulesFileFacades); |
@@ -303,11 +298,11 @@ namespace WixToolset.Bind | |||
303 | 298 | ||
304 | this.UpdateControlText(this.Output); | 299 | this.UpdateControlText(this.Output); |
305 | 300 | ||
306 | if (delayedFields.Any()) | 301 | if (this.DelayedFields.Any()) |
307 | { | 302 | { |
308 | ResolveDelayedFieldsCommand command = new ResolveDelayedFieldsCommand(); | 303 | ResolveDelayedFieldsCommand command = new ResolveDelayedFieldsCommand(); |
309 | command.OutputType = this.Output.Type; | 304 | command.OutputType = this.Output.Type; |
310 | command.DelayedFields = delayedFields; | 305 | command.DelayedFields = this.DelayedFields; |
311 | command.ModularizationGuid = null; | 306 | command.ModularizationGuid = null; |
312 | command.VariableCache = variableCache; | 307 | command.VariableCache = variableCache; |
313 | command.Execute(); | 308 | command.Execute(); |
@@ -343,7 +338,7 @@ namespace WixToolset.Bind | |||
343 | { | 338 | { |
344 | Table updatedFiles = this.Output.EnsureTable(this.TableDefinitions["WixBindUpdatedFiles"]); | 339 | Table updatedFiles = this.Output.EnsureTable(this.TableDefinitions["WixBindUpdatedFiles"]); |
345 | 340 | ||
346 | foreach (BinderExtension extension in this.Extensions) | 341 | foreach (IBinderExtension extension in this.Extensions) |
347 | { | 342 | { |
348 | extension.AfterResolvedFields(this.Output); | 343 | extension.AfterResolvedFields(this.Output); |
349 | } | 344 | } |
@@ -379,14 +374,14 @@ namespace WixToolset.Bind | |||
379 | return; | 374 | return; |
380 | } | 375 | } |
381 | 376 | ||
382 | Directory.CreateDirectory(this.TempFilesLocation); | 377 | Directory.CreateDirectory(this.IntermediateFolder); |
383 | 378 | ||
384 | if (OutputType.Patch == this.Output.Type && this.DeltaBinaryPatch) | 379 | if (OutputType.Patch == this.Output.Type && this.DeltaBinaryPatch) |
385 | { | 380 | { |
386 | CreateDeltaPatchesCommand command = new CreateDeltaPatchesCommand(); | 381 | CreateDeltaPatchesCommand command = new CreateDeltaPatchesCommand(); |
387 | command.FileFacades = fileFacades; | 382 | command.FileFacades = fileFacades; |
388 | command.WixPatchIdTable = this.Output.Tables["WixPatchId"]; | 383 | command.WixPatchIdTable = this.Output.Tables["WixPatchId"]; |
389 | command.TempFilesLocation = this.TempFilesLocation; | 384 | command.TempFilesLocation = this.IntermediateFolder; |
390 | command.Execute(); | 385 | command.Execute(); |
391 | } | 386 | } |
392 | 387 | ||
@@ -396,17 +391,18 @@ namespace WixToolset.Bind | |||
396 | { | 391 | { |
397 | Messaging.Instance.OnMessage(WixVerboses.CreatingCabinetFiles()); | 392 | Messaging.Instance.OnMessage(WixVerboses.CreatingCabinetFiles()); |
398 | 393 | ||
399 | CreateCabinetsCommand command = new CreateCabinetsCommand(); | 394 | var command = new CreateCabinetsCommand(); |
400 | command.CabbingThreadCount = this.CabbingThreadCount; | 395 | command.CabbingThreadCount = this.CabbingThreadCount; |
396 | command.CabCachePath = this.CabCachePath; | ||
401 | command.DefaultCompressionLevel = this.DefaultCompressionLevel; | 397 | command.DefaultCompressionLevel = this.DefaultCompressionLevel; |
402 | command.Output = this.Output; | 398 | command.Output = this.Output; |
403 | command.FileManagers = this.FileManagers; | 399 | command.BackendExtensions = this.BackendExtensions; |
404 | command.LayoutDirectory = layoutDirectory; | 400 | command.LayoutDirectory = layoutDirectory; |
405 | command.Compressed = compressed; | 401 | command.Compressed = compressed; |
406 | command.FileRowsByCabinet = filesByCabinetMedia; | 402 | command.FileRowsByCabinet = filesByCabinetMedia; |
407 | command.ResolveMedia = this.ResolveMedia; | 403 | command.ResolveMedia = this.ResolveMedia; |
408 | command.TableDefinitions = this.TableDefinitions; | 404 | command.TableDefinitions = this.TableDefinitions; |
409 | command.TempFilesLocation = this.TempFilesLocation; | 405 | command.TempFilesLocation = this.IntermediateFolder; |
410 | command.WixMediaTable = this.Output.Tables["WixMedia"]; | 406 | command.WixMediaTable = this.Output.Tables["WixMedia"]; |
411 | command.Execute(); | 407 | command.Execute(); |
412 | 408 | ||
@@ -450,14 +446,14 @@ namespace WixToolset.Bind | |||
450 | } | 446 | } |
451 | } | 447 | } |
452 | 448 | ||
453 | foreach (BinderExtension extension in this.Extensions) | 449 | //foreach (BinderExtension extension in this.Extensions) |
454 | { | 450 | //{ |
455 | extension.Finish(this.Output); | 451 | // extension.PostBind(this.Context); |
456 | } | 452 | //} |
457 | 453 | ||
458 | // generate database file | 454 | // generate database file |
459 | Messaging.Instance.OnMessage(WixVerboses.GeneratingDatabase()); | 455 | Messaging.Instance.OnMessage(WixVerboses.GeneratingDatabase()); |
460 | string tempDatabaseFile = Path.Combine(this.TempFilesLocation, Path.GetFileName(this.OutputPath)); | 456 | string tempDatabaseFile = Path.Combine(this.IntermediateFolder, Path.GetFileName(this.OutputPath)); |
461 | this.GenerateDatabase(this.Output, tempDatabaseFile, false, false); | 457 | this.GenerateDatabase(this.Output, tempDatabaseFile, false, false); |
462 | 458 | ||
463 | FileTransfer transfer; | 459 | FileTransfer transfer; |
@@ -501,14 +497,14 @@ namespace WixToolset.Bind | |||
501 | } | 497 | } |
502 | 498 | ||
503 | // inspect the MSI prior to running ICEs | 499 | // inspect the MSI prior to running ICEs |
504 | InspectorCore inspectorCore = new InspectorCore(); | 500 | //InspectorCore inspectorCore = new InspectorCore(); |
505 | foreach (InspectorExtension inspectorExtension in this.InspectorExtensions) | 501 | //foreach (InspectorExtension inspectorExtension in this.InspectorExtensions) |
506 | { | 502 | //{ |
507 | inspectorExtension.Core = inspectorCore; | 503 | // inspectorExtension.Core = inspectorCore; |
508 | inspectorExtension.InspectDatabase(tempDatabaseFile, pdb); | 504 | // inspectorExtension.InspectDatabase(tempDatabaseFile, pdb); |
509 | 505 | ||
510 | inspectorExtension.Core = null; // reset. | 506 | // inspectorExtension.Core = null; // reset. |
511 | } | 507 | //} |
512 | 508 | ||
513 | if (Messaging.Instance.EncounteredError) | 509 | if (Messaging.Instance.EncounteredError) |
514 | { | 510 | { |
@@ -540,7 +536,7 @@ namespace WixToolset.Bind | |||
540 | // Process uncompressed files. | 536 | // Process uncompressed files. |
541 | if (!Messaging.Instance.EncounteredError && !this.SuppressLayout && uncompressedFiles.Any()) | 537 | if (!Messaging.Instance.EncounteredError && !this.SuppressLayout && uncompressedFiles.Any()) |
542 | { | 538 | { |
543 | ProcessUncompressedFilesCommand command = new ProcessUncompressedFilesCommand(); | 539 | var command = new ProcessUncompressedFilesCommand(); |
544 | command.Compressed = compressed; | 540 | command.Compressed = compressed; |
545 | command.FileFacades = uncompressedFiles; | 541 | command.FileFacades = uncompressedFiles; |
546 | command.LayoutDirectory = layoutDirectory; | 542 | command.LayoutDirectory = layoutDirectory; |
@@ -570,8 +566,8 @@ namespace WixToolset.Bind | |||
570 | foreach (Row row in dialogTable.Rows) | 566 | foreach (Row row in dialogTable.Rows) |
571 | { | 567 | { |
572 | string dialog = (string)row[0]; | 568 | string dialog = (string)row[0]; |
573 | LocalizedControl localizedControl = this.Localizer.GetLocalizedControl(dialog, null); | 569 | |
574 | if (null != localizedControl) | 570 | if (this.WixVariableResolver.TryGetLocalizedControl(dialog, null, out LocalizedControl localizedControl)) |
575 | { | 571 | { |
576 | if (CompilerConstants.IntegerNotSet != localizedControl.X) | 572 | if (CompilerConstants.IntegerNotSet != localizedControl.X) |
577 | { | 573 | { |
@@ -610,8 +606,8 @@ namespace WixToolset.Bind | |||
610 | { | 606 | { |
611 | string dialog = (string)row[0]; | 607 | string dialog = (string)row[0]; |
612 | string control = (string)row[1]; | 608 | string control = (string)row[1]; |
613 | LocalizedControl localizedControl = this.Localizer.GetLocalizedControl(dialog, control); | 609 | |
614 | if (null != localizedControl) | 610 | if (this.WixVariableResolver.TryGetLocalizedControl(dialog, control, out LocalizedControl localizedControl)) |
615 | { | 611 | { |
616 | if (CompilerConstants.IntegerNotSet != localizedControl.X) | 612 | if (CompilerConstants.IntegerNotSet != localizedControl.X) |
617 | { | 613 | { |
@@ -651,10 +647,8 @@ namespace WixToolset.Bind | |||
651 | /// <param name="allFileRows">True if copying from transform to patch, false the other way.</param> | 647 | /// <param name="allFileRows">True if copying from transform to patch, false the other way.</param> |
652 | private IEnumerable<FileFacade> CopyFromTransformData(Output output) | 648 | private IEnumerable<FileFacade> CopyFromTransformData(Output output) |
653 | { | 649 | { |
654 | CopyTransformDataCommand command = new CopyTransformDataCommand(); | 650 | var command = new CopyTransformDataCommand(); |
655 | command.CopyOutFileRows = true; | 651 | command.CopyOutFileRows = true; |
656 | command.FileManagerCore = this.FileManagerCore; | ||
657 | command.FileManagers = this.FileManagers; | ||
658 | command.Output = output; | 652 | command.Output = output; |
659 | command.TableDefinitions = this.TableDefinitions; | 653 | command.TableDefinitions = this.TableDefinitions; |
660 | command.Execute(); | 654 | command.Execute(); |
@@ -669,35 +663,13 @@ namespace WixToolset.Bind | |||
669 | /// <param name="allFileRows">True if copying from transform to patch, false the other way.</param> | 663 | /// <param name="allFileRows">True if copying from transform to patch, false the other way.</param> |
670 | private void CopyToTransformData(Output output) | 664 | private void CopyToTransformData(Output output) |
671 | { | 665 | { |
672 | CopyTransformDataCommand command = new CopyTransformDataCommand(); | 666 | var command = new CopyTransformDataCommand(); |
673 | command.CopyOutFileRows = false; | 667 | command.CopyOutFileRows = false; |
674 | command.FileManagerCore = this.FileManagerCore; | ||
675 | command.FileManagers = this.FileManagers; | ||
676 | command.Output = output; | 668 | command.Output = output; |
677 | command.TableDefinitions = this.TableDefinitions; | 669 | command.TableDefinitions = this.TableDefinitions; |
678 | command.Execute(); | 670 | command.Execute(); |
679 | } | 671 | } |
680 | 672 | ||
681 | /// <summary> | ||
682 | /// Takes an id, and demodularizes it (if possible). | ||
683 | /// </summary> | ||
684 | /// <remarks> | ||
685 | /// If the output type is a module, returns a demodularized version of an id. Otherwise, returns the id. | ||
686 | /// </remarks> | ||
687 | /// <param name="outputType">The type of the output to bind.</param> | ||
688 | /// <param name="modularizationGuid">The modularization GUID.</param> | ||
689 | /// <param name="id">The id to demodularize.</param> | ||
690 | /// <returns>The demodularized id.</returns> | ||
691 | internal static string Demodularize(OutputType outputType, string modularizationGuid, string id) | ||
692 | { | ||
693 | if (OutputType.Module == outputType && id.EndsWith(String.Concat(".", modularizationGuid), StringComparison.Ordinal)) | ||
694 | { | ||
695 | id = id.Substring(0, id.Length - 37); | ||
696 | } | ||
697 | |||
698 | return id; | ||
699 | } | ||
700 | |||
701 | private void UpdateMediaSequences(OutputType outputType, IEnumerable<FileFacade> fileFacades, RowDictionary<MediaRow> mediaRows) | 673 | private void UpdateMediaSequences(OutputType outputType, IEnumerable<FileFacade> fileFacades, RowDictionary<MediaRow> mediaRows) |
702 | { | 674 | { |
703 | // Calculate sequence numbers and media disk id layout for all file media information objects. | 675 | // Calculate sequence numbers and media disk id layout for all file media information objects. |
@@ -855,7 +827,7 @@ namespace WixToolset.Bind | |||
855 | continue; | 827 | continue; |
856 | } | 828 | } |
857 | 829 | ||
858 | string targetName = Installer.GetName((string)row[2], false, true); | 830 | string targetName = Common.GetName((string)row[2], false, true); |
859 | directories.Add(row[0], new ResolvedDirectory((string)row[1], targetName)); | 831 | directories.Add(row[0], new ResolvedDirectory((string)row[1], targetName)); |
860 | } | 832 | } |
861 | } | 833 | } |
@@ -919,7 +891,7 @@ namespace WixToolset.Bind | |||
919 | { | 891 | { |
920 | // calculate the key file's canonical target path | 892 | // calculate the key file's canonical target path |
921 | string directoryPath = Binder.GetDirectoryPath(directories, componentIdGenSeeds, componentRow.Directory, true); | 893 | string directoryPath = Binder.GetDirectoryPath(directories, componentIdGenSeeds, componentRow.Directory, true); |
922 | string fileName = Installer.GetName(fileRow.FileName, false, true).ToLower(CultureInfo.InvariantCulture); | 894 | string fileName = Common.GetName(fileRow.FileName, false, true).ToLower(CultureInfo.InvariantCulture); |
923 | path = Path.Combine(directoryPath, fileName); | 895 | path = Path.Combine(directoryPath, fileName); |
924 | 896 | ||
925 | // find paths that are not canonicalized | 897 | // find paths that are not canonicalized |
@@ -1256,9 +1228,9 @@ namespace WixToolset.Bind | |||
1256 | { | 1228 | { |
1257 | string layout = null; | 1229 | string layout = null; |
1258 | 1230 | ||
1259 | foreach (IBinderFileManager fileManager in this.FileManagers) | 1231 | foreach (var extension in this.BackendExtensions) |
1260 | { | 1232 | { |
1261 | layout = fileManager.ResolveMedia(mediaRow, mediaLayoutDirectory, layoutDirectory); | 1233 | layout = extension.ResolveMedia(mediaRow, mediaLayoutDirectory, layoutDirectory); |
1262 | if (!String.IsNullOrEmpty(layout)) | 1234 | if (!String.IsNullOrEmpty(layout)) |
1263 | { | 1235 | { |
1264 | break; | 1236 | break; |
@@ -1294,16 +1266,15 @@ namespace WixToolset.Bind | |||
1294 | /// <param name="useSubdirectory">Whether to use a subdirectory based on the <paramref name="databaseFile"/> file name for intermediate files.</param> | 1266 | /// <param name="useSubdirectory">Whether to use a subdirectory based on the <paramref name="databaseFile"/> file name for intermediate files.</param> |
1295 | private void GenerateDatabase(Output output, string databaseFile, bool keepAddedColumns, bool useSubdirectory) | 1267 | private void GenerateDatabase(Output output, string databaseFile, bool keepAddedColumns, bool useSubdirectory) |
1296 | { | 1268 | { |
1297 | GenerateDatabaseCommand command = new GenerateDatabaseCommand(); | 1269 | var command = new GenerateDatabaseCommand(); |
1298 | command.Extensions = this.Extensions; | 1270 | command.Extensions = this.Extensions; |
1299 | command.FileManagers = this.FileManagers; | ||
1300 | command.Output = output; | 1271 | command.Output = output; |
1301 | command.OutputPath = databaseFile; | 1272 | command.OutputPath = databaseFile; |
1302 | command.KeepAddedColumns = keepAddedColumns; | 1273 | command.KeepAddedColumns = keepAddedColumns; |
1303 | command.UseSubDirectory = useSubdirectory; | 1274 | command.UseSubDirectory = useSubdirectory; |
1304 | command.SuppressAddingValidationRows = this.SuppressAddingValidationRows; | 1275 | command.SuppressAddingValidationRows = this.SuppressAddingValidationRows; |
1305 | command.TableDefinitions = this.TableDefinitions; | 1276 | command.TableDefinitions = this.TableDefinitions; |
1306 | command.TempFilesLocation = this.TempFilesLocation; | 1277 | command.TempFilesLocation = this.IntermediateFolder; |
1307 | command.Codepage = this.Codepage; | 1278 | command.Codepage = this.Codepage; |
1308 | command.Execute(); | 1279 | command.Execute(); |
1309 | } | 1280 | } |
diff --git a/src/WixToolset.Core/Bind/Databases/BindSummaryInfoCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/BindSummaryInfoCommand.cs index 95bd4cf0..5471792d 100644 --- a/src/WixToolset.Core/Bind/Databases/BindSummaryInfoCommand.cs +++ b/src/WixToolset.Core.WindowsInstaller/Bind/BindSummaryInfoCommand.cs | |||
@@ -1,6 +1,6 @@ | |||
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.Bind.Databases | 3 | namespace WixToolset.Core.WindowsInstaller.Databases |
4 | { | 4 | { |
5 | using System; | 5 | using System; |
6 | using System.Globalization; | 6 | using System.Globalization; |
@@ -9,7 +9,7 @@ namespace WixToolset.Bind.Databases | |||
9 | /// <summary> | 9 | /// <summary> |
10 | /// Binds the summary information table of a database. | 10 | /// Binds the summary information table of a database. |
11 | /// </summary> | 11 | /// </summary> |
12 | internal class BindSummaryInfoCommand : ICommand | 12 | internal class BindSummaryInfoCommand |
13 | { | 13 | { |
14 | /// <summary> | 14 | /// <summary> |
15 | /// The output to bind. | 15 | /// The output to bind. |
diff --git a/src/WixToolset.Core/Bind/BindTransformCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/BindTransformCommand.cs index e909f191..425d1f9c 100644 --- a/src/WixToolset.Core/Bind/BindTransformCommand.cs +++ b/src/WixToolset.Core.WindowsInstaller/Bind/BindTransformCommand.cs | |||
@@ -1,6 +1,6 @@ | |||
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.Bind | 3 | namespace WixToolset.Core.WindowsInstaller.Databases |
4 | { | 4 | { |
5 | using System; | 5 | using System; |
6 | using System.Collections.Generic; | 6 | using System.Collections.Generic; |
@@ -11,12 +11,10 @@ namespace WixToolset.Bind | |||
11 | using WixToolset.Msi; | 11 | using WixToolset.Msi; |
12 | using WixToolset.Core.Native; | 12 | using WixToolset.Core.Native; |
13 | 13 | ||
14 | internal class BindTransformCommand : ICommand | 14 | internal class BindTransformCommand |
15 | { | 15 | { |
16 | public IEnumerable<IBinderExtension> Extensions { private get; set; } | 16 | public IEnumerable<IBinderExtension> Extensions { private get; set; } |
17 | 17 | ||
18 | public IEnumerable<IBinderFileManager> FileManagers { private get; set; } | ||
19 | |||
20 | public TableDefinitionCollection TableDefinitions { private get; set; } | 18 | public TableDefinitionCollection TableDefinitions { private get; set; } |
21 | 19 | ||
22 | public string TempFilesLocation { private get; set; } | 20 | public string TempFilesLocation { private get; set; } |
@@ -379,10 +377,10 @@ namespace WixToolset.Bind | |||
379 | } | 377 | } |
380 | } | 378 | } |
381 | 379 | ||
382 | foreach (BinderExtension extension in this.Extensions) | 380 | //foreach (BinderExtension extension in this.Extensions) |
383 | { | 381 | //{ |
384 | extension.Finish(this.Transform); | 382 | // extension.PostBind(this.Context); |
385 | } | 383 | //} |
386 | 384 | ||
387 | // Any errors encountered up to this point can cause errors during generation. | 385 | // Any errors encountered up to this point can cause errors during generation. |
388 | if (Messaging.Instance.EncounteredError) | 386 | if (Messaging.Instance.EncounteredError) |
@@ -437,9 +435,9 @@ namespace WixToolset.Bind | |||
437 | private bool CompareFiles(string targetFile, string updatedFile) | 435 | private bool CompareFiles(string targetFile, string updatedFile) |
438 | { | 436 | { |
439 | bool? compared = null; | 437 | bool? compared = null; |
440 | foreach (IBinderFileManager fileManager in this.FileManagers) | 438 | foreach (var extension in this.Extensions) |
441 | { | 439 | { |
442 | compared = fileManager.CompareFiles(targetFile, updatedFile); | 440 | compared = extension.CompareFiles(targetFile, updatedFile); |
443 | if (compared.HasValue) | 441 | if (compared.HasValue) |
444 | { | 442 | { |
445 | break; | 443 | break; |
@@ -456,10 +454,9 @@ namespace WixToolset.Bind | |||
456 | 454 | ||
457 | private void GenerateDatabase(Output output, string outputPath, bool keepAddedColumns) | 455 | private void GenerateDatabase(Output output, string outputPath, bool keepAddedColumns) |
458 | { | 456 | { |
459 | GenerateDatabaseCommand command = new GenerateDatabaseCommand(); | 457 | var command = new GenerateDatabaseCommand(); |
460 | command.Codepage = output.Codepage; | 458 | command.Codepage = output.Codepage; |
461 | command.Extensions = this.Extensions; | 459 | command.Extensions = this.Extensions; |
462 | command.FileManagers = this.FileManagers; | ||
463 | command.KeepAddedColumns = keepAddedColumns; | 460 | command.KeepAddedColumns = keepAddedColumns; |
464 | command.Output = output; | 461 | command.Output = output; |
465 | command.OutputPath = outputPath; | 462 | command.OutputPath = outputPath; |
diff --git a/src/WixToolset.Core/Bind/Databases/CabinetBuilder.cs b/src/WixToolset.Core.WindowsInstaller/Bind/CabinetBuilder.cs index 2de6ec25..b2cc76fc 100644 --- a/src/WixToolset.Core/Bind/Databases/CabinetBuilder.cs +++ b/src/WixToolset.Core.WindowsInstaller/Bind/CabinetBuilder.cs | |||
@@ -1,15 +1,15 @@ | |||
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.Bind.Databases | 3 | namespace WixToolset.Core.WindowsInstaller.Databases |
4 | { | 4 | { |
5 | using System; | 5 | using System; |
6 | using System.Collections; | 6 | using System.Collections; |
7 | using System.IO; | 7 | using System.IO; |
8 | using System.Linq; | 8 | using System.Linq; |
9 | using System.Threading; | 9 | using System.Threading; |
10 | using WixToolset.Cab; | 10 | using WixToolset.Core.Bind; |
11 | using WixToolset.Core.Cab; | ||
11 | using WixToolset.Data; | 12 | using WixToolset.Data; |
12 | using WixToolset.Data.Rows; | ||
13 | 13 | ||
14 | /// <summary> | 14 | /// <summary> |
15 | /// Builds cabinets using multiple threads. This implements a thread pool that generates cabinets with multiple | 15 | /// Builds cabinets using multiple threads. This implements a thread pool that generates cabinets with multiple |
@@ -25,6 +25,7 @@ namespace WixToolset.Bind.Databases | |||
25 | private IntPtr newCabNamesCallBackAddress; | 25 | private IntPtr newCabNamesCallBackAddress; |
26 | 26 | ||
27 | public int MaximumCabinetSizeForLargeFileSplitting { get; set; } | 27 | public int MaximumCabinetSizeForLargeFileSplitting { get; set; } |
28 | |||
28 | public int MaximumUncompressedMediaSize { get; set; } | 29 | public int MaximumUncompressedMediaSize { get; set; } |
29 | 30 | ||
30 | /// <summary> | 31 | /// <summary> |
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/CabinetResolver.cs b/src/WixToolset.Core.WindowsInstaller/Bind/CabinetResolver.cs new file mode 100644 index 00000000..df1ccecf --- /dev/null +++ b/src/WixToolset.Core.WindowsInstaller/Bind/CabinetResolver.cs | |||
@@ -0,0 +1,122 @@ | |||
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.Bind | ||
4 | { | ||
5 | using System; | ||
6 | using System.Collections.Generic; | ||
7 | using System.IO; | ||
8 | using System.Linq; | ||
9 | using WixToolset.Core.Cab; | ||
10 | using WixToolset.Core.Bind; | ||
11 | using WixToolset.Data; | ||
12 | using WixToolset.Extensibility; | ||
13 | |||
14 | public class CabinetResolver | ||
15 | { | ||
16 | public CabinetResolver(string cabCachePath, IEnumerable<IWindowsInstallerBackendExtension> backendExtensions) | ||
17 | { | ||
18 | this.CabCachePath = cabCachePath; | ||
19 | |||
20 | this.BackendExtensions = backendExtensions; | ||
21 | } | ||
22 | |||
23 | private string CabCachePath { get; } | ||
24 | |||
25 | private IEnumerable<IWindowsInstallerBackendExtension> BackendExtensions { get; } | ||
26 | |||
27 | public ResolvedCabinet ResolveCabinet(string cabinetPath, IEnumerable<FileFacade> fileFacades) | ||
28 | { | ||
29 | var filesWithPath = fileFacades.Select(f => new BindFileWithPath() { Id = f.File.File, Path = f.WixFile.Source }).ToList(); | ||
30 | |||
31 | ResolvedCabinet resolved = null; | ||
32 | |||
33 | foreach (var extension in this.BackendExtensions) | ||
34 | { | ||
35 | resolved = extension.ResolveCabinet(cabinetPath, filesWithPath); | ||
36 | |||
37 | if (null != resolved) | ||
38 | { | ||
39 | return resolved; | ||
40 | } | ||
41 | } | ||
42 | |||
43 | // By default cabinet should be built and moved to the suggested location. | ||
44 | resolved = new ResolvedCabinet() { BuildOption = CabinetBuildOption.BuildAndMove, Path = cabinetPath }; | ||
45 | |||
46 | // If a cabinet cache path was provided, change the location for the cabinet | ||
47 | // to be built to and check if there is a cabinet that can be reused. | ||
48 | if (!String.IsNullOrEmpty(this.CabCachePath)) | ||
49 | { | ||
50 | string cabinetName = Path.GetFileName(cabinetPath); | ||
51 | resolved.Path = Path.Combine(this.CabCachePath, cabinetName); | ||
52 | |||
53 | if (CheckFileExists(resolved.Path)) | ||
54 | { | ||
55 | // Assume that none of the following are true: | ||
56 | // 1. any files are added or removed | ||
57 | // 2. order of files changed or names changed | ||
58 | // 3. modified time changed | ||
59 | bool cabinetValid = true; | ||
60 | |||
61 | // Need to force garbage collection of WixEnumerateCab to ensure the handle | ||
62 | // associated with it is closed before it is reused. | ||
63 | using (var wixEnumerateCab = new WixEnumerateCab()) | ||
64 | { | ||
65 | List<CabinetFileInfo> fileList = wixEnumerateCab.Enumerate(resolved.Path); | ||
66 | |||
67 | if (filesWithPath.Count() != fileList.Count) | ||
68 | { | ||
69 | cabinetValid = false; | ||
70 | } | ||
71 | else | ||
72 | { | ||
73 | int i = 0; | ||
74 | foreach (BindFileWithPath file in filesWithPath) | ||
75 | { | ||
76 | // First check that the file identifiers match because that is quick and easy. | ||
77 | CabinetFileInfo cabFileInfo = fileList[i]; | ||
78 | cabinetValid = (cabFileInfo.FileId == file.Id); | ||
79 | if (cabinetValid) | ||
80 | { | ||
81 | // Still valid so ensure the file sizes are the same. | ||
82 | FileInfo fileInfo = new FileInfo(file.Path); | ||
83 | cabinetValid = (cabFileInfo.Size == fileInfo.Length); | ||
84 | if (cabinetValid) | ||
85 | { | ||
86 | // Still valid so ensure the source time stamp hasn't changed. Thus we need | ||
87 | // to convert the source file time stamp into a cabinet compatible data/time. | ||
88 | Native.CabInterop.DateTimeToCabDateAndTime(fileInfo.LastWriteTime, out var sourceCabDate, out var sourceCabTime); | ||
89 | cabinetValid = (cabFileInfo.Date == sourceCabDate && cabFileInfo.Time == sourceCabTime); | ||
90 | } | ||
91 | } | ||
92 | |||
93 | if (!cabinetValid) | ||
94 | { | ||
95 | break; | ||
96 | } | ||
97 | |||
98 | i++; | ||
99 | } | ||
100 | } | ||
101 | } | ||
102 | |||
103 | resolved.BuildOption = cabinetValid ? CabinetBuildOption.Copy : CabinetBuildOption.BuildAndCopy; | ||
104 | } | ||
105 | } | ||
106 | |||
107 | return resolved; | ||
108 | } | ||
109 | |||
110 | private static bool CheckFileExists(string path) | ||
111 | { | ||
112 | try | ||
113 | { | ||
114 | return File.Exists(path); | ||
115 | } | ||
116 | catch (ArgumentException) | ||
117 | { | ||
118 | throw new WixException(WixErrors.IllegalCharactersInPath(path)); | ||
119 | } | ||
120 | } | ||
121 | } | ||
122 | } | ||
diff --git a/src/WixToolset.Core/Bind/Databases/CabinetWorkItem.cs b/src/WixToolset.Core.WindowsInstaller/Bind/CabinetWorkItem.cs index 20241bc9..dcafcd36 100644 --- a/src/WixToolset.Core/Bind/Databases/CabinetWorkItem.cs +++ b/src/WixToolset.Core.WindowsInstaller/Bind/CabinetWorkItem.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.Bind.Databases | 3 | namespace WixToolset.Core.WindowsInstaller.Databases |
4 | { | 4 | { |
5 | using System.Collections.Generic; | 5 | using System.Collections.Generic; |
6 | using WixToolset.Core.Bind; | ||
6 | using WixToolset.Data; | 7 | using WixToolset.Data; |
7 | using WixToolset.Data.Rows; | 8 | using WixToolset.Data.Rows; |
8 | 9 | ||
diff --git a/src/WixToolset.Core/Bind/Databases/ConfigurationCallback.cs b/src/WixToolset.Core.WindowsInstaller/Bind/ConfigurationCallback.cs index 7cb18e0f..d4d3799f 100644 --- a/src/WixToolset.Core/Bind/Databases/ConfigurationCallback.cs +++ b/src/WixToolset.Core.WindowsInstaller/Bind/ConfigurationCallback.cs | |||
@@ -1,6 +1,6 @@ | |||
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.Bind.Databases | 3 | namespace WixToolset.Core.WindowsInstaller.Databases |
4 | { | 4 | { |
5 | using System; | 5 | using System; |
6 | using System.Collections; | 6 | using System.Collections; |
diff --git a/src/WixToolset.Core/Bind/Databases/CopyTransformDataCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/CopyTransformDataCommand.cs index af1ab3b0..6388a352 100644 --- a/src/WixToolset.Core/Bind/Databases/CopyTransformDataCommand.cs +++ b/src/WixToolset.Core.WindowsInstaller/Bind/CopyTransformDataCommand.cs | |||
@@ -1,6 +1,6 @@ | |||
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.Bind.Databases | 3 | namespace WixToolset.Core.WindowsInstaller.Databases |
4 | { | 4 | { |
5 | using System; | 5 | using System; |
6 | using System.Collections.Generic; | 6 | using System.Collections.Generic; |
@@ -9,15 +9,14 @@ namespace WixToolset.Bind.Databases | |||
9 | using WixToolset.Data.Rows; | 9 | using WixToolset.Data.Rows; |
10 | using WixToolset.Extensibility; | 10 | using WixToolset.Extensibility; |
11 | using WixToolset.Core.Native; | 11 | using WixToolset.Core.Native; |
12 | using WixToolset.Core.Bind; | ||
12 | 13 | ||
13 | internal class CopyTransformDataCommand : ICommand | 14 | internal class CopyTransformDataCommand |
14 | { | 15 | { |
15 | public bool CopyOutFileRows { private get; set; } | 16 | public bool CopyOutFileRows { private get; set; } |
16 | 17 | ||
17 | public BinderFileManagerCore FileManagerCore { private get; set; } | 18 | public IEnumerable<IBinderExtension> Extensions { private get; set; } |
18 | 19 | ||
19 | public IEnumerable<IBinderFileManager> FileManagers { private get; set; } | ||
20 | |||
21 | public Output Output { private get; set; } | 20 | public Output Output { private get; set; } |
22 | 21 | ||
23 | public TableDefinitionCollection TableDefinitions { private get; set; } | 22 | public TableDefinitionCollection TableDefinitions { private get; set; } |
@@ -586,9 +585,10 @@ namespace WixToolset.Bind.Databases | |||
586 | private bool CompareFiles(string targetFile, string updatedFile) | 585 | private bool CompareFiles(string targetFile, string updatedFile) |
587 | { | 586 | { |
588 | bool? compared = null; | 587 | bool? compared = null; |
589 | foreach (IBinderFileManager fileManager in this.FileManagers) | 588 | foreach (var extension in this.Extensions) |
590 | { | 589 | { |
591 | compared = fileManager.CompareFiles(targetFile, updatedFile); | 590 | compared = extension.CompareFiles(targetFile, updatedFile); |
591 | |||
592 | if (compared.HasValue) | 592 | if (compared.HasValue) |
593 | { | 593 | { |
594 | break; | 594 | break; |
diff --git a/src/WixToolset.Core/Bind/Databases/CreateCabinetsCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/CreateCabinetsCommand.cs index 35c8abb4..02015744 100644 --- a/src/WixToolset.Core/Bind/Databases/CreateCabinetsCommand.cs +++ b/src/WixToolset.Core.WindowsInstaller/Bind/CreateCabinetsCommand.cs | |||
@@ -1,6 +1,6 @@ | |||
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.Bind.Databases | 3 | namespace WixToolset.Core.WindowsInstaller.Databases |
4 | { | 4 | { |
5 | using System; | 5 | using System; |
6 | using System.Collections.Generic; | 6 | using System.Collections.Generic; |
@@ -9,15 +9,21 @@ namespace WixToolset.Bind.Databases | |||
9 | using System.Linq; | 9 | using System.Linq; |
10 | using System.Runtime.InteropServices; | 10 | using System.Runtime.InteropServices; |
11 | using System.Threading; | 11 | using System.Threading; |
12 | using WixToolset.Core.Bind; | ||
13 | using WixToolset.Core.WindowsInstaller.Bind; | ||
12 | using WixToolset.Data; | 14 | using WixToolset.Data; |
15 | using WixToolset.Data.Bind; | ||
13 | using WixToolset.Data.Rows; | 16 | using WixToolset.Data.Rows; |
14 | using WixToolset.Extensibility; | 17 | using WixToolset.Extensibility; |
15 | 18 | ||
16 | /// <summary> | 19 | /// <summary> |
17 | /// Creates cabinet files. | 20 | /// Creates cabinet files. |
18 | /// </summary> | 21 | /// </summary> |
19 | internal class CreateCabinetsCommand : ICommand | 22 | internal class CreateCabinetsCommand |
20 | { | 23 | { |
24 | public const int DefaultMaximumUncompressedMediaSize = 200; // Default value is 200 MB | ||
25 | public const int MaxValueOfMaxCabSizeForLargeFileSplitting = 2 * 1024; // 2048 MB (i.e. 2 GB) | ||
26 | |||
21 | private List<FileTransfer> fileTransfers; | 27 | private List<FileTransfer> fileTransfers; |
22 | 28 | ||
23 | private FileSplitCabNamesCallback newCabNamesCallBack; | 29 | private FileSplitCabNamesCallback newCabNamesCallBack; |
@@ -28,7 +34,7 @@ namespace WixToolset.Bind.Databases | |||
28 | { | 34 | { |
29 | this.fileTransfers = new List<FileTransfer>(); | 35 | this.fileTransfers = new List<FileTransfer>(); |
30 | 36 | ||
31 | this.newCabNamesCallBack = NewCabNamesCallBack; | 37 | this.newCabNamesCallBack = this.NewCabNamesCallBack; |
32 | } | 38 | } |
33 | 39 | ||
34 | /// <summary> | 40 | /// <summary> |
@@ -36,6 +42,8 @@ namespace WixToolset.Bind.Databases | |||
36 | /// </summary> | 42 | /// </summary> |
37 | public int CabbingThreadCount { private get; set; } | 43 | public int CabbingThreadCount { private get; set; } |
38 | 44 | ||
45 | public string CabCachePath { private get; set; } | ||
46 | |||
39 | public string TempFilesLocation { private get; set; } | 47 | public string TempFilesLocation { private get; set; } |
40 | 48 | ||
41 | /// <summary> | 49 | /// <summary> |
@@ -44,9 +52,9 @@ namespace WixToolset.Bind.Databases | |||
44 | /// </summary> | 52 | /// </summary> |
45 | public CompressionLevel DefaultCompressionLevel { private get; set; } | 53 | public CompressionLevel DefaultCompressionLevel { private get; set; } |
46 | 54 | ||
47 | public Output Output { private get; set; } | 55 | public IEnumerable<IWindowsInstallerBackendExtension> BackendExtensions { private get; set; } |
48 | 56 | ||
49 | public IEnumerable<IBinderFileManager> FileManagers { private get; set; } | 57 | public Output Output { private get; set; } |
50 | 58 | ||
51 | public string LayoutDirectory { private get; set; } | 59 | public string LayoutDirectory { private get; set; } |
52 | 60 | ||
@@ -60,7 +68,7 @@ namespace WixToolset.Bind.Databases | |||
60 | 68 | ||
61 | public Table WixMediaTable { private get; set; } | 69 | public Table WixMediaTable { private get; set; } |
62 | 70 | ||
63 | public IEnumerable<FileTransfer> FileTransfers { get { return this.fileTransfers; } } | 71 | public IEnumerable<FileTransfer> FileTransfers => this.fileTransfers; |
64 | 72 | ||
65 | /// <param name="output">Output to generate image for.</param> | 73 | /// <param name="output">Output to generate image for.</param> |
66 | /// <param name="fileTransfers">Array of files to be transfered.</param> | 74 | /// <param name="fileTransfers">Array of files to be transfered.</param> |
@@ -204,7 +212,9 @@ namespace WixToolset.Bind.Databases | |||
204 | } | 212 | } |
205 | } | 213 | } |
206 | 214 | ||
207 | ResolvedCabinet resolvedCabinet = this.ResolveCabinet(tempCabinetFileX, fileFacades); | 215 | var cabinetResolver = new CabinetResolver(this.CabCachePath, this.BackendExtensions); |
216 | |||
217 | ResolvedCabinet resolvedCabinet = cabinetResolver.ResolveCabinet(tempCabinetFileX, fileFacades); | ||
208 | 218 | ||
209 | // create a cabinet work item if it's not being skipped | 219 | // create a cabinet work item if it's not being skipped |
210 | if (CabinetBuildOption.BuildAndCopy == resolvedCabinet.BuildOption || CabinetBuildOption.BuildAndMove == resolvedCabinet.BuildOption) | 220 | if (CabinetBuildOption.BuildAndCopy == resolvedCabinet.BuildOption || CabinetBuildOption.BuildAndMove == resolvedCabinet.BuildOption) |
@@ -255,23 +265,23 @@ namespace WixToolset.Bind.Databases | |||
255 | return cabinetWorkItem; | 265 | return cabinetWorkItem; |
256 | } | 266 | } |
257 | 267 | ||
258 | private ResolvedCabinet ResolveCabinet(string cabinetPath, IEnumerable<FileFacade> fileFacades) | 268 | //private ResolvedCabinet ResolveCabinet(string cabinetPath, IEnumerable<FileFacade> fileFacades) |
259 | { | 269 | //{ |
260 | ResolvedCabinet resolved = null; | 270 | // ResolvedCabinet resolved = null; |
261 | 271 | ||
262 | List<BindFileWithPath> filesWithPath = fileFacades.Select(f => new BindFileWithPath() { Id = f.File.File, Path = f.WixFile.Source }).ToList(); | 272 | // List<BindFileWithPath> filesWithPath = fileFacades.Select(f => new BindFileWithPath() { Id = f.File.File, Path = f.WixFile.Source }).ToList(); |
263 | 273 | ||
264 | foreach (IBinderFileManager fileManager in this.FileManagers) | 274 | // foreach (var extension in this.BackendExtensions) |
265 | { | 275 | // { |
266 | resolved = fileManager.ResolveCabinet(cabinetPath, filesWithPath); | 276 | // resolved = extension.ResolveCabinet(cabinetPath, filesWithPath); |
267 | if (null != resolved) | 277 | // if (null != resolved) |
268 | { | 278 | // { |
269 | break; | 279 | // break; |
270 | } | 280 | // } |
271 | } | 281 | // } |
272 | 282 | ||
273 | return resolved; | 283 | // return resolved; |
274 | } | 284 | //} |
275 | 285 | ||
276 | /// <summary> | 286 | /// <summary> |
277 | /// Delegate for Cabinet Split Callback | 287 | /// Delegate for Cabinet Split Callback |
@@ -451,7 +461,7 @@ namespace WixToolset.Bind.Databases | |||
451 | } | 461 | } |
452 | catch (OverflowException) | 462 | catch (OverflowException) |
453 | { | 463 | { |
454 | throw new WixException(WixErrors.MaximumCabinetSizeForLargeFileSplittingTooLarge(null, maxCabSizeForLargeFileInMB, CompilerCore.MaxValueOfMaxCabSizeForLargeFileSplitting)); | 464 | throw new WixException(WixErrors.MaximumCabinetSizeForLargeFileSplittingTooLarge(null, maxCabSizeForLargeFileInMB, MaxValueOfMaxCabSizeForLargeFileSplitting)); |
455 | } | 465 | } |
456 | 466 | ||
457 | try | 467 | try |
@@ -482,7 +492,7 @@ namespace WixToolset.Bind.Databases | |||
482 | else | 492 | else |
483 | { | 493 | { |
484 | maxCabSizeForLargeFileSplitting = 0; | 494 | maxCabSizeForLargeFileSplitting = 0; |
485 | maxUncompressedMediaSize = CompilerCore.DefaultMaximumUncompressedMediaSize; | 495 | maxUncompressedMediaSize = DefaultMaximumUncompressedMediaSize; |
486 | } | 496 | } |
487 | } | 497 | } |
488 | } | 498 | } |
diff --git a/src/WixToolset.Core/Bind/Databases/CreateDeltaPatchesCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/CreateDeltaPatchesCommand.cs index 933a1ea8..767671b8 100644 --- a/src/WixToolset.Core/Bind/Databases/CreateDeltaPatchesCommand.cs +++ b/src/WixToolset.Core.WindowsInstaller/Bind/CreateDeltaPatchesCommand.cs | |||
@@ -1,18 +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. | 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.Bind.Databases | 3 | namespace WixToolset.Core.WindowsInstaller.Databases |
4 | { | 4 | { |
5 | using System; | 5 | using System; |
6 | using System.Collections.Generic; | 6 | using System.Collections.Generic; |
7 | using System.Globalization; | 7 | using System.Globalization; |
8 | using System.IO; | 8 | using System.IO; |
9 | using WixToolset.Core.Bind; | ||
9 | using WixToolset.Data; | 10 | using WixToolset.Data; |
10 | using WixToolset.Data.Rows; | 11 | using WixToolset.Data.Rows; |
11 | 12 | ||
12 | /// <summary> | 13 | /// <summary> |
13 | /// Creates delta patches and updates the appropriate rows to point to the newly generated patches. | 14 | /// Creates delta patches and updates the appropriate rows to point to the newly generated patches. |
14 | /// </summary> | 15 | /// </summary> |
15 | internal class CreateDeltaPatchesCommand : ICommand | 16 | internal class CreateDeltaPatchesCommand |
16 | { | 17 | { |
17 | public IEnumerable<FileFacade> FileFacades { private get; set; } | 18 | public IEnumerable<FileFacade> FileFacades { private get; set; } |
18 | 19 | ||
@@ -23,7 +24,7 @@ namespace WixToolset.Bind.Databases | |||
23 | public void Execute() | 24 | public void Execute() |
24 | { | 25 | { |
25 | bool optimizePatchSizeForLargeFiles = false; | 26 | bool optimizePatchSizeForLargeFiles = false; |
26 | PatchAPI.PatchInterop.PatchSymbolFlagsType apiPatchingSymbolFlags = 0; | 27 | PatchSymbolFlagsType apiPatchingSymbolFlags = 0; |
27 | 28 | ||
28 | if (null != this.WixPatchIdTable) | 29 | if (null != this.WixPatchIdTable) |
29 | { | 30 | { |
@@ -37,7 +38,7 @@ namespace WixToolset.Bind.Databases | |||
37 | 38 | ||
38 | if (null != row[3]) | 39 | if (null != row[3]) |
39 | { | 40 | { |
40 | apiPatchingSymbolFlags = (PatchAPI.PatchInterop.PatchSymbolFlagsType)Convert.ToUInt32(row[3], CultureInfo.InvariantCulture); | 41 | apiPatchingSymbolFlags = (PatchSymbolFlagsType)Convert.ToUInt32(row[3], CultureInfo.InvariantCulture); |
41 | } | 42 | } |
42 | } | 43 | } |
43 | } | 44 | } |
diff --git a/src/WixToolset.Core/Bind/Databases/CreateSpecialPropertiesCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/CreateSpecialPropertiesCommand.cs index 5db2768b..aef130b0 100644 --- a/src/WixToolset.Core/Bind/Databases/CreateSpecialPropertiesCommand.cs +++ b/src/WixToolset.Core.WindowsInstaller/Bind/CreateSpecialPropertiesCommand.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.Bind.Databases | 3 | namespace WixToolset.Core.WindowsInstaller.Databases |
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.Data.Rows; | 8 | using WixToolset.Data.Rows; |
9 | 9 | ||
10 | internal class CreateSpecialPropertiesCommand : ICommand | 10 | internal class CreateSpecialPropertiesCommand |
11 | { | 11 | { |
12 | public Table PropertyTable { private get; set; } | 12 | public Table PropertyTable { private get; set; } |
13 | 13 | ||
diff --git a/src/WixToolset.Core/Bind/Databases/ExtractMergeModuleFilesCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/ExtractMergeModuleFilesCommand.cs index bee1488b..ae76037d 100644 --- a/src/WixToolset.Core/Bind/Databases/ExtractMergeModuleFilesCommand.cs +++ b/src/WixToolset.Core.WindowsInstaller/Bind/ExtractMergeModuleFilesCommand.cs | |||
@@ -1,6 +1,6 @@ | |||
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.Bind.Databases | 3 | namespace WixToolset.Core.WindowsInstaller.Databases |
4 | { | 4 | { |
5 | using System; | 5 | using System; |
6 | using System.Collections.Generic; | 6 | using System.Collections.Generic; |
@@ -9,17 +9,18 @@ namespace WixToolset.Bind.Databases | |||
9 | using System.IO; | 9 | using System.IO; |
10 | using System.Linq; | 10 | using System.Linq; |
11 | using System.Runtime.InteropServices; | 11 | using System.Runtime.InteropServices; |
12 | using WixToolset.Cab; | ||
13 | using WixToolset.Data; | 12 | using WixToolset.Data; |
14 | using WixToolset.Data.Rows; | 13 | using WixToolset.Data.Rows; |
15 | using WixToolset.MergeMod; | 14 | using WixToolset.MergeMod; |
16 | using WixToolset.Msi; | 15 | using WixToolset.Msi; |
17 | using WixToolset.Core.Native; | 16 | using WixToolset.Core.Native; |
17 | using WixToolset.Core.Bind; | ||
18 | using WixToolset.Core.Cab; | ||
18 | 19 | ||
19 | /// <summary> | 20 | /// <summary> |
20 | /// Retrieve files information and extract them from merge modules. | 21 | /// Retrieve files information and extract them from merge modules. |
21 | /// </summary> | 22 | /// </summary> |
22 | internal class ExtractMergeModuleFilesCommand : ICommand | 23 | internal class ExtractMergeModuleFilesCommand |
23 | { | 24 | { |
24 | public IEnumerable<FileFacade> FileFacades { private get; set; } | 25 | public IEnumerable<FileFacade> FileFacades { private get; set; } |
25 | 26 | ||
@@ -193,7 +194,7 @@ namespace WixToolset.Bind.Databases | |||
193 | string mergeIdPath = String.Concat(this.TempFilesLocation, Path.DirectorySeparatorChar, "MergeId.", safeMergeId); | 194 | string mergeIdPath = String.Concat(this.TempFilesLocation, Path.DirectorySeparatorChar, "MergeId.", safeMergeId); |
194 | Directory.CreateDirectory(mergeIdPath); | 195 | Directory.CreateDirectory(mergeIdPath); |
195 | 196 | ||
196 | using (WixExtractCab extractCab = new WixExtractCab()) | 197 | using (var extractCab = new WixExtractCab()) |
197 | { | 198 | { |
198 | try | 199 | try |
199 | { | 200 | { |
diff --git a/src/WixToolset.Core/Bind/GenerateDatabaseCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/GenerateDatabaseCommand.cs index fdf1ab32..26d254f2 100644 --- a/src/WixToolset.Core/Bind/GenerateDatabaseCommand.cs +++ b/src/WixToolset.Core.WindowsInstaller/Bind/GenerateDatabaseCommand.cs | |||
@@ -1,6 +1,6 @@ | |||
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.Bind | 3 | namespace WixToolset.Core.WindowsInstaller.Databases |
4 | { | 4 | { |
5 | using System; | 5 | using System; |
6 | using System.Collections.Generic; | 6 | using System.Collections.Generic; |
@@ -13,14 +13,12 @@ namespace WixToolset.Bind | |||
13 | using WixToolset.Msi; | 13 | using WixToolset.Msi; |
14 | using WixToolset.Core.Native; | 14 | using WixToolset.Core.Native; |
15 | 15 | ||
16 | internal class GenerateDatabaseCommand : ICommand | 16 | internal class GenerateDatabaseCommand |
17 | { | 17 | { |
18 | public int Codepage { private get; set; } | 18 | public int Codepage { private get; set; } |
19 | 19 | ||
20 | public IEnumerable<IBinderExtension> Extensions { private get; set; } | 20 | public IEnumerable<IBinderExtension> Extensions { private get; set; } |
21 | 21 | ||
22 | public IEnumerable<IBinderFileManager> FileManagers { private get; set; } | ||
23 | |||
24 | /// <summary> | 22 | /// <summary> |
25 | /// Whether to keep columns added in a transform. | 23 | /// Whether to keep columns added in a transform. |
26 | /// </summary> | 24 | /// </summary> |
@@ -295,7 +293,6 @@ namespace WixToolset.Bind | |||
295 | { | 293 | { |
296 | BindTransformCommand command = new BindTransformCommand(); | 294 | BindTransformCommand command = new BindTransformCommand(); |
297 | command.Extensions = this.Extensions; | 295 | command.Extensions = this.Extensions; |
298 | command.FileManagers = this.FileManagers; | ||
299 | command.TempFilesLocation = this.TempFilesLocation; | 296 | command.TempFilesLocation = this.TempFilesLocation; |
300 | command.Transform = transform; | 297 | command.Transform = transform; |
301 | command.OutputPath = outputPath; | 298 | command.OutputPath = outputPath; |
diff --git a/src/WixToolset.Core/Bind/Databases/GetFileFacadesCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/GetFileFacadesCommand.cs index b6bcd3af..caf8b7a7 100644 --- a/src/WixToolset.Core/Bind/Databases/GetFileFacadesCommand.cs +++ b/src/WixToolset.Core.WindowsInstaller/Bind/GetFileFacadesCommand.cs | |||
@@ -1,15 +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.Bind.Databases | 3 | namespace WixToolset.Core.WindowsInstaller.Databases |
4 | { | 4 | { |
5 | using System; | 5 | using System; |
6 | using System.Collections.Generic; | 6 | using System.Collections.Generic; |
7 | using System.Globalization; | 7 | using System.Globalization; |
8 | using System.Linq; | 8 | using System.Linq; |
9 | using WixToolset.Core.Bind; | ||
9 | using WixToolset.Data; | 10 | using WixToolset.Data; |
10 | using WixToolset.Data.Rows; | 11 | using WixToolset.Data.Rows; |
11 | 12 | ||
12 | internal class GetFileFacadesCommand : ICommand | 13 | internal class GetFileFacadesCommand |
13 | { | 14 | { |
14 | public Table FileTable { private get; set; } | 15 | public Table FileTable { private get; set; } |
15 | 16 | ||
diff --git a/src/WixToolset.Core/Bind/Databases/MergeModulesCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/MergeModulesCommand.cs index 035ef059..624cbb43 100644 --- a/src/WixToolset.Core/Bind/Databases/MergeModulesCommand.cs +++ b/src/WixToolset.Core.WindowsInstaller/Bind/MergeModulesCommand.cs | |||
@@ -1,6 +1,6 @@ | |||
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.Bind.Databases | 3 | namespace WixToolset.Core.WindowsInstaller.Databases |
4 | { | 4 | { |
5 | using System; | 5 | using System; |
6 | using System.Collections.Generic; | 6 | using System.Collections.Generic; |
@@ -20,11 +20,12 @@ namespace WixToolset.Bind.Databases | |||
20 | using WixToolset.MergeMod; | 20 | using WixToolset.MergeMod; |
21 | using WixToolset.Msi; | 21 | using WixToolset.Msi; |
22 | using WixToolset.Core.Native; | 22 | using WixToolset.Core.Native; |
23 | using WixToolset.Core.Bind; | ||
23 | 24 | ||
24 | /// <summary> | 25 | /// <summary> |
25 | /// Update file information. | 26 | /// Update file information. |
26 | /// </summary> | 27 | /// </summary> |
27 | internal class MergeModulesCommand : ICommand | 28 | internal class MergeModulesCommand |
28 | { | 29 | { |
29 | public IEnumerable<FileFacade> FileFacades { private get; set; } | 30 | public IEnumerable<FileFacade> FileFacades { private get; set; } |
30 | 31 | ||
diff --git a/src/WixToolset.Core/Bind/Databases/ProcessUncompressedFilesCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/ProcessUncompressedFilesCommand.cs index dd7b85b7..b3c09b9e 100644 --- a/src/WixToolset.Core/Bind/Databases/ProcessUncompressedFilesCommand.cs +++ b/src/WixToolset.Core.WindowsInstaller/Bind/ProcessUncompressedFilesCommand.cs | |||
@@ -1,6 +1,6 @@ | |||
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.Bind.Databases | 3 | namespace WixToolset.Core.WindowsInstaller.Databases |
4 | { | 4 | { |
5 | using System; | 5 | using System; |
6 | using System.Collections; | 6 | using System.Collections; |
@@ -10,11 +10,14 @@ namespace WixToolset.Bind.Databases | |||
10 | using WixToolset.Data.Rows; | 10 | using WixToolset.Data.Rows; |
11 | using WixToolset.Msi; | 11 | using WixToolset.Msi; |
12 | using WixToolset.Core.Native; | 12 | using WixToolset.Core.Native; |
13 | using WixToolset.Bind; | ||
14 | using WixToolset.Core.Bind; | ||
15 | using WixToolset.Data.Bind; | ||
13 | 16 | ||
14 | /// <summary> | 17 | /// <summary> |
15 | /// Defines the file transfers necessary to layout the uncompressed files. | 18 | /// Defines the file transfers necessary to layout the uncompressed files. |
16 | /// </summary> | 19 | /// </summary> |
17 | internal class ProcessUncompressedFilesCommand : ICommand | 20 | internal class ProcessUncompressedFilesCommand |
18 | { | 21 | { |
19 | public string DatabasePath { private get; set; } | 22 | public string DatabasePath { private get; set; } |
20 | 23 | ||
@@ -55,7 +58,7 @@ namespace WixToolset.Bind.Databases | |||
55 | break; | 58 | break; |
56 | } | 59 | } |
57 | 60 | ||
58 | string sourceName = Installer.GetName(directoryRecord.GetString(3), true, this.LongNamesInImage); | 61 | string sourceName = Common.GetName(directoryRecord.GetString(3), true, this.LongNamesInImage); |
59 | 62 | ||
60 | directories.Add(directoryRecord.GetString(1), new ResolvedDirectory(directoryRecord.GetString(2), sourceName)); | 63 | directories.Add(directoryRecord.GetString(1), new ResolvedDirectory(directoryRecord.GetString(2), sourceName)); |
61 | } | 64 | } |
diff --git a/src/WixToolset.Core/Bind/Databases/UpdateControlTextCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/UpdateControlTextCommand.cs index 9e17ee02..7da32206 100644 --- a/src/WixToolset.Core/Bind/Databases/UpdateControlTextCommand.cs +++ b/src/WixToolset.Core.WindowsInstaller/Bind/UpdateControlTextCommand.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.Bind.Databases | 3 | namespace WixToolset.Core.WindowsInstaller.Databases |
4 | { | 4 | { |
5 | using System; | 5 | using System; |
6 | using System.IO; | 6 | using System.IO; |
7 | using WixToolset.Data; | 7 | using WixToolset.Data; |
8 | using WixToolset.Data.Rows; | 8 | using WixToolset.Data.Rows; |
9 | 9 | ||
10 | internal class UpdateControlTextCommand : ICommand | 10 | internal class UpdateControlTextCommand |
11 | { | 11 | { |
12 | public Table BBControlTable { private get; set; } | 12 | public Table BBControlTable { private get; set; } |
13 | 13 | ||
diff --git a/src/WixToolset.Core/Bind/Databases/UpdateFileFacadesCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/UpdateFileFacadesCommand.cs index 36818afa..cd9444ee 100644 --- a/src/WixToolset.Core/Bind/Databases/UpdateFileFacadesCommand.cs +++ b/src/WixToolset.Core.WindowsInstaller/Bind/UpdateFileFacadesCommand.cs | |||
@@ -1,6 +1,6 @@ | |||
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.Bind.Databases | 3 | namespace WixToolset.Core.WindowsInstaller.Databases |
4 | { | 4 | { |
5 | using System; | 5 | using System; |
6 | using System.Collections.Generic; | 6 | using System.Collections.Generic; |
@@ -12,6 +12,7 @@ namespace WixToolset.Bind.Databases | |||
12 | using System.Xml; | 12 | using System.Xml; |
13 | using System.Xml.XPath; | 13 | using System.Xml.XPath; |
14 | using WixToolset.Clr.Interop; | 14 | using WixToolset.Clr.Interop; |
15 | using WixToolset.Core.Bind; | ||
15 | using WixToolset.Data; | 16 | using WixToolset.Data; |
16 | using WixToolset.Data.Rows; | 17 | using WixToolset.Data.Rows; |
17 | using WixToolset.Msi; | 18 | using WixToolset.Msi; |
@@ -19,7 +20,7 @@ namespace WixToolset.Bind.Databases | |||
19 | /// <summary> | 20 | /// <summary> |
20 | /// Update file information. | 21 | /// Update file information. |
21 | /// </summary> | 22 | /// </summary> |
22 | internal class UpdateFileFacadesCommand : ICommand | 23 | internal class UpdateFileFacadesCommand |
23 | { | 24 | { |
24 | public IEnumerable<FileFacade> FileFacades { private get; set; } | 25 | public IEnumerable<FileFacade> FileFacades { private get; set; } |
25 | 26 | ||
@@ -52,17 +53,17 @@ namespace WixToolset.Bind.Databases | |||
52 | } | 53 | } |
53 | catch (ArgumentException) | 54 | catch (ArgumentException) |
54 | { | 55 | { |
55 | Messaging.Instance.OnMessage(WixErrors.InvalidFileName(file.File.SourceLineNumbers, file.WixFile.Source)); | 56 | Messaging.Instance.OnMessage(WixDataErrors.InvalidFileName(file.File.SourceLineNumbers, file.WixFile.Source)); |
56 | return; | 57 | return; |
57 | } | 58 | } |
58 | catch (PathTooLongException) | 59 | catch (PathTooLongException) |
59 | { | 60 | { |
60 | Messaging.Instance.OnMessage(WixErrors.InvalidFileName(file.File.SourceLineNumbers, file.WixFile.Source)); | 61 | Messaging.Instance.OnMessage(WixDataErrors.InvalidFileName(file.File.SourceLineNumbers, file.WixFile.Source)); |
61 | return; | 62 | return; |
62 | } | 63 | } |
63 | catch (NotSupportedException) | 64 | catch (NotSupportedException) |
64 | { | 65 | { |
65 | Messaging.Instance.OnMessage(WixErrors.InvalidFileName(file.File.SourceLineNumbers, file.WixFile.Source)); | 66 | Messaging.Instance.OnMessage(WixDataErrors.InvalidFileName(file.File.SourceLineNumbers, file.WixFile.Source)); |
66 | return; | 67 | return; |
67 | } | 68 | } |
68 | 69 | ||
@@ -195,13 +196,13 @@ namespace WixToolset.Bind.Databases | |||
195 | { | 196 | { |
196 | if (!String.IsNullOrEmpty(file.File.Version)) | 197 | if (!String.IsNullOrEmpty(file.File.Version)) |
197 | { | 198 | { |
198 | string key = String.Format(CultureInfo.InvariantCulture, "fileversion.{0}", BindDatabaseCommand.Demodularize(this.Output.Type, this.ModularizationGuid, file.File.File)); | 199 | string key = String.Format(CultureInfo.InvariantCulture, "fileversion.{0}", Common.Demodularize(this.Output.Type, this.ModularizationGuid, file.File.File)); |
199 | this.VariableCache[key] = file.File.Version; | 200 | this.VariableCache[key] = file.File.Version; |
200 | } | 201 | } |
201 | 202 | ||
202 | if (!String.IsNullOrEmpty(file.File.Language)) | 203 | if (!String.IsNullOrEmpty(file.File.Language)) |
203 | { | 204 | { |
204 | string key = String.Format(CultureInfo.InvariantCulture, "filelanguage.{0}", BindDatabaseCommand.Demodularize(this.Output.Type, ModularizationGuid, file.File.File)); | 205 | string key = String.Format(CultureInfo.InvariantCulture, "filelanguage.{0}", Common.Demodularize(this.Output.Type, ModularizationGuid, file.File.File)); |
205 | this.VariableCache[key] = file.File.Language; | 206 | this.VariableCache[key] = file.File.Language; |
206 | } | 207 | } |
207 | } | 208 | } |
@@ -326,7 +327,7 @@ namespace WixToolset.Bind.Databases | |||
326 | // add the assembly name to the information cache | 327 | // add the assembly name to the information cache |
327 | if (null != this.VariableCache) | 328 | if (null != this.VariableCache) |
328 | { | 329 | { |
329 | string fileId = BindDatabaseCommand.Demodularize(this.Output.Type, this.ModularizationGuid, file.File.File); | 330 | string fileId = Common.Demodularize(this.Output.Type, this.ModularizationGuid, file.File.File); |
330 | string key = String.Concat("assemblyfullname.", fileId); | 331 | string key = String.Concat("assemblyfullname.", fileId); |
331 | string assemblyName = String.Concat(assemblyNameValues["name"], ", version=", assemblyNameValues["version"], ", culture=", assemblyNameValues["culture"], ", publicKeyToken=", String.IsNullOrEmpty(assemblyNameValues["publicKeyToken"]) ? "null" : assemblyNameValues["publicKeyToken"]); | 332 | string assemblyName = String.Concat(assemblyNameValues["name"], ", version=", assemblyNameValues["version"], ", culture=", assemblyNameValues["culture"], ", publicKeyToken=", String.IsNullOrEmpty(assemblyNameValues["publicKeyToken"]) ? "null" : assemblyNameValues["publicKeyToken"]); |
332 | if (assemblyNameValues.ContainsKey("processorArchitecture")) | 333 | if (assemblyNameValues.ContainsKey("processorArchitecture")) |
@@ -523,7 +524,7 @@ namespace WixToolset.Bind.Databases | |||
523 | 524 | ||
524 | if (this.VariableCache != null) | 525 | if (this.VariableCache != null) |
525 | { | 526 | { |
526 | string key = String.Format(CultureInfo.InvariantCulture, "assembly{0}.{1}", name, BindDatabaseCommand.Demodularize(this.Output.Type, this.ModularizationGuid, file.File.File)).ToLowerInvariant(); | 527 | string key = String.Format(CultureInfo.InvariantCulture, "assembly{0}.{1}", name, Common.Demodularize(this.Output.Type, this.ModularizationGuid, file.File.File)).ToLowerInvariant(); |
527 | this.VariableCache[key] = (string)assemblyNameRow[2]; | 528 | this.VariableCache[key] = (string)assemblyNameRow[2]; |
528 | } | 529 | } |
529 | } | 530 | } |
diff --git a/src/WixToolset.Core/CLR/Interop/CLRInterop.cs b/src/WixToolset.Core.WindowsInstaller/CLR/Interop/CLRInterop.cs index 4157f23a..4157f23a 100644 --- a/src/WixToolset.Core/CLR/Interop/CLRInterop.cs +++ b/src/WixToolset.Core.WindowsInstaller/CLR/Interop/CLRInterop.cs | |||
diff --git a/src/WixToolset.Core/Differ.cs b/src/WixToolset.Core.WindowsInstaller/Differ.cs index 71a64327..bdd06d32 100644 --- a/src/WixToolset.Core/Differ.cs +++ b/src/WixToolset.Core.WindowsInstaller/Differ.cs | |||
@@ -6,6 +6,7 @@ namespace WixToolset | |||
6 | using System.Collections; | 6 | using System.Collections; |
7 | using System.Collections.Generic; | 7 | using System.Collections.Generic; |
8 | using System.Globalization; | 8 | using System.Globalization; |
9 | using WixToolset.Core; | ||
9 | using WixToolset.Data; | 10 | using WixToolset.Data; |
10 | using WixToolset.Data.Rows; | 11 | using WixToolset.Data.Rows; |
11 | using WixToolset.Extensibility; | 12 | using WixToolset.Extensibility; |
@@ -155,17 +156,6 @@ namespace WixToolset | |||
155 | this.UpdateTransformSummaryInformationTable(summaryInfoTable, validationFlags); | 156 | this.UpdateTransformSummaryInformationTable(summaryInfoTable, validationFlags); |
156 | } | 157 | } |
157 | 158 | ||
158 | // inspect the transform | ||
159 | InspectorCore inspectorCore = new InspectorCore(); | ||
160 | foreach (InspectorExtension inspectorExtension in this.inspectorExtensions) | ||
161 | { | ||
162 | inspectorExtension.Core = inspectorCore; | ||
163 | inspectorExtension.InspectOutput(transform); | ||
164 | |||
165 | // reset | ||
166 | inspectorExtension.Core = null; | ||
167 | } | ||
168 | |||
169 | return transform; | 159 | return transform; |
170 | } | 160 | } |
171 | 161 | ||
diff --git a/src/WixToolset.Core.WindowsInstaller/Inscribe/InscribeMsiPackageCommand.cs b/src/WixToolset.Core.WindowsInstaller/Inscribe/InscribeMsiPackageCommand.cs new file mode 100644 index 00000000..40901d7c --- /dev/null +++ b/src/WixToolset.Core.WindowsInstaller/Inscribe/InscribeMsiPackageCommand.cs | |||
@@ -0,0 +1,282 @@ | |||
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.Inscribe | ||
4 | { | ||
5 | using System; | ||
6 | using System.Collections.Generic; | ||
7 | using System.Globalization; | ||
8 | using System.IO; | ||
9 | using System.Runtime.InteropServices; | ||
10 | using System.Security.Cryptography.X509Certificates; | ||
11 | using WixToolset.Core.Native; | ||
12 | using WixToolset.Data; | ||
13 | using WixToolset.Extensibility; | ||
14 | using WixToolset.Msi; | ||
15 | |||
16 | internal class InscribeMsiPackageCommand | ||
17 | { | ||
18 | public InscribeMsiPackageCommand(IInscribeContext context) | ||
19 | { | ||
20 | this.Context = context; | ||
21 | this.TableDefinitions = WindowsInstallerStandard.GetTableDefinitions(); | ||
22 | } | ||
23 | |||
24 | private IInscribeContext Context { get; } | ||
25 | |||
26 | private TableDefinitionCollection TableDefinitions { get; } | ||
27 | |||
28 | public bool Execute() | ||
29 | { | ||
30 | // Keeps track of whether we've encountered at least one signed cab or not - we'll throw a warning if no signed cabs were encountered | ||
31 | bool foundUnsignedExternals = false; | ||
32 | bool shouldCommit = false; | ||
33 | |||
34 | FileAttributes attributes = File.GetAttributes(this.Context.InputFilePath); | ||
35 | if (FileAttributes.ReadOnly == (attributes & FileAttributes.ReadOnly)) | ||
36 | { | ||
37 | this.Context.Messaging.OnMessage(WixErrors.ReadOnlyOutputFile(this.Context.InputFilePath)); | ||
38 | return shouldCommit; | ||
39 | } | ||
40 | |||
41 | using (Database database = new Database(this.Context.InputFilePath, OpenDatabase.Transact)) | ||
42 | { | ||
43 | // Just use the English codepage, because the tables we're importing only have binary streams / MSI identifiers / other non-localizable content | ||
44 | int codepage = 1252; | ||
45 | |||
46 | // list of certificates for this database (hash/identifier) | ||
47 | Dictionary<string, string> certificates = new Dictionary<string, string>(); | ||
48 | |||
49 | // Reset the in-memory tables for this new database | ||
50 | Table digitalSignatureTable = new Table(null, this.TableDefinitions["MsiDigitalSignature"]); | ||
51 | Table digitalCertificateTable = new Table(null, this.TableDefinitions["MsiDigitalCertificate"]); | ||
52 | |||
53 | // If any digital signature records exist that are not of the media type, preserve them | ||
54 | if (database.TableExists("MsiDigitalSignature")) | ||
55 | { | ||
56 | using (View digitalSignatureView = database.OpenExecuteView("SELECT `Table`, `SignObject`, `DigitalCertificate_`, `Hash` FROM `MsiDigitalSignature` WHERE `Table` <> 'Media'")) | ||
57 | { | ||
58 | while (true) | ||
59 | { | ||
60 | using (Record digitalSignatureRecord = digitalSignatureView.Fetch()) | ||
61 | { | ||
62 | if (null == digitalSignatureRecord) | ||
63 | { | ||
64 | break; | ||
65 | } | ||
66 | |||
67 | Row digitalSignatureRow = null; | ||
68 | digitalSignatureRow = digitalSignatureTable.CreateRow(null); | ||
69 | |||
70 | string table = digitalSignatureRecord.GetString(0); | ||
71 | string signObject = digitalSignatureRecord.GetString(1); | ||
72 | |||
73 | digitalSignatureRow[0] = table; | ||
74 | digitalSignatureRow[1] = signObject; | ||
75 | digitalSignatureRow[2] = digitalSignatureRecord.GetString(2); | ||
76 | |||
77 | if (false == digitalSignatureRecord.IsNull(3)) | ||
78 | { | ||
79 | // Export to a file, because the MSI API's require us to provide a file path on disk | ||
80 | string hashPath = Path.Combine(this.Context.IntermediateFolder, "MsiDigitalSignature"); | ||
81 | string hashFileName = string.Concat(table, ".", signObject, ".bin"); | ||
82 | |||
83 | Directory.CreateDirectory(hashPath); | ||
84 | hashPath = Path.Combine(hashPath, hashFileName); | ||
85 | |||
86 | using (FileStream fs = File.Create(hashPath)) | ||
87 | { | ||
88 | int bytesRead; | ||
89 | byte[] buffer = new byte[1024 * 4]; | ||
90 | |||
91 | while (0 != (bytesRead = digitalSignatureRecord.GetStream(3, buffer, buffer.Length))) | ||
92 | { | ||
93 | fs.Write(buffer, 0, bytesRead); | ||
94 | } | ||
95 | } | ||
96 | |||
97 | digitalSignatureRow[3] = hashFileName; | ||
98 | } | ||
99 | } | ||
100 | } | ||
101 | } | ||
102 | } | ||
103 | |||
104 | // If any digital certificates exist, extract and preserve them | ||
105 | if (database.TableExists("MsiDigitalCertificate")) | ||
106 | { | ||
107 | using (View digitalCertificateView = database.OpenExecuteView("SELECT * FROM `MsiDigitalCertificate`")) | ||
108 | { | ||
109 | while (true) | ||
110 | { | ||
111 | using (Record digitalCertificateRecord = digitalCertificateView.Fetch()) | ||
112 | { | ||
113 | if (null == digitalCertificateRecord) | ||
114 | { | ||
115 | break; | ||
116 | } | ||
117 | |||
118 | string certificateId = digitalCertificateRecord.GetString(1); // get the identifier of the certificate | ||
119 | |||
120 | // Export to a file, because the MSI API's require us to provide a file path on disk | ||
121 | string certPath = Path.Combine(this.Context.IntermediateFolder, "MsiDigitalCertificate"); | ||
122 | Directory.CreateDirectory(certPath); | ||
123 | certPath = Path.Combine(certPath, string.Concat(certificateId, ".cer")); | ||
124 | |||
125 | using (FileStream fs = File.Create(certPath)) | ||
126 | { | ||
127 | int bytesRead; | ||
128 | byte[] buffer = new byte[1024 * 4]; | ||
129 | |||
130 | while (0 != (bytesRead = digitalCertificateRecord.GetStream(2, buffer, buffer.Length))) | ||
131 | { | ||
132 | fs.Write(buffer, 0, bytesRead); | ||
133 | } | ||
134 | } | ||
135 | |||
136 | // Add it to our "add to MsiDigitalCertificate" table dictionary | ||
137 | Row digitalCertificateRow = digitalCertificateTable.CreateRow(null); | ||
138 | digitalCertificateRow[0] = certificateId; | ||
139 | |||
140 | // Now set the file path on disk where this binary stream will be picked up at import time | ||
141 | digitalCertificateRow[1] = string.Concat(certificateId, ".cer"); | ||
142 | |||
143 | // Load the cert to get it's thumbprint | ||
144 | X509Certificate cert = X509Certificate.CreateFromCertFile(certPath); | ||
145 | X509Certificate2 cert2 = new X509Certificate2(cert); | ||
146 | |||
147 | certificates.Add(cert2.Thumbprint, certificateId); | ||
148 | } | ||
149 | } | ||
150 | } | ||
151 | } | ||
152 | |||
153 | using (View mediaView = database.OpenExecuteView("SELECT * FROM `Media`")) | ||
154 | { | ||
155 | while (true) | ||
156 | { | ||
157 | using (Record mediaRecord = mediaView.Fetch()) | ||
158 | { | ||
159 | if (null == mediaRecord) | ||
160 | { | ||
161 | break; | ||
162 | } | ||
163 | |||
164 | X509Certificate2 cert2 = null; | ||
165 | Row digitalSignatureRow = null; | ||
166 | |||
167 | string cabName = mediaRecord.GetString(4); // get the name of the cab | ||
168 | // If there is no cabinet or it's an internal cab, skip it. | ||
169 | if (String.IsNullOrEmpty(cabName) || cabName.StartsWith("#", StringComparison.Ordinal)) | ||
170 | { | ||
171 | continue; | ||
172 | } | ||
173 | |||
174 | string cabId = mediaRecord.GetString(1); // get the ID of the cab | ||
175 | string cabPath = Path.Combine(Path.GetDirectoryName(this.Context.InputFilePath), cabName); | ||
176 | |||
177 | // If the cabs aren't there, throw an error but continue to catch the other errors | ||
178 | if (!File.Exists(cabPath)) | ||
179 | { | ||
180 | this.Context.Messaging.OnMessage(WixErrors.WixFileNotFound(cabPath)); | ||
181 | continue; | ||
182 | } | ||
183 | |||
184 | try | ||
185 | { | ||
186 | // Get the certificate from the cab | ||
187 | X509Certificate signedFileCert = X509Certificate.CreateFromSignedFile(cabPath); | ||
188 | cert2 = new X509Certificate2(signedFileCert); | ||
189 | } | ||
190 | catch (System.Security.Cryptography.CryptographicException e) | ||
191 | { | ||
192 | uint HResult = unchecked((uint)Marshal.GetHRForException(e)); | ||
193 | |||
194 | // If the file has no cert, continue, but flag that we found at least one so we can later give a warning | ||
195 | if (0x80092009 == HResult) // CRYPT_E_NO_MATCH | ||
196 | { | ||
197 | foundUnsignedExternals = true; | ||
198 | continue; | ||
199 | } | ||
200 | |||
201 | // todo: exactly which HRESULT corresponds to this issue? | ||
202 | // If it's one of these exact platforms, warn the user that it may be due to their OS. | ||
203 | if ((5 == Environment.OSVersion.Version.Major && 2 == Environment.OSVersion.Version.Minor) || // W2K3 | ||
204 | (5 == Environment.OSVersion.Version.Major && 1 == Environment.OSVersion.Version.Minor)) // XP | ||
205 | { | ||
206 | this.Context.Messaging.OnMessage(WixErrors.UnableToGetAuthenticodeCertOfFileDownlevelOS(cabPath, String.Format(CultureInfo.InvariantCulture, "HRESULT: 0x{0:x8}", HResult))); | ||
207 | } | ||
208 | else // otherwise, generic error | ||
209 | { | ||
210 | this.Context.Messaging.OnMessage(WixErrors.UnableToGetAuthenticodeCertOfFile(cabPath, String.Format(CultureInfo.InvariantCulture, "HRESULT: 0x{0:x8}", HResult))); | ||
211 | } | ||
212 | } | ||
213 | |||
214 | // If we haven't added this cert to the MsiDigitalCertificate table, set it up to be added | ||
215 | if (!certificates.ContainsKey(cert2.Thumbprint)) | ||
216 | { | ||
217 | // generate a stable identifier | ||
218 | string certificateGeneratedId = Common.GenerateIdentifier("cer", cert2.Thumbprint); | ||
219 | |||
220 | // Add it to our "add to MsiDigitalCertificate" table dictionary | ||
221 | Row digitalCertificateRow = digitalCertificateTable.CreateRow(null); | ||
222 | digitalCertificateRow[0] = certificateGeneratedId; | ||
223 | |||
224 | // Export to a file, because the MSI API's require us to provide a file path on disk | ||
225 | string certPath = Path.Combine(this.Context.IntermediateFolder, "MsiDigitalCertificate"); | ||
226 | Directory.CreateDirectory(certPath); | ||
227 | certPath = Path.Combine(certPath, string.Concat(cert2.Thumbprint, ".cer")); | ||
228 | File.Delete(certPath); | ||
229 | |||
230 | using (BinaryWriter writer = new BinaryWriter(File.Open(certPath, FileMode.Create))) | ||
231 | { | ||
232 | writer.Write(cert2.RawData); | ||
233 | writer.Close(); | ||
234 | } | ||
235 | |||
236 | // Now set the file path on disk where this binary stream will be picked up at import time | ||
237 | digitalCertificateRow[1] = string.Concat(cert2.Thumbprint, ".cer"); | ||
238 | |||
239 | certificates.Add(cert2.Thumbprint, certificateGeneratedId); | ||
240 | } | ||
241 | |||
242 | digitalSignatureRow = digitalSignatureTable.CreateRow(null); | ||
243 | |||
244 | digitalSignatureRow[0] = "Media"; | ||
245 | digitalSignatureRow[1] = cabId; | ||
246 | digitalSignatureRow[2] = certificates[cert2.Thumbprint]; | ||
247 | } | ||
248 | } | ||
249 | } | ||
250 | |||
251 | if (digitalCertificateTable.Rows.Count > 0) | ||
252 | { | ||
253 | database.ImportTable(codepage, digitalCertificateTable, this.Context.IntermediateFolder, true); | ||
254 | shouldCommit = true; | ||
255 | } | ||
256 | |||
257 | if (digitalSignatureTable.Rows.Count > 0) | ||
258 | { | ||
259 | database.ImportTable(codepage, digitalSignatureTable, this.Context.IntermediateFolder, true); | ||
260 | shouldCommit = true; | ||
261 | } | ||
262 | |||
263 | // TODO: if we created the table(s), then we should add the _Validation records for them. | ||
264 | |||
265 | certificates = null; | ||
266 | |||
267 | // If we did find external cabs but none of them were signed, give a warning | ||
268 | if (foundUnsignedExternals) | ||
269 | { | ||
270 | this.Context.Messaging.OnMessage(WixWarnings.ExternalCabsAreNotSigned(this.Context.InputFilePath)); | ||
271 | } | ||
272 | |||
273 | if (shouldCommit) | ||
274 | { | ||
275 | database.Commit(); | ||
276 | } | ||
277 | } | ||
278 | |||
279 | return shouldCommit; | ||
280 | } | ||
281 | } | ||
282 | } | ||
diff --git a/src/WixToolset.Core/MergeMod/NativeMethods.cs b/src/WixToolset.Core.WindowsInstaller/MergeMod/NativeMethods.cs index daf259b4..daf259b4 100644 --- a/src/WixToolset.Core/MergeMod/NativeMethods.cs +++ b/src/WixToolset.Core.WindowsInstaller/MergeMod/NativeMethods.cs | |||
diff --git a/src/WixToolset.Core/Msi/Database.cs b/src/WixToolset.Core.WindowsInstaller/Msi/Database.cs index 801ebdde..801ebdde 100644 --- a/src/WixToolset.Core/Msi/Database.cs +++ b/src/WixToolset.Core.WindowsInstaller/Msi/Database.cs | |||
diff --git a/src/WixToolset.Core/Msi/Installer.cs b/src/WixToolset.Core.WindowsInstaller/Msi/Installer.cs index 3beb26f4..f8bce602 100644 --- a/src/WixToolset.Core/Msi/Installer.cs +++ b/src/WixToolset.Core.WindowsInstaller/Msi/Installer.cs | |||
@@ -359,126 +359,5 @@ namespace WixToolset.Msi | |||
359 | { | 359 | { |
360 | return MsiInterop.MsiSetInternalUI(uiLevel, ref hwnd); | 360 | return MsiInterop.MsiSetInternalUI(uiLevel, ref hwnd); |
361 | } | 361 | } |
362 | |||
363 | /// <summary> | ||
364 | /// Get the source/target and short/long file names from an MSI Filename column. | ||
365 | /// </summary> | ||
366 | /// <param name="value">The Filename value.</param> | ||
367 | /// <returns>An array of strings of length 4. The contents are: short target, long target, short source, and long source.</returns> | ||
368 | /// <remarks> | ||
369 | /// If any particular file name part is not parsed, its set to null in the appropriate location of the returned array of strings. | ||
370 | /// However, the returned array will always be of length 4. | ||
371 | /// </remarks> | ||
372 | internal static string[] GetNames(string value) | ||
373 | { | ||
374 | string[] names = new string[4]; | ||
375 | int targetSeparator = value.IndexOf(":", StringComparison.Ordinal); | ||
376 | |||
377 | // split source and target | ||
378 | string sourceName = null; | ||
379 | string targetName = value; | ||
380 | if (0 <= targetSeparator) | ||
381 | { | ||
382 | sourceName = value.Substring(targetSeparator + 1); | ||
383 | targetName = value.Substring(0, targetSeparator); | ||
384 | } | ||
385 | |||
386 | // split the source short and long names | ||
387 | string sourceLongName = null; | ||
388 | if (null != sourceName) | ||
389 | { | ||
390 | int sourceLongNameSeparator = sourceName.IndexOf("|", StringComparison.Ordinal); | ||
391 | if (0 <= sourceLongNameSeparator) | ||
392 | { | ||
393 | sourceLongName = sourceName.Substring(sourceLongNameSeparator + 1); | ||
394 | sourceName = sourceName.Substring(0, sourceLongNameSeparator); | ||
395 | } | ||
396 | } | ||
397 | |||
398 | // split the target short and long names | ||
399 | int targetLongNameSeparator = targetName.IndexOf("|", StringComparison.Ordinal); | ||
400 | string targetLongName = null; | ||
401 | if (0 <= targetLongNameSeparator) | ||
402 | { | ||
403 | targetLongName = targetName.Substring(targetLongNameSeparator + 1); | ||
404 | targetName = targetName.Substring(0, targetLongNameSeparator); | ||
405 | } | ||
406 | |||
407 | // remove the long source name when its identical to the long source name | ||
408 | if (null != sourceName && sourceName == sourceLongName) | ||
409 | { | ||
410 | sourceLongName = null; | ||
411 | } | ||
412 | |||
413 | // remove the long target name when its identical to the long target name | ||
414 | if (null != targetName && targetName == targetLongName) | ||
415 | { | ||
416 | targetLongName = null; | ||
417 | } | ||
418 | |||
419 | // remove the source names when they are identical to the target names | ||
420 | if (sourceName == targetName && sourceLongName == targetLongName) | ||
421 | { | ||
422 | sourceName = null; | ||
423 | sourceLongName = null; | ||
424 | } | ||
425 | |||
426 | // target name(s) | ||
427 | if ("." != targetName) | ||
428 | { | ||
429 | names[0] = targetName; | ||
430 | } | ||
431 | |||
432 | if (null != targetLongName && "." != targetLongName) | ||
433 | { | ||
434 | names[1] = targetLongName; | ||
435 | } | ||
436 | |||
437 | // source name(s) | ||
438 | if (null != sourceName) | ||
439 | { | ||
440 | names[2] = sourceName; | ||
441 | } | ||
442 | |||
443 | if (null != sourceLongName && "." != sourceLongName) | ||
444 | { | ||
445 | names[3] = sourceLongName; | ||
446 | } | ||
447 | |||
448 | return names; | ||
449 | } | ||
450 | |||
451 | /// <summary> | ||
452 | /// Get a source/target and short/long file name from an MSI Filename column. | ||
453 | /// </summary> | ||
454 | /// <param name="value">The Filename value.</param> | ||
455 | /// <param name="source">true to get a source name; false to get a target name</param> | ||
456 | /// <param name="longName">true to get a long name; false to get a short name</param> | ||
457 | /// <returns>The name.</returns> | ||
458 | internal static string GetName(string value, bool source, bool longName) | ||
459 | { | ||
460 | string[] names = GetNames(value); | ||
461 | |||
462 | if (source) | ||
463 | { | ||
464 | if (longName && null != names[3]) | ||
465 | { | ||
466 | return names[3]; | ||
467 | } | ||
468 | else if (null != names[2]) | ||
469 | { | ||
470 | return names[2]; | ||
471 | } | ||
472 | } | ||
473 | |||
474 | if (longName && null != names[1]) | ||
475 | { | ||
476 | return names[1]; | ||
477 | } | ||
478 | else | ||
479 | { | ||
480 | return names[0]; | ||
481 | } | ||
482 | } | ||
483 | } | 362 | } |
484 | } | 363 | } |
diff --git a/src/WixToolset.Core/Msi/Interop/MsiInterop.cs b/src/WixToolset.Core.WindowsInstaller/Msi/Interop/MsiInterop.cs index 054289ee..054289ee 100644 --- a/src/WixToolset.Core/Msi/Interop/MsiInterop.cs +++ b/src/WixToolset.Core.WindowsInstaller/Msi/Interop/MsiInterop.cs | |||
diff --git a/src/WixToolset.Core/Msi/MsiException.cs b/src/WixToolset.Core.WindowsInstaller/Msi/MsiException.cs index b33bf27a..b33bf27a 100644 --- a/src/WixToolset.Core/Msi/MsiException.cs +++ b/src/WixToolset.Core.WindowsInstaller/Msi/MsiException.cs | |||
diff --git a/src/WixToolset.Core/Msi/MsiHandle.cs b/src/WixToolset.Core.WindowsInstaller/Msi/MsiHandle.cs index 6d2dc984..6d2dc984 100644 --- a/src/WixToolset.Core/Msi/MsiHandle.cs +++ b/src/WixToolset.Core.WindowsInstaller/Msi/MsiHandle.cs | |||
diff --git a/src/WixToolset.Core/Msi/Record.cs b/src/WixToolset.Core.WindowsInstaller/Msi/Record.cs index 438aa3b0..438aa3b0 100644 --- a/src/WixToolset.Core/Msi/Record.cs +++ b/src/WixToolset.Core.WindowsInstaller/Msi/Record.cs | |||
diff --git a/src/WixToolset.Core/Msi/Session.cs b/src/WixToolset.Core.WindowsInstaller/Msi/Session.cs index d3a19711..d3a19711 100644 --- a/src/WixToolset.Core/Msi/Session.cs +++ b/src/WixToolset.Core.WindowsInstaller/Msi/Session.cs | |||
diff --git a/src/WixToolset.Core/Msi/SummaryInformation.cs b/src/WixToolset.Core.WindowsInstaller/Msi/SummaryInformation.cs index 39949db6..26831731 100644 --- a/src/WixToolset.Core/Msi/SummaryInformation.cs +++ b/src/WixToolset.Core.WindowsInstaller/Msi/SummaryInformation.cs | |||
@@ -3,11 +3,8 @@ | |||
3 | namespace WixToolset.Msi | 3 | namespace WixToolset.Msi |
4 | { | 4 | { |
5 | using System; | 5 | using System; |
6 | using System.ComponentModel; | ||
7 | using System.Diagnostics.CodeAnalysis; | ||
8 | using System.Globalization; | 6 | using System.Globalization; |
9 | using System.Text; | 7 | using System.Text; |
10 | using System.Runtime.InteropServices; | ||
11 | using FILETIME = System.Runtime.InteropServices.ComTypes.FILETIME; | 8 | using FILETIME = System.Runtime.InteropServices.ComTypes.FILETIME; |
12 | using WixToolset.Core.Native; | 9 | using WixToolset.Core.Native; |
13 | 10 | ||
@@ -245,79 +242,4 @@ namespace WixToolset.Msi | |||
245 | } | 242 | } |
246 | } | 243 | } |
247 | } | 244 | } |
248 | |||
249 | /// <summary> | ||
250 | /// Summary information values for the CharCount property in transforms. | ||
251 | /// </summary> | ||
252 | [Flags] | ||
253 | [SuppressMessage("Microsoft.Naming", "CA1711:IdentifiersShouldNotHaveIncorrectSuffix")] | ||
254 | public enum TransformFlags | ||
255 | { | ||
256 | /// <summary>Ignore error when adding a row that exists.</summary> | ||
257 | ErrorAddExistingRow = 0x1, | ||
258 | |||
259 | /// <summary>Ignore error when deleting a row that does not exist.</summary> | ||
260 | ErrorDeleteMissingRow = 0x2, | ||
261 | |||
262 | /// <summary>Ignore error when adding a table that exists. </summary> | ||
263 | ErrorAddExistingTable = 0x4, | ||
264 | |||
265 | /// <summary>Ignore error when deleting a table that does not exist. </summary> | ||
266 | ErrorDeleteMissingTable = 0x8, | ||
267 | |||
268 | /// <summary>Ignore error when updating a row that does not exist. </summary> | ||
269 | ErrorUpdateMissingRow = 0x10, | ||
270 | |||
271 | /// <summary>Ignore error when transform and database code pages do not match, and their code pages are neutral.</summary> | ||
272 | ErrorChangeCodePage = 0x20, | ||
273 | |||
274 | /// <summary>Default language must match base database. </summary> | ||
275 | ValidateLanguage = 0x10000, | ||
276 | |||
277 | /// <summary>Product must match base database.</summary> | ||
278 | ValidateProduct = 0x20000, | ||
279 | |||
280 | /// <summary>Check major version only. </summary> | ||
281 | ValidateMajorVersion = 0x80000, | ||
282 | |||
283 | /// <summary>Check major and minor versions only. </summary> | ||
284 | ValidateMinorVersion = 0x100000, | ||
285 | |||
286 | /// <summary>Check major, minor, and update versions.</summary> | ||
287 | ValidateUpdateVersion = 0x200000, | ||
288 | |||
289 | /// <summary>Installed version lt base version. </summary> | ||
290 | ValidateNewLessBaseVersion = 0x400000, | ||
291 | |||
292 | /// <summary>Installed version lte base version. </summary> | ||
293 | ValidateNewLessEqualBaseVersion = 0x800000, | ||
294 | |||
295 | /// <summary>Installed version eq base version. </summary> | ||
296 | ValidateNewEqualBaseVersion = 0x1000000, | ||
297 | |||
298 | /// <summary>Installed version gte base version.</summary> | ||
299 | ValidateNewGreaterEqualBaseVersion = 0x2000000, | ||
300 | |||
301 | /// <summary>Installed version gt base version.</summary> | ||
302 | ValidateNewGreaterBaseVersion = 0x4000000, | ||
303 | |||
304 | /// <summary>UpgradeCode must match base database.</summary> | ||
305 | ValidateUpgradeCode = 0x8000000, | ||
306 | |||
307 | /// <summary>Masks all version checks on ProductVersion.</summary> | ||
308 | ProductVersionMask = ValidateMajorVersion | ValidateMinorVersion | ValidateUpdateVersion, | ||
309 | |||
310 | /// <summary>Masks all operations on ProductVersion.</summary> | ||
311 | ProductVersionOperatorMask = ValidateNewLessBaseVersion | ValidateNewLessEqualBaseVersion | ValidateNewEqualBaseVersion | ValidateNewGreaterEqualBaseVersion | ValidateNewGreaterBaseVersion, | ||
312 | |||
313 | /// <summary>Default value for instance transforms.</summary> | ||
314 | InstanceTransformDefault = ErrorAddExistingRow | ErrorDeleteMissingRow | ErrorAddExistingTable | ErrorDeleteMissingTable | ErrorUpdateMissingRow | ErrorChangeCodePage | ValidateProduct | ValidateUpdateVersion | ValidateNewGreaterEqualBaseVersion, | ||
315 | |||
316 | /// <summary>Default value for language transforms.</summary> | ||
317 | LanguageTransformDefault = ErrorAddExistingRow | ErrorDeleteMissingRow | ErrorAddExistingTable | ErrorDeleteMissingTable | ErrorUpdateMissingRow | ErrorChangeCodePage | ValidateProduct, | ||
318 | |||
319 | /// <summary>Default value for patch transforms.</summary> | ||
320 | PatchTransformDefault = ErrorAddExistingRow | ErrorDeleteMissingRow | ErrorAddExistingTable | ErrorDeleteMissingTable | ErrorUpdateMissingRow | ValidateProduct | ValidateUpdateVersion | ValidateNewEqualBaseVersion | ValidateUpgradeCode, | ||
321 | } | ||
322 | |||
323 | } | 245 | } |
diff --git a/src/WixToolset.Core/Msi/View.cs b/src/WixToolset.Core.WindowsInstaller/Msi/View.cs index d6542824..d6542824 100644 --- a/src/WixToolset.Core/Msi/View.cs +++ b/src/WixToolset.Core.WindowsInstaller/Msi/View.cs | |||
diff --git a/src/WixToolset.Core.WindowsInstaller/MsiBackend.cs b/src/WixToolset.Core.WindowsInstaller/MsiBackend.cs new file mode 100644 index 00000000..716ea000 --- /dev/null +++ b/src/WixToolset.Core.WindowsInstaller/MsiBackend.cs | |||
@@ -0,0 +1,36 @@ | |||
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 | ||
4 | { | ||
5 | using WixToolset.Core.WindowsInstaller.Bind; | ||
6 | using WixToolset.Core.WindowsInstaller.Inscribe; | ||
7 | using WixToolset.Core.WindowsInstaller.Unbind; | ||
8 | using WixToolset.Data; | ||
9 | using WixToolset.Data.Bind; | ||
10 | using WixToolset.Extensibility; | ||
11 | |||
12 | internal class MsiBackend : IBackend | ||
13 | { | ||
14 | public BindResult Bind(IBindContext context) | ||
15 | { | ||
16 | var validator = Validator.CreateFromContext(context, "darice.cub"); | ||
17 | |||
18 | var command = new BindDatabaseCommand(context, validator); | ||
19 | command.Execute(); | ||
20 | |||
21 | return new BindResult(command.FileTransfers, command.ContentFilePaths); | ||
22 | } | ||
23 | |||
24 | public bool Inscribe(IInscribeContext context) | ||
25 | { | ||
26 | var command = new InscribeMsiPackageCommand(context); | ||
27 | return command.Execute(); | ||
28 | } | ||
29 | |||
30 | public Output Unbind(IUnbindContext context) | ||
31 | { | ||
32 | var command = new UnbindMsiOrMsmCommand(context); | ||
33 | return command.Execute(); | ||
34 | } | ||
35 | } | ||
36 | } | ||
diff --git a/src/WixToolset.Core.WindowsInstaller/MsmBackend.cs b/src/WixToolset.Core.WindowsInstaller/MsmBackend.cs new file mode 100644 index 00000000..268213d7 --- /dev/null +++ b/src/WixToolset.Core.WindowsInstaller/MsmBackend.cs | |||
@@ -0,0 +1,34 @@ | |||
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 | ||
4 | { | ||
5 | using WixToolset.Core.WindowsInstaller.Bind; | ||
6 | using WixToolset.Core.WindowsInstaller.Unbind; | ||
7 | using WixToolset.Data; | ||
8 | using WixToolset.Data.Bind; | ||
9 | using WixToolset.Extensibility; | ||
10 | |||
11 | internal class MsmBackend : IBackend | ||
12 | { | ||
13 | public BindResult Bind(IBindContext context) | ||
14 | { | ||
15 | var validator = Validator.CreateFromContext(context, "mergemod.cub"); | ||
16 | |||
17 | var command = new BindDatabaseCommand(context, validator); | ||
18 | command.Execute(); | ||
19 | |||
20 | return new BindResult(command.FileTransfers, command.ContentFilePaths); | ||
21 | } | ||
22 | |||
23 | public bool Inscribe(IInscribeContext context) | ||
24 | { | ||
25 | return false; | ||
26 | } | ||
27 | |||
28 | public Output Unbind(IUnbindContext context) | ||
29 | { | ||
30 | var command = new UnbindMsiOrMsmCommand(context); | ||
31 | return command.Execute(); | ||
32 | } | ||
33 | } | ||
34 | } | ||
diff --git a/src/WixToolset.Core.WindowsInstaller/MspBackend.cs b/src/WixToolset.Core.WindowsInstaller/MspBackend.cs new file mode 100644 index 00000000..4b13258b --- /dev/null +++ b/src/WixToolset.Core.WindowsInstaller/MspBackend.cs | |||
@@ -0,0 +1,111 @@ | |||
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 | ||
4 | { | ||
5 | using System; | ||
6 | using System.ComponentModel; | ||
7 | using System.IO; | ||
8 | using WixToolset.Core.Native; | ||
9 | using WixToolset.Core.WindowsInstaller.Unbind; | ||
10 | using WixToolset.Data; | ||
11 | using WixToolset.Data.Bind; | ||
12 | using WixToolset.Extensibility; | ||
13 | using WixToolset.Msi; | ||
14 | using WixToolset.Ole32; | ||
15 | |||
16 | internal class MspBackend : IBackend | ||
17 | { | ||
18 | public BindResult Bind(IBindContext context) | ||
19 | { | ||
20 | throw new NotImplementedException(); | ||
21 | } | ||
22 | |||
23 | public bool Inscribe(IInscribeContext context) | ||
24 | { | ||
25 | throw new NotImplementedException(); | ||
26 | } | ||
27 | |||
28 | public Output Unbind(IUnbindContext context) | ||
29 | { | ||
30 | Output patch; | ||
31 | |||
32 | // patch files are essentially database files (use a special flag to let the API know its a patch file) | ||
33 | try | ||
34 | { | ||
35 | using (Database database = new Database(context.InputFilePath, OpenDatabase.ReadOnly | OpenDatabase.OpenPatchFile)) | ||
36 | { | ||
37 | var unbindCommand = new UnbindDatabaseCommand(context.Messaging, database, context.InputFilePath, OutputType.Patch, context.ExportBasePath, context.IntermediateFolder, context.IsAdminImage, context.SuppressDemodularization, skipSummaryInfo: false); | ||
38 | patch = unbindCommand.Execute(); | ||
39 | } | ||
40 | } | ||
41 | catch (Win32Exception e) | ||
42 | { | ||
43 | if (0x6E == e.NativeErrorCode) // ERROR_OPEN_FAILED | ||
44 | { | ||
45 | throw new WixException(WixErrors.OpenDatabaseFailed(context.InputFilePath)); | ||
46 | } | ||
47 | |||
48 | throw; | ||
49 | } | ||
50 | |||
51 | // retrieve the transforms (they are in substorages) | ||
52 | using (Storage storage = Storage.Open(context.InputFilePath, StorageMode.Read | StorageMode.ShareDenyWrite)) | ||
53 | { | ||
54 | Table summaryInformationTable = patch.Tables["_SummaryInformation"]; | ||
55 | foreach (Row row in summaryInformationTable.Rows) | ||
56 | { | ||
57 | if (8 == (int)row[0]) // PID_LASTAUTHOR | ||
58 | { | ||
59 | string value = (string)row[1]; | ||
60 | |||
61 | foreach (string decoratedSubStorageName in value.Split(';')) | ||
62 | { | ||
63 | string subStorageName = decoratedSubStorageName.Substring(1); | ||
64 | string transformFile = Path.Combine(context.IntermediateFolder, String.Concat("Transform", Path.DirectorySeparatorChar, subStorageName, ".mst")); | ||
65 | |||
66 | // ensure the parent directory exists | ||
67 | System.IO.Directory.CreateDirectory(Path.GetDirectoryName(transformFile)); | ||
68 | |||
69 | // copy the substorage to a new storage for the transform file | ||
70 | using (Storage subStorage = storage.OpenStorage(subStorageName)) | ||
71 | { | ||
72 | using (Storage transformStorage = Storage.CreateDocFile(transformFile, StorageMode.ReadWrite | StorageMode.ShareExclusive | StorageMode.Create)) | ||
73 | { | ||
74 | subStorage.CopyTo(transformStorage); | ||
75 | } | ||
76 | } | ||
77 | |||
78 | // unbind the transform | ||
79 | var unbindCommand= new UnbindTransformCommand(context.Messaging, transformFile, (null == context.ExportBasePath ? null : Path.Combine(context.ExportBasePath, subStorageName)), context.IntermediateFolder); | ||
80 | var transform = unbindCommand.Execute(); | ||
81 | |||
82 | patch.SubStorages.Add(new SubStorage(subStorageName, transform)); | ||
83 | } | ||
84 | |||
85 | break; | ||
86 | } | ||
87 | } | ||
88 | } | ||
89 | |||
90 | // extract the files from the cabinets | ||
91 | // TODO: use per-transform export paths for support of multi-product patches | ||
92 | if (null != context.ExportBasePath && !context.SuppressExtractCabinets) | ||
93 | { | ||
94 | using (Database database = new Database(context.InputFilePath, OpenDatabase.ReadOnly | OpenDatabase.OpenPatchFile)) | ||
95 | { | ||
96 | foreach (SubStorage subStorage in patch.SubStorages) | ||
97 | { | ||
98 | // only patch transforms should carry files | ||
99 | if (subStorage.Name.StartsWith("#", StringComparison.Ordinal)) | ||
100 | { | ||
101 | var extractCommand = new ExtractCabinetsCommand(subStorage.Data, database, context.InputFilePath, context.ExportBasePath, context.IntermediateFolder); | ||
102 | extractCommand.Execute(); | ||
103 | } | ||
104 | } | ||
105 | } | ||
106 | } | ||
107 | |||
108 | return patch; | ||
109 | } | ||
110 | } | ||
111 | } \ No newline at end of file | ||
diff --git a/src/WixToolset.Core.WindowsInstaller/MstBackend.cs b/src/WixToolset.Core.WindowsInstaller/MstBackend.cs new file mode 100644 index 00000000..2cb7da89 --- /dev/null +++ b/src/WixToolset.Core.WindowsInstaller/MstBackend.cs | |||
@@ -0,0 +1,37 @@ | |||
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 | ||
4 | { | ||
5 | using System; | ||
6 | using WixToolset.Core.WindowsInstaller.Databases; | ||
7 | using WixToolset.Core.WindowsInstaller.Unbind; | ||
8 | using WixToolset.Data; | ||
9 | using WixToolset.Data.Bind; | ||
10 | using WixToolset.Extensibility; | ||
11 | |||
12 | internal class MstBackend : IBackend | ||
13 | { | ||
14 | public BindResult Bind(IBindContext context) | ||
15 | { | ||
16 | var command = new BindTransformCommand(); | ||
17 | command.Extensions = context.Extensions; | ||
18 | command.TempFilesLocation = context.IntermediateFolder; | ||
19 | command.Transform = context.IntermediateRepresentation; | ||
20 | command.OutputPath = context.OutputPath; | ||
21 | command.Execute(); | ||
22 | |||
23 | return new BindResult(Array.Empty<FileTransfer>(), Array.Empty<string>()); | ||
24 | } | ||
25 | |||
26 | public bool Inscribe(IInscribeContext context) | ||
27 | { | ||
28 | throw new NotImplementedException(); | ||
29 | } | ||
30 | |||
31 | public Output Unbind(IUnbindContext context) | ||
32 | { | ||
33 | var command = new UnbindMsiOrMsmCommand(context); | ||
34 | return command.Execute(); | ||
35 | } | ||
36 | } | ||
37 | } \ No newline at end of file | ||
diff --git a/src/WixToolset.Core/Ole32/Storage.cs b/src/WixToolset.Core.WindowsInstaller/Ole32/Storage.cs index c6a43bc4..c6a43bc4 100644 --- a/src/WixToolset.Core/Ole32/Storage.cs +++ b/src/WixToolset.Core.WindowsInstaller/Ole32/Storage.cs | |||
diff --git a/src/WixToolset.Core/Patch.cs b/src/WixToolset.Core.WindowsInstaller/Patch.cs index e3e6c27f..67150e32 100644 --- a/src/WixToolset.Core/Patch.cs +++ b/src/WixToolset.Core.WindowsInstaller/Patch.cs | |||
@@ -9,35 +9,8 @@ namespace WixToolset.Data | |||
9 | using System.Globalization; | 9 | using System.Globalization; |
10 | using WixToolset.Data.Rows; | 10 | using WixToolset.Data.Rows; |
11 | using WixToolset.Extensibility; | 11 | using WixToolset.Extensibility; |
12 | using WixToolset.Msi; | ||
13 | using WixToolset.Core.Native; | 12 | using WixToolset.Core.Native; |
14 | 13 | using WixToolset.Msi; | |
15 | /// <summary> | ||
16 | /// Values for the OptimizeCA MsiPatchMetdata property, which indicates whether custom actions can be skipped when applying the patch. | ||
17 | /// </summary> | ||
18 | [Flags] | ||
19 | internal enum OptimizeCA | ||
20 | { | ||
21 | /// <summary> | ||
22 | /// No custom actions are skipped. | ||
23 | /// </summary> | ||
24 | None = 0, | ||
25 | |||
26 | /// <summary> | ||
27 | /// Skip property (type 51) and directory (type 35) assignment custom actions. | ||
28 | /// </summary> | ||
29 | SkipAssignment = 1, | ||
30 | |||
31 | /// <summary> | ||
32 | /// Skip immediate custom actions that are not property or directory assignment custom actions. | ||
33 | /// </summary> | ||
34 | SkipImmediate = 2, | ||
35 | |||
36 | /// <summary> | ||
37 | /// Skip custom actions that run within the script. | ||
38 | /// </summary> | ||
39 | SkipDeferred = 4, | ||
40 | } | ||
41 | 14 | ||
42 | /// <summary> | 15 | /// <summary> |
43 | /// Contains output tables and logic for building an MSP package. | 16 | /// Contains output tables and logic for building an MSP package. |
@@ -80,8 +53,6 @@ namespace WixToolset.Data | |||
80 | [SuppressMessage("Microsoft.Globalization", "CA1303:DoNotPassLiteralsAsLocalizedParameters", MessageId = "System.InvalidOperationException.#ctor(System.String)")] | 53 | [SuppressMessage("Microsoft.Globalization", "CA1303:DoNotPassLiteralsAsLocalizedParameters", MessageId = "System.InvalidOperationException.#ctor(System.String)")] |
81 | public void AttachTransforms(List<PatchTransform> transforms) | 54 | public void AttachTransforms(List<PatchTransform> transforms) |
82 | { | 55 | { |
83 | InspectorCore inspectorCore = new InspectorCore(); | ||
84 | |||
85 | // Track if at least one transform gets attached. | 56 | // Track if at least one transform gets attached. |
86 | bool attachedTransform = false; | 57 | bool attachedTransform = false; |
87 | 58 | ||
@@ -429,16 +400,6 @@ namespace WixToolset.Data | |||
429 | Row savedbyRow = patchSummaryInfo.CreateRow(null); | 400 | Row savedbyRow = patchSummaryInfo.CreateRow(null); |
430 | savedbyRow[0] = (int)SummaryInformation.Patch.TransformNames; | 401 | savedbyRow[0] = (int)SummaryInformation.Patch.TransformNames; |
431 | savedbyRow[1] = String.Join(";", (string[])transformNames.ToArray(typeof(string))); | 402 | savedbyRow[1] = String.Join(";", (string[])transformNames.ToArray(typeof(string))); |
432 | |||
433 | // inspect the patch and filtered transforms | ||
434 | foreach (InspectorExtension inspectorExtension in this.inspectorExtensions) | ||
435 | { | ||
436 | inspectorExtension.Core = inspectorCore; | ||
437 | inspectorExtension.InspectOutput(this.patch); | ||
438 | |||
439 | // reset | ||
440 | inspectorExtension.Core = null; | ||
441 | } | ||
442 | } | 403 | } |
443 | 404 | ||
444 | /// <summary> | 405 | /// <summary> |
diff --git a/src/WixToolset.Core/PatchAPI/PatchInterop.cs b/src/WixToolset.Core.WindowsInstaller/PatchAPI/PatchInterop.cs index ce749a33..fcd749d2 100644 --- a/src/WixToolset.Core/PatchAPI/PatchInterop.cs +++ b/src/WixToolset.Core.WindowsInstaller/PatchAPI/PatchInterop.cs | |||
@@ -7,6 +7,7 @@ namespace WixToolset.PatchAPI | |||
7 | using System.Diagnostics.CodeAnalysis; | 7 | using System.Diagnostics.CodeAnalysis; |
8 | using System.Globalization; | 8 | using System.Globalization; |
9 | using System.Runtime.InteropServices; | 9 | using System.Runtime.InteropServices; |
10 | using WixToolset.Core; | ||
10 | 11 | ||
11 | /// <summary> | 12 | /// <summary> |
12 | /// Interop class for the mspatchc.dll. | 13 | /// Interop class for the mspatchc.dll. |
@@ -323,20 +324,6 @@ namespace WixToolset.PatchAPI | |||
323 | internal const uint PATCH_OPTION_VALID_FLAGS = 0xC0FF0007; | 324 | internal const uint PATCH_OPTION_VALID_FLAGS = 0xC0FF0007; |
324 | 325 | ||
325 | // | 326 | // |
326 | // The following flags are used with PATCH_OPTION_DATA SymbolOptionFlags: | ||
327 | // | ||
328 | |||
329 | [Flags] | ||
330 | public enum PatchSymbolFlagsType :uint | ||
331 | { | ||
332 | PATCH_SYMBOL_NO_IMAGEHLP = 0x00000001, // don't use imagehlp.dll | ||
333 | PATCH_SYMBOL_NO_FAILURES = 0x00000002, // don't fail patch due to imagehlp failures | ||
334 | PATCH_SYMBOL_UNDECORATED_TOO = 0x00000004, // after matching decorated symbols, try to match remaining by undecorated names | ||
335 | PATCH_SYMBOL_RESERVED1 = 0x80000000, // (used internally) | ||
336 | MaxValue = PATCH_SYMBOL_NO_IMAGEHLP | PATCH_SYMBOL_NO_FAILURES | PATCH_SYMBOL_UNDECORATED_TOO | ||
337 | } | ||
338 | |||
339 | // | ||
340 | // The following flags are used with PATCH_OPTION_DATA ExtendedOptionFlags: | 327 | // The following flags are used with PATCH_OPTION_DATA ExtendedOptionFlags: |
341 | // | 328 | // |
342 | 329 | ||
diff --git a/src/WixToolset.Core.WindowsInstaller/Unbind/ExtractCabinetsCommand.cs b/src/WixToolset.Core.WindowsInstaller/Unbind/ExtractCabinetsCommand.cs new file mode 100644 index 00000000..229e75b4 --- /dev/null +++ b/src/WixToolset.Core.WindowsInstaller/Unbind/ExtractCabinetsCommand.cs | |||
@@ -0,0 +1,146 @@ | |||
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.Unbind | ||
4 | { | ||
5 | using System; | ||
6 | using System.Collections; | ||
7 | using System.Collections.Specialized; | ||
8 | using System.Globalization; | ||
9 | using System.IO; | ||
10 | using WixToolset.Core.Cab; | ||
11 | using WixToolset.Data; | ||
12 | using WixToolset.Data.Rows; | ||
13 | using WixToolset.Msi; | ||
14 | |||
15 | internal class ExtractCabinetsCommand | ||
16 | { | ||
17 | public ExtractCabinetsCommand(Output output, Database database, string inputFilePath, string exportBasePath, string intermediateFolder) | ||
18 | { | ||
19 | this.Output = output; | ||
20 | this.Database = database; | ||
21 | this.InputFilePath = inputFilePath; | ||
22 | this.ExportBasePath = exportBasePath; | ||
23 | this.IntermediateFolder = intermediateFolder; | ||
24 | } | ||
25 | |||
26 | private Output Output { get; } | ||
27 | |||
28 | private Database Database { get; } | ||
29 | |||
30 | private string InputFilePath { get; } | ||
31 | |||
32 | private string ExportBasePath { get; } | ||
33 | |||
34 | private string IntermediateFolder { get; } | ||
35 | |||
36 | public void Execute() | ||
37 | { | ||
38 | string databaseBasePath = Path.GetDirectoryName(this.InputFilePath); | ||
39 | StringCollection cabinetFiles = new StringCollection(); | ||
40 | SortedList embeddedCabinets = new SortedList(); | ||
41 | |||
42 | // index all of the cabinet files | ||
43 | if (OutputType.Module == this.Output.Type) | ||
44 | { | ||
45 | embeddedCabinets.Add(0, "MergeModule.CABinet"); | ||
46 | } | ||
47 | else if (null != this.Output.Tables["Media"]) | ||
48 | { | ||
49 | foreach (MediaRow mediaRow in this.Output.Tables["Media"].Rows) | ||
50 | { | ||
51 | if (null != mediaRow.Cabinet) | ||
52 | { | ||
53 | if (OutputType.Product == this.Output.Type || | ||
54 | (OutputType.Transform == this.Output.Type && RowOperation.Add == mediaRow.Operation)) | ||
55 | { | ||
56 | if (mediaRow.Cabinet.StartsWith("#", StringComparison.Ordinal)) | ||
57 | { | ||
58 | embeddedCabinets.Add(mediaRow.DiskId, mediaRow.Cabinet.Substring(1)); | ||
59 | } | ||
60 | else | ||
61 | { | ||
62 | cabinetFiles.Add(Path.Combine(databaseBasePath, mediaRow.Cabinet)); | ||
63 | } | ||
64 | } | ||
65 | } | ||
66 | } | ||
67 | } | ||
68 | |||
69 | // extract the embedded cabinet files from the database | ||
70 | if (0 < embeddedCabinets.Count) | ||
71 | { | ||
72 | using (View streamsView = this.Database.OpenView("SELECT `Data` FROM `_Streams` WHERE `Name` = ?")) | ||
73 | { | ||
74 | foreach (int diskId in embeddedCabinets.Keys) | ||
75 | { | ||
76 | using (Record record = new Record(1)) | ||
77 | { | ||
78 | record.SetString(1, (string)embeddedCabinets[diskId]); | ||
79 | streamsView.Execute(record); | ||
80 | } | ||
81 | |||
82 | using (Record record = streamsView.Fetch()) | ||
83 | { | ||
84 | if (null != record) | ||
85 | { | ||
86 | // since the cabinets are stored in case-sensitive streams inside the msi, but the file system is not case-sensitive, | ||
87 | // embedded cabinets must be extracted to a canonical file name (like their diskid) to ensure extraction will always work | ||
88 | string cabinetFile = Path.Combine(this.IntermediateFolder, String.Concat("Media", Path.DirectorySeparatorChar, diskId.ToString(CultureInfo.InvariantCulture), ".cab")); | ||
89 | |||
90 | // ensure the parent directory exists | ||
91 | System.IO.Directory.CreateDirectory(Path.GetDirectoryName(cabinetFile)); | ||
92 | |||
93 | using (FileStream fs = System.IO.File.Create(cabinetFile)) | ||
94 | { | ||
95 | int bytesRead; | ||
96 | byte[] buffer = new byte[512]; | ||
97 | |||
98 | while (0 != (bytesRead = record.GetStream(1, buffer, buffer.Length))) | ||
99 | { | ||
100 | fs.Write(buffer, 0, bytesRead); | ||
101 | } | ||
102 | } | ||
103 | |||
104 | cabinetFiles.Add(cabinetFile); | ||
105 | } | ||
106 | else | ||
107 | { | ||
108 | // TODO: warning about missing embedded cabinet | ||
109 | } | ||
110 | } | ||
111 | } | ||
112 | } | ||
113 | } | ||
114 | |||
115 | // extract the cabinet files | ||
116 | if (0 < cabinetFiles.Count) | ||
117 | { | ||
118 | string fileDirectory = Path.Combine(this.ExportBasePath, "File"); | ||
119 | |||
120 | // delete the directory and its files to prevent cab extraction due to an existing file | ||
121 | if (Directory.Exists(fileDirectory)) | ||
122 | { | ||
123 | Directory.Delete(fileDirectory, true); | ||
124 | } | ||
125 | |||
126 | // ensure the directory exists or extraction will fail | ||
127 | Directory.CreateDirectory(fileDirectory); | ||
128 | |||
129 | foreach (string cabinetFile in cabinetFiles) | ||
130 | { | ||
131 | using (var extractCab = new WixExtractCab()) | ||
132 | { | ||
133 | try | ||
134 | { | ||
135 | extractCab.Extract(cabinetFile, fileDirectory); | ||
136 | } | ||
137 | catch (FileNotFoundException) | ||
138 | { | ||
139 | throw new WixException(WixErrors.FileNotFound(new SourceLineNumber(this.InputFilePath), cabinetFile)); | ||
140 | } | ||
141 | } | ||
142 | } | ||
143 | } | ||
144 | } | ||
145 | } | ||
146 | } | ||
diff --git a/src/WixToolset.Core.WindowsInstaller/Unbind/UnbindDatabaseCommand.cs b/src/WixToolset.Core.WindowsInstaller/Unbind/UnbindDatabaseCommand.cs new file mode 100644 index 00000000..208be874 --- /dev/null +++ b/src/WixToolset.Core.WindowsInstaller/Unbind/UnbindDatabaseCommand.cs | |||
@@ -0,0 +1,791 @@ | |||
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.Unbind | ||
4 | { | ||
5 | using System; | ||
6 | using System.Collections; | ||
7 | using System.Collections.Generic; | ||
8 | using System.Globalization; | ||
9 | using System.IO; | ||
10 | using System.Text.RegularExpressions; | ||
11 | using WixToolset.Core.Native; | ||
12 | using WixToolset.Data; | ||
13 | using WixToolset.Data.Rows; | ||
14 | using WixToolset.Msi; | ||
15 | |||
16 | internal class UnbindDatabaseCommand | ||
17 | { | ||
18 | public UnbindDatabaseCommand(Messaging messaging, Database database, string databasePath, OutputType outputType, string exportBasePath, string intermediateFolder, bool isAdminImage, bool suppressDemodularization, bool skipSummaryInfo) | ||
19 | { | ||
20 | this.Messaging = messaging; | ||
21 | this.Database = database; | ||
22 | this.DatabasePath = databasePath; | ||
23 | this.OutputType = outputType; | ||
24 | this.ExportBasePath = exportBasePath; | ||
25 | this.IntermediateFolder = intermediateFolder; | ||
26 | this.IsAdminImage = isAdminImage; | ||
27 | this.SuppressDemodularization = suppressDemodularization; | ||
28 | this.SkipSummaryInfo = skipSummaryInfo; | ||
29 | |||
30 | this.TableDefinitions = WindowsInstallerStandard.GetTableDefinitions(); | ||
31 | } | ||
32 | |||
33 | public Messaging Messaging { get; } | ||
34 | |||
35 | public Database Database { get; } | ||
36 | |||
37 | public string DatabasePath { get; } | ||
38 | |||
39 | public OutputType OutputType { get; } | ||
40 | |||
41 | public string ExportBasePath { get; } | ||
42 | |||
43 | public string IntermediateFolder { get; } | ||
44 | |||
45 | public bool IsAdminImage { get; } | ||
46 | |||
47 | public bool SuppressDemodularization { get; } | ||
48 | |||
49 | public bool SkipSummaryInfo { get; } | ||
50 | |||
51 | public TableDefinitionCollection TableDefinitions { get; } | ||
52 | |||
53 | private int SectionCount { get; set; } | ||
54 | |||
55 | public Output Execute() | ||
56 | { | ||
57 | string modularizationGuid = null; | ||
58 | Output output = new Output(new SourceLineNumber(this.DatabasePath)); | ||
59 | View validationView = null; | ||
60 | |||
61 | // set the output type | ||
62 | output.Type = this.OutputType; | ||
63 | |||
64 | // get the codepage | ||
65 | this.Database.Export("_ForceCodepage", this.IntermediateFolder, "_ForceCodepage.idt"); | ||
66 | using (StreamReader sr = File.OpenText(Path.Combine(this.IntermediateFolder, "_ForceCodepage.idt"))) | ||
67 | { | ||
68 | string line; | ||
69 | |||
70 | while (null != (line = sr.ReadLine())) | ||
71 | { | ||
72 | string[] data = line.Split('\t'); | ||
73 | |||
74 | if (2 == data.Length) | ||
75 | { | ||
76 | output.Codepage = Convert.ToInt32(data[0], CultureInfo.InvariantCulture); | ||
77 | } | ||
78 | } | ||
79 | } | ||
80 | |||
81 | // get the summary information table if it exists; it won't if unbinding a transform | ||
82 | if (!this.SkipSummaryInfo) | ||
83 | { | ||
84 | using (SummaryInformation summaryInformation = new SummaryInformation(this.Database)) | ||
85 | { | ||
86 | Table table = new Table(null, this.TableDefinitions["_SummaryInformation"]); | ||
87 | |||
88 | for (int i = 1; 19 >= i; i++) | ||
89 | { | ||
90 | string value = summaryInformation.GetProperty(i); | ||
91 | |||
92 | if (0 < value.Length) | ||
93 | { | ||
94 | Row row = table.CreateRow(output.SourceLineNumbers); | ||
95 | row[0] = i; | ||
96 | row[1] = value; | ||
97 | } | ||
98 | } | ||
99 | |||
100 | output.Tables.Add(table); | ||
101 | } | ||
102 | } | ||
103 | |||
104 | try | ||
105 | { | ||
106 | // open a view on the validation table if it exists | ||
107 | if (this.Database.TableExists("_Validation")) | ||
108 | { | ||
109 | validationView = this.Database.OpenView("SELECT * FROM `_Validation` WHERE `Table` = ? AND `Column` = ?"); | ||
110 | } | ||
111 | |||
112 | // get the normal tables | ||
113 | using (View tablesView = this.Database.OpenExecuteView("SELECT * FROM _Tables")) | ||
114 | { | ||
115 | while (true) | ||
116 | { | ||
117 | using (Record tableRecord = tablesView.Fetch()) | ||
118 | { | ||
119 | if (null == tableRecord) | ||
120 | { | ||
121 | break; | ||
122 | } | ||
123 | |||
124 | string tableName = tableRecord.GetString(1); | ||
125 | |||
126 | using (View tableView = this.Database.OpenExecuteView(String.Format(CultureInfo.InvariantCulture, "SELECT * FROM `{0}`", tableName))) | ||
127 | { | ||
128 | List<ColumnDefinition> columns; | ||
129 | using (Record columnNameRecord = tableView.GetColumnInfo(MsiInterop.MSICOLINFONAMES), | ||
130 | columnTypeRecord = tableView.GetColumnInfo(MsiInterop.MSICOLINFOTYPES)) | ||
131 | { | ||
132 | // index the primary keys | ||
133 | HashSet<string> tablePrimaryKeys = new HashSet<string>(); | ||
134 | using (Record primaryKeysRecord = this.Database.PrimaryKeys(tableName)) | ||
135 | { | ||
136 | int primaryKeysFieldCount = primaryKeysRecord.GetFieldCount(); | ||
137 | |||
138 | for (int i = 1; i <= primaryKeysFieldCount; i++) | ||
139 | { | ||
140 | tablePrimaryKeys.Add(primaryKeysRecord.GetString(i)); | ||
141 | } | ||
142 | } | ||
143 | |||
144 | int columnCount = columnNameRecord.GetFieldCount(); | ||
145 | columns = new List<ColumnDefinition>(columnCount); | ||
146 | for (int i = 1; i <= columnCount; i++) | ||
147 | { | ||
148 | string columnName = columnNameRecord.GetString(i); | ||
149 | string idtType = columnTypeRecord.GetString(i); | ||
150 | |||
151 | ColumnType columnType; | ||
152 | int length; | ||
153 | bool nullable; | ||
154 | |||
155 | ColumnCategory columnCategory = ColumnCategory.Unknown; | ||
156 | ColumnModularizeType columnModularizeType = ColumnModularizeType.None; | ||
157 | bool primary = tablePrimaryKeys.Contains(columnName); | ||
158 | bool minValueSet = false; | ||
159 | int minValue = -1; | ||
160 | bool maxValueSet = false; | ||
161 | int maxValue = -1; | ||
162 | string keyTable = null; | ||
163 | bool keyColumnSet = false; | ||
164 | int keyColumn = -1; | ||
165 | string category = null; | ||
166 | string set = null; | ||
167 | string description = null; | ||
168 | |||
169 | // get the column type, length, and whether its nullable | ||
170 | switch (Char.ToLower(idtType[0], CultureInfo.InvariantCulture)) | ||
171 | { | ||
172 | case 'i': | ||
173 | columnType = ColumnType.Number; | ||
174 | break; | ||
175 | case 'l': | ||
176 | columnType = ColumnType.Localized; | ||
177 | break; | ||
178 | case 's': | ||
179 | columnType = ColumnType.String; | ||
180 | break; | ||
181 | case 'v': | ||
182 | columnType = ColumnType.Object; | ||
183 | break; | ||
184 | default: | ||
185 | // TODO: error | ||
186 | columnType = ColumnType.Unknown; | ||
187 | break; | ||
188 | } | ||
189 | length = Convert.ToInt32(idtType.Substring(1), CultureInfo.InvariantCulture); | ||
190 | nullable = Char.IsUpper(idtType[0]); | ||
191 | |||
192 | // try to get validation information | ||
193 | if (null != validationView) | ||
194 | { | ||
195 | using (Record validationRecord = new Record(2)) | ||
196 | { | ||
197 | validationRecord.SetString(1, tableName); | ||
198 | validationRecord.SetString(2, columnName); | ||
199 | |||
200 | validationView.Execute(validationRecord); | ||
201 | } | ||
202 | |||
203 | using (Record validationRecord = validationView.Fetch()) | ||
204 | { | ||
205 | if (null != validationRecord) | ||
206 | { | ||
207 | string validationNullable = validationRecord.GetString(3); | ||
208 | minValueSet = !validationRecord.IsNull(4); | ||
209 | minValue = (minValueSet ? validationRecord.GetInteger(4) : -1); | ||
210 | maxValueSet = !validationRecord.IsNull(5); | ||
211 | maxValue = (maxValueSet ? validationRecord.GetInteger(5) : -1); | ||
212 | keyTable = (!validationRecord.IsNull(6) ? validationRecord.GetString(6) : null); | ||
213 | keyColumnSet = !validationRecord.IsNull(7); | ||
214 | keyColumn = (keyColumnSet ? validationRecord.GetInteger(7) : -1); | ||
215 | category = (!validationRecord.IsNull(8) ? validationRecord.GetString(8) : null); | ||
216 | set = (!validationRecord.IsNull(9) ? validationRecord.GetString(9) : null); | ||
217 | description = (!validationRecord.IsNull(10) ? validationRecord.GetString(10) : null); | ||
218 | |||
219 | // check the validation nullable value against the column definition | ||
220 | if (null == validationNullable) | ||
221 | { | ||
222 | // TODO: warn for illegal validation nullable column | ||
223 | } | ||
224 | else if ((nullable && "Y" != validationNullable) || (!nullable && "N" != validationNullable)) | ||
225 | { | ||
226 | // TODO: warn for mismatch between column definition and validation nullable | ||
227 | } | ||
228 | |||
229 | // convert category to ColumnCategory | ||
230 | if (null != category) | ||
231 | { | ||
232 | try | ||
233 | { | ||
234 | columnCategory = (ColumnCategory)Enum.Parse(typeof(ColumnCategory), category, true); | ||
235 | } | ||
236 | catch (ArgumentException) | ||
237 | { | ||
238 | columnCategory = ColumnCategory.Unknown; | ||
239 | } | ||
240 | } | ||
241 | } | ||
242 | else | ||
243 | { | ||
244 | // TODO: warn about no validation information | ||
245 | } | ||
246 | } | ||
247 | } | ||
248 | |||
249 | // guess the modularization type | ||
250 | if ("Icon" == keyTable && 1 == keyColumn) | ||
251 | { | ||
252 | columnModularizeType = ColumnModularizeType.Icon; | ||
253 | } | ||
254 | else if ("Condition" == columnName) | ||
255 | { | ||
256 | columnModularizeType = ColumnModularizeType.Condition; | ||
257 | } | ||
258 | else if (ColumnCategory.Formatted == columnCategory || ColumnCategory.FormattedSDDLText == columnCategory) | ||
259 | { | ||
260 | columnModularizeType = ColumnModularizeType.Property; | ||
261 | } | ||
262 | else if (ColumnCategory.Identifier == columnCategory) | ||
263 | { | ||
264 | columnModularizeType = ColumnModularizeType.Column; | ||
265 | } | ||
266 | |||
267 | columns.Add(new ColumnDefinition(columnName, columnType, length, primary, nullable, columnModularizeType, (ColumnType.Localized == columnType), minValueSet, minValue, maxValueSet, maxValue, keyTable, keyColumnSet, keyColumn, columnCategory, set, description, true, true)); | ||
268 | } | ||
269 | } | ||
270 | |||
271 | TableDefinition tableDefinition = new TableDefinition(tableName, columns, false, false); | ||
272 | |||
273 | // use our table definitions if core properties are the same; this allows us to take advantage | ||
274 | // of wix concepts like localizable columns which current code assumes | ||
275 | if (this.TableDefinitions.Contains(tableName) && 0 == tableDefinition.CompareTo(this.TableDefinitions[tableName])) | ||
276 | { | ||
277 | tableDefinition = this.TableDefinitions[tableName]; | ||
278 | } | ||
279 | |||
280 | Table table = new Table(null, tableDefinition); | ||
281 | |||
282 | while (true) | ||
283 | { | ||
284 | using (Record rowRecord = tableView.Fetch()) | ||
285 | { | ||
286 | if (null == rowRecord) | ||
287 | { | ||
288 | break; | ||
289 | } | ||
290 | |||
291 | int recordCount = rowRecord.GetFieldCount(); | ||
292 | Row row = table.CreateRow(output.SourceLineNumbers); | ||
293 | |||
294 | for (int i = 0; recordCount > i && row.Fields.Length > i; i++) | ||
295 | { | ||
296 | if (rowRecord.IsNull(i + 1)) | ||
297 | { | ||
298 | if (!row.Fields[i].Column.Nullable) | ||
299 | { | ||
300 | // TODO: display an error for a null value in a non-nullable field OR | ||
301 | // display a warning and put an empty string in the value to let the compiler handle it | ||
302 | // (the second option is risky because the later code may make certain assumptions about | ||
303 | // the contents of a row value) | ||
304 | } | ||
305 | } | ||
306 | else | ||
307 | { | ||
308 | switch (row.Fields[i].Column.Type) | ||
309 | { | ||
310 | case ColumnType.Number: | ||
311 | bool success = false; | ||
312 | int intValue = rowRecord.GetInteger(i + 1); | ||
313 | if (row.Fields[i].Column.IsLocalizable) | ||
314 | { | ||
315 | success = row.BestEffortSetField(i, Convert.ToString(intValue, CultureInfo.InvariantCulture)); | ||
316 | } | ||
317 | else | ||
318 | { | ||
319 | success = row.BestEffortSetField(i, intValue); | ||
320 | } | ||
321 | |||
322 | if (!success) | ||
323 | { | ||
324 | this.Messaging.OnMessage(WixWarnings.BadColumnDataIgnored(row.SourceLineNumbers, Convert.ToString(intValue, CultureInfo.InvariantCulture), tableName, row.Fields[i].Column.Name)); | ||
325 | } | ||
326 | break; | ||
327 | case ColumnType.Object: | ||
328 | string sourceFile = "FILE NOT EXPORTED, USE THE dark.exe -x OPTION TO EXPORT BINARIES"; | ||
329 | |||
330 | if (null != this.ExportBasePath) | ||
331 | { | ||
332 | string relativeSourceFile = Path.Combine(tableName, row.GetPrimaryKey('.')); | ||
333 | sourceFile = Path.Combine(this.ExportBasePath, relativeSourceFile); | ||
334 | |||
335 | // ensure the parent directory exists | ||
336 | System.IO.Directory.CreateDirectory(Path.Combine(this.ExportBasePath, tableName)); | ||
337 | |||
338 | using (FileStream fs = System.IO.File.Create(sourceFile)) | ||
339 | { | ||
340 | int bytesRead; | ||
341 | byte[] buffer = new byte[512]; | ||
342 | |||
343 | while (0 != (bytesRead = rowRecord.GetStream(i + 1, buffer, buffer.Length))) | ||
344 | { | ||
345 | fs.Write(buffer, 0, bytesRead); | ||
346 | } | ||
347 | } | ||
348 | } | ||
349 | |||
350 | row[i] = sourceFile; | ||
351 | break; | ||
352 | default: | ||
353 | string value = rowRecord.GetString(i + 1); | ||
354 | |||
355 | switch (row.Fields[i].Column.Category) | ||
356 | { | ||
357 | case ColumnCategory.Guid: | ||
358 | value = value.ToUpper(CultureInfo.InvariantCulture); | ||
359 | break; | ||
360 | } | ||
361 | |||
362 | // de-modularize | ||
363 | if (!this.SuppressDemodularization && OutputType.Module == output.Type && ColumnModularizeType.None != row.Fields[i].Column.ModularizeType) | ||
364 | { | ||
365 | Regex modularization = new Regex(@"\.[0-9A-Fa-f]{8}_[0-9A-Fa-f]{4}_[0-9A-Fa-f]{4}_[0-9A-Fa-f]{4}_[0-9A-Fa-f]{12}"); | ||
366 | |||
367 | if (null == modularizationGuid) | ||
368 | { | ||
369 | Match match = modularization.Match(value); | ||
370 | if (match.Success) | ||
371 | { | ||
372 | modularizationGuid = String.Concat('{', match.Value.Substring(1).Replace('_', '-'), '}'); | ||
373 | } | ||
374 | } | ||
375 | |||
376 | value = modularization.Replace(value, String.Empty); | ||
377 | } | ||
378 | |||
379 | // escape "$(" for the preprocessor | ||
380 | value = value.Replace("$(", "$$("); | ||
381 | |||
382 | // escape things that look like wix variables | ||
383 | MatchCollection matches = Common.WixVariableRegex.Matches(value); | ||
384 | for (int j = matches.Count - 1; 0 <= j; j--) | ||
385 | { | ||
386 | value = value.Insert(matches[j].Index, "!"); | ||
387 | } | ||
388 | |||
389 | row[i] = value; | ||
390 | break; | ||
391 | } | ||
392 | } | ||
393 | } | ||
394 | } | ||
395 | } | ||
396 | |||
397 | output.Tables.Add(table); | ||
398 | } | ||
399 | |||
400 | } | ||
401 | } | ||
402 | } | ||
403 | } | ||
404 | finally | ||
405 | { | ||
406 | if (null != validationView) | ||
407 | { | ||
408 | validationView.Close(); | ||
409 | } | ||
410 | } | ||
411 | |||
412 | // set the modularization guid as the PackageCode | ||
413 | if (null != modularizationGuid) | ||
414 | { | ||
415 | Table table = output.Tables["_SummaryInformation"]; | ||
416 | |||
417 | foreach (Row row in table.Rows) | ||
418 | { | ||
419 | if (9 == (int)row[0]) // PID_REVNUMBER | ||
420 | { | ||
421 | row[1] = modularizationGuid; | ||
422 | } | ||
423 | } | ||
424 | } | ||
425 | |||
426 | if (this.IsAdminImage) | ||
427 | { | ||
428 | GenerateWixFileTable(this.DatabasePath, output); | ||
429 | GenerateSectionIds(output); | ||
430 | } | ||
431 | |||
432 | return output; | ||
433 | } | ||
434 | |||
435 | /// <summary> | ||
436 | /// Generates the WixFile table based on a path to an admin image msi and an Output. | ||
437 | /// </summary> | ||
438 | /// <param name="databaseFile">The path to the msi database file in an admin image.</param> | ||
439 | /// <param name="output">The Output that represents the msi database.</param> | ||
440 | private void GenerateWixFileTable(string databaseFile, Output output) | ||
441 | { | ||
442 | string adminRootPath = Path.GetDirectoryName(databaseFile); | ||
443 | |||
444 | Hashtable componentDirectoryIndex = new Hashtable(); | ||
445 | Table componentTable = output.Tables["Component"]; | ||
446 | foreach (Row row in componentTable.Rows) | ||
447 | { | ||
448 | componentDirectoryIndex.Add(row[0], row[2]); | ||
449 | } | ||
450 | |||
451 | // Index full source paths for all directories | ||
452 | Hashtable directoryDirectoryParentIndex = new Hashtable(); | ||
453 | Hashtable directoryFullPathIndex = new Hashtable(); | ||
454 | Hashtable directorySourceNameIndex = new Hashtable(); | ||
455 | Table directoryTable = output.Tables["Directory"]; | ||
456 | foreach (Row row in directoryTable.Rows) | ||
457 | { | ||
458 | directoryDirectoryParentIndex.Add(row[0], row[1]); | ||
459 | if (null == row[1]) | ||
460 | { | ||
461 | directoryFullPathIndex.Add(row[0], adminRootPath); | ||
462 | } | ||
463 | else | ||
464 | { | ||
465 | directorySourceNameIndex.Add(row[0], GetAdminSourceName((string)row[2])); | ||
466 | } | ||
467 | } | ||
468 | |||
469 | foreach (DictionaryEntry directoryEntry in directoryDirectoryParentIndex) | ||
470 | { | ||
471 | if (!directoryFullPathIndex.ContainsKey(directoryEntry.Key)) | ||
472 | { | ||
473 | GetAdminFullPath((string)directoryEntry.Key, directoryDirectoryParentIndex, directorySourceNameIndex, directoryFullPathIndex); | ||
474 | } | ||
475 | } | ||
476 | |||
477 | Table fileTable = output.Tables["File"]; | ||
478 | Table wixFileTable = output.EnsureTable(this.TableDefinitions["WixFile"]); | ||
479 | foreach (Row row in fileTable.Rows) | ||
480 | { | ||
481 | WixFileRow wixFileRow = new WixFileRow(null, this.TableDefinitions["WixFile"]); | ||
482 | wixFileRow.File = (string)row[0]; | ||
483 | wixFileRow.Directory = (string)componentDirectoryIndex[(string)row[1]]; | ||
484 | wixFileRow.Source = Path.Combine((string)directoryFullPathIndex[wixFileRow.Directory], GetAdminSourceName((string)row[2])); | ||
485 | |||
486 | if (!File.Exists(wixFileRow.Source)) | ||
487 | { | ||
488 | throw new WixException(WixErrors.WixFileNotFound(wixFileRow.Source)); | ||
489 | } | ||
490 | |||
491 | wixFileTable.Rows.Add(wixFileRow); | ||
492 | } | ||
493 | } | ||
494 | |||
495 | /// <summary> | ||
496 | /// Gets the full path of a directory. Populates the full path index with the directory's full path and all of its parent directorie's full paths. | ||
497 | /// </summary> | ||
498 | /// <param name="directory">The directory identifier.</param> | ||
499 | /// <param name="directoryDirectoryParentIndex">The Hashtable containing all the directory to directory parent mapping.</param> | ||
500 | /// <param name="directorySourceNameIndex">The Hashtable containing all the directory to source name mapping.</param> | ||
501 | /// <param name="directoryFullPathIndex">The Hashtable containing a mapping between all of the directories and their previously calculated full paths.</param> | ||
502 | /// <returns>The full path to the directory.</returns> | ||
503 | private string GetAdminFullPath(string directory, Hashtable directoryDirectoryParentIndex, Hashtable directorySourceNameIndex, Hashtable directoryFullPathIndex) | ||
504 | { | ||
505 | string parent = (string)directoryDirectoryParentIndex[directory]; | ||
506 | string sourceName = (string)directorySourceNameIndex[directory]; | ||
507 | |||
508 | string parentFullPath; | ||
509 | if (directoryFullPathIndex.ContainsKey(parent)) | ||
510 | { | ||
511 | parentFullPath = (string)directoryFullPathIndex[parent]; | ||
512 | } | ||
513 | else | ||
514 | { | ||
515 | parentFullPath = GetAdminFullPath(parent, directoryDirectoryParentIndex, directorySourceNameIndex, directoryFullPathIndex); | ||
516 | } | ||
517 | |||
518 | if (null == sourceName) | ||
519 | { | ||
520 | sourceName = String.Empty; | ||
521 | } | ||
522 | |||
523 | string fullPath = Path.Combine(parentFullPath, sourceName); | ||
524 | directoryFullPathIndex.Add(directory, fullPath); | ||
525 | |||
526 | return fullPath; | ||
527 | } | ||
528 | |||
529 | /// <summary> | ||
530 | /// Get the source name in an admin image. | ||
531 | /// </summary> | ||
532 | /// <param name="value">The Filename value.</param> | ||
533 | /// <returns>The source name of the directory in an admin image.</returns> | ||
534 | private static string GetAdminSourceName(string value) | ||
535 | { | ||
536 | string name = null; | ||
537 | string[] names; | ||
538 | string shortname = null; | ||
539 | string shortsourcename = null; | ||
540 | string sourcename = null; | ||
541 | |||
542 | names = Common.GetNames(value); | ||
543 | |||
544 | if (null != names[0] && "." != names[0]) | ||
545 | { | ||
546 | if (null != names[1]) | ||
547 | { | ||
548 | shortname = names[0]; | ||
549 | } | ||
550 | else | ||
551 | { | ||
552 | name = names[0]; | ||
553 | } | ||
554 | } | ||
555 | |||
556 | if (null != names[1]) | ||
557 | { | ||
558 | name = names[1]; | ||
559 | } | ||
560 | |||
561 | if (null != names[2]) | ||
562 | { | ||
563 | if (null != names[3]) | ||
564 | { | ||
565 | shortsourcename = names[2]; | ||
566 | } | ||
567 | else | ||
568 | { | ||
569 | sourcename = names[2]; | ||
570 | } | ||
571 | } | ||
572 | |||
573 | if (null != names[3]) | ||
574 | { | ||
575 | sourcename = names[3]; | ||
576 | } | ||
577 | |||
578 | if (null != sourcename) | ||
579 | { | ||
580 | return sourcename; | ||
581 | } | ||
582 | else if (null != shortsourcename) | ||
583 | { | ||
584 | return shortsourcename; | ||
585 | } | ||
586 | else if (null != name) | ||
587 | { | ||
588 | return name; | ||
589 | } | ||
590 | else | ||
591 | { | ||
592 | return shortname; | ||
593 | } | ||
594 | } | ||
595 | |||
596 | /// <summary> | ||
597 | /// Creates section ids on rows which form logical groupings of resources. | ||
598 | /// </summary> | ||
599 | /// <param name="output">The Output that represents the msi database.</param> | ||
600 | private void GenerateSectionIds(Output output) | ||
601 | { | ||
602 | // First assign and index section ids for the tables that are in their own sections. | ||
603 | AssignSectionIdsToTable(output.Tables["Binary"], 0); | ||
604 | Hashtable componentSectionIdIndex = AssignSectionIdsToTable(output.Tables["Component"], 0); | ||
605 | Hashtable customActionSectionIdIndex = AssignSectionIdsToTable(output.Tables["CustomAction"], 0); | ||
606 | AssignSectionIdsToTable(output.Tables["Directory"], 0); | ||
607 | Hashtable featureSectionIdIndex = AssignSectionIdsToTable(output.Tables["Feature"], 0); | ||
608 | AssignSectionIdsToTable(output.Tables["Icon"], 0); | ||
609 | Hashtable digitalCertificateSectionIdIndex = AssignSectionIdsToTable(output.Tables["MsiDigitalCertificate"], 0); | ||
610 | AssignSectionIdsToTable(output.Tables["Property"], 0); | ||
611 | |||
612 | // Now handle all the tables that rely on the first set of indexes but also produce their own indexes. Order matters here. | ||
613 | Hashtable fileSectionIdIndex = ConnectTableToSectionAndIndex(output.Tables["File"], componentSectionIdIndex, 1, 0); | ||
614 | Hashtable appIdSectionIdIndex = ConnectTableToSectionAndIndex(output.Tables["Class"], componentSectionIdIndex, 2, 5); | ||
615 | Hashtable odbcDataSourceSectionIdIndex = ConnectTableToSectionAndIndex(output.Tables["ODBCDataSource"], componentSectionIdIndex, 1, 0); | ||
616 | Hashtable odbcDriverSectionIdIndex = ConnectTableToSectionAndIndex(output.Tables["ODBCDriver"], componentSectionIdIndex, 1, 0); | ||
617 | Hashtable registrySectionIdIndex = ConnectTableToSectionAndIndex(output.Tables["Registry"], componentSectionIdIndex, 5, 0); | ||
618 | Hashtable serviceInstallSectionIdIndex = ConnectTableToSectionAndIndex(output.Tables["ServiceInstall"], componentSectionIdIndex, 11, 0); | ||
619 | |||
620 | // Now handle all the tables which only rely on previous indexes and order does not matter. | ||
621 | foreach (Table table in output.Tables) | ||
622 | { | ||
623 | switch (table.Name) | ||
624 | { | ||
625 | case "WixFile": | ||
626 | case "MsiFileHash": | ||
627 | ConnectTableToSection(table, fileSectionIdIndex, 0); | ||
628 | break; | ||
629 | case "MsiAssembly": | ||
630 | case "MsiAssemblyName": | ||
631 | ConnectTableToSection(table, componentSectionIdIndex, 0); | ||
632 | break; | ||
633 | case "MsiPackageCertificate": | ||
634 | case "MsiPatchCertificate": | ||
635 | ConnectTableToSection(table, digitalCertificateSectionIdIndex, 1); | ||
636 | break; | ||
637 | case "CreateFolder": | ||
638 | case "FeatureComponents": | ||
639 | case "MoveFile": | ||
640 | case "ReserveCost": | ||
641 | case "ODBCTranslator": | ||
642 | ConnectTableToSection(table, componentSectionIdIndex, 1); | ||
643 | break; | ||
644 | case "TypeLib": | ||
645 | ConnectTableToSection(table, componentSectionIdIndex, 2); | ||
646 | break; | ||
647 | case "Shortcut": | ||
648 | case "Environment": | ||
649 | ConnectTableToSection(table, componentSectionIdIndex, 3); | ||
650 | break; | ||
651 | case "RemoveRegistry": | ||
652 | ConnectTableToSection(table, componentSectionIdIndex, 4); | ||
653 | break; | ||
654 | case "ServiceControl": | ||
655 | ConnectTableToSection(table, componentSectionIdIndex, 5); | ||
656 | break; | ||
657 | case "IniFile": | ||
658 | case "RemoveIniFile": | ||
659 | ConnectTableToSection(table, componentSectionIdIndex, 7); | ||
660 | break; | ||
661 | case "AppId": | ||
662 | ConnectTableToSection(table, appIdSectionIdIndex, 0); | ||
663 | break; | ||
664 | case "Condition": | ||
665 | ConnectTableToSection(table, featureSectionIdIndex, 0); | ||
666 | break; | ||
667 | case "ODBCSourceAttribute": | ||
668 | ConnectTableToSection(table, odbcDataSourceSectionIdIndex, 0); | ||
669 | break; | ||
670 | case "ODBCAttribute": | ||
671 | ConnectTableToSection(table, odbcDriverSectionIdIndex, 0); | ||
672 | break; | ||
673 | case "AdminExecuteSequence": | ||
674 | case "AdminUISequence": | ||
675 | case "AdvtExecuteSequence": | ||
676 | case "AdvtUISequence": | ||
677 | case "InstallExecuteSequence": | ||
678 | case "InstallUISequence": | ||
679 | ConnectTableToSection(table, customActionSectionIdIndex, 0); | ||
680 | break; | ||
681 | case "LockPermissions": | ||
682 | case "MsiLockPermissions": | ||
683 | foreach (Row row in table.Rows) | ||
684 | { | ||
685 | string lockObject = (string)row[0]; | ||
686 | string tableName = (string)row[1]; | ||
687 | switch (tableName) | ||
688 | { | ||
689 | case "File": | ||
690 | row.SectionId = (string)fileSectionIdIndex[lockObject]; | ||
691 | break; | ||
692 | case "Registry": | ||
693 | row.SectionId = (string)registrySectionIdIndex[lockObject]; | ||
694 | break; | ||
695 | case "ServiceInstall": | ||
696 | row.SectionId = (string)serviceInstallSectionIdIndex[lockObject]; | ||
697 | break; | ||
698 | } | ||
699 | } | ||
700 | break; | ||
701 | } | ||
702 | } | ||
703 | |||
704 | // Now pass the output to each unbinder extension to allow them to analyze the output and determine thier proper section ids. | ||
705 | //foreach (IUnbinderExtension extension in this.unbinderExtensions) | ||
706 | //{ | ||
707 | // extension.GenerateSectionIds(output); | ||
708 | //} | ||
709 | } | ||
710 | |||
711 | /// <summary> | ||
712 | /// Creates new section ids on all the rows in a table. | ||
713 | /// </summary> | ||
714 | /// <param name="table">The table to add sections to.</param> | ||
715 | /// <param name="rowPrimaryKeyIndex">The index of the column which is used by other tables to reference this table.</param> | ||
716 | /// <returns>A Hashtable containing the tables key for each row paired with its assigned section id.</returns> | ||
717 | private Hashtable AssignSectionIdsToTable(Table table, int rowPrimaryKeyIndex) | ||
718 | { | ||
719 | Hashtable hashtable = new Hashtable(); | ||
720 | if (null != table) | ||
721 | { | ||
722 | foreach (Row row in table.Rows) | ||
723 | { | ||
724 | row.SectionId = GetNewSectionId(); | ||
725 | hashtable.Add(row[rowPrimaryKeyIndex], row.SectionId); | ||
726 | } | ||
727 | } | ||
728 | return hashtable; | ||
729 | } | ||
730 | |||
731 | /// <summary> | ||
732 | /// Connects a table's rows to an already sectioned table. | ||
733 | /// </summary> | ||
734 | /// <param name="table">The table containing rows that need to be connected to sections.</param> | ||
735 | /// <param name="sectionIdIndex">A hashtable containing keys to map table to its section.</param> | ||
736 | /// <param name="rowIndex">The index of the column which is used as the foreign key in to the sectionIdIndex.</param> | ||
737 | private static void ConnectTableToSection(Table table, Hashtable sectionIdIndex, int rowIndex) | ||
738 | { | ||
739 | if (null != table) | ||
740 | { | ||
741 | foreach (Row row in table.Rows) | ||
742 | { | ||
743 | if (sectionIdIndex.ContainsKey(row[rowIndex])) | ||
744 | { | ||
745 | row.SectionId = (string)sectionIdIndex[row[rowIndex]]; | ||
746 | } | ||
747 | } | ||
748 | } | ||
749 | } | ||
750 | |||
751 | /// <summary> | ||
752 | /// Connects a table's rows to an already sectioned table and produces an index for other tables to connect to it. | ||
753 | /// </summary> | ||
754 | /// <param name="table">The table containing rows that need to be connected to sections.</param> | ||
755 | /// <param name="sectionIdIndex">A hashtable containing keys to map table to its section.</param> | ||
756 | /// <param name="rowIndex">The index of the column which is used as the foreign key in to the sectionIdIndex.</param> | ||
757 | /// <param name="rowPrimaryKeyIndex">The index of the column which is used by other tables to reference this table.</param> | ||
758 | /// <returns>A Hashtable containing the tables key for each row paired with its assigned section id.</returns> | ||
759 | private static Hashtable ConnectTableToSectionAndIndex(Table table, Hashtable sectionIdIndex, int rowIndex, int rowPrimaryKeyIndex) | ||
760 | { | ||
761 | Hashtable newHashTable = new Hashtable(); | ||
762 | if (null != table) | ||
763 | { | ||
764 | foreach (Row row in table.Rows) | ||
765 | { | ||
766 | if (!sectionIdIndex.ContainsKey(row[rowIndex])) | ||
767 | { | ||
768 | continue; | ||
769 | } | ||
770 | |||
771 | row.SectionId = (string)sectionIdIndex[row[rowIndex]]; | ||
772 | if (null != row[rowPrimaryKeyIndex]) | ||
773 | { | ||
774 | newHashTable.Add(row[rowPrimaryKeyIndex], row.SectionId); | ||
775 | } | ||
776 | } | ||
777 | } | ||
778 | return newHashTable; | ||
779 | } | ||
780 | |||
781 | /// <summary> | ||
782 | /// Creates a new section identifier to be used when adding a section to an output. | ||
783 | /// </summary> | ||
784 | /// <returns>A string representing a new section id.</returns> | ||
785 | private string GetNewSectionId() | ||
786 | { | ||
787 | this.SectionCount++; | ||
788 | return "wix.section." + this.SectionCount.ToString(CultureInfo.InvariantCulture); | ||
789 | } | ||
790 | } | ||
791 | } | ||
diff --git a/src/WixToolset.Core.WindowsInstaller/Unbind/UnbindMsiOrMsmCommand.cs b/src/WixToolset.Core.WindowsInstaller/Unbind/UnbindMsiOrMsmCommand.cs new file mode 100644 index 00000000..f04dcefe --- /dev/null +++ b/src/WixToolset.Core.WindowsInstaller/Unbind/UnbindMsiOrMsmCommand.cs | |||
@@ -0,0 +1,53 @@ | |||
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.Unbind | ||
4 | { | ||
5 | using System; | ||
6 | using System.ComponentModel; | ||
7 | using WixToolset.Core.Native; | ||
8 | using WixToolset.Data; | ||
9 | using WixToolset.Extensibility; | ||
10 | using WixToolset.Msi; | ||
11 | |||
12 | internal class UnbindMsiOrMsmCommand | ||
13 | { | ||
14 | public UnbindMsiOrMsmCommand(IUnbindContext context) | ||
15 | { | ||
16 | this.Context = context; | ||
17 | } | ||
18 | |||
19 | public IUnbindContext Context { get; } | ||
20 | |||
21 | public Output Execute() | ||
22 | { | ||
23 | Output output; | ||
24 | |||
25 | try | ||
26 | { | ||
27 | using (Database database = new Database(this.Context.InputFilePath, OpenDatabase.ReadOnly)) | ||
28 | { | ||
29 | var unbindCommand = new UnbindDatabaseCommand(this.Context.Messaging, database, this.Context.InputFilePath, OutputType.Product, this.Context.ExportBasePath, this.Context.IntermediateFolder, this.Context.IsAdminImage, this.Context.SuppressDemodularization, skipSummaryInfo: false); | ||
30 | output = unbindCommand.Execute(); | ||
31 | |||
32 | // extract the files from the cabinets | ||
33 | if (!String.IsNullOrEmpty(this.Context.ExportBasePath) && !this.Context.SuppressExtractCabinets) | ||
34 | { | ||
35 | var extractCommand = new ExtractCabinetsCommand(output, database, this.Context.InputFilePath, this.Context.ExportBasePath, this.Context.IntermediateFolder); | ||
36 | extractCommand.Execute(); | ||
37 | } | ||
38 | } | ||
39 | } | ||
40 | catch (Win32Exception e) | ||
41 | { | ||
42 | if (0x6E == e.NativeErrorCode) // ERROR_OPEN_FAILED | ||
43 | { | ||
44 | throw new WixException(WixErrors.OpenDatabaseFailed(this.Context.InputFilePath)); | ||
45 | } | ||
46 | |||
47 | throw; | ||
48 | } | ||
49 | |||
50 | return output; | ||
51 | } | ||
52 | } | ||
53 | } | ||
diff --git a/src/WixToolset.Core.WindowsInstaller/Unbind/UnbindTranformCommand.cs b/src/WixToolset.Core.WindowsInstaller/Unbind/UnbindTranformCommand.cs new file mode 100644 index 00000000..c0eda9c7 --- /dev/null +++ b/src/WixToolset.Core.WindowsInstaller/Unbind/UnbindTranformCommand.cs | |||
@@ -0,0 +1,317 @@ | |||
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.Unbind | ||
4 | { | ||
5 | using System; | ||
6 | using System.Collections; | ||
7 | using System.Collections.Generic; | ||
8 | using System.ComponentModel; | ||
9 | using System.Globalization; | ||
10 | using System.IO; | ||
11 | using System.Linq; | ||
12 | using System.Text.RegularExpressions; | ||
13 | using WixToolset.Core.Native; | ||
14 | using WixToolset.Core.WindowsInstaller.Databases; | ||
15 | using WixToolset.Data; | ||
16 | using WixToolset.Data.Rows; | ||
17 | using WixToolset.Extensibility; | ||
18 | using WixToolset.Msi; | ||
19 | |||
20 | internal class UnbindTransformCommand | ||
21 | { | ||
22 | public UnbindTransformCommand(Messaging messaging, string transformFile, string exportBasePath, string intermediateFolder) | ||
23 | { | ||
24 | this.Messaging = messaging; | ||
25 | this.TransformFile = transformFile; | ||
26 | this.ExportBasePath = exportBasePath; | ||
27 | this.IntermediateFolder = intermediateFolder; | ||
28 | |||
29 | this.TableDefinitions = WindowsInstallerStandard.GetTableDefinitions(); | ||
30 | } | ||
31 | |||
32 | private Messaging Messaging { get; } | ||
33 | |||
34 | private string TransformFile { get; } | ||
35 | |||
36 | private string ExportBasePath { get; } | ||
37 | |||
38 | private string IntermediateFolder { get; } | ||
39 | |||
40 | private TableDefinitionCollection TableDefinitions { get; } | ||
41 | |||
42 | private string EmptyFile { get; set; } | ||
43 | |||
44 | public Output Execute() | ||
45 | { | ||
46 | Output transform = new Output(new SourceLineNumber(this.TransformFile)); | ||
47 | transform.Type = OutputType.Transform; | ||
48 | |||
49 | // get the summary information table | ||
50 | using (SummaryInformation summaryInformation = new SummaryInformation(this.TransformFile)) | ||
51 | { | ||
52 | Table table = transform.EnsureTable(this.TableDefinitions["_SummaryInformation"]); | ||
53 | |||
54 | for (int i = 1; 19 >= i; i++) | ||
55 | { | ||
56 | string value = summaryInformation.GetProperty(i); | ||
57 | |||
58 | if (0 < value.Length) | ||
59 | { | ||
60 | Row row = table.CreateRow(transform.SourceLineNumbers); | ||
61 | row[0] = i; | ||
62 | row[1] = value; | ||
63 | } | ||
64 | } | ||
65 | } | ||
66 | |||
67 | // create a schema msi which hopefully matches the table schemas in the transform | ||
68 | Output schemaOutput = new Output(null); | ||
69 | string msiDatabaseFile = Path.Combine(this.IntermediateFolder, "schema.msi"); | ||
70 | foreach (TableDefinition tableDefinition in this.TableDefinitions) | ||
71 | { | ||
72 | // skip unreal tables and the Patch table | ||
73 | if (!tableDefinition.Unreal && "Patch" != tableDefinition.Name) | ||
74 | { | ||
75 | schemaOutput.EnsureTable(tableDefinition); | ||
76 | } | ||
77 | } | ||
78 | |||
79 | Hashtable addedRows = new Hashtable(); | ||
80 | Table transformViewTable; | ||
81 | |||
82 | // Bind the schema msi. | ||
83 | this.GenerateDatabase(schemaOutput, msiDatabaseFile); | ||
84 | |||
85 | // apply the transform to the database and retrieve the modifications | ||
86 | using (Database msiDatabase = new Database(msiDatabaseFile, OpenDatabase.Transact)) | ||
87 | { | ||
88 | // apply the transform with the ViewTransform option to collect all the modifications | ||
89 | msiDatabase.ApplyTransform(this.TransformFile, TransformErrorConditions.All | TransformErrorConditions.ViewTransform); | ||
90 | |||
91 | // unbind the database | ||
92 | var unbindCommand = new UnbindDatabaseCommand(this.Messaging, msiDatabase, msiDatabaseFile, OutputType.Product, this.ExportBasePath, this.IntermediateFolder, false, false, skipSummaryInfo: true); | ||
93 | Output transformViewOutput = unbindCommand.Execute(); | ||
94 | |||
95 | // index the added and possibly modified rows (added rows may also appears as modified rows) | ||
96 | transformViewTable = transformViewOutput.Tables["_TransformView"]; | ||
97 | Hashtable modifiedRows = new Hashtable(); | ||
98 | foreach (Row row in transformViewTable.Rows) | ||
99 | { | ||
100 | string tableName = (string)row[0]; | ||
101 | string columnName = (string)row[1]; | ||
102 | string primaryKeys = (string)row[2]; | ||
103 | |||
104 | if ("INSERT" == columnName) | ||
105 | { | ||
106 | string index = String.Concat(tableName, ':', primaryKeys); | ||
107 | |||
108 | addedRows.Add(index, null); | ||
109 | } | ||
110 | else if ("CREATE" != columnName && "DELETE" != columnName && "DROP" != columnName && null != primaryKeys) // modified row | ||
111 | { | ||
112 | string index = String.Concat(tableName, ':', primaryKeys); | ||
113 | |||
114 | modifiedRows[index] = row; | ||
115 | } | ||
116 | } | ||
117 | |||
118 | // create placeholder rows for modified rows to make the transform insert the updated values when its applied | ||
119 | foreach (Row row in modifiedRows.Values) | ||
120 | { | ||
121 | string tableName = (string)row[0]; | ||
122 | string columnName = (string)row[1]; | ||
123 | string primaryKeys = (string)row[2]; | ||
124 | |||
125 | string index = String.Concat(tableName, ':', primaryKeys); | ||
126 | |||
127 | // ignore information for added rows | ||
128 | if (!addedRows.Contains(index)) | ||
129 | { | ||
130 | Table table = schemaOutput.Tables[tableName]; | ||
131 | this.CreateRow(table, primaryKeys, true); | ||
132 | } | ||
133 | } | ||
134 | } | ||
135 | |||
136 | // Re-bind the schema output with the placeholder rows. | ||
137 | this.GenerateDatabase(schemaOutput, msiDatabaseFile); | ||
138 | |||
139 | // apply the transform to the database and retrieve the modifications | ||
140 | using (Database msiDatabase = new Database(msiDatabaseFile, OpenDatabase.Transact)) | ||
141 | { | ||
142 | try | ||
143 | { | ||
144 | // apply the transform | ||
145 | msiDatabase.ApplyTransform(this.TransformFile, TransformErrorConditions.All); | ||
146 | |||
147 | // commit the database to guard against weird errors with streams | ||
148 | msiDatabase.Commit(); | ||
149 | } | ||
150 | catch (Win32Exception ex) | ||
151 | { | ||
152 | if (0x65B == ex.NativeErrorCode) | ||
153 | { | ||
154 | // this commonly happens when the transform was built | ||
155 | // against a database schema different from the internal | ||
156 | // table definitions | ||
157 | throw new WixException(WixErrors.TransformSchemaMismatch()); | ||
158 | } | ||
159 | } | ||
160 | |||
161 | // unbind the database | ||
162 | var unbindCommand = new UnbindDatabaseCommand(this.Messaging, msiDatabase, msiDatabaseFile, OutputType.Product, this.ExportBasePath, this.IntermediateFolder, false, false, skipSummaryInfo: true); | ||
163 | Output output = unbindCommand.Execute(); | ||
164 | |||
165 | // index all the rows to easily find modified rows | ||
166 | Hashtable rows = new Hashtable(); | ||
167 | foreach (Table table in output.Tables) | ||
168 | { | ||
169 | foreach (Row row in table.Rows) | ||
170 | { | ||
171 | rows.Add(String.Concat(table.Name, ':', row.GetPrimaryKey('\t', " ")), row); | ||
172 | } | ||
173 | } | ||
174 | |||
175 | // process the _TransformView rows into transform rows | ||
176 | foreach (Row row in transformViewTable.Rows) | ||
177 | { | ||
178 | string tableName = (string)row[0]; | ||
179 | string columnName = (string)row[1]; | ||
180 | string primaryKeys = (string)row[2]; | ||
181 | |||
182 | Table table = transform.EnsureTable(this.TableDefinitions[tableName]); | ||
183 | |||
184 | if ("CREATE" == columnName) // added table | ||
185 | { | ||
186 | table.Operation = TableOperation.Add; | ||
187 | } | ||
188 | else if ("DELETE" == columnName) // deleted row | ||
189 | { | ||
190 | Row deletedRow = this.CreateRow(table, primaryKeys, false); | ||
191 | deletedRow.Operation = RowOperation.Delete; | ||
192 | } | ||
193 | else if ("DROP" == columnName) // dropped table | ||
194 | { | ||
195 | table.Operation = TableOperation.Drop; | ||
196 | } | ||
197 | else if ("INSERT" == columnName) // added row | ||
198 | { | ||
199 | string index = String.Concat(tableName, ':', primaryKeys); | ||
200 | Row addedRow = (Row)rows[index]; | ||
201 | addedRow.Operation = RowOperation.Add; | ||
202 | table.Rows.Add(addedRow); | ||
203 | } | ||
204 | else if (null != primaryKeys) // modified row | ||
205 | { | ||
206 | string index = String.Concat(tableName, ':', primaryKeys); | ||
207 | |||
208 | // the _TransformView table includes information for added rows | ||
209 | // that looks like modified rows so it sometimes needs to be ignored | ||
210 | if (!addedRows.Contains(index)) | ||
211 | { | ||
212 | Row modifiedRow = (Row)rows[index]; | ||
213 | |||
214 | // mark the field as modified | ||
215 | int indexOfModifiedValue = -1; | ||
216 | for (int i = 0; i < modifiedRow.TableDefinition.Columns.Count; ++i) | ||
217 | { | ||
218 | if (columnName.Equals(modifiedRow.TableDefinition.Columns[i].Name, StringComparison.Ordinal)) | ||
219 | { | ||
220 | indexOfModifiedValue = i; | ||
221 | break; | ||
222 | } | ||
223 | } | ||
224 | modifiedRow.Fields[indexOfModifiedValue].Modified = true; | ||
225 | |||
226 | // move the modified row into the transform the first time its encountered | ||
227 | if (RowOperation.None == modifiedRow.Operation) | ||
228 | { | ||
229 | modifiedRow.Operation = RowOperation.Modify; | ||
230 | table.Rows.Add(modifiedRow); | ||
231 | } | ||
232 | } | ||
233 | } | ||
234 | else // added column | ||
235 | { | ||
236 | ColumnDefinition column = table.Definition.Columns.Single(c => c.Name.Equals(columnName, StringComparison.Ordinal)); | ||
237 | column.Added = true; | ||
238 | } | ||
239 | } | ||
240 | } | ||
241 | |||
242 | return transform; | ||
243 | } | ||
244 | |||
245 | private void GenerateDatabase(Output output, string databaseFile) | ||
246 | { | ||
247 | var command = new GenerateDatabaseCommand(); | ||
248 | command.Extensions = Array.Empty<IBinderExtension>(); | ||
249 | command.Output = output; | ||
250 | command.OutputPath = databaseFile; | ||
251 | command.KeepAddedColumns = true; | ||
252 | command.UseSubDirectory = false; | ||
253 | command.SuppressAddingValidationRows = true; | ||
254 | command.TableDefinitions = this.TableDefinitions; | ||
255 | command.TempFilesLocation = this.IntermediateFolder; | ||
256 | command.Codepage = -1; | ||
257 | command.Execute(); | ||
258 | } | ||
259 | |||
260 | /// <summary> | ||
261 | /// Create a deleted or modified row. | ||
262 | /// </summary> | ||
263 | /// <param name="table">The table containing the row.</param> | ||
264 | /// <param name="primaryKeys">The primary keys of the row.</param> | ||
265 | /// <param name="setRequiredFields">Option to set all required fields with placeholder values.</param> | ||
266 | /// <returns>The new row.</returns> | ||
267 | private Row CreateRow(Table table, string primaryKeys, bool setRequiredFields) | ||
268 | { | ||
269 | Row row = table.CreateRow(null); | ||
270 | |||
271 | string[] primaryKeyParts = primaryKeys.Split('\t'); | ||
272 | int primaryKeyPartIndex = 0; | ||
273 | |||
274 | for (int i = 0; i < table.Definition.Columns.Count; i++) | ||
275 | { | ||
276 | ColumnDefinition columnDefinition = table.Definition.Columns[i]; | ||
277 | |||
278 | if (columnDefinition.PrimaryKey) | ||
279 | { | ||
280 | if (ColumnType.Number == columnDefinition.Type && !columnDefinition.IsLocalizable) | ||
281 | { | ||
282 | row[i] = Convert.ToInt32(primaryKeyParts[primaryKeyPartIndex++], CultureInfo.InvariantCulture); | ||
283 | } | ||
284 | else | ||
285 | { | ||
286 | row[i] = primaryKeyParts[primaryKeyPartIndex++]; | ||
287 | } | ||
288 | } | ||
289 | else if (setRequiredFields) | ||
290 | { | ||
291 | if (ColumnType.Number == columnDefinition.Type && !columnDefinition.IsLocalizable) | ||
292 | { | ||
293 | row[i] = 1; | ||
294 | } | ||
295 | else if (ColumnType.Object == columnDefinition.Type) | ||
296 | { | ||
297 | if (null == this.EmptyFile) | ||
298 | { | ||
299 | this.EmptyFile = Path.GetTempFileName() + ".empty"; | ||
300 | using (FileStream fileStream = File.Create(this.EmptyFile)) | ||
301 | { | ||
302 | } | ||
303 | } | ||
304 | |||
305 | row[i] = this.EmptyFile; | ||
306 | } | ||
307 | else | ||
308 | { | ||
309 | row[i] = "1"; | ||
310 | } | ||
311 | } | ||
312 | } | ||
313 | |||
314 | return row; | ||
315 | } | ||
316 | } | ||
317 | } | ||
diff --git a/src/WixToolset.Core/Validator.cs b/src/WixToolset.Core.WindowsInstaller/Validator.cs index 6420b9b7..db66f600 100644 --- a/src/WixToolset.Core/Validator.cs +++ b/src/WixToolset.Core.WindowsInstaller/Validator.cs | |||
@@ -1,6 +1,6 @@ | |||
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 | 3 | namespace WixToolset.Core.WindowsInstaller |
4 | { | 4 | { |
5 | using System; | 5 | using System; |
6 | using System.Collections.Generic; | 6 | using System.Collections.Generic; |
@@ -12,8 +12,10 @@ namespace WixToolset | |||
12 | using System.Threading; | 12 | using System.Threading; |
13 | using WixToolset.Data; | 13 | using WixToolset.Data; |
14 | using WixToolset.Extensibility; | 14 | using WixToolset.Extensibility; |
15 | using WixToolset.Msi; | ||
16 | using WixToolset.Core.Native; | 15 | using WixToolset.Core.Native; |
16 | using WixToolset.Msi; | ||
17 | using System.Linq; | ||
18 | using System.Reflection; | ||
17 | 19 | ||
18 | /// <summary> | 20 | /// <summary> |
19 | /// Runs internal consistency evaluators (ICEs) from cub files against a database. | 21 | /// Runs internal consistency evaluators (ICEs) from cub files against a database. |
@@ -23,9 +25,7 @@ namespace WixToolset | |||
23 | private string actionName; | 25 | private string actionName; |
24 | private StringCollection cubeFiles; | 26 | private StringCollection cubeFiles; |
25 | private ValidatorExtension extension; | 27 | private ValidatorExtension extension; |
26 | private string[] ices; | ||
27 | private Output output; | 28 | private Output output; |
28 | private string[] suppressedICEs; | ||
29 | private InstallUIHandler validationUIHandler; | 29 | private InstallUIHandler validationUIHandler; |
30 | private bool validationSessionComplete; | 30 | private bool validationSessionComplete; |
31 | 31 | ||
@@ -54,11 +54,7 @@ namespace WixToolset | |||
54 | /// </summary> | 54 | /// </summary> |
55 | /// <value>The list of ICEs.</value> | 55 | /// <value>The list of ICEs.</value> |
56 | [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] | 56 | [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] |
57 | public string[] ICEs | 57 | public ISet<string> ICEs { get; set; } |
58 | { | ||
59 | get { return this.ices; } | ||
60 | set { this.ices = value; } | ||
61 | } | ||
62 | 58 | ||
63 | /// <summary> | 59 | /// <summary> |
64 | /// Gets or sets the output used for finding source line information. | 60 | /// Gets or sets the output used for finding source line information. |
@@ -76,16 +72,12 @@ namespace WixToolset | |||
76 | /// </summary> | 72 | /// </summary> |
77 | /// <value>The suppressed ICEs.</value> | 73 | /// <value>The suppressed ICEs.</value> |
78 | [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] | 74 | [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] |
79 | public string[] SuppressedICEs | 75 | public ISet<string> SuppressedICEs { get; set; } |
80 | { | ||
81 | get { return this.suppressedICEs; } | ||
82 | set { this.suppressedICEs = value; } | ||
83 | } | ||
84 | 76 | ||
85 | /// <summary> | 77 | /// <summary> |
86 | /// Sets the temporary path for the Binder. | 78 | /// Sets the temporary path for the Binder. |
87 | /// </summary> | 79 | /// </summary> |
88 | public string TempFilesLocation { private get; set; } | 80 | public string IntermediateFolder { private get; set; } |
89 | 81 | ||
90 | /// <summary> | 82 | /// <summary> |
91 | /// Add a cube file to the validation run. | 83 | /// Add a cube file to the validation run. |
@@ -103,8 +95,6 @@ namespace WixToolset | |||
103 | /// <returns>true if validation succeeded; false otherwise.</returns> | 95 | /// <returns>true if validation succeeded; false otherwise.</returns> |
104 | public void Validate(string databaseFile) | 96 | public void Validate(string databaseFile) |
105 | { | 97 | { |
106 | Dictionary<string, string> indexedICEs = new Dictionary<string, string>(); | ||
107 | Dictionary<string, string> indexedSuppressedICEs = new Dictionary<string, string>(); | ||
108 | int previousUILevel = (int)InstallUILevels.Basic; | 98 | int previousUILevel = (int)InstallUILevels.Basic; |
109 | IntPtr previousHwnd = IntPtr.Zero; | 99 | IntPtr previousHwnd = IntPtr.Zero; |
110 | InstallUIHandler previousUIHandler = null; | 100 | InstallUIHandler previousUIHandler = null; |
@@ -120,28 +110,10 @@ namespace WixToolset | |||
120 | this.extension.InitializeValidator(); | 110 | this.extension.InitializeValidator(); |
121 | 111 | ||
122 | // Ensure the temporary files can be created. | 112 | // Ensure the temporary files can be created. |
123 | Directory.CreateDirectory(this.TempFilesLocation); | 113 | Directory.CreateDirectory(this.IntermediateFolder); |
124 | |||
125 | // index the ICEs | ||
126 | if (null != this.ices) | ||
127 | { | ||
128 | foreach (string ice in this.ices) | ||
129 | { | ||
130 | indexedICEs[ice] = null; | ||
131 | } | ||
132 | } | ||
133 | |||
134 | // index the suppressed ICEs | ||
135 | if (null != this.suppressedICEs) | ||
136 | { | ||
137 | foreach (string suppressedICE in this.suppressedICEs) | ||
138 | { | ||
139 | indexedSuppressedICEs[suppressedICE] = null; | ||
140 | } | ||
141 | } | ||
142 | 114 | ||
143 | // copy the database to a temporary location so it can be manipulated | 115 | // copy the database to a temporary location so it can be manipulated |
144 | string tempDatabaseFile = Path.Combine(this.TempFilesLocation, Path.GetFileName(databaseFile)); | 116 | string tempDatabaseFile = Path.Combine(this.IntermediateFolder, Path.GetFileName(databaseFile)); |
145 | File.Copy(databaseFile, tempDatabaseFile); | 117 | File.Copy(databaseFile, tempDatabaseFile); |
146 | 118 | ||
147 | // remove the read-only property from the temporary database | 119 | // remove the read-only property from the temporary database |
@@ -236,7 +208,7 @@ namespace WixToolset | |||
236 | 208 | ||
237 | string action = record.GetString(1); | 209 | string action = record.GetString(1); |
238 | 210 | ||
239 | if (!indexedSuppressedICEs.ContainsKey(action)) | 211 | if ((this.SuppressedICEs == null || !this.SuppressedICEs.Contains(action)) && (this.ICEs == null || this.ICEs.Contains(action))) |
240 | { | 212 | { |
241 | actions.Add(action); | 213 | actions.Add(action); |
242 | } | 214 | } |
@@ -244,18 +216,6 @@ namespace WixToolset | |||
244 | } | 216 | } |
245 | } | 217 | } |
246 | 218 | ||
247 | if (0 != indexedICEs.Count) | ||
248 | { | ||
249 | // Walk backwards and remove those that arent in the list | ||
250 | for (int i = actions.Count - 1; 0 <= i; i--) | ||
251 | { | ||
252 | if (!indexedICEs.ContainsKey(actions[i])) | ||
253 | { | ||
254 | actions.RemoveAt(i); | ||
255 | } | ||
256 | } | ||
257 | } | ||
258 | |||
259 | // disable the internal UI handler and set an external UI handler | 219 | // disable the internal UI handler and set an external UI handler |
260 | previousUILevel = Installer.SetInternalUI((int)InstallUILevels.None, ref previousHwnd); | 220 | previousUILevel = Installer.SetInternalUI((int)InstallUILevels.None, ref previousHwnd); |
261 | previousUIHandler = Installer.SetExternalUI(this.validationUIHandler, (int)InstallLogModes.Error | (int)InstallLogModes.Warning | (int)InstallLogModes.User, IntPtr.Zero); | 221 | previousUIHandler = Installer.SetExternalUI(this.validationUIHandler, (int)InstallLogModes.Error | (int)InstallLogModes.Warning | (int)InstallLogModes.User, IntPtr.Zero); |
@@ -370,6 +330,30 @@ namespace WixToolset | |||
370 | this.extension.OnMessage(e); | 330 | this.extension.OnMessage(e); |
371 | } | 331 | } |
372 | 332 | ||
333 | public static Validator CreateFromContext(IBindContext context, string cubeFilename) | ||
334 | { | ||
335 | Validator validator = null; | ||
336 | |||
337 | // Tell the binder about the validator if validation isn't suppressed | ||
338 | if (!context.SuppressValidation) | ||
339 | { | ||
340 | validator = new Validator(); | ||
341 | validator.IntermediateFolder = Path.Combine(context.IntermediateFolder, "validate"); | ||
342 | |||
343 | // set the default cube file | ||
344 | string thisPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); | ||
345 | validator.AddCubeFile(Path.Combine(thisPath, cubeFilename)); | ||
346 | |||
347 | // Set the ICEs | ||
348 | validator.ICEs = new SortedSet<string>(context.Ices); | ||
349 | |||
350 | // Set the suppressed ICEs and disable ICEs that have equivalent-or-better checks in WiX. | ||
351 | validator.SuppressedICEs = new SortedSet<string>(context.SuppressIces.Union(new[] { "ICE08", "ICE33", "ICE47", "ICE66" })); | ||
352 | } | ||
353 | |||
354 | return validator; | ||
355 | } | ||
356 | |||
373 | /// <summary> | 357 | /// <summary> |
374 | /// The validation external UI handler. | 358 | /// The validation external UI handler. |
375 | /// </summary> | 359 | /// </summary> |
diff --git a/src/WixToolset.Core/Extensibility/ValidatorExtension.cs b/src/WixToolset.Core.WindowsInstaller/ValidatorExtension.cs index 44ec3106..44ec3106 100644 --- a/src/WixToolset.Core/Extensibility/ValidatorExtension.cs +++ b/src/WixToolset.Core.WindowsInstaller/ValidatorExtension.cs | |||
diff --git a/src/WixToolset.Core.WindowsInstaller/WindowsInstallerBackendFactory.cs b/src/WixToolset.Core.WindowsInstaller/WindowsInstallerBackendFactory.cs new file mode 100644 index 00000000..b66a4617 --- /dev/null +++ b/src/WixToolset.Core.WindowsInstaller/WindowsInstallerBackendFactory.cs | |||
@@ -0,0 +1,50 @@ | |||
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 | ||
4 | { | ||
5 | using System; | ||
6 | using System.IO; | ||
7 | using WixToolset.Extensibility; | ||
8 | |||
9 | internal class WindowsInstallerBackendFactory : IBackendFactory | ||
10 | { | ||
11 | public bool TryCreateBackend(string outputType, string outputFile, IBindContext context, out IBackend backend) | ||
12 | { | ||
13 | if (String.IsNullOrEmpty(outputType)) | ||
14 | { | ||
15 | outputType = Path.GetExtension(outputFile); | ||
16 | } | ||
17 | |||
18 | switch (outputType.ToLowerInvariant()) | ||
19 | { | ||
20 | case "module": | ||
21 | case ".msm": | ||
22 | backend = new MsmBackend(); | ||
23 | return true; | ||
24 | |||
25 | case "msipackage": | ||
26 | case "product": | ||
27 | case ".msi": | ||
28 | backend = new MsiBackend(); | ||
29 | return true; | ||
30 | |||
31 | case "patch": | ||
32 | case ".msp": | ||
33 | backend = new MspBackend(); | ||
34 | return true; | ||
35 | |||
36 | //case "patchcreation": | ||
37 | //case ".pcp": | ||
38 | // return new PatchCreationBackend(); | ||
39 | |||
40 | case "transform": | ||
41 | case ".mst": | ||
42 | backend = new MstBackend(); | ||
43 | return true; | ||
44 | } | ||
45 | |||
46 | backend = null; | ||
47 | return false; | ||
48 | } | ||
49 | } | ||
50 | } | ||
diff --git a/src/WixToolset.Core.WindowsInstaller/WixToolset.Core.WindowsInstaller.csproj b/src/WixToolset.Core.WindowsInstaller/WixToolset.Core.WindowsInstaller.csproj new file mode 100644 index 00000000..d74cb1e8 --- /dev/null +++ b/src/WixToolset.Core.WindowsInstaller/WixToolset.Core.WindowsInstaller.csproj | |||
@@ -0,0 +1,36 @@ | |||
1 | <?xml version="1.0" encoding="utf-8"?> | ||
2 | <!-- 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. --> | ||
3 | |||
4 | <Project Sdk="Microsoft.NET.Sdk"> | ||
5 | <PropertyGroup> | ||
6 | <TargetFramework>netstandard2.0</TargetFramework> | ||
7 | <Description>Core Windows Installer</Description> | ||
8 | <Title>WiX Toolset Core Windows Installer</Title> | ||
9 | </PropertyGroup> | ||
10 | |||
11 | <PropertyGroup> | ||
12 | <NoWarn>NU1701</NoWarn> | ||
13 | </PropertyGroup> | ||
14 | |||
15 | <ItemGroup> | ||
16 | <ProjectReference Include="$(WixToolsetRootFolder)\Data\src\WixToolset.Data\WixToolset.Data.csproj" Condition=" '$(Configuration)' == 'Debug' And Exists('$(WixToolsetRootFolder)\Data\src\WixToolset.Data\WixToolset.Data.csproj') " /> | ||
17 | <PackageReference Include="WixToolset.Data" Version="4.0.*" Condition=" '$(Configuration)' == 'Release' Or !Exists('$(WixToolsetRootFolder)\Data\src\WixToolset.Data\WixToolset.Data.csproj') " /> | ||
18 | |||
19 | <ProjectReference Include="$(WixToolsetRootFolder)\Extensibility\src\WixToolset.Extensibility\WixToolset.Extensibility.csproj" Condition=" '$(Configuration)' == 'Debug' And Exists('$(WixToolsetRootFolder)\Extensibility\src\WixToolset.Extensibility\WixToolset.Extensibility.csproj') " /> | ||
20 | <PackageReference Include="WixToolset.Extensibility" Version="4.0.*" Condition=" '$(Configuration)' == 'Release' Or !Exists('$(WixToolsetRootFolder)\Extensibility\src\WixToolset.Extensibility\WixToolset.Extensibility.csproj') " /> | ||
21 | |||
22 | <ProjectReference Include="$(WixToolsetRootFolder)\Core.Native\src\WixToolset.Core.Native\WixToolset.Core.Native.csproj" Condition=" '$(Configuration)' == 'Debug' And Exists('$(WixToolsetRootFolder)\Core.Native\src\WixToolset.Core.Native\WixToolset.Core.Native.csproj') " /> | ||
23 | |||
24 | <ProjectReference Include="..\WixToolset.Core\WixToolset.Core.csproj" /> | ||
25 | <PackageReference Include="WixToolset.Core.Native" Version="4.0.*" Condition=" '$(Configuration)' == 'Release' Or !Exists('$(WixToolsetRootFolder)\Core.Native\src\WixToolset.Core.Native\WixToolset.Core.Native.csproj') " /> | ||
26 | </ItemGroup> | ||
27 | |||
28 | <ItemGroup> | ||
29 | <PackageReference Include="WixToolset.Dtf.Resources" Version="4.0.*" /> | ||
30 | <PackageReference Include="WixToolset.Dtf.WindowsInstaller" Version="4.0.*" /> | ||
31 | </ItemGroup> | ||
32 | |||
33 | <ItemGroup> | ||
34 | <PackageReference Include="Nerdbank.GitVersioning" Version="2.0.41" PrivateAssets="all" /> | ||
35 | </ItemGroup> | ||
36 | </Project> | ||
diff --git a/src/WixToolset.Core/BackendContext.cs b/src/WixToolset.Core/BackendContext.cs new file mode 100644 index 00000000..7166a3a3 --- /dev/null +++ b/src/WixToolset.Core/BackendContext.cs | |||
@@ -0,0 +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. | ||
2 | |||
3 | namespace WixToolset.Core | ||
4 | { | ||
5 | using WixToolset.Data; | ||
6 | |||
7 | public class BackendContext | ||
8 | { | ||
9 | internal BackendContext() | ||
10 | { | ||
11 | this.Messaging = Messaging.Instance; | ||
12 | } | ||
13 | |||
14 | public Messaging Messaging { get; } | ||
15 | } | ||
16 | } | ||
diff --git a/src/WixToolset.Core/Bind/DelayedField.cs b/src/WixToolset.Core/Bind/DelayedField.cs index 181ac3e3..6c56f27c 100644 --- a/src/WixToolset.Core/Bind/DelayedField.cs +++ b/src/WixToolset.Core/Bind/DelayedField.cs | |||
@@ -1,18 +1,15 @@ | |||
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.Bind | 3 | namespace WixToolset.Core.Bind |
4 | { | 4 | { |
5 | using System; | ||
6 | using System.Collections.Generic; | ||
7 | using System.Linq; | ||
8 | using System.Text; | ||
9 | using WixToolset.Data; | 5 | using WixToolset.Data; |
6 | using WixToolset.Extensibility; | ||
10 | 7 | ||
11 | /// <summary> | 8 | /// <summary> |
12 | /// Structure used to hold a row and field that contain binder variables, which need to be resolved | 9 | /// Structure used to hold a row and field that contain binder variables, which need to be resolved |
13 | /// later, once the files have been resolved. | 10 | /// later, once the files have been resolved. |
14 | /// </summary> | 11 | /// </summary> |
15 | internal class DelayedField | 12 | internal class DelayedField : IDelayedField |
16 | { | 13 | { |
17 | /// <summary> | 14 | /// <summary> |
18 | /// Basic constructor for struct | 15 | /// Basic constructor for struct |
@@ -28,11 +25,11 @@ namespace WixToolset.Bind | |||
28 | /// <summary> | 25 | /// <summary> |
29 | /// The row containing the field. | 26 | /// The row containing the field. |
30 | /// </summary> | 27 | /// </summary> |
31 | public Row Row { get; private set; } | 28 | public Row Row { get; } |
32 | 29 | ||
33 | /// <summary> | 30 | /// <summary> |
34 | /// The field needing further resolving. | 31 | /// The field needing further resolving. |
35 | /// </summary> | 32 | /// </summary> |
36 | public Field Field { get; private set; } | 33 | public Field Field { get; } |
37 | } | 34 | } |
38 | } | 35 | } |
diff --git a/src/WixToolset.Core/Bind/ExpectedExtractFile.cs b/src/WixToolset.Core/Bind/ExpectedExtractFile.cs new file mode 100644 index 00000000..fc2b43c7 --- /dev/null +++ b/src/WixToolset.Core/Bind/ExpectedExtractFile.cs | |||
@@ -0,0 +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. | ||
2 | |||
3 | namespace WixToolset.Core.Bind | ||
4 | { | ||
5 | using System; | ||
6 | using WixToolset.Extensibility; | ||
7 | |||
8 | internal class ExpectedExtractFile : IExpectedExtractFile | ||
9 | { | ||
10 | public Uri Uri { get; set; } | ||
11 | |||
12 | public int EmbeddedFileIndex { get; set; } | ||
13 | |||
14 | public string OutputPath { get; set; } | ||
15 | } | ||
16 | } | ||
diff --git a/src/WixToolset.Core/Bind/ExtractEmbeddedFiles.cs b/src/WixToolset.Core/Bind/ExtractEmbeddedFiles.cs index 0ecd0096..28fc4817 100644 --- a/src/WixToolset.Core/Bind/ExtractEmbeddedFiles.cs +++ b/src/WixToolset.Core/Bind/ExtractEmbeddedFiles.cs | |||
@@ -1,6 +1,6 @@ | |||
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.Bind | 3 | namespace WixToolset.Core.Bind |
4 | { | 4 | { |
5 | using System; | 5 | using System; |
6 | using System.Collections.Generic; | 6 | using System.Collections.Generic; |
@@ -13,11 +13,11 @@ namespace WixToolset.Bind | |||
13 | /// <summary> | 13 | /// <summary> |
14 | /// Internal helper class used to extract embedded files. | 14 | /// Internal helper class used to extract embedded files. |
15 | /// </summary> | 15 | /// </summary> |
16 | internal sealed class ExtractEmbeddedFiles | 16 | internal class ExtractEmbeddedFiles |
17 | { | 17 | { |
18 | private Dictionary<Uri, SortedList<int, string>> filesWithEmbeddedFiles = new Dictionary<Uri, SortedList<int, string>>(); | 18 | private Dictionary<Uri, SortedList<int, string>> filesWithEmbeddedFiles = new Dictionary<Uri, SortedList<int, string>>(); |
19 | 19 | ||
20 | public IEnumerable<Uri> Uris { get { return this.filesWithEmbeddedFiles.Keys; } } | 20 | public IEnumerable<Uri> Uris => this.filesWithEmbeddedFiles.Keys; |
21 | 21 | ||
22 | /// <summary> | 22 | /// <summary> |
23 | /// Adds an embedded file index to track and returns the path where the embedded file will be extracted. Duplicates will return the same extract path. | 23 | /// Adds an embedded file index to track and returns the path where the embedded file will be extracted. Duplicates will return the same extract path. |
@@ -53,15 +53,30 @@ namespace WixToolset.Bind | |||
53 | return extractPath; | 53 | return extractPath; |
54 | } | 54 | } |
55 | 55 | ||
56 | public IEnumerable<ExtractFile> GetExtractFilesForUri(Uri uri) | 56 | public IEnumerable<ExpectedExtractFile> GetExpectedEmbeddedFiles() |
57 | { | 57 | { |
58 | SortedList<int, string> extracts; | 58 | foreach (var uriWithExtracts in filesWithEmbeddedFiles) |
59 | if (!filesWithEmbeddedFiles.TryGetValue(uri, out extracts)) | 59 | { |
60 | foreach (var extracts in uriWithExtracts.Value) | ||
61 | { | ||
62 | yield return new ExpectedExtractFile | ||
63 | { | ||
64 | Uri = uriWithExtracts.Key, | ||
65 | EmbeddedFileIndex = extracts.Key, | ||
66 | OutputPath = extracts.Value, | ||
67 | }; | ||
68 | } | ||
69 | } | ||
70 | } | ||
71 | |||
72 | public IEnumerable<ExpectedExtractFile> GetExtractFilesForUri(Uri uri) | ||
73 | { | ||
74 | if (!filesWithEmbeddedFiles.TryGetValue(uri, out var extracts)) | ||
60 | { | 75 | { |
61 | extracts = new SortedList<int, string>(); | 76 | extracts = new SortedList<int, string>(); |
62 | } | 77 | } |
63 | 78 | ||
64 | return extracts.Select(e => new ExtractFile() { EmbeddedFileIndex = e.Key, OutputPath = e.Value }); | 79 | return extracts.Select(e => new ExpectedExtractFile() { Uri = uri, EmbeddedFileIndex = e.Key, OutputPath = e.Value }); |
65 | } | 80 | } |
66 | 81 | ||
67 | private string HashUri(string uri) | 82 | private string HashUri(string uri) |
@@ -72,12 +87,5 @@ namespace WixToolset.Bind | |||
72 | return Convert.ToBase64String(hash).TrimEnd('=').Replace('+', '-').Replace('/', '_'); | 87 | return Convert.ToBase64String(hash).TrimEnd('=').Replace('+', '-').Replace('/', '_'); |
73 | } | 88 | } |
74 | } | 89 | } |
75 | |||
76 | internal struct ExtractFile | ||
77 | { | ||
78 | public int EmbeddedFileIndex { get; set; } | ||
79 | |||
80 | public string OutputPath { get; set; } | ||
81 | } | ||
82 | } | 90 | } |
83 | } | 91 | } |
diff --git a/src/WixToolset.Core/Bind/ExtractEmbeddedFilesCommand.cs b/src/WixToolset.Core/Bind/ExtractEmbeddedFilesCommand.cs index 68bfd8d7..7de40fb8 100644 --- a/src/WixToolset.Core/Bind/ExtractEmbeddedFilesCommand.cs +++ b/src/WixToolset.Core/Bind/ExtractEmbeddedFilesCommand.cs | |||
@@ -1,19 +1,26 @@ | |||
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.Bind | 3 | namespace WixToolset.Core.Bind |
4 | { | 4 | { |
5 | using System.Collections.Generic; | ||
5 | using System.IO; | 6 | using System.IO; |
7 | using System.Linq; | ||
6 | using System.Reflection; | 8 | using System.Reflection; |
7 | using WixToolset.Data; | 9 | using WixToolset.Data; |
10 | using WixToolset.Extensibility; | ||
8 | 11 | ||
9 | internal class ExtractEmbeddedFilesCommand : ICommand | 12 | public class ExtractEmbeddedFilesCommand |
10 | { | 13 | { |
11 | public ExtractEmbeddedFiles FilesWithEmbeddedFiles { private get; set; } | 14 | public IEnumerable<IExpectedExtractFile> FilesWithEmbeddedFiles { private get; set; } |
12 | 15 | ||
13 | public void Execute() | 16 | public void Execute() |
14 | { | 17 | { |
15 | foreach (var baseUri in this.FilesWithEmbeddedFiles.Uris) | 18 | var group = this.FilesWithEmbeddedFiles.GroupBy(e => e.Uri); |
19 | |||
20 | foreach (var expectedEmbeddedFileByUri in group) | ||
16 | { | 21 | { |
22 | var baseUri = expectedEmbeddedFileByUri.Key; | ||
23 | |||
17 | Stream stream = null; | 24 | Stream stream = null; |
18 | try | 25 | try |
19 | { | 26 | { |
@@ -34,18 +41,20 @@ namespace WixToolset.Bind | |||
34 | 41 | ||
35 | using (FileStructure fs = FileStructure.Read(stream)) | 42 | using (FileStructure fs = FileStructure.Read(stream)) |
36 | { | 43 | { |
37 | foreach (var embeddedFile in this.FilesWithEmbeddedFiles.GetExtractFilesForUri(baseUri)) | 44 | var uniqueIndicies = new SortedSet<int>(); |
45 | |||
46 | foreach (var embeddedFile in expectedEmbeddedFileByUri) | ||
38 | { | 47 | { |
39 | fs.ExtractEmbeddedFile(embeddedFile.EmbeddedFileIndex, embeddedFile.OutputPath); | 48 | if (uniqueIndicies.Add(embeddedFile.EmbeddedFileIndex)) |
49 | { | ||
50 | fs.ExtractEmbeddedFile(embeddedFile.EmbeddedFileIndex, embeddedFile.OutputPath); | ||
51 | } | ||
40 | } | 52 | } |
41 | } | 53 | } |
42 | } | 54 | } |
43 | finally | 55 | finally |
44 | { | 56 | { |
45 | if (null != stream) | 57 | stream?.Close(); |
46 | { | ||
47 | stream.Close(); | ||
48 | } | ||
49 | } | 58 | } |
50 | } | 59 | } |
51 | } | 60 | } |
diff --git a/src/WixToolset.Core/Bind/Databases/FileFacade.cs b/src/WixToolset.Core/Bind/FileFacade.cs index 37115c97..aaa6b7d3 100644 --- a/src/WixToolset.Core/Bind/Databases/FileFacade.cs +++ b/src/WixToolset.Core/Bind/FileFacade.cs | |||
@@ -1,6 +1,6 @@ | |||
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.Bind.Databases | 3 | namespace WixToolset.Core.Bind |
4 | { | 4 | { |
5 | using System.Collections.Generic; | 5 | using System.Collections.Generic; |
6 | using WixToolset.Data; | 6 | using WixToolset.Data; |
diff --git a/src/WixToolset.Core/Bind/FileResolver.cs b/src/WixToolset.Core/Bind/FileResolver.cs new file mode 100644 index 00000000..8d624e6f --- /dev/null +++ b/src/WixToolset.Core/Bind/FileResolver.cs | |||
@@ -0,0 +1,231 @@ | |||
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.Bind | ||
4 | { | ||
5 | using System; | ||
6 | using System.Collections.Generic; | ||
7 | using System.IO; | ||
8 | using System.Linq; | ||
9 | using System.Runtime.InteropServices; | ||
10 | using WixToolset.Data; | ||
11 | using WixToolset.Data.Bind; | ||
12 | using WixToolset.Extensibility; | ||
13 | |||
14 | internal class FileResolver | ||
15 | { | ||
16 | private const string BindPathOpenString = "!(bindpath."; | ||
17 | |||
18 | private FileResolver(IEnumerable<BindPath> bindPaths) | ||
19 | { | ||
20 | this.BindPaths = (bindPaths ?? Array.Empty<BindPath>()).ToLookup(b => b.Stage); | ||
21 | this.RebaseTarget = this.BindPaths[BindStage.Target].Any(); | ||
22 | this.RebaseUpdated = this.BindPaths[BindStage.Updated].Any(); | ||
23 | } | ||
24 | |||
25 | public FileResolver(IEnumerable<BindPath> bindPaths, IEnumerable<IBinderExtension> extensions) : this(bindPaths) | ||
26 | { | ||
27 | this.BinderExtensions = extensions ?? Array.Empty<IBinderExtension>(); | ||
28 | } | ||
29 | |||
30 | public FileResolver(IEnumerable<BindPath> bindPaths, IEnumerable<ILibrarianExtension> extensions) : this(bindPaths) | ||
31 | { | ||
32 | this.LibrarianExtensions = extensions ?? Array.Empty<ILibrarianExtension>(); | ||
33 | } | ||
34 | |||
35 | private ILookup<BindStage, BindPath> BindPaths { get; } | ||
36 | |||
37 | public bool RebaseTarget { get; } | ||
38 | |||
39 | public bool RebaseUpdated { get; } | ||
40 | |||
41 | private IEnumerable<IBinderExtension> BinderExtensions { get; } | ||
42 | |||
43 | private IEnumerable<ILibrarianExtension> LibrarianExtensions { get; } | ||
44 | |||
45 | /// <summary> | ||
46 | /// Copies a file. | ||
47 | /// </summary> | ||
48 | /// <param name="source">The file to copy.</param> | ||
49 | /// <param name="destination">The destination file.</param> | ||
50 | /// <param name="overwrite">true if the destination file can be overwritten; otherwise, false.</param> | ||
51 | public bool CopyFile(string source, string destination, bool overwrite) | ||
52 | { | ||
53 | foreach (var extension in this.BinderExtensions) | ||
54 | { | ||
55 | if (extension.CopyFile(source, destination, overwrite)) | ||
56 | { | ||
57 | return true; | ||
58 | } | ||
59 | } | ||
60 | |||
61 | if (overwrite && File.Exists(destination)) | ||
62 | { | ||
63 | File.Delete(destination); | ||
64 | } | ||
65 | |||
66 | if (!CreateHardLink(destination, source, IntPtr.Zero)) | ||
67 | { | ||
68 | #if DEBUG | ||
69 | int er = Marshal.GetLastWin32Error(); | ||
70 | #endif | ||
71 | |||
72 | File.Copy(source, destination, overwrite); | ||
73 | } | ||
74 | |||
75 | return true; | ||
76 | } | ||
77 | |||
78 | /// <summary> | ||
79 | /// Moves a file. | ||
80 | /// </summary> | ||
81 | /// <param name="source">The file to move.</param> | ||
82 | /// <param name="destination">The destination file.</param> | ||
83 | public bool MoveFile(string source, string destination, bool overwrite) | ||
84 | { | ||
85 | foreach (var extension in this.BinderExtensions) | ||
86 | { | ||
87 | if (extension.MoveFile(source, destination, overwrite)) | ||
88 | { | ||
89 | return true; | ||
90 | } | ||
91 | } | ||
92 | |||
93 | if (overwrite && File.Exists(destination)) | ||
94 | { | ||
95 | File.Delete(destination); | ||
96 | } | ||
97 | |||
98 | var directory = Path.GetDirectoryName(destination); | ||
99 | if (!String.IsNullOrEmpty(directory)) | ||
100 | { | ||
101 | Directory.CreateDirectory(directory); | ||
102 | } | ||
103 | |||
104 | File.Move(source, destination); | ||
105 | |||
106 | return true; | ||
107 | } | ||
108 | |||
109 | public string Resolve(SourceLineNumber sourceLineNumbers, string table, string path) | ||
110 | { | ||
111 | foreach (var extension in this.LibrarianExtensions) | ||
112 | { | ||
113 | var resolved = extension.Resolve(sourceLineNumbers, table, path); | ||
114 | |||
115 | if (null != resolved) | ||
116 | { | ||
117 | return resolved; | ||
118 | } | ||
119 | } | ||
120 | |||
121 | return this.ResolveUsingBindPaths(path, table, sourceLineNumbers, BindStage.Normal); | ||
122 | } | ||
123 | |||
124 | /// <summary> | ||
125 | /// Resolves the source path of a file using binder extensions. | ||
126 | /// </summary> | ||
127 | /// <param name="source">Original source value.</param> | ||
128 | /// <param name="type">Optional type of source file being resolved.</param> | ||
129 | /// <param name="sourceLineNumbers">Optional source line of source file being resolved.</param> | ||
130 | /// <param name="bindStage">The binding stage used to determine what collection of bind paths will be used</param> | ||
131 | /// <returns>Should return a valid path for the stream to be imported.</returns> | ||
132 | public string ResolveFile(string source, string type, SourceLineNumber sourceLineNumbers, BindStage bindStage) | ||
133 | { | ||
134 | foreach (var extension in this.BinderExtensions) | ||
135 | { | ||
136 | var resolved = extension.ResolveFile(source, type, sourceLineNumbers, bindStage); | ||
137 | |||
138 | if (null != resolved) | ||
139 | { | ||
140 | return resolved; | ||
141 | } | ||
142 | } | ||
143 | |||
144 | return this.ResolveUsingBindPaths(source, type, sourceLineNumbers, bindStage); | ||
145 | } | ||
146 | |||
147 | private string ResolveUsingBindPaths(string source, string type, SourceLineNumber sourceLineNumbers, BindStage bindStage) | ||
148 | { | ||
149 | string resolved = null; | ||
150 | |||
151 | // If the file exists, we're good to go. | ||
152 | if (CheckFileExists(source)) | ||
153 | { | ||
154 | resolved = source; | ||
155 | } | ||
156 | else if (Path.IsPathRooted(source)) // path is rooted so bindpaths won't help, bail since the file apparently doesn't exist. | ||
157 | { | ||
158 | resolved = null; | ||
159 | } | ||
160 | else // not a rooted path so let's try applying all the different source resolution options. | ||
161 | { | ||
162 | string bindName = String.Empty; | ||
163 | var path = source; | ||
164 | string pathWithoutSourceDir = null; | ||
165 | |||
166 | if (source.StartsWith(BindPathOpenString, StringComparison.Ordinal)) | ||
167 | { | ||
168 | int closeParen = source.IndexOf(')', BindPathOpenString.Length); | ||
169 | if (-1 != closeParen) | ||
170 | { | ||
171 | bindName = source.Substring(BindPathOpenString.Length, closeParen - BindPathOpenString.Length); | ||
172 | path = source.Substring(BindPathOpenString.Length + bindName.Length + 1); // +1 for the closing brace. | ||
173 | path = path.TrimStart('\\'); // remove starting '\\' char so the path doesn't look rooted. | ||
174 | } | ||
175 | } | ||
176 | else if (source.StartsWith("SourceDir\\", StringComparison.Ordinal) || source.StartsWith("SourceDir/", StringComparison.Ordinal)) | ||
177 | { | ||
178 | pathWithoutSourceDir = path.Substring(10); | ||
179 | } | ||
180 | |||
181 | var bindPaths = this.BindPaths[bindStage]; | ||
182 | |||
183 | foreach (var bindPath in bindPaths) | ||
184 | { | ||
185 | if (!String.IsNullOrEmpty(pathWithoutSourceDir)) | ||
186 | { | ||
187 | var filePath = Path.Combine(bindPath.Path, pathWithoutSourceDir); | ||
188 | |||
189 | if (CheckFileExists(filePath)) | ||
190 | { | ||
191 | resolved = filePath; | ||
192 | } | ||
193 | } | ||
194 | |||
195 | if (String.IsNullOrEmpty(resolved)) | ||
196 | { | ||
197 | var filePath = Path.Combine(bindPath.Path, path); | ||
198 | |||
199 | if (CheckFileExists(filePath)) | ||
200 | { | ||
201 | resolved = filePath; | ||
202 | } | ||
203 | } | ||
204 | } | ||
205 | } | ||
206 | |||
207 | if (null == resolved) | ||
208 | { | ||
209 | throw new WixFileNotFoundException(sourceLineNumbers, source, type); | ||
210 | } | ||
211 | |||
212 | // Didn't find the file. | ||
213 | return resolved; | ||
214 | } | ||
215 | |||
216 | private static bool CheckFileExists(string path) | ||
217 | { | ||
218 | try | ||
219 | { | ||
220 | return File.Exists(path); | ||
221 | } | ||
222 | catch (ArgumentException) | ||
223 | { | ||
224 | throw new WixException(WixErrors.IllegalCharactersInPath(path)); | ||
225 | } | ||
226 | } | ||
227 | |||
228 | [DllImport("Kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] | ||
229 | private static extern bool CreateHardLink(string lpFileName, string lpExistingFileName, IntPtr lpSecurityAttributes); | ||
230 | } | ||
231 | } | ||
diff --git a/src/WixToolset.Core/Bind/FileTransfer.cs b/src/WixToolset.Core/Bind/FileTransfer.cs deleted file mode 100644 index 64bbc5f1..00000000 --- a/src/WixToolset.Core/Bind/FileTransfer.cs +++ /dev/null | |||
@@ -1,113 +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.Bind | ||
4 | { | ||
5 | using System; | ||
6 | using System.IO; | ||
7 | using WixToolset; | ||
8 | using WixToolset.Data; | ||
9 | |||
10 | /// <summary> | ||
11 | /// Structure used for all file transfer information. | ||
12 | /// </summary> | ||
13 | internal class FileTransfer | ||
14 | { | ||
15 | /// <summary>Source path to file.</summary> | ||
16 | public string Source { get; set; } | ||
17 | |||
18 | /// <summary>Destination path for file.</summary> | ||
19 | public string Destination { get; set; } | ||
20 | |||
21 | /// <summary>Flag if file should be moved (optimal).</summary> | ||
22 | public bool Move { get; set; } | ||
23 | |||
24 | /// <summary>Optional source line numbers where this file transfer orginated.</summary> | ||
25 | public SourceLineNumber SourceLineNumbers { get; set; } | ||
26 | |||
27 | /// <summary>Optional type of file this transfer is moving or copying.</summary> | ||
28 | public string Type { get; set; } | ||
29 | |||
30 | /// <summary>Indicates whether the file transer was a built by this build or copied from other some build.</summary> | ||
31 | internal bool Built { get; set; } | ||
32 | |||
33 | /// <summary>Set during layout of media when the file transfer when the source and target resolve to the same path.</summary> | ||
34 | internal bool Redundant { get; set; } | ||
35 | |||
36 | /// <summary> | ||
37 | /// Prefer the TryCreate() method to create FileTransfer objects. | ||
38 | /// </summary> | ||
39 | /// <param name="source">Source path to file.</param> | ||
40 | /// <param name="destination">Destination path for file.</param> | ||
41 | /// <param name="move">File if file should be moved (optimal).</param> | ||
42 | /// <param name="type">Optional type of file this transfer is transferring.</param> | ||
43 | /// <param name="sourceLineNumbers">Optional source line numbers wher this transfer originated.</param> | ||
44 | public FileTransfer(string source, string destination, bool move, string type = null, SourceLineNumber sourceLineNumbers = null) | ||
45 | { | ||
46 | this.Source = source; | ||
47 | this.Destination = destination; | ||
48 | this.Move = move; | ||
49 | |||
50 | this.Type = type; | ||
51 | this.SourceLineNumbers = sourceLineNumbers; | ||
52 | } | ||
53 | |||
54 | /// <summary> | ||
55 | /// Creates a file transfer if the source and destination are different. | ||
56 | /// </summary> | ||
57 | /// <param name="source">Source path to file.</param> | ||
58 | /// <param name="destination">Destination path for file.</param> | ||
59 | /// <param name="move">File if file should be moved (optimal).</param> | ||
60 | /// <param name="type">Optional type of file this transfer is transferring.</param> | ||
61 | /// <param name="sourceLineNumbers">Optional source line numbers wher this transfer originated.</param> | ||
62 | /// <returns>true if the source and destination are the different, false if no file transfer is created.</returns> | ||
63 | public static bool TryCreate(string source, string destination, bool move, string type, SourceLineNumber sourceLineNumbers, out FileTransfer transfer) | ||
64 | { | ||
65 | string sourceFullPath = GetValidatedFullPath(sourceLineNumbers, source); | ||
66 | |||
67 | string fileLayoutFullPath = GetValidatedFullPath(sourceLineNumbers, destination); | ||
68 | |||
69 | // if the current source path (where we know that the file already exists) and the resolved | ||
70 | // path as dictated by the Directory table are not the same, then propagate the file. The | ||
71 | // image that we create may have already been done by some other process other than the linker, so | ||
72 | // there is no reason to copy the files to the resolved source if they are already there. | ||
73 | if (String.Equals(sourceFullPath, fileLayoutFullPath, StringComparison.OrdinalIgnoreCase)) | ||
74 | { | ||
75 | transfer = null; | ||
76 | return false; | ||
77 | } | ||
78 | |||
79 | transfer = new FileTransfer(source, destination, move, type, sourceLineNumbers); | ||
80 | return true; | ||
81 | } | ||
82 | |||
83 | private static string GetValidatedFullPath(SourceLineNumber sourceLineNumbers, string path) | ||
84 | { | ||
85 | string result; | ||
86 | |||
87 | try | ||
88 | { | ||
89 | result = Path.GetFullPath(path); | ||
90 | |||
91 | string filename = Path.GetFileName(result); | ||
92 | |||
93 | foreach (string reservedName in Common.ReservedFileNames) | ||
94 | { | ||
95 | if (reservedName.Equals(filename, StringComparison.OrdinalIgnoreCase)) | ||
96 | { | ||
97 | throw new WixException(WixErrors.InvalidFileName(sourceLineNumbers, path)); | ||
98 | } | ||
99 | } | ||
100 | } | ||
101 | catch (System.ArgumentException) | ||
102 | { | ||
103 | throw new WixException(WixErrors.InvalidFileName(sourceLineNumbers, path)); | ||
104 | } | ||
105 | catch (System.IO.PathTooLongException) | ||
106 | { | ||
107 | throw new WixException(WixErrors.PathTooLong(sourceLineNumbers, path)); | ||
108 | } | ||
109 | |||
110 | return result; | ||
111 | } | ||
112 | } | ||
113 | } | ||
diff --git a/src/WixToolset.Core/Bind/ResolveDelayedFieldsCommand.cs b/src/WixToolset.Core/Bind/ResolveDelayedFieldsCommand.cs index 4ffe9e82..15365c2a 100644 --- a/src/WixToolset.Core/Bind/ResolveDelayedFieldsCommand.cs +++ b/src/WixToolset.Core/Bind/ResolveDelayedFieldsCommand.cs | |||
@@ -1,23 +1,22 @@ | |||
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.Bind | 3 | namespace WixToolset.Core.Bind |
4 | { | 4 | { |
5 | using System; | 5 | using System; |
6 | using System.Collections.Generic; | 6 | using System.Collections.Generic; |
7 | using System.Globalization; | 7 | using System.Globalization; |
8 | using System.Linq; | ||
9 | using System.Text; | ||
10 | using WixToolset.Data; | 8 | using WixToolset.Data; |
9 | using WixToolset.Extensibility; | ||
11 | 10 | ||
12 | /// <summary> | 11 | /// <summary> |
13 | /// Resolves the fields which had variables that needed to be resolved after the file information | 12 | /// Resolves the fields which had variables that needed to be resolved after the file information |
14 | /// was loaded. | 13 | /// was loaded. |
15 | /// </summary> | 14 | /// </summary> |
16 | internal class ResolveDelayedFieldsCommand : ICommand | 15 | public class ResolveDelayedFieldsCommand : ICommand |
17 | { | 16 | { |
18 | public OutputType OutputType { private get; set;} | 17 | public OutputType OutputType { private get; set;} |
19 | 18 | ||
20 | public IEnumerable<DelayedField> DelayedFields { private get; set;} | 19 | public IEnumerable<IDelayedField> DelayedFields { private get; set;} |
21 | 20 | ||
22 | public IDictionary<string, string> VariableCache { private get; set; } | 21 | public IDictionary<string, string> VariableCache { private get; set; } |
23 | 22 | ||
@@ -29,9 +28,9 @@ namespace WixToolset.Bind | |||
29 | /// <param name="modularizationGuid">The modularization guid (used in case of a merge module).</param> | 28 | /// <param name="modularizationGuid">The modularization guid (used in case of a merge module).</param> |
30 | public void Execute() | 29 | public void Execute() |
31 | { | 30 | { |
32 | List<DelayedField> deferredFields = new List<DelayedField>(); | 31 | var deferredFields = new List<IDelayedField>(); |
33 | 32 | ||
34 | foreach (DelayedField delayedField in this.DelayedFields) | 33 | foreach (IDelayedField delayedField in this.DelayedFields) |
35 | { | 34 | { |
36 | try | 35 | try |
37 | { | 36 | { |
@@ -43,7 +42,7 @@ namespace WixToolset.Bind | |||
43 | string value = WixVariableResolver.ResolveDelayedVariables(propertyRow.SourceLineNumbers, (string)delayedField.Field.Data, this.VariableCache); | 42 | string value = WixVariableResolver.ResolveDelayedVariables(propertyRow.SourceLineNumbers, (string)delayedField.Field.Data, this.VariableCache); |
44 | 43 | ||
45 | // update the variable cache with the new value | 44 | // update the variable cache with the new value |
46 | string key = String.Concat("property.", BindDatabaseCommand.Demodularize(this.OutputType, this.ModularizationGuid, (string)propertyRow[0])); | 45 | string key = String.Concat("property.", Common.Demodularize(this.OutputType, this.ModularizationGuid, (string)propertyRow[0])); |
47 | this.VariableCache[key] = value; | 46 | this.VariableCache[key] = value; |
48 | 47 | ||
49 | // update the field data | 48 | // update the field data |
diff --git a/src/WixToolset.Core/Bind/ResolveFieldsCommand.cs b/src/WixToolset.Core/Bind/ResolveFieldsCommand.cs index 4caec9b4..f4f4f9e8 100644 --- a/src/WixToolset.Core/Bind/ResolveFieldsCommand.cs +++ b/src/WixToolset.Core/Bind/ResolveFieldsCommand.cs | |||
@@ -1,29 +1,32 @@ | |||
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.Bind | 3 | namespace WixToolset.Core.Bind |
4 | { | 4 | { |
5 | using System.Collections.Generic; | 5 | using System.Collections.Generic; |
6 | using WixToolset.Data; | 6 | using WixToolset.Data; |
7 | using WixToolset.Data.Bind; | ||
7 | using WixToolset.Extensibility; | 8 | using WixToolset.Extensibility; |
8 | 9 | ||
9 | /// <summary> | 10 | /// <summary> |
10 | /// Resolve source fields in the tables included in the output | 11 | /// Resolve source fields in the tables included in the output |
11 | /// </summary> | 12 | /// </summary> |
12 | internal class ResolveFieldsCommand : ICommand | 13 | internal class ResolveFieldsCommand |
13 | { | 14 | { |
14 | public TableIndexedCollection Tables { private get; set; } | 15 | public bool BuildingPatch { private get; set; } |
15 | 16 | ||
16 | public ExtractEmbeddedFiles FilesWithEmbeddedFiles { private get; set; } | 17 | public IBindVariableResolver BindVariableResolver { private get; set; } |
17 | 18 | ||
18 | public BinderFileManagerCore FileManagerCore { private get; set; } | 19 | public IEnumerable<BindPath> BindPaths { private get; set; } |
19 | 20 | ||
20 | public IEnumerable<IBinderFileManager> FileManagers { private get; set; } | 21 | public IEnumerable<IBinderExtension> Extensions { private get; set; } |
21 | 22 | ||
22 | public bool SupportDelayedResolution { private get; set; } | 23 | public ExtractEmbeddedFiles FilesWithEmbeddedFiles { private get; set; } |
24 | |||
25 | public string IntermediateFolder { private get; set; } | ||
23 | 26 | ||
24 | public string TempFilesLocation { private get; set; } | 27 | public TableIndexedCollection Tables { private get; set; } |
25 | 28 | ||
26 | public WixVariableResolver WixVariableResolver { private get; set; } | 29 | public bool SupportDelayedResolution { private get; set; } |
27 | 30 | ||
28 | public IEnumerable<DelayedField> DelayedFields { get; private set; } | 31 | public IEnumerable<DelayedField> DelayedFields { get; private set; } |
29 | 32 | ||
@@ -31,6 +34,8 @@ namespace WixToolset.Bind | |||
31 | { | 34 | { |
32 | List<DelayedField> delayedFields = this.SupportDelayedResolution ? new List<DelayedField>() : null; | 35 | List<DelayedField> delayedFields = this.SupportDelayedResolution ? new List<DelayedField>() : null; |
33 | 36 | ||
37 | var fileResolver = new FileResolver(this.BindPaths, this.Extensions); | ||
38 | |||
34 | foreach (Table table in this.Tables) | 39 | foreach (Table table in this.Tables) |
35 | { | 40 | { |
36 | foreach (Row row in table.Rows) | 41 | foreach (Row row in table.Rows) |
@@ -46,7 +51,7 @@ namespace WixToolset.Bind | |||
46 | // resolve localization and wix variables | 51 | // resolve localization and wix variables |
47 | if (field.Data is string) | 52 | if (field.Data is string) |
48 | { | 53 | { |
49 | field.Data = this.WixVariableResolver.ResolveVariables(row.SourceLineNumbers, field.AsString(), false, ref isDefault, ref delayedResolve); | 54 | field.Data = this.BindVariableResolver.ResolveVariables(row.SourceLineNumbers, field.AsString(), false, out isDefault, out delayedResolve); |
50 | if (delayedResolve) | 55 | if (delayedResolve) |
51 | { | 56 | { |
52 | delayedFields.Add(new DelayedField(row, field)); | 57 | delayedFields.Add(new DelayedField(row, field)); |
@@ -74,7 +79,7 @@ namespace WixToolset.Bind | |||
74 | // File is embedded and path to it was not modified above. | 79 | // File is embedded and path to it was not modified above. |
75 | if (objectField.EmbeddedFileIndex.HasValue && isDefault) | 80 | if (objectField.EmbeddedFileIndex.HasValue && isDefault) |
76 | { | 81 | { |
77 | string extractPath = this.FilesWithEmbeddedFiles.AddEmbeddedFileIndex(objectField.BaseUri, objectField.EmbeddedFileIndex.Value, this.TempFilesLocation); | 82 | string extractPath = this.FilesWithEmbeddedFiles.AddEmbeddedFileIndex(objectField.BaseUri, objectField.EmbeddedFileIndex.Value, this.IntermediateFolder); |
78 | 83 | ||
79 | // Set the path to the embedded file once where it will be extracted. | 84 | // Set the path to the embedded file once where it will be extracted. |
80 | objectField.Data = extractPath; | 85 | objectField.Data = extractPath; |
@@ -83,7 +88,7 @@ namespace WixToolset.Bind | |||
83 | { | 88 | { |
84 | try | 89 | try |
85 | { | 90 | { |
86 | if (OutputType.Patch != this.FileManagerCore.Output.Type) // Normal binding for non-Patch scenario such as link (light.exe) | 91 | if (!this.BuildingPatch) // Normal binding for non-Patch scenario such as link (light.exe) |
87 | { | 92 | { |
88 | // keep a copy of the un-resolved data for future replay. This will be saved into wixpdb file | 93 | // keep a copy of the un-resolved data for future replay. This will be saved into wixpdb file |
89 | if (null == objectField.UnresolvedData) | 94 | if (null == objectField.UnresolvedData) |
@@ -92,12 +97,12 @@ namespace WixToolset.Bind | |||
92 | } | 97 | } |
93 | 98 | ||
94 | // resolve the path to the file | 99 | // resolve the path to the file |
95 | objectField.Data = this.ResolveFile((string)objectField.Data, table.Name, row.SourceLineNumbers, BindStage.Normal); | 100 | objectField.Data = fileResolver.ResolveFile((string)objectField.Data, table.Name, row.SourceLineNumbers, BindStage.Normal); |
96 | } | 101 | } |
97 | else if (!(this.FileManagerCore.RebaseTarget || this.FileManagerCore.RebaseUpdated)) // Normal binding for Patch Scenario (normal patch, no re-basing logic) | 102 | else if (!fileResolver.RebaseTarget && !fileResolver.RebaseUpdated) // Normal binding for Patch Scenario (normal patch, no re-basing logic) |
98 | { | 103 | { |
99 | // resolve the path to the file | 104 | // resolve the path to the file |
100 | objectField.Data = this.ResolveFile((string)objectField.Data, table.Name, row.SourceLineNumbers, BindStage.Normal); | 105 | objectField.Data = fileResolver.ResolveFile((string)objectField.Data, table.Name, row.SourceLineNumbers, BindStage.Normal); |
101 | } | 106 | } |
102 | else // Re-base binding path scenario caused by pyro.exe -bt -bu | 107 | else // Re-base binding path scenario caused by pyro.exe -bt -bu |
103 | { | 108 | { |
@@ -106,7 +111,7 @@ namespace WixToolset.Bind | |||
106 | 111 | ||
107 | // if -bu is used in pyro command, this condition holds true and the tool | 112 | // if -bu is used in pyro command, this condition holds true and the tool |
108 | // will use pre-resolved source for new wixpdb file | 113 | // will use pre-resolved source for new wixpdb file |
109 | if (this.FileManagerCore.RebaseUpdated) | 114 | if (fileResolver.RebaseUpdated) |
110 | { | 115 | { |
111 | // try to use the unResolved Source if it exists. | 116 | // try to use the unResolved Source if it exists. |
112 | // New version of wixpdb file keeps a copy of pre-resolved Source. i.e. !(bindpath.test)\foo.dll | 117 | // New version of wixpdb file keeps a copy of pre-resolved Source. i.e. !(bindpath.test)\foo.dll |
@@ -117,7 +122,7 @@ namespace WixToolset.Bind | |||
117 | } | 122 | } |
118 | } | 123 | } |
119 | 124 | ||
120 | objectField.Data = this.ResolveFile(filePathToResolve, table.Name, row.SourceLineNumbers, BindStage.Updated); | 125 | objectField.Data = fileResolver.ResolveFile(filePathToResolve, table.Name, row.SourceLineNumbers, BindStage.Updated); |
121 | } | 126 | } |
122 | } | 127 | } |
123 | catch (WixFileNotFoundException) | 128 | catch (WixFileNotFoundException) |
@@ -127,10 +132,10 @@ namespace WixToolset.Bind | |||
127 | } | 132 | } |
128 | } | 133 | } |
129 | 134 | ||
130 | isDefault = true; | ||
131 | if (null != objectField.PreviousData) | 135 | if (null != objectField.PreviousData) |
132 | { | 136 | { |
133 | objectField.PreviousData = this.WixVariableResolver.ResolveVariables(row.SourceLineNumbers, objectField.PreviousData, false, ref isDefault); | 137 | objectField.PreviousData = this.BindVariableResolver.ResolveVariables(row.SourceLineNumbers, objectField.PreviousData, false, out isDefault); |
138 | |||
134 | if (!Messaging.Instance.EncounteredError) // TODO: make this error handling more specific to just the failure to resolve variables in this field. | 139 | if (!Messaging.Instance.EncounteredError) // TODO: make this error handling more specific to just the failure to resolve variables in this field. |
135 | { | 140 | { |
136 | // file is compressed in a cabinet (and not modified above) | 141 | // file is compressed in a cabinet (and not modified above) |
@@ -142,7 +147,7 @@ namespace WixToolset.Bind | |||
142 | objectField.PreviousBaseUri = objectField.BaseUri; | 147 | objectField.PreviousBaseUri = objectField.BaseUri; |
143 | } | 148 | } |
144 | 149 | ||
145 | string extractPath = this.FilesWithEmbeddedFiles.AddEmbeddedFileIndex(objectField.PreviousBaseUri, objectField.PreviousEmbeddedFileIndex.Value, this.TempFilesLocation); | 150 | string extractPath = this.FilesWithEmbeddedFiles.AddEmbeddedFileIndex(objectField.PreviousBaseUri, objectField.PreviousEmbeddedFileIndex.Value, this.IntermediateFolder); |
146 | 151 | ||
147 | // set the path to the file once its extracted from the cabinet | 152 | // set the path to the file once its extracted from the cabinet |
148 | objectField.PreviousData = extractPath; | 153 | objectField.PreviousData = extractPath; |
@@ -151,14 +156,14 @@ namespace WixToolset.Bind | |||
151 | { | 156 | { |
152 | try | 157 | try |
153 | { | 158 | { |
154 | if (!this.FileManagerCore.RebaseTarget && !this.FileManagerCore.RebaseUpdated) | 159 | if (!fileResolver.RebaseTarget && !fileResolver.RebaseUpdated) |
155 | { | 160 | { |
156 | // resolve the path to the file | 161 | // resolve the path to the file |
157 | objectField.PreviousData = this.ResolveFile((string)objectField.PreviousData, table.Name, row.SourceLineNumbers, BindStage.Normal); | 162 | objectField.PreviousData = fileResolver.ResolveFile((string)objectField.PreviousData, table.Name, row.SourceLineNumbers, BindStage.Normal); |
158 | } | 163 | } |
159 | else | 164 | else |
160 | { | 165 | { |
161 | if (this.FileManagerCore.RebaseTarget) | 166 | if (fileResolver.RebaseTarget) |
162 | { | 167 | { |
163 | // if -bt is used, it come here | 168 | // if -bt is used, it come here |
164 | // Try to use the original unresolved source from either target build or update build | 169 | // Try to use the original unresolved source from either target build or update build |
@@ -172,7 +177,7 @@ namespace WixToolset.Bind | |||
172 | } | 177 | } |
173 | 178 | ||
174 | // resolve the path to the file | 179 | // resolve the path to the file |
175 | objectField.PreviousData = this.ResolveFile((string)objectField.PreviousData, table.Name, row.SourceLineNumbers, BindStage.Target); | 180 | objectField.PreviousData = fileResolver.ResolveFile((string)objectField.PreviousData, table.Name, row.SourceLineNumbers, BindStage.Target); |
176 | 181 | ||
177 | } | 182 | } |
178 | } | 183 | } |
@@ -192,24 +197,28 @@ namespace WixToolset.Bind | |||
192 | this.DelayedFields = delayedFields; | 197 | this.DelayedFields = delayedFields; |
193 | } | 198 | } |
194 | 199 | ||
200 | #if false | ||
195 | private string ResolveFile(string source, string type, SourceLineNumber sourceLineNumbers, BindStage bindStage = BindStage.Normal) | 201 | private string ResolveFile(string source, string type, SourceLineNumber sourceLineNumbers, BindStage bindStage = BindStage.Normal) |
196 | { | 202 | { |
197 | string path = null; | 203 | string path = null; |
198 | foreach (IBinderFileManager fileManager in this.FileManagers) | 204 | foreach (var extension in this.Extensions) |
199 | { | 205 | { |
200 | path = fileManager.ResolveFile(source, type, sourceLineNumbers, bindStage); | 206 | path = extension.ResolveFile(source, type, sourceLineNumbers, bindStage); |
201 | if (null != path) | 207 | if (null != path) |
202 | { | 208 | { |
203 | break; | 209 | break; |
204 | } | 210 | } |
205 | } | 211 | } |
206 | 212 | ||
207 | if (null == path) | 213 | throw new NotImplementedException(); // need to do default binder stuff |
208 | { | 214 | |
209 | throw new WixFileNotFoundException(sourceLineNumbers, source, type); | 215 | //if (null == path) |
210 | } | 216 | //{ |
217 | // throw new WixFileNotFoundException(sourceLineNumbers, source, type); | ||
218 | //} | ||
211 | 219 | ||
212 | return path; | 220 | //return path; |
213 | } | 221 | } |
222 | #endif | ||
214 | } | 223 | } |
215 | } | 224 | } |
diff --git a/src/WixToolset.Core/Bind/ResolveResult.cs b/src/WixToolset.Core/Bind/ResolveResult.cs new file mode 100644 index 00000000..13f25054 --- /dev/null +++ b/src/WixToolset.Core/Bind/ResolveResult.cs | |||
@@ -0,0 +1,14 @@ | |||
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.Bind | ||
4 | { | ||
5 | using System.Collections.Generic; | ||
6 | using WixToolset.Extensibility; | ||
7 | |||
8 | public class ResolveResult | ||
9 | { | ||
10 | public IEnumerable<IExpectedExtractFile> ExpectedEmbeddedFiles { get; set; } | ||
11 | |||
12 | public IEnumerable<IDelayedField> DelayedFields { get; set; } | ||
13 | } | ||
14 | } \ No newline at end of file | ||
diff --git a/src/WixToolset.Core/Bind/ResolvedDirectory.cs b/src/WixToolset.Core/Bind/ResolvedDirectory.cs index 6985f95d..fca706d8 100644 --- a/src/WixToolset.Core/Bind/ResolvedDirectory.cs +++ b/src/WixToolset.Core/Bind/ResolvedDirectory.cs | |||
@@ -5,7 +5,7 @@ namespace WixToolset.Bind | |||
5 | /// <summary> | 5 | /// <summary> |
6 | /// Structure used for resolved directory information. | 6 | /// Structure used for resolved directory information. |
7 | /// </summary> | 7 | /// </summary> |
8 | internal struct ResolvedDirectory | 8 | public struct ResolvedDirectory |
9 | { | 9 | { |
10 | /// <summary>The directory parent.</summary> | 10 | /// <summary>The directory parent.</summary> |
11 | public string DirectoryParent; | 11 | public string DirectoryParent; |
diff --git a/src/WixToolset.Core/Bind/TransferFilesCommand.cs b/src/WixToolset.Core/Bind/TransferFilesCommand.cs index 719b8b20..f116569c 100644 --- a/src/WixToolset.Core/Bind/TransferFilesCommand.cs +++ b/src/WixToolset.Core/Bind/TransferFilesCommand.cs | |||
@@ -1,29 +1,37 @@ | |||
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.Bind | 3 | namespace WixToolset.Core.Bind |
4 | { | 4 | { |
5 | using System; | 5 | using System; |
6 | using System.Collections.Generic; | 6 | using System.Collections.Generic; |
7 | using System.IO; | 7 | using System.IO; |
8 | using System.Security.AccessControl; | 8 | using System.Security.AccessControl; |
9 | using WixToolset.Data; | 9 | using WixToolset.Data; |
10 | using WixToolset.Data.Bind; | ||
10 | using WixToolset.Extensibility; | 11 | using WixToolset.Extensibility; |
11 | 12 | ||
12 | internal class TransferFilesCommand : ICommand | 13 | internal class TransferFilesCommand |
13 | { | 14 | { |
14 | public IEnumerable<IBinderFileManager> FileManagers { private get; set; } | 15 | public TransferFilesCommand(IEnumerable<BindPath> bindPaths, IEnumerable<IBinderExtension> extensions, IEnumerable<FileTransfer> fileTransfers, bool suppressAclReset) |
16 | { | ||
17 | this.FileResolver = new FileResolver(bindPaths, extensions); | ||
18 | this.FileTransfers = fileTransfers; | ||
19 | this.SuppressAclReset = suppressAclReset; | ||
20 | } | ||
21 | |||
22 | private FileResolver FileResolver { get; } | ||
15 | 23 | ||
16 | public IEnumerable<FileTransfer> FileTransfers { private get; set; } | 24 | private IEnumerable<FileTransfer> FileTransfers { get; } |
17 | 25 | ||
18 | public bool SuppressAclReset { private get; set; } | 26 | private bool SuppressAclReset { get; } |
19 | 27 | ||
20 | public void Execute() | 28 | public void Execute() |
21 | { | 29 | { |
22 | List<string> destinationFiles = new List<string>(); | 30 | List<string> destinationFiles = new List<string>(); |
23 | 31 | ||
24 | foreach (FileTransfer fileTransfer in this.FileTransfers) | 32 | foreach (var fileTransfer in this.FileTransfers) |
25 | { | 33 | { |
26 | string fileSource = this.ResolveFile(fileTransfer.Source, fileTransfer.Type, fileTransfer.SourceLineNumbers, BindStage.Normal); | 34 | string fileSource = this.FileResolver.ResolveFile(fileTransfer.Source, fileTransfer.Type, fileTransfer.SourceLineNumbers, BindStage.Normal); |
27 | 35 | ||
28 | // If the source and destination are identical, then there's nothing to do here | 36 | // If the source and destination are identical, then there's nothing to do here |
29 | if (0 == String.Compare(fileSource, fileTransfer.Destination, StringComparison.OrdinalIgnoreCase)) | 37 | if (0 == String.Compare(fileSource, fileTransfer.Destination, StringComparison.OrdinalIgnoreCase)) |
@@ -165,44 +173,17 @@ namespace WixToolset.Bind | |||
165 | } | 173 | } |
166 | } | 174 | } |
167 | 175 | ||
168 | private string ResolveFile(string source, string type, SourceLineNumber sourceLineNumbers, BindStage bindStage) | 176 | private void TransferFile(bool move, string source, string destination) |
169 | { | 177 | { |
170 | string path = null; | 178 | bool complete = false; |
171 | foreach (IBinderFileManager fileManager in this.FileManagers) | ||
172 | { | ||
173 | path = fileManager.ResolveFile(source, type, sourceLineNumbers, bindStage); | ||
174 | if (null != path) | ||
175 | { | ||
176 | break; | ||
177 | } | ||
178 | } | ||
179 | 179 | ||
180 | if (null == path) | 180 | if (move) |
181 | { | 181 | { |
182 | throw new WixFileNotFoundException(sourceLineNumbers, source, type); | 182 | complete = this.FileResolver.MoveFile(source, destination, true); |
183 | } | 183 | } |
184 | 184 | else | |
185 | return path; | ||
186 | } | ||
187 | |||
188 | private void TransferFile(bool move, string source, string destination) | ||
189 | { | ||
190 | bool complete = false; | ||
191 | foreach (IBinderFileManager fileManager in this.FileManagers) | ||
192 | { | 185 | { |
193 | if (move) | 186 | complete = this.FileResolver.CopyFile(source, destination, true); |
194 | { | ||
195 | complete = fileManager.MoveFile(source, destination, true); | ||
196 | } | ||
197 | else | ||
198 | { | ||
199 | complete = fileManager.CopyFile(source, destination, true); | ||
200 | } | ||
201 | |||
202 | if (complete) | ||
203 | { | ||
204 | break; | ||
205 | } | ||
206 | } | 187 | } |
207 | 188 | ||
208 | if (!complete) | 189 | if (!complete) |
diff --git a/src/WixToolset.Core/BindContext.cs b/src/WixToolset.Core/BindContext.cs new file mode 100644 index 00000000..499f3245 --- /dev/null +++ b/src/WixToolset.Core/BindContext.cs | |||
@@ -0,0 +1,57 @@ | |||
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 System.Collections.Generic; | ||
6 | using WixToolset.Data; | ||
7 | using WixToolset.Extensibility; | ||
8 | |||
9 | public class BindContext : IBindContext | ||
10 | { | ||
11 | public Messaging Messaging { get; set; } | ||
12 | |||
13 | public IEnumerable<BindPath> BindPaths { get; set; } | ||
14 | |||
15 | public int CabbingThreadCount { get; set; } | ||
16 | |||
17 | public string CabCachePath { get; set; } | ||
18 | |||
19 | public int Codepage { get; set; } | ||
20 | |||
21 | public CompressionLevel DefaultCompressionLevel { get; set; } | ||
22 | |||
23 | public IEnumerable<IDelayedField> DelayedFields { get; set; } | ||
24 | |||
25 | public IEnumerable<IExpectedExtractFile> ExpectedEmbeddedFiles { get; set; } | ||
26 | |||
27 | public IExtensionManager ExtensionManager { get; set; } | ||
28 | |||
29 | public IEnumerable<IBinderExtension> Extensions { get; set; } | ||
30 | |||
31 | public IEnumerable<string> Ices { get; set; } | ||
32 | |||
33 | public string IntermediateFolder { get; set; } | ||
34 | |||
35 | public Output IntermediateRepresentation { get; set; } | ||
36 | |||
37 | public string OutputPath { get; set; } | ||
38 | |||
39 | public string OutputPdbPath { get; set; } | ||
40 | |||
41 | public bool SuppressAclReset { get; set; } | ||
42 | |||
43 | public IEnumerable<string> SuppressIces { get; set; } | ||
44 | |||
45 | public bool SuppressValidation { get; set; } | ||
46 | |||
47 | public IBindVariableResolver WixVariableResolver { get; set; } | ||
48 | |||
49 | public string ContentsFile { get; set; } | ||
50 | |||
51 | public string OutputsFile { get; set; } | ||
52 | |||
53 | public string BuiltOutputsFile { get; set; } | ||
54 | |||
55 | public string WixprojectFile { get; set; } | ||
56 | } | ||
57 | } | ||
diff --git a/src/WixToolset.Core/Binder.cs b/src/WixToolset.Core/Binder.cs index 18ad2d62..43c15634 100644 --- a/src/WixToolset.Core/Binder.cs +++ b/src/WixToolset.Core/Binder.cs | |||
@@ -1,6 +1,6 @@ | |||
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 | 3 | namespace WixToolset.Core |
4 | { | 4 | { |
5 | using System; | 5 | using System; |
6 | using System.Collections; | 6 | using System.Collections; |
@@ -11,105 +11,72 @@ namespace WixToolset | |||
11 | using System.Linq; | 11 | using System.Linq; |
12 | using System.Reflection; | 12 | using System.Reflection; |
13 | using WixToolset.Bind; | 13 | using WixToolset.Bind; |
14 | using WixToolset.Core.Bind; | ||
14 | using WixToolset.Data; | 15 | using WixToolset.Data; |
16 | using WixToolset.Data.Bind; | ||
15 | using WixToolset.Data.Rows; | 17 | using WixToolset.Data.Rows; |
16 | using WixToolset.Extensibility; | 18 | using WixToolset.Extensibility; |
17 | using WixToolset.Msi; | ||
18 | |||
19 | // TODO: (4.0) Refactor so that these don't need to be copied. | ||
20 | // Copied verbatim from ext\UtilExtension\wixext\UtilCompiler.cs | ||
21 | [Flags] | ||
22 | internal enum WixFileSearchAttributes | ||
23 | { | ||
24 | Default = 0x001, | ||
25 | MinVersionInclusive = 0x002, | ||
26 | MaxVersionInclusive = 0x004, | ||
27 | MinSizeInclusive = 0x008, | ||
28 | MaxSizeInclusive = 0x010, | ||
29 | MinDateInclusive = 0x020, | ||
30 | MaxDateInclusive = 0x040, | ||
31 | WantVersion = 0x080, | ||
32 | WantExists = 0x100, | ||
33 | IsDirectory = 0x200, | ||
34 | } | ||
35 | |||
36 | [Flags] | ||
37 | internal enum WixRegistrySearchAttributes | ||
38 | { | ||
39 | Raw = 0x01, | ||
40 | Compatible = 0x02, | ||
41 | ExpandEnvironmentVariables = 0x04, | ||
42 | WantValue = 0x08, | ||
43 | WantExists = 0x10, | ||
44 | Win64 = 0x20, | ||
45 | } | ||
46 | |||
47 | internal enum WixComponentSearchAttributes | ||
48 | { | ||
49 | KeyPath = 0x1, | ||
50 | State = 0x2, | ||
51 | WantDirectory = 0x4, | ||
52 | } | ||
53 | |||
54 | [Flags] | ||
55 | internal enum WixProductSearchAttributes | ||
56 | { | ||
57 | Version = 0x1, | ||
58 | Language = 0x2, | ||
59 | State = 0x4, | ||
60 | Assignment = 0x8, | ||
61 | UpgradeCode = 0x10, | ||
62 | } | ||
63 | 19 | ||
64 | /// <summary> | 20 | /// <summary> |
65 | /// Binder of the WiX toolset. | 21 | /// Binder of the WiX toolset. |
66 | /// </summary> | 22 | /// </summary> |
67 | public sealed class Binder | 23 | public sealed class Binder |
68 | { | 24 | { |
69 | private BinderCore core; | 25 | //private BinderCore core; |
70 | private BinderFileManagerCore fileManagerCore; | 26 | //private List<IBinderExtension> extensions; |
71 | private List<IBinderExtension> extensions; | 27 | //private List<IBinderFileManager> fileManagers; |
72 | private List<IBinderFileManager> fileManagers; | ||
73 | private List<InspectorExtension> inspectorExtensions; | ||
74 | 28 | ||
75 | public Binder() | 29 | public Binder() |
76 | { | 30 | { |
77 | this.DefaultCompressionLevel = CompressionLevel.High; | 31 | //this.DefaultCompressionLevel = CompressionLevel.High; |
78 | 32 | ||
79 | this.BindPaths = new List<BindPath>(); | 33 | //this.BindPaths = new List<BindPath>(); |
80 | this.TargetBindPaths = new List<BindPath>(); | 34 | //this.TargetBindPaths = new List<BindPath>(); |
81 | this.UpdatedBindPaths = new List<BindPath>(); | 35 | //this.UpdatedBindPaths = new List<BindPath>(); |
82 | 36 | ||
83 | this.extensions = new List<IBinderExtension>(); | 37 | //this.extensions = new List<IBinderExtension>(); |
84 | this.fileManagers = new List<IBinderFileManager>(); | 38 | //this.fileManagers = new List<IBinderFileManager>(); |
85 | this.inspectorExtensions = new List<InspectorExtension>(); | 39 | //this.inspectorExtensions = new List<InspectorExtension>(); |
86 | 40 | ||
87 | this.Ices = new List<string>(); | 41 | //this.Ices = new List<string>(); |
88 | this.SuppressIces = new List<string>(); | 42 | //this.SuppressIces = new List<string>(); |
89 | } | 43 | } |
90 | 44 | ||
91 | public string ContentsFile { private get; set; } | 45 | public Binder(BindContext context) |
46 | { | ||
47 | this.Context = context; | ||
48 | |||
49 | this.TableDefinitions = WindowsInstallerStandard.GetTableDefinitions(); | ||
50 | } | ||
51 | |||
52 | private BindContext Context { get; } | ||
53 | |||
54 | private TableDefinitionCollection TableDefinitions { get; } | ||
55 | |||
56 | //public IEnumerable<IBackendFactory> BackendFactories { get; set; } | ||
92 | 57 | ||
93 | public string OutputsFile { private get; set; } | 58 | //public string ContentsFile { private get; set; } |
94 | 59 | ||
95 | public string BuiltOutputsFile { private get; set; } | 60 | //public string OutputsFile { private get; set; } |
96 | 61 | ||
97 | public string WixprojectFile { private get; set; } | 62 | //public string BuiltOutputsFile { private get; set; } |
63 | |||
64 | //public string WixprojectFile { private get; set; } | ||
98 | 65 | ||
99 | /// <summary> | 66 | /// <summary> |
100 | /// Gets the list of bindpaths. | 67 | /// Gets the list of bindpaths. |
101 | /// </summary> | 68 | /// </summary> |
102 | public List<BindPath> BindPaths { get; private set; } | 69 | //public List<BindPath> BindPaths { get; private set; } |
103 | 70 | ||
104 | /// <summary> | 71 | /// <summary> |
105 | /// Gets the list of target bindpaths. | 72 | /// Gets the list of target bindpaths. |
106 | /// </summary> | 73 | /// </summary> |
107 | public List<BindPath> TargetBindPaths { get; private set; } | 74 | //public List<BindPath> TargetBindPaths { get; private set; } |
108 | 75 | ||
109 | /// <summary> | 76 | /// <summary> |
110 | /// Gets the list of updated bindpaths. | 77 | /// Gets the list of updated bindpaths. |
111 | /// </summary> | 78 | /// </summary> |
112 | public List<BindPath> UpdatedBindPaths { get; private set; } | 79 | //public List<BindPath> UpdatedBindPaths { get; private set; } |
113 | 80 | ||
114 | /// <summary> | 81 | /// <summary> |
115 | /// Gets or sets the option to enable building binary delta patches. | 82 | /// Gets or sets the option to enable building binary delta patches. |
@@ -132,17 +99,17 @@ namespace WixToolset | |||
132 | /// Gets or sets the default compression level to use for cabinets | 99 | /// Gets or sets the default compression level to use for cabinets |
133 | /// that don't have their compression level explicitly set. | 100 | /// that don't have their compression level explicitly set. |
134 | /// </summary> | 101 | /// </summary> |
135 | public CompressionLevel DefaultCompressionLevel { get; set; } | 102 | //public CompressionLevel DefaultCompressionLevel { get; set; } |
136 | 103 | ||
137 | /// <summary> | 104 | /// <summary> |
138 | /// Gets and sets the location to save the WixPdb. | 105 | /// Gets and sets the location to save the WixPdb. |
139 | /// </summary> | 106 | /// </summary> |
140 | /// <value>The location in which to save the WixPdb. Null if the the WixPdb should not be output.</value> | 107 | /// <value>The location in which to save the WixPdb. Null if the the WixPdb should not be output.</value> |
141 | public string PdbFile { get; set; } | 108 | //public string PdbFile { get; set; } |
142 | 109 | ||
143 | public List<string> Ices { get; private set; } | 110 | //public List<string> Ices { get; private set; } |
144 | 111 | ||
145 | public List<string> SuppressIces { get; private set; } | 112 | //public List<string> SuppressIces { get; private set; } |
146 | 113 | ||
147 | /// <summary> | 114 | /// <summary> |
148 | /// Gets and sets the option to suppress resetting ACLs by the binder. | 115 | /// Gets and sets the option to suppress resetting ACLs by the binder. |
@@ -185,24 +152,164 @@ namespace WixToolset | |||
185 | /// Gets or sets the Wix variable resolver. | 152 | /// Gets or sets the Wix variable resolver. |
186 | /// </summary> | 153 | /// </summary> |
187 | /// <value>The Wix variable resolver.</value> | 154 | /// <value>The Wix variable resolver.</value> |
188 | public WixVariableResolver WixVariableResolver { get; set; } | 155 | internal WixVariableResolver WixVariableResolver { get; set; } |
189 | 156 | ||
190 | /// <summary> | 157 | /// <summary> |
191 | /// Add a binder extension. | 158 | /// Add a binder extension. |
192 | /// </summary> | 159 | /// </summary> |
193 | /// <param name="extension">New extension.</param> | 160 | /// <param name="extension">New extension.</param> |
194 | public void AddExtension(IBinderExtension extension) | 161 | //public void AddExtension(IBinderExtension extension) |
195 | { | 162 | //{ |
196 | this.extensions.Add(extension); | 163 | // this.extensions.Add(extension); |
197 | } | 164 | //} |
198 | 165 | ||
199 | /// <summary> | 166 | /// <summary> |
200 | /// Add a file manager extension. | 167 | /// Add a file manager extension. |
201 | /// </summary> | 168 | /// </summary> |
202 | /// <param name="extension">New file manager.</param> | 169 | /// <param name="extension">New file manager.</param> |
203 | public void AddExtension(IBinderFileManager extension) | 170 | //public void AddExtension(IBinderFileManager extension) |
171 | //{ | ||
172 | // this.fileManagers.Add(extension); | ||
173 | //} | ||
174 | |||
175 | public bool Bind() | ||
176 | { | ||
177 | //if (!String.IsNullOrEmpty(this.Context.FileManagerCore.CabCachePath)) | ||
178 | //{ | ||
179 | // Directory.CreateDirectory(this.Context.FileManagerCore.CabCachePath); | ||
180 | //} | ||
181 | |||
182 | //this.core = new BinderCore(); | ||
183 | //this.core.FileManagerCore = this.Context.FileManagerCore; | ||
184 | |||
185 | this.WriteBuildInfoTable(this.Context.IntermediateRepresentation, this.Context.OutputPath); | ||
186 | |||
187 | // Prebind. | ||
188 | // | ||
189 | this.Context.Extensions = this.Context.ExtensionManager.Create<IBinderExtension>(); | ||
190 | |||
191 | foreach (IBinderExtension extension in this.Context.Extensions) | ||
192 | { | ||
193 | extension.PreBind(this.Context); | ||
194 | } | ||
195 | |||
196 | // Resolve. | ||
197 | // | ||
198 | var resolveResult = this.Resolve(); | ||
199 | |||
200 | this.Context.DelayedFields = resolveResult.DelayedFields; | ||
201 | |||
202 | this.Context.ExpectedEmbeddedFiles = resolveResult.ExpectedEmbeddedFiles; | ||
203 | |||
204 | // Backend. | ||
205 | // | ||
206 | var bindResult = this.BackendBind(); | ||
207 | |||
208 | if (bindResult != null) | ||
209 | { | ||
210 | // Postbind. | ||
211 | // | ||
212 | foreach (IBinderExtension extension in this.Context.Extensions) | ||
213 | { | ||
214 | extension.PostBind(bindResult); | ||
215 | } | ||
216 | |||
217 | // Layout. | ||
218 | // | ||
219 | this.Layout(bindResult); | ||
220 | } | ||
221 | |||
222 | return Messaging.Instance.EncounteredError; | ||
223 | } | ||
224 | |||
225 | private ResolveResult Resolve() | ||
226 | { | ||
227 | var buildingPatch = (this.Context.IntermediateRepresentation.Type == OutputType.Patch); | ||
228 | |||
229 | var filesWithEmbeddedFiles = new ExtractEmbeddedFiles(); | ||
230 | |||
231 | IEnumerable<DelayedField> delayedFields; | ||
232 | { | ||
233 | var command = new ResolveFieldsCommand(); | ||
234 | command.BuildingPatch = buildingPatch; | ||
235 | command.BindVariableResolver = this.Context.WixVariableResolver; | ||
236 | command.BindPaths = this.Context.BindPaths; | ||
237 | command.Extensions = this.Context.Extensions; | ||
238 | command.FilesWithEmbeddedFiles = filesWithEmbeddedFiles; | ||
239 | command.IntermediateFolder = this.Context.IntermediateFolder; | ||
240 | command.Tables = this.Context.IntermediateRepresentation.Tables; | ||
241 | command.SupportDelayedResolution = true; | ||
242 | command.Execute(); | ||
243 | |||
244 | delayedFields = command.DelayedFields; | ||
245 | } | ||
246 | |||
247 | if (this.Context.IntermediateRepresentation.SubStorages != null) | ||
248 | { | ||
249 | foreach (SubStorage transform in this.Context.IntermediateRepresentation.SubStorages) | ||
250 | { | ||
251 | var command = new ResolveFieldsCommand(); | ||
252 | command.BuildingPatch = buildingPatch; | ||
253 | command.BindVariableResolver = this.Context.WixVariableResolver; | ||
254 | command.BindPaths = this.Context.BindPaths; | ||
255 | command.Extensions = this.Context.Extensions; | ||
256 | command.FilesWithEmbeddedFiles = filesWithEmbeddedFiles; | ||
257 | command.IntermediateFolder = this.Context.IntermediateFolder; | ||
258 | command.Tables = transform.Data.Tables; | ||
259 | command.SupportDelayedResolution = false; | ||
260 | command.Execute(); | ||
261 | } | ||
262 | } | ||
263 | |||
264 | var expectedEmbeddedFiles = filesWithEmbeddedFiles.GetExpectedEmbeddedFiles(); | ||
265 | |||
266 | return new ResolveResult | ||
267 | { | ||
268 | ExpectedEmbeddedFiles = expectedEmbeddedFiles, | ||
269 | DelayedFields = delayedFields, | ||
270 | }; | ||
271 | } | ||
272 | |||
273 | private BindResult BackendBind() | ||
274 | { | ||
275 | var backendFactories = this.Context.ExtensionManager.Create<IBackendFactory>(); | ||
276 | |||
277 | foreach (var factory in backendFactories) | ||
278 | { | ||
279 | if (factory.TryCreateBackend(this.Context.IntermediateRepresentation.Type.ToString(), this.Context.OutputPath, null, out var backend)) | ||
280 | { | ||
281 | var result = backend.Bind(this.Context); | ||
282 | return result; | ||
283 | } | ||
284 | } | ||
285 | |||
286 | // TODO: messaging that a backend could not be found to bind the output type? | ||
287 | |||
288 | return null; | ||
289 | } | ||
290 | private void Layout(BindResult result) | ||
204 | { | 291 | { |
205 | this.fileManagers.Add(extension); | 292 | try |
293 | { | ||
294 | this.LayoutMedia(result.FileTransfers); | ||
295 | } | ||
296 | finally | ||
297 | { | ||
298 | if (!String.IsNullOrEmpty(this.Context.ContentsFile) && result.ContentFilePaths != null) | ||
299 | { | ||
300 | this.CreateContentsFile(this.Context.ContentsFile, result.ContentFilePaths); | ||
301 | } | ||
302 | |||
303 | if (!String.IsNullOrEmpty(this.Context.OutputsFile) && result.FileTransfers != null) | ||
304 | { | ||
305 | this.CreateOutputsFile(this.Context.OutputsFile, result.FileTransfers, this.Context.OutputPdbPath); | ||
306 | } | ||
307 | |||
308 | if (!String.IsNullOrEmpty(this.Context.BuiltOutputsFile) && result.FileTransfers != null) | ||
309 | { | ||
310 | this.CreateBuiltOutputsFile(this.Context.BuiltOutputsFile, result.FileTransfers, this.Context.OutputPdbPath); | ||
311 | } | ||
312 | } | ||
206 | } | 313 | } |
207 | 314 | ||
208 | /// <summary> | 315 | /// <summary> |
@@ -212,6 +319,7 @@ namespace WixToolset | |||
212 | /// <param name="file">The Windows Installer file to create.</param> | 319 | /// <param name="file">The Windows Installer file to create.</param> |
213 | /// <remarks>The Binder.DeleteTempFiles method should be called after calling this method.</remarks> | 320 | /// <remarks>The Binder.DeleteTempFiles method should be called after calling this method.</remarks> |
214 | /// <returns>true if binding completed successfully; false otherwise</returns> | 321 | /// <returns>true if binding completed successfully; false otherwise</returns> |
322 | #if false | ||
215 | public bool Bind(Output output, string file) | 323 | public bool Bind(Output output, string file) |
216 | { | 324 | { |
217 | // Ensure the cabinet cache path exists if we are going to use it. | 325 | // Ensure the cabinet cache path exists if we are going to use it. |
@@ -220,20 +328,20 @@ namespace WixToolset | |||
220 | Directory.CreateDirectory(this.CabCachePath); | 328 | Directory.CreateDirectory(this.CabCachePath); |
221 | } | 329 | } |
222 | 330 | ||
223 | this.fileManagerCore = new BinderFileManagerCore(); | 331 | //var fileManagerCore = new BinderFileManagerCore(); |
224 | this.fileManagerCore.CabCachePath = this.CabCachePath; | 332 | //fileManagerCore.CabCachePath = this.CabCachePath; |
225 | this.fileManagerCore.Output = output; | 333 | //fileManagerCore.Output = output; |
226 | this.fileManagerCore.TempFilesLocation = this.TempFilesLocation; | 334 | //fileManagerCore.TempFilesLocation = this.TempFilesLocation; |
227 | this.fileManagerCore.AddBindPaths(this.BindPaths, BindStage.Normal); | 335 | //fileManagerCore.AddBindPaths(this.BindPaths, BindStage.Normal); |
228 | this.fileManagerCore.AddBindPaths(this.TargetBindPaths, BindStage.Target); | 336 | //fileManagerCore.AddBindPaths(this.TargetBindPaths, BindStage.Target); |
229 | this.fileManagerCore.AddBindPaths(this.UpdatedBindPaths, BindStage.Updated); | 337 | //fileManagerCore.AddBindPaths(this.UpdatedBindPaths, BindStage.Updated); |
230 | foreach (IBinderFileManager fileManager in this.fileManagers) | 338 | //foreach (IBinderFileManager fileManager in this.fileManagers) |
231 | { | 339 | //{ |
232 | fileManager.Core = this.fileManagerCore; | 340 | // fileManager.Core = fileManagerCore; |
233 | } | 341 | //} |
234 | 342 | ||
235 | this.core = new BinderCore(); | 343 | this.core = new BinderCore(); |
236 | this.core.FileManagerCore = this.fileManagerCore; | 344 | this.core.FileManagerCore = fileManagerCore; |
237 | 345 | ||
238 | this.WriteBuildInfoTable(output, file); | 346 | this.WriteBuildInfoTable(output, file); |
239 | 347 | ||
@@ -246,54 +354,69 @@ namespace WixToolset | |||
246 | } | 354 | } |
247 | 355 | ||
248 | // Gather all the wix variables. | 356 | // Gather all the wix variables. |
249 | Table wixVariableTable = output.Tables["WixVariable"]; | 357 | //Table wixVariableTable = output.Tables["WixVariable"]; |
250 | if (null != wixVariableTable) | 358 | //if (null != wixVariableTable) |
359 | //{ | ||
360 | // foreach (WixVariableRow wixVariableRow in wixVariableTable.Rows) | ||
361 | // { | ||
362 | // this.WixVariableResolver.AddVariable(wixVariableRow); | ||
363 | // } | ||
364 | //} | ||
365 | |||
366 | //BindContext context = new BindContext(); | ||
367 | //context.CabbingThreadCount = this.CabbingThreadCount; | ||
368 | //context.DefaultCompressionLevel = this.DefaultCompressionLevel; | ||
369 | //context.Extensions = this.extensions; | ||
370 | //context.FileManagerCore = fileManagerCore; | ||
371 | //context.FileManagers = this.fileManagers; | ||
372 | //context.Ices = this.Ices; | ||
373 | //context.IntermediateFolder = this.TempFilesLocation; | ||
374 | //context.IntermediateRepresentation = output; | ||
375 | //context.Localizer = this.Localizer; | ||
376 | //context.OutputPath = file; | ||
377 | //context.OutputPdbPath = this.PdbFile; | ||
378 | //context.SuppressIces = this.SuppressIces; | ||
379 | //context.SuppressValidation = this.SuppressValidation; | ||
380 | //context.WixVariableResolver = this.WixVariableResolver; | ||
381 | |||
382 | BindResult result = null; | ||
383 | |||
384 | foreach (var factory in this.BackendFactories) | ||
251 | { | 385 | { |
252 | foreach (WixVariableRow wixVariableRow in wixVariableTable.Rows) | 386 | if (factory.TryCreateBackend(output.Type.ToString(), file, null, out var backend)) |
253 | { | 387 | { |
254 | this.WixVariableResolver.AddVariable(wixVariableRow); | 388 | result = backend.Bind(context); |
389 | break; | ||
255 | } | 390 | } |
256 | } | 391 | } |
257 | 392 | ||
258 | IEnumerable<FileTransfer> fileTransfers = null; | 393 | if (result == null) |
259 | IEnumerable<string> contentPaths = null; | ||
260 | |||
261 | switch (output.Type) | ||
262 | { | 394 | { |
263 | case OutputType.Bundle: | 395 | // TODO: messaging that a backend could not be found to bind the output type? |
264 | this.BindBundle(output, file, out fileTransfers, out contentPaths); | ||
265 | break; | ||
266 | |||
267 | case OutputType.Transform: | ||
268 | this.BindTransform(output, file); | ||
269 | break; | ||
270 | 396 | ||
271 | default: | 397 | return false; |
272 | this.BindDatabase(output, file, out fileTransfers, out contentPaths); | ||
273 | break; | ||
274 | } | 398 | } |
275 | 399 | ||
276 | |||
277 | // Layout media | 400 | // Layout media |
278 | try | 401 | try |
279 | { | 402 | { |
280 | this.LayoutMedia(fileTransfers); | 403 | this.LayoutMedia(result.FileTransfers); |
281 | } | 404 | } |
282 | finally | 405 | finally |
283 | { | 406 | { |
284 | if (!String.IsNullOrEmpty(this.ContentsFile) && contentPaths != null) | 407 | if (!String.IsNullOrEmpty(this.ContentsFile) && result.ContentFilePaths != null) |
285 | { | 408 | { |
286 | this.CreateContentsFile(this.ContentsFile, contentPaths); | 409 | this.CreateContentsFile(this.ContentsFile, result.ContentFilePaths); |
287 | } | 410 | } |
288 | 411 | ||
289 | if (!String.IsNullOrEmpty(this.OutputsFile) && fileTransfers != null) | 412 | if (!String.IsNullOrEmpty(this.OutputsFile) && result.FileTransfers != null) |
290 | { | 413 | { |
291 | this.CreateOutputsFile(this.OutputsFile, fileTransfers, this.PdbFile); | 414 | this.CreateOutputsFile(this.OutputsFile, result.FileTransfers, this.PdbFile); |
292 | } | 415 | } |
293 | 416 | ||
294 | if (!String.IsNullOrEmpty(this.BuiltOutputsFile) && fileTransfers != null) | 417 | if (!String.IsNullOrEmpty(this.BuiltOutputsFile) && result.FileTransfers != null) |
295 | { | 418 | { |
296 | this.CreateBuiltOutputsFile(this.BuiltOutputsFile, fileTransfers, this.PdbFile); | 419 | this.CreateBuiltOutputsFile(this.BuiltOutputsFile, result.FileTransfers, this.PdbFile); |
297 | } | 420 | } |
298 | } | 421 | } |
299 | 422 | ||
@@ -301,6 +424,7 @@ namespace WixToolset | |||
301 | 424 | ||
302 | return Messaging.Instance.EncounteredError; | 425 | return Messaging.Instance.EncounteredError; |
303 | } | 426 | } |
427 | #endif | ||
304 | 428 | ||
305 | /// <summary> | 429 | /// <summary> |
306 | /// Does any housekeeping after Bind. | 430 | /// Does any housekeeping after Bind. |
@@ -312,12 +436,12 @@ namespace WixToolset | |||
312 | { | 436 | { |
313 | if (!this.DeleteTempFiles()) | 437 | if (!this.DeleteTempFiles()) |
314 | { | 438 | { |
315 | this.core.OnMessage(WixWarnings.FailedToDeleteTempDir(this.TempFilesLocation)); | 439 | this.Context.Messaging.OnMessage(WixWarnings.FailedToDeleteTempDir(this.TempFilesLocation)); |
316 | } | 440 | } |
317 | } | 441 | } |
318 | else | 442 | else |
319 | { | 443 | { |
320 | this.core.OnMessage(WixVerboses.BinderTempDirLocatedAt(this.TempFilesLocation)); | 444 | this.Context.Messaging.OnMessage(WixVerboses.BinderTempDirLocatedAt(this.TempFilesLocation)); |
321 | } | 445 | } |
322 | } | 446 | } |
323 | 447 | ||
@@ -327,7 +451,7 @@ namespace WixToolset | |||
327 | /// <returns>True if all files were deleted, false otherwise.</returns> | 451 | /// <returns>True if all files were deleted, false otherwise.</returns> |
328 | private bool DeleteTempFiles() | 452 | private bool DeleteTempFiles() |
329 | { | 453 | { |
330 | bool deleted = Common.DeleteTempFiles(this.TempFilesLocation, this.core); | 454 | bool deleted = Common.DeleteTempFiles(this.TempFilesLocation, this.Context.Messaging); |
331 | return deleted; | 455 | return deleted; |
332 | } | 456 | } |
333 | 457 | ||
@@ -338,7 +462,7 @@ namespace WixToolset | |||
338 | /// <param name="databaseFile">The output file if OutputFile not set.</param> | 462 | /// <param name="databaseFile">The output file if OutputFile not set.</param> |
339 | private void WriteBuildInfoTable(Output output, string outputFile) | 463 | private void WriteBuildInfoTable(Output output, string outputFile) |
340 | { | 464 | { |
341 | Table buildInfoTable = output.EnsureTable(this.core.TableDefinitions["WixBuildInfo"]); | 465 | Table buildInfoTable = output.EnsureTable(this.TableDefinitions["WixBuildInfo"]); |
342 | Row buildInfoRow = buildInfoTable.CreateRow(null); | 466 | Row buildInfoRow = buildInfoTable.CreateRow(null); |
343 | 467 | ||
344 | Assembly executingAssembly = Assembly.GetExecutingAssembly(); | 468 | Assembly executingAssembly = Assembly.GetExecutingAssembly(); |
@@ -346,17 +470,18 @@ namespace WixToolset | |||
346 | buildInfoRow[0] = fileVersion.FileVersion; | 470 | buildInfoRow[0] = fileVersion.FileVersion; |
347 | buildInfoRow[1] = outputFile; | 471 | buildInfoRow[1] = outputFile; |
348 | 472 | ||
349 | if (!String.IsNullOrEmpty(this.WixprojectFile)) | 473 | if (!String.IsNullOrEmpty(this.Context.WixprojectFile)) |
350 | { | 474 | { |
351 | buildInfoRow[2] = this.WixprojectFile; | 475 | buildInfoRow[2] = this.Context.WixprojectFile; |
352 | } | 476 | } |
353 | 477 | ||
354 | if (!String.IsNullOrEmpty(this.PdbFile)) | 478 | if (!String.IsNullOrEmpty(this.Context.OutputPdbPath)) |
355 | { | 479 | { |
356 | buildInfoRow[3] = this.PdbFile; | 480 | buildInfoRow[3] = this.Context.OutputPdbPath; |
357 | } | 481 | } |
358 | } | 482 | } |
359 | 483 | ||
484 | #if DELETE_THIS_CODE | ||
360 | /// <summary> | 485 | /// <summary> |
361 | /// Binds a bundle. | 486 | /// Binds a bundle. |
362 | /// </summary> | 487 | /// </summary> |
@@ -454,6 +579,7 @@ namespace WixToolset | |||
454 | command.OutputPath = outputPath; | 579 | command.OutputPath = outputPath; |
455 | command.Execute(); | 580 | command.Execute(); |
456 | } | 581 | } |
582 | #endif | ||
457 | 583 | ||
458 | /// <summary> | 584 | /// <summary> |
459 | /// Final step in binding that transfers (moves/copies) all files generated into the appropriate | 585 | /// Final step in binding that transfers (moves/copies) all files generated into the appropriate |
@@ -464,12 +590,9 @@ namespace WixToolset | |||
464 | { | 590 | { |
465 | if (null != transfers && transfers.Any()) | 591 | if (null != transfers && transfers.Any()) |
466 | { | 592 | { |
467 | this.core.OnMessage(WixVerboses.LayingOutMedia()); | 593 | this.Context.Messaging.OnMessage(WixVerboses.LayingOutMedia()); |
468 | 594 | ||
469 | TransferFilesCommand command = new TransferFilesCommand(); | 595 | var command = new TransferFilesCommand(this.Context.BindPaths, this.Context.Extensions, transfers, this.Context.SuppressAclReset); |
470 | command.FileManagers = this.fileManagers; | ||
471 | command.FileTransfers = transfers; | ||
472 | command.SuppressAclReset = this.SuppressAclReset; | ||
473 | command.Execute(); | 596 | command.Execute(); |
474 | } | 597 | } |
475 | } | 598 | } |
@@ -482,7 +605,7 @@ namespace WixToolset | |||
482 | /// <param name="directory">Directory identifier.</param> | 605 | /// <param name="directory">Directory identifier.</param> |
483 | /// <param name="canonicalize">Canonicalize the path for standard directories.</param> | 606 | /// <param name="canonicalize">Canonicalize the path for standard directories.</param> |
484 | /// <returns>Source path of a directory.</returns> | 607 | /// <returns>Source path of a directory.</returns> |
485 | internal static string GetDirectoryPath(Hashtable directories, Hashtable componentIdGenSeeds, string directory, bool canonicalize) | 608 | public static string GetDirectoryPath(Hashtable directories, Hashtable componentIdGenSeeds, string directory, bool canonicalize) |
486 | { | 609 | { |
487 | if (!directories.Contains(directory)) | 610 | if (!directories.Contains(directory)) |
488 | { | 611 | { |
@@ -543,9 +666,9 @@ namespace WixToolset | |||
543 | /// <param name="compressed">Specifies the package is compressed.</param> | 666 | /// <param name="compressed">Specifies the package is compressed.</param> |
544 | /// <param name="useLongName">Specifies the package uses long file names.</param> | 667 | /// <param name="useLongName">Specifies the package uses long file names.</param> |
545 | /// <returns>Source path of file relative to package directory.</returns> | 668 | /// <returns>Source path of file relative to package directory.</returns> |
546 | internal static string GetFileSourcePath(Hashtable directories, string directoryId, string fileName, bool compressed, bool useLongName) | 669 | public static string GetFileSourcePath(Hashtable directories, string directoryId, string fileName, bool compressed, bool useLongName) |
547 | { | 670 | { |
548 | string fileSourcePath = Installer.GetName(fileName, true, useLongName); | 671 | string fileSourcePath = Common.GetName(fileName, true, useLongName); |
549 | 672 | ||
550 | if (compressed) | 673 | if (compressed) |
551 | { | 674 | { |
diff --git a/src/WixToolset.Core/BinderFileManager.cs b/src/WixToolset.Core/BinderFileManager.cs index 0da54002..1527d93d 100644 --- a/src/WixToolset.Core/BinderFileManager.cs +++ b/src/WixToolset.Core/BinderFileManager.cs | |||
@@ -12,6 +12,7 @@ namespace WixToolset | |||
12 | using WixToolset.Data.Rows; | 12 | using WixToolset.Data.Rows; |
13 | using WixToolset.Extensibility; | 13 | using WixToolset.Extensibility; |
14 | 14 | ||
15 | #if false | ||
15 | /// <summary> | 16 | /// <summary> |
16 | /// Base class for creating a binder file manager. | 17 | /// Base class for creating a binder file manager. |
17 | /// </summary> | 18 | /// </summary> |
@@ -367,4 +368,5 @@ namespace WixToolset | |||
367 | [DllImport("Kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] | 368 | [DllImport("Kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] |
368 | private static extern bool CreateHardLink(string lpFileName, string lpExistingFileName, IntPtr lpSecurityAttributes); | 369 | private static extern bool CreateHardLink(string lpFileName, string lpExistingFileName, IntPtr lpSecurityAttributes); |
369 | } | 370 | } |
371 | #endif | ||
370 | } | 372 | } |
diff --git a/src/WixToolset.Core/BinderFileManagerCore.cs b/src/WixToolset.Core/BinderFileManagerCore.cs index 6a5e1d5e..f1a78880 100644 --- a/src/WixToolset.Core/BinderFileManagerCore.cs +++ b/src/WixToolset.Core/BinderFileManagerCore.cs | |||
@@ -6,6 +6,7 @@ namespace WixToolset | |||
6 | using System.Collections.Generic; | 6 | using System.Collections.Generic; |
7 | using System.Linq; | 7 | using System.Linq; |
8 | using WixToolset.Data; | 8 | using WixToolset.Data; |
9 | using WixToolset.Data.Bind; | ||
9 | using WixToolset.Extensibility; | 10 | using WixToolset.Extensibility; |
10 | 11 | ||
11 | public class BinderFileManagerCore : IBinderFileManagerCore | 12 | public class BinderFileManagerCore : IBinderFileManagerCore |
diff --git a/src/WixToolset.Core/Cab/CabinetFileInfo.cs b/src/WixToolset.Core/Cab/CabinetFileInfo.cs index 849bb3bb..816f9e3e 100644 --- a/src/WixToolset.Core/Cab/CabinetFileInfo.cs +++ b/src/WixToolset.Core/Cab/CabinetFileInfo.cs | |||
@@ -1,19 +1,12 @@ | |||
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 | 3 | namespace WixToolset.Core.Cab |
4 | { | 4 | { |
5 | using System; | ||
6 | |||
7 | /// <summary> | 5 | /// <summary> |
8 | /// Properties of a file in a cabinet. | 6 | /// Properties of a file in a cabinet. |
9 | /// </summary> | 7 | /// </summary> |
10 | internal sealed class CabinetFileInfo | 8 | public sealed class CabinetFileInfo |
11 | { | 9 | { |
12 | private string fileId; | ||
13 | private ushort date; | ||
14 | private ushort time; | ||
15 | private int size; | ||
16 | |||
17 | /// <summary> | 10 | /// <summary> |
18 | /// Constructs CabinetFileInfo | 11 | /// Constructs CabinetFileInfo |
19 | /// </summary> | 12 | /// </summary> |
@@ -22,43 +15,31 @@ namespace WixToolset | |||
22 | /// <param name="time">Last modified time (MS-DOS time)</param> | 15 | /// <param name="time">Last modified time (MS-DOS time)</param> |
23 | public CabinetFileInfo(string fileId, ushort date, ushort time, int size) | 16 | public CabinetFileInfo(string fileId, ushort date, ushort time, int size) |
24 | { | 17 | { |
25 | this.fileId = fileId; | 18 | this.FileId = fileId; |
26 | this.date = date; | 19 | this.Date = date; |
27 | this.time = time; | 20 | this.Time = time; |
28 | this.size = size; | 21 | this.Size = size; |
29 | } | 22 | } |
30 | 23 | ||
31 | /// <summary> | 24 | /// <summary> |
32 | /// Gets the file Id of the file. | 25 | /// Gets the file Id of the file. |
33 | /// </summary> | 26 | /// </summary> |
34 | /// <value>file Id</value> | 27 | /// <value>file Id</value> |
35 | public string FileId | 28 | public string FileId { get; } |
36 | { | ||
37 | get { return this.fileId; } | ||
38 | } | ||
39 | 29 | ||
40 | /// <summary> | 30 | /// <summary> |
41 | /// Gets modified date (DOS format). | 31 | /// Gets modified date (DOS format). |
42 | /// </summary> | 32 | /// </summary> |
43 | public ushort Date | 33 | public ushort Date { get; } |
44 | { | ||
45 | get { return this.date; } | ||
46 | } | ||
47 | 34 | ||
48 | /// <summary> | 35 | /// <summary> |
49 | /// Gets modified time (DOS format). | 36 | /// Gets modified time (DOS format). |
50 | /// </summary> | 37 | /// </summary> |
51 | public ushort Time | 38 | public ushort Time { get; } |
52 | { | ||
53 | get { return this.time; } | ||
54 | } | ||
55 | 39 | ||
56 | /// <summary> | 40 | /// <summary> |
57 | /// Gets the size of the file in bytes. | 41 | /// Gets the size of the file in bytes. |
58 | /// </summary> | 42 | /// </summary> |
59 | public int Size | 43 | public int Size { get; } |
60 | { | ||
61 | get { return this.size; } | ||
62 | } | ||
63 | } | 44 | } |
64 | } | 45 | } |
diff --git a/src/WixToolset.Core/Cab/WixCreateCab.cs b/src/WixToolset.Core/Cab/WixCreateCab.cs index 8f985a43..4ebdd1c0 100644 --- a/src/WixToolset.Core/Cab/WixCreateCab.cs +++ b/src/WixToolset.Core/Cab/WixCreateCab.cs | |||
@@ -1,12 +1,12 @@ | |||
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.Cab | 3 | namespace WixToolset.Core.Cab |
4 | { | 4 | { |
5 | using System; | 5 | using System; |
6 | using System.Globalization; | 6 | using System.Globalization; |
7 | using System.IO; | 7 | using System.IO; |
8 | using System.Runtime.InteropServices; | 8 | using System.Runtime.InteropServices; |
9 | using WixToolset.Bind.Databases; | 9 | using WixToolset.Core.Bind; |
10 | using WixToolset.Core.Native; | 10 | using WixToolset.Core.Native; |
11 | using WixToolset.Data; | 11 | using WixToolset.Data; |
12 | 12 | ||
diff --git a/src/WixToolset.Core/Cab/WixEnumerateCab.cs b/src/WixToolset.Core/Cab/WixEnumerateCab.cs index 017eeffb..0b4055d6 100644 --- a/src/WixToolset.Core/Cab/WixEnumerateCab.cs +++ b/src/WixToolset.Core/Cab/WixEnumerateCab.cs | |||
@@ -1,6 +1,6 @@ | |||
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.Cab | 3 | namespace WixToolset.Core.Cab |
4 | { | 4 | { |
5 | using System; | 5 | using System; |
6 | using System.Collections.Generic; | 6 | using System.Collections.Generic; |
@@ -10,7 +10,7 @@ namespace WixToolset.Cab | |||
10 | /// <summary> | 10 | /// <summary> |
11 | /// Wrapper class around interop with wixcab.dll to enumerate files from a cabinet. | 11 | /// Wrapper class around interop with wixcab.dll to enumerate files from a cabinet. |
12 | /// </summary> | 12 | /// </summary> |
13 | internal sealed class WixEnumerateCab : IDisposable | 13 | public sealed class WixEnumerateCab : IDisposable |
14 | { | 14 | { |
15 | private bool disposed; | 15 | private bool disposed; |
16 | private List<CabinetFileInfo> fileInfoList; | 16 | private List<CabinetFileInfo> fileInfoList; |
@@ -38,7 +38,7 @@ namespace WixToolset.Cab | |||
38 | /// </summary> | 38 | /// </summary> |
39 | /// <param name="cabinetFile">path to cabinet</param> | 39 | /// <param name="cabinetFile">path to cabinet</param> |
40 | /// <returns>list of CabinetFileInfo</returns> | 40 | /// <returns>list of CabinetFileInfo</returns> |
41 | internal List<CabinetFileInfo> Enumerate(string cabinetFile) | 41 | public List<CabinetFileInfo> Enumerate(string cabinetFile) |
42 | { | 42 | { |
43 | this.fileInfoList = new List<CabinetFileInfo>(); | 43 | this.fileInfoList = new List<CabinetFileInfo>(); |
44 | 44 | ||
diff --git a/src/WixToolset.Core/Cab/WixExtractCab.cs b/src/WixToolset.Core/Cab/WixExtractCab.cs index debdaf15..e776b08e 100644 --- a/src/WixToolset.Core/Cab/WixExtractCab.cs +++ b/src/WixToolset.Core/Cab/WixExtractCab.cs | |||
@@ -1,9 +1,8 @@ | |||
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.Cab | 3 | namespace WixToolset.Core.Cab |
4 | { | 4 | { |
5 | using System; | 5 | using System; |
6 | using System.Runtime.InteropServices; | ||
7 | using WixToolset.Core.Native; | 6 | using WixToolset.Core.Native; |
8 | 7 | ||
9 | /// <summary> | 8 | /// <summary> |
diff --git a/src/WixToolset.Core/CommandLine/BuildCommand.cs b/src/WixToolset.Core/CommandLine/BuildCommand.cs index afb9e829..32da5bcf 100644 --- a/src/WixToolset.Core/CommandLine/BuildCommand.cs +++ b/src/WixToolset.Core/CommandLine/BuildCommand.cs | |||
@@ -7,13 +7,14 @@ namespace WixToolset.Core | |||
7 | using System.IO; | 7 | using System.IO; |
8 | using System.Linq; | 8 | using System.Linq; |
9 | using WixToolset.Data; | 9 | using WixToolset.Data; |
10 | using WixToolset.Data.Rows; | ||
10 | using WixToolset.Extensibility; | 11 | using WixToolset.Extensibility; |
11 | 12 | ||
12 | internal class BuildCommand : ICommandLineCommand | 13 | internal class BuildCommand : ICommandLineCommand |
13 | { | 14 | { |
14 | public BuildCommand(ExtensionManager extensions, IEnumerable<SourceFile> sources, IDictionary<string, string> preprocessorVariables, IEnumerable<string> locFiles, IEnumerable<string> libraryFiles, string outputPath, OutputType outputType, IEnumerable<string> cultures, bool bindFiles, IEnumerable<BindPath> bindPaths, string intermediateFolder, string contentsFile, string outputsFile, string builtOutputsFile, string wixProjectFile) | 15 | public BuildCommand(ExtensionManager extensions, IEnumerable<SourceFile> sources, IDictionary<string, string> preprocessorVariables, IEnumerable<string> locFiles, IEnumerable<string> libraryFiles, string outputPath, OutputType outputType, string cabCachePath, IEnumerable<string> cultures, bool bindFiles, IEnumerable<BindPath> bindPaths, string intermediateFolder, string contentsFile, string outputsFile, string builtOutputsFile, string wixProjectFile) |
15 | { | 16 | { |
16 | this.Extensions = extensions; | 17 | this.ExtensionManager = extensions; |
17 | this.LocFiles = locFiles; | 18 | this.LocFiles = locFiles; |
18 | this.LibraryFiles = libraryFiles; | 19 | this.LibraryFiles = libraryFiles; |
19 | this.PreprocessorVariables = preprocessorVariables; | 20 | this.PreprocessorVariables = preprocessorVariables; |
@@ -21,6 +22,7 @@ namespace WixToolset.Core | |||
21 | this.OutputPath = outputPath; | 22 | this.OutputPath = outputPath; |
22 | this.OutputType = outputType; | 23 | this.OutputType = outputType; |
23 | 24 | ||
25 | this.CabCachePath = cabCachePath; | ||
24 | this.Cultures = cultures; | 26 | this.Cultures = cultures; |
25 | this.BindFiles = bindFiles; | 27 | this.BindFiles = bindFiles; |
26 | this.BindPaths = bindPaths; | 28 | this.BindPaths = bindPaths; |
@@ -32,7 +34,7 @@ namespace WixToolset.Core | |||
32 | this.WixProjectFile = wixProjectFile; | 34 | this.WixProjectFile = wixProjectFile; |
33 | } | 35 | } |
34 | 36 | ||
35 | public ExtensionManager Extensions { get; } | 37 | public ExtensionManager ExtensionManager { get; } |
36 | 38 | ||
37 | public IEnumerable<string> LocFiles { get; } | 39 | public IEnumerable<string> LocFiles { get; } |
38 | 40 | ||
@@ -46,6 +48,8 @@ namespace WixToolset.Core | |||
46 | 48 | ||
47 | private OutputType OutputType { get; } | 49 | private OutputType OutputType { get; } |
48 | 50 | ||
51 | public string CabCachePath { get; } | ||
52 | |||
49 | public IEnumerable<string> Cultures { get; } | 53 | public IEnumerable<string> Cultures { get; } |
50 | 54 | ||
51 | public bool BindFiles { get; } | 55 | public bool BindFiles { get; } |
@@ -70,7 +74,9 @@ namespace WixToolset.Core | |||
70 | 74 | ||
71 | if (this.OutputType == OutputType.Library) | 75 | if (this.OutputType == OutputType.Library) |
72 | { | 76 | { |
73 | this.LibraryPhase(intermediates, tableDefinitions); | 77 | var library = this.LibraryPhase(intermediates, tableDefinitions); |
78 | |||
79 | library?.Save(this.OutputPath); | ||
74 | } | 80 | } |
75 | else | 81 | else |
76 | { | 82 | { |
@@ -105,51 +111,40 @@ namespace WixToolset.Core | |||
105 | return intermediates; | 111 | return intermediates; |
106 | } | 112 | } |
107 | 113 | ||
108 | private void LibraryPhase(IEnumerable<Intermediate> intermediates, TableDefinitionCollection tableDefinitions) | 114 | private Library LibraryPhase(IEnumerable<Intermediate> intermediates, TableDefinitionCollection tableDefinitions) |
109 | { | 115 | { |
110 | var localizations = this.LoadLocalizationFiles(tableDefinitions).ToList(); | 116 | var localizations = this.LoadLocalizationFiles(tableDefinitions).ToList(); |
111 | 117 | ||
112 | // If there was an error adding localization files, then bail. | 118 | // If there was an error adding localization files, then bail. |
113 | if (Messaging.Instance.EncounteredError) | 119 | if (Messaging.Instance.EncounteredError) |
114 | { | 120 | { |
115 | return; | 121 | return null; |
116 | } | 122 | } |
117 | 123 | ||
118 | var sections = intermediates.SelectMany(i => i.Sections).ToList(); | 124 | var resolver = CreateWixResolverWithVariables(null, null); |
119 | |||
120 | LibraryBinaryFileResolver resolver = null; | ||
121 | |||
122 | if (this.BindFiles) | ||
123 | { | ||
124 | resolver = new LibraryBinaryFileResolver(); | ||
125 | resolver.FileManagers = new List<IBinderFileManager> { new BinderFileManager() }; ; | ||
126 | resolver.VariableResolver = new WixVariableResolver(); | ||
127 | |||
128 | BinderFileManagerCore core = new BinderFileManagerCore(); | ||
129 | core.AddBindPaths(this.BindPaths, BindStage.Normal); | ||
130 | |||
131 | foreach (var fileManager in resolver.FileManagers) | ||
132 | { | ||
133 | fileManager.Core = core; | ||
134 | } | ||
135 | } | ||
136 | 125 | ||
137 | var librarian = new Librarian(); | 126 | var context = new LibraryContext(); |
127 | context.BindFiles = this.BindFiles; | ||
128 | context.BindPaths = this.BindPaths; | ||
129 | context.Extensions = this.ExtensionManager.Create<ILibrarianExtension>(); | ||
130 | context.Localizations = localizations; | ||
131 | context.Sections = intermediates.SelectMany(i => i.Sections).ToList(); | ||
132 | context.WixVariableResolver = resolver; | ||
138 | 133 | ||
139 | var library = librarian.Combine(sections, localizations, resolver); | 134 | var librarian = new Librarian(context); |
140 | 135 | ||
141 | library?.Save(this.OutputPath); | 136 | return librarian.Combine(); |
142 | } | 137 | } |
143 | 138 | ||
144 | private Output LinkPhase(IEnumerable<Intermediate> intermediates, TableDefinitionCollection tableDefinitions) | 139 | private Output LinkPhase(IEnumerable<Intermediate> intermediates, TableDefinitionCollection tableDefinitions) |
145 | { | 140 | { |
146 | var sections = intermediates.SelectMany(i => i.Sections).ToList(); | 141 | var sections = intermediates.SelectMany(i => i.Sections).ToList(); |
147 | 142 | ||
148 | sections.AddRange(SectionsFromLibraries(tableDefinitions)); | 143 | sections.AddRange(this.SectionsFromLibraries(tableDefinitions)); |
149 | 144 | ||
150 | var linker = new Linker(); | 145 | var linker = new Linker(); |
151 | 146 | ||
152 | foreach (var data in this.Extensions.Create<IExtensionData>()) | 147 | foreach (var data in this.ExtensionManager.Create<IExtensionData>()) |
153 | { | 148 | { |
154 | linker.AddExtensionData(data); | 149 | linker.AddExtensionData(data); |
155 | } | 150 | } |
@@ -159,6 +154,40 @@ namespace WixToolset.Core | |||
159 | return output; | 154 | return output; |
160 | } | 155 | } |
161 | 156 | ||
157 | private void BindPhase(Output output, TableDefinitionCollection tableDefinitions) | ||
158 | { | ||
159 | var localizations = this.LoadLocalizationFiles(tableDefinitions).ToList(); | ||
160 | |||
161 | var localizer = new Localizer(localizations); | ||
162 | |||
163 | var resolver = CreateWixResolverWithVariables(localizer, output); | ||
164 | |||
165 | var context = new BindContext(); | ||
166 | context.Messaging = Messaging.Instance; | ||
167 | context.ExtensionManager = this.ExtensionManager; | ||
168 | context.BindPaths = this.BindPaths ?? Array.Empty<BindPath>(); | ||
169 | //context.CabbingThreadCount = this.CabbingThreadCount; | ||
170 | context.CabCachePath = this.CabCachePath; | ||
171 | context.Codepage = localizer.Codepage; | ||
172 | //context.DefaultCompressionLevel = this.DefaultCompressionLevel; | ||
173 | //context.Ices = this.Ices; | ||
174 | context.IntermediateFolder = this.IntermediateFolder; | ||
175 | context.IntermediateRepresentation = output; | ||
176 | context.OutputPath = this.OutputPath; | ||
177 | context.OutputPdbPath = Path.ChangeExtension(this.OutputPath, ".wixpdb"); | ||
178 | //context.SuppressIces = this.SuppressIces; | ||
179 | context.SuppressValidation = true; | ||
180 | //context.SuppressValidation = this.SuppressValidation; | ||
181 | context.WixVariableResolver = resolver; | ||
182 | context.ContentsFile = this.ContentsFile; | ||
183 | context.OutputsFile = this.OutputsFile; | ||
184 | context.BuiltOutputsFile = this.BuiltOutputsFile; | ||
185 | context.WixprojectFile = this.WixProjectFile; | ||
186 | |||
187 | var binder = new Binder(context); | ||
188 | binder.Bind(); | ||
189 | } | ||
190 | |||
162 | private IEnumerable<Section> SectionsFromLibraries(TableDefinitionCollection tableDefinitions) | 191 | private IEnumerable<Section> SectionsFromLibraries(TableDefinitionCollection tableDefinitions) |
163 | { | 192 | { |
164 | var sections = new List<Section>(); | 193 | var sections = new List<Section>(); |
@@ -187,34 +216,6 @@ namespace WixToolset.Core | |||
187 | return sections; | 216 | return sections; |
188 | } | 217 | } |
189 | 218 | ||
190 | private void BindPhase(Output output, TableDefinitionCollection tableDefinitions) | ||
191 | { | ||
192 | var localizations = this.LoadLocalizationFiles(tableDefinitions).ToList(); | ||
193 | |||
194 | var localizer = new Localizer(localizations); | ||
195 | |||
196 | var resolver = new WixVariableResolver(localizer); | ||
197 | |||
198 | var binder = new Binder(); | ||
199 | binder.TempFilesLocation = this.IntermediateFolder; | ||
200 | binder.WixVariableResolver = resolver; | ||
201 | binder.SuppressValidation = true; | ||
202 | |||
203 | binder.ContentsFile = this.ContentsFile; | ||
204 | binder.OutputsFile = this.OutputsFile; | ||
205 | binder.BuiltOutputsFile = this.BuiltOutputsFile; | ||
206 | binder.WixprojectFile = this.WixProjectFile; | ||
207 | |||
208 | if (this.BindPaths != null) | ||
209 | { | ||
210 | binder.BindPaths.AddRange(this.BindPaths); | ||
211 | } | ||
212 | |||
213 | binder.AddExtension(new BinderFileManager()); | ||
214 | |||
215 | binder.Bind(output, this.OutputPath); | ||
216 | } | ||
217 | |||
218 | private IEnumerable<Localization> LoadLocalizationFiles(TableDefinitionCollection tableDefinitions) | 219 | private IEnumerable<Localization> LoadLocalizationFiles(TableDefinitionCollection tableDefinitions) |
219 | { | 220 | { |
220 | foreach (var loc in this.LocFiles) | 221 | foreach (var loc in this.LocFiles) |
@@ -225,30 +226,21 @@ namespace WixToolset.Core | |||
225 | } | 226 | } |
226 | } | 227 | } |
227 | 228 | ||
228 | /// <summary> | 229 | private static WixVariableResolver CreateWixResolverWithVariables(Localizer localizer, Output output) |
229 | /// File resolution mechanism to create binary library. | ||
230 | /// </summary> | ||
231 | private class LibraryBinaryFileResolver : ILibraryBinaryFileResolver | ||
232 | { | 230 | { |
233 | public IEnumerable<IBinderFileManager> FileManagers { get; set; } | 231 | var resolver = new WixVariableResolver(localizer); |
234 | |||
235 | public WixVariableResolver VariableResolver { get; set; } | ||
236 | 232 | ||
237 | public string Resolve(SourceLineNumber sourceLineNumber, string table, string path) | 233 | // Gather all the wix variables. |
234 | Table wixVariableTable = output?.Tables["WixVariable"]; | ||
235 | if (null != wixVariableTable) | ||
238 | { | 236 | { |
239 | string resolvedPath = this.VariableResolver.ResolveVariables(sourceLineNumber, path, false); | 237 | foreach (WixVariableRow wixVariableRow in wixVariableTable.Rows) |
240 | |||
241 | foreach (IBinderFileManager fileManager in this.FileManagers) | ||
242 | { | 238 | { |
243 | string finalPath = fileManager.ResolveFile(resolvedPath, table, sourceLineNumber, BindStage.Normal); | 239 | resolver.AddVariable(wixVariableRow); |
244 | if (!String.IsNullOrEmpty(finalPath)) | ||
245 | { | ||
246 | return finalPath; | ||
247 | } | ||
248 | } | 240 | } |
249 | |||
250 | return null; | ||
251 | } | 241 | } |
242 | |||
243 | return resolver; | ||
252 | } | 244 | } |
253 | } | 245 | } |
254 | } | 246 | } |
diff --git a/src/WixToolset.Core/CommandLine/CommandLine.cs b/src/WixToolset.Core/CommandLine/CommandLine.cs index a3a6831c..2f203ecb 100644 --- a/src/WixToolset.Core/CommandLine/CommandLine.cs +++ b/src/WixToolset.Core/CommandLine/CommandLine.cs | |||
@@ -6,6 +6,7 @@ namespace WixToolset.Core | |||
6 | using System.Collections.Generic; | 6 | using System.Collections.Generic; |
7 | using System.IO; | 7 | using System.IO; |
8 | using System.Linq; | 8 | using System.Linq; |
9 | using System.Reflection; | ||
9 | using System.Text; | 10 | using System.Text; |
10 | using System.Text.RegularExpressions; | 11 | using System.Text.RegularExpressions; |
11 | using WixToolset.Data; | 12 | using WixToolset.Data; |
@@ -71,6 +72,7 @@ namespace WixToolset.Core | |||
71 | 72 | ||
72 | var intermediateFolder = String.Empty; | 73 | var intermediateFolder = String.Empty; |
73 | 74 | ||
75 | var cabCachePath = String.Empty; | ||
74 | var cultures = new List<string>(); | 76 | var cultures = new List<string>(); |
75 | var contentsFile = String.Empty; | 77 | var contentsFile = String.Empty; |
76 | var outputsFile = String.Empty; | 78 | var outputsFile = String.Empty; |
@@ -98,6 +100,10 @@ namespace WixToolset.Core | |||
98 | cmdline.GetNextArgumentOrError(bindPaths); | 100 | cmdline.GetNextArgumentOrError(bindPaths); |
99 | return true; | 101 | return true; |
100 | 102 | ||
103 | case "cc": | ||
104 | cmdline.GetNextArgumentOrError(ref cabCachePath); | ||
105 | return true; | ||
106 | |||
101 | case "cultures": | 107 | case "cultures": |
102 | cmdline.GetNextArgumentOrError(cultures); | 108 | cmdline.GetNextArgumentOrError(cultures); |
103 | return true; | 109 | return true; |
@@ -190,12 +196,14 @@ namespace WixToolset.Core | |||
190 | { | 196 | { |
191 | case Commands.Build: | 197 | case Commands.Build: |
192 | { | 198 | { |
199 | LoadStandardBackends(cli.ExtensionManager); | ||
200 | |||
193 | var sourceFiles = GatherSourceFiles(files, outputFolder); | 201 | var sourceFiles = GatherSourceFiles(files, outputFolder); |
194 | var variables = GatherPreprocessorVariables(defines); | 202 | var variables = GatherPreprocessorVariables(defines); |
195 | var bindPathList = GatherBindPaths(bindPaths); | 203 | var bindPathList = GatherBindPaths(bindPaths); |
196 | var extensions = cli.ExtensionManager; | 204 | var extensions = cli.ExtensionManager; |
197 | var type = CalculateOutputType(outputType, outputFile); | 205 | var type = CalculateOutputType(outputType, outputFile); |
198 | return new BuildCommand(extensions, sourceFiles, variables, locFiles, libraryFiles, outputFile, type, cultures, bindFiles, bindPathList, intermediateFolder, contentsFile, outputsFile, builtOutputsFile, wixProjectFile); | 206 | return new BuildCommand(extensions, sourceFiles, variables, locFiles, libraryFiles, outputFile, type, cabCachePath, cultures, bindFiles, bindPathList, intermediateFolder, contentsFile, outputsFile, builtOutputsFile, wixProjectFile); |
199 | } | 207 | } |
200 | 208 | ||
201 | case Commands.Compile: | 209 | case Commands.Compile: |
@@ -209,6 +217,18 @@ namespace WixToolset.Core | |||
209 | return null; | 217 | return null; |
210 | } | 218 | } |
211 | 219 | ||
220 | private static void LoadStandardBackends(ExtensionManager extensionManager) | ||
221 | { | ||
222 | var folder = Path.GetDirectoryName(new Uri(Assembly.GetExecutingAssembly().CodeBase).LocalPath); | ||
223 | |||
224 | foreach (var backendAssemblyName in new[] { "WixToolset.Core.Burn.dll", "WixToolset.Core.WindowsInstaller.dll" }) | ||
225 | { | ||
226 | var path = Path.Combine(folder, backendAssemblyName); | ||
227 | |||
228 | extensionManager.Load(path); | ||
229 | } | ||
230 | } | ||
231 | |||
212 | private static OutputType CalculateOutputType(string outputType, string outputFile) | 232 | private static OutputType CalculateOutputType(string outputType, string outputFile) |
213 | { | 233 | { |
214 | if (String.IsNullOrEmpty(outputType)) | 234 | if (String.IsNullOrEmpty(outputType)) |
diff --git a/src/WixToolset.Core/Common.cs b/src/WixToolset.Core/Common.cs index a2881984..28e7ee7b 100644 --- a/src/WixToolset.Core/Common.cs +++ b/src/WixToolset.Core/Common.cs | |||
@@ -17,7 +17,7 @@ namespace WixToolset | |||
17 | /// <summary> | 17 | /// <summary> |
18 | /// Common Wix utility methods and types. | 18 | /// Common Wix utility methods and types. |
19 | /// </summary> | 19 | /// </summary> |
20 | internal static class Common | 20 | public static class Common |
21 | { | 21 | { |
22 | //------------------------------------------------------------------------------------------------- | 22 | //------------------------------------------------------------------------------------------------- |
23 | // Layout of an Access Mask (from http://technet.microsoft.com/en-us/library/cc783530(WS.10).aspx) | 23 | // Layout of an Access Mask (from http://technet.microsoft.com/en-us/library/cc783530(WS.10).aspx) |
@@ -89,9 +89,7 @@ namespace WixToolset | |||
89 | // FILE_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x1FF) | 89 | // FILE_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x1FF) |
90 | internal static readonly string[] FilePermissions = { "Read", "Write", "Append", "ReadExtendedAttributes", "WriteExtendedAttributes", "Execute", "FileAllRights", "ReadAttributes", "WriteAttributes" }; | 90 | internal static readonly string[] FilePermissions = { "Read", "Write", "Append", "ReadExtendedAttributes", "WriteExtendedAttributes", "Execute", "FileAllRights", "ReadAttributes", "WriteAttributes" }; |
91 | 91 | ||
92 | internal static readonly string[] ReservedFileNames = { "CON", "PRN", "AUX", "NUL", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9" }; | 92 | public static readonly Regex WixVariableRegex = new Regex(@"(\!|\$)\((?<namespace>loc|wix|bind|bindpath)\.(?<fullname>(?<name>[_A-Za-z][0-9A-Za-z_]+)(\.(?<scope>[_A-Za-z][0-9A-Za-z_\.]*))?)(\=(?<value>.+?))?\)", RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.ExplicitCapture); |
93 | |||
94 | internal static readonly Regex WixVariableRegex = new Regex(@"(\!|\$)\((?<namespace>loc|wix|bind|bindpath)\.(?<fullname>(?<name>[_A-Za-z][0-9A-Za-z_]+)(\.(?<scope>[_A-Za-z][0-9A-Za-z_\.]*))?)(\=(?<value>.+?))?\)", RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.ExplicitCapture); | ||
95 | 93 | ||
96 | internal const char CustomRowFieldSeparator = '\x85'; | 94 | internal const char CustomRowFieldSeparator = '\x85'; |
97 | 95 | ||
@@ -170,15 +168,14 @@ namespace WixToolset | |||
170 | /// <exception cref="ArgumentNullException"><paramref name="value"/> is null.</exception> | 168 | /// <exception cref="ArgumentNullException"><paramref name="value"/> is null.</exception> |
171 | /// <exception cref="NotSupportedException">The value doesn't not represent a valid code page name or integer value.</exception> | 169 | /// <exception cref="NotSupportedException">The value doesn't not represent a valid code page name or integer value.</exception> |
172 | /// <exception cref="WixException">The code page is invalid for summary information.</exception> | 170 | /// <exception cref="WixException">The code page is invalid for summary information.</exception> |
173 | internal static int GetValidCodePage(string value, bool allowNoChange = false, bool onlyAnsi = false, SourceLineNumber sourceLineNumbers = null) | 171 | public static int GetValidCodePage(string value, bool allowNoChange = false, bool onlyAnsi = false, SourceLineNumber sourceLineNumbers = null) |
174 | { | 172 | { |
175 | int codePage; | ||
176 | Encoding encoding; | ||
177 | |||
178 | try | 173 | try |
179 | { | 174 | { |
175 | Encoding encoding; | ||
176 | |||
180 | // check if a integer as a string was passed | 177 | // check if a integer as a string was passed |
181 | if (Int32.TryParse(value, out codePage)) | 178 | if (Int32.TryParse(value, out int codePage)) |
182 | { | 179 | { |
183 | if (0 == codePage) | 180 | if (0 == codePage) |
184 | { | 181 | { |
@@ -366,9 +363,9 @@ namespace WixToolset | |||
366 | /// Generate a new Windows Installer-friendly guid. | 363 | /// Generate a new Windows Installer-friendly guid. |
367 | /// </summary> | 364 | /// </summary> |
368 | /// <returns>A new guid.</returns> | 365 | /// <returns>A new guid.</returns> |
369 | internal static string GenerateGuid() | 366 | public static string GenerateGuid() |
370 | { | 367 | { |
371 | return Guid.NewGuid().ToString("B").ToUpper(CultureInfo.InvariantCulture); | 368 | return Guid.NewGuid().ToString("B").ToUpperInvariant(); |
372 | } | 369 | } |
373 | 370 | ||
374 | /// <summary> | 371 | /// <summary> |
@@ -465,7 +462,7 @@ namespace WixToolset | |||
465 | } | 462 | } |
466 | } | 463 | } |
467 | 464 | ||
468 | internal static string GetFileHash(string path) | 465 | public static string GetFileHash(string path) |
469 | { | 466 | { |
470 | using (SHA1Managed managed = new SHA1Managed()) | 467 | using (SHA1Managed managed = new SHA1Managed()) |
471 | { | 468 | { |
@@ -478,6 +475,147 @@ namespace WixToolset | |||
478 | } | 475 | } |
479 | 476 | ||
480 | /// <summary> | 477 | /// <summary> |
478 | /// Takes an id, and demodularizes it (if possible). | ||
479 | /// </summary> | ||
480 | /// <remarks> | ||
481 | /// If the output type is a module, returns a demodularized version of an id. Otherwise, returns the id. | ||
482 | /// </remarks> | ||
483 | /// <param name="outputType">The type of the output to bind.</param> | ||
484 | /// <param name="modularizationGuid">The modularization GUID.</param> | ||
485 | /// <param name="id">The id to demodularize.</param> | ||
486 | /// <returns>The demodularized id.</returns> | ||
487 | public static string Demodularize(OutputType outputType, string modularizationGuid, string id) | ||
488 | { | ||
489 | if (OutputType.Module == outputType && id.EndsWith(String.Concat(".", modularizationGuid), StringComparison.Ordinal)) | ||
490 | { | ||
491 | id = id.Substring(0, id.Length - 37); | ||
492 | } | ||
493 | |||
494 | return id; | ||
495 | } | ||
496 | |||
497 | /// <summary> | ||
498 | /// Get the source/target and short/long file names from an MSI Filename column. | ||
499 | /// </summary> | ||
500 | /// <param name="value">The Filename value.</param> | ||
501 | /// <returns>An array of strings of length 4. The contents are: short target, long target, short source, and long source.</returns> | ||
502 | /// <remarks> | ||
503 | /// If any particular file name part is not parsed, its set to null in the appropriate location of the returned array of strings. | ||
504 | /// However, the returned array will always be of length 4. | ||
505 | /// </remarks> | ||
506 | public static string[] GetNames(string value) | ||
507 | { | ||
508 | string[] names = new string[4]; | ||
509 | int targetSeparator = value.IndexOf(":", StringComparison.Ordinal); | ||
510 | |||
511 | // split source and target | ||
512 | string sourceName = null; | ||
513 | string targetName = value; | ||
514 | if (0 <= targetSeparator) | ||
515 | { | ||
516 | sourceName = value.Substring(targetSeparator + 1); | ||
517 | targetName = value.Substring(0, targetSeparator); | ||
518 | } | ||
519 | |||
520 | // split the source short and long names | ||
521 | string sourceLongName = null; | ||
522 | if (null != sourceName) | ||
523 | { | ||
524 | int sourceLongNameSeparator = sourceName.IndexOf("|", StringComparison.Ordinal); | ||
525 | if (0 <= sourceLongNameSeparator) | ||
526 | { | ||
527 | sourceLongName = sourceName.Substring(sourceLongNameSeparator + 1); | ||
528 | sourceName = sourceName.Substring(0, sourceLongNameSeparator); | ||
529 | } | ||
530 | } | ||
531 | |||
532 | // split the target short and long names | ||
533 | int targetLongNameSeparator = targetName.IndexOf("|", StringComparison.Ordinal); | ||
534 | string targetLongName = null; | ||
535 | if (0 <= targetLongNameSeparator) | ||
536 | { | ||
537 | targetLongName = targetName.Substring(targetLongNameSeparator + 1); | ||
538 | targetName = targetName.Substring(0, targetLongNameSeparator); | ||
539 | } | ||
540 | |||
541 | // remove the long source name when its identical to the long source name | ||
542 | if (null != sourceName && sourceName == sourceLongName) | ||
543 | { | ||
544 | sourceLongName = null; | ||
545 | } | ||
546 | |||
547 | // remove the long target name when its identical to the long target name | ||
548 | if (null != targetName && targetName == targetLongName) | ||
549 | { | ||
550 | targetLongName = null; | ||
551 | } | ||
552 | |||
553 | // remove the source names when they are identical to the target names | ||
554 | if (sourceName == targetName && sourceLongName == targetLongName) | ||
555 | { | ||
556 | sourceName = null; | ||
557 | sourceLongName = null; | ||
558 | } | ||
559 | |||
560 | // target name(s) | ||
561 | if ("." != targetName) | ||
562 | { | ||
563 | names[0] = targetName; | ||
564 | } | ||
565 | |||
566 | if (null != targetLongName && "." != targetLongName) | ||
567 | { | ||
568 | names[1] = targetLongName; | ||
569 | } | ||
570 | |||
571 | // source name(s) | ||
572 | if (null != sourceName) | ||
573 | { | ||
574 | names[2] = sourceName; | ||
575 | } | ||
576 | |||
577 | if (null != sourceLongName && "." != sourceLongName) | ||
578 | { | ||
579 | names[3] = sourceLongName; | ||
580 | } | ||
581 | |||
582 | return names; | ||
583 | } | ||
584 | |||
585 | /// <summary> | ||
586 | /// Get a source/target and short/long file name from an MSI Filename column. | ||
587 | /// </summary> | ||
588 | /// <param name="value">The Filename value.</param> | ||
589 | /// <param name="source">true to get a source name; false to get a target name</param> | ||
590 | /// <param name="longName">true to get a long name; false to get a short name</param> | ||
591 | /// <returns>The name.</returns> | ||
592 | public static string GetName(string value, bool source, bool longName) | ||
593 | { | ||
594 | string[] names = GetNames(value); | ||
595 | |||
596 | if (source) | ||
597 | { | ||
598 | if (longName && null != names[3]) | ||
599 | { | ||
600 | return names[3]; | ||
601 | } | ||
602 | else if (null != names[2]) | ||
603 | { | ||
604 | return names[2]; | ||
605 | } | ||
606 | } | ||
607 | |||
608 | if (longName && null != names[1]) | ||
609 | { | ||
610 | return names[1]; | ||
611 | } | ||
612 | else | ||
613 | { | ||
614 | return names[0]; | ||
615 | } | ||
616 | } | ||
617 | |||
618 | /// <summary> | ||
481 | /// Get an attribute value. | 619 | /// Get an attribute value. |
482 | /// </summary> | 620 | /// </summary> |
483 | /// <param name="sourceLineNumbers">Source line information about the owner element.</param> | 621 | /// <param name="sourceLineNumbers">Source line information about the owner element.</param> |
diff --git a/src/WixToolset.Core/Compiler.cs b/src/WixToolset.Core/Compiler.cs index ed7cb60e..d085e788 100644 --- a/src/WixToolset.Core/Compiler.cs +++ b/src/WixToolset.Core/Compiler.cs | |||
@@ -11,11 +11,11 @@ namespace WixToolset | |||
11 | using System.IO; | 11 | using System.IO; |
12 | using System.Text.RegularExpressions; | 12 | using System.Text.RegularExpressions; |
13 | using System.Xml.Linq; | 13 | using System.Xml.Linq; |
14 | using WixToolset.Core; | ||
15 | using WixToolset.Core.Native; | ||
14 | using WixToolset.Data; | 16 | using WixToolset.Data; |
15 | using WixToolset.Data.Rows; | 17 | using WixToolset.Data.Rows; |
16 | using WixToolset.Extensibility; | 18 | using WixToolset.Extensibility; |
17 | using WixToolset.Msi; | ||
18 | using WixToolset.Core.Native; | ||
19 | using Wix = WixToolset.Data.Serialize; | 19 | using Wix = WixToolset.Data.Serialize; |
20 | 20 | ||
21 | /// <summary> | 21 | /// <summary> |
@@ -158,10 +158,7 @@ namespace WixToolset | |||
158 | [SuppressMessage("Microsoft.Design", "CA1059:MembersShouldNotExposeCertainConcreteTypes")] | 158 | [SuppressMessage("Microsoft.Design", "CA1059:MembersShouldNotExposeCertainConcreteTypes")] |
159 | public Intermediate Compile(XDocument source) | 159 | public Intermediate Compile(XDocument source) |
160 | { | 160 | { |
161 | if (null == source) | 161 | if (null == source) throw new ArgumentNullException(nameof(source)); |
162 | { | ||
163 | throw new ArgumentNullException("source"); | ||
164 | } | ||
165 | 162 | ||
166 | bool encounteredError = false; | 163 | bool encounteredError = false; |
167 | 164 | ||
@@ -220,9 +217,7 @@ namespace WixToolset | |||
220 | { | 217 | { |
221 | if (field.Data is string) | 218 | if (field.Data is string) |
222 | { | 219 | { |
223 | bool isDefault = false; | 220 | field.Data = this.componentIdPlaceholdersResolver.ResolveVariables(row.SourceLineNumbers, (string)field.Data, false, false, out var defaultIgnored, out var delayedIgnored); |
224 | bool delayedResolve = false; | ||
225 | field.Data = this.componentIdPlaceholdersResolver.ResolveVariables(row.SourceLineNumbers, (string)field.Data, false, false, ref isDefault, ref delayedResolve); | ||
226 | } | 221 | } |
227 | } | 222 | } |
228 | } | 223 | } |
@@ -470,7 +465,8 @@ namespace WixToolset | |||
470 | case "Advertise": | 465 | case "Advertise": |
471 | appIdAdvertise = this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | 466 | appIdAdvertise = this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); |
472 | break; | 467 | break; |
473 | case "Description": description = this.core.GetAttributeValue(sourceLineNumbers, attrib); | 468 | case "Description": |
469 | description = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
474 | break; | 470 | break; |
475 | case "DllSurrogate": | 471 | case "DllSurrogate": |
476 | dllSurrogate = this.core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.CanBeEmpty); | 472 | dllSurrogate = this.core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.CanBeEmpty); |
@@ -9471,13 +9467,13 @@ namespace WixToolset | |||
9471 | targetProductName = this.core.GetAttributeValue(sourceLineNumbers, attrib); | 9467 | targetProductName = this.core.GetAttributeValue(sourceLineNumbers, attrib); |
9472 | break; | 9468 | break; |
9473 | case "ApiPatchingSymbolNoImagehlpFlag": | 9469 | case "ApiPatchingSymbolNoImagehlpFlag": |
9474 | apiPatchingSymbolFlags |= (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) ? (int)PatchAPI.PatchInterop.PatchSymbolFlagsType.PATCH_SYMBOL_NO_IMAGEHLP : 0; | 9470 | apiPatchingSymbolFlags |= (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) ? (int)PatchSymbolFlagsType.PATCH_SYMBOL_NO_IMAGEHLP : 0; |
9475 | break; | 9471 | break; |
9476 | case "ApiPatchingSymbolNoFailuresFlag": | 9472 | case "ApiPatchingSymbolNoFailuresFlag": |
9477 | apiPatchingSymbolFlags |= (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) ? (int)PatchAPI.PatchInterop.PatchSymbolFlagsType.PATCH_SYMBOL_NO_FAILURES : 0; | 9473 | apiPatchingSymbolFlags |= (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) ? (int)PatchSymbolFlagsType.PATCH_SYMBOL_NO_FAILURES : 0; |
9478 | break; | 9474 | break; |
9479 | case "ApiPatchingSymbolUndecoratedTooFlag": | 9475 | case "ApiPatchingSymbolUndecoratedTooFlag": |
9480 | apiPatchingSymbolFlags |= (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) ? (int)PatchAPI.PatchInterop.PatchSymbolFlagsType.PATCH_SYMBOL_UNDECORATED_TOO : 0; | 9476 | apiPatchingSymbolFlags |= (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) ? (int)PatchSymbolFlagsType.PATCH_SYMBOL_UNDECORATED_TOO : 0; |
9481 | break; | 9477 | break; |
9482 | case "OptimizePatchSizeForLargeFiles": | 9478 | case "OptimizePatchSizeForLargeFiles": |
9483 | optimizePatchSizeForLargeFiles = (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)); | 9479 | optimizePatchSizeForLargeFiles = (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)); |
@@ -11802,7 +11798,7 @@ namespace WixToolset | |||
11802 | private void ParseProductElement(XElement node) | 11798 | private void ParseProductElement(XElement node) |
11803 | { | 11799 | { |
11804 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | 11800 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); |
11805 | int codepage = 0; | 11801 | int codepage = 65001; |
11806 | string productCode = null; | 11802 | string productCode = null; |
11807 | string upgradeCode = null; | 11803 | string upgradeCode = null; |
11808 | string manufacturer = null; | 11804 | string manufacturer = null; |
diff --git a/src/WixToolset.Core/CompilerCore.cs b/src/WixToolset.Core/CompilerCore.cs index 8640a2da..8f4703f7 100644 --- a/src/WixToolset.Core/CompilerCore.cs +++ b/src/WixToolset.Core/CompilerCore.cs | |||
@@ -45,10 +45,6 @@ namespace WixToolset | |||
45 | internal static readonly XNamespace W3SchemaPrefix = "http://www.w3.org/"; | 45 | internal static readonly XNamespace W3SchemaPrefix = "http://www.w3.org/"; |
46 | internal static readonly XNamespace WixNamespace = "http://wixtoolset.org/schemas/v4/wxs"; | 46 | internal static readonly XNamespace WixNamespace = "http://wixtoolset.org/schemas/v4/wxs"; |
47 | 47 | ||
48 | public const int DefaultMaximumUncompressedMediaSize = 200; // Default value is 200 MB | ||
49 | public const int MinValueOfMaxCabSizeForLargeFileSplitting = 20; // 20 MB | ||
50 | public const int MaxValueOfMaxCabSizeForLargeFileSplitting = 2 * 1024; // 2048 MB (i.e. 2 GB) | ||
51 | |||
52 | private static readonly Regex AmbiguousFilename = new Regex(@"^.{6}\~\d", RegexOptions.Compiled); | 48 | private static readonly Regex AmbiguousFilename = new Regex(@"^.{6}\~\d", RegexOptions.Compiled); |
53 | 49 | ||
54 | private const string IllegalLongFilenameCharacters = @"[\\\?|><:/\*""]"; // illegal: \ ? | > < : / * " | 50 | private const string IllegalLongFilenameCharacters = @"[\\\?|><:/\*""]"; // illegal: \ ? | > < : / * " |
@@ -67,6 +63,11 @@ namespace WixToolset | |||
67 | 63 | ||
68 | private static readonly Regex LegalIdentifierWithAccess = new Regex(@"^((?<access>public|internal|protected|private)\s+)?(?<id>[_A-Za-z][0-9A-Za-z_\.]*)$", RegexOptions.Compiled | RegexOptions.ExplicitCapture); | 64 | private static readonly Regex LegalIdentifierWithAccess = new Regex(@"^((?<access>public|internal|protected|private)\s+)?(?<id>[_A-Za-z][0-9A-Za-z_\.]*)$", RegexOptions.Compiled | RegexOptions.ExplicitCapture); |
69 | 65 | ||
66 | public const int DefaultMaximumUncompressedMediaSize = 200; // Default value is 200 MB | ||
67 | public const int MinValueOfMaxCabSizeForLargeFileSplitting = 20; // 20 MB | ||
68 | public const int MaxValueOfMaxCabSizeForLargeFileSplitting = 2 * 1024; // 2048 MB (i.e. 2 GB) | ||
69 | |||
70 | |||
70 | // Built-in variables (from burn\engine\variable.cpp, "vrgBuiltInVariables", around line 113) | 71 | // Built-in variables (from burn\engine\variable.cpp, "vrgBuiltInVariables", around line 113) |
71 | private static readonly List<String> BuiltinBundleVariables = new List<string>( | 72 | private static readonly List<String> BuiltinBundleVariables = new List<string>( |
72 | new string[] { | 73 | new string[] { |
diff --git a/src/WixToolset.Core/Data/messages.xml b/src/WixToolset.Core/Data/messages.xml index edc98147..d981e2d1 100644 --- a/src/WixToolset.Core/Data/messages.xml +++ b/src/WixToolset.Core/Data/messages.xml | |||
@@ -957,12 +957,6 @@ | |||
957 | <Parameter Type="System.String" Name="exceptionMessage" /> | 957 | <Parameter Type="System.String" Name="exceptionMessage" /> |
958 | </Instance> | 958 | </Instance> |
959 | </Message> | 959 | </Message> |
960 | <Message Id="InvalidFileName" Number="85"> | ||
961 | <Instance> | ||
962 | Invalid file name '{0}'. | ||
963 | <Parameter Type="System.String" Name="fileName" /> | ||
964 | </Instance> | ||
965 | </Message> | ||
966 | <Message Id="ReferenceLoopDetected" Number="86"> | 960 | <Message Id="ReferenceLoopDetected" Number="86"> |
967 | <Instance> | 961 | <Instance> |
968 | A circular reference of groups was detected. The infinite loop includes: {0}. Group references must form a directed acyclic graph. | 962 | A circular reference of groups was detected. The infinite loop includes: {0}. Group references must form a directed acyclic graph. |
@@ -2138,12 +2132,6 @@ | |||
2138 | This patch is not uninstallable. The 'Patch' element's attribute 'AllowRemoval' should be set to 'no'. | 2132 | This patch is not uninstallable. The 'Patch' element's attribute 'AllowRemoval' should be set to 'no'. |
2139 | </Instance> | 2133 | </Instance> |
2140 | </Message> | 2134 | </Message> |
2141 | <Message Id="PathTooLong" Number="262"> | ||
2142 | <Instance> | ||
2143 | '{0}' is too long, the fully qualified file name must be less than 260 characters, and the directory name must be less than 248 characters. | ||
2144 | <Parameter Type="System.String" Name="fileName" /> | ||
2145 | </Instance> | ||
2146 | </Message> | ||
2147 | <Message Id="FileTooLarge" Number="263"> | 2135 | <Message Id="FileTooLarge" Number="263"> |
2148 | <Instance> | 2136 | <Instance> |
2149 | '{0}' is too large, file size must be less than 2147483648. | 2137 | '{0}' is too large, file size must be less than 2147483648. |
diff --git a/src/WixToolset.Core/Decompiler.cs b/src/WixToolset.Core/Decompiler.cs index 249b5788..e72b0104 100644 --- a/src/WixToolset.Core/Decompiler.cs +++ b/src/WixToolset.Core/Decompiler.cs | |||
@@ -3,7 +3,6 @@ | |||
3 | namespace WixToolset | 3 | namespace WixToolset |
4 | { | 4 | { |
5 | using System; | 5 | using System; |
6 | using System.CodeDom.Compiler; | ||
7 | using System.Collections; | 6 | using System.Collections; |
8 | using System.Collections.Generic; | 7 | using System.Collections.Generic; |
9 | using System.Collections.Specialized; | 8 | using System.Collections.Specialized; |
@@ -15,9 +14,9 @@ namespace WixToolset | |||
15 | using WixToolset.Data; | 14 | using WixToolset.Data; |
16 | using WixToolset.Data.Rows; | 15 | using WixToolset.Data.Rows; |
17 | using WixToolset.Extensibility; | 16 | using WixToolset.Extensibility; |
18 | using WixToolset.Msi; | ||
19 | using WixToolset.Core.Native; | 17 | using WixToolset.Core.Native; |
20 | using Wix = WixToolset.Data.Serialize; | 18 | using Wix = WixToolset.Data.Serialize; |
19 | using WixToolset.Core; | ||
21 | 20 | ||
22 | /// <summary> | 21 | /// <summary> |
23 | /// Decompiles an msi database into WiX source. | 22 | /// Decompiles an msi database into WiX source. |
@@ -5201,7 +5200,7 @@ namespace WixToolset | |||
5201 | 5200 | ||
5202 | directory.Id = Convert.ToString(row[0]); | 5201 | directory.Id = Convert.ToString(row[0]); |
5203 | 5202 | ||
5204 | string[] names = Installer.GetNames(Convert.ToString(row[2])); | 5203 | string[] names = Common.GetNames(Convert.ToString(row[2])); |
5205 | 5204 | ||
5206 | if (String.Equals(directory.Id, "TARGETDIR", StringComparison.Ordinal) && !String.Equals(names[0], "SourceDir", StringComparison.Ordinal)) | 5205 | if (String.Equals(directory.Id, "TARGETDIR", StringComparison.Ordinal) && !String.Equals(names[0], "SourceDir", StringComparison.Ordinal)) |
5207 | { | 5206 | { |
@@ -5319,7 +5318,7 @@ namespace WixToolset | |||
5319 | 5318 | ||
5320 | if (null != row[3]) | 5319 | if (null != row[3]) |
5321 | { | 5320 | { |
5322 | string[] names = Installer.GetNames(Convert.ToString(row[3])); | 5321 | string[] names = Common.GetNames(Convert.ToString(row[3])); |
5323 | if (null != names[0] && null != names[1]) | 5322 | if (null != names[0] && null != names[1]) |
5324 | { | 5323 | { |
5325 | copyFile.DestinationShortName = names[0]; | 5324 | copyFile.DestinationShortName = names[0]; |
@@ -5788,7 +5787,7 @@ namespace WixToolset | |||
5788 | 5787 | ||
5789 | file.Id = fileRow.File; | 5788 | file.Id = fileRow.File; |
5790 | 5789 | ||
5791 | string[] names = Installer.GetNames(fileRow.FileName); | 5790 | string[] names = Common.GetNames(fileRow.FileName); |
5792 | if (null != names[0] && null != names[1]) | 5791 | if (null != names[0] && null != names[1]) |
5793 | { | 5792 | { |
5794 | file.ShortName = names[0]; | 5793 | file.ShortName = names[0]; |
@@ -5974,7 +5973,7 @@ namespace WixToolset | |||
5974 | 5973 | ||
5975 | iniFile.Id = Convert.ToString(row[0]); | 5974 | iniFile.Id = Convert.ToString(row[0]); |
5976 | 5975 | ||
5977 | string[] names = Installer.GetNames(Convert.ToString(row[1])); | 5976 | string[] names = Common.GetNames(Convert.ToString(row[1])); |
5978 | 5977 | ||
5979 | if (null != names[0]) | 5978 | if (null != names[0]) |
5980 | { | 5979 | { |
@@ -6044,7 +6043,7 @@ namespace WixToolset | |||
6044 | 6043 | ||
6045 | iniFileSearch.Id = Convert.ToString(row[0]); | 6044 | iniFileSearch.Id = Convert.ToString(row[0]); |
6046 | 6045 | ||
6047 | string[] names = Installer.GetNames(Convert.ToString(row[1])); | 6046 | string[] names = Common.GetNames(Convert.ToString(row[1])); |
6048 | if (null != names[0] && null != names[1]) | 6047 | if (null != names[0] && null != names[1]) |
6049 | { | 6048 | { |
6050 | iniFileSearch.ShortName = names[0]; | 6049 | iniFileSearch.ShortName = names[0]; |
@@ -6681,7 +6680,7 @@ namespace WixToolset | |||
6681 | 6680 | ||
6682 | if (null != row[3]) | 6681 | if (null != row[3]) |
6683 | { | 6682 | { |
6684 | string[] names = Installer.GetNames(Convert.ToString(row[3])); | 6683 | string[] names = Common.GetNames(Convert.ToString(row[3])); |
6685 | if (null != names[0] && null != names[1]) | 6684 | if (null != names[0] && null != names[1]) |
6686 | { | 6685 | { |
6687 | copyFile.DestinationShortName = names[0]; | 6686 | copyFile.DestinationShortName = names[0]; |
@@ -8007,7 +8006,7 @@ namespace WixToolset | |||
8007 | 8006 | ||
8008 | removeFile.Id = Convert.ToString(row[0]); | 8007 | removeFile.Id = Convert.ToString(row[0]); |
8009 | 8008 | ||
8010 | string[] names = Installer.GetNames(Convert.ToString(row[2])); | 8009 | string[] names = Common.GetNames(Convert.ToString(row[2])); |
8011 | if (null != names[0] && null != names[1]) | 8010 | if (null != names[0] && null != names[1]) |
8012 | { | 8011 | { |
8013 | removeFile.ShortName = names[0]; | 8012 | removeFile.ShortName = names[0]; |
@@ -8062,7 +8061,7 @@ namespace WixToolset | |||
8062 | 8061 | ||
8063 | iniFile.Id = Convert.ToString(row[0]); | 8062 | iniFile.Id = Convert.ToString(row[0]); |
8064 | 8063 | ||
8065 | string[] names = Installer.GetNames(Convert.ToString(row[1])); | 8064 | string[] names = Common.GetNames(Convert.ToString(row[1])); |
8066 | if (null != names[0] && null != names[1]) | 8065 | if (null != names[0] && null != names[1]) |
8067 | { | 8066 | { |
8068 | iniFile.ShortName = names[0]; | 8067 | iniFile.ShortName = names[0]; |
@@ -8531,7 +8530,7 @@ namespace WixToolset | |||
8531 | 8530 | ||
8532 | shortcut.Directory = Convert.ToString(row[1]); | 8531 | shortcut.Directory = Convert.ToString(row[1]); |
8533 | 8532 | ||
8534 | string[] names = Installer.GetNames(Convert.ToString(row[2])); | 8533 | string[] names = Common.GetNames(Convert.ToString(row[2])); |
8535 | if (null != names[0] && null != names[1]) | 8534 | if (null != names[0] && null != names[1]) |
8536 | { | 8535 | { |
8537 | shortcut.ShortName = names[0]; | 8536 | shortcut.ShortName = names[0]; |
@@ -8654,7 +8653,7 @@ namespace WixToolset | |||
8654 | 8653 | ||
8655 | fileSearch.Id = Convert.ToString(row[0]); | 8654 | fileSearch.Id = Convert.ToString(row[0]); |
8656 | 8655 | ||
8657 | string[] names = Installer.GetNames(Convert.ToString(row[1])); | 8656 | string[] names = Common.GetNames(Convert.ToString(row[1])); |
8658 | if (null != names[0]) | 8657 | if (null != names[0]) |
8659 | { | 8658 | { |
8660 | // it is permissable to just have a long name | 8659 | // it is permissable to just have a long name |
diff --git a/src/WixToolset.Core/Extensibility/HeatExtension.cs b/src/WixToolset.Core/Extensibility/HeatExtension.cs index 5e292220..48e1a93b 100644 --- a/src/WixToolset.Core/Extensibility/HeatExtension.cs +++ b/src/WixToolset.Core/Extensibility/HeatExtension.cs | |||
@@ -3,14 +3,10 @@ | |||
3 | namespace WixToolset.Extensibility | 3 | namespace WixToolset.Extensibility |
4 | { | 4 | { |
5 | using System; | 5 | using System; |
6 | using System.Collections.Generic; | ||
7 | using System.IO; | 6 | using System.IO; |
8 | using System.Reflection; | 7 | using System.Reflection; |
9 | using WixToolset; | ||
10 | using WixToolset.Data; | 8 | using WixToolset.Data; |
11 | using WixToolset.Extensibilty; | ||
12 | using WixToolset.Tools; | 9 | using WixToolset.Tools; |
13 | using Wix = WixToolset.Data.Serialize; | ||
14 | 10 | ||
15 | /// <summary> | 11 | /// <summary> |
16 | /// A command line option. | 12 | /// A command line option. |
diff --git a/src/WixToolset.Core/Extensibility/IHeatCore.cs b/src/WixToolset.Core/Extensibility/IHeatCore.cs index bc853b24..dbfc8929 100644 --- a/src/WixToolset.Core/Extensibility/IHeatCore.cs +++ b/src/WixToolset.Core/Extensibility/IHeatCore.cs | |||
@@ -1,6 +1,6 @@ | |||
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.Extensibilty | 3 | namespace WixToolset.Extensibility |
4 | { | 4 | { |
5 | using WixToolset.Data; | 5 | using WixToolset.Data; |
6 | 6 | ||
diff --git a/src/WixToolset.Core/ExtensionManager.cs b/src/WixToolset.Core/ExtensionManager.cs index 45cb65ec..7e40571b 100644 --- a/src/WixToolset.Core/ExtensionManager.cs +++ b/src/WixToolset.Core/ExtensionManager.cs | |||
@@ -8,8 +8,9 @@ namespace WixToolset | |||
8 | using System.Linq; | 8 | using System.Linq; |
9 | using System.Reflection; | 9 | using System.Reflection; |
10 | using WixToolset.Data; | 10 | using WixToolset.Data; |
11 | using WixToolset.Extensibility; | ||
11 | 12 | ||
12 | public class ExtensionManager | 13 | public class ExtensionManager : IExtensionManager |
13 | { | 14 | { |
14 | private List<Assembly> extensionAssemblies = new List<Assembly>(); | 15 | private List<Assembly> extensionAssemblies = new List<Assembly>(); |
15 | 16 | ||
@@ -67,8 +68,7 @@ namespace WixToolset | |||
67 | /// <returns>Extensions created of the specified type.</returns> | 68 | /// <returns>Extensions created of the specified type.</returns> |
68 | public IEnumerable<T> Create<T>() where T : class | 69 | public IEnumerable<T> Create<T>() where T : class |
69 | { | 70 | { |
70 | var extensionType = typeof(T); | 71 | var types = this.extensionAssemblies.SelectMany(a => a.GetTypes().Where(t => !t.IsAbstract && !t.IsInterface && typeof(T).IsAssignableFrom(t))); |
71 | var types = this.extensionAssemblies.SelectMany(a => a.GetTypes().Where(t => !t.IsAbstract && !t.IsInterface && extensionType.IsAssignableFrom(t))); | ||
72 | return types.Select(t => (T)Activator.CreateInstance(t)).ToList(); | 72 | return types.Select(t => (T)Activator.CreateInstance(t)).ToList(); |
73 | } | 73 | } |
74 | 74 | ||
diff --git a/src/WixToolset.Core/HeatCore.cs b/src/WixToolset.Core/HeatCore.cs index 5c5defe8..01233c40 100644 --- a/src/WixToolset.Core/HeatCore.cs +++ b/src/WixToolset.Core/HeatCore.cs | |||
@@ -2,11 +2,8 @@ | |||
2 | 2 | ||
3 | namespace WixToolset.Tools | 3 | namespace WixToolset.Tools |
4 | { | 4 | { |
5 | using System; | ||
6 | using System.Reflection; | ||
7 | using WixToolset.Data; | 5 | using WixToolset.Data; |
8 | using WixToolset.Extensibilty; | 6 | using WixToolset.Extensibility; |
9 | using Wix = WixToolset.Data.Serialize; | ||
10 | 7 | ||
11 | /// <summary> | 8 | /// <summary> |
12 | /// The WiX Toolset Harvester application core. | 9 | /// The WiX Toolset Harvester application core. |
diff --git a/src/WixToolset.Core/IncribeContext.cs b/src/WixToolset.Core/IncribeContext.cs new file mode 100644 index 00000000..604ba5d1 --- /dev/null +++ b/src/WixToolset.Core/IncribeContext.cs | |||
@@ -0,0 +1,20 @@ | |||
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.Data; | ||
6 | using WixToolset.Extensibility; | ||
7 | |||
8 | internal class InscribeContext : IInscribeContext | ||
9 | { | ||
10 | public Messaging Messaging { get; } = Messaging.Instance; | ||
11 | |||
12 | public string IntermediateFolder { get; set; } | ||
13 | |||
14 | public string InputFilePath { get; set; } | ||
15 | |||
16 | public string SignedEngineFile { get; set; } | ||
17 | |||
18 | public string OutputFile { get; set; } | ||
19 | } | ||
20 | } | ||
diff --git a/src/WixToolset.Core/Inscriber.cs b/src/WixToolset.Core/Inscriber.cs index 5b467ec1..f01e0629 100644 --- a/src/WixToolset.Core/Inscriber.cs +++ b/src/WixToolset.Core/Inscriber.cs | |||
@@ -2,17 +2,8 @@ | |||
2 | 2 | ||
3 | namespace WixToolset | 3 | namespace WixToolset |
4 | { | 4 | { |
5 | using System; | ||
6 | using System.CodeDom.Compiler; | ||
7 | using System.Collections.Generic; | ||
8 | using System.Globalization; | ||
9 | using System.IO; | 5 | using System.IO; |
10 | using System.Runtime.InteropServices; | ||
11 | using System.Security.Cryptography.X509Certificates; | ||
12 | using WixToolset.Bind.Bundles; | ||
13 | using WixToolset.Data; | 6 | using WixToolset.Data; |
14 | using WixToolset.Msi; | ||
15 | using WixToolset.Core.Native; | ||
16 | 7 | ||
17 | /// <summary> | 8 | /// <summary> |
18 | /// Converts a wixout representation of an MSM database into a ComponentGroup the form of WiX source. | 9 | /// Converts a wixout representation of an MSM database into a ComponentGroup the form of WiX source. |
@@ -81,41 +72,41 @@ namespace WixToolset | |||
81 | /// <returns>True if bundle was updated.</returns> | 72 | /// <returns>True if bundle was updated.</returns> |
82 | public bool InscribeBundleEngine(string bundleFile, string outputFile) | 73 | public bool InscribeBundleEngine(string bundleFile, string outputFile) |
83 | { | 74 | { |
84 | string tempFile = Path.Combine(this.TempFilesLocation, "bundle_engine_unsigned.exe"); | 75 | //string tempFile = Path.Combine(this.TempFilesLocation, "bundle_engine_unsigned.exe"); |
85 | 76 | ||
86 | using (BurnReader reader = BurnReader.Open(bundleFile)) | 77 | //using (BurnReader reader = BurnReader.Open(bundleFile)) |
87 | using (FileStream writer = File.Open(tempFile, FileMode.Create, FileAccess.Write, FileShare.Read | FileShare.Delete)) | 78 | //using (FileStream writer = File.Open(tempFile, FileMode.Create, FileAccess.Write, FileShare.Read | FileShare.Delete)) |
88 | { | 79 | //{ |
89 | reader.Stream.Seek(0, SeekOrigin.Begin); | 80 | // reader.Stream.Seek(0, SeekOrigin.Begin); |
90 | 81 | ||
91 | byte[] buffer = new byte[4 * 1024]; | 82 | // byte[] buffer = new byte[4 * 1024]; |
92 | int total = 0; | 83 | // int total = 0; |
93 | int read = 0; | 84 | // int read = 0; |
94 | do | 85 | // do |
95 | { | 86 | // { |
96 | read = Math.Min(buffer.Length, (int)reader.EngineSize - total); | 87 | // read = Math.Min(buffer.Length, (int)reader.EngineSize - total); |
97 | 88 | ||
98 | read = reader.Stream.Read(buffer, 0, read); | 89 | // read = reader.Stream.Read(buffer, 0, read); |
99 | writer.Write(buffer, 0, read); | 90 | // writer.Write(buffer, 0, read); |
100 | 91 | ||
101 | total += read; | 92 | // total += read; |
102 | } while (total < reader.EngineSize && 0 < read); | 93 | // } while (total < reader.EngineSize && 0 < read); |
103 | 94 | ||
104 | if (total != reader.EngineSize) | 95 | // if (total != reader.EngineSize) |
105 | { | 96 | // { |
106 | throw new InvalidOperationException("Failed to copy engine out of bundle."); | 97 | // throw new InvalidOperationException("Failed to copy engine out of bundle."); |
107 | } | 98 | // } |
108 | 99 | ||
109 | // TODO: update writer with detached container signatures. | 100 | // // TODO: update writer with detached container signatures. |
110 | } | 101 | //} |
111 | 102 | ||
112 | Directory.CreateDirectory(Path.GetDirectoryName(outputFile)); | 103 | //Directory.CreateDirectory(Path.GetDirectoryName(outputFile)); |
113 | if (File.Exists(outputFile)) | 104 | //if (File.Exists(outputFile)) |
114 | { | 105 | //{ |
115 | File.Delete(outputFile); | 106 | // File.Delete(outputFile); |
116 | } | 107 | //} |
117 | File.Move(tempFile, outputFile); | 108 | //File.Move(tempFile, outputFile); |
118 | WixToolset.Core.Native.NativeMethods.ResetAcls(new string[] { outputFile }, 1); | 109 | //WixToolset.Core.Native.NativeMethods.ResetAcls(new string[] { outputFile }, 1); |
119 | 110 | ||
120 | return true; | 111 | return true; |
121 | } | 112 | } |
@@ -129,36 +120,37 @@ namespace WixToolset | |||
129 | /// <returns>True if bundle was updated.</returns> | 120 | /// <returns>True if bundle was updated.</returns> |
130 | public bool InscribeBundle(string bundleFile, string signedEngineFile, string outputFile) | 121 | public bool InscribeBundle(string bundleFile, string signedEngineFile, string outputFile) |
131 | { | 122 | { |
132 | bool inscribed = false; | 123 | //bool inscribed = false; |
133 | string tempFile = Path.Combine(this.TempFilesLocation, "bundle_engine_signed.exe"); | 124 | //string tempFile = Path.Combine(this.TempFilesLocation, "bundle_engine_signed.exe"); |
134 | 125 | ||
135 | using (BurnReader reader = BurnReader.Open(bundleFile)) | 126 | //using (BurnReader reader = BurnReader.Open(bundleFile)) |
136 | { | 127 | //{ |
137 | File.Copy(signedEngineFile, tempFile, true); | 128 | // File.Copy(signedEngineFile, tempFile, true); |
138 | 129 | ||
139 | // If there was an attached container on the original (unsigned) bundle, put it back. | 130 | // // If there was an attached container on the original (unsigned) bundle, put it back. |
140 | if (reader.AttachedContainerSize > 0) | 131 | // if (reader.AttachedContainerSize > 0) |
141 | { | 132 | // { |
142 | reader.Stream.Seek(reader.AttachedContainerAddress, SeekOrigin.Begin); | 133 | // reader.Stream.Seek(reader.AttachedContainerAddress, SeekOrigin.Begin); |
143 | 134 | ||
144 | using (BurnWriter writer = BurnWriter.Open(tempFile)) | 135 | // using (BurnWriter writer = BurnWriter.Open(tempFile)) |
145 | { | 136 | // { |
146 | writer.RememberThenResetSignature(); | 137 | // writer.RememberThenResetSignature(); |
147 | writer.AppendContainer(reader.Stream, reader.AttachedContainerSize, BurnCommon.Container.Attached); | 138 | // writer.AppendContainer(reader.Stream, reader.AttachedContainerSize, BurnCommon.Container.Attached); |
148 | inscribed = true; | 139 | // inscribed = true; |
149 | } | 140 | // } |
150 | } | 141 | // } |
151 | } | 142 | //} |
152 | 143 | ||
153 | Directory.CreateDirectory(Path.GetDirectoryName(outputFile)); | 144 | //Directory.CreateDirectory(Path.GetDirectoryName(outputFile)); |
154 | if (File.Exists(outputFile)) | 145 | //if (File.Exists(outputFile)) |
155 | { | 146 | //{ |
156 | File.Delete(outputFile); | 147 | // File.Delete(outputFile); |
157 | } | 148 | //} |
158 | File.Move(tempFile, outputFile); | 149 | //File.Move(tempFile, outputFile); |
159 | WixToolset.Core.Native.NativeMethods.ResetAcls(new string[] { outputFile }, 1); | 150 | //WixToolset.Core.Native.NativeMethods.ResetAcls(new string[] { outputFile }, 1); |
160 | 151 | ||
161 | return inscribed; | 152 | //return inscribed; |
153 | return false; | ||
162 | } | 154 | } |
163 | 155 | ||
164 | /// <summary> | 156 | /// <summary> |
@@ -170,256 +162,257 @@ namespace WixToolset | |||
170 | /// <returns>True if database is updated.</returns> | 162 | /// <returns>True if database is updated.</returns> |
171 | public bool InscribeDatabase(string databaseFile, string outputFile, bool tidy) | 163 | public bool InscribeDatabase(string databaseFile, string outputFile, bool tidy) |
172 | { | 164 | { |
173 | // Keeps track of whether we've encountered at least one signed cab or not - we'll throw a warning if no signed cabs were encountered | 165 | //// Keeps track of whether we've encountered at least one signed cab or not - we'll throw a warning if no signed cabs were encountered |
174 | bool foundUnsignedExternals = false; | 166 | //bool foundUnsignedExternals = false; |
175 | bool shouldCommit = false; | 167 | //bool shouldCommit = false; |
176 | 168 | ||
177 | FileAttributes attributes = File.GetAttributes(databaseFile); | 169 | //FileAttributes attributes = File.GetAttributes(databaseFile); |
178 | if (FileAttributes.ReadOnly == (attributes & FileAttributes.ReadOnly)) | 170 | //if (FileAttributes.ReadOnly == (attributes & FileAttributes.ReadOnly)) |
179 | { | 171 | //{ |
180 | this.OnMessage(WixErrors.ReadOnlyOutputFile(databaseFile)); | 172 | // this.OnMessage(WixErrors.ReadOnlyOutputFile(databaseFile)); |
181 | return shouldCommit; | 173 | // return shouldCommit; |
182 | } | 174 | //} |
183 | 175 | ||
184 | using (Database database = new Database(databaseFile, OpenDatabase.Transact)) | 176 | //using (Database database = new Database(databaseFile, OpenDatabase.Transact)) |
185 | { | 177 | //{ |
186 | // Just use the English codepage, because the tables we're importing only have binary streams / MSI identifiers / other non-localizable content | 178 | // // Just use the English codepage, because the tables we're importing only have binary streams / MSI identifiers / other non-localizable content |
187 | int codepage = 1252; | 179 | // int codepage = 1252; |
188 | 180 | ||
189 | // list of certificates for this database (hash/identifier) | 181 | // // list of certificates for this database (hash/identifier) |
190 | Dictionary<string, string> certificates = new Dictionary<string, string>(); | 182 | // Dictionary<string, string> certificates = new Dictionary<string, string>(); |
191 | 183 | ||
192 | // Reset the in-memory tables for this new database | 184 | // // Reset the in-memory tables for this new database |
193 | Table digitalSignatureTable = new Table(null, this.tableDefinitions["MsiDigitalSignature"]); | 185 | // Table digitalSignatureTable = new Table(null, this.tableDefinitions["MsiDigitalSignature"]); |
194 | Table digitalCertificateTable = new Table(null, this.tableDefinitions["MsiDigitalCertificate"]); | 186 | // Table digitalCertificateTable = new Table(null, this.tableDefinitions["MsiDigitalCertificate"]); |
195 | 187 | ||
196 | // If any digital signature records exist that are not of the media type, preserve them | 188 | // // If any digital signature records exist that are not of the media type, preserve them |
197 | if (database.TableExists("MsiDigitalSignature")) | 189 | // if (database.TableExists("MsiDigitalSignature")) |
198 | { | 190 | // { |
199 | using (View digitalSignatureView = database.OpenExecuteView("SELECT `Table`, `SignObject`, `DigitalCertificate_`, `Hash` FROM `MsiDigitalSignature` WHERE `Table` <> 'Media'")) | 191 | // using (View digitalSignatureView = database.OpenExecuteView("SELECT `Table`, `SignObject`, `DigitalCertificate_`, `Hash` FROM `MsiDigitalSignature` WHERE `Table` <> 'Media'")) |
200 | { | 192 | // { |
201 | while (true) | 193 | // while (true) |
202 | { | 194 | // { |
203 | using (Record digitalSignatureRecord = digitalSignatureView.Fetch()) | 195 | // using (Record digitalSignatureRecord = digitalSignatureView.Fetch()) |
204 | { | 196 | // { |
205 | if (null == digitalSignatureRecord) | 197 | // if (null == digitalSignatureRecord) |
206 | { | 198 | // { |
207 | break; | 199 | // break; |
208 | } | 200 | // } |
209 | 201 | ||
210 | Row digitalSignatureRow = null; | 202 | // Row digitalSignatureRow = null; |
211 | digitalSignatureRow = digitalSignatureTable.CreateRow(null); | 203 | // digitalSignatureRow = digitalSignatureTable.CreateRow(null); |
212 | 204 | ||
213 | string table = digitalSignatureRecord.GetString(0); | 205 | // string table = digitalSignatureRecord.GetString(0); |
214 | string signObject = digitalSignatureRecord.GetString(1); | 206 | // string signObject = digitalSignatureRecord.GetString(1); |
215 | 207 | ||
216 | digitalSignatureRow[0] = table; | 208 | // digitalSignatureRow[0] = table; |
217 | digitalSignatureRow[1] = signObject; | 209 | // digitalSignatureRow[1] = signObject; |
218 | digitalSignatureRow[2] = digitalSignatureRecord.GetString(2); | 210 | // digitalSignatureRow[2] = digitalSignatureRecord.GetString(2); |
219 | 211 | ||
220 | if (false == digitalSignatureRecord.IsNull(3)) | 212 | // if (false == digitalSignatureRecord.IsNull(3)) |
221 | { | 213 | // { |
222 | // Export to a file, because the MSI API's require us to provide a file path on disk | 214 | // // Export to a file, because the MSI API's require us to provide a file path on disk |
223 | string hashPath = Path.Combine(this.TempFilesLocation, "MsiDigitalSignature"); | 215 | // string hashPath = Path.Combine(this.TempFilesLocation, "MsiDigitalSignature"); |
224 | string hashFileName = string.Concat(table, ".", signObject, ".bin"); | 216 | // string hashFileName = string.Concat(table, ".", signObject, ".bin"); |
225 | 217 | ||
226 | Directory.CreateDirectory(hashPath); | 218 | // Directory.CreateDirectory(hashPath); |
227 | hashPath = Path.Combine(hashPath, hashFileName); | 219 | // hashPath = Path.Combine(hashPath, hashFileName); |
228 | 220 | ||
229 | using (FileStream fs = File.Create(hashPath)) | 221 | // using (FileStream fs = File.Create(hashPath)) |
230 | { | 222 | // { |
231 | int bytesRead; | 223 | // int bytesRead; |
232 | byte[] buffer = new byte[1024 * 4]; | 224 | // byte[] buffer = new byte[1024 * 4]; |
233 | 225 | ||
234 | while (0 != (bytesRead = digitalSignatureRecord.GetStream(3, buffer, buffer.Length))) | 226 | // while (0 != (bytesRead = digitalSignatureRecord.GetStream(3, buffer, buffer.Length))) |
235 | { | 227 | // { |
236 | fs.Write(buffer, 0, bytesRead); | 228 | // fs.Write(buffer, 0, bytesRead); |
237 | } | 229 | // } |
238 | } | 230 | // } |
239 | 231 | ||
240 | digitalSignatureRow[3] = hashFileName; | 232 | // digitalSignatureRow[3] = hashFileName; |
241 | } | 233 | // } |
242 | } | 234 | // } |
243 | } | 235 | // } |
244 | } | 236 | // } |
245 | } | 237 | // } |
246 | 238 | ||
247 | // If any digital certificates exist, extract and preserve them | 239 | // // If any digital certificates exist, extract and preserve them |
248 | if (database.TableExists("MsiDigitalCertificate")) | 240 | // if (database.TableExists("MsiDigitalCertificate")) |
249 | { | 241 | // { |
250 | using (View digitalCertificateView = database.OpenExecuteView("SELECT * FROM `MsiDigitalCertificate`")) | 242 | // using (View digitalCertificateView = database.OpenExecuteView("SELECT * FROM `MsiDigitalCertificate`")) |
251 | { | 243 | // { |
252 | while (true) | 244 | // while (true) |
253 | { | 245 | // { |
254 | using (Record digitalCertificateRecord = digitalCertificateView.Fetch()) | 246 | // using (Record digitalCertificateRecord = digitalCertificateView.Fetch()) |
255 | { | 247 | // { |
256 | if (null == digitalCertificateRecord) | 248 | // if (null == digitalCertificateRecord) |
257 | { | 249 | // { |
258 | break; | 250 | // break; |
259 | } | 251 | // } |
260 | 252 | ||
261 | string certificateId = digitalCertificateRecord.GetString(1); // get the identifier of the certificate | 253 | // string certificateId = digitalCertificateRecord.GetString(1); // get the identifier of the certificate |
262 | 254 | ||
263 | // Export to a file, because the MSI API's require us to provide a file path on disk | 255 | // // Export to a file, because the MSI API's require us to provide a file path on disk |
264 | string certPath = Path.Combine(this.TempFilesLocation, "MsiDigitalCertificate"); | 256 | // string certPath = Path.Combine(this.TempFilesLocation, "MsiDigitalCertificate"); |
265 | Directory.CreateDirectory(certPath); | 257 | // Directory.CreateDirectory(certPath); |
266 | certPath = Path.Combine(certPath, string.Concat(certificateId, ".cer")); | 258 | // certPath = Path.Combine(certPath, string.Concat(certificateId, ".cer")); |
267 | 259 | ||
268 | using (FileStream fs = File.Create(certPath)) | 260 | // using (FileStream fs = File.Create(certPath)) |
269 | { | 261 | // { |
270 | int bytesRead; | 262 | // int bytesRead; |
271 | byte[] buffer = new byte[1024 * 4]; | 263 | // byte[] buffer = new byte[1024 * 4]; |
272 | 264 | ||
273 | while (0 != (bytesRead = digitalCertificateRecord.GetStream(2, buffer, buffer.Length))) | 265 | // while (0 != (bytesRead = digitalCertificateRecord.GetStream(2, buffer, buffer.Length))) |
274 | { | 266 | // { |
275 | fs.Write(buffer, 0, bytesRead); | 267 | // fs.Write(buffer, 0, bytesRead); |
276 | } | 268 | // } |
277 | } | 269 | // } |
278 | 270 | ||
279 | // Add it to our "add to MsiDigitalCertificate" table dictionary | 271 | // // Add it to our "add to MsiDigitalCertificate" table dictionary |
280 | Row digitalCertificateRow = digitalCertificateTable.CreateRow(null); | 272 | // Row digitalCertificateRow = digitalCertificateTable.CreateRow(null); |
281 | digitalCertificateRow[0] = certificateId; | 273 | // digitalCertificateRow[0] = certificateId; |
282 | 274 | ||
283 | // Now set the file path on disk where this binary stream will be picked up at import time | 275 | // // Now set the file path on disk where this binary stream will be picked up at import time |
284 | digitalCertificateRow[1] = string.Concat(certificateId, ".cer"); | 276 | // digitalCertificateRow[1] = string.Concat(certificateId, ".cer"); |
285 | 277 | ||
286 | // Load the cert to get it's thumbprint | 278 | // // Load the cert to get it's thumbprint |
287 | X509Certificate cert = X509Certificate.CreateFromCertFile(certPath); | 279 | // X509Certificate cert = X509Certificate.CreateFromCertFile(certPath); |
288 | X509Certificate2 cert2 = new X509Certificate2(cert); | 280 | // X509Certificate2 cert2 = new X509Certificate2(cert); |
289 | 281 | ||
290 | certificates.Add(cert2.Thumbprint, certificateId); | 282 | // certificates.Add(cert2.Thumbprint, certificateId); |
291 | } | 283 | // } |
292 | } | 284 | // } |
293 | } | 285 | // } |
294 | } | 286 | // } |
295 | 287 | ||
296 | using (View mediaView = database.OpenExecuteView("SELECT * FROM `Media`")) | 288 | // using (View mediaView = database.OpenExecuteView("SELECT * FROM `Media`")) |
297 | { | 289 | // { |
298 | while (true) | 290 | // while (true) |
299 | { | 291 | // { |
300 | using (Record mediaRecord = mediaView.Fetch()) | 292 | // using (Record mediaRecord = mediaView.Fetch()) |
301 | { | 293 | // { |
302 | if (null == mediaRecord) | 294 | // if (null == mediaRecord) |
303 | { | 295 | // { |
304 | break; | 296 | // break; |
305 | } | 297 | // } |
306 | 298 | ||
307 | X509Certificate2 cert2 = null; | 299 | // X509Certificate2 cert2 = null; |
308 | Row digitalSignatureRow = null; | 300 | // Row digitalSignatureRow = null; |
309 | 301 | ||
310 | string cabName = mediaRecord.GetString(4); // get the name of the cab | 302 | // string cabName = mediaRecord.GetString(4); // get the name of the cab |
311 | // If there is no cabinet or it's an internal cab, skip it. | 303 | // // If there is no cabinet or it's an internal cab, skip it. |
312 | if (String.IsNullOrEmpty(cabName) || cabName.StartsWith("#", StringComparison.Ordinal)) | 304 | // if (String.IsNullOrEmpty(cabName) || cabName.StartsWith("#", StringComparison.Ordinal)) |
313 | { | 305 | // { |
314 | continue; | 306 | // continue; |
315 | } | 307 | // } |
316 | 308 | ||
317 | string cabId = mediaRecord.GetString(1); // get the ID of the cab | 309 | // string cabId = mediaRecord.GetString(1); // get the ID of the cab |
318 | string cabPath = Path.Combine(Path.GetDirectoryName(databaseFile), cabName); | 310 | // string cabPath = Path.Combine(Path.GetDirectoryName(databaseFile), cabName); |
319 | 311 | ||
320 | // If the cabs aren't there, throw an error but continue to catch the other errors | 312 | // // If the cabs aren't there, throw an error but continue to catch the other errors |
321 | if (!File.Exists(cabPath)) | 313 | // if (!File.Exists(cabPath)) |
322 | { | 314 | // { |
323 | this.OnMessage(WixErrors.WixFileNotFound(cabPath)); | 315 | // this.OnMessage(WixErrors.WixFileNotFound(cabPath)); |
324 | continue; | 316 | // continue; |
325 | } | 317 | // } |
326 | 318 | ||
327 | try | 319 | // try |
328 | { | 320 | // { |
329 | // Get the certificate from the cab | 321 | // // Get the certificate from the cab |
330 | X509Certificate signedFileCert = X509Certificate.CreateFromSignedFile(cabPath); | 322 | // X509Certificate signedFileCert = X509Certificate.CreateFromSignedFile(cabPath); |
331 | cert2 = new X509Certificate2(signedFileCert); | 323 | // cert2 = new X509Certificate2(signedFileCert); |
332 | } | 324 | // } |
333 | catch (System.Security.Cryptography.CryptographicException e) | 325 | // catch (System.Security.Cryptography.CryptographicException e) |
334 | { | 326 | // { |
335 | uint HResult = unchecked((uint)Marshal.GetHRForException(e)); | 327 | // uint HResult = unchecked((uint)Marshal.GetHRForException(e)); |
336 | 328 | ||
337 | // If the file has no cert, continue, but flag that we found at least one so we can later give a warning | 329 | // // If the file has no cert, continue, but flag that we found at least one so we can later give a warning |
338 | if (0x80092009 == HResult) // CRYPT_E_NO_MATCH | 330 | // if (0x80092009 == HResult) // CRYPT_E_NO_MATCH |
339 | { | 331 | // { |
340 | foundUnsignedExternals = true; | 332 | // foundUnsignedExternals = true; |
341 | continue; | 333 | // continue; |
342 | } | 334 | // } |
343 | 335 | ||
344 | // todo: exactly which HRESULT corresponds to this issue? | 336 | // // todo: exactly which HRESULT corresponds to this issue? |
345 | // If it's one of these exact platforms, warn the user that it may be due to their OS. | 337 | // // If it's one of these exact platforms, warn the user that it may be due to their OS. |
346 | if ((5 == Environment.OSVersion.Version.Major && 2 == Environment.OSVersion.Version.Minor) || // W2K3 | 338 | // if ((5 == Environment.OSVersion.Version.Major && 2 == Environment.OSVersion.Version.Minor) || // W2K3 |
347 | (5 == Environment.OSVersion.Version.Major && 1 == Environment.OSVersion.Version.Minor)) // XP | 339 | // (5 == Environment.OSVersion.Version.Major && 1 == Environment.OSVersion.Version.Minor)) // XP |
348 | { | 340 | // { |
349 | this.OnMessage(WixErrors.UnableToGetAuthenticodeCertOfFileDownlevelOS(cabPath, String.Format(CultureInfo.InvariantCulture, "HRESULT: 0x{0:x8}", HResult))); | 341 | // this.OnMessage(WixErrors.UnableToGetAuthenticodeCertOfFileDownlevelOS(cabPath, String.Format(CultureInfo.InvariantCulture, "HRESULT: 0x{0:x8}", HResult))); |
350 | } | 342 | // } |
351 | else // otherwise, generic error | 343 | // else // otherwise, generic error |
352 | { | 344 | // { |
353 | this.OnMessage(WixErrors.UnableToGetAuthenticodeCertOfFile(cabPath, String.Format(CultureInfo.InvariantCulture, "HRESULT: 0x{0:x8}", HResult))); | 345 | // this.OnMessage(WixErrors.UnableToGetAuthenticodeCertOfFile(cabPath, String.Format(CultureInfo.InvariantCulture, "HRESULT: 0x{0:x8}", HResult))); |
354 | } | 346 | // } |
355 | } | 347 | // } |
356 | 348 | ||
357 | // If we haven't added this cert to the MsiDigitalCertificate table, set it up to be added | 349 | // // If we haven't added this cert to the MsiDigitalCertificate table, set it up to be added |
358 | if (!certificates.ContainsKey(cert2.Thumbprint)) | 350 | // if (!certificates.ContainsKey(cert2.Thumbprint)) |
359 | { | 351 | // { |
360 | // generate a stable identifier | 352 | // // generate a stable identifier |
361 | string certificateGeneratedId = Common.GenerateIdentifier("cer", cert2.Thumbprint); | 353 | // string certificateGeneratedId = Common.GenerateIdentifier("cer", cert2.Thumbprint); |
362 | 354 | ||
363 | // Add it to our "add to MsiDigitalCertificate" table dictionary | 355 | // // Add it to our "add to MsiDigitalCertificate" table dictionary |
364 | Row digitalCertificateRow = digitalCertificateTable.CreateRow(null); | 356 | // Row digitalCertificateRow = digitalCertificateTable.CreateRow(null); |
365 | digitalCertificateRow[0] = certificateGeneratedId; | 357 | // digitalCertificateRow[0] = certificateGeneratedId; |
366 | 358 | ||
367 | // Export to a file, because the MSI API's require us to provide a file path on disk | 359 | // // Export to a file, because the MSI API's require us to provide a file path on disk |
368 | string certPath = Path.Combine(this.TempFilesLocation, "MsiDigitalCertificate"); | 360 | // string certPath = Path.Combine(this.TempFilesLocation, "MsiDigitalCertificate"); |
369 | Directory.CreateDirectory(certPath); | 361 | // Directory.CreateDirectory(certPath); |
370 | certPath = Path.Combine(certPath, string.Concat(cert2.Thumbprint, ".cer")); | 362 | // certPath = Path.Combine(certPath, string.Concat(cert2.Thumbprint, ".cer")); |
371 | File.Delete(certPath); | 363 | // File.Delete(certPath); |
372 | 364 | ||
373 | using (BinaryWriter writer = new BinaryWriter(File.Open(certPath, FileMode.Create))) | 365 | // using (BinaryWriter writer = new BinaryWriter(File.Open(certPath, FileMode.Create))) |
374 | { | 366 | // { |
375 | writer.Write(cert2.RawData); | 367 | // writer.Write(cert2.RawData); |
376 | writer.Close(); | 368 | // writer.Close(); |
377 | } | 369 | // } |
378 | 370 | ||
379 | // Now set the file path on disk where this binary stream will be picked up at import time | 371 | // // Now set the file path on disk where this binary stream will be picked up at import time |
380 | digitalCertificateRow[1] = string.Concat(cert2.Thumbprint, ".cer"); | 372 | // digitalCertificateRow[1] = string.Concat(cert2.Thumbprint, ".cer"); |
381 | 373 | ||
382 | certificates.Add(cert2.Thumbprint, certificateGeneratedId); | 374 | // certificates.Add(cert2.Thumbprint, certificateGeneratedId); |
383 | } | 375 | // } |
384 | 376 | ||
385 | digitalSignatureRow = digitalSignatureTable.CreateRow(null); | 377 | // digitalSignatureRow = digitalSignatureTable.CreateRow(null); |
386 | 378 | ||
387 | digitalSignatureRow[0] = "Media"; | 379 | // digitalSignatureRow[0] = "Media"; |
388 | digitalSignatureRow[1] = cabId; | 380 | // digitalSignatureRow[1] = cabId; |
389 | digitalSignatureRow[2] = certificates[cert2.Thumbprint]; | 381 | // digitalSignatureRow[2] = certificates[cert2.Thumbprint]; |
390 | } | 382 | // } |
391 | } | 383 | // } |
392 | } | 384 | // } |
393 | 385 | ||
394 | if (digitalCertificateTable.Rows.Count > 0) | 386 | // if (digitalCertificateTable.Rows.Count > 0) |
395 | { | 387 | // { |
396 | database.ImportTable(codepage, digitalCertificateTable, this.TempFilesLocation, true); | 388 | // database.ImportTable(codepage, digitalCertificateTable, this.TempFilesLocation, true); |
397 | shouldCommit = true; | 389 | // shouldCommit = true; |
398 | } | 390 | // } |
399 | 391 | ||
400 | if (digitalSignatureTable.Rows.Count > 0) | 392 | // if (digitalSignatureTable.Rows.Count > 0) |
401 | { | 393 | // { |
402 | database.ImportTable(codepage, digitalSignatureTable, this.TempFilesLocation, true); | 394 | // database.ImportTable(codepage, digitalSignatureTable, this.TempFilesLocation, true); |
403 | shouldCommit = true; | 395 | // shouldCommit = true; |
404 | } | 396 | // } |
405 | 397 | ||
406 | // TODO: if we created the table(s), then we should add the _Validation records for them. | 398 | // // TODO: if we created the table(s), then we should add the _Validation records for them. |
407 | 399 | ||
408 | certificates = null; | 400 | // certificates = null; |
409 | 401 | ||
410 | // If we did find external cabs but none of them were signed, give a warning | 402 | // // If we did find external cabs but none of them were signed, give a warning |
411 | if (foundUnsignedExternals) | 403 | // if (foundUnsignedExternals) |
412 | { | 404 | // { |
413 | this.OnMessage(WixWarnings.ExternalCabsAreNotSigned(databaseFile)); | 405 | // this.OnMessage(WixWarnings.ExternalCabsAreNotSigned(databaseFile)); |
414 | } | 406 | // } |
415 | 407 | ||
416 | if (shouldCommit) | 408 | // if (shouldCommit) |
417 | { | 409 | // { |
418 | database.Commit(); | 410 | // database.Commit(); |
419 | } | 411 | // } |
420 | } | 412 | //} |
421 | 413 | ||
422 | return shouldCommit; | 414 | //return shouldCommit; |
415 | return false; | ||
423 | } | 416 | } |
424 | 417 | ||
425 | /// <summary> | 418 | /// <summary> |
diff --git a/src/WixToolset.Core/Librarian.cs b/src/WixToolset.Core/Librarian.cs index 66a8c32d..092d81dc 100644 --- a/src/WixToolset.Core/Librarian.cs +++ b/src/WixToolset.Core/Librarian.cs | |||
@@ -1,10 +1,11 @@ | |||
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 | 3 | namespace WixToolset.Core |
4 | { | 4 | { |
5 | using System; | 5 | using System; |
6 | using System.Collections.Generic; | 6 | using System.Collections.Generic; |
7 | using System.Linq; | 7 | using System.Linq; |
8 | using WixToolset.Core.Bind; | ||
8 | using WixToolset.Data; | 9 | using WixToolset.Data; |
9 | using WixToolset.Link; | 10 | using WixToolset.Link; |
10 | 11 | ||
@@ -13,20 +14,41 @@ namespace WixToolset | |||
13 | /// </summary> | 14 | /// </summary> |
14 | public sealed class Librarian | 15 | public sealed class Librarian |
15 | { | 16 | { |
17 | public Librarian(LibraryContext context) | ||
18 | { | ||
19 | this.Context = context; | ||
20 | } | ||
21 | |||
22 | private LibraryContext Context { get; } | ||
23 | |||
16 | /// <summary> | 24 | /// <summary> |
17 | /// Create a library by combining several intermediates (objects). | 25 | /// Create a library by combining several intermediates (objects). |
18 | /// </summary> | 26 | /// </summary> |
19 | /// <param name="sections">The sections to combine into a library.</param> | 27 | /// <param name="sections">The sections to combine into a library.</param> |
20 | /// <returns>Returns the new library.</returns> | 28 | /// <returns>Returns the new library.</returns> |
21 | public Library Combine(IEnumerable<Section> sections, IEnumerable<Localization> localizations, ILibraryBinaryFileResolver resolver) | 29 | public Library Combine() |
22 | { | 30 | { |
23 | var localizationsByCulture = CollateLocalizations(localizations); | 31 | foreach (var extension in this.Context.Extensions) |
32 | { | ||
33 | extension.PreCombine(this.Context); | ||
34 | } | ||
35 | |||
36 | var fileResolver = new FileResolver(this.Context.BindPaths, this.Context.Extensions); | ||
24 | 37 | ||
25 | var embedFilePaths = ResolveFilePathsToEmbed(sections, resolver); | 38 | var localizationsByCulture = CollateLocalizations(this.Context.Localizations); |
26 | 39 | ||
27 | var library = new Library(sections, localizationsByCulture, embedFilePaths); | 40 | var embedFilePaths = ResolveFilePathsToEmbed(this.Context.Sections, fileResolver); |
28 | 41 | ||
29 | return this.Validate(library); | 42 | var library = new Library(this.Context.Sections, localizationsByCulture, embedFilePaths); |
43 | |||
44 | this.Validate(library); | ||
45 | |||
46 | foreach (var extension in this.Context.Extensions) | ||
47 | { | ||
48 | extension.PostCombine(library); | ||
49 | } | ||
50 | |||
51 | return library; | ||
30 | } | 52 | } |
31 | 53 | ||
32 | /// <summary> | 54 | /// <summary> |
@@ -70,12 +92,12 @@ namespace WixToolset | |||
70 | return localizationsByCulture; | 92 | return localizationsByCulture; |
71 | } | 93 | } |
72 | 94 | ||
73 | private static List<string> ResolveFilePathsToEmbed(IEnumerable<Section> sections, ILibraryBinaryFileResolver resolver) | 95 | private List<string> ResolveFilePathsToEmbed(IEnumerable<Section> sections, FileResolver fileResolver) |
74 | { | 96 | { |
75 | var embedFilePaths = new List<string>(); | 97 | var embedFilePaths = new List<string>(); |
76 | 98 | ||
77 | // Resolve paths to files that are to be embedded in the library. | 99 | // Resolve paths to files that are to be embedded in the library. |
78 | if (null != resolver) | 100 | if (this.Context.BindFiles) |
79 | { | 101 | { |
80 | foreach (Table table in sections.SelectMany(s => s.Tables)) | 102 | foreach (Table table in sections.SelectMany(s => s.Tables)) |
81 | { | 103 | { |
@@ -85,7 +107,10 @@ namespace WixToolset | |||
85 | { | 107 | { |
86 | if (null != objectField.Data) | 108 | if (null != objectField.Data) |
87 | { | 109 | { |
88 | string file = resolver.Resolve(row.SourceLineNumbers, table.Name, (string)objectField.Data); | 110 | string resolvedPath = this.Context.WixVariableResolver.ResolveVariables(row.SourceLineNumbers, (string)objectField.Data, false); |
111 | |||
112 | string file = fileResolver.Resolve(row.SourceLineNumbers, table.Name, resolvedPath); | ||
113 | |||
89 | if (!String.IsNullOrEmpty(file)) | 114 | if (!String.IsNullOrEmpty(file)) |
90 | { | 115 | { |
91 | // File was successfully resolved so track the embedded index as the embedded file index. | 116 | // File was successfully resolved so track the embedded index as the embedded file index. |
diff --git a/src/WixToolset.Core/LibraryContext.cs b/src/WixToolset.Core/LibraryContext.cs new file mode 100644 index 00000000..36e38739 --- /dev/null +++ b/src/WixToolset.Core/LibraryContext.cs | |||
@@ -0,0 +1,23 @@ | |||
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 System.Collections.Generic; | ||
6 | using WixToolset.Data; | ||
7 | using WixToolset.Extensibility; | ||
8 | |||
9 | public class LibraryContext : ILibraryContext | ||
10 | { | ||
11 | public bool BindFiles { get; set; } | ||
12 | |||
13 | public IEnumerable<BindPath> BindPaths { get; set; } | ||
14 | |||
15 | public IEnumerable<ILibrarianExtension> Extensions { get; set; } | ||
16 | |||
17 | public IEnumerable<Localization> Localizations { get; set; } | ||
18 | |||
19 | public IEnumerable<Section> Sections { get; set; } | ||
20 | |||
21 | public IBindVariableResolver WixVariableResolver { get; set; } | ||
22 | } | ||
23 | } | ||
diff --git a/src/WixToolset.Core/Linker.cs b/src/WixToolset.Core/Linker.cs index 1e5b6e96..c1c9f848 100644 --- a/src/WixToolset.Core/Linker.cs +++ b/src/WixToolset.Core/Linker.cs | |||
@@ -78,7 +78,7 @@ namespace WixToolset | |||
78 | /// Gets or sets the Wix variable resolver. | 78 | /// Gets or sets the Wix variable resolver. |
79 | /// </summary> | 79 | /// </summary> |
80 | /// <value>The Wix variable resolver.</value> | 80 | /// <value>The Wix variable resolver.</value> |
81 | public WixVariableResolver WixVariableResolver { get; set; } | 81 | internal IBindVariableResolver WixVariableResolver { get; set; } |
82 | 82 | ||
83 | /// <summary> | 83 | /// <summary> |
84 | /// Adds an extension. | 84 | /// Adds an extension. |
diff --git a/src/WixToolset.Core/Localizer.cs b/src/WixToolset.Core/Localizer.cs index 63ead24a..72d0955b 100644 --- a/src/WixToolset.Core/Localizer.cs +++ b/src/WixToolset.Core/Localizer.cs | |||
@@ -8,11 +8,12 @@ namespace WixToolset | |||
8 | using WixToolset.Data; | 8 | using WixToolset.Data; |
9 | using WixToolset.Data.Rows; | 9 | using WixToolset.Data.Rows; |
10 | using WixToolset.Core.Native; | 10 | using WixToolset.Core.Native; |
11 | using WixToolset.Extensibility; | ||
11 | 12 | ||
12 | /// <summary> | 13 | /// <summary> |
13 | /// Parses localization files and localizes database values. | 14 | /// Parses localization files and localizes database values. |
14 | /// </summary> | 15 | /// </summary> |
15 | public sealed class Localizer | 16 | public sealed class Localizer : ILocalizer |
16 | { | 17 | { |
17 | public static readonly XNamespace WxlNamespace = "http://wixtoolset.org/schemas/v4/wxl"; | 18 | public static readonly XNamespace WxlNamespace = "http://wixtoolset.org/schemas/v4/wxl"; |
18 | private static string XmlElementName = "WixLocalization"; | 19 | private static string XmlElementName = "WixLocalization"; |
@@ -55,7 +56,28 @@ namespace WixToolset | |||
55 | /// Gets the codepage. | 56 | /// Gets the codepage. |
56 | /// </summary> | 57 | /// </summary> |
57 | /// <value>The codepage.</value> | 58 | /// <value>The codepage.</value> |
58 | public int Codepage { get; private set; } | 59 | public int Codepage { get; } |
60 | |||
61 | /// <summary> | ||
62 | /// Get a localized data value. | ||
63 | /// </summary> | ||
64 | /// <param name="id">The name of the localization variable.</param> | ||
65 | /// <returns>The localized data value or null if it wasn't found.</returns> | ||
66 | public string GetLocalizedValue(string id) | ||
67 | { | ||
68 | return this.variables.TryGetValue(id, out var wixVariableRow) ? wixVariableRow.Value : null; | ||
69 | } | ||
70 | |||
71 | /// <summary> | ||
72 | /// Get a localized control. | ||
73 | /// </summary> | ||
74 | /// <param name="dialog">The optional id of the control's dialog.</param> | ||
75 | /// <param name="control">The id of the control.</param> | ||
76 | /// <returns>The localized control or null if it wasn't found.</returns> | ||
77 | public LocalizedControl GetLocalizedControl(string dialog, string control) | ||
78 | { | ||
79 | return this.localizedControls.TryGetValue(LocalizedControl.GetKey(dialog, control), out var localizedControl) ? localizedControl : null; | ||
80 | } | ||
59 | 81 | ||
60 | /// <summary> | 82 | /// <summary> |
61 | /// Loads a localization file from a path on disk. | 83 | /// Loads a localization file from a path on disk. |
@@ -97,36 +119,13 @@ namespace WixToolset | |||
97 | } | 119 | } |
98 | 120 | ||
99 | /// <summary> | 121 | /// <summary> |
100 | /// Get a localized data value. | ||
101 | /// </summary> | ||
102 | /// <param name="id">The name of the localization variable.</param> | ||
103 | /// <returns>The localized data value or null if it wasn't found.</returns> | ||
104 | public string GetLocalizedValue(string id) | ||
105 | { | ||
106 | return this.variables.TryGetValue(id, out var wixVariableRow) ? wixVariableRow.Value : null; | ||
107 | } | ||
108 | |||
109 | /// <summary> | ||
110 | /// Get a localized control. | ||
111 | /// </summary> | ||
112 | /// <param name="dialog">The optional id of the control's dialog.</param> | ||
113 | /// <param name="control">The id of the control.</param> | ||
114 | /// <returns>The localized control or null if it wasn't found.</returns> | ||
115 | public LocalizedControl GetLocalizedControl(string dialog, string control) | ||
116 | { | ||
117 | LocalizedControl localizedControl; | ||
118 | return this.localizedControls.TryGetValue(LocalizedControl.GetKey(dialog, control), out localizedControl) ? localizedControl : null; | ||
119 | } | ||
120 | |||
121 | /// <summary> | ||
122 | /// Adds a WixVariableRow to a dictionary while performing the expected override checks. | 122 | /// Adds a WixVariableRow to a dictionary while performing the expected override checks. |
123 | /// </summary> | 123 | /// </summary> |
124 | /// <param name="variables">Dictionary of variable rows.</param> | 124 | /// <param name="variables">Dictionary of variable rows.</param> |
125 | /// <param name="wixVariableRow">Row to add to the variables dictionary.</param> | 125 | /// <param name="wixVariableRow">Row to add to the variables dictionary.</param> |
126 | private static void AddWixVariable(IDictionary<string, WixVariableRow> variables, WixVariableRow wixVariableRow) | 126 | private static void AddWixVariable(IDictionary<string, WixVariableRow> variables, WixVariableRow wixVariableRow) |
127 | { | 127 | { |
128 | WixVariableRow existingWixVariableRow; | 128 | if (!variables.TryGetValue(wixVariableRow.Id, out var existingWixVariableRow) || (existingWixVariableRow.Overridable && !wixVariableRow.Overridable)) |
129 | if (!variables.TryGetValue(wixVariableRow.Id, out existingWixVariableRow) || (existingWixVariableRow.Overridable && !wixVariableRow.Overridable)) | ||
130 | { | 129 | { |
131 | variables[wixVariableRow.Id] = wixVariableRow; | 130 | variables[wixVariableRow.Id] = wixVariableRow; |
132 | } | 131 | } |
diff --git a/src/WixToolset.Core/OptimizeCA.cs b/src/WixToolset.Core/OptimizeCA.cs new file mode 100644 index 00000000..efd07299 --- /dev/null +++ b/src/WixToolset.Core/OptimizeCA.cs | |||
@@ -0,0 +1,33 @@ | |||
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 System; | ||
6 | |||
7 | /// <summary> | ||
8 | /// Values for the OptimizeCA MsiPatchMetdata property, which indicates whether custom actions can be skipped when applying the patch. | ||
9 | /// </summary> | ||
10 | [Flags] | ||
11 | public enum OptimizeCA | ||
12 | { | ||
13 | /// <summary> | ||
14 | /// No custom actions are skipped. | ||
15 | /// </summary> | ||
16 | None = 0, | ||
17 | |||
18 | /// <summary> | ||
19 | /// Skip property (type 51) and directory (type 35) assignment custom actions. | ||
20 | /// </summary> | ||
21 | SkipAssignment = 1, | ||
22 | |||
23 | /// <summary> | ||
24 | /// Skip immediate custom actions that are not property or directory assignment custom actions. | ||
25 | /// </summary> | ||
26 | SkipImmediate = 2, | ||
27 | |||
28 | /// <summary> | ||
29 | /// Skip custom actions that run within the script. | ||
30 | /// </summary> | ||
31 | SkipDeferred = 4, | ||
32 | } | ||
33 | } | ||
diff --git a/src/WixToolset.Core/PatchSymbolFlagsType.cs b/src/WixToolset.Core/PatchSymbolFlagsType.cs new file mode 100644 index 00000000..eeb5c798 --- /dev/null +++ b/src/WixToolset.Core/PatchSymbolFlagsType.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 System; | ||
6 | |||
7 | // | ||
8 | // The following flags are used with PATCH_OPTION_DATA SymbolOptionFlags: | ||
9 | // | ||
10 | [Flags] | ||
11 | public enum PatchSymbolFlagsType : uint | ||
12 | { | ||
13 | PATCH_SYMBOL_NO_IMAGEHLP = 0x00000001, // don't use imagehlp.dll | ||
14 | PATCH_SYMBOL_NO_FAILURES = 0x00000002, // don't fail patch due to imagehlp failures | ||
15 | PATCH_SYMBOL_UNDECORATED_TOO = 0x00000004, // after matching decorated symbols, try to match remaining by undecorated names | ||
16 | PATCH_SYMBOL_RESERVED1 = 0x80000000, // (used internally) | ||
17 | MaxValue = PATCH_SYMBOL_NO_IMAGEHLP | PATCH_SYMBOL_NO_FAILURES | PATCH_SYMBOL_UNDECORATED_TOO | ||
18 | } | ||
19 | } | ||
diff --git a/src/WixToolset.Core/PatchTransform.cs b/src/WixToolset.Core/PatchTransform.cs index c87b1a21..46e4e6d7 100644 --- a/src/WixToolset.Core/PatchTransform.cs +++ b/src/WixToolset.Core/PatchTransform.cs | |||
@@ -155,7 +155,7 @@ namespace WixToolset | |||
155 | if (!deletedComponent.ContainsKey(componentId)) | 155 | if (!deletedComponent.ContainsKey(componentId)) |
156 | { | 156 | { |
157 | bool foundRemoveFileEntry = false; | 157 | bool foundRemoveFileEntry = false; |
158 | string filename = Msi.Installer.GetName((string)row[2], false, true); | 158 | string filename = Common.GetName((string)row[2], false, true); |
159 | 159 | ||
160 | Table removeFileTable = this.Transform.Tables["RemoveFile"]; | 160 | Table removeFileTable = this.Transform.Tables["RemoveFile"]; |
161 | if (null != removeFileTable) | 161 | if (null != removeFileTable) |
@@ -172,7 +172,7 @@ namespace WixToolset | |||
172 | // Check if there is a RemoveFile entry for this file | 172 | // Check if there is a RemoveFile entry for this file |
173 | if (null != removeFileRow[2]) | 173 | if (null != removeFileRow[2]) |
174 | { | 174 | { |
175 | string removeFileName = Msi.Installer.GetName((string)removeFileRow[2], false, true); | 175 | string removeFileName = Common.GetName((string)removeFileRow[2], false, true); |
176 | 176 | ||
177 | // Convert the MSI format for a wildcard string to Regex format. | 177 | // Convert the MSI format for a wildcard string to Regex format. |
178 | removeFileName = removeFileName.Replace('.', '|').Replace('?', '.').Replace("*", ".*").Replace("|", "\\."); | 178 | removeFileName = removeFileName.Replace('.', '|').Replace('?', '.').Replace("*", ".*").Replace("|", "\\."); |
diff --git a/src/WixToolset.Core/Properties/AssemblyInfo.cs b/src/WixToolset.Core/Properties/AssemblyInfo.cs index b3740b2a..81274e3f 100644 --- a/src/WixToolset.Core/Properties/AssemblyInfo.cs +++ b/src/WixToolset.Core/Properties/AssemblyInfo.cs | |||
@@ -5,5 +5,5 @@ using System.Reflection; | |||
5 | using System.Runtime.InteropServices; | 5 | using System.Runtime.InteropServices; |
6 | 6 | ||
7 | [assembly: AssemblyCulture("")] | 7 | [assembly: AssemblyCulture("")] |
8 | [assembly: CLSCompliant(true)] | 8 | [assembly: CLSCompliant(false)] |
9 | [assembly: ComVisible(false)] | 9 | [assembly: ComVisible(false)] |
diff --git a/src/WixToolset.Core/TransformsFlags.cs b/src/WixToolset.Core/TransformsFlags.cs new file mode 100644 index 00000000..d9ec94ac --- /dev/null +++ b/src/WixToolset.Core/TransformsFlags.cs | |||
@@ -0,0 +1,81 @@ | |||
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 System; | ||
6 | using System.Diagnostics.CodeAnalysis; | ||
7 | |||
8 | /// <summary> | ||
9 | /// Summary information values for the CharCount property in transforms. | ||
10 | /// </summary> | ||
11 | [Flags] | ||
12 | [SuppressMessage("Microsoft.Naming", "CA1711:IdentifiersShouldNotHaveIncorrectSuffix")] | ||
13 | public enum TransformFlags | ||
14 | { | ||
15 | /// <summary>Ignore error when adding a row that exists.</summary> | ||
16 | ErrorAddExistingRow = 0x1, | ||
17 | |||
18 | /// <summary>Ignore error when deleting a row that does not exist.</summary> | ||
19 | ErrorDeleteMissingRow = 0x2, | ||
20 | |||
21 | /// <summary>Ignore error when adding a table that exists. </summary> | ||
22 | ErrorAddExistingTable = 0x4, | ||
23 | |||
24 | /// <summary>Ignore error when deleting a table that does not exist. </summary> | ||
25 | ErrorDeleteMissingTable = 0x8, | ||
26 | |||
27 | /// <summary>Ignore error when updating a row that does not exist. </summary> | ||
28 | ErrorUpdateMissingRow = 0x10, | ||
29 | |||
30 | /// <summary>Ignore error when transform and database code pages do not match, and their code pages are neutral.</summary> | ||
31 | ErrorChangeCodePage = 0x20, | ||
32 | |||
33 | /// <summary>Default language must match base database. </summary> | ||
34 | ValidateLanguage = 0x10000, | ||
35 | |||
36 | /// <summary>Product must match base database.</summary> | ||
37 | ValidateProduct = 0x20000, | ||
38 | |||
39 | /// <summary>Check major version only. </summary> | ||
40 | ValidateMajorVersion = 0x80000, | ||
41 | |||
42 | /// <summary>Check major and minor versions only. </summary> | ||
43 | ValidateMinorVersion = 0x100000, | ||
44 | |||
45 | /// <summary>Check major, minor, and update versions.</summary> | ||
46 | ValidateUpdateVersion = 0x200000, | ||
47 | |||
48 | /// <summary>Installed version lt base version. </summary> | ||
49 | ValidateNewLessBaseVersion = 0x400000, | ||
50 | |||
51 | /// <summary>Installed version lte base version. </summary> | ||
52 | ValidateNewLessEqualBaseVersion = 0x800000, | ||
53 | |||
54 | /// <summary>Installed version eq base version. </summary> | ||
55 | ValidateNewEqualBaseVersion = 0x1000000, | ||
56 | |||
57 | /// <summary>Installed version gte base version.</summary> | ||
58 | ValidateNewGreaterEqualBaseVersion = 0x2000000, | ||
59 | |||
60 | /// <summary>Installed version gt base version.</summary> | ||
61 | ValidateNewGreaterBaseVersion = 0x4000000, | ||
62 | |||
63 | /// <summary>UpgradeCode must match base database.</summary> | ||
64 | ValidateUpgradeCode = 0x8000000, | ||
65 | |||
66 | /// <summary>Masks all version checks on ProductVersion.</summary> | ||
67 | ProductVersionMask = ValidateMajorVersion | ValidateMinorVersion | ValidateUpdateVersion, | ||
68 | |||
69 | /// <summary>Masks all operations on ProductVersion.</summary> | ||
70 | ProductVersionOperatorMask = ValidateNewLessBaseVersion | ValidateNewLessEqualBaseVersion | ValidateNewEqualBaseVersion | ValidateNewGreaterEqualBaseVersion | ValidateNewGreaterBaseVersion, | ||
71 | |||
72 | /// <summary>Default value for instance transforms.</summary> | ||
73 | InstanceTransformDefault = ErrorAddExistingRow | ErrorDeleteMissingRow | ErrorAddExistingTable | ErrorDeleteMissingTable | ErrorUpdateMissingRow | ErrorChangeCodePage | ValidateProduct | ValidateUpdateVersion | ValidateNewGreaterEqualBaseVersion, | ||
74 | |||
75 | /// <summary>Default value for language transforms.</summary> | ||
76 | LanguageTransformDefault = ErrorAddExistingRow | ErrorDeleteMissingRow | ErrorAddExistingTable | ErrorDeleteMissingTable | ErrorUpdateMissingRow | ErrorChangeCodePage | ValidateProduct, | ||
77 | |||
78 | /// <summary>Default value for patch transforms.</summary> | ||
79 | PatchTransformDefault = ErrorAddExistingRow | ErrorDeleteMissingRow | ErrorAddExistingTable | ErrorDeleteMissingTable | ErrorUpdateMissingRow | ValidateProduct | ValidateUpdateVersion | ValidateNewEqualBaseVersion | ValidateUpgradeCode, | ||
80 | } | ||
81 | } | ||
diff --git a/src/WixToolset.Core/UnbindContext.cs b/src/WixToolset.Core/UnbindContext.cs new file mode 100644 index 00000000..ed55f312 --- /dev/null +++ b/src/WixToolset.Core/UnbindContext.cs | |||
@@ -0,0 +1,24 @@ | |||
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.Data; | ||
6 | using WixToolset.Extensibility; | ||
7 | |||
8 | internal class UnbindContext : IUnbindContext | ||
9 | { | ||
10 | public Messaging Messaging { get; } = Messaging.Instance; | ||
11 | |||
12 | public string ExportBasePath { get; set; } | ||
13 | |||
14 | public string InputFilePath { get; set; } | ||
15 | |||
16 | public string IntermediateFolder { get; set; } | ||
17 | |||
18 | public bool IsAdminImage { get; set; } | ||
19 | |||
20 | public bool SuppressExtractCabinets { get; set; } | ||
21 | |||
22 | public bool SuppressDemodularization { get; set; } | ||
23 | } | ||
24 | } | ||
diff --git a/src/WixToolset.Core/Unbinder.cs b/src/WixToolset.Core/Unbinder.cs index 744d5536..2ff51997 100644 --- a/src/WixToolset.Core/Unbinder.cs +++ b/src/WixToolset.Core/Unbinder.cs | |||
@@ -1,37 +1,18 @@ | |||
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 | 3 | namespace WixToolset.Core |
4 | { | 4 | { |
5 | using System; | ||
6 | using System.CodeDom.Compiler; | ||
7 | using System.Collections; | 5 | using System.Collections; |
8 | using System.Collections.Generic; | ||
9 | using System.Collections.Specialized; | ||
10 | using System.ComponentModel; | ||
11 | using System.Globalization; | ||
12 | using System.IO; | 6 | using System.IO; |
13 | using System.Linq; | ||
14 | using System.Text.RegularExpressions; | ||
15 | using WixToolset.Bind; | ||
16 | using WixToolset.Bind.Bundles; | ||
17 | using WixToolset.Cab; | ||
18 | using WixToolset.Data; | 7 | using WixToolset.Data; |
19 | using WixToolset.Data.Rows; | ||
20 | using WixToolset.Extensibility; | 8 | using WixToolset.Extensibility; |
21 | using WixToolset.Msi; | 9 | using System.Collections.Generic; |
22 | using WixToolset.Core.Native; | ||
23 | using WixToolset.Ole32; | ||
24 | 10 | ||
25 | /// <summary> | 11 | /// <summary> |
26 | /// Unbinder core of the WiX toolset. | 12 | /// Unbinder core of the WiX toolset. |
27 | /// </summary> | 13 | /// </summary> |
28 | public sealed class Unbinder : IMessageHandler | 14 | public sealed class Unbinder |
29 | { | 15 | { |
30 | private string emptyFile; | ||
31 | private bool isAdminImage; | ||
32 | private int sectionCount; | ||
33 | private bool suppressDemodularization; | ||
34 | private bool suppressExtractCabinets; | ||
35 | private TableDefinitionCollection tableDefinitions; | 16 | private TableDefinitionCollection tableDefinitions; |
36 | private ArrayList unbinderExtensions; | 17 | private ArrayList unbinderExtensions; |
37 | // private TempFileCollection tempFiles; | 18 | // private TempFileCollection tempFiles; |
@@ -45,61 +26,32 @@ namespace WixToolset | |||
45 | this.unbinderExtensions = new ArrayList(); | 26 | this.unbinderExtensions = new ArrayList(); |
46 | } | 27 | } |
47 | 28 | ||
29 | public IEnumerable<IBackendFactory> BackendFactories { get; } | ||
30 | |||
48 | /// <summary> | 31 | /// <summary> |
49 | /// Gets or sets whether the input msi is an admin image. | 32 | /// Gets or sets whether the input msi is an admin image. |
50 | /// </summary> | 33 | /// </summary> |
51 | /// <value>Set to true if the input msi is part of an admin image.</value> | 34 | /// <value>Set to true if the input msi is part of an admin image.</value> |
52 | public bool IsAdminImage | 35 | public bool IsAdminImage { get; set; } |
53 | { | ||
54 | get { return this.isAdminImage; } | ||
55 | set { this.isAdminImage = value; } | ||
56 | } | ||
57 | 36 | ||
58 | /// <summary> | 37 | /// <summary> |
59 | /// Gets or sets the option to suppress demodularizing values. | 38 | /// Gets or sets the option to suppress demodularizing values. |
60 | /// </summary> | 39 | /// </summary> |
61 | /// <value>The option to suppress demodularizing values.</value> | 40 | /// <value>The option to suppress demodularizing values.</value> |
62 | public bool SuppressDemodularization | 41 | public bool SuppressDemodularization { get; set; } |
63 | { | ||
64 | get { return this.suppressDemodularization; } | ||
65 | set { this.suppressDemodularization = value; } | ||
66 | } | ||
67 | 42 | ||
68 | /// <summary> | 43 | /// <summary> |
69 | /// Gets or sets the option to suppress extracting cabinets. | 44 | /// Gets or sets the option to suppress extracting cabinets. |
70 | /// </summary> | 45 | /// </summary> |
71 | /// <value>The option to suppress extracting cabinets.</value> | 46 | /// <value>The option to suppress extracting cabinets.</value> |
72 | public bool SuppressExtractCabinets | 47 | public bool SuppressExtractCabinets { get; set; } |
73 | { | ||
74 | get { return this.suppressExtractCabinets; } | ||
75 | set { this.suppressExtractCabinets = value; } | ||
76 | } | ||
77 | 48 | ||
78 | /// <summary> | 49 | /// <summary> |
79 | /// Gets or sets the temporary path for the Binder. If left null, the binder | 50 | /// Gets or sets the temporary path for the Binder. If left null, the binder |
80 | /// will use %TEMP% environment variable. | 51 | /// will use %TEMP% environment variable. |
81 | /// </summary> | 52 | /// </summary> |
82 | /// <value>Path to temp files.</value> | 53 | /// <value>Path to temp files.</value> |
83 | public string TempFilesLocation | 54 | public string TempFilesLocation => Path.GetTempPath(); |
84 | { | ||
85 | get | ||
86 | { | ||
87 | // return null == this.tempFiles ? String.Empty : this.tempFiles.BasePath; | ||
88 | return Path.GetTempPath(); | ||
89 | } | ||
90 | |||
91 | // set | ||
92 | // { | ||
93 | // if (null == value) | ||
94 | // { | ||
95 | // this.tempFiles = new TempFileCollection(); | ||
96 | // } | ||
97 | // else | ||
98 | // { | ||
99 | // this.tempFiles = new TempFileCollection(value); | ||
100 | // } | ||
101 | // } | ||
102 | } | ||
103 | 55 | ||
104 | /// <summary> | 56 | /// <summary> |
105 | /// Adds extension data. | 57 | /// Adds extension data. |
@@ -156,1336 +108,25 @@ namespace WixToolset | |||
156 | // if we don't have the temporary files object yet, get one | 108 | // if we don't have the temporary files object yet, get one |
157 | Directory.CreateDirectory(this.TempFilesLocation); // ensure the base path is there | 109 | Directory.CreateDirectory(this.TempFilesLocation); // ensure the base path is there |
158 | 110 | ||
159 | if (OutputType.Patch == outputType) | 111 | var context = new UnbindContext(); |
160 | { | 112 | context.InputFilePath = file; |
161 | return this.UnbindPatch(file, exportBasePath); | 113 | context.ExportBasePath = exportBasePath; |
162 | } | 114 | context.IntermediateFolder = this.TempFilesLocation; |
163 | else if (OutputType.Transform == outputType) | 115 | context.IsAdminImage = this.IsAdminImage; |
164 | { | 116 | context.SuppressDemodularization = this.SuppressDemodularization; |
165 | return this.UnbindTransform(file, exportBasePath); | 117 | context.SuppressExtractCabinets = this.SuppressExtractCabinets; |
166 | } | ||
167 | else if (OutputType.Bundle == outputType) | ||
168 | { | ||
169 | return this.UnbindBundle(file, exportBasePath); | ||
170 | } | ||
171 | else // other database types | ||
172 | { | ||
173 | return this.UnbindDatabase(file, outputType, exportBasePath); | ||
174 | } | ||
175 | } | ||
176 | |||
177 | /// <summary> | ||
178 | /// Cleans up the temp files used by the Decompiler. | ||
179 | /// </summary> | ||
180 | /// <returns>True if all files were deleted, false otherwise.</returns> | ||
181 | /// <remarks> | ||
182 | /// This should be called after every call to Decompile to ensure there | ||
183 | /// are no conflicts between each decompiled database. | ||
184 | /// </remarks> | ||
185 | public bool DeleteTempFiles() | ||
186 | { | ||
187 | #if REDO_IN_NETCORE | ||
188 | bool deleted = Common.DeleteTempFiles(this.tempFiles.BasePath, this); | ||
189 | |||
190 | if (deleted) | ||
191 | { | ||
192 | this.tempFiles = null; // temp files have been deleted, no need to remember this now | ||
193 | } | ||
194 | |||
195 | return deleted; | ||
196 | #endif | ||
197 | return true; | ||
198 | } | ||
199 | |||
200 | /// <summary> | ||
201 | /// Sends a message to the message delegate if there is one. | ||
202 | /// </summary> | ||
203 | /// <param name="mea">Message event arguments.</param> | ||
204 | public void OnMessage(MessageEventArgs e) | ||
205 | { | ||
206 | Messaging.Instance.OnMessage(e); | ||
207 | } | ||
208 | |||
209 | /// <summary> | ||
210 | /// Unbind an MSI database file. | ||
211 | /// </summary> | ||
212 | /// <param name="databaseFile">The database file.</param> | ||
213 | /// <param name="outputType">The output type.</param> | ||
214 | /// <param name="exportBasePath">The path where files should be exported.</param> | ||
215 | /// <returns>The unbound database.</returns> | ||
216 | private Output UnbindDatabase(string databaseFile, OutputType outputType, string exportBasePath) | ||
217 | { | ||
218 | Output output; | ||
219 | |||
220 | try | ||
221 | { | ||
222 | using (Database database = new Database(databaseFile, OpenDatabase.ReadOnly)) | ||
223 | { | ||
224 | output = this.UnbindDatabase(databaseFile, database, outputType, exportBasePath, false); | ||
225 | |||
226 | // extract the files from the cabinets | ||
227 | if (null != exportBasePath && !this.suppressExtractCabinets) | ||
228 | { | ||
229 | this.ExtractCabinets(output, database, databaseFile, exportBasePath); | ||
230 | } | ||
231 | } | ||
232 | } | ||
233 | catch (Win32Exception e) | ||
234 | { | ||
235 | if (0x6E == e.NativeErrorCode) // ERROR_OPEN_FAILED | ||
236 | { | ||
237 | throw new WixException(WixErrors.OpenDatabaseFailed(databaseFile)); | ||
238 | } | ||
239 | |||
240 | throw; | ||
241 | } | ||
242 | |||
243 | return output; | ||
244 | } | ||
245 | |||
246 | /// <summary> | ||
247 | /// Unbind an MSI database file. | ||
248 | /// </summary> | ||
249 | /// <param name="databaseFile">The database file.</param> | ||
250 | /// <param name="database">The opened database.</param> | ||
251 | /// <param name="outputType">The type of output to create.</param> | ||
252 | /// <param name="exportBasePath">The path where files should be exported.</param> | ||
253 | /// <param name="skipSummaryInfo">Option to skip unbinding the _SummaryInformation table.</param> | ||
254 | /// <returns>The output representing the database.</returns> | ||
255 | private Output UnbindDatabase(string databaseFile, Database database, OutputType outputType, string exportBasePath, bool skipSummaryInfo) | ||
256 | { | ||
257 | string modularizationGuid = null; | ||
258 | Output output = new Output(new SourceLineNumber(databaseFile)); | ||
259 | View validationView = null; | ||
260 | |||
261 | // set the output type | ||
262 | output.Type = outputType; | ||
263 | |||
264 | // get the codepage | ||
265 | database.Export("_ForceCodepage", this.TempFilesLocation, "_ForceCodepage.idt"); | ||
266 | using (StreamReader sr = File.OpenText(Path.Combine(this.TempFilesLocation, "_ForceCodepage.idt"))) | ||
267 | { | ||
268 | string line; | ||
269 | |||
270 | while (null != (line = sr.ReadLine())) | ||
271 | { | ||
272 | string[] data = line.Split('\t'); | ||
273 | |||
274 | if (2 == data.Length) | ||
275 | { | ||
276 | output.Codepage = Convert.ToInt32(data[0], CultureInfo.InvariantCulture); | ||
277 | } | ||
278 | } | ||
279 | } | ||
280 | |||
281 | // get the summary information table if it exists; it won't if unbinding a transform | ||
282 | if (!skipSummaryInfo) | ||
283 | { | ||
284 | using (SummaryInformation summaryInformation = new SummaryInformation(database)) | ||
285 | { | ||
286 | Table table = new Table(null, this.tableDefinitions["_SummaryInformation"]); | ||
287 | |||
288 | for (int i = 1; 19 >= i; i++) | ||
289 | { | ||
290 | string value = summaryInformation.GetProperty(i); | ||
291 | |||
292 | if (0 < value.Length) | ||
293 | { | ||
294 | Row row = table.CreateRow(output.SourceLineNumbers); | ||
295 | row[0] = i; | ||
296 | row[1] = value; | ||
297 | } | ||
298 | } | ||
299 | |||
300 | output.Tables.Add(table); | ||
301 | } | ||
302 | } | ||
303 | |||
304 | try | ||
305 | { | ||
306 | // open a view on the validation table if it exists | ||
307 | if (database.TableExists("_Validation")) | ||
308 | { | ||
309 | validationView = database.OpenView("SELECT * FROM `_Validation` WHERE `Table` = ? AND `Column` = ?"); | ||
310 | } | ||
311 | |||
312 | // get the normal tables | ||
313 | using (View tablesView = database.OpenExecuteView("SELECT * FROM _Tables")) | ||
314 | { | ||
315 | while (true) | ||
316 | { | ||
317 | using (Record tableRecord = tablesView.Fetch()) | ||
318 | { | ||
319 | if (null == tableRecord) | ||
320 | { | ||
321 | break; | ||
322 | } | ||
323 | |||
324 | string tableName = tableRecord.GetString(1); | ||
325 | |||
326 | using (View tableView = database.OpenExecuteView(String.Format(CultureInfo.InvariantCulture, "SELECT * FROM `{0}`", tableName))) | ||
327 | { | ||
328 | List<ColumnDefinition> columns; | ||
329 | using (Record columnNameRecord = tableView.GetColumnInfo(MsiInterop.MSICOLINFONAMES), | ||
330 | columnTypeRecord = tableView.GetColumnInfo(MsiInterop.MSICOLINFOTYPES)) | ||
331 | { | ||
332 | // index the primary keys | ||
333 | HashSet<string> tablePrimaryKeys = new HashSet<string>(); | ||
334 | using (Record primaryKeysRecord = database.PrimaryKeys(tableName)) | ||
335 | { | ||
336 | int primaryKeysFieldCount = primaryKeysRecord.GetFieldCount(); | ||
337 | |||
338 | for (int i = 1; i <= primaryKeysFieldCount; i++) | ||
339 | { | ||
340 | tablePrimaryKeys.Add(primaryKeysRecord.GetString(i)); | ||
341 | } | ||
342 | } | ||
343 | |||
344 | int columnCount = columnNameRecord.GetFieldCount(); | ||
345 | columns = new List<ColumnDefinition>(columnCount); | ||
346 | for (int i = 1; i <= columnCount; i++) | ||
347 | { | ||
348 | string columnName = columnNameRecord.GetString(i); | ||
349 | string idtType = columnTypeRecord.GetString(i); | ||
350 | |||
351 | ColumnType columnType; | ||
352 | int length; | ||
353 | bool nullable; | ||
354 | |||
355 | ColumnCategory columnCategory = ColumnCategory.Unknown; | ||
356 | ColumnModularizeType columnModularizeType = ColumnModularizeType.None; | ||
357 | bool primary = tablePrimaryKeys.Contains(columnName); | ||
358 | bool minValueSet = false; | ||
359 | int minValue = -1; | ||
360 | bool maxValueSet = false; | ||
361 | int maxValue = -1; | ||
362 | string keyTable = null; | ||
363 | bool keyColumnSet = false; | ||
364 | int keyColumn = -1; | ||
365 | string category = null; | ||
366 | string set = null; | ||
367 | string description = null; | ||
368 | |||
369 | // get the column type, length, and whether its nullable | ||
370 | switch (Char.ToLower(idtType[0], CultureInfo.InvariantCulture)) | ||
371 | { | ||
372 | case 'i': | ||
373 | columnType = ColumnType.Number; | ||
374 | break; | ||
375 | case 'l': | ||
376 | columnType = ColumnType.Localized; | ||
377 | break; | ||
378 | case 's': | ||
379 | columnType = ColumnType.String; | ||
380 | break; | ||
381 | case 'v': | ||
382 | columnType = ColumnType.Object; | ||
383 | break; | ||
384 | default: | ||
385 | // TODO: error | ||
386 | columnType = ColumnType.Unknown; | ||
387 | break; | ||
388 | } | ||
389 | length = Convert.ToInt32(idtType.Substring(1), CultureInfo.InvariantCulture); | ||
390 | nullable = Char.IsUpper(idtType[0]); | ||
391 | |||
392 | // try to get validation information | ||
393 | if (null != validationView) | ||
394 | { | ||
395 | using (Record validationRecord = new Record(2)) | ||
396 | { | ||
397 | validationRecord.SetString(1, tableName); | ||
398 | validationRecord.SetString(2, columnName); | ||
399 | |||
400 | validationView.Execute(validationRecord); | ||
401 | } | ||
402 | |||
403 | using (Record validationRecord = validationView.Fetch()) | ||
404 | { | ||
405 | if (null != validationRecord) | ||
406 | { | ||
407 | string validationNullable = validationRecord.GetString(3); | ||
408 | minValueSet = !validationRecord.IsNull(4); | ||
409 | minValue = (minValueSet ? validationRecord.GetInteger(4) : -1); | ||
410 | maxValueSet = !validationRecord.IsNull(5); | ||
411 | maxValue = (maxValueSet ? validationRecord.GetInteger(5) : -1); | ||
412 | keyTable = (!validationRecord.IsNull(6) ? validationRecord.GetString(6) : null); | ||
413 | keyColumnSet = !validationRecord.IsNull(7); | ||
414 | keyColumn = (keyColumnSet ? validationRecord.GetInteger(7) : -1); | ||
415 | category = (!validationRecord.IsNull(8) ? validationRecord.GetString(8) : null); | ||
416 | set = (!validationRecord.IsNull(9) ? validationRecord.GetString(9) : null); | ||
417 | description = (!validationRecord.IsNull(10) ? validationRecord.GetString(10) : null); | ||
418 | |||
419 | // check the validation nullable value against the column definition | ||
420 | if (null == validationNullable) | ||
421 | { | ||
422 | // TODO: warn for illegal validation nullable column | ||
423 | } | ||
424 | else if ((nullable && "Y" != validationNullable) || (!nullable && "N" != validationNullable)) | ||
425 | { | ||
426 | // TODO: warn for mismatch between column definition and validation nullable | ||
427 | } | ||
428 | |||
429 | // convert category to ColumnCategory | ||
430 | if (null != category) | ||
431 | { | ||
432 | try | ||
433 | { | ||
434 | columnCategory = (ColumnCategory)Enum.Parse(typeof(ColumnCategory), category, true); | ||
435 | } | ||
436 | catch (ArgumentException) | ||
437 | { | ||
438 | columnCategory = ColumnCategory.Unknown; | ||
439 | } | ||
440 | } | ||
441 | } | ||
442 | else | ||
443 | { | ||
444 | // TODO: warn about no validation information | ||
445 | } | ||
446 | } | ||
447 | } | ||
448 | |||
449 | // guess the modularization type | ||
450 | if ("Icon" == keyTable && 1 == keyColumn) | ||
451 | { | ||
452 | columnModularizeType = ColumnModularizeType.Icon; | ||
453 | } | ||
454 | else if ("Condition" == columnName) | ||
455 | { | ||
456 | columnModularizeType = ColumnModularizeType.Condition; | ||
457 | } | ||
458 | else if (ColumnCategory.Formatted == columnCategory || ColumnCategory.FormattedSDDLText == columnCategory) | ||
459 | { | ||
460 | columnModularizeType = ColumnModularizeType.Property; | ||
461 | } | ||
462 | else if (ColumnCategory.Identifier == columnCategory) | ||
463 | { | ||
464 | columnModularizeType = ColumnModularizeType.Column; | ||
465 | } | ||
466 | |||
467 | columns.Add(new ColumnDefinition(columnName, columnType, length, primary, nullable, columnModularizeType, (ColumnType.Localized == columnType), minValueSet, minValue, maxValueSet, maxValue, keyTable, keyColumnSet, keyColumn, columnCategory, set, description, true, true)); | ||
468 | } | ||
469 | } | ||
470 | |||
471 | TableDefinition tableDefinition = new TableDefinition(tableName, columns, false, false); | ||
472 | |||
473 | // use our table definitions if core properties are the same; this allows us to take advantage | ||
474 | // of wix concepts like localizable columns which current code assumes | ||
475 | if (this.tableDefinitions.Contains(tableName) && 0 == tableDefinition.CompareTo(this.tableDefinitions[tableName])) | ||
476 | { | ||
477 | tableDefinition = this.tableDefinitions[tableName]; | ||
478 | } | ||
479 | |||
480 | Table table = new Table(null, tableDefinition); | ||
481 | |||
482 | while (true) | ||
483 | { | ||
484 | using (Record rowRecord = tableView.Fetch()) | ||
485 | { | ||
486 | if (null == rowRecord) | ||
487 | { | ||
488 | break; | ||
489 | } | ||
490 | |||
491 | int recordCount = rowRecord.GetFieldCount(); | ||
492 | Row row = table.CreateRow(output.SourceLineNumbers); | ||
493 | |||
494 | for (int i = 0; recordCount > i && row.Fields.Length > i; i++) | ||
495 | { | ||
496 | if (rowRecord.IsNull(i + 1)) | ||
497 | { | ||
498 | if (!row.Fields[i].Column.Nullable) | ||
499 | { | ||
500 | // TODO: display an error for a null value in a non-nullable field OR | ||
501 | // display a warning and put an empty string in the value to let the compiler handle it | ||
502 | // (the second option is risky because the later code may make certain assumptions about | ||
503 | // the contents of a row value) | ||
504 | } | ||
505 | } | ||
506 | else | ||
507 | { | ||
508 | switch (row.Fields[i].Column.Type) | ||
509 | { | ||
510 | case ColumnType.Number: | ||
511 | bool success = false; | ||
512 | int intValue = rowRecord.GetInteger(i + 1); | ||
513 | if (row.Fields[i].Column.IsLocalizable) | ||
514 | { | ||
515 | success = row.BestEffortSetField(i, Convert.ToString(intValue, CultureInfo.InvariantCulture)); | ||
516 | } | ||
517 | else | ||
518 | { | ||
519 | success = row.BestEffortSetField(i, intValue); | ||
520 | } | ||
521 | |||
522 | if (!success) | ||
523 | { | ||
524 | this.OnMessage(WixWarnings.BadColumnDataIgnored(row.SourceLineNumbers, Convert.ToString(intValue, CultureInfo.InvariantCulture), tableName, row.Fields[i].Column.Name)); | ||
525 | } | ||
526 | break; | ||
527 | case ColumnType.Object: | ||
528 | string sourceFile = "FILE NOT EXPORTED, USE THE dark.exe -x OPTION TO EXPORT BINARIES"; | ||
529 | |||
530 | if (null != exportBasePath) | ||
531 | { | ||
532 | string relativeSourceFile = Path.Combine(tableName, row.GetPrimaryKey('.')); | ||
533 | sourceFile = Path.Combine(exportBasePath, relativeSourceFile); | ||
534 | |||
535 | // ensure the parent directory exists | ||
536 | System.IO.Directory.CreateDirectory(Path.Combine(exportBasePath, tableName)); | ||
537 | |||
538 | using (FileStream fs = System.IO.File.Create(sourceFile)) | ||
539 | { | ||
540 | int bytesRead; | ||
541 | byte[] buffer = new byte[512]; | ||
542 | |||
543 | while (0 != (bytesRead = rowRecord.GetStream(i + 1, buffer, buffer.Length))) | ||
544 | { | ||
545 | fs.Write(buffer, 0, bytesRead); | ||
546 | } | ||
547 | } | ||
548 | } | ||
549 | |||
550 | row[i] = sourceFile; | ||
551 | break; | ||
552 | default: | ||
553 | string value = rowRecord.GetString(i + 1); | ||
554 | 118 | ||
555 | switch (row.Fields[i].Column.Category) | 119 | foreach (var factory in this.BackendFactories) |
556 | { | ||
557 | case ColumnCategory.Guid: | ||
558 | value = value.ToUpper(CultureInfo.InvariantCulture); | ||
559 | break; | ||
560 | } | ||
561 | |||
562 | // de-modularize | ||
563 | if (!this.suppressDemodularization && OutputType.Module == output.Type && ColumnModularizeType.None != row.Fields[i].Column.ModularizeType) | ||
564 | { | ||
565 | Regex modularization = new Regex(@"\.[0-9A-Fa-f]{8}_[0-9A-Fa-f]{4}_[0-9A-Fa-f]{4}_[0-9A-Fa-f]{4}_[0-9A-Fa-f]{12}"); | ||
566 | |||
567 | if (null == modularizationGuid) | ||
568 | { | ||
569 | Match match = modularization.Match(value); | ||
570 | if (match.Success) | ||
571 | { | ||
572 | modularizationGuid = String.Concat('{', match.Value.Substring(1).Replace('_', '-'), '}'); | ||
573 | } | ||
574 | } | ||
575 | |||
576 | value = modularization.Replace(value, String.Empty); | ||
577 | } | ||
578 | |||
579 | // escape "$(" for the preprocessor | ||
580 | value = value.Replace("$(", "$$("); | ||
581 | |||
582 | // escape things that look like wix variables | ||
583 | MatchCollection matches = Common.WixVariableRegex.Matches(value); | ||
584 | for (int j = matches.Count - 1; 0 <= j; j--) | ||
585 | { | ||
586 | value = value.Insert(matches[j].Index, "!"); | ||
587 | } | ||
588 | |||
589 | row[i] = value; | ||
590 | break; | ||
591 | } | ||
592 | } | ||
593 | } | ||
594 | } | ||
595 | } | ||
596 | |||
597 | output.Tables.Add(table); | ||
598 | } | ||
599 | |||
600 | } | ||
601 | } | ||
602 | } | ||
603 | } | ||
604 | finally | ||
605 | { | ||
606 | if (null != validationView) | ||
607 | { | ||
608 | validationView.Close(); | ||
609 | } | ||
610 | } | ||
611 | |||
612 | // set the modularization guid as the PackageCode | ||
613 | if (null != modularizationGuid) | ||
614 | { | 120 | { |
615 | Table table = output.Tables["_SummaryInformation"]; | 121 | if (factory.TryCreateBackend(outputType.ToString(), file, null, out var backend)) |
616 | |||
617 | foreach (Row row in table.Rows) | ||
618 | { | 122 | { |
619 | if (9 == (int)row[0]) // PID_REVNUMBER | 123 | return backend.Unbind(context); |
620 | { | ||
621 | row[1] = modularizationGuid; | ||
622 | } | ||
623 | } | 124 | } |
624 | } | 125 | } |
625 | 126 | ||
626 | if (this.isAdminImage) | 127 | // TODO: Display message that could not find a unbinder for output type? |
627 | { | ||
628 | GenerateWixFileTable(databaseFile, output); | ||
629 | GenerateSectionIds(output); | ||
630 | } | ||
631 | |||
632 | return output; | ||
633 | } | ||
634 | |||
635 | /// <summary> | ||
636 | /// Creates section ids on rows which form logical groupings of resources. | ||
637 | /// </summary> | ||
638 | /// <param name="output">The Output that represents the msi database.</param> | ||
639 | private void GenerateSectionIds(Output output) | ||
640 | { | ||
641 | // First assign and index section ids for the tables that are in their own sections. | ||
642 | AssignSectionIdsToTable(output.Tables["Binary"], 0); | ||
643 | Hashtable componentSectionIdIndex = AssignSectionIdsToTable(output.Tables["Component"], 0); | ||
644 | Hashtable customActionSectionIdIndex = AssignSectionIdsToTable(output.Tables["CustomAction"], 0); | ||
645 | AssignSectionIdsToTable(output.Tables["Directory"], 0); | ||
646 | Hashtable featureSectionIdIndex = AssignSectionIdsToTable(output.Tables["Feature"], 0); | ||
647 | AssignSectionIdsToTable(output.Tables["Icon"], 0); | ||
648 | Hashtable digitalCertificateSectionIdIndex = AssignSectionIdsToTable(output.Tables["MsiDigitalCertificate"], 0); | ||
649 | AssignSectionIdsToTable(output.Tables["Property"], 0); | ||
650 | |||
651 | // Now handle all the tables that rely on the first set of indexes but also produce their own indexes. Order matters here. | ||
652 | Hashtable fileSectionIdIndex = ConnectTableToSectionAndIndex(output.Tables["File"], componentSectionIdIndex, 1, 0); | ||
653 | Hashtable appIdSectionIdIndex = ConnectTableToSectionAndIndex(output.Tables["Class"], componentSectionIdIndex, 2, 5); | ||
654 | Hashtable odbcDataSourceSectionIdIndex = ConnectTableToSectionAndIndex(output.Tables["ODBCDataSource"], componentSectionIdIndex, 1, 0); | ||
655 | Hashtable odbcDriverSectionIdIndex = ConnectTableToSectionAndIndex(output.Tables["ODBCDriver"], componentSectionIdIndex, 1, 0); | ||
656 | Hashtable registrySectionIdIndex = ConnectTableToSectionAndIndex(output.Tables["Registry"], componentSectionIdIndex, 5, 0); | ||
657 | Hashtable serviceInstallSectionIdIndex = ConnectTableToSectionAndIndex(output.Tables["ServiceInstall"], componentSectionIdIndex, 11, 0); | ||
658 | |||
659 | // Now handle all the tables which only rely on previous indexes and order does not matter. | ||
660 | foreach (Table table in output.Tables) | ||
661 | { | ||
662 | switch (table.Name) | ||
663 | { | ||
664 | case "WixFile": | ||
665 | case "MsiFileHash": | ||
666 | ConnectTableToSection(table, fileSectionIdIndex, 0); | ||
667 | break; | ||
668 | case "MsiAssembly": | ||
669 | case "MsiAssemblyName": | ||
670 | ConnectTableToSection(table, componentSectionIdIndex, 0); | ||
671 | break; | ||
672 | case "MsiPackageCertificate": | ||
673 | case "MsiPatchCertificate": | ||
674 | ConnectTableToSection(table, digitalCertificateSectionIdIndex, 1); | ||
675 | break; | ||
676 | case "CreateFolder": | ||
677 | case "FeatureComponents": | ||
678 | case "MoveFile": | ||
679 | case "ReserveCost": | ||
680 | case "ODBCTranslator": | ||
681 | ConnectTableToSection(table, componentSectionIdIndex, 1); | ||
682 | break; | ||
683 | case "TypeLib": | ||
684 | ConnectTableToSection(table, componentSectionIdIndex, 2); | ||
685 | break; | ||
686 | case "Shortcut": | ||
687 | case "Environment": | ||
688 | ConnectTableToSection(table, componentSectionIdIndex, 3); | ||
689 | break; | ||
690 | case "RemoveRegistry": | ||
691 | ConnectTableToSection(table, componentSectionIdIndex, 4); | ||
692 | break; | ||
693 | case "ServiceControl": | ||
694 | ConnectTableToSection(table, componentSectionIdIndex, 5); | ||
695 | break; | ||
696 | case "IniFile": | ||
697 | case "RemoveIniFile": | ||
698 | ConnectTableToSection(table, componentSectionIdIndex, 7); | ||
699 | break; | ||
700 | case "AppId": | ||
701 | ConnectTableToSection(table, appIdSectionIdIndex, 0); | ||
702 | break; | ||
703 | case "Condition": | ||
704 | ConnectTableToSection(table, featureSectionIdIndex, 0); | ||
705 | break; | ||
706 | case "ODBCSourceAttribute": | ||
707 | ConnectTableToSection(table, odbcDataSourceSectionIdIndex, 0); | ||
708 | break; | ||
709 | case "ODBCAttribute": | ||
710 | ConnectTableToSection(table, odbcDriverSectionIdIndex, 0); | ||
711 | break; | ||
712 | case "AdminExecuteSequence": | ||
713 | case "AdminUISequence": | ||
714 | case "AdvtExecuteSequence": | ||
715 | case "AdvtUISequence": | ||
716 | case "InstallExecuteSequence": | ||
717 | case "InstallUISequence": | ||
718 | ConnectTableToSection(table, customActionSectionIdIndex, 0); | ||
719 | break; | ||
720 | case "LockPermissions": | ||
721 | case "MsiLockPermissions": | ||
722 | foreach (Row row in table.Rows) | ||
723 | { | ||
724 | string lockObject = (string)row[0]; | ||
725 | string tableName = (string)row[1]; | ||
726 | switch (tableName) | ||
727 | { | ||
728 | case "File": | ||
729 | row.SectionId = (string)fileSectionIdIndex[lockObject]; | ||
730 | break; | ||
731 | case "Registry": | ||
732 | row.SectionId = (string)registrySectionIdIndex[lockObject]; | ||
733 | break; | ||
734 | case "ServiceInstall": | ||
735 | row.SectionId = (string)serviceInstallSectionIdIndex[lockObject]; | ||
736 | break; | ||
737 | } | ||
738 | } | ||
739 | break; | ||
740 | } | ||
741 | } | ||
742 | |||
743 | // Now pass the output to each unbinder extension to allow them to analyze the output and determine thier proper section ids. | ||
744 | foreach (IUnbinderExtension extension in this.unbinderExtensions) | ||
745 | { | ||
746 | extension.GenerateSectionIds(output); | ||
747 | } | ||
748 | } | ||
749 | |||
750 | /// <summary> | ||
751 | /// Creates new section ids on all the rows in a table. | ||
752 | /// </summary> | ||
753 | /// <param name="table">The table to add sections to.</param> | ||
754 | /// <param name="rowPrimaryKeyIndex">The index of the column which is used by other tables to reference this table.</param> | ||
755 | /// <returns>A Hashtable containing the tables key for each row paired with its assigned section id.</returns> | ||
756 | private Hashtable AssignSectionIdsToTable(Table table, int rowPrimaryKeyIndex) | ||
757 | { | ||
758 | Hashtable hashtable = new Hashtable(); | ||
759 | if (null != table) | ||
760 | { | ||
761 | foreach (Row row in table.Rows) | ||
762 | { | ||
763 | row.SectionId = GetNewSectionId(); | ||
764 | hashtable.Add(row[rowPrimaryKeyIndex], row.SectionId); | ||
765 | } | ||
766 | } | ||
767 | return hashtable; | ||
768 | } | ||
769 | |||
770 | /// <summary> | ||
771 | /// Connects a table's rows to an already sectioned table. | ||
772 | /// </summary> | ||
773 | /// <param name="table">The table containing rows that need to be connected to sections.</param> | ||
774 | /// <param name="sectionIdIndex">A hashtable containing keys to map table to its section.</param> | ||
775 | /// <param name="rowIndex">The index of the column which is used as the foreign key in to the sectionIdIndex.</param> | ||
776 | private static void ConnectTableToSection(Table table, Hashtable sectionIdIndex, int rowIndex) | ||
777 | { | ||
778 | if (null != table) | ||
779 | { | ||
780 | foreach (Row row in table.Rows) | ||
781 | { | ||
782 | if (sectionIdIndex.ContainsKey(row[rowIndex])) | ||
783 | { | ||
784 | row.SectionId = (string)sectionIdIndex[row[rowIndex]]; | ||
785 | } | ||
786 | } | ||
787 | } | ||
788 | } | ||
789 | |||
790 | /// <summary> | ||
791 | /// Connects a table's rows to an already sectioned table and produces an index for other tables to connect to it. | ||
792 | /// </summary> | ||
793 | /// <param name="table">The table containing rows that need to be connected to sections.</param> | ||
794 | /// <param name="sectionIdIndex">A hashtable containing keys to map table to its section.</param> | ||
795 | /// <param name="rowIndex">The index of the column which is used as the foreign key in to the sectionIdIndex.</param> | ||
796 | /// <param name="rowPrimaryKeyIndex">The index of the column which is used by other tables to reference this table.</param> | ||
797 | /// <returns>A Hashtable containing the tables key for each row paired with its assigned section id.</returns> | ||
798 | private static Hashtable ConnectTableToSectionAndIndex(Table table, Hashtable sectionIdIndex, int rowIndex, int rowPrimaryKeyIndex) | ||
799 | { | ||
800 | Hashtable newHashTable = new Hashtable(); | ||
801 | if (null != table) | ||
802 | { | ||
803 | foreach (Row row in table.Rows) | ||
804 | { | ||
805 | if (!sectionIdIndex.ContainsKey(row[rowIndex])) | ||
806 | { | ||
807 | continue; | ||
808 | } | ||
809 | |||
810 | row.SectionId = (string)sectionIdIndex[row[rowIndex]]; | ||
811 | if (null != row[rowPrimaryKeyIndex]) | ||
812 | { | ||
813 | newHashTable.Add(row[rowPrimaryKeyIndex], row.SectionId); | ||
814 | } | ||
815 | } | ||
816 | } | ||
817 | return newHashTable; | ||
818 | } | ||
819 | |||
820 | /// <summary> | ||
821 | /// Creates a new section identifier to be used when adding a section to an output. | ||
822 | /// </summary> | ||
823 | /// <returns>A string representing a new section id.</returns> | ||
824 | private string GetNewSectionId() | ||
825 | { | ||
826 | this.sectionCount++; | ||
827 | return "wix.section." + this.sectionCount.ToString(CultureInfo.InvariantCulture); | ||
828 | } | ||
829 | |||
830 | /// <summary> | ||
831 | /// Generates the WixFile table based on a path to an admin image msi and an Output. | ||
832 | /// </summary> | ||
833 | /// <param name="databaseFile">The path to the msi database file in an admin image.</param> | ||
834 | /// <param name="output">The Output that represents the msi database.</param> | ||
835 | private void GenerateWixFileTable(string databaseFile, Output output) | ||
836 | { | ||
837 | string adminRootPath = Path.GetDirectoryName(databaseFile); | ||
838 | |||
839 | Hashtable componentDirectoryIndex = new Hashtable(); | ||
840 | Table componentTable = output.Tables["Component"]; | ||
841 | foreach (Row row in componentTable.Rows) | ||
842 | { | ||
843 | componentDirectoryIndex.Add(row[0], row[2]); | ||
844 | } | ||
845 | |||
846 | // Index full source paths for all directories | ||
847 | Hashtable directoryDirectoryParentIndex = new Hashtable(); | ||
848 | Hashtable directoryFullPathIndex = new Hashtable(); | ||
849 | Hashtable directorySourceNameIndex = new Hashtable(); | ||
850 | Table directoryTable = output.Tables["Directory"]; | ||
851 | foreach (Row row in directoryTable.Rows) | ||
852 | { | ||
853 | directoryDirectoryParentIndex.Add(row[0], row[1]); | ||
854 | if (null == row[1]) | ||
855 | { | ||
856 | directoryFullPathIndex.Add(row[0], adminRootPath); | ||
857 | } | ||
858 | else | ||
859 | { | ||
860 | directorySourceNameIndex.Add(row[0], GetAdminSourceName((string)row[2])); | ||
861 | } | ||
862 | } | ||
863 | |||
864 | foreach (DictionaryEntry directoryEntry in directoryDirectoryParentIndex) | ||
865 | { | ||
866 | if (!directoryFullPathIndex.ContainsKey(directoryEntry.Key)) | ||
867 | { | ||
868 | GetAdminFullPath((string)directoryEntry.Key, directoryDirectoryParentIndex, directorySourceNameIndex, directoryFullPathIndex); | ||
869 | } | ||
870 | } | ||
871 | |||
872 | Table fileTable = output.Tables["File"]; | ||
873 | Table wixFileTable = output.EnsureTable(this.tableDefinitions["WixFile"]); | ||
874 | foreach (Row row in fileTable.Rows) | ||
875 | { | ||
876 | WixFileRow wixFileRow = new WixFileRow(null, this.tableDefinitions["WixFile"]); | ||
877 | wixFileRow.File = (string)row[0]; | ||
878 | wixFileRow.Directory = (string)componentDirectoryIndex[(string)row[1]]; | ||
879 | wixFileRow.Source = Path.Combine((string)directoryFullPathIndex[wixFileRow.Directory], GetAdminSourceName((string)row[2])); | ||
880 | |||
881 | if (!File.Exists(wixFileRow.Source)) | ||
882 | { | ||
883 | throw new WixException(WixErrors.WixFileNotFound(wixFileRow.Source)); | ||
884 | } | ||
885 | |||
886 | wixFileTable.Rows.Add(wixFileRow); | ||
887 | } | ||
888 | } | ||
889 | |||
890 | /// <summary> | ||
891 | /// Gets the full path of a directory. Populates the full path index with the directory's full path and all of its parent directorie's full paths. | ||
892 | /// </summary> | ||
893 | /// <param name="directory">The directory identifier.</param> | ||
894 | /// <param name="directoryDirectoryParentIndex">The Hashtable containing all the directory to directory parent mapping.</param> | ||
895 | /// <param name="directorySourceNameIndex">The Hashtable containing all the directory to source name mapping.</param> | ||
896 | /// <param name="directoryFullPathIndex">The Hashtable containing a mapping between all of the directories and their previously calculated full paths.</param> | ||
897 | /// <returns>The full path to the directory.</returns> | ||
898 | private string GetAdminFullPath(string directory, Hashtable directoryDirectoryParentIndex, Hashtable directorySourceNameIndex, Hashtable directoryFullPathIndex) | ||
899 | { | ||
900 | string parent = (string)directoryDirectoryParentIndex[directory]; | ||
901 | string sourceName = (string)directorySourceNameIndex[directory]; | ||
902 | |||
903 | string parentFullPath; | ||
904 | if (directoryFullPathIndex.ContainsKey(parent)) | ||
905 | { | ||
906 | parentFullPath = (string)directoryFullPathIndex[parent]; | ||
907 | } | ||
908 | else | ||
909 | { | ||
910 | parentFullPath = GetAdminFullPath(parent, directoryDirectoryParentIndex, directorySourceNameIndex, directoryFullPathIndex); | ||
911 | } | ||
912 | |||
913 | if (null == sourceName) | ||
914 | { | ||
915 | sourceName = String.Empty; | ||
916 | } | ||
917 | |||
918 | string fullPath = Path.Combine(parentFullPath, sourceName); | ||
919 | directoryFullPathIndex.Add(directory, fullPath); | ||
920 | |||
921 | return fullPath; | ||
922 | } | ||
923 | |||
924 | /// <summary> | ||
925 | /// Get the source name in an admin image. | ||
926 | /// </summary> | ||
927 | /// <param name="value">The Filename value.</param> | ||
928 | /// <returns>The source name of the directory in an admin image.</returns> | ||
929 | private static string GetAdminSourceName(string value) | ||
930 | { | ||
931 | string name = null; | ||
932 | string[] names; | ||
933 | string shortname = null; | ||
934 | string shortsourcename = null; | ||
935 | string sourcename = null; | ||
936 | |||
937 | names = Installer.GetNames(value); | ||
938 | |||
939 | if (null != names[0] && "." != names[0]) | ||
940 | { | ||
941 | if (null != names[1]) | ||
942 | { | ||
943 | shortname = names[0]; | ||
944 | } | ||
945 | else | ||
946 | { | ||
947 | name = names[0]; | ||
948 | } | ||
949 | } | ||
950 | |||
951 | if (null != names[1]) | ||
952 | { | ||
953 | name = names[1]; | ||
954 | } | ||
955 | |||
956 | if (null != names[2]) | ||
957 | { | ||
958 | if (null != names[3]) | ||
959 | { | ||
960 | shortsourcename = names[2]; | ||
961 | } | ||
962 | else | ||
963 | { | ||
964 | sourcename = names[2]; | ||
965 | } | ||
966 | } | ||
967 | |||
968 | if (null != names[3]) | ||
969 | { | ||
970 | sourcename = names[3]; | ||
971 | } | ||
972 | |||
973 | if (null != sourcename) | ||
974 | { | ||
975 | return sourcename; | ||
976 | } | ||
977 | else if (null != shortsourcename) | ||
978 | { | ||
979 | return shortsourcename; | ||
980 | } | ||
981 | else if (null != name) | ||
982 | { | ||
983 | return name; | ||
984 | } | ||
985 | else | ||
986 | { | ||
987 | return shortname; | ||
988 | } | ||
989 | } | ||
990 | |||
991 | /// <summary> | ||
992 | /// Unbind an MSP patch file. | ||
993 | /// </summary> | ||
994 | /// <param name="patchFile">The patch file.</param> | ||
995 | /// <param name="exportBasePath">The path where files should be exported.</param> | ||
996 | /// <returns>The unbound patch.</returns> | ||
997 | private Output UnbindPatch(string patchFile, string exportBasePath) | ||
998 | { | ||
999 | Output patch; | ||
1000 | |||
1001 | // patch files are essentially database files (use a special flag to let the API know its a patch file) | ||
1002 | try | ||
1003 | { | ||
1004 | using (Database database = new Database(patchFile, OpenDatabase.ReadOnly | OpenDatabase.OpenPatchFile)) | ||
1005 | { | ||
1006 | patch = this.UnbindDatabase(patchFile, database, OutputType.Patch, exportBasePath, false); | ||
1007 | } | ||
1008 | } | ||
1009 | catch (Win32Exception e) | ||
1010 | { | ||
1011 | if (0x6E == e.NativeErrorCode) // ERROR_OPEN_FAILED | ||
1012 | { | ||
1013 | throw new WixException(WixErrors.OpenDatabaseFailed(patchFile)); | ||
1014 | } | ||
1015 | |||
1016 | throw; | ||
1017 | } | ||
1018 | |||
1019 | // retrieve the transforms (they are in substorages) | ||
1020 | using (Storage storage = Storage.Open(patchFile, StorageMode.Read | StorageMode.ShareDenyWrite)) | ||
1021 | { | ||
1022 | Table summaryInformationTable = patch.Tables["_SummaryInformation"]; | ||
1023 | foreach (Row row in summaryInformationTable.Rows) | ||
1024 | { | ||
1025 | if (8 == (int)row[0]) // PID_LASTAUTHOR | ||
1026 | { | ||
1027 | string value = (string)row[1]; | ||
1028 | |||
1029 | foreach (string decoratedSubStorageName in value.Split(';')) | ||
1030 | { | ||
1031 | string subStorageName = decoratedSubStorageName.Substring(1); | ||
1032 | string transformFile = Path.Combine(this.TempFilesLocation, String.Concat("Transform", Path.DirectorySeparatorChar, subStorageName, ".mst")); | ||
1033 | |||
1034 | // ensure the parent directory exists | ||
1035 | System.IO.Directory.CreateDirectory(Path.GetDirectoryName(transformFile)); | ||
1036 | |||
1037 | // copy the substorage to a new storage for the transform file | ||
1038 | using (Storage subStorage = storage.OpenStorage(subStorageName)) | ||
1039 | { | ||
1040 | using (Storage transformStorage = Storage.CreateDocFile(transformFile, StorageMode.ReadWrite | StorageMode.ShareExclusive | StorageMode.Create)) | ||
1041 | { | ||
1042 | subStorage.CopyTo(transformStorage); | ||
1043 | } | ||
1044 | } | ||
1045 | |||
1046 | // unbind the transform | ||
1047 | Output transform = this.UnbindTransform(transformFile, (null == exportBasePath ? null : Path.Combine(exportBasePath, subStorageName))); | ||
1048 | patch.SubStorages.Add(new SubStorage(subStorageName, transform)); | ||
1049 | } | ||
1050 | |||
1051 | break; | ||
1052 | } | ||
1053 | } | ||
1054 | } | ||
1055 | |||
1056 | // extract the files from the cabinets | ||
1057 | // TODO: use per-transform export paths for support of multi-product patches | ||
1058 | if (null != exportBasePath && !this.suppressExtractCabinets) | ||
1059 | { | ||
1060 | using (Database database = new Database(patchFile, OpenDatabase.ReadOnly | OpenDatabase.OpenPatchFile)) | ||
1061 | { | ||
1062 | foreach (SubStorage subStorage in patch.SubStorages) | ||
1063 | { | ||
1064 | // only patch transforms should carry files | ||
1065 | if (subStorage.Name.StartsWith("#", StringComparison.Ordinal)) | ||
1066 | { | ||
1067 | this.ExtractCabinets(subStorage.Data, database, patchFile, exportBasePath); | ||
1068 | } | ||
1069 | } | ||
1070 | } | ||
1071 | } | ||
1072 | |||
1073 | return patch; | ||
1074 | } | ||
1075 | |||
1076 | /// <summary> | ||
1077 | /// Unbind an MSI transform file. | ||
1078 | /// </summary> | ||
1079 | /// <param name="transformFile">The transform file.</param> | ||
1080 | /// <param name="exportBasePath">The path where files should be exported.</param> | ||
1081 | /// <returns>The unbound transform.</returns> | ||
1082 | private Output UnbindTransform(string transformFile, string exportBasePath) | ||
1083 | { | ||
1084 | Output transform = new Output(new SourceLineNumber(transformFile)); | ||
1085 | transform.Type = OutputType.Transform; | ||
1086 | |||
1087 | // get the summary information table | ||
1088 | using (SummaryInformation summaryInformation = new SummaryInformation(transformFile)) | ||
1089 | { | ||
1090 | Table table = transform.EnsureTable(this.tableDefinitions["_SummaryInformation"]); | ||
1091 | |||
1092 | for (int i = 1; 19 >= i; i++) | ||
1093 | { | ||
1094 | string value = summaryInformation.GetProperty(i); | ||
1095 | |||
1096 | if (0 < value.Length) | ||
1097 | { | ||
1098 | Row row = table.CreateRow(transform.SourceLineNumbers); | ||
1099 | row[0] = i; | ||
1100 | row[1] = value; | ||
1101 | } | ||
1102 | } | ||
1103 | } | ||
1104 | |||
1105 | // create a schema msi which hopefully matches the table schemas in the transform | ||
1106 | Output schemaOutput = new Output(null); | ||
1107 | string msiDatabaseFile = Path.Combine(this.TempFilesLocation, "schema.msi"); | ||
1108 | foreach (TableDefinition tableDefinition in this.tableDefinitions) | ||
1109 | { | ||
1110 | // skip unreal tables and the Patch table | ||
1111 | if (!tableDefinition.Unreal && "Patch" != tableDefinition.Name) | ||
1112 | { | ||
1113 | schemaOutput.EnsureTable(tableDefinition); | ||
1114 | } | ||
1115 | } | ||
1116 | |||
1117 | Hashtable addedRows = new Hashtable(); | ||
1118 | Table transformViewTable; | ||
1119 | |||
1120 | // Bind the schema msi. | ||
1121 | this.GenerateDatabase(schemaOutput, msiDatabaseFile); | ||
1122 | |||
1123 | // apply the transform to the database and retrieve the modifications | ||
1124 | using (Database msiDatabase = new Database(msiDatabaseFile, OpenDatabase.Transact)) | ||
1125 | { | ||
1126 | // apply the transform with the ViewTransform option to collect all the modifications | ||
1127 | msiDatabase.ApplyTransform(transformFile, TransformErrorConditions.All | TransformErrorConditions.ViewTransform); | ||
1128 | |||
1129 | // unbind the database | ||
1130 | Output transformViewOutput = this.UnbindDatabase(msiDatabaseFile, msiDatabase, OutputType.Product, exportBasePath, true); | ||
1131 | |||
1132 | // index the added and possibly modified rows (added rows may also appears as modified rows) | ||
1133 | transformViewTable = transformViewOutput.Tables["_TransformView"]; | ||
1134 | Hashtable modifiedRows = new Hashtable(); | ||
1135 | foreach (Row row in transformViewTable.Rows) | ||
1136 | { | ||
1137 | string tableName = (string)row[0]; | ||
1138 | string columnName = (string)row[1]; | ||
1139 | string primaryKeys = (string)row[2]; | ||
1140 | |||
1141 | if ("INSERT" == columnName) | ||
1142 | { | ||
1143 | string index = String.Concat(tableName, ':', primaryKeys); | ||
1144 | |||
1145 | addedRows.Add(index, null); | ||
1146 | } | ||
1147 | else if ("CREATE" != columnName && "DELETE" != columnName && "DROP" != columnName && null != primaryKeys) // modified row | ||
1148 | { | ||
1149 | string index = String.Concat(tableName, ':', primaryKeys); | ||
1150 | |||
1151 | modifiedRows[index] = row; | ||
1152 | } | ||
1153 | } | ||
1154 | |||
1155 | // create placeholder rows for modified rows to make the transform insert the updated values when its applied | ||
1156 | foreach (Row row in modifiedRows.Values) | ||
1157 | { | ||
1158 | string tableName = (string)row[0]; | ||
1159 | string columnName = (string)row[1]; | ||
1160 | string primaryKeys = (string)row[2]; | ||
1161 | |||
1162 | string index = String.Concat(tableName, ':', primaryKeys); | ||
1163 | |||
1164 | // ignore information for added rows | ||
1165 | if (!addedRows.Contains(index)) | ||
1166 | { | ||
1167 | Table table = schemaOutput.Tables[tableName]; | ||
1168 | this.CreateRow(table, primaryKeys, true); | ||
1169 | } | ||
1170 | } | ||
1171 | } | ||
1172 | |||
1173 | // Re-bind the schema output with the placeholder rows. | ||
1174 | this.GenerateDatabase(schemaOutput, msiDatabaseFile); | ||
1175 | |||
1176 | // apply the transform to the database and retrieve the modifications | ||
1177 | using (Database msiDatabase = new Database(msiDatabaseFile, OpenDatabase.Transact)) | ||
1178 | { | ||
1179 | try | ||
1180 | { | ||
1181 | // apply the transform | ||
1182 | msiDatabase.ApplyTransform(transformFile, TransformErrorConditions.All); | ||
1183 | |||
1184 | // commit the database to guard against weird errors with streams | ||
1185 | msiDatabase.Commit(); | ||
1186 | } | ||
1187 | catch (Win32Exception ex) | ||
1188 | { | ||
1189 | if (0x65B == ex.NativeErrorCode) | ||
1190 | { | ||
1191 | // this commonly happens when the transform was built | ||
1192 | // against a database schema different from the internal | ||
1193 | // table definitions | ||
1194 | throw new WixException(WixErrors.TransformSchemaMismatch()); | ||
1195 | } | ||
1196 | } | ||
1197 | |||
1198 | // unbind the database | ||
1199 | Output output = this.UnbindDatabase(msiDatabaseFile, msiDatabase, OutputType.Product, exportBasePath, true); | ||
1200 | |||
1201 | // index all the rows to easily find modified rows | ||
1202 | Hashtable rows = new Hashtable(); | ||
1203 | foreach (Table table in output.Tables) | ||
1204 | { | ||
1205 | foreach (Row row in table.Rows) | ||
1206 | { | ||
1207 | rows.Add(String.Concat(table.Name, ':', row.GetPrimaryKey('\t', " ")), row); | ||
1208 | } | ||
1209 | } | ||
1210 | |||
1211 | // process the _TransformView rows into transform rows | ||
1212 | foreach (Row row in transformViewTable.Rows) | ||
1213 | { | ||
1214 | string tableName = (string)row[0]; | ||
1215 | string columnName = (string)row[1]; | ||
1216 | string primaryKeys = (string)row[2]; | ||
1217 | |||
1218 | Table table = transform.EnsureTable(this.tableDefinitions[tableName]); | ||
1219 | |||
1220 | if ("CREATE" == columnName) // added table | ||
1221 | { | ||
1222 | table.Operation = TableOperation.Add; | ||
1223 | } | ||
1224 | else if ("DELETE" == columnName) // deleted row | ||
1225 | { | ||
1226 | Row deletedRow = this.CreateRow(table, primaryKeys, false); | ||
1227 | deletedRow.Operation = RowOperation.Delete; | ||
1228 | } | ||
1229 | else if ("DROP" == columnName) // dropped table | ||
1230 | { | ||
1231 | table.Operation = TableOperation.Drop; | ||
1232 | } | ||
1233 | else if ("INSERT" == columnName) // added row | ||
1234 | { | ||
1235 | string index = String.Concat(tableName, ':', primaryKeys); | ||
1236 | Row addedRow = (Row)rows[index]; | ||
1237 | addedRow.Operation = RowOperation.Add; | ||
1238 | table.Rows.Add(addedRow); | ||
1239 | } | ||
1240 | else if (null != primaryKeys) // modified row | ||
1241 | { | ||
1242 | string index = String.Concat(tableName, ':', primaryKeys); | ||
1243 | |||
1244 | // the _TransformView table includes information for added rows | ||
1245 | // that looks like modified rows so it sometimes needs to be ignored | ||
1246 | if (!addedRows.Contains(index)) | ||
1247 | { | ||
1248 | Row modifiedRow = (Row)rows[index]; | ||
1249 | |||
1250 | // mark the field as modified | ||
1251 | int indexOfModifiedValue = -1; | ||
1252 | for (int i = 0; i < modifiedRow.TableDefinition.Columns.Count; ++i) | ||
1253 | { | ||
1254 | if (columnName.Equals(modifiedRow.TableDefinition.Columns[i].Name, StringComparison.Ordinal)) | ||
1255 | { | ||
1256 | indexOfModifiedValue = i; | ||
1257 | break; | ||
1258 | } | ||
1259 | } | ||
1260 | modifiedRow.Fields[indexOfModifiedValue].Modified = true; | ||
1261 | |||
1262 | // move the modified row into the transform the first time its encountered | ||
1263 | if (RowOperation.None == modifiedRow.Operation) | ||
1264 | { | ||
1265 | modifiedRow.Operation = RowOperation.Modify; | ||
1266 | table.Rows.Add(modifiedRow); | ||
1267 | } | ||
1268 | } | ||
1269 | } | ||
1270 | else // added column | ||
1271 | { | ||
1272 | ColumnDefinition column = table.Definition.Columns.Single(c => c.Name.Equals(columnName, StringComparison.Ordinal)); | ||
1273 | column.Added = true; | ||
1274 | } | ||
1275 | } | ||
1276 | } | ||
1277 | |||
1278 | return transform; | ||
1279 | } | ||
1280 | |||
1281 | private void GenerateDatabase(Output output, string databaseFile) | ||
1282 | { | ||
1283 | GenerateDatabaseCommand command = new GenerateDatabaseCommand(); | ||
1284 | command.Extensions = Enumerable.Empty<IBinderExtension>(); | ||
1285 | command.FileManagers = Enumerable.Empty<IBinderFileManager>(); | ||
1286 | command.Output = output; | ||
1287 | command.OutputPath = databaseFile; | ||
1288 | command.KeepAddedColumns = true; | ||
1289 | command.UseSubDirectory = false; | ||
1290 | command.SuppressAddingValidationRows = true; | ||
1291 | command.TableDefinitions = this.tableDefinitions; | ||
1292 | command.TempFilesLocation = this.TempFilesLocation; | ||
1293 | command.Codepage = -1; | ||
1294 | command.Execute(); | ||
1295 | } | ||
1296 | |||
1297 | /// <summary> | ||
1298 | /// Unbind a bundle. | ||
1299 | /// </summary> | ||
1300 | /// <param name="bundleFile">The bundle file.</param> | ||
1301 | /// <param name="exportBasePath">The path where files should be exported.</param> | ||
1302 | /// <returns>The unbound bundle.</returns> | ||
1303 | private Output UnbindBundle(string bundleFile, string exportBasePath) | ||
1304 | { | ||
1305 | string uxExtractPath = Path.Combine(exportBasePath, "UX"); | ||
1306 | string acExtractPath = Path.Combine(exportBasePath, "AttachedContainer"); | ||
1307 | |||
1308 | using (BurnReader reader = BurnReader.Open(bundleFile)) | ||
1309 | { | ||
1310 | reader.ExtractUXContainer(uxExtractPath, this.TempFilesLocation); | ||
1311 | reader.ExtractAttachedContainer(acExtractPath, this.TempFilesLocation); | ||
1312 | } | ||
1313 | 128 | ||
1314 | return null; | 129 | return null; |
1315 | } | 130 | } |
1316 | |||
1317 | /// <summary> | ||
1318 | /// Create a deleted or modified row. | ||
1319 | /// </summary> | ||
1320 | /// <param name="table">The table containing the row.</param> | ||
1321 | /// <param name="primaryKeys">The primary keys of the row.</param> | ||
1322 | /// <param name="setRequiredFields">Option to set all required fields with placeholder values.</param> | ||
1323 | /// <returns>The new row.</returns> | ||
1324 | private Row CreateRow(Table table, string primaryKeys, bool setRequiredFields) | ||
1325 | { | ||
1326 | Row row = table.CreateRow(null); | ||
1327 | |||
1328 | string[] primaryKeyParts = primaryKeys.Split('\t'); | ||
1329 | int primaryKeyPartIndex = 0; | ||
1330 | |||
1331 | for (int i = 0; i < table.Definition.Columns.Count; i++) | ||
1332 | { | ||
1333 | ColumnDefinition columnDefinition = table.Definition.Columns[i]; | ||
1334 | |||
1335 | if (columnDefinition.PrimaryKey) | ||
1336 | { | ||
1337 | if (ColumnType.Number == columnDefinition.Type && !columnDefinition.IsLocalizable) | ||
1338 | { | ||
1339 | row[i] = Convert.ToInt32(primaryKeyParts[primaryKeyPartIndex++], CultureInfo.InvariantCulture); | ||
1340 | } | ||
1341 | else | ||
1342 | { | ||
1343 | row[i] = primaryKeyParts[primaryKeyPartIndex++]; | ||
1344 | } | ||
1345 | } | ||
1346 | else if (setRequiredFields) | ||
1347 | { | ||
1348 | if (ColumnType.Number == columnDefinition.Type && !columnDefinition.IsLocalizable) | ||
1349 | { | ||
1350 | row[i] = 1; | ||
1351 | } | ||
1352 | else if (ColumnType.Object == columnDefinition.Type) | ||
1353 | { | ||
1354 | if (null == this.emptyFile) | ||
1355 | { | ||
1356 | this.emptyFile = Path.GetTempFileName() + ".empty"; | ||
1357 | using (FileStream fileStream = File.Create(this.emptyFile)) | ||
1358 | { | ||
1359 | } | ||
1360 | } | ||
1361 | |||
1362 | row[i] = this.emptyFile; | ||
1363 | } | ||
1364 | else | ||
1365 | { | ||
1366 | row[i] = "1"; | ||
1367 | } | ||
1368 | } | ||
1369 | } | ||
1370 | |||
1371 | return row; | ||
1372 | } | ||
1373 | |||
1374 | /// <summary> | ||
1375 | /// Extract the cabinets from a database. | ||
1376 | /// </summary> | ||
1377 | /// <param name="output">The output to use when finding cabinets.</param> | ||
1378 | /// <param name="database">The database containing the cabinets.</param> | ||
1379 | /// <param name="databaseFile">The location of the database file.</param> | ||
1380 | /// <param name="exportBasePath">The path where the files should be exported.</param> | ||
1381 | private void ExtractCabinets(Output output, Database database, string databaseFile, string exportBasePath) | ||
1382 | { | ||
1383 | string databaseBasePath = Path.GetDirectoryName(databaseFile); | ||
1384 | StringCollection cabinetFiles = new StringCollection(); | ||
1385 | SortedList embeddedCabinets = new SortedList(); | ||
1386 | |||
1387 | // index all of the cabinet files | ||
1388 | if (OutputType.Module == output.Type) | ||
1389 | { | ||
1390 | embeddedCabinets.Add(0, "MergeModule.CABinet"); | ||
1391 | } | ||
1392 | else if (null != output.Tables["Media"]) | ||
1393 | { | ||
1394 | foreach (MediaRow mediaRow in output.Tables["Media"].Rows) | ||
1395 | { | ||
1396 | if (null != mediaRow.Cabinet) | ||
1397 | { | ||
1398 | if (OutputType.Product == output.Type || | ||
1399 | (OutputType.Transform == output.Type && RowOperation.Add == mediaRow.Operation)) | ||
1400 | { | ||
1401 | if (mediaRow.Cabinet.StartsWith("#", StringComparison.Ordinal)) | ||
1402 | { | ||
1403 | embeddedCabinets.Add(mediaRow.DiskId, mediaRow.Cabinet.Substring(1)); | ||
1404 | } | ||
1405 | else | ||
1406 | { | ||
1407 | cabinetFiles.Add(Path.Combine(databaseBasePath, mediaRow.Cabinet)); | ||
1408 | } | ||
1409 | } | ||
1410 | } | ||
1411 | } | ||
1412 | } | ||
1413 | |||
1414 | // extract the embedded cabinet files from the database | ||
1415 | if (0 < embeddedCabinets.Count) | ||
1416 | { | ||
1417 | using (View streamsView = database.OpenView("SELECT `Data` FROM `_Streams` WHERE `Name` = ?")) | ||
1418 | { | ||
1419 | foreach (int diskId in embeddedCabinets.Keys) | ||
1420 | { | ||
1421 | using (Record record = new Record(1)) | ||
1422 | { | ||
1423 | record.SetString(1, (string)embeddedCabinets[diskId]); | ||
1424 | streamsView.Execute(record); | ||
1425 | } | ||
1426 | |||
1427 | using (Record record = streamsView.Fetch()) | ||
1428 | { | ||
1429 | if (null != record) | ||
1430 | { | ||
1431 | // since the cabinets are stored in case-sensitive streams inside the msi, but the file system is not case-sensitive, | ||
1432 | // embedded cabinets must be extracted to a canonical file name (like their diskid) to ensure extraction will always work | ||
1433 | string cabinetFile = Path.Combine(this.TempFilesLocation, String.Concat("Media", Path.DirectorySeparatorChar, diskId.ToString(CultureInfo.InvariantCulture), ".cab")); | ||
1434 | |||
1435 | // ensure the parent directory exists | ||
1436 | System.IO.Directory.CreateDirectory(Path.GetDirectoryName(cabinetFile)); | ||
1437 | |||
1438 | using (FileStream fs = System.IO.File.Create(cabinetFile)) | ||
1439 | { | ||
1440 | int bytesRead; | ||
1441 | byte[] buffer = new byte[512]; | ||
1442 | |||
1443 | while (0 != (bytesRead = record.GetStream(1, buffer, buffer.Length))) | ||
1444 | { | ||
1445 | fs.Write(buffer, 0, bytesRead); | ||
1446 | } | ||
1447 | } | ||
1448 | |||
1449 | cabinetFiles.Add(cabinetFile); | ||
1450 | } | ||
1451 | else | ||
1452 | { | ||
1453 | // TODO: warning about missing embedded cabinet | ||
1454 | } | ||
1455 | } | ||
1456 | } | ||
1457 | } | ||
1458 | } | ||
1459 | |||
1460 | // extract the cabinet files | ||
1461 | if (0 < cabinetFiles.Count) | ||
1462 | { | ||
1463 | string fileDirectory = Path.Combine(exportBasePath, "File"); | ||
1464 | |||
1465 | // delete the directory and its files to prevent cab extraction due to an existing file | ||
1466 | if (Directory.Exists(fileDirectory)) | ||
1467 | { | ||
1468 | Directory.Delete(fileDirectory, true); | ||
1469 | } | ||
1470 | |||
1471 | // ensure the directory exists or extraction will fail | ||
1472 | Directory.CreateDirectory(fileDirectory); | ||
1473 | |||
1474 | foreach (string cabinetFile in cabinetFiles) | ||
1475 | { | ||
1476 | using (WixExtractCab extractCab = new WixExtractCab()) | ||
1477 | { | ||
1478 | try | ||
1479 | { | ||
1480 | extractCab.Extract(cabinetFile, fileDirectory); | ||
1481 | } | ||
1482 | catch (FileNotFoundException) | ||
1483 | { | ||
1484 | throw new WixException(WixErrors.FileNotFound(new SourceLineNumber(databaseFile), cabinetFile)); | ||
1485 | } | ||
1486 | } | ||
1487 | } | ||
1488 | } | ||
1489 | } | ||
1490 | } | 131 | } |
1491 | } | 132 | } |
diff --git a/src/WixToolset.Core/Uuid.cs b/src/WixToolset.Core/Uuid.cs index 2e599793..d512d92f 100644 --- a/src/WixToolset.Core/Uuid.cs +++ b/src/WixToolset.Core/Uuid.cs | |||
@@ -10,7 +10,7 @@ namespace WixToolset | |||
10 | /// <summary> | 10 | /// <summary> |
11 | /// Implementation of RFC 4122 - A Universally Unique Identifier (UUID) URN Namespace. | 11 | /// Implementation of RFC 4122 - A Universally Unique Identifier (UUID) URN Namespace. |
12 | /// </summary> | 12 | /// </summary> |
13 | internal sealed class Uuid | 13 | public sealed class Uuid |
14 | { | 14 | { |
15 | /// <summary> | 15 | /// <summary> |
16 | /// Protect the constructor. | 16 | /// Protect the constructor. |
diff --git a/src/WixToolset.Core/WixStrings.Designer.cs b/src/WixToolset.Core/WixStrings.Designer.cs index 4ba9381a..75e2b908 100644 --- a/src/WixToolset.Core/WixStrings.Designer.cs +++ b/src/WixToolset.Core/WixStrings.Designer.cs | |||
@@ -14,7 +14,7 @@ namespace WixToolset { | |||
14 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] | 14 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] |
15 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] | 15 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] |
16 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] | 16 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] |
17 | internal class WixStrings { | 17 | public class WixStrings { |
18 | 18 | ||
19 | private static global::System.Resources.ResourceManager resourceMan; | 19 | private static global::System.Resources.ResourceManager resourceMan; |
20 | 20 | ||
@@ -127,7 +127,7 @@ namespace WixToolset { | |||
127 | /// <summary> | 127 | /// <summary> |
128 | /// Looks up a localized string similar to Could not determine ProductCode from transform summary information. | 128 | /// Looks up a localized string similar to Could not determine ProductCode from transform summary information. |
129 | /// </summary> | 129 | /// </summary> |
130 | internal static string EXP_CouldnotDetermineProductCodeFromTransformSummaryInfo { | 130 | public static string EXP_CouldnotDetermineProductCodeFromTransformSummaryInfo { |
131 | get { | 131 | get { |
132 | return ResourceManager.GetString("EXP_CouldnotDetermineProductCodeFromTransformSummaryInfo", resourceCulture); | 132 | return ResourceManager.GetString("EXP_CouldnotDetermineProductCodeFromTransformSummaryInfo", resourceCulture); |
133 | } | 133 | } |
@@ -226,7 +226,7 @@ namespace WixToolset { | |||
226 | /// <summary> | 226 | /// <summary> |
227 | /// Looks up a localized string similar to Transform authored into multiple Media '{0}' and '{1}'.. | 227 | /// Looks up a localized string similar to Transform authored into multiple Media '{0}' and '{1}'.. |
228 | /// </summary> | 228 | /// </summary> |
229 | internal static string EXP_TransformAuthoredIntoMultipleMedia { | 229 | public static string EXP_TransformAuthoredIntoMultipleMedia { |
230 | get { | 230 | get { |
231 | return ResourceManager.GetString("EXP_TransformAuthoredIntoMultipleMedia", resourceCulture); | 231 | return ResourceManager.GetString("EXP_TransformAuthoredIntoMultipleMedia", resourceCulture); |
232 | } | 232 | } |
@@ -253,7 +253,7 @@ namespace WixToolset { | |||
253 | /// <summary> | 253 | /// <summary> |
254 | /// Looks up a localized string similar to Encountered an unexpected error while merging '{0}'. More information about the merge and the failure can be found in the merge log: '{1}'. | 254 | /// Looks up a localized string similar to Encountered an unexpected error while merging '{0}'. More information about the merge and the failure can be found in the merge log: '{1}'. |
255 | /// </summary> | 255 | /// </summary> |
256 | internal static string EXP_UnexpectedMergerErrorInSourceFile { | 256 | public static string EXP_UnexpectedMergerErrorInSourceFile { |
257 | get { | 257 | get { |
258 | return ResourceManager.GetString("EXP_UnexpectedMergerErrorInSourceFile", resourceCulture); | 258 | return ResourceManager.GetString("EXP_UnexpectedMergerErrorInSourceFile", resourceCulture); |
259 | } | 259 | } |
@@ -262,7 +262,7 @@ namespace WixToolset { | |||
262 | /// <summary> | 262 | /// <summary> |
263 | /// Looks up a localized string similar to Encountered an unexpected merge error of type '{0}' for which there is currently no error message to display. More information about the merge and the failure can be found in the merge log: '{1}'. | 263 | /// Looks up a localized string similar to Encountered an unexpected merge error of type '{0}' for which there is currently no error message to display. More information about the merge and the failure can be found in the merge log: '{1}'. |
264 | /// </summary> | 264 | /// </summary> |
265 | internal static string EXP_UnexpectedMergerErrorWithType { | 265 | public static string EXP_UnexpectedMergerErrorWithType { |
266 | get { | 266 | get { |
267 | return ResourceManager.GetString("EXP_UnexpectedMergerErrorWithType", resourceCulture); | 267 | return ResourceManager.GetString("EXP_UnexpectedMergerErrorWithType", resourceCulture); |
268 | } | 268 | } |
diff --git a/src/WixToolset.Core/WixVariableResolver.cs b/src/WixToolset.Core/WixVariableResolver.cs index d437423c..357ff700 100644 --- a/src/WixToolset.Core/WixVariableResolver.cs +++ b/src/WixToolset.Core/WixVariableResolver.cs | |||
@@ -1,6 +1,6 @@ | |||
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 | 3 | namespace WixToolset.Core |
4 | { | 4 | { |
5 | using System; | 5 | using System; |
6 | using System.Collections.Generic; | 6 | using System.Collections.Generic; |
@@ -10,11 +10,12 @@ namespace WixToolset | |||
10 | using System.Text.RegularExpressions; | 10 | using System.Text.RegularExpressions; |
11 | using WixToolset.Data; | 11 | using WixToolset.Data; |
12 | using WixToolset.Data.Rows; | 12 | using WixToolset.Data.Rows; |
13 | using WixToolset.Extensibility; | ||
13 | 14 | ||
14 | /// <summary> | 15 | /// <summary> |
15 | /// WiX variable resolver. | 16 | /// WiX variable resolver. |
16 | /// </summary> | 17 | /// </summary> |
17 | public sealed class WixVariableResolver | 18 | internal sealed class WixVariableResolver : IBindVariableResolver |
18 | { | 19 | { |
19 | private Dictionary<string, string> wixVariables; | 20 | private Dictionary<string, string> wixVariables; |
20 | 21 | ||
@@ -31,7 +32,7 @@ namespace WixToolset | |||
31 | /// Gets or sets the localizer. | 32 | /// Gets or sets the localizer. |
32 | /// </summary> | 33 | /// </summary> |
33 | /// <value>The localizer.</value> | 34 | /// <value>The localizer.</value> |
34 | public Localizer Localizer { get; private set; } | 35 | private Localizer Localizer { get; } |
35 | 36 | ||
36 | /// <summary> | 37 | /// <summary> |
37 | /// Gets the count of variables added to the resolver. | 38 | /// Gets the count of variables added to the resolver. |
@@ -83,10 +84,7 @@ namespace WixToolset | |||
83 | /// <returns>The resolved value.</returns> | 84 | /// <returns>The resolved value.</returns> |
84 | public string ResolveVariables(SourceLineNumber sourceLineNumbers, string value, bool localizationOnly) | 85 | public string ResolveVariables(SourceLineNumber sourceLineNumbers, string value, bool localizationOnly) |
85 | { | 86 | { |
86 | bool isDefault = false; | 87 | return this.ResolveVariables(sourceLineNumbers, value, localizationOnly, out var defaultIgnored, out var delayedIgnored); |
87 | bool delayedResolve = false; | ||
88 | |||
89 | return this.ResolveVariables(sourceLineNumbers, value, localizationOnly, ref isDefault, ref delayedResolve); | ||
90 | } | 88 | } |
91 | 89 | ||
92 | /// <summary> | 90 | /// <summary> |
@@ -97,11 +95,9 @@ namespace WixToolset | |||
97 | /// <param name="localizationOnly">true to only resolve localization variables; false otherwise.</param> | 95 | /// <param name="localizationOnly">true to only resolve localization variables; false otherwise.</param> |
98 | /// <param name="isDefault">true if the resolved value was the default.</param> | 96 | /// <param name="isDefault">true if the resolved value was the default.</param> |
99 | /// <returns>The resolved value.</returns> | 97 | /// <returns>The resolved value.</returns> |
100 | public string ResolveVariables(SourceLineNumber sourceLineNumbers, string value, bool localizationOnly, ref bool isDefault) | 98 | public string ResolveVariables(SourceLineNumber sourceLineNumbers, string value, bool localizationOnly, out bool isDefault) |
101 | { | 99 | { |
102 | bool delayedResolve = false; | 100 | return this.ResolveVariables(sourceLineNumbers, value, localizationOnly, out isDefault, out var ignored); |
103 | |||
104 | return this.ResolveVariables(sourceLineNumbers, value, localizationOnly, ref isDefault, ref delayedResolve); | ||
105 | } | 101 | } |
106 | 102 | ||
107 | /// <summary> | 103 | /// <summary> |
@@ -114,9 +110,9 @@ namespace WixToolset | |||
114 | /// <param name="isDefault">true if the resolved value was the default.</param> | 110 | /// <param name="isDefault">true if the resolved value was the default.</param> |
115 | /// <param name="delayedResolve">true if the value has variables that cannot yet be resolved.</param> | 111 | /// <param name="delayedResolve">true if the value has variables that cannot yet be resolved.</param> |
116 | /// <returns>The resolved value.</returns> | 112 | /// <returns>The resolved value.</returns> |
117 | public string ResolveVariables(SourceLineNumber sourceLineNumbers, string value, bool localizationOnly, ref bool isDefault, ref bool delayedResolve) | 113 | public string ResolveVariables(SourceLineNumber sourceLineNumbers, string value, bool localizationOnly, out bool isDefault, out bool delayedResolve) |
118 | { | 114 | { |
119 | return this.ResolveVariables(sourceLineNumbers, value, localizationOnly, true, ref isDefault, ref delayedResolve); | 115 | return this.ResolveVariables(sourceLineNumbers, value, localizationOnly, true, out isDefault, out delayedResolve); |
120 | } | 116 | } |
121 | 117 | ||
122 | /// <summary> | 118 | /// <summary> |
@@ -129,7 +125,7 @@ namespace WixToolset | |||
129 | /// <param name="isDefault">true if the resolved value was the default.</param> | 125 | /// <param name="isDefault">true if the resolved value was the default.</param> |
130 | /// <param name="delayedResolve">true if the value has variables that cannot yet be resolved.</param> | 126 | /// <param name="delayedResolve">true if the value has variables that cannot yet be resolved.</param> |
131 | /// <returns>The resolved value.</returns> | 127 | /// <returns>The resolved value.</returns> |
132 | public string ResolveVariables(SourceLineNumber sourceLineNumbers, string value, bool localizationOnly, bool errorOnUnknown, ref bool isDefault, ref bool delayedResolve) | 128 | public string ResolveVariables(SourceLineNumber sourceLineNumbers, string value, bool localizationOnly, bool errorOnUnknown, out bool isDefault, out bool delayedResolve) |
133 | { | 129 | { |
134 | MatchCollection matches = Common.WixVariableRegex.Matches(value); | 130 | MatchCollection matches = Common.WixVariableRegex.Matches(value); |
135 | 131 | ||
@@ -190,10 +186,7 @@ namespace WixToolset | |||
190 | Messaging.Instance.OnMessage(WixWarnings.DeprecatedLocalizationVariablePrefix(sourceLineNumbers, variableId)); | 186 | Messaging.Instance.OnMessage(WixWarnings.DeprecatedLocalizationVariablePrefix(sourceLineNumbers, variableId)); |
191 | } | 187 | } |
192 | 188 | ||
193 | if (null != this.Localizer) | 189 | resolvedValue = this.Localizer?.GetLocalizedValue(variableId); |
194 | { | ||
195 | resolvedValue = this.Localizer.GetLocalizedValue(variableId); | ||
196 | } | ||
197 | } | 190 | } |
198 | else if (!localizationOnly && "wix" == variableNamespace) | 191 | else if (!localizationOnly && "wix" == variableNamespace) |
199 | { | 192 | { |
@@ -223,6 +216,7 @@ namespace WixToolset | |||
223 | } | 216 | } |
224 | else | 217 | else |
225 | { | 218 | { |
219 | |||
226 | // insert the resolved value if it was found or display an error | 220 | // insert the resolved value if it was found or display an error |
227 | if (null != resolvedValue) | 221 | if (null != resolvedValue) |
228 | { | 222 | { |
@@ -248,6 +242,19 @@ namespace WixToolset | |||
248 | } | 242 | } |
249 | 243 | ||
250 | /// <summary> | 244 | /// <summary> |
245 | /// Try to find localization information for dialog and (optional) control. | ||
246 | /// </summary> | ||
247 | /// <param name="dialog">Dialog identifier.</param> | ||
248 | /// <param name="control">Optional control identifier.</param> | ||
249 | /// <param name="localizedControl">Found localization information.</param> | ||
250 | /// <returns>True if localized control was found, otherwise false.</returns> | ||
251 | public bool TryGetLocalizedControl(string dialog, string control, out LocalizedControl localizedControl) | ||
252 | { | ||
253 | localizedControl = this.Localizer?.GetLocalizedControl(dialog, control); | ||
254 | return localizedControl != null; | ||
255 | } | ||
256 | |||
257 | /// <summary> | ||
251 | /// Resolve the delay variables in a value. | 258 | /// Resolve the delay variables in a value. |
252 | /// </summary> | 259 | /// </summary> |
253 | /// <param name="sourceLineNumbers">The source line information for the value.</param> | 260 | /// <param name="sourceLineNumbers">The source line information for the value.</param> |
diff --git a/src/wix/wix.csproj b/src/wix/wix.csproj index f183be39..828793ae 100644 --- a/src/wix/wix.csproj +++ b/src/wix/wix.csproj | |||
@@ -21,6 +21,8 @@ | |||
21 | 21 | ||
22 | <ItemGroup> | 22 | <ItemGroup> |
23 | <ProjectReference Include="..\WixToolset.Core\WixToolset.Core.csproj" /> | 23 | <ProjectReference Include="..\WixToolset.Core\WixToolset.Core.csproj" /> |
24 | <ProjectReference Include="..\WixToolset.Core.Burn\WixToolset.Core.Burn.csproj" /> | ||
25 | <ProjectReference Include="..\WixToolset.Core.WindowsInstaller\WixToolset.Core.WindowsInstaller.csproj" /> | ||
24 | 26 | ||
25 | <ProjectReference Include="$(WixToolsetRootFolder)\Data\src\WixToolset.Data\WixToolset.Data.csproj" Condition=" '$(Configuration)' == 'Debug' And Exists('$(WixToolsetRootFolder)\Data\src\WixToolset.Data\WixToolset.Data.csproj') " /> | 27 | <ProjectReference Include="$(WixToolsetRootFolder)\Data\src\WixToolset.Data\WixToolset.Data.csproj" Condition=" '$(Configuration)' == 'Debug' And Exists('$(WixToolsetRootFolder)\Data\src\WixToolset.Data\WixToolset.Data.csproj') " /> |
26 | <PackageReference Include="WixToolset.Data" Version="4.0.*" Condition=" '$(Configuration)' == 'Release' Or !Exists('$(WixToolsetRootFolder)\Data\src\WixToolset.Data\WixToolset.Data.csproj') " /> | 28 | <PackageReference Include="WixToolset.Data" Version="4.0.*" Condition=" '$(Configuration)' == 'Release' Or !Exists('$(WixToolsetRootFolder)\Data\src\WixToolset.Data\WixToolset.Data.csproj') " /> |