aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/WixToolset.Core.Burn/Bind/BindBundleCommand.cs8
-rw-r--r--src/WixToolset.Core.Burn/Bundles/CreateBootstrapperApplicationManifestCommand.cs2
-rw-r--r--src/WixToolset.Core.Burn/Bundles/CreateBundleExtensionManifestCommand.cs2
-rw-r--r--src/WixToolset.Core.Burn/Bundles/ProcessMsiPackageCommand.cs12
-rw-r--r--src/WixToolset.Core.Burn/ExtensibilityServices/BurnBackendHelper.cs34
-rw-r--r--src/WixToolset.Core.Burn/RowIndexedList.cs21
-rw-r--r--src/WixToolset.Core.Burn/TableExtensions.cs24
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Bind/AssignMediaCommand.cs36
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Bind/AttachPatchTransformsCommand.cs9
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs31
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Bind/BindSummaryInfoCommand.cs15
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Bind/BindTransformCommand.cs4
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Bind/CabinetResolver.cs5
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Bind/CabinetWorkItem.cs6
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Bind/CalculateComponentGuids.cs4
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Bind/CopyTransformDataCommand.cs630
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Bind/CreateCabinetsCommand.cs4
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Bind/CreateDeltaPatchesCommand.cs7
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Bind/CreateInstanceTransformsCommand.cs2
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Bind/CreatePatchTransformsCommand.cs9
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Bind/CreateWindowsInstallerDataFromIRCommand.cs83
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Bind/ExtractMergeModuleFilesCommand.cs19
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Bind/GetFileFacadesCommand.cs21
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Bind/GetFileFacadesFromTransforms.cs21
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Bind/MergeModulesCommand.cs6
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Bind/ModularizeCommand.cs12
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Bind/OptimizeFileFacadesOrderCommand.cs11
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Bind/ProcessDependencyReferencesCommand.cs15
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Bind/ProcessUncompressedFilesCommand.cs15
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Bind/UpdateFileFacadesCommand.cs12
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Bind/UpdateMediaSequencesCommand.cs14
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Bind/UpdateTransformsWithFileFacades.cs12
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Data/Xsd/actions.xsd73
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Data/Xsd/tables.xsd248
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Decompile/DecompileMsiOrMsmCommand.cs9
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Decompile/Decompiler.cs65
-rw-r--r--src/WixToolset.Core.WindowsInstaller/ExtensibilityServices/WindowsInstallerBackendHelper.cs33
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Inscribe/InscribeMsiPackageCommand.cs5
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Melter.cs2
-rw-r--r--src/WixToolset.Core.WindowsInstaller/MsiBackend.cs1
-rw-r--r--src/WixToolset.Core.WindowsInstaller/MsmBackend.cs1
-rw-r--r--src/WixToolset.Core.WindowsInstaller/MspBackend.cs6
-rw-r--r--src/WixToolset.Core.WindowsInstaller/PatchAPI/PatchInterop.cs202
-rw-r--r--src/WixToolset.Core.WindowsInstaller/RowDictionary.cs13
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Unbind/UnbindDatabaseCommand.cs10
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Unbind/UnbindTranformCommand.cs9
-rw-r--r--src/WixToolset.Core.WindowsInstaller/UnbindContext.cs1
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Unbinder.cs4
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Validator.cs13
-rw-r--r--src/WixToolset.Core.WindowsInstaller/ValidatorExtension.cs14
-rw-r--r--src/WixToolset.Core/AppCommon.cs45
-rw-r--r--src/WixToolset.Core/Bind/ExtractEmbeddedFilesCommand.cs3
-rw-r--r--src/WixToolset.Core/Bind/ResolveDelayedFieldsCommand.cs17
-rw-r--r--src/WixToolset.Core/CommandLine/CommandLine.cs10
-rw-r--r--src/WixToolset.Core/CommandLine/HelpCommand.cs8
-rw-r--r--src/WixToolset.Core/Common.cs324
-rw-r--r--src/WixToolset.Core/Compiler.cs8
-rw-r--r--src/WixToolset.Core/CompilerCore.cs37
-rw-r--r--src/WixToolset.Core/Compiler_Package.cs10
-rw-r--r--src/WixToolset.Core/Compiler_Patch.cs14
-rw-r--r--src/WixToolset.Core/ExtensibilityServices/BackendHelper.cs86
-rw-r--r--src/WixToolset.Core/ExtensibilityServices/FileFacade.cs (renamed from src/WixToolset.Core/Bind/FileFacade.cs)6
-rw-r--r--src/WixToolset.Core/ExtensibilityServices/ParseHelper.cs111
-rw-r--r--src/WixToolset.Core/ExtensibilityServices/WixBranding.cs124
-rw-r--r--src/WixToolset.Core/LocalizationParser.cs26
-rw-r--r--src/WixToolset.Core/OptimizeCA.cs33
-rw-r--r--src/WixToolset.Core/PatchSymbolFlagsType.cs34
-rw-r--r--src/WixToolset.Core/ResolvedCabinet.cs2
-rw-r--r--src/WixToolset.Core/WixDistribution.cs109
-rw-r--r--src/WixToolset.Core/WixToolsetServiceProvider.cs1
70 files changed, 871 insertions, 1952 deletions
diff --git a/src/WixToolset.Core.Burn/Bind/BindBundleCommand.cs b/src/WixToolset.Core.Burn/Bind/BindBundleCommand.cs
index e58e2464..afaf65ee 100644
--- a/src/WixToolset.Core.Burn/Bind/BindBundleCommand.cs
+++ b/src/WixToolset.Core.Burn/Bind/BindBundleCommand.cs
@@ -130,10 +130,9 @@ namespace WixToolset.Core.Burn
130 130
131 // Extract files that come from binary .wixlibs and WixExtensions (this does not extract files from merge modules). 131 // Extract files that come from binary .wixlibs and WixExtensions (this does not extract files from merge modules).
132 { 132 {
133 var command = new ExtractEmbeddedFilesCommand(this.BackendHelper, this.ExpectedEmbeddedFiles); 133 var extractedFiles = this.BackendHelper.ExtractEmbeddedFiles(this.ExpectedEmbeddedFiles);
134 command.Execute();
135 134
136 trackedFiles.AddRange(command.TrackedFiles); 135 trackedFiles.AddRange(extractedFiles);
137 } 136 }
138 137
139 // Get the explicit payloads. 138 // Get the explicit payloads.
@@ -367,8 +366,7 @@ namespace WixToolset.Core.Burn
367 // Resolve any delayed fields before generating the manifest. 366 // Resolve any delayed fields before generating the manifest.
368 if (this.DelayedFields.Any()) 367 if (this.DelayedFields.Any())
369 { 368 {
370 var resolveDelayedFieldsCommand = new ResolveDelayedFieldsCommand(this.Messaging, this.DelayedFields, variableCache); 369 this.BackendHelper.ResolveDelayedFields(this.DelayedFields, variableCache);
371 resolveDelayedFieldsCommand.Execute();
372 } 370 }
373 371
374 Dictionary<string, ProvidesDependencySymbol> dependencySymbolsByKey; 372 Dictionary<string, ProvidesDependencySymbol> dependencySymbolsByKey;
diff --git a/src/WixToolset.Core.Burn/Bundles/CreateBootstrapperApplicationManifestCommand.cs b/src/WixToolset.Core.Burn/Bundles/CreateBootstrapperApplicationManifestCommand.cs
index a24137f3..63a168a0 100644
--- a/src/WixToolset.Core.Burn/Bundles/CreateBootstrapperApplicationManifestCommand.cs
+++ b/src/WixToolset.Core.Burn/Bundles/CreateBootstrapperApplicationManifestCommand.cs
@@ -244,7 +244,7 @@ namespace WixToolset.Core.Burn.Bundles
244 244
245 private WixBundlePayloadSymbol CreateBootstrapperApplicationManifestPayloadRow(string baManifestPath) 245 private WixBundlePayloadSymbol CreateBootstrapperApplicationManifestPayloadRow(string baManifestPath)
246 { 246 {
247 var generatedId = Common.GenerateIdentifier("ux", BurnCommon.BADataFileName); 247 var generatedId = this.InternalBurnBackendHelper.GenerateIdentifier("ux", BurnCommon.BADataFileName);
248 248
249 var symbol = this.Section.AddSymbol(new WixBundlePayloadSymbol(this.BundleSymbol.SourceLineNumbers, new Identifier(AccessModifier.Section, generatedId)) 249 var symbol = this.Section.AddSymbol(new WixBundlePayloadSymbol(this.BundleSymbol.SourceLineNumbers, new Identifier(AccessModifier.Section, generatedId))
250 { 250 {
diff --git a/src/WixToolset.Core.Burn/Bundles/CreateBundleExtensionManifestCommand.cs b/src/WixToolset.Core.Burn/Bundles/CreateBundleExtensionManifestCommand.cs
index 9e1f85bc..7b5b9656 100644
--- a/src/WixToolset.Core.Burn/Bundles/CreateBundleExtensionManifestCommand.cs
+++ b/src/WixToolset.Core.Burn/Bundles/CreateBundleExtensionManifestCommand.cs
@@ -66,7 +66,7 @@ namespace WixToolset.Core.Burn.Bundles
66 66
67 private WixBundlePayloadSymbol CreateBundleExtensionManifestPayloadRow(string bextManifestPath) 67 private WixBundlePayloadSymbol CreateBundleExtensionManifestPayloadRow(string bextManifestPath)
68 { 68 {
69 var generatedId = Common.GenerateIdentifier("ux", BurnCommon.BundleExtensionDataFileName); 69 var generatedId = this.InternalBurnBackendHelper.GenerateIdentifier("ux", BurnCommon.BundleExtensionDataFileName);
70 70
71 var symbol = this.Section.AddSymbol(new WixBundlePayloadSymbol(this.BundleSymbol.SourceLineNumbers, new Identifier(AccessModifier.Section, generatedId)) 71 var symbol = this.Section.AddSymbol(new WixBundlePayloadSymbol(this.BundleSymbol.SourceLineNumbers, new Identifier(AccessModifier.Section, generatedId))
72 { 72 {
diff --git a/src/WixToolset.Core.Burn/Bundles/ProcessMsiPackageCommand.cs b/src/WixToolset.Core.Burn/Bundles/ProcessMsiPackageCommand.cs
index 5ba1ad07..dc1a1913 100644
--- a/src/WixToolset.Core.Burn/Bundles/ProcessMsiPackageCommand.cs
+++ b/src/WixToolset.Core.Burn/Bundles/ProcessMsiPackageCommand.cs
@@ -94,7 +94,7 @@ namespace WixToolset.Core.Burn.Bundles
94 msiPackage.ProductLanguage = Convert.ToInt32(ProcessMsiPackageCommand.GetProperty(db, "ProductLanguage"), CultureInfo.InvariantCulture); 94 msiPackage.ProductLanguage = Convert.ToInt32(ProcessMsiPackageCommand.GetProperty(db, "ProductLanguage"), CultureInfo.InvariantCulture);
95 msiPackage.ProductVersion = ProcessMsiPackageCommand.GetProperty(db, "ProductVersion"); 95 msiPackage.ProductVersion = ProcessMsiPackageCommand.GetProperty(db, "ProductVersion");
96 96
97 if (!Common.IsValidModuleOrBundleVersion(msiPackage.ProductVersion)) 97 if (!this.BackendHelper.IsValidFourPartVersion(msiPackage.ProductVersion))
98 { 98 {
99 // not a proper .NET version (e.g., five fields); can we get a valid four-part version number? 99 // not a proper .NET version (e.g., five fields); can we get a valid four-part version number?
100 string version = null; 100 string version = null;
@@ -109,7 +109,7 @@ namespace WixToolset.Core.Burn.Bundles
109 } 109 }
110 } 110 }
111 111
112 if (!String.IsNullOrEmpty(version) && Common.IsValidModuleOrBundleVersion(version)) 112 if (!String.IsNullOrEmpty(version) && this.BackendHelper.IsValidFourPartVersion(version))
113 { 113 {
114 this.Messaging.Write(WarningMessages.VersionTruncated(this.Facade.PackageSymbol.SourceLineNumbers, msiPackage.ProductVersion, sourcePath, version)); 114 this.Messaging.Write(WarningMessages.VersionTruncated(this.Facade.PackageSymbol.SourceLineNumbers, msiPackage.ProductVersion, sourcePath, version));
115 msiPackage.ProductVersion = version; 115 msiPackage.ProductVersion = version;
@@ -394,7 +394,7 @@ namespace WixToolset.Core.Burn.Bundles
394 394
395 if (!payloadNames.Contains(cabinetName)) 395 if (!payloadNames.Contains(cabinetName))
396 { 396 {
397 var generatedId = Common.GenerateIdentifier("cab", packagePayload.Id.Id, cabinet); 397 var generatedId = this.BackendHelper.GenerateIdentifier("cab", packagePayload.Id.Id, cabinet);
398 var payloadSourceFile = this.ResolveRelatedFile(packagePayload.SourceFile.Path, packagePayload.UnresolvedSourceFile, cabinet, "Cabinet", this.Facade.PackageSymbol.SourceLineNumbers); 398 var payloadSourceFile = this.ResolveRelatedFile(packagePayload.SourceFile.Path, packagePayload.UnresolvedSourceFile, cabinet, "Cabinet", this.Facade.PackageSymbol.SourceLineNumbers);
399 399
400 this.Section.AddSymbol(new WixBundlePayloadSymbol(this.Facade.PackageSymbol.SourceLineNumbers, new Identifier(AccessModifier.Section, generatedId)) 400 this.Section.AddSymbol(new WixBundlePayloadSymbol(this.Facade.PackageSymbol.SourceLineNumbers, new Identifier(AccessModifier.Section, generatedId))
@@ -437,7 +437,7 @@ namespace WixToolset.Core.Burn.Bundles
437 break; 437 break;
438 } 438 }
439 439
440 var sourceName = Common.GetName(record.GetString(3), true, longNamesInImage); 440 var sourceName = this.BackendHelper.GetMsiFileName(record.GetString(3), true, longNamesInImage);
441 441
442 var resolvedDirectory = this.BackendHelper.CreateResolvedDirectory(record.GetString(2), sourceName); 442 var resolvedDirectory = this.BackendHelper.CreateResolvedDirectory(record.GetString(2), sourceName);
443 443
@@ -471,7 +471,7 @@ namespace WixToolset.Core.Burn.Bundles
471 471
472 if (!payloadNames.Contains(name)) 472 if (!payloadNames.Contains(name))
473 { 473 {
474 var generatedId = Common.GenerateIdentifier("f", packagePayload.Id.Id, record.GetString(2)); 474 var generatedId = this.BackendHelper.GenerateIdentifier("f", packagePayload.Id.Id, record.GetString(2));
475 var payloadSourceFile = this.ResolveRelatedFile(packagePayload.SourceFile.Path, packagePayload.UnresolvedSourceFile, fileSourcePath, "File", this.Facade.PackageSymbol.SourceLineNumbers); 475 var payloadSourceFile = this.ResolveRelatedFile(packagePayload.SourceFile.Path, packagePayload.UnresolvedSourceFile, fileSourcePath, "File", this.Facade.PackageSymbol.SourceLineNumbers);
476 476
477 this.Section.AddSymbol(new WixBundlePayloadSymbol(this.Facade.PackageSymbol.SourceLineNumbers, new Identifier(AccessModifier.Section, generatedId)) 477 this.Section.AddSymbol(new WixBundlePayloadSymbol(this.Facade.PackageSymbol.SourceLineNumbers, new Identifier(AccessModifier.Section, generatedId))
@@ -526,7 +526,7 @@ namespace WixToolset.Core.Burn.Bundles
526 break; 526 break;
527 } 527 }
528 528
529 var id = new Identifier(AccessModifier.Section, Common.GenerateIdentifier("dep", msiPackage.Id.Id, record.GetString(1))); 529 var id = new Identifier(AccessModifier.Section, this.BackendHelper.GenerateIdentifier("dep", msiPackage.Id.Id, record.GetString(1)));
530 530
531 // Import the provider key and attributes. 531 // Import the provider key and attributes.
532 this.Section.AddSymbol(new ProvidesDependencySymbol(msiPackage.SourceLineNumbers, id) 532 this.Section.AddSymbol(new ProvidesDependencySymbol(msiPackage.SourceLineNumbers, id)
diff --git a/src/WixToolset.Core.Burn/ExtensibilityServices/BurnBackendHelper.cs b/src/WixToolset.Core.Burn/ExtensibilityServices/BurnBackendHelper.cs
index 59efcbc9..5502b43b 100644
--- a/src/WixToolset.Core.Burn/ExtensibilityServices/BurnBackendHelper.cs
+++ b/src/WixToolset.Core.Burn/ExtensibilityServices/BurnBackendHelper.cs
@@ -9,6 +9,8 @@ namespace WixToolset.Core.Burn.ExtensibilityServices
9 using System.Xml; 9 using System.Xml;
10 using WixToolset.Core.Burn.Bundles; 10 using WixToolset.Core.Burn.Bundles;
11 using WixToolset.Data; 11 using WixToolset.Data;
12 using WixToolset.Data.Symbols;
13 using WixToolset.Data.WindowsInstaller.Rows;
12 using WixToolset.Extensibility.Data; 14 using WixToolset.Extensibility.Data;
13 using WixToolset.Extensibility.Services; 15 using WixToolset.Extensibility.Services;
14 16
@@ -30,14 +32,44 @@ namespace WixToolset.Core.Burn.ExtensibilityServices
30 32
31 #region IBackendHelper interfaces 33 #region IBackendHelper interfaces
32 34
35 public IFileFacade CreateFileFacade(FileSymbol file, AssemblySymbol assembly) => this.backendHelper.CreateFileFacade(file, assembly);
36
37 public IFileFacade CreateFileFacade(FileRow fileRow) => this.backendHelper.CreateFileFacade(fileRow);
38
39 public IFileFacade CreateFileFacadeFromMergeModule(FileSymbol fileSymbol) => this.backendHelper.CreateFileFacadeFromMergeModule(fileSymbol);
40
33 public IFileTransfer CreateFileTransfer(string source, string destination, bool move, SourceLineNumber sourceLineNumbers = null) => this.backendHelper.CreateFileTransfer(source, destination, move, sourceLineNumbers); 41 public IFileTransfer CreateFileTransfer(string source, string destination, bool move, SourceLineNumber sourceLineNumbers = null) => this.backendHelper.CreateFileTransfer(source, destination, move, sourceLineNumbers);
34 42
43 public string CreateGuid() => this.backendHelper.CreateGuid();
44
35 public string CreateGuid(Guid namespaceGuid, string value) => this.backendHelper.CreateGuid(namespaceGuid, value); 45 public string CreateGuid(Guid namespaceGuid, string value) => this.backendHelper.CreateGuid(namespaceGuid, value);
36 46
37 public IResolvedDirectory CreateResolvedDirectory(string directoryParent, string name) => this.backendHelper.CreateResolvedDirectory(directoryParent, name); 47 public IResolvedDirectory CreateResolvedDirectory(string directoryParent, string name) => this.backendHelper.CreateResolvedDirectory(directoryParent, name);
38 48
49 public IEnumerable<ITrackedFile> ExtractEmbeddedFiles(IEnumerable<IExpectedExtractFile> embeddedFiles) => this.backendHelper.ExtractEmbeddedFiles(embeddedFiles);
50
51 public string GenerateIdentifier(string prefix, params string[] args) => this.backendHelper.GenerateIdentifier(prefix, args);
52
39 public string GetCanonicalRelativePath(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string relativePath) => this.backendHelper.GetCanonicalRelativePath(sourceLineNumbers, elementName, attributeName, relativePath); 53 public string GetCanonicalRelativePath(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string relativePath) => this.backendHelper.GetCanonicalRelativePath(sourceLineNumbers, elementName, attributeName, relativePath);
40 54
55 public int GetValidCodePage(string value, bool allowNoChange, bool onlyAnsi = false, SourceLineNumber sourceLineNumbers = null) => this.backendHelper.GetValidCodePage(value, allowNoChange, onlyAnsi, sourceLineNumbers);
56
57 public string GetMsiFileName(string value, bool source, bool longName) => this.backendHelper.GetMsiFileName(value, source, longName);
58
59 public bool IsValidBinderVariable(string variable) => this.backendHelper.IsValidBinderVariable(variable);
60
61 public bool IsValidFourPartVersion(string version) => this.backendHelper.IsValidFourPartVersion(version);
62
63 public bool IsValidIdentifier(string id) => this.backendHelper.IsValidIdentifier(id);
64
65 public bool IsValidLongFilename(string filename, bool allowWildcards, bool allowRelative) => this.backendHelper.IsValidLongFilename(filename, allowWildcards, allowRelative);
66
67 public bool IsValidShortFilename(string filename, bool allowWildcards) => this.backendHelper.IsValidShortFilename(filename, allowWildcards);
68
69 public void ResolveDelayedFields(IEnumerable<IDelayedField> delayedFields, Dictionary<string, string> variableCache) => this.backendHelper.ResolveDelayedFields(delayedFields, variableCache);
70
71 public string[] SplitMsiFileName(string value) => this.backendHelper.SplitMsiFileName(value);
72
41 public ITrackedFile TrackFile(string path, TrackedFileType type, SourceLineNumber sourceLineNumbers = null) => this.backendHelper.TrackFile(path, type, sourceLineNumbers); 73 public ITrackedFile TrackFile(string path, TrackedFileType type, SourceLineNumber sourceLineNumbers = null) => this.backendHelper.TrackFile(path, type, sourceLineNumbers);
42 74
43 #endregion 75 #endregion
@@ -87,7 +119,7 @@ namespace WixToolset.Core.Burn.ExtensibilityServices
87 119
88 private ManifestData GetBundleExtensionManifestData(string extensionId) 120 private ManifestData GetBundleExtensionManifestData(string extensionId)
89 { 121 {
90 if (!Common.IsIdentifier(extensionId)) 122 if (!this.backendHelper.IsValidIdentifier(extensionId))
91 { 123 {
92 throw new ArgumentException($"'{extensionId}' is not a valid extensionId"); 124 throw new ArgumentException($"'{extensionId}' is not a valid extensionId");
93 } 125 }
diff --git a/src/WixToolset.Core.Burn/RowIndexedList.cs b/src/WixToolset.Core.Burn/RowIndexedList.cs
index 73172dc2..fd762a24 100644
--- a/src/WixToolset.Core.Burn/RowIndexedList.cs
+++ b/src/WixToolset.Core.Burn/RowIndexedList.cs
@@ -13,9 +13,9 @@ namespace WixToolset.Core.Burn
13 /// </summary> 13 /// </summary>
14 internal sealed class RowIndexedList<T> : IList<T> where T : Row 14 internal sealed class RowIndexedList<T> : IList<T> where T : Row
15 { 15 {
16 private Dictionary<string, T> index; 16 private readonly Dictionary<string, T> index;
17 private List<T> rows; 17 private readonly List<T> rows;
18 private List<T> duplicates; 18 private readonly List<T> duplicates;
19 19
20 /// <summary> 20 /// <summary>
21 /// Creates an empty <see cref="RowIndexedList{T}"/>. 21 /// Creates an empty <see cref="RowIndexedList{T}"/>.
@@ -34,7 +34,7 @@ namespace WixToolset.Core.Burn
34 public RowIndexedList(IEnumerable<T> rows) 34 public RowIndexedList(IEnumerable<T> rows)
35 : this() 35 : this()
36 { 36 {
37 foreach (T row in rows) 37 foreach (var row in rows)
38 { 38 {
39 this.Add(row); 39 this.Add(row);
40 } 40 }
@@ -81,8 +81,7 @@ namespace WixToolset.Core.Burn
81 /// <returns>Row or null if key is not found.</returns> 81 /// <returns>Row or null if key is not found.</returns>
82 public T Get(string key) 82 public T Get(string key)
83 { 83 {
84 T result; 84 return this.TryGet(key, out var result) ? result : null;
85 return this.TryGet(key, out result) ? result : null;
86 } 85 }
87 86
88 /// <summary> 87 /// <summary>
@@ -169,12 +168,11 @@ namespace WixToolset.Core.Burn
169 /// <param name="index">Index to remove the row at.</param> 168 /// <param name="index">Index to remove the row at.</param>
170 public void RemoveAt(int index) 169 public void RemoveAt(int index)
171 { 170 {
172 T row = this.rows[index]; 171 var row = this.rows[index];
173 172
174 this.rows.RemoveAt(index); 173 this.rows.RemoveAt(index);
175 174
176 T indexRow; 175 if (this.index.TryGetValue(row.GetKey(), out var indexRow) && indexRow == row)
177 if (this.index.TryGetValue(row.GetKey(), out indexRow) && indexRow == row)
178 { 176 {
179 this.index.Remove(row.GetKey()); 177 this.index.Remove(row.GetKey());
180 } 178 }
@@ -264,11 +262,10 @@ namespace WixToolset.Core.Burn
264 /// <returns></returns> 262 /// <returns></returns>
265 public bool Remove(T row) 263 public bool Remove(T row)
266 { 264 {
267 bool removed = this.rows.Remove(row); 265 var removed = this.rows.Remove(row);
268 if (removed) 266 if (removed)
269 { 267 {
270 T indexRow; 268 if (this.index.TryGetValue(row.GetKey(), out var indexRow) && indexRow == row)
271 if (this.index.TryGetValue(row.GetKey(), out indexRow) && indexRow == row)
272 { 269 {
273 this.index.Remove(row.GetKey()); 270 this.index.Remove(row.GetKey());
274 } 271 }
diff --git a/src/WixToolset.Core.Burn/TableExtensions.cs b/src/WixToolset.Core.Burn/TableExtensions.cs
deleted file mode 100644
index 465bf870..00000000
--- a/src/WixToolset.Core.Burn/TableExtensions.cs
+++ /dev/null
@@ -1,24 +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
3namespace WixToolset.Core.Burn
4{
5 using System.Collections.Generic;
6 using System.Linq;
7 using WixToolset.Data.WindowsInstaller;
8
9 /// <summary>
10 /// Methods that extend <see cref="Table"/>.
11 /// </summary>
12 public static class TableExtensions
13 {
14 /// <summary>
15 /// Gets the rows contained in the table as a particular row type.
16 /// </summary>
17 /// <param name="table">Table to get rows from.</param>
18 /// <remarks>If the <paramref name="table"/> is null, an empty enumerable will be returned.</remarks>
19 public static IEnumerable<T> RowsAs<T>(this Table table) where T : Row
20 {
21 return (null == table) ? Enumerable.Empty<T>() : table.Rows.Cast<T>();
22 }
23 }
24}
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/AssignMediaCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/AssignMediaCommand.cs
index f6c61866..d7faa382 100644
--- a/src/WixToolset.Core.WindowsInstaller/Bind/AssignMediaCommand.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Bind/AssignMediaCommand.cs
@@ -6,9 +6,9 @@ namespace WixToolset.Core.WindowsInstaller.Bind
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;
10 using WixToolset.Data; 9 using WixToolset.Data;
11 using WixToolset.Data.Symbols; 10 using WixToolset.Data.Symbols;
11 using WixToolset.Extensibility.Data;
12 using WixToolset.Extensibility.Services; 12 using WixToolset.Extensibility.Services;
13 13
14 /// <summary> 14 /// <summary>
@@ -18,7 +18,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
18 { 18 {
19 private const int DefaultMaximumUncompressedMediaSize = 200; // Default value is 200 MB 19 private const int DefaultMaximumUncompressedMediaSize = 200; // Default value is 200 MB
20 20
21 public AssignMediaCommand(IntermediateSection section, IMessaging messaging, IEnumerable<FileFacade> fileFacades, bool compressed) 21 public AssignMediaCommand(IntermediateSection section, IMessaging messaging, IEnumerable<IFileFacade> fileFacades, bool compressed)
22 { 22 {
23 this.CabinetNameTemplate = "Cab{0}.cab"; 23 this.CabinetNameTemplate = "Cab{0}.cab";
24 this.Section = section; 24 this.Section = section;
@@ -31,7 +31,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
31 31
32 private IMessaging Messaging { get; } 32 private IMessaging Messaging { get; }
33 33
34 private IEnumerable<FileFacade> FileFacades { get; } 34 private IEnumerable<IFileFacade> FileFacades { get; }
35 35
36 private bool FilesCompressed { get; } 36 private bool FilesCompressed { get; }
37 37
@@ -40,13 +40,13 @@ namespace WixToolset.Core.WindowsInstaller.Bind
40 /// <summary> 40 /// <summary>
41 /// Gets cabinets with their file rows. 41 /// Gets cabinets with their file rows.
42 /// </summary> 42 /// </summary>
43 public Dictionary<MediaSymbol, IEnumerable<FileFacade>> FileFacadesByCabinetMedia { get; private set; } 43 public Dictionary<MediaSymbol, IEnumerable<IFileFacade>> FileFacadesByCabinetMedia { get; private set; }
44 44
45 /// <summary> 45 /// <summary>
46 /// Get uncompressed file rows. This will contain file rows of File elements that are marked with compression=no. 46 /// Get uncompressed file rows. This will contain file rows of File elements that are marked with compression=no.
47 /// This contains all the files when Package element is marked with compression=no 47 /// This contains all the files when Package element is marked with compression=no
48 /// </summary> 48 /// </summary>
49 public IEnumerable<FileFacade> UncompressedFileFacades { get; private set; } 49 public IEnumerable<IFileFacade> UncompressedFileFacades { get; private set; }
50 50
51 public void Execute() 51 public void Execute()
52 { 52 {
@@ -79,34 +79,34 @@ namespace WixToolset.Core.WindowsInstaller.Bind
79 Cabinet = "#MergeModule.CABinet", 79 Cabinet = "#MergeModule.CABinet",
80 }); 80 });
81 81
82 this.FileFacadesByCabinetMedia = new Dictionary<MediaSymbol, IEnumerable<FileFacade>> 82 this.FileFacadesByCabinetMedia = new Dictionary<MediaSymbol, IEnumerable<IFileFacade>>
83 { 83 {
84 { mergeModuleMediaSymbol, this.FileFacades } 84 { mergeModuleMediaSymbol, this.FileFacades }
85 }; 85 };
86 86
87 this.UncompressedFileFacades = Array.Empty<FileFacade>(); 87 this.UncompressedFileFacades = Array.Empty<IFileFacade>();
88 } 88 }
89 else if (mediaTemplateSymbols.Count == 0) 89 else if (mediaTemplateSymbols.Count == 0)
90 { 90 {
91 var filesByCabinetMedia = new Dictionary<MediaSymbol, List<FileFacade>>(); 91 var filesByCabinetMedia = new Dictionary<MediaSymbol, List<IFileFacade>>();
92 92
93 var uncompressedFiles = new List<FileFacade>(); 93 var uncompressedFiles = new List<IFileFacade>();
94 94
95 this.ManuallyAssignFiles(mediaSymbols, filesByCabinetMedia, uncompressedFiles); 95 this.ManuallyAssignFiles(mediaSymbols, filesByCabinetMedia, uncompressedFiles);
96 96
97 this.FileFacadesByCabinetMedia = filesByCabinetMedia.ToDictionary(kvp => kvp.Key, kvp => (IEnumerable<FileFacade>)kvp.Value); 97 this.FileFacadesByCabinetMedia = filesByCabinetMedia.ToDictionary(kvp => kvp.Key, kvp => (IEnumerable<IFileFacade>)kvp.Value);
98 98
99 this.UncompressedFileFacades = uncompressedFiles; 99 this.UncompressedFileFacades = uncompressedFiles;
100 } 100 }
101 else 101 else
102 { 102 {
103 var filesByCabinetMedia = new Dictionary<MediaSymbol, List<FileFacade>>(); 103 var filesByCabinetMedia = new Dictionary<MediaSymbol, List<IFileFacade>>();
104 104
105 var uncompressedFiles = new List<FileFacade>(); 105 var uncompressedFiles = new List<IFileFacade>();
106 106
107 this.AutoAssignFiles(mediaSymbols, filesByCabinetMedia, uncompressedFiles); 107 this.AutoAssignFiles(mediaSymbols, filesByCabinetMedia, uncompressedFiles);
108 108
109 this.FileFacadesByCabinetMedia = filesByCabinetMedia.ToDictionary(kvp => kvp.Key, kvp => (IEnumerable<FileFacade>)kvp.Value); 109 this.FileFacadesByCabinetMedia = filesByCabinetMedia.ToDictionary(kvp => kvp.Key, kvp => (IEnumerable<IFileFacade>)kvp.Value);
110 110
111 this.UncompressedFileFacades = uncompressedFiles; 111 this.UncompressedFileFacades = uncompressedFiles;
112 } 112 }
@@ -115,7 +115,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
115 /// <summary> 115 /// <summary>
116 /// Assign files to cabinets based on MediaTemplate authoring. 116 /// Assign files to cabinets based on MediaTemplate authoring.
117 /// </summary> 117 /// </summary>
118 private void AutoAssignFiles(List<MediaSymbol> mediaTable, Dictionary<MediaSymbol, List<FileFacade>> filesByCabinetMedia, List<FileFacade> uncompressedFiles) 118 private void AutoAssignFiles(List<MediaSymbol> mediaTable, Dictionary<MediaSymbol, List<IFileFacade>> filesByCabinetMedia, List<IFileFacade> uncompressedFiles)
119 { 119 {
120 const int MaxCabIndex = 999; 120 const int MaxCabIndex = 999;
121 121
@@ -194,7 +194,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
194 { 194 {
195 currentMediaRow = this.AddMediaSymbol(mediaTemplateRow, ++currentCabIndex); 195 currentMediaRow = this.AddMediaSymbol(mediaTemplateRow, ++currentCabIndex);
196 mediaSymbolsByDiskId.Add(currentMediaRow.DiskId, currentMediaRow); 196 mediaSymbolsByDiskId.Add(currentMediaRow.DiskId, currentMediaRow);
197 filesByCabinetMedia.Add(currentMediaRow, new List<FileFacade>()); 197 filesByCabinetMedia.Add(currentMediaRow, new List<IFileFacade>());
198 198
199 // Now files larger than MaxUncompressedMediaSize will be the only file in its cabinet so as to respect MaxUncompressedMediaSize 199 // Now files larger than MaxUncompressedMediaSize will be the only file in its cabinet so as to respect MaxUncompressedMediaSize
200 currentPreCabSize = (ulong)facade.FileSize; 200 currentPreCabSize = (ulong)facade.FileSize;
@@ -206,7 +206,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
206 // Create new cab and MediaRow 206 // Create new cab and MediaRow
207 currentMediaRow = this.AddMediaSymbol(mediaTemplateRow, ++currentCabIndex); 207 currentMediaRow = this.AddMediaSymbol(mediaTemplateRow, ++currentCabIndex);
208 mediaSymbolsByDiskId.Add(currentMediaRow.DiskId, currentMediaRow); 208 mediaSymbolsByDiskId.Add(currentMediaRow.DiskId, currentMediaRow);
209 filesByCabinetMedia.Add(currentMediaRow, new List<FileFacade>()); 209 filesByCabinetMedia.Add(currentMediaRow, new List<IFileFacade>());
210 } 210 }
211 } 211 }
212 } 212 }
@@ -232,7 +232,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
232 /// <summary> 232 /// <summary>
233 /// Assign files to cabinets based on Media authoring. 233 /// Assign files to cabinets based on Media authoring.
234 /// </summary> 234 /// </summary>
235 private void ManuallyAssignFiles(List<MediaSymbol> mediaSymbols, Dictionary<MediaSymbol, List<FileFacade>> filesByCabinetMedia, List<FileFacade> uncompressedFiles) 235 private void ManuallyAssignFiles(List<MediaSymbol> mediaSymbols, Dictionary<MediaSymbol, List<IFileFacade>> filesByCabinetMedia, List<IFileFacade> uncompressedFiles)
236 { 236 {
237 var mediaSymbolsByDiskId = new Dictionary<int, MediaSymbol>(); 237 var mediaSymbolsByDiskId = new Dictionary<int, MediaSymbol>();
238 238
@@ -254,7 +254,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
254 cabinetMediaSymbols.Add(mediaSymbol.Cabinet, mediaSymbol); 254 cabinetMediaSymbols.Add(mediaSymbol.Cabinet, mediaSymbol);
255 } 255 }
256 256
257 filesByCabinetMedia.Add(mediaSymbol, new List<FileFacade>()); 257 filesByCabinetMedia.Add(mediaSymbol, new List<IFileFacade>());
258 } 258 }
259 259
260 mediaSymbolsByDiskId.Add(mediaSymbol.DiskId, mediaSymbol); 260 mediaSymbolsByDiskId.Add(mediaSymbol.DiskId, mediaSymbol);
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/AttachPatchTransformsCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/AttachPatchTransformsCommand.cs
index 2249faf8..b2052b90 100644
--- a/src/WixToolset.Core.WindowsInstaller/Bind/AttachPatchTransformsCommand.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Bind/AttachPatchTransformsCommand.cs
@@ -55,16 +55,19 @@ namespace WixToolset.Core.WindowsInstaller.Bind
55 55
56 private readonly TableDefinitionCollection tableDefinitions; 56 private readonly TableDefinitionCollection tableDefinitions;
57 57
58 public AttachPatchTransformsCommand(IMessaging messaging, Intermediate intermediate, IEnumerable<PatchTransform> transforms) 58 public AttachPatchTransformsCommand(IMessaging messaging, IBackendHelper backendHelper, Intermediate intermediate, IEnumerable<PatchTransform> transforms)
59 { 59 {
60 this.tableDefinitions = new TableDefinitionCollection(WindowsInstallerTableDefinitions.All); 60 this.tableDefinitions = new TableDefinitionCollection(WindowsInstallerTableDefinitions.All);
61 this.Messaging = messaging; 61 this.Messaging = messaging;
62 this.BackendHelper = backendHelper;
62 this.Intermediate = intermediate; 63 this.Intermediate = intermediate;
63 this.Transforms = transforms; 64 this.Transforms = transforms;
64 } 65 }
65 66
66 private IMessaging Messaging { get; } 67 private IMessaging Messaging { get; }
67 68
69 private IBackendHelper BackendHelper { get; }
70
68 private Intermediate Intermediate { get; } 71 private Intermediate Intermediate { get; }
69 72
70 private IEnumerable<PatchTransform> Transforms { get; } 73 private IEnumerable<PatchTransform> Transforms { get; }
@@ -797,7 +800,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
797 if (!deletedComponent.ContainsKey(componentId)) 800 if (!deletedComponent.ContainsKey(componentId))
798 { 801 {
799 var foundRemoveFileEntry = false; 802 var foundRemoveFileEntry = false;
800 var filename = Common.GetName(row.FieldAsString(2), false, true); 803 var filename = this.BackendHelper.GetMsiFileName(row.FieldAsString(2), false, true);
801 804
802 if (transform.TryGetTable("RemoveFile", out var removeFileTable)) 805 if (transform.TryGetTable("RemoveFile", out var removeFileTable))
803 { 806 {
@@ -813,7 +816,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
813 // Check if there is a RemoveFile entry for this file 816 // Check if there is a RemoveFile entry for this file
814 if (null != removeFileRow[2]) 817 if (null != removeFileRow[2])
815 { 818 {
816 var removeFileName = Common.GetName(removeFileRow.FieldAsString(2), false, true); 819 var removeFileName = this.BackendHelper.GetMsiFileName(removeFileRow.FieldAsString(2), false, true);
817 820
818 // Convert the MSI format for a wildcard string to Regex format. 821 // Convert the MSI format for a wildcard string to Regex format.
819 removeFileName = removeFileName.Replace('.', '|').Replace('?', '.').Replace("*", ".*").Replace("|", "\\."); 822 removeFileName = removeFileName.Replace('.', '|').Replace('?', '.').Replace("*", ".*").Replace("|", "\\.");
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs
index 292f1572..b6244a6e 100644
--- a/src/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs
@@ -6,7 +6,6 @@ namespace WixToolset.Core.WindowsInstaller.Bind
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 WixToolset.Core.Bind;
10 using WixToolset.Data; 9 using WixToolset.Data;
11 using WixToolset.Data.Symbols; 10 using WixToolset.Data.Symbols;
12 using WixToolset.Data.WindowsInstaller; 11 using WixToolset.Data.WindowsInstaller;
@@ -133,7 +132,9 @@ namespace WixToolset.Core.WindowsInstaller.Bind
133 Platform platform; 132 Platform platform;
134 string modularizationSuffix; 133 string modularizationSuffix;
135 { 134 {
136 var command = new BindSummaryInfoCommand(section); 135 var branding = this.ServiceProvider.GetService<IWixBranding>();
136
137 var command = new BindSummaryInfoCommand(section, this.WindowsInstallerBackendHelper, branding);
137 command.Execute(); 138 command.Execute();
138 139
139 compressed = command.Compressed; 140 compressed = command.Compressed;
@@ -151,7 +152,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
151 // Set the ProductCode if it is to be generated. 152 // Set the ProductCode if it is to be generated.
152 if ("ProductCode".Equals(propertyRow.Id.Id, StringComparison.Ordinal) && "*".Equals(propertyRow.Value, StringComparison.Ordinal)) 153 if ("ProductCode".Equals(propertyRow.Id.Id, StringComparison.Ordinal) && "*".Equals(propertyRow.Value, StringComparison.Ordinal))
153 { 154 {
154 propertyRow.Value = Common.GenerateGuid(); 155 propertyRow.Value = this.WindowsInstallerBackendHelper.CreateGuid();
155 156
156#if TODO_PATCHING // Is this still necessary? 157#if TODO_PATCHING // Is this still necessary?
157 158
@@ -235,24 +236,23 @@ namespace WixToolset.Core.WindowsInstaller.Bind
235 236
236 // Extract files that come from binary .wixlibs and WixExtensions (this does not extract files from merge modules). 237 // Extract files that come from binary .wixlibs and WixExtensions (this does not extract files from merge modules).
237 { 238 {
238 var command = new ExtractEmbeddedFilesCommand(this.WindowsInstallerBackendHelper, this.ExpectedEmbeddedFiles); 239 var extractedFiles = this.WindowsInstallerBackendHelper.ExtractEmbeddedFiles(this.ExpectedEmbeddedFiles);
239 command.Execute();
240 240
241 trackedFiles.AddRange(command.TrackedFiles); 241 trackedFiles.AddRange(extractedFiles);
242 } 242 }
243 243
244 // This must occur after all variables and source paths have been resolved. 244 // This must occur after all variables and source paths have been resolved.
245 List<FileFacade> fileFacades; 245 List<IFileFacade> fileFacades;
246 if (SectionType.Patch == section.Type) 246 if (SectionType.Patch == section.Type)
247 { 247 {
248 var command = new GetFileFacadesFromTransforms(this.Messaging, this.FileSystemManager, this.SubStorages); 248 var command = new GetFileFacadesFromTransforms(this.Messaging, this.WindowsInstallerBackendHelper, this.FileSystemManager, this.SubStorages);
249 command.Execute(); 249 command.Execute();
250 250
251 fileFacades = command.FileFacades; 251 fileFacades = command.FileFacades;
252 } 252 }
253 else 253 else
254 { 254 {
255 var command = new GetFileFacadesCommand(section); 255 var command = new GetFileFacadesCommand(section, this.WindowsInstallerBackendHelper);
256 command.Execute(); 256 command.Execute();
257 257
258 fileFacades = command.FileFacades; 258 fileFacades = command.FileFacades;
@@ -267,7 +267,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
267 { 267 {
268 containsMergeModules = true; 268 containsMergeModules = true;
269 269
270 var command = new ExtractMergeModuleFilesCommand(this.Messaging, wixMergeSymbols, fileFacades, installerVersion, this.IntermediateFolder, this.SuppressLayout); 270 var command = new ExtractMergeModuleFilesCommand(this.Messaging, this.WindowsInstallerBackendHelper, wixMergeSymbols, fileFacades, installerVersion, this.IntermediateFolder, this.SuppressLayout);
271 command.Execute(); 271 command.Execute();
272 272
273 fileFacades.AddRange(command.MergeModulesFileFacades); 273 fileFacades.AddRange(command.MergeModulesFileFacades);
@@ -307,8 +307,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
307 // Now that the variable cache is populated, resolve any delayed fields. 307 // Now that the variable cache is populated, resolve any delayed fields.
308 if (this.DelayedFields.Any()) 308 if (this.DelayedFields.Any())
309 { 309 {
310 var command = new ResolveDelayedFieldsCommand(this.Messaging, this.DelayedFields, variableCache); 310 this.WindowsInstallerBackendHelper.ResolveDelayedFields(this.DelayedFields, variableCache);
311 command.Execute();
312 } 311 }
313 312
314 // Update symbols that reference text files on disk. 313 // Update symbols that reference text files on disk.
@@ -330,7 +329,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
330 329
331 if (dependencyRefs.Any()) 330 if (dependencyRefs.Any())
332 { 331 {
333 var command = new ProcessDependencyReferencesCommand(section, dependencyRefs); 332 var command = new ProcessDependencyReferencesCommand(this.WindowsInstallerBackendHelper, section, dependencyRefs);
334 command.Execute(); 333 command.Execute();
335 } 334 }
336 } 335 }
@@ -379,8 +378,8 @@ namespace WixToolset.Core.WindowsInstaller.Bind
379 } 378 }
380 379
381 // Assign files to media and update file sequences. 380 // Assign files to media and update file sequences.
382 Dictionary<MediaSymbol, IEnumerable<FileFacade>> filesByCabinetMedia; 381 Dictionary<MediaSymbol, IEnumerable<IFileFacade>> filesByCabinetMedia;
383 IEnumerable<FileFacade> uncompressedFiles; 382 IEnumerable<IFileFacade> uncompressedFiles;
384 { 383 {
385 var order = new OptimizeFileFacadesOrderCommand(this.WindowsInstallerBackendHelper, this.PathResolver, section, platform, fileFacades); 384 var order = new OptimizeFileFacadesOrderCommand(this.WindowsInstallerBackendHelper, this.PathResolver, section, platform, fileFacades);
386 order.Execute(); 385 order.Execute();
@@ -414,7 +413,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
414 if (data.Type == OutputType.Module) 413 if (data.Type == OutputType.Module)
415 { 414 {
416 // Modularize identifiers. 415 // Modularize identifiers.
417 var modularize = new ModularizeCommand(data, modularizationSuffix, section.Symbols.OfType<WixSuppressModularizationSymbol>()); 416 var modularize = new ModularizeCommand(this.WindowsInstallerBackendHelper, data, modularizationSuffix, section.Symbols.OfType<WixSuppressModularizationSymbol>());
418 modularize.Execute(); 417 modularize.Execute();
419 418
420 // Ensure all sequence tables in place because, mergemod.dll requires them. 419 // Ensure all sequence tables in place because, mergemod.dll requires them.
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/BindSummaryInfoCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/BindSummaryInfoCommand.cs
index a496c7ce..babe0c1b 100644
--- a/src/WixToolset.Core.WindowsInstaller/Bind/BindSummaryInfoCommand.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Bind/BindSummaryInfoCommand.cs
@@ -7,19 +7,26 @@ namespace WixToolset.Core.WindowsInstaller.Bind
7 using System.Linq; 7 using System.Linq;
8 using WixToolset.Data; 8 using WixToolset.Data;
9 using WixToolset.Data.Symbols; 9 using WixToolset.Data.Symbols;
10 using WixToolset.Extensibility.Services;
10 11
11 /// <summary> 12 /// <summary>
12 /// Binds the summary information table of a database. 13 /// Binds the summary information table of a database.
13 /// </summary> 14 /// </summary>
14 internal class BindSummaryInfoCommand 15 internal class BindSummaryInfoCommand
15 { 16 {
16 public BindSummaryInfoCommand(IntermediateSection section) 17 public BindSummaryInfoCommand(IntermediateSection section, IBackendHelper backendHelper, IWixBranding branding)
17 { 18 {
18 this.Section = section; 19 this.Section = section;
20 this.BackendHelper = backendHelper;
21 this.Branding = branding;
19 } 22 }
20 23
21 private IntermediateSection Section { get; } 24 private IntermediateSection Section { get; }
22 25
26 private IBackendHelper BackendHelper { get; }
27
28 private IWixBranding Branding { get; }
29
23 /// <summary> 30 /// <summary>
24 /// Returns a flag indicating if files are compressed by default. 31 /// Returns a flag indicating if files are compressed by default.
25 /// </summary> 32 /// </summary>
@@ -66,7 +73,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
66 } 73 }
67 else 74 else
68 { 75 {
69 summaryInformationSymbol.Value = Common.GetValidCodePage(codepage, false, false, summaryInformationSymbol.SourceLineNumbers).ToString(CultureInfo.InvariantCulture); 76 summaryInformationSymbol.Value = this.BackendHelper.GetValidCodePage(codepage, false, false, summaryInformationSymbol.SourceLineNumbers).ToString(CultureInfo.InvariantCulture);
70 } 77 }
71 break; 78 break;
72 case SummaryInformationType.PlatformAndLanguage: 79 case SummaryInformationType.PlatformAndLanguage:
@@ -116,7 +123,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
116 this.Section.AddSymbol(new SummaryInformationSymbol(null) 123 this.Section.AddSymbol(new SummaryInformationSymbol(null)
117 { 124 {
118 PropertyId = SummaryInformationType.PackageCode, 125 PropertyId = SummaryInformationType.PackageCode,
119 Value = Common.GenerateGuid(), 126 Value = this.BackendHelper.CreateGuid(),
120 }); 127 });
121 } 128 }
122 129
@@ -146,7 +153,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
146 this.Section.AddSymbol(new SummaryInformationSymbol(null) 153 this.Section.AddSymbol(new SummaryInformationSymbol(null)
147 { 154 {
148 PropertyId = SummaryInformationType.CreatingApplication, 155 PropertyId = SummaryInformationType.CreatingApplication,
149 Value = String.Format(CultureInfo.InvariantCulture, AppCommon.GetCreatingApplicationString()), 156 Value = this.Branding.GetCreatingApplication(),
150 }); 157 });
151 } 158 }
152 } 159 }
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/BindTransformCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/BindTransformCommand.cs
index bc5c6853..28e1d9ee 100644
--- a/src/WixToolset.Core.WindowsInstaller/Bind/BindTransformCommand.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Bind/BindTransformCommand.cs
@@ -99,7 +99,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
99 } 99 }
100 else 100 else
101 { 101 {
102 codePage = Common.GetValidCodePage(codePage).ToString(CultureInfo.InvariantCulture); 102 codePage = this.BackendHelper.GetValidCodePage(codePage).ToString(CultureInfo.InvariantCulture);
103 } 103 }
104 104
105 var previousCodePage = row.Fields[1].PreviousData; 105 var previousCodePage = row.Fields[1].PreviousData;
@@ -109,7 +109,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
109 } 109 }
110 else 110 else
111 { 111 {
112 previousCodePage = Common.GetValidCodePage(previousCodePage).ToString(CultureInfo.InvariantCulture); 112 previousCodePage = this.BackendHelper.GetValidCodePage(previousCodePage).ToString(CultureInfo.InvariantCulture);
113 } 113 }
114 114
115 var targetCodePageRow = targetSummaryInfo.CreateRow(null); 115 var targetCodePageRow = targetSummaryInfo.CreateRow(null);
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/CabinetResolver.cs b/src/WixToolset.Core.WindowsInstaller/Bind/CabinetResolver.cs
index 6dbcb1a1..e47e5b64 100644
--- a/src/WixToolset.Core.WindowsInstaller/Bind/CabinetResolver.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Bind/CabinetResolver.cs
@@ -6,7 +6,6 @@ namespace WixToolset.Core.WindowsInstaller.Bind
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 WixToolset.Core.Bind;
10 using WixToolset.Core.Native; 9 using WixToolset.Core.Native;
11 using WixToolset.Data; 10 using WixToolset.Data;
12 using WixToolset.Extensibility; 11 using WixToolset.Extensibility;
@@ -30,7 +29,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
30 29
31 private IEnumerable<IWindowsInstallerBackendBinderExtension> BackendExtensions { get; } 30 private IEnumerable<IWindowsInstallerBackendBinderExtension> BackendExtensions { get; }
32 31
33 public IResolvedCabinet ResolveCabinet(string cabinetPath, IEnumerable<FileFacade> fileFacades) 32 public IResolvedCabinet ResolveCabinet(string cabinetPath, IEnumerable<IFileFacade> fileFacades)
34 { 33 {
35 var filesWithPath = fileFacades.Select(this.CreateBindFileWithPath).ToList(); 34 var filesWithPath = fileFacades.Select(this.CreateBindFileWithPath).ToList();
36 35
@@ -109,7 +108,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
109 return resolved; 108 return resolved;
110 } 109 }
111 110
112 private IBindFileWithPath CreateBindFileWithPath(FileFacade facade) 111 private IBindFileWithPath CreateBindFileWithPath(IFileFacade facade)
113 { 112 {
114 var result = this.ServiceProvider.GetService<IBindFileWithPath>(); 113 var result = this.ServiceProvider.GetService<IBindFileWithPath>();
115 result.Id = facade.Id; 114 result.Id = facade.Id;
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/CabinetWorkItem.cs b/src/WixToolset.Core.WindowsInstaller/Bind/CabinetWorkItem.cs
index 48f0574e..1990ea78 100644
--- a/src/WixToolset.Core.WindowsInstaller/Bind/CabinetWorkItem.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Bind/CabinetWorkItem.cs
@@ -3,8 +3,8 @@
3namespace WixToolset.Core.WindowsInstaller.Bind 3namespace WixToolset.Core.WindowsInstaller.Bind
4{ 4{
5 using System.Collections.Generic; 5 using System.Collections.Generic;
6 using WixToolset.Core.Bind;
7 using WixToolset.Data; 6 using WixToolset.Data;
7 using WixToolset.Extensibility.Data;
8 8
9 /// <summary> 9 /// <summary>
10 /// A cabinet builder work item. 10 /// A cabinet builder work item.
@@ -20,7 +20,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
20 /// <param name="compressionLevel">The compression level of the cabinet.</param> 20 /// <param name="compressionLevel">The compression level of the cabinet.</param>
21 /// <param name="modularizationSuffix">Modularization suffix used when building a Merge Module.</param> 21 /// <param name="modularizationSuffix">Modularization suffix used when building a Merge Module.</param>
22 /// <!--<param name="binderFileManager">The binder file manager.</param>--> 22 /// <!--<param name="binderFileManager">The binder file manager.</param>-->
23 public CabinetWorkItem(IEnumerable<FileFacade> fileFacades, string cabinetFile, int maxThreshold, CompressionLevel compressionLevel, string modularizationSuffix /*, BinderFileManager binderFileManager*/) 23 public CabinetWorkItem(IEnumerable<IFileFacade> fileFacades, string cabinetFile, int maxThreshold, CompressionLevel compressionLevel, string modularizationSuffix /*, BinderFileManager binderFileManager*/)
24 { 24 {
25 this.CabinetFile = cabinetFile; 25 this.CabinetFile = cabinetFile;
26 this.CompressionLevel = compressionLevel; 26 this.CompressionLevel = compressionLevel;
@@ -51,7 +51,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
51 /// Gets the collection of files in this cabinet. 51 /// Gets the collection of files in this cabinet.
52 /// </summary> 52 /// </summary>
53 /// <value>The collection of files in this cabinet.</value> 53 /// <value>The collection of files in this cabinet.</value>
54 public IEnumerable<FileFacade> FileFacades { get; } 54 public IEnumerable<IFileFacade> FileFacades { get; }
55 55
56 // <summary> 56 // <summary>
57 // Gets the binder file manager. 57 // Gets the binder file manager.
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/CalculateComponentGuids.cs b/src/WixToolset.Core.WindowsInstaller/Bind/CalculateComponentGuids.cs
index 55cda9ea..5cb297e5 100644
--- a/src/WixToolset.Core.WindowsInstaller/Bind/CalculateComponentGuids.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Bind/CalculateComponentGuids.cs
@@ -138,8 +138,8 @@ namespace WixToolset.Core.WindowsInstaller.Bind
138 if (fileRow.Id.Id == componentSymbol.KeyPath) 138 if (fileRow.Id.Id == componentSymbol.KeyPath)
139 { 139 {
140 // calculate the key file's canonical target path 140 // calculate the key file's canonical target path
141 string directoryPath = this.PathResolver.GetCanonicalDirectoryPath(targetPathsByDirectoryId, componentIdGenSeeds, componentSymbol.DirectoryRef, this.Platform); 141 var directoryPath = this.PathResolver.GetCanonicalDirectoryPath(targetPathsByDirectoryId, componentIdGenSeeds, componentSymbol.DirectoryRef, this.Platform);
142 string fileName = Common.GetName(fileRow.Name, false, true).ToLowerInvariant(); 142 var fileName = this.BackendHelper.GetMsiFileName(fileRow.Name, false, true).ToLowerInvariant();
143 path = Path.Combine(directoryPath, fileName); 143 path = Path.Combine(directoryPath, fileName);
144 144
145 // find paths that are not canonicalized 145 // find paths that are not canonicalized
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/CopyTransformDataCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/CopyTransformDataCommand.cs
deleted file mode 100644
index 8a85a975..00000000
--- a/src/WixToolset.Core.WindowsInstaller/Bind/CopyTransformDataCommand.cs
+++ /dev/null
@@ -1,630 +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#if DELETE
4
5namespace WixToolset.Core.WindowsInstaller.Bind
6{
7 using System;
8 using System.Collections.Generic;
9 using System.Diagnostics;
10 using System.IO;
11 using System.Linq;
12 using WixToolset.Core.Bind;
13 using WixToolset.Data;
14 using WixToolset.Data.Symbols;
15 using WixToolset.Data.WindowsInstaller;
16 using WixToolset.Data.WindowsInstaller.Rows;
17 using WixToolset.Extensibility;
18 using WixToolset.Extensibility.Services;
19
20 internal class CopyTransformDataCommand
21 {
22 public CopyTransformDataCommand(IMessaging messaging, WindowsInstallerData output, TableDefinitionCollection tableDefinitions, bool copyOutFileRows)
23 {
24 this.Messaging = messaging;
25 this.Output = output;
26 this.TableDefinitions = tableDefinitions;
27 this.CopyOutFileRows = copyOutFileRows;
28 }
29
30 private bool CopyOutFileRows { get; }
31
32 public IEnumerable<IFileSystemExtension> Extensions { get; }
33
34 private IMessaging Messaging { get; }
35
36 private WindowsInstallerData Output { get; }
37
38 private TableDefinitionCollection TableDefinitions { get; }
39
40 public IEnumerable<FileFacade> FileFacades { get; private set; }
41
42 public void Execute()
43 {
44 Debug.Assert(OutputType.Patch != this.Output.Type);
45
46 var allFileRows = this.CopyOutFileRows ? new List<FileFacade>() : null;
47
48 var copyToPatch = (allFileRows != null);
49 var copyFromPatch = !copyToPatch;
50
51 var patchMediaRows = new RowDictionary<MediaRow>();
52
53 var patchMediaFileRows = new Dictionary<int, RowDictionary<WixFileRow>>();
54
55 var patchActualFileTable = this.Output.EnsureTable(this.TableDefinitions["File"]);
56 var patchFileTable = this.Output.EnsureTable(this.TableDefinitions["WixFile"]);
57
58 if (copyFromPatch)
59 {
60 // index patch files by diskId+fileId
61 foreach (WixFileRow patchFileRow in patchFileTable.Rows)
62 {
63 int diskId = patchFileRow.DiskId;
64 if (!patchMediaFileRows.TryGetValue(diskId, out var mediaFileRows))
65 {
66 mediaFileRows = new RowDictionary<WixFileRow>();
67 patchMediaFileRows.Add(diskId, mediaFileRows);
68 }
69
70 mediaFileRows.Add(patchFileRow);
71 }
72
73 var patchMediaTable = this.Output.EnsureTable(this.TableDefinitions["Media"]);
74 patchMediaRows = new RowDictionary<MediaRow>(patchMediaTable);
75 }
76
77 // Index paired transforms by name without the "#" prefix.
78 var pairedTransforms = this.Output.SubStorages.Where(s => s.Name.StartsWith("#")).ToDictionary(s => s.Name.Substring(1), s => s.Data);
79 //Dictionary<string, Output> pairedTransforms = new Dictionary<string, Output>();
80 //foreach (SubStorage substorage in this.Output.SubStorages)
81 //{
82 // if (substorage.Name.StartsWith("#"))
83 // {
84 // pairedTransforms.Add(substorage.Name.Substring(1), substorage.Data);
85 // }
86 //}
87
88 try
89 {
90 // Copy File bind data into substorages
91 foreach (var substorage in this.Output.SubStorages)
92 {
93 if (substorage.Name.StartsWith("#"))
94 {
95 // no changes necessary for paired transforms
96 continue;
97 }
98
99 var mainTransform = substorage.Data;
100 var mainWixFileTable = mainTransform.Tables["WixFile"];
101 var mainMsiFileHashTable = mainTransform.Tables["MsiFileHash"];
102
103 this.FileManagerCore.ActiveSubStorage = substorage;
104
105 var mainWixFiles = new RowDictionary<WixFileRow>(mainWixFileTable);
106 var mainMsiFileHashIndex = new RowDictionary<Row>();
107
108 var mainFileTable = mainTransform.Tables["File"];
109 var pairedTransform = pairedTransforms[substorage.Name];
110
111 // copy Media.LastSequence and index the MsiFileHash table if it exists.
112 if (copyFromPatch)
113 {
114 var pairedMediaTable = pairedTransform.Tables["Media"];
115 foreach (MediaRow pairedMediaRow in pairedMediaTable.Rows)
116 {
117 var patchMediaRow = patchMediaRows.Get(pairedMediaRow.DiskId);
118 pairedMediaRow.Fields[1] = patchMediaRow.Fields[1];
119 }
120
121 if (null != mainMsiFileHashTable)
122 {
123 mainMsiFileHashIndex = new RowDictionary<Row>(mainMsiFileHashTable);
124 }
125
126 // Validate file row changes for keypath-related issues
127 this.ValidateFileRowChanges(mainTransform);
128 }
129
130 // Index File table of pairedTransform
131 var pairedFileTable = pairedTransform.Tables["File"];
132 var pairedFileRows = new RowDictionary<FileRow>(pairedFileTable);
133
134 if (null != mainFileTable)
135 {
136 if (copyFromPatch)
137 {
138 // Remove the MsiFileHash table because it will be updated later with the final file hash for each file
139 mainTransform.Tables.Remove("MsiFileHash");
140 }
141
142 foreach (FileRow mainFileRow in mainFileTable.Rows)
143 {
144 if (RowOperation.Delete == mainFileRow.Operation)
145 {
146 continue;
147 }
148 else if (RowOperation.None == mainFileRow.Operation && !copyToPatch)
149 {
150 continue;
151 }
152
153 var mainWixFileRow = mainWixFiles.Get(mainFileRow.File);
154
155 if (copyToPatch) // when copying to the patch, we need compare the underlying files and include all file changes.
156 {
157 var objectField = (ObjectField)mainWixFileRow.Fields[6];
158 var pairedFileRow = pairedFileRows.Get(mainFileRow.File);
159
160 // If the file is new, we always need to add it to the patch.
161 if (mainFileRow.Operation != RowOperation.Add)
162 {
163 // If PreviousData doesn't exist, target and upgrade layout point to the same location. No need to compare.
164 if (null == objectField.PreviousData)
165 {
166 if (mainFileRow.Operation == RowOperation.None)
167 {
168 continue;
169 }
170 }
171 else
172 {
173 // TODO: should this entire condition be placed in the binder file manager?
174 if ((0 == (PatchAttributeType.Ignore & mainWixFileRow.PatchAttributes)) &&
175 !this.CompareFiles(objectField.PreviousData.ToString(), objectField.Data.ToString()))
176 {
177 // If the file is different, we need to mark the mainFileRow and pairedFileRow as modified.
178 mainFileRow.Operation = RowOperation.Modify;
179 if (null != pairedFileRow)
180 {
181 // Always patch-added, but never non-compressed.
182 pairedFileRow.Attributes |= WindowsInstallerConstants.MsidbFileAttributesPatchAdded;
183 pairedFileRow.Attributes &= ~WindowsInstallerConstants.MsidbFileAttributesNoncompressed;
184 pairedFileRow.Fields[6].Modified = true;
185 pairedFileRow.Operation = RowOperation.Modify;
186 }
187 }
188 else
189 {
190 // The File is same. We need mark all the attributes as unchanged.
191 mainFileRow.Operation = RowOperation.None;
192 foreach (var field in mainFileRow.Fields)
193 {
194 field.Modified = false;
195 }
196
197 if (null != pairedFileRow)
198 {
199 pairedFileRow.Attributes &= ~WindowsInstallerConstants.MsidbFileAttributesPatchAdded;
200 pairedFileRow.Fields[6].Modified = false;
201 pairedFileRow.Operation = RowOperation.None;
202 }
203 continue;
204 }
205 }
206 }
207 else if (null != pairedFileRow) // RowOperation.Add
208 {
209 // Always patch-added, but never non-compressed.
210 pairedFileRow.Attributes |= WindowsInstallerConstants.MsidbFileAttributesPatchAdded;
211 pairedFileRow.Attributes &= ~WindowsInstallerConstants.MsidbFileAttributesNoncompressed;
212 pairedFileRow.Fields[6].Modified = true;
213 pairedFileRow.Operation = RowOperation.Add;
214 }
215 }
216
217 // index patch files by diskId+fileId
218 int diskId = mainWixFileRow.DiskId;
219
220 if (!patchMediaFileRows.TryGetValue(diskId, out var mediaFileRows))
221 {
222 mediaFileRows = new RowDictionary<WixFileRow>();
223 patchMediaFileRows.Add(diskId, mediaFileRows);
224 }
225
226 var fileId = mainFileRow.File;
227 var patchFileRow = mediaFileRows.Get(fileId);
228 if (copyToPatch)
229 {
230 if (null == patchFileRow)
231 {
232 var patchActualFileRow = (FileRow)patchFileTable.CreateRow(mainFileRow.SourceLineNumbers);
233 patchActualFileRow.CopyFrom(mainFileRow);
234
235 patchFileRow = (WixFileRow)patchFileTable.CreateRow(mainFileRow.SourceLineNumbers);
236 patchFileRow.CopyFrom(mainWixFileRow);
237
238 mediaFileRows.Add(patchFileRow);
239
240 allFileRows.Add(new FileFacade(patchActualFileRow, patchFileRow, null)); // TODO: should we be passing along delta information? Probably, right?
241 }
242 else
243 {
244 // TODO: confirm the rest of data is identical?
245
246 // make sure Source is same. Otherwise we are silently ignoring a file.
247 if (0 != String.Compare(patchFileRow.Source, mainWixFileRow.Source, StringComparison.OrdinalIgnoreCase))
248 {
249 this.Messaging.Write(ErrorMessages.SameFileIdDifferentSource(mainFileRow.SourceLineNumbers, fileId, patchFileRow.Source, mainWixFileRow.Source));
250 }
251
252 // capture the previous file versions (and associated data) from this targeted instance of the baseline into the current filerow.
253 patchFileRow.AppendPreviousDataFrom(mainWixFileRow);
254 }
255 }
256 else
257 {
258 // copy data from the patch back to the transform
259 if (null != patchFileRow)
260 {
261 var pairedFileRow = pairedFileRows.Get(fileId);
262 for (var i = 0; i < patchFileRow.Fields.Length; i++)
263 {
264 var patchValue = patchFileRow[i] == null ? String.Empty : patchFileRow.FieldAsString(i);
265 var mainValue = mainFileRow[i] == null ? String.Empty : mainFileRow.FieldAsString(i);
266
267 if (1 == i)
268 {
269 // File.Component_ changes should not come from the shared file rows
270 // that contain the file information as each individual transform might
271 // have different changes (or no changes at all).
272 }
273 // File.Attributes should not changed for binary deltas
274 else if (6 == i)
275 {
276 if (null != patchFileRow.Patch)
277 {
278 // File.Attribute should not change for binary deltas
279 pairedFileRow.Attributes = mainFileRow.Attributes;
280 mainFileRow.Fields[i].Modified = false;
281 }
282 }
283 // File.Sequence is updated in pairedTransform, not mainTransform
284 else if (7 == i)
285 {
286 // file sequence is updated in Patch table instead of File table for delta patches
287 if (null != patchFileRow.Patch)
288 {
289 pairedFileRow.Fields[i].Modified = false;
290 }
291 else
292 {
293 pairedFileRow[i] = patchFileRow[i];
294 pairedFileRow.Fields[i].Modified = true;
295 }
296 mainFileRow.Fields[i].Modified = false;
297 }
298 else if (patchValue != mainValue)
299 {
300 mainFileRow[i] = patchFileRow[i];
301 mainFileRow.Fields[i].Modified = true;
302 if (mainFileRow.Operation == RowOperation.None)
303 {
304 mainFileRow.Operation = RowOperation.Modify;
305 }
306 }
307 }
308
309 // copy MsiFileHash row for this File
310 if (!mainMsiFileHashIndex.TryGetValue(patchFileRow.File, out var patchHashRow))
311 {
312 patchHashRow = patchFileRow.Hash;
313 }
314
315 if (null != patchHashRow)
316 {
317 var mainHashTable = mainTransform.EnsureTable(this.TableDefinitions["MsiFileHash"]);
318 var mainHashRow = mainHashTable.CreateRow(mainFileRow.SourceLineNumbers);
319 for (var i = 0; i < patchHashRow.Fields.Length; i++)
320 {
321 mainHashRow[i] = patchHashRow[i];
322 if (i > 1)
323 {
324 // assume all hash fields have been modified
325 mainHashRow.Fields[i].Modified = true;
326 }
327 }
328
329 // assume the MsiFileHash operation follows the File one
330 mainHashRow.Operation = mainFileRow.Operation;
331 }
332
333 // copy MsiAssemblyName rows for this File
334 List<Row> patchAssemblyNameRows = patchFileRow.AssemblyNames;
335 if (null != patchAssemblyNameRows)
336 {
337 var mainAssemblyNameTable = mainTransform.EnsureTable(this.TableDefinitions["MsiAssemblyName"]);
338 foreach (var patchAssemblyNameRow in patchAssemblyNameRows)
339 {
340 // Copy if there isn't an identical modified/added row already in the transform.
341 var foundMatchingModifiedRow = false;
342 foreach (var mainAssemblyNameRow in mainAssemblyNameTable.Rows)
343 {
344 if (RowOperation.None != mainAssemblyNameRow.Operation && mainAssemblyNameRow.GetPrimaryKey('/').Equals(patchAssemblyNameRow.GetPrimaryKey('/')))
345 {
346 foundMatchingModifiedRow = true;
347 break;
348 }
349 }
350
351 if (!foundMatchingModifiedRow)
352 {
353 var mainAssemblyNameRow = mainAssemblyNameTable.CreateRow(mainFileRow.SourceLineNumbers);
354 for (var i = 0; i < patchAssemblyNameRow.Fields.Length; i++)
355 {
356 mainAssemblyNameRow[i] = patchAssemblyNameRow[i];
357 }
358
359 // assume value field has been modified
360 mainAssemblyNameRow.Fields[2].Modified = true;
361 mainAssemblyNameRow.Operation = mainFileRow.Operation;
362 }
363 }
364 }
365
366 // Add patch header for this file
367 if (null != patchFileRow.Patch)
368 {
369 // Add the PatchFiles action automatically to the AdminExecuteSequence and InstallExecuteSequence tables.
370 this.AddPatchFilesActionToSequenceTable(SequenceTable.AdminExecuteSequence, mainTransform, pairedTransform, mainFileRow);
371 this.AddPatchFilesActionToSequenceTable(SequenceTable.InstallExecuteSequence, mainTransform, pairedTransform, mainFileRow);
372
373 // Add to Patch table
374 var patchTable = pairedTransform.EnsureTable(this.TableDefinitions["Patch"]);
375 if (0 == patchTable.Rows.Count)
376 {
377 patchTable.Operation = TableOperation.Add;
378 }
379
380 var patchRow = patchTable.CreateRow(mainFileRow.SourceLineNumbers);
381 patchRow[0] = patchFileRow.File;
382 patchRow[1] = patchFileRow.Sequence;
383
384 var patchFile = new FileInfo(patchFileRow.Source);
385 patchRow[2] = (int)patchFile.Length;
386 patchRow[3] = 0 == (PatchAttributeType.AllowIgnoreOnError & patchFileRow.PatchAttributes) ? 0 : 1;
387
388 var streamName = patchTable.Name + "." + patchRow[0] + "." + patchRow[1];
389 if (Msi.MsiInterop.MsiMaxStreamNameLength < streamName.Length)
390 {
391 streamName = "_" + Guid.NewGuid().ToString("D").ToUpperInvariant().Replace('-', '_');
392
393 var patchHeadersTable = pairedTransform.EnsureTable(this.TableDefinitions["MsiPatchHeaders"]);
394 if (0 == patchHeadersTable.Rows.Count)
395 {
396 patchHeadersTable.Operation = TableOperation.Add;
397 }
398
399 var patchHeadersRow = patchHeadersTable.CreateRow(mainFileRow.SourceLineNumbers);
400 patchHeadersRow[0] = streamName;
401 patchHeadersRow[1] = patchFileRow.Patch;
402 patchRow[5] = streamName;
403 patchHeadersRow.Operation = RowOperation.Add;
404 }
405 else
406 {
407 patchRow[4] = patchFileRow.Patch;
408 }
409 patchRow.Operation = RowOperation.Add;
410 }
411 }
412 else
413 {
414 // TODO: throw because all transform rows should have made it into the patch
415 }
416 }
417 }
418 }
419
420 if (copyFromPatch)
421 {
422 this.Output.Tables.Remove("Media");
423 this.Output.Tables.Remove("File");
424 this.Output.Tables.Remove("MsiFileHash");
425 this.Output.Tables.Remove("MsiAssemblyName");
426 }
427 }
428 }
429 finally
430 {
431 this.FileManagerCore.ActiveSubStorage = null;
432 }
433
434 this.FileFacades = allFileRows;
435 }
436
437 /// <summary>
438 /// Adds the PatchFiles action to the sequence table if it does not already exist.
439 /// </summary>
440 /// <param name="table">The sequence table to check or modify.</param>
441 /// <param name="mainTransform">The primary authoring transform.</param>
442 /// <param name="pairedTransform">The secondary patch transform.</param>
443 /// <param name="mainFileRow">The file row that contains information about the patched file.</param>
444 private void AddPatchFilesActionToSequenceTable(SequenceTable table, WindowsInstallerData mainTransform, WindowsInstallerData pairedTransform, Row mainFileRow)
445 {
446 var tableName = table.ToString();
447
448 // Find/add PatchFiles action (also determine sequence for it).
449 // Search mainTransform first, then pairedTransform (pairedTransform overrides).
450 var hasPatchFilesAction = false;
451 var installFilesSequence = 0;
452 var duplicateFilesSequence = 0;
453
454 TestSequenceTableForPatchFilesAction(
455 mainTransform.Tables[tableName],
456 ref hasPatchFilesAction,
457 ref installFilesSequence,
458 ref duplicateFilesSequence);
459 TestSequenceTableForPatchFilesAction(
460 pairedTransform.Tables[tableName],
461 ref hasPatchFilesAction,
462 ref installFilesSequence,
463 ref duplicateFilesSequence);
464 if (!hasPatchFilesAction)
465 {
466 WindowsInstallerStandard.TryGetStandardAction(tableName, "PatchFiles", out var patchFilesActionSymbol);
467
468 var sequence = patchFilesActionSymbol.Sequence;
469
470 // Test for default sequence value's appropriateness
471 if (installFilesSequence >= sequence || (0 != duplicateFilesSequence && duplicateFilesSequence <= sequence))
472 {
473 if (0 != duplicateFilesSequence)
474 {
475 if (duplicateFilesSequence < installFilesSequence)
476 {
477 throw new WixException(ErrorMessages.InsertInvalidSequenceActionOrder(mainFileRow.SourceLineNumbers, tableName, "InstallFiles", "DuplicateFiles", patchFilesActionSymbol.Action));
478 }
479 else
480 {
481 sequence = (duplicateFilesSequence + installFilesSequence) / 2;
482 if (installFilesSequence == sequence || duplicateFilesSequence == sequence)
483 {
484 throw new WixException(ErrorMessages.InsertSequenceNoSpace(mainFileRow.SourceLineNumbers, tableName, "InstallFiles", "DuplicateFiles", patchFilesActionSymbol.Action));
485 }
486 }
487 }
488 else
489 {
490 sequence = installFilesSequence + 1;
491 }
492 }
493
494 var sequenceTable = pairedTransform.EnsureTable(this.TableDefinitions[tableName]);
495 if (0 == sequenceTable.Rows.Count)
496 {
497 sequenceTable.Operation = TableOperation.Add;
498 }
499
500 var patchAction = sequenceTable.CreateRow(null);
501 patchAction[0] = patchFilesActionSymbol.Action;
502 patchAction[1] = patchFilesActionSymbol.Condition;
503 patchAction[2] = sequence;
504 patchAction.Operation = RowOperation.Add;
505 }
506 }
507
508 /// <summary>
509 /// Tests sequence table for PatchFiles and associated actions
510 /// </summary>
511 /// <param name="sequenceTable">The table to test.</param>
512 /// <param name="hasPatchFilesAction">Set to true if PatchFiles action is found. Left unchanged otherwise.</param>
513 /// <param name="installFilesSequence">Set to sequence value of InstallFiles action if found. Left unchanged otherwise.</param>
514 /// <param name="duplicateFilesSequence">Set to sequence value of DuplicateFiles action if found. Left unchanged otherwise.</param>
515 private static void TestSequenceTableForPatchFilesAction(Table sequenceTable, ref bool hasPatchFilesAction, ref int installFilesSequence, ref int duplicateFilesSequence)
516 {
517 if (null != sequenceTable)
518 {
519 foreach (var row in sequenceTable.Rows)
520 {
521 var actionName = row.FieldAsString(0);
522 switch (actionName)
523 {
524 case "PatchFiles":
525 hasPatchFilesAction = true;
526 break;
527
528 case "InstallFiles":
529 installFilesSequence = row.FieldAsInteger(2);
530 break;
531
532 case "DuplicateFiles":
533 duplicateFilesSequence = row.FieldAsInteger(2);
534 break;
535 }
536 }
537 }
538 }
539
540 /// <summary>
541 /// Signal a warning if a non-keypath file was changed in a patch without also changing the keypath file of the component.
542 /// </summary>
543 /// <param name="output">The output to validate.</param>
544 private void ValidateFileRowChanges(WindowsInstallerData transform)
545 {
546 var componentTable = transform.Tables["Component"];
547 var fileTable = transform.Tables["File"];
548
549 // There's no sense validating keypaths if the transform has no component or file table
550 if (componentTable == null || fileTable == null)
551 {
552 return;
553 }
554
555 var componentKeyPath = new Dictionary<string, string>(componentTable.Rows.Count);
556
557 // Index the Component table for non-directory & non-registry key paths.
558 foreach (var row in componentTable.Rows)
559 {
560 var keyPath = row.FieldAsString(5);
561 if (keyPath != null && 0 != (row.FieldAsInteger(3) & WindowsInstallerConstants.MsidbComponentAttributesRegistryKeyPath))
562 {
563 componentKeyPath.Add(row.FieldAsString(0), keyPath);
564 }
565 }
566
567 var componentWithChangedKeyPath = new Dictionary<string, string>();
568 var componentWithNonKeyPathChanged = new Dictionary<string, string>();
569 // Verify changes in the file table, now that file diffing has occurred
570 foreach (FileRow row in fileTable.Rows)
571 {
572 if (RowOperation.Modify != row.Operation)
573 {
574 continue;
575 }
576
577 var fileId = row.FieldAsString(0);
578 var componentId = row.FieldAsString(1);
579
580 // If this file is the keypath of a component
581 if (componentKeyPath.ContainsValue(fileId))
582 {
583 if (!componentWithChangedKeyPath.ContainsKey(componentId))
584 {
585 componentWithChangedKeyPath.Add(componentId, fileId);
586 }
587 }
588 else
589 {
590 if (!componentWithNonKeyPathChanged.ContainsKey(componentId))
591 {
592 componentWithNonKeyPathChanged.Add(componentId, fileId);
593 }
594 }
595 }
596
597 foreach (var componentFile in componentWithNonKeyPathChanged)
598 {
599 // Make sure all changes to non keypath files also had a change in the keypath.
600 if (!componentWithChangedKeyPath.ContainsKey(componentFile.Key) && componentKeyPath.TryGetValue(componentFile.Key, out var keyPath))
601 {
602 this.Messaging.Write(WarningMessages.UpdateOfNonKeyPathFile(componentFile.Value, componentFile.Key, keyPath));
603 }
604 }
605 }
606
607 private bool CompareFiles(string targetFile, string updatedFile)
608 {
609 bool? compared = null;
610 foreach (var extension in this.Extensions)
611 {
612 compared = extension.CompareFiles(targetFile, updatedFile);
613
614 if (compared.HasValue)
615 {
616 break;
617 }
618 }
619
620 if (!compared.HasValue)
621 {
622 throw new InvalidOperationException(); // TODO: something needs to be said here that none of the binder file managers returned a result.
623 }
624
625 return compared.Value;
626 }
627 }
628}
629
630#endif
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/CreateCabinetsCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/CreateCabinetsCommand.cs
index 9f94b2c7..0a543650 100644
--- a/src/WixToolset.Core.WindowsInstaller/Bind/CreateCabinetsCommand.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Bind/CreateCabinetsCommand.cs
@@ -80,7 +80,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
80 80
81 public string ModularizationSuffix { private get; set; } 81 public string ModularizationSuffix { private get; set; }
82 82
83 public Dictionary<MediaSymbol, IEnumerable<FileFacade>> FileFacadesByCabinet { private get; set; } 83 public Dictionary<MediaSymbol, IEnumerable<IFileFacade>> FileFacadesByCabinet { private get; set; }
84 84
85 public Func<MediaSymbol, string, string, string> ResolveMedia { private get; set; } 85 public Func<MediaSymbol, string, string, string> ResolveMedia { private get; set; }
86 86
@@ -177,7 +177,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
177 /// <param name="compressionLevel">Desired compression level.</param> 177 /// <param name="compressionLevel">Desired compression level.</param>
178 /// <param name="fileFacades">Collection of files in this cabinet.</param> 178 /// <param name="fileFacades">Collection of files in this cabinet.</param>
179 /// <returns>created CabinetWorkItem object</returns> 179 /// <returns>created CabinetWorkItem object</returns>
180 private CabinetWorkItem CreateCabinetWorkItem(WindowsInstallerData data, string cabinetDir, MediaSymbol mediaSymbol, CompressionLevel compressionLevel, IEnumerable<FileFacade> fileFacades) 180 private CabinetWorkItem CreateCabinetWorkItem(WindowsInstallerData data, string cabinetDir, MediaSymbol mediaSymbol, CompressionLevel compressionLevel, IEnumerable<IFileFacade> fileFacades)
181 { 181 {
182 CabinetWorkItem cabinetWorkItem = null; 182 CabinetWorkItem cabinetWorkItem = null;
183 var tempCabinetFileX = Path.Combine(this.IntermediateFolder, mediaSymbol.Cabinet); 183 var tempCabinetFileX = Path.Combine(this.IntermediateFolder, mediaSymbol.Cabinet);
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/CreateDeltaPatchesCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/CreateDeltaPatchesCommand.cs
index 93ac50ff..640322e6 100644
--- a/src/WixToolset.Core.WindowsInstaller/Bind/CreateDeltaPatchesCommand.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Bind/CreateDeltaPatchesCommand.cs
@@ -9,20 +9,21 @@ namespace WixToolset.Core.WindowsInstaller.Bind
9 using WixToolset.Core.Bind; 9 using WixToolset.Core.Bind;
10 using WixToolset.Data; 10 using WixToolset.Data;
11 using WixToolset.Data.Symbols; 11 using WixToolset.Data.Symbols;
12 using WixToolset.Extensibility.Data;
12 13
13 /// <summary> 14 /// <summary>
14 /// Creates delta patches and updates the appropriate rows to point to the newly generated patches. 15 /// Creates delta patches and updates the appropriate rows to point to the newly generated patches.
15 /// </summary> 16 /// </summary>
16 internal class CreateDeltaPatchesCommand 17 internal class CreateDeltaPatchesCommand
17 { 18 {
18 public CreateDeltaPatchesCommand(List<FileFacade> fileFacades, string intermediateFolder, WixPatchIdSymbol wixPatchId) 19 public CreateDeltaPatchesCommand(List<IFileFacade> fileFacades, string intermediateFolder, WixPatchIdSymbol wixPatchId)
19 { 20 {
20 this.FileFacades = fileFacades; 21 this.FileFacades = fileFacades;
21 this.IntermediateFolder = intermediateFolder; 22 this.IntermediateFolder = intermediateFolder;
22 this.WixPatchId = wixPatchId; 23 this.WixPatchId = wixPatchId;
23 } 24 }
24 25
25 private IEnumerable<FileFacade> FileFacades { get; } 26 private IEnumerable<IFileFacade> FileFacades { get; }
26 27
27 private WixPatchIdSymbol WixPatchId { get; } 28 private WixPatchIdSymbol WixPatchId { get; }
28 29
@@ -31,7 +32,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
31 public void Execute() 32 public void Execute()
32 { 33 {
33 var optimizePatchSizeForLargeFiles = this.WixPatchId?.OptimizePatchSizeForLargeFiles ?? false; 34 var optimizePatchSizeForLargeFiles = this.WixPatchId?.OptimizePatchSizeForLargeFiles ?? false;
34 var apiPatchingSymbolFlags = (PatchSymbolFlagsType)(this.WixPatchId?.ApiPatchingSymbolFlags ?? 0); 35 var apiPatchingSymbolFlags = (PatchSymbolFlags)(this.WixPatchId?.ApiPatchingSymbolFlags ?? 0);
35 36
36#if TODO_PATCHING_DELTA 37#if TODO_PATCHING_DELTA
37 foreach (FileFacade facade in this.FileFacades) 38 foreach (FileFacade facade in this.FileFacades)
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/CreateInstanceTransformsCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/CreateInstanceTransformsCommand.cs
index 33afca77..9a631754 100644
--- a/src/WixToolset.Core.WindowsInstaller/Bind/CreateInstanceTransformsCommand.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Bind/CreateInstanceTransformsCommand.cs
@@ -110,7 +110,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
110 var productCode = instanceSymbol.ProductCode; 110 var productCode = instanceSymbol.ProductCode;
111 if ("*" == productCode) 111 if ("*" == productCode)
112 { 112 {
113 productCode = Common.GenerateGuid(); 113 productCode = this.BackendHelper.CreateGuid();
114 } 114 }
115 115
116 var productCodeRow = propertyTable.CreateRow(instanceSymbol.SourceLineNumbers); 116 var productCodeRow = propertyTable.CreateRow(instanceSymbol.SourceLineNumbers);
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/CreatePatchTransformsCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/CreatePatchTransformsCommand.cs
index 76e6dd56..7bc1a8bd 100644
--- a/src/WixToolset.Core.WindowsInstaller/Bind/CreatePatchTransformsCommand.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Bind/CreatePatchTransformsCommand.cs
@@ -15,15 +15,18 @@ namespace WixToolset.Core.WindowsInstaller.Bind
15 15
16 internal class CreatePatchTransformsCommand 16 internal class CreatePatchTransformsCommand
17 { 17 {
18 public CreatePatchTransformsCommand(IMessaging messaging, Intermediate intermediate, string intermediateFolder) 18 public CreatePatchTransformsCommand(IMessaging messaging, IBackendHelper backendHelper, Intermediate intermediate, string intermediateFolder)
19 { 19 {
20 this.Messaging = messaging; 20 this.Messaging = messaging;
21 this.BackendHelper = backendHelper;
21 this.Intermediate = intermediate; 22 this.Intermediate = intermediate;
22 this.IntermediateFolder = intermediateFolder; 23 this.IntermediateFolder = intermediateFolder;
23 } 24 }
24 25
25 private IMessaging Messaging { get; } 26 private IMessaging Messaging { get; }
26 27
28 private IBackendHelper BackendHelper { get; }
29
27 private Intermediate Intermediate { get; } 30 private Intermediate Intermediate { get; }
28 31
29 private string IntermediateFolder { get; } 32 private string IntermediateFolder { get; }
@@ -52,7 +55,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
52 { 55 {
53 var exportBasePath = Path.Combine(this.IntermediateFolder, "_trans"); // TODO: come up with a better path. 56 var exportBasePath = Path.Combine(this.IntermediateFolder, "_trans"); // TODO: come up with a better path.
54 57
55 var command = new UnbindTransformCommand(this.Messaging, symbol.TransformFile.Path, exportBasePath, this.IntermediateFolder); 58 var command = new UnbindTransformCommand(this.Messaging, this.BackendHelper, symbol.TransformFile.Path, exportBasePath, this.IntermediateFolder);
56 transform = command.Execute(); 59 transform = command.Execute();
57 } 60 }
58 61
@@ -76,7 +79,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
76 79
77 var isAdminImage = false; // TODO: need a better way to set this 80 var isAdminImage = false; // TODO: need a better way to set this
78 81
79 var command = new UnbindDatabaseCommand(this.Messaging, database, path, OutputType.Product, exportBasePath, this.IntermediateFolder, isAdminImage, suppressDemodularization: true, skipSummaryInfo: true); 82 var command = new UnbindDatabaseCommand(this.Messaging, this.BackendHelper, database, path, OutputType.Product, exportBasePath, this.IntermediateFolder, isAdminImage, suppressDemodularization: true, skipSummaryInfo: true);
80 return command.Execute(); 83 return command.Execute();
81 } 84 }
82 } 85 }
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/CreateWindowsInstallerDataFromIRCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/CreateWindowsInstallerDataFromIRCommand.cs
index 9ec26964..0ce67591 100644
--- a/src/WixToolset.Core.WindowsInstaller/Bind/CreateWindowsInstallerDataFromIRCommand.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Bind/CreateWindowsInstallerDataFromIRCommand.cs
@@ -481,18 +481,18 @@ namespace WixToolset.Core.WindowsInstaller.Bind
481 481
482 private void AddDirectorySymbol(DirectorySymbol symbol) 482 private void AddDirectorySymbol(DirectorySymbol symbol)
483 { 483 {
484 if (String.IsNullOrEmpty(symbol.ShortName) && symbol.Name != null && !symbol.Name.Equals(".") && !symbol.Name.Equals("SourceDir") && !Common.IsValidShortFilename(symbol.Name, false)) 484 if (String.IsNullOrEmpty(symbol.ShortName) && symbol.Name != null && !symbol.Name.Equals(".") && !symbol.Name.Equals("SourceDir") && !this.BackendHelper.IsValidShortFilename(symbol.Name, false))
485 { 485 {
486 symbol.ShortName = CreateShortName(symbol.Name, false, false, "Directory", symbol.ParentDirectoryRef); 486 symbol.ShortName = this.CreateShortName(symbol.Name, false, "Directory", symbol.ParentDirectoryRef);
487 } 487 }
488 488
489 if (String.IsNullOrEmpty(symbol.SourceShortName) && !String.IsNullOrEmpty(symbol.SourceName) && !Common.IsValidShortFilename(symbol.SourceName, false)) 489 if (String.IsNullOrEmpty(symbol.SourceShortName) && !String.IsNullOrEmpty(symbol.SourceName) && !this.BackendHelper.IsValidShortFilename(symbol.SourceName, false))
490 { 490 {
491 symbol.SourceShortName = CreateShortName(symbol.SourceName, false, false, "Directory", symbol.ParentDirectoryRef); 491 symbol.SourceShortName = this.CreateShortName(symbol.SourceName, false, "Directory", symbol.ParentDirectoryRef);
492 } 492 }
493 493
494 var sourceName = GetMsiFilenameValue(symbol.SourceShortName, symbol.SourceName); 494 var sourceName = CreateMsiFilename(symbol.SourceShortName, symbol.SourceName);
495 var targetName = GetMsiFilenameValue(symbol.ShortName, symbol.Name); 495 var targetName = CreateMsiFilename(symbol.ShortName, symbol.Name);
496 496
497 if (String.IsNullOrEmpty(targetName)) 497 if (String.IsNullOrEmpty(targetName))
498 { 498 {
@@ -542,16 +542,16 @@ namespace WixToolset.Core.WindowsInstaller.Bind
542 private void AddDuplicateFileSymbol(DuplicateFileSymbol symbol) 542 private void AddDuplicateFileSymbol(DuplicateFileSymbol symbol)
543 { 543 {
544 var name = symbol.DestinationName; 544 var name = symbol.DestinationName;
545 if (null == symbol.DestinationShortName && null != name && !Common.IsValidShortFilename(name, false)) 545 if (null == symbol.DestinationShortName && null != name && !this.BackendHelper.IsValidShortFilename(name, false))
546 { 546 {
547 symbol.DestinationShortName = CreateShortName(name, true, false, "CopyFile", symbol.ComponentRef, symbol.FileRef); 547 symbol.DestinationShortName = this.CreateShortName(name, true, "CopyFile", symbol.ComponentRef, symbol.FileRef);
548 } 548 }
549 549
550 var row = this.CreateRow(symbol, "DuplicateFile"); 550 var row = this.CreateRow(symbol, "DuplicateFile");
551 row[0] = symbol.Id.Id; 551 row[0] = symbol.Id.Id;
552 row[1] = symbol.ComponentRef; 552 row[1] = symbol.ComponentRef;
553 row[2] = symbol.FileRef; 553 row[2] = symbol.FileRef;
554 row[3] = GetMsiFilenameValue(symbol.DestinationShortName, symbol.DestinationName); 554 row[3] = CreateMsiFilename(symbol.DestinationShortName, symbol.DestinationName);
555 row[4] = symbol.DestinationFolder; 555 row[4] = symbol.DestinationFolder;
556 } 556 }
557 557
@@ -621,9 +621,9 @@ namespace WixToolset.Core.WindowsInstaller.Bind
621 private void AddFileSymbol(FileSymbol symbol) 621 private void AddFileSymbol(FileSymbol symbol)
622 { 622 {
623 var name = symbol.Name; 623 var name = symbol.Name;
624 if (null == symbol.ShortName && null != name && !Common.IsValidShortFilename(name, false)) 624 if (null == symbol.ShortName && null != name && !this.BackendHelper.IsValidShortFilename(name, false))
625 { 625 {
626 symbol.ShortName = CreateShortName(name, true, false, "File", symbol.DirectoryRef); 626 symbol.ShortName = this.CreateShortName(name, true, "File", symbol.DirectoryRef);
627 627
628 if (!this.GeneratedShortNames.TryGetValue(symbol.ShortName, out var potentialConflicts)) 628 if (!this.GeneratedShortNames.TryGetValue(symbol.ShortName, out var potentialConflicts))
629 { 629 {
@@ -637,7 +637,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
637 var row = (FileRow)this.CreateRow(symbol, "File"); 637 var row = (FileRow)this.CreateRow(symbol, "File");
638 row.File = symbol.Id.Id; 638 row.File = symbol.Id.Id;
639 row.Component = symbol.ComponentRef; 639 row.Component = symbol.ComponentRef;
640 row.FileName = GetMsiFilenameValue(symbol.ShortName, name); 640 row.FileName = CreateMsiFilename(symbol.ShortName, name);
641 row.FileSize = symbol.FileSize; 641 row.FileSize = symbol.FileSize;
642 row.Version = symbol.Version; 642 row.Version = symbol.Version;
643 row.Language = symbol.Language; 643 row.Language = symbol.Language;
@@ -674,14 +674,14 @@ namespace WixToolset.Core.WindowsInstaller.Bind
674 var tableName = (IniFileActionType.AddLine == symbol.Action || IniFileActionType.AddTag == symbol.Action || IniFileActionType.CreateLine == symbol.Action) ? "IniFile" : "RemoveIniFile"; 674 var tableName = (IniFileActionType.AddLine == symbol.Action || IniFileActionType.AddTag == symbol.Action || IniFileActionType.CreateLine == symbol.Action) ? "IniFile" : "RemoveIniFile";
675 675
676 var name = symbol.FileName; 676 var name = symbol.FileName;
677 if (null == symbol.ShortFileName && null != name && !Common.IsValidShortFilename(name, false)) 677 if (null == symbol.ShortFileName && null != name && !this.BackendHelper.IsValidShortFilename(name, false))
678 { 678 {
679 symbol.ShortFileName = CreateShortName(name, true, false, "IniFile", symbol.ComponentRef); 679 symbol.ShortFileName = this.CreateShortName(name, true, "IniFile", symbol.ComponentRef);
680 } 680 }
681 681
682 var row = this.CreateRow(symbol, tableName); 682 var row = this.CreateRow(symbol, tableName);
683 row[0] = symbol.Id.Id; 683 row[0] = symbol.Id.Id;
684 row[1] = GetMsiFilenameValue(symbol.ShortFileName, name); 684 row[1] = CreateMsiFilename(symbol.ShortFileName, name);
685 row[2] = symbol.DirProperty; 685 row[2] = symbol.DirProperty;
686 row[3] = symbol.Section; 686 row[3] = symbol.Section;
687 row[4] = symbol.Key; 687 row[4] = symbol.Key;
@@ -693,14 +693,14 @@ namespace WixToolset.Core.WindowsInstaller.Bind
693 private void AddIniLocatorSymbol(IniLocatorSymbol symbol) 693 private void AddIniLocatorSymbol(IniLocatorSymbol symbol)
694 { 694 {
695 var name = symbol.FileName; 695 var name = symbol.FileName;
696 if (null == symbol.ShortFileName && null != name && !Common.IsValidShortFilename(name, false)) 696 if (null == symbol.ShortFileName && null != name && !this.BackendHelper.IsValidShortFilename(name, false))
697 { 697 {
698 symbol.ShortFileName = CreateShortName(name, true, false, "IniFileSearch"); 698 symbol.ShortFileName = this.CreateShortName(name, true, "IniFileSearch");
699 } 699 }
700 700
701 var row = this.CreateRow(symbol, "IniLocator"); 701 var row = this.CreateRow(symbol, "IniLocator");
702 row[0] = symbol.Id.Id; 702 row[0] = symbol.Id.Id;
703 row[1] = GetMsiFilenameValue(symbol.ShortFileName, name); 703 row[1] = CreateMsiFilename(symbol.ShortFileName, name);
704 row[2] = symbol.Section; 704 row[2] = symbol.Section;
705 row[3] = symbol.Key; 705 row[3] = symbol.Key;
706 row[4] = symbol.Field; 706 row[4] = symbol.Field;
@@ -786,16 +786,16 @@ namespace WixToolset.Core.WindowsInstaller.Bind
786 private void AddMoveFileSymbol(MoveFileSymbol symbol) 786 private void AddMoveFileSymbol(MoveFileSymbol symbol)
787 { 787 {
788 var name = symbol.DestinationName; 788 var name = symbol.DestinationName;
789 if (null == symbol.DestinationShortName && null != name && !Common.IsValidShortFilename(name, false)) 789 if (null == symbol.DestinationShortName && null != name && !this.BackendHelper.IsValidShortFilename(name, false))
790 { 790 {
791 symbol.DestinationShortName = CreateShortName(name, true, false, "MoveFile", symbol.ComponentRef); 791 symbol.DestinationShortName = this.CreateShortName(name, true, "MoveFile", symbol.ComponentRef);
792 } 792 }
793 793
794 var row = this.CreateRow(symbol, "MoveFile"); 794 var row = this.CreateRow(symbol, "MoveFile");
795 row[0] = symbol.Id.Id; 795 row[0] = symbol.Id.Id;
796 row[1] = symbol.ComponentRef; 796 row[1] = symbol.ComponentRef;
797 row[2] = symbol.SourceName; 797 row[2] = symbol.SourceName;
798 row[3] = GetMsiFilenameValue(symbol.DestinationShortName, symbol.DestinationName); 798 row[3] = CreateMsiFilename(symbol.DestinationShortName, symbol.DestinationName);
799 row[4] = symbol.SourceFolder; 799 row[4] = symbol.SourceFolder;
800 row[5] = symbol.DestFolder; 800 row[5] = symbol.DestFolder;
801 row[6] = symbol.Delete ? WindowsInstallerConstants.MsidbMoveFileOptionsMove : 0; 801 row[6] = symbol.Delete ? WindowsInstallerConstants.MsidbMoveFileOptionsMove : 0;
@@ -816,9 +816,9 @@ namespace WixToolset.Core.WindowsInstaller.Bind
816 private void AddRemoveFileSymbol(RemoveFileSymbol symbol) 816 private void AddRemoveFileSymbol(RemoveFileSymbol symbol)
817 { 817 {
818 var name = symbol.FileName; 818 var name = symbol.FileName;
819 if (null == symbol.ShortFileName && null != name && !Common.IsValidShortFilename(name, false)) 819 if (null == symbol.ShortFileName && null != name && !this.BackendHelper.IsValidShortFilename(name, false))
820 { 820 {
821 symbol.ShortFileName = CreateShortName(name, true, false, "RemoveFile", symbol.ComponentRef); 821 symbol.ShortFileName = this.CreateShortName(name, true, "RemoveFile", symbol.ComponentRef);
822 } 822 }
823 823
824 var installMode = symbol.OnInstall == true ? WindowsInstallerConstants.MsidbRemoveFileInstallModeOnInstall : 0; 824 var installMode = symbol.OnInstall == true ? WindowsInstallerConstants.MsidbRemoveFileInstallModeOnInstall : 0;
@@ -827,7 +827,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
827 var row = this.CreateRow(symbol, "RemoveFile"); 827 var row = this.CreateRow(symbol, "RemoveFile");
828 row[0] = symbol.Id.Id; 828 row[0] = symbol.Id.Id;
829 row[1] = symbol.ComponentRef; 829 row[1] = symbol.ComponentRef;
830 row[2] = GetMsiFilenameValue(symbol.ShortFileName, symbol.FileName); 830 row[2] = CreateMsiFilename(symbol.ShortFileName, symbol.FileName);
831 row[3] = symbol.DirPropertyRef; 831 row[3] = symbol.DirPropertyRef;
832 row[4] = installMode; 832 row[4] = installMode;
833 } 833 }
@@ -966,15 +966,15 @@ namespace WixToolset.Core.WindowsInstaller.Bind
966 private void AddShortcutSymbol(ShortcutSymbol symbol) 966 private void AddShortcutSymbol(ShortcutSymbol symbol)
967 { 967 {
968 var name = symbol.Name; 968 var name = symbol.Name;
969 if (null == symbol.ShortName && null != name && !Common.IsValidShortFilename(name, false)) 969 if (null == symbol.ShortName && null != name && !this.BackendHelper.IsValidShortFilename(name, false))
970 { 970 {
971 symbol.ShortName = CreateShortName(name, true, false, "Shortcut", symbol.ComponentRef, symbol.DirectoryRef); 971 symbol.ShortName = this.CreateShortName(name, true, "Shortcut", symbol.ComponentRef, symbol.DirectoryRef);
972 } 972 }
973 973
974 var row = this.CreateRow(symbol, "Shortcut"); 974 var row = this.CreateRow(symbol, "Shortcut");
975 row[0] = symbol.Id.Id; 975 row[0] = symbol.Id.Id;
976 row[1] = symbol.DirectoryRef; 976 row[1] = symbol.DirectoryRef;
977 row[2] = GetMsiFilenameValue(symbol.ShortName, name); 977 row[2] = CreateMsiFilename(symbol.ShortName, name);
978 row[3] = symbol.ComponentRef; 978 row[3] = symbol.ComponentRef;
979 row[4] = symbol.Target; 979 row[4] = symbol.Target;
980 row[5] = symbol.Arguments; 980 row[5] = symbol.Arguments;
@@ -1177,7 +1177,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
1177 } 1177 }
1178 else if (rowField.Column.Category == ColumnCategory.Identifier) 1178 else if (rowField.Column.Category == ColumnCategory.Identifier)
1179 { 1179 {
1180 if (Common.IsIdentifier(data) || Common.IsValidBinderVariable(data) || ColumnCategory.Formatted == rowField.Column.Category) 1180 if (this.BackendHelper.IsValidIdentifier(data) || this.BackendHelper.IsValidBinderVariable(data) || ColumnCategory.Formatted == rowField.Column.Category)
1181 { 1181 {
1182 rowField.Data = data; 1182 rowField.Data = data;
1183 } 1183 }
@@ -1488,19 +1488,8 @@ namespace WixToolset.Core.WindowsInstaller.Bind
1488 private Row CreateRow(IntermediateSymbol symbol, TableDefinition tableDefinition) => 1488 private Row CreateRow(IntermediateSymbol symbol, TableDefinition tableDefinition) =>
1489 this.BackendHelper.CreateRow(this.Section, symbol, this.Data, tableDefinition); 1489 this.BackendHelper.CreateRow(this.Section, symbol, this.Data, tableDefinition);
1490 1490
1491 private static string GetMsiFilenameValue(string shortName, string longName)
1492 {
1493 if (String.IsNullOrEmpty(shortName) || String.Equals(shortName, longName, StringComparison.OrdinalIgnoreCase))
1494 {
1495 return longName;
1496 }
1497 else
1498 {
1499 return shortName + "|" + longName;
1500 }
1501 }
1502 1491
1503 private static string CreateShortName(string longName, bool keepExtension, bool allowWildcards, params string[] args) 1492 private string CreateShortName(string longName, bool keepExtension, params string[] args)
1504 { 1493 {
1505 longName = longName.ToLowerInvariant(); 1494 longName = longName.ToLowerInvariant();
1506 1495
@@ -1537,7 +1526,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
1537 shortName.Append(extension); 1526 shortName.Append(extension);
1538 1527
1539 // check the generated short name to ensure its still legal (the extension may not be legal) 1528 // check the generated short name to ensure its still legal (the extension may not be legal)
1540 if (!Common.IsValidShortFilename(shortName.ToString(), allowWildcards)) 1529 if (!this.BackendHelper.IsValidShortFilename(shortName.ToString(), false))
1541 { 1530 {
1542 // remove the extension (by truncating the generated file name back to the generated characters) 1531 // remove the extension (by truncating the generated file name back to the generated characters)
1543 shortName.Length -= extension.Length; 1532 shortName.Length -= extension.Length;
@@ -1546,5 +1535,17 @@ namespace WixToolset.Core.WindowsInstaller.Bind
1546 1535
1547 return shortName.ToString().ToLowerInvariant(); 1536 return shortName.ToString().ToLowerInvariant();
1548 } 1537 }
1538
1539 private static string CreateMsiFilename(string shortName, string longName)
1540 {
1541 if (String.IsNullOrEmpty(shortName) || String.Equals(shortName, longName, StringComparison.OrdinalIgnoreCase))
1542 {
1543 return longName;
1544 }
1545 else
1546 {
1547 return shortName + "|" + longName;
1548 }
1549 }
1549 } 1550 }
1550} 1551}
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/ExtractMergeModuleFilesCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/ExtractMergeModuleFilesCommand.cs
index e33b38b1..d4de2dd3 100644
--- a/src/WixToolset.Core.WindowsInstaller/Bind/ExtractMergeModuleFilesCommand.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Bind/ExtractMergeModuleFilesCommand.cs
@@ -11,19 +11,20 @@ namespace WixToolset.Core.WindowsInstaller.Bind
11 using System.Runtime.InteropServices; 11 using System.Runtime.InteropServices;
12 using WixToolset.Data; 12 using WixToolset.Data;
13 using WixToolset.Core.Native; 13 using WixToolset.Core.Native;
14 using WixToolset.Core.Bind;
15 using WixToolset.Data.Symbols; 14 using WixToolset.Data.Symbols;
16 using WixToolset.Extensibility.Services; 15 using WixToolset.Extensibility.Services;
17 using WixToolset.Core.WindowsInstaller.Msi; 16 using WixToolset.Core.WindowsInstaller.Msi;
17 using WixToolset.Extensibility.Data;
18 18
19 /// <summary> 19 /// <summary>
20 /// Retrieve files information and extract them from merge modules. 20 /// Retrieve files information and extract them from merge modules.
21 /// </summary> 21 /// </summary>
22 internal class ExtractMergeModuleFilesCommand 22 internal class ExtractMergeModuleFilesCommand
23 { 23 {
24 public ExtractMergeModuleFilesCommand(IMessaging messaging, IEnumerable<WixMergeSymbol> wixMergeSymbols, IEnumerable<FileFacade> fileFacades, int installerVersion, string intermediateFolder, bool suppressLayout) 24 public ExtractMergeModuleFilesCommand(IMessaging messaging, IWindowsInstallerBackendHelper backendHelper, IEnumerable<WixMergeSymbol> wixMergeSymbols, IEnumerable<IFileFacade> fileFacades, int installerVersion, string intermediateFolder, bool suppressLayout)
25 { 25 {
26 this.Messaging = messaging; 26 this.Messaging = messaging;
27 this.BackendHelper = backendHelper;
27 this.WixMergeSymbols = wixMergeSymbols; 28 this.WixMergeSymbols = wixMergeSymbols;
28 this.FileFacades = fileFacades; 29 this.FileFacades = fileFacades;
29 this.OutputInstallerVersion = installerVersion; 30 this.OutputInstallerVersion = installerVersion;
@@ -33,9 +34,11 @@ namespace WixToolset.Core.WindowsInstaller.Bind
33 34
34 private IMessaging Messaging { get; } 35 private IMessaging Messaging { get; }
35 36
37 private IWindowsInstallerBackendHelper BackendHelper { get; }
38
36 private IEnumerable<WixMergeSymbol> WixMergeSymbols { get; } 39 private IEnumerable<WixMergeSymbol> WixMergeSymbols { get; }
37 40
38 private IEnumerable<FileFacade> FileFacades { get; } 41 private IEnumerable<IFileFacade> FileFacades { get; }
39 42
40 private int OutputInstallerVersion { get; } 43 private int OutputInstallerVersion { get; }
41 44
@@ -43,11 +46,11 @@ namespace WixToolset.Core.WindowsInstaller.Bind
43 46
44 private bool SuppressLayout { get; } 47 private bool SuppressLayout { get; }
45 48
46 public IEnumerable<FileFacade> MergeModulesFileFacades { get; private set; } 49 public IEnumerable<IFileFacade> MergeModulesFileFacades { get; private set; }
47 50
48 public void Execute() 51 public void Execute()
49 { 52 {
50 var mergeModulesFileFacades = new List<FileFacade>(); 53 var mergeModulesFileFacades = new List<IFileFacade>();
51 54
52 var interop = new MsmInterop(); 55 var interop = new MsmInterop();
53 var merge = interop.GetMsmMerge(); 56 var merge = interop.GetMsmMerge();
@@ -75,7 +78,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
75 this.MergeModulesFileFacades = mergeModulesFileFacades; 78 this.MergeModulesFileFacades = mergeModulesFileFacades;
76 } 79 }
77 80
78 private bool CreateFacadesForMergeModuleFiles(WixMergeSymbol wixMergeRow, List<FileFacade> mergeModulesFileFacades, Dictionary<string, FileFacade> indexedFileFacades) 81 private bool CreateFacadesForMergeModuleFiles(WixMergeSymbol wixMergeRow, List<IFileFacade> mergeModulesFileFacades, Dictionary<string, IFileFacade> indexedFileFacades)
79 { 82 {
80 var containsFiles = false; 83 var containsFiles = false;
81 84
@@ -86,7 +89,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
86 { 89 {
87 if (db.TableExists("File") && db.TableExists("Component")) 90 if (db.TableExists("File") && db.TableExists("Component"))
88 { 91 {
89 var uniqueModuleFileIdentifiers = new Dictionary<string, FileFacade>(StringComparer.OrdinalIgnoreCase); 92 var uniqueModuleFileIdentifiers = new Dictionary<string, IFileFacade>(StringComparer.OrdinalIgnoreCase);
90 93
91 using (var view = db.OpenExecuteView("SELECT `File`, `Directory_` FROM `File`, `Component` WHERE `Component_`=`Component`")) 94 using (var view = db.OpenExecuteView("SELECT `File`, `Directory_` FROM `File`, `Component` WHERE `Component_`=`Component`"))
92 { 95 {
@@ -102,7 +105,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
102 fileSymbol.DiskId = wixMergeRow.DiskId; 105 fileSymbol.DiskId = wixMergeRow.DiskId;
103 fileSymbol.Source = new IntermediateFieldPathValue { Path = Path.Combine(this.IntermediateFolder, wixMergeRow.Id.Id, record[1]) }; 106 fileSymbol.Source = new IntermediateFieldPathValue { Path = Path.Combine(this.IntermediateFolder, wixMergeRow.Id.Id, record[1]) };
104 107
105 var mergeModuleFileFacade = new FileFacade(true, fileSymbol); 108 var mergeModuleFileFacade = this.BackendHelper.CreateFileFacadeFromMergeModule(fileSymbol);
106 109
107 // If case-sensitive collision with another merge module or a user-authored file identifier. 110 // If case-sensitive collision with another merge module or a user-authored file identifier.
108 if (indexedFileFacades.TryGetValue(mergeModuleFileFacade.Id, out var collidingFacade)) 111 if (indexedFileFacades.TryGetValue(mergeModuleFileFacade.Id, out var collidingFacade))
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/GetFileFacadesCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/GetFileFacadesCommand.cs
index c918e866..949d5e18 100644
--- a/src/WixToolset.Core.WindowsInstaller/Bind/GetFileFacadesCommand.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Bind/GetFileFacadesCommand.cs
@@ -6,36 +6,45 @@ namespace WixToolset.Core.WindowsInstaller.Bind
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;
10 using WixToolset.Data; 9 using WixToolset.Data;
11 using WixToolset.Data.Symbols; 10 using WixToolset.Data.Symbols;
11 using WixToolset.Extensibility.Data;
12 using WixToolset.Extensibility.Services;
12 13
13 internal class GetFileFacadesCommand 14 internal class GetFileFacadesCommand
14 { 15 {
15 public GetFileFacadesCommand(IntermediateSection section) 16 public GetFileFacadesCommand(IntermediateSection section, IWindowsInstallerBackendHelper backendHelper)
16 { 17 {
17 this.Section = section; 18 this.Section = section;
19 this.BackendHelper = backendHelper;
18 } 20 }
19 21
20 private IntermediateSection Section { get; } 22 private IntermediateSection Section { get; }
21 23
22 public List<FileFacade> FileFacades { get; private set; } 24 private IWindowsInstallerBackendHelper BackendHelper { get; }
25
26 public List<IFileFacade> FileFacades { get; private set; }
23 27
24 public void Execute() 28 public void Execute()
25 { 29 {
26 var facades = new List<FileFacade>(); 30 var facades = new List<IFileFacade>();
27 31
28 var assemblyFile = this.Section.Symbols.OfType<AssemblySymbol>().ToDictionary(t => t.Id.Id); 32 var assemblyFile = this.Section.Symbols.OfType<AssemblySymbol>().ToDictionary(t => t.Id.Id);
33#if TODO_PATCHING_DELTA
29 //var deltaPatchFiles = this.Section.Symbols.OfType<WixDeltaPatchFileSymbol>().ToDictionary(t => t.Id.Id); 34 //var deltaPatchFiles = this.Section.Symbols.OfType<WixDeltaPatchFileSymbol>().ToDictionary(t => t.Id.Id);
35#endif
30 36
31 foreach (var file in this.Section.Symbols.OfType<FileSymbol>()) 37 foreach (var file in this.Section.Symbols.OfType<FileSymbol>())
32 { 38 {
33 assemblyFile.TryGetValue(file.Id.Id, out var assembly); 39 assemblyFile.TryGetValue(file.Id.Id, out var assembly);
34 40
41#if TODO_PATCHING_DELTA
35 //deltaPatchFiles.TryGetValue(file.Id.Id, out var deltaPatchFile); 42 //deltaPatchFiles.TryGetValue(file.Id.Id, out var deltaPatchFile);
43 // TODO: should we be passing along delta information to the file facade? Probably, right?
44#endif
45 var fileFacade = this.BackendHelper.CreateFileFacade(file, assembly);
36 46
37 facades.Add(new FileFacade(file, assembly)); 47 facades.Add(fileFacade);
38 //facades.Add(new FileFacade(file, wixFile, deltaPatchFile));
39 } 48 }
40 49
41#if TODO_PATCHING_DELTA 50#if TODO_PATCHING_DELTA
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/GetFileFacadesFromTransforms.cs b/src/WixToolset.Core.WindowsInstaller/Bind/GetFileFacadesFromTransforms.cs
index 585bdac0..ca074631 100644
--- a/src/WixToolset.Core.WindowsInstaller/Bind/GetFileFacadesFromTransforms.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Bind/GetFileFacadesFromTransforms.cs
@@ -5,35 +5,35 @@ namespace WixToolset.Core.WindowsInstaller.Bind
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;
9 using WixToolset.Data; 8 using WixToolset.Data;
10 using WixToolset.Data.WindowsInstaller; 9 using WixToolset.Data.WindowsInstaller;
11 using WixToolset.Data.WindowsInstaller.Rows; 10 using WixToolset.Data.WindowsInstaller.Rows;
12 using WixToolset.Extensibility; 11 using WixToolset.Extensibility.Data;
13 using WixToolset.Extensibility.Services; 12 using WixToolset.Extensibility.Services;
14 13
15 internal class GetFileFacadesFromTransforms 14 internal class GetFileFacadesFromTransforms
16 { 15 {
17 public GetFileFacadesFromTransforms(IMessaging messaging, FileSystemManager fileSystemManager, IEnumerable<SubStorage> subStorages) 16 public GetFileFacadesFromTransforms(IMessaging messaging, IWindowsInstallerBackendHelper backendHelper, FileSystemManager fileSystemManager, IEnumerable<SubStorage> subStorages)
18 { 17 {
19 this.Messaging = messaging; 18 this.Messaging = messaging;
19 this.BackendHelper = backendHelper;
20 this.FileSystemManager = fileSystemManager; 20 this.FileSystemManager = fileSystemManager;
21 this.SubStorages = subStorages; 21 this.SubStorages = subStorages;
22 } 22 }
23 23
24 private IMessaging Messaging { get; } 24 private IMessaging Messaging { get; }
25 25
26 private IWindowsInstallerBackendHelper BackendHelper { get; }
27
26 private FileSystemManager FileSystemManager { get; } 28 private FileSystemManager FileSystemManager { get; }
27 29
28 private IEnumerable<SubStorage> SubStorages { get; } 30 private IEnumerable<SubStorage> SubStorages { get; }
29 31
30 public List<FileFacade> FileFacades { get; private set; } 32 public List<IFileFacade> FileFacades { get; private set; }
31 33
32 public void Execute() 34 public void Execute()
33 { 35 {
34 var allFileRows = new List<FileFacade>(); 36 var allFileRows = new List<IFileFacade>();
35
36 var patchMediaRows = new RowDictionary<MediaRow>();
37 37
38 var patchMediaFileRows = new Dictionary<int, RowDictionary<FileRow>>(); 38 var patchMediaFileRows = new Dictionary<int, RowDictionary<FileRow>>();
39 39
@@ -143,7 +143,12 @@ namespace WixToolset.Core.WindowsInstaller.Bind
143 143
144 mediaFileRows.Add(patchFileRow); 144 mediaFileRows.Add(patchFileRow);
145 145
146 allFileRows.Add(new FileFacade(patchFileRow)); // TODO: should we be passing along delta information? Probably, right? 146#if TODO_PATCHING_DELTA
147 // TODO: should we be passing along delta information to the file facade? Probably, right?
148#endif
149 var fileFacade = this.BackendHelper.CreateFileFacade(patchFileRow);
150
151 allFileRows.Add(fileFacade);
147 } 152 }
148 else 153 else
149 { 154 {
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/MergeModulesCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/MergeModulesCommand.cs
index 80684e7c..f8a1efd6 100644
--- a/src/WixToolset.Core.WindowsInstaller/Bind/MergeModulesCommand.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Bind/MergeModulesCommand.cs
@@ -9,12 +9,12 @@ namespace WixToolset.Core.WindowsInstaller.Bind
9 using System.Linq; 9 using System.Linq;
10 using System.Runtime.InteropServices; 10 using System.Runtime.InteropServices;
11 using System.Text; 11 using System.Text;
12 using WixToolset.Core.Bind;
13 using WixToolset.Core.Native; 12 using WixToolset.Core.Native;
14 using WixToolset.Core.WindowsInstaller.Msi; 13 using WixToolset.Core.WindowsInstaller.Msi;
15 using WixToolset.Data; 14 using WixToolset.Data;
16 using WixToolset.Data.Symbols; 15 using WixToolset.Data.Symbols;
17 using WixToolset.Data.WindowsInstaller; 16 using WixToolset.Data.WindowsInstaller;
17 using WixToolset.Extensibility.Data;
18 using WixToolset.Extensibility.Services; 18 using WixToolset.Extensibility.Services;
19 19
20 /// <summary> 20 /// <summary>
@@ -22,7 +22,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
22 /// </summary> 22 /// </summary>
23 internal class MergeModulesCommand 23 internal class MergeModulesCommand
24 { 24 {
25 public MergeModulesCommand(IMessaging messaging, IEnumerable<FileFacade> fileFacades, IntermediateSection section, IEnumerable<string> suppressedTableNames, string outputPath, string intermediateFolder) 25 public MergeModulesCommand(IMessaging messaging, IEnumerable<IFileFacade> fileFacades, IntermediateSection section, IEnumerable<string> suppressedTableNames, string outputPath, string intermediateFolder)
26 { 26 {
27 this.Messaging = messaging; 27 this.Messaging = messaging;
28 this.FileFacades = fileFacades; 28 this.FileFacades = fileFacades;
@@ -34,7 +34,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
34 34
35 private IMessaging Messaging { get; } 35 private IMessaging Messaging { get; }
36 36
37 private IEnumerable<FileFacade> FileFacades { get; } 37 private IEnumerable<IFileFacade> FileFacades { get; }
38 38
39 private IntermediateSection Section { get; } 39 private IntermediateSection Section { get; }
40 40
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/ModularizeCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/ModularizeCommand.cs
index 49ef1adf..04f1b771 100644
--- a/src/WixToolset.Core.WindowsInstaller/Bind/ModularizeCommand.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Bind/ModularizeCommand.cs
@@ -12,11 +12,13 @@ namespace WixToolset.Core.WindowsInstaller.Bind
12 using WixToolset.Data; 12 using WixToolset.Data;
13 using WixToolset.Data.Symbols; 13 using WixToolset.Data.Symbols;
14 using WixToolset.Data.WindowsInstaller; 14 using WixToolset.Data.WindowsInstaller;
15 using WixToolset.Extensibility.Services;
15 16
16 internal class ModularizeCommand 17 internal class ModularizeCommand
17 { 18 {
18 public ModularizeCommand(WindowsInstallerData output, string modularizationSuffix, IEnumerable<WixSuppressModularizationSymbol> suppressSymbols) 19 public ModularizeCommand(IBackendHelper backendHelper, WindowsInstallerData output, string modularizationSuffix, IEnumerable<WixSuppressModularizationSymbol> suppressSymbols)
19 { 20 {
21 this.BackendHelper = backendHelper;
20 this.Output = output; 22 this.Output = output;
21 this.ModularizationSuffix = modularizationSuffix; 23 this.ModularizationSuffix = modularizationSuffix;
22 24
@@ -24,6 +26,8 @@ namespace WixToolset.Core.WindowsInstaller.Bind
24 this.SuppressModularizationIdentifiers = new HashSet<string>(suppressSymbols.Select(s => s.SuppressIdentifier)); 26 this.SuppressModularizationIdentifiers = new HashSet<string>(suppressSymbols.Select(s => s.SuppressIdentifier));
25 } 27 }
26 28
29 private IBackendHelper BackendHelper { get; }
30
27 private WindowsInstallerData Output { get; } 31 private WindowsInstallerData Output { get; }
28 32
29 private string ModularizationSuffix { get; } 33 private string ModularizationSuffix { get; }
@@ -90,7 +94,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
90 case "SetTargetPath": 94 case "SetTargetPath":
91 case "SpawnDialog": 95 case "SpawnDialog":
92 case "SpawnWaitDialog": 96 case "SpawnWaitDialog":
93 if (Common.IsIdentifier(fieldData)) 97 if (this.BackendHelper.IsValidIdentifier(fieldData))
94 { 98 {
95 modularizeType = ColumnModularizeType.Column; 99 modularizeType = ColumnModularizeType.Column;
96 } 100 }
@@ -107,7 +111,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
107 else if (ColumnModularizeType.ControlText == field.Column.ModularizeType) 111 else if (ColumnModularizeType.ControlText == field.Column.ModularizeType)
108 { 112 {
109 // icons are stored in the Binary table, so they get column-type modularization 113 // icons are stored in the Binary table, so they get column-type modularization
110 if (("Bitmap" == row[2].ToString() || "Icon" == row[2].ToString()) && Common.IsIdentifier(fieldData)) 114 if (("Bitmap" == row[2].ToString() || "Icon" == row[2].ToString()) && this.BackendHelper.IsValidIdentifier(fieldData))
111 { 115 {
112 modularizeType = ColumnModularizeType.Column; 116 modularizeType = ColumnModularizeType.Column;
113 } 117 }
@@ -121,7 +125,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
121 { 125 {
122 case ColumnModularizeType.Column: 126 case ColumnModularizeType.Column:
123 // ensure the value is an identifier (otherwise it shouldn't be modularized this way) 127 // ensure the value is an identifier (otherwise it shouldn't be modularized this way)
124 if (!Common.IsIdentifier(fieldData)) 128 if (!this.BackendHelper.IsValidIdentifier(fieldData))
125 { 129 {
126 throw new InvalidOperationException(String.Format(CultureInfo.CurrentUICulture, WixDataStrings.EXP_CannotModularizeIllegalID, fieldData)); 130 throw new InvalidOperationException(String.Format(CultureInfo.CurrentUICulture, WixDataStrings.EXP_CannotModularizeIllegalID, fieldData));
127 } 131 }
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/OptimizeFileFacadesOrderCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/OptimizeFileFacadesOrderCommand.cs
index 67515154..5dd4d3ea 100644
--- a/src/WixToolset.Core.WindowsInstaller/Bind/OptimizeFileFacadesOrderCommand.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Bind/OptimizeFileFacadesOrderCommand.cs
@@ -5,7 +5,6 @@ namespace WixToolset.Core.WindowsInstaller.Bind
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;
9 using WixToolset.Data; 8 using WixToolset.Data;
10 using WixToolset.Data.Symbols; 9 using WixToolset.Data.Symbols;
11 using WixToolset.Extensibility.Data; 10 using WixToolset.Extensibility.Data;
@@ -13,7 +12,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
13 12
14 internal class OptimizeFileFacadesOrderCommand 13 internal class OptimizeFileFacadesOrderCommand
15 { 14 {
16 public OptimizeFileFacadesOrderCommand(IBackendHelper helper, IPathResolver pathResolver, IntermediateSection section, Platform platform, List<FileFacade> fileFacades) 15 public OptimizeFileFacadesOrderCommand(IBackendHelper helper, IPathResolver pathResolver, IntermediateSection section, Platform platform, List<IFileFacade> fileFacades)
17 { 16 {
18 this.BackendHelper = helper; 17 this.BackendHelper = helper;
19 this.PathResolver = pathResolver; 18 this.PathResolver = pathResolver;
@@ -22,7 +21,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
22 this.FileFacades = fileFacades; 21 this.FileFacades = fileFacades;
23 } 22 }
24 23
25 public List<FileFacade> FileFacades { get; private set; } 24 public List<IFileFacade> FileFacades { get; private set; }
26 25
27 private IBackendHelper BackendHelper { get; } 26 private IBackendHelper BackendHelper { get; }
28 27
@@ -32,7 +31,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
32 31
33 private Platform Platform { get; } 32 private Platform Platform { get; }
34 33
35 public List<FileFacade> Execute() 34 public List<IFileFacade> Execute()
36 { 35 {
37 var canonicalComponentTargetPaths = this.ComponentTargetPaths(); 36 var canonicalComponentTargetPaths = this.ComponentTargetPaths();
38 37
@@ -69,7 +68,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
69 return targetPathsByDirectoryId; 68 return targetPathsByDirectoryId;
70 } 69 }
71 70
72 private class FileFacadeOptimizer : IComparer<FileFacade> 71 private class FileFacadeOptimizer : IComparer<IFileFacade>
73 { 72 {
74 public FileFacadeOptimizer(Dictionary<string, string> componentTargetPaths, bool optimizingMergeModule) 73 public FileFacadeOptimizer(Dictionary<string, string> componentTargetPaths, bool optimizingMergeModule)
75 { 74 {
@@ -81,7 +80,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
81 80
82 private bool OptimizingMergeModule { get; } 81 private bool OptimizingMergeModule { get; }
83 82
84 public int Compare(FileFacade x, FileFacade y) 83 public int Compare(IFileFacade x, IFileFacade y)
85 { 84 {
86 // First group files by DiskId but ignore if processing a Merge Module 85 // First group files by DiskId but ignore if processing a Merge Module
87 // because Merge Modules don't have separate disks. 86 // because Merge Modules don't have separate disks.
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/ProcessDependencyReferencesCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/ProcessDependencyReferencesCommand.cs
index 7a7c2649..5ec93f49 100644
--- a/src/WixToolset.Core.WindowsInstaller/Bind/ProcessDependencyReferencesCommand.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Bind/ProcessDependencyReferencesCommand.cs
@@ -17,12 +17,15 @@ namespace WixToolset.Core.WindowsInstaller.Bind
17 private const string DependencyRegistryRoot = @"Software\Classes\Installer\Dependencies\"; 17 private const string DependencyRegistryRoot = @"Software\Classes\Installer\Dependencies\";
18 private const string RegistryDependents = "Dependents"; 18 private const string RegistryDependents = "Dependents";
19 19
20 public ProcessDependencyReferencesCommand(IntermediateSection section, IEnumerable<WixDependencyRefSymbol> dependencyRefSymbols) 20 public ProcessDependencyReferencesCommand(IBackendHelper backendHelper, IntermediateSection section, IEnumerable<WixDependencyRefSymbol> dependencyRefSymbols)
21 { 21 {
22 this.BackendHelper = backendHelper;
22 this.Section = section; 23 this.Section = section;
23 this.DependencyRefSymbols = dependencyRefSymbols; 24 this.DependencyRefSymbols = dependencyRefSymbols;
24 } 25 }
25 26
27 private IBackendHelper BackendHelper { get; }
28
26 private IntermediateSection Section { get; } 29 private IntermediateSection Section { get; }
27 30
28 private IEnumerable<WixDependencyRefSymbol> DependencyRefSymbols { get; } 31 private IEnumerable<WixDependencyRefSymbol> DependencyRefSymbols { get; }
@@ -57,7 +60,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
57 // Get the component ID from the provider. 60 // Get the component ID from the provider.
58 var componentId = wixDependencyProviderRow.ComponentRef; 61 var componentId = wixDependencyProviderRow.ComponentRef;
59 62
60 var id = Common.GenerateIdentifier("reg", providesId, requiresId, "(Default)"); 63 var id = this.BackendHelper.GenerateIdentifier("reg", providesId, requiresId, "(Default)");
61 this.Section.AddSymbol(new RegistrySymbol(wixDependencyRefRow.SourceLineNumbers, new Identifier(AccessModifier.Section, id)) 64 this.Section.AddSymbol(new RegistrySymbol(wixDependencyRefRow.SourceLineNumbers, new Identifier(AccessModifier.Section, id))
62 { 65 {
63 ComponentRef = componentId, 66 ComponentRef = componentId,
@@ -68,7 +71,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
68 71
69 if (!String.IsNullOrEmpty(wixDependencyRow.MinVersion)) 72 if (!String.IsNullOrEmpty(wixDependencyRow.MinVersion))
70 { 73 {
71 id = Common.GenerateIdentifier("reg", providesId, requiresId, "MinVersion"); 74 id = this.BackendHelper.GenerateIdentifier("reg", providesId, requiresId, "MinVersion");
72 this.Section.AddSymbol(new RegistrySymbol(wixDependencyRefRow.SourceLineNumbers, new Identifier(AccessModifier.Section, id)) 75 this.Section.AddSymbol(new RegistrySymbol(wixDependencyRefRow.SourceLineNumbers, new Identifier(AccessModifier.Section, id))
73 { 76 {
74 ComponentRef = componentId, 77 ComponentRef = componentId,
@@ -79,10 +82,10 @@ namespace WixToolset.Core.WindowsInstaller.Bind
79 }); 82 });
80 } 83 }
81 84
82 string maxVersion = (string)wixDependencyRow[3]; 85 var maxVersion = (string)wixDependencyRow[3];
83 if (!String.IsNullOrEmpty(wixDependencyRow.MaxVersion)) 86 if (!String.IsNullOrEmpty(wixDependencyRow.MaxVersion))
84 { 87 {
85 id = Common.GenerateIdentifier("reg", providesId, requiresId, "MaxVersion"); 88 id = this.BackendHelper.GenerateIdentifier("reg", providesId, requiresId, "MaxVersion");
86 this.Section.AddSymbol(new RegistrySymbol(wixDependencyRefRow.SourceLineNumbers, new Identifier(AccessModifier.Section, id)) 89 this.Section.AddSymbol(new RegistrySymbol(wixDependencyRefRow.SourceLineNumbers, new Identifier(AccessModifier.Section, id))
87 { 90 {
88 ComponentRef = componentId, 91 ComponentRef = componentId,
@@ -95,7 +98,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
95 98
96 if (wixDependencyRow.Attributes != WixDependencySymbolAttributes.None) 99 if (wixDependencyRow.Attributes != WixDependencySymbolAttributes.None)
97 { 100 {
98 id = Common.GenerateIdentifier("reg", providesId, requiresId, "Attributes"); 101 id = this.BackendHelper.GenerateIdentifier("reg", providesId, requiresId, "Attributes");
99 this.Section.AddSymbol(new RegistrySymbol(wixDependencyRefRow.SourceLineNumbers, new Identifier(AccessModifier.Section, id)) 102 this.Section.AddSymbol(new RegistrySymbol(wixDependencyRefRow.SourceLineNumbers, new Identifier(AccessModifier.Section, id))
100 { 103 {
101 ComponentRef = componentId, 104 ComponentRef = componentId,
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/ProcessUncompressedFilesCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/ProcessUncompressedFilesCommand.cs
index ab5ebd4b..8c66a9e1 100644
--- a/src/WixToolset.Core.WindowsInstaller/Bind/ProcessUncompressedFilesCommand.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Bind/ProcessUncompressedFilesCommand.cs
@@ -6,7 +6,6 @@ namespace WixToolset.Core.WindowsInstaller.Bind
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 WixToolset.Core.Bind;
10 using WixToolset.Core.WindowsInstaller.Msi; 9 using WixToolset.Core.WindowsInstaller.Msi;
11 using WixToolset.Data; 10 using WixToolset.Data;
12 using WixToolset.Data.Symbols; 11 using WixToolset.Data.Symbols;
@@ -33,7 +32,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
33 32
34 public string DatabasePath { private get; set; } 33 public string DatabasePath { private get; set; }
35 34
36 public IEnumerable<FileFacade> FileFacades { private get; set; } 35 public IEnumerable<IFileFacade> FileFacades { private get; set; }
37 36
38 public string LayoutDirectory { private get; set; } 37 public string LayoutDirectory { private get; set; }
39 38
@@ -63,7 +62,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
63 { 62 {
64 foreach (var directoryRecord in directoryView.Records) 63 foreach (var directoryRecord in directoryView.Records)
65 { 64 {
66 var sourceName = Common.GetName(directoryRecord.GetString(3), true, this.LongNamesInImage); 65 var sourceName = this.BackendHelper.GetMsiFileName(directoryRecord.GetString(3), true, this.LongNamesInImage);
67 66
68 var resolvedDirectory = this.BackendHelper.CreateResolvedDirectory(directoryRecord.GetString(2), sourceName); 67 var resolvedDirectory = this.BackendHelper.CreateResolvedDirectory(directoryRecord.GetString(2), sourceName);
69 68
@@ -71,16 +70,16 @@ namespace WixToolset.Core.WindowsInstaller.Bind
71 } 70 }
72 } 71 }
73 72
74 using (View fileView = db.OpenView("SELECT `Directory_`, `FileName` FROM `Component`, `File` WHERE `Component`.`Component`=`File`.`Component_` AND `File`.`File`=?")) 73 using (var fileView = db.OpenView("SELECT `Directory_`, `FileName` FROM `Component`, `File` WHERE `Component`.`Component`=`File`.`Component_` AND `File`.`File`=?"))
75 { 74 {
76 using (Record fileQueryRecord = new Record(1)) 75 using (var fileQueryRecord = new Record(1))
77 { 76 {
78 // for each file in the array of uncompressed files 77 // for each file in the array of uncompressed files
79 foreach (FileFacade facade in this.FileFacades) 78 foreach (var facade in this.FileFacades)
80 { 79 {
81 var mediaSymbol = mediaRows[facade.DiskId]; 80 var mediaSymbol = mediaRows[facade.DiskId];
82 string relativeFileLayoutPath = null; 81 string relativeFileLayoutPath = null;
83 string mediaLayoutFolder = mediaSymbol.Layout; 82 var mediaLayoutFolder = mediaSymbol.Layout;
84 83
85 var mediaLayoutDirectory = this.ResolveMedia(mediaSymbol, mediaLayoutFolder, this.LayoutDirectory); 84 var mediaLayoutDirectory = this.ResolveMedia(mediaSymbol, mediaLayoutFolder, this.LayoutDirectory);
86 85
@@ -89,7 +88,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
89 fileQueryRecord[1] = facade.Id; 88 fileQueryRecord[1] = facade.Id;
90 fileView.Execute(fileQueryRecord); 89 fileView.Execute(fileQueryRecord);
91 90
92 using (Record fileRecord = fileView.Fetch()) 91 using (var fileRecord = fileView.Fetch())
93 { 92 {
94 if (null == fileRecord) 93 if (null == fileRecord)
95 { 94 {
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/UpdateFileFacadesCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/UpdateFileFacadesCommand.cs
index f8819a0e..9cd14cfa 100644
--- a/src/WixToolset.Core.WindowsInstaller/Bind/UpdateFileFacadesCommand.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Bind/UpdateFileFacadesCommand.cs
@@ -8,10 +8,10 @@ namespace WixToolset.Core.WindowsInstaller.Bind
8 using System.Globalization; 8 using System.Globalization;
9 using System.IO; 9 using System.IO;
10 using System.Linq; 10 using System.Linq;
11 using WixToolset.Core.Bind;
12 using WixToolset.Core.WindowsInstaller.Msi; 11 using WixToolset.Core.WindowsInstaller.Msi;
13 using WixToolset.Data; 12 using WixToolset.Data;
14 using WixToolset.Data.Symbols; 13 using WixToolset.Data.Symbols;
14 using WixToolset.Extensibility.Data;
15 using WixToolset.Extensibility.Services; 15 using WixToolset.Extensibility.Services;
16 16
17 /// <summary> 17 /// <summary>
@@ -19,7 +19,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
19 /// </summary> 19 /// </summary>
20 internal class UpdateFileFacadesCommand 20 internal class UpdateFileFacadesCommand
21 { 21 {
22 public UpdateFileFacadesCommand(IMessaging messaging, IntermediateSection section, IEnumerable<FileFacade> fileFacades, IEnumerable<FileFacade> updateFileFacades, IDictionary<string, string> variableCache, bool overwriteHash) 22 public UpdateFileFacadesCommand(IMessaging messaging, IntermediateSection section, IEnumerable<IFileFacade> fileFacades, IEnumerable<IFileFacade> updateFileFacades, IDictionary<string, string> variableCache, bool overwriteHash)
23 { 23 {
24 this.Messaging = messaging; 24 this.Messaging = messaging;
25 this.Section = section; 25 this.Section = section;
@@ -33,9 +33,9 @@ namespace WixToolset.Core.WindowsInstaller.Bind
33 33
34 private IntermediateSection Section { get; } 34 private IntermediateSection Section { get; }
35 35
36 private IEnumerable<FileFacade> FileFacades { get; } 36 private IEnumerable<IFileFacade> FileFacades { get; }
37 37
38 private IEnumerable<FileFacade> UpdateFileFacades { get; } 38 private IEnumerable<IFileFacade> UpdateFileFacades { get; }
39 39
40 private bool OverwriteHash { get; } 40 private bool OverwriteHash { get; }
41 41
@@ -51,7 +51,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
51 } 51 }
52 } 52 }
53 53
54 private void UpdateFileFacade(FileFacade facade, Dictionary<string, MsiAssemblyNameSymbol> assemblyNameSymbols) 54 private void UpdateFileFacade(IFileFacade facade, Dictionary<string, MsiAssemblyNameSymbol> assemblyNameSymbols)
55 { 55 {
56 FileInfo fileInfo = null; 56 FileInfo fileInfo = null;
57 try 57 try
@@ -314,7 +314,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
314 /// <param name="facade">FileFacade containing the assembly read for the MsiAssemblyName row.</param> 314 /// <param name="facade">FileFacade containing the assembly read for the MsiAssemblyName row.</param>
315 /// <param name="name">MsiAssemblyName name.</param> 315 /// <param name="name">MsiAssemblyName name.</param>
316 /// <param name="value">MsiAssemblyName value.</param> 316 /// <param name="value">MsiAssemblyName value.</param>
317 private void SetMsiAssemblyName(Dictionary<string, MsiAssemblyNameSymbol> assemblyNameSymbols, FileFacade facade, string name, string value) 317 private void SetMsiAssemblyName(Dictionary<string, MsiAssemblyNameSymbol> assemblyNameSymbols, IFileFacade facade, string name, string value)
318 { 318 {
319 // check for null value (this can occur when grabbing the file version from an assembly without one) 319 // check for null value (this can occur when grabbing the file version from an assembly without one)
320 if (String.IsNullOrEmpty(value)) 320 if (String.IsNullOrEmpty(value))
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/UpdateMediaSequencesCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/UpdateMediaSequencesCommand.cs
index d3f2b9ea..affec09f 100644
--- a/src/WixToolset.Core.WindowsInstaller/Bind/UpdateMediaSequencesCommand.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Bind/UpdateMediaSequencesCommand.cs
@@ -4,13 +4,13 @@ namespace WixToolset.Core.WindowsInstaller.Bind
4{ 4{
5 using System.Collections.Generic; 5 using System.Collections.Generic;
6 using System.Linq; 6 using System.Linq;
7 using WixToolset.Core.Bind;
8 using WixToolset.Data; 7 using WixToolset.Data;
9 using WixToolset.Data.Symbols; 8 using WixToolset.Data.Symbols;
9 using WixToolset.Extensibility.Data;
10 10
11 internal class UpdateMediaSequencesCommand 11 internal class UpdateMediaSequencesCommand
12 { 12 {
13 public UpdateMediaSequencesCommand(IntermediateSection section, List<FileFacade> fileFacades) 13 public UpdateMediaSequencesCommand(IntermediateSection section, IEnumerable<IFileFacade> fileFacades)
14 { 14 {
15 this.Section = section; 15 this.Section = section;
16 this.FileFacades = fileFacades; 16 this.FileFacades = fileFacades;
@@ -18,7 +18,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
18 18
19 private IntermediateSection Section { get; } 19 private IntermediateSection Section { get; }
20 20
21 private List<FileFacade> FileFacades { get; } 21 private IEnumerable<IFileFacade> FileFacades { get; }
22 22
23 public void Execute() 23 public void Execute()
24 { 24 {
@@ -38,9 +38,9 @@ namespace WixToolset.Core.WindowsInstaller.Bind
38 { 38 {
39 var lastSequence = 0; 39 var lastSequence = 0;
40 MediaSymbol mediaSymbol = null; 40 MediaSymbol mediaSymbol = null;
41 var patchGroups = new Dictionary<int, List<FileFacade>>(); 41 var patchGroups = new Dictionary<int, List<IFileFacade>>();
42 42
43 // sequence the non-patch-added files 43 // Sequence the non-patch-added files.
44 foreach (var facade in this.FileFacades) 44 foreach (var facade in this.FileFacades)
45 { 45 {
46 if (null == mediaSymbol) 46 if (null == mediaSymbol)
@@ -62,7 +62,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
62 { 62 {
63 if (patchGroups.TryGetValue(facade.PatchGroup.Value, out var patchGroup)) 63 if (patchGroups.TryGetValue(facade.PatchGroup.Value, out var patchGroup))
64 { 64 {
65 patchGroup = new List<FileFacade>(); 65 patchGroup = new List<IFileFacade>();
66 patchGroups.Add(facade.PatchGroup.Value, patchGroup); 66 patchGroups.Add(facade.PatchGroup.Value, patchGroup);
67 } 67 }
68 68
@@ -80,7 +80,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
80 mediaSymbol = null; 80 mediaSymbol = null;
81 } 81 }
82 82
83 // sequence the patch-added files 83 // Sequence the patch-added files.
84 foreach (var patchGroup in patchGroups.Values) 84 foreach (var patchGroup in patchGroups.Values)
85 { 85 {
86 foreach (var facade in patchGroup) 86 foreach (var facade in patchGroup)
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/UpdateTransformsWithFileFacades.cs b/src/WixToolset.Core.WindowsInstaller/Bind/UpdateTransformsWithFileFacades.cs
index 4e716a47..981fa0a4 100644
--- a/src/WixToolset.Core.WindowsInstaller/Bind/UpdateTransformsWithFileFacades.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Bind/UpdateTransformsWithFileFacades.cs
@@ -5,16 +5,16 @@ namespace WixToolset.Core.WindowsInstaller.Bind
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;
9 using WixToolset.Data; 8 using WixToolset.Data;
10 using WixToolset.Data.Symbols; 9 using WixToolset.Data.Symbols;
11 using WixToolset.Data.WindowsInstaller; 10 using WixToolset.Data.WindowsInstaller;
12 using WixToolset.Data.WindowsInstaller.Rows; 11 using WixToolset.Data.WindowsInstaller.Rows;
12 using WixToolset.Extensibility.Data;
13 using WixToolset.Extensibility.Services; 13 using WixToolset.Extensibility.Services;
14 14
15 internal class UpdateTransformsWithFileFacades 15 internal class UpdateTransformsWithFileFacades
16 { 16 {
17 public UpdateTransformsWithFileFacades(IMessaging messaging, WindowsInstallerData output, IEnumerable<SubStorage> subStorages, TableDefinitionCollection tableDefinitions, IEnumerable<FileFacade> fileFacades) 17 public UpdateTransformsWithFileFacades(IMessaging messaging, WindowsInstallerData output, IEnumerable<SubStorage> subStorages, TableDefinitionCollection tableDefinitions, IEnumerable<IFileFacade> fileFacades)
18 { 18 {
19 this.Messaging = messaging; 19 this.Messaging = messaging;
20 this.Output = output; 20 this.Output = output;
@@ -31,18 +31,18 @@ namespace WixToolset.Core.WindowsInstaller.Bind
31 31
32 private TableDefinitionCollection TableDefinitions { get; } 32 private TableDefinitionCollection TableDefinitions { get; }
33 33
34 private IEnumerable<FileFacade> FileFacades { get; } 34 private IEnumerable<IFileFacade> FileFacades { get; }
35 35
36 public void Execute() 36 public void Execute()
37 { 37 {
38 var fileFacadesByDiskId = new Dictionary<int, Dictionary<string, FileFacade>>(); 38 var fileFacadesByDiskId = new Dictionary<int, Dictionary<string, IFileFacade>>();
39 39
40 // Index patch file facades by diskId+fileId. 40 // Index patch file facades by diskId+fileId.
41 foreach (var facade in this.FileFacades) 41 foreach (var facade in this.FileFacades)
42 { 42 {
43 if (!fileFacadesByDiskId.TryGetValue(facade.DiskId, out var mediaFacades)) 43 if (!fileFacadesByDiskId.TryGetValue(facade.DiskId, out var mediaFacades))
44 { 44 {
45 mediaFacades = new Dictionary<string, FileFacade>(); 45 mediaFacades = new Dictionary<string, IFileFacade>();
46 fileFacadesByDiskId.Add(facade.DiskId, mediaFacades); 46 fileFacadesByDiskId.Add(facade.DiskId, mediaFacades);
47 } 47 }
48 48
@@ -97,7 +97,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
97 // Index patch files by diskId+fileId 97 // Index patch files by diskId+fileId
98 if (!fileFacadesByDiskId.TryGetValue(mainFileRow.DiskId, out var mediaFacades)) 98 if (!fileFacadesByDiskId.TryGetValue(mainFileRow.DiskId, out var mediaFacades))
99 { 99 {
100 mediaFacades = new Dictionary<string, FileFacade>(); 100 mediaFacades = new Dictionary<string, IFileFacade>();
101 fileFacadesByDiskId.Add(mainFileRow.DiskId, mediaFacades); 101 fileFacadesByDiskId.Add(mainFileRow.DiskId, mediaFacades);
102 } 102 }
103 103
diff --git a/src/WixToolset.Core.WindowsInstaller/Data/Xsd/actions.xsd b/src/WixToolset.Core.WindowsInstaller/Data/Xsd/actions.xsd
deleted file mode 100644
index bf0ccb95..00000000
--- a/src/WixToolset.Core.WindowsInstaller/Data/Xsd/actions.xsd
+++ /dev/null
@@ -1,73 +0,0 @@
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
5<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
6 targetNamespace="http://wixtoolset.org/schemas/v4/wi/actions"
7 xmlns="http://wixtoolset.org/schemas/v4/wi/actions">
8 <xs:annotation>
9 <xs:documentation>
10 Schema for describing standard actions in the Windows Installer.
11 </xs:documentation>
12 </xs:annotation>
13
14 <xs:element name="actions">
15 <xs:complexType>
16 <xs:sequence maxOccurs="unbounded">
17 <xs:element ref="action" />
18 </xs:sequence>
19 </xs:complexType>
20 </xs:element>
21
22 <xs:element name="action">
23 <xs:complexType>
24 <xs:attribute name="name" type="xs:string" use="required">
25 <xs:annotation>
26 <xs:documentation>Name of action</xs:documentation>
27 </xs:annotation>
28 </xs:attribute>
29 <xs:attribute name="condition" type="xs:string">
30 <xs:annotation>
31 <xs:documentation>Default condition for action</xs:documentation>
32 </xs:annotation>
33 </xs:attribute>
34 <xs:attribute name="sequence" type="xs:integer" use="required">
35 <xs:annotation>
36 <xs:documentation>Sequence of action</xs:documentation>
37 </xs:annotation>
38 </xs:attribute>
39 <xs:attribute name="AdminExecuteSequence" type="ActionsYesNoType">
40 <xs:annotation>
41 <xs:documentation>Specifies if action is allowed in AdminExecuteSequence</xs:documentation>
42 </xs:annotation>
43 </xs:attribute>
44 <xs:attribute name="AdminUISequence" type="ActionsYesNoType">
45 <xs:annotation>
46 <xs:documentation>Specifies if action is allowed in AdminUISequence</xs:documentation>
47 </xs:annotation>
48 </xs:attribute>
49 <xs:attribute name="AdvtExecuteSequence" type="ActionsYesNoType">
50 <xs:annotation>
51 <xs:documentation>Specifies if action is allowed in AdvtExecuteSequence</xs:documentation>
52 </xs:annotation>
53 </xs:attribute>
54 <xs:attribute name="InstallExecuteSequence" type="ActionsYesNoType">
55 <xs:annotation>
56 <xs:documentation>Specifies if action is allowed in InstallExecuteSequence</xs:documentation>
57 </xs:annotation>
58 </xs:attribute>
59 <xs:attribute name="InstallUISequence" type="ActionsYesNoType">
60 <xs:annotation>
61 <xs:documentation>Specifies if action is allowed in InstallUISequence</xs:documentation>
62 </xs:annotation>
63 </xs:attribute>
64 </xs:complexType>
65 </xs:element>
66
67 <xs:simpleType name="ActionsYesNoType">
68 <xs:restriction base="xs:NMTOKEN">
69 <xs:enumeration value="no" />
70 <xs:enumeration value="yes" />
71 </xs:restriction>
72 </xs:simpleType>
73</xs:schema>
diff --git a/src/WixToolset.Core.WindowsInstaller/Data/Xsd/tables.xsd b/src/WixToolset.Core.WindowsInstaller/Data/Xsd/tables.xsd
deleted file mode 100644
index f87471bb..00000000
--- a/src/WixToolset.Core.WindowsInstaller/Data/Xsd/tables.xsd
+++ /dev/null
@@ -1,248 +0,0 @@
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
5<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
6 targetNamespace="http://wixtoolset.org/schemas/v4/wi/tables"
7 xmlns="http://wixtoolset.org/schemas/v4/wi/tables">
8 <xs:annotation>
9 <xs:documentation>
10 Schema for describing table definitions in Windows Installer.
11 </xs:documentation>
12 </xs:annotation>
13
14 <xs:element name="tableDefinitions">
15 <xs:complexType>
16 <xs:sequence maxOccurs="unbounded">
17 <xs:element ref="tableDefinition" />
18 </xs:sequence>
19 </xs:complexType>
20 </xs:element>
21
22 <xs:element name="tableDefinition">
23 <xs:complexType>
24 <xs:sequence maxOccurs="unbounded">
25 <xs:element ref="columnDefinition" />
26 </xs:sequence>
27 <xs:attribute name="createSymbols" type="TablesYesNoType">
28 <xs:annotation>
29 <xs:documentation>Boolean whether rows in this table create symbols</xs:documentation>
30 </xs:annotation>
31 </xs:attribute>
32 <xs:attribute name="name" type="NameType" use="required">
33 <xs:annotation>
34 <xs:documentation>Name of table in Windows Installer database</xs:documentation>
35 </xs:annotation>
36 </xs:attribute>
37 <xs:attribute name="unreal" type="TablesYesNoType">
38 <xs:annotation>
39 <xs:documentation>Specifies if table is virtual or not</xs:documentation>
40 </xs:annotation>
41 </xs:attribute>
42 <xs:attribute name="bootstrapperApplicationData" type="TablesYesNoType">
43 <xs:annotation>
44 <xs:documentation>Specifies if the table is a part of the Bootstrapper Application Data manifest</xs:documentation>
45 </xs:annotation>
46 </xs:attribute>
47 </xs:complexType>
48 </xs:element>
49
50 <xs:element name="columnDefinition">
51 <xs:complexType>
52 <xs:attribute name="name" type="NameType" use="required">
53 <xs:annotation>
54 <xs:documentation>Name of column in Windows Installer table</xs:documentation>
55 </xs:annotation>
56 </xs:attribute>
57
58 <xs:attribute name="added" type="TablesYesNoType">
59 <xs:annotation>
60 <xs:documentation>Whether this column was added by a transform.</xs:documentation>
61 </xs:annotation>
62 </xs:attribute>
63
64 <xs:attribute name="type" type="ColumnDefinitionType" use="required">
65 <xs:annotation>
66 <xs:documentation>Type of column in Windows Installer table</xs:documentation>
67 </xs:annotation>
68 </xs:attribute>
69
70 <xs:attribute name="length" use="required">
71 <xs:annotation>
72 <xs:documentation>Type of column in Windows Installer table</xs:documentation>
73 </xs:annotation>
74 <xs:simpleType>
75 <xs:restriction base="xs:integer">
76 <xs:minInclusive value="0" />
77 <xs:maxInclusive value="255" />
78 </xs:restriction>
79 </xs:simpleType>
80 </xs:attribute>
81
82 <xs:attribute name="primaryKey" type="TablesYesNoType">
83 <xs:annotation>
84 <xs:documentation>Boolean whether column is primary key of Windows Installer table</xs:documentation>
85 </xs:annotation>
86 </xs:attribute>
87
88 <xs:attribute name="nullable" type="TablesYesNoType">
89 <xs:annotation>
90 <xs:documentation>Boolean whether column is nullable in Windows Installer table</xs:documentation>
91 </xs:annotation>
92 </xs:attribute>
93
94 <xs:attribute name="unreal" type="TablesYesNoType">
95 <xs:annotation>
96 <xs:documentation>Boolean whether column is virtual in Windows Installer table</xs:documentation>
97 </xs:annotation>
98 </xs:attribute>
99
100 <xs:attribute name="modularize" type="TablesModularizeType">
101 <xs:annotation>
102 <xs:documentation>Enumeration specifying how column should have the ModuleId appended</xs:documentation>
103 </xs:annotation>
104 </xs:attribute>
105
106 <xs:attribute name="localizable" type="TablesYesNoType">
107 <xs:annotation>
108 <xs:documentation>Set to "yes" in order to allow substitution for localized variables.</xs:documentation>
109 </xs:annotation>
110 </xs:attribute>
111
112 <xs:attribute name="minValue" type="xs:long">
113 <xs:annotation>
114 <xs:documentation>Minimum value for column in Windows Installer table</xs:documentation>
115 </xs:annotation>
116 </xs:attribute>
117
118 <xs:attribute name="maxValue" type="xs:long">
119 <xs:annotation>
120 <xs:documentation>Maximum value for column in Windows Installer table</xs:documentation>
121 </xs:annotation>
122 </xs:attribute>
123
124 <xs:attribute name="keyTable" type="NameType">
125 <xs:annotation>
126 <xs:documentation>Foreign key table for column in Windows Installer table</xs:documentation>
127 </xs:annotation>
128 </xs:attribute>
129
130 <xs:attribute name="keyColumn">
131 <xs:annotation>
132 <xs:documentation>Maximum value for column in Windows Installer table</xs:documentation>
133 </xs:annotation>
134 <xs:simpleType>
135 <xs:restriction base="xs:integer">
136 <xs:minInclusive value="1" />
137 <xs:maxInclusive value="32" />
138 </xs:restriction>
139 </xs:simpleType>
140 </xs:attribute>
141
142 <xs:attribute name="category" type="TablesCategoryType">
143 <xs:annotation>
144 <xs:documentation>Specific column data types for column</xs:documentation>
145 </xs:annotation>
146 </xs:attribute>
147
148 <xs:attribute name="set" type="TablesSetType">
149 <xs:annotation>
150 <xs:documentation>List of permissible values for the column</xs:documentation>
151 </xs:annotation>
152 </xs:attribute>
153
154 <xs:attribute name="description" type="xs:string">
155 <xs:annotation>
156 <xs:documentation>Description of column</xs:documentation>
157 </xs:annotation>
158 </xs:attribute>
159
160 <xs:attribute name="escapeIdtCharacters" type="TablesYesNoType">
161 <xs:annotation>
162 <xs:documentation>Set to "yes" in order to make the idt exporter escape whitespace characters \r, \n, and \t.</xs:documentation>
163 </xs:annotation>
164 </xs:attribute>
165
166 <xs:attribute name="useCData" type="TablesYesNoType">
167 <xs:annotation>
168 <xs:documentation>Set to "yes" in order to make the Intermediate and Output objects wrap their data in a CDATA element to preserve whitespace.</xs:documentation>
169 </xs:annotation>
170 </xs:attribute>
171 </xs:complexType>
172 </xs:element>
173
174 <xs:simpleType name="NameType">
175 <xs:restriction base="xs:string">
176 <xs:minLength value="1" />
177 <xs:maxLength value="64" />
178 </xs:restriction>
179 </xs:simpleType>
180
181 <xs:simpleType name="ColumnDefinitionType">
182 <xs:restriction base="xs:NMTOKEN">
183 <xs:enumeration value="string" />
184 <xs:enumeration value="localized" />
185 <xs:enumeration value="number" />
186 <xs:enumeration value="object" />
187 <xs:enumeration value="preserved" />
188 </xs:restriction>
189 </xs:simpleType>
190
191 <xs:simpleType name="TablesYesNoType">
192 <xs:restriction base="xs:NMTOKEN">
193 <xs:enumeration value="yes" />
194 <xs:enumeration value="no" />
195 </xs:restriction>
196 </xs:simpleType>
197
198 <xs:simpleType name="TablesModularizeType">
199 <xs:restriction base="xs:NMTOKEN">
200 <xs:enumeration value="column" />
201 <xs:enumeration value="companionFile" />
202 <xs:enumeration value="condition" />
203 <xs:enumeration value="controlEventArgument" />
204 <xs:enumeration value="controlText" />
205 <xs:enumeration value="icon" />
206 <xs:enumeration value="none" />
207 <xs:enumeration value="property" />
208 <xs:enumeration value="semicolonDelimited" />
209 </xs:restriction>
210 </xs:simpleType>
211
212 <xs:simpleType name="TablesCategoryType">
213 <xs:restriction base="xs:NMTOKEN">
214 <xs:enumeration value="text" />
215 <xs:enumeration value="upperCase" />
216 <xs:enumeration value="lowerCase" />
217 <xs:enumeration value="integer" />
218 <xs:enumeration value="doubleInteger" />
219 <xs:enumeration value="timeDate" />
220 <xs:enumeration value="identifier" />
221 <xs:enumeration value="property" />
222 <xs:enumeration value="filename" />
223 <xs:enumeration value="wildCardFilename" />
224 <xs:enumeration value="path" />
225 <xs:enumeration value="paths" />
226 <xs:enumeration value="anyPath" />
227 <xs:enumeration value="defaultDir" />
228 <xs:enumeration value="regPath" />
229 <xs:enumeration value="formatted" />
230 <xs:enumeration value="formattedSddl" />
231 <xs:enumeration value="template" />
232 <xs:enumeration value="condition" />
233 <xs:enumeration value="guid" />
234 <xs:enumeration value="version" />
235 <xs:enumeration value="language" />
236 <xs:enumeration value="binary" />
237 <xs:enumeration value="customSource" />
238 <xs:enumeration value="cabinet" />
239 <xs:enumeration value="shortcut" />
240 </xs:restriction>
241 </xs:simpleType>
242
243 <xs:simpleType name="TablesSetType">
244 <xs:restriction base="xs:string">
245 <xs:pattern value="\w+(;\w+)*" />
246 </xs:restriction>
247 </xs:simpleType>
248</xs:schema>
diff --git a/src/WixToolset.Core.WindowsInstaller/Decompile/DecompileMsiOrMsmCommand.cs b/src/WixToolset.Core.WindowsInstaller/Decompile/DecompileMsiOrMsmCommand.cs
index 45b669b9..849cb361 100644
--- a/src/WixToolset.Core.WindowsInstaller/Decompile/DecompileMsiOrMsmCommand.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Decompile/DecompileMsiOrMsmCommand.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
3namespace WixToolset.Core.WindowsInstaller.Unbind 3namespace WixToolset.Core.WindowsInstaller.Decompile
4{ 4{
5 using System; 5 using System;
6 using System.Collections.Generic; 6 using System.Collections.Generic;
@@ -8,6 +8,7 @@ namespace WixToolset.Core.WindowsInstaller.Unbind
8 using System.IO; 8 using System.IO;
9 using System.Linq; 9 using System.Linq;
10 using WixToolset.Core.WindowsInstaller.Msi; 10 using WixToolset.Core.WindowsInstaller.Msi;
11 using WixToolset.Core.WindowsInstaller.Unbind;
11 using WixToolset.Data; 12 using WixToolset.Data;
12 using WixToolset.Data.WindowsInstaller; 13 using WixToolset.Data.WindowsInstaller;
13 using WixToolset.Extensibility; 14 using WixToolset.Extensibility;
@@ -43,11 +44,13 @@ namespace WixToolset.Core.WindowsInstaller.Unbind
43 Directory.Delete(this.Context.ExtractFolder, true); 44 Directory.Delete(this.Context.ExtractFolder, true);
44 } 45 }
45 46
46 var unbindCommand = new UnbindDatabaseCommand(this.Messaging, database, this.Context.DecompilePath, this.Context.DecompileType, this.Context.ExtractFolder, this.Context.IntermediateFolder, this.Context.IsAdminImage, suppressDemodularization: false, skipSummaryInfo: false); 47 var backendHelper = this.Context.ServiceProvider.GetService<IBackendHelper>();
48
49 var unbindCommand = new UnbindDatabaseCommand(this.Messaging, backendHelper, database, this.Context.DecompilePath, this.Context.DecompileType, this.Context.ExtractFolder, this.Context.IntermediateFolder, this.Context.IsAdminImage, suppressDemodularization: false, skipSummaryInfo: false);
47 var output = unbindCommand.Execute(); 50 var output = unbindCommand.Execute();
48 var extractedFilePaths = new List<string>(unbindCommand.ExportedFiles); 51 var extractedFilePaths = new List<string>(unbindCommand.ExportedFiles);
49 52
50 var decompiler = new Decompiler(this.Messaging, this.Extensions, this.Context.BaseSourcePath, this.Context.SuppressCustomTables, this.Context.SuppressDroppingEmptyTables, this.Context.SuppressUI, this.Context.TreatProductAsModule); 53 var decompiler = new Decompiler(this.Messaging, backendHelper, this.Extensions, this.Context.BaseSourcePath, this.Context.SuppressCustomTables, this.Context.SuppressDroppingEmptyTables, this.Context.SuppressUI, this.Context.TreatProductAsModule);
51 result.Document = decompiler.Decompile(output); 54 result.Document = decompiler.Decompile(output);
52 55
53 result.Platform = GetPlatformFromOutput(output); 56 result.Platform = GetPlatformFromOutput(output);
diff --git a/src/WixToolset.Core.WindowsInstaller/Decompile/Decompiler.cs b/src/WixToolset.Core.WindowsInstaller/Decompile/Decompiler.cs
index 2cc61666..8e477dd1 100644
--- a/src/WixToolset.Core.WindowsInstaller/Decompile/Decompiler.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Decompile/Decompiler.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
3namespace WixToolset.Core.WindowsInstaller 3namespace WixToolset.Core.WindowsInstaller.Decompile
4{ 4{
5 using System; 5 using System;
6 using System.Collections.Generic; 6 using System.Collections.Generic;
@@ -10,8 +10,6 @@ namespace WixToolset.Core.WindowsInstaller
10 using System.Text; 10 using System.Text;
11 using System.Text.RegularExpressions; 11 using System.Text.RegularExpressions;
12 using System.Xml.Linq; 12 using System.Xml.Linq;
13 using WixToolset.Core;
14 using WixToolset.Core.WindowsInstaller.Decompile;
15 using WixToolset.Data; 13 using WixToolset.Data;
16 using WixToolset.Data.Symbols; 14 using WixToolset.Data.Symbols;
17 using WixToolset.Data.WindowsInstaller; 15 using WixToolset.Data.WindowsInstaller;
@@ -45,9 +43,10 @@ namespace WixToolset.Core.WindowsInstaller
45 /// <summary> 43 /// <summary>
46 /// Creates a new decompiler object with a default set of table definitions. 44 /// Creates a new decompiler object with a default set of table definitions.
47 /// </summary> 45 /// </summary>
48 public Decompiler(IMessaging messaging, IEnumerable<IWindowsInstallerBackendDecompilerExtension> extensions, string baseSourcePath, bool suppressCustomTables, bool suppressDroppingEmptyTables, bool suppressUI, bool treatProductAsModule) 46 public Decompiler(IMessaging messaging, IBackendHelper backendHelper, IEnumerable<IWindowsInstallerBackendDecompilerExtension> extensions, string baseSourcePath, bool suppressCustomTables, bool suppressDroppingEmptyTables, bool suppressUI, bool treatProductAsModule)
49 { 47 {
50 this.Messaging = messaging; 48 this.Messaging = messaging;
49 this.BackendHelper = backendHelper;
51 this.Extensions = extensions; 50 this.Extensions = extensions;
52 this.BaseSourcePath = baseSourcePath ?? "SourceDir"; 51 this.BaseSourcePath = baseSourcePath ?? "SourceDir";
53 this.SuppressCustomTables = suppressCustomTables; 52 this.SuppressCustomTables = suppressCustomTables;
@@ -63,6 +62,8 @@ namespace WixToolset.Core.WindowsInstaller
63 62
64 private IMessaging Messaging { get; } 63 private IMessaging Messaging { get; }
65 64
65 private IBackendHelper BackendHelper { get; }
66
66 private IEnumerable<IWindowsInstallerBackendDecompilerExtension> Extensions { get; } 67 private IEnumerable<IWindowsInstallerBackendDecompilerExtension> Extensions { get; }
67 68
68 private Dictionary<string, IWindowsInstallerBackendDecompilerExtension> ExtensionsByTableName { get; } 69 private Dictionary<string, IWindowsInstallerBackendDecompilerExtension> ExtensionsByTableName { get; }
@@ -2196,11 +2197,11 @@ namespace WixToolset.Core.WindowsInstaller
2196 { 2197 {
2197 foreach (var launchRow in launchConditionTable.Rows) 2198 foreach (var launchRow in launchConditionTable.Rows)
2198 { 2199 {
2199 if (Common.DowngradePreventedCondition == Convert.ToString(launchRow[0])) 2200 if (WixUpgradeConstants.DowngradePreventedCondition == Convert.ToString(launchRow[0]))
2200 { 2201 {
2201 downgradeErrorMessage = Convert.ToString(launchRow[1]); 2202 downgradeErrorMessage = Convert.ToString(launchRow[1]);
2202 } 2203 }
2203 else if (Common.UpgradePreventedCondition == Convert.ToString(launchRow[0])) 2204 else if (WixUpgradeConstants.UpgradePreventedCondition == Convert.ToString(launchRow[0]))
2204 { 2205 {
2205 disallowUpgradeErrorMessage = Convert.ToString(launchRow[1]); 2206 disallowUpgradeErrorMessage = Convert.ToString(launchRow[1]);
2206 } 2207 }
@@ -2213,7 +2214,7 @@ namespace WixToolset.Core.WindowsInstaller
2213 2214
2214 foreach (UpgradeRow upgradeRow in upgradeTable.Rows) 2215 foreach (UpgradeRow upgradeRow in upgradeTable.Rows)
2215 { 2216 {
2216 if (Common.UpgradeDetectedProperty == upgradeRow.ActionProperty) 2217 if (WixUpgradeConstants.UpgradeDetectedProperty == upgradeRow.ActionProperty)
2217 { 2218 {
2218 var attr = upgradeRow.Attributes; 2219 var attr = upgradeRow.Attributes;
2219 var removeFeatures = upgradeRow.Remove; 2220 var removeFeatures = upgradeRow.Remove;
@@ -2239,7 +2240,7 @@ namespace WixToolset.Core.WindowsInstaller
2239 xMajorUpgrade.SetAttributeValue("RemoveFeatures", removeFeatures); 2240 xMajorUpgrade.SetAttributeValue("RemoveFeatures", removeFeatures);
2240 } 2241 }
2241 } 2242 }
2242 else if (Common.DowngradeDetectedProperty == upgradeRow.ActionProperty) 2243 else if (WixUpgradeConstants.DowngradeDetectedProperty == upgradeRow.ActionProperty)
2243 { 2244 {
2244 xMajorUpgrade = xMajorUpgrade ?? new XElement(Names.MajorUpgradeElement); 2245 xMajorUpgrade = xMajorUpgrade ?? new XElement(Names.MajorUpgradeElement);
2245 xMajorUpgrade.SetAttributeValue("DowngradeErrorMessage", downgradeErrorMessage); 2246 xMajorUpgrade.SetAttributeValue("DowngradeErrorMessage", downgradeErrorMessage);
@@ -4291,7 +4292,7 @@ namespace WixToolset.Core.WindowsInstaller
4291 var xDirectory = new XElement(Names.DirectoryElement, 4292 var xDirectory = new XElement(Names.DirectoryElement,
4292 new XAttribute("Id", id)); 4293 new XAttribute("Id", id));
4293 4294
4294 var names = Common.GetNames(row.FieldAsString(2)); 4295 var names = this.BackendHelper.SplitMsiFileName(row.FieldAsString(2));
4295 4296
4296 if (String.Equals(id, "TARGETDIR", StringComparison.Ordinal) && !String.Equals(names[0], "SourceDir", StringComparison.Ordinal)) 4297 if (String.Equals(id, "TARGETDIR", StringComparison.Ordinal) && !String.Equals(names[0], "SourceDir", StringComparison.Ordinal))
4297 { 4298 {
@@ -4396,7 +4397,7 @@ namespace WixToolset.Core.WindowsInstaller
4396 4397
4397 if (!row.IsColumnNull(3)) 4398 if (!row.IsColumnNull(3))
4398 { 4399 {
4399 var names = Common.GetNames(row.FieldAsString(3)); 4400 var names = this.BackendHelper.SplitMsiFileName(row.FieldAsString(3));
4400 if (null != names[0] && null != names[1]) 4401 if (null != names[0] && null != names[1])
4401 { 4402 {
4402 xCopyFile.SetAttributeValue("DestinationShortName", names[0]); 4403 xCopyFile.SetAttributeValue("DestinationShortName", names[0]);
@@ -4782,7 +4783,7 @@ namespace WixToolset.Core.WindowsInstaller
4782 WindowsInstallerConstants.MsidbFileAttributesVital != (fileRow.Attributes & WindowsInstallerConstants.MsidbFileAttributesVital) ? new XAttribute("Vital", "no") : null, 4783 WindowsInstallerConstants.MsidbFileAttributesVital != (fileRow.Attributes & WindowsInstallerConstants.MsidbFileAttributesVital) ? new XAttribute("Vital", "no") : null,
4783 null != fileRow.Version && 0 < fileRow.Version.Length && !Char.IsDigit(fileRow.Version[0]) ? new XAttribute("CompanionFile", fileRow.Version) : null); 4784 null != fileRow.Version && 0 < fileRow.Version.Length && !Char.IsDigit(fileRow.Version[0]) ? new XAttribute("CompanionFile", fileRow.Version) : null);
4784 4785
4785 var names = Common.GetNames(fileRow.FileName); 4786 var names = this.BackendHelper.SplitMsiFileName(fileRow.FileName);
4786 if (null != names[0] && null != names[1]) 4787 if (null != names[0] && null != names[1])
4787 { 4788 {
4788 xFile.SetAttributeValue("ShortName", names[0]); 4789 xFile.SetAttributeValue("ShortName", names[0]);
@@ -4904,7 +4905,7 @@ namespace WixToolset.Core.WindowsInstaller
4904 new XAttribute("Value", row.FieldAsString(5)), 4905 new XAttribute("Value", row.FieldAsString(5)),
4905 row.IsColumnNull(2) ? null : new XAttribute("Directory", row.FieldAsString(2))); 4906 row.IsColumnNull(2) ? null : new XAttribute("Directory", row.FieldAsString(2)));
4906 4907
4907 var names = Common.GetNames(row.FieldAsString(1)); 4908 var names = this.BackendHelper.SplitMsiFileName(row.FieldAsString(1));
4908 4909
4909 if (null != names[0]) 4910 if (null != names[0])
4910 { 4911 {
@@ -4957,7 +4958,7 @@ namespace WixToolset.Core.WindowsInstaller
4957 new XAttribute("Key", row.FieldAsString(3)), 4958 new XAttribute("Key", row.FieldAsString(3)),
4958 row.IsColumnNull(4) || row.FieldAsInteger(4) == 0 ? null : new XAttribute("Field", row.FieldAsInteger(4))); 4959 row.IsColumnNull(4) || row.FieldAsInteger(4) == 0 ? null : new XAttribute("Field", row.FieldAsInteger(4)));
4959 4960
4960 var names = Common.GetNames(row.FieldAsString(1)); 4961 var names = this.BackendHelper.SplitMsiFileName(row.FieldAsString(1));
4961 if (null != names[0] && null != names[1]) 4962 if (null != names[0] && null != names[1])
4962 { 4963 {
4963 xIniFileSearch.SetAttributeValue("ShortName", names[0]); 4964 xIniFileSearch.SetAttributeValue("ShortName", names[0]);
@@ -5014,7 +5015,7 @@ namespace WixToolset.Core.WindowsInstaller
5014 { 5015 {
5015 foreach (var row in table.Rows) 5016 foreach (var row in table.Rows)
5016 { 5017 {
5017 if (Common.DowngradePreventedCondition == row.FieldAsString(0) || Common.UpgradePreventedCondition == row.FieldAsString(0)) 5018 if (WixUpgradeConstants.DowngradePreventedCondition == row.FieldAsString(0) || WixUpgradeConstants.UpgradePreventedCondition == row.FieldAsString(0))
5018 { 5019 {
5019 continue; // MajorUpgrade rows processed in FinalizeUpgradeTable 5020 continue; // MajorUpgrade rows processed in FinalizeUpgradeTable
5020 } 5021 }
@@ -5101,13 +5102,13 @@ namespace WixToolset.Core.WindowsInstaller
5101 switch (row.FieldAsString(1)) 5102 switch (row.FieldAsString(1))
5102 { 5103 {
5103 case "CreateFolder": 5104 case "CreateFolder":
5104 specialPermissions = Common.FolderPermissions; 5105 specialPermissions = LockPermissionConstants.FolderPermissions;
5105 break; 5106 break;
5106 case "File": 5107 case "File":
5107 specialPermissions = Common.FilePermissions; 5108 specialPermissions = LockPermissionConstants.FilePermissions;
5108 break; 5109 break;
5109 case "Registry": 5110 case "Registry":
5110 specialPermissions = Common.RegistryPermissions; 5111 specialPermissions = LockPermissionConstants.RegistryPermissions;
5111 break; 5112 break;
5112 default: 5113 default:
5113 this.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, row.Table.Name, row.Fields[1].Column.Name, row[1])); 5114 this.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, row.Table.Name, row.Fields[1].Column.Name, row[1]));
@@ -5129,13 +5130,13 @@ namespace WixToolset.Core.WindowsInstaller
5129 { 5130 {
5130 name = "SpecificRightsAll"; 5131 name = "SpecificRightsAll";
5131 } 5132 }
5132 else if (28 > i && Common.StandardPermissions.Length > (i - 16)) 5133 else if (28 > i && LockPermissionConstants.StandardPermissions.Length > (i - 16))
5133 { 5134 {
5134 name = Common.StandardPermissions[i - 16]; 5135 name = LockPermissionConstants.StandardPermissions[i - 16];
5135 } 5136 }
5136 else if (0 <= (i - 28) && Common.GenericPermissions.Length > (i - 28)) 5137 else if (0 <= (i - 28) && LockPermissionConstants.GenericPermissions.Length > (i - 28))
5137 { 5138 {
5138 name = Common.GenericPermissions[i - 28]; 5139 name = LockPermissionConstants.GenericPermissions[i - 28];
5139 } 5140 }
5140 5141
5141 if (null == name) 5142 if (null == name)
@@ -5412,7 +5413,7 @@ namespace WixToolset.Core.WindowsInstaller
5412 5413
5413 if (!row.IsColumnNull(3)) 5414 if (!row.IsColumnNull(3))
5414 { 5415 {
5415 var names = Common.GetNames(row.FieldAsString(3)); 5416 var names = this.BackendHelper.SplitMsiFileName(row.FieldAsString(3));
5416 if (null != names[0] && null != names[1]) 5417 if (null != names[0] && null != names[1])
5417 { 5418 {
5418 xCopyFile.SetAttributeValue("DestinationShortName", names[0]); 5419 xCopyFile.SetAttributeValue("DestinationShortName", names[0]);
@@ -5922,17 +5923,17 @@ namespace WixToolset.Core.WindowsInstaller
5922 case "OptimizeCA": 5923 case "OptimizeCA":
5923 var xOptimizeCustomActions = new XElement(Names.OptimizeCustomActionsElement); 5924 var xOptimizeCustomActions = new XElement(Names.OptimizeCustomActionsElement);
5924 var optimizeCA = Int32.Parse(value, CultureInfo.InvariantCulture); 5925 var optimizeCA = Int32.Parse(value, CultureInfo.InvariantCulture);
5925 if (0 != (Convert.ToInt32(OptimizeCA.SkipAssignment) & optimizeCA)) 5926 if (0 != (Convert.ToInt32(OptimizeCAFlags.SkipAssignment) & optimizeCA))
5926 { 5927 {
5927 xOptimizeCustomActions.SetAttributeValue("SkipAssignment", "yes"); 5928 xOptimizeCustomActions.SetAttributeValue("SkipAssignment", "yes");
5928 } 5929 }
5929 5930
5930 if (0 != (Convert.ToInt32(OptimizeCA.SkipImmediate) & optimizeCA)) 5931 if (0 != (Convert.ToInt32(OptimizeCAFlags.SkipImmediate) & optimizeCA))
5931 { 5932 {
5932 xOptimizeCustomActions.SetAttributeValue("SkipImmediate", "yes"); 5933 xOptimizeCustomActions.SetAttributeValue("SkipImmediate", "yes");
5933 } 5934 }
5934 5935
5935 if (0 != (Convert.ToInt32(OptimizeCA.SkipDeferred) & optimizeCA)) 5936 if (0 != (Convert.ToInt32(OptimizeCAFlags.SkipDeferred) & optimizeCA))
5936 { 5937 {
5937 xOptimizeCustomActions.SetAttributeValue("SkipDeferred", "yes"); 5938 xOptimizeCustomActions.SetAttributeValue("SkipDeferred", "yes");
5938 } 5939 }
@@ -6165,7 +6166,7 @@ namespace WixToolset.Core.WindowsInstaller
6165 { 6166 {
6166 foreach (var propertyId in value.Split(';')) 6167 foreach (var propertyId in value.Split(';'))
6167 { 6168 {
6168 if (Common.DowngradeDetectedProperty == propertyId || Common.UpgradeDetectedProperty == propertyId) 6169 if (WixUpgradeConstants.DowngradeDetectedProperty == propertyId || WixUpgradeConstants.UpgradeDetectedProperty == propertyId)
6169 { 6170 {
6170 continue; 6171 continue;
6171 } 6172 }
@@ -6547,7 +6548,7 @@ namespace WixToolset.Core.WindowsInstaller
6547 var xRemoveFile = new XElement(Names.RemoveFileElement, 6548 var xRemoveFile = new XElement(Names.RemoveFileElement,
6548 new XAttribute("Id", row.FieldAsString(0))); 6549 new XAttribute("Id", row.FieldAsString(0)));
6549 6550
6550 var names = Common.GetNames(row.FieldAsString(2)); 6551 var names = this.BackendHelper.SplitMsiFileName(row.FieldAsString(2));
6551 if (null != names[0] && null != names[1]) 6552 if (null != names[0] && null != names[1])
6552 { 6553 {
6553 xRemoveFile.SetAttributeValue("ShortName", names[0]); 6554 xRemoveFile.SetAttributeValue("ShortName", names[0]);
@@ -6597,7 +6598,7 @@ namespace WixToolset.Core.WindowsInstaller
6597 new XAttribute("Key", row.FieldAsString(4)), 6598 new XAttribute("Key", row.FieldAsString(4)),
6598 XAttributeIfNotNull("Value", row, 5)); 6599 XAttributeIfNotNull("Value", row, 5));
6599 6600
6600 var names = Common.GetNames(row.FieldAsString(1)); 6601 var names = this.BackendHelper.SplitMsiFileName(row.FieldAsString(1));
6601 if (null != names[0] && null != names[1]) 6602 if (null != names[0] && null != names[1])
6602 { 6603 {
6603 xIniFile.SetAttributeValue("ShortName", names[0]); 6604 xIniFile.SetAttributeValue("ShortName", names[0]);
@@ -6941,7 +6942,7 @@ namespace WixToolset.Core.WindowsInstaller
6941 XAttributeIfNotNull("IconIndex", row, 9), 6942 XAttributeIfNotNull("IconIndex", row, 9),
6942 XAttributeIfNotNull("WorkingDirectory", row, 11)); 6943 XAttributeIfNotNull("WorkingDirectory", row, 11));
6943 6944
6944 var names = Common.GetNames(row.FieldAsString(2)); 6945 var names = this.BackendHelper.SplitMsiFileName(row.FieldAsString(2));
6945 if (null != names[0] && null != names[1]) 6946 if (null != names[0] && null != names[1])
6946 { 6947 {
6947 xShortcut.SetAttributeValue("ShortName", names[0]); 6948 xShortcut.SetAttributeValue("ShortName", names[0]);
@@ -7016,11 +7017,11 @@ namespace WixToolset.Core.WindowsInstaller
7016 XAttributeIfNotNull("MaxSize", row, 5), 7017 XAttributeIfNotNull("MaxSize", row, 5),
7017 XAttributeIfNotNull("Languages", row, 8)); 7018 XAttributeIfNotNull("Languages", row, 8));
7018 7019
7019 var names = Common.GetNames(row.FieldAsString(1)); 7020 var names = this.BackendHelper.SplitMsiFileName(row.FieldAsString(1));
7020 if (null != names[0]) 7021 if (null != names[0])
7021 { 7022 {
7022 // it is permissable to just have a long name 7023 // it is permissable to just have a long name
7023 if (!Common.IsValidShortFilename(names[0], false) && null == names[1]) 7024 if (!this.BackendHelper.IsValidShortFilename(names[0], false) && null == names[1])
7024 { 7025 {
7025 fileSearch.SetAttributeValue("Name", names[0]); 7026 fileSearch.SetAttributeValue("Name", names[0]);
7026 } 7027 }
@@ -7248,7 +7249,7 @@ namespace WixToolset.Core.WindowsInstaller
7248 7249
7249 foreach (UpgradeRow upgradeRow in table.Rows) 7250 foreach (UpgradeRow upgradeRow in table.Rows)
7250 { 7251 {
7251 if (Common.UpgradeDetectedProperty == upgradeRow.ActionProperty || Common.DowngradeDetectedProperty == upgradeRow.ActionProperty) 7252 if (WixUpgradeConstants.UpgradeDetectedProperty == upgradeRow.ActionProperty || WixUpgradeConstants.DowngradeDetectedProperty == upgradeRow.ActionProperty)
7252 { 7253 {
7253 continue; // MajorUpgrade rows processed in FinalizeUpgradeTable 7254 continue; // MajorUpgrade rows processed in FinalizeUpgradeTable
7254 } 7255 }
diff --git a/src/WixToolset.Core.WindowsInstaller/ExtensibilityServices/WindowsInstallerBackendHelper.cs b/src/WixToolset.Core.WindowsInstaller/ExtensibilityServices/WindowsInstallerBackendHelper.cs
index 09194d4e..18060ca7 100644
--- a/src/WixToolset.Core.WindowsInstaller/ExtensibilityServices/WindowsInstallerBackendHelper.cs
+++ b/src/WixToolset.Core.WindowsInstaller/ExtensibilityServices/WindowsInstallerBackendHelper.cs
@@ -3,9 +3,12 @@
3namespace WixToolset.Core.WindowsInstaller.ExtensibilityServices 3namespace WixToolset.Core.WindowsInstaller.ExtensibilityServices
4{ 4{
5 using System; 5 using System;
6 using System.Collections.Generic;
6 using System.Linq; 7 using System.Linq;
7 using WixToolset.Data; 8 using WixToolset.Data;
9 using WixToolset.Data.Symbols;
8 using WixToolset.Data.WindowsInstaller; 10 using WixToolset.Data.WindowsInstaller;
11 using WixToolset.Data.WindowsInstaller.Rows;
9 using WixToolset.Extensibility.Data; 12 using WixToolset.Extensibility.Data;
10 using WixToolset.Extensibility.Services; 13 using WixToolset.Extensibility.Services;
11 14
@@ -20,14 +23,44 @@ namespace WixToolset.Core.WindowsInstaller.ExtensibilityServices
20 23
21 #region IBackendHelper interfaces 24 #region IBackendHelper interfaces
22 25
26 public IFileFacade CreateFileFacade(FileSymbol file, AssemblySymbol assembly) => this.backendHelper.CreateFileFacade(file, assembly);
27
28 public IFileFacade CreateFileFacade(FileRow fileRow) => this.backendHelper.CreateFileFacade(fileRow);
29
30 public IFileFacade CreateFileFacadeFromMergeModule(FileSymbol fileSymbol) => this.backendHelper.CreateFileFacadeFromMergeModule(fileSymbol);
31
23 public IFileTransfer CreateFileTransfer(string source, string destination, bool move, SourceLineNumber sourceLineNumbers = null) => this.backendHelper.CreateFileTransfer(source, destination, move, sourceLineNumbers); 32 public IFileTransfer CreateFileTransfer(string source, string destination, bool move, SourceLineNumber sourceLineNumbers = null) => this.backendHelper.CreateFileTransfer(source, destination, move, sourceLineNumbers);
24 33
34 public string CreateGuid() => this.backendHelper.CreateGuid();
35
25 public string CreateGuid(Guid namespaceGuid, string value) => this.backendHelper.CreateGuid(namespaceGuid, value); 36 public string CreateGuid(Guid namespaceGuid, string value) => this.backendHelper.CreateGuid(namespaceGuid, value);
26 37
27 public IResolvedDirectory CreateResolvedDirectory(string directoryParent, string name) => this.backendHelper.CreateResolvedDirectory(directoryParent, name); 38 public IResolvedDirectory CreateResolvedDirectory(string directoryParent, string name) => this.backendHelper.CreateResolvedDirectory(directoryParent, name);
28 39
40 public IEnumerable<ITrackedFile> ExtractEmbeddedFiles(IEnumerable<IExpectedExtractFile> embeddedFiles) => this.backendHelper.ExtractEmbeddedFiles(embeddedFiles);
41
42 public string GenerateIdentifier(string prefix, params string[] args) => this.backendHelper.GenerateIdentifier(prefix, args);
43
29 public string GetCanonicalRelativePath(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string relativePath) => this.backendHelper.GetCanonicalRelativePath(sourceLineNumbers, elementName, attributeName, relativePath); 44 public string GetCanonicalRelativePath(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string relativePath) => this.backendHelper.GetCanonicalRelativePath(sourceLineNumbers, elementName, attributeName, relativePath);
30 45
46 public int GetValidCodePage(string value, bool allowNoChange, bool onlyAnsi = false, SourceLineNumber sourceLineNumbers = null) => this.backendHelper.GetValidCodePage(value, allowNoChange, onlyAnsi, sourceLineNumbers);
47
48 public string GetMsiFileName(string value, bool source, bool longName) => this.backendHelper.GetMsiFileName(value, source, longName);
49
50 public bool IsValidBinderVariable(string variable) => this.backendHelper.IsValidBinderVariable(variable);
51
52 public bool IsValidFourPartVersion(string version) => this.backendHelper.IsValidFourPartVersion(version);
53
54 public bool IsValidIdentifier(string id) => this.backendHelper.IsValidIdentifier(id);
55
56 public bool IsValidLongFilename(string filename, bool allowWildcards, bool allowRelative) => this.backendHelper.IsValidLongFilename(filename, allowWildcards, allowRelative);
57
58 public bool IsValidShortFilename(string filename, bool allowWildcards) => this.backendHelper.IsValidShortFilename(filename, allowWildcards);
59
60 public void ResolveDelayedFields(IEnumerable<IDelayedField> delayedFields, Dictionary<string, string> variableCache) => this.backendHelper.ResolveDelayedFields(delayedFields, variableCache);
61
62 public string[] SplitMsiFileName(string value) => this.backendHelper.SplitMsiFileName(value);
63
31 public ITrackedFile TrackFile(string path, TrackedFileType type, SourceLineNumber sourceLineNumbers = null) => this.backendHelper.TrackFile(path, type, sourceLineNumbers); 64 public ITrackedFile TrackFile(string path, TrackedFileType type, SourceLineNumber sourceLineNumbers = null) => this.backendHelper.TrackFile(path, type, sourceLineNumbers);
32 65
33 #endregion 66 #endregion
diff --git a/src/WixToolset.Core.WindowsInstaller/Inscribe/InscribeMsiPackageCommand.cs b/src/WixToolset.Core.WindowsInstaller/Inscribe/InscribeMsiPackageCommand.cs
index 256d3476..19869cfa 100644
--- a/src/WixToolset.Core.WindowsInstaller/Inscribe/InscribeMsiPackageCommand.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Inscribe/InscribeMsiPackageCommand.cs
@@ -21,6 +21,7 @@ namespace WixToolset.Core.WindowsInstaller.Inscribe
21 { 21 {
22 this.Context = context; 22 this.Context = context;
23 this.Messaging = context.ServiceProvider.GetService<IMessaging>(); 23 this.Messaging = context.ServiceProvider.GetService<IMessaging>();
24 this.WindowsInstallerBackendHelper = context.ServiceProvider.GetService<IWindowsInstallerBackendHelper>();
24 this.TableDefinitions = new TableDefinitionCollection(WindowsInstallerTableDefinitions.All); 25 this.TableDefinitions = new TableDefinitionCollection(WindowsInstallerTableDefinitions.All);
25 } 26 }
26 27
@@ -28,6 +29,8 @@ namespace WixToolset.Core.WindowsInstaller.Inscribe
28 29
29 private IMessaging Messaging { get; } 30 private IMessaging Messaging { get; }
30 31
32 private IWindowsInstallerBackendHelper WindowsInstallerBackendHelper { get; }
33
31 private TableDefinitionCollection TableDefinitions { get; } 34 private TableDefinitionCollection TableDefinitions { get; }
32 35
33 public bool Execute() 36 public bool Execute()
@@ -197,7 +200,7 @@ namespace WixToolset.Core.WindowsInstaller.Inscribe
197 if (!certificates.ContainsKey(cert2.Thumbprint)) 200 if (!certificates.ContainsKey(cert2.Thumbprint))
198 { 201 {
199 // generate a stable identifier 202 // generate a stable identifier
200 var certificateGeneratedId = Common.GenerateIdentifier("cer", cert2.Thumbprint); 203 var certificateGeneratedId = this.WindowsInstallerBackendHelper.GenerateIdentifier("cer", cert2.Thumbprint);
201 204
202 // Add it to our "add to MsiDigitalCertificate" table dictionary 205 // Add it to our "add to MsiDigitalCertificate" table dictionary
203 var digitalCertificateRow = digitalCertificateTable.CreateRow(null); 206 var digitalCertificateRow = digitalCertificateTable.CreateRow(null);
diff --git a/src/WixToolset.Core.WindowsInstaller/Melter.cs b/src/WixToolset.Core.WindowsInstaller/Melter.cs
index 4e4d9e4e..29e19e49 100644
--- a/src/WixToolset.Core.WindowsInstaller/Melter.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Melter.cs
@@ -18,7 +18,7 @@ namespace WixToolset
18 /// </summary> 18 /// </summary>
19 public sealed class Melter 19 public sealed class Melter
20 { 20 {
21#if TODO 21#if TODO_MELT
22 private MelterCore core; 22 private MelterCore core;
23 private Decompiler decompiler; 23 private Decompiler decompiler;
24 24
diff --git a/src/WixToolset.Core.WindowsInstaller/MsiBackend.cs b/src/WixToolset.Core.WindowsInstaller/MsiBackend.cs
index cbd58381..a6cf4f60 100644
--- a/src/WixToolset.Core.WindowsInstaller/MsiBackend.cs
+++ b/src/WixToolset.Core.WindowsInstaller/MsiBackend.cs
@@ -3,6 +3,7 @@
3namespace WixToolset.Core.WindowsInstaller 3namespace WixToolset.Core.WindowsInstaller
4{ 4{
5 using WixToolset.Core.WindowsInstaller.Bind; 5 using WixToolset.Core.WindowsInstaller.Bind;
6 using WixToolset.Core.WindowsInstaller.Decompile;
6 using WixToolset.Core.WindowsInstaller.Inscribe; 7 using WixToolset.Core.WindowsInstaller.Inscribe;
7 using WixToolset.Core.WindowsInstaller.Unbind; 8 using WixToolset.Core.WindowsInstaller.Unbind;
8 using WixToolset.Data; 9 using WixToolset.Data;
diff --git a/src/WixToolset.Core.WindowsInstaller/MsmBackend.cs b/src/WixToolset.Core.WindowsInstaller/MsmBackend.cs
index 4860bf81..96197d44 100644
--- a/src/WixToolset.Core.WindowsInstaller/MsmBackend.cs
+++ b/src/WixToolset.Core.WindowsInstaller/MsmBackend.cs
@@ -3,6 +3,7 @@
3namespace WixToolset.Core.WindowsInstaller 3namespace WixToolset.Core.WindowsInstaller
4{ 4{
5 using WixToolset.Core.WindowsInstaller.Bind; 5 using WixToolset.Core.WindowsInstaller.Bind;
6 using WixToolset.Core.WindowsInstaller.Decompile;
6 using WixToolset.Core.WindowsInstaller.Unbind; 7 using WixToolset.Core.WindowsInstaller.Unbind;
7 using WixToolset.Data; 8 using WixToolset.Data;
8 using WixToolset.Extensibility; 9 using WixToolset.Extensibility;
diff --git a/src/WixToolset.Core.WindowsInstaller/MspBackend.cs b/src/WixToolset.Core.WindowsInstaller/MspBackend.cs
index 46ff7aa3..1caa9e29 100644
--- a/src/WixToolset.Core.WindowsInstaller/MspBackend.cs
+++ b/src/WixToolset.Core.WindowsInstaller/MspBackend.cs
@@ -22,6 +22,8 @@ namespace WixToolset.Core.WindowsInstaller
22 { 22 {
23 var messaging = context.ServiceProvider.GetService<IMessaging>(); 23 var messaging = context.ServiceProvider.GetService<IMessaging>();
24 24
25 var backendHelper = context.ServiceProvider.GetService<IBackendHelper>();
26
25 var extensionManager = context.ServiceProvider.GetService<IExtensionManager>(); 27 var extensionManager = context.ServiceProvider.GetService<IExtensionManager>();
26 28
27 var backendExtensions = extensionManager.GetServices<IWindowsInstallerBackendBinderExtension>(); 29 var backendExtensions = extensionManager.GetServices<IWindowsInstallerBackendBinderExtension>();
@@ -34,14 +36,14 @@ namespace WixToolset.Core.WindowsInstaller
34 // Create transforms named in patch transforms. 36 // Create transforms named in patch transforms.
35 IEnumerable<PatchTransform> patchTransforms; 37 IEnumerable<PatchTransform> patchTransforms;
36 { 38 {
37 var command = new CreatePatchTransformsCommand(messaging, context.IntermediateRepresentation, context.IntermediateFolder); 39 var command = new CreatePatchTransformsCommand(messaging, backendHelper, context.IntermediateRepresentation, context.IntermediateFolder);
38 patchTransforms = command.Execute(); 40 patchTransforms = command.Execute();
39 } 41 }
40 42
41 // Enhance the intermediate by attaching the created patch transforms. 43 // Enhance the intermediate by attaching the created patch transforms.
42 IEnumerable<SubStorage> subStorages; 44 IEnumerable<SubStorage> subStorages;
43 { 45 {
44 var command = new AttachPatchTransformsCommand(messaging, context.IntermediateRepresentation, patchTransforms); 46 var command = new AttachPatchTransformsCommand(messaging, backendHelper, context.IntermediateRepresentation, patchTransforms);
45 subStorages = command.Execute(); 47 subStorages = command.Execute();
46 } 48 }
47 49
diff --git a/src/WixToolset.Core.WindowsInstaller/PatchAPI/PatchInterop.cs b/src/WixToolset.Core.WindowsInstaller/PatchAPI/PatchInterop.cs
index fcd749d2..3874d8e7 100644
--- a/src/WixToolset.Core.WindowsInstaller/PatchAPI/PatchInterop.cs
+++ b/src/WixToolset.Core.WindowsInstaller/PatchAPI/PatchInterop.cs
@@ -7,7 +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 using WixToolset.Data.Symbols;
11 11
12 /// <summary> 12 /// <summary>
13 /// Interop class for the mspatchc.dll. 13 /// Interop class for the mspatchc.dll.
@@ -25,7 +25,7 @@ namespace WixToolset.PatchAPI
25 static internal UInt32 ParseHexOrDecimal(string source) 25 static internal UInt32 ParseHexOrDecimal(string source)
26 { 26 {
27 string value = source.Trim(); 27 string value = source.Trim();
28 if (String.Equals(value.Substring(0,2), "0x", StringComparison.OrdinalIgnoreCase)) 28 if (String.Equals(value.Substring(0, 2), "0x", StringComparison.OrdinalIgnoreCase))
29 { 29 {
30 return UInt32.Parse(value.Substring(2), NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture.NumberFormat); 30 return UInt32.Parse(value.Substring(2), NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture.NumberFormat);
31 } 31 }
@@ -63,13 +63,13 @@ namespace WixToolset.PatchAPI
63 string[] basisIgnoreOffsets, 63 string[] basisIgnoreOffsets,
64 string[] basisRetainLengths, 64 string[] basisRetainLengths,
65 string[] basisRetainOffsets, 65 string[] basisRetainOffsets,
66 PatchSymbolFlagsType apiPatchingSymbolFlags, 66 PatchSymbolFlags apiPatchingSymbolFlags,
67 bool optimizePatchSizeForLargeFiles, 67 bool optimizePatchSizeForLargeFiles,
68 out bool retainRangesIgnored 68 out bool retainRangesIgnored
69 ) 69 )
70 { 70 {
71 retainRangesIgnored = false; 71 retainRangesIgnored = false;
72 if (0 != (apiPatchingSymbolFlags & ~(PatchSymbolFlagsType.PATCH_SYMBOL_NO_IMAGEHLP | PatchSymbolFlagsType.PATCH_SYMBOL_NO_FAILURES | PatchSymbolFlagsType.PATCH_SYMBOL_UNDECORATED_TOO))) 72 if (0 != (apiPatchingSymbolFlags & ~(PatchSymbolFlags.PatchSymbolNoImagehlp | PatchSymbolFlags.PatchSymbolNoFailures | PatchSymbolFlags.PatchSymbolUndecoratedToo)))
73 { 73 {
74 throw new ArgumentOutOfRangeException("apiPatchingSymbolFlags"); 74 throw new ArgumentOutOfRangeException("apiPatchingSymbolFlags");
75 } 75 }
@@ -88,13 +88,13 @@ namespace WixToolset.PatchAPI
88 { 88 {
89 return false; 89 return false;
90 } 90 }
91 uint countOldFiles = (uint) basisFiles.Length; 91 uint countOldFiles = (uint)basisFiles.Length;
92 92
93 if (null != basisSymbolPaths) 93 if (null != basisSymbolPaths)
94 { 94 {
95 if (0 != basisSymbolPaths.Length) 95 if (0 != basisSymbolPaths.Length)
96 { 96 {
97 if ((uint) basisSymbolPaths.Length != countOldFiles) 97 if ((uint)basisSymbolPaths.Length != countOldFiles)
98 { 98 {
99 throw new ArgumentOutOfRangeException("basisSymbolPaths"); 99 throw new ArgumentOutOfRangeException("basisSymbolPaths");
100 } 100 }
@@ -106,7 +106,7 @@ namespace WixToolset.PatchAPI
106 { 106 {
107 if (0 != basisIgnoreLengths.Length) 107 if (0 != basisIgnoreLengths.Length)
108 { 108 {
109 if ((uint) basisIgnoreLengths.Length != countOldFiles) 109 if ((uint)basisIgnoreLengths.Length != countOldFiles)
110 { 110 {
111 throw new ArgumentOutOfRangeException("basisIgnoreLengths"); 111 throw new ArgumentOutOfRangeException("basisIgnoreLengths");
112 } 112 }
@@ -121,7 +121,7 @@ namespace WixToolset.PatchAPI
121 { 121 {
122 if (0 != basisIgnoreOffsets.Length) 122 if (0 != basisIgnoreOffsets.Length)
123 { 123 {
124 if ((uint) basisIgnoreOffsets.Length != countOldFiles) 124 if ((uint)basisIgnoreOffsets.Length != countOldFiles)
125 { 125 {
126 throw new ArgumentOutOfRangeException("basisIgnoreOffsets"); 126 throw new ArgumentOutOfRangeException("basisIgnoreOffsets");
127 } 127 }
@@ -136,7 +136,7 @@ namespace WixToolset.PatchAPI
136 { 136 {
137 if (0 != basisRetainLengths.Length) 137 if (0 != basisRetainLengths.Length)
138 { 138 {
139 if ((uint) basisRetainLengths.Length != countOldFiles) 139 if ((uint)basisRetainLengths.Length != countOldFiles)
140 { 140 {
141 throw new ArgumentOutOfRangeException("basisRetainLengths"); 141 throw new ArgumentOutOfRangeException("basisRetainLengths");
142 } 142 }
@@ -151,7 +151,7 @@ namespace WixToolset.PatchAPI
151 { 151 {
152 if (0 != basisRetainOffsets.Length) 152 if (0 != basisRetainOffsets.Length)
153 { 153 {
154 if ((uint) basisRetainOffsets.Length != countOldFiles) 154 if ((uint)basisRetainOffsets.Length != countOldFiles)
155 { 155 {
156 throw new ArgumentOutOfRangeException("basisRetainOffsets"); 156 throw new ArgumentOutOfRangeException("basisRetainOffsets");
157 } 157 }
@@ -253,15 +253,15 @@ namespace WixToolset.PatchAPI
253 253
254 // determine if this is an error or a need to use whole file. 254 // determine if this is an error or a need to use whole file.
255 int err = Marshal.GetLastWin32Error(); 255 int err = Marshal.GetLastWin32Error();
256 switch(err) 256 switch (err)
257 { 257 {
258 case unchecked((int) ERROR_PATCH_BIGGER_THAN_COMPRESSED): 258 case unchecked((int)ERROR_PATCH_BIGGER_THAN_COMPRESSED):
259 break; 259 break;
260 260
261 // too late to exclude this file -- should have been caught before 261 // too late to exclude this file -- should have been caught before
262 case unchecked((int) ERROR_PATCH_SAME_FILE): 262 case unchecked((int)ERROR_PATCH_SAME_FILE):
263 default: 263 default:
264 throw new System.ComponentModel.Win32Exception(err); 264 throw new System.ComponentModel.Win32Exception(err);
265 } 265 }
266 return false; 266 return false;
267 } 267 }
@@ -302,44 +302,44 @@ namespace WixToolset.PatchAPI
302 // The following contants can be combined and used as the OptionFlags 302 // The following contants can be combined and used as the OptionFlags
303 // parameter in the patch creation apis. 303 // parameter in the patch creation apis.
304 304
305 internal const uint PATCH_OPTION_USE_BEST = 0x00000000; // auto choose best (slower) 305 internal const uint PATCH_OPTION_USE_BEST = 0x00000000; // auto choose best (slower)
306 306
307 internal const uint PATCH_OPTION_USE_LZX_BEST = 0x00000003; // auto choose best of LXZ A/B (but not large) 307 internal const uint PATCH_OPTION_USE_LZX_BEST = 0x00000003; // auto choose best of LXZ A/B (but not large)
308 internal const uint PATCH_OPTION_USE_LZX_A = 0x00000001; // normal 308 internal const uint PATCH_OPTION_USE_LZX_A = 0x00000001; // normal
309 internal const uint PATCH_OPTION_USE_LXZ_B = 0x00000002; // better on some x86 binaries 309 internal const uint PATCH_OPTION_USE_LXZ_B = 0x00000002; // better on some x86 binaries
310 internal const uint PATCH_OPTION_USE_LZX_LARGE = 0x00000004; // better support for large files (requires 5.1 or higher applyer) 310 internal const uint PATCH_OPTION_USE_LZX_LARGE = 0x00000004; // better support for large files (requires 5.1 or higher applyer)
311 311
312 internal const uint PATCH_OPTION_NO_BINDFIX = 0x00010000; // PE bound imports 312 internal const uint PATCH_OPTION_NO_BINDFIX = 0x00010000; // PE bound imports
313 internal const uint PATCH_OPTION_NO_LOCKFIX = 0x00020000; // PE smashed locks 313 internal const uint PATCH_OPTION_NO_LOCKFIX = 0x00020000; // PE smashed locks
314 internal const uint PATCH_OPTION_NO_REBASE = 0x00040000; // PE rebased image 314 internal const uint PATCH_OPTION_NO_REBASE = 0x00040000; // PE rebased image
315 internal const uint PATCH_OPTION_FAIL_IF_SAME_FILE = 0x00080000; // don't create if same 315 internal const uint PATCH_OPTION_FAIL_IF_SAME_FILE = 0x00080000; // don't create if same
316 internal const uint PATCH_OPTION_FAIL_IF_BIGGER = 0x00100000; // fail if patch is larger than simply compressing new file (slower) 316 internal const uint PATCH_OPTION_FAIL_IF_BIGGER = 0x00100000; // fail if patch is larger than simply compressing new file (slower)
317 internal const uint PATCH_OPTION_NO_CHECKSUM = 0x00200000; // PE checksum zero 317 internal const uint PATCH_OPTION_NO_CHECKSUM = 0x00200000; // PE checksum zero
318 internal const uint PATCH_OPTION_NO_RESTIMEFIX = 0x00400000; // PE resource timestamps 318 internal const uint PATCH_OPTION_NO_RESTIMEFIX = 0x00400000; // PE resource timestamps
319 internal const uint PATCH_OPTION_NO_TIMESTAMP = 0x00800000; // don't store new file timestamp in patch 319 internal const uint PATCH_OPTION_NO_TIMESTAMP = 0x00800000; // don't store new file timestamp in patch
320 internal const uint PATCH_OPTION_SIGNATURE_MD5 = 0x01000000; // use MD5 instead of CRC (reserved for future support) 320 internal const uint PATCH_OPTION_SIGNATURE_MD5 = 0x01000000; // use MD5 instead of CRC (reserved for future support)
321 internal const uint PATCH_OPTION_INTERLEAVE_FILES = 0x40000000; // better support for large files (requires 5.2 or higher applyer) 321 internal const uint PATCH_OPTION_INTERLEAVE_FILES = 0x40000000; // better support for large files (requires 5.2 or higher applyer)
322 internal const uint PATCH_OPTION_RESERVED1 = 0x80000000; // (used internally) 322 internal const uint PATCH_OPTION_RESERVED1 = 0x80000000; // (used internally)
323 323
324 internal const uint PATCH_OPTION_VALID_FLAGS = 0xC0FF0007; 324 internal const uint PATCH_OPTION_VALID_FLAGS = 0xC0FF0007;
325 325
326 // 326 //
327 // The following flags are used with PATCH_OPTION_DATA ExtendedOptionFlags: 327 // The following flags are used with PATCH_OPTION_DATA ExtendedOptionFlags:
328 // 328 //
329 329
330 internal const uint PATCH_TRANSFORM_PE_RESOURCE_2 = 0x00000100; // better handling of PE resources (requires 5.2 or higher applyer) 330 internal const uint PATCH_TRANSFORM_PE_RESOURCE_2 = 0x00000100; // better handling of PE resources (requires 5.2 or higher applyer)
331 internal const uint PATCH_TRANSFORM_PE_IRELOC_2 = 0x00000200; // better handling of PE stripped relocs (requires 5.2 or higher applyer) 331 internal const uint PATCH_TRANSFORM_PE_IRELOC_2 = 0x00000200; // better handling of PE stripped relocs (requires 5.2 or higher applyer)
332 332
333 // 333 //
334 // In addition to the standard Win32 error codes, the following error codes may 334 // In addition to the standard Win32 error codes, the following error codes may
335 // be returned via GetLastError() when one of the patch APIs fails. 335 // be returned via GetLastError() when one of the patch APIs fails.
336 336
337 internal const uint ERROR_PATCH_ENCODE_FAILURE = 0xC00E3101; // create 337 internal const uint ERROR_PATCH_ENCODE_FAILURE = 0xC00E3101; // create
338 internal const uint ERROR_PATCH_INVALID_OPTIONS = 0xC00E3102; // create 338 internal const uint ERROR_PATCH_INVALID_OPTIONS = 0xC00E3102; // create
339 internal const uint ERROR_PATCH_SAME_FILE = 0xC00E3103; // create 339 internal const uint ERROR_PATCH_SAME_FILE = 0xC00E3103; // create
340 internal const uint ERROR_PATCH_RETAIN_RANGES_DIFFER = 0xC00E3104; // create 340 internal const uint ERROR_PATCH_RETAIN_RANGES_DIFFER = 0xC00E3104; // create
341 internal const uint ERROR_PATCH_BIGGER_THAN_COMPRESSED = 0xC00E3105; // create 341 internal const uint ERROR_PATCH_BIGGER_THAN_COMPRESSED = 0xC00E3105; // create
342 internal const uint ERROR_PATCH_IMAGEHLP_FALURE = 0xC00E3106; // create 342 internal const uint ERROR_PATCH_IMAGEHLP_FALURE = 0xC00E3106; // create
343 343
344 /// <summary> 344 /// <summary>
345 /// Delegate type that the PatchAPI calls for progress notification. 345 /// Delegate type that the PatchAPI calls for progress notification.
@@ -441,14 +441,14 @@ namespace WixToolset.PatchAPI
441 [BestFitMapping(false, ThrowOnUnmappableChar = true)] 441 [BestFitMapping(false, ThrowOnUnmappableChar = true)]
442 internal class PatchOptionData 442 internal class PatchOptionData
443 { 443 {
444 public PatchSymbolFlagsType symbolOptionFlags; // PATCH_SYMBOL_xxx flags 444 public PatchSymbolFlags symbolOptionFlags; // PATCH_SYMBOL_xxx flags
445 [MarshalAs(UnmanagedType.LPStr)] public string newFileSymbolPath; // always ANSI, never Unicode 445 [MarshalAs(UnmanagedType.LPStr)] public string newFileSymbolPath; // always ANSI, never Unicode
446 [MarshalAs(UnmanagedType.LPStr)] public string[] oldFileSymbolPathArray; // array[ OldFileCount ] 446 [MarshalAs(UnmanagedType.LPStr)] public string[] oldFileSymbolPathArray; // array[ OldFileCount ]
447 public uint extendedOptionFlags; 447 public uint extendedOptionFlags;
448 public PatchSymloadCallback symLoadCallback = null; 448 public PatchSymloadCallback symLoadCallback = null;
449 public IntPtr symLoadContext = IntPtr.Zero; 449 public IntPtr symLoadContext = IntPtr.Zero;
450 public PatchInterleaveMap[] interleaveMapArray = null; // array[ OldFileCount ] (requires 5.2 or higher applyer) 450 public PatchInterleaveMap[] interleaveMapArray = null; // array[ OldFileCount ] (requires 5.2 or higher applyer)
451 public uint maxLzxWindowSize = 0; // limit memory requirements (requires 5.2 or higher applyer) 451 public uint maxLzxWindowSize = 0; // limit memory requirements (requires 5.2 or higher applyer)
452 } 452 }
453 453
454 // 454 //
@@ -534,7 +534,7 @@ namespace WixToolset.PatchAPI
534 534
535 private PatchAPIMarshaler(string cookie) 535 private PatchAPIMarshaler(string cookie)
536 { 536 {
537 this.marshalType = (PatchAPIMarshaler.MarshalType) Enum.Parse(typeof(PatchAPIMarshaler.MarshalType), cookie); 537 this.marshalType = (PatchAPIMarshaler.MarshalType)Enum.Parse(typeof(PatchAPIMarshaler.MarshalType), cookie);
538 } 538 }
539 539
540 // 540 //
@@ -575,12 +575,12 @@ namespace WixToolset.PatchAPI
575 575
576 switch (this.marshalType) 576 switch (this.marshalType)
577 { 577 {
578 case PatchAPIMarshaler.MarshalType.PATCH_OPTION_DATA: 578 case PatchAPIMarshaler.MarshalType.PATCH_OPTION_DATA:
579 this.CleanUpPOD(pNativeData); 579 this.CleanUpPOD(pNativeData);
580 break; 580 break;
581 default: 581 default:
582 this.CleanUpPOFI_A(pNativeData); 582 this.CleanUpPOFI_A(pNativeData);
583 break; 583 break;
584 } 584 }
585 } 585 }
586 586
@@ -601,14 +601,14 @@ namespace WixToolset.PatchAPI
601 return IntPtr.Zero; 601 return IntPtr.Zero;
602 } 602 }
603 603
604 switch(this.marshalType) 604 switch (this.marshalType)
605 { 605 {
606 case PatchAPIMarshaler.MarshalType.PATCH_OPTION_DATA: 606 case PatchAPIMarshaler.MarshalType.PATCH_OPTION_DATA:
607 return this.MarshalPOD(ManagedObj as PatchOptionData); 607 return this.MarshalPOD(ManagedObj as PatchOptionData);
608 case PatchAPIMarshaler.MarshalType.PATCH_OLD_FILE_INFO_W: 608 case PatchAPIMarshaler.MarshalType.PATCH_OLD_FILE_INFO_W:
609 return this.MarshalPOFIW_A(ManagedObj as PatchOldFileInfoW[]); 609 return this.MarshalPOFIW_A(ManagedObj as PatchOldFileInfoW[]);
610 default: 610 default:
611 throw new InvalidOperationException(); 611 throw new InvalidOperationException();
612 } 612 }
613 } 613 }
614 614
@@ -631,23 +631,23 @@ namespace WixToolset.PatchAPI
631 // Implementation ************************************************* 631 // Implementation *************************************************
632 632
633 // PATCH_OPTION_DATA offsets 633 // PATCH_OPTION_DATA offsets
634 private static readonly int symbolOptionFlagsOffset = Marshal.SizeOf(typeof(Int32)); 634 private static readonly int symbolOptionFlagsOffset = Marshal.SizeOf(typeof(Int32));
635 private static readonly int newFileSymbolPathOffset = 2*Marshal.SizeOf(typeof(Int32)); 635 private static readonly int newFileSymbolPathOffset = 2 * Marshal.SizeOf(typeof(Int32));
636 private static readonly int oldFileSymbolPathArrayOffset = 2*Marshal.SizeOf(typeof(Int32)) + Marshal.SizeOf(typeof(IntPtr)); 636 private static readonly int oldFileSymbolPathArrayOffset = 2 * Marshal.SizeOf(typeof(Int32)) + Marshal.SizeOf(typeof(IntPtr));
637 private static readonly int extendedOptionFlagsOffset = 2*Marshal.SizeOf(typeof(Int32)) + 2*Marshal.SizeOf(typeof(IntPtr)); 637 private static readonly int extendedOptionFlagsOffset = 2 * Marshal.SizeOf(typeof(Int32)) + 2 * Marshal.SizeOf(typeof(IntPtr));
638 private static readonly int symLoadCallbackOffset = 3*Marshal.SizeOf(typeof(Int32)) + 2*Marshal.SizeOf(typeof(IntPtr)); 638 private static readonly int symLoadCallbackOffset = 3 * Marshal.SizeOf(typeof(Int32)) + 2 * Marshal.SizeOf(typeof(IntPtr));
639 private static readonly int symLoadContextOffset = 3*Marshal.SizeOf(typeof(Int32)) + 3*Marshal.SizeOf(typeof(IntPtr)); 639 private static readonly int symLoadContextOffset = 3 * Marshal.SizeOf(typeof(Int32)) + 3 * Marshal.SizeOf(typeof(IntPtr));
640 private static readonly int interleaveMapArrayOffset = 3*Marshal.SizeOf(typeof(Int32)) + 4*Marshal.SizeOf(typeof(IntPtr)); 640 private static readonly int interleaveMapArrayOffset = 3 * Marshal.SizeOf(typeof(Int32)) + 4 * Marshal.SizeOf(typeof(IntPtr));
641 private static readonly int maxLzxWindowSizeOffset = 3*Marshal.SizeOf(typeof(Int32)) + 5*Marshal.SizeOf(typeof(IntPtr)); 641 private static readonly int maxLzxWindowSizeOffset = 3 * Marshal.SizeOf(typeof(Int32)) + 5 * Marshal.SizeOf(typeof(IntPtr));
642 private static readonly int patchOptionDataSize = 4*Marshal.SizeOf(typeof(Int32)) + 5*Marshal.SizeOf(typeof(IntPtr)); 642 private static readonly int patchOptionDataSize = 4 * Marshal.SizeOf(typeof(Int32)) + 5 * Marshal.SizeOf(typeof(IntPtr));
643 643
644 // PATCH_OLD_FILE_INFO offsets 644 // PATCH_OLD_FILE_INFO offsets
645 private static readonly int oldFileOffset = Marshal.SizeOf(typeof(Int32)); 645 private static readonly int oldFileOffset = Marshal.SizeOf(typeof(Int32));
646 private static readonly int ignoreRangeCountOffset = Marshal.SizeOf(typeof(Int32)) + Marshal.SizeOf(typeof(IntPtr)); 646 private static readonly int ignoreRangeCountOffset = Marshal.SizeOf(typeof(Int32)) + Marshal.SizeOf(typeof(IntPtr));
647 private static readonly int ignoreRangeArrayOffset = 2*Marshal.SizeOf(typeof(Int32)) + Marshal.SizeOf(typeof(IntPtr)); 647 private static readonly int ignoreRangeArrayOffset = 2 * Marshal.SizeOf(typeof(Int32)) + Marshal.SizeOf(typeof(IntPtr));
648 private static readonly int retainRangeCountOffset = 2*Marshal.SizeOf(typeof(Int32)) + 2*Marshal.SizeOf(typeof(IntPtr)); 648 private static readonly int retainRangeCountOffset = 2 * Marshal.SizeOf(typeof(Int32)) + 2 * Marshal.SizeOf(typeof(IntPtr));
649 private static readonly int retainRangeArrayOffset = 3*Marshal.SizeOf(typeof(Int32)) + 2*Marshal.SizeOf(typeof(IntPtr)); 649 private static readonly int retainRangeArrayOffset = 3 * Marshal.SizeOf(typeof(Int32)) + 2 * Marshal.SizeOf(typeof(IntPtr));
650 private static readonly int patchOldFileInfoSize = 3*Marshal.SizeOf(typeof(Int32)) + 3*Marshal.SizeOf(typeof(IntPtr)); 650 private static readonly int patchOldFileInfoSize = 3 * Marshal.SizeOf(typeof(Int32)) + 3 * Marshal.SizeOf(typeof(IntPtr));
651 651
652 // Methods and data used to preserve data needed for cleanup 652 // Methods and data used to preserve data needed for cleanup
653 653
@@ -658,16 +658,16 @@ namespace WixToolset.PatchAPI
658 private IntPtr CreateMainStruct(int oldFileCount) 658 private IntPtr CreateMainStruct(int oldFileCount)
659 { 659 {
660 int nativeSize; 660 int nativeSize;
661 switch(this.marshalType) 661 switch (this.marshalType)
662 { 662 {
663 case PatchAPIMarshaler.MarshalType.PATCH_OPTION_DATA: 663 case PatchAPIMarshaler.MarshalType.PATCH_OPTION_DATA:
664 nativeSize = patchOptionDataSize; 664 nativeSize = patchOptionDataSize;
665 break; 665 break;
666 case PatchAPIMarshaler.MarshalType.PATCH_OLD_FILE_INFO_W: 666 case PatchAPIMarshaler.MarshalType.PATCH_OLD_FILE_INFO_W:
667 nativeSize = oldFileCount*patchOldFileInfoSize; 667 nativeSize = oldFileCount * patchOldFileInfoSize;
668 break; 668 break;
669 default: 669 default:
670 throw new InvalidOperationException(); 670 throw new InvalidOperationException();
671 } 671 }
672 672
673 IntPtr native = Marshal.AllocCoTaskMem(nativeSize); 673 IntPtr native = Marshal.AllocCoTaskMem(nativeSize);
@@ -722,7 +722,7 @@ namespace WixToolset.PatchAPI
722 722
723 for (int i = 0; i < managed.Length; ++i) 723 for (int i = 0; i < managed.Length; ++i)
724 { 724 {
725 Marshal.WriteIntPtr(native, i*Marshal.SizeOf(typeof(IntPtr)), OptionalAnsiString(managed[i])); 725 Marshal.WriteIntPtr(native, i * Marshal.SizeOf(typeof(IntPtr)), OptionalAnsiString(managed[i]));
726 } 726 }
727 727
728 return native; 728 return native;
@@ -741,7 +741,7 @@ namespace WixToolset.PatchAPI
741 741
742 for (int i = 0; i < managed.Length; ++i) 742 for (int i = 0; i < managed.Length; ++i)
743 { 743 {
744 Marshal.WriteIntPtr(native, i*Marshal.SizeOf(typeof(IntPtr)), OptionalUnicodeString(managed[i])); 744 Marshal.WriteIntPtr(native, i * Marshal.SizeOf(typeof(IntPtr)), OptionalUnicodeString(managed[i]));
745 } 745 }
746 746
747 return native; 747 return native;
@@ -765,12 +765,12 @@ namespace WixToolset.PatchAPI
765 } 765 }
766 766
767 IntPtr native = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(UInt32)) 767 IntPtr native = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(UInt32))
768 + managed.ranges.Length*(Marshal.SizeOf(typeof(PatchInterleaveMap)))); 768 + managed.ranges.Length * (Marshal.SizeOf(typeof(PatchInterleaveMap))));
769 WriteUInt32(native, (uint) managed.ranges.Length); 769 WriteUInt32(native, (uint)managed.ranges.Length);
770 770
771 for (int i = 0; i < managed.ranges.Length; ++i) 771 for (int i = 0; i < managed.ranges.Length; ++i)
772 { 772 {
773 Marshal.StructureToPtr(managed.ranges[i], (IntPtr)((Int64)native + i*Marshal.SizeOf(typeof(PatchInterleaveMap))), false); 773 Marshal.StructureToPtr(managed.ranges[i], (IntPtr)((Int64)native + i * Marshal.SizeOf(typeof(PatchInterleaveMap))), false);
774 } 774 }
775 return native; 775 return native;
776 } 776 }
@@ -786,7 +786,7 @@ namespace WixToolset.PatchAPI
786 786
787 for (int i = 0; i < managed.Length; ++i) 787 for (int i = 0; i < managed.Length; ++i)
788 { 788 {
789 Marshal.WriteIntPtr(native, i*Marshal.SizeOf(typeof(IntPtr)), CreateInterleaveMapRange(managed[i])); 789 Marshal.WriteIntPtr(native, i * Marshal.SizeOf(typeof(IntPtr)), CreateInterleaveMapRange(managed[i]));
790 } 790 }
791 791
792 return native; 792 return native;
@@ -794,12 +794,12 @@ namespace WixToolset.PatchAPI
794 794
795 private static void WriteUInt32(IntPtr native, uint data) 795 private static void WriteUInt32(IntPtr native, uint data)
796 { 796 {
797 Marshal.WriteInt32(native, unchecked((int) data)); 797 Marshal.WriteInt32(native, unchecked((int)data));
798 } 798 }
799 799
800 private static void WriteUInt32(IntPtr native, int offset, uint data) 800 private static void WriteUInt32(IntPtr native, int offset, uint data)
801 { 801 {
802 Marshal.WriteInt32(native, offset, unchecked((int) data)); 802 Marshal.WriteInt32(native, offset, unchecked((int)data));
803 } 803 }
804 804
805 // Marshal operations 805 // Marshal operations
@@ -813,7 +813,7 @@ namespace WixToolset.PatchAPI
813 813
814 IntPtr native = this.CreateMainStruct(managed.oldFileSymbolPathArray.Length); 814 IntPtr native = this.CreateMainStruct(managed.oldFileSymbolPathArray.Length);
815 Marshal.WriteInt32(native, patchOptionDataSize); // SizeOfThisStruct 815 Marshal.WriteInt32(native, patchOptionDataSize); // SizeOfThisStruct
816 WriteUInt32(native, symbolOptionFlagsOffset, (uint) managed.symbolOptionFlags); 816 WriteUInt32(native, symbolOptionFlagsOffset, (uint)managed.symbolOptionFlags);
817 Marshal.WriteIntPtr(native, newFileSymbolPathOffset, PatchAPIMarshaler.OptionalAnsiString(managed.newFileSymbolPath)); 817 Marshal.WriteIntPtr(native, newFileSymbolPathOffset, PatchAPIMarshaler.OptionalAnsiString(managed.newFileSymbolPath));
818 Marshal.WriteIntPtr(native, oldFileSymbolPathArrayOffset, PatchAPIMarshaler.CreateArrayOfStringA(managed.oldFileSymbolPathArray)); 818 Marshal.WriteIntPtr(native, oldFileSymbolPathArrayOffset, PatchAPIMarshaler.CreateArrayOfStringA(managed.oldFileSymbolPathArray));
819 WriteUInt32(native, extendedOptionFlagsOffset, managed.extendedOptionFlags); 819 WriteUInt32(native, extendedOptionFlagsOffset, managed.extendedOptionFlags);
@@ -866,10 +866,10 @@ namespace WixToolset.PatchAPI
866 { 866 {
867 Marshal.WriteInt32(native, patchOldFileInfoSize); // SizeOfThisStruct 867 Marshal.WriteInt32(native, patchOldFileInfoSize); // SizeOfThisStruct
868 WriteUInt32(native, ignoreRangeCountOffset, 868 WriteUInt32(native, ignoreRangeCountOffset,
869 (null == managed.ignoreRange) ? 0 : (uint) managed.ignoreRange.Length); // IgnoreRangeCount // maximum 255 869 (null == managed.ignoreRange) ? 0 : (uint)managed.ignoreRange.Length); // IgnoreRangeCount // maximum 255
870 Marshal.WriteIntPtr(native, ignoreRangeArrayOffset, MarshalPIRArray(managed.ignoreRange)); // IgnoreRangeArray 870 Marshal.WriteIntPtr(native, ignoreRangeArrayOffset, MarshalPIRArray(managed.ignoreRange)); // IgnoreRangeArray
871 WriteUInt32(native, retainRangeCountOffset, 871 WriteUInt32(native, retainRangeCountOffset,
872 (null == managed.retainRange) ? 0 : (uint) managed.retainRange.Length); // RetainRangeCount // maximum 255 872 (null == managed.retainRange) ? 0 : (uint)managed.retainRange.Length); // RetainRangeCount // maximum 255
873 Marshal.WriteIntPtr(native, retainRangeArrayOffset, MarshalPRRArray(managed.retainRange)); // RetainRangeArray 873 Marshal.WriteIntPtr(native, retainRangeArrayOffset, MarshalPRRArray(managed.retainRange)); // RetainRangeArray
874 } 874 }
875 875
@@ -885,11 +885,11 @@ namespace WixToolset.PatchAPI
885 return IntPtr.Zero; 885 return IntPtr.Zero;
886 } 886 }
887 887
888 IntPtr native = Marshal.AllocCoTaskMem(array.Length*Marshal.SizeOf(typeof(PatchIgnoreRange))); 888 IntPtr native = Marshal.AllocCoTaskMem(array.Length * Marshal.SizeOf(typeof(PatchIgnoreRange)));
889 889
890 for (int i = 0; i < array.Length; ++i) 890 for (int i = 0; i < array.Length; ++i)
891 { 891 {
892 Marshal.StructureToPtr(array[i], (IntPtr)((Int64)native + (i*Marshal.SizeOf(typeof(PatchIgnoreRange)))), false); 892 Marshal.StructureToPtr(array[i], (IntPtr)((Int64)native + (i * Marshal.SizeOf(typeof(PatchIgnoreRange)))), false);
893 } 893 }
894 894
895 return native; 895 return native;
@@ -907,11 +907,11 @@ namespace WixToolset.PatchAPI
907 return IntPtr.Zero; 907 return IntPtr.Zero;
908 } 908 }
909 909
910 IntPtr native = Marshal.AllocCoTaskMem(array.Length*Marshal.SizeOf(typeof(PatchRetainRange))); 910 IntPtr native = Marshal.AllocCoTaskMem(array.Length * Marshal.SizeOf(typeof(PatchRetainRange)));
911 911
912 for (int i = 0; i < array.Length; ++i) 912 for (int i = 0; i < array.Length; ++i)
913 { 913 {
914 Marshal.StructureToPtr(array[i], (IntPtr)((Int64)native + (i*Marshal.SizeOf(typeof(PatchRetainRange)))), false); 914 Marshal.StructureToPtr(array[i], (IntPtr)((Int64)native + (i * Marshal.SizeOf(typeof(PatchRetainRange)))), false);
915 } 915 }
916 916
917 return native; 917 return native;
@@ -930,7 +930,7 @@ namespace WixToolset.PatchAPI
930 Marshal.FreeCoTaskMem( 930 Marshal.FreeCoTaskMem(
931 Marshal.ReadIntPtr( 931 Marshal.ReadIntPtr(
932 Marshal.ReadIntPtr(native, oldFileSymbolPathArrayOffset), 932 Marshal.ReadIntPtr(native, oldFileSymbolPathArrayOffset),
933 i*Marshal.SizeOf(typeof(IntPtr)))); 933 i * Marshal.SizeOf(typeof(IntPtr))));
934 } 934 }
935 935
936 Marshal.FreeCoTaskMem(Marshal.ReadIntPtr(native, oldFileSymbolPathArrayOffset)); 936 Marshal.FreeCoTaskMem(Marshal.ReadIntPtr(native, oldFileSymbolPathArrayOffset));
@@ -943,7 +943,7 @@ namespace WixToolset.PatchAPI
943 Marshal.FreeCoTaskMem( 943 Marshal.FreeCoTaskMem(
944 Marshal.ReadIntPtr( 944 Marshal.ReadIntPtr(
945 Marshal.ReadIntPtr(native, interleaveMapArrayOffset), 945 Marshal.ReadIntPtr(native, interleaveMapArrayOffset),
946 i*Marshal.SizeOf(typeof(IntPtr)))); 946 i * Marshal.SizeOf(typeof(IntPtr))));
947 } 947 }
948 948
949 Marshal.FreeCoTaskMem(Marshal.ReadIntPtr(native, interleaveMapArrayOffset)); 949 Marshal.FreeCoTaskMem(Marshal.ReadIntPtr(native, interleaveMapArrayOffset));
@@ -956,7 +956,7 @@ namespace WixToolset.PatchAPI
956 { 956 {
957 for (int i = 0; i < GetOldFileCount(native); ++i) 957 for (int i = 0; i < GetOldFileCount(native); ++i)
958 { 958 {
959 PatchAPIMarshaler.CleanUpPOFI((IntPtr)((Int64)native + i*patchOldFileInfoSize)); 959 PatchAPIMarshaler.CleanUpPOFI((IntPtr)((Int64)native + i * patchOldFileInfoSize));
960 } 960 }
961 961
962 PatchAPIMarshaler.ReleaseMainStruct(native); 962 PatchAPIMarshaler.ReleaseMainStruct(native);
diff --git a/src/WixToolset.Core.WindowsInstaller/RowDictionary.cs b/src/WixToolset.Core.WindowsInstaller/RowDictionary.cs
index bbb97c25..ad7764bc 100644
--- a/src/WixToolset.Core.WindowsInstaller/RowDictionary.cs
+++ b/src/WixToolset.Core.WindowsInstaller/RowDictionary.cs
@@ -21,19 +21,6 @@ namespace WixToolset.Core.WindowsInstaller
21 } 21 }
22 22
23 /// <summary> 23 /// <summary>
24 /// Creates and populates a <see cref="RowDictionary{T}"/> with the rows from the given enumerator.
25 /// </summary>
26 /// <param name="rows">Rows to add.</param>
27 public RowDictionary(IEnumerable<T> rows)
28 : this()
29 {
30 foreach (T row in rows)
31 {
32 this.Add(row);
33 }
34 }
35
36 /// <summary>
37 /// Creates and populates a <see cref="RowDictionary{T}"/> with the rows from the given <see cref="Table"/>. 24 /// Creates and populates a <see cref="RowDictionary{T}"/> with the rows from the given <see cref="Table"/>.
38 /// </summary> 25 /// </summary>
39 /// <param name="table">The table to index.</param> 26 /// <param name="table">The table to index.</param>
diff --git a/src/WixToolset.Core.WindowsInstaller/Unbind/UnbindDatabaseCommand.cs b/src/WixToolset.Core.WindowsInstaller/Unbind/UnbindDatabaseCommand.cs
index 36172b5e..9a55dc77 100644
--- a/src/WixToolset.Core.WindowsInstaller/Unbind/UnbindDatabaseCommand.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Unbind/UnbindDatabaseCommand.cs
@@ -11,16 +11,16 @@ namespace WixToolset.Core.WindowsInstaller.Unbind
11 using WixToolset.Core.WindowsInstaller.Msi; 11 using WixToolset.Core.WindowsInstaller.Msi;
12 using WixToolset.Data; 12 using WixToolset.Data;
13 using WixToolset.Data.WindowsInstaller; 13 using WixToolset.Data.WindowsInstaller;
14 using WixToolset.Data.WindowsInstaller.Rows;
15 using WixToolset.Extensibility.Services; 14 using WixToolset.Extensibility.Services;
16 15
17 internal class UnbindDatabaseCommand 16 internal class UnbindDatabaseCommand
18 { 17 {
19 private List<string> exportedFiles; 18 private List<string> exportedFiles;
20 19
21 public UnbindDatabaseCommand(IMessaging messaging, Database database, string databasePath, OutputType outputType, string exportBasePath, string intermediateFolder, bool isAdminImage, bool suppressDemodularization, bool skipSummaryInfo) 20 public UnbindDatabaseCommand(IMessaging messaging, IBackendHelper backendHelper, Database database, string databasePath, OutputType outputType, string exportBasePath, string intermediateFolder, bool isAdminImage, bool suppressDemodularization, bool skipSummaryInfo)
22 { 21 {
23 this.Messaging = messaging; 22 this.Messaging = messaging;
23 this.BackendHelper = backendHelper;
24 this.Database = database; 24 this.Database = database;
25 this.DatabasePath = databasePath; 25 this.DatabasePath = databasePath;
26 this.OutputType = outputType; 26 this.OutputType = outputType;
@@ -35,6 +35,8 @@ namespace WixToolset.Core.WindowsInstaller.Unbind
35 35
36 public IMessaging Messaging { get; } 36 public IMessaging Messaging { get; }
37 37
38 public IBackendHelper BackendHelper { get; }
39
38 public Database Database { get; } 40 public Database Database { get; }
39 41
40 public string DatabasePath { get; } 42 public string DatabasePath { get; }
@@ -527,7 +529,7 @@ namespace WixToolset.Core.WindowsInstaller.Unbind
527 /// </summary> 529 /// </summary>
528 /// <param name="value">The Filename value.</param> 530 /// <param name="value">The Filename value.</param>
529 /// <returns>The source name of the directory in an admin image.</returns> 531 /// <returns>The source name of the directory in an admin image.</returns>
530 private static string GetAdminSourceName(string value) 532 private string GetAdminSourceName(string value)
531 { 533 {
532 string name = null; 534 string name = null;
533 string[] names; 535 string[] names;
@@ -535,7 +537,7 @@ namespace WixToolset.Core.WindowsInstaller.Unbind
535 string shortsourcename = null; 537 string shortsourcename = null;
536 string sourcename = null; 538 string sourcename = null;
537 539
538 names = Common.GetNames(value); 540 names = this.BackendHelper.SplitMsiFileName(value);
539 541
540 if (null != names[0] && "." != names[0]) 542 if (null != names[0] && "." != names[0])
541 { 543 {
diff --git a/src/WixToolset.Core.WindowsInstaller/Unbind/UnbindTranformCommand.cs b/src/WixToolset.Core.WindowsInstaller/Unbind/UnbindTranformCommand.cs
index de2c5e37..bde29405 100644
--- a/src/WixToolset.Core.WindowsInstaller/Unbind/UnbindTranformCommand.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Unbind/UnbindTranformCommand.cs
@@ -17,9 +17,10 @@ namespace WixToolset.Core.WindowsInstaller.Unbind
17 17
18 internal class UnbindTransformCommand 18 internal class UnbindTransformCommand
19 { 19 {
20 public UnbindTransformCommand(IMessaging messaging, string transformFile, string exportBasePath, string intermediateFolder) 20 public UnbindTransformCommand(IMessaging messaging, IBackendHelper backendHelper, string transformFile, string exportBasePath, string intermediateFolder)
21 { 21 {
22 this.Messaging = messaging; 22 this.Messaging = messaging;
23 this.BackendHelper = backendHelper;
23 this.TransformFile = transformFile; 24 this.TransformFile = transformFile;
24 this.ExportBasePath = exportBasePath; 25 this.ExportBasePath = exportBasePath;
25 this.IntermediateFolder = intermediateFolder; 26 this.IntermediateFolder = intermediateFolder;
@@ -29,6 +30,8 @@ namespace WixToolset.Core.WindowsInstaller.Unbind
29 30
30 private IMessaging Messaging { get; } 31 private IMessaging Messaging { get; }
31 32
33 private IBackendHelper BackendHelper { get; }
34
32 private string TransformFile { get; } 35 private string TransformFile { get; }
33 36
34 private string ExportBasePath { get; } 37 private string ExportBasePath { get; }
@@ -87,7 +90,7 @@ namespace WixToolset.Core.WindowsInstaller.Unbind
87 msiDatabase.ApplyTransform(this.TransformFile, TransformErrorConditions.All | TransformErrorConditions.ViewTransform); 90 msiDatabase.ApplyTransform(this.TransformFile, TransformErrorConditions.All | TransformErrorConditions.ViewTransform);
88 91
89 // unbind the database 92 // unbind the database
90 var unbindCommand = new UnbindDatabaseCommand(this.Messaging, msiDatabase, msiDatabaseFile, OutputType.Product, this.ExportBasePath, this.IntermediateFolder, false, false, skipSummaryInfo: true); 93 var unbindCommand = new UnbindDatabaseCommand(this.Messaging, this.BackendHelper, msiDatabase, msiDatabaseFile, OutputType.Product, this.ExportBasePath, this.IntermediateFolder, false, false, skipSummaryInfo: true);
91 var transformViewOutput = unbindCommand.Execute(); 94 var transformViewOutput = unbindCommand.Execute();
92 95
93 // index the added and possibly modified rows (added rows may also appears as modified rows) 96 // index the added and possibly modified rows (added rows may also appears as modified rows)
@@ -157,7 +160,7 @@ namespace WixToolset.Core.WindowsInstaller.Unbind
157 } 160 }
158 161
159 // unbind the database 162 // unbind the database
160 var unbindCommand = new UnbindDatabaseCommand(this.Messaging, msiDatabase, msiDatabaseFile, OutputType.Product, this.ExportBasePath, this.IntermediateFolder, false, false, skipSummaryInfo: true); 163 var unbindCommand = new UnbindDatabaseCommand(this.Messaging, this.BackendHelper, msiDatabase, msiDatabaseFile, OutputType.Product, this.ExportBasePath, this.IntermediateFolder, false, false, skipSummaryInfo: true);
161 var output = unbindCommand.Execute(); 164 var output = unbindCommand.Execute();
162 165
163 // index all the rows to easily find modified rows 166 // index all the rows to easily find modified rows
diff --git a/src/WixToolset.Core.WindowsInstaller/UnbindContext.cs b/src/WixToolset.Core.WindowsInstaller/UnbindContext.cs
index f60a0e1a..acfb8f1e 100644
--- a/src/WixToolset.Core.WindowsInstaller/UnbindContext.cs
+++ b/src/WixToolset.Core.WindowsInstaller/UnbindContext.cs
@@ -2,7 +2,6 @@
2 2
3namespace WixToolset.Core 3namespace WixToolset.Core
4{ 4{
5 using System;
6 using WixToolset.Extensibility.Data; 5 using WixToolset.Extensibility.Data;
7 using WixToolset.Extensibility.Services; 6 using WixToolset.Extensibility.Services;
8 7
diff --git a/src/WixToolset.Core.WindowsInstaller/Unbinder.cs b/src/WixToolset.Core.WindowsInstaller/Unbinder.cs
index 99caaba9..f712ec3f 100644
--- a/src/WixToolset.Core.WindowsInstaller/Unbinder.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Unbinder.cs
@@ -21,6 +21,8 @@ namespace WixToolset.Core
21 this.BackendFactories = extensionManager.GetServices<IBackendFactory>(); 21 this.BackendFactories = extensionManager.GetServices<IBackendFactory>();
22 } 22 }
23 23
24 public IWixToolsetServiceProvider ServiceProvider { get; }
25
24 public IEnumerable<IBackendFactory> BackendFactories { get; } 26 public IEnumerable<IBackendFactory> BackendFactories { get; }
25 27
26 /// <summary> 28 /// <summary>
@@ -29,8 +31,6 @@ namespace WixToolset.Core
29 /// <value>Set to true if the input msi is part of an admin image.</value> 31 /// <value>Set to true if the input msi is part of an admin image.</value>
30 public bool IsAdminImage { get; set; } 32 public bool IsAdminImage { get; set; }
31 33
32 public IWixToolsetServiceProvider ServiceProvider { get; }
33
34 /// <summary> 34 /// <summary>
35 /// Gets or sets the option to suppress demodularizing values. 35 /// Gets or sets the option to suppress demodularizing values.
36 /// </summary> 36 /// </summary>
diff --git a/src/WixToolset.Core.WindowsInstaller/Validator.cs b/src/WixToolset.Core.WindowsInstaller/Validator.cs
index e8117de7..a6a41bd7 100644
--- a/src/WixToolset.Core.WindowsInstaller/Validator.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Validator.cs
@@ -25,10 +25,10 @@ namespace WixToolset.Core.WindowsInstaller
25 internal sealed class Validator 25 internal sealed class Validator
26 { 26 {
27 private string actionName; 27 private string actionName;
28 private StringCollection cubeFiles; 28 private readonly StringCollection cubeFiles;
29 private ValidatorExtension extension; 29 private ValidatorExtension extension;
30 private WindowsInstallerData output; 30 private WindowsInstallerData output;
31 private InstallUIHandler validationUIHandler; 31 private readonly InstallUIHandler validationUIHandler;
32 private bool validationSessionComplete; 32 private bool validationSessionComplete;
33 private readonly IMessaging messaging; 33 private readonly IMessaging messaging;
34 34
@@ -57,7 +57,6 @@ namespace WixToolset.Core.WindowsInstaller
57 /// Gets or sets the list of ICEs to run. 57 /// Gets or sets the list of ICEs to run.
58 /// </summary> 58 /// </summary>
59 /// <value>The list of ICEs.</value> 59 /// <value>The list of ICEs.</value>
60 [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]
61 public ISet<string> ICEs { get; set; } 60 public ISet<string> ICEs { get; set; }
62 61
63 /// <summary> 62 /// <summary>
@@ -75,7 +74,6 @@ namespace WixToolset.Core.WindowsInstaller
75 /// Gets or sets the suppressed ICEs. 74 /// Gets or sets the suppressed ICEs.
76 /// </summary> 75 /// </summary>
77 /// <value>The suppressed ICEs.</value> 76 /// <value>The suppressed ICEs.</value>
78 [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]
79 public ISet<string> SuppressedICEs { get; set; } 77 public ISet<string> SuppressedICEs { get; set; }
80 78
81 /// <summary> 79 /// <summary>
@@ -103,13 +101,8 @@ namespace WixToolset.Core.WindowsInstaller
103 IntPtr previousHwnd = IntPtr.Zero; 101 IntPtr previousHwnd = IntPtr.Zero;
104 InstallUIHandler previousUIHandler = null; 102 InstallUIHandler previousUIHandler = null;
105 103
106 if (null == databaseFile)
107 {
108 throw new ArgumentNullException("databaseFile");
109 }
110
111 // initialize the validator extension 104 // initialize the validator extension
112 this.extension.DatabaseFile = databaseFile; 105 this.extension.DatabaseFile = databaseFile ?? throw new ArgumentNullException(nameof(databaseFile));
113 this.extension.Output = this.output; 106 this.extension.Output = this.output;
114 this.extension.InitializeValidator(); 107 this.extension.InitializeValidator();
115 108
diff --git a/src/WixToolset.Core.WindowsInstaller/ValidatorExtension.cs b/src/WixToolset.Core.WindowsInstaller/ValidatorExtension.cs
index 968ab387..20606a77 100644
--- a/src/WixToolset.Core.WindowsInstaller/ValidatorExtension.cs
+++ b/src/WixToolset.Core.WindowsInstaller/ValidatorExtension.cs
@@ -181,7 +181,7 @@ namespace WixToolset.Extensibility
181 throw new ArgumentNullException("message"); 181 throw new ArgumentNullException("message");
182 } 182 }
183 183
184 string[] messageParts = message.Split('\t'); 184 var messageParts = message.Split('\t');
185 if (3 > messageParts.Length) 185 if (3 > messageParts.Length)
186 { 186 {
187 if (null == action) 187 if (null == action)
@@ -194,10 +194,10 @@ namespace WixToolset.Extensibility
194 } 194 }
195 } 195 }
196 196
197 SourceLineNumber messageSourceLineNumbers = null; 197 SourceLineNumber messageSourceLineNumbers;
198 if (6 < messageParts.Length) 198 if (6 < messageParts.Length)
199 { 199 {
200 string[] primaryKeys = new string[messageParts.Length - 6]; 200 var primaryKeys = new string[messageParts.Length - 6];
201 201
202 Array.Copy(messageParts, 6, primaryKeys, 0, primaryKeys.Length); 202 Array.Copy(messageParts, 6, primaryKeys, 0, primaryKeys.Length);
203 203
@@ -242,7 +242,7 @@ namespace WixToolset.Extensibility
242 this.indexedSourceLineNumbers = new Hashtable(); 242 this.indexedSourceLineNumbers = new Hashtable();
243 243
244 // index each real table 244 // index each real table
245 foreach (Table table in this.output.Tables) 245 foreach (var table in this.output.Tables)
246 { 246 {
247 // skip unreal tables 247 // skip unreal tables
248 if (table.Definition.Unreal) 248 if (table.Definition.Unreal)
@@ -251,7 +251,7 @@ namespace WixToolset.Extensibility
251 } 251 }
252 252
253 // index each row 253 // index each row
254 foreach (Row row in table.Rows) 254 foreach (var row in table.Rows)
255 { 255 {
256 // skip rows that don't contain source line information 256 // skip rows that don't contain source line information
257 if (null == row.SourceLineNumbers) 257 if (null == row.SourceLineNumbers)
@@ -260,10 +260,10 @@ namespace WixToolset.Extensibility
260 } 260 }
261 261
262 // index the row using its table name and primary key 262 // index the row using its table name and primary key
263 string primaryKey = row.GetPrimaryKey(';'); 263 var primaryKey = row.GetPrimaryKey(';');
264 if (null != primaryKey) 264 if (null != primaryKey)
265 { 265 {
266 string key = String.Concat(table.Name, ":", primaryKey); 266 var key = String.Concat(table.Name, ":", primaryKey);
267 267
268 if (this.indexedSourceLineNumbers.ContainsKey(key)) 268 if (this.indexedSourceLineNumbers.ContainsKey(key))
269 { 269 {
diff --git a/src/WixToolset.Core/AppCommon.cs b/src/WixToolset.Core/AppCommon.cs
deleted file mode 100644
index 7f54b057..00000000
--- a/src/WixToolset.Core/AppCommon.cs
+++ /dev/null
@@ -1,45 +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
3namespace WixToolset.Core
4{
5 using System;
6 using System.Reflection;
7
8 /// <summary>
9 /// Common utilities for Wix applications.
10 /// </summary>
11 public static class AppCommon
12 {
13 /// <summary>
14 /// Creates and returns the string for CreatingApplication field (MSI Summary Information Stream).
15 /// </summary>
16 /// <remarks>It reads the AssemblyProductAttribute and AssemblyVersionAttribute of executing assembly
17 /// and builds the CreatingApplication string of the form "[ProductName] ([ProductVersion])".</remarks>
18 /// <returns>Returns value for PID_APPNAME."</returns>
19 public static string GetCreatingApplicationString()
20 {
21 var assembly = Assembly.GetExecutingAssembly();
22 return WixDistribution.ReplacePlaceholders("[AssemblyProduct] ([FileVersion])", assembly);
23 }
24
25 /// <summary>
26 /// Displays help message header on Console for caller tool.
27 /// </summary>
28 public static void DisplayToolHeader()
29 {
30 var assembly = Assembly.GetCallingAssembly();
31 Console.WriteLine(WixDistribution.ReplacePlaceholders("[AssemblyProduct] [AssemblyDescription] version [FileVersion]", assembly));
32 Console.WriteLine(WixDistribution.ReplacePlaceholders("[AssemblyCopyright]", assembly));
33 }
34
35 /// <summary>
36 /// Displays help message header on Console for caller tool.
37 /// </summary>
38 public static void DisplayToolFooter()
39 {
40 var assembly = Assembly.GetCallingAssembly();
41 Console.WriteLine();
42 Console.WriteLine(WixDistribution.ReplacePlaceholders("For more information see: [SupportUrl]", assembly));
43 }
44 }
45}
diff --git a/src/WixToolset.Core/Bind/ExtractEmbeddedFilesCommand.cs b/src/WixToolset.Core/Bind/ExtractEmbeddedFilesCommand.cs
index 29fba6b2..981a991f 100644
--- a/src/WixToolset.Core/Bind/ExtractEmbeddedFilesCommand.cs
+++ b/src/WixToolset.Core/Bind/ExtractEmbeddedFilesCommand.cs
@@ -9,8 +9,7 @@ namespace WixToolset.Core.Bind
9 using WixToolset.Extensibility.Data; 9 using WixToolset.Extensibility.Data;
10 using WixToolset.Extensibility.Services; 10 using WixToolset.Extensibility.Services;
11 11
12#pragma warning disable 1591 // TODO: this shouldn't be public, need interface in Extensibility 12 internal class ExtractEmbeddedFilesCommand
13 public class ExtractEmbeddedFilesCommand
14 { 13 {
15 public ExtractEmbeddedFilesCommand(IBackendHelper backendHelper, IEnumerable<IExpectedExtractFile> embeddedFiles) 14 public ExtractEmbeddedFilesCommand(IBackendHelper backendHelper, IEnumerable<IExpectedExtractFile> embeddedFiles)
16 { 15 {
diff --git a/src/WixToolset.Core/Bind/ResolveDelayedFieldsCommand.cs b/src/WixToolset.Core/Bind/ResolveDelayedFieldsCommand.cs
index 14b6d011..0afcc2b3 100644
--- a/src/WixToolset.Core/Bind/ResolveDelayedFieldsCommand.cs
+++ b/src/WixToolset.Core/Bind/ResolveDelayedFieldsCommand.cs
@@ -10,19 +10,18 @@ namespace WixToolset.Core.Bind
10 using WixToolset.Extensibility.Data; 10 using WixToolset.Extensibility.Data;
11 using WixToolset.Extensibility.Services; 11 using WixToolset.Extensibility.Services;
12 12
13#pragma warning disable 1591 // TODO: this shouldn't be public, need interface in Extensibility
14 /// <summary> 13 /// <summary>
15 /// Resolves the fields which had variables that needed to be resolved after the file information 14 /// Resolves the fields which had variables that needed to be resolved after the file information
16 /// was loaded. 15 /// was loaded.
17 /// </summary> 16 /// </summary>
18 public class ResolveDelayedFieldsCommand 17 internal class ResolveDelayedFieldsCommand
19 { 18 {
20 /// <summary> 19 /// <summary>
21 /// Resolve delayed fields. 20 /// Resolve delayed fields.
22 /// </summary> 21 /// </summary>
23 /// <param name="messaging"></param> 22 /// <param name="messaging"></param>
24 /// <param name="delayedFields">The fields which had resolution delayed.</param> 23 /// <param name="delayedFields">The fields which had resolution delayed.</param>
25 /// <param name="variableCache">The file information to use when resolving variables.</param> 24 /// <param name="variableCache">The cached variable values used when resolving delayed fields.</param>
26 public ResolveDelayedFieldsCommand(IMessaging messaging, IEnumerable<IDelayedField> delayedFields, Dictionary<string, string> variableCache) 25 public ResolveDelayedFieldsCommand(IMessaging messaging, IEnumerable<IDelayedField> delayedFields, Dictionary<string, string> variableCache)
27 { 26 {
28 this.Messaging = messaging; 27 this.Messaging = messaging;
@@ -49,7 +48,7 @@ namespace WixToolset.Core.Bind
49 // process properties first in case they refer to other binder variables 48 // process properties first in case they refer to other binder variables
50 if (delayedField.Symbol.Definition.Type == SymbolDefinitionType.Property) 49 if (delayedField.Symbol.Definition.Type == SymbolDefinitionType.Property)
51 { 50 {
52 var value = ResolveDelayedVariables(propertySymbol.SourceLineNumbers, delayedField.Field.AsString(), this.VariableCache); 51 var value = this.ResolveDelayedVariables(propertySymbol.SourceLineNumbers, delayedField.Field.AsString());
53 52
54 // update the variable cache with the new value 53 // update the variable cache with the new value
55 var key = String.Concat("property.", propertySymbol.Id.Id); 54 var key = String.Concat("property.", propertySymbol.Id.Id);
@@ -72,7 +71,7 @@ namespace WixToolset.Core.Bind
72 71
73 // add specialization for ProductVersion fields 72 // add specialization for ProductVersion fields
74 var keyProductVersion = "property.ProductVersion"; 73 var keyProductVersion = "property.ProductVersion";
75 if (this.VariableCache.TryGetValue(keyProductVersion, out var versionValue) && Version.TryParse(versionValue, out Version productVersion)) 74 if (this.VariableCache.TryGetValue(keyProductVersion, out var versionValue) && Version.TryParse(versionValue, out var productVersion))
76 { 75 {
77 // Don't add the variable if it already exists (developer defined a property with the same name). 76 // Don't add the variable if it already exists (developer defined a property with the same name).
78 var fieldKey = String.Concat(keyProductVersion, ".Major"); 77 var fieldKey = String.Concat(keyProductVersion, ".Major");
@@ -105,7 +104,7 @@ namespace WixToolset.Core.Bind
105 { 104 {
106 try 105 try
107 { 106 {
108 var value = ResolveDelayedVariables(delayedField.Symbol.SourceLineNumbers, delayedField.Field.AsString(), this.VariableCache); 107 var value = this.ResolveDelayedVariables(delayedField.Symbol.SourceLineNumbers, delayedField.Field.AsString());
109 delayedField.Field.Set(value); 108 delayedField.Field.Set(value);
110 } 109 }
111 catch (WixException we) 110 catch (WixException we)
@@ -115,7 +114,7 @@ namespace WixToolset.Core.Bind
115 } 114 }
116 } 115 }
117 116
118 private static string ResolveDelayedVariables(SourceLineNumber sourceLineNumbers, string value, IDictionary<string, string> resolutionData) 117 private string ResolveDelayedVariables(SourceLineNumber sourceLineNumbers, string value)
119 { 118 {
120 var start = 0; 119 var start = 0;
121 120
@@ -125,7 +124,7 @@ namespace WixToolset.Core.Bind
125 { 124 {
126 var key = String.Concat(parsed.Name, ".", parsed.Scope); 125 var key = String.Concat(parsed.Name, ".", parsed.Scope);
127 126
128 if (!resolutionData.TryGetValue(key, out var resolvedValue)) 127 if (!this.VariableCache.TryGetValue(key, out var resolvedValue))
129 { 128 {
130 resolvedValue = parsed.DefaultValue; 129 resolvedValue = parsed.DefaultValue;
131 } 130 }
@@ -149,7 +148,7 @@ namespace WixToolset.Core.Bind
149 } 148 }
150 else 149 else
151 { 150 {
152 throw new WixException(ErrorMessages.UnresolvedBindReference(sourceLineNumbers, value)); 151 this.Messaging.Write(ErrorMessages.UnresolvedBindReference(sourceLineNumbers, value));
153 } 152 }
154 } 153 }
155 else 154 else
diff --git a/src/WixToolset.Core/CommandLine/CommandLine.cs b/src/WixToolset.Core/CommandLine/CommandLine.cs
index 0c21eaaa..7371628b 100644
--- a/src/WixToolset.Core/CommandLine/CommandLine.cs
+++ b/src/WixToolset.Core/CommandLine/CommandLine.cs
@@ -55,7 +55,9 @@ namespace WixToolset.Core.CommandLine
55 55
56 if (command.ShowLogo) 56 if (command.ShowLogo)
57 { 57 {
58 AppCommon.DisplayToolHeader(); 58 var branding = this.ServiceProvider.GetService<IWixBranding>();
59 Console.WriteLine(branding.ReplacePlaceholders("[AssemblyProduct] [AssemblyDescription] version [FileVersion]"));
60 Console.WriteLine(branding.ReplacePlaceholders("[AssemblyCopyright]"));
59 } 61 }
60 62
61 return command; 63 return command;
@@ -73,6 +75,7 @@ namespace WixToolset.Core.CommandLine
73 75
74 private ICommandLineCommand Parse(ICommandLineContext context) 76 private ICommandLineCommand Parse(ICommandLineContext context)
75 { 77 {
78 var branding = context.ServiceProvider.GetService<IWixBranding>();
76 var extensions = context.ExtensionManager.GetServices<IExtensionCommandLine>(); 79 var extensions = context.ExtensionManager.GetServices<IExtensionCommandLine>();
77 80
78 foreach (var extension in extensions) 81 foreach (var extension in extensions)
@@ -118,7 +121,7 @@ namespace WixToolset.Core.CommandLine
118 extension.PostParse(); 121 extension.PostParse();
119 } 122 }
120 123
121 return command ?? new HelpCommand(extensions); 124 return command ?? new HelpCommand(extensions, branding);
122 } 125 }
123 126
124 private bool TryParseCommand(string arg, ICommandLineParser parser, IEnumerable<IExtensionCommandLine> extensions, out ICommandLineCommand command) 127 private bool TryParseCommand(string arg, ICommandLineParser parser, IEnumerable<IExtensionCommandLine> extensions, out ICommandLineCommand command)
@@ -134,7 +137,8 @@ namespace WixToolset.Core.CommandLine
134 case "h": 137 case "h":
135 case "help": 138 case "help":
136 case "-help": 139 case "-help":
137 command = new HelpCommand(extensions); 140 var branding = this.ServiceProvider.GetService<IWixBranding>();
141 command = new HelpCommand(extensions, branding);
138 break; 142 break;
139 143
140 case "version": 144 case "version":
diff --git a/src/WixToolset.Core/CommandLine/HelpCommand.cs b/src/WixToolset.Core/CommandLine/HelpCommand.cs
index 3af442aa..6a5ac183 100644
--- a/src/WixToolset.Core/CommandLine/HelpCommand.cs
+++ b/src/WixToolset.Core/CommandLine/HelpCommand.cs
@@ -19,9 +19,10 @@ namespace WixToolset.Core.CommandLine
19 new ExtensionCommandLineSwitch { Switch = "decompile", Description = "Decompile a package or bundle into source code." }, 19 new ExtensionCommandLineSwitch { Switch = "decompile", Description = "Decompile a package or bundle into source code." },
20 }; 20 };
21 21
22 public HelpCommand(IEnumerable<IExtensionCommandLine> extensions) 22 public HelpCommand(IEnumerable<IExtensionCommandLine> extensions, IWixBranding branding)
23 { 23 {
24 this.Extensions = extensions; 24 this.Extensions = extensions;
25 this.Branding = branding;
25 } 26 }
26 27
27 public bool ShowLogo => true; 28 public bool ShowLogo => true;
@@ -30,6 +31,8 @@ namespace WixToolset.Core.CommandLine
30 31
31 private IEnumerable<IExtensionCommandLine> Extensions { get; } 32 private IEnumerable<IExtensionCommandLine> Extensions { get; }
32 33
34 private IWixBranding Branding { get; }
35
33 public Task<int> ExecuteAsync(CancellationToken _) 36 public Task<int> ExecuteAsync(CancellationToken _)
34 { 37 {
35 var commandLineSwitches = new List<ExtensionCommandLineSwitch>(BuiltInSwitches); 38 var commandLineSwitches = new List<ExtensionCommandLineSwitch>(BuiltInSwitches);
@@ -52,7 +55,8 @@ namespace WixToolset.Core.CommandLine
52 55
53 Console.WriteLine(); 56 Console.WriteLine();
54 Console.WriteLine("Run 'wix [command] --help' for more information on a command."); 57 Console.WriteLine("Run 'wix [command] --help' for more information on a command.");
55 AppCommon.DisplayToolFooter(); 58 Console.WriteLine();
59 Console.WriteLine(this.Branding.ReplacePlaceholders("For more information see: [SupportUrl]"));
56 60
57 return Task.FromResult(-1); 61 return Task.FromResult(-1);
58 } 62 }
diff --git a/src/WixToolset.Core/Common.cs b/src/WixToolset.Core/Common.cs
index 79f06135..848f009a 100644
--- a/src/WixToolset.Core/Common.cs
+++ b/src/WixToolset.Core/Common.cs
@@ -18,124 +18,35 @@ namespace WixToolset.Core
18 /// <summary> 18 /// <summary>
19 /// Common Wix utility methods and types. 19 /// Common Wix utility methods and types.
20 /// </summary> 20 /// </summary>
21 public static class Common 21 internal static class Common
22 { 22 {
23 // TODO: Find a place to put all of these so they doesn't have to be public and exposed by WixToolset.Core.dll 23 private static readonly char[] IllegalShortFilenameCharacters = new[] { '\\', '?', '|', '>', '<', ':', '/', '*', '\"', '+', ',', ';', '=', '[', ']', '.', ' ' };
24 /// <summary> 24 private static readonly char[] IllegalWildcardShortFilenameCharacters = new[] { '\\', '|', '>', '<', ':', '/', '\"', '+', ',', ';', '=', '[', ']', '.', ' ' };
25 ///
26 /// </summary>
27 public const string UpgradeDetectedProperty = "WIX_UPGRADE_DETECTED";
28 /// <summary>
29 ///
30 /// </summary>
31 public const string UpgradePreventedCondition = "NOT WIX_UPGRADE_DETECTED";
32 /// <summary>
33 ///
34 /// </summary>
35 public const string DowngradeDetectedProperty = "WIX_DOWNGRADE_DETECTED";
36 /// <summary>
37 ///
38 /// </summary>
39 public const string DowngradePreventedCondition = "NOT WIX_DOWNGRADE_DETECTED";
40
41 //-------------------------------------------------------------------------------------------------
42 // Layout of an Access Mask (from http://technet.microsoft.com/en-us/library/cc783530(WS.10).aspx)
43 //
44 // -------------------------------------------------------------------------------------------------
45 // |31|30|29|28|27|26|25|24|23|22|21|20|19|18|17|16|15|14|13|12|11|10|09|08|07|06|05|04|03|02|01|00|
46 // -------------------------------------------------------------------------------------------------
47 // |GR|GW|GE|GA| Reserved |AS|StandardAccessRights| Object-Specific Access Rights |
48 //
49 // Key
50 // GR = Generic Read
51 // GW = Generic Write
52 // GE = Generic Execute
53 // GA = Generic All
54 // AS = Right to access SACL
55 //
56 // TODO: what is the expected decompile behavior if a bit is found that is not explicitly enumerated
57 //
58 //-------------------------------------------------------------------------------------------------
59 // Generic Access Rights (per WinNT.h)
60 // ---------------------
61 // GENERIC_ALL (0x10000000L)
62 // GENERIC_EXECUTE (0x20000000L)
63 // GENERIC_WRITE (0x40000000L)
64 // GENERIC_READ (0x80000000L)
65 // TODO: Find a place to put this that it doesn't have to be public and exposed by WixToolset.Core.dll
66 /// <summary>
67 ///
68 /// </summary>
69 public static readonly string[] GenericPermissions = { "GenericAll", "GenericExecute", "GenericWrite", "GenericRead" };
70
71 // Standard Access Rights (per WinNT.h)
72 // ----------------------
73 // DELETE (0x00010000L)
74 // READ_CONTROL (0x00020000L)
75 // WRITE_DAC (0x00040000L)
76 // WRITE_OWNER (0x00080000L)
77 // SYNCHRONIZE (0x00100000L)
78 // TODO: Find a place to put this that it doesn't have to be public and exposed by WixToolset.Core.dll
79 /// <summary>
80 ///
81 /// </summary>
82 public static readonly string[] StandardPermissions = { "Delete", "ReadPermission", "ChangePermission", "TakeOwnership", "Synchronize" };
83
84 // Object-Specific Access Rights
85 // =============================
86 // Directory Access Rights (per WinNT.h)
87 // -----------------------
88 // FILE_LIST_DIRECTORY ( 0x0001 )
89 // FILE_ADD_FILE ( 0x0002 )
90 // FILE_ADD_SUBDIRECTORY ( 0x0004 )
91 // FILE_READ_EA ( 0x0008 )
92 // FILE_WRITE_EA ( 0x0010 )
93 // FILE_TRAVERSE ( 0x0020 )
94 // FILE_DELETE_CHILD ( 0x0040 )
95 // FILE_READ_ATTRIBUTES ( 0x0080 )
96 // FILE_WRITE_ATTRIBUTES ( 0x0100 )
97 // TODO: Find a place to put this that it doesn't have to be public and exposed by WixToolset.Core.dll
98 /// <summary>
99 ///
100 /// </summary>
101 public static readonly string[] FolderPermissions = { "Read", "CreateFile", "CreateChild", "ReadExtendedAttributes", "WriteExtendedAttributes", "Traverse", "DeleteChild", "ReadAttributes", "WriteAttributes" };
102
103 // Registry Access Rights (per TODO)
104 // ----------------------
105 // TODO: Find a place to put this that it doesn't have to be public and exposed by WixToolset.Core.dll
106 /// <summary>
107 ///
108 /// </summary>
109 public static readonly string[] RegistryPermissions = { "Read", "Write", "CreateSubkeys", "EnumerateSubkeys", "Notify", "CreateLink" };
110
111 // File Access Rights (per WinNT.h)
112 // ------------------
113 // FILE_READ_DATA ( 0x0001 )
114 // FILE_WRITE_DATA ( 0x0002 )
115 // FILE_APPEND_DATA ( 0x0004 )
116 // FILE_READ_EA ( 0x0008 )
117 // FILE_WRITE_EA ( 0x0010 )
118 // FILE_EXECUTE ( 0x0020 )
119 // via mask FILE_ALL_ACCESS ( 0x0040 )
120 // FILE_READ_ATTRIBUTES ( 0x0080 )
121 // FILE_WRITE_ATTRIBUTES ( 0x0100 )
122 //
123 // STANDARD_RIGHTS_REQUIRED (0x000F0000L)
124 // FILE_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x1FF)
125 // TODO: Find a place to put this that it doesn't have to be public and exposed by WixToolset.Core.dll
126 /// <summary>
127 ///
128 /// </summary>
129 public static readonly string[] FilePermissions = { "Read", "Write", "Append", "ReadExtendedAttributes", "WriteExtendedAttributes", "Execute", "FileAllRights", "ReadAttributes", "WriteAttributes" };
130 25
131 internal static readonly char[] IllegalLongFilenameCharacters = new[] { '\\', '/', '?', '*', '|', '>', '<', ':', '\"' }; // illegal: \ / ? | > < : / * " 26 internal static readonly char[] IllegalLongFilenameCharacters = new[] { '\\', '/', '?', '*', '|', '>', '<', ':', '\"' }; // illegal: \ / ? | > < : / * "
132 internal static readonly char[] IllegalRelativeLongFilenameCharacters = new[] { '?', '*', '|', '>', '<', ':', '\"' }; // like illegal, but we allow '\' and '/' 27 internal static readonly char[] IllegalRelativeLongFilenameCharacters = new[] { '?', '*', '|', '>', '<', ':', '\"' }; // like illegal, but we allow '\' and '/'
133 internal static readonly char[] IllegalWildcardLongFilenameCharacters = new[] { '\\', '/', '|', '>', '<', ':', '\"' }; // like illegal: but we allow '*' and '?' 28 internal static readonly char[] IllegalWildcardLongFilenameCharacters = new[] { '\\', '/', '|', '>', '<', ':', '\"' }; // like illegal: but we allow '*' and '?'
134 29
135 private static readonly char[] IllegalShortFilenameCharacters = new[] { '\\', '?', '|', '>', '<', ':', '/', '*', '\"', '+', ',', ';', '=', '[', ']', '.', ' ' }; 30 public static string GetCanonicalRelativePath(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string relativePath, IMessaging messageHandler)
136 private static readonly char[] IllegalWildcardShortFilenameCharacters = new[] { '\\', '|', '>', '<', ':', '/', '\"', '+', ',', ';', '=', '[', ']', '.', ' ' }; 31 {
137 32 const string root = @"C:\";
33 if (!Path.IsPathRooted(relativePath))
34 {
35 var normalizedPath = Path.GetFullPath(root + relativePath);
36 if (normalizedPath.StartsWith(root))
37 {
38 var canonicalizedPath = normalizedPath.Substring(root.Length);
39 if (canonicalizedPath != relativePath)
40 {
41 messageHandler.Write(WarningMessages.PathCanonicalized(sourceLineNumbers, elementName, attributeName, relativePath, canonicalizedPath));
42 }
43 return canonicalizedPath;
44 }
45 }
138 46
47 messageHandler.Write(ErrorMessages.PayloadMustBeRelativeToCache(sourceLineNumbers, elementName, attributeName, relativePath));
48 return relativePath;
49 }
139 50
140 /// <summary> 51 /// <summary>
141 /// Gets a valid code page from the given web name or integer value. 52 /// Gets a valid code page from the given web name or integer value.
@@ -157,8 +68,8 @@ namespace WixToolset.Core
157 { 68 {
158 Encoding encoding; 69 Encoding encoding;
159 70
160 // check if a integer as a string was passed 71 // Check if a integer as a string was passed.
161 if (Int32.TryParse(value, out int codePage)) 72 if (Int32.TryParse(value, out var codePage))
162 { 73 {
163 if (0 == codePage) 74 if (0 == codePage)
164 { 75 {
@@ -198,18 +109,91 @@ namespace WixToolset.Core
198 } 109 }
199 catch (ArgumentException ex) 110 catch (ArgumentException ex)
200 { 111 {
201 // rethrow as NotSupportedException since either can be thrown 112 // Rethrow as NotSupportedException since either can be thrown
202 // if the system does not support the specified code page 113 // if the system does not support the specified code page.
203 throw new NotSupportedException(ex.Message, ex); 114 throw new NotSupportedException(ex.Message, ex);
204 } 115 }
205 } 116 }
206 117
207 /// <summary> 118 /// <summary>
208 /// Verifies if a filename is a valid short filename. 119 /// Verifies if an identifier is a valid binder variable name.
120 /// </summary>
121 /// <param name="variable">Binder variable name to verify.</param>
122 /// <returns>True if the identifier is a valid binder variable name.</returns>
123 public static bool IsValidBinderVariable(string variable)
124 {
125 return TryParseWixVariable(variable, 0, out var parsed) && parsed.Index == 0 && parsed.Length == variable.Length && (parsed.Namespace == "bind" || parsed.Namespace == "wix");
126 }
127
128 /// <summary>
129 /// Verifies if a string contains a valid binder variable name.
130 /// </summary>
131 /// <param name="verify">String to verify.</param>
132 /// <returns>True if the string contains a valid binder variable name.</returns>
133 public static bool ContainsValidBinderVariable(string verify)
134 {
135 return TryParseWixVariable(verify, 0, out var parsed) && (parsed.Namespace == "bind" || parsed.Namespace == "wix");
136 }
137
138 /// <summary>
139 /// Verifies the given string is a valid 4-part version module or bundle version.
209 /// </summary> 140 /// </summary>
210 /// <param name="filename">Filename to verify.</param> 141 /// <param name="version">The version to verify.</param>
211 /// <param name="allowWildcards">true if wildcards are allowed in the filename.</param> 142 /// <returns>True if version is a valid module or bundle version.</returns>
212 /// <returns>True if the filename is a valid short filename</returns> 143 public static bool IsValidFourPartVersion(string version)
144 {
145 if (!Common.IsValidBinderVariable(version))
146 {
147 if (!Version.TryParse(version, out var ver) || 65535 < ver.Major || 65535 < ver.Minor || 65535 < ver.Build || 65535 < ver.Revision)
148 {
149 return false;
150 }
151 }
152
153 return true;
154 }
155
156 public static bool IsValidLongFilename(string filename, bool allowWildcards, bool allowRelative)
157 {
158 if (String.IsNullOrEmpty(filename))
159 {
160 return false;
161 }
162 else if (filename.Length > 259)
163 {
164 return false;
165 }
166
167 // Check for a non-period character (all periods is not legal)
168 var allPeriods = true;
169 foreach (var character in filename)
170 {
171 if ('.' != character)
172 {
173 allPeriods = false;
174 break;
175 }
176 }
177
178 if (allPeriods)
179 {
180 return false;
181 }
182
183 if (allowWildcards)
184 {
185 return filename.IndexOfAny(Common.IllegalWildcardLongFilenameCharacters) == -1;
186 }
187 else if (allowRelative)
188 {
189 return filename.IndexOfAny(Common.IllegalRelativeLongFilenameCharacters) == -1;
190 }
191 else
192 {
193 return filename.IndexOfAny(Common.IllegalLongFilenameCharacters) == -1;
194 }
195 }
196
213 public static bool IsValidShortFilename(string filename, bool allowWildcards) 197 public static bool IsValidShortFilename(string filename, bool allowWildcards)
214 { 198 {
215 if (String.IsNullOrEmpty(filename)) 199 if (String.IsNullOrEmpty(filename))
@@ -291,55 +275,6 @@ namespace WixToolset.Core
291 } 275 }
292 276
293 /// <summary> 277 /// <summary>
294 /// Verifies if an identifier is a valid binder variable name.
295 /// </summary>
296 /// <param name="variable">Binder variable name to verify.</param>
297 /// <returns>True if the identifier is a valid binder variable name.</returns>
298 public static bool IsValidBinderVariable(string variable)
299 {
300 return TryParseWixVariable(variable, 0, out var parsed) && parsed.Index == 0 && parsed.Length == variable.Length && (parsed.Namespace == "bind" || parsed.Namespace == "wix");
301 }
302
303 /// <summary>
304 /// Verifies if a string contains a valid binder variable name.
305 /// </summary>
306 /// <param name="verify">String to verify.</param>
307 /// <returns>True if the string contains a valid binder variable name.</returns>
308 public static bool ContainsValidBinderVariable(string verify)
309 {
310 return TryParseWixVariable(verify, 0, out var parsed) && (parsed.Namespace == "bind" || parsed.Namespace == "wix");
311 }
312
313 /// <summary>
314 /// Verifies the given string is a valid module or bundle version.
315 /// </summary>
316 /// <param name="version">The version to verify.</param>
317 /// <returns>True if version is a valid module or bundle version.</returns>
318 public static bool IsValidModuleOrBundleVersion(string version)
319 {
320 if (!Common.IsValidBinderVariable(version))
321 {
322 Version ver;
323
324 try
325 {
326 ver = new Version(version);
327 }
328 catch (ArgumentException)
329 {
330 return false;
331 }
332
333 if (65535 < ver.Major || 65535 < ver.Minor || 65535 < ver.Build || 65535 < ver.Revision)
334 {
335 return false;
336 }
337 }
338
339 return true;
340 }
341
342 /// <summary>
343 /// Generate a new Windows Installer-friendly guid. 278 /// Generate a new Windows Installer-friendly guid.
344 /// </summary> 279 /// </summary>
345 /// <returns>A new guid.</returns> 280 /// <returns>A new guid.</returns>
@@ -451,14 +386,14 @@ namespace WixToolset.Core
451 /// <param name="markAttribute">If true, add the attribute to each file. If false, remove it.</param> 386 /// <param name="markAttribute">If true, add the attribute to each file. If false, remove it.</param>
452 private static void RecursiveFileAttributes(string path, FileAttributes fileAttribute, bool markAttribute, IMessaging messageHandler) 387 private static void RecursiveFileAttributes(string path, FileAttributes fileAttribute, bool markAttribute, IMessaging messageHandler)
453 { 388 {
454 foreach (string subDirectory in Directory.GetDirectories(path)) 389 foreach (var subDirectory in Directory.GetDirectories(path))
455 { 390 {
456 RecursiveFileAttributes(subDirectory, fileAttribute, markAttribute, messageHandler); 391 RecursiveFileAttributes(subDirectory, fileAttribute, markAttribute, messageHandler);
457 } 392 }
458 393
459 foreach (string filePath in Directory.GetFiles(path)) 394 foreach (var filePath in Directory.GetFiles(path))
460 { 395 {
461 FileAttributes attributes = File.GetAttributes(filePath); 396 var attributes = File.GetAttributes(filePath);
462 if (markAttribute) 397 if (markAttribute)
463 { 398 {
464 attributes = attributes | fileAttribute; // add to list of attributes 399 attributes = attributes | fileAttribute; // add to list of attributes
@@ -506,16 +441,15 @@ namespace WixToolset.Core
506 /// <returns>An array of strings of length 4. The contents are: short target, long target, short source, and long source.</returns> 441 /// <returns>An array of strings of length 4. The contents are: short target, long target, short source, and long source.</returns>
507 /// <remarks> 442 /// <remarks>
508 /// If any particular file name part is not parsed, its set to null in the appropriate location of the returned array of strings. 443 /// If any particular file name part is not parsed, its set to null in the appropriate location of the returned array of strings.
509 /// However, the returned array will always be of length 4. 444 /// Thus the returned array will always be of length 4.
510 /// </remarks> 445 /// </remarks>
511 public static string[] GetNames(string value) 446 public static string[] GetNames(string value)
512 { 447 {
513 string[] names = new string[4]; 448 var targetSeparator = value.IndexOf(':');
514 int targetSeparator = value.IndexOf(':');
515 449
516 // split source and target 450 // split source and target
517 string sourceName = null; 451 string sourceName = null;
518 string targetName = value; 452 var targetName = value;
519 if (0 <= targetSeparator) 453 if (0 <= targetSeparator)
520 { 454 {
521 sourceName = value.Substring(targetSeparator + 1); 455 sourceName = value.Substring(targetSeparator + 1);
@@ -526,7 +460,7 @@ namespace WixToolset.Core
526 string sourceLongName = null; 460 string sourceLongName = null;
527 if (null != sourceName) 461 if (null != sourceName)
528 { 462 {
529 int sourceLongNameSeparator = sourceName.IndexOf('|'); 463 var sourceLongNameSeparator = sourceName.IndexOf('|');
530 if (0 <= sourceLongNameSeparator) 464 if (0 <= sourceLongNameSeparator)
531 { 465 {
532 sourceLongName = sourceName.Substring(sourceLongNameSeparator + 1); 466 sourceLongName = sourceName.Substring(sourceLongNameSeparator + 1);
@@ -535,7 +469,7 @@ namespace WixToolset.Core
535 } 469 }
536 470
537 // split the target short and long names 471 // split the target short and long names
538 int targetLongNameSeparator = targetName.IndexOf('|'); 472 var targetLongNameSeparator = targetName.IndexOf('|');
539 string targetLongName = null; 473 string targetLongName = null;
540 if (0 <= targetLongNameSeparator) 474 if (0 <= targetLongNameSeparator)
541 { 475 {
@@ -543,19 +477,19 @@ namespace WixToolset.Core
543 targetName = targetName.Substring(0, targetLongNameSeparator); 477 targetName = targetName.Substring(0, targetLongNameSeparator);
544 } 478 }
545 479
546 // remove the long source name when its identical to the long source name 480 // Remove the long source name when its identical to the short source name.
547 if (null != sourceName && sourceName == sourceLongName) 481 if (null != sourceName && sourceName == sourceLongName)
548 { 482 {
549 sourceLongName = null; 483 sourceLongName = null;
550 } 484 }
551 485
552 // remove the long target name when its identical to the long target name 486 // Remove the long target name when its identical to the long target name.
553 if (null != targetName && targetName == targetLongName) 487 if (null != targetName && targetName == targetLongName)
554 { 488 {
555 targetLongName = null; 489 targetLongName = null;
556 } 490 }
557 491
558 // remove the source names when they are identical to the target names 492 // Remove the source names when they are identical to the target names.
559 if (sourceName == targetName && sourceLongName == targetLongName) 493 if (sourceName == targetName && sourceLongName == targetLongName)
560 { 494 {
561 sourceName = null; 495 sourceName = null;
@@ -563,28 +497,28 @@ namespace WixToolset.Core
563 } 497 }
564 498
565 // target name(s) 499 // target name(s)
566 if ("." != targetName) 500 if ("." == targetName)
567 { 501 {
568 names[0] = targetName; 502 targetName = null;
569 } 503 }
570 504
571 if (null != targetLongName && "." != targetLongName) 505 if ("." == targetLongName)
572 { 506 {
573 names[1] = targetLongName; 507 targetLongName = null;
574 } 508 }
575 509
576 // source name(s) 510 // source name(s)
577 if (null != sourceName) 511 if ("." == sourceName)
578 { 512 {
579 names[2] = sourceName; 513 sourceName = null;
580 } 514 }
581 515
582 if (null != sourceLongName && "." != sourceLongName) 516 if ("." == sourceLongName)
583 { 517 {
584 names[3] = sourceLongName; 518 sourceLongName = null;
585 } 519 }
586 520
587 return names; 521 return new[] { targetName, targetLongName, sourceName, sourceLongName };
588 } 522 }
589 523
590 /// <summary> 524 /// <summary>
@@ -596,7 +530,7 @@ namespace WixToolset.Core
596 /// <returns>The name.</returns> 530 /// <returns>The name.</returns>
597 public static string GetName(string value, bool source, bool longName) 531 public static string GetName(string value, bool source, bool longName)
598 { 532 {
599 string[] names = GetNames(value); 533 var names = GetNames(value);
600 534
601 if (source) 535 if (source)
602 { 536 {
@@ -674,7 +608,7 @@ namespace WixToolset.Core
674 /// <returns>The attribute's identifier value or a special value if an error occurred.</returns> 608 /// <returns>The attribute's identifier value or a special value if an error occurred.</returns>
675 internal static string GetAttributeIdentifierValue(IMessaging messaging, SourceLineNumber sourceLineNumbers, XAttribute attribute) 609 internal static string GetAttributeIdentifierValue(IMessaging messaging, SourceLineNumber sourceLineNumbers, XAttribute attribute)
676 { 610 {
677 string value = Common.GetAttributeValue(messaging, sourceLineNumbers, attribute, EmptyRule.CanBeWhitespaceOnly); 611 var value = Common.GetAttributeValue(messaging, sourceLineNumbers, attribute, EmptyRule.CanBeWhitespaceOnly);
678 612
679 if (Common.IsIdentifier(value)) 613 if (Common.IsIdentifier(value))
680 { 614 {
@@ -713,8 +647,8 @@ namespace WixToolset.Core
713 { 647 {
714 Debug.Assert(minimum > CompilerConstants.IntegerNotSet && minimum > CompilerConstants.IllegalInteger, "The legal values for this attribute collide with at least one sentinel used during parsing."); 648 Debug.Assert(minimum > CompilerConstants.IntegerNotSet && minimum > CompilerConstants.IllegalInteger, "The legal values for this attribute collide with at least one sentinel used during parsing.");
715 649
716 string value = Common.GetAttributeValue(messaging, sourceLineNumbers, attribute, EmptyRule.CanBeWhitespaceOnly); 650 var value = Common.GetAttributeValue(messaging, sourceLineNumbers, attribute, EmptyRule.CanBeWhitespaceOnly);
717 int integer = CompilerConstants.IllegalInteger; 651 var integer = CompilerConstants.IllegalInteger;
718 652
719 if (0 < value.Length) 653 if (0 < value.Length)
720 { 654 {
@@ -748,8 +682,8 @@ namespace WixToolset.Core
748 /// <returns>The attribute's YesNoType value.</returns> 682 /// <returns>The attribute's YesNoType value.</returns>
749 internal static YesNoType GetAttributeYesNoValue(IMessaging messaging, SourceLineNumber sourceLineNumbers, XAttribute attribute) 683 internal static YesNoType GetAttributeYesNoValue(IMessaging messaging, SourceLineNumber sourceLineNumbers, XAttribute attribute)
750 { 684 {
751 string value = Common.GetAttributeValue(messaging, sourceLineNumbers, attribute, EmptyRule.CanBeWhitespaceOnly); 685 var value = Common.GetAttributeValue(messaging, sourceLineNumbers, attribute, EmptyRule.CanBeWhitespaceOnly);
752 YesNoType yesNo = YesNoType.IllegalValue; 686 var yesNo = YesNoType.IllegalValue;
753 687
754 if ("yes".Equals(value) || "true".Equals(value)) 688 if ("yes".Equals(value) || "true".Equals(value))
755 { 689 {
diff --git a/src/WixToolset.Core/Compiler.cs b/src/WixToolset.Core/Compiler.cs
index f311a5f6..2aa25141 100644
--- a/src/WixToolset.Core/Compiler.cs
+++ b/src/WixToolset.Core/Compiler.cs
@@ -7073,7 +7073,7 @@ namespace WixToolset.Core
7073 Remove = removeFeatures, 7073 Remove = removeFeatures,
7074 MigrateFeatures = migrateFeatures, 7074 MigrateFeatures = migrateFeatures,
7075 IgnoreRemoveFailures = ignoreRemoveFailure, 7075 IgnoreRemoveFailures = ignoreRemoveFailure,
7076 ActionProperty = Common.UpgradeDetectedProperty 7076 ActionProperty = WixUpgradeConstants.UpgradeDetectedProperty
7077 }); 7077 });
7078 7078
7079 if (allowDowngrades) 7079 if (allowDowngrades)
@@ -7094,7 +7094,7 @@ namespace WixToolset.Core
7094 { 7094 {
7095 this.Core.AddSymbol(new LaunchConditionSymbol(sourceLineNumbers) 7095 this.Core.AddSymbol(new LaunchConditionSymbol(sourceLineNumbers)
7096 { 7096 {
7097 Condition = Common.UpgradePreventedCondition, 7097 Condition = WixUpgradeConstants.UpgradePreventedCondition,
7098 Description = downgradeErrorMessage 7098 Description = downgradeErrorMessage
7099 }); 7099 });
7100 } 7100 }
@@ -7109,12 +7109,12 @@ namespace WixToolset.Core
7109 Language = productLanguage, 7109 Language = productLanguage,
7110 OnlyDetect = true, 7110 OnlyDetect = true,
7111 IgnoreRemoveFailures = ignoreRemoveFailure, 7111 IgnoreRemoveFailures = ignoreRemoveFailure,
7112 ActionProperty = Common.DowngradeDetectedProperty 7112 ActionProperty = WixUpgradeConstants.DowngradeDetectedProperty
7113 }); 7113 });
7114 7114
7115 this.Core.AddSymbol(new LaunchConditionSymbol(sourceLineNumbers) 7115 this.Core.AddSymbol(new LaunchConditionSymbol(sourceLineNumbers)
7116 { 7116 {
7117 Condition = Common.DowngradePreventedCondition, 7117 Condition = WixUpgradeConstants.DowngradePreventedCondition,
7118 Description = downgradeErrorMessage 7118 Description = downgradeErrorMessage
7119 }); 7119 });
7120 } 7120 }
diff --git a/src/WixToolset.Core/CompilerCore.cs b/src/WixToolset.Core/CompilerCore.cs
index cfe3082e..ec22a8ec 100644
--- a/src/WixToolset.Core/CompilerCore.cs
+++ b/src/WixToolset.Core/CompilerCore.cs
@@ -297,20 +297,6 @@ namespace WixToolset.Core
297 } 297 }
298 298
299 /// <summary> 299 /// <summary>
300 /// Creates a short file/directory name using an identifier and long file/directory name as input.
301 /// </summary>
302 /// <param name="longName">The long file/directory name.</param>
303 /// <param name="keepExtension">The option to keep the extension on generated short names.</param>
304 /// <param name="allowWildcards">true if wildcards are allowed in the filename.</param>
305 /// <param name="args">Any additional information to include in the hash for the generated short name.</param>
306 /// <returns>The generated 8.3-compliant short file/directory name.</returns>
307 [Obsolete]
308 public string CreateShortName(string longName, bool keepExtension, bool allowWildcards, params string[] args)
309 {
310 return this.parseHelper.CreateShortName(longName, keepExtension, allowWildcards, args);
311 }
312
313 /// <summary>
314 /// Verifies the given string is a valid product version. 300 /// Verifies the given string is a valid product version.
315 /// </summary> 301 /// </summary>
316 /// <param name="version">The product version to verify.</param> 302 /// <param name="version">The product version to verify.</param>
@@ -337,7 +323,7 @@ namespace WixToolset.Core
337 /// <returns>True if version is a valid module or bundle version.</returns> 323 /// <returns>True if version is a valid module or bundle version.</returns>
338 public static bool IsValidModuleOrBundleVersion(string version) 324 public static bool IsValidModuleOrBundleVersion(string version)
339 { 325 {
340 return Common.IsValidModuleOrBundleVersion(version); 326 return Common.IsValidFourPartVersion(version);
341 } 327 }
342 328
343 /// <summary> 329 /// <summary>
@@ -547,15 +533,14 @@ namespace WixToolset.Core
547 { 533 {
548 if (null == attribute) 534 if (null == attribute)
549 { 535 {
550 throw new ArgumentNullException("attribute"); 536 throw new ArgumentNullException(nameof(attribute));
551 } 537 }
552 538
553 string value = this.GetAttributeValue(sourceLineNumbers, attribute); 539 var value = this.GetAttributeValue(sourceLineNumbers, attribute);
554 540
555 try 541 try
556 { 542 {
557 int codePage = Common.GetValidCodePage(value); 543 return Common.GetValidCodePage(value);
558 return codePage;
559 } 544 }
560 catch (NotSupportedException) 545 catch (NotSupportedException)
561 { 546 {
@@ -576,12 +561,12 @@ namespace WixToolset.Core
576 { 561 {
577 if (null == attribute) 562 if (null == attribute)
578 { 563 {
579 throw new ArgumentNullException("attribute"); 564 throw new ArgumentNullException(nameof(attribute));
580 } 565 }
581 566
582 string value = this.GetAttributeValue(sourceLineNumbers, attribute); 567 var value = this.GetAttributeValue(sourceLineNumbers, attribute);
583 568
584 // allow for localization of code page names and values 569 // Allow for localization of code page names and values.
585 if (this.IsValidLocIdentifier(value)) 570 if (this.IsValidLocIdentifier(value))
586 { 571 {
587 return value; 572 return value;
@@ -589,13 +574,13 @@ namespace WixToolset.Core
589 574
590 try 575 try
591 { 576 {
592 int codePage = Common.GetValidCodePage(value, false, onlyAnsi, sourceLineNumbers); 577 var codePage = Common.GetValidCodePage(value, false, onlyAnsi, sourceLineNumbers);
593 return codePage.ToString(CultureInfo.InvariantCulture); 578 return codePage.ToString(CultureInfo.InvariantCulture);
594 } 579 }
595 catch (NotSupportedException) 580 catch (NotSupportedException)
596 { 581 {
597 // not a valid windows code page 582 // Not a valid windows code page.
598 this.Write(ErrorMessages.IllegalCodepageAttribute(sourceLineNumbers, value, attribute.Parent.Name.LocalName, attribute.Name.LocalName)); 583 this.messaging.Write(ErrorMessages.IllegalCodepageAttribute(sourceLineNumbers, value, attribute.Parent.Name.LocalName, attribute.Name.LocalName));
599 } 584 }
600 catch (WixException e) 585 catch (WixException e)
601 { 586 {
@@ -805,7 +790,7 @@ namespace WixToolset.Core
805 790
806 if (0 < value.Length) 791 if (0 < value.Length)
807 { 792 {
808 if (!this.IsValidShortFilename(value, allowWildcards) && !Common.ContainsValidBinderVariable(value)) 793 if (!this.parseHelper.IsValidShortFilename(value, allowWildcards) && !Common.ContainsValidBinderVariable(value))
809 { 794 {
810 this.Write(ErrorMessages.IllegalShortFilename(sourceLineNumbers, attribute.Parent.Name.LocalName, attribute.Name.LocalName, value)); 795 this.Write(ErrorMessages.IllegalShortFilename(sourceLineNumbers, attribute.Parent.Name.LocalName, attribute.Name.LocalName, value));
811 } 796 }
diff --git a/src/WixToolset.Core/Compiler_Package.cs b/src/WixToolset.Core/Compiler_Package.cs
index 03ba1c40..1dac5399 100644
--- a/src/WixToolset.Core/Compiler_Package.cs
+++ b/src/WixToolset.Core/Compiler_Package.cs
@@ -1024,13 +1024,13 @@ namespace WixToolset.Core
1024 switch (tableName) 1024 switch (tableName)
1025 { 1025 {
1026 case "CreateFolder": 1026 case "CreateFolder":
1027 specialPermissions = Common.FolderPermissions; 1027 specialPermissions = LockPermissionConstants.FolderPermissions;
1028 break; 1028 break;
1029 case "File": 1029 case "File":
1030 specialPermissions = Common.FilePermissions; 1030 specialPermissions = LockPermissionConstants.FilePermissions;
1031 break; 1031 break;
1032 case "Registry": 1032 case "Registry":
1033 specialPermissions = Common.RegistryPermissions; 1033 specialPermissions = LockPermissionConstants.RegistryPermissions;
1034 break; 1034 break;
1035 default: 1035 default:
1036 this.Core.UnexpectedElement(node.Parent, node); 1036 this.Core.UnexpectedElement(node.Parent, node);
@@ -1059,9 +1059,9 @@ namespace WixToolset.Core
1059 break; 1059 break;
1060 default: 1060 default:
1061 var attribValue = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); 1061 var attribValue = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
1062 if (!this.Core.TrySetBitFromName(Common.StandardPermissions, attrib.Name.LocalName, attribValue, bits, 16)) 1062 if (!this.Core.TrySetBitFromName(LockPermissionConstants.StandardPermissions, attrib.Name.LocalName, attribValue, bits, 16))
1063 { 1063 {
1064 if (!this.Core.TrySetBitFromName(Common.GenericPermissions, attrib.Name.LocalName, attribValue, bits, 28)) 1064 if (!this.Core.TrySetBitFromName(LockPermissionConstants.GenericPermissions, attrib.Name.LocalName, attribValue, bits, 28))
1065 { 1065 {
1066 if (!this.Core.TrySetBitFromName(specialPermissions, attrib.Name.LocalName, attribValue, bits, 0)) 1066 if (!this.Core.TrySetBitFromName(specialPermissions, attrib.Name.LocalName, attribValue, bits, 0))
1067 { 1067 {
diff --git a/src/WixToolset.Core/Compiler_Patch.cs b/src/WixToolset.Core/Compiler_Patch.cs
index 998894d8..a2cadd67 100644
--- a/src/WixToolset.Core/Compiler_Patch.cs
+++ b/src/WixToolset.Core/Compiler_Patch.cs
@@ -95,13 +95,13 @@ namespace WixToolset.Core
95 targetProductName = this.Core.GetAttributeValue(sourceLineNumbers, attrib); 95 targetProductName = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
96 break; 96 break;
97 case "ApiPatchingSymbolNoImagehlpFlag": 97 case "ApiPatchingSymbolNoImagehlpFlag":
98 apiPatchingSymbolFlags |= (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) ? (int)PatchSymbolFlagsType.PATCH_SYMBOL_NO_IMAGEHLP : 0; 98 apiPatchingSymbolFlags |= (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) ? (int)PatchSymbolFlags.PatchSymbolNoImagehlp : 0;
99 break; 99 break;
100 case "ApiPatchingSymbolNoFailuresFlag": 100 case "ApiPatchingSymbolNoFailuresFlag":
101 apiPatchingSymbolFlags |= (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) ? (int)PatchSymbolFlagsType.PATCH_SYMBOL_NO_FAILURES : 0; 101 apiPatchingSymbolFlags |= (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) ? (int)PatchSymbolFlags.PatchSymbolNoFailures : 0;
102 break; 102 break;
103 case "ApiPatchingSymbolUndecoratedTooFlag": 103 case "ApiPatchingSymbolUndecoratedTooFlag":
104 apiPatchingSymbolFlags |= (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) ? (int)PatchSymbolFlagsType.PATCH_SYMBOL_UNDECORATED_TOO : 0; 104 apiPatchingSymbolFlags |= (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) ? (int)PatchSymbolFlags.PatchSymbolUndecoratedToo : 0;
105 break; 105 break;
106 case "OptimizePatchSizeForLargeFiles": 106 case "OptimizePatchSizeForLargeFiles":
107 optimizePatchSizeForLargeFiles = (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)); 107 optimizePatchSizeForLargeFiles = (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib));
@@ -275,7 +275,7 @@ namespace WixToolset.Core
275 private int ParseOptimizeCustomActionsElement(XElement node) 275 private int ParseOptimizeCustomActionsElement(XElement node)
276 { 276 {
277 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); 277 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
278 var optimizeCA = OptimizeCA.None; 278 var optimizeCA = OptimizeCAFlags.None;
279 279
280 foreach (var attrib in node.Attributes()) 280 foreach (var attrib in node.Attributes())
281 { 281 {
@@ -286,19 +286,19 @@ namespace WixToolset.Core
286 case "SkipAssignment": 286 case "SkipAssignment":
287 if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) 287 if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib))
288 { 288 {
289 optimizeCA |= OptimizeCA.SkipAssignment; 289 optimizeCA |= OptimizeCAFlags.SkipAssignment;
290 } 290 }
291 break; 291 break;
292 case "SkipImmediate": 292 case "SkipImmediate":
293 if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) 293 if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib))
294 { 294 {
295 optimizeCA |= OptimizeCA.SkipImmediate; 295 optimizeCA |= OptimizeCAFlags.SkipImmediate;
296 } 296 }
297 break; 297 break;
298 case "SkipDeferred": 298 case "SkipDeferred":
299 if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) 299 if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib))
300 { 300 {
301 optimizeCA |= OptimizeCA.SkipDeferred; 301 optimizeCA |= OptimizeCAFlags.SkipDeferred;
302 } 302 }
303 break; 303 break;
304 default: 304 default:
diff --git a/src/WixToolset.Core/ExtensibilityServices/BackendHelper.cs b/src/WixToolset.Core/ExtensibilityServices/BackendHelper.cs
index 7b20286c..3dcc0ce9 100644
--- a/src/WixToolset.Core/ExtensibilityServices/BackendHelper.cs
+++ b/src/WixToolset.Core/ExtensibilityServices/BackendHelper.cs
@@ -3,8 +3,12 @@
3namespace WixToolset.Core.ExtensibilityServices 3namespace WixToolset.Core.ExtensibilityServices
4{ 4{
5 using System; 5 using System;
6 using System.Collections.Generic;
6 using System.IO; 7 using System.IO;
8 using WixToolset.Core.Bind;
7 using WixToolset.Data; 9 using WixToolset.Data;
10 using WixToolset.Data.Symbols;
11 using WixToolset.Data.WindowsInstaller.Rows;
8 using WixToolset.Extensibility.Data; 12 using WixToolset.Extensibility.Data;
9 using WixToolset.Extensibility.Services; 13 using WixToolset.Extensibility.Services;
10 14
@@ -15,12 +19,24 @@ namespace WixToolset.Core.ExtensibilityServices
15 public BackendHelper(IWixToolsetServiceProvider serviceProvider) 19 public BackendHelper(IWixToolsetServiceProvider serviceProvider)
16 { 20 {
17 this.Messaging = serviceProvider.GetService<IMessaging>(); 21 this.Messaging = serviceProvider.GetService<IMessaging>();
18 this.ParseHelper = serviceProvider.GetService<IParseHelper>();
19 } 22 }
20 23
21 private IMessaging Messaging { get; } 24 private IMessaging Messaging { get; }
22 25
23 private IParseHelper ParseHelper { get; } 26 public IFileFacade CreateFileFacade(FileSymbol file, AssemblySymbol assembly)
27 {
28 return new FileFacade(file, assembly);
29 }
30
31 public IFileFacade CreateFileFacade(FileRow fileRow)
32 {
33 return new FileFacade(fileRow);
34 }
35
36 public IFileFacade CreateFileFacadeFromMergeModule(FileSymbol fileSymbol)
37 {
38 return new FileFacade(true, fileSymbol);
39 }
24 40
25 public IFileTransfer CreateFileTransfer(string source, string destination, bool move, SourceLineNumber sourceLineNumbers = null) 41 public IFileTransfer CreateFileTransfer(string source, string destination, bool move, SourceLineNumber sourceLineNumbers = null)
26 { 42 {
@@ -38,6 +54,11 @@ namespace WixToolset.Core.ExtensibilityServices
38 }; 54 };
39 } 55 }
40 56
57 public string CreateGuid()
58 {
59 return Common.GenerateGuid();
60 }
61
41 public string CreateGuid(Guid namespaceGuid, string value) 62 public string CreateGuid(Guid namespaceGuid, string value)
42 { 63 {
43 return Uuid.NewUuid(namespaceGuid, value).ToString("B").ToUpperInvariant(); 64 return Uuid.NewUuid(namespaceGuid, value).ToString("B").ToUpperInvariant();
@@ -52,9 +73,43 @@ namespace WixToolset.Core.ExtensibilityServices
52 }; 73 };
53 } 74 }
54 75
76 public IEnumerable<ITrackedFile> ExtractEmbeddedFiles(IEnumerable<IExpectedExtractFile> embeddedFiles)
77 {
78 var command = new ExtractEmbeddedFilesCommand(this, embeddedFiles);
79 command.Execute();
80
81 return command.TrackedFiles;
82 }
83
84 public string GenerateIdentifier(string prefix, params string[] args)
85 {
86 return Common.GenerateIdentifier(prefix, args);
87 }
88
55 public string GetCanonicalRelativePath(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string relativePath) 89 public string GetCanonicalRelativePath(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string relativePath)
56 { 90 {
57 return this.ParseHelper.GetCanonicalRelativePath(sourceLineNumbers, elementName, attributeName, relativePath); 91 return Common.GetCanonicalRelativePath(sourceLineNumbers, elementName, attributeName, relativePath, this.Messaging);
92 }
93
94 public int GetValidCodePage(string value, bool allowNoChange = false, bool onlyAnsi = false, SourceLineNumber sourceLineNumbers = null)
95 {
96 return Common.GetValidCodePage(value, allowNoChange, onlyAnsi, sourceLineNumbers);
97 }
98
99 public string GetMsiFileName(string value, bool source, bool longName)
100 {
101 return Common.GetName(value, source, longName);
102 }
103
104 public void ResolveDelayedFields(IEnumerable<IDelayedField> delayedFields, Dictionary<string, string> variableCache)
105 {
106 var command = new ResolveDelayedFieldsCommand(this.Messaging, delayedFields, variableCache);
107 command.Execute();
108 }
109
110 public string[] SplitMsiFileName(string value)
111 {
112 return Common.GetNames(value);
58 } 113 }
59 114
60 public ITrackedFile TrackFile(string path, TrackedFileType type, SourceLineNumber sourceLineNumbers = null) 115 public ITrackedFile TrackFile(string path, TrackedFileType type, SourceLineNumber sourceLineNumbers = null)
@@ -62,6 +117,31 @@ namespace WixToolset.Core.ExtensibilityServices
62 return new TrackedFile(path, type, sourceLineNumbers); 117 return new TrackedFile(path, type, sourceLineNumbers);
63 } 118 }
64 119
120 public bool IsValidBinderVariable(string variable)
121 {
122 return Common.IsValidBinderVariable(variable);
123 }
124
125 public bool IsValidFourPartVersion(string version)
126 {
127 return Common.IsValidFourPartVersion(version);
128 }
129
130 public bool IsValidIdentifier(string id)
131 {
132 return Common.IsIdentifier(id);
133 }
134
135 public bool IsValidLongFilename(string filename, bool allowWildcards, bool allowRelative)
136 {
137 return Common.IsValidLongFilename(filename, allowWildcards, allowRelative);
138 }
139
140 public bool IsValidShortFilename(string filename, bool allowWildcards)
141 {
142 return Common.IsValidShortFilename(filename, allowWildcards);
143 }
144
65 private string GetValidatedFullPath(SourceLineNumber sourceLineNumbers, string path) 145 private string GetValidatedFullPath(SourceLineNumber sourceLineNumbers, string path)
66 { 146 {
67 try 147 try
diff --git a/src/WixToolset.Core/Bind/FileFacade.cs b/src/WixToolset.Core/ExtensibilityServices/FileFacade.cs
index d1e5ae60..f85d4842 100644
--- a/src/WixToolset.Core/Bind/FileFacade.cs
+++ b/src/WixToolset.Core/ExtensibilityServices/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
3namespace WixToolset.Core.Bind 3namespace WixToolset.Core.ExtensibilityServices
4{ 4{
5 using System; 5 using System;
6 using System.Collections.Generic; 6 using System.Collections.Generic;
@@ -8,9 +8,9 @@ namespace WixToolset.Core.Bind
8 using WixToolset.Data.Symbols; 8 using WixToolset.Data.Symbols;
9 using WixToolset.Data.WindowsInstaller; 9 using WixToolset.Data.WindowsInstaller;
10 using WixToolset.Data.WindowsInstaller.Rows; 10 using WixToolset.Data.WindowsInstaller.Rows;
11 using WixToolset.Extensibility.Data;
11 12
12#pragma warning disable 1591 // TODO: this shouldn't be public, need interface in Extensibility 13 internal class FileFacade : IFileFacade
13 public class FileFacade
14 { 14 {
15 public FileFacade(FileSymbol file, AssemblySymbol assembly) 15 public FileFacade(FileSymbol file, AssemblySymbol assembly)
16 { 16 {
diff --git a/src/WixToolset.Core/ExtensibilityServices/ParseHelper.cs b/src/WixToolset.Core/ExtensibilityServices/ParseHelper.cs
index 7894ce8e..3c040b35 100644
--- a/src/WixToolset.Core/ExtensibilityServices/ParseHelper.cs
+++ b/src/WixToolset.Core/ExtensibilityServices/ParseHelper.cs
@@ -6,9 +6,6 @@ namespace WixToolset.Core.ExtensibilityServices
6 using System.Collections.Generic; 6 using System.Collections.Generic;
7 using System.Diagnostics; 7 using System.Diagnostics;
8 using System.Globalization; 8 using System.Globalization;
9 using System.IO;
10 using System.Security.Cryptography;
11 using System.Text;
12 using System.Xml.Linq; 9 using System.Xml.Linq;
13 using WixToolset.Data; 10 using WixToolset.Data;
14 using WixToolset.Data.Symbols; 11 using WixToolset.Data.Symbols;
@@ -292,56 +289,6 @@ namespace WixToolset.Core.ExtensibilityServices
292 return section.AddSymbol(symbolDefinition.CreateSymbol(sourceLineNumbers, identifier)); 289 return section.AddSymbol(symbolDefinition.CreateSymbol(sourceLineNumbers, identifier));
293 } 290 }
294 291
295 public string CreateShortName(string longName, bool keepExtension, bool allowWildcards, params string[] args)
296 {
297 // canonicalize the long name if its not a localization identifier (they are case-sensitive)
298 if (!this.IsValidLocIdentifier(longName))
299 {
300 longName = longName.ToLowerInvariant();
301 }
302
303 // collect all the data
304 var strings = new List<string>(1 + args.Length);
305 strings.Add(longName);
306 strings.AddRange(args);
307
308 // prepare for hashing
309 var stringData = String.Join("|", strings);
310 var data = Encoding.UTF8.GetBytes(stringData);
311
312 // hash the data
313 byte[] hash;
314 using (var sha1 = new SHA1CryptoServiceProvider())
315 {
316 hash = sha1.ComputeHash(data);
317 }
318
319 // generate the short file/directory name without an extension
320 var shortName = new StringBuilder(Convert.ToBase64String(hash));
321 shortName.Remove(8, shortName.Length - 8).Replace('+', '-').Replace('/', '_');
322
323 if (keepExtension)
324 {
325 var extension = Path.GetExtension(longName);
326
327 if (4 < extension.Length)
328 {
329 extension = extension.Substring(0, 4);
330 }
331
332 shortName.Append(extension);
333
334 // check the generated short name to ensure its still legal (the extension may not be legal)
335 if (!this.IsValidShortFilename(shortName.ToString(), allowWildcards))
336 {
337 // remove the extension (by truncating the generated file name back to the generated characters)
338 shortName.Length -= extension.Length;
339 }
340 }
341
342 return shortName.ToString().ToLowerInvariant();
343 }
344
345 public void EnsureTable(IntermediateSection section, SourceLineNumber sourceLineNumbers, TableDefinition tableDefinition) 292 public void EnsureTable(IntermediateSection section, SourceLineNumber sourceLineNumbers, TableDefinition tableDefinition)
346 { 293 {
347 section.AddSymbol(new WixEnsureTableSymbol(sourceLineNumbers) 294 section.AddSymbol(new WixEnsureTableSymbol(sourceLineNumbers)
@@ -673,23 +620,7 @@ namespace WixToolset.Core.ExtensibilityServices
673 620
674 public string GetCanonicalRelativePath(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string relativePath) 621 public string GetCanonicalRelativePath(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string relativePath)
675 { 622 {
676 const string root = @"C:\"; 623 return Common.GetCanonicalRelativePath(sourceLineNumbers, elementName, attributeName, relativePath, this.Messaging);
677 if (!Path.IsPathRooted(relativePath))
678 {
679 var normalizedPath = Path.GetFullPath(root + relativePath);
680 if (normalizedPath.StartsWith(root))
681 {
682 var canonicalizedPath = normalizedPath.Substring(root.Length);
683 if (canonicalizedPath != relativePath)
684 {
685 this.Messaging.Write(WarningMessages.PathCanonicalized(sourceLineNumbers, elementName, attributeName, relativePath, canonicalizedPath));
686 }
687 return canonicalizedPath;
688 }
689 }
690
691 this.Messaging.Write(ErrorMessages.PayloadMustBeRelativeToCache(sourceLineNumbers, elementName, attributeName, relativePath));
692 return relativePath;
693 } 624 }
694 625
695 public SourceLineNumber GetSourceLineNumbers(XElement element) 626 public SourceLineNumber GetSourceLineNumbers(XElement element)
@@ -723,46 +654,10 @@ namespace WixToolset.Core.ExtensibilityServices
723 654
724 public bool IsValidLongFilename(string filename, bool allowWildcards, bool allowRelative) 655 public bool IsValidLongFilename(string filename, bool allowWildcards, bool allowRelative)
725 { 656 {
726 if (String.IsNullOrEmpty(filename)) 657 return Common.IsValidLongFilename(filename, allowWildcards, allowRelative);
727 {
728 return false;
729 }
730 else if (filename.Length > 259)
731 {
732 return false;
733 }
734
735 // Check for a non-period character (all periods is not legal)
736 var allPeriods = true;
737 foreach (var character in filename)
738 {
739 if ('.' != character)
740 {
741 allPeriods = false;
742 break;
743 }
744 }
745
746 if (allPeriods)
747 {
748 return false;
749 }
750
751 if (allowWildcards)
752 {
753 return filename.IndexOfAny(Common.IllegalWildcardLongFilenameCharacters) == -1;
754 }
755 else if (allowRelative)
756 {
757 return filename.IndexOfAny(Common.IllegalRelativeLongFilenameCharacters) == -1;
758 }
759 else
760 {
761 return filename.IndexOfAny(Common.IllegalLongFilenameCharacters) == -1;
762 }
763 } 658 }
764 659
765 public bool IsValidShortFilename(string filename, bool allowWildcards = false) 660 public bool IsValidShortFilename(string filename, bool allowWildcards)
766 { 661 {
767 return Common.IsValidShortFilename(filename, allowWildcards); 662 return Common.IsValidShortFilename(filename, allowWildcards);
768 } 663 }
diff --git a/src/WixToolset.Core/ExtensibilityServices/WixBranding.cs b/src/WixToolset.Core/ExtensibilityServices/WixBranding.cs
new file mode 100644
index 00000000..56300400
--- /dev/null
+++ b/src/WixToolset.Core/ExtensibilityServices/WixBranding.cs
@@ -0,0 +1,124 @@
1// Copyright (c) .NET 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
3using System.Resources;
4
5[assembly: NeutralResourcesLanguage("en-US")]
6
7namespace WixToolset.Core.ExtensibilityServices
8{
9 using System;
10 using System.Diagnostics;
11 using System.IO;
12 using System.Reflection;
13 using WixToolset.Extensibility.Services;
14
15 /// <summary>
16 /// Branding strings.
17 /// </summary>
18 internal class WixBranding : IWixBranding
19 {
20 /// <summary>
21 /// News URL for the distribution.
22 /// </summary>
23 public static string NewsUrl = "http://wixtoolset.org/news/";
24
25 /// <summary>
26 /// Short product name for the distribution.
27 /// </summary>
28 public static string ShortProduct = "WiX Toolset";
29
30 /// <summary>
31 /// Support URL for the distribution.
32 /// </summary>
33 public static string SupportUrl = "http://wixtoolset.org/";
34
35 /// <summary>
36 /// Telemetry URL format for the distribution.
37 /// </summary>
38 public static string TelemetryUrlFormat = "http://wixtoolset.org/telemetry/v{0}/?r={1}";
39
40 /// <summary>
41 /// VS Extensions Landing page Url for the distribution.
42 /// </summary>
43 public static string VSExtensionsLandingUrl = "http://wixtoolset.org/releases/";
44
45 public string GetCreatingApplication()
46 {
47 return this.ReplacePlaceholders("[AssemblyProduct] ([FileVersion])");
48 }
49
50 public string ReplacePlaceholders(string original, Assembly assembly = null)
51 {
52 if (assembly == null)
53 {
54 assembly = typeof(WixBranding).Assembly;
55 }
56
57 var commonVersionPath = Path.Combine(Path.GetDirectoryName(typeof(WixBranding).Assembly.Location), "wixver.dll");
58 if (File.Exists(commonVersionPath))
59 {
60 var commonFileVersion = FileVersionInfo.GetVersionInfo(commonVersionPath);
61
62 original = original.Replace("[FileCopyright]", commonFileVersion.LegalCopyright);
63 original = original.Replace("[FileVersion]", commonFileVersion.FileVersion);
64 }
65
66 var fileVersion = FileVersionInfo.GetVersionInfo(assembly.Location);
67
68 original = original.Replace("[FileComments]", fileVersion.Comments);
69 original = original.Replace("[FileCopyright]", fileVersion.LegalCopyright);
70 original = original.Replace("[FileProductName]", fileVersion.ProductName);
71 original = original.Replace("[FileVersion]", fileVersion.FileVersion);
72
73 if (original.Contains("[FileVersionMajorMinor]"))
74 {
75 var version = new Version(fileVersion.FileVersion);
76 original = original.Replace("[FileVersionMajorMinor]", String.Concat(version.Major, ".", version.Minor));
77 }
78
79 if (TryGetAttribute(assembly, out AssemblyCompanyAttribute company))
80 {
81 original = original.Replace("[AssemblyCompany]", company.Company);
82 }
83
84 if (TryGetAttribute(assembly, out AssemblyCopyrightAttribute copyright))
85 {
86 original = original.Replace("[AssemblyCopyright]", copyright.Copyright);
87 }
88
89 if (TryGetAttribute(assembly, out AssemblyDescriptionAttribute description))
90 {
91 original = original.Replace("[AssemblyDescription]", description.Description);
92 }
93
94 if (TryGetAttribute(assembly, out AssemblyProductAttribute product))
95 {
96 original = original.Replace("[AssemblyProduct]", product.Product);
97 }
98
99 if (TryGetAttribute(assembly, out AssemblyTitleAttribute title))
100 {
101 original = original.Replace("[AssemblyTitle]", title.Title);
102 }
103
104 original = original.Replace("[NewsUrl]", NewsUrl);
105 original = original.Replace("[ShortProduct]", ShortProduct);
106 original = original.Replace("[SupportUrl]", SupportUrl);
107
108 return original;
109 }
110
111 private static bool TryGetAttribute<T>(Assembly assembly, out T attribute) where T : Attribute
112 {
113 attribute = null;
114
115 var customAttributes = assembly.GetCustomAttributes(typeof(T), false);
116 if (null != customAttributes && 0 < customAttributes.Length)
117 {
118 attribute = customAttributes[0] as T;
119 }
120
121 return null != attribute;
122 }
123 }
124}
diff --git a/src/WixToolset.Core/LocalizationParser.cs b/src/WixToolset.Core/LocalizationParser.cs
index a0cf38a9..aaf4c425 100644
--- a/src/WixToolset.Core/LocalizationParser.cs
+++ b/src/WixToolset.Core/LocalizationParser.cs
@@ -30,10 +30,10 @@ namespace WixToolset.Core
30 30
31 public Localization ParseLocalization(XDocument document) 31 public Localization ParseLocalization(XDocument document)
32 { 32 {
33 XElement root = document.Root; 33 var root = document.Root;
34 Localization localization = null; 34 Localization localization = null;
35 35
36 SourceLineNumber sourceLineNumbers = SourceLineNumber.CreateFromXObject(root); 36 var sourceLineNumbers = SourceLineNumber.CreateFromXObject(root);
37 if (LocalizationParser.XmlElementName == root.Name.LocalName) 37 if (LocalizationParser.XmlElementName == root.Name.LocalName)
38 { 38 {
39 if (LocalizationParser.WxlNamespace == root.Name.Namespace) 39 if (LocalizationParser.WxlNamespace == root.Name.Namespace)
@@ -85,11 +85,11 @@ namespace WixToolset.Core
85 /// <param name="node">Element to parse.</param> 85 /// <param name="node">Element to parse.</param>
86 private static Localization ParseWixLocalizationElement(IMessaging messaging, XElement node) 86 private static Localization ParseWixLocalizationElement(IMessaging messaging, XElement node)
87 { 87 {
88 int codepage = -1; 88 var sourceLineNumbers = SourceLineNumber.CreateFromXObject(node);
89 var codepage = -1;
89 string culture = null; 90 string culture = null;
90 SourceLineNumber sourceLineNumbers = SourceLineNumber.CreateFromXObject(node);
91 91
92 foreach (XAttribute attrib in node.Attributes()) 92 foreach (var attrib in node.Attributes())
93 { 93 {
94 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || LocalizationParser.WxlNamespace == attrib.Name.Namespace) 94 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || LocalizationParser.WxlNamespace == attrib.Name.Namespace)
95 { 95 {
@@ -115,10 +115,10 @@ namespace WixToolset.Core
115 } 115 }
116 } 116 }
117 117
118 Dictionary<string, BindVariable> variables = new Dictionary<string, BindVariable>(); 118 var variables = new Dictionary<string, BindVariable>();
119 Dictionary<string, LocalizedControl> localizedControls = new Dictionary<string, LocalizedControl>(); 119 var localizedControls = new Dictionary<string, LocalizedControl>();
120 120
121 foreach (XElement child in node.Elements()) 121 foreach (var child in node.Elements())
122 { 122 {
123 if (LocalizationParser.WxlNamespace == child.Name.Namespace) 123 if (LocalizationParser.WxlNamespace == child.Name.Namespace)
124 { 124 {
@@ -155,10 +155,10 @@ namespace WixToolset.Core
155 private static void ParseString(IMessaging messaging, XElement node, IDictionary<string, BindVariable> variables) 155 private static void ParseString(IMessaging messaging, XElement node, IDictionary<string, BindVariable> variables)
156 { 156 {
157 string id = null; 157 string id = null;
158 bool overridable = false; 158 var overridable = false;
159 SourceLineNumber sourceLineNumbers = SourceLineNumber.CreateFromXObject(node); 159 var sourceLineNumbers = SourceLineNumber.CreateFromXObject(node);
160 160
161 foreach (XAttribute attrib in node.Attributes()) 161 foreach (var attrib in node.Attributes())
162 { 162 {
163 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || LocalizationParser.WxlNamespace == attrib.Name.Namespace) 163 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || LocalizationParser.WxlNamespace == attrib.Name.Namespace)
164 { 164 {
@@ -184,7 +184,7 @@ namespace WixToolset.Core
184 } 184 }
185 } 185 }
186 186
187 string value = Common.GetInnerText(node); 187 var value = Common.GetInnerText(node);
188 188
189 if (null == id) 189 if (null == id)
190 { 190 {
@@ -228,7 +228,7 @@ namespace WixToolset.Core
228 var rightAligned = false; 228 var rightAligned = false;
229 var leftScroll = false; 229 var leftScroll = false;
230 230
231 foreach (XAttribute attrib in node.Attributes()) 231 foreach (var attrib in node.Attributes())
232 { 232 {
233 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || LocalizationParser.WxlNamespace == attrib.Name.Namespace) 233 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || LocalizationParser.WxlNamespace == attrib.Name.Namespace)
234 { 234 {
diff --git a/src/WixToolset.Core/OptimizeCA.cs b/src/WixToolset.Core/OptimizeCA.cs
deleted file mode 100644
index 0d7b5e1a..00000000
--- a/src/WixToolset.Core/OptimizeCA.cs
+++ /dev/null
@@ -1,33 +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
3namespace 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 // TODO: review where to place this data so it can not be exposed by WixToolset.Core
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
deleted file mode 100644
index e751fd18..00000000
--- a/src/WixToolset.Core/PatchSymbolFlagsType.cs
+++ /dev/null
@@ -1,34 +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
3namespace WixToolset.Core
4{
5 using System;
6
7 /// <summary>
8 /// The following flags are used with PATCH_OPTION_DATA SymbolOptionFlags:
9 /// </summary>
10 [Flags]
11 public enum PatchSymbolFlagsType : uint
12 {
13 /// <summary>
14 /// don't use imagehlp.dll
15 /// </summary>
16 PATCH_SYMBOL_NO_IMAGEHLP = 0x00000001,
17 /// <summary>
18 /// don't fail patch due to imagehlp failures
19 /// </summary>
20 PATCH_SYMBOL_NO_FAILURES = 0x00000002,
21 /// <summary>
22 /// after matching decorated symbols, try to match remaining by undecorated names
23 /// </summary>
24 PATCH_SYMBOL_UNDECORATED_TOO = 0x00000004,
25 /// <summary>
26 /// (used internally)
27 /// </summary>
28 PATCH_SYMBOL_RESERVED1 = 0x80000000,
29 /// <summary>
30 ///
31 /// </summary>
32 MaxValue = PATCH_SYMBOL_NO_IMAGEHLP | PATCH_SYMBOL_NO_FAILURES | PATCH_SYMBOL_UNDECORATED_TOO
33 }
34}
diff --git a/src/WixToolset.Core/ResolvedCabinet.cs b/src/WixToolset.Core/ResolvedCabinet.cs
index 9304b413..be04831f 100644
--- a/src/WixToolset.Core/ResolvedCabinet.cs
+++ b/src/WixToolset.Core/ResolvedCabinet.cs
@@ -7,7 +7,7 @@ namespace WixToolset.Core
7 /// <summary> 7 /// <summary>
8 /// Data returned from build file manager ResolveCabinet callback. 8 /// Data returned from build file manager ResolveCabinet callback.
9 /// </summary> 9 /// </summary>
10 public class ResolvedCabinet : IResolvedCabinet 10 internal class ResolvedCabinet : IResolvedCabinet
11 { 11 {
12 /// <summary> 12 /// <summary>
13 /// Gets or sets the build option for the resolved cabinet. 13 /// Gets or sets the build option for the resolved cabinet.
diff --git a/src/WixToolset.Core/WixDistribution.cs b/src/WixToolset.Core/WixDistribution.cs
deleted file mode 100644
index 4ceb8982..00000000
--- a/src/WixToolset.Core/WixDistribution.cs
+++ /dev/null
@@ -1,109 +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
3using System;
4using System.Diagnostics;
5using System.Reflection;
6using System.Resources;
7
8[assembly: NeutralResourcesLanguage("en-US")]
9
10namespace WixToolset
11{
12 /// <summary>
13 /// Distribution specific strings.
14 /// </summary>
15 internal static class WixDistribution
16 {
17 /// <summary>
18 /// News URL for the distribution.
19 /// </summary>
20 public static string NewsUrl = "http://wixtoolset.org/news/";
21
22 /// <summary>
23 /// Short product name for the distribution.
24 /// </summary>
25 public static string ShortProduct = "WiX Toolset";
26
27 /// <summary>
28 /// Support URL for the distribution.
29 /// </summary>
30 public static string SupportUrl = "http://wixtoolset.org/";
31
32 /// <summary>
33 /// Telemetry URL format for the distribution.
34 /// </summary>
35 public static string TelemetryUrlFormat = "http://wixtoolset.org/telemetry/v{0}/?r={1}";
36
37 /// <summary>
38 /// VS Extensions Landing page Url for the distribution.
39 /// </summary>
40 public static string VSExtensionsLandingUrl = "http://wixtoolset.org/releases/";
41
42 public static string ReplacePlaceholders(string original, Assembly assembly)
43 {
44 if (null != assembly)
45 {
46 FileVersionInfo fileVersion = FileVersionInfo.GetVersionInfo(assembly.Location);
47
48 original = original.Replace("[FileComments]", fileVersion.Comments);
49 original = original.Replace("[FileCopyright]", fileVersion.LegalCopyright);
50 original = original.Replace("[FileProductName]", fileVersion.ProductName);
51 original = original.Replace("[FileVersion]", fileVersion.FileVersion);
52
53 if (original.Contains("[FileVersionMajorMinor]"))
54 {
55 Version version = new Version(fileVersion.FileVersion);
56 original = original.Replace("[FileVersionMajorMinor]", String.Concat(version.Major, ".", version.Minor));
57 }
58
59 AssemblyCompanyAttribute company;
60 if (WixDistribution.TryGetAttribute(assembly, out company))
61 {
62 original = original.Replace("[AssemblyCompany]", company.Company);
63 }
64
65 AssemblyCopyrightAttribute copyright;
66 if (WixDistribution.TryGetAttribute(assembly, out copyright))
67 {
68 original = original.Replace("[AssemblyCopyright]", copyright.Copyright);
69 }
70
71 AssemblyDescriptionAttribute description;
72 if (WixDistribution.TryGetAttribute(assembly, out description))
73 {
74 original = original.Replace("[AssemblyDescription]", description.Description);
75 }
76
77 AssemblyProductAttribute product;
78 if (WixDistribution.TryGetAttribute(assembly, out product))
79 {
80 original = original.Replace("[AssemblyProduct]", product.Product);
81 }
82
83 AssemblyTitleAttribute title;
84 if (WixDistribution.TryGetAttribute(assembly, out title))
85 {
86 original = original.Replace("[AssemblyTitle]", title.Title);
87 }
88 }
89
90 original = original.Replace("[NewsUrl]", WixDistribution.NewsUrl);
91 original = original.Replace("[ShortProduct]", WixDistribution.ShortProduct);
92 original = original.Replace("[SupportUrl]", WixDistribution.SupportUrl);
93 return original;
94 }
95
96 private static bool TryGetAttribute<T>(Assembly assembly, out T attribute) where T : Attribute
97 {
98 attribute = null;
99
100 object[] customAttributes = assembly.GetCustomAttributes(typeof(T), false);
101 if (null != customAttributes && 0 < customAttributes.Length)
102 {
103 attribute = customAttributes[0] as T;
104 }
105
106 return null != attribute;
107 }
108 }
109}
diff --git a/src/WixToolset.Core/WixToolsetServiceProvider.cs b/src/WixToolset.Core/WixToolsetServiceProvider.cs
index 646b21fa..d4f186de 100644
--- a/src/WixToolset.Core/WixToolsetServiceProvider.cs
+++ b/src/WixToolset.Core/WixToolsetServiceProvider.cs
@@ -25,6 +25,7 @@ namespace WixToolset.Core
25 this.AddService((provider, singletons) => AddSingleton<IPreprocessHelper>(singletons, new PreprocessHelper(provider))); 25 this.AddService((provider, singletons) => AddSingleton<IPreprocessHelper>(singletons, new PreprocessHelper(provider)));
26 this.AddService((provider, singletons) => AddSingleton<IBackendHelper>(singletons, new BackendHelper(provider))); 26 this.AddService((provider, singletons) => AddSingleton<IBackendHelper>(singletons, new BackendHelper(provider)));
27 this.AddService((provider, singletons) => AddSingleton<IPathResolver>(singletons, new PathResolver())); 27 this.AddService((provider, singletons) => AddSingleton<IPathResolver>(singletons, new PathResolver()));
28 this.AddService((provider, singletons) => AddSingleton<IWixBranding>(singletons, new WixBranding()));
28 29
29 // Transients. 30 // Transients.
30 this.AddService<ICommandLineArguments>((provider, singletons) => new CommandLineArguments(provider)); 31 this.AddService<ICommandLineArguments>((provider, singletons) => new CommandLineArguments(provider));