taml.cc 58 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527
  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. U32 nBufferSize = dStrlen( pFieldValue ) + 1;
  527. FrameTemp<char> valueCopy( nBufferSize );
  528. dStrcpy( (char *)valueCopy, pFieldValue );
  529. // Skip if field should not be written.
  530. if (!pSimObject->writeField(fieldName, valueCopy))
  531. continue;
  532. // Reassign field value.
  533. pFieldValue = valueCopy;
  534. // Detect and collapse relative path information
  535. char fnBuf[1024];
  536. if ((S32)pField->type == TypeFilename)
  537. {
  538. Con::collapsePath( fnBuf, 1024, pFieldValue );
  539. pFieldValue = fnBuf;
  540. }
  541. // Save field/value.
  542. TamlWriteNode::FieldValuePair* pFieldValuePair = new TamlWriteNode::FieldValuePair( fieldName, pFieldValue );
  543. pTamlWriteNode->mFields.push_back( pFieldValuePair );
  544. }
  545. }
  546. }
  547. //-----------------------------------------------------------------------------
  548. static S32 QSORT_CALLBACK compareFieldEntries(const void* a,const void* b)
  549. {
  550. // Debug Profiling.
  551. PROFILE_SCOPE(Taml_CompareFieldEntries);
  552. SimFieldDictionary::Entry *fa = *((SimFieldDictionary::Entry **)a);
  553. SimFieldDictionary::Entry *fb = *((SimFieldDictionary::Entry **)b);
  554. return dStricmp(fa->slotName, fb->slotName);
  555. }
  556. //-----------------------------------------------------------------------------
  557. void Taml::compileDynamicFields( TamlWriteNode* pTamlWriteNode )
  558. {
  559. // Debug Profiling.
  560. PROFILE_SCOPE(Taml_CompileDynamicFields);
  561. // Sanity!
  562. AssertFatal( pTamlWriteNode != NULL, "Cannot compile dynamic fields on a NULL node." );
  563. AssertFatal( pTamlWriteNode->mpSimObject != NULL, "Cannot compile dynamic fields on a node with no object." );
  564. // Fetch object.
  565. SimObject* pSimObject = pTamlWriteNode->mpSimObject;
  566. // Fetch field dictionary.
  567. SimFieldDictionary* pFieldDictionary = pSimObject->getFieldDictionary();
  568. // Ignore if not writing dynamic fields.
  569. if ( !pFieldDictionary || !pSimObject->getCanSaveDynamicFields() )
  570. return;
  571. // Fetch field list.
  572. const AbstractClassRep::FieldList& fieldList = pSimObject->getFieldList();
  573. // Fetch field count.
  574. const U32 fieldCount = fieldList.size();
  575. Vector<SimFieldDictionary::Entry*> dynamicFieldList(__FILE__, __LINE__);
  576. // Ensure the dynamic field doesn't conflict with static field.
  577. for( U32 hashIndex = 0; hashIndex < SimFieldDictionary::HashTableSize; ++hashIndex )
  578. {
  579. for( SimFieldDictionary::Entry* pEntry = pFieldDictionary->mHashTable[hashIndex]; pEntry; pEntry = pEntry->next )
  580. {
  581. // Iterate static fields.
  582. U32 fieldIndex;
  583. for( fieldIndex = 0; fieldIndex < fieldCount; ++fieldIndex )
  584. {
  585. if( fieldList[fieldIndex].pFieldname == pEntry->slotName)
  586. break;
  587. }
  588. // Skip if found.
  589. if( fieldIndex != (U32)fieldList.size() )
  590. continue;
  591. // Skip if not writing field.
  592. if ( !pSimObject->writeField( pEntry->slotName, pEntry->value) )
  593. continue;
  594. dynamicFieldList.push_back( pEntry );
  595. }
  596. }
  597. // Sort Entries to prevent version control conflicts
  598. if ( dynamicFieldList.size() > 1 )
  599. dQsort(dynamicFieldList.address(), dynamicFieldList.size(), sizeof(SimFieldDictionary::Entry*), compareFieldEntries);
  600. // Save the fields.
  601. for( Vector<SimFieldDictionary::Entry*>::iterator entryItr = dynamicFieldList.begin(); entryItr != dynamicFieldList.end(); ++entryItr )
  602. {
  603. // Fetch entry.
  604. SimFieldDictionary::Entry* pEntry = *entryItr;
  605. // Save field/value.
  606. TamlWriteNode::FieldValuePair* pFieldValuePair = new TamlWriteNode::FieldValuePair( pEntry->slotName, pEntry->value );
  607. pTamlWriteNode->mFields.push_back( pFieldValuePair );
  608. }
  609. }
  610. //-----------------------------------------------------------------------------
  611. void Taml::compileChildren( TamlWriteNode* pTamlWriteNode )
  612. {
  613. // Debug Profiling.
  614. PROFILE_SCOPE(Taml_CompileChildren);
  615. // Sanity!
  616. AssertFatal( pTamlWriteNode != NULL, "Cannot compile children on a NULL node." );
  617. AssertFatal( pTamlWriteNode->mpSimObject != NULL, "Cannot compile children on a node with no object." );
  618. // Fetch object.
  619. SimObject* pSimObject = pTamlWriteNode->mpSimObject;
  620. // Fetch the Taml children.
  621. TamlChildren* pChildren = dynamic_cast<TamlChildren*>( pSimObject );
  622. // Finish if object does not contain Taml children.
  623. if ( pChildren == NULL || pChildren->getTamlChildCount() == 0 )
  624. return;
  625. // Create children vector.
  626. pTamlWriteNode->mChildren = new typeNodeVector();
  627. // Fetch the child count.
  628. const U32 childCount = pChildren->getTamlChildCount();
  629. // Iterate children.
  630. for ( U32 childIndex = 0; childIndex < childCount; childIndex++ )
  631. {
  632. // Compile object.
  633. TamlWriteNode* pChildTamlWriteNode = compileObject( pChildren->getTamlChild(childIndex) );
  634. // Save node.
  635. pTamlWriteNode->mChildren->push_back( pChildTamlWriteNode );
  636. }
  637. }
  638. //-----------------------------------------------------------------------------
  639. void Taml::compileCustomState( TamlWriteNode* pTamlWriteNode )
  640. {
  641. // Debug Profiling.
  642. PROFILE_SCOPE(Taml_CompileCustomProperties);
  643. // Sanity!
  644. AssertFatal( pTamlWriteNode != NULL, "Cannot compile custom state on a NULL node." );
  645. AssertFatal( pTamlWriteNode->mpSimObject != NULL, "Cannot compile custom state on a node with no object." );
  646. // Fetch the custom node on the write node.
  647. TamlCustomNodes& customNodes = pTamlWriteNode->mCustomNodes;
  648. // Are there any Taml callbacks?
  649. if ( pTamlWriteNode->mpTamlCallbacks != NULL )
  650. {
  651. // Yes, so call it.
  652. tamlCustomWrite( pTamlWriteNode->mpTamlCallbacks, customNodes );
  653. }
  654. // Fetch custom nodes.
  655. const TamlCustomNodeVector& nodes = customNodes.getNodes();
  656. // Finish if no custom nodes to process.
  657. if ( nodes.size() == 0 )
  658. return;
  659. // Iterate custom properties.
  660. for( TamlCustomNodeVector::const_iterator customNodesItr = nodes.begin(); customNodesItr != nodes.end(); ++customNodesItr )
  661. {
  662. // Fetch the custom node.
  663. TamlCustomNode* pCustomNode = *customNodesItr;
  664. // Compile custom node state.
  665. compileCustomNodeState( pCustomNode );
  666. }
  667. }
  668. //-----------------------------------------------------------------------------
  669. void Taml::compileCustomNodeState( TamlCustomNode* pCustomNode )
  670. {
  671. // Sanity!
  672. AssertFatal( pCustomNode != NULL, "Taml: Cannot compile NULL custom node state." );
  673. // Fetch children.
  674. const TamlCustomNodeVector& children = pCustomNode->getChildren();
  675. // Fetch proxy object.
  676. SimObject* pProxyObject = pCustomNode->getProxyObject<SimObject>(false);
  677. // Do we have a proxy object?
  678. if ( pProxyObject != NULL )
  679. {
  680. // Yes, so sanity!
  681. AssertFatal( children.size() == 0, "Taml: Cannot compile a proxy object on a custom node that has children." );
  682. // Yes, so compile it.
  683. // NOTE: We force an Id for custom compiled objects so we guarantee an Id. The reason for this is fairly
  684. // weak in that the XML parser currently has no way of distinguishing between a compiled object node
  685. // 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.
  686. pCustomNode->setWriteNode( compileObject( pProxyObject, true ) );
  687. return;
  688. }
  689. // Finish if no children.
  690. if ( children.size() == 0 )
  691. return;
  692. // Iterate children.
  693. for( TamlCustomNodeVector::const_iterator childItr = children.begin(); childItr != children.end(); ++childItr )
  694. {
  695. // Fetch shape node.
  696. TamlCustomNode* pChildNode = *childItr;
  697. // Compile the child.
  698. compileCustomNodeState( pChildNode );
  699. }
  700. }
  701. //-----------------------------------------------------------------------------
  702. SimObject* Taml::createType( StringTableEntry typeName, const Taml* pTaml, const char* pProgenitorSuffix )
  703. {
  704. // Debug Profiling.
  705. PROFILE_SCOPE(Taml_CreateType);
  706. typedef HashMap<StringTableEntry, AbstractClassRep*> typeClassHash;
  707. static typeClassHash mClassMap;
  708. // Sanity!
  709. AssertFatal( typeName != NULL, "Taml: Type cannot be NULL" );
  710. // Find type.
  711. typeClassHash::iterator typeItr = mClassMap.find( typeName );
  712. // Found type?
  713. if ( typeItr == mClassMap.end() )
  714. {
  715. // No, so find type.
  716. AbstractClassRep* pClassRep = AbstractClassRep::getClassList();
  717. while( pClassRep )
  718. {
  719. // Is this the type?
  720. if( dStricmp( pClassRep->getClassName(), typeName ) == 0 )
  721. {
  722. // Yes, so insert it.
  723. typeItr = mClassMap.insert( typeName, pClassRep );
  724. break;
  725. }
  726. // Next type.
  727. pClassRep = pClassRep->getNextClass();
  728. }
  729. // Did we find the type?
  730. if ( typeItr == mClassMap.end() )
  731. {
  732. // No, so warn and fail.
  733. Con::warnf( "Taml: Failed to create type '%s' as such a registered type could not be found.", typeName );
  734. return NULL;
  735. }
  736. }
  737. // Create the object.
  738. ConsoleObject* pConsoleObject = typeItr->value->create();
  739. // NOTE: It is important that we don't register the object here as many objects rely on the fact that
  740. // fields are set prior to the object being registered. Registering here will invalid those assumptions.
  741. // Fetch the SimObject.
  742. SimObject* pSimObject = dynamic_cast<SimObject*>( pConsoleObject );
  743. // Was it a SimObject?
  744. if ( pSimObject == NULL )
  745. {
  746. // No, so warn.
  747. Con::warnf( "Taml: Failed to create type '%s' as it is not a SimObject.", typeName );
  748. // Destroy object and fail.
  749. delete pConsoleObject;
  750. return NULL;
  751. }
  752. // Are we updating the file-progenitor?
  753. if ( pTaml->getProgenitorUpdate() )
  754. {
  755. // Yes, so do we have a progenitor suffix?
  756. if ( pProgenitorSuffix == NULL )
  757. {
  758. // No, so just set it to the progenitor file.
  759. pSimObject->setProgenitorFile( pTaml->getFilePathBuffer() );
  760. }
  761. else
  762. {
  763. // Yes, so format the progenitor buffer.
  764. char progenitorBuffer[2048];
  765. dSprintf( progenitorBuffer, sizeof(progenitorBuffer), "%s,%s", pTaml->getFilePathBuffer(), pProgenitorSuffix );
  766. // Set the progenitor file.
  767. pSimObject->setProgenitorFile( progenitorBuffer );
  768. }
  769. }
  770. return pSimObject;
  771. }
  772. //-----------------------------------------------------------------------------
  773. bool Taml::generateTamlSchema()
  774. {
  775. // Fetch any TAML Schema file reference.
  776. const char* pTamlSchemaFile = Con::getVariable( TAML_SCHEMA_VARIABLE );
  777. // Do we have a schema file reference?
  778. if ( pTamlSchemaFile == NULL || *pTamlSchemaFile == 0 )
  779. {
  780. // No, so warn.
  781. Con::warnf( "Taml::generateTamlSchema() - Cannot write a TAML schema as no schema variable is set ('%s').", TAML_SCHEMA_VARIABLE );
  782. return false;
  783. }
  784. // Expand the file-name into the file-path buffer.
  785. char filePathBuffer[1024];
  786. Con::expandPath( filePathBuffer, sizeof(filePathBuffer), pTamlSchemaFile );
  787. FileStream stream;
  788. // File opened?
  789. if ( !stream.open( filePathBuffer, FileStream::Write ) )
  790. {
  791. // No, so warn.
  792. Con::warnf("Taml::GenerateTamlSchema() - Could not open filename '%s' for write.", filePathBuffer );
  793. return false;
  794. }
  795. // Create document.
  796. TiXmlDocument schemaDocument;
  797. // Add declaration.
  798. TiXmlDeclaration schemaDeclaration( "1.0", "iso-8859-1", "no" );
  799. schemaDocument.InsertEndChild( schemaDeclaration );
  800. // Add schema element.
  801. TiXmlElement* pSchemaElement = new TiXmlElement( "xs:schema" );
  802. pSchemaElement->SetAttribute( "xmlns:xs", "http://www.w3.org/2001/XMLSchema" );
  803. schemaDocument.LinkEndChild( pSchemaElement );
  804. // Fetch class-rep root.
  805. AbstractClassRep* pRootType = AbstractClassRep::getClassList();
  806. // Fetch SimObject class rep.
  807. AbstractClassRep* pSimObjectType = AbstractClassRep::findClassRep( "SimObject" );
  808. // Sanity!
  809. AssertFatal( pSimObjectType != NULL, "Taml::GenerateTamlSchema() - Could not find SimObject class rep." );
  810. // Reset scratch state.
  811. char buffer[1024];
  812. HashMap<AbstractClassRep*, StringTableEntry> childGroups;
  813. // *************************************************************
  814. // Generate console type elements.
  815. // *************************************************************
  816. // Vector2.
  817. TiXmlComment* pVector2Comment = new TiXmlComment( "Vector2 Console Type" );
  818. pSchemaElement->LinkEndChild( pVector2Comment );
  819. TiXmlElement* pVector2TypeElement = new TiXmlElement( "xs:simpleType" );
  820. pVector2TypeElement->SetAttribute( "name", "Vector2_ConsoleType" );
  821. pSchemaElement->LinkEndChild( pVector2TypeElement );
  822. TiXmlElement* pVector2ElementA = new TiXmlElement( "xs:restriction" );
  823. pVector2ElementA->SetAttribute( "base", "xs:string" );
  824. pVector2TypeElement->LinkEndChild( pVector2ElementA );
  825. TiXmlElement* pVector2ElementB = new TiXmlElement( "xs:pattern" );
  826. pVector2ElementB->SetAttribute( "value", "([-]?(\\b[0-9]+)?\\.)?[0-9]+\\b ([-]?(\\b[0-9]+)?\\.)?[0-9]+\\b" );
  827. pVector2ElementA->LinkEndChild( pVector2ElementB );
  828. // Point2F.
  829. TiXmlComment* pPoint2FComment = new TiXmlComment( "Point2F Console Type" );
  830. pSchemaElement->LinkEndChild( pPoint2FComment );
  831. TiXmlElement* pPoint2FTypeElement = new TiXmlElement( "xs:simpleType" );
  832. pPoint2FTypeElement->SetAttribute( "name", "Point2F_ConsoleType" );
  833. pSchemaElement->LinkEndChild( pPoint2FTypeElement );
  834. TiXmlElement* pPoint2FElementA = new TiXmlElement( "xs:restriction" );
  835. pPoint2FElementA->SetAttribute( "base", "xs:string" );
  836. pPoint2FTypeElement->LinkEndChild( pPoint2FElementA );
  837. TiXmlElement* pPoint2FElementB = new TiXmlElement( "xs:pattern" );
  838. pPoint2FElementB->SetAttribute( "value", "([-]?(\\b[0-9]+)?\\.)?[0-9]+\\b ([-]?(\\b[0-9]+)?\\.)?[0-9]+\\b" );
  839. pPoint2FElementA->LinkEndChild( pPoint2FElementB );
  840. // Point2I.
  841. TiXmlComment* pPoint2IComment = new TiXmlComment( "Point2I Console Type" );
  842. pSchemaElement->LinkEndChild( pPoint2IComment );
  843. TiXmlElement* pPoint2ITypeElement = new TiXmlElement( "xs:simpleType" );
  844. pPoint2ITypeElement->SetAttribute( "name", "Point2I_ConsoleType" );
  845. pSchemaElement->LinkEndChild( pPoint2ITypeElement );
  846. TiXmlElement* pPoint2IElementA = new TiXmlElement( "xs:restriction" );
  847. pPoint2IElementA->SetAttribute( "base", "xs:string" );
  848. pPoint2ITypeElement->LinkEndChild( pPoint2IElementA );
  849. TiXmlElement* pPoint2IElementB = new TiXmlElement( "xs:pattern" );
  850. pPoint2IElementB->SetAttribute( "value", "[-]?[0-9]* [-]?[0-9]*" );
  851. pPoint2IElementA->LinkEndChild( pPoint2IElementB );
  852. // b2AABB.
  853. TiXmlComment* pb2AABBComment = new TiXmlComment( "b2AABB Console Type" );
  854. pSchemaElement->LinkEndChild( pb2AABBComment );
  855. TiXmlElement* pb2AABBTypeElement = new TiXmlElement( "xs:simpleType" );
  856. pb2AABBTypeElement->SetAttribute( "name", "b2AABB_ConsoleType" );
  857. pSchemaElement->LinkEndChild( pb2AABBTypeElement );
  858. TiXmlElement* pb2AABBElementA = new TiXmlElement( "xs:restriction" );
  859. pb2AABBElementA->SetAttribute( "base", "xs:string" );
  860. pb2AABBTypeElement->LinkEndChild( pb2AABBElementA );
  861. TiXmlElement* pb2AABBElementB = new TiXmlElement( "xs:pattern" );
  862. 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" );
  863. pb2AABBElementA->LinkEndChild( pb2AABBElementB );
  864. // RectI.
  865. TiXmlComment* pRectIComment = new TiXmlComment( "RectI Console Type" );
  866. pSchemaElement->LinkEndChild( pRectIComment );
  867. TiXmlElement* pRectITypeElement = new TiXmlElement( "xs:simpleType" );
  868. pRectITypeElement->SetAttribute( "name", "RectI_ConsoleType" );
  869. pSchemaElement->LinkEndChild( pRectITypeElement );
  870. TiXmlElement* pRectIElementA = new TiXmlElement( "xs:restriction" );
  871. pRectIElementA->SetAttribute( "base", "xs:string" );
  872. pRectITypeElement->LinkEndChild( pRectIElementA );
  873. TiXmlElement* pRectIElementB = new TiXmlElement( "xs:pattern" );
  874. pRectIElementB->SetAttribute( "value", "[-]?[0-9]* [-]?[0-9]* [-]?[0-9]* [-]?[0-9]*" );
  875. pRectIElementA->LinkEndChild( pRectIElementB );
  876. // RectF.
  877. TiXmlComment* pRectFComment = new TiXmlComment( "RectF Console Type" );
  878. pSchemaElement->LinkEndChild( pRectFComment );
  879. TiXmlElement* pRectFTypeElement = new TiXmlElement( "xs:simpleType" );
  880. pRectFTypeElement->SetAttribute( "name", "RectF_ConsoleType" );
  881. pSchemaElement->LinkEndChild( pRectFTypeElement );
  882. TiXmlElement* pRectFElementA = new TiXmlElement( "xs:restriction" );
  883. pRectFElementA->SetAttribute( "base", "xs:string" );
  884. pRectFTypeElement->LinkEndChild( pRectFElementA );
  885. TiXmlElement* pRectFElementB = new TiXmlElement( "xs:pattern" );
  886. pRectFElementB->SetAttribute( "value", "(\\b[-]?(b[0-9]+)?\\.)?[0-9]+\\b" );
  887. pRectFElementA->LinkEndChild( pRectFElementB );
  888. // AssetId.
  889. TiXmlComment* pAssetIdComment = new TiXmlComment( "AssetId Console Type" );
  890. pSchemaElement->LinkEndChild( pAssetIdComment );
  891. TiXmlElement* pAssetIdTypeElement = new TiXmlElement( "xs:simpleType" );
  892. pAssetIdTypeElement->SetAttribute( "name", "AssetId_ConsoleType" );
  893. pSchemaElement->LinkEndChild( pAssetIdTypeElement );
  894. TiXmlElement* pAssetIdElementA = new TiXmlElement( "xs:restriction" );
  895. pAssetIdElementA->SetAttribute( "base", "xs:string" );
  896. pAssetIdTypeElement->LinkEndChild( pAssetIdElementA );
  897. TiXmlElement* pAssetIdElementB = new TiXmlElement( "xs:pattern" );
  898. 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 );
  899. pAssetIdElementB->SetAttribute( "value", buffer );
  900. pAssetIdElementA->LinkEndChild( pAssetIdElementB );
  901. // Color Enums.
  902. TiXmlComment* pColorEnumsComment = new TiXmlComment( "Color Enums" );
  903. pSchemaElement->LinkEndChild( pColorEnumsComment );
  904. TiXmlElement* pColorEnumsTypeElement = new TiXmlElement( "xs:simpleType" );
  905. pColorEnumsTypeElement->SetAttribute( "name", "Color_Enums" );
  906. pSchemaElement->LinkEndChild( pColorEnumsTypeElement );
  907. TiXmlElement* pColorEnumsRestrictionElement = new TiXmlElement( "xs:restriction" );
  908. pColorEnumsRestrictionElement->SetAttribute( "base", "xs:string" );
  909. pColorEnumsTypeElement->LinkEndChild( pColorEnumsRestrictionElement );
  910. const S32 ColorEnumsCount = StockColor::getCount();
  911. for( S32 index = 0; index < ColorEnumsCount; ++index )
  912. {
  913. // Add enumeration element.
  914. TiXmlElement* pColorEnumsAttributeEnumerationElement = new TiXmlElement( "xs:enumeration" );
  915. pColorEnumsAttributeEnumerationElement->SetAttribute( "value", StockColor::getColorItem(index)->getColorName() );
  916. pColorEnumsRestrictionElement->LinkEndChild( pColorEnumsAttributeEnumerationElement );
  917. }
  918. // ColorF.
  919. TiXmlComment* pColorFValuesComment = new TiXmlComment( "ColorF Values" );
  920. pSchemaElement->LinkEndChild( pColorFValuesComment );
  921. TiXmlElement* pColorFValuesTypeElement = new TiXmlElement( "xs:simpleType" );
  922. pColorFValuesTypeElement->SetAttribute( "name", "ColorF_Values" );
  923. pSchemaElement->LinkEndChild( pColorFValuesTypeElement );
  924. TiXmlElement* pColorFValuesElementA = new TiXmlElement( "xs:restriction" );
  925. pColorFValuesElementA->SetAttribute( "base", "xs:string" );
  926. pColorFValuesTypeElement->LinkEndChild( pColorFValuesElementA );
  927. TiXmlElement* pColorFValuesElementB = new TiXmlElement( "xs:pattern" );
  928. 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" );
  929. pColorFValuesElementA->LinkEndChild( pColorFValuesElementB );
  930. TiXmlComment* pColorFComment = new TiXmlComment( "ColorF Console Type" );
  931. pSchemaElement->LinkEndChild( pColorFComment );
  932. TiXmlElement* pColorFTypeElement = new TiXmlElement( "xs:simpleType" );
  933. pColorFTypeElement->SetAttribute( "name", "ColorF_ConsoleType" );
  934. pSchemaElement->LinkEndChild( pColorFTypeElement );
  935. TiXmlElement* pColorFUnionElement = new TiXmlElement( "xs:union" );
  936. pColorFUnionElement->SetAttribute( "memberTypes", "ColorF_Values Color_Enums" );
  937. pColorFTypeElement->LinkEndChild( pColorFUnionElement );
  938. // ColorI.
  939. TiXmlComment* pColorIValuesComment = new TiXmlComment( "ColorI Values" );
  940. pSchemaElement->LinkEndChild( pColorIValuesComment );
  941. TiXmlElement* pColorIValuesTypeElement = new TiXmlElement( "xs:simpleType" );
  942. pColorIValuesTypeElement->SetAttribute( "name", "ColorI_Values" );
  943. pSchemaElement->LinkEndChild( pColorIValuesTypeElement );
  944. TiXmlElement* pColorIValuesElementA = new TiXmlElement( "xs:restriction" );
  945. pColorIValuesElementA->SetAttribute( "base", "xs:string" );
  946. pColorIValuesTypeElement->LinkEndChild( pColorIValuesElementA );
  947. TiXmlElement* pColorIValuesElementB = new TiXmlElement( "xs:pattern" );
  948. pColorIValuesElementB->SetAttribute( "value", "[-]?[0-9]* [-]?[0-9]* [-]?[0-9]* [-]?[0-9]*" );
  949. pColorIValuesElementA->LinkEndChild( pColorIValuesElementB );
  950. TiXmlComment* pColorIComment = new TiXmlComment( "ColorI Console Type" );
  951. pSchemaElement->LinkEndChild( pColorIComment );
  952. TiXmlElement* pColorITypeElement = new TiXmlElement( "xs:simpleType" );
  953. pColorITypeElement->SetAttribute( "name", "ColorI_ConsoleType" );
  954. pSchemaElement->LinkEndChild( pColorITypeElement );
  955. TiXmlElement* pColorIUnionElement = new TiXmlElement( "xs:union" );
  956. pColorIUnionElement->SetAttribute( "memberTypes", "ColorI_Values Color_Enums" );
  957. pColorITypeElement->LinkEndChild( pColorIUnionElement );
  958. // *************************************************************
  959. // Generate engine type elements.
  960. // *************************************************************
  961. // Generate the engine type elements.
  962. TiXmlComment* pComment = new TiXmlComment( "Type Elements" );
  963. pSchemaElement->LinkEndChild( pComment );
  964. for ( AbstractClassRep* pType = pRootType; pType != NULL; pType = pType->getNextClass() )
  965. {
  966. // Add type.
  967. TiXmlElement* pTypeElement = new TiXmlElement( "xs:element" );
  968. pTypeElement->SetAttribute( "name", pType->getClassName() );
  969. dSprintf( buffer, sizeof(buffer), "%s_Type", pType->getClassName() );
  970. pTypeElement->SetAttribute( "type", buffer );
  971. pSchemaElement->LinkEndChild( pTypeElement );
  972. }
  973. // *************************************************************
  974. // Generate the engine complex types.
  975. // *************************************************************
  976. for ( AbstractClassRep* pType = pRootType; pType != NULL; pType = pType->getNextClass() )
  977. {
  978. // Add complex type comment.
  979. dSprintf( buffer, sizeof(buffer), " %s Type ", pType->getClassName() );
  980. TiXmlComment* pComment = new TiXmlComment( buffer );
  981. pSchemaElement->LinkEndChild( pComment );
  982. // Add complex type.
  983. TiXmlElement* pComplexTypeElement = new TiXmlElement( "xs:complexType" );
  984. dSprintf( buffer, sizeof(buffer), "%s_Type", pType->getClassName() );
  985. pComplexTypeElement->SetAttribute( "name", buffer );
  986. pSchemaElement->LinkEndChild( pComplexTypeElement );
  987. // Add sequence.
  988. TiXmlElement* pSequenceElement = new TiXmlElement( "xs:sequence" );
  989. pComplexTypeElement->LinkEndChild( pSequenceElement );
  990. // Fetch container child class.
  991. AbstractClassRep* pContainerChildClass = pType->getContainerChildClass( true );
  992. // Is the type allowed children?
  993. if ( pContainerChildClass != NULL )
  994. {
  995. // Yes, so add choice element.
  996. TiXmlElement* pChoiceElement = new TiXmlElement( "xs:choice" );
  997. pChoiceElement->SetAttribute( "minOccurs", 0 );
  998. pChoiceElement->SetAttribute( "maxOccurs", "unbounded" );
  999. pSequenceElement->LinkEndChild( pChoiceElement );
  1000. // Find child group.
  1001. HashMap<AbstractClassRep*, StringTableEntry>::iterator childGroupItr = childGroups.find( pContainerChildClass );
  1002. // Does the group exist?
  1003. if ( childGroupItr == childGroups.end() )
  1004. {
  1005. // No, so format group name.
  1006. dSprintf( buffer, sizeof(buffer), "%s_ChildrenTypes", pContainerChildClass->getClassName() );
  1007. // Insert into child group hash.
  1008. childGroupItr = childGroups.insert( pContainerChildClass, StringTable->insert( buffer ) );
  1009. // Add the group.
  1010. TiXmlElement* pChildrenGroupElement = new TiXmlElement( "xs:group" );
  1011. pChildrenGroupElement->SetAttribute( "name", buffer );
  1012. pSchemaElement->LinkEndChild( pChildrenGroupElement );
  1013. // Add choice element.
  1014. TiXmlElement* pChildreGroupChoiceElement = new TiXmlElement( "xs:choice" );
  1015. pChildrenGroupElement->LinkEndChild( pChildreGroupChoiceElement );
  1016. // Add choice members.
  1017. for ( AbstractClassRep* pChoiceType = pRootType; pChoiceType != NULL; pChoiceType = pChoiceType->getNextClass() )
  1018. {
  1019. // Skip if not derived from the container child class.
  1020. if ( !pChoiceType->isClass( pContainerChildClass ) )
  1021. continue;
  1022. // Add choice member.
  1023. TiXmlElement* pChildrenMemberElement = new TiXmlElement( "xs:element" );
  1024. pChildrenMemberElement->SetAttribute( "name", pChoiceType->getClassName() );
  1025. dSprintf( buffer, sizeof(buffer), "%s_Type", pChoiceType->getClassName() );
  1026. pChildrenMemberElement->SetAttribute( "type", buffer );
  1027. pChildreGroupChoiceElement->LinkEndChild( pChildrenMemberElement );
  1028. }
  1029. }
  1030. // Reference the child group.
  1031. TiXmlElement* pChoiceGroupReferenceElement = new TiXmlElement( "xs:group" );
  1032. pChoiceGroupReferenceElement->SetAttribute( "ref", childGroupItr->value );
  1033. pChoiceGroupReferenceElement->SetAttribute( "minOccurs", 0 );
  1034. pChoiceElement->LinkEndChild( pChoiceGroupReferenceElement );
  1035. }
  1036. // Generate the custom Taml schema.
  1037. for ( AbstractClassRep* pCustomSchemaType = pType; pCustomSchemaType != NULL; pCustomSchemaType = pCustomSchemaType->getParentClass() )
  1038. {
  1039. // Fetch the types custom TAML schema function.
  1040. AbstractClassRep::WriteCustomTamlSchema customSchemaFn = pCustomSchemaType->getCustomTamlSchema();
  1041. // Skip if no function avilable.
  1042. if ( customSchemaFn == NULL )
  1043. continue;
  1044. // Call schema generation function.
  1045. customSchemaFn( pType, pSequenceElement );
  1046. }
  1047. // Generate field attribute group.
  1048. TiXmlElement* pFieldAttributeGroupElement = new TiXmlElement( "xs:attributeGroup" );
  1049. dSprintf( buffer, sizeof(buffer), "%s_Fields", pType->getClassName() );
  1050. pFieldAttributeGroupElement->SetAttribute( "name", buffer );
  1051. pSchemaElement->LinkEndChild( pFieldAttributeGroupElement );
  1052. // Fetch field list.
  1053. const AbstractClassRep::FieldList& fields = pType->mFieldList;
  1054. // Fetcj field count.
  1055. const S32 fieldCount = fields.size();
  1056. // Iterate static fields (in reverse as most types are organized from the root-fields up).
  1057. for( S32 index = fieldCount-1; index > 0; --index )
  1058. {
  1059. // Fetch field.
  1060. const AbstractClassRep::Field& field = fields[index];
  1061. // Skip if not a data field.
  1062. if( field.type == AbstractClassRep::DepricatedFieldType ||
  1063. field.type == AbstractClassRep::StartGroupFieldType ||
  1064. field.type == AbstractClassRep::EndGroupFieldType )
  1065. continue;
  1066. // Skip if the field root is not this type.
  1067. if ( pType->findFieldRoot( field.pFieldname ) != pType )
  1068. continue;
  1069. // Add attribute element.
  1070. TiXmlElement* pAttributeElement = new TiXmlElement( "xs:attribute" );
  1071. pAttributeElement->SetAttribute( "name", field.pFieldname );
  1072. // Handle the console type appropriately.
  1073. const S32 fieldType = (S32)field.type;
  1074. // Is the field an enumeration?
  1075. if ( fieldType == TypeEnum )
  1076. {
  1077. // Yes, so add attribute type.
  1078. TiXmlElement* pAttributeSimpleTypeElement = new TiXmlElement( "xs:simpleType" );
  1079. pAttributeElement->LinkEndChild( pAttributeSimpleTypeElement );
  1080. // Add restriction element.
  1081. TiXmlElement* pAttributeRestrictionElement = new TiXmlElement( "xs:restriction" );
  1082. pAttributeRestrictionElement->SetAttribute( "base", "xs:string" );
  1083. pAttributeSimpleTypeElement->LinkEndChild( pAttributeRestrictionElement );
  1084. // Yes, so fetch enumeration count.
  1085. const S32 enumCount = field.table->size;
  1086. // Iterate enumeration.
  1087. for( S32 index = 0; index < enumCount; ++index )
  1088. {
  1089. // Add enumeration element.
  1090. TiXmlElement* pAttributeEnumerationElement = new TiXmlElement( "xs:enumeration" );
  1091. pAttributeEnumerationElement->SetAttribute( "value", field.table->table[index].label );
  1092. pAttributeRestrictionElement->LinkEndChild( pAttributeEnumerationElement );
  1093. }
  1094. }
  1095. else
  1096. {
  1097. // No, so assume it's a string type initially.
  1098. const char* pFieldTypeDescription = "xs:string";
  1099. // Handle known types.
  1100. if( fieldType == TypeF32 )
  1101. {
  1102. pFieldTypeDescription = "xs:float";
  1103. }
  1104. else if( fieldType == TypeS8 || fieldType == TypeS32 )
  1105. {
  1106. pFieldTypeDescription = "xs:int";
  1107. }
  1108. else if( fieldType == TypeBool || fieldType == TypeFlag )
  1109. {
  1110. pFieldTypeDescription = "xs:boolean";
  1111. }
  1112. else if( fieldType == TypeVector2 )
  1113. {
  1114. pFieldTypeDescription = "Vector2_ConsoleType";
  1115. }
  1116. else if( fieldType == TypePoint2F )
  1117. {
  1118. pFieldTypeDescription = "Point2F_ConsoleType";
  1119. }
  1120. else if( fieldType == TypePoint2I )
  1121. {
  1122. pFieldTypeDescription = "Point2I_ConsoleType";
  1123. }
  1124. else if( fieldType == Typeb2AABB )
  1125. {
  1126. pFieldTypeDescription = "b2AABB_ConsoleType";
  1127. }
  1128. else if( fieldType == TypeRectI )
  1129. {
  1130. pFieldTypeDescription = "RectI_ConsoleType";
  1131. }
  1132. else if( fieldType == TypeRectF )
  1133. {
  1134. pFieldTypeDescription = "RectF_ConsoleType";
  1135. }
  1136. else if( fieldType == TypeColorF )
  1137. {
  1138. pFieldTypeDescription = "ColorF_ConsoleType";
  1139. }
  1140. else if( fieldType == TypeColorI )
  1141. {
  1142. pFieldTypeDescription = "ColorI_ConsoleType";
  1143. }
  1144. else if( fieldType == TypeAssetId ||
  1145. fieldType == TypeImageAssetPtr ||
  1146. fieldType == TypeAnimationAssetPtr ||
  1147. fieldType == TypeAudioAssetPtr )
  1148. {
  1149. pFieldTypeDescription = "AssetId_ConsoleType";
  1150. }
  1151. // Set attribute type.
  1152. pAttributeElement->SetAttribute( "type", pFieldTypeDescription );
  1153. }
  1154. pAttributeElement->SetAttribute( "use", "optional" );
  1155. pFieldAttributeGroupElement->LinkEndChild( pAttributeElement );
  1156. }
  1157. // Is this the SimObject Type?
  1158. if ( pType == pSimObjectType )
  1159. {
  1160. // Yes, so add reserved Taml field attributes here...
  1161. // Add Taml "Name" attribute element.
  1162. TiXmlElement* pNameAttributeElement = new TiXmlElement( "xs:attribute" );
  1163. pNameAttributeElement->SetAttribute( "name", tamlNamedObjectName );
  1164. pNameAttributeElement->SetAttribute( "type", "xs:normalizedString" );
  1165. pFieldAttributeGroupElement->LinkEndChild( pNameAttributeElement );
  1166. // Add Taml "TamlId" attribute element.
  1167. TiXmlElement* pTamlIdAttributeElement = new TiXmlElement( "xs:attribute" );
  1168. pTamlIdAttributeElement->SetAttribute( "name", tamlRefIdName );
  1169. pTamlIdAttributeElement->SetAttribute( "type", "xs:nonNegativeInteger" );
  1170. pFieldAttributeGroupElement->LinkEndChild( pTamlIdAttributeElement );
  1171. // Add Taml "TamlRefId" attribute element.
  1172. TiXmlElement* pTamlRefIdAttributeElement = new TiXmlElement( "xs:attribute" );
  1173. pTamlRefIdAttributeElement->SetAttribute( "name", tamlRefToIdName );
  1174. pTamlRefIdAttributeElement->SetAttribute( "type", "xs:nonNegativeInteger" );
  1175. pFieldAttributeGroupElement->LinkEndChild( pTamlRefIdAttributeElement );
  1176. }
  1177. // Add attribute group types.
  1178. for ( AbstractClassRep* pAttributeGroupsType = pType; pAttributeGroupsType != NULL; pAttributeGroupsType = pAttributeGroupsType->getParentClass() )
  1179. {
  1180. TiXmlElement* pFieldAttributeGroupRefElement = new TiXmlElement( "xs:attributeGroup" );
  1181. dSprintf( buffer, sizeof(buffer), "%s_Fields", pAttributeGroupsType->getClassName() );
  1182. pFieldAttributeGroupRefElement->SetAttribute( "ref", buffer );
  1183. pComplexTypeElement->LinkEndChild( pFieldAttributeGroupRefElement );
  1184. }
  1185. // Add "any" attribute element (dynamic fields).
  1186. TiXmlElement* pAnyAttributeElement = new TiXmlElement( "xs:anyAttribute" );
  1187. pAnyAttributeElement->SetAttribute( "processContents", "skip" );
  1188. pComplexTypeElement->LinkEndChild( pAnyAttributeElement );
  1189. }
  1190. // Write the schema document.
  1191. schemaDocument.SaveFile( stream );
  1192. // Close file.
  1193. stream.close();
  1194. return true;
  1195. }
  1196. //-----------------------------------------------------------------------------
  1197. void Taml::WriteUnrestrictedCustomTamlSchema( const char* pCustomNodeName, const AbstractClassRep* pClassRep, TiXmlElement* pParentElement )
  1198. {
  1199. // Sanity!
  1200. AssertFatal( pCustomNodeName != NULL, "Taml::WriteDefaultCustomTamlSchema() - Node name cannot be NULL." );
  1201. AssertFatal( pClassRep != NULL, "Taml::WriteDefaultCustomTamlSchema() - ClassRep cannot be NULL." );
  1202. AssertFatal( pParentElement != NULL, "Taml::WriteDefaultCustomTamlSchema() - Parent Element cannot be NULL." );
  1203. char buffer[1024];
  1204. // Add custom type element.
  1205. TiXmlElement* pCustomElement = new TiXmlElement( "xs:element" );
  1206. dSprintf( buffer, sizeof(buffer), "%s.%s", pClassRep->getClassName(), pCustomNodeName );
  1207. pCustomElement->SetAttribute( "name", buffer );
  1208. pCustomElement->SetAttribute( "minOccurs", 0 );
  1209. pCustomElement->SetAttribute( "maxOccurs", 1 );
  1210. pParentElement->LinkEndChild( pCustomElement );
  1211. // Add complex type element.
  1212. TiXmlElement* pComplexTypeElement = new TiXmlElement( "xs:complexType" );
  1213. pCustomElement->LinkEndChild( pComplexTypeElement );
  1214. // Add choice element.
  1215. TiXmlElement* pChoiceElement = new TiXmlElement( "xs:choice" );
  1216. pChoiceElement->SetAttribute( "minOccurs", 0 );
  1217. pChoiceElement->SetAttribute( "maxOccurs", "unbounded" );
  1218. pComplexTypeElement->LinkEndChild( pChoiceElement );
  1219. // Add sequence element.
  1220. TiXmlElement* pSequenceElement = new TiXmlElement( "xs:sequence" );
  1221. pChoiceElement->LinkEndChild( pSequenceElement );
  1222. // Add "any" element.
  1223. TiXmlElement* pAnyElement = new TiXmlElement( "xs:any" );
  1224. pAnyElement->SetAttribute( "processContents", "skip" );
  1225. pSequenceElement->LinkEndChild( pAnyElement );
  1226. }