cmWIXPatchParser.cxx 4.1 KB

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