Enhance bundle backend validation.
Sean Hall committed
Mar 15, 2022 at 18:09 UTC
db22d99a4d603caab18fd42cb40881431c353912
26 files changed
+926
-278
src/api/wix/WixToolset.Data/ErrorMessages.cs
+6
@@ -1184,6 +1184,11 @@ namespace WixToolset.Data
1184
return Message(null, Ids.InvalidCommandLineFileName, "Invalid file name specified on the command line: '{0}'. Error message: '{1}'", fileName, error);
1185
}
1186
1187
+ public static Message InvalidBundleCondition(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string condition)
1188
+ {
1189
+ return Message(sourceLineNumbers, Ids.InvalidBundleCondition, "The {0}/@{1} attribute's value '{2}' is not a valid bundle condition.", elementName, attributeName, condition);
1190
+ }
1191
+
1192
public static Message InvalidDateTimeFormat(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string value)
1193
{
1194
return Message(sourceLineNumbers, Ids.InvalidDateTimeFormat, "The {0}/@{1} attribute's value '{2}' is not a valid date/time value. A date/time value should follow the format YYYY-MM-DDTHH:mm:ss.", elementName, attributeName, value);
@@ -2686,6 +2691,7 @@ namespace WixToolset.Data
2691
MultiplePackagePayloads3 = 406,
2692
MissingPackagePayload = 407,
2693
ExpectedAttributeWithoutOtherAttributes = 408,
2694
+ InvalidBundleCondition = 409,
2695
}
2696
}
2697
}
src/api/wix/WixToolset.Data/WarningMessages.cs
+6
@@ -593,6 +593,11 @@ namespace WixToolset.Data
593
return Message(null, Ids.UnableToResetAcls, "Unable to reset acls on destination files. Exception detail: {0}", error);
594
}
595
596
+ public static Message UnavailableBundleConditionVariable(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string variable, string illegalValueList)
597
+ {
598
+ return Message(sourceLineNumbers, Ids.UnavailableBundleConditionVariable, "{0}/@{1} contains the built-in Variable '{2}', which is not available when it is evaluated. (Unavailable Variables are: {3}.). Rewrite the condition to avoid Variables that are never valid during its evaluation.", elementName, attributeName, variable, illegalValueList);
599
+ }
600
+
601
public static Message UnclearShortcut(SourceLineNumber sourceLineNumbers, string shortcutId, string fileId, string componentId)
602
{
603
return Message(sourceLineNumbers, Ids.UnclearShortcut, "Because it is an advertised shortcut, the target of shortcut '{0}' will be the keypath of component '{2}' rather than parent file '{1}'. To eliminate this warning, you can (1) make the Shortcut element a child of the File element that is the keypath of component '{2}', (2) make file '{1}' the keypath of component '{2}', or (3) remove the @Advertise attribute so the shortcut is a non-advertised shortcut.", shortcutId, fileId, componentId);
@@ -804,6 +809,7 @@ namespace WixToolset.Data
809
DetectConditionRecommended = 1153,
810
CollidingModularizationTypes = 1156,
811
InvalidEnvironmentVariable = 1157,
812
+ UnavailableBundleConditionVariable = 1159,
813
}
814
}
815
}
src/api/wix/WixToolset.Extensibility/Data/BundleConditionPhase.cs
new
+35
@@ -0,0 +1,35 @@
1
+// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
+
3
+namespace WixToolset.Extensibility.Data
4
+{
5
+ /// <summary>
6
+ /// The Burn execution phase during which a Condition will be evaluated.
7
+ /// </summary>
8
+ public enum BundleConditionPhase
9
+ {
10
+ /// <summary>
11
+ /// Condition is evaluated by the engine before loading the BootstrapperApplication (Bundle/@Condition).
12
+ /// </summary>
13
+ Startup,
14
+
15
+ /// <summary>
16
+ /// Condition is evaluated during Detect (ExePackage/@DetectCondition).
17
+ /// </summary>
18
+ Detect,
19
+
20
+ /// <summary>
21
+ /// Condition is evaluated during Plan (ExePackage/@InstallCondition).
22
+ /// </summary>
23
+ Plan,
24
+
25
+ /// <summary>
26
+ /// Condition is evaluated during Apply (MsiProperty/@Condition).
27
+ /// </summary>
28
+ Execute,
29
+
30
+ /// <summary>
31
+ /// Condition is evaluated after Apply.
32
+ /// </summary>
33
+ Shutdown,
34
+ }
35
+}
src/api/wix/WixToolset.Extensibility/Services/IBackendHelper.cs
-11
@@ -73,17 +73,6 @@ namespace WixToolset.Extensibility.Services
73
/// <returns>The generated identifier.</returns>
74
string GenerateIdentifier(string prefix, params string[] args);
75
76
- /// <summary>
77
- /// Validates path is relative and canonicalizes it.
78
- /// For example, "a\..\c\.\d.exe" => "c\d.exe".
79
- /// </summary>
80
- /// <param name="sourceLineNumbers"></param>
81
- /// <param name="elementName"></param>
82
- /// <param name="attributeName"></param>
83
- /// <param name="relativePath"></param>
84
- /// <returns>The original value if not relative, otherwise the canonicalized relative path.</returns>
85
- string GetCanonicalRelativePath(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string relativePath);
86
-
76
/// <summary>
77
/// Gets a valid code page from the given web name or integer value.
78
/// </summary>
src/api/wix/WixToolset.Extensibility/Services/IBundleValidator.cs
new
+56
@@ -0,0 +1,56 @@
1
+// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
+
3
+namespace WixToolset.Extensibility.Services
4
+{
5
+ using WixToolset.Data;
6
+ using WixToolset.Extensibility.Data;
7
+
8
+ /// <summary>
9
+ /// Interface provided to help with bundle validation.
10
+ /// </summary>
11
+ public interface IBundleValidator
12
+ {
13
+
14
+ /// <summary>
15
+ /// Validates path is relative and canonicalizes it.
16
+ /// For example, "a\..\c\.\d.exe" => "c\d.exe".
17
+ /// </summary>
18
+ /// <param name="sourceLineNumbers"></param>
19
+ /// <param name="elementName"></param>
20
+ /// <param name="attributeName"></param>
21
+ /// <param name="relativePath"></param>
22
+ /// <returns>The original value if not relative, otherwise the canonicalized relative path.</returns>
23
+ string GetCanonicalRelativePath(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string relativePath);
24
+
25
+ /// <summary>
26
+ /// Validates an MsiProperty name value and displays an error for an illegal value.
27
+ /// </summary>
28
+ /// <param name="sourceLineNumbers"></param>
29
+ /// <param name="elementName"></param>
30
+ /// <param name="attributeName"></param>
31
+ /// <param name="propertyName"></param>
32
+ /// <returns>Whether the name is valid.</returns>
33
+ bool ValidateBundleMsiPropertyName(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string propertyName);
34
+
35
+ /// <summary>
36
+ /// Validates a Bundle variable name and displays an error for an illegal value.
37
+ /// </summary>
38
+ /// <param name="sourceLineNumbers"></param>
39
+ /// <param name="elementName"></param>
40
+ /// <param name="attributeName"></param>
41
+ /// <param name="variableName"></param>
42
+ /// <returns>Whether the name is valid.</returns>
43
+ bool ValidateBundleVariableName(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string variableName);
44
+
45
+ /// <summary>
46
+ /// Validates a bundle condition and displays an error for an illegal value.
47
+ /// </summary>
48
+ /// <param name="sourceLineNumbers"></param>
49
+ /// <param name="elementName"></param>
50
+ /// <param name="attributeName"></param>
51
+ /// <param name="condition"></param>
52
+ /// <param name="phase"></param>
53
+ /// <returns>Whether the condition is valid.</returns>
54
+ bool ValidateBundleCondition(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string condition, BundleConditionPhase phase);
55
+ }
56
+}
src/api/wix/WixToolset.Extensibility/Services/IBurnBackendHelper.cs
+1
-1
@@ -7,7 +7,7 @@ namespace WixToolset.Extensibility.Services
7
/// <summary>
8
/// Interface provided to help Burn backend extensions.
9
/// </summary>
10
- public interface IBurnBackendHelper : IBackendHelper
10
+ public interface IBurnBackendHelper : IBackendHelper, IBundleValidator
11
{
12
/// <summary>
13
/// Adds the given XML to the BootstrapperApplicationData manifest.
src/api/wix/WixToolset.Extensibility/Services/IParseHelper.cs
+1
-12
@@ -13,7 +13,7 @@ namespace WixToolset.Extensibility.Services
13
/// <summary>
14
/// Interface provided to help compiler extensions parse.
15
/// </summary>
16
- public interface IParseHelper
16
+ public interface IParseHelper : IBundleValidator
17
{
18
/// <summary>
19
/// Creates a version 3 name-based UUID.
@@ -322,17 +322,6 @@ namespace WixToolset.Extensibility.Services
322
/// <returns>The attribute's YesNoType value.</returns>
323
YesNoDefaultType GetAttributeYesNoDefaultValue(SourceLineNumber sourceLineNumbers, XAttribute attribute);
324
325
- /// <summary>
326
- /// Validates path is relative and canonicalizes it.
327
- /// For example, "a\..\c\.\d.exe" => "c\d.exe".
328
- /// </summary>
329
- /// <param name="sourceLineNumbers"></param>
330
- /// <param name="elementName"></param>
331
- /// <param name="attributeName"></param>
332
- /// <param name="relativePath"></param>
333
- /// <returns>The original value if not relative, otherwise the canonicalized relative path.</returns>
334
- string GetCanonicalRelativePath(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string relativePath);
335
-
325
/// <summary>
326
/// Gets a source line number for an element.
327
/// </summary>
src/burn/test/BurnUnitTest/VariableTest.cpp
+1
@@ -381,6 +381,7 @@ namespace Bootstrapper
381
Assert::True(EvaluateConditionHelper(&variables, L"(PROP3 = \"NOT\" OR PROP1 = \"VAL1\") AND PROP2 = \"VAL2\""));
382
Assert::True(EvaluateConditionHelper(&variables, L"PROP3 = \"NOT\" OR (PROP1 = \"VAL1\" AND PROP2 = \"VAL2\")"));
383
384
+ Assert::True(EvaluateFailureConditionHelper(&variables, L""));
385
Assert::True(EvaluateFailureConditionHelper(&variables, L"="));
386
Assert::True(EvaluateFailureConditionHelper(&variables, L"(PROP1"));
387
Assert::True(EvaluateFailureConditionHelper(&variables, L"(PROP1 = \""));
src/ext/Bal/test/WixToolsetTest.Bal/BalExtensionFixture.cs
+18
-4
@@ -2,6 +2,7 @@
2
3
namespace WixToolsetTest.Bal
4
{
5
+ using System;
6
using System.IO;
7
using System.Linq;
8
using System.Xml;
@@ -138,20 +139,33 @@ namespace WixToolsetTest.Bal
139
{
140
var baseFolder = fs.GetFolder();
141
var bundleFile = Path.Combine(baseFolder, "bin", "test.exe");
141
- var bundleSourceFolder = TestData.Get(@"TestData\Overridable");
142
+ var bundleSourceFolder = TestData.Get(@"TestData");
143
var intermediateFolder = Path.Combine(baseFolder, "obj");
144
var baFolderPath = Path.Combine(baseFolder, "ba");
145
var extractFolderPath = Path.Combine(baseFolder, "extract");
146
146
- var compileResult = WixRunner.Execute(new[]
147
+ var result = WixRunner.Execute(new[]
148
{
149
"build",
149
- Path.Combine(bundleSourceFolder, "WrongCaseBundle.wxs"),
150
+ Path.Combine(bundleSourceFolder, "Overridable", "WrongCaseBundle.wxs"),
151
+ "-loc", Path.Combine(bundleSourceFolder, "Overridable", "WrongCaseBundle.wxl"),
152
+ "-bindpath", Path.Combine(bundleSourceFolder, "WixStdBa", "Data"),
153
"-ext", TestData.Get(@"WixToolset.Bal.wixext.dll"),
154
"-intermediateFolder", intermediateFolder,
155
"-o", bundleFile,
156
});
154
- Assert.Equal((int)BalErrors.Ids.NonUpperCaseOverridableVariable, compileResult.ExitCode);
157
+
158
+ Assert.InRange(result.ExitCode, 2, Int32.MaxValue);
159
+
160
+ var messages = result.Messages.Select(m => m.ToString()).ToList();
161
+ messages.Sort();
162
+
163
+ WixAssert.CompareLineByLine(new[]
164
+ {
165
+ "bal:Condition/@Condition contains the built-in Variable 'WixBundleAction', which is not available when it is evaluated. (Unavailable Variables are: 'WixBundleAction'.). Rewrite the condition to avoid Variables that are never valid during its evaluation.",
166
+ "Overridable variable 'Test1' must be 'TEST1' with Bundle/@CommandLineVariables value 'upperCase'.",
167
+ "The *Package/@bal:DisplayInternalUICondition attribute's value '=' is not a valid bundle condition.",
168
+ }, messages.ToArray());
169
}
170
}
171
}
src/ext/Bal/test/WixToolsetTest.Bal/TestData/Overridable/WrongCaseBundle.wxl
new
+4
@@ -0,0 +1,4 @@
1
+<WixLocalization xmlns="http://wixtoolset.org/schemas/v4/wxl" Culture="en-US">
2
+ <String Id="NonsenseDetectCondition">WixBundleAction = 4</String>
3
+ <String Id="NonsensePlanCondition">=</String>
4
+</WixLocalization>
src/ext/Bal/test/WixToolsetTest.Bal/TestData/Overridable/WrongCaseBundle.wxs
+2
@@ -8,6 +8,8 @@
8
<Variable Name="Test1" bal:Overridable="yes" />
9
<Chain>
10
<ExePackage Permanent="yes" DetectCondition="none" SourceFile="runtimes\win-x86\native\wixnative.exe" />
11
+ <MsiPackage SourceFile="test.msi" bal:DisplayInternalUICondition="!(loc.NonsensePlanCondition)" />
12
</Chain>
13
+ <bal:Condition Condition="!(loc.NonsenseDetectCondition)" Message="Unsupported" />
14
</Bundle>
15
</Wix>
src/ext/Bal/wixext/BalBurnBackendExtension.cs
+22
-1
@@ -10,6 +10,7 @@ namespace WixToolset.Bal
10
using WixToolset.Data.Burn;
11
using WixToolset.Data.Symbols;
12
using WixToolset.Extensibility;
13
+ using WixToolset.Extensibility.Data;
14
15
public class BalBurnBackendExtension : BaseBurnBackendBinderExtension
16
{
@@ -31,6 +32,8 @@ namespace WixToolset.Bal
32
{
33
base.SymbolsFinalized(section);
34
35
+ this.VerifyBalConditions(section);
36
+ this.VerifyBalPackageInfos(section);
37
this.VerifyOverridableVariables(section);
38
39
var baSymbol = section.Symbols.OfType<WixBootstrapperApplicationDllSymbol>().SingleOrDefault();
@@ -100,7 +103,7 @@ namespace WixToolset.Bal
103
{
104
foreach (var payloadPropertiesSymbol in payloadPropertiesSymbols)
105
{
103
- if (string.Equals(payloadPropertiesSymbol.Name, "bafunctions.dll", StringComparison.OrdinalIgnoreCase) &&
106
+ if (String.Equals(payloadPropertiesSymbol.Name, "bafunctions.dll", StringComparison.OrdinalIgnoreCase) &&
107
BurnConstants.BurnUXContainerName == payloadPropertiesSymbol.ContainerRef)
108
{
109
this.Messaging.Write(BalWarnings.UnmarkedBAFunctionsDLL(payloadPropertiesSymbol.SourceLineNumbers));
@@ -120,6 +123,24 @@ namespace WixToolset.Bal
123
}
124
}
125
126
+ private void VerifyBalConditions(IntermediateSection section)
127
+ {
128
+ var balConditionSymbols = section.Symbols.OfType<WixBalConditionSymbol>().ToList();
129
+ foreach (var balConditionSymbol in balConditionSymbols)
130
+ {
131
+ this.BackendHelper.ValidateBundleCondition(balConditionSymbol.SourceLineNumbers, "bal:Condition", "Condition", balConditionSymbol.Condition, BundleConditionPhase.Detect);
132
+ }
133
+ }
134
+
135
+ private void VerifyBalPackageInfos(IntermediateSection section)
136
+ {
137
+ var balPackageInfoSymbols = section.Symbols.OfType<WixBalPackageInfoSymbol>().ToList();
138
+ foreach (var balPackageInfoSymbol in balPackageInfoSymbols)
139
+ {
140
+ this.BackendHelper.ValidateBundleCondition(balPackageInfoSymbol.SourceLineNumbers, "*Package", "bal:DisplayInternalUICondition", balPackageInfoSymbol.DisplayInternalUICondition, BundleConditionPhase.Plan);
141
+ }
142
+ }
143
+
144
private void VerifyOverridableVariables(IntermediateSection section)
145
{
146
var bundleSymbol = section.Symbols.OfType<WixBundleSymbol>().Single();
src/wix/WixToolset.Core.Burn/Bind/BindBundleCommand.cs
+13
-2
@@ -150,7 +150,7 @@ namespace WixToolset.Core.Burn
150
// Process the explicitly authored payloads.
151
ISet<string> processedPayloads;
152
{
153
- var command = new ProcessPayloadsCommand(this.BackendHelper, this.PayloadHarvester, payloadSymbols.Values, bundleSymbol.DefaultPackagingType, layoutDirectory);
153
+ var command = new ProcessPayloadsCommand(this.InternalBurnBackendHelper, this.PayloadHarvester, payloadSymbols.Values, bundleSymbol.DefaultPackagingType, layoutDirectory);
154
command.Execute();
155
156
fileTransfers.AddRange(command.FileTransfers);
@@ -228,7 +228,7 @@ namespace WixToolset.Core.Burn
228
{
229
var toProcess = payloadSymbols.Values.Where(r => !processedPayloads.Contains(r.Id.Id)).ToList();
230
231
- var command = new ProcessPayloadsCommand(this.BackendHelper, this.PayloadHarvester, toProcess, bundleSymbol.DefaultPackagingType, layoutDirectory);
231
+ var command = new ProcessPayloadsCommand(this.InternalBurnBackendHelper, this.PayloadHarvester, toProcess, bundleSymbol.DefaultPackagingType, layoutDirectory);
232
command.Execute();
233
234
fileTransfers.AddRange(command.FileTransfers);
@@ -381,6 +381,17 @@ namespace WixToolset.Core.Burn
381
return;
382
}
383
384
+ // Now that extensions can't change anything else, verify everything is still valid.
385
+ {
386
+ var command = new PerformBundleBackendValidationCommand(this.Messaging, this.InternalBurnBackendHelper, section, facades);
387
+ command.Execute();
388
+ }
389
+
390
+ if (this.Messaging.EncounteredError)
391
+ {
392
+ return;
393
+ }
394
+
395
// Generate data for all manifests.
396
{
397
var command = new GenerateManifestDataFromIRCommand(this.Messaging, section, this.BackendExtensions, this.InternalBurnBackendHelper, extensionSearchSymbolsById);
src/wix/WixToolset.Core.Burn/Bundles/PerformBundleBackendValidationCommand.cs
new
+156
@@ -0,0 +1,156 @@
1
+// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
+
3
+namespace WixToolset.Core.Burn.Bundles
4
+{
5
+ using System;
6
+ using System.Collections.Generic;
7
+ using WixToolset.Data;
8
+ using WixToolset.Data.Symbols;
9
+ using WixToolset.Extensibility.Data;
10
+ using WixToolset.Extensibility.Services;
11
+
12
+ internal class PerformBundleBackendValidationCommand
13
+ {
14
+ public PerformBundleBackendValidationCommand(IMessaging messaging, IBurnBackendHelper burnBackendHelper, IntermediateSection section, IDictionary<string, PackageFacade> packageFacadesById)
15
+ {
16
+ this.Messaging = messaging;
17
+ this.BackendHelper = burnBackendHelper;
18
+ this.Section = section;
19
+ this.PackageFacadesById = packageFacadesById;
20
+ }
21
+
22
+ public IMessaging Messaging { get; }
23
+
24
+ public IBurnBackendHelper BackendHelper { get; }
25
+
26
+ public IntermediateSection Section { get; }
27
+
28
+ public IDictionary<string, PackageFacade> PackageFacadesById { get; }
29
+
30
+ public void Execute()
31
+ {
32
+ foreach (var symbol in this.Section.Symbols)
33
+ {
34
+ if (symbol is WixBundleSymbol wixBundleSymbol)
35
+ {
36
+ this.ValidateBundle(wixBundleSymbol);
37
+ }
38
+ else if (symbol is WixBundleMsiPropertySymbol wixBundleMsiPropertySymbol)
39
+ {
40
+ this.ValidateMsiProperty(wixBundleMsiPropertySymbol);
41
+ }
42
+ else if (symbol is WixBundleVariableSymbol wixBundleVariableSymbol)
43
+ {
44
+ this.ValidateVariable(wixBundleVariableSymbol);
45
+ }
46
+ else if (symbol is WixBundlePackageCommandLineSymbol wixBundlePackageCommandLineSymbol)
47
+ {
48
+ this.ValidatePackageCommandLine(wixBundlePackageCommandLineSymbol);
49
+ }
50
+ else if (symbol is WixSearchSymbol wixSearchSymbol)
51
+ {
52
+ this.ValidateSearch(wixSearchSymbol);
53
+ }
54
+ }
55
+
56
+ foreach (var packageFacade in this.PackageFacadesById.Values)
57
+ {
58
+ if (packageFacade.SpecificPackageSymbol is WixBundleExePackageSymbol wixBundleExePackageSymbol)
59
+ {
60
+ this.ValidateExePackage(wixBundleExePackageSymbol, packageFacade.PackageSymbol);
61
+ }
62
+ else if (packageFacade.SpecificPackageSymbol is WixBundleMsiPackageSymbol wixBundleMsiPackageSymbol)
63
+ {
64
+ this.ValidateMsiPackage(wixBundleMsiPackageSymbol, packageFacade.PackageSymbol);
65
+ }
66
+ else if (packageFacade.SpecificPackageSymbol is WixBundleMspPackageSymbol wixBundleMspPackageSymbol)
67
+ {
68
+ this.ValidateMspPackage(wixBundleMspPackageSymbol, packageFacade.PackageSymbol);
69
+ }
70
+ else if (packageFacade.SpecificPackageSymbol is WixBundleMsuPackageSymbol wixBundleMsuPackageSymbol)
71
+ {
72
+ this.ValidateMsuPackage(wixBundleMsuPackageSymbol, packageFacade.PackageSymbol);
73
+ }
74
+ }
75
+ }
76
+
77
+ private void ValidateBundle(WixBundleSymbol symbol)
78
+ {
79
+ if (symbol.Condition != null)
80
+ {
81
+ this.BackendHelper.ValidateBundleCondition(symbol.SourceLineNumbers, "Bundle", "Condition", symbol.Condition, BundleConditionPhase.Startup);
82
+ }
83
+ }
84
+
85
+ private void ValidateChainPackage(WixBundlePackageSymbol symbol, string elementName)
86
+ {
87
+ if (!String.IsNullOrEmpty(symbol.InstallCondition))
88
+ {
89
+ this.BackendHelper.ValidateBundleCondition(symbol.SourceLineNumbers, elementName, "InstallCondition", symbol.InstallCondition, BundleConditionPhase.Plan);
90
+ }
91
+ }
92
+
93
+ private void ValidateExePackage(WixBundleExePackageSymbol symbol, WixBundlePackageSymbol packageSymbol)
94
+ {
95
+ this.ValidateChainPackage(packageSymbol, "ExePackage");
96
+
97
+ if (!packageSymbol.Permanent)
98
+ {
99
+ this.BackendHelper.ValidateBundleCondition(symbol.SourceLineNumbers, "ExePackage", "DetectCondition", symbol.DetectCondition, BundleConditionPhase.Detect);
100
+ }
101
+ }
102
+
103
+ private void ValidateMsiPackage(WixBundleMsiPackageSymbol symbol, WixBundlePackageSymbol packageSymbol)
104
+ {
105
+ this.ValidateChainPackage(packageSymbol, "MsiPackage");
106
+ }
107
+
108
+ private void ValidateMsiProperty(WixBundleMsiPropertySymbol symbol)
109
+ {
110
+ this.BackendHelper.ValidateBundleMsiPropertyName(symbol.SourceLineNumbers, "MsiProperty", "Name", symbol.Name);
111
+
112
+ if (symbol.Condition != null)
113
+ {
114
+ this.BackendHelper.ValidateBundleCondition(symbol.SourceLineNumbers, "MsiProperty", "Condition", symbol.Condition, BundleConditionPhase.Execute);
115
+ }
116
+ }
117
+
118
+ private void ValidateMspPackage(WixBundleMspPackageSymbol symbol, WixBundlePackageSymbol packageSymbol)
119
+ {
120
+ this.ValidateChainPackage(packageSymbol, "MspPackage");
121
+ }
122
+
123
+ private void ValidateMsuPackage(WixBundleMsuPackageSymbol symbol, WixBundlePackageSymbol packageSymbol)
124
+ {
125
+ this.ValidateChainPackage(packageSymbol, "MsuPackage");
126
+
127
+ if (!packageSymbol.Permanent)
128
+ {
129
+ this.BackendHelper.ValidateBundleCondition(symbol.SourceLineNumbers, "MsuPackage", "DetectCondition", symbol.DetectCondition, BundleConditionPhase.Detect);
130
+ }
131
+ }
132
+
133
+ private void ValidatePackageCommandLine(WixBundlePackageCommandLineSymbol symbol)
134
+ {
135
+ if (symbol.Condition != null)
136
+ {
137
+ this.BackendHelper.ValidateBundleCondition(symbol.SourceLineNumbers, "CommandLine", "Condition", symbol.Condition, BundleConditionPhase.Execute);
138
+ }
139
+ }
140
+
141
+ private void ValidateSearch(WixSearchSymbol symbol)
142
+ {
143
+ this.BackendHelper.ValidateBundleVariableName(symbol.SourceLineNumbers, "*Search", "Variable", symbol.Variable);
144
+
145
+ if (symbol.Condition != null)
146
+ {
147
+ this.BackendHelper.ValidateBundleCondition(symbol.SourceLineNumbers, "*Search", "Condition", symbol.Condition, BundleConditionPhase.Detect);
148
+ }
149
+ }
150
+
151
+ private void ValidateVariable(WixBundleVariableSymbol symbol)
152
+ {
153
+ this.BackendHelper.ValidateBundleVariableName(symbol.SourceLineNumbers, "Variable", "Name", symbol.Id.Id);
154
+ }
155
+ }
156
+}
src/wix/WixToolset.Core.Burn/Bundles/ProcessPayloadsCommand.cs
+2
-2
@@ -15,7 +15,7 @@ namespace WixToolset.Core.Burn.Bundles
15
16
internal class ProcessPayloadsCommand
17
{
18
- public ProcessPayloadsCommand(IBackendHelper backendHelper, IPayloadHarvester payloadHarvester, IEnumerable<WixBundlePayloadSymbol> payloads, PackagingType defaultPackaging, string layoutDirectory)
18
+ public ProcessPayloadsCommand(IBurnBackendHelper backendHelper, IPayloadHarvester payloadHarvester, IEnumerable<WixBundlePayloadSymbol> payloads, PackagingType defaultPackaging, string layoutDirectory)
19
{
20
this.BackendHelper = backendHelper;
21
this.PayloadHarvester = payloadHarvester;
@@ -28,7 +28,7 @@ namespace WixToolset.Core.Burn.Bundles
28
29
public IEnumerable<ITrackedFile> TrackedFiles { get; private set; }
30
31
- private IBackendHelper BackendHelper { get; }
31
+ private IBurnBackendHelper BackendHelper { get; }
32
33
private IPayloadHarvester PayloadHarvester { get; }
34
src/wix/WixToolset.Core.Burn/ExtensibilityServices/BurnBackendHelper.cs
+100
-21
@@ -20,6 +20,7 @@ namespace WixToolset.Core.Burn.ExtensibilityServices
20
public static readonly XmlWriterSettings WriterSettings = new XmlWriterSettings { ConformanceLevel = ConformanceLevel.Fragment };
21
22
private readonly IBackendHelper backendHelper;
23
+ private readonly IBundleValidator bundleValidator;
24
25
private ManifestData BootstrapperApplicationManifestData { get; } = new ManifestData();
26
@@ -28,49 +29,105 @@ namespace WixToolset.Core.Burn.ExtensibilityServices
29
public BurnBackendHelper(IServiceProvider serviceProvider)
30
{
31
this.backendHelper = serviceProvider.GetService<IBackendHelper>();
32
+ this.bundleValidator = serviceProvider.GetService<IBundleValidator>();
33
}
34
35
#region IBackendHelper interfaces
36
35
- public IFileFacade CreateFileFacade(FileSymbol file, AssemblySymbol assembly) => this.backendHelper.CreateFileFacade(file, assembly);
36
-
37
- public IFileFacade CreateFileFacade(FileRow fileRow) => this.backendHelper.CreateFileFacade(fileRow);
37
+ public IFileFacade CreateFileFacade(FileSymbol file, AssemblySymbol assembly)
38
+ {
39
+ return this.backendHelper.CreateFileFacade(file, assembly);
40
+ }
41
39
- public IFileFacade CreateFileFacadeFromMergeModule(FileSymbol fileSymbol) => this.backendHelper.CreateFileFacadeFromMergeModule(fileSymbol);
42
+ public IFileFacade CreateFileFacade(FileRow fileRow)
43
+ {
44
+ return this.backendHelper.CreateFileFacade(fileRow);
45
+ }
46
41
- public IFileTransfer CreateFileTransfer(string source, string destination, bool move, SourceLineNumber sourceLineNumbers = null) => this.backendHelper.CreateFileTransfer(source, destination, move, sourceLineNumbers);
47
+ public IFileFacade CreateFileFacadeFromMergeModule(FileSymbol fileSymbol)
48
+ {
49
+ return this.backendHelper.CreateFileFacadeFromMergeModule(fileSymbol);
50
+ }
51
43
- public string CreateGuid() => this.backendHelper.CreateGuid();
52
+ public IFileTransfer CreateFileTransfer(string source, string destination, bool move, SourceLineNumber sourceLineNumbers = null)
53
+ {
54
+ return this.backendHelper.CreateFileTransfer(source, destination, move, sourceLineNumbers);
55
+ }
56
45
- public string CreateGuid(Guid namespaceGuid, string value) => this.backendHelper.CreateGuid(namespaceGuid, value);
57
+ public string CreateGuid()
58
+ {
59
+ return this.backendHelper.CreateGuid();
60
+ }
61
47
- public IResolvedDirectory CreateResolvedDirectory(string directoryParent, string name) => this.backendHelper.CreateResolvedDirectory(directoryParent, name);
62
+ public string CreateGuid(Guid namespaceGuid, string value)
63
+ {
64
+ return this.backendHelper.CreateGuid(namespaceGuid, value);
65
+ }
66
49
- public IReadOnlyList<ITrackedFile> ExtractEmbeddedFiles(IEnumerable<IExpectedExtractFile> embeddedFiles) => this.backendHelper.ExtractEmbeddedFiles(embeddedFiles);
67
+ public IResolvedDirectory CreateResolvedDirectory(string directoryParent, string name)
68
+ {
69
+ return this.backendHelper.CreateResolvedDirectory(directoryParent, name);
70
+ }
71
51
- public string GenerateIdentifier(string prefix, params string[] args) => this.backendHelper.GenerateIdentifier(prefix, args);
72
+ public IReadOnlyList<ITrackedFile> ExtractEmbeddedFiles(IEnumerable<IExpectedExtractFile> embeddedFiles)
73
+ {
74
+ return this.backendHelper.ExtractEmbeddedFiles(embeddedFiles);
75
+ }
76
53
- public string GetCanonicalRelativePath(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string relativePath) => this.backendHelper.GetCanonicalRelativePath(sourceLineNumbers, elementName, attributeName, relativePath);
77
+ public string GenerateIdentifier(string prefix, params string[] args)
78
+ {
79
+ return this.backendHelper.GenerateIdentifier(prefix, args);
80
+ }
81
55
- public int GetValidCodePage(string value, bool allowNoChange, bool onlyAnsi = false, SourceLineNumber sourceLineNumbers = null) => this.backendHelper.GetValidCodePage(value, allowNoChange, onlyAnsi, sourceLineNumbers);
82
+ public int GetValidCodePage(string value, bool allowNoChange, bool onlyAnsi = false, SourceLineNumber sourceLineNumbers = null)
83
+ {
84
+ return this.backendHelper.GetValidCodePage(value, allowNoChange, onlyAnsi, sourceLineNumbers);
85
+ }
86
57
- public string GetMsiFileName(string value, bool source, bool longName) => this.backendHelper.GetMsiFileName(value, source, longName);
87
+ public string GetMsiFileName(string value, bool source, bool longName)
88
+ {
89
+ return this.backendHelper.GetMsiFileName(value, source, longName);
90
+ }
91
59
- public bool IsValidBinderVariable(string variable) => this.backendHelper.IsValidBinderVariable(variable);
92
+ public bool IsValidBinderVariable(string variable)
93
+ {
94
+ return this.backendHelper.IsValidBinderVariable(variable);
95
+ }
96
61
- public bool IsValidFourPartVersion(string version) => this.backendHelper.IsValidFourPartVersion(version);
97
+ public bool IsValidFourPartVersion(string version)
98
+ {
99
+ return this.backendHelper.IsValidFourPartVersion(version);
100
+ }
101
63
- public bool IsValidIdentifier(string id) => this.backendHelper.IsValidIdentifier(id);
102
+ public bool IsValidIdentifier(string id)
103
+ {
104
+ return this.backendHelper.IsValidIdentifier(id);
105
+ }
106
65
- public bool IsValidLongFilename(string filename, bool allowWildcards, bool allowRelative) => this.backendHelper.IsValidLongFilename(filename, allowWildcards, allowRelative);
107
+ public bool IsValidLongFilename(string filename, bool allowWildcards, bool allowRelative)
108
+ {
109
+ return this.backendHelper.IsValidLongFilename(filename, allowWildcards, allowRelative);
110
+ }
111
67
- public bool IsValidShortFilename(string filename, bool allowWildcards) => this.backendHelper.IsValidShortFilename(filename, allowWildcards);
112
+ public bool IsValidShortFilename(string filename, bool allowWildcards)
113
+ {
114
+ return this.backendHelper.IsValidShortFilename(filename, allowWildcards);
115
+ }
116
69
- public void ResolveDelayedFields(IEnumerable<IDelayedField> delayedFields, Dictionary<string, string> variableCache) => this.backendHelper.ResolveDelayedFields(delayedFields, variableCache);
117
+ public void ResolveDelayedFields(IEnumerable<IDelayedField> delayedFields, Dictionary<string, string> variableCache)
118
+ {
119
+ this.backendHelper.ResolveDelayedFields(delayedFields, variableCache);
120
+ }
121
71
- public string[] SplitMsiFileName(string value) => this.backendHelper.SplitMsiFileName(value);
122
+ public string[] SplitMsiFileName(string value)
123
+ {
124
+ return this.backendHelper.SplitMsiFileName(value);
125
+ }
126
73
- public ITrackedFile TrackFile(string path, TrackedFileType type, SourceLineNumber sourceLineNumbers = null) => this.backendHelper.TrackFile(path, type, sourceLineNumbers);
127
+ public ITrackedFile TrackFile(string path, TrackedFileType type, SourceLineNumber sourceLineNumbers = null)
128
+ {
129
+ return this.backendHelper.TrackFile(path, type, sourceLineNumbers);
130
+ }
131
132
#endregion
133
@@ -100,6 +157,28 @@ namespace WixToolset.Core.Burn.ExtensibilityServices
157
158
#endregion
159
160
+ #region IBundleValidator
161
+ public string GetCanonicalRelativePath(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string relativePath)
162
+ {
163
+ return this.bundleValidator.GetCanonicalRelativePath(sourceLineNumbers, elementName, attributeName, relativePath);
164
+ }
165
+
166
+ public bool ValidateBundleMsiPropertyName(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string propertyName)
167
+ {
168
+ return this.bundleValidator.ValidateBundleMsiPropertyName(sourceLineNumbers, elementName, attributeName, propertyName);
169
+ }
170
+
171
+ public bool ValidateBundleVariableName(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string variableName)
172
+ {
173
+ return this.bundleValidator.ValidateBundleVariableName(sourceLineNumbers, elementName, attributeName, variableName);
174
+ }
175
+
176
+ public bool ValidateBundleCondition(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string condition, BundleConditionPhase phase)
177
+ {
178
+ return this.bundleValidator.ValidateBundleCondition(sourceLineNumbers, elementName, attributeName, condition, phase);
179
+ }
180
+ #endregion
181
+
182
#region IInternalBurnBackendHelper interfaces
183
184
public void WriteBootstrapperApplicationData(XmlWriter writer)
src/wix/WixToolset.Core.WindowsInstaller/ExtensibilityServices/WindowsInstallerBackendHelper.cs
+76
-21
@@ -23,45 +23,100 @@ namespace WixToolset.Core.WindowsInstaller.ExtensibilityServices
23
24
#region IBackendHelper interfaces
25
26
- public IFileFacade CreateFileFacade(FileSymbol file, AssemblySymbol assembly) => this.backendHelper.CreateFileFacade(file, assembly);
27
-
28
- public IFileFacade CreateFileFacade(FileRow fileRow) => this.backendHelper.CreateFileFacade(fileRow);
26
+ public IFileFacade CreateFileFacade(FileSymbol file, AssemblySymbol assembly)
27
+ {
28
+ return this.backendHelper.CreateFileFacade(file, assembly);
29
+ }
30
30
- public IFileFacade CreateFileFacadeFromMergeModule(FileSymbol fileSymbol) => this.backendHelper.CreateFileFacadeFromMergeModule(fileSymbol);
31
+ public IFileFacade CreateFileFacade(FileRow fileRow)
32
+ {
33
+ return this.backendHelper.CreateFileFacade(fileRow);
34
+ }
35
32
- public IFileTransfer CreateFileTransfer(string source, string destination, bool move, SourceLineNumber sourceLineNumbers = null) => this.backendHelper.CreateFileTransfer(source, destination, move, sourceLineNumbers);
36
+ public IFileFacade CreateFileFacadeFromMergeModule(FileSymbol fileSymbol)
37
+ {
38
+ return this.backendHelper.CreateFileFacadeFromMergeModule(fileSymbol);
39
+ }
40
34
- public string CreateGuid() => this.backendHelper.CreateGuid();
41
+ public IFileTransfer CreateFileTransfer(string source, string destination, bool move, SourceLineNumber sourceLineNumbers = null)
42
+ {
43
+ return this.backendHelper.CreateFileTransfer(source, destination, move, sourceLineNumbers);
44
+ }
45
36
- public string CreateGuid(Guid namespaceGuid, string value) => this.backendHelper.CreateGuid(namespaceGuid, value);
46
+ public string CreateGuid()
47
+ {
48
+ return this.backendHelper.CreateGuid();
49
+ }
50
38
- public IResolvedDirectory CreateResolvedDirectory(string directoryParent, string name) => this.backendHelper.CreateResolvedDirectory(directoryParent, name);
51
+ public string CreateGuid(Guid namespaceGuid, string value)
52
+ {
53
+ return this.backendHelper.CreateGuid(namespaceGuid, value);
54
+ }
55
40
- public IReadOnlyList<ITrackedFile> ExtractEmbeddedFiles(IEnumerable<IExpectedExtractFile> embeddedFiles) => this.backendHelper.ExtractEmbeddedFiles(embeddedFiles);
56
+ public IResolvedDirectory CreateResolvedDirectory(string directoryParent, string name)
57
+ {
58
+ return this.backendHelper.CreateResolvedDirectory(directoryParent, name);
59
+ }
60
42
- public string GenerateIdentifier(string prefix, params string[] args) => this.backendHelper.GenerateIdentifier(prefix, args);
61
+ public IReadOnlyList<ITrackedFile> ExtractEmbeddedFiles(IEnumerable<IExpectedExtractFile> embeddedFiles)
62
+ {
63
+ return this.backendHelper.ExtractEmbeddedFiles(embeddedFiles);
64
+ }
65
44
- public string GetCanonicalRelativePath(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string relativePath) => this.backendHelper.GetCanonicalRelativePath(sourceLineNumbers, elementName, attributeName, relativePath);
66
+ public string GenerateIdentifier(string prefix, params string[] args)
67
+ {
68
+ return this.backendHelper.GenerateIdentifier(prefix, args);
69
+ }
70
46
- public int GetValidCodePage(string value, bool allowNoChange, bool onlyAnsi = false, SourceLineNumber sourceLineNumbers = null) => this.backendHelper.GetValidCodePage(value, allowNoChange, onlyAnsi, sourceLineNumbers);
71
+ public int GetValidCodePage(string value, bool allowNoChange, bool onlyAnsi = false, SourceLineNumber sourceLineNumbers = null)
72
+ {
73
+ return this.backendHelper.GetValidCodePage(value, allowNoChange, onlyAnsi, sourceLineNumbers);
74
+ }
75
48
- public string GetMsiFileName(string value, bool source, bool longName) => this.backendHelper.GetMsiFileName(value, source, longName);
76
+ public string GetMsiFileName(string value, bool source, bool longName)
77
+ {
78
+ return this.backendHelper.GetMsiFileName(value, source, longName);
79
+ }
80
50
- public bool IsValidBinderVariable(string variable) => this.backendHelper.IsValidBinderVariable(variable);
81
+ public bool IsValidBinderVariable(string variable)
82
+ {
83
+ return this.backendHelper.IsValidBinderVariable(variable);
84
+ }
85
52
- public bool IsValidFourPartVersion(string version) => this.backendHelper.IsValidFourPartVersion(version);
86
+ public bool IsValidFourPartVersion(string version)
87
+ {
88
+ return this.backendHelper.IsValidFourPartVersion(version);
89
+ }
90
54
- public bool IsValidIdentifier(string id) => this.backendHelper.IsValidIdentifier(id);
91
+ public bool IsValidIdentifier(string id)
92
+ {
93
+ return this.backendHelper.IsValidIdentifier(id);
94
+ }
95
56
- public bool IsValidLongFilename(string filename, bool allowWildcards, bool allowRelative) => this.backendHelper.IsValidLongFilename(filename, allowWildcards, allowRelative);
96
+ public bool IsValidLongFilename(string filename, bool allowWildcards, bool allowRelative)
97
+ {
98
+ return this.backendHelper.IsValidLongFilename(filename, allowWildcards, allowRelative);
99
+ }
100
58
- public bool IsValidShortFilename(string filename, bool allowWildcards) => this.backendHelper.IsValidShortFilename(filename, allowWildcards);
101
+ public bool IsValidShortFilename(string filename, bool allowWildcards)
102
+ {
103
+ return this.backendHelper.IsValidShortFilename(filename, allowWildcards);
104
+ }
105
60
- public void ResolveDelayedFields(IEnumerable<IDelayedField> delayedFields, Dictionary<string, string> variableCache) => this.backendHelper.ResolveDelayedFields(delayedFields, variableCache);
106
+ public void ResolveDelayedFields(IEnumerable<IDelayedField> delayedFields, Dictionary<string, string> variableCache)
107
+ {
108
+ this.backendHelper.ResolveDelayedFields(delayedFields, variableCache);
109
+ }
110
62
- public string[] SplitMsiFileName(string value) => this.backendHelper.SplitMsiFileName(value);
111
+ public string[] SplitMsiFileName(string value)
112
+ {
113
+ return this.backendHelper.SplitMsiFileName(value);
114
+ }
115
64
- public ITrackedFile TrackFile(string path, TrackedFileType type, SourceLineNumber sourceLineNumbers = null) => this.backendHelper.TrackFile(path, type, sourceLineNumbers);
116
+ public ITrackedFile TrackFile(string path, TrackedFileType type, SourceLineNumber sourceLineNumbers = null)
117
+ {
118
+ return this.backendHelper.TrackFile(path, type, sourceLineNumbers);
119
+ }
120
121
#endregion
122
src/wix/WixToolset.Core/Common.cs
-21
@@ -27,27 +27,6 @@ namespace WixToolset.Core
27
internal static readonly char[] IllegalRelativeLongFilenameCharacters = new[] { '?', '*', '|', '>', '<', ':', '\"' }; // like illegal, but we allow '\' and '/'
28
internal static readonly char[] IllegalWildcardLongFilenameCharacters = new[] { '\\', '/', '|', '>', '<', ':', '\"' }; // like illegal: but we allow '*' and '?'
29
30
- public static string GetCanonicalRelativePath(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string relativePath, IMessaging messageHandler)
31
- {
32
- const string root = @"C:\";
33
- if (!Path.IsPathRooted(relativePath))
34
- {
35
- var normalizedPath = Path.GetFullPath(root + relativePath);
36
- if (normalizedPath.StartsWith(root))
37
- {
38
- var canonicalizedPath = normalizedPath.Substring(root.Length);
39
- if (canonicalizedPath != relativePath)
40
- {
41
- messageHandler.Write(WarningMessages.PathCanonicalized(sourceLineNumbers, elementName, attributeName, relativePath, canonicalizedPath));
42
- }
43
- return canonicalizedPath;
44
- }
45
- }
46
-
47
- messageHandler.Write(ErrorMessages.PayloadMustBeRelativeToCache(sourceLineNumbers, elementName, attributeName, relativePath));
48
- return relativePath;
49
- }
50
-
30
/// <summary>
31
/// Gets a valid code page from the given web name or integer value.
32
/// </summary>
src/wix/WixToolset.Core/CompilerCore.cs
+2
-171
@@ -17,24 +17,6 @@ namespace WixToolset.Core
17
using WixToolset.Extensibility.Data;
18
using WixToolset.Extensibility.Services;
19
20
- internal enum ValueListKind
21
- {
22
- /// <summary>
23
- /// A list of values with nothing before the final value.
24
- /// </summary>
25
- None,
26
-
27
- /// <summary>
28
- /// A list of values with 'and' before the final value.
29
- /// </summary>
30
- And,
31
-
32
- /// <summary>
33
- /// A list of values with 'or' before the final value.
34
- /// </summary>
35
- Or
36
- }
37
-
20
/// <summary>
21
/// Core class for the compiler.
22
/// </summary>
@@ -43,80 +25,6 @@ namespace WixToolset.Core
25
internal static readonly XNamespace W3SchemaPrefix = "http://www.w3.org/";
26
internal static readonly XNamespace WixNamespace = "http://wixtoolset.org/schemas/v4/wxs";
27
46
- // Built-in variables (from burn\engine\variable.cpp, "vrgBuiltInVariables", around line 113)
47
- private static readonly List<string> BuiltinBundleVariables = new List<string>(
48
- new string[] {
49
- "AdminToolsFolder",
50
- "AppDataFolder",
51
- "CommonAppDataFolder",
52
- "CommonFiles64Folder",
53
- "CommonFilesFolder",
54
- "CompatibilityMode",
55
- "Date",
56
- "DesktopFolder",
57
- "FavoritesFolder",
58
- "FontsFolder",
59
- "InstallerName",
60
- "InstallerVersion",
61
- "LocalAppDataFolder",
62
- "LogonUser",
63
- "MyPicturesFolder",
64
- "NativeMachine",
65
- "NTProductType",
66
- "NTSuiteBackOffice",
67
- "NTSuiteDataCenter",
68
- "NTSuiteEnterprise",
69
- "NTSuitePersonal",
70
- "NTSuiteSmallBusiness",
71
- "NTSuiteSmallBusinessRestricted",
72
- "NTSuiteWebServer",
73
- "PersonalFolder",
74
- "Privileged",
75
- "ProgramFiles64Folder",
76
- "ProgramFiles6432Folder",
77
- "ProgramFilesFolder",
78
- "ProgramMenuFolder",
79
- "RebootPending",
80
- "SendToFolder",
81
- "ServicePackLevel",
82
- "StartMenuFolder",
83
- "StartupFolder",
84
- "System64Folder",
85
- "SystemFolder",
86
- "TempFolder",
87
- "TemplateFolder",
88
- "TerminalServer",
89
- "UserLanguageID",
90
- "UserUILanguageID",
91
- "VersionMsi",
92
- "VersionNT",
93
- "VersionNT64",
94
- "WindowsFolder",
95
- "WindowsVolume",
96
- "WixBundleAction",
97
- "WixBundleCommandLineAction",
98
- "WixBundleForcedRestartPackage",
99
- "WixBundleElevated",
100
- "WixBundleInstalled",
101
- "WixBundleProviderKey",
102
- "WixBundleTag",
103
- "WixBundleVersion",
104
- });
105
-
106
- private static readonly List<string> DisallowedMsiProperties = new List<string>(
107
- new string[] {
108
- "ACTION",
109
- "ADDLOCAL",
110
- "ADDSOURCE",
111
- "ADDDEFAULT",
112
- "ADVERTISE",
113
- "ALLUSERS",
114
- "REBOOT",
115
- "REINSTALL",
116
- "REINSTALLMODE",
117
- "REMOVE"
118
- });
119
-
28
private readonly Dictionary<XNamespace, ICompilerExtension> extensions;
29
private readonly IParseHelper parseHelper;
30
private readonly Intermediate intermediate;
@@ -857,11 +765,7 @@ namespace WixToolset.Core
765
766
if (!String.IsNullOrEmpty(value))
767
{
860
- if (CompilerCore.BuiltinBundleVariables.Contains(value))
861
- {
862
- string illegalValues = CompilerCore.CreateValueList(ValueListKind.Or, CompilerCore.BuiltinBundleVariables);
863
- this.Write(ErrorMessages.IllegalAttributeValueWithIllegalList(sourceLineNumbers, attribute.Parent.Name.LocalName, attribute.Name.LocalName, value, illegalValues));
864
- }
768
+ this.parseHelper.ValidateBundleVariableName(sourceLineNumbers, attribute.Parent.Name.LocalName, attribute.Name.LocalName, value);
769
}
770
771
return value;
@@ -879,11 +783,7 @@ namespace WixToolset.Core
783
784
if (0 < value.Length)
785
{
882
- if (CompilerCore.DisallowedMsiProperties.Contains(value))
883
- {
884
- string illegalValues = CompilerCore.CreateValueList(ValueListKind.Or, CompilerCore.DisallowedMsiProperties);
885
- this.Write(ErrorMessages.DisallowedMsiProperty(sourceLineNumbers, value, illegalValues));
886
- }
786
+ this.parseHelper.ValidateBundleMsiPropertyName(sourceLineNumbers, attribute.Parent.Name.LocalName, attribute.Name.LocalName, value);
787
}
788
789
return value;
@@ -1095,74 +995,5 @@ namespace WixToolset.Core
995
{
996
return this.parseHelper.ScheduleActionSymbol(this.ActiveSection, sourceLineNumbers, access, sequence, actionName, condition, beforeAction, afterAction, overridable);
997
}
1098
-
1099
- private static string CreateValueList(ValueListKind kind, IEnumerable<string> values)
1100
- {
1101
- // Ideally, we could denote the list kind (and the list itself) directly in the
1102
- // message XML, and detect and expand in the MessageHandler.GenerateMessageString()
1103
- // method. Doing so would make vararg-style messages much easier, but impacts
1104
- // every single message we format. For now, callers just have to know when a
1105
- // message takes a list of values in a single string argument, the caller will
1106
- // have to do the expansion themselves. (And, unfortunately, hard-code the knowledge
1107
- // that the list is an 'and' or 'or' list.)
1108
-
1109
- // For a localizable solution, we need to be able to get the list format string
1110
- // from resources. We aren't currently localized right now, so the values are
1111
- // just hard-coded.
1112
- const string valueFormat = "'{0}'";
1113
- const string valueSeparator = ", ";
1114
- string terminalTerm = String.Empty;
1115
-
1116
- switch (kind)
1117
- {
1118
- case ValueListKind.None:
1119
- terminalTerm = "";
1120
- break;
1121
- case ValueListKind.And:
1122
- terminalTerm = "and ";
1123
- break;
1124
- case ValueListKind.Or:
1125
- terminalTerm = "or ";
1126
- break;
1127
- }
1128
-
1129
- StringBuilder list = new StringBuilder();
1130
-
1131
- // This weird construction helps us determine when we're adding the last value
1132
- // to the list. Instead of adding them as we encounter them, we cache the current
1133
- // value and append the *previous* one.
1134
- string previousValue = null;
1135
- bool haveValues = false;
1136
- foreach (string value in values)
1137
- {
1138
- if (null != previousValue)
1139
- {
1140
- if (haveValues)
1141
- {
1142
- list.Append(valueSeparator);
1143
- }
1144
- list.AppendFormat(valueFormat, previousValue);
1145
- haveValues = true;
1146
- }
1147
-
1148
- previousValue = value;
1149
- }
1150
-
1151
- // If we have no previous value, that means that the list contained no values, and
1152
- // something has gone very wrong.
1153
- Debug.Assert(null != previousValue);
1154
- if (null != previousValue)
1155
- {
1156
- if (haveValues)
1157
- {
1158
- list.Append(valueSeparator);
1159
- list.Append(terminalTerm);
1160
- }
1161
- list.AppendFormat(valueFormat, previousValue);
1162
- haveValues = true;
1163
- }
1164
-
1165
- return list.ToString();
1166
- }
998
}
999
}
src/wix/WixToolset.Core/ExtensibilityServices/BackendHelper.cs
-5
@@ -64,11 +64,6 @@ namespace WixToolset.Core.ExtensibilityServices
64
return Common.GenerateIdentifier(prefix, args);
65
}
66
67
- public string GetCanonicalRelativePath(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string relativePath)
68
- {
69
- return Common.GetCanonicalRelativePath(sourceLineNumbers, elementName, attributeName, relativePath, this.Messaging);
70
- }
71
-
67
public int GetValidCodePage(string value, bool allowNoChange = false, bool onlyAnsi = false, SourceLineNumber sourceLineNumbers = null)
68
{
69
return Common.GetValidCodePage(value, allowNoChange, onlyAnsi, sourceLineNumbers);
src/wix/WixToolset.Core/ExtensibilityServices/BundleValidator.cs
new
+326
@@ -0,0 +1,326 @@
1
+// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
+
3
+namespace WixToolset.Core.ExtensibilityServices
4
+{
5
+ using System;
6
+ using System.Collections.Generic;
7
+ using System.Diagnostics;
8
+ using System.IO;
9
+ using System.Text;
10
+ using WixToolset.Data;
11
+ using WixToolset.Extensibility.Data;
12
+ using WixToolset.Extensibility.Services;
13
+
14
+ internal class BundleValidator : IBundleValidator
15
+ {
16
+ public BundleValidator(IServiceProvider serviceProvider)
17
+ {
18
+ this.Messaging = serviceProvider.GetService<IMessaging>();
19
+ }
20
+
21
+ protected IMessaging Messaging { get; }
22
+
23
+ private enum ValueListKind
24
+ {
25
+ /// <summary>
26
+ /// A list of values with nothing before the final value.
27
+ /// </summary>
28
+ None,
29
+
30
+ /// <summary>
31
+ /// A list of values with 'and' before the final value.
32
+ /// </summary>
33
+ And,
34
+
35
+ /// <summary>
36
+ /// A list of values with 'or' before the final value.
37
+ /// </summary>
38
+ Or,
39
+ }
40
+
41
+ // Built-in variables (from burn\engine\variable.cpp, "vrgBuiltInVariables", around line 207)
42
+ private static readonly List<string> BuiltinBundleVariables = new List<string>(
43
+ new string[] {
44
+ "AdminToolsFolder",
45
+ "AppDataFolder",
46
+ "CommonAppDataFolder",
47
+ "CommonFiles64Folder",
48
+ "CommonFilesFolder",
49
+ "CompatibilityMode",
50
+ "Date",
51
+ "DesktopFolder",
52
+ "FavoritesFolder",
53
+ "FontsFolder",
54
+ "InstallerName",
55
+ "InstallerVersion",
56
+ "LocalAppDataFolder",
57
+ "LogonUser",
58
+ "MyPicturesFolder",
59
+ "NativeMachine",
60
+ "NTProductType",
61
+ "NTSuiteBackOffice",
62
+ "NTSuiteDataCenter",
63
+ "NTSuiteEnterprise",
64
+ "NTSuitePersonal",
65
+ "NTSuiteSmallBusiness",
66
+ "NTSuiteSmallBusinessRestricted",
67
+ "NTSuiteWebServer",
68
+ "PersonalFolder",
69
+ "Privileged",
70
+ "ProgramFiles64Folder",
71
+ "ProgramFiles6432Folder",
72
+ "ProgramFilesFolder",
73
+ "ProgramMenuFolder",
74
+ "RebootPending",
75
+ "SendToFolder",
76
+ "ServicePackLevel",
77
+ "StartMenuFolder",
78
+ "StartupFolder",
79
+ "System64Folder",
80
+ "SystemFolder",
81
+ "TempFolder",
82
+ "TemplateFolder",
83
+ "TerminalServer",
84
+ "UserLanguageID",
85
+ "UserUILanguageID",
86
+ "VersionMsi",
87
+ "VersionNT",
88
+ "VersionNT64",
89
+ "WindowsFolder",
90
+ "WindowsVolume",
91
+ "WixBundleAction",
92
+ "WixBundleCommandLineAction",
93
+ "WixBundleForcedRestartPackage",
94
+ "WixBundleElevated",
95
+ "WixBundleInstalled",
96
+ "WixBundleProviderKey",
97
+ "WixBundleTag",
98
+ "WixBundleVersion",
99
+ });
100
+
101
+ private static readonly List<string> DisallowedMsiProperties = new List<string>(
102
+ new string[] {
103
+ "ACTION",
104
+ "ADDLOCAL",
105
+ "ADDSOURCE",
106
+ "ADDDEFAULT",
107
+ "ADVERTISE",
108
+ "ALLUSERS",
109
+ "REBOOT",
110
+ "REINSTALL",
111
+ "REINSTALLMODE",
112
+ "REMOVE"
113
+ });
114
+
115
+ private static readonly List<string> UnavailableStartupVariables = new List<string>(
116
+ new string[] {
117
+ "RebootPending",
118
+ "WixBundleAction",
119
+ "WixBundleInstalled",
120
+ });
121
+
122
+ private static readonly List<string> UnavailableDetectVariables = new List<string>(
123
+ new string[] {
124
+ "WixBundleAction",
125
+ });
126
+
127
+ public string GetCanonicalRelativePath(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string relativePath)
128
+ {
129
+ const string root = @"C:\";
130
+ if (!Path.IsPathRooted(relativePath))
131
+ {
132
+ var normalizedPath = Path.GetFullPath(root + relativePath);
133
+ if (normalizedPath.StartsWith(root))
134
+ {
135
+ var canonicalizedPath = normalizedPath.Substring(root.Length);
136
+ if (canonicalizedPath != relativePath)
137
+ {
138
+ this.Messaging.Write(WarningMessages.PathCanonicalized(sourceLineNumbers, elementName, attributeName, relativePath, canonicalizedPath));
139
+ }
140
+ return canonicalizedPath;
141
+ }
142
+ }
143
+
144
+ this.Messaging.Write(ErrorMessages.PayloadMustBeRelativeToCache(sourceLineNumbers, elementName, attributeName, relativePath));
145
+ return relativePath;
146
+ }
147
+
148
+ public bool ValidateBundleVariableName(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string variableName)
149
+ {
150
+ if (String.IsNullOrEmpty(variableName))
151
+ {
152
+ this.Messaging.Write(ErrorMessages.IllegalEmptyAttributeValue(sourceLineNumbers, elementName, attributeName));
153
+
154
+ return false;
155
+ }
156
+ else if (BuiltinBundleVariables.Contains(variableName))
157
+ {
158
+ var illegalValues = CreateValueList(ValueListKind.Or, BuiltinBundleVariables);
159
+ this.Messaging.Write(ErrorMessages.IllegalAttributeValueWithIllegalList(sourceLineNumbers, elementName, attributeName, variableName, illegalValues));
160
+
161
+ return false;
162
+ }
163
+ else
164
+ {
165
+ return true;
166
+ }
167
+ }
168
+
169
+ public bool ValidateBundleMsiPropertyName(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string propertyName)
170
+ {
171
+ if (String.IsNullOrEmpty(propertyName))
172
+ {
173
+ this.Messaging.Write(ErrorMessages.IllegalEmptyAttributeValue(sourceLineNumbers, elementName, attributeName));
174
+
175
+ return false;
176
+ }
177
+ else if (DisallowedMsiProperties.Contains(propertyName))
178
+ {
179
+ var illegalValues = CreateValueList(ValueListKind.Or, DisallowedMsiProperties);
180
+ this.Messaging.Write(ErrorMessages.DisallowedMsiProperty(sourceLineNumbers, propertyName, illegalValues));
181
+
182
+ return false;
183
+ }
184
+ else
185
+ {
186
+ return true;
187
+ }
188
+ }
189
+
190
+ public bool ValidateBundleCondition(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string condition, BundleConditionPhase phase)
191
+ {
192
+ if (!this.TryParseCondition(sourceLineNumbers, elementName, attributeName, condition))
193
+ {
194
+ return false;
195
+ }
196
+
197
+
198
+ // TODO: These lists are incomplete.
199
+ List<string> unavailableVariables = null;
200
+ switch (phase)
201
+ {
202
+ case BundleConditionPhase.Startup:
203
+ unavailableVariables = UnavailableStartupVariables;
204
+ break;
205
+ case BundleConditionPhase.Detect:
206
+ unavailableVariables = UnavailableDetectVariables;
207
+ break;
208
+ }
209
+
210
+ if (unavailableVariables != null)
211
+ {
212
+ return this.ValidateBundleConditionUnavailableVariables(sourceLineNumbers, elementName, attributeName, condition, unavailableVariables);
213
+ }
214
+ else
215
+ {
216
+ return true;
217
+ }
218
+ }
219
+
220
+ private bool ValidateBundleConditionUnavailableVariables(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string condition, List<string> unavailableVariables)
221
+ {
222
+ foreach (var variableName in unavailableVariables)
223
+ {
224
+ //TODO: use the results of parsing to validate that the restricted variables are actually used as variables
225
+ if (condition.Contains(variableName))
226
+ {
227
+ var illegalValues = CreateValueList(ValueListKind.Or, unavailableVariables);
228
+ this.Messaging.Write(WarningMessages.UnavailableBundleConditionVariable(sourceLineNumbers, elementName, attributeName, variableName, illegalValues));
229
+
230
+ return false;
231
+ }
232
+ }
233
+
234
+ return true;
235
+ }
236
+
237
+ private bool TryParseCondition(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string condition)
238
+ {
239
+ if (String.IsNullOrEmpty(condition))
240
+ {
241
+ this.Messaging.Write(ErrorMessages.IllegalEmptyAttributeValue(sourceLineNumbers, elementName, attributeName));
242
+
243
+ return false;
244
+ }
245
+ //TODO: Actually parse the condition to definitively tell which Variables are referenced.
246
+ else if (condition.Trim() == "=")
247
+ {
248
+ this.Messaging.Write(ErrorMessages.InvalidBundleCondition(sourceLineNumbers, elementName, attributeName, condition));
249
+ return false;
250
+ }
251
+ else
252
+ {
253
+ return true;
254
+ }
255
+ }
256
+
257
+ private static string CreateValueList(ValueListKind kind, IEnumerable<string> values)
258
+ {
259
+ // Ideally, we could denote the list kind (and the list itself) directly in the
260
+ // message XML, and detect and expand in the MessageHandler.GenerateMessageString()
261
+ // method. Doing so would make vararg-style messages much easier, but impacts
262
+ // every single message we format. For now, callers just have to know when a
263
+ // message takes a list of values in a single string argument, the caller will
264
+ // have to do the expansion themselves. (And, unfortunately, hard-code the knowledge
265
+ // that the list is an 'and' or 'or' list.)
266
+
267
+ // For a localizable solution, we need to be able to get the list format string
268
+ // from resources. We aren't currently localized right now, so the values are
269
+ // just hard-coded.
270
+ const string valueFormat = "'{0}'";
271
+ const string valueSeparator = ", ";
272
+ var terminalTerm = String.Empty;
273
+
274
+ switch (kind)
275
+ {
276
+ case ValueListKind.None:
277
+ terminalTerm = "";
278
+ break;
279
+ case ValueListKind.And:
280
+ terminalTerm = "and ";
281
+ break;
282
+ case ValueListKind.Or:
283
+ terminalTerm = "or ";
284
+ break;
285
+ }
286
+
287
+ var list = new StringBuilder();
288
+
289
+ // This weird construction helps us determine when we're adding the last value
290
+ // to the list. Instead of adding them as we encounter them, we cache the current
291
+ // value and append the *previous* one.
292
+ string previousValue = null;
293
+ var haveValues = false;
294
+ foreach (var value in values)
295
+ {
296
+ if (null != previousValue)
297
+ {
298
+ if (haveValues)
299
+ {
300
+ list.Append(valueSeparator);
301
+ }
302
+ list.AppendFormat(valueFormat, previousValue);
303
+ haveValues = true;
304
+ }
305
+
306
+ previousValue = value;
307
+ }
308
+
309
+ // If we have no previous value, that means that the list contained no values, and
310
+ // something has gone very wrong.
311
+ Debug.Assert(null != previousValue);
312
+ if (null != previousValue)
313
+ {
314
+ if (haveValues)
315
+ {
316
+ list.Append(valueSeparator);
317
+ list.Append(terminalTerm);
318
+ }
319
+ list.AppendFormat(valueFormat, previousValue);
320
+ //haveValues = true;
321
+ }
322
+
323
+ return list.ToString();
324
+ }
325
+ }
326
+}
src/wix/WixToolset.Core/ExtensibilityServices/ParseHelper.cs
+29
-6
@@ -22,11 +22,14 @@ namespace WixToolset.Core.ExtensibilityServices
22
{
23
this.ServiceProvider = serviceProvider;
24
25
+ this.BundleValidator = serviceProvider.GetService<IBundleValidator>();
26
this.Messaging = serviceProvider.GetService<IMessaging>();
27
}
28
29
private IServiceProvider ServiceProvider { get; }
30
31
+ private IBundleValidator BundleValidator { get; }
32
+
33
private IMessaging Messaging { get; }
34
35
private ISymbolDefinitionCreator Creator { get; set; }
@@ -239,11 +242,14 @@ namespace WixToolset.Core.ExtensibilityServices
242
243
public void CreateWixSearchSymbol(IntermediateSection section, SourceLineNumber sourceLineNumbers, string elementName, Identifier id, string variable, string condition, string after, string bundleExtensionId)
244
{
242
- // TODO: verify variable is not a standard bundle variable
245
if (variable == null)
246
{
247
this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, elementName, "Variable"));
248
}
249
+ else
250
+ {
251
+ this.BundleValidator.ValidateBundleVariableName(sourceLineNumbers, elementName, "Variable", variable);
252
+ }
253
254
section.AddSymbol(new WixSearchSymbol(sourceLineNumbers, id)
255
{
@@ -623,11 +629,6 @@ namespace WixToolset.Core.ExtensibilityServices
629
}
630
}
631
626
- public string GetCanonicalRelativePath(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string relativePath)
627
- {
628
- return Common.GetCanonicalRelativePath(sourceLineNumbers, elementName, attributeName, relativePath, this.Messaging);
629
- }
630
-
632
public SourceLineNumber GetSourceLineNumbers(XElement element)
633
{
634
return Preprocessor.GetSourceLineNumbers(element);
@@ -858,5 +859,27 @@ namespace WixToolset.Core.ExtensibilityServices
859
860
return extension != null;
861
}
862
+
863
+ #region IBundleValidator
864
+ public string GetCanonicalRelativePath(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string relativePath)
865
+ {
866
+ return this.BundleValidator.GetCanonicalRelativePath(sourceLineNumbers, elementName, attributeName, relativePath);
867
+ }
868
+
869
+ public bool ValidateBundleMsiPropertyName(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string propertyName)
870
+ {
871
+ return this.BundleValidator.ValidateBundleMsiPropertyName(sourceLineNumbers, elementName, attributeName, propertyName);
872
+ }
873
+
874
+ public bool ValidateBundleVariableName(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string variableName)
875
+ {
876
+ return this.BundleValidator.ValidateBundleVariableName(sourceLineNumbers, elementName, attributeName, variableName);
877
+ }
878
+
879
+ public bool ValidateBundleCondition(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string condition, BundleConditionPhase phase)
880
+ {
881
+ return this.BundleValidator.ValidateBundleCondition(sourceLineNumbers, elementName, attributeName, condition, phase);
882
+ }
883
+ #endregion
884
}
885
}
src/wix/WixToolset.Core/WixToolsetServiceProvider.cs
+1
@@ -20,6 +20,7 @@ namespace WixToolset.Core
20
// Singletons.
21
this.AddService((provider, singletons) => AddSingleton<IExtensionManager>(singletons, new ExtensionManager(provider)));
22
this.AddService((provider, singletons) => AddSingleton<IMessaging>(singletons, new Messaging()));
23
+ this.AddService((provider, singletons) => AddSingleton<IBundleValidator>(singletons, new BundleValidator(provider)));
24
this.AddService((provider, singletons) => AddSingleton<ISymbolDefinitionCreator>(singletons, new SymbolDefinitionCreator(provider)));
25
this.AddService((provider, singletons) => AddSingleton<IParseHelper>(singletons, new ParseHelper(provider)));
26
this.AddService((provider, singletons) => AddSingleton<IPreprocessHelper>(singletons, new PreprocessHelper(provider)));
src/wix/test/WixToolsetTest.CoreIntegration/BadInputFixture.cs
+43
@@ -4,6 +4,7 @@ namespace WixToolsetTest.CoreIntegration
4
{
5
using System;
6
using System.IO;
7
+ using System.Linq;
8
using WixBuildTools.TestSupport;
9
using WixToolset.Core.TestPackage;
10
using Xunit;
@@ -129,5 +130,47 @@ namespace WixToolsetTest.CoreIntegration
130
Assert.Equal(193, result.ExitCode);
131
}
132
}
133
+
134
+ [Fact]
135
+ public void GuardsAgainstVariousBundleValuesFromLoc()
136
+ {
137
+ var folder = TestData.Get(@"TestData");
138
+
139
+ using (var fs = new DisposableFileSystem())
140
+ {
141
+ var baseFolder = fs.GetFolder();
142
+ var intermediateFolder = Path.Combine(baseFolder, "obj");
143
+
144
+ var result = WixRunner.Execute(new[]
145
+ {
146
+ "build",
147
+ Path.Combine(folder, "BundleWithInvalid", "BundleWithInvalidLocValues.wxs"),
148
+ "-loc", Path.Combine(folder, "BundleWithInvalid", "BundleWithInvalidLocValues.wxl"),
149
+ "-bindpath", Path.Combine(folder, ".Data"),
150
+ "-bindpath", Path.Combine(folder, "DecompileSingleFileCompressed"),
151
+ "-bindpath", Path.Combine(folder, "SimpleBundle", "data"),
152
+ "-intermediateFolder", intermediateFolder,
153
+ "-o", Path.Combine(baseFolder, @"bin\test.exe")
154
+ });
155
+
156
+ Assert.InRange(result.ExitCode, 2, Int32.MaxValue);
157
+
158
+ var messages = result.Messages.Select(m => m.ToString()).ToList();
159
+ messages.Sort();
160
+
161
+ WixAssert.CompareLineByLine(new[]
162
+ {
163
+ "*Search/@Condition contains the built-in Variable 'WixBundleAction', which is not available when it is evaluated. (Unavailable Variables are: 'WixBundleAction'.). Rewrite the condition to avoid Variables that are never valid during its evaluation.",
164
+ "Bundle/@Condition contains the built-in Variable 'WixBundleInstalled', which is not available when it is evaluated. (Unavailable Variables are: 'RebootPending', 'WixBundleAction', or 'WixBundleInstalled'.). Rewrite the condition to avoid Variables that are never valid during its evaluation.",
165
+ "ExePackage/@DetectCondition contains the built-in Variable 'WixBundleAction', which is not available when it is evaluated. (Unavailable Variables are: 'WixBundleAction'.). Rewrite the condition to avoid Variables that are never valid during its evaluation.",
166
+ "The *Search/@Variable attribute's value, 'WixBundleInstalled', is one of the illegal options: 'AdminToolsFolder', 'AppDataFolder', 'CommonAppDataFolder', 'CommonFiles64Folder', 'CommonFilesFolder', 'CompatibilityMode', 'Date', 'DesktopFolder', 'FavoritesFolder', 'FontsFolder', 'InstallerName', 'InstallerVersion', 'LocalAppDataFolder', 'LogonUser', 'MyPicturesFolder', 'NativeMachine', 'NTProductType', 'NTSuiteBackOffice', 'NTSuiteDataCenter', 'NTSuiteEnterprise', 'NTSuitePersonal', 'NTSuiteSmallBusiness', 'NTSuiteSmallBusinessRestricted', 'NTSuiteWebServer', 'PersonalFolder', 'Privileged', 'ProgramFiles64Folder', 'ProgramFiles6432Folder', 'ProgramFilesFolder', 'ProgramMenuFolder', 'RebootPending', 'SendToFolder', 'ServicePackLevel', 'StartMenuFolder', 'StartupFolder', 'System64Folder', 'SystemFolder', 'TempFolder', 'TemplateFolder', 'TerminalServer', 'UserLanguageID', 'UserUILanguageID', 'VersionMsi', 'VersionNT', 'VersionNT64', 'WindowsFolder', 'WindowsVolume', 'WixBundleAction', 'WixBundleCommandLineAction', 'WixBundleForcedRestartPackage', 'WixBundleElevated', 'WixBundleInstalled', 'WixBundleProviderKey', 'WixBundleTag', or 'WixBundleVersion'.",
167
+ "The CommandLine/@Condition attribute's value '=' is not a valid bundle condition.",
168
+ "The MsiPackage/@InstallCondition attribute's value '=' is not a valid bundle condition.",
169
+ "The MsiProperty/@Condition attribute's value '=' is not a valid bundle condition.",
170
+ //"The Variable/@Name attribute's value, 'WixBundleInstalled', is one of the illegal options: 'AdminToolsFolder', 'AppDataFolder', 'CommonAppDataFolder', 'CommonFiles64Folder', 'CommonFilesFolder', 'CompatibilityMode', 'Date', 'DesktopFolder', 'FavoritesFolder', 'FontsFolder', 'InstallerName', 'InstallerVersion', 'LocalAppDataFolder', 'LogonUser', 'MyPicturesFolder', 'NativeMachine', 'NTProductType', 'NTSuiteBackOffice', 'NTSuiteDataCenter', 'NTSuiteEnterprise', 'NTSuitePersonal', 'NTSuiteSmallBusiness', 'NTSuiteSmallBusinessRestricted', 'NTSuiteWebServer', 'PersonalFolder', 'Privileged', 'ProgramFiles64Folder', 'ProgramFiles6432Folder', 'ProgramFilesFolder', 'ProgramMenuFolder', 'RebootPending', 'SendToFolder', 'ServicePackLevel', 'StartMenuFolder', 'StartupFolder', 'System64Folder', 'SystemFolder', 'TempFolder', 'TemplateFolder', 'TerminalServer', 'UserLanguageID', 'UserUILanguageID', 'VersionMsi', 'VersionNT', 'VersionNT64', 'WindowsFolder', 'WindowsVolume', 'WixBundleAction', 'WixBundleCommandLineAction', 'WixBundleForcedRestartPackage', 'WixBundleElevated', 'WixBundleInstalled', 'WixBundleProviderKey', 'WixBundleTag', or 'WixBundleVersion'.",
171
+ "The 'REINSTALLMODE' MsiProperty is controlled by the bootstrapper and cannot be authored. (Illegal properties are: 'ACTION', 'ADDLOCAL', 'ADDSOURCE', 'ADDDEFAULT', 'ADVERTISE', 'ALLUSERS', 'REBOOT', 'REINSTALL', 'REINSTALLMODE', or 'REMOVE'.) Remove the MsiProperty element.",
172
+ }, messages.ToArray());
173
+ }
174
+ }
175
}
176
}
src/wix/test/WixToolsetTest.CoreIntegration/TestData/BundleWithInvalid/BundleWithInvalidLocValues.wxl
new
+8
@@ -0,0 +1,8 @@
1
+<WixLocalization xmlns="http://wixtoolset.org/schemas/v4/wxl" Culture="en-US">
2
+ <String Id="BuiltinMsiPropertyName">REINSTALLMODE</String>
3
+ <String Id="BuiltinBurnVariableName">WixBundleInstalled</String>
4
+ <String Id="NonsenseDetectCondition">WixBundleAction = 4</String>
5
+ <String Id="NonsenseExecuteCondition">=</String>
6
+ <String Id="NonsenseGlobalCondition">WixBundleInstalled <> 1</String>
7
+ <String Id="NonsensePlanCondition">=</String>
8
+</WixLocalization>
src/wix/test/WixToolsetTest.CoreIntegration/TestData/BundleWithInvalid/BundleWithInvalidLocValues.wxs
new
+18
@@ -0,0 +1,18 @@
1
+<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
2
+ <Bundle Name="BundleWithInvalidUpgradeCode" Condition="!(loc.NonsenseGlobalCondition)"
3
+ Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="{F2A56B65-2105-44C8-A532-A93A8C169D07}">
4
+ <BootstrapperApplication>
5
+ <BootstrapperApplicationDll SourceFile="fakeba.dll" />
6
+ </BootstrapperApplication>
7
+ <Chain>
8
+ <MsiPackage SourceFile="example.msi" InstallCondition="!(loc.NonsensePlanCondition)">
9
+ <MsiProperty Condition="!(loc.NonsenseExecuteCondition)" Name="!(loc.BuiltinMsiPropertyName)" Value="1" />
10
+ </MsiPackage>
11
+ <ExePackage DetectCondition="!(loc.NonsenseDetectCondition)" UninstallArguments="-uninstall" SourceFile="burn.exe">
12
+ <CommandLine Condition="!(loc.NonsenseExecuteCondition)" />
13
+ </ExePackage>
14
+ </Chain>
15
+ <Variable Name="!(loc.BuiltinBurnVariableName)" Value="1" />
16
+ <SetVariable Id="Builtin" Condition="!(loc.NonsenseDetectCondition)" Variable="!(loc.BuiltinBurnVariableName)" Value="1" />
17
+ </Bundle>
18
+</Wix>