aboutsummaryrefslogtreecommitdiff
path: root/src/WixToolset.Core/Compiler_2.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/WixToolset.Core/Compiler_2.cs')
-rw-r--r--src/WixToolset.Core/Compiler_2.cs5615
1 files changed, 5615 insertions, 0 deletions
diff --git a/src/WixToolset.Core/Compiler_2.cs b/src/WixToolset.Core/Compiler_2.cs
new file mode 100644
index 00000000..f42c9da1
--- /dev/null
+++ b/src/WixToolset.Core/Compiler_2.cs
@@ -0,0 +1,5615 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3namespace WixToolset.Core
4{
5 using System;
6 using System.Collections;
7 using System.Collections.Generic;
8 using System.Diagnostics.CodeAnalysis;
9 using System.Globalization;
10 using System.IO;
11 using System.Xml.Linq;
12 using WixToolset.Data;
13 using WixToolset.Data.Tuples;
14 using WixToolset.Data.WindowsInstaller;
15 using WixToolset.Extensibility;
16
17 /// <summary>
18 /// Compiler of the WiX toolset.
19 /// </summary>
20 internal partial class Compiler : ICompiler
21 {
22 /// <summary>
23 /// Parses an odbc driver or translator element.
24 /// </summary>
25 /// <param name="node">Element to parse.</param>
26 /// <param name="componentId">Identifier of parent component.</param>
27 /// <param name="fileId">Default identifer for driver/translator file.</param>
28 /// <param name="table">Table we're processing for.</param>
29 private void ParseODBCDriverOrTranslator(XElement node, string componentId, string fileId, TupleDefinitionType tableName)
30 {
31 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
32 Identifier id = null;
33 var driver = fileId;
34 string name = null;
35 var setup = fileId;
36
37 foreach (var attrib in node.Attributes())
38 {
39 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace)
40 {
41 switch (attrib.Name.LocalName)
42 {
43 case "Id":
44 id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib);
45 break;
46 case "File":
47 driver = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
48 this.Core.CreateSimpleReference(sourceLineNumbers, "File", driver);
49 break;
50 case "Name":
51 name = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
52 break;
53 case "SetupFile":
54 setup = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
55 this.Core.CreateSimpleReference(sourceLineNumbers, "File", setup);
56 break;
57 default:
58 this.Core.UnexpectedAttribute(node, attrib);
59 break;
60 }
61 }
62 else
63 {
64 this.Core.ParseExtensionAttribute(node, attrib);
65 }
66 }
67
68 if (null == name)
69 {
70 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Name"));
71 }
72
73 if (null == id)
74 {
75 id = this.Core.CreateIdentifier("odb", name, fileId, setup);
76 }
77
78 // drivers have a few possible children
79 if (TupleDefinitionType.ODBCDriver == tableName)
80 {
81 // process any data sources for the driver
82 foreach (var child in node.Elements())
83 {
84 if (CompilerCore.WixNamespace == child.Name.Namespace)
85 {
86 switch (child.Name.LocalName)
87 {
88 case "ODBCDataSource":
89 string ignoredKeyPath = null;
90 this.ParseODBCDataSource(child, componentId, name, out ignoredKeyPath);
91 break;
92 case "Property":
93 this.ParseODBCProperty(child, id.Id, TupleDefinitionType.ODBCAttribute);
94 break;
95 default:
96 this.Core.UnexpectedElement(node, child);
97 break;
98 }
99 }
100 else
101 {
102 this.Core.ParseExtensionElement(node, child);
103 }
104 }
105 }
106 else
107 {
108 this.Core.ParseForExtensionElements(node);
109 }
110
111 if (!this.Core.EncounteredError)
112 {
113 var row = this.Core.CreateRow(sourceLineNumbers, tableName, id);
114 row.Set(1, componentId);
115 row.Set(2, name);
116 row.Set(3, driver);
117 row.Set(4, setup);
118 }
119 }
120
121 /// <summary>
122 /// Parses a Property element underneath an ODBC driver or translator.
123 /// </summary>
124 /// <param name="node">Element to parse.</param>
125 /// <param name="parentId">Identifier of parent driver or translator.</param>
126 /// <param name="tableName">Name of the table to create property in.</param>
127 private void ParseODBCProperty(XElement node, string parentId, TupleDefinitionType tableName)
128 {
129 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
130 string id = null;
131 string propertyValue = null;
132
133 foreach (var attrib in node.Attributes())
134 {
135 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace)
136 {
137 switch (attrib.Name.LocalName)
138 {
139 case "Id":
140 id = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
141 break;
142 case "Value":
143 propertyValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
144 break;
145 default:
146 this.Core.UnexpectedAttribute(node, attrib);
147 break;
148 }
149 }
150 else
151 {
152 this.Core.ParseExtensionAttribute(node, attrib);
153 }
154 }
155
156 if (null == id)
157 {
158 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id"));
159 }
160
161 this.Core.ParseForExtensionElements(node);
162
163 if (!this.Core.EncounteredError)
164 {
165 var row = this.Core.CreateRow(sourceLineNumbers, tableName);
166 row.Set(0, parentId);
167 row.Set(1, id);
168 row.Set(2, propertyValue);
169 }
170 }
171
172 /// <summary>
173 /// Parse an odbc data source element.
174 /// </summary>
175 /// <param name="node">Element to parse.</param>
176 /// <param name="componentId">Identifier of parent component.</param>
177 /// <param name="driverName">Default name of driver.</param>
178 /// <param name="possibleKeyPath">Identifier of this element in case it is a keypath.</param>
179 /// <returns>Yes if this element was marked as the parent component's key path, No if explicitly marked as not being a key path, or NotSet otherwise.</returns>
180 private YesNoType ParseODBCDataSource(XElement node, string componentId, string driverName, out string possibleKeyPath)
181 {
182 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
183 Identifier id = null;
184 var keyPath = YesNoType.NotSet;
185 string name = null;
186 var registration = CompilerConstants.IntegerNotSet;
187
188 foreach (var attrib in node.Attributes())
189 {
190 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace)
191 {
192 switch (attrib.Name.LocalName)
193 {
194 case "Id":
195 id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib);
196 break;
197 case "DriverName":
198 driverName = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
199 break;
200 case "KeyPath":
201 keyPath = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
202 break;
203 case "Name":
204 name = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
205 break;
206 case "Registration":
207 var registrationValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
208 switch (registrationValue)
209 {
210 case "machine":
211 registration = 0;
212 break;
213 case "user":
214 registration = 1;
215 break;
216 case "":
217 break;
218 default:
219 this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, "Registration", registrationValue, "machine", "user"));
220 break;
221 }
222 break;
223 default:
224 this.Core.UnexpectedAttribute(node, attrib);
225 break;
226 }
227 }
228 else
229 {
230 this.Core.ParseExtensionAttribute(node, attrib);
231 }
232 }
233
234 if (CompilerConstants.IntegerNotSet == registration)
235 {
236 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Registration"));
237 registration = CompilerConstants.IllegalInteger;
238 }
239
240 if (null == id)
241 {
242 id = this.Core.CreateIdentifier("odc", name, driverName, registration.ToString());
243 }
244
245 foreach (var child in node.Elements())
246 {
247 if (CompilerCore.WixNamespace == child.Name.Namespace)
248 {
249 switch (child.Name.LocalName)
250 {
251 case "Property":
252 this.ParseODBCProperty(child, id.Id, TupleDefinitionType.ODBCSourceAttribute);
253 break;
254 default:
255 this.Core.UnexpectedElement(node, child);
256 break;
257 }
258 }
259 else
260 {
261 this.Core.ParseExtensionElement(node, child);
262 }
263 }
264
265 if (!this.Core.EncounteredError)
266 {
267 var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.ODBCDataSource, id);
268 row.Set(1, componentId);
269 row.Set(2, name);
270 row.Set(3, driverName);
271 row.Set(4, registration);
272 }
273
274 possibleKeyPath = id.Id;
275 return keyPath;
276 }
277
278 /// <summary>
279 /// Parses a package element.
280 /// </summary>
281 /// <param name="node">Element to parse.</param>
282 /// <param name="productAuthor">Default package author.</param>
283 /// <param name="moduleId">The module guid - this is necessary until Module/@Guid is removed.</param>
284 private void ParsePackageElement(XElement node, string productAuthor, string moduleId)
285 {
286 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
287 var codepage = "1252";
288 var comments = String.Format(CultureInfo.InvariantCulture, "This installer database contains the logic and data required to install {0}.", this.activeName);
289 var keywords = "Installer";
290 var msiVersion = 100; // lowest released version, really should be specified
291 var packageAuthor = productAuthor;
292 string packageCode = null;
293 var packageLanguages = this.activeLanguage;
294 var packageName = this.activeName;
295 string platform = null;
296 string platformValue = null;
297 var security = YesNoDefaultType.Default;
298 var sourceBits = (this.compilingModule ? 2 : 0);
299 IntermediateTuple row;
300 var installPrivilegeSeen = false;
301 var installScopeSeen = false;
302
303 switch (this.CurrentPlatform)
304 {
305 case Platform.X86:
306 platform = "Intel";
307 break;
308 case Platform.X64:
309 platform = "x64";
310 msiVersion = 200;
311 break;
312 case Platform.IA64:
313 platform = "Intel64";
314 msiVersion = 200;
315 break;
316 case Platform.ARM:
317 platform = "Arm";
318 msiVersion = 500;
319 break;
320 default:
321 throw new ArgumentException("Unknown platform enumeration '{0}' encountered.", this.CurrentPlatform.ToString());
322 }
323
324 foreach (var attrib in node.Attributes())
325 {
326 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace)
327 {
328 switch (attrib.Name.LocalName)
329 {
330 case "Id":
331 packageCode = this.Core.GetAttributeGuidValue(sourceLineNumbers, attrib, this.compilingProduct);
332 break;
333 case "AdminImage":
334 if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib))
335 {
336 sourceBits = sourceBits | 4;
337 }
338 break;
339 case "Comments":
340 comments = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
341 break;
342 case "Compressed":
343 // merge modules must always be compressed, so this attribute is invalid
344 if (this.compilingModule)
345 {
346 this.Core.Write(WarningMessages.DeprecatedPackageCompressedAttribute(sourceLineNumbers));
347 // this.core.OnMessage(WixErrors.IllegalAttributeWhenNested(sourceLineNumbers, node.Name.LocalName, "Compressed", "Module"));
348 }
349 else if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib))
350 {
351 sourceBits = sourceBits | 2;
352 }
353 break;
354 case "Description":
355 packageName = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
356 break;
357 case "InstallPrivileges":
358 var installPrivileges = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
359 switch (installPrivileges)
360 {
361 case "elevated":
362 // this is the default setting
363 installPrivilegeSeen = true;
364 break;
365 case "limited":
366 sourceBits = sourceBits | 8;
367 installPrivilegeSeen = true;
368 break;
369 case "":
370 break;
371 default:
372 this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, installPrivileges, "elevated", "limited"));
373 break;
374 }
375 break;
376 case "InstallScope":
377 var installScope = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
378 switch (installScope)
379 {
380 case "perMachine":
381 {
382 row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.Property, new Identifier("ALLUSERS", AccessModifier.Public));
383 row.Set(1, "1");
384 installScopeSeen = true;
385 }
386 break;
387 case "perUser":
388 sourceBits = sourceBits | 8;
389 installScopeSeen = true;
390 break;
391 case "":
392 break;
393 default:
394 this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, installScope, "perMachine", "perUser"));
395 break;
396 }
397 break;
398 case "InstallerVersion":
399 msiVersion = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int32.MaxValue);
400 break;
401 case "Keywords":
402 keywords = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
403 break;
404 case "Languages":
405 packageLanguages = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
406 break;
407 case "Manufacturer":
408 packageAuthor = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
409 if ("PUT-COMPANY-NAME-HERE" == packageAuthor)
410 {
411 this.Core.Write(WarningMessages.PlaceholderValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, packageAuthor));
412 }
413 break;
414 case "Platform":
415 if (null != platformValue)
416 {
417 this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "Platforms"));
418 }
419
420 platformValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
421 switch (platformValue)
422 {
423 case "intel":
424 this.Core.Write(WarningMessages.DeprecatedAttributeValue(sourceLineNumbers, platformValue, node.Name.LocalName, attrib.Name.LocalName, "x86"));
425 goto case "x86";
426 case "x86":
427 platform = "Intel";
428 break;
429 case "x64":
430 platform = "x64";
431 break;
432 case "intel64":
433 this.Core.Write(WarningMessages.DeprecatedAttributeValue(sourceLineNumbers, platformValue, node.Name.LocalName, attrib.Name.LocalName, "ia64"));
434 goto case "ia64";
435 case "ia64":
436 platform = "Intel64";
437 break;
438 case "arm":
439 platform = "Arm";
440 break;
441 case "":
442 break;
443 default:
444 this.Core.Write(ErrorMessages.InvalidPlatformValue(sourceLineNumbers, platformValue));
445 break;
446 }
447 break;
448 case "Platforms":
449 if (null != platformValue)
450 {
451 this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "Platform"));
452 }
453
454 this.Core.Write(WarningMessages.DeprecatedAttribute(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "Platform"));
455 platformValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
456 platform = platformValue;
457 break;
458 case "ReadOnly":
459 security = this.Core.GetAttributeYesNoDefaultValue(sourceLineNumbers, attrib);
460 break;
461 case "ShortNames":
462 if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib))
463 {
464 sourceBits = sourceBits | 1;
465 this.useShortFileNames = true;
466 }
467 break;
468 case "SummaryCodepage":
469 codepage = this.Core.GetAttributeLocalizableCodePageValue(sourceLineNumbers, attrib, true);
470 break;
471 default:
472 this.Core.UnexpectedAttribute(node, attrib);
473 break;
474 }
475 }
476 else
477 {
478 this.Core.ParseExtensionAttribute(node, attrib);
479 }
480 }
481
482 if (installPrivilegeSeen && installScopeSeen)
483 {
484 this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "InstallPrivileges", "InstallScope"));
485 }
486
487 if ((0 != String.Compare(platform, "Intel", StringComparison.OrdinalIgnoreCase)) && 200 > msiVersion)
488 {
489 msiVersion = 200;
490 this.Core.Write(WarningMessages.RequiresMsi200for64bitPackage(sourceLineNumbers));
491 }
492
493 if ((0 == String.Compare(platform, "Arm", StringComparison.OrdinalIgnoreCase)) && 500 > msiVersion)
494 {
495 msiVersion = 500;
496 this.Core.Write(WarningMessages.RequiresMsi500forArmPackage(sourceLineNumbers));
497 }
498
499 if (null == packageAuthor)
500 {
501 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Manufacturer"));
502 }
503
504 if (this.compilingModule)
505 {
506 if (null == packageCode)
507 {
508 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id"));
509 }
510
511 // merge modules use the modularization guid as the package code
512 if (null != moduleId)
513 {
514 packageCode = moduleId;
515 }
516
517 // merge modules are always compressed
518 sourceBits = 2;
519 }
520 else // product
521 {
522 if (null == packageCode)
523 {
524 packageCode = "*";
525 }
526
527 if ("*" != packageCode)
528 {
529 this.Core.Write(WarningMessages.PackageCodeSet(sourceLineNumbers));
530 }
531 }
532
533 this.Core.ParseForExtensionElements(node);
534
535 if (!this.Core.EncounteredError)
536 {
537 row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType._SummaryInformation);
538 row.Set(0, 1);
539 row.Set(1, codepage);
540
541 row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType._SummaryInformation);
542 row.Set(0, 2);
543 row.Set(1, "Installation Database");
544
545 row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType._SummaryInformation);
546 row.Set(0, 3);
547 row.Set(1, packageName);
548
549 row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType._SummaryInformation);
550 row.Set(0, 4);
551 row.Set(1, packageAuthor);
552
553 row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType._SummaryInformation);
554 row.Set(0, 5);
555 row.Set(1, keywords);
556
557 row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType._SummaryInformation);
558 row.Set(0, 6);
559 row.Set(1, comments);
560
561 row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType._SummaryInformation);
562 row.Set(0, 7);
563 row.Set(1, String.Format(CultureInfo.InvariantCulture, "{0};{1}", platform, packageLanguages));
564
565 row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType._SummaryInformation);
566 row.Set(0, 9);
567 row.Set(1, packageCode);
568
569 row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType._SummaryInformation);
570 row.Set(0, 14);
571 row.Set(1, msiVersion.ToString(CultureInfo.InvariantCulture));
572
573 row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType._SummaryInformation);
574 row.Set(0, 15);
575 row.Set(1, sourceBits.ToString(CultureInfo.InvariantCulture));
576
577 row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType._SummaryInformation);
578 row.Set(0, 19);
579 switch (security)
580 {
581 case YesNoDefaultType.No: // no restriction
582 row.Set(1, "0");
583 break;
584 case YesNoDefaultType.Default: // read-only recommended
585 row.Set(1, "2");
586 break;
587 case YesNoDefaultType.Yes: // read-only enforced
588 row.Set(1, "4");
589 break;
590 }
591 }
592 }
593
594 /// <summary>
595 /// Parses a patch metadata element.
596 /// </summary>
597 /// <param name="node">Element to parse.</param>
598 private void ParsePatchMetadataElement(XElement node)
599 {
600 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
601 var allowRemoval = YesNoType.NotSet;
602 string classification = null;
603 string creationTimeUtc = null;
604 string description = null;
605 string displayName = null;
606 string manufacturerName = null;
607 string minorUpdateTargetRTM = null;
608 string moreInfoUrl = null;
609 var optimizeCA = CompilerConstants.IntegerNotSet;
610 var optimizedInstallMode = YesNoType.NotSet;
611 string targetProductName = null;
612
613 foreach (var attrib in node.Attributes())
614 {
615 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace)
616 {
617 switch (attrib.Name.LocalName)
618 {
619 case "AllowRemoval":
620 allowRemoval = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
621 break;
622 case "Classification":
623 classification = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
624 break;
625 case "CreationTimeUTC":
626 creationTimeUtc = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
627 break;
628 case "Description":
629 description = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
630 break;
631 case "DisplayName":
632 displayName = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
633 break;
634 case "ManufacturerName":
635 manufacturerName = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
636 break;
637 case "MinorUpdateTargetRTM":
638 minorUpdateTargetRTM = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
639 break;
640 case "MoreInfoURL":
641 moreInfoUrl = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
642 break;
643 case "OptimizedInstallMode":
644 optimizedInstallMode = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
645 break;
646 case "TargetProductName":
647 targetProductName = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
648 break;
649 default:
650 this.Core.UnexpectedAttribute(node, attrib);
651 break;
652 }
653 }
654 else
655 {
656 this.Core.ParseExtensionAttribute(node, attrib);
657 }
658 }
659
660 if (YesNoType.NotSet == allowRemoval)
661 {
662 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "AllowRemoval"));
663 }
664
665 if (null == classification)
666 {
667 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Classification"));
668 }
669
670 if (null == description)
671 {
672 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Description"));
673 }
674
675 if (null == displayName)
676 {
677 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "DisplayName"));
678 }
679
680 if (null == manufacturerName)
681 {
682 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "ManufacturerName"));
683 }
684
685 if (null == moreInfoUrl)
686 {
687 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "MoreInfoURL"));
688 }
689
690 if (null == targetProductName)
691 {
692 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "TargetProductName"));
693 }
694
695 foreach (var child in node.Elements())
696 {
697 if (CompilerCore.WixNamespace == child.Name.Namespace)
698 {
699 switch (child.Name.LocalName)
700 {
701 case "CustomProperty":
702 this.ParseCustomPropertyElement(child);
703 break;
704 case "OptimizeCustomActions":
705 optimizeCA = this.ParseOptimizeCustomActionsElement(child);
706 break;
707 default:
708 this.Core.UnexpectedElement(node, child);
709 break;
710 }
711 }
712 else
713 {
714 this.Core.ParseExtensionElement(node, child);
715 }
716 }
717
718 if (!this.Core.EncounteredError)
719 {
720 if (YesNoType.NotSet != allowRemoval)
721 {
722 var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.PatchMetadata);
723 row.Set(1, "AllowRemoval");
724 row.Set(2, YesNoType.Yes == allowRemoval ? "1" : "0");
725 }
726
727 if (null != classification)
728 {
729 var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.PatchMetadata);
730 row.Set(1, "Classification");
731 row.Set(2, classification);
732 }
733
734 if (null != creationTimeUtc)
735 {
736 var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.PatchMetadata);
737 row.Set(1, "CreationTimeUTC");
738 row.Set(2, creationTimeUtc);
739 }
740
741 if (null != description)
742 {
743 var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.PatchMetadata);
744 row.Set(1, "Description");
745 row.Set(2, description);
746 }
747
748 if (null != displayName)
749 {
750 var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.PatchMetadata);
751 row.Set(1, "DisplayName");
752 row.Set(2, displayName);
753 }
754
755 if (null != manufacturerName)
756 {
757 var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.PatchMetadata);
758 row.Set(1, "ManufacturerName");
759 row.Set(2, manufacturerName);
760 }
761
762 if (null != minorUpdateTargetRTM)
763 {
764 var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.PatchMetadata);
765 row.Set(1, "MinorUpdateTargetRTM");
766 row.Set(2, minorUpdateTargetRTM);
767 }
768
769 if (null != moreInfoUrl)
770 {
771 var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.PatchMetadata);
772 row.Set(1, "MoreInfoURL");
773 row.Set(2, moreInfoUrl);
774 }
775
776 if (CompilerConstants.IntegerNotSet != optimizeCA)
777 {
778 var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.PatchMetadata);
779 row.Set(1, "OptimizeCA");
780 row.Set(2, optimizeCA.ToString(CultureInfo.InvariantCulture));
781 }
782
783 if (YesNoType.NotSet != optimizedInstallMode)
784 {
785 var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.PatchMetadata);
786 row.Set(1, "OptimizedInstallMode");
787 row.Set(2, YesNoType.Yes == optimizedInstallMode ? "1" : "0");
788 }
789
790 if (null != targetProductName)
791 {
792 var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.PatchMetadata);
793 row.Set(1, "TargetProductName");
794 row.Set(2, targetProductName);
795 }
796 }
797 }
798
799 /// <summary>
800 /// Parses a custom property element for the PatchMetadata table.
801 /// </summary>
802 /// <param name="node">Element to parse.</param>
803 private void ParseCustomPropertyElement(XElement node)
804 {
805 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
806 string company = null;
807 string property = null;
808 string value = null;
809
810 foreach (var attrib in node.Attributes())
811 {
812 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace)
813 {
814 switch (attrib.Name.LocalName)
815 {
816 case "Company":
817 company = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
818 break;
819 case "Property":
820 property = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
821 break;
822 case "Value":
823 value = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
824 break;
825 default:
826 this.Core.UnexpectedAttribute(node, attrib);
827 break;
828 }
829 }
830 else
831 {
832 this.Core.ParseExtensionAttribute(node, attrib);
833 }
834 }
835
836 if (null == company)
837 {
838 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Company"));
839 }
840
841 if (null == property)
842 {
843 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Property"));
844 }
845
846 if (null == value)
847 {
848 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Value"));
849 }
850
851 this.Core.ParseForExtensionElements(node);
852
853 if (!this.Core.EncounteredError)
854 {
855 var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.PatchMetadata);
856 row.Set(0, company);
857 row.Set(1, property);
858 row.Set(2, value);
859 }
860 }
861
862 /// <summary>
863 /// Parses the OptimizeCustomActions element.
864 /// </summary>
865 /// <param name="node">Element to parse.</param>
866 /// <returns>The combined integer value for callers to store as appropriate.</returns>
867 private int ParseOptimizeCustomActionsElement(XElement node)
868 {
869 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
870 var optimizeCA = OptimizeCA.None;
871
872 foreach (var attrib in node.Attributes())
873 {
874 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace)
875 {
876 switch (attrib.Name.LocalName)
877 {
878 case "SkipAssignment":
879 if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib))
880 {
881 optimizeCA |= OptimizeCA.SkipAssignment;
882 }
883 break;
884 case "SkipImmediate":
885 if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib))
886 {
887 optimizeCA |= OptimizeCA.SkipImmediate;
888 }
889 break;
890 case "SkipDeferred":
891 if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib))
892 {
893 optimizeCA |= OptimizeCA.SkipDeferred;
894 }
895 break;
896 default:
897 this.Core.UnexpectedAttribute(node, attrib);
898 break;
899 }
900 }
901 else
902 {
903 this.Core.ParseExtensionAttribute(node, attrib);
904 }
905 }
906
907 return (int)optimizeCA;
908 }
909
910 /// <summary>
911 /// Parses a patch information element.
912 /// </summary>
913 /// <param name="node">Element to parse.</param>
914 private void ParsePatchInformationElement(XElement node)
915 {
916 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
917 var codepage = "1252";
918 string comments = null;
919 var keywords = "Installer,Patching,PCP,Database";
920 var msiVersion = 1; // Should always be 1 for patches
921 string packageAuthor = null;
922 var packageName = this.activeName;
923 var security = YesNoDefaultType.Default;
924
925 foreach (var attrib in node.Attributes())
926 {
927 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace)
928 {
929 switch (attrib.Name.LocalName)
930 {
931 case "AdminImage":
932 this.Core.Write(WarningMessages.DeprecatedAttribute(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName));
933 break;
934 case "Comments":
935 comments = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
936 break;
937 case "Compressed":
938 this.Core.Write(WarningMessages.DeprecatedAttribute(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName));
939 break;
940 case "Description":
941 packageName = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
942 break;
943 case "Keywords":
944 keywords = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
945 break;
946 case "Languages":
947 this.Core.Write(WarningMessages.DeprecatedAttribute(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName));
948 break;
949 case "Manufacturer":
950 packageAuthor = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
951 break;
952 case "Platforms":
953 this.Core.Write(WarningMessages.DeprecatedAttribute(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName));
954 break;
955 case "ReadOnly":
956 security = this.Core.GetAttributeYesNoDefaultValue(sourceLineNumbers, attrib);
957 break;
958 case "ShortNames":
959 this.Core.Write(WarningMessages.DeprecatedAttribute(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName));
960 break;
961 case "SummaryCodepage":
962 codepage = this.Core.GetAttributeLocalizableCodePageValue(sourceLineNumbers, attrib);
963 break;
964 default:
965 this.Core.UnexpectedAttribute(node, attrib);
966 break;
967 }
968 }
969 else
970 {
971 this.Core.ParseExtensionAttribute(node, attrib);
972 }
973 }
974
975 this.Core.ParseForExtensionElements(node);
976
977 if (!this.Core.EncounteredError)
978 {
979 // PID_CODEPAGE
980 var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType._SummaryInformation);
981 row.Set(0, 1);
982 row.Set(1, codepage);
983
984 // PID_TITLE
985 row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType._SummaryInformation);
986 row.Set(0, 2);
987 row.Set(1, "Patch");
988
989 // PID_SUBJECT
990 if (null != packageName)
991 {
992 row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType._SummaryInformation);
993 row.Set(0, 3);
994 row.Set(1, packageName);
995 }
996
997 // PID_AUTHOR
998 if (null != packageAuthor)
999 {
1000 row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType._SummaryInformation);
1001 row.Set(0, 4);
1002 row.Set(1, packageAuthor);
1003 }
1004
1005 // PID_KEYWORDS
1006 if (null != keywords)
1007 {
1008 row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType._SummaryInformation);
1009 row.Set(0, 5);
1010 row.Set(1, keywords);
1011 }
1012
1013 // PID_COMMENTS
1014 if (null != comments)
1015 {
1016 row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType._SummaryInformation);
1017 row.Set(0, 6);
1018 row.Set(1, comments);
1019 }
1020
1021 // PID_PAGECOUNT
1022 row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType._SummaryInformation);
1023 row.Set(0, 14);
1024 row.Set(1, msiVersion.ToString(CultureInfo.InvariantCulture));
1025
1026 // PID_WORDCOUNT
1027 row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType._SummaryInformation);
1028 row.Set(0, 15);
1029 row.Set(1, "0");
1030
1031 // PID_SECURITY
1032 row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType._SummaryInformation);
1033 row.Set(0, 19);
1034 switch (security)
1035 {
1036 case YesNoDefaultType.No: // no restriction
1037 row.Set(1, "0");
1038 break;
1039 case YesNoDefaultType.Default: // read-only recommended
1040 row.Set(1, "2");
1041 break;
1042 case YesNoDefaultType.Yes: // read-only enforced
1043 row.Set(1, "4");
1044 break;
1045 }
1046 }
1047 }
1048
1049 /// <summary>
1050 /// Parses a permission element.
1051 /// </summary>
1052 /// <param name="node">Element to parse.</param>
1053 /// <param name="objectId">Identifier of object to be secured.</param>
1054 /// <param name="tableName">Name of table that contains objectId.</param>
1055 private void ParsePermissionElement(XElement node, string objectId, string tableName)
1056 {
1057 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
1058 var bits = new BitArray(32);
1059 string domain = null;
1060 var permission = 0;
1061 string[] specialPermissions = null;
1062 string user = null;
1063
1064 switch (tableName)
1065 {
1066 case "CreateFolder":
1067 specialPermissions = Common.FolderPermissions;
1068 break;
1069 case "File":
1070 specialPermissions = Common.FilePermissions;
1071 break;
1072 case "Registry":
1073 specialPermissions = Common.RegistryPermissions;
1074 break;
1075 default:
1076 this.Core.UnexpectedElement(node.Parent, node);
1077 return; // stop processing this element since no valid permissions are available
1078 }
1079
1080 foreach (var attrib in node.Attributes())
1081 {
1082 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace)
1083 {
1084 switch (attrib.Name.LocalName)
1085 {
1086 case "Domain":
1087 domain = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
1088 break;
1089 case "User":
1090 user = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
1091 break;
1092 case "FileAllRights":
1093 // match the WinNT.h mask FILE_ALL_ACCESS for value 0x001F01FF (aka 1 1111 0000 0001 1111 1111 or 2032127)
1094 bits[0] = bits[1] = bits[2] = bits[3] = bits[4] = bits[5] = bits[6] = bits[7] = bits[8] = bits[16] = bits[17] = bits[18] = bits[19] = bits[20] = true;
1095 break;
1096 case "SpecificRightsAll":
1097 // match the WinNT.h mask SPECIFIC_RIGHTS_ALL for value 0x0000FFFF (aka 1111 1111 1111 1111)
1098 bits[0] = bits[1] = bits[2] = bits[3] = bits[4] = bits[5] = bits[6] = bits[7] = bits[8] = bits[9] = bits[10] = bits[11] = bits[12] = bits[13] = bits[14] = bits[15] = true;
1099 break;
1100 default:
1101 var attribValue = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
1102 if (!this.Core.TrySetBitFromName(Common.StandardPermissions, attrib.Name.LocalName, attribValue, bits, 16))
1103 {
1104 if (!this.Core.TrySetBitFromName(Common.GenericPermissions, attrib.Name.LocalName, attribValue, bits, 28))
1105 {
1106 if (!this.Core.TrySetBitFromName(specialPermissions, attrib.Name.LocalName, attribValue, bits, 0))
1107 {
1108 this.Core.UnexpectedAttribute(node, attrib);
1109 break;
1110 }
1111 }
1112 }
1113 break;
1114 }
1115 }
1116 else
1117 {
1118 this.Core.ParseExtensionAttribute(node, attrib);
1119 }
1120 }
1121
1122 permission = this.Core.CreateIntegerFromBitArray(bits);
1123
1124 if (null == user)
1125 {
1126 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "User"));
1127 }
1128
1129 if (Int32.MinValue == permission) // just GENERIC_READ, which is MSI_NULL
1130 {
1131 this.Core.Write(ErrorMessages.GenericReadNotAllowed(sourceLineNumbers));
1132 }
1133
1134 this.Core.ParseForExtensionElements(node);
1135
1136 if (!this.Core.EncounteredError)
1137 {
1138 var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.LockPermissions);
1139 row.Set(0, objectId);
1140 row.Set(1, tableName);
1141 row.Set(2, domain);
1142 row.Set(3, user);
1143 row.Set(4, permission);
1144 }
1145 }
1146
1147 /// <summary>
1148 /// Parses an extended permission element.
1149 /// </summary>
1150 /// <param name="node">Element to parse.</param>
1151 /// <param name="objectId">Identifier of object to be secured.</param>
1152 /// <param name="tableName">Name of table that contains objectId.</param>
1153 private void ParsePermissionExElement(XElement node, string objectId, string tableName)
1154 {
1155 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
1156 string condition = null;
1157 Identifier id = null;
1158 string sddl = null;
1159
1160 switch (tableName)
1161 {
1162 case "CreateFolder":
1163 case "File":
1164 case "Registry":
1165 case "ServiceInstall":
1166 break;
1167 default:
1168 this.Core.UnexpectedElement(node.Parent, node);
1169 return; // stop processing this element since nothing will be valid.
1170 }
1171
1172 foreach (var attrib in node.Attributes())
1173 {
1174 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace)
1175 {
1176 switch (attrib.Name.LocalName)
1177 {
1178 case "Id":
1179 id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib);
1180 break;
1181 case "Sddl":
1182 sddl = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
1183 break;
1184 default:
1185 this.Core.UnexpectedAttribute(node, attrib);
1186 break;
1187 }
1188 }
1189 else
1190 {
1191 this.Core.ParseExtensionAttribute(node, attrib);
1192 }
1193 }
1194
1195 if (null == sddl)
1196 {
1197 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Sddl"));
1198 }
1199
1200 if (null == id)
1201 {
1202 id = this.Core.CreateIdentifier("pme", objectId, tableName, sddl);
1203 }
1204
1205 foreach (var child in node.Elements())
1206 {
1207 if (CompilerCore.WixNamespace == child.Name.Namespace)
1208 {
1209 switch (child.Name.LocalName)
1210 {
1211 case "Condition":
1212 if (null != condition)
1213 {
1214 var childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
1215 this.Core.Write(ErrorMessages.TooManyChildren(childSourceLineNumbers, node.Name.LocalName, child.Name.LocalName));
1216 }
1217
1218 condition = this.ParseConditionElement(child, node.Name.LocalName, null, null);
1219 break;
1220 default:
1221 this.Core.UnexpectedElement(node, child);
1222 break;
1223 }
1224 }
1225 else
1226 {
1227 this.Core.ParseExtensionElement(node, child);
1228 }
1229 }
1230
1231 if (!this.Core.EncounteredError)
1232 {
1233 var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.MsiLockPermissionsEx, id);
1234 row.Set(1, objectId);
1235 row.Set(2, tableName);
1236 row.Set(3, sddl);
1237 row.Set(4, condition);
1238 }
1239 }
1240
1241 /// <summary>
1242 /// Parses a product element.
1243 /// </summary>
1244 /// <param name="node">Element to parse.</param>
1245 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily")]
1246 private void ParseProductElement(XElement node)
1247 {
1248 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
1249 var codepage = 65001;
1250 string productCode = null;
1251 string upgradeCode = null;
1252 string manufacturer = null;
1253 string version = null;
1254 string symbols = null;
1255
1256 this.activeName = null;
1257 this.activeLanguage = null;
1258
1259 foreach (var attrib in node.Attributes())
1260 {
1261 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace)
1262 {
1263 switch (attrib.Name.LocalName)
1264 {
1265 case "Id":
1266 productCode = this.Core.GetAttributeGuidValue(sourceLineNumbers, attrib, true);
1267 break;
1268 case "Codepage":
1269 codepage = this.Core.GetAttributeCodePageValue(sourceLineNumbers, attrib);
1270 break;
1271 case "Language":
1272 this.activeLanguage = this.Core.GetAttributeLocalizableIntegerValue(sourceLineNumbers, attrib, 0, Int16.MaxValue);
1273 break;
1274 case "Manufacturer":
1275 manufacturer = this.Core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.MustHaveNonWhitespaceCharacters);
1276 if ("PUT-COMPANY-NAME-HERE" == manufacturer)
1277 {
1278 this.Core.Write(WarningMessages.PlaceholderValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, manufacturer));
1279 }
1280 break;
1281 case "Name":
1282 this.activeName = this.Core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.MustHaveNonWhitespaceCharacters);
1283 if ("PUT-PRODUCT-NAME-HERE" == this.activeName)
1284 {
1285 this.Core.Write(WarningMessages.PlaceholderValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, this.activeName));
1286 }
1287 break;
1288 case "UpgradeCode":
1289 upgradeCode = this.Core.GetAttributeGuidValue(sourceLineNumbers, attrib, false);
1290 break;
1291 case "Version": // if the attribute is valid version, use the attribute value as is (so "1.0000.01.01" would *not* get translated to "1.0.1.1").
1292 var verifiedVersion = this.Core.GetAttributeVersionValue(sourceLineNumbers, attrib);
1293 if (!String.IsNullOrEmpty(verifiedVersion))
1294 {
1295 version = attrib.Value;
1296 }
1297 break;
1298 default:
1299 this.Core.UnexpectedAttribute(node, attrib);
1300 break;
1301 }
1302 }
1303 else
1304 {
1305 this.Core.ParseExtensionAttribute(node, attrib);
1306 }
1307 }
1308
1309 if (null == productCode)
1310 {
1311 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id"));
1312 }
1313
1314 if (null == this.activeLanguage)
1315 {
1316 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Language"));
1317 }
1318
1319 if (null == manufacturer)
1320 {
1321 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Manufacturer"));
1322 }
1323
1324 if (null == this.activeName)
1325 {
1326 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Name"));
1327 }
1328
1329 if (null == upgradeCode)
1330 {
1331 this.Core.Write(WarningMessages.MissingUpgradeCode(sourceLineNumbers));
1332 }
1333
1334 if (null == version)
1335 {
1336 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Version"));
1337 }
1338 else if (!CompilerCore.IsValidProductVersion(version))
1339 {
1340 this.Core.Write(ErrorMessages.InvalidProductVersion(sourceLineNumbers, version));
1341 }
1342
1343 if (this.Core.EncounteredError)
1344 {
1345 return;
1346 }
1347
1348 try
1349 {
1350 this.compilingProduct = true;
1351 this.Core.CreateActiveSection(productCode, SectionType.Product, codepage, this.Context.CompilationId);
1352
1353 this.AddProperty(sourceLineNumbers, new Identifier("Manufacturer", AccessModifier.Public), manufacturer, false, false, false, true);
1354 this.AddProperty(sourceLineNumbers, new Identifier("ProductCode", AccessModifier.Public), productCode, false, false, false, true);
1355 this.AddProperty(sourceLineNumbers, new Identifier("ProductLanguage", AccessModifier.Public), this.activeLanguage, false, false, false, true);
1356 this.AddProperty(sourceLineNumbers, new Identifier("ProductName", AccessModifier.Public), this.activeName, false, false, false, true);
1357 this.AddProperty(sourceLineNumbers, new Identifier("ProductVersion", AccessModifier.Public), version, false, false, false, true);
1358 if (null != upgradeCode)
1359 {
1360 this.AddProperty(sourceLineNumbers, new Identifier("UpgradeCode", AccessModifier.Public), upgradeCode, false, false, false, true);
1361 }
1362
1363 var contextValues = new Dictionary<string, string>
1364 {
1365 ["ProductLanguage"] = this.activeLanguage,
1366 ["ProductVersion"] = version,
1367 ["UpgradeCode"] = upgradeCode
1368 };
1369
1370 var featureDisplay = 0;
1371 foreach (var child in node.Elements())
1372 {
1373 if (CompilerCore.WixNamespace == child.Name.Namespace)
1374 {
1375 switch (child.Name.LocalName)
1376 {
1377 case "_locDefinition":
1378 break;
1379 case "AdminExecuteSequence":
1380 case "AdminUISequence":
1381 case "AdvertiseExecuteSequence":
1382 case "InstallExecuteSequence":
1383 case "InstallUISequence":
1384 this.ParseSequenceElement(child, child.Name.LocalName);
1385 break;
1386 case "AppId":
1387 this.ParseAppIdElement(child, null, YesNoType.Yes, null, null, null);
1388 break;
1389 case "Binary":
1390 this.ParseBinaryElement(child);
1391 break;
1392 case "ComplianceCheck":
1393 this.ParseComplianceCheckElement(child);
1394 break;
1395 case "Component":
1396 this.ParseComponentElement(child, ComplexReferenceParentType.Unknown, null, null, CompilerConstants.IntegerNotSet, null, null);
1397 break;
1398 case "ComponentGroup":
1399 this.ParseComponentGroupElement(child, ComplexReferenceParentType.Unknown, null);
1400 break;
1401 case "Condition":
1402 this.ParseConditionElement(child, node.Name.LocalName, null, null);
1403 break;
1404 case "CustomAction":
1405 this.ParseCustomActionElement(child);
1406 break;
1407 case "CustomActionRef":
1408 this.ParseSimpleRefElement(child, "CustomAction");
1409 break;
1410 case "CustomTable":
1411 this.ParseCustomTableElement(child);
1412 break;
1413 case "Directory":
1414 this.ParseDirectoryElement(child, null, CompilerConstants.IntegerNotSet, String.Empty);
1415 break;
1416 case "DirectoryRef":
1417 this.ParseDirectoryRefElement(child);
1418 break;
1419 case "EmbeddedChainer":
1420 this.ParseEmbeddedChainerElement(child);
1421 break;
1422 case "EmbeddedChainerRef":
1423 this.ParseSimpleRefElement(child, "MsiEmbeddedChainer");
1424 break;
1425 case "EnsureTable":
1426 this.ParseEnsureTableElement(child);
1427 break;
1428 case "Feature":
1429 this.ParseFeatureElement(child, ComplexReferenceParentType.Product, productCode, ref featureDisplay);
1430 break;
1431 case "FeatureRef":
1432 this.ParseFeatureRefElement(child, ComplexReferenceParentType.Product, productCode);
1433 break;
1434 case "FeatureGroupRef":
1435 this.ParseFeatureGroupRefElement(child, ComplexReferenceParentType.Product, productCode);
1436 break;
1437 case "Icon":
1438 this.ParseIconElement(child);
1439 break;
1440 case "InstanceTransforms":
1441 this.ParseInstanceTransformsElement(child);
1442 break;
1443 case "MajorUpgrade":
1444 this.ParseMajorUpgradeElement(child, contextValues);
1445 break;
1446 case "Media":
1447 this.ParseMediaElement(child, null);
1448 break;
1449 case "MediaTemplate":
1450 this.ParseMediaTemplateElement(child, null);
1451 break;
1452 case "Package":
1453 this.ParsePackageElement(child, manufacturer, null);
1454 break;
1455 case "PackageCertificates":
1456 case "PatchCertificates":
1457 this.ParseCertificatesElement(child);
1458 break;
1459 case "Property":
1460 this.ParsePropertyElement(child);
1461 break;
1462 case "PropertyRef":
1463 this.ParseSimpleRefElement(child, "Property");
1464 break;
1465 case "SetDirectory":
1466 this.ParseSetDirectoryElement(child);
1467 break;
1468 case "SetProperty":
1469 this.ParseSetPropertyElement(child);
1470 break;
1471 case "SFPCatalog":
1472 string parentName = null;
1473 this.ParseSFPCatalogElement(child, ref parentName);
1474 break;
1475 case "SymbolPath":
1476 if (null != symbols)
1477 {
1478 symbols += ";" + this.ParseSymbolPathElement(child);
1479 }
1480 else
1481 {
1482 symbols = this.ParseSymbolPathElement(child);
1483 }
1484 break;
1485 case "UI":
1486 this.ParseUIElement(child);
1487 break;
1488 case "UIRef":
1489 this.ParseSimpleRefElement(child, "WixUI");
1490 break;
1491 case "Upgrade":
1492 this.ParseUpgradeElement(child);
1493 break;
1494 case "WixVariable":
1495 this.ParseWixVariableElement(child);
1496 break;
1497 default:
1498 this.Core.UnexpectedElement(node, child);
1499 break;
1500 }
1501 }
1502 else
1503 {
1504 this.Core.ParseExtensionElement(node, child);
1505 }
1506 }
1507
1508 if (!this.Core.EncounteredError)
1509 {
1510 if (null != symbols)
1511 {
1512 var symbolRow = (WixDeltaPatchSymbolPathsTuple)this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixDeltaPatchSymbolPaths);
1513 symbolRow.Id = productCode;
1514 symbolRow.Type = SymbolPathType.Product;
1515 symbolRow.SymbolPaths = symbols;
1516 }
1517 }
1518 }
1519 finally
1520 {
1521 this.compilingProduct = false;
1522 }
1523 }
1524
1525 /// <summary>
1526 /// Parses a progid element
1527 /// </summary>
1528 /// <param name="node">Element to parse.</param>
1529 /// <param name="componentId">Identifier of parent component.</param>
1530 /// <param name="advertise">Flag if progid is advertised.</param>
1531 /// <param name="classId">CLSID related to ProgId.</param>
1532 /// <param name="description">Default description of ProgId</param>
1533 /// <param name="parent">Optional parent ProgId</param>
1534 /// <param name="foundExtension">Set to true if an extension is found; used for error-checking.</param>
1535 /// <param name="firstProgIdForClass">Whether or not this ProgId is the first one found in the parent class.</param>
1536 /// <returns>This element's Id.</returns>
1537 private string ParseProgIdElement(XElement node, string componentId, YesNoType advertise, string classId, string description, string parent, ref bool foundExtension, YesNoType firstProgIdForClass)
1538 {
1539 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
1540 string icon = null;
1541 var iconIndex = CompilerConstants.IntegerNotSet;
1542 string noOpen = null;
1543 string progId = null;
1544 var progIdAdvertise = YesNoType.NotSet;
1545
1546 foreach (var attrib in node.Attributes())
1547 {
1548 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace)
1549 {
1550 switch (attrib.Name.LocalName)
1551 {
1552 case "Id":
1553 progId = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
1554 break;
1555 case "Advertise":
1556 progIdAdvertise = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
1557 break;
1558 case "Description":
1559 description = this.Core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.CanBeEmpty);
1560 break;
1561 case "Icon":
1562 icon = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
1563 break;
1564 case "IconIndex":
1565 iconIndex = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, Int16.MinValue + 1, Int16.MaxValue);
1566 break;
1567 case "NoOpen":
1568 noOpen = this.Core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.CanBeEmpty);
1569 break;
1570 default:
1571 this.Core.UnexpectedAttribute(node, attrib);
1572 break;
1573 }
1574 }
1575 else
1576 {
1577 this.Core.ParseExtensionAttribute(node, attrib);
1578 }
1579 }
1580
1581 if ((YesNoType.No == advertise && YesNoType.Yes == progIdAdvertise) || (YesNoType.Yes == advertise && YesNoType.No == progIdAdvertise))
1582 {
1583 this.Core.Write(ErrorMessages.AdvertiseStateMustMatch(sourceLineNumbers, advertise.ToString(), progIdAdvertise.ToString()));
1584 }
1585 else
1586 {
1587 advertise = progIdAdvertise;
1588 }
1589
1590 if (YesNoType.NotSet == advertise)
1591 {
1592 advertise = YesNoType.No;
1593 }
1594
1595 if (null != parent && (null != icon || CompilerConstants.IntegerNotSet != iconIndex))
1596 {
1597 this.Core.Write(ErrorMessages.VersionIndependentProgIdsCannotHaveIcons(sourceLineNumbers));
1598 }
1599
1600 var firstProgIdForNestedClass = YesNoType.Yes;
1601 foreach (var child in node.Elements())
1602 {
1603 if (CompilerCore.WixNamespace == child.Name.Namespace)
1604 {
1605 switch (child.Name.LocalName)
1606 {
1607 case "Extension":
1608 this.ParseExtensionElement(child, componentId, advertise, progId);
1609 foundExtension = true;
1610 break;
1611 case "ProgId":
1612 // Only allow one nested ProgId. If we have a child, we should not have a parent.
1613 if (null == parent)
1614 {
1615 if (YesNoType.Yes == advertise)
1616 {
1617 this.ParseProgIdElement(child, componentId, advertise, null, description, progId, ref foundExtension, firstProgIdForNestedClass);
1618 }
1619 else if (YesNoType.No == advertise)
1620 {
1621 this.ParseProgIdElement(child, componentId, advertise, classId, description, progId, ref foundExtension, firstProgIdForNestedClass);
1622 }
1623
1624 firstProgIdForNestedClass = YesNoType.No; // any ProgId after this one is definitely not the first.
1625 }
1626 else
1627 {
1628 var childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(child);
1629 this.Core.Write(ErrorMessages.ProgIdNestedTooDeep(childSourceLineNumbers));
1630 }
1631 break;
1632 default:
1633 this.Core.UnexpectedElement(node, child);
1634 break;
1635 }
1636 }
1637 else
1638 {
1639 this.Core.ParseExtensionElement(node, child);
1640 }
1641 }
1642
1643 if (YesNoType.Yes == advertise)
1644 {
1645 if (!this.Core.EncounteredError)
1646 {
1647 var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.ProgId);
1648 row.Set(0, progId);
1649 row.Set(1, parent);
1650 row.Set(2, classId);
1651 row.Set(3, description);
1652 if (null != icon)
1653 {
1654 row.Set(4, icon);
1655 this.Core.CreateSimpleReference(sourceLineNumbers, "Icon", icon);
1656 }
1657
1658 if (CompilerConstants.IntegerNotSet != iconIndex)
1659 {
1660 row.Set(5, iconIndex);
1661 }
1662
1663 this.Core.EnsureTable(sourceLineNumbers, "Class");
1664 }
1665 }
1666 else if (YesNoType.No == advertise)
1667 {
1668 this.Core.CreateRegistryRow(sourceLineNumbers, RegistryRootType.ClassesRoot, progId, String.Empty, description, componentId);
1669 if (null != classId)
1670 {
1671 this.Core.CreateRegistryRow(sourceLineNumbers, RegistryRootType.ClassesRoot, String.Concat(progId, "\\CLSID"), String.Empty, classId, componentId);
1672 if (null != parent) // if this is a version independent ProgId
1673 {
1674 if (YesNoType.Yes == firstProgIdForClass)
1675 {
1676 this.Core.CreateRegistryRow(sourceLineNumbers, RegistryRootType.ClassesRoot, String.Concat("CLSID\\", classId, "\\VersionIndependentProgID"), String.Empty, progId, componentId);
1677 }
1678
1679 this.Core.CreateRegistryRow(sourceLineNumbers, RegistryRootType.ClassesRoot, String.Concat(progId, "\\CurVer"), String.Empty, parent, componentId);
1680 }
1681 else
1682 {
1683 if (YesNoType.Yes == firstProgIdForClass)
1684 {
1685 this.Core.CreateRegistryRow(sourceLineNumbers, RegistryRootType.ClassesRoot, String.Concat("CLSID\\", classId, "\\ProgID"), String.Empty, progId, componentId);
1686 }
1687 }
1688 }
1689
1690 if (null != icon) // ProgId's Default Icon
1691 {
1692 this.Core.CreateSimpleReference(sourceLineNumbers, "File", icon);
1693
1694 icon = String.Format(CultureInfo.InvariantCulture, "\"[#{0}]\"", icon);
1695
1696 if (CompilerConstants.IntegerNotSet != iconIndex)
1697 {
1698 icon = String.Concat(icon, ",", iconIndex);
1699 }
1700
1701 this.Core.CreateRegistryRow(sourceLineNumbers, RegistryRootType.ClassesRoot, String.Concat(progId, "\\DefaultIcon"), String.Empty, icon, componentId);
1702 }
1703 }
1704
1705 if (null != noOpen)
1706 {
1707 this.Core.CreateRegistryRow(sourceLineNumbers, RegistryRootType.ClassesRoot, progId, "NoOpen", noOpen, componentId); // ProgId NoOpen name
1708 }
1709
1710 // raise an error for an orphaned ProgId
1711 if (YesNoType.Yes == advertise && !foundExtension && null == parent && null == classId)
1712 {
1713 this.Core.Write(WarningMessages.OrphanedProgId(sourceLineNumbers, progId));
1714 }
1715
1716 return progId;
1717 }
1718
1719 /// <summary>
1720 /// Parses a property element.
1721 /// </summary>
1722 /// <param name="node">Element to parse.</param>
1723 private void ParsePropertyElement(XElement node)
1724 {
1725 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
1726 Identifier id = null;
1727 var admin = false;
1728 var complianceCheck = false;
1729 var hidden = false;
1730 var secure = false;
1731 var suppressModularization = YesNoType.NotSet;
1732 string value = null;
1733
1734 foreach (var attrib in node.Attributes())
1735 {
1736 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace)
1737 {
1738 switch (attrib.Name.LocalName)
1739 {
1740 case "Id":
1741 id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib);
1742 break;
1743 case "Admin":
1744 admin = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
1745 break;
1746 case "ComplianceCheck":
1747 complianceCheck = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
1748 break;
1749 case "Hidden":
1750 hidden = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
1751 break;
1752 case "Secure":
1753 secure = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
1754 break;
1755 case "SuppressModularization":
1756 suppressModularization = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
1757 break;
1758 case "Value":
1759 value = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
1760 break;
1761 default:
1762 this.Core.UnexpectedAttribute(node, attrib);
1763 break;
1764 }
1765 }
1766 else
1767 {
1768 this.Core.ParseExtensionAttribute(node, attrib);
1769 }
1770 }
1771
1772 if (null == id)
1773 {
1774 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id"));
1775 id = Identifier.Invalid;
1776 }
1777 else if ("ProductID" == id.Id)
1778 {
1779 this.Core.Write(WarningMessages.ProductIdAuthored(sourceLineNumbers));
1780 }
1781 else if ("SecureCustomProperties" == id.Id || "AdminProperties" == id.Id || "MsiHiddenProperties" == id.Id)
1782 {
1783 this.Core.Write(ErrorMessages.CannotAuthorSpecialProperties(sourceLineNumbers, id.Id));
1784 }
1785
1786 var innerText = this.Core.GetTrimmedInnerText(node);
1787 if (null != value)
1788 {
1789 // cannot specify both the value attribute and inner text
1790 if (!String.IsNullOrEmpty(innerText))
1791 {
1792 this.Core.Write(ErrorMessages.IllegalAttributeWithInnerText(sourceLineNumbers, node.Name.LocalName, "Value"));
1793 }
1794 }
1795 else // value attribute not specified, use inner text if any.
1796 {
1797 value = innerText;
1798 }
1799
1800 if ("ErrorDialog" == id.Id)
1801 {
1802 this.Core.CreateSimpleReference(sourceLineNumbers, "Dialog", value);
1803 }
1804
1805 foreach (var child in node.Elements())
1806 {
1807 if (CompilerCore.WixNamespace == child.Name.Namespace)
1808 {
1809 {
1810 switch (child.Name.LocalName)
1811 {
1812 case "ProductSearch":
1813 this.ParseProductSearchElement(child, id.Id);
1814 secure = true;
1815 break;
1816 default:
1817 // let ParseSearchSignatures handle standard AppSearch children and unknown elements
1818 break;
1819 }
1820 }
1821 }
1822 }
1823
1824 // see if this property is used for appSearch
1825 var signatures = this.ParseSearchSignatures(node);
1826
1827 // If we're doing CCP then there must be a signature.
1828 if (complianceCheck && 0 == signatures.Count)
1829 {
1830 this.Core.Write(ErrorMessages.SearchElementRequiredWithAttribute(sourceLineNumbers, node.Name.LocalName, "ComplianceCheck", "yes"));
1831 }
1832
1833 foreach (var sig in signatures)
1834 {
1835 if (complianceCheck && !this.Core.EncounteredError)
1836 {
1837 this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.CCPSearch, new Identifier(sig, AccessModifier.Private));
1838 }
1839
1840 this.AddAppSearch(sourceLineNumbers, id, sig);
1841 }
1842
1843 // If we're doing AppSearch get that setup.
1844 if (0 < signatures.Count)
1845 {
1846 this.AddProperty(sourceLineNumbers, id, value, admin, secure, hidden, false);
1847 }
1848 else // just a normal old property.
1849 {
1850 // If the property value is empty and none of the flags are set, print out a warning that we're ignoring
1851 // the element.
1852 if (String.IsNullOrEmpty(value) && !admin && !secure && !hidden)
1853 {
1854 this.Core.Write(WarningMessages.PropertyUseless(sourceLineNumbers, id.Id));
1855 }
1856 else // there is a value and/or a flag set, do that.
1857 {
1858 this.AddProperty(sourceLineNumbers, id, value, admin, secure, hidden, false);
1859 }
1860 }
1861
1862 if (!this.Core.EncounteredError && YesNoType.Yes == suppressModularization)
1863 {
1864 this.Core.Write(WarningMessages.PropertyModularizationSuppressed(sourceLineNumbers));
1865
1866 this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixSuppressModularization, id);
1867 }
1868 }
1869
1870 /// <summary>
1871 /// Parses a RegistryKey element.
1872 /// </summary>
1873 /// <param name="node">Element to parse.</param>
1874 /// <param name="componentId">Identifier for parent component.</param>
1875 /// <param name="root">Root specified when element is nested under another Registry element, otherwise CompilerConstants.IntegerNotSet.</param>
1876 /// <param name="parentKey">Parent key for this Registry element when nested.</param>
1877 /// <param name="win64Component">true if the component is 64-bit.</param>
1878 /// <param name="possibleKeyPath">Identifier of this registry key since it could be the component's keypath.</param>
1879 /// <returns>Yes if this element was marked as the parent component's key path, No if explicitly marked as not being a key path, or NotSet otherwise.</returns>
1880 [SuppressMessage("Microsoft.Globalization", "CA1308:NormalizeStringsToUppercase", Justification = "Changing the way this string normalizes would result " +
1881 "in a change to the way the Registry table is generated, potentially causing extra churn in patches on an MSI built from an older version of WiX. " +
1882 "Furthermore, there is no security hole here, as the strings won't need to make a round trip")]
1883 private YesNoType ParseRegistryKeyElement(XElement node, string componentId, RegistryRootType? root, string parentKey, bool win64Component, out string possibleKeyPath)
1884 {
1885 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
1886 Identifier id = null;
1887 var key = parentKey; // default to parent key path
1888 var forceCreateOnInstall = false;
1889 var forceDeleteOnUninstall = false;
1890 var keyPath = YesNoType.NotSet;
1891
1892 possibleKeyPath = null;
1893
1894 foreach (var attrib in node.Attributes())
1895 {
1896 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace)
1897 {
1898 switch (attrib.Name.LocalName)
1899 {
1900 case "Id":
1901 id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib);
1902 break;
1903 case "Action":
1904 this.Core.Write(WarningMessages.DeprecatedRegistryKeyActionAttribute(sourceLineNumbers));
1905 var actionValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
1906 switch (actionValue)
1907 {
1908 case "create":
1909 forceCreateOnInstall = true;
1910 break;
1911 case "createAndRemoveOnUninstall":
1912 forceCreateOnInstall = true;
1913 forceDeleteOnUninstall = true;
1914 break;
1915 case "none":
1916 break;
1917 case "":
1918 break;
1919 default:
1920 this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, actionValue, "create", "createAndRemoveOnUninstall", "none"));
1921 break;
1922 }
1923 break;
1924 case "ForceCreateOnInstall":
1925 forceCreateOnInstall = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
1926 break;
1927 case "ForceDeleteOnUninstall":
1928 forceDeleteOnUninstall = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
1929 break;
1930 case "Key":
1931 key = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
1932 if (null != parentKey)
1933 {
1934 key = Path.Combine(parentKey, key);
1935 }
1936 break;
1937 case "Root":
1938 if (root.HasValue)
1939 {
1940 this.Core.Write(ErrorMessages.RegistryRootInvalid(sourceLineNumbers));
1941 }
1942
1943 root = this.Core.GetAttributeRegistryRootValue(sourceLineNumbers, attrib, true);
1944 break;
1945 default:
1946 this.Core.UnexpectedAttribute(node, attrib);
1947 break;
1948 }
1949 }
1950 else
1951 {
1952 this.Core.ParseExtensionAttribute(node, attrib);
1953 }
1954 }
1955
1956 var name = forceCreateOnInstall ? (forceDeleteOnUninstall ? "*" : "+") : (forceDeleteOnUninstall ? "-" : null);
1957
1958 if (forceCreateOnInstall || forceDeleteOnUninstall) // generates a Registry row, so an Id must be present
1959 {
1960 // generate the identifier if it wasn't provided
1961 if (null == id)
1962 {
1963 id = this.Core.CreateIdentifier("reg", componentId, ((int)root).ToString(CultureInfo.InvariantCulture.NumberFormat), LowercaseOrNull(key), LowercaseOrNull(name));
1964 }
1965 }
1966 else // does not generate a Registry row, so no Id should be present
1967 {
1968 if (null != id)
1969 {
1970 this.Core.Write(ErrorMessages.IllegalAttributeWithoutOtherAttributes(sourceLineNumbers, node.Name.LocalName, "Id", "ForceCreateOnInstall", "ForceDeleteOnUninstall", "yes", true));
1971 }
1972 }
1973
1974 if (!root.HasValue)
1975 {
1976 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Root"));
1977 }
1978
1979 if (null == key)
1980 {
1981 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Key"));
1982 key = String.Empty; // set the key to something to prevent null reference exceptions
1983 }
1984
1985 foreach (var child in node.Elements())
1986 {
1987 if (CompilerCore.WixNamespace == child.Name.Namespace)
1988 {
1989 string possibleChildKeyPath = null;
1990
1991 switch (child.Name.LocalName)
1992 {
1993 case "RegistryKey":
1994 if (YesNoType.Yes == this.ParseRegistryKeyElement(child, componentId, root, key, win64Component, out possibleChildKeyPath))
1995 {
1996 if (YesNoType.Yes == keyPath)
1997 {
1998 this.Core.Write(ErrorMessages.ComponentMultipleKeyPaths(sourceLineNumbers, child.Name.LocalName, "KeyPath", "yes", "File", "RegistryValue", "ODBCDataSource"));
1999 }
2000
2001 possibleKeyPath = possibleChildKeyPath; // the child is the key path
2002 keyPath = YesNoType.Yes;
2003 }
2004 else if (null == possibleKeyPath && null != possibleChildKeyPath)
2005 {
2006 possibleKeyPath = possibleChildKeyPath;
2007 }
2008 break;
2009 case "RegistryValue":
2010 if (YesNoType.Yes == this.ParseRegistryValueElement(child, componentId, root, key, win64Component, out possibleChildKeyPath))
2011 {
2012 if (YesNoType.Yes == keyPath)
2013 {
2014 this.Core.Write(ErrorMessages.ComponentMultipleKeyPaths(sourceLineNumbers, child.Name.LocalName, "KeyPath", "yes", "File", "RegistryValue", "ODBCDataSource"));
2015 }
2016
2017 possibleKeyPath = possibleChildKeyPath; // the child is the key path
2018 keyPath = YesNoType.Yes;
2019 }
2020 else if (null == possibleKeyPath && null != possibleChildKeyPath)
2021 {
2022 possibleKeyPath = possibleChildKeyPath;
2023 }
2024 break;
2025 case "Permission":
2026 if (!forceCreateOnInstall)
2027 {
2028 this.Core.Write(ErrorMessages.UnexpectedElementWithAttributeValue(sourceLineNumbers, node.Name.LocalName, child.Name.LocalName, "ForceCreateOnInstall", "yes"));
2029 }
2030 this.ParsePermissionElement(child, id.Id, "Registry");
2031 break;
2032 case "PermissionEx":
2033 if (!forceCreateOnInstall)
2034 {
2035 this.Core.Write(ErrorMessages.UnexpectedElementWithAttributeValue(sourceLineNumbers, node.Name.LocalName, child.Name.LocalName, "ForceCreateOnInstall", "yes"));
2036 }
2037 this.ParsePermissionExElement(child, id.Id, "Registry");
2038 break;
2039 default:
2040 this.Core.UnexpectedElement(node, child);
2041 break;
2042 }
2043 }
2044 else
2045 {
2046 var context = new Dictionary<string, string>() { { "RegistryId", id.Id }, { "ComponentId", componentId }, { "Win64", win64Component.ToString() } };
2047 this.Core.ParseExtensionElement(node, child, context);
2048 }
2049 }
2050
2051 if (!this.Core.EncounteredError && null != name)
2052 {
2053 var tuple = new RegistryTuple(sourceLineNumbers, id)
2054 {
2055 Root = root.Value,
2056 Key = key,
2057 Name = name,
2058 Component_ = componentId,
2059 };
2060
2061 this.Core.AddTuple(tuple);
2062 }
2063
2064 return keyPath;
2065 }
2066
2067 /// <summary>
2068 /// Parses a RegistryValue element.
2069 /// </summary>
2070 /// <param name="node">Element to parse.</param>
2071 /// <param name="componentId">Identifier for parent component.</param>
2072 /// <param name="root">Root specified when element is nested under a RegistryKey element, otherwise CompilerConstants.IntegerNotSet.</param>
2073 /// <param name="parentKey">Root specified when element is nested under a RegistryKey element, otherwise CompilerConstants.IntegerNotSet.</param>
2074 /// <param name="win64Component">true if the component is 64-bit.</param>
2075 /// <param name="possibleKeyPath">Identifier of this registry key since it could be the component's keypath.</param>
2076 /// <returns>Yes if this element was marked as the parent component's key path, No if explicitly marked as not being a key path, or NotSet otherwise.</returns>
2077 [SuppressMessage("Microsoft.Globalization", "CA1308:NormalizeStringsToUppercase", Justification = "Changing the way this string normalizes would result " +
2078 "in a change to the way the Registry table is generated, potentially causing extra churn in patches on an MSI built from an older version of WiX. " +
2079 "Furthermore, there is no security hole here, as the strings won't need to make a round trip")]
2080 private YesNoType ParseRegistryValueElement(XElement node, string componentId, RegistryRootType? root, string parentKey, bool win64Component, out string possibleKeyPath)
2081 {
2082 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
2083 Identifier id = null;
2084 var key = parentKey; // default to parent key path
2085 string name = null;
2086 string value = null;
2087 string action = null;
2088 var valueType = RegistryValueType.String;
2089 var actionType = RegistryValueActionType.Write;
2090 var keyPath = YesNoType.NotSet;
2091
2092 possibleKeyPath = null;
2093
2094 foreach (var attrib in node.Attributes())
2095 {
2096 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace)
2097 {
2098 switch (attrib.Name.LocalName)
2099 {
2100 case "Id":
2101 id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib);
2102 break;
2103 case "Action":
2104 var actionValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
2105 switch (actionValue)
2106 {
2107 case "append":
2108 actionType = RegistryValueActionType.Append;
2109 break;
2110 case "prepend":
2111 actionType = RegistryValueActionType.Prepend;
2112 break;
2113 case "write":
2114 actionType = RegistryValueActionType.Write;
2115 break;
2116 case "":
2117 break;
2118 default:
2119 this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, actionValue, "append", "prepend", "write"));
2120 break;
2121 }
2122 break;
2123 case "Key":
2124 key = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
2125 if (null != parentKey)
2126 {
2127 if (parentKey.EndsWith("\\", StringComparison.Ordinal))
2128 {
2129 key = String.Concat(parentKey, key);
2130 }
2131 else
2132 {
2133 key = String.Concat(parentKey, "\\", key);
2134 }
2135 }
2136 break;
2137 case "KeyPath":
2138 keyPath = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
2139 break;
2140 case "Name":
2141 name = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
2142 break;
2143 case "Root":
2144 if (root.HasValue)
2145 {
2146 this.Core.Write(ErrorMessages.RegistryRootInvalid(sourceLineNumbers));
2147 }
2148
2149 root = this.Core.GetAttributeRegistryRootValue(sourceLineNumbers, attrib, true);
2150 break;
2151 case "Type":
2152 var typeValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
2153 switch (typeValue)
2154 {
2155 case "binary":
2156 valueType = RegistryValueType.Binary;
2157 break;
2158 case "expandable":
2159 valueType = RegistryValueType.Expandable;
2160 break;
2161 case "integer":
2162 valueType = RegistryValueType.Integer;
2163 break;
2164 case "multiString":
2165 valueType = RegistryValueType.MultiString;
2166 break;
2167 case "string":
2168 valueType = RegistryValueType.String;
2169 break;
2170 case "":
2171 break;
2172 default:
2173 this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, typeValue, "binary", "expandable", "integer", "multiString", "string"));
2174 break;
2175 }
2176 break;
2177 case "Value":
2178 value = this.Core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.CanBeEmpty);
2179 break;
2180 default:
2181 this.Core.UnexpectedAttribute(node, attrib);
2182 break;
2183 }
2184 }
2185 else
2186 {
2187 this.Core.ParseExtensionAttribute(node, attrib);
2188 }
2189 }
2190
2191 // generate the identifier if it wasn't provided
2192 if (null == id)
2193 {
2194 id = this.Core.CreateIdentifier("reg", componentId, ((int)(root ?? RegistryRootType.Unknown)).ToString(), LowercaseOrNull(key), LowercaseOrNull(name));
2195 }
2196
2197 if (RegistryValueType.MultiString != valueType && (RegistryValueActionType.Append == actionType || RegistryValueActionType.Prepend == actionType))
2198 {
2199 this.Core.Write(ErrorMessages.IllegalAttributeValueWithoutOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Action", action, "Type", "multiString"));
2200 }
2201
2202 if (null == key)
2203 {
2204 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Key"));
2205 }
2206
2207 if (!root.HasValue)
2208 {
2209 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Root"));
2210 }
2211
2212 foreach (var child in node.Elements())
2213 {
2214 if (CompilerCore.WixNamespace == child.Name.Namespace)
2215 {
2216 switch (child.Name.LocalName)
2217 {
2218 case "MultiStringValue":
2219 if (RegistryValueType.MultiString != valueType && null != value)
2220 {
2221 this.Core.Write(ErrorMessages.RegistryMultipleValuesWithoutMultiString(sourceLineNumbers, node.Name.LocalName, "Value", child.Name.LocalName, "Type"));
2222 }
2223 else if (null == value)
2224 {
2225 value = Common.GetInnerText(child);
2226 }
2227 else
2228 {
2229 value = String.Concat(value, "[~]", Common.GetInnerText(child));
2230 }
2231 break;
2232 case "Permission":
2233 this.ParsePermissionElement(child, id.Id, "Registry");
2234 break;
2235 case "PermissionEx":
2236 this.ParsePermissionExElement(child, id.Id, "Registry");
2237 break;
2238 default:
2239 this.Core.UnexpectedElement(node, child);
2240 break;
2241 }
2242 }
2243 else
2244 {
2245 var context = new Dictionary<string, string>() { { "RegistryId", id.Id }, { "ComponentId", componentId }, { "Win64", win64Component.ToString() } };
2246 this.Core.ParseExtensionElement(node, child, context);
2247 }
2248 }
2249
2250 //switch (typeType)
2251 //{
2252 //case Wix.RegistryValue.TypeType.binary:
2253 // value = String.Concat("#x", value);
2254 // break;
2255 //case Wix.RegistryValue.TypeType.expandable:
2256 // value = String.Concat("#%", value);
2257 // break;
2258 //case Wix.RegistryValue.TypeType.integer:
2259 // value = String.Concat("#", value);
2260 // break;
2261 //case Wix.RegistryValue.TypeType.multiString:
2262 // switch (actionType)
2263 // {
2264 // case Wix.RegistryValue.ActionType.append:
2265 // value = String.Concat("[~]", value);
2266 // break;
2267 // case Wix.RegistryValue.ActionType.prepend:
2268 // value = String.Concat(value, "[~]");
2269 // break;
2270 // case Wix.RegistryValue.ActionType.write:
2271 // default:
2272 // if (null != value && -1 == value.IndexOf("[~]", StringComparison.Ordinal))
2273 // {
2274 // value = String.Format(CultureInfo.InvariantCulture, "[~]{0}[~]", value);
2275 // }
2276 // break;
2277 // }
2278 // break;
2279 //case Wix.RegistryValue.TypeType.@string:
2280 // // escape the leading '#' character for string registry keys
2281 // if (null != value && value.StartsWith("#", StringComparison.Ordinal))
2282 // {
2283 // value = String.Concat("#", value);
2284 // }
2285 // break;
2286 //}
2287
2288 // value may be set by child MultiStringValue elements, so it must be checked here
2289 if (null == value)
2290 {
2291 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Value"));
2292 }
2293 else if (0 == value.Length && ("+" == name || "-" == name || "*" == name)) // prevent accidental authoring of special name values
2294 {
2295 this.Core.Write(ErrorMessages.RegistryNameValueIncorrect(sourceLineNumbers, node.Name.LocalName, "Name", name));
2296 }
2297
2298 if (!this.Core.EncounteredError)
2299 {
2300 var tuple = new RegistryTuple(sourceLineNumbers, id)
2301 {
2302 Root = root.Value,
2303 Name = name,
2304 Value = value,
2305 ValueType = valueType,
2306 ValueAction = actionType,
2307 Component_ = componentId,
2308 };
2309
2310 this.Core.AddTuple(tuple);
2311 //var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.Registry, id);
2312 //row.Set(1, (int)root);
2313 //row.Set(2, key);
2314 //row.Set(3, name);
2315 //row.Set(4, value);
2316 //row.Set(5, componentId);
2317 }
2318
2319 // If this was just a regular registry key (that could be the key path)
2320 // and no child registry key set the possible key path, let's make this
2321 // Registry/@Id a possible key path.
2322 if (null == possibleKeyPath)
2323 {
2324 possibleKeyPath = id.Id;
2325 }
2326
2327 return keyPath;
2328 }
2329
2330 /// <summary>
2331 /// Parses a RemoveRegistryKey element.
2332 /// </summary>
2333 /// <param name="node">The element to parse.</param>
2334 /// <param name="componentId">The component identifier of the parent element.</param>
2335 [SuppressMessage("Microsoft.Globalization", "CA1308:NormalizeStringsToUppercase", Justification = "Changing the way this string normalizes would result " +
2336 "in a change to the way the Registry table is generated, potentially causing extra churn in patches on an MSI built from an older version of WiX. " +
2337 "Furthermore, there is no security hole here, as the strings won't need to make a round trip")]
2338 private void ParseRemoveRegistryKeyElement(XElement node, string componentId)
2339 {
2340 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
2341 Identifier id = null;
2342 RemoveRegistryActionType? actionType = null;
2343 string key = null;
2344 var name = "-";
2345 RegistryRootType? root = null;
2346
2347 foreach (var attrib in node.Attributes())
2348 {
2349 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace)
2350 {
2351 switch (attrib.Name.LocalName)
2352 {
2353 case "Id":
2354 id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib);
2355 break;
2356 case "Action":
2357 var actionValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
2358 switch (actionValue)
2359 {
2360 case "removeOnInstall":
2361 actionType = RemoveRegistryActionType.RemoveOnInstall;
2362 break;
2363 case "removeOnUninstall":
2364 actionType = RemoveRegistryActionType.RemoveOnUninstall;
2365 break;
2366 case "":
2367 break;
2368 default:
2369 this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, actionValue, "removeOnInstall", "removeOnUninstall"));
2370 break;
2371 }
2372 //if (0 < action.Length)
2373 //{
2374 // if (!Wix.RemoveRegistryKey.TryParseActionType(action, out actionType))
2375 // {
2376 // this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, action, "removeOnInstall", "removeOnUninstall"));
2377 // }
2378 //}
2379 break;
2380 case "Key":
2381 key = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
2382 break;
2383 case "Root":
2384 root = this.Core.GetAttributeRegistryRootValue(sourceLineNumbers, attrib, true);
2385 break;
2386 default:
2387 this.Core.UnexpectedAttribute(node, attrib);
2388 break;
2389 }
2390 }
2391 else
2392 {
2393 this.Core.ParseExtensionAttribute(node, attrib);
2394 }
2395 }
2396
2397 // generate the identifier if it wasn't provided
2398 if (null == id)
2399 {
2400 id = this.Core.CreateIdentifier("reg", componentId, ((int)root).ToString(CultureInfo.InvariantCulture.NumberFormat), LowercaseOrNull(key), LowercaseOrNull(name));
2401 }
2402
2403 if (!root.HasValue)
2404 {
2405 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Root"));
2406 }
2407
2408 if (null == key)
2409 {
2410 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Key"));
2411 }
2412
2413 if (!actionType.HasValue)
2414 {
2415 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Action"));
2416 }
2417
2418 this.Core.ParseForExtensionElements(node);
2419
2420 if (!this.Core.EncounteredError)
2421 {
2422 var tuple = new RemoveRegistryTuple(sourceLineNumbers, id)
2423 {
2424 Root = root.Value,
2425 Key = key,
2426 Name = name,
2427 Action = actionType.Value,
2428 Component_ = componentId
2429 };
2430
2431 this.Core.AddTuple(tuple);
2432 }
2433 }
2434
2435 /// <summary>
2436 /// Parses a RemoveRegistryValue element.
2437 /// </summary>
2438 /// <param name="node">The element to parse.</param>
2439 /// <param name="componentId">The component identifier of the parent element.</param>
2440 [SuppressMessage("Microsoft.Globalization", "CA1308:NormalizeStringsToUppercase", Justification = "Changing the way this string normalizes would result " +
2441 "in a change to the way the Registry table is generated, potentially causing extra churn in patches on an MSI built from an older version of WiX. " +
2442 "Furthermore, there is no security hole here, as the strings won't need to make a round trip")]
2443 private void ParseRemoveRegistryValueElement(XElement node, string componentId)
2444 {
2445 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
2446 Identifier id = null;
2447 string key = null;
2448 string name = null;
2449 RegistryRootType? root = null;
2450
2451 foreach (var attrib in node.Attributes())
2452 {
2453 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace)
2454 {
2455 switch (attrib.Name.LocalName)
2456 {
2457 case "Id":
2458 id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib);
2459 break;
2460 case "Key":
2461 key = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
2462 break;
2463 case "Name":
2464 name = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
2465 break;
2466 case "Root":
2467 root = this.Core.GetAttributeRegistryRootValue(sourceLineNumbers, attrib, true);
2468 break;
2469 default:
2470 this.Core.UnexpectedAttribute(node, attrib);
2471 break;
2472 }
2473 }
2474 else
2475 {
2476 this.Core.ParseExtensionAttribute(node, attrib);
2477 }
2478 }
2479
2480 // generate the identifier if it wasn't provided
2481 if (null == id)
2482 {
2483 id = this.Core.CreateIdentifier("reg", componentId, ((int)root).ToString(CultureInfo.InvariantCulture.NumberFormat), LowercaseOrNull(key), LowercaseOrNull(name));
2484 }
2485
2486 if (!root.HasValue)
2487 {
2488 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Root"));
2489 }
2490
2491 if (null == key)
2492 {
2493 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Key"));
2494 }
2495
2496 this.Core.ParseForExtensionElements(node);
2497
2498 if (!this.Core.EncounteredError)
2499 {
2500 var tuple = new RemoveRegistryTuple(sourceLineNumbers, id)
2501 {
2502 Root = root.Value,
2503 Key = key,
2504 Name = name,
2505 Component_ = componentId
2506 };
2507
2508 this.Core.AddTuple(tuple);
2509 }
2510 }
2511
2512 /// <summary>
2513 /// Parses a remove file element.
2514 /// </summary>
2515 /// <param name="node">Element to parse.</param>
2516 /// <param name="componentId">Identifier of parent component.</param>
2517 /// <param name="parentDirectory">Identifier of the parent component's directory.</param>
2518 private void ParseRemoveFileElement(XElement node, string componentId, string parentDirectory)
2519 {
2520 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
2521 Identifier id = null;
2522 string directory = null;
2523 string name = null;
2524 var on = CompilerConstants.IntegerNotSet;
2525 string property = null;
2526 string shortName = null;
2527
2528 foreach (var attrib in node.Attributes())
2529 {
2530 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace)
2531 {
2532 switch (attrib.Name.LocalName)
2533 {
2534 case "Id":
2535 id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib);
2536 break;
2537 case "Directory":
2538 directory = this.Core.CreateDirectoryReferenceFromInlineSyntax(sourceLineNumbers, attrib, parentDirectory);
2539 break;
2540 case "Name":
2541 name = this.Core.GetAttributeLongFilename(sourceLineNumbers, attrib, true);
2542 break;
2543 case "On":
2544 var onValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
2545 switch (onValue)
2546 {
2547 case "install":
2548 on = 1;
2549 break;
2550 case "uninstall":
2551 on = 2;
2552 break;
2553 case "both":
2554 on = 3;
2555 break;
2556 default:
2557 on = CompilerConstants.IllegalInteger;
2558 break;
2559 }
2560 break;
2561 case "Property":
2562 property = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
2563 break;
2564 case "ShortName":
2565 shortName = this.Core.GetAttributeShortFilename(sourceLineNumbers, attrib, true);
2566 break;
2567 default:
2568 this.Core.UnexpectedAttribute(node, attrib);
2569 break;
2570 }
2571 }
2572 else
2573 {
2574 this.Core.ParseExtensionAttribute(node, attrib);
2575 }
2576 }
2577
2578 if (null == name)
2579 {
2580 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Name"));
2581 }
2582 else if (0 < name.Length)
2583 {
2584 if (this.Core.IsValidShortFilename(name, true))
2585 {
2586 if (null == shortName)
2587 {
2588 shortName = name;
2589 name = null;
2590 }
2591 else
2592 {
2593 this.Core.Write(ErrorMessages.IllegalAttributeValueWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Name", name, "ShortName"));
2594 }
2595 }
2596 else if (null == shortName) // generate a short file name.
2597 {
2598 shortName = this.Core.CreateShortName(name, true, true, node.Name.LocalName, componentId);
2599 }
2600 }
2601
2602 if (CompilerConstants.IntegerNotSet == on)
2603 {
2604 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "On"));
2605 on = CompilerConstants.IllegalInteger;
2606 }
2607
2608 if (null != directory && null != property)
2609 {
2610 this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Property", "Directory", directory));
2611 }
2612
2613 if (null == id)
2614 {
2615 id = this.Core.CreateIdentifier("rmf", directory ?? property ?? parentDirectory, LowercaseOrNull(shortName), LowercaseOrNull(name), on.ToString());
2616 }
2617
2618 this.Core.ParseForExtensionElements(node);
2619
2620 if (!this.Core.EncounteredError)
2621 {
2622 var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.RemoveFile, id);
2623 row.Set(1, componentId);
2624 row.Set(2, this.GetMsiFilenameValue(shortName, name));
2625 if (null != directory)
2626 {
2627 row.Set(3, directory);
2628 }
2629 else if (null != property)
2630 {
2631 row.Set(3, property);
2632 }
2633 else
2634 {
2635 row.Set(3, parentDirectory);
2636 }
2637 row.Set(4, on);
2638 }
2639 }
2640
2641 /// <summary>
2642 /// Parses a RemoveFolder element.
2643 /// </summary>
2644 /// <param name="node">Element to parse.</param>
2645 /// <param name="componentId">Identifier of parent component.</param>
2646 /// <param name="parentDirectory">Identifier of parent component's directory.</param>
2647 private void ParseRemoveFolderElement(XElement node, string componentId, string parentDirectory)
2648 {
2649 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
2650 Identifier id = null;
2651 string directory = null;
2652 var on = CompilerConstants.IntegerNotSet;
2653 string property = null;
2654
2655 foreach (var attrib in node.Attributes())
2656 {
2657 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace)
2658 {
2659 switch (attrib.Name.LocalName)
2660 {
2661 case "Id":
2662 id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib);
2663 break;
2664 case "Directory":
2665 directory = this.Core.CreateDirectoryReferenceFromInlineSyntax(sourceLineNumbers, attrib, parentDirectory);
2666 break;
2667 case "On":
2668 var onValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
2669 switch (onValue)
2670 {
2671 case "install":
2672 on = 1;
2673 break;
2674 case "uninstall":
2675 on = 2;
2676 break;
2677 case "both":
2678 on = 3;
2679 break;
2680 default:
2681 on = CompilerConstants.IllegalInteger;
2682 break;
2683 }
2684 break;
2685 case "Property":
2686 property = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
2687 break;
2688 default:
2689 this.Core.UnexpectedAttribute(node, attrib);
2690 break;
2691 }
2692 }
2693 else
2694 {
2695 this.Core.ParseExtensionAttribute(node, attrib);
2696 }
2697 }
2698
2699 if (CompilerConstants.IntegerNotSet == on)
2700 {
2701 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "On"));
2702 on = CompilerConstants.IllegalInteger;
2703 }
2704
2705 if (null != directory && null != property)
2706 {
2707 this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Property", "Directory", directory));
2708 }
2709
2710 if (null == id)
2711 {
2712 id = this.Core.CreateIdentifier("rmf", directory ?? property ?? parentDirectory, on.ToString());
2713 }
2714
2715 this.Core.ParseForExtensionElements(node);
2716
2717 if (!this.Core.EncounteredError)
2718 {
2719 var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.RemoveFile, id);
2720 row.Set(1, componentId);
2721 //row.Set(2, null);
2722 if (null != directory)
2723 {
2724 row.Set(3, directory);
2725 }
2726 else if (null != property)
2727 {
2728 row.Set(3, property);
2729 }
2730 else
2731 {
2732 row.Set(3, parentDirectory);
2733 }
2734 row.Set(4, on);
2735 }
2736 }
2737
2738 /// <summary>
2739 /// Parses a reserve cost element.
2740 /// </summary>
2741 /// <param name="node">Element to parse.</param>
2742 /// <param name="componentId">Identifier of parent component.</param>
2743 /// <param name="directoryId">Optional and default identifier of referenced directory.</param>
2744 private void ParseReserveCostElement(XElement node, string componentId, string directoryId)
2745 {
2746 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
2747 Identifier id = null;
2748 var runFromSource = CompilerConstants.IntegerNotSet;
2749 var runLocal = CompilerConstants.IntegerNotSet;
2750
2751 foreach (var attrib in node.Attributes())
2752 {
2753 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace)
2754 {
2755 switch (attrib.Name.LocalName)
2756 {
2757 case "Id":
2758 id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib);
2759 break;
2760 case "Directory":
2761 directoryId = this.Core.CreateDirectoryReferenceFromInlineSyntax(sourceLineNumbers, attrib, directoryId);
2762 break;
2763 case "RunFromSource":
2764 runFromSource = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int32.MaxValue);
2765 break;
2766 case "RunLocal":
2767 runLocal = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int32.MaxValue);
2768 break;
2769 default:
2770 this.Core.UnexpectedAttribute(node, attrib);
2771 break;
2772 }
2773 }
2774 else
2775 {
2776 this.Core.ParseExtensionAttribute(node, attrib);
2777 }
2778 }
2779
2780 if (null == id)
2781 {
2782 id = this.Core.CreateIdentifier("rc", componentId, directoryId);
2783 }
2784
2785 if (CompilerConstants.IntegerNotSet == runFromSource)
2786 {
2787 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "RunFromSource"));
2788 }
2789
2790 if (CompilerConstants.IntegerNotSet == runLocal)
2791 {
2792 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "RunLocal"));
2793 }
2794
2795 this.Core.ParseForExtensionElements(node);
2796
2797 if (!this.Core.EncounteredError)
2798 {
2799 var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.ReserveCost, id);
2800 row.Set(1, componentId);
2801 row.Set(2, directoryId);
2802 row.Set(3, runLocal);
2803 row.Set(4, runFromSource);
2804 }
2805 }
2806
2807 /// <summary>
2808 /// Parses a sequence element.
2809 /// </summary>
2810 /// <param name="node">Element to parse.</param>
2811 /// <param name="sequenceTable">Name of sequence table.</param>
2812 private void ParseSequenceElement(XElement node, string sequenceTable)
2813 {
2814 // use the proper table name internally
2815 if ("AdvertiseExecuteSequence" == sequenceTable)
2816 {
2817 sequenceTable = "AdvtExecuteSequence";
2818 }
2819
2820 // Parse each action in the sequence.
2821 foreach (var child in node.Elements())
2822 {
2823 var childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(child);
2824 var actionName = child.Name.LocalName;
2825 string afterAction = null;
2826 string beforeAction = null;
2827 string condition = null;
2828 var customAction = "Custom" == actionName;
2829 var overridable = false;
2830 var exitSequence = CompilerConstants.IntegerNotSet;
2831 var sequence = CompilerConstants.IntegerNotSet;
2832 var showDialog = "Show" == actionName;
2833 var specialAction = "InstallExecute" == actionName || "InstallExecuteAgain" == actionName || "RemoveExistingProducts" == actionName || "DisableRollback" == actionName || "ScheduleReboot" == actionName || "ForceReboot" == actionName || "ResolveSource" == actionName;
2834 var specialStandardAction = "AppSearch" == actionName || "CCPSearch" == actionName || "RMCCPSearch" == actionName || "LaunchConditions" == actionName || "FindRelatedProducts" == actionName;
2835 var suppress = false;
2836
2837 foreach (var attrib in child.Attributes())
2838 {
2839 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace)
2840 {
2841 switch (attrib.Name.LocalName)
2842 {
2843 case "Action":
2844 if (customAction)
2845 {
2846 actionName = this.Core.GetAttributeIdentifierValue(childSourceLineNumbers, attrib);
2847 this.Core.CreateSimpleReference(childSourceLineNumbers, "CustomAction", actionName);
2848 }
2849 else
2850 {
2851 this.Core.UnexpectedAttribute(child, attrib);
2852 }
2853 break;
2854 case "After":
2855 if (customAction || showDialog || specialAction || specialStandardAction)
2856 {
2857 afterAction = this.Core.GetAttributeIdentifierValue(childSourceLineNumbers, attrib);
2858 this.Core.CreateSimpleReference(childSourceLineNumbers, "WixAction", sequenceTable, afterAction);
2859 }
2860 else
2861 {
2862 this.Core.UnexpectedAttribute(child, attrib);
2863 }
2864 break;
2865 case "Before":
2866 if (customAction || showDialog || specialAction || specialStandardAction)
2867 {
2868 beforeAction = this.Core.GetAttributeIdentifierValue(childSourceLineNumbers, attrib);
2869 this.Core.CreateSimpleReference(childSourceLineNumbers, "WixAction", sequenceTable, beforeAction);
2870 }
2871 else
2872 {
2873 this.Core.UnexpectedAttribute(child, attrib);
2874 }
2875 break;
2876 case "Dialog":
2877 if (showDialog)
2878 {
2879 actionName = this.Core.GetAttributeIdentifierValue(childSourceLineNumbers, attrib);
2880 this.Core.CreateSimpleReference(childSourceLineNumbers, "Dialog", actionName);
2881 }
2882 else
2883 {
2884 this.Core.UnexpectedAttribute(child, attrib);
2885 }
2886 break;
2887 case "OnExit":
2888 if (customAction || showDialog || specialAction)
2889 {
2890 var exitValue = this.Core.GetAttributeValue(childSourceLineNumbers, attrib);
2891 switch (exitValue)
2892 {
2893 case "success":
2894 exitSequence = -1;
2895 break;
2896 case "cancel":
2897 exitSequence = -2;
2898 break;
2899 case "error":
2900 exitSequence = -3;
2901 break;
2902 case "suspend":
2903 exitSequence = -4;
2904 break;
2905 }
2906 }
2907 else
2908 {
2909 this.Core.UnexpectedAttribute(child, attrib);
2910 }
2911 break;
2912 case "Overridable":
2913 overridable = YesNoType.Yes == this.Core.GetAttributeYesNoValue(childSourceLineNumbers, attrib);
2914 break;
2915 case "Sequence":
2916 sequence = this.Core.GetAttributeIntegerValue(childSourceLineNumbers, attrib, 1, Int16.MaxValue);
2917 break;
2918 case "Suppress":
2919 suppress = YesNoType.Yes == this.Core.GetAttributeYesNoValue(childSourceLineNumbers, attrib);
2920 break;
2921 default:
2922 this.Core.UnexpectedAttribute(node, attrib);
2923 break;
2924 }
2925 }
2926 else
2927 {
2928 this.Core.ParseExtensionAttribute(node, attrib);
2929 }
2930 }
2931
2932 // Get the condition from the inner text of the element.
2933 condition = this.Core.GetConditionInnerText(child);
2934
2935 if (customAction && "Custom" == actionName)
2936 {
2937 this.Core.Write(ErrorMessages.ExpectedAttribute(childSourceLineNumbers, child.Name.LocalName, "Action"));
2938 }
2939 else if (showDialog && "Show" == actionName)
2940 {
2941 this.Core.Write(ErrorMessages.ExpectedAttribute(childSourceLineNumbers, child.Name.LocalName, "Dialog"));
2942 }
2943
2944 if (CompilerConstants.IntegerNotSet != sequence)
2945 {
2946 if (CompilerConstants.IntegerNotSet != exitSequence)
2947 {
2948 this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(childSourceLineNumbers, child.Name.LocalName, "Sequence", "OnExit"));
2949 }
2950 else if (null != beforeAction || null != afterAction)
2951 {
2952 this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(childSourceLineNumbers, child.Name.LocalName, "Sequence", "Before", "After"));
2953 }
2954 }
2955 else // sequence not specified use OnExit (which may also be not set).
2956 {
2957 sequence = exitSequence;
2958 }
2959
2960 if (null != beforeAction && null != afterAction)
2961 {
2962 this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(childSourceLineNumbers, child.Name.LocalName, "After", "Before"));
2963 }
2964 else if ((customAction || showDialog || specialAction) && !suppress && CompilerConstants.IntegerNotSet == sequence && null == beforeAction && null == afterAction)
2965 {
2966 this.Core.Write(ErrorMessages.NeedSequenceBeforeOrAfter(childSourceLineNumbers, child.Name.LocalName));
2967 }
2968
2969 // action that is scheduled to occur before/after itself
2970 if (beforeAction == actionName)
2971 {
2972 this.Core.Write(ErrorMessages.ActionScheduledRelativeToItself(childSourceLineNumbers, child.Name.LocalName, "Before", beforeAction));
2973 }
2974 else if (afterAction == actionName)
2975 {
2976 this.Core.Write(ErrorMessages.ActionScheduledRelativeToItself(childSourceLineNumbers, child.Name.LocalName, "After", afterAction));
2977 }
2978
2979 // normal standard actions cannot be set overridable by the user (since they are overridable by default)
2980 if (overridable && WindowsInstallerStandard.IsStandardAction(actionName) && !specialAction)
2981 {
2982 this.Core.Write(ErrorMessages.UnexpectedAttribute(childSourceLineNumbers, child.Name.LocalName, "Overridable"));
2983 }
2984
2985 // suppress cannot be specified at the same time as Before, After, or Sequence
2986 if (suppress && (null != afterAction || null != beforeAction || CompilerConstants.IntegerNotSet != sequence || overridable))
2987 {
2988 this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttributes(childSourceLineNumbers, child.Name.LocalName, "Suppress", "Before", "After", "Sequence", "Overridable"));
2989 }
2990
2991 this.Core.ParseForExtensionElements(child);
2992
2993 // add the row and any references needed
2994 if (!this.Core.EncounteredError)
2995 {
2996 if (suppress)
2997 {
2998 var row = this.Core.CreateRow(childSourceLineNumbers, TupleDefinitionType.WixSuppressAction, new Identifier(AccessModifier.Public, sequenceTable, actionName));
2999 row.Set(0, sequenceTable);
3000 row.Set(1, actionName);
3001 }
3002 else
3003 {
3004 var row = this.Core.CreateRow(childSourceLineNumbers, TupleDefinitionType.WixAction, new Identifier(AccessModifier.Public, sequenceTable, actionName));
3005 row.Set(0, sequenceTable);
3006 row.Set(1, actionName);
3007 row.Set(2, condition);
3008 if (CompilerConstants.IntegerNotSet != sequence)
3009 {
3010 row.Set(3, sequence);
3011 }
3012 row.Set(4, beforeAction);
3013 row.Set(5, afterAction);
3014 row.Set(6, overridable ? 1 : 0);
3015 }
3016 }
3017 }
3018 }
3019
3020
3021 /// <summary>
3022 /// Parses a service config element.
3023 /// </summary>
3024 /// <param name="node">Element to parse.</param>
3025 /// <param name="componentId">Identifier of parent component.</param>
3026 /// <param name="serviceName">Optional element containing parent's service name.</param>
3027 private void ParseServiceConfigElement(XElement node, string componentId, string serviceName)
3028 {
3029 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
3030 Identifier id = null;
3031 string delayedAutoStart = null;
3032 string failureActionsWhen = null;
3033 var name = serviceName;
3034 var install = false;
3035 var reinstall = false;
3036 var uninstall = false;
3037 string preShutdownDelay = null;
3038 string requiredPrivileges = null;
3039 string sid = null;
3040
3041 this.Core.Write(WarningMessages.ServiceConfigFamilyNotSupported(sourceLineNumbers, node.Name.LocalName));
3042
3043 foreach (var attrib in node.Attributes())
3044 {
3045 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace)
3046 {
3047 switch (attrib.Name.LocalName)
3048 {
3049 case "Id":
3050 id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib);
3051 break;
3052 case "DelayedAutoStart":
3053 delayedAutoStart = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
3054 switch (delayedAutoStart)
3055 {
3056 case "no":
3057 delayedAutoStart = "0";
3058 break;
3059 case "yes":
3060 delayedAutoStart = "1";
3061 break;
3062 default:
3063 // allow everything else to pass through that are hopefully "formatted" Properties.
3064 break;
3065 }
3066 break;
3067 case "FailureActionsWhen":
3068 failureActionsWhen = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
3069 switch (failureActionsWhen)
3070 {
3071 case "failedToStop":
3072 failureActionsWhen = "0";
3073 break;
3074 case "failedToStopOrReturnedError":
3075 failureActionsWhen = "1";
3076 break;
3077 default:
3078 // allow everything else to pass through that are hopefully "formatted" Properties.
3079 break;
3080 }
3081 break;
3082 case "OnInstall":
3083 install = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
3084 //if (YesNoType.Yes == install)
3085 //{
3086 // events |= MsiInterop.MsidbServiceConfigEventInstall;
3087 //}
3088 break;
3089 case "OnReinstall":
3090 reinstall = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
3091 //if (YesNoType.Yes == reinstall)
3092 //{
3093 // events |= MsiInterop.MsidbServiceConfigEventReinstall;
3094 //}
3095 break;
3096 case "OnUninstall":
3097 uninstall = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
3098 //if (YesNoType.Yes == uninstall)
3099 //{
3100 // events |= MsiInterop.MsidbServiceConfigEventUninstall;
3101 //}
3102 break;
3103 default:
3104 this.Core.UnexpectedAttribute(node, attrib);
3105 break;
3106 case "PreShutdownDelay":
3107 preShutdownDelay = this.Core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.CanBeEmpty);
3108 break;
3109 case "ServiceName":
3110 if (!String.IsNullOrEmpty(serviceName))
3111 {
3112 this.Core.Write(ErrorMessages.IllegalAttributeWhenNested(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "ServiceInstall"));
3113 }
3114
3115 name = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
3116 break;
3117 case "ServiceSid":
3118 sid = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
3119 switch (sid)
3120 {
3121 case "none":
3122 sid = "0";
3123 break;
3124 case "restricted":
3125 sid = "3";
3126 break;
3127 case "unrestricted":
3128 sid = "1";
3129 break;
3130 default:
3131 // allow everything else to pass through that are hopefully "formatted" Properties.
3132 break;
3133 }
3134 break;
3135 }
3136 }
3137 else
3138 {
3139 this.Core.ParseExtensionAttribute(node, attrib);
3140 }
3141 }
3142
3143 // Get the ServiceConfig required privilegs.
3144 foreach (var child in node.Elements())
3145 {
3146 if (CompilerCore.WixNamespace == child.Name.Namespace)
3147 {
3148 switch (child.Name.LocalName)
3149 {
3150 case "RequiredPrivilege":
3151 var privilege = this.Core.GetTrimmedInnerText(child);
3152 switch (privilege)
3153 {
3154 case "assignPrimaryToken":
3155 privilege = "SeAssignPrimaryTokenPrivilege";
3156 break;
3157 case "audit":
3158 privilege = "SeAuditPrivilege";
3159 break;
3160 case "backup":
3161 privilege = "SeBackupPrivilege";
3162 break;
3163 case "changeNotify":
3164 privilege = "SeChangeNotifyPrivilege";
3165 break;
3166 case "createGlobal":
3167 privilege = "SeCreateGlobalPrivilege";
3168 break;
3169 case "createPagefile":
3170 privilege = "SeCreatePagefilePrivilege";
3171 break;
3172 case "createPermanent":
3173 privilege = "SeCreatePermanentPrivilege";
3174 break;
3175 case "createSymbolicLink":
3176 privilege = "SeCreateSymbolicLinkPrivilege";
3177 break;
3178 case "createToken":
3179 privilege = "SeCreateTokenPrivilege";
3180 break;
3181 case "debug":
3182 privilege = "SeDebugPrivilege";
3183 break;
3184 case "enableDelegation":
3185 privilege = "SeEnableDelegationPrivilege";
3186 break;
3187 case "impersonate":
3188 privilege = "SeImpersonatePrivilege";
3189 break;
3190 case "increaseBasePriority":
3191 privilege = "SeIncreaseBasePriorityPrivilege";
3192 break;
3193 case "increaseQuota":
3194 privilege = "SeIncreaseQuotaPrivilege";
3195 break;
3196 case "increaseWorkingSet":
3197 privilege = "SeIncreaseWorkingSetPrivilege";
3198 break;
3199 case "loadDriver":
3200 privilege = "SeLoadDriverPrivilege";
3201 break;
3202 case "lockMemory":
3203 privilege = "SeLockMemoryPrivilege";
3204 break;
3205 case "machineAccount":
3206 privilege = "SeMachineAccountPrivilege";
3207 break;
3208 case "manageVolume":
3209 privilege = "SeManageVolumePrivilege";
3210 break;
3211 case "profileSingleProcess":
3212 privilege = "SeProfileSingleProcessPrivilege";
3213 break;
3214 case "relabel":
3215 privilege = "SeRelabelPrivilege";
3216 break;
3217 case "remoteShutdown":
3218 privilege = "SeRemoteShutdownPrivilege";
3219 break;
3220 case "restore":
3221 privilege = "SeRestorePrivilege";
3222 break;
3223 case "security":
3224 privilege = "SeSecurityPrivilege";
3225 break;
3226 case "shutdown":
3227 privilege = "SeShutdownPrivilege";
3228 break;
3229 case "syncAgent":
3230 privilege = "SeSyncAgentPrivilege";
3231 break;
3232 case "systemEnvironment":
3233 privilege = "SeSystemEnvironmentPrivilege";
3234 break;
3235 case "systemProfile":
3236 privilege = "SeSystemProfilePrivilege";
3237 break;
3238 case "systemTime":
3239 case "modifySystemTime":
3240 privilege = "SeSystemtimePrivilege";
3241 break;
3242 case "takeOwnership":
3243 privilege = "SeTakeOwnershipPrivilege";
3244 break;
3245 case "tcb":
3246 case "trustedComputerBase":
3247 privilege = "SeTcbPrivilege";
3248 break;
3249 case "timeZone":
3250 case "modifyTimeZone":
3251 privilege = "SeTimeZonePrivilege";
3252 break;
3253 case "trustedCredManAccess":
3254 case "trustedCredentialManagerAccess":
3255 privilege = "SeTrustedCredManAccessPrivilege";
3256 break;
3257 case "undock":
3258 privilege = "SeUndockPrivilege";
3259 break;
3260 case "unsolicitedInput":
3261 privilege = "SeUnsolicitedInputPrivilege";
3262 break;
3263 default:
3264 // allow everything else to pass through that are hopefully "formatted" Properties.
3265 break;
3266 }
3267
3268 if (null != requiredPrivileges)
3269 {
3270 requiredPrivileges = String.Concat(requiredPrivileges, "[~]");
3271 }
3272 requiredPrivileges = String.Concat(requiredPrivileges, privilege);
3273 break;
3274 default:
3275 this.Core.UnexpectedElement(node, child);
3276 break;
3277 }
3278 }
3279 else
3280 {
3281 this.Core.ParseExtensionElement(node, child);
3282 }
3283 }
3284
3285 if (String.IsNullOrEmpty(name))
3286 {
3287 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "ServiceName"));
3288 }
3289 else if (null == id)
3290 {
3291 id = this.Core.CreateIdentifierFromFilename(name);
3292 }
3293
3294 if (!install && !reinstall && !uninstall)
3295 {
3296 this.Core.Write(ErrorMessages.ExpectedAttributes(sourceLineNumbers, node.Name.LocalName, "OnInstall", "OnReinstall", "OnUninstall"));
3297 }
3298
3299 if (String.IsNullOrEmpty(delayedAutoStart) && String.IsNullOrEmpty(failureActionsWhen) && String.IsNullOrEmpty(preShutdownDelay) && String.IsNullOrEmpty(requiredPrivileges) && String.IsNullOrEmpty(sid))
3300 {
3301 this.Core.Write(ErrorMessages.ExpectedAttributes(sourceLineNumbers, node.Name.LocalName, "DelayedAutoStart", "FailureActionsWhen", "PreShutdownDelay", "ServiceSid", "RequiredPrivilege"));
3302 }
3303
3304 if (!this.Core.EncounteredError)
3305 {
3306 if (!String.IsNullOrEmpty(delayedAutoStart))
3307 {
3308 var tuple = new MsiServiceConfigTuple(sourceLineNumbers, new Identifier(String.Concat(id.Id, ".DS"), id.Access))
3309 {
3310 Name = name,
3311 OnInstall = install,
3312 OnReinstall = reinstall,
3313 OnUninstall = uninstall,
3314 ConfigType = MsiServiceConfigType.DelayedAutoStart,
3315 Argument = delayedAutoStart,
3316 Component_ = componentId,
3317 };
3318
3319 this.Core.AddTuple(tuple);
3320 //var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.MsiServiceConfig, new Identifier(String.Concat(id.Id, ".DS"), id.Access));
3321 //row.Set(1, name);
3322 //row.Set(2, events);
3323 //row.Set(3, 3);
3324 //row.Set(4, delayedAutoStart);
3325 //row.Set(5, componentId);
3326 }
3327
3328 if (!String.IsNullOrEmpty(failureActionsWhen))
3329 {
3330 var tuple = new MsiServiceConfigTuple(sourceLineNumbers, new Identifier(String.Concat(id.Id, ".FA"), id.Access))
3331 {
3332 Name = name,
3333 OnInstall = install,
3334 OnReinstall = reinstall,
3335 OnUninstall = uninstall,
3336 ConfigType = MsiServiceConfigType.FailureActionsFlag,
3337 Argument = failureActionsWhen,
3338 Component_ = componentId,
3339 };
3340
3341 this.Core.AddTuple(tuple);
3342 //var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.MsiServiceConfig, new Identifier(String.Concat(id.Id, ".FA"), id.Access));
3343 //row.Set(1, name);
3344 //row.Set(2, events);
3345 //row.Set(3, 4);
3346 //row.Set(4, failureActionsWhen);
3347 //row.Set(5, componentId);
3348 }
3349
3350 if (!String.IsNullOrEmpty(sid))
3351 {
3352 var tuple = new MsiServiceConfigTuple(sourceLineNumbers, new Identifier(String.Concat(id.Id, ".SS"), id.Access))
3353 {
3354 Name = name,
3355 OnInstall = install,
3356 OnReinstall = reinstall,
3357 OnUninstall = uninstall,
3358 ConfigType = MsiServiceConfigType.ServiceSidInfo,
3359 Argument = sid,
3360 Component_ = componentId,
3361 };
3362
3363 this.Core.AddTuple(tuple);
3364 //var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.MsiServiceConfig, new Identifier(String.Concat(id.Id, ".SS"), id.Access));
3365 //row.Set(1, name);
3366 //row.Set(2, events);
3367 //row.Set(3, 5);
3368 //row.Set(4, sid);
3369 //row.Set(5, componentId);
3370 }
3371
3372 if (!String.IsNullOrEmpty(requiredPrivileges))
3373 {
3374 var tuple = new MsiServiceConfigTuple(sourceLineNumbers, new Identifier(String.Concat(id.Id, ".RP"), id.Access))
3375 {
3376 Name = name,
3377 OnInstall = install,
3378 OnReinstall = reinstall,
3379 OnUninstall = uninstall,
3380 ConfigType = MsiServiceConfigType.RequiredPrivilegesInfo,
3381 Argument = requiredPrivileges,
3382 Component_ = componentId,
3383 };
3384
3385 this.Core.AddTuple(tuple);
3386 //var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.MsiServiceConfig, new Identifier(String.Concat(id.Id, ".RP"), id.Access));
3387 //row.Set(1, name);
3388 //row.Set(2, events);
3389 //row.Set(3, 6);
3390 //row.Set(4, requiredPrivileges);
3391 //row.Set(5, componentId);
3392 }
3393
3394 if (!String.IsNullOrEmpty(preShutdownDelay))
3395 {
3396 var tuple = new MsiServiceConfigTuple(sourceLineNumbers, new Identifier(String.Concat(id.Id, ".PD"), id.Access))
3397 {
3398 Name = name,
3399 OnInstall = install,
3400 OnReinstall = reinstall,
3401 OnUninstall = uninstall,
3402 ConfigType = MsiServiceConfigType.PreshutdownInfo,
3403 Argument = preShutdownDelay,
3404 Component_ = componentId,
3405 };
3406
3407 this.Core.AddTuple(tuple);
3408 //var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.MsiServiceConfig, new Identifier(String.Concat(id.Id, ".PD"), id.Access));
3409 //row.Set(1, name);
3410 //row.Set(2, events);
3411 //row.Set(3, 7);
3412 //row.Set(4, preShutdownDelay);
3413 //row.Set(5, componentId);
3414 }
3415 }
3416 }
3417
3418 /// <summary>
3419 /// Parses a service config failure actions element.
3420 /// </summary>
3421 /// <param name="node">Element to parse.</param>
3422 /// <param name="componentId">Identifier of parent component.</param>
3423 /// <param name="serviceName">Optional element containing parent's service name.</param>
3424 private void ParseServiceConfigFailureActionsElement(XElement node, string componentId, string serviceName)
3425 {
3426 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
3427 Identifier id = null;
3428 var name = serviceName;
3429 var install = false;
3430 var reinstall = false;
3431 var uninstall = false;
3432 int? resetPeriod = null;
3433 string rebootMessage = null;
3434 string command = null;
3435 string actions = null;
3436 string actionsDelays = null;
3437
3438 this.Core.Write(WarningMessages.ServiceConfigFamilyNotSupported(sourceLineNumbers, node.Name.LocalName));
3439
3440 foreach (var attrib in node.Attributes())
3441 {
3442 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace)
3443 {
3444 switch (attrib.Name.LocalName)
3445 {
3446 case "Id":
3447 id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib);
3448 break;
3449 case "Command":
3450 command = this.Core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.CanBeEmpty);
3451 break;
3452 case "OnInstall":
3453 install = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
3454 break;
3455 case "OnReinstall":
3456 reinstall = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
3457 break;
3458 case "OnUninstall":
3459 uninstall = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
3460 break;
3461 case "RebootMessage":
3462 rebootMessage = this.Core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.CanBeEmpty);
3463 break;
3464 case "ResetPeriod":
3465 resetPeriod = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int32.MaxValue);
3466 break;
3467 case "ServiceName":
3468 if (!String.IsNullOrEmpty(serviceName))
3469 {
3470 this.Core.Write(ErrorMessages.IllegalAttributeWhenNested(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "ServiceInstall"));
3471 }
3472
3473 name = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
3474 break;
3475 default:
3476 this.Core.UnexpectedAttribute(node, attrib);
3477 break;
3478 }
3479 }
3480 else
3481 {
3482 this.Core.ParseExtensionAttribute(node, attrib);
3483 }
3484 }
3485
3486 // Get the ServiceConfigFailureActions actions.
3487 foreach (var child in node.Elements())
3488 {
3489 if (CompilerCore.WixNamespace == child.Name.Namespace)
3490 {
3491 switch (child.Name.LocalName)
3492 {
3493 case "Failure":
3494 string action = null;
3495 string delay = null;
3496 var childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(child);
3497
3498 foreach (var childAttrib in child.Attributes())
3499 {
3500 if (String.IsNullOrEmpty(childAttrib.Name.NamespaceName) || CompilerCore.WixNamespace == childAttrib.Name.Namespace)
3501 {
3502 switch (childAttrib.Name.LocalName)
3503 {
3504 case "Action":
3505 action = this.Core.GetAttributeValue(childSourceLineNumbers, childAttrib);
3506 switch (action)
3507 {
3508 case "none":
3509 action = "0";
3510 break;
3511 case "restartComputer":
3512 action = "2";
3513 break;
3514 case "restartService":
3515 action = "1";
3516 break;
3517 case "runCommand":
3518 action = "3";
3519 break;
3520 default:
3521 // allow everything else to pass through that are hopefully "formatted" Properties.
3522 break;
3523 }
3524 break;
3525 case "Delay":
3526 delay = this.Core.GetAttributeValue(childSourceLineNumbers, childAttrib);
3527 break;
3528 default:
3529 this.Core.UnexpectedAttribute(child, childAttrib);
3530 break;
3531 }
3532 }
3533 }
3534
3535 if (String.IsNullOrEmpty(action))
3536 {
3537 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, child.Name.LocalName, "Action"));
3538 }
3539
3540 if (String.IsNullOrEmpty(delay))
3541 {
3542 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, child.Name.LocalName, "Delay"));
3543 }
3544
3545 if (!String.IsNullOrEmpty(actions))
3546 {
3547 actions = String.Concat(actions, "[~]");
3548 }
3549 actions = String.Concat(actions, action);
3550
3551 if (!String.IsNullOrEmpty(actionsDelays))
3552 {
3553 actionsDelays = String.Concat(actionsDelays, "[~]");
3554 }
3555 actionsDelays = String.Concat(actionsDelays, delay);
3556 break;
3557 default:
3558 this.Core.UnexpectedElement(node, child);
3559 break;
3560 }
3561 }
3562 else
3563 {
3564 this.Core.ParseExtensionElement(node, child);
3565 }
3566 }
3567
3568 if (String.IsNullOrEmpty(name))
3569 {
3570 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "ServiceName"));
3571 }
3572 else if (null == id)
3573 {
3574 id = this.Core.CreateIdentifierFromFilename(name);
3575 }
3576
3577 if (!install && !reinstall && !uninstall)
3578 {
3579 this.Core.Write(ErrorMessages.ExpectedAttributes(sourceLineNumbers, node.Name.LocalName, "OnInstall", "OnReinstall", "OnUninstall"));
3580 }
3581
3582 if (!this.Core.EncounteredError)
3583 {
3584 var tuple = new MsiServiceConfigFailureActionsTuple(sourceLineNumbers, id)
3585 {
3586 Name = name,
3587 OnInstall = install,
3588 OnReinstall = reinstall,
3589 OnUninstall = uninstall,
3590 ResetPeriod = resetPeriod,
3591 RebootMessage = rebootMessage,
3592 Command = command,
3593 Actions = actions,
3594 DelayActions = actionsDelays,
3595 Component_ = componentId,
3596 };
3597
3598 this.Core.AddTuple(tuple);
3599 }
3600 }
3601
3602 /// <summary>
3603 /// Parses a service control element.
3604 /// </summary>
3605 /// <param name="node">Element to parse.</param>
3606 /// <param name="componentId">Identifier of parent component.</param>
3607 private void ParseServiceControlElement(XElement node, string componentId)
3608 {
3609 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
3610 string arguments = null;
3611 Identifier id = null;
3612 string name = null;
3613 var installRemove = false;
3614 var uninstallRemove = false;
3615 var installStart = false;
3616 var uninstallStart = false;
3617 var installStop = false;
3618 var uninstallStop = false;
3619 bool? wait = null;
3620
3621 foreach (var attrib in node.Attributes())
3622 {
3623 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace)
3624 {
3625 switch (attrib.Name.LocalName)
3626 {
3627 case "Id":
3628 id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib);
3629 break;
3630 case "Name":
3631 name = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
3632 break;
3633 case "Remove":
3634 var removeValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
3635 switch (removeValue)
3636 {
3637 case "install":
3638 installRemove = true;
3639 break;
3640 case "uninstall":
3641 uninstallRemove = true;
3642 break;
3643 case "both":
3644 installRemove = true;
3645 uninstallRemove = true;
3646 break;
3647 case "":
3648 break;
3649 }
3650 break;
3651 case "Start":
3652 var startValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
3653 switch (startValue)
3654 {
3655 case "install":
3656 installStart = true;
3657 break;
3658 case "uninstall":
3659 uninstallStart = true;
3660 break;
3661 case "both":
3662 installStart = true;
3663 uninstallStart = true;
3664 break;
3665 case "":
3666 break;
3667 }
3668 break;
3669 case "Stop":
3670 var stopValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
3671 switch (stopValue)
3672 {
3673 case "install":
3674 installStop = true;
3675 break;
3676 case "uninstall":
3677 uninstallStop = true;
3678 break;
3679 case "both":
3680 installStop = true;
3681 uninstallStop = true;
3682 break;
3683 case "":
3684 break;
3685 }
3686 break;
3687 case "Wait":
3688 wait = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
3689 break;
3690 default:
3691 this.Core.UnexpectedAttribute(node, attrib);
3692 break;
3693 }
3694 }
3695 else
3696 {
3697 this.Core.ParseExtensionAttribute(node, attrib);
3698 }
3699 }
3700
3701 if (null == id)
3702 {
3703 id = this.Core.CreateIdentifierFromFilename(name);
3704 }
3705
3706 if (null == name)
3707 {
3708 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Name"));
3709 }
3710
3711 // get the ServiceControl arguments
3712 foreach (var child in node.Elements())
3713 {
3714 if (CompilerCore.WixNamespace == child.Name.Namespace)
3715 {
3716 switch (child.Name.LocalName)
3717 {
3718 case "ServiceArgument":
3719 if (null != arguments)
3720 {
3721 arguments = String.Concat(arguments, "[~]");
3722 }
3723 arguments = String.Concat(arguments, this.Core.GetTrimmedInnerText(child));
3724 break;
3725 default:
3726 this.Core.UnexpectedElement(node, child);
3727 break;
3728 }
3729 }
3730 else
3731 {
3732 this.Core.ParseExtensionElement(node, child);
3733 }
3734 }
3735
3736 if (!this.Core.EncounteredError)
3737 {
3738 var tuple = new ServiceControlTuple(sourceLineNumbers, id)
3739 {
3740 Name = name,
3741 InstallRemove = installRemove,
3742 UninstallRemove = uninstallRemove,
3743 InstallStart = installStart,
3744 UninstallStart = uninstallStart,
3745 InstallStop = installStop,
3746 UninstallStop = uninstallStop,
3747 Arguments = arguments,
3748 Wait = wait,
3749 Component_ = componentId
3750 };
3751
3752 this.Core.AddTuple(tuple);
3753 }
3754 }
3755
3756 /// <summary>
3757 /// Parses a service dependency element.
3758 /// </summary>
3759 /// <param name="node">Element to parse.</param>
3760 /// <returns>Parsed sevice dependency name.</returns>
3761 private string ParseServiceDependencyElement(XElement node)
3762 {
3763 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
3764 string dependency = null;
3765 var group = false;
3766
3767 foreach (var attrib in node.Attributes())
3768 {
3769 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace)
3770 {
3771 switch (attrib.Name.LocalName)
3772 {
3773 case "Id":
3774 dependency = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
3775 break;
3776 case "Group":
3777 group = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
3778 break;
3779 default:
3780 this.Core.UnexpectedAttribute(node, attrib);
3781 break;
3782 }
3783 }
3784 else
3785 {
3786 this.Core.ParseExtensionAttribute(node, attrib);
3787 }
3788 }
3789
3790 if (null == dependency)
3791 {
3792 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id"));
3793 }
3794
3795 this.Core.ParseForExtensionElements(node);
3796
3797 return group ? String.Concat("+", dependency) : dependency;
3798 }
3799
3800 /// <summary>
3801 /// Parses a service install element.
3802 /// </summary>
3803 /// <param name="node">Element to parse.</param>
3804 /// <param name="componentId">Identifier of parent component.</param>
3805 private void ParseServiceInstallElement(XElement node, string componentId, bool win64Component)
3806 {
3807 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
3808 Identifier id = null;
3809 string account = null;
3810 string arguments = null;
3811 string dependencies = null;
3812 string description = null;
3813 string displayName = null;
3814 var eraseDescription = false;
3815 string loadOrderGroup = null;
3816 string name = null;
3817 string password = null;
3818
3819 var serviceType = ServiceType.OwnProcess;
3820 var startType = ServiceStartType.Demand;
3821 var errorControl = ServiceErrorControl.Normal;
3822 var interactive = false;
3823 var vital = false;
3824
3825 foreach (var attrib in node.Attributes())
3826 {
3827 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace)
3828 {
3829 switch (attrib.Name.LocalName)
3830 {
3831 case "Id":
3832 id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib);
3833 break;
3834 case "Account":
3835 account = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
3836 break;
3837 case "Arguments":
3838 arguments = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
3839 break;
3840 case "Description":
3841 description = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
3842 break;
3843 case "DisplayName":
3844 displayName = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
3845 break;
3846 case "EraseDescription":
3847 eraseDescription = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
3848 break;
3849 case "ErrorControl":
3850 var errorControlValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
3851 switch (errorControlValue)
3852 {
3853 case "ignore":
3854 errorControl = ServiceErrorControl.Ignore;
3855 break;
3856 case "normal":
3857 errorControl = ServiceErrorControl.Normal;
3858 break;
3859 case "critical":
3860 errorControl = ServiceErrorControl.Critical;
3861 break;
3862 case "": // error case handled by GetAttributeValue()
3863 break;
3864 default:
3865 this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, errorControlValue, "ignore", "normal", "critical"));
3866 break;
3867 }
3868 break;
3869 case "Interactive":
3870 interactive = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
3871 break;
3872 case "LoadOrderGroup":
3873 loadOrderGroup = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
3874 break;
3875 case "Name":
3876 name = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
3877 break;
3878 case "Password":
3879 password = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
3880 break;
3881 case "Start":
3882 var startValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
3883 switch (startValue)
3884 {
3885 case "auto":
3886 startType = ServiceStartType.Auto;
3887 break;
3888 case "demand":
3889 startType = ServiceStartType.Demand;
3890 break;
3891 case "disabled":
3892 startType = ServiceStartType.Disabled;
3893 break;
3894 case "boot":
3895 case "system":
3896 this.Core.Write(ErrorMessages.ValueNotSupported(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, startValue));
3897 break;
3898 case "":
3899 break;
3900 default:
3901 this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, startValue, "auto", "demand", "disabled"));
3902 break;
3903 }
3904 break;
3905 case "Type":
3906 var typeValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
3907 switch (typeValue)
3908 {
3909 case "ownProcess":
3910 serviceType = ServiceType.OwnProcess;
3911 break;
3912 case "shareProcess":
3913 serviceType = ServiceType.ShareProcess;
3914 break;
3915 case "kernelDriver":
3916 case "systemDriver":
3917 this.Core.Write(ErrorMessages.ValueNotSupported(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, typeValue));
3918 break;
3919 case "":
3920 break;
3921 default:
3922 this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, node.Name.LocalName, typeValue, "ownProcess", "shareProcess"));
3923 break;
3924 }
3925 break;
3926 case "Vital":
3927 vital = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
3928 break;
3929 default:
3930 this.Core.UnexpectedAttribute(node, attrib);
3931 break;
3932 }
3933 }
3934 else
3935 {
3936 this.Core.ParseExtensionAttribute(node, attrib);
3937 }
3938 }
3939
3940 if (String.IsNullOrEmpty(name))
3941 {
3942 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Name"));
3943 }
3944 else if (null == id)
3945 {
3946 id = this.Core.CreateIdentifierFromFilename(name);
3947 }
3948
3949 if (0 == startType)
3950 {
3951 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Start"));
3952 }
3953
3954 if (eraseDescription)
3955 {
3956 description = "[~]";
3957 }
3958
3959 // get the ServiceInstall dependencies and config
3960 foreach (var child in node.Elements())
3961 {
3962 if (CompilerCore.WixNamespace == child.Name.Namespace)
3963 {
3964 switch (child.Name.LocalName)
3965 {
3966 case "PermissionEx":
3967 this.ParsePermissionExElement(child, id.Id, "ServiceInstall");
3968 break;
3969 case "ServiceConfig":
3970 this.ParseServiceConfigElement(child, componentId, name);
3971 break;
3972 case "ServiceConfigFailureActions":
3973 this.ParseServiceConfigFailureActionsElement(child, componentId, name);
3974 break;
3975 case "ServiceDependency":
3976 dependencies = String.Concat(dependencies, this.ParseServiceDependencyElement(child), "[~]");
3977 break;
3978 default:
3979 this.Core.UnexpectedElement(node, child);
3980 break;
3981 }
3982 }
3983 else
3984 {
3985 var context = new Dictionary<string, string>() { { "ServiceInstallId", id.Id }, { "ServiceInstallName", name }, { "ServiceInstallComponentId", componentId }, { "Win64", win64Component.ToString() } };
3986 this.Core.ParseExtensionElement(node, child, context);
3987 }
3988 }
3989
3990 if (null != dependencies)
3991 {
3992 dependencies = String.Concat(dependencies, "[~]");
3993 }
3994
3995 if (!this.Core.EncounteredError)
3996 {
3997 var tuple = new ServiceInstallTuple(sourceLineNumbers, id)
3998 {
3999 Name = name,
4000 DisplayName = displayName,
4001 ServiceType = serviceType,
4002 StartType = startType,
4003 ErrorControl = errorControl,
4004 LoadOrderGroup = loadOrderGroup,
4005 Dependencies = dependencies,
4006 StartName = account,
4007 Password = password,
4008 Arguments = arguments,
4009 Component_ = componentId,
4010 Description = description,
4011 Interactive = interactive,
4012 Vital = vital
4013 };
4014
4015 this.Core.AddTuple(tuple);
4016
4017 //var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.ServiceInstall, id);
4018 //row.Set(1, name);
4019 //row.Set(2, displayName);
4020 //row.Set(3, typebits);
4021 //row.Set(4, startType);
4022 //row.Set(5, errorbits);
4023 //row.Set(6, loadOrderGroup);
4024 //row.Set(7, dependencies);
4025 //row.Set(8, account);
4026 //row.Set(9, password);
4027 //row.Set(10, arguments);
4028 //row.Set(11, componentId);
4029 //row.Set(12, description);
4030 }
4031 }
4032
4033 /// <summary>
4034 /// Parses a SetDirectory element.
4035 /// </summary>
4036 /// <param name="node">Element to parse.</param>
4037 private void ParseSetDirectoryElement(XElement node)
4038 {
4039 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
4040 string actionName = null;
4041 string id = null;
4042 string condition = null;
4043 var executionType = CustomActionExecutionType.Immediate;
4044 var sequences = new[] { SequenceTable.InstallUISequence, SequenceTable.InstallExecuteSequence }; // default to "both"
4045 string value = null;
4046
4047 foreach (var attrib in node.Attributes())
4048 {
4049 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace)
4050 {
4051 switch (attrib.Name.LocalName)
4052 {
4053 case "Action":
4054 actionName = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
4055 break;
4056 case "Id":
4057 id = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
4058 this.Core.CreateSimpleReference(sourceLineNumbers, "Directory", id);
4059 break;
4060 case "Sequence":
4061 var sequenceValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
4062 switch (sequenceValue)
4063 {
4064 case "execute":
4065 sequences = new[] { SequenceTable.InstallExecuteSequence };
4066 break;
4067 case "first":
4068 executionType = CustomActionExecutionType.FirstSequence;
4069 break;
4070 case "ui":
4071 sequences = new[] { SequenceTable.InstallUISequence };
4072 break;
4073 case "both":
4074 break;
4075 case "":
4076 break;
4077 default:
4078 this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, sequenceValue, "execute", "ui", "both"));
4079 break;
4080 }
4081 break;
4082 case "Value":
4083 value = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
4084 break;
4085 default:
4086 this.Core.UnexpectedAttribute(node, attrib);
4087 break;
4088 }
4089 }
4090 else
4091 {
4092 this.Core.ParseExtensionAttribute(node, attrib);
4093 }
4094 }
4095
4096 condition = this.Core.GetConditionInnerText(node);
4097
4098 if (null == id)
4099 {
4100 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id"));
4101 }
4102 else if (String.IsNullOrEmpty(actionName))
4103 {
4104 actionName = String.Concat("Set", id);
4105 }
4106
4107 if (null == value)
4108 {
4109 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Value"));
4110 }
4111
4112 this.Core.ParseForExtensionElements(node);
4113
4114 if (!this.Core.EncounteredError)
4115 {
4116 var tuple = new CustomActionTuple(sourceLineNumbers, new Identifier(AccessModifier.Public, actionName))
4117 {
4118 ExecutionType = executionType,
4119 SourceType = CustomActionSourceType.Directory,
4120 TargetType = CustomActionTargetType.TextData,
4121 Source = id,
4122 Target = value
4123 };
4124
4125 this.Core.AddTuple(tuple);
4126
4127 foreach (var sequence in sequences)
4128 {
4129 var sequenceId = new Identifier(AccessModifier.Public, sequence.ToString(), actionName);
4130
4131 var sequenceTuple = new WixActionTuple(sourceLineNumbers, sequenceId)
4132 {
4133 SequenceTable = sequence,
4134 Action = actionName,
4135 Condition = condition,
4136 After = "CostInialize",
4137 Overridable = false
4138 };
4139
4140 this.Core.AddTuple(tuple);
4141 }
4142 }
4143 }
4144
4145 /// <summary>
4146 /// Parses a SetProperty element.
4147 /// </summary>
4148 /// <param name="node">Element to parse.</param>
4149 private void ParseSetPropertyElement(XElement node)
4150 {
4151 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
4152 string actionName = null;
4153 string id = null;
4154 string afterAction = null;
4155 string beforeAction = null;
4156 var executionType = CustomActionExecutionType.Immediate;
4157 var sequences = new[] { SequenceTable.InstallUISequence, SequenceTable.InstallExecuteSequence }; // default to "both"
4158 string value = null;
4159
4160 foreach (var attrib in node.Attributes())
4161 {
4162 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace)
4163 {
4164 switch (attrib.Name.LocalName)
4165 {
4166 case "Action":
4167 actionName = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
4168 break;
4169 case "Id":
4170 id = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
4171 break;
4172 case "After":
4173 afterAction = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
4174 break;
4175 case "Before":
4176 beforeAction = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
4177 break;
4178 case "Sequence":
4179 var sequenceValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
4180 switch (sequenceValue)
4181 {
4182 case "execute":
4183 sequences = new[] { SequenceTable.InstallExecuteSequence };
4184 break;
4185 case "first":
4186 executionType = CustomActionExecutionType.FirstSequence;
4187 break;
4188 case "ui":
4189 sequences = new[] { SequenceTable.InstallUISequence };
4190 break;
4191 case "both":
4192 break;
4193 case "":
4194 break;
4195 default:
4196 this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, sequenceValue, "execute", "ui", "both"));
4197 break;
4198 }
4199 //if (0 < sequenceValue.Length)
4200 //{
4201 // var sequenceType = Wix.Enums.ParseSequenceType(sequenceValue);
4202 // switch (sequenceType)
4203 // {
4204 // case Wix.SequenceType.execute:
4205 // sequences = new string[] { "InstallExecuteSequence" };
4206 // break;
4207 // case Wix.SequenceType.ui:
4208 // sequences = new string[] { "InstallUISequence" };
4209 // break;
4210 // case Wix.SequenceType.first:
4211 // firstSequence = true;
4212 // // default puts it in both sequence which is what we want
4213 // break;
4214 // case Wix.SequenceType.both:
4215 // // default so no work necessary.
4216 // break;
4217 // default:
4218 // this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, sequenceValue, "execute", "ui", "both"));
4219 // break;
4220 // }
4221 //}
4222 break;
4223 case "Value":
4224 value = this.Core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.CanBeEmpty);
4225 break;
4226 default:
4227 this.Core.UnexpectedAttribute(node, attrib);
4228 break;
4229 }
4230 }
4231 else
4232 {
4233 this.Core.ParseExtensionAttribute(node, attrib);
4234 }
4235 }
4236
4237 var condition = this.Core.GetConditionInnerText(node);
4238
4239 if (null == id)
4240 {
4241 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id"));
4242 }
4243 else if (String.IsNullOrEmpty(actionName))
4244 {
4245 actionName = String.Concat("Set", id);
4246 }
4247
4248 if (null == value)
4249 {
4250 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Value"));
4251 }
4252
4253 if (null != beforeAction && null != afterAction)
4254 {
4255 this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "After", "Before"));
4256 }
4257 else if (null == beforeAction && null == afterAction)
4258 {
4259 this.Core.Write(ErrorMessages.ExpectedAttributesWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "After", "Before", "Id"));
4260 }
4261
4262 this.Core.ParseForExtensionElements(node);
4263
4264 // add the row and any references needed
4265 if (!this.Core.EncounteredError)
4266 {
4267 // action that is scheduled to occur before/after itself
4268 if (beforeAction == actionName)
4269 {
4270 this.Core.Write(ErrorMessages.ActionScheduledRelativeToItself(sourceLineNumbers, node.Name.LocalName, "Before", beforeAction));
4271 }
4272 else if (afterAction == actionName)
4273 {
4274 this.Core.Write(ErrorMessages.ActionScheduledRelativeToItself(sourceLineNumbers, node.Name.LocalName, "After", afterAction));
4275 }
4276
4277 var tuple = new CustomActionTuple(sourceLineNumbers, new Identifier(AccessModifier.Public, actionName))
4278 {
4279 ExecutionType = executionType,
4280 SourceType = CustomActionSourceType.Property,
4281 TargetType = CustomActionTargetType.TextData,
4282 Source = id,
4283 Target = value
4284 };
4285
4286 this.Core.AddTuple(tuple);
4287
4288 foreach (var sequence in sequences)
4289 {
4290 var sequenceId = new Identifier(AccessModifier.Public, sequence.ToString(), actionName);
4291
4292 var sequenceTuple = new WixActionTuple(sourceLineNumbers, sequenceId)
4293 {
4294 SequenceTable = sequence,
4295 Action = actionName,
4296 Condition = condition,
4297 Before = beforeAction,
4298 After = afterAction,
4299 Overridable = false
4300 };
4301
4302 this.Core.AddTuple(tuple);
4303
4304 if (null != beforeAction)
4305 {
4306 if (WindowsInstallerStandard.IsStandardAction(beforeAction))
4307 {
4308 this.Core.CreateSimpleReference(sourceLineNumbers, "WixAction", sequence.ToString(), beforeAction);
4309 }
4310 else
4311 {
4312 this.Core.CreateSimpleReference(sourceLineNumbers, "CustomAction", beforeAction);
4313 }
4314 }
4315
4316 if (null != afterAction)
4317 {
4318 if (WindowsInstallerStandard.IsStandardAction(afterAction))
4319 {
4320 this.Core.CreateSimpleReference(sourceLineNumbers, "WixAction", sequence.ToString(), afterAction);
4321 }
4322 else
4323 {
4324 this.Core.CreateSimpleReference(sourceLineNumbers, "CustomAction", afterAction);
4325 }
4326 }
4327 }
4328 }
4329 }
4330
4331 /// <summary>
4332 /// Parses a SFP catalog element.
4333 /// </summary>
4334 /// <param name="node">Element to parse.</param>
4335 /// <param name="parentSFPCatalog">Parent SFPCatalog.</param>
4336 private void ParseSFPFileElement(XElement node, string parentSFPCatalog)
4337 {
4338 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
4339 string id = null;
4340
4341 foreach (var attrib in node.Attributes())
4342 {
4343 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace)
4344 {
4345 switch (attrib.Name.LocalName)
4346 {
4347 case "Id":
4348 id = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
4349 break;
4350 default:
4351 this.Core.UnexpectedAttribute(node, attrib);
4352 break;
4353 }
4354 }
4355 else
4356 {
4357 this.Core.ParseExtensionAttribute(node, attrib);
4358 }
4359 }
4360
4361 if (null == id)
4362 {
4363 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id"));
4364 }
4365
4366 this.Core.ParseForExtensionElements(node);
4367
4368 if (!this.Core.EncounteredError)
4369 {
4370 var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.FileSFPCatalog);
4371 row.Set(0, id);
4372 row.Set(1, parentSFPCatalog);
4373 }
4374 }
4375
4376 /// <summary>
4377 /// Parses a SFP catalog element.
4378 /// </summary>
4379 /// <param name="node">Element to parse.</param>
4380 /// <param name="parentSFPCatalog">Parent SFPCatalog.</param>
4381 private void ParseSFPCatalogElement(XElement node, ref string parentSFPCatalog)
4382 {
4383 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
4384 string parentName = null;
4385 string dependency = null;
4386 string name = null;
4387 string sourceFile = null;
4388
4389 foreach (var attrib in node.Attributes())
4390 {
4391 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace)
4392 {
4393 switch (attrib.Name.LocalName)
4394 {
4395 case "Dependency":
4396 dependency = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
4397 break;
4398 case "Name":
4399 name = this.Core.GetAttributeShortFilename(sourceLineNumbers, attrib, false);
4400 parentSFPCatalog = name;
4401 break;
4402 case "SourceFile":
4403 sourceFile = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
4404 break;
4405 default:
4406 this.Core.UnexpectedAttribute(node, attrib);
4407 break;
4408 }
4409 }
4410 else
4411 {
4412 this.Core.ParseExtensionAttribute(node, attrib);
4413 }
4414 }
4415
4416 if (null == name)
4417 {
4418 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Name"));
4419 }
4420
4421 if (null == sourceFile)
4422 {
4423 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "SourceFile"));
4424 }
4425
4426 foreach (var child in node.Elements())
4427 {
4428 if (CompilerCore.WixNamespace == child.Name.Namespace)
4429 {
4430 switch (child.Name.LocalName)
4431 {
4432 case "SFPCatalog":
4433 this.ParseSFPCatalogElement(child, ref parentName);
4434 if (null != dependency && parentName == dependency)
4435 {
4436 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Dependency"));
4437 }
4438 dependency = parentName;
4439 break;
4440 case "SFPFile":
4441 this.ParseSFPFileElement(child, name);
4442 break;
4443 default:
4444 this.Core.UnexpectedElement(node, child);
4445 break;
4446 }
4447 }
4448 else
4449 {
4450 this.Core.ParseExtensionElement(node, child);
4451 }
4452 }
4453
4454 if (null == dependency)
4455 {
4456 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Dependency"));
4457 }
4458
4459 if (!this.Core.EncounteredError)
4460 {
4461 var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.SFPCatalog);
4462 row.Set(0, name);
4463 row.Set(1, sourceFile);
4464 row.Set(2, dependency);
4465 }
4466 }
4467
4468 /// <summary>
4469 /// Parses a shortcut element.
4470 /// </summary>
4471 /// <param name="node">Element to parse.</param>
4472 /// <param name="componentId">Identifer for parent component.</param>
4473 /// <param name="parentElementLocalName">Local name of parent element.</param>
4474 /// <param name="defaultTarget">Default identifier of parent (which is usually the target).</param>
4475 /// <param name="parentKeyPath">Flag to indicate whether the parent element is the keypath of a component or not (will only be true for file parent elements).</param>
4476 private void ParseShortcutElement(XElement node, string componentId, string parentElementLocalName, string defaultTarget, YesNoType parentKeyPath)
4477 {
4478 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
4479 Identifier id = null;
4480 var advertise = false;
4481 string arguments = null;
4482 string description = null;
4483 string descriptionResourceDll = null;
4484 int? descriptionResourceId = null;
4485 string directory = null;
4486 string displayResourceDll = null;
4487 int? displayResourceId = null;
4488 int? hotkey = null;
4489 string icon = null;
4490 int? iconIndex = null;
4491 string name = null;
4492 string shortName = null;
4493 ShortcutShowType? show = null;
4494 string target = null;
4495 string workingDirectory = null;
4496
4497 foreach (var attrib in node.Attributes())
4498 {
4499 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace)
4500 {
4501 switch (attrib.Name.LocalName)
4502 {
4503 case "Id":
4504 id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib);
4505 break;
4506 case "Advertise":
4507 advertise = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
4508 break;
4509 case "Arguments":
4510 arguments = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
4511 break;
4512 case "Description":
4513 description = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
4514 break;
4515 case "DescriptionResourceDll":
4516 descriptionResourceDll = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
4517 break;
4518 case "DescriptionResourceId":
4519 descriptionResourceId = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int16.MaxValue);
4520 break;
4521 case "Directory":
4522 directory = this.Core.CreateDirectoryReferenceFromInlineSyntax(sourceLineNumbers, attrib, null);
4523 break;
4524 case "DisplayResourceDll":
4525 displayResourceDll = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
4526 break;
4527 case "DisplayResourceId":
4528 displayResourceId = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int16.MaxValue);
4529 break;
4530 case "Hotkey":
4531 hotkey = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int16.MaxValue);
4532 break;
4533 case "Icon":
4534 icon = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
4535 this.Core.CreateSimpleReference(sourceLineNumbers, "Icon", icon);
4536 break;
4537 case "IconIndex":
4538 iconIndex = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, Int16.MinValue + 1, Int16.MaxValue);
4539 break;
4540 case "Name":
4541 name = this.Core.GetAttributeLongFilename(sourceLineNumbers, attrib, false);
4542 break;
4543 case "ShortName":
4544 shortName = this.Core.GetAttributeShortFilename(sourceLineNumbers, attrib, false);
4545 break;
4546 case "Show":
4547 var showValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
4548 switch (showValue)
4549 {
4550 case "normal":
4551 show = ShortcutShowType.Normal;
4552 break;
4553 case "maximized":
4554 show = ShortcutShowType.Maximized;
4555 break;
4556 case "minimized":
4557 show = ShortcutShowType.Minimized;
4558 break;
4559 case "":
4560 break;
4561 default:
4562 this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, "Show", showValue, "normal", "maximized", "minimized"));
4563 break;
4564 }
4565 //if (showValue.Length == 0)
4566 //{
4567 // show = CompilerConstants.IllegalInteger;
4568 //}
4569 //else
4570 //{
4571 // var showType = Wix.Shortcut.ParseShowType(showValue);
4572 // switch (showType)
4573 // {
4574 // case Wix.Shortcut.ShowType.normal:
4575 // show = 1;
4576 // break;
4577 // case Wix.Shortcut.ShowType.maximized:
4578 // show = 3;
4579 // break;
4580 // case Wix.Shortcut.ShowType.minimized:
4581 // show = 7;
4582 // break;
4583 // default:
4584 // this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, "Show", showValue, "normal", "maximized", "minimized"));
4585 // show = CompilerConstants.IllegalInteger;
4586 // break;
4587 // }
4588 //}
4589 break;
4590 case "Target":
4591 target = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
4592 break;
4593 case "WorkingDirectory":
4594 workingDirectory = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
4595 break;
4596 default:
4597 this.Core.UnexpectedAttribute(node, attrib);
4598 break;
4599 }
4600 }
4601 else
4602 {
4603 this.Core.ParseExtensionAttribute(node, attrib);
4604 }
4605 }
4606
4607 if (advertise && null != target)
4608 {
4609 this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Target", "Advertise", "yes"));
4610 }
4611
4612 if (null == directory)
4613 {
4614 if ("Component" == parentElementLocalName)
4615 {
4616 directory = defaultTarget;
4617 }
4618 else
4619 {
4620 this.Core.Write(ErrorMessages.ExpectedAttributeWhenElementNotUnderElement(sourceLineNumbers, node.Name.LocalName, "Directory", "Component"));
4621 }
4622 }
4623
4624 if (null != descriptionResourceDll)
4625 {
4626 if (!descriptionResourceId.HasValue)
4627 {
4628 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "DescriptionResourceDll", "DescriptionResourceId"));
4629 }
4630 }
4631 else
4632 {
4633 if (descriptionResourceId.HasValue)
4634 {
4635 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "DescriptionResourceId", "DescriptionResourceDll"));
4636 }
4637 }
4638
4639 if (null != displayResourceDll)
4640 {
4641 if (!displayResourceId.HasValue)
4642 {
4643 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "DisplayResourceDll", "DisplayResourceId"));
4644 }
4645 }
4646 else
4647 {
4648 if (displayResourceId.HasValue)
4649 {
4650 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "DisplayResourceId", "DisplayResourceDll"));
4651 }
4652 }
4653
4654 if (null == name)
4655 {
4656 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Name"));
4657 }
4658 else if (0 < name.Length)
4659 {
4660 if (this.Core.IsValidShortFilename(name, false))
4661 {
4662 if (null == shortName)
4663 {
4664 shortName = name;
4665 name = null;
4666 }
4667 else
4668 {
4669 this.Core.Write(ErrorMessages.IllegalAttributeValueWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Name", name, "ShortName"));
4670 }
4671 }
4672 else if (null == shortName) // generate a short file name.
4673 {
4674 shortName = this.Core.CreateShortName(name, true, false, node.Name.LocalName, componentId, directory);
4675 }
4676 }
4677
4678 if ("Component" != parentElementLocalName && null != target)
4679 {
4680 this.Core.Write(ErrorMessages.IllegalAttributeWhenNested(sourceLineNumbers, node.Name.LocalName, "Target", parentElementLocalName));
4681 }
4682
4683 if (null == id)
4684 {
4685 id = this.Core.CreateIdentifier("sct", directory, LowercaseOrNull(name) ?? LowercaseOrNull(shortName));
4686 }
4687
4688 foreach (var child in node.Elements())
4689 {
4690 if (CompilerCore.WixNamespace == child.Name.Namespace)
4691 {
4692 switch (child.Name.LocalName)
4693 {
4694 case "Icon":
4695 icon = this.ParseIconElement(child);
4696 break;
4697 case "ShortcutProperty":
4698 this.ParseShortcutPropertyElement(child, id.Id);
4699 break;
4700 default:
4701 this.Core.UnexpectedElement(node, child);
4702 break;
4703 }
4704 }
4705 else
4706 {
4707 this.Core.ParseExtensionElement(node, child);
4708 }
4709 }
4710
4711 if (!this.Core.EncounteredError)
4712 {
4713 if (advertise)
4714 {
4715 if (YesNoType.Yes != parentKeyPath && "Component" != parentElementLocalName)
4716 {
4717 this.Core.Write(WarningMessages.UnclearShortcut(sourceLineNumbers, id.Id, componentId, defaultTarget));
4718 }
4719
4720 target = Guid.Empty.ToString("B");
4721 }
4722 else if (null != target)
4723 {
4724 }
4725 else if ("Component" == parentElementLocalName || "CreateFolder" == parentElementLocalName)
4726 {
4727 target = String.Format(CultureInfo.InvariantCulture, "[{0}]", defaultTarget);
4728 }
4729 else if ("File" == parentElementLocalName)
4730 {
4731 target = String.Format(CultureInfo.InvariantCulture, "[#{0}]", defaultTarget);
4732 }
4733
4734 var tuple = new ShortcutTuple(sourceLineNumbers, id)
4735 {
4736 Directory_ = directory,
4737 Name = this.GetMsiFilenameValue(shortName, name),
4738 Component_ = componentId,
4739 Target = target,
4740 Arguments = arguments,
4741 Description = description,
4742 Hotkey = hotkey,
4743 Icon_ = icon,
4744 IconIndex = iconIndex,
4745 Show = show,
4746 WorkingDirectory = workingDirectory,
4747 DisplayResourceDll = displayResourceDll,
4748 DisplayResourceId = displayResourceId,
4749 DescriptionResourceDll = descriptionResourceDll,
4750 DescriptionResourceId = descriptionResourceId,
4751 };
4752
4753 this.Core.AddTuple(tuple);
4754
4755 //var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.Shortcut, id);
4756 //row.Set(1, directory);
4757 //row.Set(2, this.GetMsiFilenameValue(shortName, name));
4758 //row.Set(3, componentId);
4759 //if (advertise)
4760 //{
4761 // if (YesNoType.Yes != parentKeyPath && "Component" != parentElementLocalName)
4762 // {
4763 // this.Core.Write(WarningMessages.UnclearShortcut(sourceLineNumbers, id.Id, componentId, defaultTarget));
4764 // }
4765 // row.Set(4, Guid.Empty.ToString("B"));
4766 //}
4767 //else if (null != target)
4768 //{
4769 // row.Set(4, target);
4770 //}
4771 //else if ("Component" == parentElementLocalName || "CreateFolder" == parentElementLocalName)
4772 //{
4773 // row.Set(4, String.Format(CultureInfo.InvariantCulture, "[{0}]", defaultTarget));
4774 //}
4775 //else if ("File" == parentElementLocalName)
4776 //{
4777 // row.Set(4, String.Format(CultureInfo.InvariantCulture, "[#{0}]", defaultTarget));
4778 //}
4779 //row.Set(5, arguments);
4780 //row.Set(6, description);
4781 //if (CompilerConstants.IntegerNotSet != hotkey)
4782 //{
4783 // row.Set(7, hotkey);
4784 //}
4785 //row.Set(8, icon);
4786 //if (CompilerConstants.IntegerNotSet != iconIndex)
4787 //{
4788 // row.Set(9, iconIndex);
4789 //}
4790
4791 //if (show.HasValue)
4792 //{
4793 // row.Set(10, show.Value);
4794 //}
4795 //row.Set(11, workingDirectory);
4796 //row.Set(12, displayResourceDll);
4797 //if (CompilerConstants.IntegerNotSet != displayResourceId)
4798 //{
4799 // row.Set(13, displayResourceId);
4800 //}
4801 //row.Set(14, descriptionResourceDll);
4802 //if (CompilerConstants.IntegerNotSet != descriptionResourceId)
4803 //{
4804 // row.Set(15, descriptionResourceId);
4805 //}
4806 }
4807 }
4808
4809 /// <summary>
4810 /// Parses a shortcut property element.
4811 /// </summary>
4812 /// <param name="node">Element to parse.</param>
4813 private void ParseShortcutPropertyElement(XElement node, string shortcutId)
4814 {
4815 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
4816 Identifier id = null;
4817 string key = null;
4818 string value = null;
4819
4820 foreach (var attrib in node.Attributes())
4821 {
4822 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace)
4823 {
4824 switch (attrib.Name.LocalName)
4825 {
4826 case "Id":
4827 id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib);
4828 break;
4829 case "Key":
4830 key = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
4831 break;
4832 case "Value":
4833 value = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
4834 break;
4835 default:
4836 this.Core.UnexpectedAttribute(node, attrib);
4837 break;
4838 }
4839 }
4840 else
4841 {
4842 this.Core.ParseExtensionAttribute(node, attrib);
4843 }
4844 }
4845
4846 if (String.IsNullOrEmpty(key))
4847 {
4848 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Key"));
4849 }
4850 else if (null == id)
4851 {
4852 id = this.Core.CreateIdentifier("scp", shortcutId, key.ToUpperInvariant());
4853 }
4854
4855 var innerText = this.Core.GetTrimmedInnerText(node);
4856 if (!String.IsNullOrEmpty(innerText))
4857 {
4858 if (String.IsNullOrEmpty(value))
4859 {
4860 value = innerText;
4861 }
4862 else // cannot specify both the value attribute and inner text
4863 {
4864 this.Core.Write(ErrorMessages.IllegalAttributeWithInnerText(sourceLineNumbers, node.Name.LocalName, "Value"));
4865 }
4866 }
4867
4868 if (String.IsNullOrEmpty(value))
4869 {
4870 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Value"));
4871 }
4872
4873 this.Core.ParseForExtensionElements(node);
4874
4875 if (!this.Core.EncounteredError)
4876 {
4877 var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.MsiShortcutProperty, id);
4878 row.Set(1, shortcutId);
4879 row.Set(2, key);
4880 row.Set(3, value);
4881 }
4882 }
4883
4884 /// <summary>
4885 /// Parses a typelib element.
4886 /// </summary>
4887 /// <param name="node">Element to parse.</param>
4888 /// <param name="componentId">Identifier of parent component.</param>
4889 /// <param name="fileServer">Identifier of file that acts as typelib server.</param>
4890 /// <param name="win64Component">true if the component is 64-bit.</param>
4891 private void ParseTypeLibElement(XElement node, string componentId, string fileServer, bool win64Component)
4892 {
4893 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
4894 string id = null;
4895 var advertise = YesNoType.NotSet;
4896 var cost = CompilerConstants.IntegerNotSet;
4897 string description = null;
4898 var flags = 0;
4899 string helpDirectory = null;
4900 var language = CompilerConstants.IntegerNotSet;
4901 var majorVersion = CompilerConstants.IntegerNotSet;
4902 var minorVersion = CompilerConstants.IntegerNotSet;
4903 var resourceId = CompilerConstants.LongNotSet;
4904
4905 foreach (var attrib in node.Attributes())
4906 {
4907 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace)
4908 {
4909 switch (attrib.Name.LocalName)
4910 {
4911 case "Id":
4912 id = this.Core.GetAttributeGuidValue(sourceLineNumbers, attrib, false);
4913 break;
4914 case "Advertise":
4915 advertise = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
4916 break;
4917 case "Control":
4918 if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib))
4919 {
4920 flags |= 2;
4921 }
4922 break;
4923 case "Cost":
4924 cost = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int32.MaxValue);
4925 break;
4926 case "Description":
4927 description = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
4928 break;
4929 case "HasDiskImage":
4930 if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib))
4931 {
4932 flags |= 8;
4933 }
4934 break;
4935 case "HelpDirectory":
4936 helpDirectory = this.Core.CreateDirectoryReferenceFromInlineSyntax(sourceLineNumbers, attrib, null);
4937 break;
4938 case "Hidden":
4939 if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib))
4940 {
4941 flags |= 4;
4942 }
4943 break;
4944 case "Language":
4945 language = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int16.MaxValue);
4946 break;
4947 case "MajorVersion":
4948 majorVersion = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, UInt16.MaxValue);
4949 break;
4950 case "MinorVersion":
4951 minorVersion = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Byte.MaxValue);
4952 break;
4953 case "ResourceId":
4954 resourceId = this.Core.GetAttributeLongValue(sourceLineNumbers, attrib, Int32.MinValue, Int32.MaxValue);
4955 break;
4956 case "Restricted":
4957 if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib))
4958 {
4959 flags |= 1;
4960 }
4961 break;
4962 default:
4963 this.Core.UnexpectedAttribute(node, attrib);
4964 break;
4965 }
4966 }
4967 else
4968 {
4969 this.Core.ParseExtensionAttribute(node, attrib);
4970 }
4971 }
4972
4973 if (null == id)
4974 {
4975 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id"));
4976 }
4977
4978 if (CompilerConstants.IntegerNotSet == language)
4979 {
4980 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Language"));
4981 language = CompilerConstants.IllegalInteger;
4982 }
4983
4984 // build up the typelib version string for the registry if the major or minor version was specified
4985 string registryVersion = null;
4986 if (CompilerConstants.IntegerNotSet != majorVersion || CompilerConstants.IntegerNotSet != minorVersion)
4987 {
4988 if (CompilerConstants.IntegerNotSet != majorVersion)
4989 {
4990 registryVersion = majorVersion.ToString("x", CultureInfo.InvariantCulture.NumberFormat);
4991 }
4992 else
4993 {
4994 registryVersion = "0";
4995 }
4996
4997 if (CompilerConstants.IntegerNotSet != minorVersion)
4998 {
4999 registryVersion = String.Concat(registryVersion, ".", minorVersion.ToString("x", CultureInfo.InvariantCulture.NumberFormat));
5000 }
5001 else
5002 {
5003 registryVersion = String.Concat(registryVersion, ".0");
5004 }
5005 }
5006
5007 // if the advertise state has not been set, default to non-advertised
5008 if (YesNoType.NotSet == advertise)
5009 {
5010 advertise = YesNoType.No;
5011 }
5012
5013 foreach (var child in node.Elements())
5014 {
5015 if (CompilerCore.WixNamespace == child.Name.Namespace)
5016 {
5017 switch (child.Name.LocalName)
5018 {
5019 case "AppId":
5020 this.ParseAppIdElement(child, componentId, YesNoType.NotSet, fileServer, id, registryVersion);
5021 break;
5022 case "Class":
5023 this.ParseClassElement(child, componentId, YesNoType.NotSet, fileServer, id, registryVersion, null);
5024 break;
5025 case "Interface":
5026 this.ParseInterfaceElement(child, componentId, null, null, id, registryVersion);
5027 break;
5028 default:
5029 this.Core.UnexpectedElement(node, child);
5030 break;
5031 }
5032 }
5033 else
5034 {
5035 this.Core.ParseExtensionElement(node, child);
5036 }
5037 }
5038
5039
5040 if (YesNoType.Yes == advertise)
5041 {
5042 if (CompilerConstants.LongNotSet != resourceId)
5043 {
5044 this.Core.Write(ErrorMessages.IllegalAttributeWhenAdvertised(sourceLineNumbers, node.Name.LocalName, "ResourceId"));
5045 }
5046
5047 if (0 != flags)
5048 {
5049 if (0x1 == (flags & 0x1))
5050 {
5051 this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Restricted", "Advertise", "yes"));
5052 }
5053
5054 if (0x2 == (flags & 0x2))
5055 {
5056 this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Control", "Advertise", "yes"));
5057 }
5058
5059 if (0x4 == (flags & 0x4))
5060 {
5061 this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Hidden", "Advertise", "yes"));
5062 }
5063
5064 if (0x8 == (flags & 0x8))
5065 {
5066 this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "HasDiskImage", "Advertise", "yes"));
5067 }
5068 }
5069
5070 if (!this.Core.EncounteredError)
5071 {
5072 var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.TypeLib);
5073 row.Set(0, id);
5074 row.Set(1, language);
5075 row.Set(2, componentId);
5076 if (CompilerConstants.IntegerNotSet != majorVersion || CompilerConstants.IntegerNotSet != minorVersion)
5077 {
5078 row.Set(3, (CompilerConstants.IntegerNotSet != majorVersion ? majorVersion * 256 : 0) + (CompilerConstants.IntegerNotSet != minorVersion ? minorVersion : 0));
5079 }
5080 row.Set(4, description);
5081 row.Set(5, helpDirectory);
5082 row.Set(6, Guid.Empty.ToString("B"));
5083 if (CompilerConstants.IntegerNotSet != cost)
5084 {
5085 row.Set(7, cost);
5086 }
5087 }
5088 }
5089 else if (YesNoType.No == advertise)
5090 {
5091 if (CompilerConstants.IntegerNotSet != cost && CompilerConstants.IllegalInteger != cost)
5092 {
5093 this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Cost", "Advertise", "no"));
5094 }
5095
5096 if (null == fileServer)
5097 {
5098 this.Core.Write(ErrorMessages.MissingTypeLibFile(sourceLineNumbers, node.Name.LocalName, "File"));
5099 }
5100
5101 if (null == registryVersion)
5102 {
5103 this.Core.Write(ErrorMessages.ExpectedAttributesWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "MajorVersion", "MinorVersion", "Advertise", "no"));
5104 }
5105
5106 // HKCR\TypeLib\[ID]\[MajorVersion].[MinorVersion], (Default) = [Description]
5107 this.Core.CreateRegistryRow(sourceLineNumbers, RegistryRootType.ClassesRoot, String.Format(CultureInfo.InvariantCulture, @"TypeLib\{0}\{1}", id, registryVersion), null, description, componentId);
5108
5109 // HKCR\TypeLib\[ID]\[MajorVersion].[MinorVersion]\[Language]\[win16|win32|win64], (Default) = [TypeLibPath]\[ResourceId]
5110 var path = String.Concat("[#", fileServer, "]");
5111 if (CompilerConstants.LongNotSet != resourceId)
5112 {
5113 path = String.Concat(path, Path.DirectorySeparatorChar, resourceId.ToString(CultureInfo.InvariantCulture.NumberFormat));
5114 }
5115 this.Core.CreateRegistryRow(sourceLineNumbers, RegistryRootType.ClassesRoot, String.Format(CultureInfo.InvariantCulture, @"TypeLib\{0}\{1}\{2}\{3}", id, registryVersion, language, (win64Component ? "win64" : "win32")), null, path, componentId);
5116
5117 // HKCR\TypeLib\[ID]\[MajorVersion].[MinorVersion]\FLAGS, (Default) = [TypeLibFlags]
5118 this.Core.CreateRegistryRow(sourceLineNumbers, RegistryRootType.ClassesRoot, String.Format(CultureInfo.InvariantCulture, @"TypeLib\{0}\{1}\FLAGS", id, registryVersion), null, flags.ToString(CultureInfo.InvariantCulture.NumberFormat), componentId);
5119
5120 if (null != helpDirectory)
5121 {
5122 // HKCR\TypeLib\[ID]\[MajorVersion].[MinorVersion]\HELPDIR, (Default) = [HelpDirectory]
5123 this.Core.CreateRegistryRow(sourceLineNumbers, RegistryRootType.ClassesRoot, String.Format(CultureInfo.InvariantCulture, @"TypeLib\{0}\{1}\HELPDIR", id, registryVersion), null, String.Concat("[", helpDirectory, "]"), componentId);
5124 }
5125 }
5126 }
5127
5128 /// <summary>
5129 /// Parses an upgrade element.
5130 /// </summary>
5131 /// <param name="node">Element to parse.</param>
5132 private void ParseUpgradeElement(XElement node)
5133 {
5134 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
5135 string id = null;
5136
5137 foreach (var attrib in node.Attributes())
5138 {
5139 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace)
5140 {
5141 switch (attrib.Name.LocalName)
5142 {
5143 case "Id":
5144 id = this.Core.GetAttributeGuidValue(sourceLineNumbers, attrib, false);
5145 break;
5146 default:
5147 this.Core.UnexpectedAttribute(node, attrib);
5148 break;
5149 }
5150 }
5151 else
5152 {
5153 this.Core.ParseExtensionAttribute(node, attrib);
5154 }
5155 }
5156
5157 if (null == id)
5158 {
5159 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id"));
5160 }
5161
5162 // process the UpgradeVersion children here
5163 foreach (var child in node.Elements())
5164 {
5165 if (CompilerCore.WixNamespace == child.Name.Namespace)
5166 {
5167 var childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(child);
5168
5169 switch (child.Name.LocalName)
5170 {
5171 case "Property":
5172 this.ParsePropertyElement(child);
5173 this.Core.Write(WarningMessages.DeprecatedUpgradeProperty(childSourceLineNumbers));
5174 break;
5175 case "UpgradeVersion":
5176 this.ParseUpgradeVersionElement(child, id);
5177 break;
5178 default:
5179 this.Core.UnexpectedElement(node, child);
5180 break;
5181 }
5182 }
5183 else
5184 {
5185 this.Core.ParseExtensionElement(node, child);
5186 }
5187 }
5188
5189 // No rows created here. All row creation is done in ParseUpgradeVersionElement.
5190 }
5191
5192 /// <summary>
5193 /// Parse upgrade version element.
5194 /// </summary>
5195 /// <param name="node">Element to parse.</param>
5196 /// <param name="upgradeId">Upgrade code.</param>
5197 private void ParseUpgradeVersionElement(XElement node, string upgradeId)
5198 {
5199 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
5200
5201 string actionProperty = null;
5202 string language = null;
5203 string maximum = null;
5204 string minimum = null;
5205 var excludeLanguages = false;
5206 var ignoreFailures = false;
5207 var includeMax = false;
5208 var includeMin = true;
5209 var migrateFeatures = false;
5210 var onlyDetect = false;
5211 string removeFeatures = null;
5212
5213 foreach (var attrib in node.Attributes())
5214 {
5215 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace)
5216 {
5217 switch (attrib.Name.LocalName)
5218 {
5219 case "ExcludeLanguages":
5220 excludeLanguages = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
5221 break;
5222 case "IgnoreRemoveFailure":
5223 ignoreFailures = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
5224 break;
5225 case "IncludeMaximum":
5226 includeMax = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
5227 break;
5228 case "IncludeMinimum": // this is "yes" by default
5229 includeMin = YesNoType.No == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
5230 break;
5231 case "Language":
5232 language = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
5233 break;
5234 case "Minimum":
5235 minimum = this.Core.GetAttributeVersionValue(sourceLineNumbers, attrib);
5236 break;
5237 case "Maximum":
5238 maximum = this.Core.GetAttributeVersionValue(sourceLineNumbers, attrib);
5239 break;
5240 case "MigrateFeatures":
5241 migrateFeatures = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
5242 break;
5243 case "OnlyDetect":
5244 onlyDetect = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
5245 break;
5246 case "Property":
5247 actionProperty = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
5248 break;
5249 case "RemoveFeatures":
5250 removeFeatures = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
5251 break;
5252 default:
5253 this.Core.UnexpectedAttribute(node, attrib);
5254 break;
5255 }
5256 }
5257 else
5258 {
5259 this.Core.ParseExtensionAttribute(node, attrib);
5260 }
5261 }
5262
5263 if (null == actionProperty)
5264 {
5265 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Property"));
5266 }
5267 else if (actionProperty.ToUpper(CultureInfo.InvariantCulture) != actionProperty)
5268 {
5269 this.Core.Write(ErrorMessages.SecurePropertyNotUppercase(sourceLineNumbers, node.Name.LocalName, "Property", actionProperty));
5270 }
5271
5272 if (null == minimum && null == maximum)
5273 {
5274 this.Core.Write(ErrorMessages.ExpectedAttributes(sourceLineNumbers, node.Name.LocalName, "Minimum", "Maximum"));
5275 }
5276
5277 this.Core.ParseForExtensionElements(node);
5278
5279 if (!this.Core.EncounteredError)
5280 {
5281 var tuple = new UpgradeTuple(sourceLineNumbers)
5282 {
5283 UpgradeCode = upgradeId,
5284 VersionMin = minimum,
5285 VersionMax = maximum,
5286 Language = language,
5287 ExcludeLanguages = excludeLanguages,
5288 IgnoreRemoveFailures = ignoreFailures,
5289 VersionMaxInclusive = includeMax,
5290 VersionMinInclusive = includeMin,
5291 MigrateFeatures = migrateFeatures,
5292 OnlyDetect = onlyDetect,
5293 Remove = removeFeatures,
5294 ActionProperty = actionProperty
5295 };
5296
5297 this.Core.AddTuple(tuple);
5298
5299 // Ensure the action property is secure.
5300 this.AddWixPropertyRow(sourceLineNumbers, new Identifier(actionProperty, AccessModifier.Private), false, true, false);
5301
5302 // Ensure that RemoveExistingProducts is authored in InstallExecuteSequence
5303 // if at least one row in Upgrade table lacks the OnlyDetect attribute.
5304 if (onlyDetect)
5305 {
5306 this.Core.CreateSimpleReference(sourceLineNumbers, "WixAction", "InstallExecuteSequence", "RemoveExistingProducts");
5307 }
5308 }
5309 }
5310
5311 /// <summary>
5312 /// Parses a verb element.
5313 /// </summary>
5314 /// <param name="node">Element to parse.</param>
5315 /// <param name="extension">Extension verb is releated to.</param>
5316 /// <param name="progId">Optional progId for extension.</param>
5317 /// <param name="componentId">Identifier for parent component.</param>
5318 /// <param name="advertise">Flag if verb is advertised.</param>
5319 private void ParseVerbElement(XElement node, string extension, string progId, string componentId, YesNoType advertise)
5320 {
5321 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
5322 string id = null;
5323 string argument = null;
5324 string command = null;
5325 var sequence = CompilerConstants.IntegerNotSet;
5326 string target = null;
5327 string targetFile = null;
5328 string targetProperty = null;
5329
5330 foreach (var attrib in node.Attributes())
5331 {
5332 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace)
5333 {
5334 switch (attrib.Name.LocalName)
5335 {
5336 case "Id":
5337 id = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
5338 break;
5339 case "Argument":
5340 argument = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
5341 break;
5342 case "Command":
5343 command = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
5344 break;
5345 case "Sequence":
5346 sequence = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 1, Int16.MaxValue);
5347 break;
5348 case "Target":
5349 target = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
5350 this.Core.Write(WarningMessages.DeprecatedAttribute(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "TargetFile", "TargetProperty"));
5351 break;
5352 case "TargetFile":
5353 targetFile = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
5354 this.Core.CreateSimpleReference(sourceLineNumbers, "File", targetFile);
5355 break;
5356 case "TargetProperty":
5357 targetProperty = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
5358 break;
5359 default:
5360 this.Core.UnexpectedAttribute(node, attrib);
5361 break;
5362 }
5363 }
5364 else
5365 {
5366 this.Core.ParseExtensionAttribute(node, attrib);
5367 }
5368 }
5369
5370 if (null == id)
5371 {
5372 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id"));
5373 }
5374
5375 if (null != target && null != targetFile)
5376 {
5377 this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Target", "TargetFile"));
5378 }
5379
5380 if (null != target && null != targetProperty)
5381 {
5382 this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Target", "TargetProperty"));
5383 }
5384
5385 if (null != targetFile && null != targetProperty)
5386 {
5387 this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "TargetFile", "TargetProperty"));
5388 }
5389
5390 this.Core.ParseForExtensionElements(node);
5391
5392 if (YesNoType.Yes == advertise)
5393 {
5394 if (null != target)
5395 {
5396 this.Core.Write(ErrorMessages.IllegalAttributeWhenAdvertised(sourceLineNumbers, node.Name.LocalName, "Target"));
5397 }
5398
5399 if (null != targetFile)
5400 {
5401 this.Core.Write(ErrorMessages.IllegalAttributeWhenAdvertised(sourceLineNumbers, node.Name.LocalName, "TargetFile"));
5402 }
5403
5404 if (null != targetProperty)
5405 {
5406 this.Core.Write(ErrorMessages.IllegalAttributeWhenAdvertised(sourceLineNumbers, node.Name.LocalName, "TargetProperty"));
5407 }
5408
5409 if (!this.Core.EncounteredError)
5410 {
5411 var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.Verb);
5412 row.Set(0, extension);
5413 row.Set(1, id);
5414 if (CompilerConstants.IntegerNotSet != sequence)
5415 {
5416 row.Set(2, sequence);
5417 }
5418 row.Set(3, command);
5419 row.Set(4, argument);
5420 }
5421 }
5422 else if (YesNoType.No == advertise)
5423 {
5424 if (CompilerConstants.IntegerNotSet != sequence)
5425 {
5426 this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Sequence", "Advertise", "no"));
5427 }
5428
5429 if (null == target && null == targetFile && null == targetProperty)
5430 {
5431 this.Core.Write(ErrorMessages.ExpectedAttributesWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "TargetFile", "TargetProperty", "Advertise", "no"));
5432 }
5433
5434 if (null == target)
5435 {
5436 if (null != targetFile)
5437 {
5438 target = String.Concat("\"[#", targetFile, "]\"");
5439 }
5440
5441 if (null != targetProperty)
5442 {
5443 target = String.Concat("\"[", targetProperty, "]\"");
5444 }
5445 }
5446
5447 if (null != argument)
5448 {
5449 target = String.Concat(target, " ", argument);
5450 }
5451
5452 var prefix = (null != progId ? progId : String.Concat(".", extension));
5453
5454 if (null != command)
5455 {
5456 this.Core.CreateRegistryRow(sourceLineNumbers, RegistryRootType.ClassesRoot, String.Concat(prefix, "\\shell\\", id), String.Empty, command, componentId);
5457 }
5458
5459 this.Core.CreateRegistryRow(sourceLineNumbers, RegistryRootType.ClassesRoot, String.Concat(prefix, "\\shell\\", id, "\\command"), String.Empty, target, componentId);
5460 }
5461 }
5462
5463 /// <summary>
5464 /// Parses a Wix element.
5465 /// </summary>
5466 /// <param name="node">Element to parse.</param>
5467 private void ParseWixElement(XElement node)
5468 {
5469 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
5470 string requiredVersion = null;
5471
5472 foreach (var attrib in node.Attributes())
5473 {
5474 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace)
5475 {
5476 switch (attrib.Name.LocalName)
5477 {
5478 case "RequiredVersion":
5479 requiredVersion = this.Core.GetAttributeVersionValue(sourceLineNumbers, attrib);
5480 break;
5481 default:
5482 this.Core.UnexpectedAttribute(node, attrib);
5483 break;
5484 }
5485 }
5486 else
5487 {
5488 this.Core.ParseExtensionAttribute(node, attrib);
5489 }
5490 }
5491
5492 if (null != requiredVersion)
5493 {
5494 this.Core.VerifyRequiredVersion(sourceLineNumbers, requiredVersion);
5495 }
5496
5497 foreach (var child in node.Elements())
5498 {
5499 if (CompilerCore.WixNamespace == child.Name.Namespace)
5500 {
5501 switch (child.Name.LocalName)
5502 {
5503 case "Bundle":
5504 this.ParseBundleElement(child);
5505 break;
5506 case "Fragment":
5507 this.ParseFragmentElement(child);
5508 break;
5509 case "Module":
5510 this.ParseModuleElement(child);
5511 break;
5512 case "PatchCreation":
5513 this.ParsePatchCreationElement(child);
5514 break;
5515 case "Product":
5516 this.ParseProductElement(child);
5517 break;
5518 case "Patch":
5519 this.ParsePatchElement(child);
5520 break;
5521 default:
5522 this.Core.UnexpectedElement(node, child);
5523 break;
5524 }
5525 }
5526 else
5527 {
5528 this.Core.ParseExtensionElement(node, child);
5529 }
5530 }
5531 }
5532
5533 /// <summary>
5534 /// Parses a WixVariable element.
5535 /// </summary>
5536 /// <param name="node">Element to parse.</param>
5537 private void ParseWixVariableElement(XElement node)
5538 {
5539 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
5540 Identifier id = null;
5541 var overridable = false;
5542 string value = null;
5543
5544 foreach (var attrib in node.Attributes())
5545 {
5546 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace)
5547 {
5548 switch (attrib.Name.LocalName)
5549 {
5550 case "Id":
5551 id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib);
5552 break;
5553 case "Overridable":
5554 overridable = (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib));
5555 break;
5556 case "Value":
5557 value = this.Core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.CanBeEmpty);
5558 break;
5559 default:
5560 this.Core.UnexpectedAttribute(node, attrib);
5561 break;
5562 }
5563 }
5564 else
5565 {
5566 this.Core.ParseExtensionAttribute(node, attrib);
5567 }
5568 }
5569
5570 if (null == id)
5571 {
5572 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id"));
5573 }
5574
5575 if (null == value)
5576 {
5577 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Value"));
5578 }
5579
5580 this.Core.ParseForExtensionElements(node);
5581
5582 if (!this.Core.EncounteredError)
5583 {
5584 var wixVariableRow = (WixVariableTuple)this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixVariable, id);
5585 wixVariableRow.Value = value;
5586 wixVariableRow.Overridable = overridable;
5587 }
5588 }
5589
5590 private CompressionLevel? ParseCompressionLevel(SourceLineNumber sourceLineNumbers, XElement node, XAttribute attribute)
5591 {
5592 var compressionLevel = this.Core.GetAttributeValue(sourceLineNumbers, attribute);
5593 switch (compressionLevel)
5594 {
5595 case "high":
5596 return CompressionLevel.High;
5597 case "low":
5598 return CompressionLevel.Low;
5599 case "medium":
5600 return CompressionLevel.Medium;
5601 case "mszip":
5602 return CompressionLevel.Mszip;
5603 case "none":
5604 return CompressionLevel.None;
5605 case "":
5606 break;
5607 default:
5608 this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attribute.Name.LocalName, compressionLevel, "high", "low", "medium", "mszip", "none"));
5609 break;
5610 }
5611
5612 return null;
5613 }
5614 }
5615}