tamlJSONReader.cpp 22 KB

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