taml.cc 54 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393
  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 "taml.h"
  23. #ifndef _TAML_XMLWRITER_H_
  24. #include "persistence/taml/tamlXmlWriter.h"
  25. #endif
  26. #ifndef _TAML_XMLREADER_H_
  27. #include "persistence/taml/tamlXmlReader.h"
  28. #endif
  29. #ifndef _TAML_BINARYWRITER_H_
  30. #include "persistence/taml/tamlBinaryWriter.h"
  31. #endif
  32. #ifndef _TAML_BINARYREADER_H_
  33. #include "persistence/taml/tamlBinaryReader.h"
  34. #endif
  35. #ifndef _FRAMEALLOCATOR_H_
  36. #include "memory/frameAllocator.h"
  37. #endif
  38. #ifndef _CONSOLETYPES_H_
  39. #include "console/consoleTypes.h"
  40. #endif
  41. #ifndef _CONSOLEINTERNAL_H_
  42. #include "console/consoleInternal.h"
  43. #endif
  44. #ifndef _ASSET_FIELD_TYPES_H_
  45. #include "assets/assetFieldTypes.h"
  46. #endif
  47. #ifndef _MATHTYPES_H_
  48. #include "math/mathTypes.h"
  49. #endif
  50. #ifndef _VECTOR2_H_
  51. #include "2d/core/vector2.h"
  52. #endif
  53. #ifndef _IMAGE_ASSET_H_
  54. #include "2d/assets/imageAsset.h"
  55. #endif
  56. #ifndef _ANIMATION_ASSET_H_
  57. #include "2d/assets/animationAsset.h"
  58. #endif
  59. #ifndef _AUDIO_ASSET_H_
  60. #include "audio/audioAsset.h"
  61. #endif
  62. // Script bindings.
  63. #include "taml_ScriptBinding.h"
  64. // Debug Profiling.
  65. #include "debug/profiler.h"
  66. //-----------------------------------------------------------------------------
  67. IMPLEMENT_CONOBJECT( Taml );
  68. //-----------------------------------------------------------------------------
  69. StringTableEntry tamlRefIdName = StringTable->insert( "TamlId" );
  70. StringTableEntry tamlRefToIdName = StringTable->insert( "TamlRefId" );
  71. StringTableEntry tamlNamedObjectName = StringTable->insert( "Name" );
  72. //-----------------------------------------------------------------------------
  73. static EnumTable::Enums tamlFormatModeLookup[] =
  74. {
  75. { Taml::XmlFormat, "xml" },
  76. { Taml::BinaryFormat, "binary" },
  77. };
  78. EnumTable tamlFormatModeTable(sizeof(tamlFormatModeLookup) / sizeof(EnumTable::Enums), &tamlFormatModeLookup[0]);
  79. //-----------------------------------------------------------------------------
  80. Taml::TamlFormatMode Taml::getFormatModeEnum(const char* label)
  81. {
  82. // Search for Mnemonic.
  83. for (U32 i = 0; i < (sizeof(tamlFormatModeLookup) / sizeof(EnumTable::Enums)); i++)
  84. {
  85. if( dStricmp(tamlFormatModeLookup[i].label, label) == 0)
  86. return (TamlFormatMode)tamlFormatModeLookup[i].index;
  87. }
  88. // Warn.
  89. Con::warnf( "Taml::getFormatModeEnum() - Invalid format of '%s'.", label );
  90. return Taml::InvalidFormat;
  91. }
  92. //-----------------------------------------------------------------------------
  93. const char* Taml::getFormatModeDescription(const Taml::TamlFormatMode formatMode)
  94. {
  95. // Search for Mnemonic.
  96. for (U32 i = 0; i < (sizeof(tamlFormatModeLookup) / sizeof(EnumTable::Enums)); i++)
  97. {
  98. if( tamlFormatModeLookup[i].index == (S32)formatMode )
  99. return tamlFormatModeLookup[i].label;
  100. }
  101. // Warn.
  102. Con::warnf( "Taml::getFormatModeDescription() - Invalid format mode." );
  103. return StringTable->EmptyString;
  104. }
  105. //-----------------------------------------------------------------------------
  106. // The string-table-entries are set to string literals below because Taml is used in a static scope and the string-table cannot currently be used like that.
  107. Taml::Taml() :
  108. mFormatMode(XmlFormat),
  109. mBinaryCompression(true),
  110. mWriteDefaults(false),
  111. mProgenitorUpdate(true),
  112. mAutoFormat(true),
  113. mAutoFormatXmlExtension("taml"),
  114. mAutoFormatBinaryExtension("baml")
  115. {
  116. // Reset the file-path buffer.
  117. mFilePathBuffer[0] = 0;
  118. }
  119. //-----------------------------------------------------------------------------
  120. void Taml::initPersistFields()
  121. {
  122. // Call parent.
  123. Parent::initPersistFields();
  124. addField("Format", TypeEnum, Offset(mFormatMode, Taml), 1, &tamlFormatModeTable, "The read/write format that should be used.");
  125. addField("BinaryCompression", TypeBool, Offset(mBinaryCompression, Taml), "Whether ZIP compression is used on binary formatting or not.\n");
  126. addField("WriteDefaults", TypeBool, Offset(mWriteDefaults, Taml), "Whether to write static fields that are at their default or not.\n");
  127. addField("ProgenitorUpdate", TypeBool, Offset(mProgenitorUpdate, Taml), "Whether to update each type instances file-progenitor or not.\n");
  128. addField("AutoFormat", TypeBool, Offset(mAutoFormat, Taml), "Whether the format type is automatically determined by the filename extension or not.\n");
  129. addField("AutoFormatXmlExtension", TypeString, Offset(mAutoFormatXmlExtension, Taml), "When using auto-format, this is the extension (end of filename) used to detect the XML format.\n");
  130. addField("AutoFormatBinaryExtension", TypeString, Offset(mAutoFormatBinaryExtension, Taml), "When using auto-format, this is the extension (end of filename) used to detect the BINARY format.\n");
  131. }
  132. //-----------------------------------------------------------------------------
  133. bool Taml::write( SimObject* pSimObject, const char* pFilename )
  134. {
  135. // Debug Profiling.
  136. PROFILE_SCOPE(Taml_Write);
  137. // Sanity!
  138. AssertFatal( pSimObject != NULL, "Cannot write a NULL object." );
  139. AssertFatal( pFilename != NULL, "Cannot write to a NULL filename." );
  140. // Expand the file-name into the file-path buffer.
  141. Con::expandPath( mFilePathBuffer, sizeof(mFilePathBuffer), pFilename );
  142. FileStream stream;
  143. // File opened?
  144. if ( !stream.open( mFilePathBuffer, FileStream::Write ) )
  145. {
  146. // No, so warn.
  147. Con::warnf("Taml::writeFile() - Could not open filename '%s' for write.", mFilePathBuffer );
  148. return false;
  149. }
  150. // Get the file auto-format mode.
  151. const TamlFormatMode formatMode = getFileAutoFormatMode( mFilePathBuffer );
  152. // Reset the compilation.
  153. resetCompilation();
  154. // Write object.
  155. const bool status = write( stream, pSimObject, formatMode );
  156. // Close file.
  157. stream.close();
  158. // Reset the compilation.
  159. resetCompilation();
  160. return status;
  161. }
  162. //-----------------------------------------------------------------------------
  163. SimObject* Taml::read( const char* pFilename )
  164. {
  165. // Debug Profiling.
  166. PROFILE_SCOPE(Taml_Read);
  167. // Sanity!
  168. AssertFatal( pFilename != NULL, "Cannot read from a NULL filename." );
  169. // Expand the file-name into the file-path buffer.
  170. Con::expandPath( mFilePathBuffer, sizeof(mFilePathBuffer), pFilename );
  171. FileStream stream;
  172. // File opened?
  173. if ( !stream.open( mFilePathBuffer, FileStream::Read ) )
  174. {
  175. // No, so warn.
  176. Con::warnf("Taml::read() - Could not open filename '%s' for read.", mFilePathBuffer );
  177. return NULL;
  178. }
  179. // Get the file auto-format mode.
  180. const TamlFormatMode formatMode = getFileAutoFormatMode( mFilePathBuffer );
  181. // Reset the compilation.
  182. resetCompilation();
  183. // Write object.
  184. SimObject* pSimObject = read( stream, formatMode );
  185. // Close file.
  186. stream.close();
  187. // Reset the compilation.
  188. resetCompilation();
  189. // Did we generate an object?
  190. if ( pSimObject == NULL )
  191. {
  192. // No, so warn.
  193. Con::warnf( "Taml::read() - Failed to load an object from the file '%s'.", mFilePathBuffer );
  194. }
  195. return pSimObject;
  196. }
  197. //-----------------------------------------------------------------------------
  198. bool Taml::write( FileStream& stream, SimObject* pSimObject, const TamlFormatMode formatMode )
  199. {
  200. // Sanity!
  201. AssertFatal( pSimObject != NULL, "Cannot write a NULL object." );
  202. // Compile nodes.
  203. TamlWriteNode* pRootNode = compileObject( pSimObject );
  204. // Format appropriately.
  205. switch( formatMode )
  206. {
  207. /// Xml.
  208. case XmlFormat:
  209. {
  210. // Create writer.
  211. TamlXmlWriter writer( this );
  212. // Write.
  213. return writer.write( stream, pRootNode );
  214. }
  215. /// Binary.
  216. case BinaryFormat:
  217. {
  218. // Create writer.
  219. TamlBinaryWriter writer( this );
  220. // Write.
  221. return writer.write( stream, pRootNode, mBinaryCompression );
  222. }
  223. /// Invalid.
  224. case InvalidFormat:
  225. {
  226. // Warn.
  227. Con::warnf("Taml::write() - Cannot write, invalid format.");
  228. return false;
  229. }
  230. }
  231. // Warn.
  232. Con::warnf("Taml::write() - Unknown format.");
  233. return false;
  234. }
  235. //-----------------------------------------------------------------------------
  236. SimObject* Taml::read( FileStream& stream, const TamlFormatMode formatMode )
  237. {
  238. // Format appropriately.
  239. switch( formatMode )
  240. {
  241. /// Xml.
  242. case XmlFormat:
  243. {
  244. // Create reader.
  245. TamlXmlReader reader( this );
  246. // Read.
  247. return reader.read( stream );
  248. }
  249. /// Binary.
  250. case BinaryFormat:
  251. {
  252. // Create reader.
  253. TamlBinaryReader reader( this );
  254. // Read.
  255. return reader.read( stream );
  256. }
  257. /// Invalid.
  258. case InvalidFormat:
  259. {
  260. // Warn.
  261. Con::warnf("Taml::read() - Cannot read, invalid format.");
  262. return NULL;
  263. }
  264. }
  265. // Warn.
  266. Con::warnf("Taml::read() - Unknown format.");
  267. return NULL;
  268. }
  269. //-----------------------------------------------------------------------------
  270. void Taml::resetCompilation( void )
  271. {
  272. // Debug Profiling.
  273. PROFILE_SCOPE(Taml_ResetCompilation);
  274. // Clear compiled nodes.
  275. for( typeNodeVector::iterator itr = mCompiledNodes.begin(); itr != mCompiledNodes.end(); ++itr )
  276. {
  277. // Fetch node.
  278. TamlWriteNode* pNode = (*itr);
  279. // Reset node.
  280. pNode->resetNode();
  281. // Delete node.
  282. delete pNode;
  283. }
  284. mCompiledNodes.clear();
  285. // Clear compiled objects.
  286. mCompiledObjects.clear();
  287. // Reset master node Id.
  288. mMasterNodeId = 0;
  289. }
  290. //-----------------------------------------------------------------------------
  291. Taml::TamlFormatMode Taml::getFileAutoFormatMode( const char* pFilename )
  292. {
  293. // Sanity!
  294. AssertFatal( pFilename != NULL, "Cannot auto-format using a NULL filename." );
  295. // Is auto-format active?
  296. if ( mAutoFormat )
  297. {
  298. // Yes, so fetch the extension lengths.
  299. const U32 xmlExtensionLength = dStrlen( mAutoFormatXmlExtension );
  300. const U32 binaryExtensionLength = dStrlen( mAutoFormatBinaryExtension );
  301. // Fetch filename length.
  302. const U32 filenameLength = dStrlen( pFilename );
  303. // Fetch end of filename,
  304. const char* pEndOfFilename = pFilename + filenameLength;
  305. // Check for the XML format.
  306. if ( xmlExtensionLength <= filenameLength && dStricmp( pEndOfFilename - xmlExtensionLength, mAutoFormatXmlExtension ) == 0 )
  307. return Taml::XmlFormat;
  308. // Check for the Binary format.
  309. if ( binaryExtensionLength <= filenameLength && dStricmp( pEndOfFilename - xmlExtensionLength, mAutoFormatBinaryExtension ) == 0 )
  310. return Taml::BinaryFormat;
  311. }
  312. // Use the explicitly specified format mode.
  313. return mFormatMode;
  314. }
  315. //-----------------------------------------------------------------------------
  316. TamlWriteNode* Taml::compileObject( SimObject* pSimObject, const bool forceId )
  317. {
  318. // Debug Profiling.
  319. PROFILE_SCOPE(Taml_CompileObject);
  320. // Sanity!
  321. AssertFatal( pSimObject != NULL, "Cannot compile a NULL object." );
  322. // Fetch object Id.
  323. const SimObjectId objectId = pSimObject->getId();
  324. // Find a previously compiled node.
  325. typeCompiledHash::iterator compiledItr = mCompiledObjects.find( objectId );
  326. // Have we already compiled this?
  327. if ( compiledItr != mCompiledObjects.end() )
  328. {
  329. // Yes, so sanity!
  330. AssertFatal( mCompiledNodes.size() != 0, "Found a compiled node at the root." );
  331. // Yes, so fetch node.
  332. TamlWriteNode* compiledNode = compiledItr->value;
  333. // Is a reference Id already present?
  334. if ( compiledNode->mRefId == 0 )
  335. {
  336. // No, so allocate one.
  337. compiledNode->mRefId = ++mMasterNodeId;
  338. }
  339. // Create write node.
  340. TamlWriteNode* pNewNode = new TamlWriteNode();
  341. pNewNode->set( pSimObject );
  342. // Set reference node.
  343. pNewNode->mRefToNode = compiledNode;
  344. // Push new node.
  345. mCompiledNodes.push_back( pNewNode );
  346. return pNewNode;
  347. }
  348. // No, so create write node.
  349. TamlWriteNode* pNewNode = new TamlWriteNode();
  350. pNewNode->set( pSimObject );
  351. // Is an Id being forced for this object?
  352. if ( forceId )
  353. {
  354. // Yes, so allocate one.
  355. pNewNode->mRefId = ++mMasterNodeId;
  356. }
  357. // Push new node.
  358. mCompiledNodes.push_back( pNewNode );
  359. // Insert compiled object.
  360. mCompiledObjects.insert( objectId, pNewNode );
  361. // Are there any Taml callbacks?
  362. if ( pNewNode->mpTamlCallbacks != NULL )
  363. {
  364. // Yes, so call it.
  365. tamlPreWrite( pNewNode->mpTamlCallbacks );
  366. }
  367. // Compile static and dynamic fields.
  368. compileStaticFields( pNewNode );
  369. compileDynamicFields( pNewNode );
  370. // Compile children.
  371. compileChildren( pNewNode );
  372. // Compile custom state.
  373. compileCustomState( pNewNode );
  374. // Are there any Taml callbacks?
  375. if ( pNewNode->mpTamlCallbacks != NULL )
  376. {
  377. // Yes, so call it.
  378. tamlPostWrite( pNewNode->mpTamlCallbacks );
  379. }
  380. return pNewNode;
  381. }
  382. //-----------------------------------------------------------------------------
  383. void Taml::compileStaticFields( TamlWriteNode* pTamlWriteNode )
  384. {
  385. // Debug Profiling.
  386. PROFILE_SCOPE(Taml_CompileStaticFields);
  387. // Sanity!
  388. AssertFatal( pTamlWriteNode != NULL, "Cannot compile static fields on a NULL node." );
  389. AssertFatal( pTamlWriteNode->mpSimObject != NULL, "Cannot compile static fields on a node with no object." );
  390. // Fetch object.
  391. SimObject* pSimObject = pTamlWriteNode->mpSimObject;
  392. // Fetch field list.
  393. const AbstractClassRep::FieldList& fieldList = pSimObject->getFieldList();
  394. // Fetch field count.
  395. const U32 fieldCount = fieldList.size();
  396. // Iterate fields.
  397. for( U32 index = 0; index < fieldCount; ++index )
  398. {
  399. // Fetch field.
  400. const AbstractClassRep::Field* pField = &fieldList[index];
  401. // Ignore if field not appropriate.
  402. if( pField->type == AbstractClassRep::DepricatedFieldType ||
  403. pField->type == AbstractClassRep::StartGroupFieldType ||
  404. pField->type == AbstractClassRep::EndGroupFieldType)
  405. continue;
  406. // Fetch fieldname.
  407. StringTableEntry fieldName = StringTable->insert( pField->pFieldname );
  408. // Fetch element count.
  409. const U32 elementCount = pField->elementCount;
  410. // Skip if the field should not be written.
  411. // For now, we only deal with non-array fields.
  412. if ( elementCount == 1 &&
  413. pField->writeDataFn != NULL &&
  414. ( !getWriteDefaults() && pField->writeDataFn( pSimObject, fieldName ) == false) )
  415. continue;
  416. // Iterate elements.
  417. for( U32 elementIndex = 0; elementIndex < elementCount; ++elementIndex )
  418. {
  419. char indexBuffer[8];
  420. dSprintf( indexBuffer, 8, "%d", elementIndex );
  421. // Fetch object field value.
  422. const char* pFieldValue = pSimObject->getPrefixedDataField( fieldName, indexBuffer );
  423. U32 nBufferSize = dStrlen( pFieldValue ) + 1;
  424. FrameTemp<char> valueCopy( nBufferSize );
  425. dStrcpy( (char *)valueCopy, pFieldValue );
  426. // Skip if field should not be written.
  427. if (!pSimObject->writeField(fieldName, valueCopy))
  428. continue;
  429. // Reassign field value.
  430. pFieldValue = valueCopy;
  431. // Detect and collapse relative path information
  432. char fnBuf[1024];
  433. if ((S32)pField->type == TypeFilename)
  434. {
  435. Con::collapsePath( fnBuf, 1024, pFieldValue );
  436. pFieldValue = fnBuf;
  437. }
  438. // Save field/value.
  439. TamlWriteNode::FieldValuePair* pFieldValuePair = new TamlWriteNode::FieldValuePair( fieldName, pFieldValue );
  440. pTamlWriteNode->mFields.push_back( pFieldValuePair );
  441. }
  442. }
  443. }
  444. //-----------------------------------------------------------------------------
  445. static S32 QSORT_CALLBACK compareFieldEntries(const void* a,const void* b)
  446. {
  447. // Debug Profiling.
  448. PROFILE_SCOPE(Taml_CompareFieldEntries);
  449. SimFieldDictionary::Entry *fa = *((SimFieldDictionary::Entry **)a);
  450. SimFieldDictionary::Entry *fb = *((SimFieldDictionary::Entry **)b);
  451. return dStricmp(fa->slotName, fb->slotName);
  452. }
  453. //-----------------------------------------------------------------------------
  454. void Taml::compileDynamicFields( TamlWriteNode* pTamlWriteNode )
  455. {
  456. // Debug Profiling.
  457. PROFILE_SCOPE(Taml_CompileDynamicFields);
  458. // Sanity!
  459. AssertFatal( pTamlWriteNode != NULL, "Cannot compile dynamic fields on a NULL node." );
  460. AssertFatal( pTamlWriteNode->mpSimObject != NULL, "Cannot compile dynamic fields on a node with no object." );
  461. // Fetch object.
  462. SimObject* pSimObject = pTamlWriteNode->mpSimObject;
  463. // Fetch field dictionary.
  464. SimFieldDictionary* pFieldDictionary = pSimObject->getFieldDictionary();
  465. // Ignore if not writing dynamic fields.
  466. if ( !pFieldDictionary || !pSimObject->getCanSaveDynamicFields() )
  467. return;
  468. // Fetch field list.
  469. const AbstractClassRep::FieldList& fieldList = pSimObject->getFieldList();
  470. // Fetch field count.
  471. const U32 fieldCount = fieldList.size();
  472. Vector<SimFieldDictionary::Entry*> dynamicFieldList(__FILE__, __LINE__);
  473. // Ensure the dynamic field doesn't conflict with static field.
  474. for( U32 hashIndex = 0; hashIndex < SimFieldDictionary::HashTableSize; ++hashIndex )
  475. {
  476. for( SimFieldDictionary::Entry* pEntry = pFieldDictionary->mHashTable[hashIndex]; pEntry; pEntry = pEntry->next )
  477. {
  478. // Iterate static fields.
  479. U32 fieldIndex;
  480. for( fieldIndex = 0; fieldIndex < fieldCount; ++fieldIndex )
  481. {
  482. if( fieldList[fieldIndex].pFieldname == pEntry->slotName)
  483. break;
  484. }
  485. // Skip if found.
  486. if( fieldIndex != (U32)fieldList.size() )
  487. continue;
  488. // Skip if not writing field.
  489. if ( !pSimObject->writeField( pEntry->slotName, pEntry->value) )
  490. continue;
  491. dynamicFieldList.push_back( pEntry );
  492. }
  493. }
  494. // Sort Entries to prevent version control conflicts
  495. if ( dynamicFieldList.size() > 1 )
  496. dQsort(dynamicFieldList.address(), dynamicFieldList.size(), sizeof(SimFieldDictionary::Entry*), compareFieldEntries);
  497. // Save the fields.
  498. for( Vector<SimFieldDictionary::Entry*>::iterator entryItr = dynamicFieldList.begin(); entryItr != dynamicFieldList.end(); ++entryItr )
  499. {
  500. // Fetch entry.
  501. SimFieldDictionary::Entry* pEntry = *entryItr;
  502. // Save field/value.
  503. TamlWriteNode::FieldValuePair* pFieldValuePair = new TamlWriteNode::FieldValuePair( pEntry->slotName, pEntry->value );
  504. pTamlWriteNode->mFields.push_back( pFieldValuePair );
  505. }
  506. }
  507. //-----------------------------------------------------------------------------
  508. void Taml::compileChildren( TamlWriteNode* pTamlWriteNode )
  509. {
  510. // Debug Profiling.
  511. PROFILE_SCOPE(Taml_CompileChildren);
  512. // Sanity!
  513. AssertFatal( pTamlWriteNode != NULL, "Cannot compile children on a NULL node." );
  514. AssertFatal( pTamlWriteNode->mpSimObject != NULL, "Cannot compile children on a node with no object." );
  515. // Fetch object.
  516. SimObject* pSimObject = pTamlWriteNode->mpSimObject;
  517. // Fetch the Taml children.
  518. TamlChildren* pChildren = dynamic_cast<TamlChildren*>( pSimObject );
  519. // Finish if object does not contain Taml children.
  520. if ( pChildren == NULL || pChildren->getTamlChildCount() == 0 )
  521. return;
  522. // Create children vector.
  523. pTamlWriteNode->mChildren = new typeNodeVector();
  524. // Fetch the child count.
  525. const U32 childCount = pChildren->getTamlChildCount();
  526. // Iterate children.
  527. for ( U32 childIndex = 0; childIndex < childCount; childIndex++ )
  528. {
  529. // Compile object.
  530. TamlWriteNode* pChildTamlWriteNode = compileObject( pChildren->getTamlChild(childIndex) );
  531. // Save node.
  532. pTamlWriteNode->mChildren->push_back( pChildTamlWriteNode );
  533. }
  534. }
  535. //-----------------------------------------------------------------------------
  536. void Taml::compileCustomState( TamlWriteNode* pTamlWriteNode )
  537. {
  538. // Debug Profiling.
  539. PROFILE_SCOPE(Taml_CompileCustomProperties);
  540. // Sanity!
  541. AssertFatal( pTamlWriteNode != NULL, "Cannot compile custom state on a NULL node." );
  542. AssertFatal( pTamlWriteNode->mpSimObject != NULL, "Cannot compile custom state on a node with no object." );
  543. // Fetch the custom node on the write node.
  544. TamlCustomNodes& customNodes = pTamlWriteNode->mCustomNodes;
  545. // Are there any Taml callbacks?
  546. if ( pTamlWriteNode->mpTamlCallbacks != NULL )
  547. {
  548. // Yes, so call it.
  549. tamlCustomWrite( pTamlWriteNode->mpTamlCallbacks, customNodes );
  550. }
  551. // Fetch custom nodes.
  552. const TamlCustomNodeVector& nodes = customNodes.getNodes();
  553. // Finish if no custom nodes to process.
  554. if ( nodes.size() == 0 )
  555. return;
  556. // Iterate custom properties.
  557. for( TamlCustomNodeVector::const_iterator customNodesItr = nodes.begin(); customNodesItr != nodes.end(); ++customNodesItr )
  558. {
  559. // Fetch the custom node.
  560. TamlCustomNode* pCustomNode = *customNodesItr;
  561. // Compile custom node state.
  562. compileCustomNodeState( pCustomNode );
  563. }
  564. }
  565. //-----------------------------------------------------------------------------
  566. void Taml::compileCustomNodeState( TamlCustomNode* pCustomNode )
  567. {
  568. // Sanity!
  569. AssertFatal( pCustomNode != NULL, "Taml: Cannot compile NULL custom node state." );
  570. // Fetch children.
  571. const TamlCustomNodeVector& children = pCustomNode->getChildren();
  572. // Fetch proxy object.
  573. SimObject* pProxyObject = pCustomNode->getProxyObject<SimObject>(false);
  574. // Do we have a proxy object?
  575. if ( pProxyObject != NULL )
  576. {
  577. // Yes, so sanity!
  578. AssertFatal( children.size() == 0, "Taml: Cannot compile a proxy object on a custom node that has children." );
  579. // Yes, so compile it.
  580. // NOTE: We force an Id for custom compiled objects so we guarantee an Id. The reason for this is fairly
  581. // weak in that the XML parser currently has no way of distinguishing between a compiled object node
  582. // and a custom node. If the node has an Id or an Id-Ref then it's obviously an object and should be parsed as such.
  583. pCustomNode->setWriteNode( compileObject( pProxyObject, true ) );
  584. return;
  585. }
  586. // Finish if no children.
  587. if ( children.size() == 0 )
  588. return;
  589. // Iterate children.
  590. for( TamlCustomNodeVector::const_iterator childItr = children.begin(); childItr != children.end(); ++childItr )
  591. {
  592. // Fetch shape node.
  593. TamlCustomNode* pChildNode = *childItr;
  594. // Compile the child.
  595. compileCustomNodeState( pChildNode );
  596. }
  597. }
  598. //-----------------------------------------------------------------------------
  599. SimObject* Taml::createType( StringTableEntry typeName, const Taml* pTaml, const char* pProgenitorSuffix )
  600. {
  601. // Debug Profiling.
  602. PROFILE_SCOPE(Taml_CreateType);
  603. typedef HashMap<StringTableEntry, AbstractClassRep*> typeClassHash;
  604. static typeClassHash mClassMap;
  605. // Sanity!
  606. AssertFatal( typeName != NULL, "Taml: Type cannot be NULL" );
  607. // Find type.
  608. typeClassHash::iterator typeItr = mClassMap.find( typeName );
  609. // Found type?
  610. if ( typeItr == mClassMap.end() )
  611. {
  612. // No, so find type.
  613. AbstractClassRep* pClassRep = AbstractClassRep::getClassList();
  614. while( pClassRep )
  615. {
  616. // Is this the type?
  617. if( dStricmp( pClassRep->getClassName(), typeName ) == 0 )
  618. {
  619. // Yes, so insert it.
  620. typeItr = mClassMap.insert( typeName, pClassRep );
  621. break;
  622. }
  623. // Next type.
  624. pClassRep = pClassRep->getNextClass();
  625. }
  626. // Did we find the type?
  627. if ( typeItr == mClassMap.end() )
  628. {
  629. // No, so warn and fail.
  630. Con::warnf( "Taml: Failed to create type '%s' as such a registered type could not be found.", typeName );
  631. return NULL;
  632. }
  633. }
  634. // Create the object.
  635. ConsoleObject* pConsoleObject = typeItr->value->create();
  636. // NOTE: It is important that we don't register the object here as many objects rely on the fact that
  637. // fields are set prior to the object being registered. Registering here will invalid those assumptions.
  638. // Fetch the SimObject.
  639. SimObject* pSimObject = dynamic_cast<SimObject*>( pConsoleObject );
  640. // Was it a SimObject?
  641. if ( pSimObject == NULL )
  642. {
  643. // No, so warn.
  644. Con::warnf( "Taml: Failed to create type '%s' as it is not a SimObject.", typeName );
  645. // Destroy object and fail.
  646. delete pConsoleObject;
  647. return NULL;
  648. }
  649. // Are we updating the file-progenitor?
  650. if ( pTaml->getProgenitorUpdate() )
  651. {
  652. // Yes, so do we have a progenitor suffix?
  653. if ( pProgenitorSuffix == NULL )
  654. {
  655. // No, so just set it to the progenitor file.
  656. pSimObject->setProgenitorFile( pTaml->getFilePathBuffer() );
  657. }
  658. else
  659. {
  660. // Yes, so format the progenitor buffer.
  661. char progenitorBuffer[2048];
  662. dSprintf( progenitorBuffer, sizeof(progenitorBuffer), "%s,%s", pTaml->getFilePathBuffer(), pProgenitorSuffix );
  663. // Set the progenitor file.
  664. pSimObject->setProgenitorFile( progenitorBuffer );
  665. }
  666. }
  667. return pSimObject;
  668. }
  669. //-----------------------------------------------------------------------------
  670. bool Taml::generateTamlSchema()
  671. {
  672. // Fetch any TAML Schema file reference.
  673. const char* pTamlSchemaFile = Con::getVariable( TAML_SCHEMA_VARIABLE );
  674. // Do we have a schema file reference?
  675. if ( pTamlSchemaFile == NULL || *pTamlSchemaFile == 0 )
  676. {
  677. // No, so warn.
  678. Con::warnf( "Taml::generateTamlSchema() - Cannot write a TAML schema as no schema variable is set ('%s').", TAML_SCHEMA_VARIABLE );
  679. return false;
  680. }
  681. // Expand the file-name into the file-path buffer.
  682. char filePathBuffer[1024];
  683. Con::expandPath( filePathBuffer, sizeof(filePathBuffer), pTamlSchemaFile );
  684. FileStream stream;
  685. // File opened?
  686. if ( !stream.open( filePathBuffer, FileStream::Write ) )
  687. {
  688. // No, so warn.
  689. Con::warnf("Taml::GenerateTamlSchema() - Could not open filename '%s' for write.", filePathBuffer );
  690. return false;
  691. }
  692. // Create document.
  693. TiXmlDocument schemaDocument;
  694. // Add declaration.
  695. TiXmlDeclaration schemaDeclaration( "1.0", "iso-8859-1", "no" );
  696. schemaDocument.InsertEndChild( schemaDeclaration );
  697. // Add schema element.
  698. TiXmlElement* pSchemaElement = new TiXmlElement( "xs:schema" );
  699. pSchemaElement->SetAttribute( "xmlns:xs", "http://www.w3.org/2001/XMLSchema" );
  700. schemaDocument.LinkEndChild( pSchemaElement );
  701. // Fetch class-rep root.
  702. AbstractClassRep* pRootType = AbstractClassRep::getClassList();
  703. // Fetch SimObject class rep.
  704. AbstractClassRep* pSimObjectType = AbstractClassRep::findClassRep( "SimObject" );
  705. // Sanity!
  706. AssertFatal( pSimObjectType != NULL, "Taml::GenerateTamlSchema() - Could not find SimObject class rep." );
  707. // Reset scratch state.
  708. char buffer[1024];
  709. HashMap<AbstractClassRep*, StringTableEntry> childGroups;
  710. // *************************************************************
  711. // Generate console type elements.
  712. // *************************************************************
  713. // Vector2.
  714. TiXmlComment* pVector2Comment = new TiXmlComment( "Vector2 Console Type" );
  715. pSchemaElement->LinkEndChild( pVector2Comment );
  716. TiXmlElement* pVector2TypeElement = new TiXmlElement( "xs:simpleType" );
  717. pVector2TypeElement->SetAttribute( "name", "Vector2_ConsoleType" );
  718. pSchemaElement->LinkEndChild( pVector2TypeElement );
  719. TiXmlElement* pVector2ElementA = new TiXmlElement( "xs:restriction" );
  720. pVector2ElementA->SetAttribute( "base", "xs:string" );
  721. pVector2TypeElement->LinkEndChild( pVector2ElementA );
  722. TiXmlElement* pVector2ElementB = new TiXmlElement( "xs:pattern" );
  723. pVector2ElementB->SetAttribute( "value", "([-]?(\\b[0-9]+)?\\.)?[0-9]+\\b ([-]?(\\b[0-9]+)?\\.)?[0-9]+\\b" );
  724. pVector2ElementA->LinkEndChild( pVector2ElementB );
  725. // Point2F.
  726. TiXmlComment* pPoint2FComment = new TiXmlComment( "Point2F Console Type" );
  727. pSchemaElement->LinkEndChild( pPoint2FComment );
  728. TiXmlElement* pPoint2FTypeElement = new TiXmlElement( "xs:simpleType" );
  729. pPoint2FTypeElement->SetAttribute( "name", "Point2F_ConsoleType" );
  730. pSchemaElement->LinkEndChild( pPoint2FTypeElement );
  731. TiXmlElement* pPoint2FElementA = new TiXmlElement( "xs:restriction" );
  732. pPoint2FElementA->SetAttribute( "base", "xs:string" );
  733. pPoint2FTypeElement->LinkEndChild( pPoint2FElementA );
  734. TiXmlElement* pPoint2FElementB = new TiXmlElement( "xs:pattern" );
  735. pPoint2FElementB->SetAttribute( "value", "([-]?(\\b[0-9]+)?\\.)?[0-9]+\\b ([-]?(\\b[0-9]+)?\\.)?[0-9]+\\b" );
  736. pPoint2FElementA->LinkEndChild( pPoint2FElementB );
  737. // Point2I.
  738. TiXmlComment* pPoint2IComment = new TiXmlComment( "Point2I Console Type" );
  739. pSchemaElement->LinkEndChild( pPoint2IComment );
  740. TiXmlElement* pPoint2ITypeElement = new TiXmlElement( "xs:simpleType" );
  741. pPoint2ITypeElement->SetAttribute( "name", "Point2I_ConsoleType" );
  742. pSchemaElement->LinkEndChild( pPoint2ITypeElement );
  743. TiXmlElement* pPoint2IElementA = new TiXmlElement( "xs:restriction" );
  744. pPoint2IElementA->SetAttribute( "base", "xs:string" );
  745. pPoint2ITypeElement->LinkEndChild( pPoint2IElementA );
  746. TiXmlElement* pPoint2IElementB = new TiXmlElement( "xs:pattern" );
  747. pPoint2IElementB->SetAttribute( "value", "[-]?[0-9]* [-]?[0-9]*" );
  748. pPoint2IElementA->LinkEndChild( pPoint2IElementB );
  749. // b2AABB.
  750. TiXmlComment* pb2AABBComment = new TiXmlComment( "b2AABB Console Type" );
  751. pSchemaElement->LinkEndChild( pb2AABBComment );
  752. TiXmlElement* pb2AABBTypeElement = new TiXmlElement( "xs:simpleType" );
  753. pb2AABBTypeElement->SetAttribute( "name", "b2AABB_ConsoleType" );
  754. pSchemaElement->LinkEndChild( pb2AABBTypeElement );
  755. TiXmlElement* pb2AABBElementA = new TiXmlElement( "xs:restriction" );
  756. pb2AABBElementA->SetAttribute( "base", "xs:string" );
  757. pb2AABBTypeElement->LinkEndChild( pb2AABBElementA );
  758. TiXmlElement* pb2AABBElementB = new TiXmlElement( "xs:pattern" );
  759. pb2AABBElementB->SetAttribute( "value", "([-]?(\\b[0-9]+)?\\.)?[0-9]+\\b ([-]?(\\b[0-9]+)?\\.)?[0-9]+\\b ([-]?(\\b[0-9]+)?\\.)?[0-9]+\\b ([-]?(\\b[0-9]+)?\\.)?[0-9]+\\b" );
  760. pb2AABBElementA->LinkEndChild( pb2AABBElementB );
  761. // RectI.
  762. TiXmlComment* pRectIComment = new TiXmlComment( "RectI Console Type" );
  763. pSchemaElement->LinkEndChild( pRectIComment );
  764. TiXmlElement* pRectITypeElement = new TiXmlElement( "xs:simpleType" );
  765. pRectITypeElement->SetAttribute( "name", "RectI_ConsoleType" );
  766. pSchemaElement->LinkEndChild( pRectITypeElement );
  767. TiXmlElement* pRectIElementA = new TiXmlElement( "xs:restriction" );
  768. pRectIElementA->SetAttribute( "base", "xs:string" );
  769. pRectITypeElement->LinkEndChild( pRectIElementA );
  770. TiXmlElement* pRectIElementB = new TiXmlElement( "xs:pattern" );
  771. pRectIElementB->SetAttribute( "value", "[-]?[0-9]* [-]?[0-9]* [-]?[0-9]* [-]?[0-9]*" );
  772. pRectIElementA->LinkEndChild( pRectIElementB );
  773. // RectF.
  774. TiXmlComment* pRectFComment = new TiXmlComment( "RectF Console Type" );
  775. pSchemaElement->LinkEndChild( pRectFComment );
  776. TiXmlElement* pRectFTypeElement = new TiXmlElement( "xs:simpleType" );
  777. pRectFTypeElement->SetAttribute( "name", "RectF_ConsoleType" );
  778. pSchemaElement->LinkEndChild( pRectFTypeElement );
  779. TiXmlElement* pRectFElementA = new TiXmlElement( "xs:restriction" );
  780. pRectFElementA->SetAttribute( "base", "xs:string" );
  781. pRectFTypeElement->LinkEndChild( pRectFElementA );
  782. TiXmlElement* pRectFElementB = new TiXmlElement( "xs:pattern" );
  783. pRectFElementB->SetAttribute( "value", "(\\b[-]?(b[0-9]+)?\\.)?[0-9]+\\b" );
  784. pRectFElementA->LinkEndChild( pRectFElementB );
  785. // AssetId.
  786. TiXmlComment* pAssetIdComment = new TiXmlComment( "AssetId Console Type" );
  787. pSchemaElement->LinkEndChild( pAssetIdComment );
  788. TiXmlElement* pAssetIdTypeElement = new TiXmlElement( "xs:simpleType" );
  789. pAssetIdTypeElement->SetAttribute( "name", "AssetId_ConsoleType" );
  790. pSchemaElement->LinkEndChild( pAssetIdTypeElement );
  791. TiXmlElement* pAssetIdElementA = new TiXmlElement( "xs:restriction" );
  792. pAssetIdElementA->SetAttribute( "base", "xs:string" );
  793. pAssetIdTypeElement->LinkEndChild( pAssetIdElementA );
  794. TiXmlElement* pAssetIdElementB = new TiXmlElement( "xs:pattern" );
  795. dSprintf( buffer, sizeof(buffer), "(%s)?\\b[a-zA-Z0-9]+\\b%s\\b[a-zA-Z0-9]+\\b", ASSET_ID_FIELD_PREFIX, ASSET_SCOPE_TOKEN );
  796. pAssetIdElementB->SetAttribute( "value", buffer );
  797. pAssetIdElementA->LinkEndChild( pAssetIdElementB );
  798. // Color Enums.
  799. TiXmlComment* pColorEnumsComment = new TiXmlComment( "Color Enums" );
  800. pSchemaElement->LinkEndChild( pColorEnumsComment );
  801. TiXmlElement* pColorEnumsTypeElement = new TiXmlElement( "xs:simpleType" );
  802. pColorEnumsTypeElement->SetAttribute( "name", "Color_Enums" );
  803. pSchemaElement->LinkEndChild( pColorEnumsTypeElement );
  804. TiXmlElement* pColorEnumsRestrictionElement = new TiXmlElement( "xs:restriction" );
  805. pColorEnumsRestrictionElement->SetAttribute( "base", "xs:string" );
  806. pColorEnumsTypeElement->LinkEndChild( pColorEnumsRestrictionElement );
  807. const S32 ColorEnumsCount = StockColor::getCount();
  808. for( S32 index = 0; index < ColorEnumsCount; ++index )
  809. {
  810. // Add enumeration element.
  811. TiXmlElement* pColorEnumsAttributeEnumerationElement = new TiXmlElement( "xs:enumeration" );
  812. pColorEnumsAttributeEnumerationElement->SetAttribute( "value", StockColor::getColorItem(index)->getColorName() );
  813. pColorEnumsRestrictionElement->LinkEndChild( pColorEnumsAttributeEnumerationElement );
  814. }
  815. // ColorF.
  816. TiXmlComment* pColorFValuesComment = new TiXmlComment( "ColorF Values" );
  817. pSchemaElement->LinkEndChild( pColorFValuesComment );
  818. TiXmlElement* pColorFValuesTypeElement = new TiXmlElement( "xs:simpleType" );
  819. pColorFValuesTypeElement->SetAttribute( "name", "ColorF_Values" );
  820. pSchemaElement->LinkEndChild( pColorFValuesTypeElement );
  821. TiXmlElement* pColorFValuesElementA = new TiXmlElement( "xs:restriction" );
  822. pColorFValuesElementA->SetAttribute( "base", "xs:string" );
  823. pColorFValuesTypeElement->LinkEndChild( pColorFValuesElementA );
  824. TiXmlElement* pColorFValuesElementB = new TiXmlElement( "xs:pattern" );
  825. pColorFValuesElementB->SetAttribute( "value", "([-]?(\\b[0-9]+)?\\.)?[0-9]+\\b ([-]?(\\b[0-9]+)?\\.)?[0-9]+\\b ([-]?(\\b[0-9]+)?\\.)?[0-9]+\\b ([-]?(\\b[0-9]+)?\\.)?[0-9]+\\b" );
  826. pColorFValuesElementA->LinkEndChild( pColorFValuesElementB );
  827. TiXmlComment* pColorFComment = new TiXmlComment( "ColorF Console Type" );
  828. pSchemaElement->LinkEndChild( pColorFComment );
  829. TiXmlElement* pColorFTypeElement = new TiXmlElement( "xs:simpleType" );
  830. pColorFTypeElement->SetAttribute( "name", "ColorF_ConsoleType" );
  831. pSchemaElement->LinkEndChild( pColorFTypeElement );
  832. TiXmlElement* pColorFUnionElement = new TiXmlElement( "xs:union" );
  833. pColorFUnionElement->SetAttribute( "memberTypes", "ColorF_Values Color_Enums" );
  834. pColorFTypeElement->LinkEndChild( pColorFUnionElement );
  835. // ColorI.
  836. TiXmlComment* pColorIValuesComment = new TiXmlComment( "ColorI Values" );
  837. pSchemaElement->LinkEndChild( pColorIValuesComment );
  838. TiXmlElement* pColorIValuesTypeElement = new TiXmlElement( "xs:simpleType" );
  839. pColorIValuesTypeElement->SetAttribute( "name", "ColorI_Values" );
  840. pSchemaElement->LinkEndChild( pColorIValuesTypeElement );
  841. TiXmlElement* pColorIValuesElementA = new TiXmlElement( "xs:restriction" );
  842. pColorIValuesElementA->SetAttribute( "base", "xs:string" );
  843. pColorIValuesTypeElement->LinkEndChild( pColorIValuesElementA );
  844. TiXmlElement* pColorIValuesElementB = new TiXmlElement( "xs:pattern" );
  845. pColorIValuesElementB->SetAttribute( "value", "[-]?[0-9]* [-]?[0-9]* [-]?[0-9]* [-]?[0-9]*" );
  846. pColorIValuesElementA->LinkEndChild( pColorIValuesElementB );
  847. TiXmlComment* pColorIComment = new TiXmlComment( "ColorI Console Type" );
  848. pSchemaElement->LinkEndChild( pColorIComment );
  849. TiXmlElement* pColorITypeElement = new TiXmlElement( "xs:simpleType" );
  850. pColorITypeElement->SetAttribute( "name", "ColorI_ConsoleType" );
  851. pSchemaElement->LinkEndChild( pColorITypeElement );
  852. TiXmlElement* pColorIUnionElement = new TiXmlElement( "xs:union" );
  853. pColorIUnionElement->SetAttribute( "memberTypes", "ColorI_Values Color_Enums" );
  854. pColorITypeElement->LinkEndChild( pColorIUnionElement );
  855. // *************************************************************
  856. // Generate engine type elements.
  857. // *************************************************************
  858. // Generate the engine type elements.
  859. TiXmlComment* pComment = new TiXmlComment( "Type Elements" );
  860. pSchemaElement->LinkEndChild( pComment );
  861. for ( AbstractClassRep* pType = pRootType; pType != NULL; pType = pType->getNextClass() )
  862. {
  863. // Add type.
  864. TiXmlElement* pTypeElement = new TiXmlElement( "xs:element" );
  865. pTypeElement->SetAttribute( "name", pType->getClassName() );
  866. dSprintf( buffer, sizeof(buffer), "%s_Type", pType->getClassName() );
  867. pTypeElement->SetAttribute( "type", buffer );
  868. pSchemaElement->LinkEndChild( pTypeElement );
  869. }
  870. // *************************************************************
  871. // Generate the engine complex types.
  872. // *************************************************************
  873. for ( AbstractClassRep* pType = pRootType; pType != NULL; pType = pType->getNextClass() )
  874. {
  875. // Add complex type comment.
  876. dSprintf( buffer, sizeof(buffer), " %s Type ", pType->getClassName() );
  877. TiXmlComment* pComment = new TiXmlComment( buffer );
  878. pSchemaElement->LinkEndChild( pComment );
  879. // Add complex type.
  880. TiXmlElement* pComplexTypeElement = new TiXmlElement( "xs:complexType" );
  881. dSprintf( buffer, sizeof(buffer), "%s_Type", pType->getClassName() );
  882. pComplexTypeElement->SetAttribute( "name", buffer );
  883. pSchemaElement->LinkEndChild( pComplexTypeElement );
  884. // Add sequence.
  885. TiXmlElement* pSequenceElement = new TiXmlElement( "xs:sequence" );
  886. pComplexTypeElement->LinkEndChild( pSequenceElement );
  887. // Fetch container child class.
  888. AbstractClassRep* pContainerChildClass = pType->getContainerChildClass( true );
  889. // Is the type allowed children?
  890. if ( pContainerChildClass != NULL )
  891. {
  892. // Yes, so add choice element.
  893. TiXmlElement* pChoiceElement = new TiXmlElement( "xs:choice" );
  894. pChoiceElement->SetAttribute( "minOccurs", 0 );
  895. pChoiceElement->SetAttribute( "maxOccurs", "unbounded" );
  896. pSequenceElement->LinkEndChild( pChoiceElement );
  897. // Find child group.
  898. HashMap<AbstractClassRep*, StringTableEntry>::iterator childGroupItr = childGroups.find( pContainerChildClass );
  899. // Does the group exist?
  900. if ( childGroupItr == childGroups.end() )
  901. {
  902. // No, so format group name.
  903. dSprintf( buffer, sizeof(buffer), "%s_ChildrenTypes", pContainerChildClass->getClassName() );
  904. // Insert into child group hash.
  905. childGroupItr = childGroups.insert( pContainerChildClass, StringTable->insert( buffer ) );
  906. // Add the group.
  907. TiXmlElement* pChildrenGroupElement = new TiXmlElement( "xs:group" );
  908. pChildrenGroupElement->SetAttribute( "name", buffer );
  909. pSchemaElement->LinkEndChild( pChildrenGroupElement );
  910. // Add choice element.
  911. TiXmlElement* pChildreGroupChoiceElement = new TiXmlElement( "xs:choice" );
  912. pChildrenGroupElement->LinkEndChild( pChildreGroupChoiceElement );
  913. // Add choice members.
  914. for ( AbstractClassRep* pChoiceType = pRootType; pChoiceType != NULL; pChoiceType = pChoiceType->getNextClass() )
  915. {
  916. // Skip if not derived from the container child class.
  917. if ( !pChoiceType->isClass( pContainerChildClass ) )
  918. continue;
  919. // Add choice member.
  920. TiXmlElement* pChildrenMemberElement = new TiXmlElement( "xs:element" );
  921. pChildrenMemberElement->SetAttribute( "name", pChoiceType->getClassName() );
  922. dSprintf( buffer, sizeof(buffer), "%s_Type", pChoiceType->getClassName() );
  923. pChildrenMemberElement->SetAttribute( "type", buffer );
  924. pChildreGroupChoiceElement->LinkEndChild( pChildrenMemberElement );
  925. }
  926. }
  927. // Reference the child group.
  928. TiXmlElement* pChoiceGroupReferenceElement = new TiXmlElement( "xs:group" );
  929. pChoiceGroupReferenceElement->SetAttribute( "ref", childGroupItr->value );
  930. pChoiceGroupReferenceElement->SetAttribute( "minOccurs", 0 );
  931. pChoiceElement->LinkEndChild( pChoiceGroupReferenceElement );
  932. }
  933. // Generate the custom Taml schema.
  934. for ( AbstractClassRep* pCustomSchemaType = pType; pCustomSchemaType != NULL; pCustomSchemaType = pCustomSchemaType->getParentClass() )
  935. {
  936. // Fetch the types custom TAML schema function.
  937. AbstractClassRep::WriteCustomTamlSchema customSchemaFn = pCustomSchemaType->getCustomTamlSchema();
  938. // Skip if no function avilable.
  939. if ( customSchemaFn == NULL )
  940. continue;
  941. // Call schema generation function.
  942. customSchemaFn( pType, pSequenceElement );
  943. }
  944. // Generate field attribute group.
  945. TiXmlElement* pFieldAttributeGroupElement = new TiXmlElement( "xs:attributeGroup" );
  946. dSprintf( buffer, sizeof(buffer), "%s_Fields", pType->getClassName() );
  947. pFieldAttributeGroupElement->SetAttribute( "name", buffer );
  948. pSchemaElement->LinkEndChild( pFieldAttributeGroupElement );
  949. // Fetch field list.
  950. const AbstractClassRep::FieldList& fields = pType->mFieldList;
  951. // Fetcj field count.
  952. const S32 fieldCount = fields.size();
  953. // Iterate static fields (in reverse as most types are organized from the root-fields up).
  954. for( S32 index = fieldCount-1; index > 0; --index )
  955. {
  956. // Fetch field.
  957. const AbstractClassRep::Field& field = fields[index];
  958. // Skip if not a data field.
  959. if( field.type == AbstractClassRep::DepricatedFieldType ||
  960. field.type == AbstractClassRep::StartGroupFieldType ||
  961. field.type == AbstractClassRep::EndGroupFieldType )
  962. continue;
  963. // Skip if the field root is not this type.
  964. if ( pType->findFieldRoot( field.pFieldname ) != pType )
  965. continue;
  966. // Add attribute element.
  967. TiXmlElement* pAttributeElement = new TiXmlElement( "xs:attribute" );
  968. pAttributeElement->SetAttribute( "name", field.pFieldname );
  969. // Handle the console type appropriately.
  970. const S32 fieldType = (S32)field.type;
  971. // Is the field an enumeration?
  972. if ( fieldType == TypeEnum )
  973. {
  974. // Yes, so add attribute type.
  975. TiXmlElement* pAttributeSimpleTypeElement = new TiXmlElement( "xs:simpleType" );
  976. pAttributeElement->LinkEndChild( pAttributeSimpleTypeElement );
  977. // Add restriction element.
  978. TiXmlElement* pAttributeRestrictionElement = new TiXmlElement( "xs:restriction" );
  979. pAttributeRestrictionElement->SetAttribute( "base", "xs:string" );
  980. pAttributeSimpleTypeElement->LinkEndChild( pAttributeRestrictionElement );
  981. // Yes, so fetch enumeration count.
  982. const S32 enumCount = field.table->size;
  983. // Iterate enumeration.
  984. for( S32 index = 0; index < enumCount; ++index )
  985. {
  986. // Add enumeration element.
  987. TiXmlElement* pAttributeEnumerationElement = new TiXmlElement( "xs:enumeration" );
  988. pAttributeEnumerationElement->SetAttribute( "value", field.table->table[index].label );
  989. pAttributeRestrictionElement->LinkEndChild( pAttributeEnumerationElement );
  990. }
  991. }
  992. else
  993. {
  994. // No, so assume it's a string type initially.
  995. const char* pFieldTypeDescription = "xs:string";
  996. // Handle known types.
  997. if( fieldType == TypeF32 )
  998. {
  999. pFieldTypeDescription = "xs:float";
  1000. }
  1001. else if( fieldType == TypeS8 || fieldType == TypeS32 )
  1002. {
  1003. pFieldTypeDescription = "xs:int";
  1004. }
  1005. else if( fieldType == TypeBool || fieldType == TypeFlag )
  1006. {
  1007. pFieldTypeDescription = "xs:boolean";
  1008. }
  1009. else if( fieldType == TypeVector2 )
  1010. {
  1011. pFieldTypeDescription = "Vector2_ConsoleType";
  1012. }
  1013. else if( fieldType == TypePoint2F )
  1014. {
  1015. pFieldTypeDescription = "Point2F_ConsoleType";
  1016. }
  1017. else if( fieldType == TypePoint2I )
  1018. {
  1019. pFieldTypeDescription = "Point2I_ConsoleType";
  1020. }
  1021. else if( fieldType == Typeb2AABB )
  1022. {
  1023. pFieldTypeDescription = "b2AABB_ConsoleType";
  1024. }
  1025. else if( fieldType == TypeRectI )
  1026. {
  1027. pFieldTypeDescription = "RectI_ConsoleType";
  1028. }
  1029. else if( fieldType == TypeRectF )
  1030. {
  1031. pFieldTypeDescription = "RectF_ConsoleType";
  1032. }
  1033. else if( fieldType == TypeColorF )
  1034. {
  1035. pFieldTypeDescription = "ColorF_ConsoleType";
  1036. }
  1037. else if( fieldType == TypeColorI )
  1038. {
  1039. pFieldTypeDescription = "ColorI_ConsoleType";
  1040. }
  1041. else if( fieldType == TypeAssetId ||
  1042. fieldType == TypeImageAssetPtr ||
  1043. fieldType == TypeAnimationAssetPtr ||
  1044. fieldType == TypeAudioAssetPtr )
  1045. {
  1046. pFieldTypeDescription = "AssetId_ConsoleType";
  1047. }
  1048. // Set attribute type.
  1049. pAttributeElement->SetAttribute( "type", pFieldTypeDescription );
  1050. }
  1051. pAttributeElement->SetAttribute( "use", "optional" );
  1052. pFieldAttributeGroupElement->LinkEndChild( pAttributeElement );
  1053. }
  1054. // Is this the SimObject Type?
  1055. if ( pType == pSimObjectType )
  1056. {
  1057. // Yes, so add reserved Taml field attributes here...
  1058. // Add Taml "Name" attribute element.
  1059. TiXmlElement* pNameAttributeElement = new TiXmlElement( "xs:attribute" );
  1060. pNameAttributeElement->SetAttribute( "name", tamlNamedObjectName );
  1061. pNameAttributeElement->SetAttribute( "type", "xs:normalizedString" );
  1062. pFieldAttributeGroupElement->LinkEndChild( pNameAttributeElement );
  1063. // Add Taml "TamlId" attribute element.
  1064. TiXmlElement* pTamlIdAttributeElement = new TiXmlElement( "xs:attribute" );
  1065. pTamlIdAttributeElement->SetAttribute( "name", tamlRefIdName );
  1066. pTamlIdAttributeElement->SetAttribute( "type", "xs:nonNegativeInteger" );
  1067. pFieldAttributeGroupElement->LinkEndChild( pTamlIdAttributeElement );
  1068. // Add Taml "TamlRefId" attribute element.
  1069. TiXmlElement* pTamlRefIdAttributeElement = new TiXmlElement( "xs:attribute" );
  1070. pTamlRefIdAttributeElement->SetAttribute( "name", tamlRefToIdName );
  1071. pTamlRefIdAttributeElement->SetAttribute( "type", "xs:nonNegativeInteger" );
  1072. pFieldAttributeGroupElement->LinkEndChild( pTamlRefIdAttributeElement );
  1073. }
  1074. // Add attribute group types.
  1075. for ( AbstractClassRep* pAttributeGroupsType = pType; pAttributeGroupsType != NULL; pAttributeGroupsType = pAttributeGroupsType->getParentClass() )
  1076. {
  1077. TiXmlElement* pFieldAttributeGroupRefElement = new TiXmlElement( "xs:attributeGroup" );
  1078. dSprintf( buffer, sizeof(buffer), "%s_Fields", pAttributeGroupsType->getClassName() );
  1079. pFieldAttributeGroupRefElement->SetAttribute( "ref", buffer );
  1080. pComplexTypeElement->LinkEndChild( pFieldAttributeGroupRefElement );
  1081. }
  1082. // Add "any" attribute element (dynamic fields).
  1083. TiXmlElement* pAnyAttributeElement = new TiXmlElement( "xs:anyAttribute" );
  1084. pAnyAttributeElement->SetAttribute( "processContents", "skip" );
  1085. pComplexTypeElement->LinkEndChild( pAnyAttributeElement );
  1086. }
  1087. // Write the schema document.
  1088. schemaDocument.SaveFile( stream );
  1089. // Close file.
  1090. stream.close();
  1091. return true;
  1092. }
  1093. //-----------------------------------------------------------------------------
  1094. void Taml::WriteUnrestrictedCustomTamlSchema( const char* pCustomNodeName, const AbstractClassRep* pClassRep, TiXmlElement* pParentElement )
  1095. {
  1096. // Sanity!
  1097. AssertFatal( pCustomNodeName != NULL, "Taml::WriteDefaultCustomTamlSchema() - Node name cannot be NULL." );
  1098. AssertFatal( pClassRep != NULL, "Taml::WriteDefaultCustomTamlSchema() - ClassRep cannot be NULL." );
  1099. AssertFatal( pParentElement != NULL, "Taml::WriteDefaultCustomTamlSchema() - Parent Element cannot be NULL." );
  1100. char buffer[1024];
  1101. // Add custom type element.
  1102. TiXmlElement* pCustomElement = new TiXmlElement( "xs:element" );
  1103. dSprintf( buffer, sizeof(buffer), "%s.%s", pClassRep->getClassName(), pCustomNodeName );
  1104. pCustomElement->SetAttribute( "name", buffer );
  1105. pCustomElement->SetAttribute( "minOccurs", 0 );
  1106. pCustomElement->SetAttribute( "maxOccurs", 1 );
  1107. pParentElement->LinkEndChild( pCustomElement );
  1108. // Add complex type element.
  1109. TiXmlElement* pComplexTypeElement = new TiXmlElement( "xs:complexType" );
  1110. pCustomElement->LinkEndChild( pComplexTypeElement );
  1111. // Add choice element.
  1112. TiXmlElement* pChoiceElement = new TiXmlElement( "xs:choice" );
  1113. pChoiceElement->SetAttribute( "minOccurs", 0 );
  1114. pChoiceElement->SetAttribute( "maxOccurs", "unbounded" );
  1115. pComplexTypeElement->LinkEndChild( pChoiceElement );
  1116. // Add sequence element.
  1117. TiXmlElement* pSequenceElement = new TiXmlElement( "xs:sequence" );
  1118. pChoiceElement->LinkEndChild( pSequenceElement );
  1119. // Add "any" element.
  1120. TiXmlElement* pAnyElement = new TiXmlElement( "xs:any" );
  1121. pAnyElement->SetAttribute( "processContents", "skip" );
  1122. pSequenceElement->LinkEndChild( pAnyElement );
  1123. }