cmXMLParser.cxx 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  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 "cmXMLParser.h"
  4. #include <cstring>
  5. #include <iostream>
  6. #include <sstream>
  7. #include <cm3p/expat.h>
  8. #include "cmsys/FStream.hxx"
  9. cmXMLParser::cmXMLParser()
  10. {
  11. this->Parser = nullptr;
  12. this->ParseError = 0;
  13. this->ReportCallback = nullptr;
  14. this->ReportCallbackData = nullptr;
  15. }
  16. cmXMLParser::~cmXMLParser()
  17. {
  18. if (this->Parser) {
  19. this->CleanupParser();
  20. }
  21. }
  22. int cmXMLParser::Parse(const char* string)
  23. {
  24. return this->InitializeParser() &&
  25. this->ParseChunk(string, strlen(string)) && this->CleanupParser();
  26. }
  27. int cmXMLParser::ParseFile(const char* file)
  28. {
  29. if (!file) {
  30. return 0;
  31. }
  32. cmsys::ifstream ifs(file);
  33. if (!ifs) {
  34. return 0;
  35. }
  36. std::ostringstream str;
  37. str << ifs.rdbuf();
  38. return this->Parse(str.str().c_str());
  39. }
  40. int cmXMLParser::InitializeParser()
  41. {
  42. if (this->Parser) {
  43. std::cerr << "Parser already initialized" << std::endl;
  44. this->ParseError = 1;
  45. return 0;
  46. }
  47. // Create the expat XML parser.
  48. this->Parser = XML_ParserCreate(nullptr);
  49. XML_SetElementHandler(static_cast<XML_Parser>(this->Parser),
  50. &cmXMLParserStartElement, &cmXMLParserEndElement);
  51. XML_SetCharacterDataHandler(static_cast<XML_Parser>(this->Parser),
  52. &cmXMLParserCharacterDataHandler);
  53. XML_SetUserData(static_cast<XML_Parser>(this->Parser), this);
  54. this->ParseError = 0;
  55. return 1;
  56. }
  57. int cmXMLParser::ParseChunk(const char* inputString,
  58. std::string::size_type length)
  59. {
  60. if (!this->Parser) {
  61. std::cerr << "Parser not initialized" << std::endl;
  62. this->ParseError = 1;
  63. return 0;
  64. }
  65. int res;
  66. res = this->ParseBuffer(inputString, length);
  67. if (res == 0) {
  68. this->ParseError = 1;
  69. }
  70. return res;
  71. }
  72. int cmXMLParser::CleanupParser()
  73. {
  74. if (!this->Parser) {
  75. std::cerr << "Parser not initialized" << std::endl;
  76. this->ParseError = 1;
  77. return 0;
  78. }
  79. int result = !this->ParseError;
  80. if (result) {
  81. // Tell the expat XML parser about the end-of-input.
  82. if (!XML_Parse(static_cast<XML_Parser>(this->Parser), "", 0, 1)) {
  83. this->ReportXmlParseError();
  84. result = 0;
  85. }
  86. }
  87. // Clean up the parser.
  88. XML_ParserFree(static_cast<XML_Parser>(this->Parser));
  89. this->Parser = nullptr;
  90. return result;
  91. }
  92. int cmXMLParser::ParseBuffer(const char* buffer, std::string::size_type count)
  93. {
  94. // Pass the buffer to the expat XML parser.
  95. if (!XML_Parse(static_cast<XML_Parser>(this->Parser), buffer,
  96. static_cast<int>(count), 0)) {
  97. this->ReportXmlParseError();
  98. return 0;
  99. }
  100. return 1;
  101. }
  102. int cmXMLParser::ParseBuffer(const char* buffer)
  103. {
  104. return this->ParseBuffer(buffer, static_cast<int>(strlen(buffer)));
  105. }
  106. int cmXMLParser::ParsingComplete()
  107. {
  108. // Default behavior is to parse to end of stream.
  109. return 0;
  110. }
  111. void cmXMLParser::StartElement(const std::string& name, const char** /*atts*/)
  112. {
  113. std::cout << "Start element: " << name << std::endl;
  114. }
  115. void cmXMLParser::EndElement(const std::string& name)
  116. {
  117. std::cout << "End element: " << name << std::endl;
  118. }
  119. void cmXMLParser::CharacterDataHandler(const char* /*inData*/,
  120. int /*inLength*/)
  121. {
  122. }
  123. const char* cmXMLParser::FindAttribute(const char** atts,
  124. const char* attribute)
  125. {
  126. if (atts && attribute) {
  127. for (const char** a = atts; *a && *(a + 1); a += 2) {
  128. if (strcmp(*a, attribute) == 0) {
  129. return *(a + 1);
  130. }
  131. }
  132. }
  133. return nullptr;
  134. }
  135. void cmXMLParserStartElement(void* parser, const char* name, const char** atts)
  136. {
  137. // Begin element handler that is registered with the XML_Parser.
  138. // This just casts the user data to a cmXMLParser and calls
  139. // StartElement.
  140. static_cast<cmXMLParser*>(parser)->StartElement(name, atts);
  141. }
  142. void cmXMLParserEndElement(void* parser, const char* name)
  143. {
  144. // End element handler that is registered with the XML_Parser. This
  145. // just casts the user data to a cmXMLParser and calls EndElement.
  146. static_cast<cmXMLParser*>(parser)->EndElement(name);
  147. }
  148. void cmXMLParserCharacterDataHandler(void* parser, const char* data,
  149. int length)
  150. {
  151. // Character data handler that is registered with the XML_Parser.
  152. // This just casts the user data to a cmXMLParser and calls
  153. // CharacterDataHandler.
  154. static_cast<cmXMLParser*>(parser)->CharacterDataHandler(data, length);
  155. }
  156. void cmXMLParser::ReportXmlParseError()
  157. {
  158. XML_Parser parser = static_cast<XML_Parser>(this->Parser);
  159. this->ReportError(static_cast<int>(XML_GetCurrentLineNumber(parser)),
  160. static_cast<int>(XML_GetCurrentColumnNumber(parser)),
  161. XML_ErrorString(XML_GetErrorCode(parser)));
  162. }
  163. void cmXMLParser::ReportError(int line, int /*unused*/, const char* msg)
  164. {
  165. if (this->ReportCallback) {
  166. this->ReportCallback(line, msg, this->ReportCallbackData);
  167. } else {
  168. std::cerr << "Error parsing XML in stream at line " << line << ": " << msg
  169. << std::endl;
  170. }
  171. }