Handle versioned extension ids.
Bob Arnson committed
Mar 5, 2020 at 19:52 UTC
4965ca76323d2ee709bc1790ed1e49ab958445b4
2 files changed
+311
-269
src/WixToolset.Converters/Wix3Converter.cs
+277
-269
@@ -305,368 +305,376 @@ namespace WixToolset.Converters
305
}
306
}
307
308
- private void ConvertDirectoryElement(XElement element)
309
- {
310
- if (null == element.Attribute("Name"))
308
+ private void ConvertDirectoryElement(XElement element)
309
{
312
- var attribute = element.Attribute("ShortName");
313
- if (null != attribute)
310
+ if (null == element.Attribute("Name"))
311
{
315
- var shortName = attribute.Value;
316
- if (this.OnError(ConverterTestType.AssignDirectoryNameFromShortName, element, "The directory ShortName attribute is being renamed to Name since Name wasn't specified for value '{0}'", shortName))
312
+ var attribute = element.Attribute("ShortName");
313
+ if (null != attribute)
314
{
318
- element.Add(new XAttribute("Name", shortName));
319
- attribute.Remove();
315
+ var shortName = attribute.Value;
316
+ if (this.OnError(ConverterTestType.AssignDirectoryNameFromShortName, element, "The directory ShortName attribute is being renamed to Name since Name wasn't specified for value '{0}'", shortName))
317
+ {
318
+ element.Add(new XAttribute("Name", shortName));
319
+ attribute.Remove();
320
+ }
321
}
322
}
323
}
323
- }
324
325
- private void ConvertFileElement(XElement element)
326
- {
327
- if (null == element.Attribute("Id"))
325
+ private void ConvertFileElement(XElement element)
326
{
329
- var attribute = element.Attribute("Name");
330
-
331
- if (null == attribute)
327
+ if (null == element.Attribute("Id"))
328
{
333
- attribute = element.Attribute("Source");
334
- }
329
+ var attribute = element.Attribute("Name");
330
336
- if (null != attribute)
337
- {
338
- var name = Path.GetFileName(attribute.Value);
331
+ if (null == attribute)
332
+ {
333
+ attribute = element.Attribute("Source");
334
+ }
335
340
- if (this.OnError(ConverterTestType.AssignAnonymousFileId, element, "The file id is being updated to '{0}' to ensure it remains the same as the default", name))
336
+ if (null != attribute)
337
{
342
- IEnumerable<XAttribute> attributes = element.Attributes().ToList();
343
- element.RemoveAttributes();
344
- element.Add(new XAttribute("Id", GetIdentifierFromName(name)));
345
- element.Add(attributes);
338
+ var name = Path.GetFileName(attribute.Value);
339
+
340
+ if (this.OnError(ConverterTestType.AssignAnonymousFileId, element, "The file id is being updated to '{0}' to ensure it remains the same as the default", name))
341
+ {
342
+ IEnumerable<XAttribute> attributes = element.Attributes().ToList();
343
+ element.RemoveAttributes();
344
+ element.Add(new XAttribute("Id", GetIdentifierFromName(name)));
345
+ element.Add(attributes);
346
+ }
347
}
348
}
349
}
349
- }
350
-
351
- private void ConvertSuppressSignatureValidation(XElement element)
352
- {
353
- var suppressSignatureValidation = element.Attribute("SuppressSignatureValidation");
350
355
- if (null != suppressSignatureValidation)
351
+ private void ConvertSuppressSignatureValidation(XElement element)
352
{
357
- if (this.OnError(ConverterTestType.SuppressSignatureValidationDeprecated, element, "The chain package element contains deprecated '{0}' attribute. Use the 'EnableSignatureValidation' attribute instead.", suppressSignatureValidation.Name))
353
+ var suppressSignatureValidation = element.Attribute("SuppressSignatureValidation");
354
+
355
+ if (null != suppressSignatureValidation)
356
{
359
- if ("no" == suppressSignatureValidation.Value)
357
+ if (this.OnError(ConverterTestType.SuppressSignatureValidationDeprecated, element, "The chain package element contains deprecated '{0}' attribute. Use the 'EnableSignatureValidation' attribute instead.", suppressSignatureValidation.Name))
358
{
361
- element.Add(new XAttribute("EnableSignatureValidation", "yes"));
359
+ if ("no" == suppressSignatureValidation.Value)
360
+ {
361
+ element.Add(new XAttribute("EnableSignatureValidation", "yes"));
362
+ }
363
}
363
- }
364
365
- suppressSignatureValidation.Remove();
365
+ suppressSignatureValidation.Remove();
366
+ }
367
}
367
- }
368
-
369
- private void ConvertCustomActionElement(XElement xCustomAction)
370
- {
371
- var xBinaryKey = xCustomAction.Attribute("BinaryKey");
368
373
- if (xBinaryKey?.Value == "WixCA")
369
+ private void ConvertCustomActionElement(XElement xCustomAction)
370
{
375
- if (this.OnError(ConverterTestType.WixCABinaryIdRenamed, xCustomAction, "The WixCA custom action DLL Binary table id has been renamed. Use the id 'UtilCA' instead."))
371
+ var xBinaryKey = xCustomAction.Attribute("BinaryKey");
372
+
373
+ if (xBinaryKey?.Value == "WixCA" || xBinaryKey?.Value == "UtilCA")
374
{
377
- xBinaryKey.Value = "UtilCA";
375
+ if (this.OnError(ConverterTestType.WixCABinaryIdRenamed, xCustomAction, "The WixCA custom action DLL Binary table id has been renamed. Use the id 'Wix4UtilCA_X86' instead."))
376
+ {
377
+ xBinaryKey.Value = "Wix4UtilCA_X86";
378
+ }
379
}
379
- }
380
-
381
- var xDllEntry = xCustomAction.Attribute("DllEntry");
380
383
- if (xDllEntry?.Value == "CAQuietExec" || xDllEntry?.Value == "CAQuietExec64")
384
- {
385
- if (this.OnError(ConverterTestType.QuietExecCustomActionsRenamed, xCustomAction, "The CAQuietExec and CAQuietExec64 custom action ids have been renamed. Use the ids 'WixQuietExec' and 'WixQuietExec64' instead."))
381
+ if (xBinaryKey?.Value == "WixCA_x64" || xBinaryKey?.Value == "UtilCA_x64")
382
{
387
- xDllEntry.Value = xDllEntry.Value.Replace("CAQuietExec", "WixQuietExec");
383
+ if (this.OnError(ConverterTestType.WixCABinaryIdRenamed, xCustomAction, "The WixCA_x64 custom action DLL Binary table id has been renamed. Use the id 'Wix4UtilCA_X64' instead."))
384
+ {
385
+ xBinaryKey.Value = "Wix4UtilCA_X64";
386
+ }
387
}
389
- }
388
391
- var xProperty = xCustomAction.Attribute("Property");
389
+ var xDllEntry = xCustomAction.Attribute("DllEntry");
390
393
- if (xProperty?.Value == "QtExecCmdLine" || xProperty?.Value == "QtExec64CmdLine")
394
- {
395
- if (this.OnError(ConverterTestType.QuietExecCustomActionsRenamed, xCustomAction, "The QtExecCmdLine and QtExec64CmdLine property ids have been renamed. Use the ids 'WixQuietExecCmdLine' and 'WixQuietExec64CmdLine' instead."))
391
+ if (xDllEntry?.Value == "CAQuietExec" || xDllEntry?.Value == "CAQuietExec64")
392
{
397
- xProperty.Value = xProperty.Value.Replace("QtExec", "WixQuietExec");
393
+ if (this.OnError(ConverterTestType.QuietExecCustomActionsRenamed, xCustomAction, "The CAQuietExec and CAQuietExec64 custom action ids have been renamed. Use the ids 'WixQuietExec' and 'WixQuietExec64' instead."))
394
+ {
395
+ xDllEntry.Value = xDllEntry.Value.Replace("CAQuietExec", "WixQuietExec");
396
+ }
397
}
399
- }
400
- }
398
402
- private void ConvertPropertyElement(XElement xProperty)
403
- {
404
- var xId = xProperty.Attribute("Id");
399
+ var xProperty = xCustomAction.Attribute("Property");
400
406
- if (xId.Value == "QtExecCmdTimeout")
407
- {
408
- this.OnError(ConverterTestType.QtExecCmdTimeoutAmbiguous, xProperty, "QtExecCmdTimeout was previously used for both CAQuietExec and CAQuietExec64. For WixQuietExec, use WixQuietExecCmdTimeout. For WixQuietExec64, use WixQuietExec64CmdTimeout.");
401
+ if (xProperty?.Value == "QtExecCmdLine" || xProperty?.Value == "QtExec64CmdLine")
402
+ {
403
+ if (this.OnError(ConverterTestType.QuietExecCustomActionsRenamed, xCustomAction, "The QtExecCmdLine and QtExec64CmdLine property ids have been renamed. Use the ids 'WixQuietExecCmdLine' and 'WixQuietExec64CmdLine' instead."))
404
+ {
405
+ xProperty.Value = xProperty.Value.Replace("QtExec", "WixQuietExec");
406
+ }
407
+ }
408
}
410
- }
409
412
- /// <summary>
413
- /// Converts a Wix element.
414
- /// </summary>
415
- /// <param name="element">The Wix element to convert.</param>
416
- /// <returns>The converted element.</returns>
417
- private void ConvertElementWithoutNamespace(XElement element)
418
- {
419
- if (this.OnError(ConverterTestType.XmlnsMissing, element, "The xmlns attribute is missing. It must be present with a value of '{0}'.", WixNamespace.NamespaceName))
410
+ private void ConvertPropertyElement(XElement xProperty)
411
{
421
- element.Name = WixNamespace.GetName(element.Name.LocalName);
422
-
423
- element.Add(new XAttribute("xmlns", WixNamespace.NamespaceName)); // set the default namespace.
412
+ var xId = xProperty.Attribute("Id");
413
425
- foreach (var elementWithoutNamespace in element.DescendantsAndSelf().Where(e => XNamespace.None == e.Name.Namespace))
414
+ if (xId.Value == "QtExecCmdTimeout")
415
{
427
- elementWithoutNamespace.Name = WixNamespace.GetName(elementWithoutNamespace.Name.LocalName);
416
+ this.OnError(ConverterTestType.QtExecCmdTimeoutAmbiguous, xProperty, "QtExecCmdTimeout was previously used for both CAQuietExec and CAQuietExec64. For WixQuietExec, use WixQuietExecCmdTimeout. For WixQuietExec64, use WixQuietExec64CmdTimeout.");
417
}
418
}
430
- }
419
432
- private IEnumerable<ConverterTestType> YieldConverterTypes(IEnumerable<string> types)
433
- {
434
- if (null != types)
420
+ /// <summary>
421
+ /// Converts a Wix element.
422
+ /// </summary>
423
+ /// <param name="element">The Wix element to convert.</param>
424
+ /// <returns>The converted element.</returns>
425
+ private void ConvertElementWithoutNamespace(XElement element)
426
{
436
- foreach (var type in types)
427
+ if (this.OnError(ConverterTestType.XmlnsMissing, element, "The xmlns attribute is missing. It must be present with a value of '{0}'.", WixNamespace.NamespaceName))
428
{
429
+ element.Name = WixNamespace.GetName(element.Name.LocalName);
430
439
- if (Enum.TryParse<ConverterTestType>(type, true, out var itt))
440
- {
441
- yield return itt;
442
- }
443
- else // not a known ConverterTestType
431
+ element.Add(new XAttribute("xmlns", WixNamespace.NamespaceName)); // set the default namespace.
432
+
433
+ foreach (var elementWithoutNamespace in element.DescendantsAndSelf().Where(e => XNamespace.None == e.Name.Namespace))
434
{
445
- this.OnError(ConverterTestType.ConverterTestTypeUnknown, null, "Unknown error type: '{0}'.", type);
435
+ elementWithoutNamespace.Name = WixNamespace.GetName(elementWithoutNamespace.Name.LocalName);
436
}
437
}
438
}
449
- }
439
451
- private static void UpdateElementsWithDeprecatedNamespaces(IEnumerable<XElement> elements, Dictionary<XNamespace, XNamespace> deprecatedToUpdatedNamespaces)
452
- {
453
- foreach (var element in elements)
440
+ private IEnumerable<ConverterTestType> YieldConverterTypes(IEnumerable<string> types)
441
{
455
-
456
- if (deprecatedToUpdatedNamespaces.TryGetValue(element.Name.Namespace, out var ns))
457
- {
458
- element.Name = ns.GetName(element.Name.LocalName);
459
- }
460
-
461
- // Remove all the attributes and add them back to with their namespace updated (as necessary).
462
- IEnumerable<XAttribute> attributes = element.Attributes().ToList();
463
- element.RemoveAttributes();
464
-
465
- foreach (var attribute in attributes)
442
+ if (null != types)
443
{
467
- var convertedAttribute = attribute;
468
-
469
- if (attribute.IsNamespaceDeclaration)
444
+ foreach (var type in types)
445
{
471
- if (deprecatedToUpdatedNamespaces.TryGetValue(attribute.Value, out ns))
446
+
447
+ if (Enum.TryParse<ConverterTestType>(type, true, out var itt))
448
{
473
- convertedAttribute = ("xmlns" == attribute.Name.LocalName) ? new XAttribute(attribute.Name.LocalName, ns.NamespaceName) : new XAttribute(XNamespace.Xmlns + attribute.Name.LocalName, ns.NamespaceName);
449
+ yield return itt;
450
+ }
451
+ else // not a known ConverterTestType
452
+ {
453
+ this.OnError(ConverterTestType.ConverterTestTypeUnknown, null, "Unknown error type: '{0}'.", type);
454
}
455
}
476
- else if (deprecatedToUpdatedNamespaces.TryGetValue(attribute.Name.Namespace, out ns))
477
- {
478
- convertedAttribute = new XAttribute(ns.GetName(attribute.Name.LocalName), attribute.Value);
479
- }
480
-
481
- element.Add(convertedAttribute);
456
}
457
}
484
- }
458
486
- /// <summary>
487
- /// Determine if the whitespace preceding a node is appropriate for its depth level.
488
- /// </summary>
489
- /// <param name="indentationAmount">Indentation value to use when validating leading whitespace.</param>
490
- /// <param name="level">The depth level that should match this whitespace.</param>
491
- /// <param name="whitespace">The whitespace to validate.</param>
492
- /// <returns>true if the whitespace is legal; false otherwise.</returns>
493
- private static bool LeadingWhitespaceValid(int indentationAmount, int level, string whitespace)
494
- {
495
- // Strip off leading newlines; there can be an arbitrary number of these.
496
- whitespace = whitespace.TrimStart(XDocumentNewLine);
497
-
498
- var indentation = new string(' ', level * indentationAmount);
499
-
500
- return whitespace == indentation;
501
- }
502
-
503
- /// <summary>
504
- /// Fix the whitespace in a whitespace node.
505
- /// </summary>
506
- /// <param name="indentationAmount">Indentation value to use when validating leading whitespace.</param>
507
- /// <param name="level">The depth level of the desired whitespace.</param>
508
- /// <param name="whitespace">The whitespace node to fix.</param>
509
- private static void FixupWhitespace(int indentationAmount, int level, XText whitespace)
510
- {
511
- var value = new StringBuilder(whitespace.Value.Length);
512
-
513
- // Keep any previous preceeding new lines.
514
- var newlines = whitespace.Value.TakeWhile(c => c == XDocumentNewLine).Count();
515
-
516
- // Ensure there is always at least one new line before the indentation.
517
- value.Append(XDocumentNewLine, newlines == 0 ? 1 : newlines);
518
-
519
- whitespace.Value = value.Append(' ', level * indentationAmount).ToString();
520
- }
521
-
522
- /// <summary>
523
- /// Output an error message to the console.
524
- /// </summary>
525
- /// <param name="converterTestType">The type of converter test.</param>
526
- /// <param name="node">The node that caused the error.</param>
527
- /// <param name="message">Detailed error message.</param>
528
- /// <param name="args">Additional formatted string arguments.</param>
529
- /// <returns>Returns true indicating that action should be taken on this error, and false if it should be ignored.</returns>
530
- private bool OnError(ConverterTestType converterTestType, XObject node, string message, params object[] args)
531
- {
532
- if (this.IgnoreErrors.Contains(converterTestType)) // ignore the error
459
+ private static void UpdateElementsWithDeprecatedNamespaces(IEnumerable<XElement> elements, Dictionary<XNamespace, XNamespace> deprecatedToUpdatedNamespaces)
460
{
534
- return false;
535
- }
536
-
537
- // Increase the error count.
538
- this.Errors++;
539
-
540
- var sourceLine = (null == node) ? new SourceLineNumber(this.SourceFile ?? "wixcop.exe") : new SourceLineNumber(this.SourceFile, ((IXmlLineInfo)node).LineNumber);
541
- var warning = this.ErrorsAsWarnings.Contains(converterTestType);
542
- var display = String.Format(CultureInfo.CurrentCulture, message, args);
461
+ foreach (var element in elements)
462
+ {
463
544
- var msg = new Message(sourceLine, warning ? MessageLevel.Warning : MessageLevel.Error, (int)converterTestType, "{0} ({1})", display, converterTestType.ToString());
464
+ if (deprecatedToUpdatedNamespaces.TryGetValue(element.Name.Namespace, out var ns))
465
+ {
466
+ element.Name = ns.GetName(element.Name.LocalName);
467
+ }
468
546
- this.Messaging.Write(msg);
469
+ // Remove all the attributes and add them back to with their namespace updated (as necessary).
470
+ IEnumerable<XAttribute> attributes = element.Attributes().ToList();
471
+ element.RemoveAttributes();
472
548
- return true;
549
- }
473
+ foreach (var attribute in attributes)
474
+ {
475
+ var convertedAttribute = attribute;
476
551
- /// <summary>
552
- /// Return an identifier based on passed file/directory name
553
- /// </summary>
554
- /// <param name="name">File/directory name to generate identifer from</param>
555
- /// <returns>A version of the name that is a legal identifier.</returns>
556
- /// <remarks>This is duplicated from WiX's Common class.</remarks>
557
- private static string GetIdentifierFromName(string name)
558
- {
559
- string result = IllegalIdentifierCharacters.Replace(name, "_"); // replace illegal characters with "_".
477
+ if (attribute.IsNamespaceDeclaration)
478
+ {
479
+ if (deprecatedToUpdatedNamespaces.TryGetValue(attribute.Value, out ns))
480
+ {
481
+ convertedAttribute = ("xmlns" == attribute.Name.LocalName) ? new XAttribute(attribute.Name.LocalName, ns.NamespaceName) : new XAttribute(XNamespace.Xmlns + attribute.Name.LocalName, ns.NamespaceName);
482
+ }
483
+ }
484
+ else if (deprecatedToUpdatedNamespaces.TryGetValue(attribute.Name.Namespace, out ns))
485
+ {
486
+ convertedAttribute = new XAttribute(ns.GetName(attribute.Name.LocalName), attribute.Value);
487
+ }
488
561
- // MSI identifiers must begin with an alphabetic character or an
562
- // underscore. Prefix all other values with an underscore.
563
- if (AddPrefix.IsMatch(name))
564
- {
565
- result = String.Concat("_", result);
489
+ element.Add(convertedAttribute);
490
+ }
491
+ }
492
}
493
568
- return result;
569
- }
570
-
571
- /// <summary>
572
- /// Converter test types. These are used to condition error messages down to warnings.
573
- /// </summary>
574
- private enum ConverterTestType
575
- {
576
- /// <summary>
577
- /// Internal-only: displayed when a string cannot be converted to an ConverterTestType.
578
- /// </summary>
579
- ConverterTestTypeUnknown,
580
-
494
/// <summary>
582
- /// Displayed when an XML loading exception has occurred.
495
+ /// Determine if the whitespace preceding a node is appropriate for its depth level.
496
/// </summary>
584
- XmlException,
585
-
586
- /// <summary>
587
- /// Displayed when a file cannot be accessed; typically when trying to save back a fixed file.
588
- /// </summary>
589
- UnauthorizedAccessException,
497
+ /// <param name="indentationAmount">Indentation value to use when validating leading whitespace.</param>
498
+ /// <param name="level">The depth level that should match this whitespace.</param>
499
+ /// <param name="whitespace">The whitespace to validate.</param>
500
+ /// <returns>true if the whitespace is legal; false otherwise.</returns>
501
+ private static bool LeadingWhitespaceValid(int indentationAmount, int level, string whitespace)
502
+ {
503
+ // Strip off leading newlines; there can be an arbitrary number of these.
504
+ whitespace = whitespace.TrimStart(XDocumentNewLine);
505
591
- /// <summary>
592
- /// Displayed when the encoding attribute in the XML declaration is not 'UTF-8'.
593
- /// </summary>
594
- DeclarationEncodingWrong,
506
+ var indentation = new string(' ', level * indentationAmount);
507
596
- /// <summary>
597
- /// Displayed when the XML declaration is missing from the source file.
598
- /// </summary>
599
- DeclarationMissing,
508
+ return whitespace == indentation;
509
+ }
510
511
/// <summary>
602
- /// Displayed when the whitespace preceding a CDATA node is wrong.
512
+ /// Fix the whitespace in a whitespace node.
513
/// </summary>
604
- WhitespacePrecedingCDATAWrong,
514
+ /// <param name="indentationAmount">Indentation value to use when validating leading whitespace.</param>
515
+ /// <param name="level">The depth level of the desired whitespace.</param>
516
+ /// <param name="whitespace">The whitespace node to fix.</param>
517
+ private static void FixupWhitespace(int indentationAmount, int level, XText whitespace)
518
+ {
519
+ var value = new StringBuilder(whitespace.Value.Length);
520
606
- /// <summary>
607
- /// Displayed when the whitespace preceding a node is wrong.
608
- /// </summary>
609
- WhitespacePrecedingNodeWrong,
521
+ // Keep any previous preceeding new lines.
522
+ var newlines = whitespace.Value.TakeWhile(c => c == XDocumentNewLine).Count();
523
611
- /// <summary>
612
- /// Displayed when an element is not empty as it should be.
613
- /// </summary>
614
- NotEmptyElement,
524
+ // Ensure there is always at least one new line before the indentation.
525
+ value.Append(XDocumentNewLine, newlines == 0 ? 1 : newlines);
526
616
- /// <summary>
617
- /// Displayed when the whitespace following a CDATA node is wrong.
618
- /// </summary>
619
- WhitespaceFollowingCDATAWrong,
527
+ whitespace.Value = value.Append(' ', level * indentationAmount).ToString();
528
+ }
529
530
/// <summary>
622
- /// Displayed when the whitespace preceding an end element is wrong.
531
+ /// Output an error message to the console.
532
/// </summary>
624
- WhitespacePrecedingEndElementWrong,
533
+ /// <param name="converterTestType">The type of converter test.</param>
534
+ /// <param name="node">The node that caused the error.</param>
535
+ /// <param name="message">Detailed error message.</param>
536
+ /// <param name="args">Additional formatted string arguments.</param>
537
+ /// <returns>Returns true indicating that action should be taken on this error, and false if it should be ignored.</returns>
538
+ private bool OnError(ConverterTestType converterTestType, XObject node, string message, params object[] args)
539
+ {
540
+ if (this.IgnoreErrors.Contains(converterTestType)) // ignore the error
541
+ {
542
+ return false;
543
+ }
544
626
- /// <summary>
627
- /// Displayed when the xmlns attribute is missing from the document element.
628
- /// </summary>
629
- XmlnsMissing,
545
+ // Increase the error count.
546
+ this.Errors++;
547
631
- /// <summary>
632
- /// Displayed when the xmlns attribute on the document element is wrong.
633
- /// </summary>
634
- XmlnsValueWrong,
548
+ var sourceLine = (null == node) ? new SourceLineNumber(this.SourceFile ?? "wixcop.exe") : new SourceLineNumber(this.SourceFile, ((IXmlLineInfo)node).LineNumber);
549
+ var warning = this.ErrorsAsWarnings.Contains(converterTestType);
550
+ var display = String.Format(CultureInfo.CurrentCulture, message, args);
551
636
- /// <summary>
637
- /// Assign an identifier to a File element when on Id attribute is specified.
638
- /// </summary>
639
- AssignAnonymousFileId,
552
+ var msg = new Message(sourceLine, warning ? MessageLevel.Warning : MessageLevel.Error, (int)converterTestType, "{0} ({1})", display, converterTestType.ToString());
553
641
- /// <summary>
642
- /// SuppressSignatureValidation attribute is deprecated and replaced with EnableSignatureValidation.
643
- /// </summary>
644
- SuppressSignatureValidationDeprecated,
554
+ this.Messaging.Write(msg);
555
646
- /// <summary>
647
- /// WixCA Binary/@Id has been renamed to UtilCA.
648
- /// </summary>
649
- WixCABinaryIdRenamed,
556
+ return true;
557
+ }
558
559
/// <summary>
652
- /// QtExec custom actions have been renamed.
560
+ /// Return an identifier based on passed file/directory name
561
/// </summary>
654
- QuietExecCustomActionsRenamed,
562
+ /// <param name="name">File/directory name to generate identifer from</param>
563
+ /// <returns>A version of the name that is a legal identifier.</returns>
564
+ /// <remarks>This is duplicated from WiX's Common class.</remarks>
565
+ private static string GetIdentifierFromName(string name)
566
+ {
567
+ string result = IllegalIdentifierCharacters.Replace(name, "_"); // replace illegal characters with "_".
568
656
- /// <summary>
657
- /// QtExecCmdTimeout was previously used for both CAQuietExec and CAQuietExec64. For WixQuietExec, use WixQuietExecCmdTimeout. For WixQuietExec64, use WixQuietExec64CmdTimeout.
658
- /// </summary>
659
- QtExecCmdTimeoutAmbiguous,
569
+ // MSI identifiers must begin with an alphabetic character or an
570
+ // underscore. Prefix all other values with an underscore.
571
+ if (AddPrefix.IsMatch(name))
572
+ {
573
+ result = String.Concat("_", result);
574
+ }
575
661
- /// <summary>
662
- /// Directory/@ShortName may only be specified with Directory/@Name.
663
- /// </summary>
664
- AssignDirectoryNameFromShortName,
576
+ return result;
577
+ }
578
579
/// <summary>
667
- /// BootstrapperApplicationData attribute is deprecated and replaced with Unreal.
580
+ /// Converter test types. These are used to condition error messages down to warnings.
581
/// </summary>
669
- BootstrapperApplicationDataDeprecated,
582
+ private enum ConverterTestType
583
+ {
584
+ /// <summary>
585
+ /// Internal-only: displayed when a string cannot be converted to an ConverterTestType.
586
+ /// </summary>
587
+ ConverterTestTypeUnknown,
588
+
589
+ /// <summary>
590
+ /// Displayed when an XML loading exception has occurred.
591
+ /// </summary>
592
+ XmlException,
593
+
594
+ /// <summary>
595
+ /// Displayed when a file cannot be accessed; typically when trying to save back a fixed file.
596
+ /// </summary>
597
+ UnauthorizedAccessException,
598
+
599
+ /// <summary>
600
+ /// Displayed when the encoding attribute in the XML declaration is not 'UTF-8'.
601
+ /// </summary>
602
+ DeclarationEncodingWrong,
603
+
604
+ /// <summary>
605
+ /// Displayed when the XML declaration is missing from the source file.
606
+ /// </summary>
607
+ DeclarationMissing,
608
+
609
+ /// <summary>
610
+ /// Displayed when the whitespace preceding a CDATA node is wrong.
611
+ /// </summary>
612
+ WhitespacePrecedingCDATAWrong,
613
+
614
+ /// <summary>
615
+ /// Displayed when the whitespace preceding a node is wrong.
616
+ /// </summary>
617
+ WhitespacePrecedingNodeWrong,
618
+
619
+ /// <summary>
620
+ /// Displayed when an element is not empty as it should be.
621
+ /// </summary>
622
+ NotEmptyElement,
623
+
624
+ /// <summary>
625
+ /// Displayed when the whitespace following a CDATA node is wrong.
626
+ /// </summary>
627
+ WhitespaceFollowingCDATAWrong,
628
+
629
+ /// <summary>
630
+ /// Displayed when the whitespace preceding an end element is wrong.
631
+ /// </summary>
632
+ WhitespacePrecedingEndElementWrong,
633
+
634
+ /// <summary>
635
+ /// Displayed when the xmlns attribute is missing from the document element.
636
+ /// </summary>
637
+ XmlnsMissing,
638
+
639
+ /// <summary>
640
+ /// Displayed when the xmlns attribute on the document element is wrong.
641
+ /// </summary>
642
+ XmlnsValueWrong,
643
+
644
+ /// <summary>
645
+ /// Assign an identifier to a File element when on Id attribute is specified.
646
+ /// </summary>
647
+ AssignAnonymousFileId,
648
+
649
+ /// <summary>
650
+ /// SuppressSignatureValidation attribute is deprecated and replaced with EnableSignatureValidation.
651
+ /// </summary>
652
+ SuppressSignatureValidationDeprecated,
653
+
654
+ /// <summary>
655
+ /// WixCA Binary/@Id has been renamed to UtilCA.
656
+ /// </summary>
657
+ WixCABinaryIdRenamed,
658
+
659
+ /// <summary>
660
+ /// QtExec custom actions have been renamed.
661
+ /// </summary>
662
+ QuietExecCustomActionsRenamed,
663
+
664
+ /// <summary>
665
+ /// QtExecCmdTimeout was previously used for both CAQuietExec and CAQuietExec64. For WixQuietExec, use WixQuietExecCmdTimeout. For WixQuietExec64, use WixQuietExec64CmdTimeout.
666
+ /// </summary>
667
+ QtExecCmdTimeoutAmbiguous,
668
+
669
+ /// <summary>
670
+ /// Directory/@ShortName may only be specified with Directory/@Name.
671
+ /// </summary>
672
+ AssignDirectoryNameFromShortName,
673
+
674
+ /// <summary>
675
+ /// BootstrapperApplicationData attribute is deprecated and replaced with Unreal.
676
+ /// </summary>
677
+ BootstrapperApplicationDataDeprecated,
678
+ }
679
}
680
}
672
-}
src/test/WixToolsetTest.Converters/ConverterFixture.cs
+34
@@ -590,6 +590,40 @@ namespace WixToolsetTest.Converters
590
Assert.Equal(expected, actual);
591
}
592
593
+ [Fact]
594
+ public void CanConvertCustomAction()
595
+ {
596
+ var parse = String.Join(Environment.NewLine,
597
+ "<?xml version='1.0' encoding='utf-8'?>",
598
+ "<Wix xmlns='http://wixtoolset.org/schemas/v4/wxs'>",
599
+ " <CustomAction Id='Foo' BinaryKey='WixCA' DllEntry='CAQuietExec' />",
600
+ " <CustomAction Id='Foo' BinaryKey='WixCA_x64' DllEntry='CAQuietExec64' />",
601
+ " <CustomAction Id='Foo' BinaryKey='UtilCA' DllEntry='WixQuietExec' />",
602
+ " <CustomAction Id='Foo' BinaryKey='UtilCA_x64' DllEntry='WixQuietExec64' />",
603
+ "</Wix>");
604
+
605
+ var expected = String.Join(Environment.NewLine,
606
+ "<?xml version=\"1.0\" encoding=\"utf-16\"?>",
607
+ "<Wix xmlns=\"http://wixtoolset.org/schemas/v4/wxs\">",
608
+ " <CustomAction Id=\"Foo\" BinaryKey=\"Wix4UtilCA_X86\" DllEntry=\"WixQuietExec\" />",
609
+ " <CustomAction Id=\"Foo\" BinaryKey=\"Wix4UtilCA_X64\" DllEntry=\"WixQuietExec64\" />",
610
+ " <CustomAction Id=\"Foo\" BinaryKey=\"Wix4UtilCA_X86\" DllEntry=\"WixQuietExec\" />",
611
+ " <CustomAction Id=\"Foo\" BinaryKey=\"Wix4UtilCA_X64\" DllEntry=\"WixQuietExec64\" />",
612
+ "</Wix>");
613
+
614
+ var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo);
615
+
616
+ var messaging = new DummyMessaging();
617
+ var converter = new Wix3Converter(messaging, 2, null, null);
618
+
619
+ var errors = converter.ConvertDocument(document);
620
+
621
+ var actual = UnformattedDocumentString(document);
622
+
623
+ Assert.Equal(6, errors);
624
+ Assert.Equal(expected, actual);
625
+ }
626
+
627
private static string UnformattedDocumentString(XDocument document)
628
{
629
var sb = new StringBuilder();