diff options
Diffstat (limited to 'src/wixext/DependencyCompiler.cs')
-rw-r--r-- | src/wixext/DependencyCompiler.cs | 542 |
1 files changed, 15 insertions, 527 deletions
diff --git a/src/wixext/DependencyCompiler.cs b/src/wixext/DependencyCompiler.cs index 18bb89df..0405c324 100644 --- a/src/wixext/DependencyCompiler.cs +++ b/src/wixext/DependencyCompiler.cs | |||
@@ -2,13 +2,9 @@ | |||
2 | 2 | ||
3 | namespace WixToolset.Dependency | 3 | namespace WixToolset.Dependency |
4 | { | 4 | { |
5 | using System; | ||
6 | using System.Collections.Generic; | 5 | using System.Collections.Generic; |
7 | using System.Text; | ||
8 | using System.Xml.Linq; | 6 | using System.Xml.Linq; |
9 | using WixToolset.Data; | 7 | using WixToolset.Data; |
10 | using WixToolset.Data.Symbols; | ||
11 | using WixToolset.Dependency.Symbols; | ||
12 | using WixToolset.Extensibility; | 8 | using WixToolset.Extensibility; |
13 | using WixToolset.Extensibility.Data; | 9 | using WixToolset.Extensibility.Data; |
14 | 10 | ||
@@ -17,18 +13,6 @@ namespace WixToolset.Dependency | |||
17 | /// </summary> | 13 | /// </summary> |
18 | public sealed class DependencyCompiler : BaseCompilerExtension | 14 | public sealed class DependencyCompiler : BaseCompilerExtension |
19 | { | 15 | { |
20 | /// <summary> | ||
21 | /// Package type when parsing the Provides element. | ||
22 | /// </summary> | ||
23 | private enum PackageType | ||
24 | { | ||
25 | None, | ||
26 | ExePackage, | ||
27 | MsiPackage, | ||
28 | MspPackage, | ||
29 | MsuPackage | ||
30 | } | ||
31 | |||
32 | public override XNamespace Namespace => "http://wixtoolset.org/schemas/v4/wxs/dependency"; | 16 | public override XNamespace Namespace => "http://wixtoolset.org/schemas/v4/wxs/dependency"; |
33 | 17 | ||
34 | /// <summary> | 18 | /// <summary> |
@@ -40,534 +24,38 @@ namespace WixToolset.Dependency | |||
40 | public override void ParseAttribute(Intermediate intermediate, IntermediateSection section, XElement parentElement, XAttribute attribute, IDictionary<string, string> context) | 24 | public override void ParseAttribute(Intermediate intermediate, IntermediateSection section, XElement parentElement, XAttribute attribute, IDictionary<string, string> context) |
41 | { | 25 | { |
42 | var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(parentElement); | 26 | var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(parentElement); |
43 | switch (parentElement.Name.LocalName) | 27 | var addCheck = YesNoType.NotSet; |
44 | { | 28 | var addRequire = YesNoType.NotSet; |
45 | case "Bundle": | ||
46 | switch (attribute.Name.LocalName) | ||
47 | { | ||
48 | case "ProviderKey": | ||
49 | this.ParseProviderKeyAttribute(section, sourceLineNumbers, parentElement, attribute); | ||
50 | break; | ||
51 | default: | ||
52 | this.ParseHelper.UnexpectedAttribute(parentElement, attribute); | ||
53 | break; | ||
54 | } | ||
55 | break; | ||
56 | default: | ||
57 | this.ParseHelper.UnexpectedAttribute(parentElement, attribute); | ||
58 | break; | ||
59 | } | ||
60 | } | ||
61 | |||
62 | /// <summary> | ||
63 | /// Processes an element for the Compiler. | ||
64 | /// </summary> | ||
65 | /// <param name="sourceLineNumbers">Source line number for the parent element.</param> | ||
66 | /// <param name="parentElement">Parent element of element to process.</param> | ||
67 | /// <param name="element">Element to process.</param> | ||
68 | /// <param name="contextValues">Extra information about the context in which this element is being parsed.</param> | ||
69 | public override void ParseElement(Intermediate intermediate, IntermediateSection section, XElement parentElement, XElement element, IDictionary<string, string> context) | ||
70 | { | ||
71 | var packageType = PackageType.None; | ||
72 | 29 | ||
73 | switch (parentElement.Name.LocalName) | 30 | switch (parentElement.Name.LocalName) |
74 | { | 31 | { |
75 | case "Bundle": | 32 | case "Provides": |
76 | case "Fragment": | 33 | if (attribute.Name.LocalName == "Check" && parentElement.Parent.Name.LocalName == "Component") |
77 | case "Module": | ||
78 | case "Package": | ||
79 | switch (element.Name.LocalName) | ||
80 | { | 34 | { |
81 | case "Requires": | 35 | addCheck = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attribute); |
82 | this.ParseRequiresElement(intermediate, section, element, null, false); | ||
83 | break; | ||
84 | default: | ||
85 | this.ParseHelper.UnexpectedElement(parentElement, element); | ||
86 | break; | ||
87 | } | 36 | } |
88 | break; | 37 | break; |
89 | case "ExePackage": | 38 | case "Requires": |
90 | packageType = PackageType.ExePackage; | 39 | case "RequiresRef": |
91 | break; | 40 | if (attribute.Name.LocalName == "Enforce" && parentElement.Parent.Name.LocalName == "Component") |
92 | case "MsiPackage": | ||
93 | packageType = PackageType.MsiPackage; | ||
94 | break; | ||
95 | case "MspPackage": | ||
96 | packageType = PackageType.MspPackage; | ||
97 | break; | ||
98 | case "MsuPackage": | ||
99 | packageType = PackageType.MsuPackage; | ||
100 | break; | ||
101 | default: | ||
102 | this.ParseHelper.UnexpectedElement(parentElement, element); | ||
103 | break; | ||
104 | } | ||
105 | |||
106 | if (PackageType.None != packageType) | ||
107 | { | ||
108 | var packageId = context["PackageId"]; | ||
109 | |||
110 | switch (element.Name.LocalName) | ||
111 | { | ||
112 | case "Provides": | ||
113 | this.ParseProvidesElement(intermediate, section, element, packageType, packageId); | ||
114 | break; | ||
115 | default: | ||
116 | this.ParseHelper.UnexpectedElement(parentElement, element); | ||
117 | break; | ||
118 | } | ||
119 | } | ||
120 | } | ||
121 | |||
122 | /// <summary> | ||
123 | /// Processes a child element of a Component for the Compiler. | ||
124 | /// </summary> | ||
125 | /// <param name="parentElement">Parent element of element to process.</param> | ||
126 | /// <param name="element">Element to process.</param> | ||
127 | /// <param name="context">Extra information about the context in which this element is being parsed.</param> | ||
128 | /// <returns>The component key path type if set.</returns> | ||
129 | public override IComponentKeyPath ParsePossibleKeyPathElement(Intermediate intermediate, IntermediateSection section, XElement parentElement, XElement element, IDictionary<string, string> context) | ||
130 | { | ||
131 | var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(parentElement); | ||
132 | IComponentKeyPath keyPath = null; | ||
133 | |||
134 | switch (parentElement.Name.LocalName) | ||
135 | { | ||
136 | case "Component": | ||
137 | var componentId = context["ComponentId"]; | ||
138 | |||
139 | // 64-bit components may cause issues downlevel. | ||
140 | Boolean.TryParse(context["Win64"], out var win64); | ||
141 | |||
142 | switch (element.Name.LocalName) | ||
143 | { | 41 | { |
144 | case "Provides": | 42 | addRequire = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attribute); |
145 | if (win64) | ||
146 | { | ||
147 | this.Messaging.Write(DependencyWarnings.Win64Component(sourceLineNumbers, componentId)); | ||
148 | } | ||
149 | |||
150 | keyPath = this.ParseProvidesElement(intermediate, section, element, PackageType.None, componentId); | ||
151 | break; | ||
152 | default: | ||
153 | this.ParseHelper.UnexpectedElement(parentElement, element); | ||
154 | break; | ||
155 | } | 43 | } |
156 | break; | 44 | break; |
157 | default: | ||
158 | this.ParseHelper.UnexpectedElement(parentElement, element); | ||
159 | break; | ||
160 | } | ||
161 | |||
162 | return keyPath; | ||
163 | } | ||
164 | |||
165 | /// <summary> | ||
166 | /// Processes the ProviderKey bundle attribute. | ||
167 | /// </summary> | ||
168 | /// <param name="sourceLineNumbers">Source line number for the parent element.</param> | ||
169 | /// <param name="parentElement">Parent element of attribute.</param> | ||
170 | /// <param name="attribute">The XML attribute for the ProviderKey attribute.</param> | ||
171 | private void ParseProviderKeyAttribute(IntermediateSection section, SourceLineNumber sourceLineNumbers, XElement parentElement, XAttribute attribute) | ||
172 | { | ||
173 | Identifier id = null; | ||
174 | string providerKey = null; | ||
175 | int illegalChar = -1; | ||
176 | |||
177 | switch (attribute.Name.LocalName) | ||
178 | { | ||
179 | case "ProviderKey": | ||
180 | providerKey = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attribute); | ||
181 | break; | ||
182 | default: | ||
183 | this.ParseHelper.UnexpectedAttribute(parentElement, attribute); | ||
184 | break; | ||
185 | } | ||
186 | |||
187 | // Make sure the key does not contain any illegal characters or values. | ||
188 | if (String.IsNullOrEmpty(providerKey)) | ||
189 | { | ||
190 | this.Messaging.Write(ErrorMessages.IllegalEmptyAttributeValue(sourceLineNumbers, parentElement.Name.LocalName, attribute.Name.LocalName)); | ||
191 | } | 45 | } |
192 | else if (0 <= (illegalChar = providerKey.IndexOfAny(DependencyCommon.InvalidCharacters))) | ||
193 | { | ||
194 | var sb = new StringBuilder(DependencyCommon.InvalidCharacters.Length * 2); | ||
195 | Array.ForEach<char>(DependencyCommon.InvalidCharacters, c => sb.Append(c).Append(" ")); | ||
196 | 46 | ||
197 | this.Messaging.Write(DependencyErrors.IllegalCharactersInProvider(sourceLineNumbers, "ProviderKey", providerKey[illegalChar], sb.ToString())); | 47 | if (addCheck == YesNoType.NotSet && addRequire == YesNoType.NotSet) |
198 | } | ||
199 | else if ("ALL" == providerKey) | ||
200 | { | 48 | { |
201 | this.Messaging.Write(DependencyErrors.ReservedValue(sourceLineNumbers, parentElement.Name.LocalName, "ProviderKey", providerKey)); | 49 | this.ParseHelper.UnexpectedAttribute(parentElement, attribute); |
202 | } | 50 | } |
203 | 51 | else if (addCheck == YesNoType.Yes) | |
204 | // Generate the primary key for the row. | ||
205 | id = this.ParseHelper.CreateIdentifier("dep", attribute.Name.LocalName, providerKey); | ||
206 | |||
207 | if (!this.Messaging.EncounteredError) | ||
208 | { | 52 | { |
209 | // Create the provider symbol for the bundle. The Component_ field is required | 53 | this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4DependencyCheck", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64); |
210 | // in the table definition but unused for bundles, so just set it to the valid ID. | ||
211 | section.AddSymbol(new WixDependencyProviderSymbol(sourceLineNumbers, id) | ||
212 | { | ||
213 | ComponentRef = id.Id, | ||
214 | ProviderKey = providerKey, | ||
215 | Attributes = WixDependencyProviderAttributes.ProvidesAttributesBundle, | ||
216 | }); | ||
217 | } | 54 | } |
218 | } | 55 | else if (addRequire == YesNoType.Yes) |
219 | |||
220 | /// <summary> | ||
221 | /// Processes the Provides element. | ||
222 | /// </summary> | ||
223 | /// <param name="node">The XML node for the Provides element.</param> | ||
224 | /// <param name="packageType">The type of the package being chained into a bundle, or "None" if building an MSI package.</param> | ||
225 | /// <param name="keyPath">Explicit key path.</param> | ||
226 | /// <param name="parentId">The identifier of the parent component or package.</param> | ||
227 | /// <returns>The type of key path if set.</returns> | ||
228 | private IComponentKeyPath ParseProvidesElement(Intermediate intermediate, IntermediateSection section, XElement node, PackageType packageType, string parentId) | ||
229 | { | ||
230 | var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(node); | ||
231 | IComponentKeyPath keyPath = null; | ||
232 | Identifier id = null; | ||
233 | string key = null; | ||
234 | string version = null; | ||
235 | string displayName = null; | ||
236 | int illegalChar = -1; | ||
237 | |||
238 | foreach (var attrib in node.Attributes()) | ||
239 | { | 56 | { |
240 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) | 57 | this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4DependencyRequire", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64); |
241 | { | ||
242 | switch (attrib.Name.LocalName) | ||
243 | { | ||
244 | case "Id": | ||
245 | id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
246 | break; | ||
247 | case "Key": | ||
248 | key = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); | ||
249 | break; | ||
250 | case "Version": | ||
251 | version = this.ParseHelper.GetAttributeVersionValue(sourceLineNumbers, attrib); | ||
252 | break; | ||
253 | case "DisplayName": | ||
254 | displayName = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); | ||
255 | break; | ||
256 | default: | ||
257 | this.ParseHelper.UnexpectedAttribute(node, attrib); | ||
258 | break; | ||
259 | } | ||
260 | } | ||
261 | else | ||
262 | { | ||
263 | this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, node, attrib); | ||
264 | } | ||
265 | } | 58 | } |
266 | |||
267 | // Make sure the key is valid. The key will default to the ProductCode for MSI packages | ||
268 | // and the package code for MSP packages in the binder if not specified. | ||
269 | if (!String.IsNullOrEmpty(key)) | ||
270 | { | ||
271 | // Make sure the key does not contain any illegal characters or values. | ||
272 | if (0 <= (illegalChar = key.IndexOfAny(DependencyCommon.InvalidCharacters))) | ||
273 | { | ||
274 | var sb = new StringBuilder(DependencyCommon.InvalidCharacters.Length * 2); | ||
275 | Array.ForEach<char>(DependencyCommon.InvalidCharacters, c => sb.Append(c).Append(" ")); | ||
276 | |||
277 | this.Messaging.Write(DependencyErrors.IllegalCharactersInProvider(sourceLineNumbers, "Key", key[illegalChar], sb.ToString())); | ||
278 | } | ||
279 | else if ("ALL" == key) | ||
280 | { | ||
281 | this.Messaging.Write(DependencyErrors.ReservedValue(sourceLineNumbers, node.Name.LocalName, "Key", key)); | ||
282 | } | ||
283 | } | ||
284 | else if (PackageType.ExePackage == packageType || PackageType.MsuPackage == packageType) | ||
285 | { | ||
286 | // Must specify the provider key when authored for a package. | ||
287 | this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Key")); | ||
288 | } | ||
289 | else if (PackageType.None == packageType) | ||
290 | { | ||
291 | // Make sure the ProductCode is authored and set the key. | ||
292 | this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, SymbolDefinitions.Property, "ProductCode"); | ||
293 | key = "!(bind.property.ProductCode)"; | ||
294 | } | ||
295 | |||
296 | // The Version attribute should not be authored in or for an MSI package. | ||
297 | if (!String.IsNullOrEmpty(version)) | ||
298 | { | ||
299 | switch (packageType) | ||
300 | { | ||
301 | case PackageType.None: | ||
302 | this.Messaging.Write(DependencyWarnings.DiscouragedVersionAttribute(sourceLineNumbers)); | ||
303 | break; | ||
304 | case PackageType.MsiPackage: | ||
305 | this.Messaging.Write(DependencyWarnings.DiscouragedVersionAttribute(sourceLineNumbers, parentId)); | ||
306 | break; | ||
307 | } | ||
308 | } | ||
309 | else if (PackageType.MspPackage == packageType || PackageType.MsuPackage == packageType) | ||
310 | { | ||
311 | // Must specify the Version when authored for packages that do not contain a version. | ||
312 | this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Version")); | ||
313 | } | ||
314 | |||
315 | // Need the element ID for child element processing, so generate now if not authored. | ||
316 | if (null == id) | ||
317 | { | ||
318 | id = this.ParseHelper.CreateIdentifier("dep", node.Name.LocalName, parentId, key); | ||
319 | } | ||
320 | |||
321 | foreach (var child in node.Elements()) | ||
322 | { | ||
323 | if (this.Namespace == child.Name.Namespace) | ||
324 | { | ||
325 | switch (child.Name.LocalName) | ||
326 | { | ||
327 | case "Requires": | ||
328 | this.ParseRequiresElement(intermediate, section, child, id.Id, PackageType.None == packageType); | ||
329 | break; | ||
330 | case "RequiresRef": | ||
331 | this.ParseRequiresRefElement(intermediate, section, child, id.Id, PackageType.None == packageType); | ||
332 | break; | ||
333 | default: | ||
334 | this.ParseHelper.UnexpectedElement(node, child); | ||
335 | break; | ||
336 | } | ||
337 | } | ||
338 | else | ||
339 | { | ||
340 | this.ParseHelper.ParseExtensionElement(this.Context.Extensions, intermediate, section, node, child); | ||
341 | } | ||
342 | } | ||
343 | |||
344 | if (!this.Messaging.EncounteredError) | ||
345 | { | ||
346 | var symbol = section.AddSymbol(new WixDependencyProviderSymbol(sourceLineNumbers, id) | ||
347 | { | ||
348 | ComponentRef = parentId, | ||
349 | ProviderKey = key, | ||
350 | }); | ||
351 | |||
352 | if (!String.IsNullOrEmpty(version)) | ||
353 | { | ||
354 | symbol.Version = version; | ||
355 | } | ||
356 | |||
357 | if (!String.IsNullOrEmpty(displayName)) | ||
358 | { | ||
359 | symbol.DisplayName = displayName; | ||
360 | } | ||
361 | |||
362 | if (PackageType.None == packageType) | ||
363 | { | ||
364 | this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "DependencyCheck", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64); | ||
365 | |||
366 | // Generate registry rows for the provider using binder properties. | ||
367 | var keyProvides = String.Concat(DependencyCommon.RegistryRoot, key); | ||
368 | var root = RegistryRootType.MachineUser; | ||
369 | |||
370 | var value = "[ProductCode]"; | ||
371 | this.ParseHelper.CreateRegistrySymbol(section, sourceLineNumbers, root, keyProvides, null, value, parentId, false); | ||
372 | |||
373 | value = !String.IsNullOrEmpty(version) ? version : "[ProductVersion]"; | ||
374 | var versionRegistrySymbol = | ||
375 | this.ParseHelper.CreateRegistrySymbol(section, sourceLineNumbers, root, keyProvides, "Version", value, parentId, false); | ||
376 | |||
377 | value = !String.IsNullOrEmpty(displayName) ? displayName : "[ProductName]"; | ||
378 | this.ParseHelper.CreateRegistrySymbol(section, sourceLineNumbers, root, keyProvides, "DisplayName", value, parentId, false); | ||
379 | |||
380 | // Use the Version registry value and use that as a potential key path. | ||
381 | keyPath = this.CreateComponentKeyPath(); | ||
382 | keyPath.Id = versionRegistrySymbol.Id; | ||
383 | keyPath.Explicit = false; | ||
384 | keyPath.Type = PossibleKeyPathType.Registry; | ||
385 | } | ||
386 | } | ||
387 | |||
388 | return keyPath; | ||
389 | } | ||
390 | |||
391 | /// <summary> | ||
392 | /// Processes the Requires element. | ||
393 | /// </summary> | ||
394 | /// <param name="node">The XML node for the Requires element.</param> | ||
395 | /// <param name="providerId">The parent provider identifier.</param> | ||
396 | /// <param name="requiresAction">Whether the Requires custom action should be referenced.</param> | ||
397 | private void ParseRequiresElement(Intermediate intermediate, IntermediateSection section, XElement node, string providerId, bool requiresAction) | ||
398 | { | ||
399 | var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(node); | ||
400 | Identifier id = null; | ||
401 | string providerKey = null; | ||
402 | string minVersion = null; | ||
403 | string maxVersion = null; | ||
404 | int attributes = 0; | ||
405 | int illegalChar = -1; | ||
406 | |||
407 | foreach (var attrib in node.Attributes()) | ||
408 | { | ||
409 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) | ||
410 | { | ||
411 | switch (attrib.Name.LocalName) | ||
412 | { | ||
413 | case "Id": | ||
414 | id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
415 | break; | ||
416 | case "ProviderKey": | ||
417 | providerKey = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); | ||
418 | break; | ||
419 | case "Minimum": | ||
420 | minVersion = this.ParseHelper.GetAttributeVersionValue(sourceLineNumbers, attrib); | ||
421 | break; | ||
422 | case "Maximum": | ||
423 | maxVersion = this.ParseHelper.GetAttributeVersionValue(sourceLineNumbers, attrib); | ||
424 | break; | ||
425 | case "IncludeMinimum": | ||
426 | if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
427 | { | ||
428 | attributes |= DependencyCommon.RequiresAttributesMinVersionInclusive; | ||
429 | } | ||
430 | break; | ||
431 | case "IncludeMaximum": | ||
432 | if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
433 | { | ||
434 | attributes |= DependencyCommon.RequiresAttributesMaxVersionInclusive; | ||
435 | } | ||
436 | break; | ||
437 | default: | ||
438 | this.ParseHelper.UnexpectedAttribute(node, attrib); | ||
439 | break; | ||
440 | } | ||
441 | } | ||
442 | else | ||
443 | { | ||
444 | this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, node, attrib); | ||
445 | } | ||
446 | } | ||
447 | |||
448 | this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, node); | ||
449 | |||
450 | if (null == id) | ||
451 | { | ||
452 | // Generate an ID only if this element is authored under a Provides element; otherwise, a RequiresRef | ||
453 | // element will be necessary and the Id attribute will be required. | ||
454 | if (!String.IsNullOrEmpty(providerId)) | ||
455 | { | ||
456 | id = this.ParseHelper.CreateIdentifier("dep", node.Name.LocalName, providerKey); | ||
457 | } | ||
458 | else | ||
459 | { | ||
460 | this.Messaging.Write(ErrorMessages.ExpectedAttributeWhenElementNotUnderElement(sourceLineNumbers, node.Name.LocalName, "Id", "Provides")); | ||
461 | id = Identifier.Invalid; | ||
462 | } | ||
463 | } | ||
464 | |||
465 | if (String.IsNullOrEmpty(providerKey)) | ||
466 | { | ||
467 | this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "ProviderKey")); | ||
468 | } | ||
469 | // Make sure the key does not contain any illegal characters. | ||
470 | else if (0 <= (illegalChar = providerKey.IndexOfAny(DependencyCommon.InvalidCharacters))) | ||
471 | { | ||
472 | var sb = new StringBuilder(DependencyCommon.InvalidCharacters.Length * 2); | ||
473 | Array.ForEach<char>(DependencyCommon.InvalidCharacters, c => sb.Append(c).Append(" ")); | ||
474 | |||
475 | this.Messaging.Write(DependencyErrors.IllegalCharactersInProvider(sourceLineNumbers, "ProviderKey", providerKey[illegalChar], sb.ToString())); | ||
476 | } | ||
477 | |||
478 | if (!this.Messaging.EncounteredError) | ||
479 | { | ||
480 | // Reference the Require custom action if required. | ||
481 | if (requiresAction) | ||
482 | { | ||
483 | this.AddReferenceToWixDependencyRequire(section, sourceLineNumbers); | ||
484 | } | ||
485 | |||
486 | var symbol = section.AddSymbol(new WixDependencySymbol(sourceLineNumbers, id) | ||
487 | { | ||
488 | ProviderKey = providerKey, | ||
489 | MinVersion = minVersion, | ||
490 | MaxVersion = maxVersion, | ||
491 | }); | ||
492 | |||
493 | if (0 != attributes) | ||
494 | { | ||
495 | symbol.Attributes = attributes; | ||
496 | } | ||
497 | |||
498 | // Create the relationship between this WixDependency symbol and the WixDependencyProvider symbol. | ||
499 | if (!String.IsNullOrEmpty(providerId)) | ||
500 | { | ||
501 | section.AddSymbol(new WixDependencyRefSymbol(sourceLineNumbers) | ||
502 | { | ||
503 | WixDependencyProviderRef = providerId, | ||
504 | WixDependencyRef = id.Id, | ||
505 | }); | ||
506 | } | ||
507 | } | ||
508 | } | ||
509 | |||
510 | /// <summary> | ||
511 | /// Processes the RequiresRef element. | ||
512 | /// </summary> | ||
513 | /// <param name="node">The XML node for the RequiresRef element.</param> | ||
514 | /// <param name="providerId">The parent provider identifier.</param> | ||
515 | /// <param name="requiresAction">Whether the Requires custom action should be referenced.</param> | ||
516 | private void ParseRequiresRefElement(Intermediate intermediate, IntermediateSection section, XElement node, string providerId, bool requiresAction) | ||
517 | { | ||
518 | var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(node); | ||
519 | string id = null; | ||
520 | |||
521 | foreach (var attrib in node.Attributes()) | ||
522 | { | ||
523 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) | ||
524 | { | ||
525 | switch (attrib.Name.LocalName) | ||
526 | { | ||
527 | case "Id": | ||
528 | id = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
529 | break; | ||
530 | default: | ||
531 | this.ParseHelper.UnexpectedAttribute(node, attrib); | ||
532 | break; | ||
533 | } | ||
534 | } | ||
535 | else | ||
536 | { | ||
537 | this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, node, attrib); | ||
538 | } | ||
539 | } | ||
540 | |||
541 | this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, node); | ||
542 | |||
543 | if (String.IsNullOrEmpty(id)) | ||
544 | { | ||
545 | this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
546 | } | ||
547 | |||
548 | if (!this.Messaging.EncounteredError) | ||
549 | { | ||
550 | // Reference the Require custom action if required. | ||
551 | if (requiresAction) | ||
552 | { | ||
553 | this.AddReferenceToWixDependencyRequire(section, sourceLineNumbers); | ||
554 | } | ||
555 | |||
556 | // Create a link dependency on the row that contains information we'll need during bind. | ||
557 | this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, DependencySymbolDefinitions.WixDependency, id); | ||
558 | |||
559 | // Create the relationship between the WixDependency row and the parent WixDependencyProvider row. | ||
560 | section.AddSymbol(new WixDependencyRefSymbol(sourceLineNumbers) | ||
561 | { | ||
562 | WixDependencyProviderRef = providerId, | ||
563 | WixDependencyRef = id, | ||
564 | }); | ||
565 | } | ||
566 | } | ||
567 | |||
568 | private void AddReferenceToWixDependencyRequire(IntermediateSection section, SourceLineNumber sourceLineNumbers) | ||
569 | { | ||
570 | this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "DependencyRequire", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64); | ||
571 | } | 59 | } |
572 | } | 60 | } |
573 | } | 61 | } |