taml.cc 58 KB

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