SimXMLDocument.cpp 35 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117
  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. TiXmlText* text = pNode->FirstChild()->ToText();
  968. if( !text )
  969. return "";
  970. return text->Value();
  971. }
  972. ConsoleMethod(SimXMLDocument, getData, const char*, 2, 2, "() Gets the text from the current stack element.\n"
  973. "@return Returns the desired text or empty string if failed (no text)")
  974. {
  975. const char* text = object->getData();
  976. if( !text )
  977. return "";
  978. char* pBuffer = Con::getReturnBuffer(dStrlen( text ) + 1);
  979. dStrcpy( pBuffer, text );
  980. return pBuffer;
  981. }
  982. ////EOF/////////////////////////////////////////////////////////////////////////