diff options
| author | Rob Mensching <rob@firegiant.com> | 2017-10-14 16:12:07 -0700 |
|---|---|---|
| committer | Rob Mensching <rob@firegiant.com> | 2017-10-14 16:12:07 -0700 |
| commit | dbde9e7104b907bbbaea17e21247d8cafc8b3a4c (patch) | |
| tree | 0f5fbbb6fe12c6b2e5e622a0e18ce4c5b4eb2b96 /src | |
| parent | fbf986eb97f68396797a89fc7d40dec07b775440 (diff) | |
| download | wix-dbde9e7104b907bbbaea17e21247d8cafc8b3a4c.tar.gz wix-dbde9e7104b907bbbaea17e21247d8cafc8b3a4c.tar.bz2 wix-dbde9e7104b907bbbaea17e21247d8cafc8b3a4c.zip | |
Massive refactoring to introduce the concept of IBackend
Diffstat (limited to 'src')
127 files changed, 4269 insertions, 2917 deletions
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') " /> |
