From 7d497383da662b82f9ba5341427d2c166e9beb14 Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Fri, 10 Oct 2025 10:28:46 +0100 Subject: [PATCH] adds json back to taml Allow taml to be compiled and read as json All of this was already there just was hidden from cmake and code was commented out so just a commit to reapply this. The rest is just some cleanup --- Engine/source/CMakeLists.txt | 3 +- Engine/source/persistence/taml/taml.cpp | 2899 ++++++++--------- .../persistence/taml/taml_ScriptBinding.h | 61 +- 3 files changed, 1479 insertions(+), 1484 deletions(-) diff --git a/Engine/source/CMakeLists.txt b/Engine/source/CMakeLists.txt index 9b840b649..3aec54791 100644 --- a/Engine/source/CMakeLists.txt +++ b/Engine/source/CMakeLists.txt @@ -115,7 +115,8 @@ torqueAddSourceDirectories("scene" "scene/culling" "scene/zones" "scene/mixin") torqueAddSourceDirectories("math" "math/util") # Handle persistence -torqueAddSourceDirectories("persistence/taml" "persistence/taml/binary" "persistence/taml/xml") +set(TORQUE_INCLUDE_DIRECTORIES ${TORQUE_INCLUDE_DIRECTORIES} "persistence/rapidjson") +torqueAddSourceDirectories("persistence/taml" "persistence/taml/binary" "persistence/taml/xml" "persistence/taml/json") # Handle Cinterface torqueAddSourceDirectories("cinterface") diff --git a/Engine/source/persistence/taml/taml.cpp b/Engine/source/persistence/taml/taml.cpp index 0d636b172..5f1c44977 100644 --- a/Engine/source/persistence/taml/taml.cpp +++ b/Engine/source/persistence/taml/taml.cpp @@ -42,17 +42,17 @@ #include "persistence/taml/binary/tamlBinaryReader.h" #endif -/*#ifndef _TAML_JSONWRITER_H_ -#include "taml/json/tamlJSONWriter.h" +#ifndef _TAML_JSONWRITER_H_ +#include "persistence/taml/json/tamlJSONWriter.h" #endif #ifndef _TAML_JSONREADER_H_ -#include "taml/json/tamlJSONReader.h" +#include "persistence/taml/json/tamlJSONReader.h" #endif #ifndef _TAML_JSONPARSER_H_ -#include "taml/json/tamlJSONParser.h" -#endif*/ +#include "persistence/taml/json/tamlJSONParser.h" +#endif #ifndef _FRAMEALLOCATOR_H_ #include "core/frameAllocator.h" @@ -94,1587 +94,1582 @@ StringTableEntry tamlNamedObjectName = StringTable->insert("Name"); typedef Taml::TamlFormatMode _TamlFormatMode; ImplementEnumType(_TamlFormatMode, - "") +"") + { Taml::XmlFormat, "xml" }, + { Taml::BinaryFormat, "binary" }, + { Taml::JSONFormat, "json" } +EndImplementEnumType; + +//----------------------------------------------------------------------------- + +Taml::TamlFormatMode Taml::getFormatModeEnum(const char* label) { - Taml::XmlFormat, "xml" -}, -{ Taml::BinaryFormat, "binary" }//, - //{ Taml::JSONFormat, "json" } - EndImplementEnumType; - - //----------------------------------------------------------------------------- - - Taml::TamlFormatMode Taml::getFormatModeEnum(const char* label) + // Search for Mnemonic. + for (U32 i = 0; i < (sizeof(__TamlFormatMode::_sEnums) / sizeof(EnumTable::Value)); i++) { - // Search for Mnemonic. - for (U32 i = 0; i < (sizeof(__TamlFormatMode::_sEnums) / sizeof(EnumTable::Value)); i++) - { - if (dStricmp(__TamlFormatMode::_sEnumTable[i].getName(), label) == 0) - return (TamlFormatMode)__TamlFormatMode::_sEnumTable[i].getInt(); - } - - // Warn. - Con::warnf("Taml::getFormatModeEnum() - Invalid format of '%s'.", label); - - return Taml::InvalidFormat; + if (dStricmp(__TamlFormatMode::_sEnumTable[i].getName(), label) == 0) + return (TamlFormatMode)__TamlFormatMode::_sEnumTable[i].getInt(); } - //----------------------------------------------------------------------------- + // Warn. + Con::warnf("Taml::getFormatModeEnum() - Invalid format of '%s'.", label); - const char* Taml::getFormatModeDescription(const Taml::TamlFormatMode formatMode) + return Taml::InvalidFormat; +} + +//----------------------------------------------------------------------------- + +const char* Taml::getFormatModeDescription(const Taml::TamlFormatMode formatMode) +{ + // Search for Mnemonic. + for (U32 i = 0; i < (sizeof(__TamlFormatMode::_sEnums) / sizeof(EnumTable::Value)); i++) { - // Search for Mnemonic. - for (U32 i = 0; i < (sizeof(__TamlFormatMode::_sEnums) / sizeof(EnumTable::Value)); i++) - { - if (__TamlFormatMode::_sEnumTable[i].getInt() == (S32)formatMode) - return __TamlFormatMode::_sEnumTable[i].getName(); - } - - // Warn. - Con::warnf("Taml::getFormatModeDescription() - Invalid format mode."); - - return StringTable->EmptyString(); + if (__TamlFormatMode::_sEnumTable[i].getInt() == (S32)formatMode) + return __TamlFormatMode::_sEnumTable[i].getName(); } - //----------------------------------------------------------------------------- + // Warn. + Con::warnf("Taml::getFormatModeDescription() - Invalid format mode."); - // 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. - Taml::Taml() : - mMasterNodeId(0), - mFormatMode(XmlFormat), - mJSONStrict(true), - mBinaryCompression(true), - mWriteDefaults(false), - mAutoFormatXmlExtension("taml"), - mAutoFormat(true), - mProgenitorUpdate(true), - mAutoFormatBinaryExtension("baml"), - mAutoFormatJSONExtension("json") - { - // Reset the file-path buffer. - mFilePathBuffer[0] = 0; - } + return StringTable->EmptyString(); +} - //----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- - void Taml::initPersistFields() - { - docsURL; - // Call parent. - Parent::initPersistFields(); +// 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. +Taml::Taml() : + mMasterNodeId(0), + mFormatMode(XmlFormat), + mJSONStrict(true), + mBinaryCompression(true), + mWriteDefaults(false), + mAutoFormatXmlExtension("taml"), + mAutoFormat(true), + mProgenitorUpdate(true), + mAutoFormatBinaryExtension("baml"), + mAutoFormatJSONExtension("json") +{ + // Reset the file-path buffer. + mFilePathBuffer[0] = 0; +} - addField("Format", TYPEID<_TamlFormatMode>(), Offset(mFormatMode, Taml), "The read/write format that should be used."); - addField("JSONStrict", TypeBool, Offset(mBinaryCompression, Taml), "Whether to write JSON that is strictly compatible with RFC4627 or not.\n"); - addField("BinaryCompression", TypeBool, Offset(mBinaryCompression, Taml), "Whether ZIP compression is used on binary formatting or not.\n"); - addField("WriteDefaults", TypeBool, Offset(mWriteDefaults, Taml), "Whether to write static fields that are at their default or not.\n"); - addField("ProgenitorUpdate", TypeBool, Offset(mProgenitorUpdate, Taml), "Whether to update each type instances file-progenitor or not.\n"); - addField("AutoFormat", TypeBool, Offset(mAutoFormat, Taml), "Whether the format type is automatically determined by the filename extension or not.\n"); - addField("AutoFormatXmlExtension", TypeString, Offset(mAutoFormatXmlExtension, Taml), "When using auto-format, this is the extension (end of filename) used to detect the XML format.\n"); - addField("AutoFormatBinaryExtension", TypeString, Offset(mAutoFormatBinaryExtension, Taml), "When using auto-format, this is the extension (end of filename) used to detect the BINARY format.\n"); - addField("AutoFormatJSONExtension", TypeString, Offset(mAutoFormatJSONExtension, Taml), "When using auto-format, this is the extension (end of filename) used to detect the JSON format.\n"); - } +//----------------------------------------------------------------------------- - //----------------------------------------------------------------------------- +void Taml::initPersistFields() +{ + docsURL; + // Call parent. + Parent::initPersistFields(); - bool Taml::onAdd() - { - // Call parent. - if (!Parent::onAdd()) - return false; + addField("Format", TYPEID<_TamlFormatMode>(), Offset(mFormatMode, Taml), "The read/write format that should be used."); + addField("JSONStrict", TypeBool, Offset(mBinaryCompression, Taml), "Whether to write JSON that is strictly compatible with RFC4627 or not.\n"); + addField("BinaryCompression", TypeBool, Offset(mBinaryCompression, Taml), "Whether ZIP compression is used on binary formatting or not.\n"); + addField("WriteDefaults", TypeBool, Offset(mWriteDefaults, Taml), "Whether to write static fields that are at their default or not.\n"); + addField("ProgenitorUpdate", TypeBool, Offset(mProgenitorUpdate, Taml), "Whether to update each type instances file-progenitor or not.\n"); + addField("AutoFormat", TypeBool, Offset(mAutoFormat, Taml), "Whether the format type is automatically determined by the filename extension or not.\n"); + addField("AutoFormatXmlExtension", TypeString, Offset(mAutoFormatXmlExtension, Taml), "When using auto-format, this is the extension (end of filename) used to detect the XML format.\n"); + addField("AutoFormatBinaryExtension", TypeString, Offset(mAutoFormatBinaryExtension, Taml), "When using auto-format, this is the extension (end of filename) used to detect the BINARY format.\n"); + addField("AutoFormatJSONExtension", TypeString, Offset(mAutoFormatJSONExtension, Taml), "When using auto-format, this is the extension (end of filename) used to detect the JSON format.\n"); +} - // Set JSON strict mode. - mJSONStrict = Con::getBoolVariable(TAML_JSON_STRICT_VARIBLE, true); +//----------------------------------------------------------------------------- - // Reset the compilation. - resetCompilation(); +bool Taml::onAdd() +{ + // Call parent. + if (!Parent::onAdd()) + return false; - return true; - } + // Set JSON strict mode. + mJSONStrict = Con::getBoolVariable(TAML_JSON_STRICT_VARIBLE, true); - //----------------------------------------------------------------------------- + // Reset the compilation. + resetCompilation(); - void Taml::onRemove() - { - // Reset the compilation. - resetCompilation(); + return true; +} - // Call parent. - Parent::onRemove(); - } +//----------------------------------------------------------------------------- - //----------------------------------------------------------------------------- +void Taml::onRemove() +{ + // Reset the compilation. + resetCompilation(); - bool Taml::write(SimObject* pSimObject, const char* pFilename) - { - // Debug Profiling. - PROFILE_SCOPE(Taml_Write); + // Call parent. + Parent::onRemove(); +} - // Sanity! - AssertFatal(pSimObject != NULL, "Cannot write a NULL object."); - AssertFatal(pFilename != NULL, "Cannot write to a NULL filename."); +//----------------------------------------------------------------------------- - // Expand the file-name into the file-path buffer unless we're a secure VFS +bool Taml::write(SimObject* pSimObject, const char* pFilename) +{ + // Debug Profiling. + PROFILE_SCOPE(Taml_Write); + + // Sanity! + AssertFatal(pSimObject != NULL, "Cannot write a NULL object."); + AssertFatal(pFilename != NULL, "Cannot write to a NULL filename."); + + // Expand the file-name into the file-path buffer unless we're a secure VFS #ifndef TORQUE_SECURE_VFS - Con::expandToolScriptFilename(mFilePathBuffer, sizeof(mFilePathBuffer), pFilename); + Con::expandToolScriptFilename(mFilePathBuffer, sizeof(mFilePathBuffer), pFilename); #else - dMemset(mFilePathBuffer, 0x00, sizeof(mFilePathBuffer)); - dMemcpy(mFilePathBuffer, pFilename, dStrlen(pFilename)); + dMemset(mFilePathBuffer, 0x00, sizeof(mFilePathBuffer)); + dMemcpy(mFilePathBuffer, pFilename, dStrlen(pFilename)); #endif - FileStream stream; + FileStream stream; - // File opened? - if (!stream.open(mFilePathBuffer, Torque::FS::File::Write)) - { - // No, so warn. - Con::warnf("Taml::writeFile() - Could not open filename '%s' for write.", mFilePathBuffer); - return false; - } - - // Get the file auto-format mode. - const TamlFormatMode formatMode = getFileAutoFormatMode(mFilePathBuffer); - - // Reset the compilation. - resetCompilation(); - - // Write object. - const bool status = write(stream, pSimObject, formatMode); - - // Close file. - stream.close(); - - // Reset the compilation. - resetCompilation(); - - return status; - } - - //----------------------------------------------------------------------------- - - SimObject* Taml::read(const char* pFilename) + // File opened? + if (!stream.open(mFilePathBuffer, Torque::FS::File::Write)) { - // Debug Profiling. - PROFILE_SCOPE(Taml_Read); - - // Sanity! - AssertFatal(pFilename != NULL, "Cannot read from a NULL filename."); - - // Expand the file-name into the file-path buffer. - Con::expandScriptFilename(mFilePathBuffer, sizeof(mFilePathBuffer), pFilename); - - FileStream stream; - - // File opened? - if (!stream.open(mFilePathBuffer, Torque::FS::File::Read)) - { - // No, so warn. - Con::warnf("Taml::read() - Could not open filename '%s' for read.", mFilePathBuffer); - return NULL; - } - - // Get the file auto-format mode. - const TamlFormatMode formatMode = getFileAutoFormatMode(mFilePathBuffer); - - // Reset the compilation. - resetCompilation(); - - // Write object. - SimObject* pSimObject = read(stream, formatMode); - - // Close file. - stream.close(); - - // Reset the compilation. - resetCompilation(); - - // Did we generate an object? - if (pSimObject == NULL) - { - // No, so warn. - Con::warnf("Taml::read() - Failed to load an object from the file '%s'.", mFilePathBuffer); - } - else - { - pSimObject->onPostAdd(); - } - - return pSimObject; - } - - //----------------------------------------------------------------------------- - - bool Taml::write(FileStream& stream, SimObject* pSimObject, const TamlFormatMode formatMode) - { - // Sanity! - AssertFatal(pSimObject != NULL, "Cannot write a NULL object."); - - // Compile nodes. - TamlWriteNode* pRootNode = compileObject(pSimObject); - - // Format appropriately. - switch (formatMode) - { - /// Xml. - case XmlFormat: - { - // Create writer. - TamlXmlWriter writer(this); - // Write. - return writer.write(stream, pRootNode); - } - - /// Binary. - case BinaryFormat: - { - // Create writer. - TamlBinaryWriter writer(this); - - // Write. - return writer.write(stream, pRootNode, mBinaryCompression); - } - - /// JSON. - case JSONFormat: - { - // Create writer. - //TamlJSONWriter writer( this ); - - // Write. - //return writer.write( stream, pRootNode ); - return false; - } - - /// Invalid. - case InvalidFormat: - { - // Warn. - Con::warnf("Taml::write() - Cannot write, invalid format."); - return false; - } - } - - // Warn. - Con::warnf("Taml::write() - Unknown format."); + // No, so warn. + Con::warnf("Taml::writeFile() - Could not open filename '%s' for write.", mFilePathBuffer); return false; } - //----------------------------------------------------------------------------- + // Get the file auto-format mode. + const TamlFormatMode formatMode = getFileAutoFormatMode(mFilePathBuffer); - SimObject* Taml::read(FileStream& stream, const TamlFormatMode formatMode) + // Reset the compilation. + resetCompilation(); + + // Write object. + const bool status = write(stream, pSimObject, formatMode); + + // Close file. + stream.close(); + + // Reset the compilation. + resetCompilation(); + + return status; +} + +//----------------------------------------------------------------------------- + +SimObject* Taml::read(const char* pFilename) +{ + // Debug Profiling. + PROFILE_SCOPE(Taml_Read); + + // Sanity! + AssertFatal(pFilename != NULL, "Cannot read from a NULL filename."); + + // Expand the file-name into the file-path buffer. + Con::expandScriptFilename(mFilePathBuffer, sizeof(mFilePathBuffer), pFilename); + + FileStream stream; + + // File opened? + if (!stream.open(mFilePathBuffer, Torque::FS::File::Read)) { - // Format appropriately. - switch (formatMode) - { - /// Xml. - case XmlFormat: - { - // Create reader. - TamlXmlReader reader(this); - - // Read. - return reader.read(stream); - } - - /// Binary. - case BinaryFormat: - { - // Create reader. - TamlBinaryReader reader(this); - - // Read. - return reader.read(stream); - } - - /// JSON. - case JSONFormat: - { - // Create reader. - //TamlJSONReader reader( this ); - - // Read. - //return reader.read( stream ); - return NULL; - } - - /// Invalid. - case InvalidFormat: - { - // Warn. - Con::warnf("Taml::read() - Cannot read, invalid format."); - return NULL; - } - } - - // Warn. - Con::warnf("Taml::read() - Unknown format."); + // No, so warn. + Con::warnf("Taml::read() - Could not open filename '%s' for read.", mFilePathBuffer); return NULL; } - //----------------------------------------------------------------------------- + // Get the file auto-format mode. + const TamlFormatMode formatMode = getFileAutoFormatMode(mFilePathBuffer); - bool Taml::parse(const char* pFilename, TamlVisitor& visitor) + // Reset the compilation. + resetCompilation(); + + // Write object. + SimObject* pSimObject = read(stream, formatMode); + + // Close file. + stream.close(); + + // Reset the compilation. + resetCompilation(); + + // Did we generate an object? + if (pSimObject == NULL) { - // Debug Profiling. - PROFILE_SCOPE(Taml_Parse); + // No, so warn. + Con::warnf("Taml::read() - Failed to load an object from the file '%s'.", mFilePathBuffer); + } + else + { + pSimObject->onPostAdd(); + } - // Sanity! - AssertFatal(pFilename != NULL, "Taml::parse() - Cannot parse a NULL filename."); + return pSimObject; +} - // Fetch format mode. - const TamlFormatMode formatMode = getFileAutoFormatMode(pFilename); +//----------------------------------------------------------------------------- - // Handle format mode appropriately. - switch (formatMode) - { - case XmlFormat: - { - // Parse with the visitor. - TamlXmlParser parser; +bool Taml::write(FileStream& stream, SimObject* pSimObject, const TamlFormatMode formatMode) +{ + // Sanity! + AssertFatal(pSimObject != NULL, "Cannot write a NULL object."); - // Are property changes needed but not supported? - if (visitor.wantsPropertyChanges() && !parser.canChangeProperty()) - { - // Yes, so warn. - 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); - return false; - } + // Compile nodes. + TamlWriteNode* pRootNode = compileObject(pSimObject); - return parser.accept(pFilename, visitor); - } + // Format appropriately. + switch (formatMode) + { + /// Xml. + case XmlFormat: + { + // Create writer. + TamlXmlWriter writer(this); + // Write. + return writer.write(stream, pRootNode); + } - case JSONFormat: - { - // Parse with the visitor. - /*TamlJSONParser parser; + /// Binary. + case BinaryFormat: + { + // Create writer. + TamlBinaryWriter writer(this); - // Are property changes needed but not supported? - if ( visitor.wantsPropertyChanges() && !parser.canChangeProperty() ) - { - // Yes, so warn. - 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 ); - return false; - } + // Write. + return writer.write(stream, pRootNode, mBinaryCompression); + } - return parser.accept( pFilename, visitor ); */ - return false; - } + /// JSON. + case JSONFormat: + { + // Create writer. + TamlJSONWriter writer( this ); - case BinaryFormat: - default: - break; - } + // Write. + return writer.write( stream, pRootNode ); + } + /// Invalid. + case InvalidFormat: + { // Warn. - Con::warnf("Taml::parse() - Cannot parse '%s' file-type for filename '%s' as a required parser is not available.", getFormatModeDescription(formatMode), pFilename); + Con::warnf("Taml::write() - Cannot write, invalid format."); return false; } - - //----------------------------------------------------------------------------- - - void Taml::resetCompilation(void) - { - // Debug Profiling. - PROFILE_SCOPE(Taml_ResetCompilation); - - // Clear compiled nodes. - for (typeNodeVector::iterator itr = mCompiledNodes.begin(); itr != mCompiledNodes.end(); ++itr) - { - // Fetch node. - TamlWriteNode* pNode = (*itr); - - // Reset node. - pNode->resetNode(); - - // Delete node. - delete pNode; - } - mCompiledNodes.clear(); - - // Clear compiled objects. - mCompiledObjects.clear(); - - // Reset master node Id. - mMasterNodeId = 0; } - //----------------------------------------------------------------------------- + // Warn. + Con::warnf("Taml::write() - Unknown format."); + return false; +} - Taml::TamlFormatMode Taml::getFileAutoFormatMode(const char* pFilename) +//----------------------------------------------------------------------------- + +SimObject* Taml::read(FileStream& stream, const TamlFormatMode formatMode) +{ + // Format appropriately. + switch (formatMode) { - // Sanity! - AssertFatal(pFilename != NULL, "Taml::getFileAutoFormatMode() - Cannot auto-format using a NULL filename."); + /// Xml. + case XmlFormat: + { + // Create reader. + TamlXmlReader reader(this); - // Is auto-format active? - if (mAutoFormat) - { - // Yes, so fetch the extension lengths. - const U32 xmlExtensionLength = dStrlen(mAutoFormatXmlExtension); - const U32 binaryExtensionLength = dStrlen(mAutoFormatBinaryExtension); - const U32 jsonExtensionLength = dStrlen(mAutoFormatJSONExtension); - - // Fetch filename length. - const U32 filenameLength = dStrlen(pFilename); - - // Fetch end of filename, - const char* pEndOfFilename = pFilename + filenameLength; - - // Check for the XML format. - if (xmlExtensionLength <= filenameLength && dStricmp(pEndOfFilename - xmlExtensionLength, mAutoFormatXmlExtension) == 0) - return Taml::XmlFormat; - - // Check for the Binary format. - if (binaryExtensionLength <= filenameLength && dStricmp(pEndOfFilename - xmlExtensionLength, mAutoFormatBinaryExtension) == 0) - return Taml::BinaryFormat; - - // Check for the XML format. - if (jsonExtensionLength <= filenameLength && dStricmp(pEndOfFilename - jsonExtensionLength, mAutoFormatJSONExtension) == 0) - return Taml::JSONFormat; - } - - // Use the explicitly specified format mode. - return mFormatMode; + // Read. + return reader.read(stream); } - //----------------------------------------------------------------------------- - - TamlWriteNode* Taml::compileObject(SimObject* pSimObject, const bool forceId) + /// Binary. + case BinaryFormat: { - // Debug Profiling. - PROFILE_SCOPE(Taml_CompileObject); + // Create reader. + TamlBinaryReader reader(this); - // Sanity! - AssertFatal(pSimObject != NULL, "Taml::compileObject() - Cannot compile a NULL object."); + // Read. + return reader.read(stream); + } - // Fetch object Id. - const SimObjectId objectId = pSimObject->getId(); + /// JSON. + case JSONFormat: + { + // Create reader. + TamlJSONReader reader( this ); - // Find a previously compiled node. - typeCompiledHash::Iterator compiledItr = mCompiledObjects.find(objectId); + // Read. + return reader.read( stream ); + } - // Have we already compiled this? - if (compiledItr != mCompiledObjects.end()) + /// Invalid. + case InvalidFormat: + { + // Warn. + Con::warnf("Taml::read() - Cannot read, invalid format."); + return NULL; + } + } + + // Warn. + Con::warnf("Taml::read() - Unknown format."); + return NULL; +} + +//----------------------------------------------------------------------------- + +bool Taml::parse(const char* pFilename, TamlVisitor& visitor) +{ + // Debug Profiling. + PROFILE_SCOPE(Taml_Parse); + + // Sanity! + AssertFatal(pFilename != NULL, "Taml::parse() - Cannot parse a NULL filename."); + + // Fetch format mode. + const TamlFormatMode formatMode = getFileAutoFormatMode(pFilename); + + // Handle format mode appropriately. + switch (formatMode) + { + case XmlFormat: + { + // Parse with the visitor. + TamlXmlParser parser; + + // Are property changes needed but not supported? + if (visitor.wantsPropertyChanges() && !parser.canChangeProperty()) { - // Yes, so sanity! - AssertFatal(mCompiledNodes.size() != 0, "Taml::compileObject() - Found a compiled node at the root."); - - // Yes, so fetch node. - TamlWriteNode* compiledNode = compiledItr->value; - - // Is a reference Id already present? - if (compiledNode->mRefId == 0) - { - // No, so allocate one. - compiledNode->mRefId = ++mMasterNodeId; - } - - // Create write node. - TamlWriteNode* pNewNode = new TamlWriteNode(); - pNewNode->set(pSimObject); - - // Set reference node. - pNewNode->mRefToNode = compiledNode; - - // Push new node. - mCompiledNodes.push_back(pNewNode); - - return pNewNode; + // Yes, so warn. + 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); + return false; } - // No, so create write node. + return parser.accept(pFilename, visitor); + } + + case JSONFormat: + { + // Parse with the visitor. + TamlJSONParser parser; + + // Are property changes needed but not supported? + if ( visitor.wantsPropertyChanges() && !parser.canChangeProperty() ) + { + // Yes, so warn. + 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 ); + return false; + } + + return parser.accept( pFilename, visitor ); + } + + case BinaryFormat: + default: + break; + } + + // Warn. + Con::warnf("Taml::parse() - Cannot parse '%s' file-type for filename '%s' as a required parser is not available.", getFormatModeDescription(formatMode), pFilename); + return false; +} + +//----------------------------------------------------------------------------- + +void Taml::resetCompilation(void) +{ + // Debug Profiling. + PROFILE_SCOPE(Taml_ResetCompilation); + + // Clear compiled nodes. + for (typeNodeVector::iterator itr = mCompiledNodes.begin(); itr != mCompiledNodes.end(); ++itr) + { + // Fetch node. + TamlWriteNode* pNode = (*itr); + + // Reset node. + pNode->resetNode(); + + // Delete node. + delete pNode; + } + mCompiledNodes.clear(); + + // Clear compiled objects. + mCompiledObjects.clear(); + + // Reset master node Id. + mMasterNodeId = 0; +} + +//----------------------------------------------------------------------------- + +Taml::TamlFormatMode Taml::getFileAutoFormatMode(const char* pFilename) +{ + // Sanity! + AssertFatal(pFilename != NULL, "Taml::getFileAutoFormatMode() - Cannot auto-format using a NULL filename."); + + // Is auto-format active? + if (mAutoFormat) + { + // Yes, so fetch the extension lengths. + const U32 xmlExtensionLength = dStrlen(mAutoFormatXmlExtension); + const U32 binaryExtensionLength = dStrlen(mAutoFormatBinaryExtension); + const U32 jsonExtensionLength = dStrlen(mAutoFormatJSONExtension); + + // Fetch filename length. + const U32 filenameLength = dStrlen(pFilename); + + // Fetch end of filename, + const char* pEndOfFilename = pFilename + filenameLength; + + // Check for the XML format. + if (xmlExtensionLength <= filenameLength && dStricmp(pEndOfFilename - xmlExtensionLength, mAutoFormatXmlExtension) == 0) + return Taml::XmlFormat; + + // Check for the Binary format. + if (binaryExtensionLength <= filenameLength && dStricmp(pEndOfFilename - xmlExtensionLength, mAutoFormatBinaryExtension) == 0) + return Taml::BinaryFormat; + + // Check for the XML format. + if (jsonExtensionLength <= filenameLength && dStricmp(pEndOfFilename - jsonExtensionLength, mAutoFormatJSONExtension) == 0) + return Taml::JSONFormat; + } + + // Use the explicitly specified format mode. + return mFormatMode; +} + +//----------------------------------------------------------------------------- + +TamlWriteNode* Taml::compileObject(SimObject* pSimObject, const bool forceId) +{ + // Debug Profiling. + PROFILE_SCOPE(Taml_CompileObject); + + // Sanity! + AssertFatal(pSimObject != NULL, "Taml::compileObject() - Cannot compile a NULL object."); + + // Fetch object Id. + const SimObjectId objectId = pSimObject->getId(); + + // Find a previously compiled node. + typeCompiledHash::Iterator compiledItr = mCompiledObjects.find(objectId); + + // Have we already compiled this? + if (compiledItr != mCompiledObjects.end()) + { + // Yes, so sanity! + AssertFatal(mCompiledNodes.size() != 0, "Taml::compileObject() - Found a compiled node at the root."); + + // Yes, so fetch node. + TamlWriteNode* compiledNode = compiledItr->value; + + // Is a reference Id already present? + if (compiledNode->mRefId == 0) + { + // No, so allocate one. + compiledNode->mRefId = ++mMasterNodeId; + } + + // Create write node. TamlWriteNode* pNewNode = new TamlWriteNode(); pNewNode->set(pSimObject); - // Is an Id being forced for this object? - if (forceId) - { - // Yes, so allocate one. - pNewNode->mRefId = ++mMasterNodeId; - } + // Set reference node. + pNewNode->mRefToNode = compiledNode; // Push new node. mCompiledNodes.push_back(pNewNode); - // Insert compiled object. - mCompiledObjects.insertUnique(objectId, pNewNode); - - // Are there any Taml callbacks? - if (pNewNode->mpTamlCallbacks != NULL) - { - // Yes, so call it. - tamlPreWrite(pNewNode->mpTamlCallbacks); - } - - // Compile static and dynamic fields. - compileStaticFields(pNewNode); - compileDynamicFields(pNewNode); - - // Compile children. - compileChildren(pNewNode); - - // Compile custom state. - compileCustomState(pNewNode); - - // Are there any Taml callbacks? - if (pNewNode->mpTamlCallbacks != NULL) - { - // Yes, so call it. - tamlPostWrite(pNewNode->mpTamlCallbacks); - } - return pNewNode; } - //----------------------------------------------------------------------------- + // No, so create write node. + TamlWriteNode* pNewNode = new TamlWriteNode(); + pNewNode->set(pSimObject); - void Taml::compileStaticFields(TamlWriteNode* pTamlWriteNode) + // Is an Id being forced for this object? + if (forceId) { - // Debug Profiling. - PROFILE_SCOPE(Taml_CompileStaticFields); + // Yes, so allocate one. + pNewNode->mRefId = ++mMasterNodeId; + } - // Sanity! - AssertFatal(pTamlWriteNode != NULL, "Cannot compile static fields on a NULL node."); - AssertFatal(pTamlWriteNode->mpSimObject != NULL, "Cannot compile static fields on a node with no object."); + // Push new node. + mCompiledNodes.push_back(pNewNode); - // Fetch object. - SimObject* pSimObject = pTamlWriteNode->mpSimObject; + // Insert compiled object. + mCompiledObjects.insertUnique(objectId, pNewNode); - // Fetch field list. - const AbstractClassRep::FieldList& fieldList = pSimObject->getFieldList(); + // Are there any Taml callbacks? + if (pNewNode->mpTamlCallbacks != NULL) + { + // Yes, so call it. + tamlPreWrite(pNewNode->mpTamlCallbacks); + } - // Fetch field count. - const U32 fieldCount = fieldList.size(); + // Compile static and dynamic fields. + compileStaticFields(pNewNode); + compileDynamicFields(pNewNode); - ConsoleObject* defaultConObject = NULL; - SimObject* defaultObject = NULL; - if (!getWriteDefaults()) - { - // Create a default object of the same type - defaultConObject = ConsoleObject::create(pSimObject->getClassName()); - if (!defaultConObject) - return; - defaultObject = dynamic_cast(defaultConObject); + // Compile children. + compileChildren(pNewNode); + + // Compile custom state. + compileCustomState(pNewNode); + + // Are there any Taml callbacks? + if (pNewNode->mpTamlCallbacks != NULL) + { + // Yes, so call it. + tamlPostWrite(pNewNode->mpTamlCallbacks); + } + + return pNewNode; +} + +//----------------------------------------------------------------------------- + +void Taml::compileStaticFields(TamlWriteNode* pTamlWriteNode) +{ + // Debug Profiling. + PROFILE_SCOPE(Taml_CompileStaticFields); + + // Sanity! + AssertFatal(pTamlWriteNode != NULL, "Cannot compile static fields on a NULL node."); + AssertFatal(pTamlWriteNode->mpSimObject != NULL, "Cannot compile static fields on a node with no object."); + + // Fetch object. + SimObject* pSimObject = pTamlWriteNode->mpSimObject; + + // Fetch field list. + const AbstractClassRep::FieldList& fieldList = pSimObject->getFieldList(); + + // Fetch field count. + const U32 fieldCount = fieldList.size(); + + ConsoleObject* defaultConObject = NULL; + SimObject* defaultObject = NULL; + if (!getWriteDefaults()) + { + // Create a default object of the same type + defaultConObject = ConsoleObject::create(pSimObject->getClassName()); + if (!defaultConObject) + return; + defaultObject = dynamic_cast(defaultConObject); - } - // ***Really*** shouldn't happen - if (!defaultConObject || !defaultObject) - return; - - // Iterate fields. - U8 arrayDepth = 0; - TamlCustomNode* currentArrayNode = NULL; - for (U32 index = 0; index < fieldCount; ++index) - { - // Fetch field. - const AbstractClassRep::Field* pField = &fieldList[index]; - - // Ignore if field not appropriate. - if (pField->type == AbstractClassRep::DeprecatedFieldType || - pField->type == AbstractClassRep::StartGroupFieldType || - pField->type == AbstractClassRep::EndGroupFieldType) - continue; - - if (pField->type == AbstractClassRep::StartArrayFieldType) - { - TamlCustomNodes& pCustomNodes = pTamlWriteNode->mCustomNodes; - currentArrayNode = pCustomNodes.addNode(pField->pGroupname); - for (U16 idx = 0; idx < pField->elementCount; idx++) - currentArrayNode->addNode(pField->pFieldname); - arrayDepth++; - continue; - } - - if (pField->type == AbstractClassRep::EndArrayFieldType) - { - arrayDepth--; - continue; - } - - if (arrayDepth == 0 && pField->elementCount > 1) - { - TamlCustomNodes& pCustomNodes = pTamlWriteNode->mCustomNodes; - char* niceFieldName = const_cast(pField->pFieldname); - niceFieldName[0] = dToupper(niceFieldName[0]); - String str_niceFieldName = String(niceFieldName); - currentArrayNode = pCustomNodes.addNode(str_niceFieldName + "s"); - for (U16 idx = 0; idx < pField->elementCount; idx++) - currentArrayNode->addNode(str_niceFieldName); - } - - // Fetch fieldname. - StringTableEntry fieldName = StringTable->insert(pField->pFieldname); - - // Fetch element count. - const U32 elementCount = pField->elementCount; - - // Skip if the field should not be written. - // For now, we only deal with non-array fields. - if (elementCount == 1 && - pField->setDataFn != NULL && - (!getWriteDefaults() && pField->writeDataFn(pSimObject, fieldName) == false)) - continue; - - // Iterate elements. - for (U32 elementIndex = 0; elementIndex < elementCount; ++elementIndex) - { - char indexBuffer[8]; - dSprintf(indexBuffer, 8, "%d", elementIndex); - - // Fetch object field value. - const char* pFieldValue = pSimObject->getPrefixedDataField(fieldName, indexBuffer); - - if (!pFieldValue) - pFieldValue = StringTable->EmptyString(); - - U32 nBufferSize = dStrlen(pFieldValue) + 1; - FrameTemp valueCopy(nBufferSize); - dStrcpy((char *)valueCopy, pFieldValue, nBufferSize); - - // Skip if field should not be written. - if (!pSimObject->writeField(fieldName, valueCopy)) - continue; - - if (!getWriteDefaults()) - { - //If the field hasn't been changed from the default value, then don't bother writing it out - const char* fieldData = defaultObject->getDataField(fieldName, indexBuffer); - if (fieldData && fieldData[0] != '\0' && dStricmp(fieldData, pFieldValue) == 0) - continue; - } - - // Reassign field value. - pFieldValue = valueCopy; - - if (pField->type == TypeBool) - pFieldValue = dAtob(pFieldValue) ? "true" : "false"; - - // Detect and collapse relative path information - char fnBuf[1024]; - if ((S32)pField->type == TypeFilename) - { - Con::collapseScriptFilename(fnBuf, 1024, pFieldValue); - pFieldValue = fnBuf; - } - - // Save field/value. - if (currentArrayNode && (arrayDepth > 0 || pField->elementCount > 1)) - currentArrayNode->getChildren()[elementIndex]->addField(fieldName, pFieldValue); - else - { - TamlWriteNode::FieldValuePair* pFieldValuePair = new TamlWriteNode::FieldValuePair(fieldName, pFieldValue); - pTamlWriteNode->mFields.push_back(pFieldValuePair); - } - } - } - - if (!getWriteDefaults()) - { - // Cleanup our created default object - delete defaultConObject; - } } + // ***Really*** shouldn't happen + if (!defaultConObject || !defaultObject) + return; - //----------------------------------------------------------------------------- - - static S32 QSORT_CALLBACK compareFieldEntries(const void* a, const void* b) + // Iterate fields. + U8 arrayDepth = 0; + TamlCustomNode* currentArrayNode = NULL; + for (U32 index = 0; index < fieldCount; ++index) { - // Debug Profiling. - PROFILE_SCOPE(Taml_CompareFieldEntries); + // Fetch field. + const AbstractClassRep::Field* pField = &fieldList[index]; - SimFieldDictionary::Entry *fa = *((SimFieldDictionary::Entry **)a); - SimFieldDictionary::Entry *fb = *((SimFieldDictionary::Entry **)b); - return dStricmp(fa->slotName, fb->slotName); - } + // Ignore if field not appropriate. + if (pField->type == AbstractClassRep::DeprecatedFieldType || + pField->type == AbstractClassRep::StartGroupFieldType || + pField->type == AbstractClassRep::EndGroupFieldType) + continue; - //----------------------------------------------------------------------------- - - void Taml::compileDynamicFields(TamlWriteNode* pTamlWriteNode) - { - // Debug Profiling. - PROFILE_SCOPE(Taml_CompileDynamicFields); - - // Sanity! - AssertFatal(pTamlWriteNode != NULL, "Cannot compile dynamic fields on a NULL node."); - AssertFatal(pTamlWriteNode->mpSimObject != NULL, "Cannot compile dynamic fields on a node with no object."); - - // Fetch object. - SimObject* pSimObject = pTamlWriteNode->mpSimObject; - - // Fetch field dictionary. - SimFieldDictionary* pFieldDictionary = pSimObject->getFieldDictionary(); - - // Ignore if not writing dynamic fields. - if (!pFieldDictionary || !pSimObject->getCanSaveDynamicFields()) - return; - - // Fetch field list. - const AbstractClassRep::FieldList& fieldList = pSimObject->getFieldList(); - - // Fetch field count. - const U32 fieldCount = fieldList.size(); - - Vector dynamicFieldList(__FILE__, __LINE__); - - // Ensure the dynamic field doesn't conflict with static field. - for (U32 hashIndex = 0; hashIndex < SimFieldDictionary::HashTableSize; ++hashIndex) + if (pField->type == AbstractClassRep::StartArrayFieldType) { - for (SimFieldDictionary::Entry* pEntry = pFieldDictionary->mHashTable[hashIndex]; pEntry; pEntry = pEntry->next) - { - // Iterate static fields. - U32 fieldIndex; - for (fieldIndex = 0; fieldIndex < fieldCount; ++fieldIndex) - { - if (fieldList[fieldIndex].pFieldname == pEntry->slotName) - break; - } - - // Skip if found. - if (fieldIndex != (U32)fieldList.size()) - continue; - - // Skip if not writing field. - if (!pSimObject->writeField(pEntry->slotName, pEntry->value)) - continue; - - dynamicFieldList.push_back(pEntry); - } + TamlCustomNodes& pCustomNodes = pTamlWriteNode->mCustomNodes; + currentArrayNode = pCustomNodes.addNode(pField->pGroupname); + for (U16 idx = 0; idx < pField->elementCount; idx++) + currentArrayNode->addNode(pField->pFieldname); + arrayDepth++; + continue; } - // Sort Entries to prevent version control conflicts - if (dynamicFieldList.size() > 1) - dQsort(dynamicFieldList.address(), dynamicFieldList.size(), sizeof(SimFieldDictionary::Entry*), compareFieldEntries); - - // Save the fields. - for (Vector::iterator entryItr = dynamicFieldList.begin(); entryItr != dynamicFieldList.end(); ++entryItr) + if (pField->type == AbstractClassRep::EndArrayFieldType) { - // Fetch entry. - SimFieldDictionary::Entry* pEntry = *entryItr; + arrayDepth--; + continue; + } + + if (arrayDepth == 0 && pField->elementCount > 1) + { + TamlCustomNodes& pCustomNodes = pTamlWriteNode->mCustomNodes; + char* niceFieldName = const_cast(pField->pFieldname); + niceFieldName[0] = dToupper(niceFieldName[0]); + String str_niceFieldName = String(niceFieldName); + currentArrayNode = pCustomNodes.addNode(str_niceFieldName + "s"); + for (U16 idx = 0; idx < pField->elementCount; idx++) + currentArrayNode->addNode(str_niceFieldName); + } + + // Fetch fieldname. + StringTableEntry fieldName = StringTable->insert(pField->pFieldname); + + // Fetch element count. + const U32 elementCount = pField->elementCount; + + // Skip if the field should not be written. + // For now, we only deal with non-array fields. + if (elementCount == 1 && + pField->setDataFn != NULL && + (!getWriteDefaults() && pField->writeDataFn(pSimObject, fieldName) == false)) + continue; + + // Iterate elements. + for (U32 elementIndex = 0; elementIndex < elementCount; ++elementIndex) + { + char indexBuffer[8]; + dSprintf(indexBuffer, 8, "%d", elementIndex); + + // Fetch object field value. + const char* pFieldValue = pSimObject->getPrefixedDataField(fieldName, indexBuffer); + + if (!pFieldValue) + pFieldValue = StringTable->EmptyString(); + + U32 nBufferSize = dStrlen(pFieldValue) + 1; + FrameTemp valueCopy(nBufferSize); + dStrcpy((char *)valueCopy, pFieldValue, nBufferSize); + + // Skip if field should not be written. + if (!pSimObject->writeField(fieldName, valueCopy)) + continue; + + if (!getWriteDefaults()) + { + //If the field hasn't been changed from the default value, then don't bother writing it out + const char* fieldData = defaultObject->getDataField(fieldName, indexBuffer); + if (fieldData && fieldData[0] != '\0' && dStricmp(fieldData, pFieldValue) == 0) + continue; + } + + // Reassign field value. + pFieldValue = valueCopy; + + if (pField->type == TypeBool) + pFieldValue = dAtob(pFieldValue) ? "true" : "false"; + + // Detect and collapse relative path information + char fnBuf[1024]; + if ((S32)pField->type == TypeFilename) + { + Con::collapseScriptFilename(fnBuf, 1024, pFieldValue); + pFieldValue = fnBuf; + } // Save field/value. - TamlWriteNode::FieldValuePair* pFieldValuePair = new TamlWriteNode::FieldValuePair(pEntry->slotName, pEntry->value); - pTamlWriteNode->mFields.push_back(pFieldValuePair); - } - } - - //----------------------------------------------------------------------------- - - void Taml::compileChildren(TamlWriteNode* pTamlWriteNode) - { - // Debug Profiling. - PROFILE_SCOPE(Taml_CompileChildren); - - // Sanity! - AssertFatal(pTamlWriteNode != NULL, "Cannot compile children on a NULL node."); - AssertFatal(pTamlWriteNode->mpSimObject != NULL, "Cannot compile children on a node with no object."); - - // Fetch object. - SimObject* pSimObject = pTamlWriteNode->mpSimObject; - - // Fetch the Taml children. - TamlChildren* pChildren = dynamic_cast(pSimObject); - - // Finish if object does not contain Taml children. - if (pChildren == NULL || pChildren->getTamlChildCount() == 0) - return; - - // Create children vector. - pTamlWriteNode->mChildren = new typeNodeVector(); - - // Fetch the child count. - const U32 childCount = pChildren->getTamlChildCount(); - - // Iterate children. - for (U32 childIndex = 0; childIndex < childCount; childIndex++) - { - // Compile object. - TamlWriteNode* pChildTamlWriteNode = compileObject(pChildren->getTamlChild(childIndex)); - - // Save node. - pTamlWriteNode->mChildren->push_back(pChildTamlWriteNode); - } - } - - //----------------------------------------------------------------------------- - - void Taml::compileCustomState(TamlWriteNode* pTamlWriteNode) - { - // Debug Profiling. - PROFILE_SCOPE(Taml_CompileCustomProperties); - - // Sanity! - AssertFatal(pTamlWriteNode != NULL, "Cannot compile custom state on a NULL node."); - AssertFatal(pTamlWriteNode->mpSimObject != NULL, "Cannot compile custom state on a node with no object."); - - // Fetch the custom node on the write node. - TamlCustomNodes& customNodes = pTamlWriteNode->mCustomNodes; - - // Are there any Taml callbacks? - if (pTamlWriteNode->mpTamlCallbacks != NULL) - { - // Yes, so call it. - tamlCustomWrite(pTamlWriteNode->mpTamlCallbacks, customNodes); - } - - // Fetch custom nodes. - const TamlCustomNodeVector& nodes = customNodes.getNodes(); - - // Finish if no custom nodes to process. - if (nodes.size() == 0) - return; - - // Iterate custom properties. - for (TamlCustomNodeVector::const_iterator customNodesItr = nodes.begin(); customNodesItr != nodes.end(); ++customNodesItr) - { - // Fetch the custom node. - TamlCustomNode* pCustomNode = *customNodesItr; - - // Compile custom node state. - compileCustomNodeState(pCustomNode); - } - } - - //----------------------------------------------------------------------------- - - void Taml::compileCustomNodeState(TamlCustomNode* pCustomNode) - { - // Sanity! - AssertFatal(pCustomNode != NULL, "Taml: Cannot compile NULL custom node state."); - - // Fetch children. - const TamlCustomNodeVector& children = pCustomNode->getChildren(); - - // Fetch proxy object. - SimObject* pProxyObject = pCustomNode->getProxyObject(false); - - // Do we have a proxy object? - if (pProxyObject != NULL) - { - // Yes, so sanity! - AssertFatal(children.size() == 0, "Taml: Cannot compile a proxy object on a custom node that has children."); - - // Yes, so compile it. - // NOTE: We force an Id for custom compiled objects so we guarantee an Id. The reason for this is fairly - // weak in that the XML parser currently has no way of distinguishing between a compiled object node - // 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. - pCustomNode->setWriteNode(compileObject(pProxyObject, true)); - return; - } - - // Finish if no children. - if (children.size() == 0) - return; - - // Iterate children. - for (TamlCustomNodeVector::const_iterator childItr = children.begin(); childItr != children.end(); ++childItr) - { - // Fetch shape node. - TamlCustomNode* pChildNode = *childItr; - - // Compile the child. - compileCustomNodeState(pChildNode); - } - } - - //----------------------------------------------------------------------------- - - SimObject* Taml::createType(StringTableEntry typeName, const Taml* pTaml, const char* pProgenitorSuffix) - { - // Debug Profiling. - PROFILE_SCOPE(Taml_CreateType); - - typedef HashTable typeClassHash; - static typeClassHash mClassMap; - - // Sanity! - AssertFatal(typeName != NULL, "Taml: Type cannot be NULL"); - - // Find type. - typeClassHash::Iterator typeItr = mClassMap.find(typeName); - - // Found type? - if (typeItr == mClassMap.end()) - { - // No, so find type. - AbstractClassRep* pClassRep = AbstractClassRep::getClassList(); - while (pClassRep) - { - // Is this the type? - if (dStricmp(pClassRep->getClassName(), typeName) == 0) - { - // Yes, so insert it. - typeItr = mClassMap.insertUnique(typeName, pClassRep); - break; - } - - // Next type. - pClassRep = pClassRep->getNextClass(); - } - - // Did we find the type? - if (typeItr == mClassMap.end()) - { - // No, so warn and fail. - Con::warnf("Taml: Failed to create type '%s' as such a registered type could not be found.", typeName); - return NULL; - } - } - - // Create the object. - ConsoleObject* pConsoleObject = typeItr->value->create(); - - // NOTE: It is important that we don't register the object here as many objects rely on the fact that - // fields are set prior to the object being registered. Registering here will invalid those assumptions. - - // Fetch the SimObject. - SimObject* pSimObject = dynamic_cast(pConsoleObject); - - // Was it a SimObject? - if (pSimObject == NULL) - { - // No, so warn. - Con::warnf("Taml: Failed to create type '%s' as it is not a SimObject.", typeName); - - // Destroy object and fail. - delete pConsoleObject; - return NULL; - } - - // Are we updating the file-progenitor? - if (pTaml->getProgenitorUpdate()) - { - // Yes, so do we have a progenitor suffix? - if (pProgenitorSuffix == NULL) - { - // No, so just set it to the progenitor file. - pSimObject->setProgenitorFile(pTaml->getFilePathBuffer()); - } + if (currentArrayNode && (arrayDepth > 0 || pField->elementCount > 1)) + currentArrayNode->getChildren()[elementIndex]->addField(fieldName, pFieldValue); else { - // Yes, so format the progenitor buffer. - char progenitorBuffer[2048]; - dSprintf(progenitorBuffer, sizeof(progenitorBuffer), "%s,%s", pTaml->getFilePathBuffer(), pProgenitorSuffix); - - // Set the progenitor file. - pSimObject->setProgenitorFile(progenitorBuffer); + TamlWriteNode::FieldValuePair* pFieldValuePair = new TamlWriteNode::FieldValuePair(fieldName, pFieldValue); + pTamlWriteNode->mFields.push_back(pFieldValuePair); } } - - return pSimObject; } - //----------------------------------------------------------------------------- - - tinyxml2::XMLElement* g__write_schema_attribute_element(const AbstractClassRep::Field& field, AbstractClassRep* pType, - tinyxml2::XMLDocument& schemaDocument) + if (!getWriteDefaults()) { - // Skip if not a data field. - if (field.type == AbstractClassRep::DeprecatedFieldType || - field.type == AbstractClassRep::StartGroupFieldType || - field.type == AbstractClassRep::EndGroupFieldType) - return NULL; + // Cleanup our created default object + delete defaultConObject; + } +} - // Skip if the field root is not this type. - if (pType->findFieldRoot(field.pFieldname) != pType) - return NULL; +//----------------------------------------------------------------------------- - // Add attribute element. - tinyxml2::XMLElement* pAttributeElement = schemaDocument.NewElement("xs:attribute"); - pAttributeElement->SetAttribute("name", field.pFieldname); +static S32 QSORT_CALLBACK compareFieldEntries(const void* a, const void* b) +{ + // Debug Profiling. + PROFILE_SCOPE(Taml_CompareFieldEntries); - // Handle the console type appropriately. - const S32 fieldType = (S32)field.type; + SimFieldDictionary::Entry *fa = *((SimFieldDictionary::Entry **)a); + SimFieldDictionary::Entry *fb = *((SimFieldDictionary::Entry **)b); + return dStricmp(fa->slotName, fb->slotName); +} - /* - // Is the field an enumeration? - if ( fieldType == TypeEnum ) +//----------------------------------------------------------------------------- + +void Taml::compileDynamicFields(TamlWriteNode* pTamlWriteNode) +{ + // Debug Profiling. + PROFILE_SCOPE(Taml_CompileDynamicFields); + + // Sanity! + AssertFatal(pTamlWriteNode != NULL, "Cannot compile dynamic fields on a NULL node."); + AssertFatal(pTamlWriteNode->mpSimObject != NULL, "Cannot compile dynamic fields on a node with no object."); + + // Fetch object. + SimObject* pSimObject = pTamlWriteNode->mpSimObject; + + // Fetch field dictionary. + SimFieldDictionary* pFieldDictionary = pSimObject->getFieldDictionary(); + + // Ignore if not writing dynamic fields. + if (!pFieldDictionary || !pSimObject->getCanSaveDynamicFields()) + return; + + // Fetch field list. + const AbstractClassRep::FieldList& fieldList = pSimObject->getFieldList(); + + // Fetch field count. + const U32 fieldCount = fieldList.size(); + + Vector dynamicFieldList(__FILE__, __LINE__); + + // Ensure the dynamic field doesn't conflict with static field. + for (U32 hashIndex = 0; hashIndex < SimFieldDictionary::HashTableSize; ++hashIndex) + { + for (SimFieldDictionary::Entry* pEntry = pFieldDictionary->mHashTable[hashIndex]; pEntry; pEntry = pEntry->next) { - // Yes, so add attribute type. - tinyxml2::XMLElement* pAttributeSimpleTypeElement = schemaDocument.NewElement( "xs:simpleType" ); - pAttributeElement->LinkEndChild( pAttributeSimpleTypeElement ); + // Iterate static fields. + U32 fieldIndex; + for (fieldIndex = 0; fieldIndex < fieldCount; ++fieldIndex) + { + if (fieldList[fieldIndex].pFieldname == pEntry->slotName) + break; + } - // Add restriction element. - tinyxml2::XMLElement* pAttributeRestrictionElement = schemaDocument.NewElement( "xs:restriction" ); - pAttributeRestrictionElement->SetAttribute( "base", "xs:string" ); - pAttributeSimpleTypeElement->LinkEndChild( pAttributeRestrictionElement ); + // Skip if found. + if (fieldIndex != (U32)fieldList.size()) + continue; - // Yes, so fetch enumeration count. - const S32 enumCount = field.table->size; + // Skip if not writing field. + if (!pSimObject->writeField(pEntry->slotName, pEntry->value)) + continue; - // Iterate enumeration. - for( S32 index = 0; index < enumCount; ++index ) - { - // Add enumeration element. - tinyxml2::XMLElement* pAttributeEnumerationElement = schemaDocument.NewElement( "xs:enumeration" ); - pAttributeEnumerationElement->SetAttribute( "value", field.table->table[index].label ); - pAttributeRestrictionElement->LinkEndChild( pAttributeEnumerationElement ); + dynamicFieldList.push_back(pEntry); } + } + + // Sort Entries to prevent version control conflicts + if (dynamicFieldList.size() > 1) + dQsort(dynamicFieldList.address(), dynamicFieldList.size(), sizeof(SimFieldDictionary::Entry*), compareFieldEntries); + + // Save the fields. + for (Vector::iterator entryItr = dynamicFieldList.begin(); entryItr != dynamicFieldList.end(); ++entryItr) + { + // Fetch entry. + SimFieldDictionary::Entry* pEntry = *entryItr; + + // Save field/value. + TamlWriteNode::FieldValuePair* pFieldValuePair = new TamlWriteNode::FieldValuePair(pEntry->slotName, pEntry->value); + pTamlWriteNode->mFields.push_back(pFieldValuePair); + } +} + +//----------------------------------------------------------------------------- + +void Taml::compileChildren(TamlWriteNode* pTamlWriteNode) +{ + // Debug Profiling. + PROFILE_SCOPE(Taml_CompileChildren); + + // Sanity! + AssertFatal(pTamlWriteNode != NULL, "Cannot compile children on a NULL node."); + AssertFatal(pTamlWriteNode->mpSimObject != NULL, "Cannot compile children on a node with no object."); + + // Fetch object. + SimObject* pSimObject = pTamlWriteNode->mpSimObject; + + // Fetch the Taml children. + TamlChildren* pChildren = dynamic_cast(pSimObject); + + // Finish if object does not contain Taml children. + if (pChildren == NULL || pChildren->getTamlChildCount() == 0) + return; + + // Create children vector. + pTamlWriteNode->mChildren = new typeNodeVector(); + + // Fetch the child count. + const U32 childCount = pChildren->getTamlChildCount(); + + // Iterate children. + for (U32 childIndex = 0; childIndex < childCount; childIndex++) + { + // Compile object. + TamlWriteNode* pChildTamlWriteNode = compileObject(pChildren->getTamlChild(childIndex)); + + // Save node. + pTamlWriteNode->mChildren->push_back(pChildTamlWriteNode); + } +} + +//----------------------------------------------------------------------------- + +void Taml::compileCustomState(TamlWriteNode* pTamlWriteNode) +{ + // Debug Profiling. + PROFILE_SCOPE(Taml_CompileCustomProperties); + + // Sanity! + AssertFatal(pTamlWriteNode != NULL, "Cannot compile custom state on a NULL node."); + AssertFatal(pTamlWriteNode->mpSimObject != NULL, "Cannot compile custom state on a node with no object."); + + // Fetch the custom node on the write node. + TamlCustomNodes& customNodes = pTamlWriteNode->mCustomNodes; + + // Are there any Taml callbacks? + if (pTamlWriteNode->mpTamlCallbacks != NULL) + { + // Yes, so call it. + tamlCustomWrite(pTamlWriteNode->mpTamlCallbacks, customNodes); + } + + // Fetch custom nodes. + const TamlCustomNodeVector& nodes = customNodes.getNodes(); + + // Finish if no custom nodes to process. + if (nodes.size() == 0) + return; + + // Iterate custom properties. + for (TamlCustomNodeVector::const_iterator customNodesItr = nodes.begin(); customNodesItr != nodes.end(); ++customNodesItr) + { + // Fetch the custom node. + TamlCustomNode* pCustomNode = *customNodesItr; + + // Compile custom node state. + compileCustomNodeState(pCustomNode); + } +} + +//----------------------------------------------------------------------------- + +void Taml::compileCustomNodeState(TamlCustomNode* pCustomNode) +{ + // Sanity! + AssertFatal(pCustomNode != NULL, "Taml: Cannot compile NULL custom node state."); + + // Fetch children. + const TamlCustomNodeVector& children = pCustomNode->getChildren(); + + // Fetch proxy object. + SimObject* pProxyObject = pCustomNode->getProxyObject(false); + + // Do we have a proxy object? + if (pProxyObject != NULL) + { + // Yes, so sanity! + AssertFatal(children.size() == 0, "Taml: Cannot compile a proxy object on a custom node that has children."); + + // Yes, so compile it. + // NOTE: We force an Id for custom compiled objects so we guarantee an Id. The reason for this is fairly + // weak in that the XML parser currently has no way of distinguishing between a compiled object node + // 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. + pCustomNode->setWriteNode(compileObject(pProxyObject, true)); + return; + } + + // Finish if no children. + if (children.size() == 0) + return; + + // Iterate children. + for (TamlCustomNodeVector::const_iterator childItr = children.begin(); childItr != children.end(); ++childItr) + { + // Fetch shape node. + TamlCustomNode* pChildNode = *childItr; + + // Compile the child. + compileCustomNodeState(pChildNode); + } +} + +//----------------------------------------------------------------------------- + +SimObject* Taml::createType(StringTableEntry typeName, const Taml* pTaml, const char* pProgenitorSuffix) +{ + // Debug Profiling. + PROFILE_SCOPE(Taml_CreateType); + + typedef HashTable typeClassHash; + static typeClassHash mClassMap; + + // Sanity! + AssertFatal(typeName != NULL, "Taml: Type cannot be NULL"); + + // Find type. + typeClassHash::Iterator typeItr = mClassMap.find(typeName); + + // Found type? + if (typeItr == mClassMap.end()) + { + // No, so find type. + AbstractClassRep* pClassRep = AbstractClassRep::getClassList(); + while (pClassRep) + { + // Is this the type? + if (dStricmp(pClassRep->getClassName(), typeName) == 0) + { + // Yes, so insert it. + typeItr = mClassMap.insertUnique(typeName, pClassRep); + break; + } + + // Next type. + pClassRep = pClassRep->getNextClass(); + } + + // Did we find the type? + if (typeItr == mClassMap.end()) + { + // No, so warn and fail. + Con::warnf("Taml: Failed to create type '%s' as such a registered type could not be found.", typeName); + return NULL; + } + } + + // Create the object. + ConsoleObject* pConsoleObject = typeItr->value->create(); + + // NOTE: It is important that we don't register the object here as many objects rely on the fact that + // fields are set prior to the object being registered. Registering here will invalid those assumptions. + + // Fetch the SimObject. + SimObject* pSimObject = dynamic_cast(pConsoleObject); + + // Was it a SimObject? + if (pSimObject == NULL) + { + // No, so warn. + Con::warnf("Taml: Failed to create type '%s' as it is not a SimObject.", typeName); + + // Destroy object and fail. + delete pConsoleObject; + return NULL; + } + + // Are we updating the file-progenitor? + if (pTaml->getProgenitorUpdate()) + { + // Yes, so do we have a progenitor suffix? + if (pProgenitorSuffix == NULL) + { + // No, so just set it to the progenitor file. + pSimObject->setProgenitorFile(pTaml->getFilePathBuffer()); } else - {*/ - // No, so assume it's a string type initially. - const char* pFieldTypeDescription = "xs:string"; + { + // Yes, so format the progenitor buffer. + char progenitorBuffer[2048]; + dSprintf(progenitorBuffer, sizeof(progenitorBuffer), "%s,%s", pTaml->getFilePathBuffer(), pProgenitorSuffix); - // Handle known types. - if (fieldType == TypeF32) - { - pFieldTypeDescription = "xs:float"; + // Set the progenitor file. + pSimObject->setProgenitorFile(progenitorBuffer); } - else if (fieldType == TypeS8 || fieldType == TypeS16 || fieldType == TypeS32) - { - pFieldTypeDescription = "xs:int"; - } - else if (fieldType == TypeBool || fieldType == TypeFlag) - { - pFieldTypeDescription = "xs:boolean"; - } - else if (fieldType == TypePoint2F) - { - pFieldTypeDescription = "Point2F_ConsoleType"; - } - else if (fieldType == TypePoint2I) - { - pFieldTypeDescription = "Point2I_ConsoleType"; - } - else if (fieldType == TypeRectI) - { - pFieldTypeDescription = "RectI_ConsoleType"; - } - else if (fieldType == TypeRectF) - { - pFieldTypeDescription = "RectF_ConsoleType"; - } - else if (fieldType == TypeColorF) - { - pFieldTypeDescription = "ColorF_ConsoleType"; - } - else if (fieldType == TypeColorI) - { - pFieldTypeDescription = "ColorI_ConsoleType"; - } - else if (fieldType == TypeAssetId/* || - fieldType == TypeImageAssetPtr || - fieldType == TypeAnimationAssetPtr || - fieldType == TypeAudioAssetPtr*/) - { - pFieldTypeDescription = "AssetId_ConsoleType"; - } - - // Set attribute type. - pAttributeElement->SetAttribute("type", pFieldTypeDescription); - //} - - pAttributeElement->SetAttribute("use", "optional"); - return pAttributeElement; } - String g_sanitize_schema_element_name(String buffer) + return pSimObject; +} + +//----------------------------------------------------------------------------- + +tinyxml2::XMLElement* g__write_schema_attribute_element(const AbstractClassRep::Field& field, AbstractClassRep* pType, + tinyxml2::XMLDocument& schemaDocument) +{ + // Skip if not a data field. + if (field.type == AbstractClassRep::DeprecatedFieldType || + field.type == AbstractClassRep::StartGroupFieldType || + field.type == AbstractClassRep::EndGroupFieldType) + return NULL; + + // Skip if the field root is not this type. + if (pType->findFieldRoot(field.pFieldname) != pType) + return NULL; + + // Add attribute element. + tinyxml2::XMLElement* pAttributeElement = schemaDocument.NewElement("xs:attribute"); + pAttributeElement->SetAttribute("name", field.pFieldname); + + // Handle the console type appropriately. + const S32 fieldType = (S32)field.type; + + /* + // Is the field an enumeration? + if ( fieldType == TypeEnum ) { - return buffer.replace("(", "") - .replace(")", ""); + // Yes, so add attribute type. + tinyxml2::XMLElement* pAttributeSimpleTypeElement = schemaDocument.NewElement( "xs:simpleType" ); + pAttributeElement->LinkEndChild( pAttributeSimpleTypeElement ); + + // Add restriction element. + tinyxml2::XMLElement* pAttributeRestrictionElement = schemaDocument.NewElement( "xs:restriction" ); + pAttributeRestrictionElement->SetAttribute( "base", "xs:string" ); + pAttributeSimpleTypeElement->LinkEndChild( pAttributeRestrictionElement ); + + // Yes, so fetch enumeration count. + const S32 enumCount = field.table->size; + + // Iterate enumeration. + for( S32 index = 0; index < enumCount; ++index ) + { + // Add enumeration element. + tinyxml2::XMLElement* pAttributeEnumerationElement = schemaDocument.NewElement( "xs:enumeration" ); + pAttributeEnumerationElement->SetAttribute( "value", field.table->table[index].label ); + pAttributeRestrictionElement->LinkEndChild( pAttributeEnumerationElement ); + } + } + else + {*/ + // No, so assume it's a string type initially. + const char* pFieldTypeDescription = "xs:string"; + + // Handle known types. + if (fieldType == TypeF32) + { + pFieldTypeDescription = "xs:float"; + } + else if (fieldType == TypeS8 || fieldType == TypeS16 || fieldType == TypeS32) + { + pFieldTypeDescription = "xs:int"; + } + else if (fieldType == TypeBool || fieldType == TypeFlag) + { + pFieldTypeDescription = "xs:boolean"; + } + else if (fieldType == TypePoint2F) + { + pFieldTypeDescription = "Point2F_ConsoleType"; + } + else if (fieldType == TypePoint2I) + { + pFieldTypeDescription = "Point2I_ConsoleType"; + } + else if (fieldType == TypeRectI) + { + pFieldTypeDescription = "RectI_ConsoleType"; + } + else if (fieldType == TypeRectF) + { + pFieldTypeDescription = "RectF_ConsoleType"; + } + else if (fieldType == TypeColorF) + { + pFieldTypeDescription = "ColorF_ConsoleType"; + } + else if (fieldType == TypeColorI) + { + pFieldTypeDescription = "ColorI_ConsoleType"; + } + else if (fieldType == TypeAssetId/* || + fieldType == TypeImageAssetPtr || + fieldType == TypeAnimationAssetPtr || + fieldType == TypeAudioAssetPtr*/) + { + pFieldTypeDescription = "AssetId_ConsoleType"; } - bool Taml::generateTamlSchema() + // Set attribute type. + pAttributeElement->SetAttribute("type", pFieldTypeDescription); + //} + + pAttributeElement->SetAttribute("use", "optional"); + return pAttributeElement; +} + +String g_sanitize_schema_element_name(String buffer) +{ + return buffer.replace("(", "") + .replace(")", ""); +} + +bool Taml::generateTamlSchema() +{ + // Fetch any TAML Schema file reference. + const char* pTamlSchemaFile = Con::getVariable(TAML_SCHEMA_VARIABLE); + + // Do we have a schema file reference? + if (pTamlSchemaFile == NULL || *pTamlSchemaFile == 0) { - // Fetch any TAML Schema file reference. - const char* pTamlSchemaFile = Con::getVariable(TAML_SCHEMA_VARIABLE); - - // Do we have a schema file reference? - if (pTamlSchemaFile == NULL || *pTamlSchemaFile == 0) - { - // No, so warn. - Con::warnf("Taml::generateTamlSchema() - Cannot write a TAML schema as no schema variable is set ('%s').", TAML_SCHEMA_VARIABLE); - return false; - } - - // Expand the file-name into the file-path buffer. - char filePathBuffer[1024]; - Con::expandToolScriptFilename(filePathBuffer, sizeof(filePathBuffer), pTamlSchemaFile); - - FileStream stream; - - // File opened? - /*if ( !stream.open( filePathBuffer, Torque::FS::File::Write ) ) - { // No, so warn. - Con::warnf("Taml::GenerateTamlSchema() - Could not open filename '%s' for write.", filePathBuffer ); + Con::warnf("Taml::generateTamlSchema() - Cannot write a TAML schema as no schema variable is set ('%s').", TAML_SCHEMA_VARIABLE); return false; - }*/ - - // Create document. - tinyxml2::XMLDocument schemaDocument; - - // Add declaration. - tinyxml2::XMLDeclaration* schemaDeclaration = schemaDocument.NewDeclaration("xml version=\"1.0\" encoding=\"iso-8859-1\" standalone =\"no\""); - schemaDocument.InsertEndChild(schemaDeclaration); - - // Add schema element. - tinyxml2::XMLElement* pSchemaElement = schemaDocument.NewElement("xs:schema"); - pSchemaElement->SetAttribute("xmlns:xs", "http://www.w3.org/2001/XMLSchema"); - schemaDocument.LinkEndChild(pSchemaElement); - - // Fetch class-rep root. - AbstractClassRep* pRootType = AbstractClassRep::getClassList(); - - // Fetch SimObject class rep. - AbstractClassRep* pSimObjectType = AbstractClassRep::findClassRep("SimObject"); - // Sanity! - AssertFatal(pSimObjectType != NULL, "Taml::GenerateTamlSchema() - Could not find SimObject class rep."); - - // Reset scratch state. - char buffer[1024]; - HashTable childGroups; - - // ************************************************************* - // Generate console type elements. - // ************************************************************* - - // Vector2. - tinyxml2::XMLComment* pVector2Comment = schemaDocument.NewComment("Vector2 Console Type"); - pSchemaElement->LinkEndChild(pVector2Comment); - tinyxml2::XMLElement* pVector2TypeElement = schemaDocument.NewElement("xs:simpleType"); - pVector2TypeElement->SetAttribute("name", "Vector2_ConsoleType"); - pSchemaElement->LinkEndChild(pVector2TypeElement); - tinyxml2::XMLElement* pVector2ElementA = schemaDocument.NewElement("xs:restriction"); - pVector2ElementA->SetAttribute("base", "xs:string"); - pVector2TypeElement->LinkEndChild(pVector2ElementA); - tinyxml2::XMLElement* pVector2ElementB = schemaDocument.NewElement("xs:pattern"); - pVector2ElementB->SetAttribute("value", "([-]?(\\b[0-9]+)?\\.)?[0-9]+\\b ([-]?(\\b[0-9]+)?\\.)?[0-9]+\\b"); - pVector2ElementA->LinkEndChild(pVector2ElementB); - - // Point2F. - tinyxml2::XMLComment* pPoint2FComment = schemaDocument.NewComment("Point2F Console Type"); - pSchemaElement->LinkEndChild(pPoint2FComment); - tinyxml2::XMLElement* pPoint2FTypeElement = schemaDocument.NewElement("xs:simpleType"); - pPoint2FTypeElement->SetAttribute("name", "Point2F_ConsoleType"); - pSchemaElement->LinkEndChild(pPoint2FTypeElement); - tinyxml2::XMLElement* pPoint2FElementA = schemaDocument.NewElement("xs:restriction"); - pPoint2FElementA->SetAttribute("base", "xs:string"); - pPoint2FTypeElement->LinkEndChild(pPoint2FElementA); - tinyxml2::XMLElement* pPoint2FElementB = schemaDocument.NewElement("xs:pattern"); - pPoint2FElementB->SetAttribute("value", "([-]?(\\b[0-9]+)?\\.)?[0-9]+\\b ([-]?(\\b[0-9]+)?\\.)?[0-9]+\\b"); - pPoint2FElementA->LinkEndChild(pPoint2FElementB); - - // Point2I. - tinyxml2::XMLComment* pPoint2IComment = schemaDocument.NewComment("Point2I Console Type"); - pSchemaElement->LinkEndChild(pPoint2IComment); - tinyxml2::XMLElement* pPoint2ITypeElement = schemaDocument.NewElement("xs:simpleType"); - pPoint2ITypeElement->SetAttribute("name", "Point2I_ConsoleType"); - pSchemaElement->LinkEndChild(pPoint2ITypeElement); - tinyxml2::XMLElement* pPoint2IElementA = schemaDocument.NewElement("xs:restriction"); - pPoint2IElementA->SetAttribute("base", "xs:string"); - pPoint2ITypeElement->LinkEndChild(pPoint2IElementA); - tinyxml2::XMLElement* pPoint2IElementB = schemaDocument.NewElement("xs:pattern"); - pPoint2IElementB->SetAttribute("value", "[-]?[0-9]* [-]?[0-9]*"); - pPoint2IElementA->LinkEndChild(pPoint2IElementB); - - // b2AABB. - tinyxml2::XMLComment* pb2AABBComment = schemaDocument.NewComment("b2AABB Console Type"); - pSchemaElement->LinkEndChild(pb2AABBComment); - tinyxml2::XMLElement* pb2AABBTypeElement = schemaDocument.NewElement("xs:simpleType"); - pb2AABBTypeElement->SetAttribute("name", "b2AABB_ConsoleType"); - pSchemaElement->LinkEndChild(pb2AABBTypeElement); - tinyxml2::XMLElement* pb2AABBElementA = schemaDocument.NewElement("xs:restriction"); - pb2AABBElementA->SetAttribute("base", "xs:string"); - pb2AABBTypeElement->LinkEndChild(pb2AABBElementA); - tinyxml2::XMLElement* pb2AABBElementB = schemaDocument.NewElement("xs:pattern"); - 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"); - pb2AABBElementA->LinkEndChild(pb2AABBElementB); - - // RectI. - tinyxml2::XMLComment* pRectIComment = schemaDocument.NewComment("RectI Console Type"); - pSchemaElement->LinkEndChild(pRectIComment); - tinyxml2::XMLElement* pRectITypeElement = schemaDocument.NewElement("xs:simpleType"); - pRectITypeElement->SetAttribute("name", "RectI_ConsoleType"); - pSchemaElement->LinkEndChild(pRectITypeElement); - tinyxml2::XMLElement* pRectIElementA = schemaDocument.NewElement("xs:restriction"); - pRectIElementA->SetAttribute("base", "xs:string"); - pRectITypeElement->LinkEndChild(pRectIElementA); - tinyxml2::XMLElement* pRectIElementB = schemaDocument.NewElement("xs:pattern"); - pRectIElementB->SetAttribute("value", "[-]?[0-9]* [-]?[0-9]* [-]?[0-9]* [-]?[0-9]*"); - pRectIElementA->LinkEndChild(pRectIElementB); - - // RectF. - tinyxml2::XMLComment* pRectFComment = schemaDocument.NewComment("RectF Console Type"); - pSchemaElement->LinkEndChild(pRectFComment); - tinyxml2::XMLElement* pRectFTypeElement = schemaDocument.NewElement("xs:simpleType"); - pRectFTypeElement->SetAttribute("name", "RectF_ConsoleType"); - pSchemaElement->LinkEndChild(pRectFTypeElement); - tinyxml2::XMLElement* pRectFElementA = schemaDocument.NewElement("xs:restriction"); - pRectFElementA->SetAttribute("base", "xs:string"); - pRectFTypeElement->LinkEndChild(pRectFElementA); - tinyxml2::XMLElement* pRectFElementB = schemaDocument.NewElement("xs:pattern"); - pRectFElementB->SetAttribute("value", "(\\b[-]?(b[0-9]+)?\\.)?[0-9]+\\b"); - pRectFElementA->LinkEndChild(pRectFElementB); - - // AssetId. - tinyxml2::XMLComment* pAssetIdComment = schemaDocument.NewComment("AssetId Console Type"); - pSchemaElement->LinkEndChild(pAssetIdComment); - tinyxml2::XMLElement* pAssetIdTypeElement = schemaDocument.NewElement("xs:simpleType"); - pAssetIdTypeElement->SetAttribute("name", "AssetId_ConsoleType"); - pSchemaElement->LinkEndChild(pAssetIdTypeElement); - tinyxml2::XMLElement* pAssetIdElementA = schemaDocument.NewElement("xs:restriction"); - pAssetIdElementA->SetAttribute("base", "xs:string"); - pAssetIdTypeElement->LinkEndChild(pAssetIdElementA); - tinyxml2::XMLElement* pAssetIdElementB = schemaDocument.NewElement("xs:pattern"); - 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); - pAssetIdElementB->SetAttribute("value", buffer); - pAssetIdElementA->LinkEndChild(pAssetIdElementB); - - // Color Enums. - tinyxml2::XMLComment* pColorEnumsComment = schemaDocument.NewComment("Color Enums"); - pSchemaElement->LinkEndChild(pColorEnumsComment); - tinyxml2::XMLElement* pColorEnumsTypeElement = schemaDocument.NewElement("xs:simpleType"); - pColorEnumsTypeElement->SetAttribute("name", "Color_Enums"); - pSchemaElement->LinkEndChild(pColorEnumsTypeElement); - tinyxml2::XMLElement* pColorEnumsRestrictionElement = schemaDocument.NewElement("xs:restriction"); - pColorEnumsRestrictionElement->SetAttribute("base", "xs:string"); - pColorEnumsTypeElement->LinkEndChild(pColorEnumsRestrictionElement); - const S32 ColorEnumsCount = StockColor::getCount(); - for (S32 index = 0; index < ColorEnumsCount; ++index) - { - // Add enumeration element. - tinyxml2::XMLElement* pColorEnumsAttributeEnumerationElement = schemaDocument.NewElement("xs:enumeration"); - pColorEnumsAttributeEnumerationElement->SetAttribute("value", StockColor::getColorItem(index)->getColorName()); - pColorEnumsRestrictionElement->LinkEndChild(pColorEnumsAttributeEnumerationElement); - } - - // LinearColorF. - tinyxml2::XMLComment* pColorFValuesComment = schemaDocument.NewComment("LinearColorF Values"); - pSchemaElement->LinkEndChild(pColorFValuesComment); - tinyxml2::XMLElement* pColorFValuesTypeElement = schemaDocument.NewElement("xs:simpleType"); - pColorFValuesTypeElement->SetAttribute("name", "ColorF_Values"); - pSchemaElement->LinkEndChild(pColorFValuesTypeElement); - tinyxml2::XMLElement* pColorFValuesElementA = schemaDocument.NewElement("xs:restriction"); - pColorFValuesElementA->SetAttribute("base", "xs:string"); - pColorFValuesTypeElement->LinkEndChild(pColorFValuesElementA); - tinyxml2::XMLElement* pColorFValuesElementB = schemaDocument.NewElement("xs:pattern"); - 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"); - pColorFValuesElementA->LinkEndChild(pColorFValuesElementB); - - tinyxml2::XMLComment* pColorFComment = schemaDocument.NewComment("LinearColorF Console Type"); - pSchemaElement->LinkEndChild(pColorFComment); - tinyxml2::XMLElement* pColorFTypeElement = schemaDocument.NewElement("xs:simpleType"); - pColorFTypeElement->SetAttribute("name", "ColorF_ConsoleType"); - pSchemaElement->LinkEndChild(pColorFTypeElement); - tinyxml2::XMLElement* pColorFUnionElement = schemaDocument.NewElement("xs:union"); - pColorFUnionElement->SetAttribute("memberTypes", "ColorF_Values Color_Enums"); - pColorFTypeElement->LinkEndChild(pColorFUnionElement); - - // ColorI. - tinyxml2::XMLComment* pColorIValuesComment = schemaDocument.NewComment("ColorI Values"); - pSchemaElement->LinkEndChild(pColorIValuesComment); - tinyxml2::XMLElement* pColorIValuesTypeElement = schemaDocument.NewElement("xs:simpleType"); - pColorIValuesTypeElement->SetAttribute("name", "ColorI_Values"); - pSchemaElement->LinkEndChild(pColorIValuesTypeElement); - tinyxml2::XMLElement* pColorIValuesElementA = schemaDocument.NewElement("xs:restriction"); - pColorIValuesElementA->SetAttribute("base", "xs:string"); - pColorIValuesTypeElement->LinkEndChild(pColorIValuesElementA); - tinyxml2::XMLElement* pColorIValuesElementB = schemaDocument.NewElement("xs:pattern"); - pColorIValuesElementB->SetAttribute("value", "[-]?[0-9]* [-]?[0-9]* [-]?[0-9]* [-]?[0-9]*"); - pColorIValuesElementA->LinkEndChild(pColorIValuesElementB); - - tinyxml2::XMLComment* pColorIComment = schemaDocument.NewComment("ColorI Console Type"); - pSchemaElement->LinkEndChild(pColorIComment); - tinyxml2::XMLElement* pColorITypeElement = schemaDocument.NewElement("xs:simpleType"); - pColorITypeElement->SetAttribute("name", "ColorI_ConsoleType"); - pSchemaElement->LinkEndChild(pColorITypeElement); - tinyxml2::XMLElement* pColorIUnionElement = schemaDocument.NewElement("xs:union"); - pColorIUnionElement->SetAttribute("memberTypes", "ColorI_Values Color_Enums"); - pColorITypeElement->LinkEndChild(pColorIUnionElement); - - // ************************************************************* - // Generate engine type elements. - // ************************************************************* - - // Generate the engine type elements. - tinyxml2::XMLComment* tComment = schemaDocument.NewComment("Type Elements"); - pSchemaElement->LinkEndChild(tComment); - for (AbstractClassRep* pType = pRootType; pType != NULL; pType = pType->getNextClass()) - { - // Add type. - tinyxml2::XMLElement* pTypeElement = schemaDocument.NewElement("xs:element"); - pTypeElement->SetAttribute("name", pType->getClassName()); - dSprintf(buffer, sizeof(buffer), "%s_Type", pType->getClassName()); - pTypeElement->SetAttribute("type", buffer); - pSchemaElement->LinkEndChild(pTypeElement); - } - - // ************************************************************* - // Generate the engine complex types. - // ************************************************************* - for (AbstractClassRep* pType = pRootType; pType != NULL; pType = pType->getNextClass()) - { - // Add complex type comment. - dSprintf(buffer, sizeof(buffer), " %s Type ", pType->getClassName()); - tinyxml2::XMLComment* ctComment = schemaDocument.NewComment(buffer); - pSchemaElement->LinkEndChild(ctComment); - - // Add complex type. - tinyxml2::XMLElement* pComplexTypeElement = schemaDocument.NewElement("xs:complexType"); - dSprintf(buffer, sizeof(buffer), "%s_Type", pType->getClassName()); - pComplexTypeElement->SetAttribute("name", buffer); - pSchemaElement->LinkEndChild(pComplexTypeElement); - - // Add sequence. - tinyxml2::XMLElement* pAllElement = schemaDocument.NewElement("xs:all"); - pComplexTypeElement->LinkEndChild(pAllElement); - - // Fetch container child class. - AbstractClassRep* pContainerChildClass = pType->getContainerChildClass(true); - - // Is the type allowed children? - if (pContainerChildClass != NULL) - { - // Yes, so add choice element. - tinyxml2::XMLElement* pChoiceElement = schemaDocument.NewElement("xs:choice"); - pChoiceElement->SetAttribute("minOccurs", 0); - pChoiceElement->SetAttribute("maxOccurs", "unbounded"); - pAllElement->LinkEndChild(pChoiceElement); - - // Find child group. - HashTable::Iterator childGroupItr = childGroups.find(pContainerChildClass); - - // Does the group exist? - if (childGroupItr == childGroups.end()) - { - // No, so format group name. - dSprintf(buffer, sizeof(buffer), "%s_ChildrenTypes", pContainerChildClass->getClassName()); - - // Insert into child group hash. - childGroupItr = childGroups.insertUnique(pContainerChildClass, StringTable->insert(buffer)); - - // Add the group. - tinyxml2::XMLElement* pChildrenGroupElement = schemaDocument.NewElement("xs:group"); - pChildrenGroupElement->SetAttribute("name", buffer); - pSchemaElement->LinkEndChild(pChildrenGroupElement); - - // Add choice element. - tinyxml2::XMLElement* pChildreGroupChoiceElement = schemaDocument.NewElement("xs:choice"); - pChildrenGroupElement->LinkEndChild(pChildreGroupChoiceElement); - - // Add choice members. - for (AbstractClassRep* pChoiceType = pRootType; pChoiceType != NULL; pChoiceType = pChoiceType->getNextClass()) - { - // Skip if not derived from the container child class. - if (!pChoiceType->isClass(pContainerChildClass)) - continue; - - // Add choice member. - tinyxml2::XMLElement* pChildrenMemberElement = schemaDocument.NewElement("xs:element"); - pChildrenMemberElement->SetAttribute("name", pChoiceType->getClassName()); - dSprintf(buffer, sizeof(buffer), "%s_Type", pChoiceType->getClassName()); - pChildrenMemberElement->SetAttribute("type", buffer); - pChildreGroupChoiceElement->LinkEndChild(pChildrenMemberElement); - } - - } - - // Reference the child group. - tinyxml2::XMLElement* pChoiceGroupReferenceElement = schemaDocument.NewElement("xs:group"); - pChoiceGroupReferenceElement->SetAttribute("ref", childGroupItr->value); - pChoiceGroupReferenceElement->SetAttribute("minOccurs", 0); - pChoiceElement->LinkEndChild(pChoiceGroupReferenceElement); - } - - // Generate the custom Taml schema. - for (AbstractClassRep* pCustomSchemaType = pType; pCustomSchemaType != NULL; pCustomSchemaType = pCustomSchemaType->getParentClass()) - { - // Fetch the types custom TAML schema function. - AbstractClassRep::WriteCustomTamlSchema customSchemaFn = pCustomSchemaType->getCustomTamlSchema(); - - // Skip if no function avilable. - if (customSchemaFn == NULL) - continue; - - // Call schema generation function. - customSchemaFn(pType, pAllElement); - } - - // Fetch field list. - const AbstractClassRep::FieldList& fields = pType->mFieldList; - - // Fetch field count. - const S32 fieldCount = fields.size(); - - // Generate array attribute groups - for (S32 index = 0; index < fieldCount; ++index) - { - // Fetch field. - const AbstractClassRep::Field& field = fields[index]; - - if (field.type == AbstractClassRep::StartArrayFieldType) - { - // Add the top-level array identifier - tinyxml2::XMLElement* pArrayElement = schemaDocument.NewElement("xs:element"); - dSprintf(buffer, sizeof(buffer), "%s.%s", pType->getClassName(), g_sanitize_schema_element_name(field.pGroupname).c_str()); - pArrayElement->SetAttribute("name", buffer); - pArrayElement->SetAttribute("minOccurs", 0); - pAllElement->LinkEndChild(pArrayElement); - - // Inline type specification - tinyxml2::XMLElement* pArrayComplexTypeElement = schemaDocument.NewElement("xs:complexType"); - pArrayElement->LinkEndChild(pArrayComplexTypeElement); - - // Add the actual (repeating) array elements - tinyxml2::XMLElement* pInnerArrayElement = schemaDocument.NewElement("xs:element"); - pInnerArrayElement->SetAttribute("name", g_sanitize_schema_element_name(field.pFieldname).c_str()); - pInnerArrayElement->SetAttribute("minOccurs", 0); - pInnerArrayElement->SetAttribute("maxOccurs", field.elementCount); - pArrayComplexTypeElement->LinkEndChild(pInnerArrayElement); - - // Inline type specification - tinyxml2::XMLElement* pInnerComplexTypeElement = schemaDocument.NewElement("xs:complexType"); - pInnerArrayElement->LinkEndChild(pInnerComplexTypeElement); - - // Add a reference to the attribute group for the array - tinyxml2::XMLElement* pInnerAttributeGroupElement = schemaDocument.NewElement("xs:attributeGroup"); - dSprintf(buffer, sizeof(buffer), "%s_%s_Array_Fields", pType->getClassName(), g_sanitize_schema_element_name(field.pFieldname).c_str()); - pInnerAttributeGroupElement->SetAttribute("ref", buffer); - pInnerComplexTypeElement->LinkEndChild(pInnerAttributeGroupElement); - - // Add the attribute group itself - tinyxml2::XMLElement* pFieldAttributeGroupElement = schemaDocument.NewElement("xs:attributeGroup"); - pFieldAttributeGroupElement->SetAttribute("name", buffer); - pSchemaElement->LinkEndChild(pFieldAttributeGroupElement); - - // Keep adding fields to attribute group until we hit the end of the array - for (; index < fieldCount; ++index) - { - const AbstractClassRep::Field& array_field = fields[index]; - if (array_field.type == AbstractClassRep::EndArrayFieldType) - { - break; - } - - tinyxml2::XMLElement* pAttributeElement = g__write_schema_attribute_element(array_field, pType, schemaDocument); - if (pAttributeElement == NULL) - { - continue; - } - - pFieldAttributeGroupElement->LinkEndChild(pAttributeElement); - } - } - } - - // Generate field attribute group. - tinyxml2::XMLElement* pFieldAttributeGroupElement = schemaDocument.NewElement("xs:attributeGroup"); - dSprintf(buffer, sizeof(buffer), "%s_Fields", pType->getClassName()); - pFieldAttributeGroupElement->SetAttribute("name", buffer); - pSchemaElement->LinkEndChild(pFieldAttributeGroupElement); - - // Iterate static fields (in reverse as most types are organized from the root-fields up). - for (S32 index = fieldCount - 1; index > 0; --index) - { - // Fetch field. - const AbstractClassRep::Field& field = fields[index]; - - // Skip fields inside arrays - if (field.type == AbstractClassRep::EndArrayFieldType) - { - for (; index > 0; --index) - { - if (field.type == AbstractClassRep::StartArrayFieldType) - { - break; - } - } - continue; - } - - tinyxml2::XMLElement* pAttributeElement = g__write_schema_attribute_element(field, pType, schemaDocument); - if (pAttributeElement == NULL) - { - continue; - } - - pFieldAttributeGroupElement->LinkEndChild(pAttributeElement); - } - - // Is this the SimObject Type? - if (pType == pSimObjectType) - { - // Yes, so add reserved Taml field attributes here... - - // Add Taml "Name" attribute element. - tinyxml2::XMLElement* pNameAttributeElement = schemaDocument.NewElement("xs:attribute"); - pNameAttributeElement->SetAttribute("name", tamlNamedObjectName); - pNameAttributeElement->SetAttribute("type", "xs:normalizedString"); - pFieldAttributeGroupElement->LinkEndChild(pNameAttributeElement); - - // Add Taml "TamlId" attribute element. - tinyxml2::XMLElement* pTamlIdAttributeElement = schemaDocument.NewElement("xs:attribute"); - pTamlIdAttributeElement->SetAttribute("name", tamlRefIdName); - pTamlIdAttributeElement->SetAttribute("type", "xs:nonNegativeInteger"); - pFieldAttributeGroupElement->LinkEndChild(pTamlIdAttributeElement); - - // Add Taml "TamlRefId" attribute element. - tinyxml2::XMLElement* pTamlRefIdAttributeElement = schemaDocument.NewElement("xs:attribute"); - pTamlRefIdAttributeElement->SetAttribute("name", tamlRefToIdName); - pTamlRefIdAttributeElement->SetAttribute("type", "xs:nonNegativeInteger"); - pFieldAttributeGroupElement->LinkEndChild(pTamlRefIdAttributeElement); - } - - // Add attribute group types. - for (AbstractClassRep* pAttributeGroupsType = pType; pAttributeGroupsType != NULL; pAttributeGroupsType = pAttributeGroupsType->getParentClass()) - { - tinyxml2::XMLElement* pFieldAttributeGroupRefElement = schemaDocument.NewElement("xs:attributeGroup"); - dSprintf(buffer, sizeof(buffer), "%s_Fields", pAttributeGroupsType->getClassName()); - pFieldAttributeGroupRefElement->SetAttribute("ref", buffer); - pComplexTypeElement->LinkEndChild(pFieldAttributeGroupRefElement); - } - - // Add "any" attribute element (dynamic fields). - tinyxml2::XMLElement* pAnyAttributeElement = schemaDocument.NewElement("xs:anyAttribute"); - pAnyAttributeElement->SetAttribute("processContents", "skip"); - pComplexTypeElement->LinkEndChild(pAnyAttributeElement); - } - - // Write the schema document. - schemaDocument.SaveFile(filePathBuffer); - - // Close file. - stream.close(); - - return true; } - //----------------------------------------------------------------------------- + // Expand the file-name into the file-path buffer. + char filePathBuffer[1024]; + Con::expandToolScriptFilename(filePathBuffer, sizeof(filePathBuffer), pTamlSchemaFile); - void Taml::WriteUnrestrictedCustomTamlSchema(const char* pCustomNodeName, const AbstractClassRep* pClassRep, tinyxml2::XMLElement* pParentElement) + FileStream stream; + + // File opened? + /*if ( !stream.open( filePathBuffer, Torque::FS::File::Write ) ) { - // Sanity! - AssertFatal(pCustomNodeName != NULL, "Taml::WriteDefaultCustomTamlSchema() - Node name cannot be NULL."); - AssertFatal(pClassRep != NULL, "Taml::WriteDefaultCustomTamlSchema() - ClassRep cannot be NULL."); - AssertFatal(pParentElement != NULL, "Taml::WriteDefaultCustomTamlSchema() - Parent Element cannot be NULL."); + // No, so warn. + Con::warnf("Taml::GenerateTamlSchema() - Could not open filename '%s' for write.", filePathBuffer ); + return false; + }*/ - tinyxml2::XMLDocument* doc = pParentElement->GetDocument(); + // Create document. + tinyxml2::XMLDocument schemaDocument; - char buffer[1024]; + // Add declaration. + tinyxml2::XMLDeclaration* schemaDeclaration = schemaDocument.NewDeclaration("xml version=\"1.0\" encoding=\"iso-8859-1\" standalone =\"no\""); + schemaDocument.InsertEndChild(schemaDeclaration); - // Add custom type element. - tinyxml2::XMLElement* pCustomElement = doc->NewElement("xs:element"); - dSprintf(buffer, sizeof(buffer), "%s.%s", pClassRep->getClassName(), pCustomNodeName); - pCustomElement->SetAttribute("name", buffer); - pCustomElement->SetAttribute("minOccurs", 0); - pCustomElement->SetAttribute("maxOccurs", 1); - pParentElement->LinkEndChild(pCustomElement); + // Add schema element. + tinyxml2::XMLElement* pSchemaElement = schemaDocument.NewElement("xs:schema"); + pSchemaElement->SetAttribute("xmlns:xs", "http://www.w3.org/2001/XMLSchema"); + schemaDocument.LinkEndChild(pSchemaElement); - // Add complex type element. - tinyxml2::XMLElement* pComplexTypeElement = doc->NewElement("xs:complexType"); - pCustomElement->LinkEndChild(pComplexTypeElement); + // Fetch class-rep root. + AbstractClassRep* pRootType = AbstractClassRep::getClassList(); - // Add choice element. - tinyxml2::XMLElement* pChoiceElement = doc->NewElement("xs:choice"); - pChoiceElement->SetAttribute("minOccurs", 0); - pChoiceElement->SetAttribute("maxOccurs", "unbounded"); - pComplexTypeElement->LinkEndChild(pChoiceElement); + // Fetch SimObject class rep. + AbstractClassRep* pSimObjectType = AbstractClassRep::findClassRep("SimObject"); + // Sanity! + AssertFatal(pSimObjectType != NULL, "Taml::GenerateTamlSchema() - Could not find SimObject class rep."); - // Add sequence element. - tinyxml2::XMLElement* pSequenceElement = doc->NewElement("xs:sequence"); - pChoiceElement->LinkEndChild(pSequenceElement); + // Reset scratch state. + char buffer[1024]; + HashTable childGroups; - // Add "any" element. - tinyxml2::XMLElement* pAnyElement = doc->NewElement("xs:any"); - pAnyElement->SetAttribute("processContents", "skip"); - pSequenceElement->LinkEndChild(pAnyElement); + // ************************************************************* + // Generate console type elements. + // ************************************************************* + + // Vector2. + tinyxml2::XMLComment* pVector2Comment = schemaDocument.NewComment("Vector2 Console Type"); + pSchemaElement->LinkEndChild(pVector2Comment); + tinyxml2::XMLElement* pVector2TypeElement = schemaDocument.NewElement("xs:simpleType"); + pVector2TypeElement->SetAttribute("name", "Vector2_ConsoleType"); + pSchemaElement->LinkEndChild(pVector2TypeElement); + tinyxml2::XMLElement* pVector2ElementA = schemaDocument.NewElement("xs:restriction"); + pVector2ElementA->SetAttribute("base", "xs:string"); + pVector2TypeElement->LinkEndChild(pVector2ElementA); + tinyxml2::XMLElement* pVector2ElementB = schemaDocument.NewElement("xs:pattern"); + pVector2ElementB->SetAttribute("value", "([-]?(\\b[0-9]+)?\\.)?[0-9]+\\b ([-]?(\\b[0-9]+)?\\.)?[0-9]+\\b"); + pVector2ElementA->LinkEndChild(pVector2ElementB); + + // Point2F. + tinyxml2::XMLComment* pPoint2FComment = schemaDocument.NewComment("Point2F Console Type"); + pSchemaElement->LinkEndChild(pPoint2FComment); + tinyxml2::XMLElement* pPoint2FTypeElement = schemaDocument.NewElement("xs:simpleType"); + pPoint2FTypeElement->SetAttribute("name", "Point2F_ConsoleType"); + pSchemaElement->LinkEndChild(pPoint2FTypeElement); + tinyxml2::XMLElement* pPoint2FElementA = schemaDocument.NewElement("xs:restriction"); + pPoint2FElementA->SetAttribute("base", "xs:string"); + pPoint2FTypeElement->LinkEndChild(pPoint2FElementA); + tinyxml2::XMLElement* pPoint2FElementB = schemaDocument.NewElement("xs:pattern"); + pPoint2FElementB->SetAttribute("value", "([-]?(\\b[0-9]+)?\\.)?[0-9]+\\b ([-]?(\\b[0-9]+)?\\.)?[0-9]+\\b"); + pPoint2FElementA->LinkEndChild(pPoint2FElementB); + + // Point2I. + tinyxml2::XMLComment* pPoint2IComment = schemaDocument.NewComment("Point2I Console Type"); + pSchemaElement->LinkEndChild(pPoint2IComment); + tinyxml2::XMLElement* pPoint2ITypeElement = schemaDocument.NewElement("xs:simpleType"); + pPoint2ITypeElement->SetAttribute("name", "Point2I_ConsoleType"); + pSchemaElement->LinkEndChild(pPoint2ITypeElement); + tinyxml2::XMLElement* pPoint2IElementA = schemaDocument.NewElement("xs:restriction"); + pPoint2IElementA->SetAttribute("base", "xs:string"); + pPoint2ITypeElement->LinkEndChild(pPoint2IElementA); + tinyxml2::XMLElement* pPoint2IElementB = schemaDocument.NewElement("xs:pattern"); + pPoint2IElementB->SetAttribute("value", "[-]?[0-9]* [-]?[0-9]*"); + pPoint2IElementA->LinkEndChild(pPoint2IElementB); + + // b2AABB. + tinyxml2::XMLComment* pb2AABBComment = schemaDocument.NewComment("b2AABB Console Type"); + pSchemaElement->LinkEndChild(pb2AABBComment); + tinyxml2::XMLElement* pb2AABBTypeElement = schemaDocument.NewElement("xs:simpleType"); + pb2AABBTypeElement->SetAttribute("name", "b2AABB_ConsoleType"); + pSchemaElement->LinkEndChild(pb2AABBTypeElement); + tinyxml2::XMLElement* pb2AABBElementA = schemaDocument.NewElement("xs:restriction"); + pb2AABBElementA->SetAttribute("base", "xs:string"); + pb2AABBTypeElement->LinkEndChild(pb2AABBElementA); + tinyxml2::XMLElement* pb2AABBElementB = schemaDocument.NewElement("xs:pattern"); + 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"); + pb2AABBElementA->LinkEndChild(pb2AABBElementB); + + // RectI. + tinyxml2::XMLComment* pRectIComment = schemaDocument.NewComment("RectI Console Type"); + pSchemaElement->LinkEndChild(pRectIComment); + tinyxml2::XMLElement* pRectITypeElement = schemaDocument.NewElement("xs:simpleType"); + pRectITypeElement->SetAttribute("name", "RectI_ConsoleType"); + pSchemaElement->LinkEndChild(pRectITypeElement); + tinyxml2::XMLElement* pRectIElementA = schemaDocument.NewElement("xs:restriction"); + pRectIElementA->SetAttribute("base", "xs:string"); + pRectITypeElement->LinkEndChild(pRectIElementA); + tinyxml2::XMLElement* pRectIElementB = schemaDocument.NewElement("xs:pattern"); + pRectIElementB->SetAttribute("value", "[-]?[0-9]* [-]?[0-9]* [-]?[0-9]* [-]?[0-9]*"); + pRectIElementA->LinkEndChild(pRectIElementB); + + // RectF. + tinyxml2::XMLComment* pRectFComment = schemaDocument.NewComment("RectF Console Type"); + pSchemaElement->LinkEndChild(pRectFComment); + tinyxml2::XMLElement* pRectFTypeElement = schemaDocument.NewElement("xs:simpleType"); + pRectFTypeElement->SetAttribute("name", "RectF_ConsoleType"); + pSchemaElement->LinkEndChild(pRectFTypeElement); + tinyxml2::XMLElement* pRectFElementA = schemaDocument.NewElement("xs:restriction"); + pRectFElementA->SetAttribute("base", "xs:string"); + pRectFTypeElement->LinkEndChild(pRectFElementA); + tinyxml2::XMLElement* pRectFElementB = schemaDocument.NewElement("xs:pattern"); + pRectFElementB->SetAttribute("value", "(\\b[-]?(b[0-9]+)?\\.)?[0-9]+\\b"); + pRectFElementA->LinkEndChild(pRectFElementB); + + // AssetId. + tinyxml2::XMLComment* pAssetIdComment = schemaDocument.NewComment("AssetId Console Type"); + pSchemaElement->LinkEndChild(pAssetIdComment); + tinyxml2::XMLElement* pAssetIdTypeElement = schemaDocument.NewElement("xs:simpleType"); + pAssetIdTypeElement->SetAttribute("name", "AssetId_ConsoleType"); + pSchemaElement->LinkEndChild(pAssetIdTypeElement); + tinyxml2::XMLElement* pAssetIdElementA = schemaDocument.NewElement("xs:restriction"); + pAssetIdElementA->SetAttribute("base", "xs:string"); + pAssetIdTypeElement->LinkEndChild(pAssetIdElementA); + tinyxml2::XMLElement* pAssetIdElementB = schemaDocument.NewElement("xs:pattern"); + 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); + pAssetIdElementB->SetAttribute("value", buffer); + pAssetIdElementA->LinkEndChild(pAssetIdElementB); + + // Color Enums. + tinyxml2::XMLComment* pColorEnumsComment = schemaDocument.NewComment("Color Enums"); + pSchemaElement->LinkEndChild(pColorEnumsComment); + tinyxml2::XMLElement* pColorEnumsTypeElement = schemaDocument.NewElement("xs:simpleType"); + pColorEnumsTypeElement->SetAttribute("name", "Color_Enums"); + pSchemaElement->LinkEndChild(pColorEnumsTypeElement); + tinyxml2::XMLElement* pColorEnumsRestrictionElement = schemaDocument.NewElement("xs:restriction"); + pColorEnumsRestrictionElement->SetAttribute("base", "xs:string"); + pColorEnumsTypeElement->LinkEndChild(pColorEnumsRestrictionElement); + const S32 ColorEnumsCount = StockColor::getCount(); + for (S32 index = 0; index < ColorEnumsCount; ++index) + { + // Add enumeration element. + tinyxml2::XMLElement* pColorEnumsAttributeEnumerationElement = schemaDocument.NewElement("xs:enumeration"); + pColorEnumsAttributeEnumerationElement->SetAttribute("value", StockColor::getColorItem(index)->getColorName()); + pColorEnumsRestrictionElement->LinkEndChild(pColorEnumsAttributeEnumerationElement); } + + // LinearColorF. + tinyxml2::XMLComment* pColorFValuesComment = schemaDocument.NewComment("LinearColorF Values"); + pSchemaElement->LinkEndChild(pColorFValuesComment); + tinyxml2::XMLElement* pColorFValuesTypeElement = schemaDocument.NewElement("xs:simpleType"); + pColorFValuesTypeElement->SetAttribute("name", "ColorF_Values"); + pSchemaElement->LinkEndChild(pColorFValuesTypeElement); + tinyxml2::XMLElement* pColorFValuesElementA = schemaDocument.NewElement("xs:restriction"); + pColorFValuesElementA->SetAttribute("base", "xs:string"); + pColorFValuesTypeElement->LinkEndChild(pColorFValuesElementA); + tinyxml2::XMLElement* pColorFValuesElementB = schemaDocument.NewElement("xs:pattern"); + 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"); + pColorFValuesElementA->LinkEndChild(pColorFValuesElementB); + + tinyxml2::XMLComment* pColorFComment = schemaDocument.NewComment("LinearColorF Console Type"); + pSchemaElement->LinkEndChild(pColorFComment); + tinyxml2::XMLElement* pColorFTypeElement = schemaDocument.NewElement("xs:simpleType"); + pColorFTypeElement->SetAttribute("name", "ColorF_ConsoleType"); + pSchemaElement->LinkEndChild(pColorFTypeElement); + tinyxml2::XMLElement* pColorFUnionElement = schemaDocument.NewElement("xs:union"); + pColorFUnionElement->SetAttribute("memberTypes", "ColorF_Values Color_Enums"); + pColorFTypeElement->LinkEndChild(pColorFUnionElement); + + // ColorI. + tinyxml2::XMLComment* pColorIValuesComment = schemaDocument.NewComment("ColorI Values"); + pSchemaElement->LinkEndChild(pColorIValuesComment); + tinyxml2::XMLElement* pColorIValuesTypeElement = schemaDocument.NewElement("xs:simpleType"); + pColorIValuesTypeElement->SetAttribute("name", "ColorI_Values"); + pSchemaElement->LinkEndChild(pColorIValuesTypeElement); + tinyxml2::XMLElement* pColorIValuesElementA = schemaDocument.NewElement("xs:restriction"); + pColorIValuesElementA->SetAttribute("base", "xs:string"); + pColorIValuesTypeElement->LinkEndChild(pColorIValuesElementA); + tinyxml2::XMLElement* pColorIValuesElementB = schemaDocument.NewElement("xs:pattern"); + pColorIValuesElementB->SetAttribute("value", "[-]?[0-9]* [-]?[0-9]* [-]?[0-9]* [-]?[0-9]*"); + pColorIValuesElementA->LinkEndChild(pColorIValuesElementB); + + tinyxml2::XMLComment* pColorIComment = schemaDocument.NewComment("ColorI Console Type"); + pSchemaElement->LinkEndChild(pColorIComment); + tinyxml2::XMLElement* pColorITypeElement = schemaDocument.NewElement("xs:simpleType"); + pColorITypeElement->SetAttribute("name", "ColorI_ConsoleType"); + pSchemaElement->LinkEndChild(pColorITypeElement); + tinyxml2::XMLElement* pColorIUnionElement = schemaDocument.NewElement("xs:union"); + pColorIUnionElement->SetAttribute("memberTypes", "ColorI_Values Color_Enums"); + pColorITypeElement->LinkEndChild(pColorIUnionElement); + + // ************************************************************* + // Generate engine type elements. + // ************************************************************* + + // Generate the engine type elements. + tinyxml2::XMLComment* tComment = schemaDocument.NewComment("Type Elements"); + pSchemaElement->LinkEndChild(tComment); + for (AbstractClassRep* pType = pRootType; pType != NULL; pType = pType->getNextClass()) + { + // Add type. + tinyxml2::XMLElement* pTypeElement = schemaDocument.NewElement("xs:element"); + pTypeElement->SetAttribute("name", pType->getClassName()); + dSprintf(buffer, sizeof(buffer), "%s_Type", pType->getClassName()); + pTypeElement->SetAttribute("type", buffer); + pSchemaElement->LinkEndChild(pTypeElement); + } + + // ************************************************************* + // Generate the engine complex types. + // ************************************************************* + for (AbstractClassRep* pType = pRootType; pType != NULL; pType = pType->getNextClass()) + { + // Add complex type comment. + dSprintf(buffer, sizeof(buffer), " %s Type ", pType->getClassName()); + tinyxml2::XMLComment* ctComment = schemaDocument.NewComment(buffer); + pSchemaElement->LinkEndChild(ctComment); + + // Add complex type. + tinyxml2::XMLElement* pComplexTypeElement = schemaDocument.NewElement("xs:complexType"); + dSprintf(buffer, sizeof(buffer), "%s_Type", pType->getClassName()); + pComplexTypeElement->SetAttribute("name", buffer); + pSchemaElement->LinkEndChild(pComplexTypeElement); + + // Add sequence. + tinyxml2::XMLElement* pAllElement = schemaDocument.NewElement("xs:all"); + pComplexTypeElement->LinkEndChild(pAllElement); + + // Fetch container child class. + AbstractClassRep* pContainerChildClass = pType->getContainerChildClass(true); + + // Is the type allowed children? + if (pContainerChildClass != NULL) + { + // Yes, so add choice element. + tinyxml2::XMLElement* pChoiceElement = schemaDocument.NewElement("xs:choice"); + pChoiceElement->SetAttribute("minOccurs", 0); + pChoiceElement->SetAttribute("maxOccurs", "unbounded"); + pAllElement->LinkEndChild(pChoiceElement); + + // Find child group. + HashTable::Iterator childGroupItr = childGroups.find(pContainerChildClass); + + // Does the group exist? + if (childGroupItr == childGroups.end()) + { + // No, so format group name. + dSprintf(buffer, sizeof(buffer), "%s_ChildrenTypes", pContainerChildClass->getClassName()); + + // Insert into child group hash. + childGroupItr = childGroups.insertUnique(pContainerChildClass, StringTable->insert(buffer)); + + // Add the group. + tinyxml2::XMLElement* pChildrenGroupElement = schemaDocument.NewElement("xs:group"); + pChildrenGroupElement->SetAttribute("name", buffer); + pSchemaElement->LinkEndChild(pChildrenGroupElement); + + // Add choice element. + tinyxml2::XMLElement* pChildreGroupChoiceElement = schemaDocument.NewElement("xs:choice"); + pChildrenGroupElement->LinkEndChild(pChildreGroupChoiceElement); + + // Add choice members. + for (AbstractClassRep* pChoiceType = pRootType; pChoiceType != NULL; pChoiceType = pChoiceType->getNextClass()) + { + // Skip if not derived from the container child class. + if (!pChoiceType->isClass(pContainerChildClass)) + continue; + + // Add choice member. + tinyxml2::XMLElement* pChildrenMemberElement = schemaDocument.NewElement("xs:element"); + pChildrenMemberElement->SetAttribute("name", pChoiceType->getClassName()); + dSprintf(buffer, sizeof(buffer), "%s_Type", pChoiceType->getClassName()); + pChildrenMemberElement->SetAttribute("type", buffer); + pChildreGroupChoiceElement->LinkEndChild(pChildrenMemberElement); + } + + } + + // Reference the child group. + tinyxml2::XMLElement* pChoiceGroupReferenceElement = schemaDocument.NewElement("xs:group"); + pChoiceGroupReferenceElement->SetAttribute("ref", childGroupItr->value); + pChoiceGroupReferenceElement->SetAttribute("minOccurs", 0); + pChoiceElement->LinkEndChild(pChoiceGroupReferenceElement); + } + + // Generate the custom Taml schema. + for (AbstractClassRep* pCustomSchemaType = pType; pCustomSchemaType != NULL; pCustomSchemaType = pCustomSchemaType->getParentClass()) + { + // Fetch the types custom TAML schema function. + AbstractClassRep::WriteCustomTamlSchema customSchemaFn = pCustomSchemaType->getCustomTamlSchema(); + + // Skip if no function avilable. + if (customSchemaFn == NULL) + continue; + + // Call schema generation function. + customSchemaFn(pType, pAllElement); + } + + // Fetch field list. + const AbstractClassRep::FieldList& fields = pType->mFieldList; + + // Fetch field count. + const S32 fieldCount = fields.size(); + + // Generate array attribute groups + for (S32 index = 0; index < fieldCount; ++index) + { + // Fetch field. + const AbstractClassRep::Field& field = fields[index]; + + if (field.type == AbstractClassRep::StartArrayFieldType) + { + // Add the top-level array identifier + tinyxml2::XMLElement* pArrayElement = schemaDocument.NewElement("xs:element"); + dSprintf(buffer, sizeof(buffer), "%s.%s", pType->getClassName(), g_sanitize_schema_element_name(field.pGroupname).c_str()); + pArrayElement->SetAttribute("name", buffer); + pArrayElement->SetAttribute("minOccurs", 0); + pAllElement->LinkEndChild(pArrayElement); + + // Inline type specification + tinyxml2::XMLElement* pArrayComplexTypeElement = schemaDocument.NewElement("xs:complexType"); + pArrayElement->LinkEndChild(pArrayComplexTypeElement); + + // Add the actual (repeating) array elements + tinyxml2::XMLElement* pInnerArrayElement = schemaDocument.NewElement("xs:element"); + pInnerArrayElement->SetAttribute("name", g_sanitize_schema_element_name(field.pFieldname).c_str()); + pInnerArrayElement->SetAttribute("minOccurs", 0); + pInnerArrayElement->SetAttribute("maxOccurs", field.elementCount); + pArrayComplexTypeElement->LinkEndChild(pInnerArrayElement); + + // Inline type specification + tinyxml2::XMLElement* pInnerComplexTypeElement = schemaDocument.NewElement("xs:complexType"); + pInnerArrayElement->LinkEndChild(pInnerComplexTypeElement); + + // Add a reference to the attribute group for the array + tinyxml2::XMLElement* pInnerAttributeGroupElement = schemaDocument.NewElement("xs:attributeGroup"); + dSprintf(buffer, sizeof(buffer), "%s_%s_Array_Fields", pType->getClassName(), g_sanitize_schema_element_name(field.pFieldname).c_str()); + pInnerAttributeGroupElement->SetAttribute("ref", buffer); + pInnerComplexTypeElement->LinkEndChild(pInnerAttributeGroupElement); + + // Add the attribute group itself + tinyxml2::XMLElement* pFieldAttributeGroupElement = schemaDocument.NewElement("xs:attributeGroup"); + pFieldAttributeGroupElement->SetAttribute("name", buffer); + pSchemaElement->LinkEndChild(pFieldAttributeGroupElement); + + // Keep adding fields to attribute group until we hit the end of the array + for (; index < fieldCount; ++index) + { + const AbstractClassRep::Field& array_field = fields[index]; + if (array_field.type == AbstractClassRep::EndArrayFieldType) + { + break; + } + + tinyxml2::XMLElement* pAttributeElement = g__write_schema_attribute_element(array_field, pType, schemaDocument); + if (pAttributeElement == NULL) + { + continue; + } + + pFieldAttributeGroupElement->LinkEndChild(pAttributeElement); + } + } + } + + // Generate field attribute group. + tinyxml2::XMLElement* pFieldAttributeGroupElement = schemaDocument.NewElement("xs:attributeGroup"); + dSprintf(buffer, sizeof(buffer), "%s_Fields", pType->getClassName()); + pFieldAttributeGroupElement->SetAttribute("name", buffer); + pSchemaElement->LinkEndChild(pFieldAttributeGroupElement); + + // Iterate static fields (in reverse as most types are organized from the root-fields up). + for (S32 index = fieldCount - 1; index > 0; --index) + { + // Fetch field. + const AbstractClassRep::Field& field = fields[index]; + + // Skip fields inside arrays + if (field.type == AbstractClassRep::EndArrayFieldType) + { + for (; index > 0; --index) + { + if (field.type == AbstractClassRep::StartArrayFieldType) + { + break; + } + } + continue; + } + + tinyxml2::XMLElement* pAttributeElement = g__write_schema_attribute_element(field, pType, schemaDocument); + if (pAttributeElement == NULL) + { + continue; + } + + pFieldAttributeGroupElement->LinkEndChild(pAttributeElement); + } + + // Is this the SimObject Type? + if (pType == pSimObjectType) + { + // Yes, so add reserved Taml field attributes here... + + // Add Taml "Name" attribute element. + tinyxml2::XMLElement* pNameAttributeElement = schemaDocument.NewElement("xs:attribute"); + pNameAttributeElement->SetAttribute("name", tamlNamedObjectName); + pNameAttributeElement->SetAttribute("type", "xs:normalizedString"); + pFieldAttributeGroupElement->LinkEndChild(pNameAttributeElement); + + // Add Taml "TamlId" attribute element. + tinyxml2::XMLElement* pTamlIdAttributeElement = schemaDocument.NewElement("xs:attribute"); + pTamlIdAttributeElement->SetAttribute("name", tamlRefIdName); + pTamlIdAttributeElement->SetAttribute("type", "xs:nonNegativeInteger"); + pFieldAttributeGroupElement->LinkEndChild(pTamlIdAttributeElement); + + // Add Taml "TamlRefId" attribute element. + tinyxml2::XMLElement* pTamlRefIdAttributeElement = schemaDocument.NewElement("xs:attribute"); + pTamlRefIdAttributeElement->SetAttribute("name", tamlRefToIdName); + pTamlRefIdAttributeElement->SetAttribute("type", "xs:nonNegativeInteger"); + pFieldAttributeGroupElement->LinkEndChild(pTamlRefIdAttributeElement); + } + + // Add attribute group types. + for (AbstractClassRep* pAttributeGroupsType = pType; pAttributeGroupsType != NULL; pAttributeGroupsType = pAttributeGroupsType->getParentClass()) + { + tinyxml2::XMLElement* pFieldAttributeGroupRefElement = schemaDocument.NewElement("xs:attributeGroup"); + dSprintf(buffer, sizeof(buffer), "%s_Fields", pAttributeGroupsType->getClassName()); + pFieldAttributeGroupRefElement->SetAttribute("ref", buffer); + pComplexTypeElement->LinkEndChild(pFieldAttributeGroupRefElement); + } + + // Add "any" attribute element (dynamic fields). + tinyxml2::XMLElement* pAnyAttributeElement = schemaDocument.NewElement("xs:anyAttribute"); + pAnyAttributeElement->SetAttribute("processContents", "skip"); + pComplexTypeElement->LinkEndChild(pAnyAttributeElement); + } + + // Write the schema document. + schemaDocument.SaveFile(filePathBuffer); + + // Close file. + stream.close(); + + return true; +} + +//----------------------------------------------------------------------------- + +void Taml::WriteUnrestrictedCustomTamlSchema(const char* pCustomNodeName, const AbstractClassRep* pClassRep, tinyxml2::XMLElement* pParentElement) +{ + // Sanity! + AssertFatal(pCustomNodeName != NULL, "Taml::WriteDefaultCustomTamlSchema() - Node name cannot be NULL."); + AssertFatal(pClassRep != NULL, "Taml::WriteDefaultCustomTamlSchema() - ClassRep cannot be NULL."); + AssertFatal(pParentElement != NULL, "Taml::WriteDefaultCustomTamlSchema() - Parent Element cannot be NULL."); + + tinyxml2::XMLDocument* doc = pParentElement->GetDocument(); + + char buffer[1024]; + + // Add custom type element. + tinyxml2::XMLElement* pCustomElement = doc->NewElement("xs:element"); + dSprintf(buffer, sizeof(buffer), "%s.%s", pClassRep->getClassName(), pCustomNodeName); + pCustomElement->SetAttribute("name", buffer); + pCustomElement->SetAttribute("minOccurs", 0); + pCustomElement->SetAttribute("maxOccurs", 1); + pParentElement->LinkEndChild(pCustomElement); + + // Add complex type element. + tinyxml2::XMLElement* pComplexTypeElement = doc->NewElement("xs:complexType"); + pCustomElement->LinkEndChild(pComplexTypeElement); + + // Add choice element. + tinyxml2::XMLElement* pChoiceElement = doc->NewElement("xs:choice"); + pChoiceElement->SetAttribute("minOccurs", 0); + pChoiceElement->SetAttribute("maxOccurs", "unbounded"); + pComplexTypeElement->LinkEndChild(pChoiceElement); + + // Add sequence element. + tinyxml2::XMLElement* pSequenceElement = doc->NewElement("xs:sequence"); + pChoiceElement->LinkEndChild(pSequenceElement); + + // Add "any" element. + tinyxml2::XMLElement* pAnyElement = doc->NewElement("xs:any"); + pAnyElement->SetAttribute("processContents", "skip"); + pSequenceElement->LinkEndChild(pAnyElement); +} diff --git a/Engine/source/persistence/taml/taml_ScriptBinding.h b/Engine/source/persistence/taml/taml_ScriptBinding.h index 841fadb8f..65ffd7313 100644 --- a/Engine/source/persistence/taml/taml_ScriptBinding.h +++ b/Engine/source/persistence/taml/taml_ScriptBinding.h @@ -235,37 +235,36 @@ DefineEngineFunction(TamlWrite, bool, (SimObject* simObject, const char* filenam "@return Whether the write was successful or not.") { - // Did we find the object? - if ( simObject == NULL ) - { - // No, so warn. - //Con::warnf( "TamlWrite() - Could not find object '%s' to write to file '%s'.", simObject->getIdString(), filename ); - Con::warnf( "TamlWrite() - Could not find object to write to file '%s'.", filename ); - return false; - } + // Did we find the object? + if ( simObject == NULL ) + { + // No, so warn. + Con::warnf( "TamlWrite() - Could not find object to write to file '%s'.", filename ); + return false; + } - Taml taml; + Taml taml; - taml.setFormatMode( Taml::getFormatModeEnum(format) ); + taml.setFormatMode( Taml::getFormatModeEnum(format) ); // Yes, so is the format mode binary? if ( taml.getFormatMode() == Taml::BinaryFormat ) { - // Yes, so set binary compression. + // Yes, so set binary compression. taml.setBinaryCompression( compressed ); } else { -#ifdef TORQUE_DEBUG + #ifdef TORQUE_DEBUG // No, so warn. Con::warnf( "TamlWrite() - Setting binary compression is only valid for XML formatting." ); -#endif + #endif } // Turn-off auto-formatting. taml.setAutoFormat( false ); - // Write. + // Write. return taml.write( simObject, filename ); } @@ -277,27 +276,27 @@ DefineEngineFunction(TamlRead, const char*, (const char* filename, const char* f "@return (Object) The object read from the file or an empty string if read failed.") { - // Set the format mode. - Taml taml; + // Set the format mode. + Taml taml; - // Yes, so set it. - taml.setFormatMode( Taml::getFormatModeEnum(format) ); + // Yes, so set it. + taml.setFormatMode( Taml::getFormatModeEnum(format) ); - // Turn-off auto-formatting. - taml.setAutoFormat( false ); + // Turn-off auto-formatting. + taml.setAutoFormat( false ); - // Read object. + // Read object. SimObject* pSimObject = taml.read( filename ); - // Did we find the object? - if ( pSimObject == NULL ) - { - // No, so warn. - Con::warnf( "TamlRead() - Could not read object from file '%s'.", filename ); - return StringTable->EmptyString(); - } + // Did we find the object? + if ( pSimObject == NULL ) + { + // No, so warn. + Con::warnf( "TamlRead() - Could not read object from file '%s'.", filename ); + return StringTable->EmptyString(); + } - return pSimObject->getIdString(); + return pSimObject->getIdString(); } //----------------------------------------------------------------------------- @@ -306,8 +305,8 @@ DefineEngineFunction(GenerateTamlSchema, bool, (), , "() - Generate a TAML schem "The schema file is specified using the console variable '" TAML_SCHEMA_VARIABLE "'.\n" "@return Whether the schema file was writtent or not." ) { - // Generate the schema. - return Taml::generateTamlSchema(); + // Generate the schema. + return Taml::generateTamlSchema(); } #endif //_TAML_SCRIPTBINDING_H