SimXMLDocument.cpp 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2013 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. ////////////////////////////////////////////////////////////////////////////////
  23. // XML Document Object
  24. ////////////////////////////////////////////////////////////////////////////////
  25. #include "persistence/SimXMLDocument.h"
  26. #include "memory/frameAllocator.h"
  27. #include "sim/simBase.h"
  28. #include "console/consoleInternal.h"
  29. #include "io/resource/resourceManager.h"
  30. #include "io/fileStream.h"
  31. IMPLEMENT_CONOBJECT(SimXMLDocument);
  32. // -----------------------------------------------------------------------------
  33. // Constructor.
  34. // -----------------------------------------------------------------------------
  35. SimXMLDocument::SimXMLDocument():
  36. m_qDocument(0),
  37. m_CurrentAttribute(0)
  38. {
  39. }
  40. // -----------------------------------------------------------------------------
  41. // Destructor.
  42. // -----------------------------------------------------------------------------
  43. SimXMLDocument::~SimXMLDocument()
  44. {
  45. }
  46. // -----------------------------------------------------------------------------
  47. // Included for completeness.
  48. // -----------------------------------------------------------------------------
  49. bool SimXMLDocument::processArguments(S32 argc, const char** argv)
  50. {
  51. if(0 == argc)
  52. {
  53. return true;
  54. }
  55. else
  56. {
  57. return true;
  58. }
  59. return false;
  60. }
  61. // -----------------------------------------------------------------------------
  62. // Script constructor.
  63. // -----------------------------------------------------------------------------
  64. bool SimXMLDocument::onAdd()
  65. {
  66. if(!Parent::onAdd())
  67. {
  68. return false;
  69. }
  70. if(!m_qDocument)
  71. {
  72. m_qDocument = new TiXmlDocument();
  73. }
  74. return true;
  75. }
  76. // -----------------------------------------------------------------------------
  77. // Script destructor.
  78. // -----------------------------------------------------------------------------
  79. void SimXMLDocument::onRemove()
  80. {
  81. Parent::onRemove();
  82. if(m_qDocument)
  83. {
  84. m_qDocument->Clear();
  85. delete(m_qDocument);
  86. }
  87. }
  88. // -----------------------------------------------------------------------------
  89. // Initialize peristent fields (datablocks).
  90. // -----------------------------------------------------------------------------
  91. void SimXMLDocument::initPersistFields()
  92. {
  93. Parent::initPersistFields();
  94. }
  95. // -----------------------------------------------------------------------------
  96. // Set this to default state at construction.
  97. // -----------------------------------------------------------------------------
  98. void SimXMLDocument::reset(void)
  99. {
  100. m_qDocument->Clear();
  101. m_paNode.clear();
  102. m_CurrentAttribute = 0;
  103. }
  104. ConsoleMethod(SimXMLDocument, reset, void, 2, 2,
  105. "() Set this to default state at construction.\n"
  106. "@return No return value")
  107. {
  108. object->reset();
  109. }
  110. // -----------------------------------------------------------------------------
  111. // Get true if file loads successfully.
  112. // -----------------------------------------------------------------------------
  113. S32 SimXMLDocument::loadFile(const char* rFileName)
  114. {
  115. reset();
  116. return m_qDocument->LoadFile(rFileName);
  117. }
  118. ConsoleMethod(SimXMLDocument, loadFile, S32, 3, 3, "(string fileName) Load file from given filename.\n"
  119. "@param fileName The name of the desired file\n"
  120. "@return Returns 1 on success and 0 otherwise")
  121. {
  122. return object->loadFile( argv[2] );
  123. }
  124. // -----------------------------------------------------------------------------
  125. // Get true if file saves successfully.
  126. // -----------------------------------------------------------------------------
  127. S32 SimXMLDocument::saveFile(const char* rFileName)
  128. {
  129. char buffer[1024];
  130. Con::expandPath(buffer, sizeof(buffer), rFileName);
  131. if(buffer == NULL || *buffer == 0)
  132. return false;
  133. FileStream strm;
  134. if(!ResourceManager->openFileForWrite(strm, buffer, FileStream::Write))
  135. {
  136. Con::errorf(ConsoleLogEntry::General, "Unable to open file '%s for writing.", buffer);
  137. return false;
  138. }
  139. bool retVal = m_qDocument->SaveFile(strm);//m_qDocument->SaveFile( buffer );
  140. // close the stream
  141. strm.close();
  142. return retVal;
  143. }
  144. ConsoleMethod(SimXMLDocument, saveFile, S32, 3, 3, "(string fileName) Save file to given filename.\n"
  145. "@param fileName A string presenting the filename to save the XML document as\n"
  146. "@return Returns 1 on success, and 0 otherwise")
  147. {
  148. return object->saveFile( argv[2] );
  149. }
  150. // -----------------------------------------------------------------------------
  151. // Get true if XML text parses correctly.
  152. // -----------------------------------------------------------------------------
  153. S32 SimXMLDocument::parse(const char* rText)
  154. {
  155. reset();
  156. m_qDocument->Parse( rText );
  157. return 1;
  158. }
  159. ConsoleMethod(SimXMLDocument, parse, S32, 3, 3, "(string txtXML) Create document from XML string.\n"
  160. "@param txtXML The text of the XML document\n"
  161. "@return Returns 1 on success")
  162. {
  163. return object->parse( argv[2] );
  164. }
  165. // -----------------------------------------------------------------------------
  166. // Clear contents of XML document.
  167. // -----------------------------------------------------------------------------
  168. void SimXMLDocument::clear(void)
  169. {
  170. reset();
  171. }
  172. ConsoleMethod(SimXMLDocument, clear, void, 2, 2, "() Clear contents of XML document.\n"
  173. "@return No return value")
  174. {
  175. object->clear();
  176. }
  177. // -----------------------------------------------------------------------------
  178. // Get error description of XML document.
  179. // -----------------------------------------------------------------------------
  180. const char* SimXMLDocument::getErrorDesc(void) const
  181. {
  182. if(!m_qDocument)
  183. {
  184. return StringTable->insert("No document");
  185. }
  186. return m_qDocument->ErrorDesc();
  187. }
  188. ConsoleMethod(SimXMLDocument, getErrorDesc, const char*, 2, 2,
  189. "() Get current error description.\n"
  190. "@return Returns a string with the error description")
  191. {
  192. // Create Returnable Buffer (duration of error description is unknown).
  193. char* pBuffer = Con::getReturnBuffer(256);
  194. // Format Buffer.
  195. dSprintf(pBuffer, 256, "%s", object->getErrorDesc());
  196. // Return Velocity.
  197. return pBuffer;
  198. }
  199. // -----------------------------------------------------------------------------
  200. // Clear error description of this.
  201. // -----------------------------------------------------------------------------
  202. void SimXMLDocument::clearError(void)
  203. {
  204. m_qDocument->ClearError();
  205. }
  206. ConsoleMethod(SimXMLDocument, clearError, void, 2, 2,
  207. "() Clear error description.\n"
  208. "@return No return value")
  209. {
  210. object->clearError();
  211. }
  212. // -----------------------------------------------------------------------------
  213. // Get true if first child element was successfully pushed onto stack.
  214. // -----------------------------------------------------------------------------
  215. bool SimXMLDocument::pushFirstChildElement(const char* rName)
  216. {
  217. // Clear the current attribute pointer
  218. m_CurrentAttribute = 0;
  219. // Push the first element found under the current element of the given name
  220. TiXmlElement* pElement;
  221. if(!m_paNode.empty())
  222. {
  223. const int iLastElement = m_paNode.size() - 1;
  224. TiXmlElement* pNode = m_paNode[iLastElement];
  225. if(!pNode)
  226. {
  227. return false;
  228. }
  229. pElement = pNode->FirstChildElement(rName);
  230. }
  231. else
  232. {
  233. if(!m_qDocument)
  234. {
  235. return false;
  236. }
  237. pElement = m_qDocument->FirstChildElement(rName);
  238. }
  239. if(!pElement)
  240. {
  241. return false;
  242. }
  243. m_paNode.push_back(pElement);
  244. return true;
  245. }
  246. ConsoleMethod(SimXMLDocument, pushFirstChildElement, bool, 3, 3,
  247. "(string name) Push first child element with given name onto stack.\n"
  248. "@param name The name of the child element"
  249. "@return returns true on success, false otherwise.")
  250. {
  251. return object->pushFirstChildElement( argv[2] );
  252. }
  253. // -----------------------------------------------------------------------------
  254. // Get true if first child element was successfully pushed onto stack.
  255. // -----------------------------------------------------------------------------
  256. bool SimXMLDocument::pushChildElement(S32 index)
  257. {
  258. // Clear the current attribute pointer
  259. m_CurrentAttribute = 0;
  260. // Push the first element found under the current element of the given name
  261. TiXmlElement* pElement;
  262. if(!m_paNode.empty())
  263. {
  264. const int iLastElement = m_paNode.size() - 1;
  265. TiXmlElement* pNode = m_paNode[iLastElement];
  266. if(!pNode)
  267. {
  268. return false;
  269. }
  270. pElement = pNode->FirstChildElement();
  271. for( S32 i = 0; i < index; i++ )
  272. {
  273. if( !pElement )
  274. return false;
  275. pElement = pElement->NextSiblingElement();
  276. }
  277. }
  278. else
  279. {
  280. if(!m_qDocument)
  281. {
  282. return false;
  283. }
  284. pElement = m_qDocument->FirstChildElement();
  285. for( S32 i = 0; i < index; i++ )
  286. {
  287. if( !pElement )
  288. return false;
  289. pElement = pElement->NextSiblingElement();
  290. }
  291. }
  292. if(!pElement)
  293. {
  294. return false;
  295. }
  296. m_paNode.push_back(pElement);
  297. return true;
  298. }
  299. ConsoleMethod(SimXMLDocument, pushChildElement, bool, 3, 3,
  300. "(int index) Push the child element at the given index onto stack.\n"
  301. "@param index A nonnegative integer representing the index of the child element\n"
  302. "@return Returns true on success, and false otherwise")
  303. {
  304. return object->pushChildElement( dAtoi( argv[2] ) );
  305. }
  306. // -----------------------------------------------------------------------------
  307. // Convert top stack element into its next sibling element.
  308. // -----------------------------------------------------------------------------
  309. bool SimXMLDocument::nextSiblingElement(const char* rName)
  310. {
  311. // Clear the current attribute pointer
  312. m_CurrentAttribute = 0;
  313. // Attempt to find the next sibling element
  314. if(m_paNode.empty())
  315. {
  316. return false;
  317. }
  318. const int iLastElement = m_paNode.size() - 1;
  319. TiXmlElement*& pElement = m_paNode[iLastElement];
  320. if(!pElement)
  321. {
  322. return false;
  323. }
  324. pElement = pElement->NextSiblingElement(rName);
  325. if(!pElement)
  326. {
  327. return false;
  328. }
  329. return true;
  330. }
  331. ConsoleMethod(SimXMLDocument, nextSiblingElement, bool, 3, 3,
  332. "(string name) Set top element on stack to next element with given name.\n"
  333. "@param name The name of the element.\n"
  334. "@return Returns true on success, false otherwise")
  335. {
  336. return object->nextSiblingElement( argv[2] );
  337. }
  338. // -----------------------------------------------------------------------------
  339. // Get element value if it exists. Used to extract a text node from the element.
  340. // for example.
  341. // -----------------------------------------------------------------------------
  342. const char* SimXMLDocument::elementValue()
  343. {
  344. if(m_paNode.empty())
  345. {
  346. return StringTable->EmptyString;
  347. }
  348. const int iLastElement = m_paNode.size() - 1;
  349. TiXmlElement* pNode = m_paNode[iLastElement];
  350. if(!pNode)
  351. {
  352. return StringTable->EmptyString;
  353. }
  354. return pNode->Value();
  355. }
  356. ConsoleMethod(SimXMLDocument, elementValue, const char*, 2, 2,
  357. "() Get element value if it exists.\n"
  358. "@return A string with the desired value, or empty if not found.")
  359. {
  360. // Create Returnable Buffer (because duration of value is unknown).
  361. char* pBuffer = Con::getReturnBuffer(256);
  362. dSprintf(pBuffer, 256, "%s", object->elementValue());
  363. return pBuffer;
  364. }
  365. // -----------------------------------------------------------------------------
  366. // Pop last element off of stack.
  367. // -----------------------------------------------------------------------------
  368. void SimXMLDocument::popElement(void)
  369. {
  370. m_paNode.pop_back();
  371. }
  372. ConsoleMethod(SimXMLDocument, popElement, void, 2, 2,
  373. "() Pop last element off of stack.\n"
  374. "@return No return value")
  375. {
  376. object->popElement();
  377. }
  378. // -----------------------------------------------------------------------------
  379. // Get attribute value if it exists.
  380. // -----------------------------------------------------------------------------
  381. const char* SimXMLDocument::attribute(const char* rAttribute)
  382. {
  383. if(m_paNode.empty())
  384. {
  385. return StringTable->EmptyString;
  386. }
  387. const int iLastElement = m_paNode.size() - 1;
  388. TiXmlElement* pNode = m_paNode[iLastElement];
  389. if(!pNode)
  390. {
  391. return StringTable->EmptyString;
  392. }
  393. if(!pNode->Attribute(rAttribute))
  394. {
  395. return StringTable->EmptyString;
  396. }
  397. return pNode->Attribute(rAttribute);
  398. }
  399. ConsoleMethod(SimXMLDocument, attribute, const char*, 3, 3,
  400. "(string attribute) Get attribute value if it exists.\n"
  401. "@param attribute The desired SimXMLDocument attribute\n"
  402. "@return Returns the value of the attribute as a string, or an empty string on failure")
  403. {
  404. // Create Returnable Buffer (because duration of attribute is unknown).
  405. char* pBuffer = Con::getReturnBuffer(256);
  406. // Format Buffer.
  407. dSprintf(pBuffer, 256, "%s", object->attribute( argv[2] ));
  408. // Return Velocity.
  409. return pBuffer;
  410. }
  411. ConsoleMethod(SimXMLDocument, attributeF32, F32, 3, 3,
  412. "(string attribute) Get attribute value if it exists.\n"
  413. "@param attribute The desired SimXMLDocument attribute\n"
  414. "@return Returns the value of the attribute converted to 32-bit floating-point value from string")
  415. {
  416. return dAtof( object->attribute( argv[2] ) );
  417. }
  418. ConsoleMethod(SimXMLDocument, attributeS32, S32, 3, 3,
  419. "(string attribute) Get attribute value if it exists.\n"
  420. "@param attribute The desired SimXMLDocument attribute\n"
  421. "@return Returns the value of the attribute converted to 32-bit integer value from string")
  422. {
  423. return dAtoi( object->attribute( argv[2] ) );
  424. }
  425. // -----------------------------------------------------------------------------
  426. // Get true if given attribute exists.
  427. // -----------------------------------------------------------------------------
  428. bool SimXMLDocument::attributeExists(const char* rAttribute)
  429. {
  430. if(m_paNode.empty())
  431. {
  432. return false;
  433. }
  434. const int iLastElement = m_paNode.size() - 1;
  435. TiXmlElement* pNode = m_paNode[iLastElement];
  436. if(!pNode)
  437. {
  438. return false;
  439. }
  440. if(!pNode->Attribute(rAttribute))
  441. {
  442. return false;
  443. }
  444. return true;
  445. }
  446. ConsoleMethod(SimXMLDocument, attributeExists, bool, 3, 3,
  447. "(string attribute) Get true if named attribute exists.\n"
  448. "@param attribute The desired attribute's name\n"
  449. "@return Returns true if attribute exists and false otherwise")
  450. {
  451. return object->attributeExists( argv[2] );
  452. }
  453. // -----------------------------------------------------------------------------
  454. // Obtain the name of the current element's first attribute
  455. // -----------------------------------------------------------------------------
  456. const char* SimXMLDocument::firstAttribute()
  457. {
  458. // Get the current element
  459. if(m_paNode.empty())
  460. {
  461. return StringTable->EmptyString;
  462. }
  463. const int iLastElement = m_paNode.size() - 1;
  464. TiXmlElement* pNode = m_paNode[iLastElement];
  465. if(!pNode)
  466. {
  467. return StringTable->EmptyString;
  468. }
  469. // Gets its first attribute, if any
  470. m_CurrentAttribute = pNode->FirstAttribute();
  471. if(!m_CurrentAttribute)
  472. {
  473. return StringTable->EmptyString;
  474. }
  475. return m_CurrentAttribute->Name();
  476. }
  477. ConsoleMethod(SimXMLDocument, firstAttribute, const char*, 2, 2,
  478. "() Obtain the name of the current element's first attribute.\n"
  479. "@return A string with the name of the first attribute")
  480. {
  481. const char* name = object->firstAttribute();
  482. // Create Returnable Buffer (because duration of attribute is unknown).
  483. char* pBuffer = Con::getReturnBuffer(dStrlen(name)+1);
  484. dStrcpy(pBuffer, name);
  485. return pBuffer;
  486. }
  487. // -----------------------------------------------------------------------------
  488. // Obtain the name of the current element's last attribute
  489. // -----------------------------------------------------------------------------
  490. const char* SimXMLDocument::lastAttribute()
  491. {
  492. // Get the current element
  493. if(m_paNode.empty())
  494. {
  495. return StringTable->EmptyString;
  496. }
  497. const int iLastElement = m_paNode.size() - 1;
  498. TiXmlElement* pNode = m_paNode[iLastElement];
  499. if(!pNode)
  500. {
  501. return StringTable->EmptyString;
  502. }
  503. // Gets its last attribute, if any
  504. m_CurrentAttribute = pNode->LastAttribute();
  505. if(!m_CurrentAttribute)
  506. {
  507. return StringTable->EmptyString;
  508. }
  509. return m_CurrentAttribute->Name();
  510. }
  511. ConsoleMethod(SimXMLDocument, lastAttribute, const char*, 2, 2,
  512. "() Obtain the name of the current element's last attribute.\n"
  513. "@return A string with the name of the last attribute")
  514. {
  515. const char* name = object->lastAttribute();
  516. // Create Returnable Buffer (because duration of attribute is unknown).
  517. char* pBuffer = Con::getReturnBuffer(dStrlen(name)+1);
  518. dStrcpy(pBuffer, name);
  519. return pBuffer;
  520. }
  521. // -----------------------------------------------------------------------------
  522. // Get the name of the next attribute for the current element after a call
  523. // to firstAttribute().
  524. // -----------------------------------------------------------------------------
  525. const char* SimXMLDocument::nextAttribute()
  526. {
  527. if(!m_CurrentAttribute)
  528. {
  529. return StringTable->EmptyString;
  530. }
  531. // Gets its next attribute, if any
  532. m_CurrentAttribute = m_CurrentAttribute->Next();
  533. if(!m_CurrentAttribute)
  534. {
  535. return StringTable->EmptyString;
  536. }
  537. return m_CurrentAttribute->Name();
  538. }
  539. ConsoleMethod(SimXMLDocument, nextAttribute, const char*, 2, 2,
  540. "() Get the name of the next attribute for the current element after a call to firstAttribute().\n"
  541. "@return A string with the name of the next attribute")
  542. {
  543. const char* name = object->nextAttribute();
  544. // Create Returnable Buffer (because duration of attribute is unknown).
  545. char* pBuffer = Con::getReturnBuffer(dStrlen(name)+1);
  546. dStrcpy(pBuffer, name);
  547. return pBuffer;
  548. }
  549. // -----------------------------------------------------------------------------
  550. // Get the name of the previous attribute for the current element after a call
  551. // to lastAttribute().
  552. // -----------------------------------------------------------------------------
  553. const char* SimXMLDocument::prevAttribute()
  554. {
  555. if(!m_CurrentAttribute)
  556. {
  557. return StringTable->EmptyString;
  558. }
  559. // Gets its next attribute, if any
  560. m_CurrentAttribute = m_CurrentAttribute->Previous();
  561. if(!m_CurrentAttribute)
  562. {
  563. return StringTable->EmptyString;
  564. }
  565. return m_CurrentAttribute->Name();
  566. }
  567. ConsoleMethod(SimXMLDocument, prevAttribute, const char*, 2, 2,
  568. "() Get the name of the previous attribute for the current element after a call to lastAttribute().\n"
  569. "@return A string with the name of the previous attribute")
  570. {
  571. const char* name = object->prevAttribute();
  572. // Create Returnable Buffer (because duration of attribute is unknown).
  573. char* pBuffer = Con::getReturnBuffer(dStrlen(name)+1);
  574. dStrcpy(pBuffer, name);
  575. return pBuffer;
  576. }
  577. // -----------------------------------------------------------------------------
  578. // Set attribute of top stack element to given value.
  579. // -----------------------------------------------------------------------------
  580. void SimXMLDocument::setAttribute(const char* rAttribute, const char* rVal)
  581. {
  582. if(m_paNode.empty())
  583. {
  584. return;
  585. }
  586. const int iLastElement = m_paNode.size() - 1;
  587. TiXmlElement* pElement = m_paNode[iLastElement];
  588. if(!pElement)
  589. {
  590. return;
  591. }
  592. pElement->SetAttribute(rAttribute, rVal);
  593. }
  594. ConsoleMethod(SimXMLDocument, setAttribute, void, 4, 4,
  595. "(string attributeName, string attributeValue) Set attribute of top stack element to given value.\n"
  596. "@param attributeName The name of the attribute of the element you wish to set\n"
  597. "@param attributeValue The value you wish to set the given attribute to\n"
  598. "@return No return value.")
  599. {
  600. object->setAttribute(argv[2], argv[3]);
  601. }
  602. // -----------------------------------------------------------------------------
  603. // Set attribute of top stack element to given value.
  604. // -----------------------------------------------------------------------------
  605. void SimXMLDocument::setObjectAttributes(const char* objectID)
  606. {
  607. if( !objectID || !objectID[0] )
  608. return;
  609. if(m_paNode.empty())
  610. return;
  611. SimObject *pObject = Sim::findObject( objectID );
  612. if( pObject == NULL )
  613. return;
  614. const int iLastElement = m_paNode.size() - 1;
  615. TiXmlElement* pElement = m_paNode[iLastElement];
  616. if(!pElement)
  617. return;
  618. char textbuf[1024];
  619. TiXmlElement field( "Field" );
  620. TiXmlElement group( "FieldGroup" );
  621. pElement->SetAttribute( "Name", pObject->getName() );
  622. // Iterate over our filed list and add them to the XML document...
  623. AbstractClassRep::FieldList fieldList = pObject->getFieldList();
  624. AbstractClassRep::FieldList::iterator itr;
  625. for(itr = fieldList.begin(); itr != fieldList.end(); itr++)
  626. {
  627. if( itr->type == AbstractClassRep::DepricatedFieldType ||
  628. itr->type == AbstractClassRep::StartGroupFieldType ||
  629. itr->type == AbstractClassRep::EndGroupFieldType) continue;
  630. // Not an Array
  631. if(itr->elementCount == 1)
  632. {
  633. // get the value of the field as a string.
  634. ConsoleBaseType *cbt = ConsoleBaseType::getType(itr->type);
  635. const char *val = Con::getData(itr->type, (void *) (((const char *)pObject) + itr->offset), 0, itr->table, itr->flag);
  636. // Make a copy for the field check.
  637. if (!val)
  638. continue;
  639. FrameTemp<char> valCopy( dStrlen( val ) + 1 );
  640. dStrcpy( (char *)valCopy, val );
  641. if (!pObject->writeField(itr->pFieldname, valCopy))
  642. continue;
  643. val = valCopy;
  644. expandEscape(textbuf, val);
  645. if( !pObject->writeField( itr->pFieldname, textbuf ) )
  646. continue;
  647. field.SetValue( "Property" );
  648. field.SetAttribute( "name", itr->pFieldname );
  649. if( cbt != NULL )
  650. field.SetAttribute( "type", cbt->getTypeName() );
  651. else
  652. field.SetAttribute( "type", "TypeString" );
  653. field.SetAttribute( "data", textbuf );
  654. pElement->InsertEndChild( field );
  655. continue;
  656. }
  657. }
  658. //// IS An Array
  659. //for(U32 j = 0; S32(j) < f->elementCount; j++)
  660. //{
  661. // // If the start of a group create an element for the group and
  662. // // the our chache to it
  663. // const char *val = Con::getData(itr->type, (void *) (((const char *)pObject) + itr->offset), j, itr->table, itr->flag);
  664. // // Make a copy for the field check.
  665. // if (!val)
  666. // continue;
  667. // FrameTemp<char> valCopy( dStrlen( val ) + 1 );
  668. // dStrcpy( (char *)valCopy, val );
  669. // if (!pObject->writeField(itr->pFieldname, valCopy))
  670. // continue;
  671. // val = valCopy;
  672. // // get the value of the field as a string.
  673. // ConsoleBaseType *cbt = ConsoleBaseType::getType(itr->type);
  674. // const char * dstr = Con::getData(itr->type, (void *)(((const char *)pObject) + itr->offset), 0, itr->table, itr->flag);
  675. // if(!dstr)
  676. // dstr = "";
  677. // expandEscape(textbuf, dstr);
  678. // if( !pObject->writeField( itr->pFieldname, dstr ) )
  679. // continue;
  680. // field.SetValue( "Property" );
  681. // field.SetAttribute( "name", itr->pFieldname );
  682. // if( cbt != NULL )
  683. // field.SetAttribute( "type", cbt->getTypeName() );
  684. // else
  685. // field.SetAttribute( "type", "TypeString" );
  686. // field.SetAttribute( "data", textbuf );
  687. // pElement->InsertEndChild( field );
  688. //}
  689. }
  690. ConsoleMethod(SimXMLDocument, setObjectAttributes, void, 3, 3,
  691. "(string attributeValue) Set attribute of top stack element to given value.\n"
  692. "@param attributeValue The value you wish to set the given attribute to\n"
  693. "@return No return value.")
  694. {
  695. object->setObjectAttributes(argv[2]);
  696. }
  697. // -----------------------------------------------------------------------------
  698. // Create a new element and set to child of current stack element.
  699. // New element is placed on top of element stack.
  700. // -----------------------------------------------------------------------------
  701. void SimXMLDocument::pushNewElement(const char* rName)
  702. {
  703. TiXmlElement cElement( rName );
  704. TiXmlElement* pStackTop = 0;
  705. if(m_paNode.empty())
  706. {
  707. pStackTop = dynamic_cast<TiXmlElement*>
  708. (m_qDocument->InsertEndChild( cElement ) );
  709. }
  710. else
  711. {
  712. const int iFinalElement = m_paNode.size() - 1;
  713. TiXmlElement* pNode = m_paNode[iFinalElement];
  714. if(!pNode)
  715. {
  716. return;
  717. }
  718. pStackTop = dynamic_cast<TiXmlElement*>
  719. (pNode->InsertEndChild( cElement ));
  720. }
  721. if(!pStackTop)
  722. {
  723. return;
  724. }
  725. m_paNode.push_back(pStackTop);
  726. }
  727. ConsoleMethod(SimXMLDocument, pushNewElement, void, 3, 3,
  728. "(string name) Create new element as child of current stack element "
  729. "and push new element on to stack.\n"
  730. "@param name The anme of the new element\n"
  731. "@return No return value")
  732. {
  733. object->pushNewElement( argv[2] );
  734. }
  735. // -----------------------------------------------------------------------------
  736. // Create a new element and set to child of current stack element.
  737. // New element is placed on top of element stack.
  738. // -----------------------------------------------------------------------------
  739. void SimXMLDocument::addNewElement(const char* rName)
  740. {
  741. TiXmlElement cElement( rName );
  742. TiXmlElement* pStackTop = 0;
  743. if(m_paNode.empty())
  744. {
  745. pStackTop = dynamic_cast<TiXmlElement*>
  746. (m_qDocument->InsertEndChild( cElement ));
  747. if(!pStackTop)
  748. {
  749. return;
  750. }
  751. m_paNode.push_back(pStackTop);
  752. return;
  753. }
  754. const int iParentElement = m_paNode.size() - 2;
  755. if(iParentElement < 0)
  756. {
  757. pStackTop = dynamic_cast<TiXmlElement*>
  758. (m_qDocument->InsertEndChild( cElement ));
  759. if(!pStackTop)
  760. {
  761. return;
  762. }
  763. m_paNode.push_back(pStackTop);
  764. return;
  765. }
  766. else
  767. {
  768. TiXmlElement* pNode = m_paNode[iParentElement];
  769. if(!pNode)
  770. {
  771. return;
  772. }
  773. pStackTop = dynamic_cast<TiXmlElement*>
  774. (pNode->InsertEndChild( cElement ));
  775. if(!pStackTop)
  776. {
  777. return;
  778. }
  779. // Overwrite top stack position.
  780. const int iFinalElement = m_paNode.size() - 1;
  781. m_paNode[iFinalElement] = pStackTop;
  782. //pNode = pStackTop;
  783. }
  784. }
  785. ConsoleMethod(SimXMLDocument, addNewElement, void, 3, 3,
  786. "(string name) Create new element as child of current stack element "
  787. "and push new element on to stack.\n"
  788. "@param name The anme of the new element\n"
  789. "@return No return value")
  790. {
  791. object->addNewElement( argv[2] );
  792. }
  793. // -----------------------------------------------------------------------------
  794. // Write XML document declaration.
  795. // -----------------------------------------------------------------------------
  796. void SimXMLDocument::addHeader(void)
  797. {
  798. TiXmlDeclaration cDeclaration("1.0", "utf-8", "yes");
  799. m_qDocument->InsertEndChild(cDeclaration);
  800. }
  801. ConsoleMethod(SimXMLDocument, addHeader, void, 2, 2, "() Add XML header to document.\n"
  802. "@return No return value.")
  803. {
  804. object->addHeader();
  805. }
  806. void SimXMLDocument::addComment(const char* comment)
  807. {
  808. TiXmlComment cComment;
  809. cComment.SetValue(comment);
  810. if(m_paNode.empty())
  811. {
  812. Con::warnf("Cannot add comment without any elements: '%s'", comment);
  813. return;
  814. }
  815. const int iFinalElement = m_paNode.size() - 1;
  816. TiXmlElement* pNode = m_paNode[iFinalElement];
  817. if(!pNode)
  818. {
  819. return;
  820. }
  821. pNode->InsertEndChild( cComment );
  822. }
  823. ConsoleMethod(SimXMLDocument, addComment, void, 3, 3, "(string comment) Add the given comment as a child of current stack element.\n"
  824. "@param comment The desired comment to add\n"
  825. "@return No return value.")
  826. {
  827. object->addComment(argv[2]);
  828. }
  829. const char* SimXMLDocument::readComment( S32 index )
  830. {
  831. // Clear the current attribute pointer
  832. m_CurrentAttribute = 0;
  833. // Push the first element found under the current element of the given name
  834. if(!m_paNode.empty())
  835. {
  836. const int iLastElement = m_paNode.size() - 1;
  837. TiXmlElement* pNode = m_paNode[iLastElement];
  838. if(!pNode)
  839. {
  840. return "";
  841. }
  842. TiXmlNode* node = pNode->FirstChild();
  843. for( S32 i = 0; i < index; i++ )
  844. {
  845. if( !node )
  846. return "";
  847. node = node->NextSiblingElement();
  848. }
  849. if( node )
  850. {
  851. TiXmlComment* comment = node->ToComment();
  852. if( comment )
  853. return comment->Value();
  854. }
  855. }
  856. else
  857. {
  858. if(!m_qDocument)
  859. {
  860. return "";
  861. }
  862. TiXmlNode* node = m_qDocument->FirstChild();
  863. for( S32 i = 0; i < index; i++ )
  864. {
  865. if( !node )
  866. return "";
  867. node = node->NextSibling();
  868. }
  869. if( node )
  870. {
  871. TiXmlComment* comment = node->ToComment();
  872. if( comment )
  873. return comment->Value();
  874. }
  875. }
  876. return "";
  877. }
  878. ConsoleMethod(SimXMLDocument, readComment, const char*, 3, 3, "(S32 index) Returns the comment at the specified index.\n"
  879. "@param index The index of the desired comment as a nonnegative integer value\n"
  880. "@return The comment as a string")
  881. {
  882. return object->readComment( dAtoi( argv[2] ) );
  883. }
  884. void SimXMLDocument::addText(const char* text)
  885. {
  886. if(m_paNode.empty())
  887. return;
  888. const int iFinalElement = m_paNode.size() - 1;
  889. TiXmlElement* pNode = m_paNode[iFinalElement];
  890. if(!pNode)
  891. return;
  892. TiXmlText cText(text);
  893. pNode->InsertEndChild( cText );
  894. }
  895. ConsoleMethod(SimXMLDocument, addText, void, 3, 3, "(string text) Add the given text as a child of current stack element.\n"
  896. "@param text The desired text to add\n"
  897. "@return No return value.")
  898. {
  899. object->addText(argv[2]);
  900. }
  901. const char* SimXMLDocument::getText()
  902. {
  903. if(m_paNode.empty())
  904. return "";
  905. const int iFinalElement = m_paNode.size() - 1;
  906. TiXmlNode* pNode = m_paNode[iFinalElement];
  907. if(!pNode)
  908. return "";
  909. TiXmlText* text = pNode->FirstChild()->ToText();
  910. if( !text )
  911. return "";
  912. return text->Value();
  913. }
  914. ConsoleMethod(SimXMLDocument, getText, const char*, 2, 2, "() Gets the text from the current stack element.\n"
  915. "@return Returns the desired text, or empty string on failure")
  916. {
  917. const char* text = object->getText();
  918. if( !text )
  919. return "";
  920. char* pBuffer = Con::getReturnBuffer(dStrlen( text ) + 1);
  921. dStrcpy( pBuffer, text );
  922. return pBuffer;
  923. }
  924. void SimXMLDocument::removeText()
  925. {
  926. if(m_paNode.empty())
  927. return;
  928. const int iFinalElement = m_paNode.size() - 1;
  929. TiXmlElement* pNode = m_paNode[iFinalElement];
  930. if(!pNode)
  931. return;
  932. TiXmlText* text = pNode->FirstChild()->ToText();
  933. if( !text )
  934. return;
  935. pNode->RemoveChild(text);
  936. }
  937. ConsoleMethod(SimXMLDocument, removeText, void, 2, 2, "() Remove any text on the current stack element.\n"
  938. "@return No return value\n")
  939. {
  940. object->removeText();
  941. }
  942. void SimXMLDocument::addData(const char* text)
  943. {
  944. if(m_paNode.empty())
  945. return;
  946. const int iFinalElement = m_paNode.size() - 1;
  947. TiXmlElement* pNode = m_paNode[iFinalElement];
  948. if(!pNode)
  949. return;
  950. TiXmlText cText(text);
  951. pNode->InsertEndChild( cText );
  952. }
  953. ConsoleMethod(SimXMLDocument, addData, void, 3, 3, "(string text) Add the given text as a child of current stack element.\n"
  954. "@param The desired text to add\n"
  955. "@return No return value")
  956. {
  957. object->addData(argv[2]);
  958. }
  959. const char* SimXMLDocument::getData()
  960. {
  961. if(m_paNode.empty())
  962. return "";
  963. const int iFinalElement = m_paNode.size() - 1;
  964. TiXmlNode* pNode = m_paNode[iFinalElement];
  965. if(!pNode)
  966. return "";
  967. TiXmlNode * firstChild = pNode->FirstChild();
  968. if(!firstChild)
  969. return "";
  970. TiXmlText* text = firstChild->ToText();
  971. if( !text )
  972. return "";
  973. return text->Value();
  974. }
  975. ConsoleMethod(SimXMLDocument, getData, const char*, 2, 2, "() Gets the text from the current stack element.\n"
  976. "@return Returns the desired text or empty string if failed (no text)")
  977. {
  978. const char* text = object->getData();
  979. if( !text )
  980. return "";
  981. char* pBuffer = Con::getReturnBuffer(dStrlen( text ) + 1);
  982. dStrcpy( pBuffer, text );
  983. return pBuffer;
  984. }
  985. ////EOF/////////////////////////////////////////////////////////////////////////