cmWIXPatchParser.cxx 4.2 KB

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