diff options
Diffstat (limited to 'Source/cmXMLParser.cxx')
-rw-r--r-- | Source/cmXMLParser.cxx | 202 |
1 files changed, 202 insertions, 0 deletions
diff --git a/Source/cmXMLParser.cxx b/Source/cmXMLParser.cxx new file mode 100644 index 0000000..4c6c35a --- /dev/null +++ b/Source/cmXMLParser.cxx @@ -0,0 +1,202 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "cmXMLParser.h" + +#include "cm_expat.h" +#include "cmsys/FStream.hxx" +#include <ctype.h> +#include <iostream> +#include <sstream> +#include <string.h> + +cmXMLParser::cmXMLParser() +{ + this->Parser = nullptr; + this->ParseError = 0; + this->ReportCallback = nullptr; + this->ReportCallbackData = nullptr; +} + +cmXMLParser::~cmXMLParser() +{ + if (this->Parser) { + this->CleanupParser(); + } +} + +int cmXMLParser::Parse(const char* string) +{ + return this->InitializeParser() && + this->ParseChunk(string, strlen(string)) && this->CleanupParser(); +} + +int cmXMLParser::ParseFile(const char* file) +{ + if (!file) { + return 0; + } + + cmsys::ifstream ifs(file); + if (!ifs) { + return 0; + } + + std::ostringstream str; + str << ifs.rdbuf(); + return this->Parse(str.str().c_str()); +} + +int cmXMLParser::InitializeParser() +{ + if (this->Parser) { + std::cerr << "Parser already initialized" << std::endl; + this->ParseError = 1; + return 0; + } + + // Create the expat XML parser. + this->Parser = XML_ParserCreate(nullptr); + XML_SetElementHandler(static_cast<XML_Parser>(this->Parser), + &cmXMLParserStartElement, &cmXMLParserEndElement); + XML_SetCharacterDataHandler(static_cast<XML_Parser>(this->Parser), + &cmXMLParserCharacterDataHandler); + XML_SetUserData(static_cast<XML_Parser>(this->Parser), this); + this->ParseError = 0; + return 1; +} + +int cmXMLParser::ParseChunk(const char* inputString, + std::string::size_type length) +{ + if (!this->Parser) { + std::cerr << "Parser not initialized" << std::endl; + this->ParseError = 1; + return 0; + } + int res; + res = this->ParseBuffer(inputString, length); + if (res == 0) { + this->ParseError = 1; + } + return res; +} + +int cmXMLParser::CleanupParser() +{ + if (!this->Parser) { + std::cerr << "Parser not initialized" << std::endl; + this->ParseError = 1; + return 0; + } + int result = !this->ParseError; + if (result) { + // Tell the expat XML parser about the end-of-input. + if (!XML_Parse(static_cast<XML_Parser>(this->Parser), "", 0, 1)) { + this->ReportXmlParseError(); + result = 0; + } + } + + // Clean up the parser. + XML_ParserFree(static_cast<XML_Parser>(this->Parser)); + this->Parser = nullptr; + + return result; +} + +int cmXMLParser::ParseBuffer(const char* buffer, std::string::size_type count) +{ + // Pass the buffer to the expat XML parser. + if (!XML_Parse(static_cast<XML_Parser>(this->Parser), buffer, + static_cast<int>(count), 0)) { + this->ReportXmlParseError(); + return 0; + } + return 1; +} + +int cmXMLParser::ParseBuffer(const char* buffer) +{ + return this->ParseBuffer(buffer, static_cast<int>(strlen(buffer))); +} + +int cmXMLParser::ParsingComplete() +{ + // Default behavior is to parse to end of stream. + return 0; +} + +void cmXMLParser::StartElement(const std::string& name, const char** /*atts*/) +{ + std::cout << "Start element: " << name << std::endl; +} + +void cmXMLParser::EndElement(const std::string& name) +{ + std::cout << "End element: " << name << std::endl; +} + +void cmXMLParser::CharacterDataHandler(const char* /*inData*/, + int /*inLength*/) +{ +} + +int cmXMLParser::IsSpace(char c) +{ + return isspace(c); +} + +const char* cmXMLParser::FindAttribute(const char** atts, + const char* attribute) +{ + if (atts && attribute) { + for (const char** a = atts; *a && *(a + 1); a += 2) { + if (strcmp(*a, attribute) == 0) { + return *(a + 1); + } + } + } + return nullptr; +} + +void cmXMLParserStartElement(void* parser, const char* name, const char** atts) +{ + // Begin element handler that is registered with the XML_Parser. + // This just casts the user data to a cmXMLParser and calls + // StartElement. + static_cast<cmXMLParser*>(parser)->StartElement(name, atts); +} + +void cmXMLParserEndElement(void* parser, const char* name) +{ + // End element handler that is registered with the XML_Parser. This + // just casts the user data to a cmXMLParser and calls EndElement. + static_cast<cmXMLParser*>(parser)->EndElement(name); +} + +void cmXMLParserCharacterDataHandler(void* parser, const char* data, + int length) +{ + // Character data handler that is registered with the XML_Parser. + // This just casts the user data to a cmXMLParser and calls + // CharacterDataHandler. + static_cast<cmXMLParser*>(parser)->CharacterDataHandler(data, length); +} + +void cmXMLParser::ReportXmlParseError() +{ + XML_Parser parser = static_cast<XML_Parser>(this->Parser); + this->ReportError(static_cast<int>(XML_GetCurrentLineNumber(parser)), + static_cast<int>(XML_GetCurrentColumnNumber(parser)), + XML_ErrorString(XML_GetErrorCode(parser))); +} + +void cmXMLParser::ReportError(int line, int /*unused*/, const char* msg) +{ + if (this->ReportCallback) { + this->ReportCallback(line, msg, this->ReportCallbackData); + } else { + std::cerr << "Error parsing XML in stream at line " << line << ": " << msg + << std::endl; + } +} |