aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Mensching <rob@firegiant.com>2021-04-05 12:55:26 -0700
committerRob Mensching <rob@firegiant.com>2021-04-06 16:10:05 -0700
commit860f77f7c9d522074dc7e44cfe11281efd20687f (patch)
tree49527e82264f2dac88247885e937f935ae2ac658
parent94db5671e85ce63487e3a415251cad0eb6abe3d1 (diff)
downloadwix-860f77f7c9d522074dc7e44cfe11281efd20687f.tar.gz
wix-860f77f7c9d522074dc7e44cfe11281efd20687f.tar.bz2
wix-860f77f7c9d522074dc7e44cfe11281efd20687f.zip
Introduce "Subdirectory" which simplifies inline directory syntax
Completes wixtoolset/issues#4727
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Bind/CreateWindowsInstallerDataFromIRCommand.cs58
-rw-r--r--src/WixToolset.Core/Compiler.cs199
-rw-r--r--src/WixToolset.Core/CompilerCore.cs17
-rw-r--r--src/WixToolset.Core/Compiler_Package.cs116
-rw-r--r--src/WixToolset.Core/ExtensibilityServices/ParseHelper.cs126
-rw-r--r--src/WixToolset.Core/Linker.cs1
-rw-r--r--src/test/WixToolsetTest.CoreIntegration/DirectoryFixture.cs35
-rw-r--r--src/test/WixToolsetTest.CoreIntegration/ExtensionFixture.cs2
-rw-r--r--src/test/WixToolsetTest.CoreIntegration/LanguageFixture.cs19
-rw-r--r--src/test/WixToolsetTest.CoreIntegration/LinkerFixture.cs2
-rw-r--r--src/test/WixToolsetTest.CoreIntegration/MsiFixture.cs12
-rw-r--r--src/test/WixToolsetTest.CoreIntegration/TestData/CopyFile/CopyFile.wxs4
-rw-r--r--src/test/WixToolsetTest.CoreIntegration/TestData/DuplicateDir/DuplicateDir.wxs4
-rw-r--r--src/test/WixToolsetTest.CoreIntegration/TestData/Language/Package.wxs4
-rw-r--r--src/test/WixToolsetTest.CoreIntegration/TestData/Media/MultiMedia.wxs8
-rw-r--r--src/test/WixToolsetTest.CoreIntegration/TestData/PatchNoFileChanges/Package.wxs4
-rw-r--r--src/test/WixToolsetTest.CoreIntegration/TestData/ProductWithComponentGroupRef/Product.wxs6
-rw-r--r--src/test/WixToolsetTest.CoreIntegration/TestData/SameFileFolders/TestComponents.wxs8
-rw-r--r--src/test/WixToolsetTest.CoreIntegration/TestData/UsingProvides/Package.wxs4
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
18 18
19 internal class CreateWindowsInstallerDataFromIRCommand 19 internal class CreateWindowsInstallerDataFromIRCommand
20 { 20 {
21 private static readonly char[] PathSeparatorChars = new[] { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar };
22
21 public CreateWindowsInstallerDataFromIRCommand(IMessaging messaging, IntermediateSection section, TableDefinitionCollection tableDefinitions, int codepage, IEnumerable<IWindowsInstallerBackendBinderExtension> backendExtensions, IWindowsInstallerBackendHelper backendHelper) 23 public CreateWindowsInstallerDataFromIRCommand(IMessaging messaging, IntermediateSection section, TableDefinitionCollection tableDefinitions, int codepage, IEnumerable<IWindowsInstallerBackendBinderExtension> backendExtensions, IWindowsInstallerBackendHelper backendHelper)
22 { 24 {
23 this.Messaging = messaging; 25 this.Messaging = messaging;
@@ -488,18 +490,23 @@ namespace WixToolset.Core.WindowsInstaller.Bind
488 490
489 private void AddDirectorySymbol(DirectorySymbol symbol) 491 private void AddDirectorySymbol(DirectorySymbol symbol)
490 { 492 {
491 if (String.IsNullOrEmpty(symbol.ShortName) && symbol.Name != null && !symbol.Name.Equals(".") && !symbol.Name.Equals("SourceDir") && !this.BackendHelper.IsValidShortFilename(symbol.Name, false)) 493 (var name, var parentDir) = this.AddDirectorySubdirectories(symbol);
494
495 var shortName = symbol.ShortName;
496 var sourceShortname = symbol.SourceShortName;
497
498 if (String.IsNullOrEmpty(shortName) && name != null && name != "." && name != "SourceDir" && !this.BackendHelper.IsValidShortFilename(name, false))
492 { 499 {
493 symbol.ShortName = this.CreateShortName(symbol.Name, false, "Directory", symbol.ParentDirectoryRef); 500 shortName = this.CreateShortName(name, false, "Directory", symbol.ParentDirectoryRef);
494 } 501 }
495 502
496 if (String.IsNullOrEmpty(symbol.SourceShortName) && !String.IsNullOrEmpty(symbol.SourceName) && !this.BackendHelper.IsValidShortFilename(symbol.SourceName, false)) 503 if (String.IsNullOrEmpty(sourceShortname) && !String.IsNullOrEmpty(symbol.SourceName) && !this.BackendHelper.IsValidShortFilename(symbol.SourceName, false))
497 { 504 {
498 symbol.SourceShortName = this.CreateShortName(symbol.SourceName, false, "Directory", symbol.ParentDirectoryRef); 505 sourceShortname = this.CreateShortName(symbol.SourceName, false, "Directory", symbol.ParentDirectoryRef);
499 } 506 }
500 507
501 var sourceName = CreateMsiFilename(symbol.SourceShortName, symbol.SourceName); 508 var sourceName = CreateMsiFilename(sourceShortname, symbol.SourceName);
502 var targetName = CreateMsiFilename(symbol.ShortName, symbol.Name); 509 var targetName = CreateMsiFilename(shortName, name);
503 510
504 if (String.IsNullOrEmpty(targetName)) 511 if (String.IsNullOrEmpty(targetName))
505 { 512 {
@@ -510,7 +517,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
510 517
511 var row = this.CreateRow(symbol, "Directory"); 518 var row = this.CreateRow(symbol, "Directory");
512 row[0] = symbol.Id.Id; 519 row[0] = symbol.Id.Id;
513 row[1] = symbol.ParentDirectoryRef; 520 row[1] = parentDir;
514 row[2] = defaultDir; 521 row[2] = defaultDir;
515 522
516 if (OutputType.Module == this.Data.Type) 523 if (OutputType.Module == this.Data.Type)
@@ -1267,6 +1274,43 @@ namespace WixToolset.Core.WindowsInstaller.Bind
1267 } 1274 }
1268 } 1275 }
1269 1276
1277 private (string, string) AddDirectorySubdirectories(DirectorySymbol symbol)
1278 {
1279 var directory = symbol.Name.Trim(PathSeparatorChars);
1280 var parentDir = symbol.ParentDirectoryRef ?? (symbol.Id.Id == "TARGETDIR" ? null : "TARGETDIR");
1281
1282 var start = 0;
1283 var end = directory.IndexOfAny(PathSeparatorChars);
1284 var path = String.Empty;
1285
1286 while (start <= end)
1287 {
1288 var subdirectoryName = directory.Substring(start, end - start);
1289
1290 if (!String.IsNullOrEmpty(subdirectoryName))
1291 {
1292 path = Path.Combine(path, subdirectoryName);
1293
1294 var id = this.BackendHelper.GenerateIdentifier("d", symbol.ParentDirectoryRef, path);
1295 var shortnameSubdirectory = this.BackendHelper.IsValidShortFilename(subdirectoryName, false) ? null : this.CreateShortName(subdirectoryName, false, "Directory", symbol.ParentDirectoryRef);
1296
1297 var subdirectoryRow = this.CreateRow(symbol, "Directory");
1298 subdirectoryRow[0] = id;
1299 subdirectoryRow[1] = parentDir;
1300 subdirectoryRow[2] = CreateMsiFilename(shortnameSubdirectory, subdirectoryName);
1301
1302 parentDir = id;
1303 }
1304
1305 start = end + 1;
1306 end = symbol.Name.IndexOfAny(PathSeparatorChars, start);
1307 }
1308
1309 var name = (start == 0) ? directory : directory.Substring(start);
1310
1311 return (name, parentDir);
1312 }
1313
1270 private void EnsureRequiredTables() 1314 private void EnsureRequiredTables()
1271 { 1315 {
1272 // check for missing table and add them or display an error as appropriate 1316 // 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
5 using System; 5 using System;
6 using System.Collections.Generic; 6 using System.Collections.Generic;
7 using System.Diagnostics; 7 using System.Diagnostics;
8 using System.Diagnostics.CodeAnalysis;
9 using System.Globalization; 8 using System.Globalization;
10 using System.IO; 9 using System.IO;
11 using System.Linq; 10 using System.Linq;
@@ -2107,6 +2106,7 @@ namespace WixToolset.Core
2107 2106
2108 var comPlusBits = CompilerConstants.IntegerNotSet; 2107 var comPlusBits = CompilerConstants.IntegerNotSet;
2109 string condition = null; 2108 string condition = null;
2109 string subdirectory = null;
2110 var encounteredODBCDataSource = false; 2110 var encounteredODBCDataSource = false;
2111 var files = 0; 2111 var files = 0;
2112 var guid = "*"; 2112 var guid = "*";
@@ -2163,16 +2163,16 @@ namespace WixToolset.Core
2163 break; 2163 break;
2164 case "DisableRegistryReflection": 2164 case "DisableRegistryReflection":
2165 disableRegistryReflection = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); 2165 disableRegistryReflection = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
2166 //if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib))
2167 //{
2168 // bits |= MsiInterop.MsidbComponentAttributesDisableRegistryReflection;
2169 //}
2170 break; 2166 break;
2171 case "Condition": 2167 case "Condition":
2172 condition = this.Core.GetAttributeValue(sourceLineNumbers, attrib); 2168 condition = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
2173 break; 2169 break;
2174 case "Directory": 2170 case "Directory":
2175 directoryId = this.Core.CreateDirectoryReferenceFromInlineSyntax(sourceLineNumbers, attrib, directoryId); 2171 directoryId = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
2172 this.Core.CreateSimpleReference(sourceLineNumbers, SymbolDefinitions.Directory, directoryId);
2173 break;
2174 case "Subdirectory":
2175 subdirectory = this.Core.GetAttributeLongFilename(sourceLineNumbers, attrib, allowRelative: true);
2176 break; 2176 break;
2177 case "DiskId": 2177 case "DiskId":
2178 diskId = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 1, Int16.MaxValue); 2178 diskId = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 1, Int16.MaxValue);
@@ -2196,14 +2196,12 @@ namespace WixToolset.Core
2196 { 2196 {
2197 case "either": 2197 case "either":
2198 location = ComponentLocation.Either; 2198 location = ComponentLocation.Either;
2199 //bits |= MsiInterop.MsidbComponentAttributesOptional;
2200 break; 2199 break;
2201 case "local": // this is the default 2200 case "local": // this is the default
2202 location = ComponentLocation.LocalOnly; 2201 location = ComponentLocation.LocalOnly;
2203 break; 2202 break;
2204 case "source": 2203 case "source":
2205 location = ComponentLocation.SourceOnly; 2204 location = ComponentLocation.SourceOnly;
2206 //bits |= MsiInterop.MsidbComponentAttributesSourceOnly;
2207 break; 2205 break;
2208 case "": 2206 case "":
2209 break; 2207 break;
@@ -2217,45 +2215,21 @@ namespace WixToolset.Core
2217 break; 2215 break;
2218 case "NeverOverwrite": 2216 case "NeverOverwrite":
2219 neverOverwrite = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); 2217 neverOverwrite = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
2220 //if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib))
2221 //{
2222 // bits |= MsiInterop.MsidbComponentAttributesNeverOverwrite;
2223 //}
2224 break; 2218 break;
2225 case "Permanent": 2219 case "Permanent":
2226 permanent = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); 2220 permanent = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
2227 //if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib))
2228 //{
2229 // bits |= MsiInterop.MsidbComponentAttributesPermanent;
2230 //}
2231 break; 2221 break;
2232 case "Shared": 2222 case "Shared":
2233 shared = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); 2223 shared = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
2234 //if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib))
2235 //{
2236 // bits |= MsiInterop.MsidbComponentAttributesShared;
2237 //}
2238 break; 2224 break;
2239 case "SharedDllRefCount": 2225 case "SharedDllRefCount":
2240 sharedDllRefCount = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); 2226 sharedDllRefCount = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
2241 //if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib))
2242 //{
2243 // bits |= MsiInterop.MsidbComponentAttributesSharedDllRefCount;
2244 //}
2245 break; 2227 break;
2246 case "Transitive": 2228 case "Transitive":
2247 transitive = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); 2229 transitive = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
2248 //if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib))
2249 //{
2250 // bits |= MsiInterop.MsidbComponentAttributesTransitive;
2251 //}
2252 break; 2230 break;
2253 case "UninstallWhenSuperseded": 2231 case "UninstallWhenSuperseded":
2254 uninstallWhenSuperseded = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); 2232 uninstallWhenSuperseded = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
2255 //if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib))
2256 //{
2257 // bits |= MsiInterop.MsidbComponentAttributesUninstallOnSupersedence;
2258 //}
2259 break; 2233 break;
2260 default: 2234 default:
2261 this.Core.UnexpectedAttribute(node, attrib); 2235 this.Core.UnexpectedAttribute(node, attrib);
@@ -2275,17 +2249,22 @@ namespace WixToolset.Core
2275 id = new Identifier(AccessModifier.Section, componentIdPlaceholder); 2249 id = new Identifier(AccessModifier.Section, componentIdPlaceholder);
2276 } 2250 }
2277 2251
2278 if (null == directoryId) 2252 if (String.IsNullOrEmpty(directoryId))
2279 { 2253 {
2280 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Directory")); 2254 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Directory"));
2281 } 2255 }
2282 2256
2283 if (String.IsNullOrEmpty(guid) && shared /*MsiInterop.MsidbComponentAttributesShared == (bits & MsiInterop.MsidbComponentAttributesShared)*/) 2257 if (!String.IsNullOrEmpty(subdirectory))
2258 {
2259 directoryId = this.Core.CreateDirectoryReferenceFromInlineSyntax(sourceLineNumbers, directoryId, subdirectory);
2260 }
2261
2262 if (String.IsNullOrEmpty(guid) && shared)
2284 { 2263 {
2285 this.Core.Write(ErrorMessages.IllegalAttributeValueWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Shared", "yes", "Guid", "")); 2264 this.Core.Write(ErrorMessages.IllegalAttributeValueWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Shared", "yes", "Guid", ""));
2286 } 2265 }
2287 2266
2288 if (String.IsNullOrEmpty(guid) && permanent /*MsiInterop.MsidbComponentAttributesPermanent == (bits & MsiInterop.MsidbComponentAttributesPermanent)*/) 2267 if (String.IsNullOrEmpty(guid) && permanent)
2289 { 2268 {
2290 this.Core.Write(ErrorMessages.IllegalAttributeValueWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Permanent", "yes", "Guid", "")); 2269 this.Core.Write(ErrorMessages.IllegalAttributeValueWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Permanent", "yes", "Guid", ""));
2291 } 2270 }
@@ -2587,6 +2566,7 @@ namespace WixToolset.Core
2587 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); 2566 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
2588 Identifier id = null; 2567 Identifier id = null;
2589 string directoryId = null; 2568 string directoryId = null;
2569 string subdirectory = null;
2590 string source = null; 2570 string source = null;
2591 2571
2592 foreach (var attrib in node.Attributes()) 2572 foreach (var attrib in node.Attributes())
@@ -2599,9 +2579,11 @@ namespace WixToolset.Core
2599 id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); 2579 id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib);
2600 break; 2580 break;
2601 case "Directory": 2581 case "Directory":
2602 // If the inline syntax is invalid it returns null. Use a static error identifier so the null 2582 directoryId = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
2603 // directory identifier here doesn't trickle down false errors into child elements. 2583 this.Core.CreateSimpleReference(sourceLineNumbers, SymbolDefinitions.Directory, directoryId);
2604 directoryId = this.Core.CreateDirectoryReferenceFromInlineSyntax(sourceLineNumbers, attrib, null) ?? "ErrorParsingInlineSyntax"; 2584 break;
2585 case "Subdirectory":
2586 subdirectory = this.Core.GetAttributeLongFilename(sourceLineNumbers, attrib, allowRelative: true);
2605 break; 2587 break;
2606 case "Source": 2588 case "Source":
2607 source = this.Core.GetAttributeValue(sourceLineNumbers, attrib); 2589 source = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
@@ -2623,6 +2605,8 @@ namespace WixToolset.Core
2623 id = Identifier.Invalid; 2605 id = Identifier.Invalid;
2624 } 2606 }
2625 2607
2608 directoryId = this.HandleSubdirectory(sourceLineNumbers, node, directoryId, subdirectory, "Directory", "Subdirectory");
2609
2626 if (!String.IsNullOrEmpty(source) && !source.EndsWith(Path.DirectorySeparatorChar.ToString(), StringComparison.Ordinal)) 2610 if (!String.IsNullOrEmpty(source) && !source.EndsWith(Path.DirectorySeparatorChar.ToString(), StringComparison.Ordinal))
2627 { 2611 {
2628 source = String.Concat(source, Path.DirectorySeparatorChar); 2612 source = String.Concat(source, Path.DirectorySeparatorChar);
@@ -2898,18 +2882,24 @@ namespace WixToolset.Core
2898 private string ParseCreateFolderElement(XElement node, string componentId, string directoryId, bool win64Component) 2882 private string ParseCreateFolderElement(XElement node, string componentId, string directoryId, bool win64Component)
2899 { 2883 {
2900 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); 2884 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
2885 string subdirectory = null;
2886
2901 foreach (var attrib in node.Attributes()) 2887 foreach (var attrib in node.Attributes())
2902 { 2888 {
2903 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) 2889 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace)
2904 { 2890 {
2905 switch (attrib.Name.LocalName) 2891 switch (attrib.Name.LocalName)
2906 { 2892 {
2907 case "Directory": 2893 case "Directory":
2908 directoryId = this.Core.CreateDirectoryReferenceFromInlineSyntax(sourceLineNumbers, attrib, directoryId); 2894 directoryId = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
2909 break; 2895 this.Core.CreateSimpleReference(sourceLineNumbers, SymbolDefinitions.Directory, directoryId);
2910 default: 2896 break;
2911 this.Core.UnexpectedAttribute(node, attrib); 2897 case "Subdirectory":
2912 break; 2898 subdirectory = this.Core.GetAttributeLongFilename(sourceLineNumbers, attrib, allowRelative: true);
2899 break;
2900 default:
2901 this.Core.UnexpectedAttribute(node, attrib);
2902 break;
2913 } 2903 }
2914 } 2904 }
2915 else 2905 else
@@ -2918,24 +2908,26 @@ namespace WixToolset.Core
2918 } 2908 }
2919 } 2909 }
2920 2910
2911 directoryId = this.HandleSubdirectory(sourceLineNumbers, node, directoryId, subdirectory, "Directory", "Subdirectory");
2912
2921 foreach (var child in node.Elements()) 2913 foreach (var child in node.Elements())
2922 { 2914 {
2923 if (CompilerCore.WixNamespace == child.Name.Namespace) 2915 if (CompilerCore.WixNamespace == child.Name.Namespace)
2924 { 2916 {
2925 switch (child.Name.LocalName) 2917 switch (child.Name.LocalName)
2926 { 2918 {
2927 case "Shortcut": 2919 case "Shortcut":
2928 this.ParseShortcutElement(child, componentId, node.Name.LocalName, directoryId, YesNoType.No); 2920 this.ParseShortcutElement(child, componentId, node.Name.LocalName, directoryId, YesNoType.No);
2929 break; 2921 break;
2930 case "Permission": 2922 case "Permission":
2931 this.ParsePermissionElement(child, directoryId, "CreateFolder"); 2923 this.ParsePermissionElement(child, directoryId, "CreateFolder");
2932 break; 2924 break;
2933 case "PermissionEx": 2925 case "PermissionEx":
2934 this.ParsePermissionExElement(child, directoryId, "CreateFolder"); 2926 this.ParsePermissionExElement(child, directoryId, "CreateFolder");
2935 break; 2927 break;
2936 default: 2928 default:
2937 this.Core.UnexpectedElement(node, child); 2929 this.Core.UnexpectedElement(node, child);
2938 break; 2930 break;
2939 } 2931 }
2940 } 2932 }
2941 else 2933 else
@@ -2969,10 +2961,12 @@ namespace WixToolset.Core
2969 Identifier id = null; 2961 Identifier id = null;
2970 var delete = false; 2962 var delete = false;
2971 string destinationDirectory = null; 2963 string destinationDirectory = null;
2964 string destinationSubdirectory = null;
2972 string destinationName = null; 2965 string destinationName = null;
2973 string destinationShortName = null; 2966 string destinationShortName = null;
2974 string destinationProperty = null; 2967 string destinationProperty = null;
2975 string sourceDirectory = null; 2968 string sourceDirectory = null;
2969 string sourceSubdirectory = null;
2976 string sourceFolder = null; 2970 string sourceFolder = null;
2977 string sourceName = null; 2971 string sourceName = null;
2978 string sourceProperty = null; 2972 string sourceProperty = null;
@@ -2990,16 +2984,20 @@ namespace WixToolset.Core
2990 delete = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); 2984 delete = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
2991 break; 2985 break;
2992 case "DestinationDirectory": 2986 case "DestinationDirectory":
2993 destinationDirectory = this.Core.CreateDirectoryReferenceFromInlineSyntax(sourceLineNumbers, attrib, null); 2987 destinationDirectory = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
2988 this.Core.CreateSimpleReference(sourceLineNumbers, SymbolDefinitions.Directory, destinationDirectory);
2989 break;
2990 case "DestinationSubdirectory":
2991 destinationSubdirectory = this.Core.GetAttributeLongFilename(sourceLineNumbers, attrib, allowRelative: true);
2994 break; 2992 break;
2995 case "DestinationName": 2993 case "DestinationName":
2996 destinationName = this.Core.GetAttributeLongFilename(sourceLineNumbers, attrib, false); 2994 destinationName = this.Core.GetAttributeLongFilename(sourceLineNumbers, attrib);
2997 break; 2995 break;
2998 case "DestinationProperty": 2996 case "DestinationProperty":
2999 destinationProperty = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); 2997 destinationProperty = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
3000 break; 2998 break;
3001 case "DestinationShortName": 2999 case "DestinationShortName":
3002 destinationShortName = this.Core.GetAttributeShortFilename(sourceLineNumbers, attrib, false); 3000 destinationShortName = this.Core.GetAttributeShortFilename(sourceLineNumbers, attrib);
3003 break; 3001 break;
3004 case "FileId": 3002 case "FileId":
3005 if (null != fileId) 3003 if (null != fileId)
@@ -3010,7 +3008,11 @@ namespace WixToolset.Core
3010 this.Core.CreateSimpleReference(sourceLineNumbers, SymbolDefinitions.File, fileId); 3008 this.Core.CreateSimpleReference(sourceLineNumbers, SymbolDefinitions.File, fileId);
3011 break; 3009 break;
3012 case "SourceDirectory": 3010 case "SourceDirectory":
3013 sourceDirectory = this.Core.CreateDirectoryReferenceFromInlineSyntax(sourceLineNumbers, attrib, null); 3011 sourceDirectory = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
3012 this.Core.CreateSimpleReference(sourceLineNumbers, SymbolDefinitions.Directory, sourceDirectory);
3013 break;
3014 case "SourceSubdirectory":
3015 sourceSubdirectory = this.Core.GetAttributeLongFilename(sourceLineNumbers, attrib, allowRelative: true);
3014 break; 3016 break;
3015 case "SourceName": 3017 case "SourceName":
3016 sourceName = this.Core.GetAttributeValue(sourceLineNumbers, attrib); 3018 sourceName = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
@@ -3044,11 +3046,15 @@ namespace WixToolset.Core
3044 this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "SourceProperty", "SourceDirectory")); 3046 this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "SourceProperty", "SourceDirectory"));
3045 } 3047 }
3046 3048
3049 sourceDirectory = this.HandleSubdirectory(sourceLineNumbers, node, sourceDirectory, sourceSubdirectory, "SourceDirectory", "SourceSubdirectory");
3050
3047 if (null != destinationDirectory && null != destinationProperty) // DestinationDirectory and DestinationProperty cannot coexist 3051 if (null != destinationDirectory && null != destinationProperty) // DestinationDirectory and DestinationProperty cannot coexist
3048 { 3052 {
3049 this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "DestinationProperty", "DestinationDirectory")); 3053 this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "DestinationProperty", "DestinationDirectory"));
3050 } 3054 }
3051 3055
3056 destinationDirectory = this.HandleSubdirectory(sourceLineNumbers, node, destinationDirectory, destinationSubdirectory, "DestinationDirectory", "DestinationSubdirectory");
3057
3052 if (null == id) 3058 if (null == id)
3053 { 3059 {
3054 id = this.Core.CreateIdentifier("cf", sourceFolder, sourceDirectory, sourceProperty, destinationDirectory, destinationProperty, destinationName); 3060 id = this.Core.CreateIdentifier("cf", sourceFolder, sourceDirectory, sourceProperty, destinationDirectory, destinationProperty, destinationName);
@@ -3139,6 +3145,7 @@ namespace WixToolset.Core
3139 var explicitWin64 = false; 3145 var explicitWin64 = false;
3140 3146
3141 string scriptFile = null; 3147 string scriptFile = null;
3148 string subdirectory = null;
3142 3149
3143 CustomActionSourceType? sourceType = null; 3150 CustomActionSourceType? sourceType = null;
3144 CustomActionTargetType? targetType = null; 3151 CustomActionTargetType? targetType = null;
@@ -3194,8 +3201,9 @@ namespace WixToolset.Core
3194 { 3201 {
3195 this.Core.Write(ErrorMessages.CustomActionMultipleSources(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "BinaryKey", "Directory", "FileRef", "Property", "Script")); 3202 this.Core.Write(ErrorMessages.CustomActionMultipleSources(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "BinaryKey", "Directory", "FileRef", "Property", "Script"));
3196 } 3203 }
3197 source = this.Core.CreateDirectoryReferenceFromInlineSyntax(sourceLineNumbers, attrib, null); 3204 source = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
3198 sourceType = CustomActionSourceType.Directory; 3205 sourceType = CustomActionSourceType.Directory;
3206 this.Core.CreateSimpleReference(sourceLineNumbers, SymbolDefinitions.Directory, source);
3199 break; 3207 break;
3200 case "DllEntry": 3208 case "DllEntry":
3201 if (null != target) 3209 if (null != target)
@@ -3355,6 +3363,9 @@ namespace WixToolset.Core
3355 case "ScriptSourceFile": 3363 case "ScriptSourceFile":
3356 scriptFile = this.Core.GetAttributeValue(sourceLineNumbers, attrib); 3364 scriptFile = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
3357 break; 3365 break;
3366 case "Subdirectory":
3367 subdirectory = this.Core.GetAttributeLongFilename(sourceLineNumbers, attrib, allowRelative: true);
3368 break;
3358 case "SuppressModularization": 3369 case "SuppressModularization":
3359 suppressModularization = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); 3370 suppressModularization = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
3360 break; 3371 break;
@@ -3399,6 +3410,18 @@ namespace WixToolset.Core
3399 win64 = true; 3410 win64 = true;
3400 } 3411 }
3401 3412
3413 if (!String.IsNullOrEmpty(subdirectory))
3414 {
3415 if (sourceType == CustomActionSourceType.Directory)
3416 {
3417 source = this.HandleSubdirectory(sourceLineNumbers, node, source, subdirectory, "Directory", "Subdirectory");
3418 }
3419 else
3420 {
3421 this.Core.Write(ErrorMessages.IllegalAttributeWithoutOtherAttributes(sourceLineNumbers, node.Name.LocalName, "Subdirectory", "Directory"));
3422 }
3423 }
3424
3402 // if we have an in-lined Script CustomAction ensure no source or target attributes were provided 3425 // if we have an in-lined Script CustomAction ensure no source or target attributes were provided
3403 if (inlineScript) 3426 if (inlineScript)
3404 { 3427 {
@@ -4168,7 +4191,6 @@ namespace WixToolset.Core
4168 var fileSourceAttribSet = false; 4191 var fileSourceAttribSet = false;
4169 XAttribute nameAttribute = null; 4192 XAttribute nameAttribute = null;
4170 var name = "."; // default to parent directory. 4193 var name = "."; // default to parent directory.
4171 string inlineSyntax = null;
4172 string shortName = null; 4194 string shortName = null;
4173 string sourceName = null; 4195 string sourceName = null;
4174 string shortSourceName = null; 4196 string shortSourceName = null;
@@ -4194,7 +4216,7 @@ namespace WixToolset.Core
4194 fileSourceAttribSet = true; 4216 fileSourceAttribSet = true;
4195 break; 4217 break;
4196 case "Name": 4218 case "Name":
4197 name = this.Core.GetAttributeValue(sourceLineNumbers, attrib); 4219 name = this.Core.GetAttributeLongFilename(sourceLineNumbers, attrib, allowRelative: true);
4198 nameAttribute = attrib; 4220 nameAttribute = attrib;
4199 break; 4221 break;
4200 case "ShortName": 4222 case "ShortName":
@@ -4268,37 +4290,22 @@ namespace WixToolset.Core
4268 } 4290 }
4269 } 4291 }
4270 4292
4271 // Create the directory rows for the inline. 4293 if (null == id)
4272 if (nameAttribute != null)
4273 { 4294 {
4274 var lastSlash = name.LastIndexOf('\\'); 4295 id = this.Core.CreateIdentifier("d", parentId, name, shortName, sourceName, shortSourceName);
4275 if (lastSlash > 0)
4276 {
4277 inlineSyntax = name;
4278 name = inlineSyntax.Substring(lastSlash + 1);
4279
4280 parentId = this.Core.CreateDirectoryReferenceFromInlineSyntax(sourceLineNumbers, nameAttribute, parentId, inlineSyntax.Substring(0, lastSlash));
4281
4282 if (!this.Core.IsValidLongFilename(name, false, false))
4283 {
4284 this.Messaging.Write(ErrorMessages.IllegalLongFilename(sourceLineNumbers, node.Name.LocalName, nameAttribute.Name.LocalName, nameAttribute.Value, name));
4285 }
4286 }
4287 } 4296 }
4288 4297 else if (WindowsInstallerStandard.IsStandardDirectory(id.Id))
4289 if (null == id)
4290 { 4298 {
4291 id = this.Core.CreateIdentifier("dir", parentId, name, shortName, sourceName, shortSourceName); 4299 if (String.IsNullOrEmpty(sourceName))
4292
4293 if (!String.IsNullOrEmpty(inlineSyntax))
4294 { 4300 {
4295 this.Core.AddInlineDirectoryId(inlineSyntax, id.Id); 4301 this.Core.Write(CompilerWarnings.DefiningStandardDirectoryDeprecated(sourceLineNumbers, id.Id));
4296 } 4302 }
4297 } 4303
4298 else if ("TARGETDIR".Equals(id.Id, StringComparison.Ordinal) && !("SourceDir".Equals(name, StringComparison.Ordinal) && shortName == null && shortSourceName == null && sourceName == null)) 4304 if (id.Id == "TARGETDIR" && name != "SourceDir" && shortName == null && shortSourceName == null && sourceName == null)
4299 { 4305 {
4300 this.Core.Write(ErrorMessages.IllegalTargetDirDefaultDir(sourceLineNumbers, name)); 4306 this.Core.Write(ErrorMessages.IllegalTargetDirDefaultDir(sourceLineNumbers, name));
4301 } 4307 }
4308 }
4302 4309
4303 // Update the file source path appropriately. 4310 // Update the file source path appropriately.
4304 if (fileSourceAttribSet) 4311 if (fileSourceAttribSet)
@@ -4761,7 +4768,8 @@ namespace WixToolset.Core
4761 disallowAdvertise = (this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib) == YesNoType.No); 4768 disallowAdvertise = (this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib) == YesNoType.No);
4762 break; 4769 break;
4763 case "ConfigurableDirectory": 4770 case "ConfigurableDirectory":
4764 configurableDirectory = this.Core.CreateDirectoryReferenceFromInlineSyntax(sourceLineNumbers, attrib, null); 4771 configurableDirectory = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
4772 this.Core.CreateSimpleReference(sourceLineNumbers, SymbolDefinitions.Directory, configurableDirectory);
4765 break; 4773 break;
4766 case "Description": 4774 case "Description":
4767 description = this.Core.GetAttributeValue(sourceLineNumbers, attrib); 4775 description = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
@@ -8403,5 +8411,22 @@ namespace WixToolset.Core
8403 } 8411 }
8404 } 8412 }
8405 } 8413 }
8414
8415 private string HandleSubdirectory(SourceLineNumber sourceLineNumbers, XElement element, string directoryId, string subdirectory, string directoryAttributeName, string subdirectoryAttributename)
8416 {
8417 if (!String.IsNullOrEmpty(subdirectory))
8418 {
8419 if (String.IsNullOrEmpty(directoryId))
8420 {
8421 this.Core.Write(ErrorMessages.IllegalAttributeWithoutOtherAttributes(sourceLineNumbers, element.Name.LocalName, subdirectoryAttributename, directoryAttributeName));
8422 }
8423 else
8424 {
8425 directoryId = this.Core.CreateDirectoryReferenceFromInlineSyntax(sourceLineNumbers, directoryId, subdirectory);
8426 }
8427 }
8428
8429 return directoryId;
8430 }
8406 } 8431 }
8407} 8432}
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
386 /// Creates directories using the inline directory syntax. 386 /// Creates directories using the inline directory syntax.
387 /// </summary> 387 /// </summary>
388 /// <param name="sourceLineNumbers">Source line information.</param> 388 /// <param name="sourceLineNumbers">Source line information.</param>
389 /// <param name="attribute">Attribute containing the inline syntax.</param>
390 /// <param name="parentId">Optional identifier of parent directory.</param> 389 /// <param name="parentId">Optional identifier of parent directory.</param>
391 /// <param name="inlineSyntax">Optional inline syntax to override attribute's value.</param> 390 /// <param name="inlineSyntax">Optional inline syntax to override attribute's value.</param>
392 /// <returns>Identifier of the leaf directory created.</returns> 391 /// <returns>Identifier of the leaf directory created.</returns>
393 public string CreateDirectoryReferenceFromInlineSyntax(SourceLineNumber sourceLineNumbers, XAttribute attribute, string parentId, string inlineSyntax = null) 392 public string CreateDirectoryReferenceFromInlineSyntax(SourceLineNumber sourceLineNumbers, string parentId, string inlineSyntax = null)
394 { 393 {
395 return this.parseHelper.CreateDirectoryReferenceFromInlineSyntax(this.ActiveSection, sourceLineNumbers, attribute, parentId, inlineSyntax, this.activeSectionCachedInlinedDirectoryIds); 394 return this.parseHelper.CreateDirectoryReferenceFromInlineSyntax(this.ActiveSection, sourceLineNumbers, attribute: null, parentId, inlineSyntax, this.activeSectionCachedInlinedDirectoryIds);
396 } 395 }
397 396
398 /// <summary> 397 /// <summary>
@@ -784,7 +783,7 @@ namespace WixToolset.Core
784 /// <param name="attribute">The attribute containing the value to get.</param> 783 /// <param name="attribute">The attribute containing the value to get.</param>
785 /// <param name="allowWildcards">true if wildcards are allowed in the filename.</param> 784 /// <param name="allowWildcards">true if wildcards are allowed in the filename.</param>
786 /// <returns>The attribute's short filename value.</returns> 785 /// <returns>The attribute's short filename value.</returns>
787 public string GetAttributeShortFilename(SourceLineNumber sourceLineNumbers, XAttribute attribute, bool allowWildcards) 786 public string GetAttributeShortFilename(SourceLineNumber sourceLineNumbers, XAttribute attribute, bool allowWildcards = false)
788 { 787 {
789 if (null == attribute) 788 if (null == attribute)
790 { 789 {
@@ -1022,16 +1021,6 @@ namespace WixToolset.Core
1022 } 1021 }
1023 1022
1024 /// <summary> 1023 /// <summary>
1025 /// Adds inline directory syntax generated identifier.
1026 /// </summary>
1027 /// <param name="inlineSyntax">Inline directory syntax the identifier was generated.</param>
1028 /// <param name="id">Generated identifier for inline syntax.</param>
1029 internal void AddInlineDirectoryId(string inlineSyntax, string id)
1030 {
1031 this.activeSectionCachedInlinedDirectoryIds.Add(inlineSyntax, id);
1032 }
1033
1034 /// <summary>
1035 /// Creates a new section and makes it the active section in the core. 1024 /// Creates a new section and makes it the active section in the core.
1036 /// </summary> 1025 /// </summary>
1037 /// <param name="id">Unique identifier for the section.</param> 1026 /// <param name="id">Unique identifier for the section.</param>
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
2146 { 2146 {
2147 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); 2147 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
2148 Identifier id = null; 2148 Identifier id = null;
2149 string directory = null; 2149 string directoryId = null;
2150 string subdirectory = null;
2150 string name = null; 2151 string name = null;
2151 bool? onInstall = null; 2152 bool? onInstall = null;
2152 bool? onUninstall = null; 2153 bool? onUninstall = null;
2153 string property = null; 2154 string propertyId = null;
2154 string shortName = null; 2155 string shortName = null;
2155 2156
2156 foreach (var attrib in node.Attributes()) 2157 foreach (var attrib in node.Attributes())
@@ -2163,7 +2164,11 @@ namespace WixToolset.Core
2163 id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); 2164 id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib);
2164 break; 2165 break;
2165 case "Directory": 2166 case "Directory":
2166 directory = this.Core.CreateDirectoryReferenceFromInlineSyntax(sourceLineNumbers, attrib, parentDirectory); 2167 directoryId = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
2168 this.Core.CreateSimpleReference(sourceLineNumbers, SymbolDefinitions.Directory, directoryId);
2169 break;
2170 case "Subdirectory":
2171 directoryId = this.Core.GetAttributeLongFilename(sourceLineNumbers, attrib, allowRelative: true);
2167 break; 2172 break;
2168 case "Name": 2173 case "Name":
2169 name = this.Core.GetAttributeLongFilename(sourceLineNumbers, attrib, true); 2174 name = this.Core.GetAttributeLongFilename(sourceLineNumbers, attrib, true);
@@ -2185,7 +2190,7 @@ namespace WixToolset.Core
2185 } 2190 }
2186 break; 2191 break;
2187 case "Property": 2192 case "Property":
2188 property = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); 2193 propertyId = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
2189 break; 2194 break;
2190 case "ShortName": 2195 case "ShortName":
2191 shortName = this.Core.GetAttributeShortFilename(sourceLineNumbers, attrib, true); 2196 shortName = this.Core.GetAttributeShortFilename(sourceLineNumbers, attrib, true);
@@ -2211,15 +2216,23 @@ namespace WixToolset.Core
2211 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "On")); 2216 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "On"));
2212 } 2217 }
2213 2218
2214 if (null != directory && null != property) 2219 if (String.IsNullOrEmpty(propertyId))
2220 {
2221 directoryId = this.HandleSubdirectory(sourceLineNumbers, node, directoryId ?? parentDirectory, subdirectory, "Directory", "Subdirectory");
2222 }
2223 else if (!String.IsNullOrEmpty(directoryId))
2224 {
2225 this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Property", "Directory", directoryId));
2226 }
2227 else if (!String.IsNullOrEmpty(subdirectory))
2215 { 2228 {
2216 this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Property", "Directory", directory)); 2229 this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Property", "Subdirectory", subdirectory));
2217 } 2230 }
2218 2231
2219 if (null == id) 2232 if (null == id)
2220 { 2233 {
2221 var on = (onInstall == true && onUninstall == true) ? 3 : (onUninstall == true) ? 2 : (onInstall == true) ? 1 : 0; 2234 var on = (onInstall == true && onUninstall == true) ? 3 : (onUninstall == true) ? 2 : (onInstall == true) ? 1 : 0;
2222 id = this.Core.CreateIdentifier("rmf", directory ?? property ?? parentDirectory, LowercaseOrNull(shortName), LowercaseOrNull(name), on.ToString()); 2235 id = this.Core.CreateIdentifier("rmf", directoryId ?? propertyId ?? parentDirectory, LowercaseOrNull(shortName), LowercaseOrNull(name), on.ToString());
2223 } 2236 }
2224 2237
2225 this.Core.ParseForExtensionElements(node); 2238 this.Core.ParseForExtensionElements(node);
@@ -2231,7 +2244,7 @@ namespace WixToolset.Core
2231 ComponentRef = componentId, 2244 ComponentRef = componentId,
2232 FileName = name, 2245 FileName = name,
2233 ShortFileName = shortName, 2246 ShortFileName = shortName,
2234 DirPropertyRef = directory ?? property ?? parentDirectory, 2247 DirPropertyRef = directoryId ?? propertyId ?? parentDirectory,
2235 OnInstall = onInstall, 2248 OnInstall = onInstall,
2236 OnUninstall = onUninstall, 2249 OnUninstall = onUninstall,
2237 }); 2250 });
@@ -2248,10 +2261,11 @@ namespace WixToolset.Core
2248 { 2261 {
2249 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); 2262 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
2250 Identifier id = null; 2263 Identifier id = null;
2251 string directory = null; 2264 string directoryId = null;
2265 string subdirectory = null;
2252 bool? onInstall = null; 2266 bool? onInstall = null;
2253 bool? onUninstall = null; 2267 bool? onUninstall = null;
2254 string property = null; 2268 string propertyId = null;
2255 2269
2256 foreach (var attrib in node.Attributes()) 2270 foreach (var attrib in node.Attributes())
2257 { 2271 {
@@ -2263,7 +2277,11 @@ namespace WixToolset.Core
2263 id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); 2277 id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib);
2264 break; 2278 break;
2265 case "Directory": 2279 case "Directory":
2266 directory = this.Core.CreateDirectoryReferenceFromInlineSyntax(sourceLineNumbers, attrib, parentDirectory); 2280 directoryId = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
2281 this.Core.CreateSimpleReference(sourceLineNumbers, SymbolDefinitions.Directory, directoryId);
2282 break;
2283 case "Subdirectory":
2284 subdirectory = this.Core.GetAttributeLongFilename(sourceLineNumbers, attrib, allowRelative: true);
2267 break; 2285 break;
2268 case "On": 2286 case "On":
2269 var onValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); 2287 var onValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
@@ -2282,7 +2300,7 @@ namespace WixToolset.Core
2282 } 2300 }
2283 break; 2301 break;
2284 case "Property": 2302 case "Property":
2285 property = this.Core.GetAttributeValue(sourceLineNumbers, attrib); 2303 propertyId = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
2286 break; 2304 break;
2287 default: 2305 default:
2288 this.Core.UnexpectedAttribute(node, attrib); 2306 this.Core.UnexpectedAttribute(node, attrib);
@@ -2300,15 +2318,23 @@ namespace WixToolset.Core
2300 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "On")); 2318 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "On"));
2301 } 2319 }
2302 2320
2303 if (null != directory && null != property) 2321 if (String.IsNullOrEmpty(propertyId))
2322 {
2323 directoryId = this.HandleSubdirectory(sourceLineNumbers, node, directoryId ?? parentDirectory, subdirectory, "Directory", "Subdirectory");
2324 }
2325 else if (!String.IsNullOrEmpty(directoryId))
2326 {
2327 this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Property", "Directory", directoryId));
2328 }
2329 else if (!String.IsNullOrEmpty(subdirectory))
2304 { 2330 {
2305 this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Property", "Directory", directory)); 2331 this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Property", "Subdirectory", subdirectory));
2306 } 2332 }
2307 2333
2308 if (null == id) 2334 if (null == id)
2309 { 2335 {
2310 var on = (onInstall == true && onUninstall == true) ? 3 : (onUninstall == true) ? 2 : (onInstall == true) ? 1 : 0; 2336 var on = (onInstall == true && onUninstall == true) ? 3 : (onUninstall == true) ? 2 : (onInstall == true) ? 1 : 0;
2311 id = this.Core.CreateIdentifier("rmf", directory ?? property ?? parentDirectory, on.ToString()); 2337 id = this.Core.CreateIdentifier("rmf", directoryId ?? propertyId, on.ToString());
2312 } 2338 }
2313 2339
2314 this.Core.ParseForExtensionElements(node); 2340 this.Core.ParseForExtensionElements(node);
@@ -2318,7 +2344,7 @@ namespace WixToolset.Core
2318 this.Core.AddSymbol(new RemoveFileSymbol(sourceLineNumbers, id) 2344 this.Core.AddSymbol(new RemoveFileSymbol(sourceLineNumbers, id)
2319 { 2345 {
2320 ComponentRef = componentId, 2346 ComponentRef = componentId,
2321 DirPropertyRef = directory ?? property ?? parentDirectory, 2347 DirPropertyRef = directoryId ?? propertyId,
2322 OnInstall = onInstall, 2348 OnInstall = onInstall,
2323 OnUninstall = onUninstall 2349 OnUninstall = onUninstall
2324 }); 2350 });
@@ -2335,6 +2361,7 @@ namespace WixToolset.Core
2335 { 2361 {
2336 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); 2362 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
2337 Identifier id = null; 2363 Identifier id = null;
2364 string subdirectory = null;
2338 var runFromSource = CompilerConstants.IntegerNotSet; 2365 var runFromSource = CompilerConstants.IntegerNotSet;
2339 var runLocal = CompilerConstants.IntegerNotSet; 2366 var runLocal = CompilerConstants.IntegerNotSet;
2340 2367
@@ -2348,7 +2375,11 @@ namespace WixToolset.Core
2348 id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); 2375 id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib);
2349 break; 2376 break;
2350 case "Directory": 2377 case "Directory":
2351 directoryId = this.Core.CreateDirectoryReferenceFromInlineSyntax(sourceLineNumbers, attrib, directoryId); 2378 directoryId = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
2379 this.Core.CreateSimpleReference(sourceLineNumbers, SymbolDefinitions.Directory, directoryId);
2380 break;
2381 case "Subdirectory":
2382 subdirectory = this.Core.GetAttributeLongFilename(sourceLineNumbers, attrib, allowRelative: true);
2352 break; 2383 break;
2353 case "RunFromSource": 2384 case "RunFromSource":
2354 runFromSource = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int32.MaxValue); 2385 runFromSource = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int32.MaxValue);
@@ -2367,6 +2398,8 @@ namespace WixToolset.Core
2367 } 2398 }
2368 } 2399 }
2369 2400
2401 directoryId = this.HandleSubdirectory(sourceLineNumbers, node, directoryId, subdirectory, "Directory", "Subdirectory");
2402
2370 if (null == id) 2403 if (null == id)
2371 { 2404 {
2372 id = this.Core.CreateIdentifier("rc", componentId, directoryId); 2405 id = this.Core.CreateIdentifier("rc", componentId, directoryId);
@@ -4001,7 +4034,8 @@ namespace WixToolset.Core
4001 string description = null; 4034 string description = null;
4002 string descriptionResourceDll = null; 4035 string descriptionResourceDll = null;
4003 int? descriptionResourceId = null; 4036 int? descriptionResourceId = null;
4004 string directory = null; 4037 string directoryId = null;
4038 string subdirectory = null;
4005 string displayResourceDll = null; 4039 string displayResourceDll = null;
4006 int? displayResourceId = null; 4040 int? displayResourceId = null;
4007 int? hotkey = null; 4041 int? hotkey = null;
@@ -4011,7 +4045,8 @@ namespace WixToolset.Core
4011 string shortName = null; 4045 string shortName = null;
4012 ShortcutShowType? show = null; 4046 ShortcutShowType? show = null;
4013 string target = null; 4047 string target = null;
4014 string workingDirectory = null; 4048 string workingDirectoryId = null;
4049 string workingSubdirectory = null;
4015 4050
4016 foreach (var attrib in node.Attributes()) 4051 foreach (var attrib in node.Attributes())
4017 { 4052 {
@@ -4038,7 +4073,11 @@ namespace WixToolset.Core
4038 descriptionResourceId = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int16.MaxValue); 4073 descriptionResourceId = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int16.MaxValue);
4039 break; 4074 break;
4040 case "Directory": 4075 case "Directory":
4041 directory = this.Core.CreateDirectoryReferenceFromInlineSyntax(sourceLineNumbers, attrib, null); 4076 directoryId = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
4077 this.Core.CreateSimpleReference(sourceLineNumbers, SymbolDefinitions.Directory, directoryId);
4078 break;
4079 case "Subdirectory":
4080 subdirectory = this.Core.GetAttributeLongFilename(sourceLineNumbers, attrib, allowRelative: true);
4042 break; 4081 break;
4043 case "DisplayResourceDll": 4082 case "DisplayResourceDll":
4044 displayResourceDll = this.Core.GetAttributeValue(sourceLineNumbers, attrib); 4083 displayResourceDll = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
@@ -4086,7 +4125,11 @@ namespace WixToolset.Core
4086 target = this.Core.GetAttributeValue(sourceLineNumbers, attrib); 4125 target = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
4087 break; 4126 break;
4088 case "WorkingDirectory": 4127 case "WorkingDirectory":
4089 workingDirectory = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); 4128 workingDirectoryId = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
4129 this.Core.CreateSimpleReference(sourceLineNumbers, SymbolDefinitions.Directory, workingDirectoryId);
4130 break;
4131 case "WorkingSubdirectory":
4132 workingSubdirectory = this.Core.GetAttributeLongFilename(sourceLineNumbers, attrib, allowRelative: true);
4090 break; 4133 break;
4091 default: 4134 default:
4092 this.Core.UnexpectedAttribute(node, attrib); 4135 this.Core.UnexpectedAttribute(node, attrib);
@@ -4104,11 +4147,11 @@ namespace WixToolset.Core
4104 this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Target", "Advertise", "yes")); 4147 this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Target", "Advertise", "yes"));
4105 } 4148 }
4106 4149
4107 if (null == directory) 4150 if (null == directoryId)
4108 { 4151 {
4109 if ("Component" == parentElementLocalName) 4152 if ("Component" == parentElementLocalName)
4110 { 4153 {
4111 directory = defaultTarget; 4154 directoryId = defaultTarget;
4112 } 4155 }
4113 else 4156 else
4114 { 4157 {
@@ -4116,6 +4159,8 @@ namespace WixToolset.Core
4116 } 4159 }
4117 } 4160 }
4118 4161
4162 directoryId = this.HandleSubdirectory(sourceLineNumbers, node, directoryId, subdirectory, "Directory", "Subdirectory");
4163
4119 if (null != descriptionResourceDll) 4164 if (null != descriptionResourceDll)
4120 { 4165 {
4121 if (!descriptionResourceId.HasValue) 4166 if (!descriptionResourceId.HasValue)
@@ -4151,6 +4196,8 @@ namespace WixToolset.Core
4151 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Name")); 4196 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Name"));
4152 } 4197 }
4153 4198
4199 workingDirectoryId = this.HandleSubdirectory(sourceLineNumbers, node, workingDirectoryId, workingSubdirectory, "WorkingDirectory", "WorkingSubdirectory");
4200
4154 if ("Component" != parentElementLocalName && null != target) 4201 if ("Component" != parentElementLocalName && null != target)
4155 { 4202 {
4156 this.Core.Write(ErrorMessages.IllegalAttributeWhenNested(sourceLineNumbers, node.Name.LocalName, "Target", parentElementLocalName)); 4203 this.Core.Write(ErrorMessages.IllegalAttributeWhenNested(sourceLineNumbers, node.Name.LocalName, "Target", parentElementLocalName));
@@ -4158,7 +4205,7 @@ namespace WixToolset.Core
4158 4205
4159 if (null == id) 4206 if (null == id)
4160 { 4207 {
4161 id = this.Core.CreateIdentifier("sct", directory, LowercaseOrNull(name)); 4208 id = this.Core.CreateIdentifier("sct", directoryId, LowercaseOrNull(name));
4162 } 4209 }
4163 4210
4164 foreach (var child in node.Elements()) 4211 foreach (var child in node.Elements())
@@ -4209,7 +4256,7 @@ namespace WixToolset.Core
4209 4256
4210 this.Core.AddSymbol(new ShortcutSymbol(sourceLineNumbers, id) 4257 this.Core.AddSymbol(new ShortcutSymbol(sourceLineNumbers, id)
4211 { 4258 {
4212 DirectoryRef = directory, 4259 DirectoryRef = directoryId,
4213 Name = name, 4260 Name = name,
4214 ShortName = shortName, 4261 ShortName = shortName,
4215 ComponentRef = componentId, 4262 ComponentRef = componentId,
@@ -4220,7 +4267,7 @@ namespace WixToolset.Core
4220 IconRef = icon, 4267 IconRef = icon,
4221 IconIndex = iconIndex, 4268 IconIndex = iconIndex,
4222 Show = show, 4269 Show = show,
4223 WorkingDirectory = workingDirectory, 4270 WorkingDirectory = workingDirectoryId,
4224 DisplayResourceDll = displayResourceDll, 4271 DisplayResourceDll = displayResourceDll,
4225 DisplayResourceId = displayResourceId, 4272 DisplayResourceId = displayResourceId,
4226 DescriptionResourceDll = descriptionResourceDll, 4273 DescriptionResourceDll = descriptionResourceDll,
@@ -4309,7 +4356,8 @@ namespace WixToolset.Core
4309 var cost = CompilerConstants.IntegerNotSet; 4356 var cost = CompilerConstants.IntegerNotSet;
4310 string description = null; 4357 string description = null;
4311 var flags = 0; 4358 var flags = 0;
4312 string helpDirectory = null; 4359 string helpDirectoryId = null;
4360 string helpSubdirectory = null;
4313 var language = CompilerConstants.IntegerNotSet; 4361 var language = CompilerConstants.IntegerNotSet;
4314 var majorVersion = CompilerConstants.IntegerNotSet; 4362 var majorVersion = CompilerConstants.IntegerNotSet;
4315 var minorVersion = CompilerConstants.IntegerNotSet; 4363 var minorVersion = CompilerConstants.IntegerNotSet;
@@ -4346,7 +4394,11 @@ namespace WixToolset.Core
4346 } 4394 }
4347 break; 4395 break;
4348 case "HelpDirectory": 4396 case "HelpDirectory":
4349 helpDirectory = this.Core.CreateDirectoryReferenceFromInlineSyntax(sourceLineNumbers, attrib, null); 4397 helpDirectoryId = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
4398 this.Core.CreateSimpleReference(sourceLineNumbers, SymbolDefinitions.Directory, helpDirectoryId);
4399 break;
4400 case "HelpSubdirectory":
4401 helpSubdirectory = this.Core.GetAttributeLongFilename(sourceLineNumbers, attrib, allowRelative: true);
4350 break; 4402 break;
4351 case "Hidden": 4403 case "Hidden":
4352 if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) 4404 if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib))
@@ -4394,6 +4446,8 @@ namespace WixToolset.Core
4394 language = CompilerConstants.IllegalInteger; 4446 language = CompilerConstants.IllegalInteger;
4395 } 4447 }
4396 4448
4449 helpDirectoryId = this.HandleSubdirectory(sourceLineNumbers, node, helpDirectoryId, helpSubdirectory, "HelpDirectory", "HelpSubdirectory");
4450
4397 // build up the typelib version string for the registry if the major or minor version was specified 4451 // build up the typelib version string for the registry if the major or minor version was specified
4398 string registryVersion = null; 4452 string registryVersion = null;
4399 if (CompilerConstants.IntegerNotSet != majorVersion || CompilerConstants.IntegerNotSet != minorVersion) 4453 if (CompilerConstants.IntegerNotSet != majorVersion || CompilerConstants.IntegerNotSet != minorVersion)
@@ -4488,7 +4542,7 @@ namespace WixToolset.Core
4488 Language = language, 4542 Language = language,
4489 ComponentRef = componentId, 4543 ComponentRef = componentId,
4490 Description = description, 4544 Description = description,
4491 DirectoryRef = helpDirectory, 4545 DirectoryRef = helpDirectoryId,
4492 FeatureRef = Guid.Empty.ToString("B") 4546 FeatureRef = Guid.Empty.ToString("B")
4493 }); 4547 });
4494 4548
@@ -4534,10 +4588,10 @@ namespace WixToolset.Core
4534 // HKCR\TypeLib\[ID]\[MajorVersion].[MinorVersion]\FLAGS, (Default) = [TypeLibFlags] 4588 // HKCR\TypeLib\[ID]\[MajorVersion].[MinorVersion]\FLAGS, (Default) = [TypeLibFlags]
4535 this.Core.CreateRegistryRow(sourceLineNumbers, RegistryRootType.ClassesRoot, String.Format(CultureInfo.InvariantCulture, @"TypeLib\{0}\{1}\FLAGS", id, registryVersion), null, flags.ToString(CultureInfo.InvariantCulture.NumberFormat), componentId); 4589 this.Core.CreateRegistryRow(sourceLineNumbers, RegistryRootType.ClassesRoot, String.Format(CultureInfo.InvariantCulture, @"TypeLib\{0}\{1}\FLAGS", id, registryVersion), null, flags.ToString(CultureInfo.InvariantCulture.NumberFormat), componentId);
4536 4590
4537 if (null != helpDirectory) 4591 if (null != helpDirectoryId)
4538 { 4592 {
4539 // HKCR\TypeLib\[ID]\[MajorVersion].[MinorVersion]\HELPDIR, (Default) = [HelpDirectory] 4593 // HKCR\TypeLib\[ID]\[MajorVersion].[MinorVersion]\HELPDIR, (Default) = [HelpDirectory]
4540 this.Core.CreateRegistryRow(sourceLineNumbers, RegistryRootType.ClassesRoot, String.Format(CultureInfo.InvariantCulture, @"TypeLib\{0}\{1}\HELPDIR", id, registryVersion), null, String.Concat("[", helpDirectory, "]"), componentId); 4594 this.Core.CreateRegistryRow(sourceLineNumbers, RegistryRootType.ClassesRoot, String.Format(CultureInfo.InvariantCulture, @"TypeLib\{0}\{1}\HELPDIR", id, registryVersion), null, String.Concat("[", helpDirectoryId, "]"), componentId);
4541 } 4595 }
4542 } 4596 }
4543 } 4597 }
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
18 18
19 internal class ParseHelper : IParseHelper 19 internal class ParseHelper : IParseHelper
20 { 20 {
21 private static readonly char[] InlineDirectorySeparators = new char[] { ':', '\\', '/' };
22
23 public ParseHelper(IServiceProvider serviceProvider) 21 public ParseHelper(IServiceProvider serviceProvider)
24 { 22 {
25 this.ServiceProvider = serviceProvider; 23 this.ServiceProvider = serviceProvider;
@@ -56,12 +54,9 @@ namespace WixToolset.Core.ExtensibilityServices
56 54
57 public Identifier CreateDirectorySymbol(IntermediateSection section, SourceLineNumber sourceLineNumbers, Identifier id, string parentId, string name, string shortName = null, string sourceName = null, string shortSourceName = null) 55 public Identifier CreateDirectorySymbol(IntermediateSection section, SourceLineNumber sourceLineNumbers, Identifier id, string parentId, string name, string shortName = null, string sourceName = null, string shortSourceName = null)
58 { 56 {
59 // For anonymous directories, create the identifier. If this identifier already exists in the
60 // active section, bail so we don't add duplicate anonymous directory symbols (which are legal
61 // but bloat the intermediate and ultimately make the linker do "busy work").
62 if (null == id) 57 if (null == id)
63 { 58 {
64 id = this.CreateIdentifier("dir", parentId, name, shortName, sourceName, shortSourceName); 59 id = this.CreateIdentifier("d", parentId, name, shortName, sourceName, shortSourceName);
65 } 60 }
66 61
67 var symbol = section.AddSymbol(new DirectorySymbol(sourceLineNumbers, id) 62 var symbol = section.AddSymbol(new DirectorySymbol(sourceLineNumbers, id)
@@ -78,28 +73,37 @@ namespace WixToolset.Core.ExtensibilityServices
78 73
79 public string CreateDirectoryReferenceFromInlineSyntax(IntermediateSection section, SourceLineNumber sourceLineNumbers, XAttribute attribute, string parentId, string inlineSyntax, IDictionary<string, string> sectionCachedInlinedDirectoryIds) 74 public string CreateDirectoryReferenceFromInlineSyntax(IntermediateSection section, SourceLineNumber sourceLineNumbers, XAttribute attribute, string parentId, string inlineSyntax, IDictionary<string, string> sectionCachedInlinedDirectoryIds)
80 { 75 {
81 if (String.IsNullOrEmpty(inlineSyntax)) 76 if (String.IsNullOrEmpty(parentId))
82 { 77 {
83 inlineSyntax = attribute.Value; 78 throw new ArgumentNullException(nameof(parentId));
84 } 79 }
85 80
86 // If no separator is found, the string is a simple reference. 81 if (String.IsNullOrEmpty(inlineSyntax))
87 var separatorFound = inlineSyntax.IndexOfAny(InlineDirectorySeparators);
88 if (separatorFound == -1)
89 { 82 {
90 this.CreateSimpleReference(section, sourceLineNumbers, SymbolDefinitions.Directory, inlineSyntax); 83 inlineSyntax = this.GetAttributeLongFilename(sourceLineNumbers, attribute, false, true);
91 return inlineSyntax;
92 } 84 }
93 85
94 // If a parent id was provided and the inline syntax does not start with a directory reference, prepend the parent id. 86 if (String.IsNullOrEmpty(inlineSyntax))
95 if (!String.IsNullOrEmpty(parentId) && inlineSyntax[separatorFound] != ':')
96 { 87 {
97 inlineSyntax = String.Concat(parentId, ":", inlineSyntax); 88 return parentId;
98 } 89 }
99 90
100 inlineSyntax = inlineSyntax.TrimEnd('\\', '/'); 91 inlineSyntax = inlineSyntax.Trim('\\', '/');
92
93 var cacheKey = String.Concat(parentId, ":", inlineSyntax);
94
95 if (!sectionCachedInlinedDirectoryIds.TryGetValue(cacheKey, out var id))
96 {
97 var identifier = this.CreateDirectorySymbol(section, sourceLineNumbers, id: null, parentId, inlineSyntax);
98
99 id = identifier.Id;
100 }
101 else
102 {
103 this.CreateSimpleReference(section, sourceLineNumbers, SymbolDefinitions.Directory, id);
104 }
101 105
102 return this.ParseInlineSyntax(section, sourceLineNumbers, attribute, inlineSyntax, sectionCachedInlinedDirectoryIds); 106 return id; //this.ParseInlineSyntax(section, sourceLineNumbers, attribute, inlineSyntax, sectionCachedInlinedDirectoryIds);
103 } 107 }
104 108
105 public string CreateGuid(Guid namespaceGuid, string value) 109 public string CreateGuid(Guid namespaceGuid, string value)
@@ -444,7 +448,7 @@ namespace WixToolset.Core.ExtensibilityServices
444 448
445 var value = this.GetAttributeValue(sourceLineNumbers, attribute); 449 var value = this.GetAttributeValue(sourceLineNumbers, attribute);
446 450
447 if (0 < value.Length) 451 if (!String.IsNullOrEmpty(value))
448 { 452 {
449 if (!this.IsValidLongFilename(value, allowWildcards, allowRelative) && !this.IsValidLocIdentifier(value)) 453 if (!this.IsValidLongFilename(value, allowWildcards, allowRelative) && !this.IsValidLocIdentifier(value))
450 { 454 {
@@ -840,90 +844,6 @@ namespace WixToolset.Core.ExtensibilityServices
840 this.Creator = this.ServiceProvider.GetService<ISymbolDefinitionCreator>(); 844 this.Creator = this.ServiceProvider.GetService<ISymbolDefinitionCreator>();
841 } 845 }
842 846
843 private string ParseInlineSyntax(IntermediateSection section, SourceLineNumber sourceLineNumbers, XAttribute attribute, string inlineSyntax, IDictionary<string, string> sectionCachedInlinedDirectoryIds)
844 {
845 if (!sectionCachedInlinedDirectoryIds.TryGetValue(inlineSyntax, out var id))
846 {
847 string parentId;
848 int nameIndex;
849
850 var separatorIndex = inlineSyntax.LastIndexOfAny(InlineDirectorySeparators);
851 if (separatorIndex == -1)
852 {
853 nameIndex = 0;
854 parentId = "TARGETDIR";
855 }
856 else if (inlineSyntax[separatorIndex] == '\\' || inlineSyntax[separatorIndex] == '/')
857 {
858 nameIndex = separatorIndex + 1;
859
860 if (separatorIndex == 0)
861 {
862 parentId = "TARGETDIR";
863 }
864 else if (inlineSyntax[separatorIndex - 1] == ':')
865 {
866 parentId = this.ParseParentReference(section, sourceLineNumbers, attribute, inlineSyntax, separatorIndex - 1);
867 }
868 else
869 {
870 var parentInlineDirectory = inlineSyntax.Substring(0, separatorIndex);
871 parentId = this.ParseInlineSyntax(section, sourceLineNumbers, attribute, parentInlineDirectory.TrimEnd('\\', '/'), sectionCachedInlinedDirectoryIds);
872 }
873 }
874 else
875 {
876 nameIndex = separatorIndex + 1;
877 parentId = this.ParseParentReference(section, sourceLineNumbers, attribute, inlineSyntax, separatorIndex);
878 }
879
880 if (nameIndex == inlineSyntax.Length)
881 {
882 id = parentId;
883 }
884 else
885 {
886 var name = nameIndex != -1 ? inlineSyntax.Substring(nameIndex) : null;
887
888 if (!this.IsValidLongFilename(name, false, false))
889 {
890 this.Messaging.Write(ErrorMessages.IllegalLongFilename(sourceLineNumbers, attribute.Parent.Name.LocalName, attribute.Name.LocalName, attribute.Value, name));
891 return null;
892 }
893
894 var identifier = this.CreateDirectorySymbol(section, sourceLineNumbers, null, parentId, name);
895
896 id = identifier.Id;
897 }
898
899 sectionCachedInlinedDirectoryIds.Add(inlineSyntax, id);
900 }
901
902 return id;
903 }
904
905 private string ParseParentReference(IntermediateSection section, SourceLineNumber sourceLineNumbers, XAttribute attribute, string reference, int colonIndex)
906 {
907 if (colonIndex == 0)
908 {
909 this.Messaging.Write(ErrorMessages.IllegalIdentifier(sourceLineNumbers, attribute.Parent.Name.LocalName, attribute.Name.LocalName, attribute.Value, String.Empty));
910 return null;
911 }
912 else
913 {
914 var parentId = reference.Substring(0, colonIndex);
915
916 if (!Common.IsIdentifier(parentId))
917 {
918 this.Messaging.Write(ErrorMessages.IllegalIdentifier(sourceLineNumbers, attribute.Parent.Name.LocalName, attribute.Name.LocalName, attribute.Value, parentId));
919 return null;
920 }
921
922 this.CreateSimpleReference(section, sourceLineNumbers, SymbolDefinitions.Directory, parentId);
923 return parentId;
924 }
925 }
926
927 private static bool TryFindExtension(IEnumerable<ICompilerExtension> extensions, XNamespace ns, out ICompilerExtension extension) 847 private static bool TryFindExtension(IEnumerable<ICompilerExtension> extensions, XNamespace ns, out ICompilerExtension extension)
928 { 848 {
929 extension = null; 849 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
587 { 587 {
588 var removeSymbols = new List<IntermediateSymbol>(); 588 var removeSymbols = new List<IntermediateSymbol>();
589 589
590 // Count down because we'll sometimes remove items from the list.
591 foreach (var symbol in section.Symbols) 590 foreach (var symbol in section.Symbols)
592 { 591 {
593 // Only process the "grouping parents" such as FeatureGroup, ComponentGroup, Feature, 592 // 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
7 using WixBuildTools.TestSupport; 7 using WixBuildTools.TestSupport;
8 using WixToolset.Core.TestPackage; 8 using WixToolset.Core.TestPackage;
9 using WixToolset.Data; 9 using WixToolset.Data;
10 using WixToolset.Data.WindowsInstaller;
10 using Xunit; 11 using Xunit;
11 12
12 public class DirectoryFixture 13 public class DirectoryFixture
@@ -40,11 +41,11 @@ namespace WixToolsetTest.CoreIntegration
40 var dirSymbols = section.Symbols.OfType<WixToolset.Data.Symbols.DirectorySymbol>().ToList(); 41 var dirSymbols = section.Symbols.OfType<WixToolset.Data.Symbols.DirectorySymbol>().ToList();
41 Assert.Equal(new[] 42 Assert.Equal(new[]
42 { 43 {
43 "INSTALLFOLDER", 44 "INSTALLFOLDER:ProgramFiles6432Folder:MsiPackage",
44 "ProgramFiles6432Folder", 45 "ProgramFiles6432Folder:ProgramFilesFolder:.",
45 "ProgramFilesFolder", 46 "ProgramFilesFolder:TARGETDIR:PFiles",
46 "TARGETDIR" 47 "TARGETDIR::SourceDir"
47 }, dirSymbols.Select(d => d.Id.Id).ToArray()); 48 }, dirSymbols.OrderBy(d => d.Id.Id).Select(d => d.Id.Id + ":" + d.ParentDirectoryRef + ":" + d.Name).ToArray());
48 } 49 }
49 } 50 }
50 51
@@ -78,11 +79,11 @@ namespace WixToolsetTest.CoreIntegration
78 var dirSymbols = section.Symbols.OfType<WixToolset.Data.Symbols.DirectorySymbol>().ToList(); 79 var dirSymbols = section.Symbols.OfType<WixToolset.Data.Symbols.DirectorySymbol>().ToList();
79 Assert.Equal(new[] 80 Assert.Equal(new[]
80 { 81 {
81 "INSTALLFOLDER", 82 "INSTALLFOLDER:ProgramFiles6432Folder:MsiPackage",
82 "ProgramFiles6432Folder", 83 "ProgramFiles6432Folder:ProgramFiles64Folder:.",
83 "ProgramFiles64Folder", 84 "ProgramFiles64Folder:TARGETDIR:PFiles64",
84 "TARGETDIR" 85 "TARGETDIR::SourceDir"
85 }, dirSymbols.Select(d => d.Id.Id).ToArray()); 86 }, dirSymbols.OrderBy(d => d.Id.Id).Select(d => d.Id.Id + ":" + d.ParentDirectoryRef + ":" + d.Name).ToArray());
86 } 87 }
87 } 88 }
88 89
@@ -116,12 +117,14 @@ namespace WixToolsetTest.CoreIntegration
116 var dirSymbols = section.Symbols.OfType<WixToolset.Data.Symbols.DirectorySymbol>().ToList(); 117 var dirSymbols = section.Symbols.OfType<WixToolset.Data.Symbols.DirectorySymbol>().ToList();
117 Assert.Equal(new[] 118 Assert.Equal(new[]
118 { 119 {
119 "dirZsSsu81KcG46xXTwc4mTSZO5Zx4", 120 "dZsSsu81KcG46xXTwc4mTSZO5Zx4:INSTALLFOLDER:dupe",
120 "INSTALLFOLDER", 121 "INSTALLFOLDER:ProgramFiles6432Folder:MsiPackage",
121 "ProgramFiles6432Folder", 122 "ProgramFiles6432Folder:ProgramFiles64Folder:.",
122 "ProgramFiles64Folder", 123 "ProgramFiles64Folder:TARGETDIR:PFiles64",
123 "TARGETDIR" 124 "TARGETDIR::SourceDir"
124 }, dirSymbols.Select(d => d.Id.Id).ToArray()); 125 }, dirSymbols.OrderBy(d => d.Id.Id).Select(d => d.Id.Id + ":" + d.ParentDirectoryRef + ":" + d.Name).ToArray());
126 }
127 }
125 } 128 }
126 } 129 }
127 } 130 }
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
53 53
54 Assert.True(File.Exists(Path.Combine(intermediateFolder, @"bin\extest.msi"))); 54 Assert.True(File.Exists(Path.Combine(intermediateFolder, @"bin\extest.msi")));
55 Assert.True(File.Exists(Path.Combine(intermediateFolder, @"bin\extest.wixpdb"))); 55 Assert.True(File.Exists(Path.Combine(intermediateFolder, @"bin\extest.wixpdb")));
56 Assert.True(File.Exists(Path.Combine(intermediateFolder, @"bin\MsiPackage\example.txt"))); 56 Assert.True(File.Exists(Path.Combine(intermediateFolder, @"bin\PFiles\MsiPackage\example.txt")));
57 57
58 var intermediate = Intermediate.Load(Path.Combine(intermediateFolder, @"bin\extest.wixpdb")); 58 var intermediate = Intermediate.Load(Path.Combine(intermediateFolder, @"bin\extest.wixpdb"));
59 var section = intermediate.Sections.Single(); 59 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
8 using WixToolset.Core.TestPackage; 8 using WixToolset.Core.TestPackage;
9 using WixToolset.Data; 9 using WixToolset.Data;
10 using WixToolset.Data.Symbols; 10 using WixToolset.Data.Symbols;
11 using WixToolset.Data.WindowsInstaller;
11 using Xunit; 12 using Xunit;
12 13
13 public class LanguageFixture 14 public class LanguageFixture
@@ -36,6 +37,14 @@ namespace WixToolsetTest.CoreIntegration
36 var intermediate = Intermediate.Load(Path.Combine(baseFolder, @"bin\test.wixpdb")); 37 var intermediate = Intermediate.Load(Path.Combine(baseFolder, @"bin\test.wixpdb"));
37 var section = intermediate.Sections.Single(); 38 var section = intermediate.Sections.Single();
38 39
40 var directorySymbols = section.Symbols.OfType<DirectorySymbol>();
41 Assert.Equal(new[]
42 {
43 "INSTALLFOLDER:Example Corporation\\MsiPackage",
44 "ProgramFilesFolder:PFiles",
45 "TARGETDIR:SourceDir"
46 }, directorySymbols.OrderBy(s => s.Id.Id).Select(s => s.Id.Id + ":" + s.Name).ToArray());
47
39 var propertySymbol = section.Symbols.OfType<PropertySymbol>().Single(p => p.Id.Id == "ProductLanguage"); 48 var propertySymbol = section.Symbols.OfType<PropertySymbol>().Single(p => p.Id.Id == "ProductLanguage");
40 Assert.Equal("0", propertySymbol.Value); 49 Assert.Equal("0", propertySymbol.Value);
41 50
@@ -44,6 +53,16 @@ namespace WixToolsetTest.CoreIntegration
44 53
45 var summaryCodepage = section.Symbols.OfType<SummaryInformationSymbol>().Single(s => s.PropertyId == SummaryInformationType.Codepage); 54 var summaryCodepage = section.Symbols.OfType<SummaryInformationSymbol>().Single(s => s.PropertyId == SummaryInformationType.Codepage);
46 Assert.Equal("1252", summaryCodepage.Value); 55 Assert.Equal("1252", summaryCodepage.Value);
56
57 var data = WindowsInstallerData.Load(Path.Combine(baseFolder, @"bin\test.wixpdb"));
58 var directoryRows = data.Tables["Directory"].Rows;
59 Assert.Equal(new[]
60 {
61 "d4EceYatXTyy8HXPt5B6DT9Rj.wE:u7-b4gch|Example Corporation",
62 "INSTALLFOLDER:oekcr5lq|MsiPackage",
63 "ProgramFilesFolder:PFiles",
64 "TARGETDIR:SourceDir"
65 }, directoryRows.Select(r => r.FieldAsString(0) + ":" + r.FieldAsString(2)).ToArray());
47 } 66 }
48 } 67 }
49 68
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
68 68
69 Assert.True(File.Exists(Path.Combine(baseFolder, @"bin\test.msi"))); 69 Assert.True(File.Exists(Path.Combine(baseFolder, @"bin\test.msi")));
70 Assert.True(File.Exists(Path.Combine(baseFolder, @"bin\test.wixpdb"))); 70 Assert.True(File.Exists(Path.Combine(baseFolder, @"bin\test.wixpdb")));
71 Assert.True(File.Exists(Path.Combine(baseFolder, @"bin\MsiPackage\test.txt"))); 71 Assert.True(File.Exists(Path.Combine(baseFolder, @"bin\PFiles\MsiPackage\test.txt")));
72 72
73 var intermediate = Intermediate.Load(Path.Combine(baseFolder, @"bin\test.wixpdb")); 73 var intermediate = Intermediate.Load(Path.Combine(baseFolder, @"bin\test.wixpdb"));
74 var section = intermediate.Sections.Single(); 74 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
40 40
41 Assert.True(File.Exists(Path.Combine(baseFolder, @"bin\test.msi"))); 41 Assert.True(File.Exists(Path.Combine(baseFolder, @"bin\test.msi")));
42 Assert.True(File.Exists(Path.Combine(baseFolder, @"bin\test.wixpdb"))); 42 Assert.True(File.Exists(Path.Combine(baseFolder, @"bin\test.wixpdb")));
43 Assert.True(File.Exists(Path.Combine(baseFolder, @"bin\MsiPackage\test.txt"))); 43 Assert.True(File.Exists(Path.Combine(baseFolder, @"bin\PFiles\MsiPackage\test.txt")));
44 44
45 var intermediate = Intermediate.Load(Path.Combine(baseFolder, @"bin\test.wixpdb")); 45 var intermediate = Intermediate.Load(Path.Combine(baseFolder, @"bin\test.wixpdb"));
46 46
@@ -240,7 +240,7 @@ namespace WixToolsetTest.CoreIntegration
240 240
241 Assert.True(File.Exists(Path.Combine(baseFolder, @"bin\test.msi"))); 241 Assert.True(File.Exists(Path.Combine(baseFolder, @"bin\test.msi")));
242 Assert.True(File.Exists(Path.Combine(baseFolder, @"bin\test.wixpdb"))); 242 Assert.True(File.Exists(Path.Combine(baseFolder, @"bin\test.wixpdb")));
243 Assert.True(File.Exists(Path.Combine(baseFolder, @"bin\MsiPackage\test.txt"))); 243 Assert.True(File.Exists(Path.Combine(baseFolder, @"bin\PFiles\MsiPackage\test.txt")));
244 244
245 var intermediate = Intermediate.Load(Path.Combine(baseFolder, @"bin\test.wixpdb")); 245 var intermediate = Intermediate.Load(Path.Combine(baseFolder, @"bin\test.wixpdb"));
246 var section = intermediate.Sections.Single(); 246 var section = intermediate.Sections.Single();
@@ -351,7 +351,7 @@ namespace WixToolsetTest.CoreIntegration
351 var pdbPath = Path.Combine(intermediateFolder, @"bin\test.wixpdb"); 351 var pdbPath = Path.Combine(intermediateFolder, @"bin\test.wixpdb");
352 Assert.True(File.Exists(Path.Combine(intermediateFolder, @"bin\test.msi"))); 352 Assert.True(File.Exists(Path.Combine(intermediateFolder, @"bin\test.msi")));
353 Assert.True(File.Exists(pdbPath)); 353 Assert.True(File.Exists(pdbPath));
354 Assert.True(File.Exists(Path.Combine(intermediateFolder, @"bin\MsiPackage\test.txt"))); 354 Assert.True(File.Exists(Path.Combine(intermediateFolder, @"bin\PFiles\MsiPackage\test.txt")));
355 355
356 var intermediate = Intermediate.Load(pdbPath); 356 var intermediate = Intermediate.Load(pdbPath);
357 var section = intermediate.Sections.Single(); 357 var section = intermediate.Sections.Single();
@@ -527,7 +527,7 @@ namespace WixToolsetTest.CoreIntegration
527 527
528 Assert.True(File.Exists(Path.Combine(baseFolder, @"bin\test.msi"))); 528 Assert.True(File.Exists(Path.Combine(baseFolder, @"bin\test.msi")));
529 Assert.True(File.Exists(Path.Combine(baseFolder, @"bin\test.wixpdb"))); 529 Assert.True(File.Exists(Path.Combine(baseFolder, @"bin\test.wixpdb")));
530 Assert.True(File.Exists(Path.Combine(baseFolder, @"bin\MsiPackage\test.txt"))); 530 Assert.True(File.Exists(Path.Combine(baseFolder, @"bin\PFiles\MsiPackage\test.txt")));
531 531
532 var intermediate = Intermediate.Load(Path.Combine(baseFolder, @"bin\test.wixpdb")); 532 var intermediate = Intermediate.Load(Path.Combine(baseFolder, @"bin\test.wixpdb"));
533 var section = intermediate.Sections.Single(); 533 var section = intermediate.Sections.Single();
@@ -563,7 +563,7 @@ namespace WixToolsetTest.CoreIntegration
563 563
564 Assert.True(File.Exists(Path.Combine(baseFolder, @"bin\test.msi"))); 564 Assert.True(File.Exists(Path.Combine(baseFolder, @"bin\test.msi")));
565 Assert.True(File.Exists(Path.Combine(baseFolder, @"bin\test.wixpdb"))); 565 Assert.True(File.Exists(Path.Combine(baseFolder, @"bin\test.wixpdb")));
566 Assert.True(File.Exists(Path.Combine(baseFolder, @"bin\AssemblyMsiPackage\candle.exe"))); 566 Assert.True(File.Exists(Path.Combine(baseFolder, @"bin\PFiles\AssemblyMsiPackage\candle.exe")));
567 567
568 var intermediate = Intermediate.Load(Path.Combine(baseFolder, @"bin\test.wixpdb")); 568 var intermediate = Intermediate.Load(Path.Combine(baseFolder, @"bin\test.wixpdb"));
569 var section = intermediate.Sections.Single(); 569 var section = intermediate.Sections.Single();
@@ -721,7 +721,7 @@ namespace WixToolsetTest.CoreIntegration
721 721
722 Assert.True(File.Exists(Path.Combine(baseFolder, @"bin\test.msi"))); 722 Assert.True(File.Exists(Path.Combine(baseFolder, @"bin\test.msi")));
723 Assert.True(File.Exists(Path.Combine(baseFolder, @"bin\test.wixpdb"))); 723 Assert.True(File.Exists(Path.Combine(baseFolder, @"bin\test.wixpdb")));
724 Assert.True(File.Exists(Path.Combine(baseFolder, @"bin\MsiPackage\Foo.exe"))); 724 Assert.True(File.Exists(Path.Combine(baseFolder, @"bin\PFiles\MsiPackage\Foo.exe")));
725 725
726 var intermediate = Intermediate.Load(Path.Combine(baseFolder, @"bin\test.wixpdb")); 726 var intermediate = Intermediate.Load(Path.Combine(baseFolder, @"bin\test.wixpdb"));
727 var section = intermediate.Sections.Single(); 727 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 @@
10 </Fragment> 10 </Fragment>
11 11
12 <Fragment> 12 <Fragment>
13 <Directory Id="OtherFolder" Name="INSTALLFOLDER:\other" /> 13 <DirectoryRef Id="INSTALLFOLDER">
14 <Directory Id="OtherFolder" Name="other" />
15 </DirectoryRef>
14 </Fragment> 16 </Fragment>
15</Wix> 17</Wix>
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 @@
8 </Fragment> 8 </Fragment>
9 9
10 <Fragment> 10 <Fragment>
11 <ComponentGroup Id="GroupA" Directory="INSTALLFOLDER:\dupe"> 11 <ComponentGroup Id="GroupA" Directory="INSTALLFOLDER" Subdirectory="dupe">
12 <Component> 12 <Component>
13 <File Name="a.txt" Source="test.txt" /> 13 <File Name="a.txt" Source="test.txt" />
14 </Component> 14 </Component>
@@ -16,7 +16,7 @@
16 </Fragment> 16 </Fragment>
17 17
18 <Fragment> 18 <Fragment>
19 <ComponentGroup Id="GroupB" Directory="INSTALLFOLDER:\dupe"> 19 <ComponentGroup Id="GroupB" Directory="INSTALLFOLDER" Subdirectory="dupe">
20 <Component> 20 <Component>
21 <File Name="b.txt" Source="test.txt" /> 21 <File Name="b.txt" Source="test.txt" />
22 </Component> 22 </Component>
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 @@
11 </Package> 11 </Package>
12 12
13 <Fragment> 13 <Fragment>
14 <Directory Id="INSTALLFOLDER" Name="ProgramFilesFolder:\MsiPackage" /> 14 <DirectoryRef Id="ProgramFilesFolder">
15 <Directory Id="INSTALLFOLDER" Name="MsiPackage" />
16 </DirectoryRef>
15 </Fragment> 17 </Fragment>
16</Wix> 18</Wix>
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 @@
8 <Media Id="2" Cabinet="cab2.cab" /> 8 <Media Id="2" Cabinet="cab2.cab" />
9 9
10 <Feature Id="ProductFeature" Title="MsiPackageTitle"> 10 <Feature Id="ProductFeature" Title="MsiPackageTitle">
11 <Component Directory="ProgramFilesFolder:\~MultiMedia" DiskId="1"> 11 <Component Directory="ProgramFilesFolder" Subdirectory="~MultiMedia" DiskId="1">
12 <File Source="a1.txt" /> 12 <File Source="a1.txt" />
13 </Component> 13 </Component>
14 14
15 <Component Directory="ProgramFilesFolder:\~MultiMedia" DiskId="1"> 15 <Component Directory="ProgramFilesFolder" Subdirectory="~MultiMedia" DiskId="1">
16 <File Source="a2.txt" /> 16 <File Source="a2.txt" />
17 </Component> 17 </Component>
18 18
19 <Component Directory="ProgramFilesFolder:\~MultiMedia" DiskId="2"> 19 <Component Directory="ProgramFilesFolder" Subdirectory="~MultiMedia" DiskId="2">
20 <File Source="b2.txt" /> 20 <File Source="b2.txt" />
21 </Component> 21 </Component>
22 22
23 <Component Directory="ProgramFilesFolder:\~MultiMedia" DiskId="2"> 23 <Component Directory="ProgramFilesFolder" Subdirectory="~MultiMedia" DiskId="2">
24 <File Source="b1.txt" /> 24 <File Source="b1.txt" />
25 </Component> 25 </Component>
26 </Feature> 26 </Feature>
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 @@
4 <MajorUpgrade DowngradeErrorMessage="Newer version already installed." /> 4 <MajorUpgrade DowngradeErrorMessage="Newer version already installed." />
5 <MediaTemplate EmbedCab="yes" /> 5 <MediaTemplate EmbedCab="yes" />
6 6
7 <Directory Id="INSTALLFOLDER" Name="ProgramFilesFolder:\~Test App" /> 7 <DirectoryRef Id="ProgramFilesFolder">
8 <Directory Id="INSTALLFOLDER" Name="~Test App" />
9 </DirectoryRef>
8 10
9 <Feature Id="Main"> 11 <Feature Id="Main">
10 <ComponentGroupRef Id="Components" /> 12 <ComponentGroupRef Id="Components" />
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 @@
1<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"> 1<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
2 <Package Name="MsiPackage" Codepage="1252" Language="1033" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="12E4699F-E774-4D05-8A01-5BDD41BBA127" Compressed="no" Scope="perMachine" ProductCode="83f9c623-26fe-42ab-951e-170022117f54"> 2 <Package Name="MsiPackage" Codepage="1252" Language="1033" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="12E4699F-E774-4D05-8A01-5BDD41BBA127" Compressed="no" Scope="perMachine" ProductCode="83f9c623-26fe-42ab-951e-170022117f54">
3 3
4 <MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." /> 4 <MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
@@ -9,6 +9,8 @@
9 </Package> 9 </Package>
10 10
11 <Fragment> 11 <Fragment>
12 <Directory Id="INSTALLFOLDER" Name="ProgramFiles6432Folder:\MsiPackage" /> 12 <DirectoryRef Id="ProgramFiles6432Folder">
13 <Directory Id="INSTALLFOLDER" Name="MsiPackage" />
14 </DirectoryRef>
13 </Fragment> 15 </Fragment>
14</Wix> 16</Wix>
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 @@
1<?xml version="1.0" encoding="utf-8"?> 1<?xml version="1.0" encoding="utf-8"?>
2<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"> 2<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
3 <Fragment> 3 <Fragment>
4 <ComponentGroup Id="ProductComponents"> 4 <ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER">
5 <Component Directory="INSTALLFOLDER:\a"> 5 <Component Subdirectory="a">
6 <File Source="a\test.txt" /> 6 <File Source="a\test.txt" />
7 </Component> 7 </Component>
8 <Component Directory="INSTALLFOLDER:\b"> 8 <Component Subdirectory="b">
9 <File Source="b\test.txt" /> 9 <File Source="b\test.txt" />
10 </Component> 10 </Component>
11 <Component Directory="INSTALLFOLDER:\c"> 11 <Component Subdirectory="c">
12 <File Source="c\test.txt" /> 12 <File Source="c\test.txt" />
13 </Component> 13 </Component>
14 </ComponentGroup> 14 </ComponentGroup>
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 @@
9 </Package> 9 </Package>
10 10
11 <Fragment> 11 <Fragment>
12 <Directory Id="INSTALLFOLDER" Name="ProgramFilesFolder:\MsiPackage" /> 12 <DirectoryRef Id="ProgramFilesFolder">
13 <Directory Id="INSTALLFOLDER" Name="MsiPackage" />
14 </DirectoryRef>
13 </Fragment> 15 </Fragment>
14</Wix> 16</Wix>