cmWIXPatchParser.cxx 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
  2. file Copyright.txt or https://cmake.org/licensing for details. */
  3. #include "cmWIXPatchParser.h"
  4. #include <utility>
  5. #include <cm/memory>
  6. #include <cmext/string_view>
  7. #include <cm3p/expat.h>
  8. #include "cmCPackGenerator.h"
  9. cmWIXPatchNode::Type cmWIXPatchText::type()
  10. {
  11. return cmWIXPatchNode::TEXT;
  12. }
  13. cmWIXPatchNode::Type cmWIXPatchElement::type()
  14. {
  15. return cmWIXPatchNode::ELEMENT;
  16. }
  17. cmWIXPatchNode::~cmWIXPatchNode() = default;
  18. cmWIXPatchElement::cmWIXPatchElement() = default;
  19. cmWIXPatchElement::~cmWIXPatchElement() = default;
  20. cmWIXPatchParser::cmWIXPatchParser(fragment_map_t& fragments,
  21. cmCPackLog* logger)
  22. : Logger(logger)
  23. , State(BEGIN_DOCUMENT)
  24. , Valid(true)
  25. , Fragments(fragments)
  26. {
  27. }
  28. void cmWIXPatchParser::StartElement(std::string const& name, char const** atts)
  29. {
  30. if (State == BEGIN_DOCUMENT) {
  31. if (name == "CPackWiXPatch"_s) {
  32. State = BEGIN_FRAGMENTS;
  33. } else {
  34. ReportValidationError("Expected root element 'CPackWiXPatch'");
  35. }
  36. } else if (State == BEGIN_FRAGMENTS) {
  37. if (name == "CPackWiXFragment"_s) {
  38. State = INSIDE_FRAGMENT;
  39. StartFragment(atts);
  40. } else {
  41. ReportValidationError("Expected 'CPackWixFragment' element");
  42. }
  43. } else if (State == INSIDE_FRAGMENT) {
  44. cmWIXPatchElement& parent = *ElementStack.back();
  45. auto element = cm::make_unique<cmWIXPatchElement>();
  46. element->name = name;
  47. for (size_t i = 0; atts[i]; i += 2) {
  48. std::string key = atts[i];
  49. std::string value = atts[i + 1];
  50. element->attributes[key] = value;
  51. }
  52. ElementStack.push_back(element.get());
  53. parent.children.push_back(std::move(element));
  54. }
  55. }
  56. void cmWIXPatchParser::StartFragment(char const** attributes)
  57. {
  58. cmWIXPatchElement* new_element = nullptr;
  59. /* find the id of for fragment */
  60. for (size_t i = 0; attributes[i]; i += 2) {
  61. std::string const key = attributes[i];
  62. std::string const value = attributes[i + 1];
  63. if (key == "Id"_s) {
  64. if (Fragments.find(value) != Fragments.end()) {
  65. std::ostringstream tmp;
  66. tmp << "Invalid reuse of 'CPackWixFragment' 'Id': " << value;
  67. ReportValidationError(tmp.str());
  68. }
  69. new_element = &Fragments[value];
  70. ElementStack.push_back(new_element);
  71. }
  72. }
  73. /* add any additional attributes for the fragment */
  74. if (!new_element) {
  75. ReportValidationError("No 'Id' specified for 'CPackWixFragment' element");
  76. } else {
  77. for (size_t i = 0; attributes[i]; i += 2) {
  78. std::string const key = attributes[i];
  79. std::string const value = attributes[i + 1];
  80. if (key != "Id"_s) {
  81. new_element->attributes[key] = value;
  82. }
  83. }
  84. }
  85. }
  86. void cmWIXPatchParser::EndElement(std::string const& name)
  87. {
  88. if (State == INSIDE_FRAGMENT) {
  89. if (name == "CPackWiXFragment"_s) {
  90. State = BEGIN_FRAGMENTS;
  91. ElementStack.clear();
  92. } else {
  93. ElementStack.pop_back();
  94. }
  95. }
  96. }
  97. void cmWIXPatchParser::CharacterDataHandler(char const* data, int length)
  98. {
  99. char const* whitespace = "\x20\x09\x0d\x0a";
  100. if (State == INSIDE_FRAGMENT) {
  101. cmWIXPatchElement& parent = *ElementStack.back();
  102. std::string text(data, length);
  103. std::string::size_type first = text.find_first_not_of(whitespace);
  104. std::string::size_type last = text.find_last_not_of(whitespace);
  105. if (first != std::string::npos && last != std::string::npos) {
  106. auto text_node = cm::make_unique<cmWIXPatchText>();
  107. text_node->text = text.substr(first, last - first + 1);
  108. parent.children.push_back(std::move(text_node));
  109. }
  110. }
  111. }
  112. void cmWIXPatchParser::ReportError(int line, int column, char const* msg)
  113. {
  114. cmCPackLogger(cmCPackLog::LOG_ERROR,
  115. "Error while processing XML patch file at "
  116. << line << ':' << column << ": " << msg << std::endl);
  117. Valid = false;
  118. }
  119. void cmWIXPatchParser::ReportValidationError(std::string const& message)
  120. {
  121. ReportError(
  122. XML_GetCurrentLineNumber(static_cast<XML_Parser>(this->Parser)),
  123. XML_GetCurrentColumnNumber(static_cast<XML_Parser>(this->Parser)),
  124. message.c_str());
  125. }
  126. bool cmWIXPatchParser::IsValid() const
  127. {
  128. return Valid;
  129. }