tamlJSONReader.cc 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685
  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. #include "persistence/taml/json/tamlJSONReader.h"
  23. #include "persistence/taml/json/tamlJSONWriter.h"
  24. #include "io/fileStream.h"
  25. #include "string/stringUnit.h"
  26. #include "memory/frameAllocator.h"
  27. // Debug Profiling.
  28. #include "debug/profiler.h"
  29. //-----------------------------------------------------------------------------
  30. SimObject* TamlJSONReader::read( FileStream& stream )
  31. {
  32. // Debug Profiling.
  33. PROFILE_SCOPE(TamlJSONReader_Read);
  34. // Read JSON file.
  35. const U32 streamSize = stream.getStreamSize();
  36. FrameTemp<char> jsonText( streamSize + 1 );
  37. if ( !stream.read( streamSize, jsonText ) )
  38. {
  39. // Warn!
  40. Con::warnf("TamlJSONReader::read() - Could not load Taml JSON file from stream.");
  41. return NULL;
  42. }
  43. // Create JSON document.
  44. rapidjson::Document document;
  45. document.Parse<0>( jsonText );
  46. // Check the document is valid.
  47. if ( document.GetType() != rapidjson::kObjectType )
  48. {
  49. // Warn!
  50. Con::warnf("TamlJSONReader::read() - Load Taml JSON file from stream but was invalid.");
  51. return NULL;
  52. }
  53. // Parse root value.
  54. SimObject* pSimObject = parseType( document.MemberBegin() );
  55. // Reset parse.
  56. resetParse();
  57. return pSimObject;
  58. }
  59. //-----------------------------------------------------------------------------
  60. void TamlJSONReader::resetParse( void )
  61. {
  62. // Debug Profiling.
  63. PROFILE_SCOPE(TamlJSONReader_ResetParse);
  64. // Clear object reference map.
  65. mObjectReferenceMap.clear();
  66. }
  67. //-----------------------------------------------------------------------------
  68. SimObject* TamlJSONReader::parseType( const rapidjson::Value::ConstMemberIterator& memberItr )
  69. {
  70. // Debug Profiling.
  71. PROFILE_SCOPE(TamlJSONReader_ParseType);
  72. // Fetch name and value.
  73. const rapidjson::Value& typeName = memberItr->name;
  74. const rapidjson::Value& typeValue = memberItr->value;
  75. // Is value an object?
  76. if ( !typeValue.IsObject() )
  77. {
  78. // No, so warn.
  79. Con::warnf( "TamlJSONReader::parseType() - Cannot process type '%s' as it is not an object.", typeName.GetString() );
  80. return NULL;
  81. }
  82. // Fetch engine type name (demangled).
  83. StringTableEntry engineTypeName = getDemangledName( typeName.GetString() );
  84. // Fetch reference to Id.
  85. const U32 tamlRefToId = getTamlRefToId( typeValue );
  86. // Do we have a reference to Id?
  87. if ( tamlRefToId != 0 )
  88. {
  89. // Yes, so fetch reference.
  90. typeObjectReferenceHash::iterator referenceItr = mObjectReferenceMap.find( tamlRefToId );
  91. // Did we find the reference?
  92. if ( referenceItr == mObjectReferenceMap.end() )
  93. {
  94. // No, so warn.
  95. Con::warnf( "TamlJSONReader::parseType() - Could not find a reference Id of '%d'", tamlRefToId );
  96. return NULL;
  97. }
  98. // Return object.
  99. return referenceItr->value;
  100. }
  101. // No, so fetch reference Id.
  102. const U32 tamlRefId = getTamlRefId( typeValue );
  103. // Create type.
  104. SimObject* pSimObject = Taml::createType( engineTypeName, mpTaml );
  105. // Finish if we couldn't create the type.
  106. if ( pSimObject == NULL )
  107. return NULL;
  108. // Find Taml callbacks.
  109. TamlCallbacks* pCallbacks = dynamic_cast<TamlCallbacks*>( pSimObject );
  110. TamlCustomNodes customNodes;
  111. // Are there any Taml callbacks?
  112. if ( pCallbacks != NULL )
  113. {
  114. // Yes, so call it.
  115. mpTaml->tamlPreRead( pCallbacks );
  116. }
  117. // Parse field members.
  118. for( rapidjson::Value::ConstMemberIterator fieldMemberItr = typeValue.MemberBegin(); fieldMemberItr != typeValue.MemberEnd(); ++fieldMemberItr )
  119. {
  120. // Fetch value.
  121. const rapidjson::Value& fieldValue = fieldMemberItr->value;
  122. // Skip if not a field.
  123. if ( fieldValue.IsObject() )
  124. continue;
  125. // Parse as field.
  126. parseField( fieldMemberItr, pSimObject );
  127. }
  128. // Fetch object name.
  129. StringTableEntry objectName = StringTable->insert( getTamlObjectName( typeValue ) );
  130. // Does the object require a name?
  131. if ( objectName == StringTable->EmptyString )
  132. {
  133. // No, so just register anonymously.
  134. pSimObject->registerObject();
  135. }
  136. else
  137. {
  138. // Yes, so register a named object.
  139. pSimObject->registerObject( objectName );
  140. // Was the name assigned?
  141. if ( pSimObject->getName() != objectName )
  142. {
  143. // No, so warn that the name was rejected.
  144. Con::warnf( "Taml::parseType() - Registered an instance of type '%s' but a request to name it '%s' was rejected. This is typically because an object of that name already exists.",
  145. engineTypeName, objectName );
  146. }
  147. }
  148. // Do we have a reference Id?
  149. if ( tamlRefId != 0 )
  150. {
  151. // Yes, so insert reference.
  152. mObjectReferenceMap.insert( tamlRefId, pSimObject );
  153. }
  154. // Parse children and custom node members.
  155. for( rapidjson::Value::ConstMemberIterator objectMemberItr = typeValue.MemberBegin(); objectMemberItr != typeValue.MemberEnd(); ++objectMemberItr )
  156. {
  157. // Fetch name and value.
  158. const rapidjson::Value& objectName = objectMemberItr->name;
  159. const rapidjson::Value& objectValue = objectMemberItr->value;
  160. // Skip if not an object.
  161. if ( !objectValue.IsObject() )
  162. continue;
  163. // Find the period character in the name.
  164. const char* pPeriod = dStrchr( objectName.GetString(), '.' );
  165. // Did we find the period?
  166. if ( pPeriod == NULL )
  167. {
  168. // No, so parse child object.
  169. parseChild( objectMemberItr, pSimObject );
  170. continue;
  171. }
  172. // Yes, so parse custom object.
  173. parseCustom( objectMemberItr, pSimObject, pPeriod+1, customNodes );
  174. }
  175. // Call custom read.
  176. if ( pCallbacks )
  177. {
  178. mpTaml->tamlCustomRead( pCallbacks, customNodes );
  179. mpTaml->tamlPostRead( pCallbacks, customNodes );
  180. }
  181. // Return object.
  182. return pSimObject;
  183. }
  184. //-----------------------------------------------------------------------------
  185. inline void TamlJSONReader::parseField( rapidjson::Value::ConstMemberIterator& memberItr, SimObject* pSimObject )
  186. {
  187. // Debug Profiling.
  188. PROFILE_SCOPE(TamlJSONReader_ParseField);
  189. // Fetch name and value.
  190. const rapidjson::Value& name = memberItr->name;
  191. const rapidjson::Value& value = memberItr->value;
  192. // Insert the field name.
  193. StringTableEntry fieldName = StringTable->insert( name.GetString() );
  194. // Ignore if this is a Taml attribute.
  195. if ( fieldName == tamlRefIdName ||
  196. fieldName == tamlRefToIdName ||
  197. fieldName == tamlNamedObjectName )
  198. return;
  199. // Get field value.
  200. char valueBuffer[4096];
  201. if ( !parseStringValue( valueBuffer, sizeof(valueBuffer), value, fieldName ) )
  202. {
  203. // Warn.
  204. Con::warnf( "Taml::parseField() Could not interpret value for field '%s'", fieldName );
  205. return;
  206. }
  207. // Set field.
  208. pSimObject->setPrefixedDataField( fieldName, NULL, valueBuffer );
  209. }
  210. //-----------------------------------------------------------------------------
  211. inline void TamlJSONReader::parseChild( rapidjson::Value::ConstMemberIterator& memberItr, SimObject* pSimObject )
  212. {
  213. // Debug Profiling.
  214. PROFILE_SCOPE(TamlJSONReader_ParseChild);
  215. // Fetch name.
  216. const rapidjson::Value& name = memberItr->name;
  217. // Fetch the Taml children.
  218. TamlChildren* pChildren = dynamic_cast<TamlChildren*>( pSimObject );
  219. // Is this a Taml child?
  220. if ( pChildren == NULL )
  221. {
  222. // No, so warn.
  223. Con::warnf("Taml::parseChild() - Child member '%s' found under parent '%s' but object cannot have children.",
  224. name.GetString(),
  225. pSimObject->getClassName() );
  226. return;
  227. }
  228. // Fetch any container child class specifier.
  229. AbstractClassRep* pContainerChildClass = pSimObject->getClassRep()->getContainerChildClass( true );
  230. // Parse child member.
  231. SimObject* pChildSimObject = parseType( memberItr );
  232. // Finish if the child was not created.
  233. if ( pChildSimObject == NULL )
  234. return;
  235. // Do we have a container child class?
  236. if ( pContainerChildClass != NULL )
  237. {
  238. // Yes, so is the child object the correctly derived type?
  239. if ( !pChildSimObject->getClassRep()->isClass( pContainerChildClass ) )
  240. {
  241. // No, so warn.
  242. Con::warnf("Taml::parseChild() - Child element '%s' found under parent '%s' but object is restricted to children of type '%s'.",
  243. pChildSimObject->getClassName(),
  244. pSimObject->getClassName(),
  245. pContainerChildClass->getClassName() );
  246. // NOTE: We can't delete the object as it may be referenced elsewhere!
  247. pChildSimObject = NULL;
  248. return;
  249. }
  250. }
  251. // Add child.
  252. pChildren->addTamlChild( pChildSimObject );
  253. // Find Taml callbacks for child.
  254. TamlCallbacks* pChildCallbacks = dynamic_cast<TamlCallbacks*>( pChildSimObject );
  255. // Do we have callbacks on the child?
  256. if ( pChildCallbacks != NULL )
  257. {
  258. // Yes, so perform callback.
  259. mpTaml->tamlAddParent( pChildCallbacks, pSimObject );
  260. }
  261. }
  262. //-----------------------------------------------------------------------------
  263. inline void TamlJSONReader::parseCustom( rapidjson::Value::ConstMemberIterator& memberItr, SimObject* pSimObject, const char* pCustomNodeName, TamlCustomNodes& customNodes )
  264. {
  265. // Debug Profiling.
  266. PROFILE_SCOPE(TamlJSONReader_ParseCustom);
  267. // Fetch value.
  268. const rapidjson::Value& value = memberItr->value;
  269. // Add custom node.
  270. TamlCustomNode* pCustomNode = customNodes.addNode( pCustomNodeName );
  271. // Iterate members.
  272. for( rapidjson::Value::ConstMemberIterator customMemberItr = value.MemberBegin(); customMemberItr != value.MemberEnd(); ++customMemberItr )
  273. {
  274. // Fetch value.
  275. const rapidjson::Value& customValue = customMemberItr->value;
  276. // Is the member an object?
  277. if ( !customValue.IsObject() && !customValue.IsArray() )
  278. {
  279. // No, so warn.
  280. Con::warnf( "Taml::parseCustom() - Cannot process custom node name '%s' member as child value is not an object or array.", pCustomNodeName );
  281. return;
  282. }
  283. // Parse custom node.
  284. parseCustomNode( customMemberItr, pCustomNode );
  285. }
  286. }
  287. //-----------------------------------------------------------------------------
  288. inline void TamlJSONReader::parseCustomNode( rapidjson::Value::ConstMemberIterator& memberItr, TamlCustomNode* pCustomNode )
  289. {
  290. // Debug Profiling.
  291. PROFILE_SCOPE(TamlJSONReader_ParseCustomNode);
  292. // Fetch name and value.
  293. const rapidjson::Value& name = memberItr->name;
  294. const rapidjson::Value& value = memberItr->value;
  295. // Is the value an object?
  296. if ( value.IsObject() )
  297. {
  298. // Yes, so is the node a proxy object?
  299. if ( getTamlRefId( value ) != 0 || getTamlRefToId( value ) != 0 )
  300. {
  301. // Yes, so parse proxy object.
  302. SimObject* pProxyObject = parseType( memberItr );
  303. // Add child node.
  304. pCustomNode->addNode( pProxyObject );
  305. return;
  306. }
  307. }
  308. char valueBuffer[4096];
  309. // Fetch the node name.
  310. StringTableEntry nodeName = getDemangledName( name.GetString() );
  311. // Yes, so add child node.
  312. TamlCustomNode* pChildNode = pCustomNode->addNode( nodeName );
  313. // Is the value an array?
  314. if ( value.IsArray() )
  315. {
  316. // Yes, so does it have a single entry?
  317. if ( value.Size() == 1 )
  318. {
  319. // Yes, so parse the node text.
  320. if ( parseStringValue( valueBuffer, sizeof(valueBuffer), value.Begin(), nodeName ) )
  321. {
  322. pChildNode->setNodeText( valueBuffer );
  323. }
  324. else
  325. {
  326. // Warn.
  327. Con::warnf( "Taml::parseCustomNode() - Encountered text in the custom node '%s' but could not interpret the value.", nodeName );
  328. }
  329. }
  330. else
  331. {
  332. // No, so warn.
  333. Con::warnf( "Taml::parseCustomNode() - Encountered text in the custom node '%s' but more than a single element was found in the array.", nodeName );
  334. }
  335. return;
  336. }
  337. // Iterate child members.
  338. for( rapidjson::Value::ConstMemberIterator childMemberItr = value.MemberBegin(); childMemberItr != value.MemberEnd(); ++childMemberItr )
  339. {
  340. // Fetch name and value.
  341. const rapidjson::Value& childName = childMemberItr->name;
  342. const rapidjson::Value& childValue = childMemberItr->value;
  343. // Fetch the field name.
  344. StringTableEntry fieldName = StringTable->insert( childName.GetString() );
  345. // Is the value an array?
  346. if ( childValue.IsArray() )
  347. {
  348. // Yes, so does it have a single entry?
  349. if ( childValue.Size() == 1 )
  350. {
  351. // Yes, so parse the node text.
  352. if ( parseStringValue( valueBuffer, sizeof(valueBuffer), *childValue.Begin(), fieldName ) )
  353. {
  354. // Yes, so add sub-child node.
  355. TamlCustomNode* pSubChildNode = pChildNode->addNode( fieldName );
  356. // Set sub-child text.
  357. pSubChildNode->setNodeText( valueBuffer );
  358. continue;
  359. }
  360. // Warn.
  361. Con::warnf( "Taml::parseCustomNode() - Encountered text in the custom node '%s' but could not interpret the value.", fieldName );
  362. return;
  363. }
  364. // No, so warn.
  365. Con::warnf( "Taml::parseCustomNode() - Encountered text in the custom node '%s' but more than a single element was found in the array.", fieldName );
  366. return;
  367. }
  368. // Is the member an object?
  369. if ( childValue.IsObject() )
  370. {
  371. // Yes, so parse custom node.
  372. parseCustomNode( childMemberItr, pChildNode );
  373. continue;
  374. }
  375. // Ignore if this is a Taml attribute.
  376. if ( fieldName == tamlRefIdName ||
  377. fieldName == tamlRefToIdName ||
  378. fieldName == tamlNamedObjectName )
  379. continue;
  380. // Parse string value.
  381. if ( !parseStringValue( valueBuffer, sizeof(valueBuffer), childValue, childName.GetString() ) )
  382. {
  383. // Warn.
  384. Con::warnf( "Taml::parseCustomNode() - Could not interpret value for field '%s'", fieldName );
  385. continue;
  386. }
  387. // Add node field.
  388. pChildNode->addField( fieldName, valueBuffer );
  389. }
  390. }
  391. //-----------------------------------------------------------------------------
  392. inline StringTableEntry TamlJSONReader::getDemangledName( const char* pMangledName )
  393. {
  394. // Debug Profiling.
  395. PROFILE_SCOPE(TamlJSONReader_GetDemangledName);
  396. // Is the type name mangled?
  397. if ( StringUnit::getUnitCount( pMangledName, JSON_RFC4627_NAME_MANGLING_CHARACTERS ) > 1 )
  398. {
  399. // Yes, so fetch type name portion.
  400. return StringTable->insert( StringUnit::getUnit( pMangledName, 0, JSON_RFC4627_NAME_MANGLING_CHARACTERS ) );
  401. }
  402. // No, so use all the type name.
  403. return StringTable->insert( pMangledName );
  404. }
  405. //-----------------------------------------------------------------------------
  406. inline bool TamlJSONReader::parseStringValue( char* pBuffer, const S32 bufferSize, const rapidjson::Value& value, const char* pName )
  407. {
  408. // Debug Profiling.
  409. PROFILE_SCOPE(TamlJSONReader_ParseStringValue);
  410. // Handle field value appropriately.
  411. if ( value.IsString() )
  412. {
  413. dSprintf( pBuffer, bufferSize, "%s", value.GetString() );
  414. return true;
  415. }
  416. if ( value.IsNumber() )
  417. {
  418. if ( value.IsInt() )
  419. {
  420. dSprintf( pBuffer, bufferSize, "%d", value.GetInt() );
  421. return true;
  422. }
  423. if ( value.IsUint() )
  424. {
  425. dSprintf( pBuffer, bufferSize, "%d", value.GetUint() );
  426. return true;
  427. }
  428. if ( value.IsInt64() )
  429. {
  430. dSprintf( pBuffer, bufferSize, "%d", value.GetInt64() );
  431. return true;
  432. }
  433. if ( value.IsUint64() )
  434. {
  435. dSprintf( pBuffer, bufferSize, "%d", value.GetUint64() );
  436. return true;
  437. }
  438. if ( value.IsDouble() )
  439. {
  440. dSprintf( pBuffer, bufferSize, "%f", value.GetDouble() );
  441. return true;
  442. }
  443. }
  444. if ( value.IsBool() )
  445. {
  446. dSprintf( pBuffer, bufferSize, "%d", value.GetBool() );
  447. return true;
  448. }
  449. // Failed to get value type.
  450. Con::warnf( "Taml: Encountered a field '%s' but its value is an unknown type.", pName );
  451. return false;
  452. }
  453. //-----------------------------------------------------------------------------
  454. inline U32 TamlJSONReader::getTamlRefId( const rapidjson::Value& value )
  455. {
  456. // Debug Profiling.
  457. PROFILE_SCOPE(TamlJSONReader_GetTamlRefId);
  458. // Is the value an object?
  459. if ( !value.IsObject() )
  460. {
  461. // No, so warn.
  462. Con::warnf( "Taml::getTamlRefId() - Cannot get '%s' member as value is not an object.", tamlRefIdName );
  463. return 0;
  464. }
  465. // Iterate members.
  466. for( rapidjson::Value::ConstMemberIterator memberItr = value.MemberBegin(); memberItr != value.MemberEnd(); ++memberItr )
  467. {
  468. // Insert member name.
  469. StringTableEntry attributeName = StringTable->insert( memberItr->name.GetString() );
  470. // Skip if not the correct attribute.
  471. if ( attributeName != tamlRefIdName )
  472. continue;
  473. // Is the value an integer?
  474. if ( !memberItr->value.IsInt() )
  475. {
  476. // No, so warn.
  477. Con::warnf( "Taml::getTamlRefId() - Found '%s' member but it is not an integer.", tamlRefIdName );
  478. return 0;
  479. }
  480. // Return it.
  481. return (U32)memberItr->value.GetInt();
  482. }
  483. // Not found.
  484. return 0;
  485. }
  486. //-----------------------------------------------------------------------------
  487. inline U32 TamlJSONReader::getTamlRefToId( const rapidjson::Value& value )
  488. {
  489. // Debug Profiling.
  490. PROFILE_SCOPE(TamlJSONReader_GetTamlRefToId);
  491. // Is the value an object?
  492. if ( !value.IsObject() )
  493. {
  494. // No, so warn.
  495. Con::warnf( "Taml::getTamlRefToId() - Cannot get '%s' member as value is not an object.", tamlRefToIdName );
  496. return 0;
  497. }
  498. // Iterate members.
  499. for( rapidjson::Value::ConstMemberIterator memberItr = value.MemberBegin(); memberItr != value.MemberEnd(); ++memberItr )
  500. {
  501. // Insert member name.
  502. StringTableEntry attributeName = StringTable->insert( memberItr->name.GetString() );
  503. // Skip if not the correct attribute.
  504. if ( attributeName != tamlRefToIdName )
  505. continue;
  506. // Is the value an integer?
  507. if ( !memberItr->value.IsInt() )
  508. {
  509. // No, so warn.
  510. Con::warnf( "Taml::getTamlRefToId() - Found '%s' member but it is not an integer.", tamlRefToIdName );
  511. return 0;
  512. }
  513. // Return it.
  514. return (U32)memberItr->value.GetInt();
  515. }
  516. // Not found.
  517. return 0;
  518. }
  519. //-----------------------------------------------------------------------------
  520. inline const char* TamlJSONReader::getTamlObjectName( const rapidjson::Value& value )
  521. {
  522. // Debug Profiling.
  523. PROFILE_SCOPE(TamlJSONReader_GetTamlObjectName);
  524. // Is the value an object?
  525. if ( !value.IsObject() )
  526. {
  527. // No, so warn.
  528. Con::warnf( "Taml::getTamlObjectName() - Cannot get '%s' member as value is not an object.", tamlNamedObjectName );
  529. return 0;
  530. }
  531. // Iterate members.
  532. for( rapidjson::Value::ConstMemberIterator memberItr = value.MemberBegin(); memberItr != value.MemberEnd(); ++memberItr )
  533. {
  534. // Insert member name.
  535. StringTableEntry attributeName = StringTable->insert( memberItr->name.GetString() );
  536. // Skip if not the correct attribute.
  537. if ( attributeName != tamlRefToIdName )
  538. continue;
  539. // Is the value an integer?
  540. if ( !memberItr->value.IsString() )
  541. {
  542. // No, so warn.
  543. Con::warnf( "Taml::getTamlObjectName() - Found '%s' member but it is not a string.", tamlNamedObjectName );
  544. return NULL;
  545. }
  546. // Return it.
  547. return memberItr->value.GetString();
  548. }
  549. // Not found.
  550. return NULL;
  551. }