taml.cc 52 KB

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