taml.cpp 57 KB

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