taml.cc 58 KB

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