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