PageRenderTime 154ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/llcommon/llsdserialize_xml.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 934 lines | 877 code | 23 blank | 34 comment | 20 complexity | 898d42fa51f43d4fcb59530c7bf2d29e MD5 | raw file
Possible License(s): LGPL-2.1
  1. /**
  2. * @file llsdserialize_xml.cpp
  3. * @brief XML parsers and formatters for LLSD
  4. *
  5. * $LicenseInfo:firstyear=2006&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. #include "linden_common.h"
  27. #include "llsdserialize_xml.h"
  28. #include <iostream>
  29. #include <deque>
  30. #include "apr_base64.h"
  31. #include <boost/regex.hpp>
  32. extern "C"
  33. {
  34. #ifdef LL_STANDALONE
  35. # include <expat.h>
  36. #else
  37. # include "expat/expat.h"
  38. #endif
  39. }
  40. /**
  41. * LLSDXMLFormatter
  42. */
  43. LLSDXMLFormatter::LLSDXMLFormatter()
  44. {
  45. }
  46. // virtual
  47. LLSDXMLFormatter::~LLSDXMLFormatter()
  48. {
  49. }
  50. // virtual
  51. S32 LLSDXMLFormatter::format(const LLSD& data, std::ostream& ostr, U32 options) const
  52. {
  53. std::streamsize old_precision = ostr.precision(25);
  54. std::string post;
  55. if (options & LLSDFormatter::OPTIONS_PRETTY)
  56. {
  57. post = "\n";
  58. }
  59. ostr << "<llsd>" << post;
  60. S32 rv = format_impl(data, ostr, options, 1);
  61. ostr << "</llsd>\n";
  62. ostr.precision(old_precision);
  63. return rv;
  64. }
  65. S32 LLSDXMLFormatter::format_impl(const LLSD& data, std::ostream& ostr, U32 options, U32 level) const
  66. {
  67. S32 format_count = 1;
  68. std::string pre;
  69. std::string post;
  70. if (options & LLSDFormatter::OPTIONS_PRETTY)
  71. {
  72. for (U32 i = 0; i < level; i++)
  73. {
  74. pre += " ";
  75. }
  76. post = "\n";
  77. }
  78. switch(data.type())
  79. {
  80. case LLSD::TypeMap:
  81. if(0 == data.size())
  82. {
  83. ostr << pre << "<map />" << post;
  84. }
  85. else
  86. {
  87. ostr << pre << "<map>" << post;
  88. LLSD::map_const_iterator iter = data.beginMap();
  89. LLSD::map_const_iterator end = data.endMap();
  90. for(; iter != end; ++iter)
  91. {
  92. ostr << pre << "<key>" << escapeString((*iter).first) << "</key>" << post;
  93. format_count += format_impl((*iter).second, ostr, options, level + 1);
  94. }
  95. ostr << pre << "</map>" << post;
  96. }
  97. break;
  98. case LLSD::TypeArray:
  99. if(0 == data.size())
  100. {
  101. ostr << pre << "<array />" << post;
  102. }
  103. else
  104. {
  105. ostr << pre << "<array>" << post;
  106. LLSD::array_const_iterator iter = data.beginArray();
  107. LLSD::array_const_iterator end = data.endArray();
  108. for(; iter != end; ++iter)
  109. {
  110. format_count += format_impl(*iter, ostr, options, level + 1);
  111. }
  112. ostr << pre << "</array>" << post;
  113. }
  114. break;
  115. case LLSD::TypeUndefined:
  116. ostr << pre << "<undef />" << post;
  117. break;
  118. case LLSD::TypeBoolean:
  119. ostr << pre << "<boolean>";
  120. if(mBoolAlpha ||
  121. (ostr.flags() & std::ios::boolalpha)
  122. )
  123. {
  124. ostr << (data.asBoolean() ? "true" : "false");
  125. }
  126. else
  127. {
  128. ostr << (data.asBoolean() ? 1 : 0);
  129. }
  130. ostr << "</boolean>" << post;
  131. break;
  132. case LLSD::TypeInteger:
  133. ostr << pre << "<integer>" << data.asInteger() << "</integer>" << post;
  134. break;
  135. case LLSD::TypeReal:
  136. ostr << pre << "<real>";
  137. if(mRealFormat.empty())
  138. {
  139. ostr << data.asReal();
  140. }
  141. else
  142. {
  143. formatReal(data.asReal(), ostr);
  144. }
  145. ostr << "</real>" << post;
  146. break;
  147. case LLSD::TypeUUID:
  148. if(data.asUUID().isNull()) ostr << pre << "<uuid />" << post;
  149. else ostr << pre << "<uuid>" << data.asUUID() << "</uuid>" << post;
  150. break;
  151. case LLSD::TypeString:
  152. if(data.asString().empty()) ostr << pre << "<string />" << post;
  153. else ostr << pre << "<string>" << escapeString(data.asString()) <<"</string>" << post;
  154. break;
  155. case LLSD::TypeDate:
  156. ostr << pre << "<date>" << data.asDate() << "</date>" << post;
  157. break;
  158. case LLSD::TypeURI:
  159. ostr << pre << "<uri>" << escapeString(data.asString()) << "</uri>" << post;
  160. break;
  161. case LLSD::TypeBinary:
  162. {
  163. LLSD::Binary buffer = data.asBinary();
  164. if(buffer.empty())
  165. {
  166. ostr << pre << "<binary />" << post;
  167. }
  168. else
  169. {
  170. // *FIX: memory inefficient.
  171. // *TODO: convert to use LLBase64
  172. ostr << pre << "<binary encoding=\"base64\">";
  173. int b64_buffer_length = apr_base64_encode_len(buffer.size());
  174. char* b64_buffer = new char[b64_buffer_length];
  175. b64_buffer_length = apr_base64_encode_binary(
  176. b64_buffer,
  177. &buffer[0],
  178. buffer.size());
  179. ostr.write(b64_buffer, b64_buffer_length - 1);
  180. delete[] b64_buffer;
  181. ostr << "</binary>" << post;
  182. }
  183. break;
  184. }
  185. default:
  186. // *NOTE: This should never happen.
  187. ostr << pre << "<undef />" << post;
  188. break;
  189. }
  190. return format_count;
  191. }
  192. // static
  193. std::string LLSDXMLFormatter::escapeString(const std::string& in)
  194. {
  195. std::ostringstream out;
  196. std::string::const_iterator it = in.begin();
  197. std::string::const_iterator end = in.end();
  198. for(; it != end; ++it)
  199. {
  200. switch((*it))
  201. {
  202. case '<':
  203. out << "&lt;";
  204. break;
  205. case '>':
  206. out << "&gt;";
  207. break;
  208. case '&':
  209. out << "&amp;";
  210. break;
  211. case '\'':
  212. out << "&apos;";
  213. break;
  214. case '"':
  215. out << "&quot;";
  216. break;
  217. default:
  218. out << (*it);
  219. break;
  220. }
  221. }
  222. return out.str();
  223. }
  224. class LLSDXMLParser::Impl
  225. {
  226. public:
  227. Impl();
  228. ~Impl();
  229. S32 parse(std::istream& input, LLSD& data);
  230. S32 parseLines(std::istream& input, LLSD& data);
  231. void parsePart(const char *buf, int len);
  232. void reset();
  233. private:
  234. void startElementHandler(const XML_Char* name, const XML_Char** attributes);
  235. void endElementHandler(const XML_Char* name);
  236. void characterDataHandler(const XML_Char* data, int length);
  237. static void sStartElementHandler(
  238. void* userData, const XML_Char* name, const XML_Char** attributes);
  239. static void sEndElementHandler(
  240. void* userData, const XML_Char* name);
  241. static void sCharacterDataHandler(
  242. void* userData, const XML_Char* data, int length);
  243. void startSkipping();
  244. enum Element {
  245. ELEMENT_LLSD,
  246. ELEMENT_UNDEF,
  247. ELEMENT_BOOL,
  248. ELEMENT_INTEGER,
  249. ELEMENT_REAL,
  250. ELEMENT_STRING,
  251. ELEMENT_UUID,
  252. ELEMENT_DATE,
  253. ELEMENT_URI,
  254. ELEMENT_BINARY,
  255. ELEMENT_MAP,
  256. ELEMENT_ARRAY,
  257. ELEMENT_KEY,
  258. ELEMENT_UNKNOWN
  259. };
  260. static Element readElement(const XML_Char* name);
  261. static const XML_Char* findAttribute(const XML_Char* name, const XML_Char** pairs);
  262. XML_Parser mParser;
  263. LLSD mResult;
  264. S32 mParseCount;
  265. bool mInLLSDElement; // true if we're on LLSD
  266. bool mGracefullStop; // true if we found the </llsd
  267. typedef std::deque<LLSD*> LLSDRefStack;
  268. LLSDRefStack mStack;
  269. int mDepth;
  270. bool mSkipping;
  271. int mSkipThrough;
  272. std::string mCurrentKey; // Current XML <tag>
  273. std::string mCurrentContent; // String data between <tag> and </tag>
  274. };
  275. LLSDXMLParser::Impl::Impl()
  276. {
  277. mParser = XML_ParserCreate(NULL);
  278. reset();
  279. }
  280. LLSDXMLParser::Impl::~Impl()
  281. {
  282. XML_ParserFree(mParser);
  283. }
  284. inline bool is_eol(char c)
  285. {
  286. return (c == '\n' || c == '\r');
  287. }
  288. void clear_eol(std::istream& input)
  289. {
  290. char c = input.peek();
  291. while (input.good() && is_eol(c))
  292. {
  293. input.get(c);
  294. c = input.peek();
  295. }
  296. }
  297. static unsigned get_till_eol(std::istream& input, char *buf, unsigned bufsize)
  298. {
  299. unsigned count = 0;
  300. while (count < bufsize && input.good())
  301. {
  302. char c = input.get();
  303. buf[count++] = c;
  304. if (is_eol(c))
  305. break;
  306. }
  307. return count;
  308. }
  309. S32 LLSDXMLParser::Impl::parse(std::istream& input, LLSD& data)
  310. {
  311. XML_Status status;
  312. static const int BUFFER_SIZE = 1024;
  313. void* buffer = NULL;
  314. int count = 0;
  315. while (input.good() && !input.eof())
  316. {
  317. buffer = XML_GetBuffer(mParser, BUFFER_SIZE);
  318. /*
  319. * If we happened to end our last buffer right at the end of the llsd, but the
  320. * stream is still going we will get a null buffer here. Check for mGracefullStop.
  321. */
  322. if (!buffer)
  323. {
  324. break;
  325. }
  326. {
  327. count = get_till_eol(input, (char *)buffer, BUFFER_SIZE);
  328. if (!count)
  329. {
  330. break;
  331. }
  332. }
  333. status = XML_ParseBuffer(mParser, count, false);
  334. if (status == XML_STATUS_ERROR)
  335. {
  336. break;
  337. }
  338. }
  339. // *FIX.: This code is buggy - if the stream was empty or not
  340. // good, there is not buffer to parse, both the call to
  341. // XML_ParseBuffer and the buffer manipulations are illegal
  342. // futhermore, it isn't clear that the expat buffer semantics are
  343. // preserved
  344. status = XML_ParseBuffer(mParser, 0, true);
  345. if (status == XML_STATUS_ERROR && !mGracefullStop)
  346. {
  347. if (buffer)
  348. {
  349. ((char*) buffer)[count ? count - 1 : 0] = '\0';
  350. }
  351. llinfos << "LLSDXMLParser::Impl::parse: XML_STATUS_ERROR parsing:" << (char*) buffer << llendl;
  352. data = LLSD();
  353. return LLSDParser::PARSE_FAILURE;
  354. }
  355. clear_eol(input);
  356. data = mResult;
  357. return mParseCount;
  358. }
  359. S32 LLSDXMLParser::Impl::parseLines(std::istream& input, LLSD& data)
  360. {
  361. XML_Status status = XML_STATUS_OK;
  362. data = LLSD();
  363. static const int BUFFER_SIZE = 1024;
  364. //static char last_buffer[ BUFFER_SIZE ];
  365. //std::streamsize last_num_read;
  366. // Must get rid of any leading \n, otherwise the stream gets into an error/eof state
  367. clear_eol(input);
  368. while( !mGracefullStop
  369. && input.good()
  370. && !input.eof())
  371. {
  372. void* buffer = XML_GetBuffer(mParser, BUFFER_SIZE);
  373. /*
  374. * If we happened to end our last buffer right at the end of the llsd, but the
  375. * stream is still going we will get a null buffer here. Check for mGracefullStop.
  376. * -- I don't think this is actually true - zero 2008-05-09
  377. */
  378. if (!buffer)
  379. {
  380. break;
  381. }
  382. // Get one line
  383. input.getline((char*)buffer, BUFFER_SIZE);
  384. std::streamsize num_read = input.gcount();
  385. //memcpy( last_buffer, buffer, num_read );
  386. //last_num_read = num_read;
  387. if ( num_read > 0 )
  388. {
  389. if (!input.good() )
  390. { // Clear state that's set when we run out of buffer
  391. input.clear();
  392. }
  393. // Re-insert with the \n that was absorbed by getline()
  394. char * text = (char *) buffer;
  395. if ( text[num_read - 1] == 0)
  396. {
  397. text[num_read - 1] = '\n';
  398. }
  399. }
  400. status = XML_ParseBuffer(mParser, num_read, false);
  401. if (status == XML_STATUS_ERROR)
  402. {
  403. break;
  404. }
  405. }
  406. if (status != XML_STATUS_ERROR
  407. && !mGracefullStop)
  408. { // Parse last bit
  409. status = XML_ParseBuffer(mParser, 0, true);
  410. }
  411. if (status == XML_STATUS_ERROR
  412. && !mGracefullStop)
  413. {
  414. llinfos << "LLSDXMLParser::Impl::parseLines: XML_STATUS_ERROR" << llendl;
  415. return LLSDParser::PARSE_FAILURE;
  416. }
  417. clear_eol(input);
  418. data = mResult;
  419. return mParseCount;
  420. }
  421. void LLSDXMLParser::Impl::reset()
  422. {
  423. mResult.clear();
  424. mParseCount = 0;
  425. mInLLSDElement = false;
  426. mDepth = 0;
  427. mGracefullStop = false;
  428. mStack.clear();
  429. mSkipping = false;
  430. mCurrentKey.clear();
  431. XML_ParserReset(mParser, "utf-8");
  432. XML_SetUserData(mParser, this);
  433. XML_SetElementHandler(mParser, sStartElementHandler, sEndElementHandler);
  434. XML_SetCharacterDataHandler(mParser, sCharacterDataHandler);
  435. }
  436. void LLSDXMLParser::Impl::startSkipping()
  437. {
  438. mSkipping = true;
  439. mSkipThrough = mDepth;
  440. }
  441. const XML_Char*
  442. LLSDXMLParser::Impl::findAttribute(const XML_Char* name, const XML_Char** pairs)
  443. {
  444. while (NULL != pairs && NULL != *pairs)
  445. {
  446. if(0 == strcmp(name, *pairs))
  447. {
  448. return *(pairs + 1);
  449. }
  450. pairs += 2;
  451. }
  452. return NULL;
  453. }
  454. void LLSDXMLParser::Impl::parsePart(const char* buf, int len)
  455. {
  456. if ( buf != NULL
  457. && len > 0 )
  458. {
  459. XML_Status status = XML_Parse(mParser, buf, len, false);
  460. if (status == XML_STATUS_ERROR)
  461. {
  462. llinfos << "Unexpected XML parsing error at start" << llendl;
  463. }
  464. }
  465. }
  466. // Performance testing code
  467. //#define XML_PARSER_PERFORMANCE_TESTS
  468. #ifdef XML_PARSER_PERFORMANCE_TESTS
  469. extern U64 totalTime();
  470. U64 readElementTime = 0;
  471. U64 startElementTime = 0;
  472. U64 endElementTime = 0;
  473. U64 charDataTime = 0;
  474. U64 parseTime = 0;
  475. class XML_Timer
  476. {
  477. public:
  478. XML_Timer( U64 * sum ) : mSum( sum )
  479. {
  480. mStart = totalTime();
  481. }
  482. ~XML_Timer()
  483. {
  484. *mSum += (totalTime() - mStart);
  485. }
  486. U64 * mSum;
  487. U64 mStart;
  488. };
  489. #endif // XML_PARSER_PERFORMANCE_TESTS
  490. void LLSDXMLParser::Impl::startElementHandler(const XML_Char* name, const XML_Char** attributes)
  491. {
  492. #ifdef XML_PARSER_PERFORMANCE_TESTS
  493. XML_Timer timer( &startElementTime );
  494. #endif // XML_PARSER_PERFORMANCE_TESTS
  495. ++mDepth;
  496. if (mSkipping)
  497. {
  498. return;
  499. }
  500. Element element = readElement(name);
  501. mCurrentContent.clear();
  502. switch (element)
  503. {
  504. case ELEMENT_LLSD:
  505. if (mInLLSDElement) { return startSkipping(); }
  506. mInLLSDElement = true;
  507. return;
  508. case ELEMENT_KEY:
  509. if (mStack.empty() || !(mStack.back()->isMap()))
  510. {
  511. return startSkipping();
  512. }
  513. return;
  514. case ELEMENT_BINARY:
  515. {
  516. const XML_Char* encoding = findAttribute("encoding", attributes);
  517. if(encoding && strcmp("base64", encoding) != 0) { return startSkipping(); }
  518. break;
  519. }
  520. default:
  521. // all rest are values, fall through
  522. ;
  523. }
  524. if (!mInLLSDElement) { return startSkipping(); }
  525. if (mStack.empty())
  526. {
  527. mStack.push_back(&mResult);
  528. }
  529. else if (mStack.back()->isMap())
  530. {
  531. if (mCurrentKey.empty()) { return startSkipping(); }
  532. LLSD& map = *mStack.back();
  533. LLSD& newElement = map[mCurrentKey];
  534. mStack.push_back(&newElement);
  535. mCurrentKey.clear();
  536. }
  537. else if (mStack.back()->isArray())
  538. {
  539. LLSD& array = *mStack.back();
  540. array.append(LLSD());
  541. LLSD& newElement = array[array.size()-1];
  542. mStack.push_back(&newElement);
  543. }
  544. else {
  545. // improperly nested value in a non-structure
  546. return startSkipping();
  547. }
  548. ++mParseCount;
  549. switch (element)
  550. {
  551. case ELEMENT_MAP:
  552. *mStack.back() = LLSD::emptyMap();
  553. break;
  554. case ELEMENT_ARRAY:
  555. *mStack.back() = LLSD::emptyArray();
  556. break;
  557. default:
  558. // all the other values will be set in the end element handler
  559. ;
  560. }
  561. }
  562. void LLSDXMLParser::Impl::endElementHandler(const XML_Char* name)
  563. {
  564. #ifdef XML_PARSER_PERFORMANCE_TESTS
  565. XML_Timer timer( &endElementTime );
  566. #endif // XML_PARSER_PERFORMANCE_TESTS
  567. --mDepth;
  568. if (mSkipping)
  569. {
  570. if (mDepth < mSkipThrough)
  571. {
  572. mSkipping = false;
  573. }
  574. return;
  575. }
  576. Element element = readElement(name);
  577. switch (element)
  578. {
  579. case ELEMENT_LLSD:
  580. if (mInLLSDElement)
  581. {
  582. mInLLSDElement = false;
  583. mGracefullStop = true;
  584. XML_StopParser(mParser, false);
  585. }
  586. return;
  587. case ELEMENT_KEY:
  588. mCurrentKey = mCurrentContent;
  589. return;
  590. default:
  591. // all rest are values, fall through
  592. ;
  593. }
  594. if (!mInLLSDElement) { return; }
  595. LLSD& value = *mStack.back();
  596. mStack.pop_back();
  597. switch (element)
  598. {
  599. case ELEMENT_UNDEF:
  600. value.clear();
  601. break;
  602. case ELEMENT_BOOL:
  603. value = (mCurrentContent == "true" || mCurrentContent == "1");
  604. break;
  605. case ELEMENT_INTEGER:
  606. {
  607. S32 i;
  608. // sscanf okay here with different locales - ints don't change for different locale settings like floats do.
  609. if ( sscanf(mCurrentContent.c_str(), "%d", &i ) == 1 )
  610. { // See if sscanf works - it's faster
  611. value = i;
  612. }
  613. else
  614. {
  615. value = LLSD(mCurrentContent).asInteger();
  616. }
  617. }
  618. break;
  619. case ELEMENT_REAL:
  620. {
  621. value = LLSD(mCurrentContent).asReal();
  622. // removed since this breaks when locale has decimal separator that isn't '.'
  623. // investigated changing local to something compatible each time but deemed higher
  624. // risk that just using LLSD.asReal() each time.
  625. //F64 r;
  626. //if ( sscanf(mCurrentContent.c_str(), "%lf", &r ) == 1 )
  627. //{ // See if sscanf works - it's faster
  628. // value = r;
  629. //}
  630. //else
  631. //{
  632. // value = LLSD(mCurrentContent).asReal();
  633. //}
  634. }
  635. break;
  636. case ELEMENT_STRING:
  637. value = mCurrentContent;
  638. break;
  639. case ELEMENT_UUID:
  640. value = LLSD(mCurrentContent).asUUID();
  641. break;
  642. case ELEMENT_DATE:
  643. value = LLSD(mCurrentContent).asDate();
  644. break;
  645. case ELEMENT_URI:
  646. value = LLSD(mCurrentContent).asURI();
  647. break;
  648. case ELEMENT_BINARY:
  649. {
  650. // Regex is expensive, but only fix for whitespace in base64,
  651. // created by python and other non-linden systems - DEV-39358
  652. // Fortunately we have very little binary passing now,
  653. // so performance impact shold be negligible. + poppy 2009-09-04
  654. boost::regex r;
  655. r.assign("\\s");
  656. std::string stripped = boost::regex_replace(mCurrentContent, r, "");
  657. S32 len = apr_base64_decode_len(stripped.c_str());
  658. std::vector<U8> data;
  659. data.resize(len);
  660. len = apr_base64_decode_binary(&data[0], stripped.c_str());
  661. data.resize(len);
  662. value = data;
  663. break;
  664. }
  665. case ELEMENT_UNKNOWN:
  666. value.clear();
  667. break;
  668. default:
  669. // other values, map and array, have already been set
  670. break;
  671. }
  672. mCurrentContent.clear();
  673. }
  674. void LLSDXMLParser::Impl::characterDataHandler(const XML_Char* data, int length)
  675. {
  676. #ifdef XML_PARSER_PERFORMANCE_TESTS
  677. XML_Timer timer( &charDataTime );
  678. #endif // XML_PARSER_PERFORMANCE_TESTS
  679. mCurrentContent.append(data, length);
  680. }
  681. void LLSDXMLParser::Impl::sStartElementHandler(
  682. void* userData, const XML_Char* name, const XML_Char** attributes)
  683. {
  684. ((LLSDXMLParser::Impl*)userData)->startElementHandler(name, attributes);
  685. }
  686. void LLSDXMLParser::Impl::sEndElementHandler(
  687. void* userData, const XML_Char* name)
  688. {
  689. ((LLSDXMLParser::Impl*)userData)->endElementHandler(name);
  690. }
  691. void LLSDXMLParser::Impl::sCharacterDataHandler(
  692. void* userData, const XML_Char* data, int length)
  693. {
  694. ((LLSDXMLParser::Impl*)userData)->characterDataHandler(data, length);
  695. }
  696. /*
  697. This code is time critical
  698. This is a sample of tag occurances of text in simstate file with ~8000 objects.
  699. A tag pair (<key>something</key>) counts is counted as two:
  700. key - 2680178
  701. real - 1818362
  702. integer - 906078
  703. array - 295682
  704. map - 191818
  705. uuid - 177903
  706. binary - 175748
  707. string - 53482
  708. undef - 40353
  709. boolean - 33874
  710. llsd - 16332
  711. uri - 38
  712. date - 1
  713. */
  714. LLSDXMLParser::Impl::Element LLSDXMLParser::Impl::readElement(const XML_Char* name)
  715. {
  716. #ifdef XML_PARSER_PERFORMANCE_TESTS
  717. XML_Timer timer( &readElementTime );
  718. #endif // XML_PARSER_PERFORMANCE_TESTS
  719. XML_Char c = *name;
  720. switch (c)
  721. {
  722. case 'k':
  723. if (strcmp(name, "key") == 0) { return ELEMENT_KEY; }
  724. break;
  725. case 'r':
  726. if (strcmp(name, "real") == 0) { return ELEMENT_REAL; }
  727. break;
  728. case 'i':
  729. if (strcmp(name, "integer") == 0) { return ELEMENT_INTEGER; }
  730. break;
  731. case 'a':
  732. if (strcmp(name, "array") == 0) { return ELEMENT_ARRAY; }
  733. break;
  734. case 'm':
  735. if (strcmp(name, "map") == 0) { return ELEMENT_MAP; }
  736. break;
  737. case 'u':
  738. if (strcmp(name, "uuid") == 0) { return ELEMENT_UUID; }
  739. if (strcmp(name, "undef") == 0) { return ELEMENT_UNDEF; }
  740. if (strcmp(name, "uri") == 0) { return ELEMENT_URI; }
  741. break;
  742. case 'b':
  743. if (strcmp(name, "binary") == 0) { return ELEMENT_BINARY; }
  744. if (strcmp(name, "boolean") == 0) { return ELEMENT_BOOL; }
  745. break;
  746. case 's':
  747. if (strcmp(name, "string") == 0) { return ELEMENT_STRING; }
  748. break;
  749. case 'l':
  750. if (strcmp(name, "llsd") == 0) { return ELEMENT_LLSD; }
  751. break;
  752. case 'd':
  753. if (strcmp(name, "date") == 0) { return ELEMENT_DATE; }
  754. break;
  755. }
  756. return ELEMENT_UNKNOWN;
  757. }
  758. /**
  759. * LLSDXMLParser
  760. */
  761. LLSDXMLParser::LLSDXMLParser() : impl(* new Impl)
  762. {
  763. }
  764. LLSDXMLParser::~LLSDXMLParser()
  765. {
  766. delete &impl;
  767. }
  768. void LLSDXMLParser::parsePart(const char *buf, int len)
  769. {
  770. impl.parsePart(buf, len);
  771. }
  772. // virtual
  773. S32 LLSDXMLParser::doParse(std::istream& input, LLSD& data) const
  774. {
  775. #ifdef XML_PARSER_PERFORMANCE_TESTS
  776. XML_Timer timer( &parseTime );
  777. #endif // XML_PARSER_PERFORMANCE_TESTS
  778. if (mParseLines)
  779. {
  780. // Use line-based reading (faster code)
  781. return impl.parseLines(input, data);
  782. }
  783. return impl.parse(input, data);
  784. }
  785. // virtual
  786. void LLSDXMLParser::doReset()
  787. {
  788. impl.reset();
  789. }