From 860f77f7c9d522074dc7e44cfe11281efd20687f Mon Sep 17 00:00:00 2001 From: Rob Mensching Date: Mon, 5 Apr 2021 12:55:26 -0700 Subject: Introduce "Subdirectory" which simplifies inline directory syntax Completes wixtoolset/issues#4727 --- .../CreateWindowsInstallerDataFromIRCommand.cs | 58 +++++- src/WixToolset.Core/Compiler.cs | 199 ++++++++++++--------- src/WixToolset.Core/CompilerCore.cs | 17 +- src/WixToolset.Core/Compiler_Package.cs | 116 ++++++++---- .../ExtensibilityServices/ParseHelper.cs | 126 +++---------- src/WixToolset.Core/Linker.cs | 1 - .../DirectoryFixture.cs | 35 ++-- .../ExtensionFixture.cs | 2 +- .../LanguageFixture.cs | 19 ++ .../LinkerFixture.cs | 2 +- .../WixToolsetTest.CoreIntegration/MsiFixture.cs | 12 +- .../TestData/CopyFile/CopyFile.wxs | 4 +- .../TestData/DuplicateDir/DuplicateDir.wxs | 4 +- .../TestData/Language/Package.wxs | 4 +- .../TestData/Media/MultiMedia.wxs | 8 +- .../TestData/PatchNoFileChanges/Package.wxs | 4 +- .../ProductWithComponentGroupRef/Product.wxs | 6 +- .../TestData/SameFileFolders/TestComponents.wxs | 8 +- .../TestData/UsingProvides/Package.wxs | 4 +- 19 files changed, 346 insertions(+), 283 deletions(-) diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/CreateWindowsInstallerDataFromIRCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/CreateWindowsInstallerDataFromIRCommand.cs index 1bd00900..cee87df0 100644 --- a/src/WixToolset.Core.WindowsInstaller/Bind/CreateWindowsInstallerDataFromIRCommand.cs +++ b/src/WixToolset.Core.WindowsInstaller/Bind/CreateWindowsInstallerDataFromIRCommand.cs @@ -18,6 +18,8 @@ namespace WixToolset.Core.WindowsInstaller.Bind internal class CreateWindowsInstallerDataFromIRCommand { + private static readonly char[] PathSeparatorChars = new[] { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar }; + public CreateWindowsInstallerDataFromIRCommand(IMessaging messaging, IntermediateSection section, TableDefinitionCollection tableDefinitions, int codepage, IEnumerable backendExtensions, IWindowsInstallerBackendHelper backendHelper) { this.Messaging = messaging; @@ -488,18 +490,23 @@ namespace WixToolset.Core.WindowsInstaller.Bind private void AddDirectorySymbol(DirectorySymbol symbol) { - if (String.IsNullOrEmpty(symbol.ShortName) && symbol.Name != null && !symbol.Name.Equals(".") && !symbol.Name.Equals("SourceDir") && !this.BackendHelper.IsValidShortFilename(symbol.Name, false)) + (var name, var parentDir) = this.AddDirectorySubdirectories(symbol); + + var shortName = symbol.ShortName; + var sourceShortname = symbol.SourceShortName; + + if (String.IsNullOrEmpty(shortName) && name != null && name != "." && name != "SourceDir" && !this.BackendHelper.IsValidShortFilename(name, false)) { - symbol.ShortName = this.CreateShortName(symbol.Name, false, "Directory", symbol.ParentDirectoryRef); + shortName = this.CreateShortName(name, false, "Directory", symbol.ParentDirectoryRef); } - if (String.IsNullOrEmpty(symbol.SourceShortName) && !String.IsNullOrEmpty(symbol.SourceName) && !this.BackendHelper.IsValidShortFilename(symbol.SourceName, false)) + if (String.IsNullOrEmpty(sourceShortname) && !String.IsNullOrEmpty(symbol.SourceName) && !this.BackendHelper.IsValidShortFilename(symbol.SourceName, false)) { - symbol.SourceShortName = this.CreateShortName(symbol.SourceName, false, "Directory", symbol.ParentDirectoryRef); + sourceShortname = this.CreateShortName(symbol.SourceName, false, "Directory", symbol.ParentDirectoryRef); } - var sourceName = CreateMsiFilename(symbol.SourceShortName, symbol.SourceName); - var targetName = CreateMsiFilename(symbol.ShortName, symbol.Name); + var sourceName = CreateMsiFilename(sourceShortname, symbol.SourceName); + var targetName = CreateMsiFilename(shortName, name); if (String.IsNullOrEmpty(targetName)) { @@ -510,7 +517,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind var row = this.CreateRow(symbol, "Directory"); row[0] = symbol.Id.Id; - row[1] = symbol.ParentDirectoryRef; + row[1] = parentDir; row[2] = defaultDir; if (OutputType.Module == this.Data.Type) @@ -1267,6 +1274,43 @@ namespace WixToolset.Core.WindowsInstaller.Bind } } + private (string, string) AddDirectorySubdirectories(DirectorySymbol symbol) + { + var directory = symbol.Name.Trim(PathSeparatorChars); + var parentDir = symbol.ParentDirectoryRef ?? (symbol.Id.Id == "TARGETDIR" ? null : "TARGETDIR"); + + var start = 0; + var end = directory.IndexOfAny(PathSeparatorChars); + var path = String.Empty; + + while (start <= end) + { + var subdirectoryName = directory.Substring(start, end - start); + + if (!String.IsNullOrEmpty(subdirectoryName)) + { + path = Path.Combine(path, subdirectoryName); + + var id = this.BackendHelper.GenerateIdentifier("d", symbol.ParentDirectoryRef, path); + var shortnameSubdirectory = this.BackendHelper.IsValidShortFilename(subdirectoryName, false) ? null : this.CreateShortName(subdirectoryName, false, "Directory", symbol.ParentDirectoryRef); + + var subdirectoryRow = this.CreateRow(symbol, "Directory"); + subdirectoryRow[0] = id; + subdirectoryRow[1] = parentDir; + subdirectoryRow[2] = CreateMsiFilename(shortnameSubdirectory, subdirectoryName); + + parentDir = id; + } + + start = end + 1; + end = symbol.Name.IndexOfAny(PathSeparatorChars, start); + } + + var name = (start == 0) ? directory : directory.Substring(start); + + return (name, parentDir); + } + private void EnsureRequiredTables() { // check for missing table and add them or display an error as appropriate diff --git a/src/WixToolset.Core/Compiler.cs b/src/WixToolset.Core/Compiler.cs index 926a46c5..184c5b3e 100644 --- a/src/WixToolset.Core/Compiler.cs +++ b/src/WixToolset.Core/Compiler.cs @@ -5,7 +5,6 @@ namespace WixToolset.Core using System; using System.Collections.Generic; using System.Diagnostics; - using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.IO; using System.Linq; @@ -2107,6 +2106,7 @@ namespace WixToolset.Core var comPlusBits = CompilerConstants.IntegerNotSet; string condition = null; + string subdirectory = null; var encounteredODBCDataSource = false; var files = 0; var guid = "*"; @@ -2163,16 +2163,16 @@ namespace WixToolset.Core break; case "DisableRegistryReflection": disableRegistryReflection = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); - //if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) - //{ - // bits |= MsiInterop.MsidbComponentAttributesDisableRegistryReflection; - //} break; case "Condition": condition = this.Core.GetAttributeValue(sourceLineNumbers, attrib); break; case "Directory": - directoryId = this.Core.CreateDirectoryReferenceFromInlineSyntax(sourceLineNumbers, attrib, directoryId); + directoryId = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); + this.Core.CreateSimpleReference(sourceLineNumbers, SymbolDefinitions.Directory, directoryId); + break; + case "Subdirectory": + subdirectory = this.Core.GetAttributeLongFilename(sourceLineNumbers, attrib, allowRelative: true); break; case "DiskId": diskId = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 1, Int16.MaxValue); @@ -2196,14 +2196,12 @@ namespace WixToolset.Core { case "either": location = ComponentLocation.Either; - //bits |= MsiInterop.MsidbComponentAttributesOptional; break; case "local": // this is the default location = ComponentLocation.LocalOnly; break; case "source": location = ComponentLocation.SourceOnly; - //bits |= MsiInterop.MsidbComponentAttributesSourceOnly; break; case "": break; @@ -2217,45 +2215,21 @@ namespace WixToolset.Core break; case "NeverOverwrite": neverOverwrite = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); - //if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) - //{ - // bits |= MsiInterop.MsidbComponentAttributesNeverOverwrite; - //} break; case "Permanent": permanent = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); - //if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) - //{ - // bits |= MsiInterop.MsidbComponentAttributesPermanent; - //} break; case "Shared": shared = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); - //if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) - //{ - // bits |= MsiInterop.MsidbComponentAttributesShared; - //} break; case "SharedDllRefCount": sharedDllRefCount = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); - //if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) - //{ - // bits |= MsiInterop.MsidbComponentAttributesSharedDllRefCount; - //} break; case "Transitive": transitive = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); - //if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) - //{ - // bits |= MsiInterop.MsidbComponentAttributesTransitive; - //} break; case "UninstallWhenSuperseded": uninstallWhenSuperseded = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); - //if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) - //{ - // bits |= MsiInterop.MsidbComponentAttributesUninstallOnSupersedence; - //} break; default: this.Core.UnexpectedAttribute(node, attrib); @@ -2275,17 +2249,22 @@ namespace WixToolset.Core id = new Identifier(AccessModifier.Section, componentIdPlaceholder); } - if (null == directoryId) + if (String.IsNullOrEmpty(directoryId)) { this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Directory")); } - if (String.IsNullOrEmpty(guid) && shared /*MsiInterop.MsidbComponentAttributesShared == (bits & MsiInterop.MsidbComponentAttributesShared)*/) + if (!String.IsNullOrEmpty(subdirectory)) + { + directoryId = this.Core.CreateDirectoryReferenceFromInlineSyntax(sourceLineNumbers, directoryId, subdirectory); + } + + if (String.IsNullOrEmpty(guid) && shared) { this.Core.Write(ErrorMessages.IllegalAttributeValueWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Shared", "yes", "Guid", "")); } - if (String.IsNullOrEmpty(guid) && permanent /*MsiInterop.MsidbComponentAttributesPermanent == (bits & MsiInterop.MsidbComponentAttributesPermanent)*/) + if (String.IsNullOrEmpty(guid) && permanent) { this.Core.Write(ErrorMessages.IllegalAttributeValueWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Permanent", "yes", "Guid", "")); } @@ -2587,6 +2566,7 @@ namespace WixToolset.Core var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); Identifier id = null; string directoryId = null; + string subdirectory = null; string source = null; foreach (var attrib in node.Attributes()) @@ -2599,9 +2579,11 @@ namespace WixToolset.Core id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); break; case "Directory": - // If the inline syntax is invalid it returns null. Use a static error identifier so the null - // directory identifier here doesn't trickle down false errors into child elements. - directoryId = this.Core.CreateDirectoryReferenceFromInlineSyntax(sourceLineNumbers, attrib, null) ?? "ErrorParsingInlineSyntax"; + directoryId = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); + this.Core.CreateSimpleReference(sourceLineNumbers, SymbolDefinitions.Directory, directoryId); + break; + case "Subdirectory": + subdirectory = this.Core.GetAttributeLongFilename(sourceLineNumbers, attrib, allowRelative: true); break; case "Source": source = this.Core.GetAttributeValue(sourceLineNumbers, attrib); @@ -2623,6 +2605,8 @@ namespace WixToolset.Core id = Identifier.Invalid; } + directoryId = this.HandleSubdirectory(sourceLineNumbers, node, directoryId, subdirectory, "Directory", "Subdirectory"); + if (!String.IsNullOrEmpty(source) && !source.EndsWith(Path.DirectorySeparatorChar.ToString(), StringComparison.Ordinal)) { source = String.Concat(source, Path.DirectorySeparatorChar); @@ -2898,18 +2882,24 @@ namespace WixToolset.Core private string ParseCreateFolderElement(XElement node, string componentId, string directoryId, bool win64Component) { var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); + string subdirectory = null; + foreach (var attrib in node.Attributes()) { if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) { switch (attrib.Name.LocalName) { - case "Directory": - directoryId = this.Core.CreateDirectoryReferenceFromInlineSyntax(sourceLineNumbers, attrib, directoryId); - break; - default: - this.Core.UnexpectedAttribute(node, attrib); - break; + case "Directory": + directoryId = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); + this.Core.CreateSimpleReference(sourceLineNumbers, SymbolDefinitions.Directory, directoryId); + break; + case "Subdirectory": + subdirectory = this.Core.GetAttributeLongFilename(sourceLineNumbers, attrib, allowRelative: true); + break; + default: + this.Core.UnexpectedAttribute(node, attrib); + break; } } else @@ -2918,24 +2908,26 @@ namespace WixToolset.Core } } + directoryId = this.HandleSubdirectory(sourceLineNumbers, node, directoryId, subdirectory, "Directory", "Subdirectory"); + foreach (var child in node.Elements()) { if (CompilerCore.WixNamespace == child.Name.Namespace) { switch (child.Name.LocalName) { - case "Shortcut": - this.ParseShortcutElement(child, componentId, node.Name.LocalName, directoryId, YesNoType.No); - break; - case "Permission": - this.ParsePermissionElement(child, directoryId, "CreateFolder"); - break; - case "PermissionEx": - this.ParsePermissionExElement(child, directoryId, "CreateFolder"); - break; - default: - this.Core.UnexpectedElement(node, child); - break; + case "Shortcut": + this.ParseShortcutElement(child, componentId, node.Name.LocalName, directoryId, YesNoType.No); + break; + case "Permission": + this.ParsePermissionElement(child, directoryId, "CreateFolder"); + break; + case "PermissionEx": + this.ParsePermissionExElement(child, directoryId, "CreateFolder"); + break; + default: + this.Core.UnexpectedElement(node, child); + break; } } else @@ -2969,10 +2961,12 @@ namespace WixToolset.Core Identifier id = null; var delete = false; string destinationDirectory = null; + string destinationSubdirectory = null; string destinationName = null; string destinationShortName = null; string destinationProperty = null; string sourceDirectory = null; + string sourceSubdirectory = null; string sourceFolder = null; string sourceName = null; string sourceProperty = null; @@ -2990,16 +2984,20 @@ namespace WixToolset.Core delete = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); break; case "DestinationDirectory": - destinationDirectory = this.Core.CreateDirectoryReferenceFromInlineSyntax(sourceLineNumbers, attrib, null); + destinationDirectory = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); + this.Core.CreateSimpleReference(sourceLineNumbers, SymbolDefinitions.Directory, destinationDirectory); + break; + case "DestinationSubdirectory": + destinationSubdirectory = this.Core.GetAttributeLongFilename(sourceLineNumbers, attrib, allowRelative: true); break; case "DestinationName": - destinationName = this.Core.GetAttributeLongFilename(sourceLineNumbers, attrib, false); + destinationName = this.Core.GetAttributeLongFilename(sourceLineNumbers, attrib); break; case "DestinationProperty": destinationProperty = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); break; case "DestinationShortName": - destinationShortName = this.Core.GetAttributeShortFilename(sourceLineNumbers, attrib, false); + destinationShortName = this.Core.GetAttributeShortFilename(sourceLineNumbers, attrib); break; case "FileId": if (null != fileId) @@ -3010,7 +3008,11 @@ namespace WixToolset.Core this.Core.CreateSimpleReference(sourceLineNumbers, SymbolDefinitions.File, fileId); break; case "SourceDirectory": - sourceDirectory = this.Core.CreateDirectoryReferenceFromInlineSyntax(sourceLineNumbers, attrib, null); + sourceDirectory = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); + this.Core.CreateSimpleReference(sourceLineNumbers, SymbolDefinitions.Directory, sourceDirectory); + break; + case "SourceSubdirectory": + sourceSubdirectory = this.Core.GetAttributeLongFilename(sourceLineNumbers, attrib, allowRelative: true); break; case "SourceName": sourceName = this.Core.GetAttributeValue(sourceLineNumbers, attrib); @@ -3044,11 +3046,15 @@ namespace WixToolset.Core this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "SourceProperty", "SourceDirectory")); } + sourceDirectory = this.HandleSubdirectory(sourceLineNumbers, node, sourceDirectory, sourceSubdirectory, "SourceDirectory", "SourceSubdirectory"); + if (null != destinationDirectory && null != destinationProperty) // DestinationDirectory and DestinationProperty cannot coexist { this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "DestinationProperty", "DestinationDirectory")); } + destinationDirectory = this.HandleSubdirectory(sourceLineNumbers, node, destinationDirectory, destinationSubdirectory, "DestinationDirectory", "DestinationSubdirectory"); + if (null == id) { id = this.Core.CreateIdentifier("cf", sourceFolder, sourceDirectory, sourceProperty, destinationDirectory, destinationProperty, destinationName); @@ -3139,6 +3145,7 @@ namespace WixToolset.Core var explicitWin64 = false; string scriptFile = null; + string subdirectory = null; CustomActionSourceType? sourceType = null; CustomActionTargetType? targetType = null; @@ -3194,8 +3201,9 @@ namespace WixToolset.Core { this.Core.Write(ErrorMessages.CustomActionMultipleSources(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "BinaryKey", "Directory", "FileRef", "Property", "Script")); } - source = this.Core.CreateDirectoryReferenceFromInlineSyntax(sourceLineNumbers, attrib, null); + source = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); sourceType = CustomActionSourceType.Directory; + this.Core.CreateSimpleReference(sourceLineNumbers, SymbolDefinitions.Directory, source); break; case "DllEntry": if (null != target) @@ -3355,6 +3363,9 @@ namespace WixToolset.Core case "ScriptSourceFile": scriptFile = this.Core.GetAttributeValue(sourceLineNumbers, attrib); break; + case "Subdirectory": + subdirectory = this.Core.GetAttributeLongFilename(sourceLineNumbers, attrib, allowRelative: true); + break; case "SuppressModularization": suppressModularization = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); break; @@ -3399,6 +3410,18 @@ namespace WixToolset.Core win64 = true; } + if (!String.IsNullOrEmpty(subdirectory)) + { + if (sourceType == CustomActionSourceType.Directory) + { + source = this.HandleSubdirectory(sourceLineNumbers, node, source, subdirectory, "Directory", "Subdirectory"); + } + else + { + this.Core.Write(ErrorMessages.IllegalAttributeWithoutOtherAttributes(sourceLineNumbers, node.Name.LocalName, "Subdirectory", "Directory")); + } + } + // if we have an in-lined Script CustomAction ensure no source or target attributes were provided if (inlineScript) { @@ -4168,7 +4191,6 @@ namespace WixToolset.Core var fileSourceAttribSet = false; XAttribute nameAttribute = null; var name = "."; // default to parent directory. - string inlineSyntax = null; string shortName = null; string sourceName = null; string shortSourceName = null; @@ -4194,7 +4216,7 @@ namespace WixToolset.Core fileSourceAttribSet = true; break; case "Name": - name = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + name = this.Core.GetAttributeLongFilename(sourceLineNumbers, attrib, allowRelative: true); nameAttribute = attrib; break; case "ShortName": @@ -4268,37 +4290,22 @@ namespace WixToolset.Core } } - // Create the directory rows for the inline. - if (nameAttribute != null) + if (null == id) { - var lastSlash = name.LastIndexOf('\\'); - if (lastSlash > 0) - { - inlineSyntax = name; - name = inlineSyntax.Substring(lastSlash + 1); - - parentId = this.Core.CreateDirectoryReferenceFromInlineSyntax(sourceLineNumbers, nameAttribute, parentId, inlineSyntax.Substring(0, lastSlash)); - - if (!this.Core.IsValidLongFilename(name, false, false)) - { - this.Messaging.Write(ErrorMessages.IllegalLongFilename(sourceLineNumbers, node.Name.LocalName, nameAttribute.Name.LocalName, nameAttribute.Value, name)); - } - } + id = this.Core.CreateIdentifier("d", parentId, name, shortName, sourceName, shortSourceName); } - - if (null == id) + else if (WindowsInstallerStandard.IsStandardDirectory(id.Id)) { - id = this.Core.CreateIdentifier("dir", parentId, name, shortName, sourceName, shortSourceName); - - if (!String.IsNullOrEmpty(inlineSyntax)) + if (String.IsNullOrEmpty(sourceName)) { - this.Core.AddInlineDirectoryId(inlineSyntax, id.Id); + this.Core.Write(CompilerWarnings.DefiningStandardDirectoryDeprecated(sourceLineNumbers, id.Id)); } - } - else if ("TARGETDIR".Equals(id.Id, StringComparison.Ordinal) && !("SourceDir".Equals(name, StringComparison.Ordinal) && shortName == null && shortSourceName == null && sourceName == null)) + + if (id.Id == "TARGETDIR" && name != "SourceDir" && shortName == null && shortSourceName == null && sourceName == null) { this.Core.Write(ErrorMessages.IllegalTargetDirDefaultDir(sourceLineNumbers, name)); } + } // Update the file source path appropriately. if (fileSourceAttribSet) @@ -4761,7 +4768,8 @@ namespace WixToolset.Core disallowAdvertise = (this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib) == YesNoType.No); break; case "ConfigurableDirectory": - configurableDirectory = this.Core.CreateDirectoryReferenceFromInlineSyntax(sourceLineNumbers, attrib, null); + configurableDirectory = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); + this.Core.CreateSimpleReference(sourceLineNumbers, SymbolDefinitions.Directory, configurableDirectory); break; case "Description": description = this.Core.GetAttributeValue(sourceLineNumbers, attrib); @@ -8403,5 +8411,22 @@ namespace WixToolset.Core } } } + + private string HandleSubdirectory(SourceLineNumber sourceLineNumbers, XElement element, string directoryId, string subdirectory, string directoryAttributeName, string subdirectoryAttributename) + { + if (!String.IsNullOrEmpty(subdirectory)) + { + if (String.IsNullOrEmpty(directoryId)) + { + this.Core.Write(ErrorMessages.IllegalAttributeWithoutOtherAttributes(sourceLineNumbers, element.Name.LocalName, subdirectoryAttributename, directoryAttributeName)); + } + else + { + directoryId = this.Core.CreateDirectoryReferenceFromInlineSyntax(sourceLineNumbers, directoryId, subdirectory); + } + } + + return directoryId; + } } } diff --git a/src/WixToolset.Core/CompilerCore.cs b/src/WixToolset.Core/CompilerCore.cs index df532d74..8705cacd 100644 --- a/src/WixToolset.Core/CompilerCore.cs +++ b/src/WixToolset.Core/CompilerCore.cs @@ -386,13 +386,12 @@ namespace WixToolset.Core /// Creates directories using the inline directory syntax. /// /// Source line information. - /// Attribute containing the inline syntax. /// Optional identifier of parent directory. /// Optional inline syntax to override attribute's value. /// Identifier of the leaf directory created. - public string CreateDirectoryReferenceFromInlineSyntax(SourceLineNumber sourceLineNumbers, XAttribute attribute, string parentId, string inlineSyntax = null) + public string CreateDirectoryReferenceFromInlineSyntax(SourceLineNumber sourceLineNumbers, string parentId, string inlineSyntax = null) { - return this.parseHelper.CreateDirectoryReferenceFromInlineSyntax(this.ActiveSection, sourceLineNumbers, attribute, parentId, inlineSyntax, this.activeSectionCachedInlinedDirectoryIds); + return this.parseHelper.CreateDirectoryReferenceFromInlineSyntax(this.ActiveSection, sourceLineNumbers, attribute: null, parentId, inlineSyntax, this.activeSectionCachedInlinedDirectoryIds); } /// @@ -784,7 +783,7 @@ namespace WixToolset.Core /// The attribute containing the value to get. /// true if wildcards are allowed in the filename. /// The attribute's short filename value. - public string GetAttributeShortFilename(SourceLineNumber sourceLineNumbers, XAttribute attribute, bool allowWildcards) + public string GetAttributeShortFilename(SourceLineNumber sourceLineNumbers, XAttribute attribute, bool allowWildcards = false) { if (null == attribute) { @@ -1021,16 +1020,6 @@ namespace WixToolset.Core } } - /// - /// Adds inline directory syntax generated identifier. - /// - /// Inline directory syntax the identifier was generated. - /// Generated identifier for inline syntax. - internal void AddInlineDirectoryId(string inlineSyntax, string id) - { - this.activeSectionCachedInlinedDirectoryIds.Add(inlineSyntax, id); - } - /// /// Creates a new section and makes it the active section in the core. /// diff --git a/src/WixToolset.Core/Compiler_Package.cs b/src/WixToolset.Core/Compiler_Package.cs index afe02f08..576450f4 100644 --- a/src/WixToolset.Core/Compiler_Package.cs +++ b/src/WixToolset.Core/Compiler_Package.cs @@ -2146,11 +2146,12 @@ namespace WixToolset.Core { var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); Identifier id = null; - string directory = null; + string directoryId = null; + string subdirectory = null; string name = null; bool? onInstall = null; bool? onUninstall = null; - string property = null; + string propertyId = null; string shortName = null; foreach (var attrib in node.Attributes()) @@ -2163,7 +2164,11 @@ namespace WixToolset.Core id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); break; case "Directory": - directory = this.Core.CreateDirectoryReferenceFromInlineSyntax(sourceLineNumbers, attrib, parentDirectory); + directoryId = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); + this.Core.CreateSimpleReference(sourceLineNumbers, SymbolDefinitions.Directory, directoryId); + break; + case "Subdirectory": + directoryId = this.Core.GetAttributeLongFilename(sourceLineNumbers, attrib, allowRelative: true); break; case "Name": name = this.Core.GetAttributeLongFilename(sourceLineNumbers, attrib, true); @@ -2185,7 +2190,7 @@ namespace WixToolset.Core } break; case "Property": - property = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); + propertyId = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); break; case "ShortName": shortName = this.Core.GetAttributeShortFilename(sourceLineNumbers, attrib, true); @@ -2211,15 +2216,23 @@ namespace WixToolset.Core this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "On")); } - if (null != directory && null != property) + if (String.IsNullOrEmpty(propertyId)) + { + directoryId = this.HandleSubdirectory(sourceLineNumbers, node, directoryId ?? parentDirectory, subdirectory, "Directory", "Subdirectory"); + } + else if (!String.IsNullOrEmpty(directoryId)) + { + this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Property", "Directory", directoryId)); + } + else if (!String.IsNullOrEmpty(subdirectory)) { - this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Property", "Directory", directory)); + this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Property", "Subdirectory", subdirectory)); } if (null == id) { var on = (onInstall == true && onUninstall == true) ? 3 : (onUninstall == true) ? 2 : (onInstall == true) ? 1 : 0; - id = this.Core.CreateIdentifier("rmf", directory ?? property ?? parentDirectory, LowercaseOrNull(shortName), LowercaseOrNull(name), on.ToString()); + id = this.Core.CreateIdentifier("rmf", directoryId ?? propertyId ?? parentDirectory, LowercaseOrNull(shortName), LowercaseOrNull(name), on.ToString()); } this.Core.ParseForExtensionElements(node); @@ -2231,7 +2244,7 @@ namespace WixToolset.Core ComponentRef = componentId, FileName = name, ShortFileName = shortName, - DirPropertyRef = directory ?? property ?? parentDirectory, + DirPropertyRef = directoryId ?? propertyId ?? parentDirectory, OnInstall = onInstall, OnUninstall = onUninstall, }); @@ -2248,10 +2261,11 @@ namespace WixToolset.Core { var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); Identifier id = null; - string directory = null; + string directoryId = null; + string subdirectory = null; bool? onInstall = null; bool? onUninstall = null; - string property = null; + string propertyId = null; foreach (var attrib in node.Attributes()) { @@ -2263,7 +2277,11 @@ namespace WixToolset.Core id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); break; case "Directory": - directory = this.Core.CreateDirectoryReferenceFromInlineSyntax(sourceLineNumbers, attrib, parentDirectory); + directoryId = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); + this.Core.CreateSimpleReference(sourceLineNumbers, SymbolDefinitions.Directory, directoryId); + break; + case "Subdirectory": + subdirectory = this.Core.GetAttributeLongFilename(sourceLineNumbers, attrib, allowRelative: true); break; case "On": var onValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); @@ -2282,7 +2300,7 @@ namespace WixToolset.Core } break; case "Property": - property = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + propertyId = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); break; default: this.Core.UnexpectedAttribute(node, attrib); @@ -2300,15 +2318,23 @@ namespace WixToolset.Core this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "On")); } - if (null != directory && null != property) + if (String.IsNullOrEmpty(propertyId)) + { + directoryId = this.HandleSubdirectory(sourceLineNumbers, node, directoryId ?? parentDirectory, subdirectory, "Directory", "Subdirectory"); + } + else if (!String.IsNullOrEmpty(directoryId)) + { + this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Property", "Directory", directoryId)); + } + else if (!String.IsNullOrEmpty(subdirectory)) { - this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Property", "Directory", directory)); + this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Property", "Subdirectory", subdirectory)); } if (null == id) { var on = (onInstall == true && onUninstall == true) ? 3 : (onUninstall == true) ? 2 : (onInstall == true) ? 1 : 0; - id = this.Core.CreateIdentifier("rmf", directory ?? property ?? parentDirectory, on.ToString()); + id = this.Core.CreateIdentifier("rmf", directoryId ?? propertyId, on.ToString()); } this.Core.ParseForExtensionElements(node); @@ -2318,7 +2344,7 @@ namespace WixToolset.Core this.Core.AddSymbol(new RemoveFileSymbol(sourceLineNumbers, id) { ComponentRef = componentId, - DirPropertyRef = directory ?? property ?? parentDirectory, + DirPropertyRef = directoryId ?? propertyId, OnInstall = onInstall, OnUninstall = onUninstall }); @@ -2335,6 +2361,7 @@ namespace WixToolset.Core { var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); Identifier id = null; + string subdirectory = null; var runFromSource = CompilerConstants.IntegerNotSet; var runLocal = CompilerConstants.IntegerNotSet; @@ -2348,7 +2375,11 @@ namespace WixToolset.Core id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); break; case "Directory": - directoryId = this.Core.CreateDirectoryReferenceFromInlineSyntax(sourceLineNumbers, attrib, directoryId); + directoryId = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); + this.Core.CreateSimpleReference(sourceLineNumbers, SymbolDefinitions.Directory, directoryId); + break; + case "Subdirectory": + subdirectory = this.Core.GetAttributeLongFilename(sourceLineNumbers, attrib, allowRelative: true); break; case "RunFromSource": runFromSource = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int32.MaxValue); @@ -2367,6 +2398,8 @@ namespace WixToolset.Core } } + directoryId = this.HandleSubdirectory(sourceLineNumbers, node, directoryId, subdirectory, "Directory", "Subdirectory"); + if (null == id) { id = this.Core.CreateIdentifier("rc", componentId, directoryId); @@ -4001,7 +4034,8 @@ namespace WixToolset.Core string description = null; string descriptionResourceDll = null; int? descriptionResourceId = null; - string directory = null; + string directoryId = null; + string subdirectory = null; string displayResourceDll = null; int? displayResourceId = null; int? hotkey = null; @@ -4011,7 +4045,8 @@ namespace WixToolset.Core string shortName = null; ShortcutShowType? show = null; string target = null; - string workingDirectory = null; + string workingDirectoryId = null; + string workingSubdirectory = null; foreach (var attrib in node.Attributes()) { @@ -4038,7 +4073,11 @@ namespace WixToolset.Core descriptionResourceId = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int16.MaxValue); break; case "Directory": - directory = this.Core.CreateDirectoryReferenceFromInlineSyntax(sourceLineNumbers, attrib, null); + directoryId = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); + this.Core.CreateSimpleReference(sourceLineNumbers, SymbolDefinitions.Directory, directoryId); + break; + case "Subdirectory": + subdirectory = this.Core.GetAttributeLongFilename(sourceLineNumbers, attrib, allowRelative: true); break; case "DisplayResourceDll": displayResourceDll = this.Core.GetAttributeValue(sourceLineNumbers, attrib); @@ -4086,7 +4125,11 @@ namespace WixToolset.Core target = this.Core.GetAttributeValue(sourceLineNumbers, attrib); break; case "WorkingDirectory": - workingDirectory = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); + workingDirectoryId = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); + this.Core.CreateSimpleReference(sourceLineNumbers, SymbolDefinitions.Directory, workingDirectoryId); + break; + case "WorkingSubdirectory": + workingSubdirectory = this.Core.GetAttributeLongFilename(sourceLineNumbers, attrib, allowRelative: true); break; default: this.Core.UnexpectedAttribute(node, attrib); @@ -4104,11 +4147,11 @@ namespace WixToolset.Core this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Target", "Advertise", "yes")); } - if (null == directory) + if (null == directoryId) { if ("Component" == parentElementLocalName) { - directory = defaultTarget; + directoryId = defaultTarget; } else { @@ -4116,6 +4159,8 @@ namespace WixToolset.Core } } + directoryId = this.HandleSubdirectory(sourceLineNumbers, node, directoryId, subdirectory, "Directory", "Subdirectory"); + if (null != descriptionResourceDll) { if (!descriptionResourceId.HasValue) @@ -4151,6 +4196,8 @@ namespace WixToolset.Core this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Name")); } + workingDirectoryId = this.HandleSubdirectory(sourceLineNumbers, node, workingDirectoryId, workingSubdirectory, "WorkingDirectory", "WorkingSubdirectory"); + if ("Component" != parentElementLocalName && null != target) { this.Core.Write(ErrorMessages.IllegalAttributeWhenNested(sourceLineNumbers, node.Name.LocalName, "Target", parentElementLocalName)); @@ -4158,7 +4205,7 @@ namespace WixToolset.Core if (null == id) { - id = this.Core.CreateIdentifier("sct", directory, LowercaseOrNull(name)); + id = this.Core.CreateIdentifier("sct", directoryId, LowercaseOrNull(name)); } foreach (var child in node.Elements()) @@ -4209,7 +4256,7 @@ namespace WixToolset.Core this.Core.AddSymbol(new ShortcutSymbol(sourceLineNumbers, id) { - DirectoryRef = directory, + DirectoryRef = directoryId, Name = name, ShortName = shortName, ComponentRef = componentId, @@ -4220,7 +4267,7 @@ namespace WixToolset.Core IconRef = icon, IconIndex = iconIndex, Show = show, - WorkingDirectory = workingDirectory, + WorkingDirectory = workingDirectoryId, DisplayResourceDll = displayResourceDll, DisplayResourceId = displayResourceId, DescriptionResourceDll = descriptionResourceDll, @@ -4309,7 +4356,8 @@ namespace WixToolset.Core var cost = CompilerConstants.IntegerNotSet; string description = null; var flags = 0; - string helpDirectory = null; + string helpDirectoryId = null; + string helpSubdirectory = null; var language = CompilerConstants.IntegerNotSet; var majorVersion = CompilerConstants.IntegerNotSet; var minorVersion = CompilerConstants.IntegerNotSet; @@ -4346,7 +4394,11 @@ namespace WixToolset.Core } break; case "HelpDirectory": - helpDirectory = this.Core.CreateDirectoryReferenceFromInlineSyntax(sourceLineNumbers, attrib, null); + helpDirectoryId = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); + this.Core.CreateSimpleReference(sourceLineNumbers, SymbolDefinitions.Directory, helpDirectoryId); + break; + case "HelpSubdirectory": + helpSubdirectory = this.Core.GetAttributeLongFilename(sourceLineNumbers, attrib, allowRelative: true); break; case "Hidden": if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) @@ -4394,6 +4446,8 @@ namespace WixToolset.Core language = CompilerConstants.IllegalInteger; } + helpDirectoryId = this.HandleSubdirectory(sourceLineNumbers, node, helpDirectoryId, helpSubdirectory, "HelpDirectory", "HelpSubdirectory"); + // build up the typelib version string for the registry if the major or minor version was specified string registryVersion = null; if (CompilerConstants.IntegerNotSet != majorVersion || CompilerConstants.IntegerNotSet != minorVersion) @@ -4488,7 +4542,7 @@ namespace WixToolset.Core Language = language, ComponentRef = componentId, Description = description, - DirectoryRef = helpDirectory, + DirectoryRef = helpDirectoryId, FeatureRef = Guid.Empty.ToString("B") }); @@ -4534,10 +4588,10 @@ namespace WixToolset.Core // HKCR\TypeLib\[ID]\[MajorVersion].[MinorVersion]\FLAGS, (Default) = [TypeLibFlags] this.Core.CreateRegistryRow(sourceLineNumbers, RegistryRootType.ClassesRoot, String.Format(CultureInfo.InvariantCulture, @"TypeLib\{0}\{1}\FLAGS", id, registryVersion), null, flags.ToString(CultureInfo.InvariantCulture.NumberFormat), componentId); - if (null != helpDirectory) + if (null != helpDirectoryId) { // HKCR\TypeLib\[ID]\[MajorVersion].[MinorVersion]\HELPDIR, (Default) = [HelpDirectory] - this.Core.CreateRegistryRow(sourceLineNumbers, RegistryRootType.ClassesRoot, String.Format(CultureInfo.InvariantCulture, @"TypeLib\{0}\{1}\HELPDIR", id, registryVersion), null, String.Concat("[", helpDirectory, "]"), componentId); + this.Core.CreateRegistryRow(sourceLineNumbers, RegistryRootType.ClassesRoot, String.Format(CultureInfo.InvariantCulture, @"TypeLib\{0}\{1}\HELPDIR", id, registryVersion), null, String.Concat("[", helpDirectoryId, "]"), componentId); } } } diff --git a/src/WixToolset.Core/ExtensibilityServices/ParseHelper.cs b/src/WixToolset.Core/ExtensibilityServices/ParseHelper.cs index a9a0fa9d..4b7b5ca4 100644 --- a/src/WixToolset.Core/ExtensibilityServices/ParseHelper.cs +++ b/src/WixToolset.Core/ExtensibilityServices/ParseHelper.cs @@ -18,8 +18,6 @@ namespace WixToolset.Core.ExtensibilityServices internal class ParseHelper : IParseHelper { - private static readonly char[] InlineDirectorySeparators = new char[] { ':', '\\', '/' }; - public ParseHelper(IServiceProvider serviceProvider) { this.ServiceProvider = serviceProvider; @@ -56,12 +54,9 @@ namespace WixToolset.Core.ExtensibilityServices public Identifier CreateDirectorySymbol(IntermediateSection section, SourceLineNumber sourceLineNumbers, Identifier id, string parentId, string name, string shortName = null, string sourceName = null, string shortSourceName = null) { - // For anonymous directories, create the identifier. If this identifier already exists in the - // active section, bail so we don't add duplicate anonymous directory symbols (which are legal - // but bloat the intermediate and ultimately make the linker do "busy work"). if (null == id) { - id = this.CreateIdentifier("dir", parentId, name, shortName, sourceName, shortSourceName); + id = this.CreateIdentifier("d", parentId, name, shortName, sourceName, shortSourceName); } var symbol = section.AddSymbol(new DirectorySymbol(sourceLineNumbers, id) @@ -78,28 +73,37 @@ namespace WixToolset.Core.ExtensibilityServices public string CreateDirectoryReferenceFromInlineSyntax(IntermediateSection section, SourceLineNumber sourceLineNumbers, XAttribute attribute, string parentId, string inlineSyntax, IDictionary sectionCachedInlinedDirectoryIds) { - if (String.IsNullOrEmpty(inlineSyntax)) + if (String.IsNullOrEmpty(parentId)) { - inlineSyntax = attribute.Value; + throw new ArgumentNullException(nameof(parentId)); } - // If no separator is found, the string is a simple reference. - var separatorFound = inlineSyntax.IndexOfAny(InlineDirectorySeparators); - if (separatorFound == -1) + if (String.IsNullOrEmpty(inlineSyntax)) { - this.CreateSimpleReference(section, sourceLineNumbers, SymbolDefinitions.Directory, inlineSyntax); - return inlineSyntax; + inlineSyntax = this.GetAttributeLongFilename(sourceLineNumbers, attribute, false, true); } - // If a parent id was provided and the inline syntax does not start with a directory reference, prepend the parent id. - if (!String.IsNullOrEmpty(parentId) && inlineSyntax[separatorFound] != ':') + if (String.IsNullOrEmpty(inlineSyntax)) { - inlineSyntax = String.Concat(parentId, ":", inlineSyntax); + return parentId; } - inlineSyntax = inlineSyntax.TrimEnd('\\', '/'); + inlineSyntax = inlineSyntax.Trim('\\', '/'); + + var cacheKey = String.Concat(parentId, ":", inlineSyntax); + + if (!sectionCachedInlinedDirectoryIds.TryGetValue(cacheKey, out var id)) + { + var identifier = this.CreateDirectorySymbol(section, sourceLineNumbers, id: null, parentId, inlineSyntax); + + id = identifier.Id; + } + else + { + this.CreateSimpleReference(section, sourceLineNumbers, SymbolDefinitions.Directory, id); + } - return this.ParseInlineSyntax(section, sourceLineNumbers, attribute, inlineSyntax, sectionCachedInlinedDirectoryIds); + return id; //this.ParseInlineSyntax(section, sourceLineNumbers, attribute, inlineSyntax, sectionCachedInlinedDirectoryIds); } public string CreateGuid(Guid namespaceGuid, string value) @@ -444,7 +448,7 @@ namespace WixToolset.Core.ExtensibilityServices var value = this.GetAttributeValue(sourceLineNumbers, attribute); - if (0 < value.Length) + if (!String.IsNullOrEmpty(value)) { if (!this.IsValidLongFilename(value, allowWildcards, allowRelative) && !this.IsValidLocIdentifier(value)) { @@ -840,90 +844,6 @@ namespace WixToolset.Core.ExtensibilityServices this.Creator = this.ServiceProvider.GetService(); } - private string ParseInlineSyntax(IntermediateSection section, SourceLineNumber sourceLineNumbers, XAttribute attribute, string inlineSyntax, IDictionary sectionCachedInlinedDirectoryIds) - { - if (!sectionCachedInlinedDirectoryIds.TryGetValue(inlineSyntax, out var id)) - { - string parentId; - int nameIndex; - - var separatorIndex = inlineSyntax.LastIndexOfAny(InlineDirectorySeparators); - if (separatorIndex == -1) - { - nameIndex = 0; - parentId = "TARGETDIR"; - } - else if (inlineSyntax[separatorIndex] == '\\' || inlineSyntax[separatorIndex] == '/') - { - nameIndex = separatorIndex + 1; - - if (separatorIndex == 0) - { - parentId = "TARGETDIR"; - } - else if (inlineSyntax[separatorIndex - 1] == ':') - { - parentId = this.ParseParentReference(section, sourceLineNumbers, attribute, inlineSyntax, separatorIndex - 1); - } - else - { - var parentInlineDirectory = inlineSyntax.Substring(0, separatorIndex); - parentId = this.ParseInlineSyntax(section, sourceLineNumbers, attribute, parentInlineDirectory.TrimEnd('\\', '/'), sectionCachedInlinedDirectoryIds); - } - } - else - { - nameIndex = separatorIndex + 1; - parentId = this.ParseParentReference(section, sourceLineNumbers, attribute, inlineSyntax, separatorIndex); - } - - if (nameIndex == inlineSyntax.Length) - { - id = parentId; - } - else - { - var name = nameIndex != -1 ? inlineSyntax.Substring(nameIndex) : null; - - if (!this.IsValidLongFilename(name, false, false)) - { - this.Messaging.Write(ErrorMessages.IllegalLongFilename(sourceLineNumbers, attribute.Parent.Name.LocalName, attribute.Name.LocalName, attribute.Value, name)); - return null; - } - - var identifier = this.CreateDirectorySymbol(section, sourceLineNumbers, null, parentId, name); - - id = identifier.Id; - } - - sectionCachedInlinedDirectoryIds.Add(inlineSyntax, id); - } - - return id; - } - - private string ParseParentReference(IntermediateSection section, SourceLineNumber sourceLineNumbers, XAttribute attribute, string reference, int colonIndex) - { - if (colonIndex == 0) - { - this.Messaging.Write(ErrorMessages.IllegalIdentifier(sourceLineNumbers, attribute.Parent.Name.LocalName, attribute.Name.LocalName, attribute.Value, String.Empty)); - return null; - } - else - { - var parentId = reference.Substring(0, colonIndex); - - if (!Common.IsIdentifier(parentId)) - { - this.Messaging.Write(ErrorMessages.IllegalIdentifier(sourceLineNumbers, attribute.Parent.Name.LocalName, attribute.Name.LocalName, attribute.Value, parentId)); - return null; - } - - this.CreateSimpleReference(section, sourceLineNumbers, SymbolDefinitions.Directory, parentId); - return parentId; - } - } - private static bool TryFindExtension(IEnumerable extensions, XNamespace ns, out ICompilerExtension extension) { extension = null; diff --git a/src/WixToolset.Core/Linker.cs b/src/WixToolset.Core/Linker.cs index 2c8508a8..bf7130db 100644 --- a/src/WixToolset.Core/Linker.cs +++ b/src/WixToolset.Core/Linker.cs @@ -587,7 +587,6 @@ namespace WixToolset.Core { var removeSymbols = new List(); - // Count down because we'll sometimes remove items from the list. foreach (var symbol in section.Symbols) { // Only process the "grouping parents" such as FeatureGroup, ComponentGroup, Feature, diff --git a/src/test/WixToolsetTest.CoreIntegration/DirectoryFixture.cs b/src/test/WixToolsetTest.CoreIntegration/DirectoryFixture.cs index 2d6e4802..56f8ba82 100644 --- a/src/test/WixToolsetTest.CoreIntegration/DirectoryFixture.cs +++ b/src/test/WixToolsetTest.CoreIntegration/DirectoryFixture.cs @@ -7,6 +7,7 @@ namespace WixToolsetTest.CoreIntegration using WixBuildTools.TestSupport; using WixToolset.Core.TestPackage; using WixToolset.Data; + using WixToolset.Data.WindowsInstaller; using Xunit; public class DirectoryFixture @@ -40,11 +41,11 @@ namespace WixToolsetTest.CoreIntegration var dirSymbols = section.Symbols.OfType().ToList(); Assert.Equal(new[] { - "INSTALLFOLDER", - "ProgramFiles6432Folder", - "ProgramFilesFolder", - "TARGETDIR" - }, dirSymbols.Select(d => d.Id.Id).ToArray()); + "INSTALLFOLDER:ProgramFiles6432Folder:MsiPackage", + "ProgramFiles6432Folder:ProgramFilesFolder:.", + "ProgramFilesFolder:TARGETDIR:PFiles", + "TARGETDIR::SourceDir" + }, dirSymbols.OrderBy(d => d.Id.Id).Select(d => d.Id.Id + ":" + d.ParentDirectoryRef + ":" + d.Name).ToArray()); } } @@ -78,11 +79,11 @@ namespace WixToolsetTest.CoreIntegration var dirSymbols = section.Symbols.OfType().ToList(); Assert.Equal(new[] { - "INSTALLFOLDER", - "ProgramFiles6432Folder", - "ProgramFiles64Folder", - "TARGETDIR" - }, dirSymbols.Select(d => d.Id.Id).ToArray()); + "INSTALLFOLDER:ProgramFiles6432Folder:MsiPackage", + "ProgramFiles6432Folder:ProgramFiles64Folder:.", + "ProgramFiles64Folder:TARGETDIR:PFiles64", + "TARGETDIR::SourceDir" + }, dirSymbols.OrderBy(d => d.Id.Id).Select(d => d.Id.Id + ":" + d.ParentDirectoryRef + ":" + d.Name).ToArray()); } } @@ -116,12 +117,14 @@ namespace WixToolsetTest.CoreIntegration var dirSymbols = section.Symbols.OfType().ToList(); Assert.Equal(new[] { - "dirZsSsu81KcG46xXTwc4mTSZO5Zx4", - "INSTALLFOLDER", - "ProgramFiles6432Folder", - "ProgramFiles64Folder", - "TARGETDIR" - }, dirSymbols.Select(d => d.Id.Id).ToArray()); + "dZsSsu81KcG46xXTwc4mTSZO5Zx4:INSTALLFOLDER:dupe", + "INSTALLFOLDER:ProgramFiles6432Folder:MsiPackage", + "ProgramFiles6432Folder:ProgramFiles64Folder:.", + "ProgramFiles64Folder:TARGETDIR:PFiles64", + "TARGETDIR::SourceDir" + }, dirSymbols.OrderBy(d => d.Id.Id).Select(d => d.Id.Id + ":" + d.ParentDirectoryRef + ":" + d.Name).ToArray()); + } + } } } } diff --git a/src/test/WixToolsetTest.CoreIntegration/ExtensionFixture.cs b/src/test/WixToolsetTest.CoreIntegration/ExtensionFixture.cs index ff0c3258..089658e6 100644 --- a/src/test/WixToolsetTest.CoreIntegration/ExtensionFixture.cs +++ b/src/test/WixToolsetTest.CoreIntegration/ExtensionFixture.cs @@ -53,7 +53,7 @@ namespace WixToolsetTest.CoreIntegration Assert.True(File.Exists(Path.Combine(intermediateFolder, @"bin\extest.msi"))); Assert.True(File.Exists(Path.Combine(intermediateFolder, @"bin\extest.wixpdb"))); - Assert.True(File.Exists(Path.Combine(intermediateFolder, @"bin\MsiPackage\example.txt"))); + Assert.True(File.Exists(Path.Combine(intermediateFolder, @"bin\PFiles\MsiPackage\example.txt"))); var intermediate = Intermediate.Load(Path.Combine(intermediateFolder, @"bin\extest.wixpdb")); var section = intermediate.Sections.Single(); diff --git a/src/test/WixToolsetTest.CoreIntegration/LanguageFixture.cs b/src/test/WixToolsetTest.CoreIntegration/LanguageFixture.cs index 319b0788..610e44b8 100644 --- a/src/test/WixToolsetTest.CoreIntegration/LanguageFixture.cs +++ b/src/test/WixToolsetTest.CoreIntegration/LanguageFixture.cs @@ -8,6 +8,7 @@ namespace WixToolsetTest.CoreIntegration using WixToolset.Core.TestPackage; using WixToolset.Data; using WixToolset.Data.Symbols; + using WixToolset.Data.WindowsInstaller; using Xunit; public class LanguageFixture @@ -36,6 +37,14 @@ namespace WixToolsetTest.CoreIntegration var intermediate = Intermediate.Load(Path.Combine(baseFolder, @"bin\test.wixpdb")); var section = intermediate.Sections.Single(); + var directorySymbols = section.Symbols.OfType(); + Assert.Equal(new[] + { + "INSTALLFOLDER:Example Corporation\\MsiPackage", + "ProgramFilesFolder:PFiles", + "TARGETDIR:SourceDir" + }, directorySymbols.OrderBy(s => s.Id.Id).Select(s => s.Id.Id + ":" + s.Name).ToArray()); + var propertySymbol = section.Symbols.OfType().Single(p => p.Id.Id == "ProductLanguage"); Assert.Equal("0", propertySymbol.Value); @@ -44,6 +53,16 @@ namespace WixToolsetTest.CoreIntegration var summaryCodepage = section.Symbols.OfType().Single(s => s.PropertyId == SummaryInformationType.Codepage); Assert.Equal("1252", summaryCodepage.Value); + + var data = WindowsInstallerData.Load(Path.Combine(baseFolder, @"bin\test.wixpdb")); + var directoryRows = data.Tables["Directory"].Rows; + Assert.Equal(new[] + { + "d4EceYatXTyy8HXPt5B6DT9Rj.wE:u7-b4gch|Example Corporation", + "INSTALLFOLDER:oekcr5lq|MsiPackage", + "ProgramFilesFolder:PFiles", + "TARGETDIR:SourceDir" + }, directoryRows.Select(r => r.FieldAsString(0) + ":" + r.FieldAsString(2)).ToArray()); } } diff --git a/src/test/WixToolsetTest.CoreIntegration/LinkerFixture.cs b/src/test/WixToolsetTest.CoreIntegration/LinkerFixture.cs index f73a57d0..676d7d87 100644 --- a/src/test/WixToolsetTest.CoreIntegration/LinkerFixture.cs +++ b/src/test/WixToolsetTest.CoreIntegration/LinkerFixture.cs @@ -68,7 +68,7 @@ namespace WixToolsetTest.CoreIntegration Assert.True(File.Exists(Path.Combine(baseFolder, @"bin\test.msi"))); Assert.True(File.Exists(Path.Combine(baseFolder, @"bin\test.wixpdb"))); - Assert.True(File.Exists(Path.Combine(baseFolder, @"bin\MsiPackage\test.txt"))); + Assert.True(File.Exists(Path.Combine(baseFolder, @"bin\PFiles\MsiPackage\test.txt"))); var intermediate = Intermediate.Load(Path.Combine(baseFolder, @"bin\test.wixpdb")); var section = intermediate.Sections.Single(); diff --git a/src/test/WixToolsetTest.CoreIntegration/MsiFixture.cs b/src/test/WixToolsetTest.CoreIntegration/MsiFixture.cs index a8ea0a18..3bdfa0ef 100644 --- a/src/test/WixToolsetTest.CoreIntegration/MsiFixture.cs +++ b/src/test/WixToolsetTest.CoreIntegration/MsiFixture.cs @@ -40,7 +40,7 @@ namespace WixToolsetTest.CoreIntegration Assert.True(File.Exists(Path.Combine(baseFolder, @"bin\test.msi"))); Assert.True(File.Exists(Path.Combine(baseFolder, @"bin\test.wixpdb"))); - Assert.True(File.Exists(Path.Combine(baseFolder, @"bin\MsiPackage\test.txt"))); + Assert.True(File.Exists(Path.Combine(baseFolder, @"bin\PFiles\MsiPackage\test.txt"))); var intermediate = Intermediate.Load(Path.Combine(baseFolder, @"bin\test.wixpdb")); @@ -240,7 +240,7 @@ namespace WixToolsetTest.CoreIntegration Assert.True(File.Exists(Path.Combine(baseFolder, @"bin\test.msi"))); Assert.True(File.Exists(Path.Combine(baseFolder, @"bin\test.wixpdb"))); - Assert.True(File.Exists(Path.Combine(baseFolder, @"bin\MsiPackage\test.txt"))); + Assert.True(File.Exists(Path.Combine(baseFolder, @"bin\PFiles\MsiPackage\test.txt"))); var intermediate = Intermediate.Load(Path.Combine(baseFolder, @"bin\test.wixpdb")); var section = intermediate.Sections.Single(); @@ -351,7 +351,7 @@ namespace WixToolsetTest.CoreIntegration var pdbPath = Path.Combine(intermediateFolder, @"bin\test.wixpdb"); Assert.True(File.Exists(Path.Combine(intermediateFolder, @"bin\test.msi"))); Assert.True(File.Exists(pdbPath)); - Assert.True(File.Exists(Path.Combine(intermediateFolder, @"bin\MsiPackage\test.txt"))); + Assert.True(File.Exists(Path.Combine(intermediateFolder, @"bin\PFiles\MsiPackage\test.txt"))); var intermediate = Intermediate.Load(pdbPath); var section = intermediate.Sections.Single(); @@ -527,7 +527,7 @@ namespace WixToolsetTest.CoreIntegration Assert.True(File.Exists(Path.Combine(baseFolder, @"bin\test.msi"))); Assert.True(File.Exists(Path.Combine(baseFolder, @"bin\test.wixpdb"))); - Assert.True(File.Exists(Path.Combine(baseFolder, @"bin\MsiPackage\test.txt"))); + Assert.True(File.Exists(Path.Combine(baseFolder, @"bin\PFiles\MsiPackage\test.txt"))); var intermediate = Intermediate.Load(Path.Combine(baseFolder, @"bin\test.wixpdb")); var section = intermediate.Sections.Single(); @@ -563,7 +563,7 @@ namespace WixToolsetTest.CoreIntegration Assert.True(File.Exists(Path.Combine(baseFolder, @"bin\test.msi"))); Assert.True(File.Exists(Path.Combine(baseFolder, @"bin\test.wixpdb"))); - Assert.True(File.Exists(Path.Combine(baseFolder, @"bin\AssemblyMsiPackage\candle.exe"))); + Assert.True(File.Exists(Path.Combine(baseFolder, @"bin\PFiles\AssemblyMsiPackage\candle.exe"))); var intermediate = Intermediate.Load(Path.Combine(baseFolder, @"bin\test.wixpdb")); var section = intermediate.Sections.Single(); @@ -721,7 +721,7 @@ namespace WixToolsetTest.CoreIntegration Assert.True(File.Exists(Path.Combine(baseFolder, @"bin\test.msi"))); Assert.True(File.Exists(Path.Combine(baseFolder, @"bin\test.wixpdb"))); - Assert.True(File.Exists(Path.Combine(baseFolder, @"bin\MsiPackage\Foo.exe"))); + Assert.True(File.Exists(Path.Combine(baseFolder, @"bin\PFiles\MsiPackage\Foo.exe"))); var intermediate = Intermediate.Load(Path.Combine(baseFolder, @"bin\test.wixpdb")); var section = intermediate.Sections.Single(); diff --git a/src/test/WixToolsetTest.CoreIntegration/TestData/CopyFile/CopyFile.wxs b/src/test/WixToolsetTest.CoreIntegration/TestData/CopyFile/CopyFile.wxs index 66208806..90d66cc3 100644 --- a/src/test/WixToolsetTest.CoreIntegration/TestData/CopyFile/CopyFile.wxs +++ b/src/test/WixToolsetTest.CoreIntegration/TestData/CopyFile/CopyFile.wxs @@ -10,6 +10,8 @@ - + + + diff --git a/src/test/WixToolsetTest.CoreIntegration/TestData/DuplicateDir/DuplicateDir.wxs b/src/test/WixToolsetTest.CoreIntegration/TestData/DuplicateDir/DuplicateDir.wxs index ffee969d..a58b68c8 100644 --- a/src/test/WixToolsetTest.CoreIntegration/TestData/DuplicateDir/DuplicateDir.wxs +++ b/src/test/WixToolsetTest.CoreIntegration/TestData/DuplicateDir/DuplicateDir.wxs @@ -8,7 +8,7 @@ - + @@ -16,7 +16,7 @@ - + diff --git a/src/test/WixToolsetTest.CoreIntegration/TestData/Language/Package.wxs b/src/test/WixToolsetTest.CoreIntegration/TestData/Language/Package.wxs index 2bbc14f9..db15796d 100644 --- a/src/test/WixToolsetTest.CoreIntegration/TestData/Language/Package.wxs +++ b/src/test/WixToolsetTest.CoreIntegration/TestData/Language/Package.wxs @@ -11,6 +11,8 @@ - + + + diff --git a/src/test/WixToolsetTest.CoreIntegration/TestData/Media/MultiMedia.wxs b/src/test/WixToolsetTest.CoreIntegration/TestData/Media/MultiMedia.wxs index 8a555bda..e7492db4 100644 --- a/src/test/WixToolsetTest.CoreIntegration/TestData/Media/MultiMedia.wxs +++ b/src/test/WixToolsetTest.CoreIntegration/TestData/Media/MultiMedia.wxs @@ -8,19 +8,19 @@ - + - + - + - + diff --git a/src/test/WixToolsetTest.CoreIntegration/TestData/PatchNoFileChanges/Package.wxs b/src/test/WixToolsetTest.CoreIntegration/TestData/PatchNoFileChanges/Package.wxs index 9d530376..5ad21a75 100644 --- a/src/test/WixToolsetTest.CoreIntegration/TestData/PatchNoFileChanges/Package.wxs +++ b/src/test/WixToolsetTest.CoreIntegration/TestData/PatchNoFileChanges/Package.wxs @@ -4,7 +4,9 @@ - + + + diff --git a/src/test/WixToolsetTest.CoreIntegration/TestData/ProductWithComponentGroupRef/Product.wxs b/src/test/WixToolsetTest.CoreIntegration/TestData/ProductWithComponentGroupRef/Product.wxs index f297c9e9..5a4e2c07 100644 --- a/src/test/WixToolsetTest.CoreIntegration/TestData/ProductWithComponentGroupRef/Product.wxs +++ b/src/test/WixToolsetTest.CoreIntegration/TestData/ProductWithComponentGroupRef/Product.wxs @@ -1,4 +1,4 @@ - + @@ -9,6 +9,8 @@ - + + + diff --git a/src/test/WixToolsetTest.CoreIntegration/TestData/SameFileFolders/TestComponents.wxs b/src/test/WixToolsetTest.CoreIntegration/TestData/SameFileFolders/TestComponents.wxs index 765e6778..bbad63e6 100644 --- a/src/test/WixToolsetTest.CoreIntegration/TestData/SameFileFolders/TestComponents.wxs +++ b/src/test/WixToolsetTest.CoreIntegration/TestData/SameFileFolders/TestComponents.wxs @@ -1,14 +1,14 @@ - - + + - + - + diff --git a/src/test/WixToolsetTest.CoreIntegration/TestData/UsingProvides/Package.wxs b/src/test/WixToolsetTest.CoreIntegration/TestData/UsingProvides/Package.wxs index 9ddcdc90..70fdbb46 100644 --- a/src/test/WixToolsetTest.CoreIntegration/TestData/UsingProvides/Package.wxs +++ b/src/test/WixToolsetTest.CoreIntegration/TestData/UsingProvides/Package.wxs @@ -9,6 +9,8 @@ - + + + -- cgit v1.2.3-55-g6feb