@joebigelow / wix / commits / 2c6285da

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 {