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