| /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying |
| file Copyright.txt or https://cmake.org/licensing for details. */ |
| #include "cmWIXPatchParser.h" |
| |
| #include <utility> |
| |
| #include <cm/memory> |
| #include <cmext/string_view> |
| |
| #include <cm3p/expat.h> |
| |
| #include "cmCPackGenerator.h" |
| |
| cmWIXPatchNode::Type cmWIXPatchText::type() |
| { |
| return cmWIXPatchNode::TEXT; |
| } |
| |
| cmWIXPatchNode::Type cmWIXPatchElement::type() |
| { |
| return cmWIXPatchNode::ELEMENT; |
| } |
| |
| cmWIXPatchNode::~cmWIXPatchNode() = default; |
| |
| cmWIXPatchElement::cmWIXPatchElement() = default; |
| cmWIXPatchElement::~cmWIXPatchElement() = default; |
| |
| cmWIXPatchParser::cmWIXPatchParser(fragment_map_t& fragments, |
| cmCPackLog* logger) |
| : Logger(logger) |
| , State(BEGIN_DOCUMENT) |
| , Valid(true) |
| , Fragments(fragments) |
| { |
| } |
| |
| void cmWIXPatchParser::StartElement(const std::string& name, const char** atts) |
| { |
| if (State == BEGIN_DOCUMENT) { |
| if (name == "CPackWiXPatch"_s) { |
| State = BEGIN_FRAGMENTS; |
| } else { |
| ReportValidationError("Expected root element 'CPackWiXPatch'"); |
| } |
| } else if (State == BEGIN_FRAGMENTS) { |
| if (name == "CPackWiXFragment"_s) { |
| State = INSIDE_FRAGMENT; |
| StartFragment(atts); |
| } else { |
| ReportValidationError("Expected 'CPackWixFragment' element"); |
| } |
| } else if (State == INSIDE_FRAGMENT) { |
| cmWIXPatchElement& parent = *ElementStack.back(); |
| |
| auto element = cm::make_unique<cmWIXPatchElement>(); |
| |
| element->name = name; |
| |
| for (size_t i = 0; atts[i]; i += 2) { |
| std::string key = atts[i]; |
| std::string value = atts[i + 1]; |
| |
| element->attributes[key] = value; |
| } |
| |
| ElementStack.push_back(element.get()); |
| parent.children.push_back(std::move(element)); |
| } |
| } |
| |
| void cmWIXPatchParser::StartFragment(const char** attributes) |
| { |
| cmWIXPatchElement* new_element = nullptr; |
| /* find the id of for fragment */ |
| for (size_t i = 0; attributes[i]; i += 2) { |
| const std::string key = attributes[i]; |
| const std::string value = attributes[i + 1]; |
| |
| if (key == "Id"_s) { |
| if (Fragments.find(value) != Fragments.end()) { |
| std::ostringstream tmp; |
| tmp << "Invalid reuse of 'CPackWixFragment' 'Id': " << value; |
| ReportValidationError(tmp.str()); |
| } |
| |
| new_element = &Fragments[value]; |
| ElementStack.push_back(new_element); |
| } |
| } |
| |
| /* add any additional attributes for the fragment */ |
| if (!new_element) { |
| ReportValidationError("No 'Id' specified for 'CPackWixFragment' element"); |
| } else { |
| for (size_t i = 0; attributes[i]; i += 2) { |
| const std::string key = attributes[i]; |
| const std::string value = attributes[i + 1]; |
| |
| if (key != "Id"_s) { |
| new_element->attributes[key] = value; |
| } |
| } |
| } |
| } |
| |
| void cmWIXPatchParser::EndElement(const std::string& name) |
| { |
| if (State == INSIDE_FRAGMENT) { |
| if (name == "CPackWiXFragment"_s) { |
| State = BEGIN_FRAGMENTS; |
| ElementStack.clear(); |
| } else { |
| ElementStack.pop_back(); |
| } |
| } |
| } |
| |
| void cmWIXPatchParser::CharacterDataHandler(const char* data, int length) |
| { |
| const char* whitespace = "\x20\x09\x0d\x0a"; |
| |
| if (State == INSIDE_FRAGMENT) { |
| cmWIXPatchElement& parent = *ElementStack.back(); |
| |
| std::string text(data, length); |
| |
| std::string::size_type first = text.find_first_not_of(whitespace); |
| std::string::size_type last = text.find_last_not_of(whitespace); |
| |
| if (first != std::string::npos && last != std::string::npos) { |
| auto text_node = cm::make_unique<cmWIXPatchText>(); |
| text_node->text = text.substr(first, last - first + 1); |
| |
| parent.children.push_back(std::move(text_node)); |
| } |
| } |
| } |
| |
| void cmWIXPatchParser::ReportError(int line, int column, const char* msg) |
| { |
| cmCPackLogger(cmCPackLog::LOG_ERROR, |
| "Error while processing XML patch file at " |
| << line << ':' << column << ": " << msg << std::endl); |
| Valid = false; |
| } |
| |
| void cmWIXPatchParser::ReportValidationError(std::string const& message) |
| { |
| ReportError( |
| XML_GetCurrentLineNumber(static_cast<XML_Parser>(this->Parser)), |
| XML_GetCurrentColumnNumber(static_cast<XML_Parser>(this->Parser)), |
| message.c_str()); |
| } |
| |
| bool cmWIXPatchParser::IsValid() const |
| { |
| return Valid; |
| } |