diff options
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 | } |