diff options
author | Rob Mensching <rob@firegiant.com> | 2022-11-15 15:47:48 -0800 |
---|---|---|
committer | Rob Mensching <rob@firegiant.com> | 2022-11-15 22:04:07 -0800 |
commit | d14c02d4ca6ee820b7111b789d9f904e0fd52804 (patch) | |
tree | 012cf555619080c80a8688ad44257bd5e9d7a90b /src | |
parent | 266aed497296cdb087eac157c575e95253ed67ca (diff) | |
download | wix-d14c02d4ca6ee820b7111b789d9f904e0fd52804.tar.gz wix-d14c02d4ca6ee820b7111b789d9f904e0fd52804.tar.bz2 wix-d14c02d4ca6ee820b7111b789d9f904e0fd52804.zip |
Fix when xmlns placed directly on PermissionEx
This is NOT recommended in v4 and its converter will move namespaces to
the root element, but WiX v3 allowed it so we'll continued to do so in
v4.
Fixes 7010
Diffstat (limited to 'src')
4 files changed, 237 insertions, 18 deletions
diff --git a/src/ext/Util/test/WixToolsetTest.Util/TestData/PermissionEx/PackageComponents.wxs b/src/ext/Util/test/WixToolsetTest.Util/TestData/PermissionEx/PackageComponents.wxs index 0634d7d4..09f0a724 100644 --- a/src/ext/Util/test/WixToolsetTest.Util/TestData/PermissionEx/PackageComponents.wxs +++ b/src/ext/Util/test/WixToolsetTest.Util/TestData/PermissionEx/PackageComponents.wxs | |||
@@ -1,4 +1,4 @@ | |||
1 | <Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:util="http://wixtoolset.org/schemas/v4/wxs/util"> | 1 | <Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:util="http://wixtoolset.org/schemas/v4/wxs/util"> |
2 | <Fragment> | 2 | <Fragment> |
3 | <ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER"> | 3 | <ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER"> |
4 | <Component> | 4 | <Component> |
@@ -15,7 +15,12 @@ | |||
15 | <util:PermissionEx User="Everyone" GenericAll="yes" /> | 15 | <util:PermissionEx User="Everyone" GenericAll="yes" /> |
16 | </RegistryKey> | 16 | </RegistryKey> |
17 | <RegistryValue Root="HKLM" Key="TestRegistryValueKey" Value="abc"> | 17 | <RegistryValue Root="HKLM" Key="TestRegistryValueKey" Value="abc"> |
18 | <util:PermissionEx User="Everyone" GenericAll="yes" /> | 18 | <!-- |
19 | Example of placing the namespace on the extension element. This is NOT recommended | ||
20 | in v4 and its converter will move namespaces to the root, but WiX v3 allowed it so | ||
21 | we'll continued to do so for now. | ||
22 | --> | ||
23 | <PermissionEx User="Everyone" GenericAll="yes" xmlns="http://wixtoolset.org/schemas/v4/wxs/util" /> | ||
19 | </RegistryValue> | 24 | </RegistryValue> |
20 | </Component> | 25 | </Component> |
21 | </ComponentGroup> | 26 | </ComponentGroup> |
diff --git a/src/ext/Util/wixext/UtilCompiler.cs b/src/ext/Util/wixext/UtilCompiler.cs index 47f82ca6..96b2ee0a 100644 --- a/src/ext/Util/wixext/UtilCompiler.cs +++ b/src/ext/Util/wixext/UtilCompiler.cs | |||
@@ -1286,6 +1286,8 @@ namespace WixToolset.Util | |||
1286 | var bits = new BitArray(32); | 1286 | var bits = new BitArray(32); |
1287 | string user = null; | 1287 | string user = null; |
1288 | 1288 | ||
1289 | var validBitNames = new HashSet<string>(UtilConstants.StandardPermissions.Concat(UtilConstants.GenericPermissions).Concat(UtilConstants.FolderPermissions)); | ||
1290 | |||
1289 | foreach (var attrib in element.Attributes()) | 1291 | foreach (var attrib in element.Attributes()) |
1290 | { | 1292 | { |
1291 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) | 1293 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) |
@@ -1297,18 +1299,18 @@ namespace WixToolset.Util | |||
1297 | this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, UtilSymbolDefinitions.User, user); | 1299 | this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, UtilSymbolDefinitions.User, user); |
1298 | break; | 1300 | break; |
1299 | default: | 1301 | default: |
1300 | var attribValue = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib); | 1302 | if (validBitNames.Contains(attrib.Name.LocalName)) |
1301 | if (!this.TrySetBitFromName(UtilConstants.StandardPermissions, attrib.Name.LocalName, attribValue, bits, 16)) | ||
1302 | { | 1303 | { |
1303 | if (!this.TrySetBitFromName(UtilConstants.GenericPermissions, attrib.Name.LocalName, attribValue, bits, 28)) | 1304 | var attribValue = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib); |
1305 | if (this.TrySetBitFromName(UtilConstants.StandardPermissions, attrib.Name.LocalName, attribValue, bits, 16) || | ||
1306 | this.TrySetBitFromName(UtilConstants.GenericPermissions, attrib.Name.LocalName, attribValue, bits, 28) || | ||
1307 | this.TrySetBitFromName(UtilConstants.FolderPermissions, attrib.Name.LocalName, attribValue, bits, 0)) | ||
1304 | { | 1308 | { |
1305 | if (!this.TrySetBitFromName(UtilConstants.FolderPermissions, attrib.Name.LocalName, attribValue, bits, 0)) | 1309 | break; |
1306 | { | ||
1307 | this.ParseHelper.UnexpectedAttribute(element, attrib); | ||
1308 | break; | ||
1309 | } | ||
1310 | } | 1310 | } |
1311 | } | 1311 | } |
1312 | |||
1313 | this.ParseHelper.UnexpectedAttribute(element, attrib); | ||
1312 | break; | 1314 | break; |
1313 | } | 1315 | } |
1314 | } | 1316 | } |
@@ -2477,6 +2479,8 @@ namespace WixToolset.Util | |||
2477 | break; | 2479 | break; |
2478 | } | 2480 | } |
2479 | 2481 | ||
2482 | var validBitNames = new HashSet<string>(UtilConstants.StandardPermissions.Concat(UtilConstants.GenericPermissions).Concat(specialPermissions)); | ||
2483 | |||
2480 | foreach (var attrib in element.Attributes()) | 2484 | foreach (var attrib in element.Attributes()) |
2481 | { | 2485 | { |
2482 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) | 2486 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) |
@@ -2500,18 +2504,18 @@ namespace WixToolset.Util | |||
2500 | user = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); | 2504 | user = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); |
2501 | break; | 2505 | break; |
2502 | default: | 2506 | default: |
2503 | var attribValue = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib); | 2507 | if (validBitNames.Contains(attrib.Name.LocalName)) |
2504 | if (!this.TrySetBitFromName(UtilConstants.StandardPermissions, attrib.Name.LocalName, attribValue, bits, 16)) | ||
2505 | { | 2508 | { |
2506 | if (!this.TrySetBitFromName(UtilConstants.GenericPermissions, attrib.Name.LocalName, attribValue, bits, 28)) | 2509 | var attribValue = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib); |
2510 | if (this.TrySetBitFromName(UtilConstants.StandardPermissions, attrib.Name.LocalName, attribValue, bits, 16) || | ||
2511 | this.TrySetBitFromName(UtilConstants.GenericPermissions, attrib.Name.LocalName, attribValue, bits, 28) || | ||
2512 | this.TrySetBitFromName(specialPermissions, attrib.Name.LocalName, attribValue, bits, 0)) | ||
2507 | { | 2513 | { |
2508 | if (!this.TrySetBitFromName(specialPermissions, attrib.Name.LocalName, attribValue, bits, 0)) | 2514 | break; |
2509 | { | ||
2510 | this.ParseHelper.UnexpectedAttribute(element, attrib); | ||
2511 | break; | ||
2512 | } | ||
2513 | } | 2515 | } |
2514 | } | 2516 | } |
2517 | |||
2518 | this.ParseHelper.UnexpectedAttribute(element, attrib); | ||
2515 | break; | 2519 | break; |
2516 | } | 2520 | } |
2517 | } | 2521 | } |
diff --git a/src/wix/WixToolset.Converters/WixConverter.cs b/src/wix/WixToolset.Converters/WixConverter.cs index 37b99a95..941a5062 100644 --- a/src/wix/WixToolset.Converters/WixConverter.cs +++ b/src/wix/WixToolset.Converters/WixConverter.cs | |||
@@ -402,6 +402,7 @@ namespace WixToolset.Converters | |||
402 | // Start converting the nodes at the top. | 402 | // Start converting the nodes at the top. |
403 | this.ConvertNodes(document.Nodes(), 0); | 403 | this.ConvertNodes(document.Nodes(), 0); |
404 | this.RemoveUnusedNamespaces(document.Root); | 404 | this.RemoveUnusedNamespaces(document.Root); |
405 | this.MoveNamespacesToRoot(document.Root); | ||
405 | } | 406 | } |
406 | 407 | ||
407 | private void Format(XDocument document) | 408 | private void Format(XDocument document) |
@@ -424,6 +425,7 @@ namespace WixToolset.Converters | |||
424 | // Start converting the nodes at the top. | 425 | // Start converting the nodes at the top. |
425 | this.ConvertNodes(document.Nodes(), 0); | 426 | this.ConvertNodes(document.Nodes(), 0); |
426 | this.RemoveUnusedNamespaces(document.Root); | 427 | this.RemoveUnusedNamespaces(document.Root); |
428 | this.MoveNamespacesToRoot(document.Root); | ||
427 | } | 429 | } |
428 | 430 | ||
429 | private bool TryOpenSourceFile(string sourceFile, out XDocument document) | 431 | private bool TryOpenSourceFile(string sourceFile, out XDocument document) |
@@ -2253,6 +2255,50 @@ namespace WixToolset.Converters | |||
2253 | } | 2255 | } |
2254 | } | 2256 | } |
2255 | 2257 | ||
2258 | private void MoveNamespacesToRoot(XElement root) | ||
2259 | { | ||
2260 | var rootNamespaces = new HashSet<string>(); | ||
2261 | var rootNamespacePrefixes = new HashSet<string>(); | ||
2262 | var nonRootDeclarations = new List<XAttribute>(); | ||
2263 | |||
2264 | VisitElement(root, x => | ||
2265 | { | ||
2266 | if (x is XAttribute a && a.IsNamespaceDeclaration) | ||
2267 | { | ||
2268 | if (x.Parent == root) | ||
2269 | { | ||
2270 | rootNamespaces.Add(a.Value); | ||
2271 | rootNamespacePrefixes.Add(a.Name.LocalName); | ||
2272 | } | ||
2273 | else | ||
2274 | { | ||
2275 | nonRootDeclarations.Add(a); | ||
2276 | } | ||
2277 | } | ||
2278 | |||
2279 | return true; | ||
2280 | }); | ||
2281 | |||
2282 | foreach (var declaration in nonRootDeclarations) | ||
2283 | { | ||
2284 | if (this.OnInformation(ConverterTestType.MoveNamespacesToRoot, declaration, "Namespace should be defined on the root. The '{0}' namespace was move to the root element.", declaration.Value)) | ||
2285 | { | ||
2286 | if (!rootNamespaces.Contains(declaration.Value)) | ||
2287 | { | ||
2288 | var prefix = GetNamespacePrefix(declaration, rootNamespacePrefixes); | ||
2289 | |||
2290 | var rootDeclaration = new XAttribute(XNamespace.Xmlns + prefix, declaration.Value); | ||
2291 | root.Add(rootDeclaration); | ||
2292 | |||
2293 | rootNamespaces.Add(rootDeclaration.Value); | ||
2294 | rootNamespacePrefixes.Add(rootDeclaration.Name.LocalName); | ||
2295 | } | ||
2296 | |||
2297 | declaration.Remove(); | ||
2298 | } | ||
2299 | } | ||
2300 | } | ||
2301 | |||
2256 | private int ReportMessages(XDocument document, bool saved) | 2302 | private int ReportMessages(XDocument document, bool saved) |
2257 | { | 2303 | { |
2258 | var conversionCount = this.ConversionMessages.Count; | 2304 | var conversionCount = this.ConversionMessages.Count; |
@@ -2457,6 +2503,83 @@ namespace WixToolset.Converters | |||
2457 | return result; | 2503 | return result; |
2458 | } | 2504 | } |
2459 | 2505 | ||
2506 | private static string GetNamespacePrefix(XAttribute declaration, HashSet<string> usedPrefixes) | ||
2507 | { | ||
2508 | var baseNamespace = String.Empty; | ||
2509 | |||
2510 | switch (declaration.Value) | ||
2511 | { | ||
2512 | case "http://wixtoolset.org/schemas/v4/wxs/bal": | ||
2513 | baseNamespace = "bal"; | ||
2514 | break; | ||
2515 | |||
2516 | case "http://wixtoolset.org/schemas/v4/wxs/complus": | ||
2517 | baseNamespace = "complus"; | ||
2518 | break; | ||
2519 | |||
2520 | case "http://wixtoolset.org/schemas/v4/wxs/dependency": | ||
2521 | baseNamespace = "dependency"; | ||
2522 | break; | ||
2523 | |||
2524 | case "http://wixtoolset.org/schemas/v4/wxs/difxapp": | ||
2525 | baseNamespace = "difx"; | ||
2526 | break; | ||
2527 | |||
2528 | case "http://wixtoolset.org/schemas/v4/wxs/directx": | ||
2529 | baseNamespace = "directx"; | ||
2530 | break; | ||
2531 | |||
2532 | case "http://wixtoolset.org/schemas/v4/wxs/firewall": | ||
2533 | baseNamespace = "fw"; | ||
2534 | break; | ||
2535 | |||
2536 | case "http://wixtoolset.org/schemas/v4/wxs/http": | ||
2537 | baseNamespace = "http"; | ||
2538 | break; | ||
2539 | |||
2540 | case "http://wixtoolset.org/schemas/v4/wxs/iis": | ||
2541 | baseNamespace = "iis"; | ||
2542 | break; | ||
2543 | |||
2544 | case "http://wixtoolset.org/schemas/v4/wxs/msmq": | ||
2545 | baseNamespace = "msmq"; | ||
2546 | break; | ||
2547 | |||
2548 | case "http://wixtoolset.org/schemas/v4/wxs/netfx": | ||
2549 | baseNamespace = "netfx"; | ||
2550 | break; | ||
2551 | |||
2552 | case "http://wixtoolset.org/schemas/v4/wxs/powershell": | ||
2553 | baseNamespace = "ps"; | ||
2554 | break; | ||
2555 | |||
2556 | case "http://wixtoolset.org/schemas/v4/wxs/sql": | ||
2557 | baseNamespace = "sql"; | ||
2558 | break; | ||
2559 | |||
2560 | case "http://wixtoolset.org/schemas/v4/wxs/ui": | ||
2561 | baseNamespace = "ui"; | ||
2562 | break; | ||
2563 | |||
2564 | case "http://wixtoolset.org/schemas/v4/wxs/util": | ||
2565 | baseNamespace = "util"; | ||
2566 | break; | ||
2567 | |||
2568 | case "http://wixtoolset.org/schemas/v4/wxs/vs": | ||
2569 | baseNamespace = "vs"; | ||
2570 | break; | ||
2571 | } | ||
2572 | |||
2573 | var ns = baseNamespace; | ||
2574 | |||
2575 | for (var i = 1; usedPrefixes.Contains(ns); ++i) | ||
2576 | { | ||
2577 | ns = baseNamespace + i; | ||
2578 | } | ||
2579 | |||
2580 | return ns; | ||
2581 | } | ||
2582 | |||
2460 | private static string LowercaseFirstChar(string value) | 2583 | private static string LowercaseFirstChar(string value) |
2461 | { | 2584 | { |
2462 | if (!String.IsNullOrEmpty(value)) | 2585 | if (!String.IsNullOrEmpty(value)) |
@@ -2928,6 +3051,11 @@ namespace WixToolset.Converters | |||
2928 | /// The MsuPackage element contains obsolete '{0}' attribute. MSU packages are now always permanent because Windows no longer supports silently removing MSUs. The attribute will be removed. | 3051 | /// The MsuPackage element contains obsolete '{0}' attribute. MSU packages are now always permanent because Windows no longer supports silently removing MSUs. The attribute will be removed. |
2929 | /// </summary> | 3052 | /// </summary> |
2930 | MsuPackagePermanentObsolete, | 3053 | MsuPackagePermanentObsolete, |
3054 | |||
3055 | /// <summary> | ||
3056 | /// Namespace should be defined on the root. The '{0}' namespace was move to the root element. | ||
3057 | /// </summary> | ||
3058 | MoveNamespacesToRoot, | ||
2931 | } | 3059 | } |
2932 | } | 3060 | } |
2933 | } | 3061 | } |
diff --git a/src/wix/test/WixToolsetTest.Converters/FirewallExtensionFixture.cs b/src/wix/test/WixToolsetTest.Converters/FirewallExtensionFixture.cs index 3d3fde16..2c1179d7 100644 --- a/src/wix/test/WixToolsetTest.Converters/FirewallExtensionFixture.cs +++ b/src/wix/test/WixToolsetTest.Converters/FirewallExtensionFixture.cs | |||
@@ -3,6 +3,7 @@ | |||
3 | namespace WixToolsetTest.Converters | 3 | namespace WixToolsetTest.Converters |
4 | { | 4 | { |
5 | using System; | 5 | using System; |
6 | using System.Linq; | ||
6 | using System.Xml.Linq; | 7 | using System.Xml.Linq; |
7 | using WixInternal.TestSupport; | 8 | using WixInternal.TestSupport; |
8 | using WixToolset.Converters; | 9 | using WixToolset.Converters; |
@@ -43,5 +44,86 @@ namespace WixToolsetTest.Converters | |||
43 | var actualLines = UnformattedDocumentLines(document); | 44 | var actualLines = UnformattedDocumentLines(document); |
44 | WixAssert.CompareLineByLine(expected, actualLines); | 45 | WixAssert.CompareLineByLine(expected, actualLines); |
45 | } | 46 | } |
47 | |||
48 | [Fact] | ||
49 | public void FixNamespacePlacement() | ||
50 | { | ||
51 | var parse = String.Join(Environment.NewLine, | ||
52 | "<Wix xmlns='http://schemas.microsoft.com/wix/2006/wi'>", | ||
53 | " <Fragment>", | ||
54 | " <RemoteAddress xmlns='http://schemas.microsoft.com/wix/FirewallExtension'>", | ||
55 | " 127.0.0.1", | ||
56 | " </RemoteAddress>", | ||
57 | " </Fragment>", | ||
58 | "</Wix>"); | ||
59 | |||
60 | var expected = new[] | ||
61 | { | ||
62 | "<Wix xmlns=\"http://wixtoolset.org/schemas/v4/wxs\" xmlns:fw=\"http://wixtoolset.org/schemas/v4/wxs/firewall\">", | ||
63 | " <Fragment>", | ||
64 | " <fw:RemoteAddress Value=\"127.0.0.1\" />", | ||
65 | " </Fragment>", | ||
66 | "</Wix>" | ||
67 | }; | ||
68 | |||
69 | var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); | ||
70 | |||
71 | var messaging = new MockMessaging(); | ||
72 | var converter = new WixConverter(messaging, 2, null, null); | ||
73 | |||
74 | var errors = converter.ConvertDocument(document); | ||
75 | WixAssert.CompareLineByLine(new[] | ||
76 | { | ||
77 | "[Converted] The namespace 'http://schemas.microsoft.com/wix/2006/wi' is out of date. It must be 'http://wixtoolset.org/schemas/v4/wxs'. (XmlnsValueWrong)", | ||
78 | "[Converted] The namespace 'http://schemas.microsoft.com/wix/FirewallExtension' is out of date. It must be 'http://wixtoolset.org/schemas/v4/wxs/firewall'. (XmlnsValueWrong)", | ||
79 | "[Converted] Using RemoteAddress element text is deprecated. Use the 'Value' attribute instead. (InnerTextDeprecated)", | ||
80 | "[Converted] Namespace should be defined on the root. The 'http://wixtoolset.org/schemas/v4/wxs/firewall' namespace was move to the root element. (MoveNamespacesToRoot)" | ||
81 | }, messaging.Messages.Select(m => m.ToString()).ToArray()); | ||
82 | Assert.Equal(4, errors); | ||
83 | |||
84 | var actualLines = UnformattedDocumentLines(document); | ||
85 | WixAssert.CompareLineByLine(expected, actualLines); | ||
86 | } | ||
87 | |||
88 | [Fact] | ||
89 | public void FixNamespacePlacementWhenItExists() | ||
90 | { | ||
91 | //xmlns:abc='http://schemas.microsoft.com/wix/FirewallExtension' | ||
92 | var parse = String.Join(Environment.NewLine, | ||
93 | "<Wix xmlns='http://schemas.microsoft.com/wix/2006/wi'>", | ||
94 | " <Fragment>", | ||
95 | " <RemoteAddress xmlns='http://schemas.microsoft.com/wix/FirewallExtension'>", | ||
96 | " 127.0.0.1", | ||
97 | " </RemoteAddress>", | ||
98 | " </Fragment>", | ||
99 | "</Wix>"); | ||
100 | |||
101 | var expected = new[] | ||
102 | { | ||
103 | "<Wix xmlns=\"http://wixtoolset.org/schemas/v4/wxs\" xmlns:fw=\"http://wixtoolset.org/schemas/v4/wxs/firewall\">", | ||
104 | " <Fragment>", | ||
105 | " <fw:RemoteAddress Value=\"127.0.0.1\" />", | ||
106 | " </Fragment>", | ||
107 | "</Wix>" | ||
108 | }; | ||
109 | |||
110 | var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); | ||
111 | |||
112 | var messaging = new MockMessaging(); | ||
113 | var converter = new WixConverter(messaging, 2, null, null); | ||
114 | |||
115 | var errors = converter.ConvertDocument(document); | ||
116 | WixAssert.CompareLineByLine(new[] | ||
117 | { | ||
118 | "[Converted] The namespace 'http://schemas.microsoft.com/wix/2006/wi' is out of date. It must be 'http://wixtoolset.org/schemas/v4/wxs'. (XmlnsValueWrong)", | ||
119 | "[Converted] The namespace 'http://schemas.microsoft.com/wix/FirewallExtension' is out of date. It must be 'http://wixtoolset.org/schemas/v4/wxs/firewall'. (XmlnsValueWrong)", | ||
120 | "[Converted] Using RemoteAddress element text is deprecated. Use the 'Value' attribute instead. (InnerTextDeprecated)", | ||
121 | "[Converted] Namespace should be defined on the root. The 'http://wixtoolset.org/schemas/v4/wxs/firewall' namespace was move to the root element. (MoveNamespacesToRoot)" | ||
122 | }, messaging.Messages.Select(m => m.ToString()).ToArray()); | ||
123 | Assert.Equal(4, errors); | ||
124 | |||
125 | var actualLines = UnformattedDocumentLines(document); | ||
126 | WixAssert.CompareLineByLine(expected, actualLines); | ||
127 | } | ||
46 | } | 128 | } |
47 | } | 129 | } |