aboutsummaryrefslogtreecommitdiff
path: root/src/ext/Util/wixext/UtilCompiler.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/ext/Util/wixext/UtilCompiler.cs')
-rw-r--r--src/ext/Util/wixext/UtilCompiler.cs3889
1 files changed, 3889 insertions, 0 deletions
diff --git a/src/ext/Util/wixext/UtilCompiler.cs b/src/ext/Util/wixext/UtilCompiler.cs
new file mode 100644
index 00000000..45079150
--- /dev/null
+++ b/src/ext/Util/wixext/UtilCompiler.cs
@@ -0,0 +1,3889 @@
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
3namespace WixToolset.Util
4{
5 using System;
6 using System.Collections;
7 using System.Collections.Generic;
8 using System.Globalization;
9 using System.Linq;
10 using System.Text;
11 using System.Text.RegularExpressions;
12 using System.Xml.Linq;
13 using WixToolset.Data;
14 using WixToolset.Data.Symbols;
15 using WixToolset.Extensibility;
16 using WixToolset.Extensibility.Data;
17 using WixToolset.Util.Symbols;
18
19 /// <summary>
20 /// The compiler for the WiX Toolset Utility Extension.
21 /// </summary>
22 public sealed class UtilCompiler : BaseCompilerExtension
23 {
24 // user creation attributes definitions (from sca.h)
25 internal const int UserDontExpirePasswrd = 0x00000001;
26 internal const int UserPasswdCantChange = 0x00000002;
27 internal const int UserPasswdChangeReqdOnLogin = 0x00000004;
28 internal const int UserDisableAccount = 0x00000008;
29 internal const int UserFailIfExists = 0x00000010;
30 internal const int UserUpdateIfExists = 0x00000020;
31 internal const int UserLogonAsService = 0x00000040;
32 internal const int UserLogonAsBatchJob = 0x00000080;
33
34 internal const int UserDontRemoveOnUninstall = 0x00000100;
35 internal const int UserDontCreateUser = 0x00000200;
36 internal const int UserNonVital = 0x00000400;
37
38 private static readonly Regex FindPropertyBrackets = new Regex(@"\[(?!\\|\])|(?<!\[\\\]|\[\\|\\\[)\]", RegexOptions.ExplicitCapture | RegexOptions.Compiled);
39
40 public override XNamespace Namespace => "http://wixtoolset.org/schemas/v4/wxs/util";
41
42 /// <summary>
43 /// Types of Internet shortcuts.
44 /// </summary>
45 public enum InternetShortcutType
46 {
47 /// <summary>Create a .lnk file.</summary>
48 Link = 0,
49
50 /// <summary>Create a .url file.</summary>
51 Url,
52 }
53
54 /// <summary>
55 /// Types of permission setting methods.
56 /// </summary>
57 private enum PermissionType
58 {
59 /// <summary>LockPermissions (normal) type permission setting.</summary>
60 LockPermissions,
61
62 /// <summary>FileSharePermissions type permission setting.</summary>
63 FileSharePermissions,
64
65 /// <summary>SecureObjects type permission setting.</summary>
66 SecureObjects,
67 }
68
69 /// <summary>
70 /// Processes an element for the Compiler.
71 /// </summary>
72 /// <param name="parentElement">Parent element of element to process.</param>
73 /// <param name="element">Element to process.</param>
74 /// <param name="context">Extra information about the context in which this element is being parsed.</param>
75 public override void ParseElement(Intermediate intermediate, IntermediateSection section, XElement parentElement, XElement element, IDictionary<string, string> context)
76 {
77 this.ParsePossibleKeyPathElement(intermediate, section, parentElement, element, context);
78 }
79
80 /// <summary>
81 /// Processes an element for the Compiler.
82 /// </summary>
83 /// <param name="sourceLineNumbers">Source line number for the parent element.</param>
84 /// <param name="parentElement">Parent element of element to process.</param>
85 /// <param name="element">Element to process.</param>
86 /// <param name="contextValues">Extra information about the context in which this element is being parsed.</param>
87 public override IComponentKeyPath ParsePossibleKeyPathElement(Intermediate intermediate, IntermediateSection section, XElement parentElement, XElement element, IDictionary<string, string> context)
88 {
89 IComponentKeyPath possibleKeyPath = null;
90
91 switch (parentElement.Name.LocalName)
92 {
93 case "CreateFolder":
94 var createFolderId = context["DirectoryId"];
95 var createFolderComponentId = context["ComponentId"];
96
97 // If this doesn't parse successfully, something really odd is going on, so let the exception get thrown
98 var createFolderWin64 = Boolean.Parse(context["Win64"]);
99
100 switch (element.Name.LocalName)
101 {
102 case "PermissionEx":
103 this.ParsePermissionExElement(intermediate, section, element, createFolderId, createFolderComponentId, createFolderWin64, "CreateFolder");
104 break;
105 default:
106 this.ParseHelper.UnexpectedElement(parentElement, element);
107 break;
108 }
109 break;
110 case "Component":
111 var componentId = context["ComponentId"];
112 var directoryId = context["DirectoryId"];
113 var componentWin64 = Boolean.Parse(context["Win64"]);
114
115 switch (element.Name.LocalName)
116 {
117 case "EventSource":
118 possibleKeyPath = this.ParseEventSourceElement(intermediate, section, element, componentId);
119 break;
120 case "FileShare":
121 this.ParseFileShareElement(intermediate, section, element, componentId, directoryId);
122 break;
123 case "InternetShortcut":
124 this.ParseInternetShortcutElement(intermediate, section, element, componentId, directoryId);
125 break;
126 case "PerformanceCategory":
127 this.ParsePerformanceCategoryElement(intermediate, section, element, componentId);
128 break;
129 case "RemoveFolderEx":
130 this.ParseRemoveFolderExElement(intermediate, section, element, componentId);
131 break;
132 case "RemoveRegistryKey":
133 this.ParseRemoveRegistryKeyExElement(intermediate, section, element, componentId);
134 break;
135 case "RestartResource":
136 this.ParseRestartResourceElement(intermediate, section, element, componentId);
137 break;
138 case "ServiceConfig":
139 this.ParseServiceConfigElement(intermediate, section, element, componentId, "Component", null);
140 break;
141 case "TouchFile":
142 this.ParseTouchFileElement(intermediate, section, element, componentId, componentWin64);
143 break;
144 case "User":
145 this.ParseUserElement(intermediate, section, element, componentId);
146 break;
147 case "XmlFile":
148 this.ParseXmlFileElement(intermediate, section, element, componentId);
149 break;
150 case "XmlConfig":
151 this.ParseXmlConfigElement(intermediate, section, element, componentId, false);
152 break;
153 default:
154 this.ParseHelper.UnexpectedElement(parentElement, element);
155 break;
156 }
157 break;
158 case "File":
159 var fileId = context["FileId"];
160 var fileComponentId = context["ComponentId"];
161
162 // If this doesn't parse successfully, something really odd is going on, so let the exception get thrown
163 var fileWin64 = Boolean.Parse(context["Win64"]);
164
165 switch (element.Name.LocalName)
166 {
167 case "PerfCounter":
168 this.ParsePerfCounterElement(intermediate, section, element, fileComponentId, fileId);
169 break;
170 case "PermissionEx":
171 this.ParsePermissionExElement(intermediate, section, element, fileId, fileComponentId, fileWin64, "File");
172 break;
173 case "PerfCounterManifest":
174 this.ParsePerfCounterManifestElement(intermediate, section, element, fileComponentId, fileId);
175 break;
176 case "EventManifest":
177 this.ParseEventManifestElement(intermediate, section, element, fileComponentId, fileId);
178 break;
179 case "FormatFile":
180 this.ParseFormatFileElement(intermediate, section, element, fileId, fileWin64);
181 break;
182 default:
183 this.ParseHelper.UnexpectedElement(parentElement, element);
184 break;
185 }
186 break;
187 case "Bundle":
188 case "Fragment":
189 case "Module":
190 case "Package":
191 switch (element.Name.LocalName)
192 {
193 case "CloseApplication":
194 this.ParseCloseApplicationElement(intermediate, section, element);
195 break;
196 case "Group":
197 this.ParseGroupElement(intermediate, section, element, null);
198 break;
199 case "RestartResource":
200 // Currently not supported for Bundles.
201 if (parentElement.Name.LocalName != "Bundle")
202 {
203 this.ParseRestartResourceElement(intermediate, section, element, null);
204 }
205 else
206 {
207 this.ParseHelper.UnexpectedElement(parentElement, element);
208 }
209 break;
210 case "User":
211 this.ParseUserElement(intermediate, section, element, null);
212 break;
213 case "BroadcastEnvironmentChange":
214 case "BroadcastSettingChange":
215 case "CheckRebootRequired":
216 case "ExitEarlyWithSuccess":
217 case "FailWhenDeferred":
218 case "QueryWindowsDirectories":
219 case "QueryWindowsDriverInfo":
220 case "QueryWindowsSuiteInfo":
221 case "QueryWindowsWellKnownSIDs":
222 case "WaitForEvent":
223 case "WaitForEventDeferred":
224 this.AddCustomActionReference(intermediate, section, element, parentElement);
225 break;
226 case "ComponentSearch":
227 case "ComponentSearchRef":
228 case "DirectorySearch":
229 case "DirectorySearchRef":
230 case "FileSearch":
231 case "FileSearchRef":
232 case "ProductSearch":
233 case "ProductSearchRef":
234 case "RegistrySearch":
235 case "RegistrySearchRef":
236 case "WindowsFeatureSearch":
237 case "WindowsFeatureSearchRef":
238 // These will eventually be supported under Module/Product, but are not yet.
239 if (parentElement.Name.LocalName == "Bundle" || parentElement.Name.LocalName == "Fragment")
240 {
241 // TODO: When these are supported by all section types, move
242 // these out of the nested switch and back into the surrounding one.
243 switch (element.Name.LocalName)
244 {
245 case "ComponentSearch":
246 this.ParseComponentSearchElement(intermediate, section, element);
247 break;
248 case "ComponentSearchRef":
249 this.ParseComponentSearchRefElement(intermediate, section, element);
250 break;
251 case "DirectorySearch":
252 this.ParseDirectorySearchElement(intermediate, section, element);
253 break;
254 case "DirectorySearchRef":
255 this.ParseWixSearchRefElement(intermediate, section, element);
256 break;
257 case "FileSearch":
258 this.ParseFileSearchElement(intermediate, section, element);
259 break;
260 case "FileSearchRef":
261 this.ParseWixSearchRefElement(intermediate, section, element);
262 break;
263 case "ProductSearch":
264 this.ParseProductSearchElement(intermediate, section, element);
265 break;
266 case "ProductSearchRef":
267 this.ParseWixSearchRefElement(intermediate, section, element);
268 break;
269 case "RegistrySearch":
270 this.ParseRegistrySearchElement(intermediate, section, element);
271 break;
272 case "RegistrySearchRef":
273 this.ParseWixSearchRefElement(intermediate, section, element);
274 break;
275 case "WindowsFeatureSearch":
276 this.ParseWindowsFeatureSearchElement(intermediate, section, element);
277 break;
278 case "WindowsFeatureSearchRef":
279 this.ParseWindowsFeatureSearchRefElement(intermediate, section, element);
280 break;
281 }
282 }
283 else
284 {
285 this.ParseHelper.UnexpectedElement(parentElement, element);
286 }
287 break;
288 default:
289 this.ParseHelper.UnexpectedElement(parentElement, element);
290 break;
291 }
292 break;
293 case "Registry":
294 case "RegistryKey":
295 case "RegistryValue":
296 var registryId = context["RegistryId"];
297 var registryComponentId = context["ComponentId"];
298
299 // If this doesn't parse successfully, something really odd is going on, so let the exception get thrown
300 var registryWin64 = Boolean.Parse(context["Win64"]);
301
302 switch (element.Name.LocalName)
303 {
304 case "PermissionEx":
305 this.ParsePermissionExElement(intermediate, section, element, registryId, registryComponentId, registryWin64, "Registry");
306 break;
307 default:
308 this.ParseHelper.UnexpectedElement(parentElement, element);
309 break;
310 }
311 break;
312 case "ServiceInstall":
313 var serviceInstallId = context["ServiceInstallId"];
314 var serviceInstallName = context["ServiceInstallName"];
315 var serviceInstallComponentId = context["ServiceInstallComponentId"];
316
317 // If this doesn't parse successfully, something really odd is going on, so let the exception get thrown
318 var serviceInstallWin64 = Boolean.Parse(context["Win64"]);
319
320 switch (element.Name.LocalName)
321 {
322 case "PermissionEx":
323 this.ParsePermissionExElement(intermediate, section, element, serviceInstallId, serviceInstallComponentId, serviceInstallWin64, "ServiceInstall");
324 break;
325 case "ServiceConfig":
326 this.ParseServiceConfigElement(intermediate, section, element, serviceInstallComponentId, "ServiceInstall", serviceInstallName);
327 break;
328 default:
329 this.ParseHelper.UnexpectedElement(parentElement, element);
330 break;
331 }
332 break;
333 case "UI":
334 switch (element.Name.LocalName)
335 {
336 case "BroadcastEnvironmentChange":
337 case "BroadcastSettingChange":
338 case "CheckRebootRequired":
339 case "ExitEarlyWithSuccess":
340 case "FailWhenDeferred":
341 case "QueryWindowsDirectories":
342 case "QueryWindowsDriverInfo":
343 case "QueryWindowsSuiteInfo":
344 case "QueryWindowsWellKnownSIDs":
345 case "WaitForEvent":
346 case "WaitForEventDeferred":
347 this.AddCustomActionReference(intermediate, section, element, parentElement);
348 break;
349 }
350 break;
351 default:
352 this.ParseHelper.UnexpectedElement(parentElement, element);
353 break;
354 }
355
356 return possibleKeyPath;
357 }
358
359 private void AddCustomActionReference(Intermediate intermediate, IntermediateSection section, XElement element, XElement parentElement)
360 {
361 // These elements are not supported for bundles.
362 if (parentElement.Name.LocalName == "Bundle")
363 {
364 this.ParseHelper.UnexpectedElement(parentElement, element);
365 return;
366 }
367
368 var customAction = element.Name.LocalName;
369 switch (element.Name.LocalName)
370 {
371 case "BroadcastEnvironmentChange":
372 case "BroadcastSettingChange":
373 case "CheckRebootRequired":
374 case "ExitEarlyWithSuccess":
375 case "FailWhenDeferred":
376 case "WaitForEvent":
377 case "WaitForEventDeferred":
378 //default: customAction = element.Name.LocalName;
379 break;
380 case "QueryWindowsDirectories":
381 customAction = "QueryOsDirs";
382 break;
383 case "QueryWindowsDriverInfo":
384 customAction = "QueryOsDriverInfo";
385 break;
386 case "QueryWindowsSuiteInfo":
387 customAction = "QueryOsInfo";
388 break;
389 case "QueryWindowsWellKnownSIDs":
390 customAction = "QueryOsWellKnownSID";
391 break;
392 }
393
394 foreach (var attrib in element.Attributes())
395 {
396 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
397 {
398 // no attributes today
399 }
400 else
401 {
402 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
403 }
404 }
405
406 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
407
408 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
409
410 this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4" + customAction, this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
411 }
412
413 /// <summary>
414 /// Parses the common search attributes shared across all searches.
415 /// </summary>
416 /// <param name="sourceLineNumbers">Source line number for the parent element.</param>
417 /// <param name="attrib">Attribute to parse.</param>
418 /// <param name="id">Value of the Id attribute.</param>
419 /// <param name="variable">Value of the Variable attribute.</param>
420 /// <param name="condition">Value of the Condition attribute.</param>
421 /// <param name="after">Value of the After attribute.</param>
422 private void ParseCommonSearchAttributes(SourceLineNumber sourceLineNumbers, XAttribute attrib, ref Identifier id, ref string variable, ref string condition, ref string after)
423 {
424 switch (attrib.Name.LocalName)
425 {
426 case "Id":
427 id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
428 break;
429 case "Variable":
430 variable = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
431 // TODO: handle standard bundle variables
432 break;
433 case "Condition":
434 condition = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
435 break;
436 case "After":
437 after = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
438 break;
439 default:
440 System.Diagnostics.Debug.Assert(false);
441 break;
442 }
443 }
444
445 /// <summary>
446 /// Parses a ComponentSearch element.
447 /// </summary>
448 /// <param name="element">Element to parse.</param>
449 private void ParseComponentSearchElement(Intermediate intermediate, IntermediateSection section, XElement element)
450 {
451 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
452 Identifier id = null;
453 string variable = null;
454 string condition = null;
455 string after = null;
456 string guid = null;
457 string productCode = null;
458 var attributes = WixComponentSearchAttributes.KeyPath;
459
460 foreach (var attrib in element.Attributes())
461 {
462 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
463 {
464 switch (attrib.Name.LocalName)
465 {
466 case "Id":
467 case "Variable":
468 case "Condition":
469 case "After":
470 this.ParseCommonSearchAttributes(sourceLineNumbers, attrib, ref id, ref variable, ref condition, ref after);
471 break;
472 case "Guid":
473 guid = this.ParseHelper.GetAttributeGuidValue(sourceLineNumbers, attrib);
474 break;
475 case "ProductCode":
476 productCode = this.ParseHelper.GetAttributeGuidValue(sourceLineNumbers, attrib);
477 break;
478 case "Result":
479 var result = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
480 switch (result)
481 {
482 case "directory":
483 attributes = WixComponentSearchAttributes.WantDirectory;
484 break;
485 case "keyPath":
486 attributes = WixComponentSearchAttributes.KeyPath;
487 break;
488 case "state":
489 attributes = WixComponentSearchAttributes.State;
490 break;
491 default:
492 this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, attrib.Parent.Name.LocalName, attrib.Name.LocalName, result, "directory", "keyPath", "state"));
493 break;
494 }
495 break;
496 default:
497 this.ParseHelper.UnexpectedAttribute(element, attrib);
498 break;
499 }
500 }
501 else
502 {
503 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
504 }
505 }
506
507 if (null == guid)
508 {
509 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Guid"));
510 }
511
512 if (null == id)
513 {
514 id = this.ParseHelper.CreateIdentifier("wcs", variable, condition, after, guid, productCode, attributes.ToString());
515 }
516
517 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
518
519 this.ParseHelper.CreateWixSearchSymbol(section, sourceLineNumbers, element.Name.LocalName, id, variable, condition, after, null);
520
521 if (!this.Messaging.EncounteredError)
522 {
523 section.AddSymbol(new WixComponentSearchSymbol(sourceLineNumbers, id)
524 {
525 Guid = guid,
526 ProductCode = productCode,
527 Attributes = attributes,
528 });
529 }
530 }
531
532 /// <summary>
533 /// Parses a ComponentSearchRef element
534 /// </summary>
535 /// <param name="element">Element to parse.</param>
536 private void ParseComponentSearchRefElement(Intermediate intermediate, IntermediateSection section, XElement element)
537 {
538 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
539 string refId = null;
540
541 foreach (var attrib in element.Attributes())
542 {
543 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
544 {
545 switch (attrib.Name.LocalName)
546 {
547 case "Id":
548 refId = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
549 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, SymbolDefinitions.WixComponentSearch, refId);
550 break;
551 default:
552 this.ParseHelper.UnexpectedAttribute(element, attrib);
553 break;
554 }
555 }
556 else
557 {
558 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
559 }
560 }
561
562 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
563 }
564
565 /// <summary>
566 /// Parses a WindowsFeatureSearch element.
567 /// </summary>
568 /// <param name="element">Element to parse.</param>
569 private void ParseWindowsFeatureSearchElement(Intermediate intermediate, IntermediateSection section, XElement element)
570 {
571 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
572 Identifier id = null;
573 string variable = null;
574 string condition = null;
575 string after = null;
576 string feature = null;
577
578 foreach (var attrib in element.Attributes())
579 {
580 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
581 {
582 switch (attrib.Name.LocalName)
583 {
584 case "Id":
585 case "Variable":
586 case "Condition":
587 case "After":
588 this.ParseCommonSearchAttributes(sourceLineNumbers, attrib, ref id, ref variable, ref condition, ref after);
589 break;
590 case "Feature":
591 feature = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
592 switch (feature)
593 {
594 case "sha2CodeSigning":
595 break;
596 default:
597 this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, "Feature", feature, "sha2CodeSigning"));
598 break;
599 }
600 break;
601 default:
602 this.ParseHelper.UnexpectedAttribute(element, attrib);
603 break;
604 }
605 }
606 else
607 {
608 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
609 }
610 }
611
612 if (id == null)
613 {
614 id = this.ParseHelper.CreateIdentifier("wwfs", variable, condition, after);
615 }
616
617 if (feature == null)
618 {
619 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Feature"));
620 }
621
622 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
623
624 var bundleExtensionId = this.ParseHelper.CreateIdentifierValueFromPlatform("Wix4UtilBundleExtension", this.Context.Platform, BurnPlatforms.X86 | BurnPlatforms.X64 | BurnPlatforms.ARM64);
625 if (bundleExtensionId == null)
626 {
627 this.Messaging.Write(ErrorMessages.UnsupportedPlatformForElement(sourceLineNumbers, this.Context.Platform.ToString(), element.Name.LocalName));
628 }
629
630 this.ParseHelper.CreateWixSearchSymbol(section, sourceLineNumbers, element.Name.LocalName, id, variable, condition, after, bundleExtensionId);
631
632 if (!this.Messaging.EncounteredError)
633 {
634 section.AddSymbol(new WixWindowsFeatureSearchSymbol(sourceLineNumbers, id)
635 {
636 Type = feature,
637 });
638 }
639 }
640
641 /// <summary>
642 /// Parses a WindowsFeatureSearchRef element
643 /// </summary>
644 /// <param name="element">Element to parse.</param>
645 private void ParseWindowsFeatureSearchRefElement(Intermediate intermediate, IntermediateSection section, XElement element)
646 {
647 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
648
649 foreach (var attrib in element.Attributes())
650 {
651 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
652 {
653 switch (attrib.Name.LocalName)
654 {
655 case "Id":
656 var refId = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
657 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, UtilSymbolDefinitions.WixWindowsFeatureSearch, refId);
658 break;
659 default:
660 this.ParseHelper.UnexpectedAttribute(element, attrib);
661 break;
662 }
663 }
664 else
665 {
666 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
667 }
668 }
669
670 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
671 }
672
673 /// <summary>
674 /// Parses an event source element.
675 /// </summary>
676 /// <param name="element">Element to parse.</param>
677 /// <param name="componentId">Identifier of parent component.</param>
678 private IComponentKeyPath ParseEventSourceElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId)
679 {
680 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
681 string sourceName = null;
682 string logName = null;
683 string categoryMessageFile = null;
684 var categoryCount = CompilerConstants.IntegerNotSet;
685 string eventMessageFile = null;
686 string parameterMessageFile = null;
687 int typesSupported = 0;
688 var isKeyPath = false;
689
690 foreach (var attrib in element.Attributes())
691 {
692 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
693 {
694 switch (attrib.Name.LocalName)
695 {
696 case "CategoryCount":
697 categoryCount = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int32.MaxValue);
698 break;
699 case "CategoryMessageFile":
700 categoryMessageFile = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
701 break;
702 case "EventMessageFile":
703 eventMessageFile = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
704 break;
705 case "KeyPath":
706 isKeyPath = YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib);
707 break;
708 case "Log":
709 logName = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
710 if ("Security" == logName)
711 {
712 this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, logName, "Application", "System", "<customEventLog>"));
713 }
714 break;
715 case "Name":
716 sourceName = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
717 break;
718 case "ParameterMessageFile":
719 parameterMessageFile = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
720 break;
721 case "SupportsErrors":
722 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
723 {
724 typesSupported |= 0x01; // EVENTLOG_ERROR_TYPE
725 }
726 break;
727 case "SupportsFailureAudits":
728 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
729 {
730 typesSupported |= 0x10; // EVENTLOG_AUDIT_FAILURE
731 }
732 break;
733 case "SupportsInformationals":
734 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
735 {
736 typesSupported |= 0x04; // EVENTLOG_INFORMATION_TYPE
737 }
738 break;
739 case "SupportsSuccessAudits":
740 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
741 {
742 typesSupported |= 0x08; // EVENTLOG_AUDIT_SUCCESS
743 }
744 break;
745 case "SupportsWarnings":
746 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
747 {
748 typesSupported |= 0x02; // EVENTLOG_WARNING_TYPE
749 }
750 break;
751 default:
752 this.ParseHelper.UnexpectedAttribute(element, attrib);
753 break;
754 }
755 }
756 else
757 {
758 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
759 }
760 }
761
762 if (null == sourceName)
763 {
764 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Name"));
765 }
766
767 if (null == logName)
768 {
769 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "EventLog"));
770 }
771
772 if (null == eventMessageFile)
773 {
774 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "EventMessageFile"));
775 }
776
777 if (null == categoryMessageFile && 0 < categoryCount)
778 {
779 this.Messaging.Write(ErrorMessages.IllegalAttributeWithoutOtherAttributes(sourceLineNumbers, element.Name.LocalName, "CategoryCount", "CategoryMessageFile"));
780 }
781
782 if (null != categoryMessageFile && CompilerConstants.IntegerNotSet == categoryCount)
783 {
784 this.Messaging.Write(ErrorMessages.IllegalAttributeWithoutOtherAttributes(sourceLineNumbers, element.Name.LocalName, "CategoryMessageFile", "CategoryCount"));
785 }
786
787 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
788
789 string eventSourceKey = $@"SYSTEM\CurrentControlSet\Services\EventLog\{logName}\{sourceName}";
790 var id = this.ParseHelper.CreateRegistrySymbol(section, sourceLineNumbers, RegistryRootType.LocalMachine, eventSourceKey, "EventMessageFile", String.Concat("#%", eventMessageFile), componentId, false);
791
792 if (null != categoryMessageFile)
793 {
794 this.ParseHelper.CreateRegistrySymbol(section, sourceLineNumbers, RegistryRootType.LocalMachine, eventSourceKey, "CategoryMessageFile", String.Concat("#%", categoryMessageFile), componentId, false);
795 }
796
797 if (CompilerConstants.IntegerNotSet != categoryCount)
798 {
799 this.ParseHelper.CreateRegistrySymbol(section, sourceLineNumbers, RegistryRootType.LocalMachine, eventSourceKey, "CategoryCount", String.Concat("#", categoryCount), componentId, false);
800 }
801
802 if (null != parameterMessageFile)
803 {
804 this.ParseHelper.CreateRegistrySymbol(section, sourceLineNumbers, RegistryRootType.LocalMachine, eventSourceKey, "ParameterMessageFile", String.Concat("#%", parameterMessageFile), componentId, false);
805 }
806
807 if (0 != typesSupported)
808 {
809 this.ParseHelper.CreateRegistrySymbol(section, sourceLineNumbers, RegistryRootType.LocalMachine, eventSourceKey, "TypesSupported", String.Concat("#", typesSupported), componentId, false);
810 }
811
812 var componentKeyPath = this.CreateComponentKeyPath();
813 componentKeyPath.Id = id.Id;
814 componentKeyPath.Explicit = isKeyPath;
815 componentKeyPath.Type = PossibleKeyPathType.Registry;
816 return componentKeyPath;
817 }
818
819 /// <summary>
820 /// Parses a close application element.
821 /// </summary>
822 /// <param name="element">Element to parse.</param>
823 private void ParseCloseApplicationElement(Intermediate intermediate, IntermediateSection section, XElement element)
824 {
825 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
826 string condition = null;
827 string description = null;
828 string target = null;
829 string property = null;
830 Identifier id = null;
831 int attributes = 2; // default to CLOSEAPP_ATTRIBUTE_REBOOTPROMPT enabled
832 var sequence = CompilerConstants.IntegerNotSet;
833 var terminateExitCode = CompilerConstants.IntegerNotSet;
834 var timeout = CompilerConstants.IntegerNotSet;
835
836 foreach (var attrib in element.Attributes())
837 {
838 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
839 {
840 switch (attrib.Name.LocalName)
841 {
842 case "Id":
843 id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
844 break;
845 case "Condition":
846 condition = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
847 break;
848 case "Description":
849 description = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
850 break;
851 case "Property":
852 property = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
853 break;
854 case "Sequence":
855 sequence = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int32.MaxValue);
856 break;
857 case "Timeout":
858 timeout = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int32.MaxValue);
859 break;
860 case "Target":
861 target = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
862 break;
863 case "CloseMessage":
864 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
865 {
866 attributes |= 1; // CLOSEAPP_ATTRIBUTE_CLOSEMESSAGE
867 }
868 else
869 {
870 attributes &= ~1; // CLOSEAPP_ATTRIBUTE_CLOSEMESSAGE
871 }
872 break;
873 case "EndSessionMessage":
874 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
875 {
876 attributes |= 8; // CLOSEAPP_ATTRIBUTE_ENDSESSIONMESSAGE
877 }
878 else
879 {
880 attributes &= ~8; // CLOSEAPP_ATTRIBUTE_ENDSESSIONMESSAGE
881 }
882 break;
883 case "PromptToContinue":
884 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
885 {
886 attributes |= 0x40; // CLOSEAPP_ATTRIBUTE_PROMPTTOCONTINUE
887 }
888 else
889 {
890 attributes &= ~0x40; // CLOSEAPP_ATTRIBUTE_PROMPTTOCONTINUE
891 }
892 break;
893 case "RebootPrompt":
894 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
895 {
896 attributes |= 2; // CLOSEAPP_ATTRIBUTE_REBOOTPROMPT
897 }
898 else
899 {
900 attributes &= ~2; // CLOSEAPP_ATTRIBUTE_REBOOTPROMPT
901 }
902 break;
903 case "ElevatedCloseMessage":
904 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
905 {
906 attributes |= 4; // CLOSEAPP_ATTRIBUTE_ELEVATEDCLOSEMESSAGE
907 }
908 else
909 {
910 attributes &= ~4; // CLOSEAPP_ATTRIBUTE_ELEVATEDCLOSEMESSAGE
911 }
912 break;
913 case "ElevatedEndSessionMessage":
914 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
915 {
916 attributes |= 0x10; // CLOSEAPP_ATTRIBUTE_ELEVATEDENDSESSIONMESSAGE
917 }
918 else
919 {
920 attributes &= ~0x10; // CLOSEAPP_ATTRIBUTE_ELEVATEDENDSESSIONMESSAGE
921 }
922 break;
923 case "TerminateProcess":
924 terminateExitCode = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int32.MaxValue);
925 attributes |= 0x20; // CLOSEAPP_ATTRIBUTE_TERMINATEPROCESS
926 break;
927 default:
928 this.ParseHelper.UnexpectedAttribute(element, attrib);
929 break;
930 }
931 }
932 else
933 {
934 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
935 }
936 }
937
938 if (null == target)
939 {
940 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Target"));
941 }
942 else if (null == id)
943 {
944 id = this.ParseHelper.CreateIdentifier("ca", target);
945 }
946
947 if (String.IsNullOrEmpty(description) && 0x40 == (attributes & 0x40))
948 {
949 this.Messaging.Write(ErrorMessages.IllegalAttributeValueWithoutOtherAttribute(sourceLineNumbers, element.Name.LocalName, "PromptToContinue", "yes", "Description"));
950 }
951
952 if (0x22 == (attributes & 0x22))
953 {
954 this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, element.Name.LocalName, "TerminateProcess", "RebootPrompt", "yes"));
955 }
956
957 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
958
959 this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4CloseApplications", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
960
961 if (!this.Messaging.EncounteredError)
962 {
963 var symbol = section.AddSymbol(new WixCloseApplicationSymbol(sourceLineNumbers, id)
964 {
965 Target = target,
966 Description = description,
967 Condition = condition,
968 Attributes = attributes,
969 Property = property,
970 });
971 if (CompilerConstants.IntegerNotSet != sequence)
972 {
973 symbol.Sequence = sequence;
974 }
975 if (CompilerConstants.IntegerNotSet != terminateExitCode)
976 {
977 symbol.TerminateExitCode = terminateExitCode;
978 }
979 if (CompilerConstants.IntegerNotSet != timeout)
980 {
981 symbol.Timeout = timeout * 1000; // make the timeout milliseconds in the table.
982 }
983 }
984 }
985
986 /// <summary>
987 /// Parses a DirectorySearch element.
988 /// </summary>
989 /// <param name="element">Element to parse.</param>
990 private void ParseDirectorySearchElement(Intermediate intermediate, IntermediateSection section, XElement element)
991 {
992 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
993 Identifier id = null;
994 string variable = null;
995 string condition = null;
996 string after = null;
997 string path = null;
998 var attributes = WixFileSearchAttributes.IsDirectory;
999
1000 foreach (var attrib in element.Attributes())
1001 {
1002 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
1003 {
1004 switch (attrib.Name.LocalName)
1005 {
1006 case "Id":
1007 case "Variable":
1008 case "Condition":
1009 case "After":
1010 this.ParseCommonSearchAttributes(sourceLineNumbers, attrib, ref id, ref variable, ref condition, ref after);
1011 break;
1012 case "Path":
1013 path = this.ParseHelper.GetAttributeLongFilename(sourceLineNumbers, attrib, false, true);
1014 break;
1015 case "Result":
1016 var result = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
1017 switch (result)
1018 {
1019 case "exists":
1020 attributes |= WixFileSearchAttributes.WantExists;
1021 break;
1022 default:
1023 this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, attrib.Parent.Name.LocalName, attrib.Name.LocalName, result, "exists"));
1024 break;
1025 }
1026 break;
1027 default:
1028 this.ParseHelper.UnexpectedAttribute(element, attrib);
1029 break;
1030 }
1031 }
1032 else
1033 {
1034 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
1035 }
1036 }
1037
1038 if (null == path)
1039 {
1040 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Path"));
1041 }
1042
1043 if (null == id)
1044 {
1045 id = this.ParseHelper.CreateIdentifier("wds", variable, condition, after, path, attributes.ToString());
1046 }
1047
1048 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
1049
1050 this.ParseHelper.CreateWixSearchSymbol(section, sourceLineNumbers, element.Name.LocalName, id, variable, condition, after, null);
1051
1052 if (!this.Messaging.EncounteredError)
1053 {
1054 this.CreateWixFileSearchRow(section, sourceLineNumbers, id, path, attributes);
1055 }
1056 }
1057
1058 /// <summary>
1059 /// Parses a DirectorySearchRef, FileSearchRef, ProductSearchRef, and RegistrySearchRef elements
1060 /// </summary>
1061 /// <param name="node">Element to parse.</param>
1062 private void ParseWixSearchRefElement(Intermediate intermediate, IntermediateSection section, XElement node)
1063 {
1064 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(node);
1065
1066 foreach (XAttribute attrib in node.Attributes())
1067 {
1068 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
1069 {
1070 switch (attrib.Name.LocalName)
1071 {
1072 case "Id":
1073 var refId = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
1074 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, SymbolDefinitions.WixSearch, refId);
1075 break;
1076 default:
1077 this.ParseHelper.UnexpectedAttribute(node, attrib);
1078 break;
1079 }
1080 }
1081 else
1082 {
1083 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, node, attrib);
1084 }
1085 }
1086
1087 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, node);
1088 }
1089
1090 /// <summary>
1091 /// Parses a FileSearch element.
1092 /// </summary>
1093 /// <param name="node">Element to parse.</param>
1094 private void ParseFileSearchElement(Intermediate intermediate, IntermediateSection section, XElement node)
1095 {
1096 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(node);
1097 Identifier id = null;
1098 string variable = null;
1099 string condition = null;
1100 string after = null;
1101 string path = null;
1102 var attributes = WixFileSearchAttributes.Default;
1103
1104 foreach (var attrib in node.Attributes())
1105 {
1106 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
1107 {
1108 switch (attrib.Name.LocalName)
1109 {
1110 case "Id":
1111 case "Variable":
1112 case "Condition":
1113 case "After":
1114 this.ParseCommonSearchAttributes(sourceLineNumbers, attrib, ref id, ref variable, ref condition, ref after);
1115 break;
1116 case "Path":
1117 path = this.ParseHelper.GetAttributeLongFilename(sourceLineNumbers, attrib, false, true);
1118 break;
1119 case "Result":
1120 string result = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
1121 switch (result)
1122 {
1123 case "exists":
1124 attributes |= WixFileSearchAttributes.WantExists;
1125 break;
1126 case "version":
1127 attributes |= WixFileSearchAttributes.WantVersion;
1128 break;
1129 default:
1130 this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, attrib.Parent.Name.LocalName, attrib.Name.LocalName, result, "exists", "version"));
1131 break;
1132 }
1133 break;
1134 default:
1135 this.ParseHelper.UnexpectedAttribute(node, attrib);
1136 break;
1137 }
1138 }
1139 else
1140 {
1141 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, node, attrib);
1142 }
1143 }
1144
1145 if (null == path)
1146 {
1147 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Path"));
1148 }
1149
1150 if (null == id)
1151 {
1152 id = this.ParseHelper.CreateIdentifier("wfs", variable, condition, after, path, attributes.ToString());
1153 }
1154
1155 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, node);
1156
1157 this.ParseHelper.CreateWixSearchSymbol(section, sourceLineNumbers, node.Name.LocalName, id, variable, condition, after, null);
1158
1159 if (!this.Messaging.EncounteredError)
1160 {
1161 this.CreateWixFileSearchRow(section, sourceLineNumbers, id, path, attributes);
1162 }
1163 }
1164
1165 /// <summary>
1166 /// Creates a row in the WixFileSearch table.
1167 /// </summary>
1168 /// <param name="sourceLineNumbers">Source line number for the parent element.</param>
1169 /// <param name="id">Identifier of the search (key into the WixSearch table)</param>
1170 /// <param name="path">File/directory path to search for.</param>
1171 /// <param name="attributes"></param>
1172 private void CreateWixFileSearchRow(IntermediateSection section, SourceLineNumber sourceLineNumbers, Identifier id, string path, WixFileSearchAttributes attributes)
1173 {
1174 section.AddSymbol(new WixFileSearchSymbol(sourceLineNumbers, id)
1175 {
1176 Path = path,
1177 Attributes = attributes,
1178 });
1179 }
1180
1181 /// <summary>
1182 /// Parses a file share element.
1183 /// </summary>
1184 /// <param name="element">Element to parse.</param>
1185 /// <param name="componentId">Identifier of parent component.</param>
1186 /// <param name="directoryId">Identifier of referred to directory.</param>
1187 private void ParseFileShareElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId, string directoryId)
1188 {
1189 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
1190 string description = null;
1191 string name = null;
1192 Identifier id = null;
1193
1194 foreach (var attrib in element.Attributes())
1195 {
1196 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
1197 {
1198 switch (attrib.Name.LocalName)
1199 {
1200 case "Id":
1201 id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
1202 break;
1203 case "Name":
1204 name = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
1205 break;
1206 case "Description":
1207 description = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
1208 break;
1209 default:
1210 this.ParseHelper.UnexpectedAttribute(element, attrib);
1211 break;
1212 }
1213 }
1214 else
1215 {
1216 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
1217 }
1218 }
1219
1220 if (null == id)
1221 {
1222 id = this.ParseHelper.CreateIdentifier("ufs", componentId, name);
1223 }
1224
1225 if (null == name)
1226 {
1227 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Name"));
1228 }
1229
1230 if (!element.Elements().Any())
1231 {
1232 this.Messaging.Write(ErrorMessages.ExpectedElement(sourceLineNumbers, element.Name.LocalName, "FileSharePermission"));
1233 }
1234
1235 foreach (var child in element.Elements())
1236 {
1237 if (this.Namespace == child.Name.Namespace)
1238 {
1239 switch (child.Name.LocalName)
1240 {
1241 case "FileSharePermission":
1242 this.ParseFileSharePermissionElement(intermediate, section, child, id);
1243 break;
1244 default:
1245 this.ParseHelper.UnexpectedElement(element, child);
1246 break;
1247 }
1248 }
1249 else
1250 {
1251 this.ParseHelper.ParseExtensionElement(this.Context.Extensions, intermediate, section, element, child);
1252 }
1253 }
1254
1255 this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4ConfigureSmbInstall", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
1256 this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4ConfigureSmbUninstall", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
1257
1258 if (!this.Messaging.EncounteredError)
1259 {
1260 section.AddSymbol(new FileShareSymbol(sourceLineNumbers, id)
1261 {
1262 ShareName = name,
1263 ComponentRef = componentId,
1264 Description = description,
1265 DirectoryRef = directoryId,
1266 });
1267 }
1268 }
1269
1270 /// <summary>
1271 /// Parses a FileSharePermission element.
1272 /// </summary>
1273 /// <param name="element">Element to parse.</param>
1274 /// <param name="fileShareId">The identifier of the parent FileShare element.</param>
1275 private void ParseFileSharePermissionElement(Intermediate intermediate, IntermediateSection section, XElement element, Identifier fileShareId)
1276 {
1277 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
1278 var bits = new BitArray(32);
1279 string user = null;
1280
1281 foreach (var attrib in element.Attributes())
1282 {
1283 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
1284 {
1285 switch (attrib.Name.LocalName)
1286 {
1287 case "User":
1288 user = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
1289 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, UtilSymbolDefinitions.User, user);
1290 break;
1291 default:
1292 var attribValue = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib);
1293 if (!this.TrySetBitFromName(UtilConstants.StandardPermissions, attrib.Name.LocalName, attribValue, bits, 16))
1294 {
1295 if (!this.TrySetBitFromName(UtilConstants.GenericPermissions, attrib.Name.LocalName, attribValue, bits, 28))
1296 {
1297 if (!this.TrySetBitFromName(UtilConstants.FolderPermissions, attrib.Name.LocalName, attribValue, bits, 0))
1298 {
1299 this.ParseHelper.UnexpectedAttribute(element, attrib);
1300 break;
1301 }
1302 }
1303 }
1304 break;
1305 }
1306 }
1307 else
1308 {
1309 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
1310 }
1311 }
1312
1313 var permission = this.CreateIntegerFromBitArray(bits);
1314
1315 if (null == user)
1316 {
1317 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "User"));
1318 }
1319
1320 if (Int32.MinValue == permission) // just GENERIC_READ, which is MSI_NULL
1321 {
1322 this.Messaging.Write(ErrorMessages.GenericReadNotAllowed(sourceLineNumbers));
1323 }
1324
1325 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
1326
1327 if (!this.Messaging.EncounteredError)
1328 {
1329 section.AddSymbol(new FileSharePermissionsSymbol(sourceLineNumbers)
1330 {
1331 FileShareRef = fileShareId.Id,
1332 UserRef = user,
1333 Permissions = permission,
1334 });
1335 }
1336 }
1337
1338 /// <summary>
1339 /// Parses a group element.
1340 /// </summary>
1341 /// <param name="element">Node to be parsed.</param>
1342 /// <param name="componentId">Component Id of the parent component of this element.</param>
1343 private void ParseGroupElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId)
1344 {
1345 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
1346 Identifier id = null;
1347 string domain = null;
1348 string name = null;
1349
1350 foreach (var attrib in element.Attributes())
1351 {
1352 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
1353 {
1354 switch (attrib.Name.LocalName)
1355 {
1356 case "Id":
1357 id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
1358 break;
1359 case "Name":
1360 name = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
1361 break;
1362 case "Domain":
1363 domain = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
1364 break;
1365 default:
1366 this.ParseHelper.UnexpectedAttribute(element, attrib);
1367 break;
1368 }
1369 }
1370 else
1371 {
1372 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
1373 }
1374 }
1375
1376 if (null == id)
1377 {
1378 id = this.ParseHelper.CreateIdentifier("ugr", componentId, domain, name);
1379 }
1380
1381 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
1382
1383 if (!this.Messaging.EncounteredError)
1384 {
1385 section.AddSymbol(new GroupSymbol(sourceLineNumbers, id)
1386 {
1387 ComponentRef = componentId,
1388 Name = name,
1389 Domain = domain,
1390 });
1391 }
1392 }
1393
1394 /// <summary>
1395 /// Parses a GroupRef element
1396 /// </summary>
1397 /// <param name="element">Element to parse.</param>
1398 /// <param name="userId">Required user id to be joined to the group.</param>
1399 private void ParseGroupRefElement(Intermediate intermediate, IntermediateSection section, XElement element, string userId)
1400 {
1401 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
1402 string groupId = null;
1403
1404 foreach (var attrib in element.Attributes())
1405 {
1406 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
1407 {
1408 switch (attrib.Name.LocalName)
1409 {
1410 case "Id":
1411 groupId = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
1412 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, UtilSymbolDefinitions.Group, groupId);
1413 break;
1414 default:
1415 this.ParseHelper.UnexpectedAttribute(element, attrib);
1416 break;
1417 }
1418 }
1419 else
1420 {
1421 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
1422 }
1423 }
1424
1425 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
1426
1427 if (!this.Messaging.EncounteredError)
1428 {
1429 section.AddSymbol(new UserGroupSymbol(sourceLineNumbers)
1430 {
1431 UserRef = userId,
1432 GroupRef = groupId,
1433 });
1434 }
1435 }
1436
1437 /// <summary>
1438 /// Parses an InternetShortcut element.
1439 /// </summary>
1440 /// <param name="element">Element to parse.</param>
1441 /// <param name="componentId">Identifier of parent component.</param>
1442 /// <param name="defaultTarget">Default directory if none is specified on the InternetShortcut element.</param>
1443 private void ParseInternetShortcutElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId, string defaultTarget)
1444 {
1445 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
1446 Identifier id = null;
1447 string name = null;
1448 string target = null;
1449 string directoryId = null;
1450 string type = null;
1451 string iconFile = null;
1452 int iconIndex = 0;
1453
1454 foreach (var attrib in element.Attributes())
1455 {
1456 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
1457 {
1458 switch (attrib.Name.LocalName)
1459 {
1460 case "Directory":
1461 directoryId = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
1462 break;
1463 case "Id":
1464 id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
1465 break;
1466 case "Name":
1467 name = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
1468 break;
1469 case "Target":
1470 target = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
1471 break;
1472 case "Type":
1473 type = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
1474 break;
1475 case "IconFile":
1476 iconFile = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
1477 break;
1478 case "IconIndex":
1479 iconIndex = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int32.MaxValue);
1480 break;
1481 default:
1482 this.ParseHelper.UnexpectedAttribute(element, attrib);
1483 break;
1484 }
1485 }
1486 else
1487 {
1488 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
1489 }
1490 }
1491
1492 // If there was no directoryId specified on the InternetShortcut element, default to the one on
1493 // the parent component.
1494 if (null == directoryId)
1495 {
1496 directoryId = defaultTarget;
1497 }
1498
1499 if (null == id)
1500 {
1501 id = this.ParseHelper.CreateIdentifier("uis", componentId, directoryId, name, target);
1502 }
1503
1504 // In theory this can never be the case, since InternetShortcut can only be under
1505 // a component element, and if the Directory wasn't specified the default will come
1506 // from the component. However, better safe than sorry, so here's a check to make sure
1507 // it didn't wind up being null after setting it to the defaultTarget.
1508 if (null == directoryId)
1509 {
1510 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Directory"));
1511 }
1512
1513 if (null == name)
1514 {
1515 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Name"));
1516 }
1517
1518 if (null == target)
1519 {
1520 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Target"));
1521 }
1522
1523 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
1524
1525 var shortcutType = InternetShortcutType.Link;
1526 if (String.Equals(type, "url", StringComparison.OrdinalIgnoreCase))
1527 {
1528 shortcutType = InternetShortcutType.Url;
1529 }
1530
1531 if (!this.Messaging.EncounteredError)
1532 {
1533 this.CreateWixInternetShortcut(section, sourceLineNumbers, componentId, directoryId, id, name, target, shortcutType, iconFile, iconIndex);
1534 }
1535 }
1536
1537 /// <summary>
1538 /// Creates the rows needed for WixInternetShortcut to work.
1539 /// </summary>
1540 /// <param name="core">The CompilerCore object used to create rows.</param>
1541 /// <param name="sourceLineNumbers">Source line information about the owner element.</param>
1542 /// <param name="componentId">Identifier of parent component.</param>
1543 /// <param name="directoryId">Identifier of directory containing shortcut.</param>
1544 /// <param name="id">Identifier of shortcut.</param>
1545 /// <param name="name">Name of shortcut without extension.</param>
1546 /// <param name="target">Target URL of shortcut.</param>
1547 private void CreateWixInternetShortcut(IntermediateSection section, SourceLineNumber sourceLineNumbers, string componentId, string directoryId, Identifier shortcutId, string name, string target, InternetShortcutType type, string iconFile, int iconIndex)
1548 {
1549 // add the appropriate extension based on type of shortcut
1550 name = String.Concat(name, InternetShortcutType.Url == type ? ".url" : ".lnk");
1551
1552 section.AddSymbol(new WixInternetShortcutSymbol(sourceLineNumbers, shortcutId)
1553 {
1554 ComponentRef = componentId,
1555 DirectoryRef = directoryId,
1556 Name = name,
1557 Target = target,
1558 Attributes = (int)type,
1559 IconFile = iconFile,
1560 IconIndex = iconIndex,
1561 });
1562
1563 this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4SchedInternetShortcuts", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
1564
1565 // make sure we have a CreateFolder table so that the immediate CA can add temporary rows to handle installation and uninstallation
1566 this.ParseHelper.EnsureTable(section, sourceLineNumbers, "CreateFolder");
1567
1568 // use built-in MSI functionality to remove the shortcuts rather than doing so via CA
1569 section.AddSymbol(new RemoveFileSymbol(sourceLineNumbers, shortcutId)
1570 {
1571 ComponentRef = componentId,
1572 DirPropertyRef = directoryId,
1573 OnUninstall = true,
1574 FileName = name,
1575 });
1576 }
1577
1578 /// <summary>
1579 /// Parses a performance category element.
1580 /// </summary>
1581 /// <param name="element">Element to parse.</param>
1582 /// <param name="componentId">Identifier of parent component.</param>
1583 private void ParsePerformanceCategoryElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId)
1584 {
1585 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
1586 Identifier id = null;
1587 string name = null;
1588 string help = null;
1589 var multiInstance = YesNoType.No;
1590 int defaultLanguage = 0x09; // default to "english"
1591
1592 var parsedPerformanceCounters = new List<ParsedPerformanceCounter>();
1593
1594 // default to managed performance counter
1595 var library = "netfxperf.dll";
1596 var openEntryPoint = "OpenPerformanceData";
1597 var collectEntryPoint = "CollectPerformanceData";
1598 var closeEntryPoint = "ClosePerformanceData";
1599
1600 foreach (var attrib in element.Attributes())
1601 {
1602 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
1603 {
1604 switch (attrib.Name.LocalName)
1605 {
1606 case "Close":
1607 closeEntryPoint = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
1608 break;
1609 case "Collect":
1610 collectEntryPoint = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
1611 break;
1612 case "DefaultLanguage":
1613 defaultLanguage = this.GetPerformanceCounterLanguage(sourceLineNumbers, attrib);
1614 break;
1615 case "Help":
1616 help = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
1617 break;
1618 case "Id":
1619 id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
1620 break;
1621 case "Library":
1622 library = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
1623 break;
1624 case "MultiInstance":
1625 multiInstance = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib);
1626 break;
1627 case "Name":
1628 name = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
1629 break;
1630 case "Open":
1631 openEntryPoint = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
1632 break;
1633 default:
1634 this.ParseHelper.UnexpectedAttribute(element, attrib);
1635 break;
1636 }
1637 }
1638 else
1639 {
1640 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
1641 }
1642 }
1643
1644 if (null == id && null == name)
1645 {
1646 this.Messaging.Write(ErrorMessages.ExpectedAttributes(sourceLineNumbers, element.Name.LocalName, "Id", "Name"));
1647 }
1648 else if (null == id)
1649 {
1650 id = this.ParseHelper.CreateIdentifier("upc", componentId, name);
1651 }
1652 else if (null == name)
1653 {
1654 name = id.Id;
1655 }
1656
1657 // Process the child counter elements.
1658 foreach (var child in element.Elements())
1659 {
1660 if (this.Namespace == child.Name.Namespace)
1661 {
1662 switch (child.Name.LocalName)
1663 {
1664 case "PerformanceCounter":
1665 var counter = this.ParsePerformanceCounterElement(intermediate, section, child, defaultLanguage);
1666 if (null != counter)
1667 {
1668 parsedPerformanceCounters.Add(counter);
1669 }
1670 break;
1671 default:
1672 this.ParseHelper.UnexpectedElement(element, child);
1673 break;
1674 }
1675 }
1676 else
1677 {
1678 this.ParseHelper.ParseExtensionElement(this.Context.Extensions, intermediate, section, element, child);
1679 }
1680 }
1681
1682
1683 if (!this.Messaging.EncounteredError)
1684 {
1685 // Calculate the ini and h file content.
1686 var objectName = "OBJECT_1";
1687 var objectLanguage = defaultLanguage.ToString("D3", CultureInfo.InvariantCulture);
1688
1689 var sbIniData = new StringBuilder();
1690 sbIniData.AppendFormat("[info]\r\ndrivername={0}\r\nsymbolfile=wixperf.h\r\n\r\n[objects]\r\n{1}_{2}_NAME=\r\n\r\n[languages]\r\n{2}=LANG{2}\r\n\r\n", name, objectName, objectLanguage);
1691 sbIniData.AppendFormat("[text]\r\n{0}_{1}_NAME={2}\r\n", objectName, objectLanguage, name);
1692 if (null != help)
1693 {
1694 sbIniData.AppendFormat("{0}_{1}_HELP={2}\r\n", objectName, objectLanguage, help);
1695 }
1696
1697 int symbolConstantsCounter = 0;
1698 var sbSymbolicConstants = new StringBuilder();
1699 sbSymbolicConstants.AppendFormat("#define {0} {1}\r\n", objectName, symbolConstantsCounter);
1700
1701 var sbCounterNames = new StringBuilder("[~]");
1702 var sbCounterTypes = new StringBuilder("[~]");
1703 for (int i = 0; i < parsedPerformanceCounters.Count; ++i)
1704 {
1705 var counter = parsedPerformanceCounters[i];
1706 var counterName = String.Concat("DEVICE_COUNTER_", i + 1);
1707
1708 sbIniData.AppendFormat("{0}_{1}_NAME={2}\r\n", counterName, counter.Language, counter.Name);
1709 if (null != counter.Help)
1710 {
1711 sbIniData.AppendFormat("{0}_{1}_HELP={2}\r\n", counterName, counter.Language, counter.Help);
1712 }
1713
1714 symbolConstantsCounter += 2;
1715 sbSymbolicConstants.AppendFormat("#define {0} {1}\r\n", counterName, symbolConstantsCounter);
1716
1717 sbCounterNames.Append(UtilCompiler.FindPropertyBrackets.Replace(counter.Name, this.EscapeProperties));
1718 sbCounterNames.Append("[~]");
1719 sbCounterTypes.Append(counter.Type);
1720 sbCounterTypes.Append("[~]");
1721 }
1722
1723 sbSymbolicConstants.AppendFormat("#define LAST_{0}_COUNTER_OFFSET {1}\r\n", objectName, symbolConstantsCounter);
1724
1725 // Add the calculated INI and H strings to the PerformanceCategory table.
1726 section.AddSymbol(new PerformanceCategorySymbol(sourceLineNumbers, id)
1727 {
1728 ComponentRef = componentId,
1729 Name = name,
1730 IniData = sbIniData.ToString(),
1731 ConstantData = sbSymbolicConstants.ToString(),
1732 });
1733
1734 // Set up the application's performance key.
1735 var escapedName = UtilCompiler.FindPropertyBrackets.Replace(name, this.EscapeProperties);
1736 var linkageKey = String.Format(@"SYSTEM\CurrentControlSet\Services\{0}\Linkage", escapedName);
1737 var performanceKey = String.Format(@"SYSTEM\CurrentControlSet\Services\{0}\Performance", escapedName);
1738
1739 this.ParseHelper.CreateRegistrySymbol(section, sourceLineNumbers, RegistryRootType.LocalMachine, linkageKey, "Export", escapedName, componentId, false);
1740 this.ParseHelper.CreateRegistrySymbol(section, sourceLineNumbers, RegistryRootType.LocalMachine, performanceKey, "-", null, componentId, false);
1741 this.ParseHelper.CreateRegistrySymbol(section, sourceLineNumbers, RegistryRootType.LocalMachine, performanceKey, "Library", library, componentId, false);
1742 this.ParseHelper.CreateRegistrySymbol(section, sourceLineNumbers, RegistryRootType.LocalMachine, performanceKey, "Open", openEntryPoint, componentId, false);
1743 this.ParseHelper.CreateRegistrySymbol(section, sourceLineNumbers, RegistryRootType.LocalMachine, performanceKey, "Collect", collectEntryPoint, componentId, false);
1744 this.ParseHelper.CreateRegistrySymbol(section, sourceLineNumbers, RegistryRootType.LocalMachine, performanceKey, "Close", closeEntryPoint, componentId, false);
1745 this.ParseHelper.CreateRegistrySymbol(section, sourceLineNumbers, RegistryRootType.LocalMachine, performanceKey, "IsMultiInstance", YesNoType.Yes == multiInstance ? "#1" : "#0", componentId, false);
1746 this.ParseHelper.CreateRegistrySymbol(section, sourceLineNumbers, RegistryRootType.LocalMachine, performanceKey, "Counter Names", sbCounterNames.ToString(), componentId, false);
1747 this.ParseHelper.CreateRegistrySymbol(section, sourceLineNumbers, RegistryRootType.LocalMachine, performanceKey, "Counter Types", sbCounterTypes.ToString(), componentId, false);
1748 }
1749
1750 this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4InstallPerfCounterData", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
1751 this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4UninstallPerfCounterData", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
1752 }
1753
1754 /// <summary>
1755 /// Gets the performance counter language as a decimal number.
1756 /// </summary>
1757 /// <param name="sourceLineNumbers">Source line information about the owner element.</param>
1758 /// <param name="attribute">The attribute containing the value to get.</param>
1759 /// <returns>Numeric representation of the language as per WinNT.h.</returns>
1760 private int GetPerformanceCounterLanguage(SourceLineNumber sourceLineNumbers, XAttribute attribute)
1761 {
1762 int language = 0;
1763 if (String.Empty == attribute.Value)
1764 {
1765 this.Messaging.Write(ErrorMessages.IllegalEmptyAttributeValue(sourceLineNumbers, attribute.Parent.Name.LocalName, attribute.Name.LocalName));
1766 }
1767 else
1768 {
1769 switch (attribute.Value)
1770 {
1771 case "afrikaans":
1772 language = 0x36;
1773 break;
1774 case "albanian":
1775 language = 0x1c;
1776 break;
1777 case "arabic":
1778 language = 0x01;
1779 break;
1780 case "armenian":
1781 language = 0x2b;
1782 break;
1783 case "assamese":
1784 language = 0x4d;
1785 break;
1786 case "azeri":
1787 language = 0x2c;
1788 break;
1789 case "basque":
1790 language = 0x2d;
1791 break;
1792 case "belarusian":
1793 language = 0x23;
1794 break;
1795 case "bengali":
1796 language = 0x45;
1797 break;
1798 case "bulgarian":
1799 language = 0x02;
1800 break;
1801 case "catalan":
1802 language = 0x03;
1803 break;
1804 case "chinese":
1805 language = 0x04;
1806 break;
1807 case "croatian":
1808 language = 0x1a;
1809 break;
1810 case "czech":
1811 language = 0x05;
1812 break;
1813 case "danish":
1814 language = 0x06;
1815 break;
1816 case "divehi":
1817 language = 0x65;
1818 break;
1819 case "dutch":
1820 language = 0x13;
1821 break;
1822 case "piglatin":
1823 case "english":
1824 language = 0x09;
1825 break;
1826 case "estonian":
1827 language = 0x25;
1828 break;
1829 case "faeroese":
1830 language = 0x38;
1831 break;
1832 case "farsi":
1833 language = 0x29;
1834 break;
1835 case "finnish":
1836 language = 0x0b;
1837 break;
1838 case "french":
1839 language = 0x0c;
1840 break;
1841 case "galician":
1842 language = 0x56;
1843 break;
1844 case "georgian":
1845 language = 0x37;
1846 break;
1847 case "german":
1848 language = 0x07;
1849 break;
1850 case "greek":
1851 language = 0x08;
1852 break;
1853 case "gujarati":
1854 language = 0x47;
1855 break;
1856 case "hebrew":
1857 language = 0x0d;
1858 break;
1859 case "hindi":
1860 language = 0x39;
1861 break;
1862 case "hungarian":
1863 language = 0x0e;
1864 break;
1865 case "icelandic":
1866 language = 0x0f;
1867 break;
1868 case "indonesian":
1869 language = 0x21;
1870 break;
1871 case "italian":
1872 language = 0x10;
1873 break;
1874 case "japanese":
1875 language = 0x11;
1876 break;
1877 case "kannada":
1878 language = 0x4b;
1879 break;
1880 case "kashmiri":
1881 language = 0x60;
1882 break;
1883 case "kazak":
1884 language = 0x3f;
1885 break;
1886 case "konkani":
1887 language = 0x57;
1888 break;
1889 case "korean":
1890 language = 0x12;
1891 break;
1892 case "kyrgyz":
1893 language = 0x40;
1894 break;
1895 case "latvian":
1896 language = 0x26;
1897 break;
1898 case "lithuanian":
1899 language = 0x27;
1900 break;
1901 case "macedonian":
1902 language = 0x2f;
1903 break;
1904 case "malay":
1905 language = 0x3e;
1906 break;
1907 case "malayalam":
1908 language = 0x4c;
1909 break;
1910 case "manipuri":
1911 language = 0x58;
1912 break;
1913 case "marathi":
1914 language = 0x4e;
1915 break;
1916 case "mongolian":
1917 language = 0x50;
1918 break;
1919 case "nepali":
1920 language = 0x61;
1921 break;
1922 case "norwegian":
1923 language = 0x14;
1924 break;
1925 case "oriya":
1926 language = 0x48;
1927 break;
1928 case "polish":
1929 language = 0x15;
1930 break;
1931 case "portuguese":
1932 language = 0x16;
1933 break;
1934 case "punjabi":
1935 language = 0x46;
1936 break;
1937 case "romanian":
1938 language = 0x18;
1939 break;
1940 case "russian":
1941 language = 0x19;
1942 break;
1943 case "sanskrit":
1944 language = 0x4f;
1945 break;
1946 case "serbian":
1947 language = 0x1a;
1948 break;
1949 case "sindhi":
1950 language = 0x59;
1951 break;
1952 case "slovak":
1953 language = 0x1b;
1954 break;
1955 case "slovenian":
1956 language = 0x24;
1957 break;
1958 case "spanish":
1959 language = 0x0a;
1960 break;
1961 case "swahili":
1962 language = 0x41;
1963 break;
1964 case "swedish":
1965 language = 0x1d;
1966 break;
1967 case "syriac":
1968 language = 0x5a;
1969 break;
1970 case "tamil":
1971 language = 0x49;
1972 break;
1973 case "tatar":
1974 language = 0x44;
1975 break;
1976 case "telugu":
1977 language = 0x4a;
1978 break;
1979 case "thai":
1980 language = 0x1e;
1981 break;
1982 case "turkish":
1983 language = 0x1f;
1984 break;
1985 case "ukrainian":
1986 language = 0x22;
1987 break;
1988 case "urdu":
1989 language = 0x20;
1990 break;
1991 case "uzbek":
1992 language = 0x43;
1993 break;
1994 case "vietnamese":
1995 language = 0x2a;
1996 break;
1997 default:
1998 this.Messaging.Write(ErrorMessages.IllegalEmptyAttributeValue(sourceLineNumbers, attribute.Parent.Name.LocalName, attribute.Name.LocalName));
1999 break;
2000 }
2001 }
2002
2003 return language;
2004 }
2005
2006 /// <summary>
2007 /// Parses a performance counter element.
2008 /// </summary>
2009 /// <param name="element">Element to parse.</param>
2010 /// <param name="defaultLanguage">Default language for the performance counter.</param>
2011 private ParsedPerformanceCounter ParsePerformanceCounterElement(Intermediate intermediate, IntermediateSection section, XElement element, int defaultLanguage)
2012 {
2013 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
2014 ParsedPerformanceCounter parsedPerformanceCounter = null;
2015 string name = null;
2016 string help = null;
2017 var type = System.Diagnostics.PerformanceCounterType.NumberOfItems32;
2018 int language = defaultLanguage;
2019
2020 foreach (var attrib in element.Attributes())
2021 {
2022 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
2023 {
2024 switch (attrib.Name.LocalName)
2025 {
2026 case "Help":
2027 help = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
2028 break;
2029 case "Name":
2030 name = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
2031 break;
2032 case "Type":
2033 type = this.GetPerformanceCounterType(sourceLineNumbers, attrib);
2034 break;
2035 case "Language":
2036 language = this.GetPerformanceCounterLanguage(sourceLineNumbers, attrib);
2037 break;
2038 default:
2039 this.ParseHelper.UnexpectedAttribute(element, attrib);
2040 break;
2041 }
2042 }
2043 else
2044 {
2045 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
2046 }
2047 }
2048
2049 if (null == name)
2050 {
2051 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Name"));
2052 }
2053
2054 if (null == help)
2055 {
2056 this.Messaging.Write(UtilWarnings.RequiredAttributeForWindowsXP(sourceLineNumbers, element.Name.LocalName, "Help"));
2057 }
2058
2059 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
2060
2061 if (!this.Messaging.EncounteredError)
2062 {
2063 parsedPerformanceCounter = new ParsedPerformanceCounter(name, help, type, language);
2064 }
2065
2066 return parsedPerformanceCounter;
2067 }
2068
2069 /// <summary>
2070 /// Gets the performance counter type.
2071 /// </summary>
2072 /// <param name="sourceLineNumbers">Source line information about the owner element.</param>
2073 /// <param name="attribute">The attribute containing the value to get.</param>
2074 /// <returns>Numeric representation of the language as per WinNT.h.</returns>
2075 private System.Diagnostics.PerformanceCounterType GetPerformanceCounterType(SourceLineNumber sourceLineNumbers, XAttribute attribute)
2076 {
2077 var type = System.Diagnostics.PerformanceCounterType.NumberOfItems32;
2078 if (String.Empty == attribute.Value)
2079 {
2080 this.Messaging.Write(ErrorMessages.IllegalEmptyAttributeValue(sourceLineNumbers, attribute.Parent.Name.LocalName, attribute.Name.LocalName));
2081 }
2082 else
2083 {
2084 switch (attribute.Value)
2085 {
2086 case "averageBase":
2087 type = System.Diagnostics.PerformanceCounterType.AverageBase;
2088 break;
2089 case "averageCount64":
2090 type = System.Diagnostics.PerformanceCounterType.AverageCount64;
2091 break;
2092 case "averageTimer32":
2093 type = System.Diagnostics.PerformanceCounterType.AverageTimer32;
2094 break;
2095 case "counterDelta32":
2096 type = System.Diagnostics.PerformanceCounterType.CounterDelta32;
2097 break;
2098 case "counterTimerInverse":
2099 type = System.Diagnostics.PerformanceCounterType.CounterTimerInverse;
2100 break;
2101 case "sampleFraction":
2102 type = System.Diagnostics.PerformanceCounterType.SampleFraction;
2103 break;
2104 case "timer100Ns":
2105 type = System.Diagnostics.PerformanceCounterType.Timer100Ns;
2106 break;
2107 case "counterTimer":
2108 type = System.Diagnostics.PerformanceCounterType.CounterTimer;
2109 break;
2110 case "rawFraction":
2111 type = System.Diagnostics.PerformanceCounterType.RawFraction;
2112 break;
2113 case "timer100NsInverse":
2114 type = System.Diagnostics.PerformanceCounterType.Timer100NsInverse;
2115 break;
2116 case "counterMultiTimer":
2117 type = System.Diagnostics.PerformanceCounterType.CounterMultiTimer;
2118 break;
2119 case "counterMultiTimer100Ns":
2120 type = System.Diagnostics.PerformanceCounterType.CounterMultiTimer100Ns;
2121 break;
2122 case "counterMultiTimerInverse":
2123 type = System.Diagnostics.PerformanceCounterType.CounterMultiTimerInverse;
2124 break;
2125 case "counterMultiTimer100NsInverse":
2126 type = System.Diagnostics.PerformanceCounterType.CounterMultiTimer100NsInverse;
2127 break;
2128 case "elapsedTime":
2129 type = System.Diagnostics.PerformanceCounterType.ElapsedTime;
2130 break;
2131 case "sampleBase":
2132 type = System.Diagnostics.PerformanceCounterType.SampleBase;
2133 break;
2134 case "rawBase":
2135 type = System.Diagnostics.PerformanceCounterType.RawBase;
2136 break;
2137 case "counterMultiBase":
2138 type = System.Diagnostics.PerformanceCounterType.CounterMultiBase;
2139 break;
2140 case "rateOfCountsPerSecond64":
2141 type = System.Diagnostics.PerformanceCounterType.RateOfCountsPerSecond64;
2142 break;
2143 case "rateOfCountsPerSecond32":
2144 type = System.Diagnostics.PerformanceCounterType.RateOfCountsPerSecond32;
2145 break;
2146 case "countPerTimeInterval64":
2147 type = System.Diagnostics.PerformanceCounterType.CountPerTimeInterval64;
2148 break;
2149 case "countPerTimeInterval32":
2150 type = System.Diagnostics.PerformanceCounterType.CountPerTimeInterval32;
2151 break;
2152 case "sampleCounter":
2153 type = System.Diagnostics.PerformanceCounterType.SampleCounter;
2154 break;
2155 case "counterDelta64":
2156 type = System.Diagnostics.PerformanceCounterType.CounterDelta64;
2157 break;
2158 case "numberOfItems64":
2159 type = System.Diagnostics.PerformanceCounterType.NumberOfItems64;
2160 break;
2161 case "numberOfItems32":
2162 type = System.Diagnostics.PerformanceCounterType.NumberOfItems32;
2163 break;
2164 case "numberOfItemsHEX64":
2165 type = System.Diagnostics.PerformanceCounterType.NumberOfItemsHEX64;
2166 break;
2167 case "numberOfItemsHEX32":
2168 type = System.Diagnostics.PerformanceCounterType.NumberOfItemsHEX32;
2169 break;
2170 default:
2171 this.Messaging.Write(ErrorMessages.IllegalEmptyAttributeValue(sourceLineNumbers, attribute.Parent.Name.LocalName, attribute.Name.LocalName));
2172 break;
2173 }
2174 }
2175
2176 return type;
2177 }
2178
2179 /// <summary>
2180 /// Parses a perf counter element.
2181 /// </summary>
2182 /// <param name="element">Element to parse.</param>
2183 /// <param name="componentId">Identifier of parent component.</param>
2184 /// <param name="fileId">Identifier of referenced file.</param>
2185 private void ParsePerfCounterElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId, string fileId)
2186 {
2187 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
2188 string name = null;
2189
2190 this.Messaging.Write(UtilWarnings.DeprecatedPerfCounterElement(sourceLineNumbers));
2191
2192 foreach (var attrib in element.Attributes())
2193 {
2194 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
2195 {
2196 switch (attrib.Name.LocalName)
2197 {
2198 case "Name":
2199 name = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
2200 break;
2201 default:
2202 this.ParseHelper.UnexpectedAttribute(element, attrib);
2203 break;
2204 }
2205 }
2206 else
2207 {
2208 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
2209 }
2210 }
2211
2212 if (null == name)
2213 {
2214 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Name"));
2215 }
2216
2217 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
2218
2219 if (!this.Messaging.EncounteredError)
2220 {
2221 section.AddSymbol(new PerfmonSymbol(sourceLineNumbers)
2222 {
2223 ComponentRef = componentId,
2224 File = $"[#{fileId}]",
2225 Name = name,
2226 });
2227 }
2228
2229 this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4ConfigurePerfmonInstall", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
2230 this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4ConfigurePerfmonUninstall", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
2231 }
2232
2233
2234 /// <summary>
2235 /// Parses a perf manifest element.
2236 /// </summary>
2237 /// <param name="element">Element to parse.</param>
2238 /// <param name="componentId">Identifier of parent component.</param>
2239 /// <param name="fileId">Identifier of referenced file.</param>
2240 private void ParsePerfCounterManifestElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId, string fileId)
2241 {
2242 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
2243 string resourceFileDirectory = null;
2244
2245 foreach (var attrib in element.Attributes())
2246 {
2247 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
2248 {
2249 switch (attrib.Name.LocalName)
2250 {
2251 case "ResourceFileDirectory":
2252 resourceFileDirectory = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
2253 break;
2254 default:
2255 this.ParseHelper.UnexpectedAttribute(element, attrib);
2256 break;
2257 }
2258 }
2259 else
2260 {
2261 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
2262 }
2263 }
2264
2265 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
2266
2267 if (!this.Messaging.EncounteredError)
2268 {
2269 section.AddSymbol(new PerfmonManifestSymbol(sourceLineNumbers)
2270 {
2271 ComponentRef = componentId,
2272 File = $"[#{fileId}]",
2273 ResourceFileDirectory = resourceFileDirectory,
2274 });
2275 }
2276
2277 this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4ConfigurePerfmonManifestRegister", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
2278 this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4ConfigurePerfmonManifestUnregister", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
2279 }
2280
2281 /// <summary>
2282 /// Parses a format files element.
2283 /// </summary>
2284 /// <param name="element">Element to parse.</param>
2285 /// <param name="fileId">Identifier of referenced file.</param>
2286 /// <param name="win64">Flag to determine whether the component is 64-bit.</param>
2287 private void ParseFormatFileElement(Intermediate intermediate, IntermediateSection section, XElement element, string fileId, bool win64)
2288 {
2289 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
2290 string binaryId = null;
2291
2292 foreach (var attrib in element.Attributes())
2293 {
2294 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
2295 {
2296 switch (attrib.Name.LocalName)
2297 {
2298 case "BinaryRef":
2299 binaryId = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
2300 break;
2301 default:
2302 this.ParseHelper.UnexpectedAttribute(element, attrib);
2303 break;
2304 }
2305 }
2306 else
2307 {
2308 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
2309 }
2310 }
2311
2312 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
2313
2314 if (null == binaryId)
2315 {
2316 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "BinaryRef"));
2317 }
2318
2319 if (!this.Messaging.EncounteredError)
2320 {
2321 this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4SchedFormatFiles", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
2322
2323 section.AddSymbol(new WixFormatFilesSymbol(sourceLineNumbers)
2324 {
2325 BinaryRef = binaryId,
2326 FileRef = fileId,
2327 });
2328
2329 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, SymbolDefinitions.Binary, binaryId);
2330 }
2331 }
2332
2333 /// <summary>
2334 /// Parses a event manifest element.
2335 /// </summary>
2336 /// <param name="element">Element to parse.</param>
2337 /// <param name="componentId">Identifier of parent component.</param>
2338 /// <param name="fileId">Identifier of referenced file.</param>
2339 private void ParseEventManifestElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId, string fileId)
2340 {
2341 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
2342 string messageFile = null;
2343 string resourceFile = null;
2344 string parameterFile = null;
2345
2346 foreach (var attrib in element.Attributes())
2347 {
2348 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
2349 {
2350 switch (attrib.Name.LocalName)
2351 {
2352 case "MessageFile":
2353 messageFile = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
2354 break;
2355 case "ResourceFile":
2356 resourceFile = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
2357 break;
2358 case "ParameterFile":
2359 parameterFile = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
2360 break;
2361 default:
2362 this.ParseHelper.UnexpectedAttribute(element, attrib);
2363 break;
2364 }
2365 }
2366 else
2367 {
2368 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
2369 }
2370 }
2371
2372 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
2373
2374 if (!this.Messaging.EncounteredError)
2375 {
2376 section.AddSymbol(new EventManifestSymbol(sourceLineNumbers)
2377 {
2378 ComponentRef = componentId,
2379 File = $"[#{fileId}]",
2380 });
2381
2382 if (null != messageFile)
2383 {
2384 section.AddSymbol(new XmlFileSymbol(sourceLineNumbers, new Identifier(AccessModifier.Section, $"Config_{fileId}MessageFile"))
2385 {
2386 File = $"[#{fileId}]",
2387 ElementPath = "/*/*/*/*[\\[]@messageFileName[\\]]",
2388 Name = "messageFileName",
2389 Value = messageFile,
2390 Flags = 4 | 0x00001000, //bulk write | preserve modified date
2391 ComponentRef = componentId,
2392 });
2393 }
2394 if (null != parameterFile)
2395 {
2396 section.AddSymbol(new XmlFileSymbol(sourceLineNumbers, new Identifier(AccessModifier.Section, $"Config_{fileId}ParameterFile"))
2397 {
2398 File = $"[#{fileId}]",
2399 ElementPath = "/*/*/*/*[\\[]@parameterFileName[\\]]",
2400 Name = "parameterFileName",
2401 Value = parameterFile,
2402 Flags = 4 | 0x00001000, //bulk write | preserve modified date
2403 ComponentRef = componentId,
2404 });
2405 }
2406 if (null != resourceFile)
2407 {
2408 section.AddSymbol(new XmlFileSymbol(sourceLineNumbers, new Identifier(AccessModifier.Section, $"Config_{fileId}ResourceFile"))
2409 {
2410 File = $"[#{fileId}]",
2411 ElementPath = "/*/*/*/*[\\[]@resourceFileName[\\]]",
2412 Name = "resourceFileName",
2413 Value = resourceFile,
2414 Flags = 4 | 0x00001000, //bulk write | preserve modified date
2415 ComponentRef = componentId,
2416 });
2417 }
2418
2419 }
2420
2421 this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4ConfigureEventManifestRegister", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
2422 this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4ConfigureEventManifestUnregister", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
2423
2424 if (null != messageFile || null != parameterFile || null != resourceFile)
2425 {
2426 this.AddReferenceToSchedXmlFile(sourceLineNumbers, section);
2427 }
2428 }
2429
2430 /// <summary>
2431 /// Parses a PermissionEx element.
2432 /// </summary>
2433 /// <param name="element">Element to parse.</param>
2434 /// <param name="objectId">Identifier of object to be secured.</param>
2435 /// <param name="componentId">Identifier of component, used to determine install state.</param>
2436 /// <param name="win64">Flag to determine whether the component is 64-bit.</param>
2437 /// <param name="tableName">Name of table that contains objectId.</param>
2438 private void ParsePermissionExElement(Intermediate intermediate, IntermediateSection section, XElement element, string objectId, string componentId, bool win64, string tableName)
2439 {
2440 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
2441 var bits = new BitArray(32);
2442 string domain = null;
2443 string[] specialPermissions = null;
2444 string user = null;
2445 var attributes = WixPermissionExAttributes.Inheritable; // default to inheritable.
2446
2447 var permissionType = PermissionType.SecureObjects;
2448
2449 switch (tableName)
2450 {
2451 case "CreateFolder":
2452 specialPermissions = UtilConstants.FolderPermissions;
2453 break;
2454 case "File":
2455 specialPermissions = UtilConstants.FilePermissions;
2456 break;
2457 case "Registry":
2458 specialPermissions = UtilConstants.RegistryPermissions;
2459 if (String.IsNullOrEmpty(objectId))
2460 {
2461 this.Messaging.Write(UtilErrors.InvalidRegistryObject(sourceLineNumbers, element.Parent.Name.LocalName));
2462 }
2463 break;
2464 case "ServiceInstall":
2465 specialPermissions = UtilConstants.ServicePermissions;
2466 permissionType = PermissionType.SecureObjects;
2467 break;
2468 default:
2469 this.ParseHelper.UnexpectedElement(element.Parent, element);
2470 break;
2471 }
2472
2473 foreach (var attrib in element.Attributes())
2474 {
2475 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
2476 {
2477 switch (attrib.Name.LocalName)
2478 {
2479 case "Domain":
2480 if (PermissionType.FileSharePermissions == permissionType)
2481 {
2482 this.Messaging.Write(ErrorMessages.IllegalAttributeWhenNested(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, element.Parent.Name.LocalName));
2483 }
2484 domain = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
2485 break;
2486 case "Inheritable":
2487 if (this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib) == YesNoType.No)
2488 {
2489 attributes &= ~WixPermissionExAttributes.Inheritable;
2490 }
2491 break;
2492 case "User":
2493 user = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
2494 break;
2495 default:
2496 var attribValue = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib);
2497 if (!this.TrySetBitFromName(UtilConstants.StandardPermissions, attrib.Name.LocalName, attribValue, bits, 16))
2498 {
2499 if (!this.TrySetBitFromName(UtilConstants.GenericPermissions, attrib.Name.LocalName, attribValue, bits, 28))
2500 {
2501 if (!this.TrySetBitFromName(specialPermissions, attrib.Name.LocalName, attribValue, bits, 0))
2502 {
2503 this.ParseHelper.UnexpectedAttribute(element, attrib);
2504 break;
2505 }
2506 }
2507 }
2508 break;
2509 }
2510 }
2511 else
2512 {
2513 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
2514 }
2515 }
2516
2517 var permission = this.CreateIntegerFromBitArray(bits);
2518
2519 if (null == user)
2520 {
2521 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "User"));
2522 }
2523
2524 if (Int32.MinValue == permission) // just GENERIC_READ, which is MSI_NULL
2525 {
2526 this.Messaging.Write(ErrorMessages.GenericReadNotAllowed(sourceLineNumbers));
2527 }
2528
2529 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
2530
2531 if (!this.Messaging.EncounteredError)
2532 {
2533 this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4SchedSecureObjects", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
2534
2535 var id = this.ParseHelper.CreateIdentifier("sec", objectId, tableName, domain, user);
2536 section.AddSymbol(new SecureObjectsSymbol(sourceLineNumbers, id)
2537 {
2538 SecureObject = objectId,
2539 Table = tableName,
2540 Domain = domain,
2541 User = user,
2542 Attributes = attributes,
2543 Permission = permission,
2544 ComponentRef = componentId,
2545 });
2546 }
2547 }
2548
2549 /// <summary>
2550 /// Parses a ProductSearch element.
2551 /// </summary>
2552 /// <param name="element">Element to parse.</param>
2553 private void ParseProductSearchElement(Intermediate intermediate, IntermediateSection section, XElement element)
2554 {
2555 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
2556 Identifier id = null;
2557 string variable = null;
2558 string condition = null;
2559 string after = null;
2560 string productCode = null;
2561 string upgradeCode = null;
2562 var attributes = WixProductSearchAttributes.Version;
2563
2564 foreach (var attrib in element.Attributes())
2565 {
2566 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
2567 {
2568 switch (attrib.Name.LocalName)
2569 {
2570 case "Id":
2571 case "Variable":
2572 case "Condition":
2573 case "After":
2574 this.ParseCommonSearchAttributes(sourceLineNumbers, attrib, ref id, ref variable, ref condition, ref after);
2575 break;
2576 case "ProductCode":
2577 productCode = this.ParseHelper.GetAttributeGuidValue(sourceLineNumbers, attrib, false);
2578 break;
2579 case "UpgradeCode":
2580 upgradeCode = this.ParseHelper.GetAttributeGuidValue(sourceLineNumbers, attrib, false);
2581 break;
2582 case "Result":
2583 var result = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
2584 switch (result)
2585 {
2586 case "version":
2587 attributes = WixProductSearchAttributes.Version;
2588 break;
2589 case "language":
2590 attributes = WixProductSearchAttributes.Language;
2591 break;
2592 case "state":
2593 attributes = WixProductSearchAttributes.State;
2594 break;
2595 case "assignment":
2596 attributes = WixProductSearchAttributes.Assignment;
2597 break;
2598 default:
2599 this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, attrib.Parent.Name.LocalName, attrib.Name.LocalName, result, "version", "language", "state", "assignment"));
2600 break;
2601 }
2602 break;
2603 default:
2604 this.ParseHelper.UnexpectedAttribute(element, attrib);
2605 break;
2606 }
2607 }
2608 else
2609 {
2610 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
2611 }
2612 }
2613
2614 if (null == upgradeCode && null == productCode)
2615 {
2616 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "ProductCode", "UpgradeCode", true));
2617 }
2618
2619 if (null != upgradeCode && null != productCode)
2620 {
2621 this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, element.Name.LocalName, "UpgradeCode", "ProductCode"));
2622 }
2623
2624 if (null == id)
2625 {
2626 id = this.ParseHelper.CreateIdentifier("wps", variable, condition, after, (productCode == null ? upgradeCode : productCode), attributes.ToString());
2627 }
2628
2629 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
2630
2631 this.ParseHelper.CreateWixSearchSymbol(section, sourceLineNumbers, element.Name.LocalName, id, variable, condition, after, null);
2632
2633 if (!this.Messaging.EncounteredError)
2634 {
2635 // set an additional flag if this is an upgrade code
2636 if (null != upgradeCode)
2637 {
2638 attributes |= WixProductSearchAttributes.UpgradeCode;
2639 }
2640
2641 section.AddSymbol(new WixProductSearchSymbol(sourceLineNumbers, id)
2642 {
2643 Guid = productCode ?? upgradeCode,
2644 Attributes = attributes,
2645 });
2646 }
2647 }
2648
2649 /// <summary>
2650 /// Parses a RegistrySearch element.
2651 /// </summary>
2652 /// <param name="element">Element to parse.</param>
2653 private void ParseRegistrySearchElement(Intermediate intermediate, IntermediateSection section, XElement element)
2654 {
2655 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
2656 Identifier id = null;
2657 string variable = null;
2658 string condition = null;
2659 string after = null;
2660 RegistryRootType? root = null;
2661 string key = null;
2662 string value = null;
2663 var expand = YesNoType.NotSet;
2664 var win64 = this.Context.IsCurrentPlatform64Bit;
2665 var attributes = WixRegistrySearchAttributes.Raw | WixRegistrySearchAttributes.WantValue;
2666
2667 foreach (var attrib in element.Attributes())
2668 {
2669 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
2670 {
2671 switch (attrib.Name.LocalName)
2672 {
2673 case "Id":
2674 case "Variable":
2675 case "Condition":
2676 case "After":
2677 this.ParseCommonSearchAttributes(sourceLineNumbers, attrib, ref id, ref variable, ref condition, ref after);
2678 break;
2679 case "Bitness":
2680 var bitnessValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
2681 switch (bitnessValue)
2682 {
2683 case "always32":
2684 win64 = false;
2685 break;
2686 case "always64":
2687 win64 = true;
2688 break;
2689 case "default":
2690 case "":
2691 break;
2692 default:
2693 this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, attrib.Name.LocalName, attrib.Name.LocalName, bitnessValue, "default", "always32", "always64"));
2694 break;
2695 }
2696 break;
2697 case "Root":
2698 root = this.ParseHelper.GetAttributeRegistryRootValue(sourceLineNumbers, attrib, false);
2699 break;
2700 case "Key":
2701 key = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
2702 break;
2703 case "Value":
2704 value = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
2705 break;
2706 case "ExpandEnvironmentVariables":
2707 expand = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib);
2708 break;
2709 case "Format":
2710 string format = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
2711 switch (format)
2712 {
2713 case "raw":
2714 attributes |= WixRegistrySearchAttributes.Raw;
2715 break;
2716 case "compatible":
2717 attributes |= WixRegistrySearchAttributes.Compatible;
2718 break;
2719 default:
2720 this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, attrib.Parent.Name.LocalName, attrib.Name.LocalName, format, "raw", "compatible"));
2721 break;
2722 }
2723 break;
2724 case "Result":
2725 var result = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
2726 switch (result)
2727 {
2728 case "exists":
2729 attributes |= WixRegistrySearchAttributes.WantExists;
2730 break;
2731 case "value":
2732 attributes |= WixRegistrySearchAttributes.WantValue;
2733 break;
2734 default:
2735 this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, attrib.Parent.Name.LocalName, attrib.Name.LocalName, result, "exists", "value"));
2736 break;
2737 }
2738 break;
2739 default:
2740 this.ParseHelper.UnexpectedAttribute(element, attrib);
2741 break;
2742 }
2743 }
2744 else
2745 {
2746 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
2747 }
2748 }
2749
2750 if (!root.HasValue)
2751 {
2752 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Root"));
2753 }
2754
2755 if (null == key)
2756 {
2757 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Key"));
2758 }
2759
2760 if (null == id)
2761 {
2762 id = this.ParseHelper.CreateIdentifier("wrs", variable, condition, after, root.ToString(), key, value, attributes.ToString());
2763 }
2764
2765 if (expand == YesNoType.Yes)
2766 {
2767 if (0 != (attributes & WixRegistrySearchAttributes.WantExists))
2768 {
2769 this.Messaging.Write(ErrorMessages.IllegalAttributeValueWithOtherAttribute(sourceLineNumbers, element.Name.LocalName, "ExpandEnvironmentVariables", expand.ToString(), "Result", "exists"));
2770 }
2771
2772 attributes |= WixRegistrySearchAttributes.ExpandEnvironmentVariables;
2773 }
2774
2775 if (win64)
2776 {
2777 attributes |= WixRegistrySearchAttributes.Win64;
2778 }
2779
2780 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
2781
2782 this.ParseHelper.CreateWixSearchSymbol(section, sourceLineNumbers, element.Name.LocalName, id, variable, condition, after, null);
2783
2784 if (!this.Messaging.EncounteredError)
2785 {
2786 section.AddSymbol(new WixRegistrySearchSymbol(sourceLineNumbers, id)
2787 {
2788 Root = root.Value,
2789 Key = key,
2790 Value = value,
2791 Attributes = attributes,
2792 });
2793 }
2794 }
2795
2796 /// <summary>
2797 /// Parses a RemoveFolderEx element.
2798 /// </summary>
2799 /// <param name="element">Element to parse.</param>
2800 /// <param name="componentId">Identifier of parent component.</param>
2801 private void ParseRemoveFolderExElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId)
2802 {
2803 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
2804 Identifier id = null;
2805 var mode = WixRemoveFolderExInstallMode.Uninstall;
2806 string property = null;
2807 string condition = null;
2808
2809 foreach (var attrib in element.Attributes())
2810 {
2811 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
2812 {
2813 switch (attrib.Name.LocalName)
2814 {
2815 case "Condition":
2816 condition = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
2817 break;
2818 case "Id":
2819 id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
2820 break;
2821 case "On":
2822 var onValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
2823 if (onValue.Length == 0)
2824 {
2825 }
2826 else
2827 {
2828 switch (onValue)
2829 {
2830 case "install":
2831 mode = WixRemoveFolderExInstallMode.Install;
2832 break;
2833 case "uninstall":
2834 mode = WixRemoveFolderExInstallMode.Uninstall;
2835 break;
2836 case "both":
2837 mode = WixRemoveFolderExInstallMode.Both;
2838 break;
2839 default:
2840 this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, "On", onValue, "install", "uninstall", "both"));
2841 break;
2842 }
2843 }
2844 break;
2845 case "Property":
2846 property = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
2847 break;
2848 default:
2849 this.ParseHelper.UnexpectedAttribute(element, attrib);
2850 break;
2851 }
2852 }
2853 else
2854 {
2855 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
2856 }
2857 }
2858
2859 if (String.IsNullOrEmpty(property))
2860 {
2861 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Property"));
2862 }
2863
2864 if (id == null)
2865 {
2866 id = this.ParseHelper.CreateIdentifier("wrf", componentId, property, mode.ToString());
2867 }
2868
2869 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
2870
2871 if (!this.Messaging.EncounteredError)
2872 {
2873 this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4RemoveFoldersEx", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
2874
2875 section.AddSymbol(new WixRemoveFolderExSymbol(sourceLineNumbers, id)
2876 {
2877 ComponentRef = componentId,
2878 Property = property,
2879 InstallMode = mode,
2880 Condition = condition
2881 });
2882
2883 this.ParseHelper.EnsureTable(section, sourceLineNumbers, "RemoveFile");
2884 }
2885 }
2886
2887 /// <summary>
2888 /// Parses a RemoveRegistryKeyEx element.
2889 /// </summary>
2890 /// <param name="node">Element to parse.</param>
2891 /// <param name="componentId">Identifier of parent component.</param>
2892 private void ParseRemoveRegistryKeyExElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId)
2893 {
2894 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
2895 Identifier id = null;
2896 var mode = WixRemoveRegistryKeyExInstallMode.Uninstall;
2897 string condition = null;
2898 RegistryRootType? root = null;
2899 string key = null;
2900
2901 foreach (var attrib in element.Attributes())
2902 {
2903 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
2904 {
2905 switch (attrib.Name.LocalName)
2906 {
2907 case "Condition":
2908 condition = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
2909 break;
2910 case "Id":
2911 id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
2912 break;
2913 case "On":
2914 var actionValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
2915 switch (actionValue)
2916 {
2917 case "":
2918 break;
2919 case "install":
2920 mode = WixRemoveRegistryKeyExInstallMode.Install;
2921 break;
2922 case "uninstall":
2923 mode = WixRemoveRegistryKeyExInstallMode.Uninstall;
2924 break;
2925 default:
2926 this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, "On", actionValue, "install", "uninstall"));
2927 break;
2928 }
2929 break;
2930 case "Root":
2931 root = this.ParseHelper.GetAttributeRegistryRootValue(sourceLineNumbers, attrib, false);
2932 break;
2933 case "Key":
2934 key = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
2935 break;
2936 default:
2937 this.ParseHelper.UnexpectedAttribute(element, attrib);
2938 break;
2939 }
2940 }
2941 else
2942 {
2943 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
2944 }
2945 }
2946
2947 if (!root.HasValue)
2948 {
2949 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Root"));
2950 }
2951
2952 if (key == null)
2953 {
2954 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Key"));
2955 }
2956
2957 if (id == null)
2958 {
2959 id = this.ParseHelper.CreateIdentifier("rrx", componentId, condition, root.ToString(), key, mode.ToString());
2960 }
2961
2962 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
2963
2964 if (!this.Messaging.EncounteredError)
2965 {
2966 this.ParseHelper.EnsureTable(section, sourceLineNumbers, "Registry");
2967 this.ParseHelper.EnsureTable(section, sourceLineNumbers, "RemoveRegistry");
2968 this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4RemoveRegistryKeysEx", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
2969
2970 section.AddSymbol(new WixRemoveRegistryKeyExSymbol(sourceLineNumbers, id)
2971 {
2972 ComponentRef = componentId,
2973 Root = root.Value,
2974 Key = key,
2975 InstallMode = mode,
2976 Condition = condition
2977 });
2978 }
2979 }
2980
2981 /// <summary>
2982 /// Parses a RestartResource element.
2983 /// </summary>
2984 /// <param name="element">The element to parse.</param>
2985 /// <param name="componentId">The identity of the parent component.</param>
2986 private void ParseRestartResourceElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId)
2987 {
2988 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
2989 Identifier id = null;
2990 string resource = null;
2991 WixRestartResourceAttributes? attributes = null;
2992
2993 foreach (var attrib in element.Attributes())
2994 {
2995 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
2996 {
2997 switch (attrib.Name.LocalName)
2998 {
2999 case "Id":
3000 id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
3001 break;
3002
3003 case "Path":
3004 resource = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
3005 attributes = WixRestartResourceAttributes.Filename;
3006 break;
3007
3008 case "ProcessName":
3009 resource = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
3010 attributes = WixRestartResourceAttributes.ProcessName;
3011 break;
3012
3013 case "ServiceName":
3014 resource = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
3015 attributes = WixRestartResourceAttributes.ServiceName;
3016 break;
3017
3018 default:
3019 this.ParseHelper.UnexpectedAttribute(element, attrib);
3020 break;
3021 }
3022 }
3023 else
3024 {
3025 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
3026 }
3027 }
3028
3029 // Validate the attribute.
3030 if (id == null)
3031 {
3032 id = this.ParseHelper.CreateIdentifier("wrr", componentId, resource, attributes.ToString());
3033 }
3034
3035 if (!attributes.HasValue)
3036 {
3037 this.Messaging.Write(ErrorMessages.ExpectedAttributes(sourceLineNumbers, element.Name.LocalName, "Path", "ProcessName", "ServiceName"));
3038 }
3039
3040 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
3041
3042 if (!this.Messaging.EncounteredError)
3043 {
3044 this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4RegisterRestartResources", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
3045
3046 section.AddSymbol(new WixRestartResourceSymbol(sourceLineNumbers, id)
3047 {
3048 ComponentRef = componentId,
3049 Resource = resource,
3050 Attributes = attributes,
3051 });
3052 }
3053 }
3054
3055 /// <summary>
3056 /// Parses a service configuration element.
3057 /// </summary>
3058 /// <param name="element">Element to parse.</param>
3059 /// <param name="componentId">Identifier of parent component.</param>
3060 /// <param name="parentTableName">Name of parent element.</param>
3061 /// <param name="parentTableServiceName">Optional name of service </param>
3062 private void ParseServiceConfigElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId, string parentTableName, string parentTableServiceName)
3063 {
3064 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
3065 string firstFailureActionType = null;
3066 var newService = false;
3067 string programCommandLine = null;
3068 string rebootMessage = null;
3069 var resetPeriod = CompilerConstants.IntegerNotSet;
3070 var restartServiceDelay = CompilerConstants.IntegerNotSet;
3071 string secondFailureActionType = null;
3072 string serviceName = null;
3073 string thirdFailureActionType = null;
3074
3075 foreach (var attrib in element.Attributes())
3076 {
3077 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
3078 {
3079 switch (attrib.Name.LocalName)
3080 {
3081 case "FirstFailureActionType":
3082 firstFailureActionType = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
3083 break;
3084 case "ProgramCommandLine":
3085 programCommandLine = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
3086 break;
3087 case "RebootMessage":
3088 rebootMessage = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
3089 break;
3090 case "ResetPeriodInDays":
3091 resetPeriod = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int32.MaxValue);
3092 break;
3093 case "RestartServiceDelayInSeconds":
3094 restartServiceDelay = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int32.MaxValue);
3095 break;
3096 case "SecondFailureActionType":
3097 secondFailureActionType = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
3098 break;
3099 case "ServiceName":
3100 serviceName = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
3101 break;
3102 case "ThirdFailureActionType":
3103 thirdFailureActionType = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
3104 break;
3105 default:
3106 this.ParseHelper.UnexpectedAttribute(element, attrib);
3107 break;
3108 }
3109 }
3110 else
3111 {
3112 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
3113 }
3114 }
3115
3116 // if this element is a child of ServiceInstall then ignore the service name provided.
3117 if ("ServiceInstall" == parentTableName)
3118 {
3119 // TODO: the ServiceName attribute should not be allowed in this case (the overwriting behavior may confuse users)
3120 serviceName = parentTableServiceName;
3121 newService = true;
3122 }
3123 else
3124 {
3125 // not a child of ServiceInstall, so ServiceName must have been provided
3126 if (null == serviceName)
3127 {
3128 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "ServiceName"));
3129 }
3130 }
3131
3132 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
3133
3134 if (!this.Messaging.EncounteredError)
3135 {
3136 this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4SchedServiceConfig", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
3137
3138 section.AddSymbol(new ServiceConfigSymbol(sourceLineNumbers)
3139 {
3140 ServiceName = serviceName,
3141 ComponentRef = componentId,
3142 NewService = newService ? 1 : 0,
3143 FirstFailureActionType = firstFailureActionType,
3144 SecondFailureActionType = secondFailureActionType,
3145 ThirdFailureActionType = thirdFailureActionType,
3146 ResetPeriodInDays = resetPeriod,
3147 RestartServiceDelayInSeconds = restartServiceDelay,
3148 ProgramCommandLine = programCommandLine,
3149 RebootMessage = rebootMessage,
3150 });
3151 }
3152 }
3153
3154 /// <summary>
3155 /// Parses a touch file element.
3156 /// </summary>
3157 /// <param name="element">Element to parse.</param>
3158 /// <param name="componentId">Identifier of parent component.</param>
3159 /// <param name="win64">Indicates whether the path is a 64-bit path.</param>
3160 private void ParseTouchFileElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId, bool win64)
3161 {
3162 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
3163 Identifier id = null;
3164 string path = null;
3165 var onInstall = YesNoType.NotSet;
3166 var onReinstall = YesNoType.NotSet;
3167 var onUninstall = YesNoType.NotSet;
3168 var nonvital = YesNoType.NotSet;
3169 int attributes = 0;
3170
3171 foreach (var attrib in element.Attributes())
3172 {
3173 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
3174 {
3175 switch (attrib.Name.LocalName)
3176 {
3177 case "Id":
3178 id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
3179 break;
3180 case "Path":
3181 path = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
3182 break;
3183 case "OnInstall":
3184 onInstall = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib);
3185 break;
3186 case "OnReinstall":
3187 onReinstall = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib);
3188 break;
3189 case "OnUninstall":
3190 onUninstall = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib);
3191 break;
3192 case "Nonvital":
3193 nonvital = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib);
3194 break;
3195 default:
3196 this.ParseHelper.UnexpectedAttribute(element, attrib);
3197 break;
3198 }
3199 }
3200 else
3201 {
3202 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
3203 }
3204 }
3205
3206 if (null == path)
3207 {
3208 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Path"));
3209 }
3210
3211 // If none of the scheduling actions are set, default to touching on install and reinstall.
3212 if (YesNoType.NotSet == onInstall && YesNoType.NotSet == onReinstall && YesNoType.NotSet == onUninstall)
3213 {
3214 onInstall = YesNoType.Yes;
3215 onReinstall = YesNoType.Yes;
3216 }
3217
3218 attributes |= YesNoType.Yes == onInstall ? 0x1 : 0;
3219 attributes |= YesNoType.Yes == onReinstall ? 0x2 : 0;
3220 attributes |= YesNoType.Yes == onUninstall ? 0x4 : 0;
3221 attributes |= win64 ? 0x10 : 0;
3222 attributes |= YesNoType.Yes == nonvital ? 0 : 0x20;
3223
3224 if (null == id)
3225 {
3226 id = this.ParseHelper.CreateIdentifier("tf", path, attributes.ToString());
3227 }
3228
3229 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
3230
3231 if (!this.Messaging.EncounteredError)
3232 {
3233 section.AddSymbol(new WixTouchFileSymbol(sourceLineNumbers, id)
3234 {
3235 ComponentRef = componentId,
3236 Path = path,
3237 Attributes = attributes,
3238 });
3239
3240 this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4TouchFileDuringInstall", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
3241 }
3242 }
3243
3244 /// <summary>
3245 /// Parses an user element.
3246 /// </summary>
3247 /// <param name="element">Element to parse.</param>
3248 /// <param name="componentId">Optional identifier of parent component.</param>
3249 private void ParseUserElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId)
3250 {
3251 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
3252 Identifier id = null;
3253 int attributes = 0;
3254 string domain = null;
3255 string name = null;
3256 string password = null;
3257
3258 foreach (var attrib in element.Attributes())
3259 {
3260 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
3261 {
3262 switch (attrib.Name.LocalName)
3263 {
3264 case "Id":
3265 id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
3266 break;
3267 case "CanNotChangePassword":
3268 if (null == componentId)
3269 {
3270 this.Messaging.Write(UtilErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
3271 }
3272
3273 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
3274 {
3275 attributes |= UserPasswdCantChange;
3276 }
3277 break;
3278 case "CreateUser":
3279 if (null == componentId)
3280 {
3281 this.Messaging.Write(UtilErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
3282 }
3283
3284 if (YesNoType.No == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
3285 {
3286 attributes |= UserDontCreateUser;
3287 }
3288 break;
3289 case "Disabled":
3290 if (null == componentId)
3291 {
3292 this.Messaging.Write(UtilErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
3293 }
3294
3295 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
3296 {
3297 attributes |= UserDisableAccount;
3298 }
3299 break;
3300 case "Domain":
3301 domain = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
3302 break;
3303 case "FailIfExists":
3304 if (null == componentId)
3305 {
3306 this.Messaging.Write(UtilErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
3307 }
3308
3309 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
3310 {
3311 attributes |= UserFailIfExists;
3312 }
3313 break;
3314 case "LogonAsService":
3315 if (null == componentId)
3316 {
3317 this.Messaging.Write(UtilErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
3318 }
3319 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
3320 {
3321 attributes |= UserLogonAsService;
3322 }
3323 break;
3324 case "LogonAsBatchJob":
3325 if (null == componentId)
3326 {
3327 this.Messaging.Write(UtilErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
3328 }
3329 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
3330 {
3331 attributes |= UserLogonAsBatchJob;
3332 }
3333 break;
3334 case "Name":
3335 name = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
3336 break;
3337 case "Password":
3338 password = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
3339 break;
3340 case "PasswordExpired":
3341 if (null == componentId)
3342 {
3343 this.Messaging.Write(UtilErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
3344 }
3345
3346 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
3347 {
3348 attributes |= UserPasswdChangeReqdOnLogin;
3349 }
3350 break;
3351 case "PasswordNeverExpires":
3352 if (null == componentId)
3353 {
3354 this.Messaging.Write(UtilErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
3355 }
3356
3357 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
3358 {
3359 attributes |= UserDontExpirePasswrd;
3360 }
3361 break;
3362 case "RemoveOnUninstall":
3363 if (null == componentId)
3364 {
3365 this.Messaging.Write(UtilErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
3366 }
3367
3368 if (YesNoType.No == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
3369 {
3370 attributes |= UserDontRemoveOnUninstall;
3371 }
3372 break;
3373 case "UpdateIfExists":
3374 if (null == componentId)
3375 {
3376 this.Messaging.Write(UtilErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
3377 }
3378
3379 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
3380 {
3381 attributes |= UserUpdateIfExists;
3382 }
3383 break;
3384 case "Vital":
3385 if (null == componentId)
3386 {
3387 this.Messaging.Write(UtilErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
3388 }
3389
3390 if (YesNoType.No == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
3391 {
3392 attributes |= UserNonVital;
3393 }
3394 break;
3395 default:
3396 this.ParseHelper.UnexpectedAttribute(element, attrib);
3397 break;
3398 }
3399 }
3400 else
3401 {
3402 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
3403 }
3404 }
3405
3406 if (null == id)
3407 {
3408 id = this.ParseHelper.CreateIdentifier("usr", componentId, name);
3409 }
3410
3411 if (null == name)
3412 {
3413 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Name"));
3414 }
3415
3416 foreach (var child in element.Elements())
3417 {
3418 if (this.Namespace == child.Name.Namespace)
3419 {
3420 switch (child.Name.LocalName)
3421 {
3422 case "GroupRef":
3423 if (null == componentId)
3424 {
3425 var childSourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(child);
3426 this.Messaging.Write(UtilErrors.IllegalElementWithoutComponent(childSourceLineNumbers, child.Name.LocalName));
3427 }
3428
3429 this.ParseGroupRefElement(intermediate, section, child, id.Id);
3430 break;
3431 default:
3432 this.ParseHelper.UnexpectedElement(element, child);
3433 break;
3434 }
3435 }
3436 else
3437 {
3438 this.ParseHelper.ParseExtensionElement(this.Context.Extensions, intermediate, section, element, child);
3439 }
3440 }
3441
3442 if (null != componentId)
3443 {
3444 this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4ConfigureUsers", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
3445 }
3446
3447 if (!this.Messaging.EncounteredError)
3448 {
3449 section.AddSymbol(new UserSymbol(sourceLineNumbers, id)
3450 {
3451 ComponentRef = componentId,
3452 Name = name,
3453 Domain = domain,
3454 Password = password,
3455 Attributes = attributes,
3456 });
3457 }
3458 }
3459
3460 /// <summary>
3461 /// Parses a XmlFile element.
3462 /// </summary>
3463 /// <param name="element">Element to parse.</param>
3464 /// <param name="componentId">Identifier of parent component.</param>
3465 private void ParseXmlFileElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId)
3466 {
3467 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
3468 Identifier id = null;
3469 string file = null;
3470 string elementPath = null;
3471 string name = null;
3472 string value = null;
3473 int sequence = -1;
3474 int flags = 0;
3475
3476 foreach (var attrib in element.Attributes())
3477 {
3478 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
3479 {
3480 switch (attrib.Name.LocalName)
3481 {
3482 case "Action":
3483 var actionValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
3484 switch (actionValue)
3485 {
3486 case "createElement":
3487 flags |= 0x00000001; // XMLFILE_CREATE_ELEMENT
3488 break;
3489 case "deleteValue":
3490 flags |= 0x00000002; // XMLFILE_DELETE_VALUE
3491 break;
3492 case "bulkSetValue":
3493 flags |= 0x00000004; // XMLFILE_BULKWRITE_VALUE
3494 break;
3495 case "setValue":
3496 // no flag for set value since it's the default
3497 break;
3498 default:
3499 this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, "Action", actionValue, "createElement", "deleteValue", "setValue", "bulkSetValue"));
3500 break;
3501 }
3502 break;
3503 case "SelectionLanguage":
3504 string selectionLanguage = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
3505 switch (selectionLanguage)
3506 {
3507 case "XPath":
3508 flags |= 0x00000100; // XMLFILE_USE_XPATH
3509 break;
3510 case "XSLPattern":
3511 // no flag for since it's the default
3512 break;
3513 default:
3514 this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, "SelectionLanguage", selectionLanguage, "XPath", "XSLPattern"));
3515 break;
3516 }
3517 break;
3518 case "Id":
3519 id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
3520 break;
3521 case "File":
3522 file = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
3523 break;
3524 case "ElementPath":
3525 elementPath = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
3526 break;
3527 case "Name":
3528 name = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
3529 break;
3530 case "Permanent":
3531 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
3532 {
3533 flags |= 0x00010000; // XMLFILE_DONT_UNINSTALL
3534 }
3535 break;
3536 case "Sequence":
3537 sequence = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 1, Int16.MaxValue);
3538 break;
3539 case "Value":
3540 value = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
3541 break;
3542 case "PreserveModifiedDate":
3543 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
3544 {
3545 flags |= 0x00001000; // XMLFILE_PRESERVE_MODIFIED
3546 }
3547 break;
3548 default:
3549 this.ParseHelper.UnexpectedAttribute(element, attrib);
3550 break;
3551 }
3552 }
3553 else
3554 {
3555 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
3556 }
3557 }
3558
3559 if (null == id)
3560 {
3561 id = this.ParseHelper.CreateIdentifier("uxf", componentId, file, elementPath, name);
3562 }
3563
3564 if (null == file)
3565 {
3566 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "File"));
3567 }
3568
3569 if (null == elementPath)
3570 {
3571 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "ElementPath"));
3572 }
3573
3574 if ((0x00000001 /*XMLFILE_CREATE_ELEMENT*/ & flags) != 0 && null == name)
3575 {
3576 this.Messaging.Write(ErrorMessages.IllegalAttributeWithoutOtherAttributes(sourceLineNumbers, element.Name.LocalName, "Action", "Name"));
3577 }
3578
3579 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
3580
3581 if (!this.Messaging.EncounteredError)
3582 {
3583 var symbol = section.AddSymbol(new XmlFileSymbol(sourceLineNumbers, id)
3584 {
3585 File = file,
3586 ElementPath = elementPath,
3587 Name = name,
3588 Value = value,
3589 Flags = flags,
3590 ComponentRef = componentId,
3591 });
3592 if (-1 != sequence)
3593 {
3594 symbol.Sequence = sequence;
3595 }
3596 }
3597
3598 this.AddReferenceToSchedXmlFile(sourceLineNumbers, section);
3599 }
3600
3601 /// <summary>
3602 /// Parses a XmlConfig element.
3603 /// </summary>
3604 /// <param name="element">Element to parse.</param>
3605 /// <param name="componentId">Identifier of parent component.</param>
3606 /// <param name="nested">Whether or not the element is nested.</param>
3607 private void ParseXmlConfigElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId, bool nested)
3608 {
3609 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
3610 Identifier id = null;
3611 string elementId = null;
3612 string elementPath = null;
3613 int flags = 0;
3614 string file = null;
3615 string name = null;
3616 var sequence = CompilerConstants.IntegerNotSet;
3617 string value = null;
3618 string verifyPath = null;
3619
3620 foreach (var attrib in element.Attributes())
3621 {
3622 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
3623 {
3624 switch (attrib.Name.LocalName)
3625 {
3626 case "Id":
3627 id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
3628 break;
3629 case "Action":
3630 if (nested)
3631 {
3632 this.Messaging.Write(ErrorMessages.IllegalAttributeWhenNested(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, element.Parent.Name.LocalName));
3633 }
3634 else
3635 {
3636 string actionValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
3637 switch (actionValue)
3638 {
3639 case "create":
3640 flags |= 0x10; // XMLCONFIG_CREATE
3641 break;
3642 case "delete":
3643 flags |= 0x20; // XMLCONFIG_DELETE
3644 break;
3645 default:
3646 this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, actionValue, "create", "delete"));
3647 break;
3648 }
3649 }
3650 break;
3651 case "ElementId":
3652 elementId = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
3653 break;
3654 case "ElementPath":
3655 elementPath = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
3656 break;
3657 case "File":
3658 file = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
3659 break;
3660 case "Name":
3661 name = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
3662 break;
3663 case "Node":
3664 if (nested)
3665 {
3666 this.Messaging.Write(ErrorMessages.IllegalAttributeWhenNested(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, element.Parent.Name.LocalName));
3667 }
3668 else
3669 {
3670 var nodeValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
3671 switch (nodeValue)
3672 {
3673 case "element":
3674 flags |= 0x1; // XMLCONFIG_ELEMENT
3675 break;
3676 case "value":
3677 flags |= 0x2; // XMLCONFIG_VALUE
3678 break;
3679 case "document":
3680 flags |= 0x4; // XMLCONFIG_DOCUMENT
3681 break;
3682 default:
3683 this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, nodeValue, "element", "value", "document"));
3684 break;
3685 }
3686 }
3687 break;
3688 case "On":
3689 if (nested)
3690 {
3691 this.Messaging.Write(ErrorMessages.IllegalAttributeWhenNested(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, element.Parent.Name.LocalName));
3692 }
3693 else
3694 {
3695 var onValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
3696 switch (onValue)
3697 {
3698 case "install":
3699 flags |= 0x100; // XMLCONFIG_INSTALL
3700 break;
3701 case "uninstall":
3702 flags |= 0x200; // XMLCONFIG_UNINSTALL
3703 break;
3704 default:
3705 this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, onValue, "install", "uninstall"));
3706 break;
3707 }
3708 }
3709 break;
3710 case "PreserveModifiedDate":
3711 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
3712 {
3713 flags |= 0x00001000; // XMLCONFIG_PRESERVE_MODIFIED
3714 }
3715 break;
3716 case "Sequence":
3717 sequence = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 1, Int16.MaxValue);
3718 break;
3719 case "Value":
3720 value = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
3721 break;
3722 case "VerifyPath":
3723 verifyPath = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
3724 break;
3725 default:
3726 this.ParseHelper.UnexpectedAttribute(element, attrib);
3727 break;
3728 }
3729 }
3730 else
3731 {
3732 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
3733 }
3734 }
3735
3736 if (null == id)
3737 {
3738 id = this.ParseHelper.CreateIdentifier("uxc", componentId, file, elementId, elementPath);
3739 }
3740
3741 if (null == file)
3742 {
3743 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "File"));
3744 }
3745
3746 if (null == elementId && null == elementPath)
3747 {
3748 this.Messaging.Write(ErrorMessages.ExpectedAttributes(sourceLineNumbers, element.Name.LocalName, "ElementId", "ElementPath"));
3749 }
3750 else if (null != elementId)
3751 {
3752 if (null != elementPath)
3753 {
3754 this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, element.Name.LocalName, "ElementId", "ElementPath"));
3755 }
3756
3757 if (0 != flags)
3758 {
3759 this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttributes(sourceLineNumbers, element.Name.LocalName, "ElementId", "Action", "Node", "On"));
3760 }
3761
3762 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, UtilSymbolDefinitions.XmlConfig, elementId);
3763 }
3764
3765 // find unexpected child elements
3766 foreach (var child in element.Elements())
3767 {
3768 if (this.Namespace == child.Name.Namespace)
3769 {
3770 switch (child.Name.LocalName)
3771 {
3772 case "XmlConfig":
3773 if (nested)
3774 {
3775 this.Messaging.Write(ErrorMessages.UnexpectedElement(sourceLineNumbers, element.Name.LocalName, child.Name.LocalName));
3776 }
3777 else
3778 {
3779 this.ParseXmlConfigElement(intermediate, section, child, componentId, true);
3780 }
3781 break;
3782 default:
3783 this.ParseHelper.UnexpectedElement(element, child);
3784 break;
3785 }
3786 }
3787 else
3788 {
3789 this.ParseHelper.ParseExtensionElement(this.Context.Extensions, intermediate, section, element, child);
3790 }
3791 }
3792
3793 if (!this.Messaging.EncounteredError)
3794 {
3795 var symbol = section.AddSymbol(new XmlConfigSymbol(sourceLineNumbers, id)
3796 {
3797 File = file,
3798 ElementId = elementId,
3799 ElementPath = elementPath,
3800 VerifyPath = verifyPath,
3801 Name = name,
3802 Value = value,
3803 Flags = flags,
3804 ComponentRef = componentId,
3805 });
3806
3807 if (CompilerConstants.IntegerNotSet != sequence)
3808 {
3809 symbol.Sequence = sequence;
3810 }
3811 }
3812
3813 this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4SchedXmlConfig", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
3814 }
3815
3816 /// <summary>
3817 /// Match evaluator to escape properties in a string.
3818 /// </summary>
3819 private string EscapeProperties(Match match)
3820 {
3821 string escape = null;
3822 switch (match.Value)
3823 {
3824 case "[":
3825 escape = @"[\[]";
3826 break;
3827 case "]":
3828 escape = @"[\]]";
3829 break;
3830 }
3831
3832 return escape;
3833 }
3834
3835 private int CreateIntegerFromBitArray(BitArray bits)
3836 {
3837 if (32 != bits.Length)
3838 {
3839 throw new ArgumentException(String.Format("Can only convert a bit array with 32-bits to integer. Actual number of bits in array: {0}", bits.Length), "bits");
3840 }
3841
3842 var intArray = new int[1];
3843 bits.CopyTo(intArray, 0);
3844
3845 return intArray[0];
3846 }
3847
3848 private bool TrySetBitFromName(string[] attributeNames, string attributeName, YesNoType attributeValue, BitArray bits, int offset)
3849 {
3850 for (var i = 0; i < attributeNames.Length; i++)
3851 {
3852 if (attributeName.Equals(attributeNames[i], StringComparison.Ordinal))
3853 {
3854 bits.Set(i + offset, YesNoType.Yes == attributeValue);
3855 return true;
3856 }
3857 }
3858
3859 return false;
3860 }
3861
3862 private void AddReferenceToSchedXmlFile(SourceLineNumber sourceLineNumbers, IntermediateSection section)
3863 {
3864 this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4SchedXmlFile", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
3865 }
3866
3867 /// <summary>
3868 /// Private class that stores the data from a parsed PerformanceCounter element.
3869 /// </summary>
3870 private class ParsedPerformanceCounter
3871 {
3872 internal ParsedPerformanceCounter(string name, string help, System.Diagnostics.PerformanceCounterType type, int language)
3873 {
3874 this.Name = name;
3875 this.Help = help;
3876 this.Type = (int)type;
3877 this.Language = language.ToString("D3", CultureInfo.InvariantCulture);
3878 }
3879
3880 internal string Name { get; }
3881
3882 internal string Help { get; }
3883
3884 internal int Type { get; }
3885
3886 internal string Language { get; }
3887 }
3888 }
3889}