taml.cpp 57 KB

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