aboutsummaryrefslogtreecommitdiff
path: root/src/WixToolset.Converters/Wix3Converter.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/WixToolset.Converters/Wix3Converter.cs')
-rw-r--r--src/WixToolset.Converters/Wix3Converter.cs280
1 files changed, 279 insertions, 1 deletions
diff --git a/src/WixToolset.Converters/Wix3Converter.cs b/src/WixToolset.Converters/Wix3Converter.cs
index 9329bd13..27c29e4d 100644
--- a/src/WixToolset.Converters/Wix3Converter.cs
+++ b/src/WixToolset.Converters/Wix3Converter.cs
@@ -26,16 +26,43 @@ namespace WixToolset.Converters
26 private static readonly XNamespace WixNamespace = "http://wixtoolset.org/schemas/v4/wxs"; 26 private static readonly XNamespace WixNamespace = "http://wixtoolset.org/schemas/v4/wxs";
27 private static readonly XNamespace WixUtilNamespace = "http://wixtoolset.org/schemas/v4/wxs/util"; 27 private static readonly XNamespace WixUtilNamespace = "http://wixtoolset.org/schemas/v4/wxs/util";
28 28
29 private static readonly XName AdminExecuteSequenceElementName = WixNamespace + "AdminExecuteSequence";
30 private static readonly XName AdminUISequenceSequenceElementName = WixNamespace + "AdminUISequence";
31 private static readonly XName AdvertiseExecuteSequenceElementName = WixNamespace + "AdvertiseExecuteSequence";
32 private static readonly XName InstallExecuteSequenceElementName = WixNamespace + "InstallExecuteSequence";
33 private static readonly XName InstallUISequenceSequenceElementName = WixNamespace + "InstallUISequence";
34 private static readonly XName EmbeddedChainerElementName = WixNamespace + "EmbeddedChainer";
29 private static readonly XName ColumnElementName = WixNamespace + "Column"; 35 private static readonly XName ColumnElementName = WixNamespace + "Column";
36 private static readonly XName ComponentElementName = WixNamespace + "Component";
37 private static readonly XName ControlElementName = WixNamespace + "Control";
38 private static readonly XName ConditionElementName = WixNamespace + "Condition";
30 private static readonly XName CreateFolderElementName = WixNamespace + "CreateFolder"; 39 private static readonly XName CreateFolderElementName = WixNamespace + "CreateFolder";
31 private static readonly XName CustomTableElementName = WixNamespace + "CustomTable"; 40 private static readonly XName CustomTableElementName = WixNamespace + "CustomTable";
32 private static readonly XName DirectoryElementName = WixNamespace + "Directory"; 41 private static readonly XName DirectoryElementName = WixNamespace + "Directory";
42 private static readonly XName FeatureElementName = WixNamespace + "Feature";
33 private static readonly XName FileElementName = WixNamespace + "File"; 43 private static readonly XName FileElementName = WixNamespace + "File";
44 private static readonly XName FragmentElementName = WixNamespace + "Fragment";
45 private static readonly XName ErrorElementName = WixNamespace + "Error";
46 private static readonly XName LaunchElementName = WixNamespace + "Launch";
47 private static readonly XName LevelElementName = WixNamespace + "Level";
34 private static readonly XName ExePackageElementName = WixNamespace + "ExePackage"; 48 private static readonly XName ExePackageElementName = WixNamespace + "ExePackage";
35 private static readonly XName MsiPackageElementName = WixNamespace + "MsiPackage"; 49 private static readonly XName MsiPackageElementName = WixNamespace + "MsiPackage";
36 private static readonly XName MspPackageElementName = WixNamespace + "MspPackage"; 50 private static readonly XName MspPackageElementName = WixNamespace + "MspPackage";
37 private static readonly XName MsuPackageElementName = WixNamespace + "MsuPackage"; 51 private static readonly XName MsuPackageElementName = WixNamespace + "MsuPackage";
38 private static readonly XName PayloadElementName = WixNamespace + "Payload"; 52 private static readonly XName PayloadElementName = WixNamespace + "Payload";
53 private static readonly XName PermissionExElementName = WixNamespace + "PermissionEx";
54 private static readonly XName ProductElementName = WixNamespace + "Product";
55 private static readonly XName ProgressTextElementName = WixNamespace + "ProgressText";
56 private static readonly XName PublishElementName = WixNamespace + "Publish";
57 private static readonly XName MultiStringValueElementName = WixNamespace + "MultiStringValue";
58 private static readonly XName RequiredPrivilegeElementName = WixNamespace + "RequiredPrivilege";
59 private static readonly XName RowElementName = WixNamespace + "Row";
60 private static readonly XName ServiceArgumentElementName = WixNamespace + "ServiceArgument";
61 private static readonly XName SetDirectoryElementName = WixNamespace + "SetDirectory";
62 private static readonly XName SetPropertyElementName = WixNamespace + "SetProperty";
63 private static readonly XName ShortcutPropertyElementName = WixNamespace + "ShortcutProperty";
64 private static readonly XName TextElementName = WixNamespace + "Text";
65 private static readonly XName UITextElementName = WixNamespace + "UIText";
39 private static readonly XName UtilPermissionExElementName = WixUtilNamespace + "PermissionEx"; 66 private static readonly XName UtilPermissionExElementName = WixUtilNamespace + "PermissionEx";
40 private static readonly XName CustomActionElementName = WixNamespace + "CustomAction"; 67 private static readonly XName CustomActionElementName = WixNamespace + "CustomAction";
41 private static readonly XName PropertyElementName = WixNamespace + "Property"; 68 private static readonly XName PropertyElementName = WixNamespace + "Property";
@@ -83,16 +110,40 @@ namespace WixToolset.Converters
83 { 110 {
84 this.ConvertElementMapping = new Dictionary<XName, Action<XElement>> 111 this.ConvertElementMapping = new Dictionary<XName, Action<XElement>>
85 { 112 {
113 { Wix3Converter.AdminExecuteSequenceElementName, this.ConvertSequenceElement },
114 { Wix3Converter.AdminUISequenceSequenceElementName, this.ConvertSequenceElement },
115 { Wix3Converter.AdvertiseExecuteSequenceElementName, this.ConvertSequenceElement },
116 { Wix3Converter.InstallUISequenceSequenceElementName, this.ConvertSequenceElement },
117 { Wix3Converter.InstallExecuteSequenceElementName, this.ConvertSequenceElement },
86 { Wix3Converter.ColumnElementName, this.ConvertColumnElement }, 118 { Wix3Converter.ColumnElementName, this.ConvertColumnElement },
87 { Wix3Converter.CustomTableElementName, this.ConvertCustomTableElement }, 119 { Wix3Converter.CustomTableElementName, this.ConvertCustomTableElement },
120 { Wix3Converter.ControlElementName, this.ConvertControlElement },
121 { Wix3Converter.ComponentElementName, this.ConvertComponentElement },
88 { Wix3Converter.DirectoryElementName, this.ConvertDirectoryElement }, 122 { Wix3Converter.DirectoryElementName, this.ConvertDirectoryElement },
123 { Wix3Converter.FeatureElementName, this.ConvertFeatureElement },
89 { Wix3Converter.FileElementName, this.ConvertFileElement }, 124 { Wix3Converter.FileElementName, this.ConvertFileElement },
125 { Wix3Converter.FragmentElementName, this.ConvertFragmentElement },
126 { Wix3Converter.EmbeddedChainerElementName, this.ConvertEmbeddedChainerElement },
127 { Wix3Converter.ErrorElementName, this.ConvertErrorElement },
90 { Wix3Converter.ExePackageElementName, this.ConvertSuppressSignatureValidation }, 128 { Wix3Converter.ExePackageElementName, this.ConvertSuppressSignatureValidation },
91 { Wix3Converter.MsiPackageElementName, this.ConvertSuppressSignatureValidation }, 129 { Wix3Converter.MsiPackageElementName, this.ConvertSuppressSignatureValidation },
92 { Wix3Converter.MspPackageElementName, this.ConvertSuppressSignatureValidation }, 130 { Wix3Converter.MspPackageElementName, this.ConvertSuppressSignatureValidation },
93 { Wix3Converter.MsuPackageElementName, this.ConvertSuppressSignatureValidation }, 131 { Wix3Converter.MsuPackageElementName, this.ConvertSuppressSignatureValidation },
94 { Wix3Converter.PayloadElementName, this.ConvertSuppressSignatureValidation }, 132 { Wix3Converter.PayloadElementName, this.ConvertSuppressSignatureValidation },
133 { Wix3Converter.PermissionExElementName, this.ConvertPermissionExElement },
134 { Wix3Converter.ProductElementName, this.ConvertProductElement },
135 { Wix3Converter.ProgressTextElementName, this.ConvertProgressTextElement },
136 { Wix3Converter.PublishElementName, this.ConvertPublishElement },
137 { Wix3Converter.MultiStringValueElementName, this.ConvertMultiStringValueElement },
138 { Wix3Converter.RequiredPrivilegeElementName, this.ConvertRequiredPrivilegeElement },
139 { Wix3Converter.RowElementName, this.ConvertRowElement },
95 { Wix3Converter.CustomActionElementName, this.ConvertCustomActionElement }, 140 { Wix3Converter.CustomActionElementName, this.ConvertCustomActionElement },
141 { Wix3Converter.ServiceArgumentElementName, this.ConvertServiceArgumentElement },
142 { Wix3Converter.SetDirectoryElementName, this.ConvertSetDirectoryElement },
143 { Wix3Converter.SetPropertyElementName, this.ConvertSetPropertyElement },
144 { Wix3Converter.ShortcutPropertyElementName, this.ConvertShortcutPropertyElement },
145 { Wix3Converter.TextElementName, this.ConvertTextElement },
146 { Wix3Converter.UITextElementName, this.ConvertUITextElement },
96 { Wix3Converter.UtilPermissionExElementName, this.ConvertUtilPermissionExElement }, 147 { Wix3Converter.UtilPermissionExElementName, this.ConvertUtilPermissionExElement },
97 { Wix3Converter.PropertyElementName, this.ConvertPropertyElement }, 148 { Wix3Converter.PropertyElementName, this.ConvertPropertyElement },
98 { Wix3Converter.WixElementWithoutNamespaceName, this.ConvertElementWithoutNamespace }, 149 { Wix3Converter.WixElementWithoutNamespaceName, this.ConvertElementWithoutNamespace },
@@ -173,6 +224,8 @@ namespace WixToolset.Converters
173 /// <returns>The number of errors found.</returns> 224 /// <returns>The number of errors found.</returns>
174 public int ConvertDocument(XDocument document) 225 public int ConvertDocument(XDocument document)
175 { 226 {
227 this.Errors = 0;
228
176 var declaration = document.Declaration; 229 var declaration = document.Declaration;
177 230
178 // Convert the declaration. 231 // Convert the declaration.
@@ -336,6 +389,36 @@ namespace WixToolset.Converters
336 } 389 }
337 } 390 }
338 391
392 private void ConvertControlElement(XElement element)
393 {
394 var xCondition = element.Element(ConditionElementName);
395 if (xCondition != null)
396 {
397 var action = UppercaseFirstChar(xCondition.Attribute("Action")?.Value);
398 if (!String.IsNullOrEmpty(action) &&
399 TryGetInnerText(xCondition, out var text) &&
400 this.OnError(ConverterTestType.InnerTextDeprecated, element, "Using {0} element text is deprecated. Use the '{1}Condition' attribute instead.", xCondition.Name.LocalName, action))
401 {
402 element.Add(new XAttribute(action + "Condition", text));
403 xCondition.Remove();
404 }
405 }
406 }
407
408 private void ConvertComponentElement(XElement element)
409 {
410 var xCondition = element.Element(ConditionElementName);
411 if (xCondition != null)
412 {
413 if (TryGetInnerText(xCondition, out var text) &&
414 this.OnError(ConverterTestType.InnerTextDeprecated, element, "Using {0} element text is deprecated. Use the 'Condition' attribute instead.", xCondition.Name.LocalName))
415 {
416 element.Add(new XAttribute("Condition", text));
417 xCondition.Remove();
418 }
419 }
420 }
421
339 private void ConvertDirectoryElement(XElement element) 422 private void ConvertDirectoryElement(XElement element)
340 { 423 {
341 if (null == element.Attribute("Name")) 424 if (null == element.Attribute("Name"))
@@ -353,6 +436,25 @@ namespace WixToolset.Converters
353 } 436 }
354 } 437 }
355 438
439 private void ConvertFeatureElement(XElement element)
440 {
441 var xCondition = element.Element(ConditionElementName);
442 if (xCondition != null)
443 {
444 var level = xCondition.Attribute("Level")?.Value;
445 if (!String.IsNullOrEmpty(level) &&
446 TryGetInnerText(xCondition, out var text) &&
447 this.OnError(ConverterTestType.InnerTextDeprecated, element, "Using {0} element text is deprecated. Use the 'Level' element instead.", xCondition.Name.LocalName))
448 {
449 xCondition.AddAfterSelf(new XElement(LevelElementName,
450 new XAttribute("Value", level),
451 new XAttribute("Condition", text)
452 ));
453 xCondition.Remove();
454 }
455 }
456 }
457
356 private void ConvertFileElement(XElement element) 458 private void ConvertFileElement(XElement element)
357 { 459 {
358 if (null == element.Attribute("Id")) 460 if (null == element.Attribute("Id"))
@@ -379,6 +481,90 @@ namespace WixToolset.Converters
379 } 481 }
380 } 482 }
381 483
484 private void ConvertFragmentElement(XElement element)
485 {
486 var xCondition = element.Element(ConditionElementName);
487 if (xCondition != null)
488 {
489 var message = xCondition.Attribute("Message")?.Value;
490
491 if (!String.IsNullOrEmpty(message) &&
492 TryGetInnerText(xCondition, out var text) &&
493 this.OnError(ConverterTestType.InnerTextDeprecated, element, "Using {0} element text is deprecated. Use the 'Launch' element instead.", xCondition.Name.LocalName))
494 {
495 xCondition.AddAfterSelf(new XElement(LaunchElementName,
496 new XAttribute("Condition", text),
497 new XAttribute("Message", message)
498 ));
499 xCondition.Remove();
500 }
501 }
502 }
503
504 private void ConvertEmbeddedChainerElement(XElement element) => this.ConvertInnerTextToAttribute(element, "Condition");
505
506 private void ConvertErrorElement(XElement element) => this.ConvertInnerTextToAttribute(element, "Message");
507
508 private void ConvertPermissionExElement(XElement element)
509 {
510 var xCondition = element.Element(ConditionElementName);
511 if (xCondition != null)
512 {
513 if (TryGetInnerText(xCondition, out var text) &&
514 this.OnError(ConverterTestType.InnerTextDeprecated, element, "Using {0} element text is deprecated. Use the 'Condition' attribute instead.", xCondition.Name.LocalName))
515 {
516 element.Add(new XAttribute("Condition", text));
517 xCondition.Remove();
518 }
519 }
520 }
521
522 private void ConvertProgressTextElement(XElement element) => this.ConvertInnerTextToAttribute(element, "Message");
523
524 private void ConvertProductElement(XElement element)
525 {
526 var xCondition = element.Element(ConditionElementName);
527 if (xCondition != null)
528 {
529 var message = element.Attribute("Message")?.Value;
530
531 if (!String.IsNullOrEmpty(message) &&
532 TryGetInnerText(xCondition, out var text) &&
533 this.OnError(ConverterTestType.InnerTextDeprecated, element, "Using {0} element text is deprecated. Use the 'Launch' element instead.", xCondition.Name.LocalName))
534 {
535 xCondition.AddAfterSelf(new XElement(LaunchElementName,
536 new XAttribute("Condition", text),
537 new XAttribute("Message", message)
538 ));
539 xCondition.Remove();
540 }
541 }
542 }
543
544 private void ConvertPublishElement(XElement element) => this.ConvertInnerTextToAttribute(element, "Condition");
545
546 private void ConvertMultiStringValueElement(XElement element) => this.ConvertInnerTextToAttribute(element, "Value");
547
548 private void ConvertRequiredPrivilegeElement(XElement element) => this.ConvertInnerTextToAttribute(element, "Name");
549
550 private void ConvertRowElement(XElement element) => this.ConvertInnerTextToAttribute(element, "Value");
551
552 private void ConvertSequenceElement(XElement element)
553 {
554 foreach (var child in element.Elements())
555 {
556 this.ConvertInnerTextToAttribute(child, "Condition");
557 }
558 }
559
560 private void ConvertServiceArgumentElement(XElement element) => this.ConvertInnerTextToAttribute(element, "Value");
561
562 private void ConvertSetDirectoryElement(XElement element) => this.ConvertInnerTextToAttribute(element, "Condition");
563
564 private void ConvertSetPropertyElement(XElement element) => this.ConvertInnerTextToAttribute(element, "Condition");
565
566 private void ConvertShortcutPropertyElement(XElement element) => this.ConvertInnerTextToAttribute(element, "Value");
567
382 private void ConvertSuppressSignatureValidation(XElement element) 568 private void ConvertSuppressSignatureValidation(XElement element)
383 { 569 {
384 var suppressSignatureValidation = element.Attribute("SuppressSignatureValidation"); 570 var suppressSignatureValidation = element.Attribute("SuppressSignatureValidation");
@@ -397,6 +583,10 @@ namespace WixToolset.Converters
397 } 583 }
398 } 584 }
399 585
586 private void ConvertTextElement(XElement element) => this.ConvertInnerTextToAttribute(element, "Value");
587
588 private void ConvertUITextElement(XElement element) => this.ConvertInnerTextToAttribute(element, "Value");
589
400 private void ConvertCustomActionElement(XElement xCustomAction) 590 private void ConvertCustomActionElement(XElement xCustomAction)
401 { 591 {
402 var xBinaryKey = xCustomAction.Attribute("BinaryKey"); 592 var xBinaryKey = xCustomAction.Attribute("BinaryKey");
@@ -436,6 +626,24 @@ namespace WixToolset.Converters
436 xProperty.Value = xProperty.Value.Replace("QtExec", "WixQuietExec"); 626 xProperty.Value = xProperty.Value.Replace("QtExec", "WixQuietExec");
437 } 627 }
438 } 628 }
629
630 var xScript = xCustomAction.Attribute("Script");
631
632 if (xScript != null && TryGetInnerText(xCustomAction, out var scriptText))
633 {
634 if (this.OnError(ConverterTestType.InnerTextDeprecated, xCustomAction, "Using {0} element text is deprecated. Extract the text to a file and use the 'ScriptFile' attribute to reference it.", xCustomAction.Name.LocalName))
635 {
636 var scriptFolder = Path.GetDirectoryName(this.SourceFile) ?? String.Empty;
637 var id = xCustomAction.Attribute("Id")?.Value ?? Guid.NewGuid().ToString("N");
638 var ext = (xScript.Value == "jscript") ? ".js" : (xScript.Value == "vbscript") ? ".vbs" : ".txt";
639
640 var scriptFile = Path.Combine(scriptFolder, id + ext);
641 File.WriteAllText(scriptFile, scriptText);
642
643 RemoveChildren(xCustomAction);
644 xCustomAction.Add(new XAttribute("ScriptFile", scriptFile));
645 }
646 }
439 } 647 }
440 648
441 private void ConvertPropertyElement(XElement xProperty) 649 private void ConvertPropertyElement(XElement xProperty)
@@ -446,6 +654,8 @@ namespace WixToolset.Converters
446 { 654 {
447 this.OnError(ConverterTestType.QtExecCmdTimeoutAmbiguous, xProperty, "QtExecCmdTimeout was previously used for both CAQuietExec and CAQuietExec64. For WixQuietExec, use WixQuietExecCmdTimeout. For WixQuietExec64, use WixQuietExec64CmdTimeout."); 655 this.OnError(ConverterTestType.QtExecCmdTimeoutAmbiguous, xProperty, "QtExecCmdTimeout was previously used for both CAQuietExec and CAQuietExec64. For WixQuietExec, use WixQuietExecCmdTimeout. For WixQuietExec64, use WixQuietExec64CmdTimeout.");
448 } 656 }
657
658 this.ConvertInnerTextToAttribute(xProperty, "Value");
449 } 659 }
450 660
451 private void ConvertUtilPermissionExElement(XElement element) 661 private void ConvertUtilPermissionExElement(XElement element)
@@ -483,13 +693,22 @@ namespace WixToolset.Converters
483 } 693 }
484 } 694 }
485 695
696 private void ConvertInnerTextToAttribute(XElement element, string attributeName)
697 {
698 if (TryGetInnerText(element, out var text) &&
699 this.OnError(ConverterTestType.InnerTextDeprecated, element, "Using {0} element text is deprecated. Use the '{1}' attribute instead.", element.Name.LocalName, attributeName))
700 {
701 element.Add(new XAttribute(attributeName, text));
702 RemoveChildren(element);
703 }
704 }
705
486 private IEnumerable<ConverterTestType> YieldConverterTypes(IEnumerable<string> types) 706 private IEnumerable<ConverterTestType> YieldConverterTypes(IEnumerable<string> types)
487 { 707 {
488 if (null != types) 708 if (null != types)
489 { 709 {
490 foreach (var type in types) 710 foreach (var type in types)
491 { 711 {
492
493 if (Enum.TryParse<ConverterTestType>(type, true, out var itt)) 712 if (Enum.TryParse<ConverterTestType>(type, true, out var itt))
494 { 713 {
495 yield return itt; 714 yield return itt;
@@ -637,6 +856,60 @@ namespace WixToolset.Converters
637 return value; 856 return value;
638 } 857 }
639 858
859 private static string UppercaseFirstChar(string value)
860 {
861 if (!String.IsNullOrEmpty(value))
862 {
863 var c = Char.ToUpperInvariant(value[0]);
864 if (c != value[0])
865 {
866 var remainder = value.Length > 1 ? value.Substring(1) : String.Empty;
867 return c + remainder;
868 }
869 }
870
871 return value;
872 }
873
874 private static bool TryGetInnerText(XElement element, out string value)
875 {
876 value = null;
877
878 var nodes = element.Nodes();
879
880 if (nodes.All(e => e.NodeType == XmlNodeType.Text || e.NodeType == XmlNodeType.CDATA))
881 {
882 value = String.Join(String.Empty, nodes.Cast<XText>().Select(TrimTextValue));
883 }
884
885 return !String.IsNullOrEmpty(value);
886 }
887
888 private static string TrimTextValue(XText text)
889 {
890 var value = text.Value;
891
892 if (String.IsNullOrEmpty(value))
893 {
894 return String.Empty;
895 }
896 else if (text.NodeType == XmlNodeType.CDATA && String.IsNullOrWhiteSpace(value))
897 {
898 return " ";
899 }
900
901 return value.Trim();
902 }
903
904 private static void RemoveChildren(XElement element)
905 {
906 var nodes = element.Nodes().ToList();
907 foreach (var node in nodes)
908 {
909 node.Remove();
910 }
911 }
912
640 /// <summary> 913 /// <summary>
641 /// Converter test types. These are used to condition error messages down to warnings. 914 /// Converter test types. These are used to condition error messages down to warnings.
642 /// </summary> 915 /// </summary>
@@ -751,6 +1024,11 @@ namespace WixToolset.Converters
751 /// Column element's Modularize attribute is camel-case. 1024 /// Column element's Modularize attribute is camel-case.
752 /// </summary> 1025 /// </summary>
753 ColumnModularizeCamelCase, 1026 ColumnModularizeCamelCase,
1027
1028 /// <summary>
1029 /// Inner text value should move to an attribute.
1030 /// </summary>
1031 InnerTextDeprecated,
754 } 1032 }
755 } 1033 }
756} 1034}