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