XMLRawParser.cpp 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. //==============================================================================
  2. //
  3. // XMLParser - the XML parser class
  4. //
  5. // Copyright (C) 2018 Dick van Oudheusden
  6. //
  7. // This library is free software; you can redistribute it and/or
  8. // modify it under the terms of the GNU Lesser General Public
  9. // License as published by the Free Software Foundation; either
  10. // version 3 of the License, or (at your option) any later version.
  11. //
  12. // This library is distributed in the hope that it will be useful,
  13. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. // Lesser General Public License for more details.
  16. //
  17. // You should have received a copy of the GNU Lesser General Public
  18. // License along with this library; if not, write to the Free
  19. // Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20. //
  21. //==============================================================================
  22. #include <string>
  23. #include <cstring>
  24. #include "XMLRawParser.h"
  25. namespace gpxtools
  26. {
  27. XMLRawParser::XMLRawParser(XMLParserHandler *handler) :
  28. _handler(handler),
  29. _parser(nullptr),
  30. _path(""),
  31. _errorText(),
  32. _errorLineNumber(0),
  33. _errorColumnNumber(0),
  34. _lastXMLItem(NOTHING),
  35. _lastName(),
  36. _lastPath(),
  37. _lastAttributes(),
  38. _buffer(),
  39. _startByteIndex(0)
  40. {
  41. }
  42. XMLRawParser::~XMLRawParser()
  43. {
  44. if (_parser != nullptr)
  45. {
  46. stopExpat();
  47. }
  48. }
  49. // Parsing
  50. bool XMLRawParser::parse(const char *data, std::size_t length, bool isFinal)
  51. {
  52. bool ok = false;
  53. if (_parser == nullptr)
  54. {
  55. startExpat();
  56. if (_parser == nullptr) return false;
  57. _buffer.clear();
  58. _startByteIndex = 0;
  59. _path.clear();
  60. _errorText.clear();
  61. _errorLineNumber = 0;
  62. _errorColumnNumber = 0;
  63. }
  64. _buffer.append(data, length);
  65. ok = (XML_Parse(_parser, data, int(length), isFinal) != XML_STATUS_ERROR);
  66. if (!ok)
  67. {
  68. _errorText = XML_ErrorString(XML_GetErrorCode(_parser));
  69. _errorLineNumber = XML_GetCurrentLineNumber(_parser);
  70. _errorColumnNumber = XML_GetCurrentColumnNumber(_parser);
  71. }
  72. if (isFinal)
  73. {
  74. sendLast(_buffer);
  75. stopExpat();
  76. }
  77. return ok;
  78. }
  79. bool XMLRawParser::parse(const char *text, bool isFinal)
  80. {
  81. return parse(text, strlen(text), isFinal);
  82. }
  83. bool XMLRawParser::parse(const std::string &data, bool isFinal)
  84. {
  85. return parse(data.c_str(), data.length(), isFinal);
  86. }
  87. // Parse a stream
  88. bool XMLRawParser::parse(std::istream &stream)
  89. {
  90. bool ok = stream.good();
  91. if (ok)
  92. {
  93. char buffer[4096];
  94. while ((ok) && (stream.good()))
  95. {
  96. stream.read(buffer, sizeof(buffer));
  97. ok = parse(buffer, stream.gcount(), (stream.gcount() < sizeof(buffer)));
  98. }
  99. }
  100. return ok;
  101. }
  102. // Buffer
  103. std::string XMLRawParser::readBuffer()
  104. {
  105. if (_parser == nullptr) return std::string();
  106. std::size_t current = std::size_t(XML_GetCurrentByteIndex(_parser));
  107. if (current < _startByteIndex) return std::string();
  108. std::string text = _buffer.substr(0, current - _startByteIndex);
  109. _buffer.erase(0, current - _startByteIndex);
  110. _startByteIndex = current;
  111. return text;
  112. }
  113. // Helpers
  114. void XMLRawParser::trim(std::string &text)
  115. {
  116. std::size_t start = text.find_first_not_of(" \t\r\n");
  117. if (start == std::string::npos)
  118. {
  119. text.clear();
  120. }
  121. else
  122. {
  123. text.erase(0, start);
  124. std::size_t end = text.find_last_not_of(" \t\r\n");
  125. text.erase(end + 1);
  126. }
  127. }
  128. // Store XML items
  129. void XMLRawParser::storeStartElement(const XML_Char *name, const XML_Char **atts)
  130. {
  131. _lastXMLItem = START_ELEMENT;
  132. _lastName = std::string(name);
  133. _lastPath = _path;
  134. _lastAttributes.clear();
  135. for (int i = 0; atts[i] != nullptr; i+=2)
  136. {
  137. _lastAttributes[std::string(atts[i])] = atts[i+1];
  138. }
  139. }
  140. void XMLRawParser::storeEndElement(const XML_Char *name)
  141. {
  142. _lastXMLItem = END_ELEMENT;
  143. _lastName = std::string(name);
  144. _lastPath = _path;
  145. _lastAttributes.clear();
  146. }
  147. void XMLRawParser::storeText()
  148. {
  149. _lastXMLItem = TEXT;
  150. _lastName.clear();
  151. _lastPath = _path;
  152. _lastAttributes.clear();
  153. }
  154. void XMLRawParser::storeUnhandled()
  155. {
  156. _lastXMLItem = UNHANDLED;
  157. _lastName.clear();
  158. _lastPath = _path;
  159. _lastAttributes.clear();
  160. }
  161. void XMLRawParser::sendLast(const std::string &raw)
  162. {
  163. switch(_lastXMLItem)
  164. {
  165. case START_ELEMENT:
  166. _handler->startElement(_lastPath, raw, _lastName, _lastAttributes);
  167. break;
  168. case END_ELEMENT:
  169. _handler->endElement(_lastPath, raw, _lastName);
  170. break;
  171. case TEXT:
  172. _handler->text(_lastPath, raw);
  173. break;
  174. case UNHANDLED:
  175. _handler->unhandled(_lastPath, raw);
  176. break;
  177. case NOTHING:
  178. break;
  179. }
  180. _lastXMLItem = NOTHING;
  181. }
  182. // Privates
  183. void XMLRawParser::startExpat()
  184. {
  185. _parser = XML_ParserCreate(nullptr);
  186. XML_SetUserData(_parser, this);
  187. XML_SetElementHandler(_parser, startElementHandler, endElementHandler);
  188. XML_SetCharacterDataHandler(_parser, characterDataHandler);
  189. XML_SetDefaultHandler(_parser, unhandledHandler);
  190. }
  191. void XMLRawParser::stopExpat()
  192. {
  193. XML_ParserFree(_parser);
  194. _parser = nullptr;
  195. }
  196. void XMLRawParser::startElementHandler(void *userData, const XML_Char *name, const XML_Char **atts)
  197. {
  198. XMLRawParser *self = static_cast<XMLRawParser*>(userData);
  199. self->sendLast(self->readBuffer());
  200. self->_path.append("/");
  201. self->_path.append(name);
  202. self->storeStartElement(name, atts);
  203. }
  204. void XMLRawParser::endElementHandler(void *userData, const XML_Char *name)
  205. {
  206. XMLRawParser *self = static_cast<XMLRawParser*>(userData);
  207. self->sendLast(self->readBuffer());
  208. self->storeEndElement(name);
  209. size_t i = self->_path.find_last_of('/');
  210. if (i != std::string::npos)
  211. {
  212. self->_path.erase(i);
  213. }
  214. }
  215. void XMLRawParser::characterDataHandler(void *userData, const XML_Char *, int)
  216. {
  217. XMLRawParser *self = static_cast<XMLRawParser*>(userData);
  218. self->sendLast(self->readBuffer());
  219. self->storeText();
  220. }
  221. void XMLRawParser::unhandledHandler(void *userData, const XML_Char *, int)
  222. {
  223. XMLRawParser *self = static_cast<XMLRawParser*>(userData);
  224. self->sendLast(self->readBuffer());
  225. self->storeUnhandled();
  226. }
  227. }