PageRenderTime 39ms CodeModel.GetById 15ms RepoModel.GetById 3ms app.codeStats 1ms

/indra/llxml/llxmltree.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 692 lines | 529 code | 100 blank | 63 comment | 60 complexity | d4ef1470132690ba358672fdbd3e7179 MD5 | raw file
Possible License(s): LGPL-2.1
  1. /**
  2. * @file llxmltree.cpp
  3. * @brief LLXmlTree 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. #include "linden_common.h"
  27. #include "llxmltree.h"
  28. #include "v3color.h"
  29. #include "v4color.h"
  30. #include "v4coloru.h"
  31. #include "v3math.h"
  32. #include "v3dmath.h"
  33. #include "v4math.h"
  34. #include "llquaternion.h"
  35. #include "lluuid.h"
  36. //////////////////////////////////////////////////////////////
  37. // LLXmlTree
  38. // static
  39. LLStdStringTable LLXmlTree::sAttributeKeys(1024);
  40. LLXmlTree::LLXmlTree()
  41. : mRoot( NULL ),
  42. mNodeNames(512)
  43. {
  44. }
  45. LLXmlTree::~LLXmlTree()
  46. {
  47. cleanup();
  48. }
  49. void LLXmlTree::cleanup()
  50. {
  51. delete mRoot;
  52. mRoot = NULL;
  53. mNodeNames.cleanup();
  54. }
  55. BOOL LLXmlTree::parseFile(const std::string &path, BOOL keep_contents)
  56. {
  57. delete mRoot;
  58. mRoot = NULL;
  59. LLXmlTreeParser parser(this);
  60. BOOL success = parser.parseFile( path, &mRoot, keep_contents );
  61. if( !success )
  62. {
  63. S32 line_number = parser.getCurrentLineNumber();
  64. const char* error = parser.getErrorString();
  65. llwarns << "LLXmlTree parse failed. Line " << line_number << ": " << error << llendl;
  66. }
  67. return success;
  68. }
  69. void LLXmlTree::dump()
  70. {
  71. if( mRoot )
  72. {
  73. dumpNode( mRoot, " " );
  74. }
  75. }
  76. void LLXmlTree::dumpNode( LLXmlTreeNode* node, const std::string& prefix )
  77. {
  78. node->dump( prefix );
  79. std::string new_prefix = prefix + " ";
  80. for( LLXmlTreeNode* child = node->getFirstChild(); child; child = node->getNextChild() )
  81. {
  82. dumpNode( child, new_prefix );
  83. }
  84. }
  85. //////////////////////////////////////////////////////////////
  86. // LLXmlTreeNode
  87. LLXmlTreeNode::LLXmlTreeNode( const std::string& name, LLXmlTreeNode* parent, LLXmlTree* tree )
  88. : mName(name),
  89. mParent(parent),
  90. mTree(tree)
  91. {
  92. }
  93. LLXmlTreeNode::~LLXmlTreeNode()
  94. {
  95. attribute_map_t::iterator iter;
  96. for (iter=mAttributes.begin(); iter != mAttributes.end(); iter++)
  97. delete iter->second;
  98. child_list_t::iterator child_iter;
  99. for (child_iter=mChildList.begin(); child_iter != mChildList.end(); child_iter++)
  100. delete *child_iter;
  101. }
  102. void LLXmlTreeNode::dump( const std::string& prefix )
  103. {
  104. llinfos << prefix << mName ;
  105. if( !mContents.empty() )
  106. {
  107. llcont << " contents = \"" << mContents << "\"";
  108. }
  109. attribute_map_t::iterator iter;
  110. for (iter=mAttributes.begin(); iter != mAttributes.end(); iter++)
  111. {
  112. LLStdStringHandle key = iter->first;
  113. const std::string* value = iter->second;
  114. llcont << prefix << " " << key << "=" << (value->empty() ? "NULL" : *value);
  115. }
  116. llcont << llendl;
  117. }
  118. BOOL LLXmlTreeNode::hasAttribute(const std::string& name)
  119. {
  120. LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
  121. attribute_map_t::iterator iter = mAttributes.find(canonical_name);
  122. return (iter == mAttributes.end()) ? false : true;
  123. }
  124. void LLXmlTreeNode::addAttribute(const std::string& name, const std::string& value)
  125. {
  126. LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
  127. const std::string *newstr = new std::string(value);
  128. mAttributes[canonical_name] = newstr; // insert + copy
  129. }
  130. LLXmlTreeNode* LLXmlTreeNode::getFirstChild()
  131. {
  132. mChildListIter = mChildList.begin();
  133. return getNextChild();
  134. }
  135. LLXmlTreeNode* LLXmlTreeNode::getNextChild()
  136. {
  137. if (mChildListIter == mChildList.end())
  138. return 0;
  139. else
  140. return *mChildListIter++;
  141. }
  142. LLXmlTreeNode* LLXmlTreeNode::getChildByName(const std::string& name)
  143. {
  144. LLStdStringHandle tableptr = mTree->mNodeNames.checkString(name);
  145. mChildMapIter = mChildMap.lower_bound(tableptr);
  146. mChildMapEndIter = mChildMap.upper_bound(tableptr);
  147. return getNextNamedChild();
  148. }
  149. LLXmlTreeNode* LLXmlTreeNode::getNextNamedChild()
  150. {
  151. if (mChildMapIter == mChildMapEndIter)
  152. return NULL;
  153. else
  154. return (mChildMapIter++)->second;
  155. }
  156. void LLXmlTreeNode::appendContents(const std::string& str)
  157. {
  158. mContents.append( str );
  159. }
  160. void LLXmlTreeNode::addChild(LLXmlTreeNode* child)
  161. {
  162. llassert( child );
  163. mChildList.push_back( child );
  164. // Add a name mapping to this node
  165. LLStdStringHandle tableptr = mTree->mNodeNames.insert(child->mName);
  166. mChildMap.insert( child_map_t::value_type(tableptr, child));
  167. child->mParent = this;
  168. }
  169. //////////////////////////////////////////////////////////////
  170. // These functions assume that name is already in mAttritrubteKeys
  171. BOOL LLXmlTreeNode::getFastAttributeBOOL(LLStdStringHandle canonical_name, BOOL& value)
  172. {
  173. const std::string *s = getAttribute( canonical_name );
  174. return s && LLStringUtil::convertToBOOL( *s, value );
  175. }
  176. BOOL LLXmlTreeNode::getFastAttributeU8(LLStdStringHandle canonical_name, U8& value)
  177. {
  178. const std::string *s = getAttribute( canonical_name );
  179. return s && LLStringUtil::convertToU8( *s, value );
  180. }
  181. BOOL LLXmlTreeNode::getFastAttributeS8(LLStdStringHandle canonical_name, S8& value)
  182. {
  183. const std::string *s = getAttribute( canonical_name );
  184. return s && LLStringUtil::convertToS8( *s, value );
  185. }
  186. BOOL LLXmlTreeNode::getFastAttributeS16(LLStdStringHandle canonical_name, S16& value)
  187. {
  188. const std::string *s = getAttribute( canonical_name );
  189. return s && LLStringUtil::convertToS16( *s, value );
  190. }
  191. BOOL LLXmlTreeNode::getFastAttributeU16(LLStdStringHandle canonical_name, U16& value)
  192. {
  193. const std::string *s = getAttribute( canonical_name );
  194. return s && LLStringUtil::convertToU16( *s, value );
  195. }
  196. BOOL LLXmlTreeNode::getFastAttributeU32(LLStdStringHandle canonical_name, U32& value)
  197. {
  198. const std::string *s = getAttribute( canonical_name );
  199. return s && LLStringUtil::convertToU32( *s, value );
  200. }
  201. BOOL LLXmlTreeNode::getFastAttributeS32(LLStdStringHandle canonical_name, S32& value)
  202. {
  203. const std::string *s = getAttribute( canonical_name );
  204. return s && LLStringUtil::convertToS32( *s, value );
  205. }
  206. BOOL LLXmlTreeNode::getFastAttributeF32(LLStdStringHandle canonical_name, F32& value)
  207. {
  208. const std::string *s = getAttribute( canonical_name );
  209. return s && LLStringUtil::convertToF32( *s, value );
  210. }
  211. BOOL LLXmlTreeNode::getFastAttributeF64(LLStdStringHandle canonical_name, F64& value)
  212. {
  213. const std::string *s = getAttribute( canonical_name );
  214. return s && LLStringUtil::convertToF64( *s, value );
  215. }
  216. BOOL LLXmlTreeNode::getFastAttributeColor(LLStdStringHandle canonical_name, LLColor4& value)
  217. {
  218. const std::string *s = getAttribute( canonical_name );
  219. return s ? LLColor4::parseColor(*s, &value) : FALSE;
  220. }
  221. BOOL LLXmlTreeNode::getFastAttributeColor4(LLStdStringHandle canonical_name, LLColor4& value)
  222. {
  223. const std::string *s = getAttribute( canonical_name );
  224. return s ? LLColor4::parseColor4(*s, &value) : FALSE;
  225. }
  226. BOOL LLXmlTreeNode::getFastAttributeColor4U(LLStdStringHandle canonical_name, LLColor4U& value)
  227. {
  228. const std::string *s = getAttribute( canonical_name );
  229. return s ? LLColor4U::parseColor4U(*s, &value ) : FALSE;
  230. }
  231. BOOL LLXmlTreeNode::getFastAttributeVector3(LLStdStringHandle canonical_name, LLVector3& value)
  232. {
  233. const std::string *s = getAttribute( canonical_name );
  234. return s ? LLVector3::parseVector3(*s, &value ) : FALSE;
  235. }
  236. BOOL LLXmlTreeNode::getFastAttributeVector3d(LLStdStringHandle canonical_name, LLVector3d& value)
  237. {
  238. const std::string *s = getAttribute( canonical_name );
  239. return s ? LLVector3d::parseVector3d(*s, &value ) : FALSE;
  240. }
  241. BOOL LLXmlTreeNode::getFastAttributeQuat(LLStdStringHandle canonical_name, LLQuaternion& value)
  242. {
  243. const std::string *s = getAttribute( canonical_name );
  244. return s ? LLQuaternion::parseQuat(*s, &value ) : FALSE;
  245. }
  246. BOOL LLXmlTreeNode::getFastAttributeUUID(LLStdStringHandle canonical_name, LLUUID& value)
  247. {
  248. const std::string *s = getAttribute( canonical_name );
  249. return s ? LLUUID::parseUUID(*s, &value ) : FALSE;
  250. }
  251. BOOL LLXmlTreeNode::getFastAttributeString(LLStdStringHandle canonical_name, std::string& value)
  252. {
  253. const std::string *s = getAttribute( canonical_name );
  254. if( !s )
  255. {
  256. return FALSE;
  257. }
  258. value = *s;
  259. return TRUE;
  260. }
  261. //////////////////////////////////////////////////////////////
  262. BOOL LLXmlTreeNode::getAttributeBOOL(const std::string& name, BOOL& value)
  263. {
  264. LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
  265. return getFastAttributeBOOL(canonical_name, value);
  266. }
  267. BOOL LLXmlTreeNode::getAttributeU8(const std::string& name, U8& value)
  268. {
  269. LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
  270. return getFastAttributeU8(canonical_name, value);
  271. }
  272. BOOL LLXmlTreeNode::getAttributeS8(const std::string& name, S8& value)
  273. {
  274. LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
  275. return getFastAttributeS8(canonical_name, value);
  276. }
  277. BOOL LLXmlTreeNode::getAttributeS16(const std::string& name, S16& value)
  278. {
  279. LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
  280. return getFastAttributeS16(canonical_name, value);
  281. }
  282. BOOL LLXmlTreeNode::getAttributeU16(const std::string& name, U16& value)
  283. {
  284. LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
  285. return getFastAttributeU16(canonical_name, value);
  286. }
  287. BOOL LLXmlTreeNode::getAttributeU32(const std::string& name, U32& value)
  288. {
  289. LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
  290. return getFastAttributeU32(canonical_name, value);
  291. }
  292. BOOL LLXmlTreeNode::getAttributeS32(const std::string& name, S32& value)
  293. {
  294. LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
  295. return getFastAttributeS32(canonical_name, value);
  296. }
  297. BOOL LLXmlTreeNode::getAttributeF32(const std::string& name, F32& value)
  298. {
  299. LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
  300. return getFastAttributeF32(canonical_name, value);
  301. }
  302. BOOL LLXmlTreeNode::getAttributeF64(const std::string& name, F64& value)
  303. {
  304. LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
  305. return getFastAttributeF64(canonical_name, value);
  306. }
  307. BOOL LLXmlTreeNode::getAttributeColor(const std::string& name, LLColor4& value)
  308. {
  309. LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
  310. return getFastAttributeColor(canonical_name, value);
  311. }
  312. BOOL LLXmlTreeNode::getAttributeColor4(const std::string& name, LLColor4& value)
  313. {
  314. LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
  315. return getFastAttributeColor4(canonical_name, value);
  316. }
  317. BOOL LLXmlTreeNode::getAttributeColor4U(const std::string& name, LLColor4U& value)
  318. {
  319. LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
  320. return getFastAttributeColor4U(canonical_name, value);
  321. }
  322. BOOL LLXmlTreeNode::getAttributeVector3(const std::string& name, LLVector3& value)
  323. {
  324. LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
  325. return getFastAttributeVector3(canonical_name, value);
  326. }
  327. BOOL LLXmlTreeNode::getAttributeVector3d(const std::string& name, LLVector3d& value)
  328. {
  329. LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
  330. return getFastAttributeVector3d(canonical_name, value);
  331. }
  332. BOOL LLXmlTreeNode::getAttributeQuat(const std::string& name, LLQuaternion& value)
  333. {
  334. LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
  335. return getFastAttributeQuat(canonical_name, value);
  336. }
  337. BOOL LLXmlTreeNode::getAttributeUUID(const std::string& name, LLUUID& value)
  338. {
  339. LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
  340. return getFastAttributeUUID(canonical_name, value);
  341. }
  342. BOOL LLXmlTreeNode::getAttributeString(const std::string& name, std::string& value)
  343. {
  344. LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
  345. return getFastAttributeString(canonical_name, value);
  346. }
  347. /*
  348. The following xml <message> nodes will all return the string from getTextContents():
  349. "The quick brown fox\n Jumps over the lazy dog"
  350. 1. HTML paragraph format:
  351. <message>
  352. <p>The quick brown fox</p>
  353. <p> Jumps over the lazy dog</p>
  354. </message>
  355. 2. Each quoted section -> paragraph:
  356. <message>
  357. "The quick brown fox"
  358. " Jumps over the lazy dog"
  359. </message>
  360. 3. Literal text with beginning and trailing whitespace removed:
  361. <message>
  362. The quick brown fox
  363. Jumps over the lazy dog
  364. </message>
  365. */
  366. std::string LLXmlTreeNode::getTextContents()
  367. {
  368. std::string msg;
  369. LLXmlTreeNode* p = getChildByName("p");
  370. if (p)
  371. {
  372. // Case 1: node has <p>text</p> tags
  373. while (p)
  374. {
  375. msg += p->getContents() + "\n";
  376. p = getNextNamedChild();
  377. }
  378. }
  379. else
  380. {
  381. std::string::size_type n = mContents.find_first_not_of(" \t\n");
  382. if (n != std::string::npos && mContents[n] == '\"')
  383. {
  384. // Case 2: node has quoted text
  385. S32 num_lines = 0;
  386. while(1)
  387. {
  388. // mContents[n] == '"'
  389. ++n;
  390. std::string::size_type t = n;
  391. std::string::size_type m = 0;
  392. // fix-up escaped characters
  393. while(1)
  394. {
  395. m = mContents.find_first_of("\\\"", t); // find first \ or "
  396. if ((m == std::string::npos) || (mContents[m] == '\"'))
  397. {
  398. break;
  399. }
  400. mContents.erase(m,1);
  401. t = m+1;
  402. }
  403. if (m == std::string::npos)
  404. {
  405. break;
  406. }
  407. // mContents[m] == '"'
  408. num_lines++;
  409. msg += mContents.substr(n,m-n) + "\n";
  410. n = mContents.find_first_of("\"", m+1);
  411. if (n == std::string::npos)
  412. {
  413. if (num_lines == 1)
  414. {
  415. msg.erase(msg.size()-1); // remove "\n" if only one line
  416. }
  417. break;
  418. }
  419. }
  420. }
  421. else
  422. {
  423. // Case 3: node has embedded text (beginning and trailing whitespace trimmed)
  424. msg = mContents;
  425. }
  426. }
  427. return msg;
  428. }
  429. //////////////////////////////////////////////////////////////
  430. // LLXmlTreeParser
  431. LLXmlTreeParser::LLXmlTreeParser(LLXmlTree* tree)
  432. : mTree(tree),
  433. mRoot( NULL ),
  434. mCurrent( NULL ),
  435. mDump( FALSE ),
  436. mKeepContents(FALSE)
  437. {
  438. }
  439. LLXmlTreeParser::~LLXmlTreeParser()
  440. {
  441. }
  442. BOOL LLXmlTreeParser::parseFile(const std::string &path, LLXmlTreeNode** root, BOOL keep_contents)
  443. {
  444. llassert( !mRoot );
  445. llassert( !mCurrent );
  446. mKeepContents = keep_contents;
  447. BOOL success = LLXmlParser::parseFile(path);
  448. *root = mRoot;
  449. mRoot = NULL;
  450. if( success )
  451. {
  452. llassert( !mCurrent );
  453. }
  454. mCurrent = NULL;
  455. return success;
  456. }
  457. const std::string& LLXmlTreeParser::tabs()
  458. {
  459. static std::string s;
  460. s = "";
  461. S32 num_tabs = getDepth() - 1;
  462. for( S32 i = 0; i < num_tabs; i++)
  463. {
  464. s += " ";
  465. }
  466. return s;
  467. }
  468. void LLXmlTreeParser::startElement(const char* name, const char **atts)
  469. {
  470. if( mDump )
  471. {
  472. llinfos << tabs() << "startElement " << name << llendl;
  473. S32 i = 0;
  474. while( atts[i] && atts[i+1] )
  475. {
  476. llinfos << tabs() << "attribute: " << atts[i] << "=" << atts[i+1] << llendl;
  477. i += 2;
  478. }
  479. }
  480. LLXmlTreeNode* child = CreateXmlTreeNode( std::string(name), mCurrent );
  481. S32 i = 0;
  482. while( atts[i] && atts[i+1] )
  483. {
  484. child->addAttribute( atts[i], atts[i+1] );
  485. i += 2;
  486. }
  487. if( mCurrent )
  488. {
  489. mCurrent->addChild( child );
  490. }
  491. else
  492. {
  493. llassert( !mRoot );
  494. mRoot = child;
  495. }
  496. mCurrent = child;
  497. }
  498. LLXmlTreeNode* LLXmlTreeParser::CreateXmlTreeNode(const std::string& name, LLXmlTreeNode* parent)
  499. {
  500. return new LLXmlTreeNode(name, parent, mTree);
  501. }
  502. void LLXmlTreeParser::endElement(const char* name)
  503. {
  504. if( mDump )
  505. {
  506. llinfos << tabs() << "endElement " << name << llendl;
  507. }
  508. if( !mCurrent->mContents.empty() )
  509. {
  510. LLStringUtil::trim(mCurrent->mContents);
  511. LLStringUtil::removeCRLF(mCurrent->mContents);
  512. }
  513. mCurrent = mCurrent->getParent();
  514. }
  515. void LLXmlTreeParser::characterData(const char *s, int len)
  516. {
  517. std::string str;
  518. if (s) str = std::string(s, len);
  519. if( mDump )
  520. {
  521. llinfos << tabs() << "CharacterData " << str << llendl;
  522. }
  523. if (mKeepContents)
  524. {
  525. mCurrent->appendContents( str );
  526. }
  527. }
  528. void LLXmlTreeParser::processingInstruction(const char *target, const char *data)
  529. {
  530. if( mDump )
  531. {
  532. llinfos << tabs() << "processingInstruction " << data << llendl;
  533. }
  534. }
  535. void LLXmlTreeParser::comment(const char *data)
  536. {
  537. if( mDump )
  538. {
  539. llinfos << tabs() << "comment " << data << llendl;
  540. }
  541. }
  542. void LLXmlTreeParser::startCdataSection()
  543. {
  544. if( mDump )
  545. {
  546. llinfos << tabs() << "startCdataSection" << llendl;
  547. }
  548. }
  549. void LLXmlTreeParser::endCdataSection()
  550. {
  551. if( mDump )
  552. {
  553. llinfos << tabs() << "endCdataSection" << llendl;
  554. }
  555. }
  556. void LLXmlTreeParser::defaultData(const char *s, int len)
  557. {
  558. if( mDump )
  559. {
  560. std::string str;
  561. if (s) str = std::string(s, len);
  562. llinfos << tabs() << "defaultData " << str << llendl;
  563. }
  564. }
  565. void LLXmlTreeParser::unparsedEntityDecl(
  566. const char* entity_name,
  567. const char* base,
  568. const char* system_id,
  569. const char* public_id,
  570. const char* notation_name)
  571. {
  572. if( mDump )
  573. {
  574. llinfos << tabs() << "unparsed entity:" << llendl;
  575. llinfos << tabs() << " entityName " << entity_name << llendl;
  576. llinfos << tabs() << " base " << base << llendl;
  577. llinfos << tabs() << " systemId " << system_id << llendl;
  578. llinfos << tabs() << " publicId " << public_id << llendl;
  579. llinfos << tabs() << " notationName " << notation_name<< llendl;
  580. }
  581. }
  582. void test_llxmltree()
  583. {
  584. LLXmlTree tree;
  585. BOOL success = tree.parseFile( "test.xml" );
  586. if( success )
  587. {
  588. tree.dump();
  589. }
  590. }