/indra/llxml/llxmlparser.cpp

https://bitbucket.org/lindenlab/viewer-beta/ · C++ · 416 lines · 162 code · 47 blank · 207 comment · 7 complexity · 7eb08cb350ddb953b59be1bd6d89add2 MD5 · raw file

  1. /**
  2. * @file llxmlparser.cpp
  3. * @brief LLXmlParser implementation
  4. *
  5. * $LicenseInfo:firstyear=2002&license=viewerlgpl$
  6. * Second Life Viewer Source Code
  7. * Copyright (C) 2010, Linden Research, Inc.
  8. *
  9. * This library is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU Lesser General Public
  11. * License as published by the Free Software Foundation;
  12. * version 2.1 of the License only.
  13. *
  14. * This library is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * Lesser General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Lesser General Public
  20. * License along with this library; if not, write to the Free Software
  21. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  22. *
  23. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  24. * $/LicenseInfo$
  25. */
  26. // llxmlparser.cpp
  27. //
  28. // copyright 2002, linden research inc
  29. #include "linden_common.h"
  30. #include "llxmlparser.h"
  31. #include "llerror.h"
  32. LLXmlParser::LLXmlParser()
  33. :
  34. mParser( NULL ),
  35. mDepth( 0 )
  36. {
  37. mAuxErrorString = "no error";
  38. // Override the document's declared encoding.
  39. mParser = XML_ParserCreate(NULL);
  40. XML_SetUserData(mParser, this);
  41. XML_SetElementHandler( mParser, startElementHandler, endElementHandler);
  42. XML_SetCharacterDataHandler( mParser, characterDataHandler);
  43. XML_SetProcessingInstructionHandler( mParser, processingInstructionHandler);
  44. XML_SetCommentHandler( mParser, commentHandler);
  45. XML_SetCdataSectionHandler( mParser, startCdataSectionHandler, endCdataSectionHandler);
  46. // This sets the default handler but does not inhibit expansion of internal entities.
  47. // The entity reference will not be passed to the default handler.
  48. XML_SetDefaultHandlerExpand( mParser, defaultDataHandler);
  49. XML_SetUnparsedEntityDeclHandler( mParser, unparsedEntityDeclHandler);
  50. }
  51. LLXmlParser::~LLXmlParser()
  52. {
  53. XML_ParserFree( mParser );
  54. }
  55. BOOL LLXmlParser::parseFile(const std::string &path)
  56. {
  57. llassert( !mDepth );
  58. BOOL success = TRUE;
  59. LLFILE* file = LLFile::fopen(path, "rb"); /* Flawfinder: ignore */
  60. if( !file )
  61. {
  62. mAuxErrorString = llformat( "Couldn't open file %s", path.c_str());
  63. success = FALSE;
  64. }
  65. else
  66. {
  67. S32 bytes_read = 0;
  68. fseek(file, 0L, SEEK_END);
  69. S32 buffer_size = ftell(file);
  70. fseek(file, 0L, SEEK_SET);
  71. void* buffer = XML_GetBuffer(mParser, buffer_size);
  72. if( !buffer )
  73. {
  74. mAuxErrorString = llformat( "Unable to allocate XML buffer while reading file %s", path.c_str() );
  75. success = FALSE;
  76. goto exit_label;
  77. }
  78. bytes_read = (S32)fread(buffer, 1, buffer_size, file);
  79. if( bytes_read <= 0 )
  80. {
  81. mAuxErrorString = llformat( "Error while reading file %s", path.c_str() );
  82. success = FALSE;
  83. goto exit_label;
  84. }
  85. if( !XML_ParseBuffer(mParser, bytes_read, TRUE ) )
  86. {
  87. mAuxErrorString = llformat( "Error while parsing file %s", path.c_str() );
  88. success = FALSE;
  89. }
  90. exit_label:
  91. fclose( file );
  92. }
  93. if( success )
  94. {
  95. llassert( !mDepth );
  96. }
  97. mDepth = 0;
  98. if( !success )
  99. {
  100. llwarns << mAuxErrorString << llendl;
  101. }
  102. return success;
  103. }
  104. // Parses some input. Returns 0 if a fatal error is detected.
  105. // The last call must have isFinal true;
  106. // len may be zero for this call (or any other).
  107. S32 LLXmlParser::parse( const char* buf, int len, int isFinal )
  108. {
  109. return XML_Parse(mParser, buf, len, isFinal);
  110. }
  111. const char* LLXmlParser::getErrorString()
  112. {
  113. const char* error_string = XML_ErrorString(XML_GetErrorCode( mParser ));
  114. if( !error_string )
  115. {
  116. error_string = mAuxErrorString.c_str();
  117. }
  118. return error_string;
  119. }
  120. S32 LLXmlParser::getCurrentLineNumber()
  121. {
  122. return XML_GetCurrentLineNumber( mParser );
  123. }
  124. S32 LLXmlParser::getCurrentColumnNumber()
  125. {
  126. return XML_GetCurrentColumnNumber(mParser);
  127. }
  128. ///////////////////////////////////////////////////////////////////////////////
  129. // Pseudo-private methods. These are only used by internal callbacks.
  130. // static
  131. void LLXmlParser::startElementHandler(
  132. void *userData,
  133. const XML_Char *name,
  134. const XML_Char **atts)
  135. {
  136. LLXmlParser* self = (LLXmlParser*) userData;
  137. self->startElement( name, atts );
  138. self->mDepth++;
  139. }
  140. // static
  141. void LLXmlParser::endElementHandler(
  142. void *userData,
  143. const XML_Char *name)
  144. {
  145. LLXmlParser* self = (LLXmlParser*) userData;
  146. self->mDepth--;
  147. self->endElement( name );
  148. }
  149. // s is not 0 terminated.
  150. // static
  151. void LLXmlParser::characterDataHandler(
  152. void *userData,
  153. const XML_Char *s,
  154. int len)
  155. {
  156. LLXmlParser* self = (LLXmlParser*) userData;
  157. self->characterData( s, len );
  158. }
  159. // target and data are 0 terminated
  160. // static
  161. void LLXmlParser::processingInstructionHandler(
  162. void *userData,
  163. const XML_Char *target,
  164. const XML_Char *data)
  165. {
  166. LLXmlParser* self = (LLXmlParser*) userData;
  167. self->processingInstruction( target, data );
  168. }
  169. // data is 0 terminated
  170. // static
  171. void LLXmlParser::commentHandler(void *userData, const XML_Char *data)
  172. {
  173. LLXmlParser* self = (LLXmlParser*) userData;
  174. self->comment( data );
  175. }
  176. // static
  177. void LLXmlParser::startCdataSectionHandler(void *userData)
  178. {
  179. LLXmlParser* self = (LLXmlParser*) userData;
  180. self->mDepth++;
  181. self->startCdataSection();
  182. }
  183. // static
  184. void LLXmlParser::endCdataSectionHandler(void *userData)
  185. {
  186. LLXmlParser* self = (LLXmlParser*) userData;
  187. self->endCdataSection();
  188. self->mDepth++;
  189. }
  190. // This is called for any characters in the XML document for
  191. // which there is no applicable handler. This includes both
  192. // characters that are part of markup which is of a kind that is
  193. // not reported (comments, markup declarations), or characters
  194. // that are part of a construct which could be reported but
  195. // for which no handler has been supplied. The characters are passed
  196. // exactly as they were in the XML document except that
  197. // they will be encoded in UTF-8. Line boundaries are not normalized.
  198. // Note that a byte order mark character is not passed to the default handler.
  199. // There are no guarantees about how characters are divided between calls
  200. // to the default handler: for example, a comment might be split between
  201. // multiple calls.
  202. // static
  203. void LLXmlParser::defaultDataHandler(
  204. void *userData,
  205. const XML_Char *s,
  206. int len)
  207. {
  208. LLXmlParser* self = (LLXmlParser*) userData;
  209. self->defaultData( s, len );
  210. }
  211. // This is called for a declaration of an unparsed (NDATA)
  212. // entity. The base argument is whatever was set by XML_SetBase.
  213. // The entityName, systemId and notationName arguments will never be null.
  214. // The other arguments may be.
  215. // static
  216. void LLXmlParser::unparsedEntityDeclHandler(
  217. void *userData,
  218. const XML_Char *entityName,
  219. const XML_Char *base,
  220. const XML_Char *systemId,
  221. const XML_Char *publicId,
  222. const XML_Char *notationName)
  223. {
  224. LLXmlParser* self = (LLXmlParser*) userData;
  225. self->unparsedEntityDecl( entityName, base, systemId, publicId, notationName );
  226. }
  227. ////////////////////////////////////////////////////////////////////
  228. // Test code.
  229. /*
  230. class LLXmlDOMParser : public LLXmlParser
  231. {
  232. public:
  233. LLXmlDOMParser() {}
  234. virtual ~LLXmlDOMParser() {}
  235. void tabs()
  236. {
  237. for ( int i = 0; i < getDepth(); i++)
  238. {
  239. putchar(' ');
  240. }
  241. }
  242. virtual void startElement(const char *name, const char **atts)
  243. {
  244. tabs();
  245. printf("startElement %s\n", name);
  246. S32 i = 0;
  247. while( atts[i] && atts[i+1] )
  248. {
  249. tabs();
  250. printf( "\t%s=%s\n", atts[i], atts[i+1] );
  251. i += 2;
  252. }
  253. if( atts[i] )
  254. {
  255. tabs();
  256. printf( "\ttrailing attribute: %s\n", atts[i] );
  257. }
  258. }
  259. virtual void endElement(const char *name)
  260. {
  261. tabs();
  262. printf("endElement %s\n", name);
  263. }
  264. virtual void characterData(const char *s, int len)
  265. {
  266. tabs();
  267. char* str = new char[len+1];
  268. strncpy( str, s, len );
  269. str[len] = '\0';
  270. printf("CharacterData %s\n", str);
  271. delete str;
  272. }
  273. virtual void processingInstruction(const char *target, const char *data)
  274. {
  275. tabs();
  276. printf("processingInstruction %s\n", data);
  277. }
  278. virtual void comment(const char *data)
  279. {
  280. tabs();
  281. printf("comment %s\n", data);
  282. }
  283. virtual void startCdataSection()
  284. {
  285. tabs();
  286. printf("startCdataSection\n");
  287. }
  288. virtual void endCdataSection()
  289. {
  290. tabs();
  291. printf("endCdataSection\n");
  292. }
  293. virtual void defaultData(const char *s, int len)
  294. {
  295. tabs();
  296. char* str = new char[len+1];
  297. strncpy( str, s, len );
  298. str[len] = '\0';
  299. printf("defaultData %s\n", str);
  300. delete str;
  301. }
  302. virtual void unparsedEntityDecl(
  303. const char *entityName,
  304. const char *base,
  305. const char *systemId,
  306. const char *publicId,
  307. const char *notationName)
  308. {
  309. tabs();
  310. printf(
  311. "unparsed entity:\n"
  312. "\tentityName %s\n"
  313. "\tbase %s\n"
  314. "\tsystemId %s\n"
  315. "\tpublicId %s\n"
  316. "\tnotationName %s\n",
  317. entityName,
  318. base,
  319. systemId,
  320. publicId,
  321. notationName );
  322. }
  323. };
  324. int main()
  325. {
  326. char buf[1024];
  327. LLFILE* file = LLFile::fopen("test.xml", "rb");
  328. if( !file )
  329. {
  330. return 1;
  331. }
  332. LLXmlDOMParser parser;
  333. int done;
  334. do {
  335. size_t len = fread(buf, 1, sizeof(buf), file);
  336. done = len < sizeof(buf);
  337. if( 0 == parser.parse( buf, len, done) )
  338. {
  339. fprintf(stderr,
  340. "%s at line %d\n",
  341. parser.getErrorString(),
  342. parser.getCurrentLineNumber() );
  343. return 1;
  344. }
  345. } while (!done);
  346. fclose( file );
  347. return 0;
  348. }
  349. */