Initial Implementation of the Taml, Asset and Modules systems.

Only has example and shape assets currently.
This commit is contained in:
Areloch 2015-10-13 15:19:36 -05:00
parent 2044b2691e
commit 7a3b40a86d
123 changed files with 30435 additions and 181 deletions

View file

@ -0,0 +1,258 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2013 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "persistence/taml/json/tamlJSONParser.h"
#include "persistence/taml/tamlVisitor.h"
#include "console/console.h"
#include "core/stream/fileStream.h"
#include "core/frameAllocator.h"
// Debug Profiling.
#include "platform/profiler.h"
//-----------------------------------------------------------------------------
bool TamlJSONParser::accept( const char* pFilename, TamlVisitor& visitor )
{
// Debug Profiling.
PROFILE_SCOPE(TamlJSONParser_Accept);
// Sanity!
AssertFatal( pFilename != NULL, "Cannot parse a NULL filename." );
// Expand the file-path.
char filenameBuffer[1024];
Con::expandToolScriptFilename( filenameBuffer, sizeof(filenameBuffer), pFilename );
FileStream stream;
// File open for read?
if ( !stream.open( filenameBuffer, Torque::FS::File::Write ) )
{
// No, so warn.
Con::warnf("TamlJSONParser::parse() - Could not open filename '%s' for parse.", filenameBuffer );
return false;
}
// Read JSON file.
const U32 streamSize = stream.getStreamSize();
FrameTemp<char> jsonText( streamSize + 1 );
if ( !stream.read( streamSize, jsonText ) )
{
// Warn!
Con::warnf("TamlJSONParser::parse() - Could not load Taml JSON file from stream.");
return false;
}
// Create JSON document.
rapidjson::Document inputDocument;
inputDocument.Parse<0>( jsonText );
// Close the stream.
stream.close();
// Check the document is valid.
if ( inputDocument.GetType() != rapidjson::kObjectType )
{
// Warn!
Con::warnf("TamlJSONParser::parse() - Load Taml JSON file from stream but was invalid.");
return false;
}
// Set parsing filename.
setParsingFilename( filenameBuffer );
// Flag document as not dirty.
mDocumentDirty = false;
// Fetch the root.
rapidjson::Value::MemberIterator rootItr = inputDocument.MemberBegin();
// Parse root value.
parseType( rootItr, visitor, true );
// Reset parsing filename.
setParsingFilename( StringTable->EmptyString() );
// Finish if the document is not dirty.
if ( !mDocumentDirty )
return true;
// Open for write?
if ( !stream.open( filenameBuffer, Torque::FS::File::Write ) )
{
// No, so warn.
Con::warnf("TamlJSONParser::parse() - Could not open filename '%s' for write.", filenameBuffer );
return false;
}
// Create output document.
rapidjson::Document outputDocument;
outputDocument.AddMember( rootItr->name, rootItr->value, outputDocument.GetAllocator() );
// Write document to stream.
rapidjson::PrettyWriter<FileStream> jsonStreamWriter( stream );
outputDocument.Accept( jsonStreamWriter );
// Close the stream.
stream.close();
return true;
}
//-----------------------------------------------------------------------------
inline bool TamlJSONParser::parseType( rapidjson::Value::MemberIterator& memberItr, TamlVisitor& visitor, const bool isRoot )
{
// Debug Profiling.
PROFILE_SCOPE(TamlJSONParser_ParseType);
// Fetch name and value.
const rapidjson::Value& typeName = memberItr->name;
rapidjson::Value& typeValue = memberItr->value;
// Create a visitor property state.
TamlVisitor::PropertyState propertyState;
propertyState.setObjectName( typeName.GetString(), isRoot );
// Parse field members.
for( rapidjson::Value::MemberIterator fieldMemberItr = typeValue.MemberBegin(); fieldMemberItr != typeValue.MemberEnd(); ++fieldMemberItr )
{
// Fetch value.
const rapidjson::Value& fieldName = fieldMemberItr->name;
rapidjson::Value& fieldValue = fieldMemberItr->value;
// Skip if not a field.
if ( fieldValue.IsObject() )
continue;
char valueBuffer[4096];
if ( !parseStringValue( valueBuffer, sizeof(valueBuffer), fieldValue, fieldName.GetString() ) )
{
// Warn.
Con::warnf( "TamlJSONParser::parseTyoe() - Could not interpret value for field '%s'", fieldName.GetString() );
continue;
}
// Configure property state.
propertyState.setProperty( fieldName.GetString(), valueBuffer );
// Visit this attribute.
const bool visitStatus = visitor.visit( *this, propertyState );
// Was the property value changed?
if ( propertyState.getPropertyValueDirty() )
{
// Yes, so update the attribute.
fieldValue.SetString( propertyState.getPropertyValue() );
// Flag the document as dirty.
mDocumentDirty = true;
}
// Finish if requested.
if ( !visitStatus )
return false;
}
// Finish if only the root is needed.
if ( visitor.wantsRootOnly() )
return false;
// Parse children and custom node members.
for( rapidjson::Value::MemberIterator objectMemberItr = typeValue.MemberBegin(); objectMemberItr != typeValue.MemberEnd(); ++objectMemberItr )
{
// Fetch name and value.
const rapidjson::Value& objectValue = objectMemberItr->value;
// Skip if not an object.
if ( !objectValue.IsObject() )
continue;
// Parse the type.
if ( !parseType( objectMemberItr, visitor, false ) )
return false;
}
return true;
}
//-----------------------------------------------------------------------------
inline bool TamlJSONParser::parseStringValue( char* pBuffer, const S32 bufferSize, const rapidjson::Value& value, const char* pName )
{
// Debug Profiling.
PROFILE_SCOPE(TamlJSONParser_ParseStringValue);
// Handle field value appropriately.
if ( value.IsString() )
{
dSprintf( pBuffer, bufferSize, "%s", value.GetString() );
return true;
}
if ( value.IsNumber() )
{
if ( value.IsInt() )
{
dSprintf( pBuffer, bufferSize, "%d", value.GetInt() );
return true;
}
if ( value.IsUint() )
{
dSprintf( pBuffer, bufferSize, "%d", value.GetUint() );
return true;
}
if ( value.IsInt64() )
{
dSprintf( pBuffer, bufferSize, "%d", value.GetInt64() );
return true;
}
if ( value.IsUint64() )
{
dSprintf( pBuffer, bufferSize, "%d", value.GetUint64() );
return true;
}
if ( value.IsDouble() )
{
dSprintf( pBuffer, bufferSize, "%f", value.GetDouble() );
return true;
}
}
if ( value.IsBool() )
{
dSprintf( pBuffer, bufferSize, "%d", value.GetBool() );
return true;
}
// Failed to get value type.
Con::warnf( "Taml: Encountered a field '%s' but its value is an unknown type.", pName );
return false;
}

View file

@ -0,0 +1,57 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2013 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef _TAML_JSONPARSER_H_
#define _TAML_JSONPARSER_H_
#ifndef _TAML_PARSER_H_
#include "persistence/taml/tamlParser.h"
#endif
/// RapidJson.
#include "persistence/rapidjson/document.h"
#include "persistence/rapidjson/prettywriter.h"
//-----------------------------------------------------------------------------
/// @ingroup tamlGroup
/// @see tamlGroup
class TamlJSONParser : public TamlParser
{
public:
TamlJSONParser() {}
virtual ~TamlJSONParser() {}
/// Whether the parser can change a property or not.
virtual bool canChangeProperty( void ) { return true; }
/// Accept visitor.
virtual bool accept( const char* pFilename, TamlVisitor& visitor );
private:
inline bool parseType( rapidjson::Value::MemberIterator& memberItr, TamlVisitor& visitor, const bool isRoot );
inline bool parseStringValue( char* pBuffer, const S32 bufferSize, const rapidjson::Value& value, const char* pName );
bool mDocumentDirty;
};
#endif // _TAML_JSONPARSER_H_

View file

@ -0,0 +1,686 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2013 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "persistence/taml/json/tamlJSONReader.h"
#include "persistence/taml/json/tamlJSONWriter.h"
#include "core/stream/fileStream.h"
#include "core/strings/stringUnit.h"
#include "core/frameAllocator.h"
// Debug Profiling.
#include "platform/profiler.h"
//-----------------------------------------------------------------------------
SimObject* TamlJSONReader::read( FileStream& stream )
{
// Debug Profiling.
PROFILE_SCOPE(TamlJSONReader_Read);
// Read JSON file.
const U32 streamSize = stream.getStreamSize();
FrameTemp<char> jsonText( streamSize + 1 );
if ( !stream.read( streamSize, jsonText ) )
{
// Warn!
Con::warnf("TamlJSONReader::read() - Could not load Taml JSON file from stream.");
return NULL;
}
jsonText[streamSize] = '\0';
// Create JSON document.
rapidjson::Document document;
document.Parse<0>( jsonText );
// Check the document is valid.
if ( document.GetType() != rapidjson::kObjectType )
{
// Warn!
Con::warnf("TamlJSONReader::read() - Load Taml JSON file from stream but was invalid.");
return NULL;
}
// Parse root value.
SimObject* pSimObject = parseType( document.MemberBegin() );
// Reset parse.
resetParse();
return pSimObject;
}
//-----------------------------------------------------------------------------
void TamlJSONReader::resetParse( void )
{
// Debug Profiling.
PROFILE_SCOPE(TamlJSONReader_ResetParse);
// Clear object reference map.
mObjectReferenceMap.clear();
}
//-----------------------------------------------------------------------------
SimObject* TamlJSONReader::parseType( const rapidjson::Value::ConstMemberIterator& memberItr )
{
// Debug Profiling.
PROFILE_SCOPE(TamlJSONReader_ParseType);
// Fetch name and value.
const rapidjson::Value& typeName = memberItr->name;
const rapidjson::Value& typeValue = memberItr->value;
// Is value an object?
if ( !typeValue.IsObject() )
{
// No, so warn.
Con::warnf( "TamlJSONReader::parseType() - Cannot process type '%s' as it is not an object.", typeName.GetString() );
return NULL;
}
// Fetch engine type name (demangled).
StringTableEntry engineTypeName = getDemangledName( typeName.GetString() );
// Fetch reference to Id.
const U32 tamlRefToId = getTamlRefToId( typeValue );
// Do we have a reference to Id?
if ( tamlRefToId != 0 )
{
// Yes, so fetch reference.
typeObjectReferenceHash::Iterator referenceItr = mObjectReferenceMap.find( tamlRefToId );
// Did we find the reference?
if ( referenceItr == mObjectReferenceMap.end() )
{
// No, so warn.
Con::warnf( "TamlJSONReader::parseType() - Could not find a reference Id of '%d'", tamlRefToId );
return NULL;
}
// Return object.
return referenceItr->value;
}
// No, so fetch reference Id.
const U32 tamlRefId = getTamlRefId( typeValue );
// Create type.
SimObject* pSimObject = Taml::createType( engineTypeName, mpTaml );
// Finish if we couldn't create the type.
if ( pSimObject == NULL )
return NULL;
// Find Taml callbacks.
TamlCallbacks* pCallbacks = dynamic_cast<TamlCallbacks*>( pSimObject );
TamlCustomNodes customNodes;
// Are there any Taml callbacks?
if ( pCallbacks != NULL )
{
// Yes, so call it.
mpTaml->tamlPreRead( pCallbacks );
}
// Parse field members.
for( rapidjson::Value::ConstMemberIterator fieldMemberItr = typeValue.MemberBegin(); fieldMemberItr != typeValue.MemberEnd(); ++fieldMemberItr )
{
// Fetch value.
const rapidjson::Value& fieldValue = fieldMemberItr->value;
// Skip if not a field.
if ( fieldValue.IsObject() )
continue;
// Parse as field.
parseField( fieldMemberItr, pSimObject );
}
// Fetch object name.
StringTableEntry objectName = StringTable->insert( getTamlObjectName( typeValue ) );
// Does the object require a name?
if ( objectName == StringTable->EmptyString() )
{
// No, so just register anonymously.
pSimObject->registerObject();
}
else
{
// Yes, so register a named object.
pSimObject->registerObject( objectName );
// Was the name assigned?
if ( pSimObject->getName() != objectName )
{
// No, so warn that the name was rejected.
Con::warnf( "Taml::parseType() - Registered an instance of type '%s' but a request to name it '%s' was rejected. This is typically because an object of that name already exists.",
engineTypeName, objectName );
}
}
// Do we have a reference Id?
if ( tamlRefId != 0 )
{
// Yes, so insert reference.
mObjectReferenceMap.insertUnique( tamlRefId, pSimObject );
}
// Parse children and custom node members.
for( rapidjson::Value::ConstMemberIterator objectMemberItr = typeValue.MemberBegin(); objectMemberItr != typeValue.MemberEnd(); ++objectMemberItr )
{
// Fetch name and value.
const rapidjson::Value& objectName = objectMemberItr->name;
const rapidjson::Value& objectValue = objectMemberItr->value;
// Skip if not an object.
if ( !objectValue.IsObject() )
continue;
// Find the period character in the name.
const char* pPeriod = dStrchr( objectName.GetString(), '.' );
// Did we find the period?
if ( pPeriod == NULL )
{
// No, so parse child object.
parseChild( objectMemberItr, pSimObject );
continue;
}
// Yes, so parse custom object.
parseCustom( objectMemberItr, pSimObject, pPeriod+1, customNodes );
}
// Call custom read.
if ( pCallbacks )
{
mpTaml->tamlCustomRead( pCallbacks, customNodes );
mpTaml->tamlPostRead( pCallbacks, customNodes );
}
// Return object.
return pSimObject;
}
//-----------------------------------------------------------------------------
inline void TamlJSONReader::parseField( rapidjson::Value::ConstMemberIterator& memberItr, SimObject* pSimObject )
{
// Debug Profiling.
PROFILE_SCOPE(TamlJSONReader_ParseField);
// Fetch name and value.
const rapidjson::Value& name = memberItr->name;
const rapidjson::Value& value = memberItr->value;
// Insert the field name.
StringTableEntry fieldName = StringTable->insert( name.GetString() );
// Ignore if this is a Taml attribute.
if ( fieldName == tamlRefIdName ||
fieldName == tamlRefToIdName ||
fieldName == tamlNamedObjectName )
return;
// Get field value.
char valueBuffer[4096];
if ( !parseStringValue( valueBuffer, sizeof(valueBuffer), value, fieldName ) )
{
// Warn.
Con::warnf( "Taml::parseField() Could not interpret value for field '%s'", fieldName );
return;
}
// Set field.
pSimObject->setPrefixedDataField(fieldName, NULL, valueBuffer);
}
//-----------------------------------------------------------------------------
inline void TamlJSONReader::parseChild( rapidjson::Value::ConstMemberIterator& memberItr, SimObject* pSimObject )
{
// Debug Profiling.
PROFILE_SCOPE(TamlJSONReader_ParseChild);
// Fetch name.
const rapidjson::Value& name = memberItr->name;
// Fetch the Taml children.
TamlChildren* pChildren = dynamic_cast<TamlChildren*>( pSimObject );
// Is this a Taml child?
if ( pChildren == NULL )
{
// No, so warn.
Con::warnf("Taml::parseChild() - Child member '%s' found under parent '%s' but object cannot have children.",
name.GetString(),
pSimObject->getClassName() );
return;
}
// Fetch any container child class specifier.
AbstractClassRep* pContainerChildClass = pSimObject->getClassRep()->getContainerChildClass( true );
// Parse child member.
SimObject* pChildSimObject = parseType( memberItr );
// Finish if the child was not created.
if ( pChildSimObject == NULL )
return;
// Do we have a container child class?
if ( pContainerChildClass != NULL )
{
// Yes, so is the child object the correctly derived type?
if ( !pChildSimObject->getClassRep()->isClass( pContainerChildClass ) )
{
// No, so warn.
Con::warnf("Taml::parseChild() - Child element '%s' found under parent '%s' but object is restricted to children of type '%s'.",
pChildSimObject->getClassName(),
pSimObject->getClassName(),
pContainerChildClass->getClassName() );
// NOTE: We can't delete the object as it may be referenced elsewhere!
pChildSimObject = NULL;
return;
}
}
// Add child.
pChildren->addTamlChild( pChildSimObject );
// Find Taml callbacks for child.
TamlCallbacks* pChildCallbacks = dynamic_cast<TamlCallbacks*>( pChildSimObject );
// Do we have callbacks on the child?
if ( pChildCallbacks != NULL )
{
// Yes, so perform callback.
mpTaml->tamlAddParent( pChildCallbacks, pSimObject );
}
}
//-----------------------------------------------------------------------------
inline void TamlJSONReader::parseCustom( rapidjson::Value::ConstMemberIterator& memberItr, SimObject* pSimObject, const char* pCustomNodeName, TamlCustomNodes& customNodes )
{
// Debug Profiling.
PROFILE_SCOPE(TamlJSONReader_ParseCustom);
// Fetch value.
const rapidjson::Value& value = memberItr->value;
// Add custom node.
TamlCustomNode* pCustomNode = customNodes.addNode( pCustomNodeName );
// Iterate members.
for( rapidjson::Value::ConstMemberIterator customMemberItr = value.MemberBegin(); customMemberItr != value.MemberEnd(); ++customMemberItr )
{
// Fetch value.
const rapidjson::Value& customValue = customMemberItr->value;
// Is the member an object?
if ( !customValue.IsObject() && !customValue.IsArray() )
{
// No, so warn.
Con::warnf( "Taml::parseCustom() - Cannot process custom node name '%s' member as child value is not an object or array.", pCustomNodeName );
return;
}
// Parse custom node.
parseCustomNode( customMemberItr, pCustomNode );
}
}
//-----------------------------------------------------------------------------
inline void TamlJSONReader::parseCustomNode( rapidjson::Value::ConstMemberIterator& memberItr, TamlCustomNode* pCustomNode )
{
// Debug Profiling.
PROFILE_SCOPE(TamlJSONReader_ParseCustomNode);
// Fetch name and value.
const rapidjson::Value& name = memberItr->name;
const rapidjson::Value& value = memberItr->value;
// Is the value an object?
if ( value.IsObject() )
{
// Yes, so is the node a proxy object?
if ( getTamlRefId( value ) != 0 || getTamlRefToId( value ) != 0 )
{
// Yes, so parse proxy object.
SimObject* pProxyObject = parseType( memberItr );
// Add child node.
pCustomNode->addNode( pProxyObject );
return;
}
}
char valueBuffer[4096];
// Fetch the node name.
StringTableEntry nodeName = getDemangledName( name.GetString() );
// Yes, so add child node.
TamlCustomNode* pChildNode = pCustomNode->addNode( nodeName );
// Is the value an array?
if ( value.IsArray() )
{
// Yes, so does it have a single entry?
if ( value.Size() == 1 )
{
// Yes, so parse the node text.
if ( parseStringValue( valueBuffer, sizeof(valueBuffer), value.Begin(), nodeName ) )
{
pChildNode->setNodeText( valueBuffer );
}
else
{
// Warn.
Con::warnf( "Taml::parseCustomNode() - Encountered text in the custom node '%s' but could not interpret the value.", nodeName );
}
}
else
{
// No, so warn.
Con::warnf( "Taml::parseCustomNode() - Encountered text in the custom node '%s' but more than a single element was found in the array.", nodeName );
}
return;
}
// Iterate child members.
for( rapidjson::Value::ConstMemberIterator childMemberItr = value.MemberBegin(); childMemberItr != value.MemberEnd(); ++childMemberItr )
{
// Fetch name and value.
const rapidjson::Value& childName = childMemberItr->name;
const rapidjson::Value& childValue = childMemberItr->value;
// Fetch the field name.
StringTableEntry fieldName = StringTable->insert( childName.GetString() );
// Is the value an array?
if ( childValue.IsArray() )
{
// Yes, so does it have a single entry?
if ( childValue.Size() == 1 )
{
// Yes, so parse the node text.
if ( parseStringValue( valueBuffer, sizeof(valueBuffer), *childValue.Begin(), fieldName ) )
{
// Yes, so add sub-child node.
TamlCustomNode* pSubChildNode = pChildNode->addNode( fieldName );
// Set sub-child text.
pSubChildNode->setNodeText( valueBuffer );
continue;
}
// Warn.
Con::warnf( "Taml::parseCustomNode() - Encountered text in the custom node '%s' but could not interpret the value.", fieldName );
return;
}
// No, so warn.
Con::warnf( "Taml::parseCustomNode() - Encountered text in the custom node '%s' but more than a single element was found in the array.", fieldName );
return;
}
// Is the member an object?
if ( childValue.IsObject() )
{
// Yes, so parse custom node.
parseCustomNode( childMemberItr, pChildNode );
continue;
}
// Ignore if this is a Taml attribute.
if ( fieldName == tamlRefIdName ||
fieldName == tamlRefToIdName ||
fieldName == tamlNamedObjectName )
continue;
// Parse string value.
if ( !parseStringValue( valueBuffer, sizeof(valueBuffer), childValue, childName.GetString() ) )
{
// Warn.
Con::warnf( "Taml::parseCustomNode() - Could not interpret value for field '%s'", fieldName );
continue;
}
// Add node field.
pChildNode->addField( fieldName, valueBuffer );
}
}
//-----------------------------------------------------------------------------
inline StringTableEntry TamlJSONReader::getDemangledName( const char* pMangledName )
{
// Debug Profiling.
PROFILE_SCOPE(TamlJSONReader_GetDemangledName);
// Is the type name mangled?
if ( StringUnit::getUnitCount( pMangledName, JSON_RFC4627_NAME_MANGLING_CHARACTERS ) > 1 )
{
// Yes, so fetch type name portion.
return StringTable->insert( StringUnit::getUnit( pMangledName, 0, JSON_RFC4627_NAME_MANGLING_CHARACTERS ) );
}
// No, so use all the type name.
return StringTable->insert( pMangledName );
}
//-----------------------------------------------------------------------------
inline bool TamlJSONReader::parseStringValue( char* pBuffer, const S32 bufferSize, const rapidjson::Value& value, const char* pName )
{
// Debug Profiling.
PROFILE_SCOPE(TamlJSONReader_ParseStringValue);
// Handle field value appropriately.
if ( value.IsString() )
{
dSprintf( pBuffer, bufferSize, "%s", value.GetString() );
return true;
}
if ( value.IsNumber() )
{
if ( value.IsInt() )
{
dSprintf( pBuffer, bufferSize, "%d", value.GetInt() );
return true;
}
if ( value.IsUint() )
{
dSprintf( pBuffer, bufferSize, "%d", value.GetUint() );
return true;
}
if ( value.IsInt64() )
{
dSprintf( pBuffer, bufferSize, "%d", value.GetInt64() );
return true;
}
if ( value.IsUint64() )
{
dSprintf( pBuffer, bufferSize, "%d", value.GetUint64() );
return true;
}
if ( value.IsDouble() )
{
dSprintf( pBuffer, bufferSize, "%f", value.GetDouble() );
return true;
}
}
if ( value.IsBool() )
{
dSprintf( pBuffer, bufferSize, "%d", value.GetBool() );
return true;
}
// Failed to get value type.
Con::warnf( "Taml: Encountered a field '%s' but its value is an unknown type.", pName );
return false;
}
//-----------------------------------------------------------------------------
inline U32 TamlJSONReader::getTamlRefId( const rapidjson::Value& value )
{
// Debug Profiling.
PROFILE_SCOPE(TamlJSONReader_GetTamlRefId);
// Is the value an object?
if ( !value.IsObject() )
{
// No, so warn.
Con::warnf( "Taml::getTamlRefId() - Cannot get '%s' member as value is not an object.", tamlRefIdName );
return 0;
}
// Iterate members.
for( rapidjson::Value::ConstMemberIterator memberItr = value.MemberBegin(); memberItr != value.MemberEnd(); ++memberItr )
{
// Insert member name.
StringTableEntry attributeName = StringTable->insert( memberItr->name.GetString() );
// Skip if not the correct attribute.
if ( attributeName != tamlRefIdName )
continue;
// Is the value an integer?
if ( !memberItr->value.IsInt() )
{
// No, so warn.
Con::warnf( "Taml::getTamlRefId() - Found '%s' member but it is not an integer.", tamlRefIdName );
return 0;
}
// Return it.
return (U32)memberItr->value.GetInt();
}
// Not found.
return 0;
}
//-----------------------------------------------------------------------------
inline U32 TamlJSONReader::getTamlRefToId( const rapidjson::Value& value )
{
// Debug Profiling.
PROFILE_SCOPE(TamlJSONReader_GetTamlRefToId);
// Is the value an object?
if ( !value.IsObject() )
{
// No, so warn.
Con::warnf( "Taml::getTamlRefToId() - Cannot get '%s' member as value is not an object.", tamlRefToIdName );
return 0;
}
// Iterate members.
for( rapidjson::Value::ConstMemberIterator memberItr = value.MemberBegin(); memberItr != value.MemberEnd(); ++memberItr )
{
// Insert member name.
StringTableEntry attributeName = StringTable->insert( memberItr->name.GetString() );
// Skip if not the correct attribute.
if ( attributeName != tamlRefToIdName )
continue;
// Is the value an integer?
if ( !memberItr->value.IsInt() )
{
// No, so warn.
Con::warnf( "Taml::getTamlRefToId() - Found '%s' member but it is not an integer.", tamlRefToIdName );
return 0;
}
// Return it.
return (U32)memberItr->value.GetInt();
}
// Not found.
return 0;
}
//-----------------------------------------------------------------------------
inline const char* TamlJSONReader::getTamlObjectName( const rapidjson::Value& value )
{
// Debug Profiling.
PROFILE_SCOPE(TamlJSONReader_GetTamlObjectName);
// Is the value an object?
if ( !value.IsObject() )
{
// No, so warn.
Con::warnf( "Taml::getTamlObjectName() - Cannot get '%s' member as value is not an object.", tamlNamedObjectName );
return 0;
}
// Iterate members.
for( rapidjson::Value::ConstMemberIterator memberItr = value.MemberBegin(); memberItr != value.MemberEnd(); ++memberItr )
{
// Insert member name.
StringTableEntry attributeName = StringTable->insert( memberItr->name.GetString() );
// Skip if not the correct attribute.
if ( attributeName != tamlNamedObjectName )
continue;
// Is the value an integer?
if ( !memberItr->value.IsString() )
{
// No, so warn.
Con::warnf( "Taml::getTamlObjectName() - Found '%s' member but it is not a string.", tamlNamedObjectName );
return NULL;
}
// Return it.
return memberItr->value.GetString();
}
// Not found.
return NULL;
}

View file

@ -0,0 +1,76 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2013 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef _TAML_JSONREADER_H_
#define _TAML_JSONREADER_H_
#ifndef _TDICTIONARY_H_
#include "core/util/tDictionary.h"
#endif
#ifndef _TAML_H_
#include "persistence/taml/taml.h"
#endif
/// RapidJson.
#include "persistence/rapidjson/document.h"
#include "persistence/rapidjson/prettywriter.h"
//-----------------------------------------------------------------------------
/// @ingroup tamlGroup
/// @see tamlGroup
class TamlJSONReader
{
public:
TamlJSONReader( Taml* pTaml ) :
mpTaml( pTaml )
{}
virtual ~TamlJSONReader() {}
/// Read.
SimObject* read( FileStream& stream );
private:
Taml* mpTaml;
typedef HashTable<SimObjectId, SimObject*> typeObjectReferenceHash;
typeObjectReferenceHash mObjectReferenceMap;
private:
void resetParse( void );
SimObject* parseType( const rapidjson::Value::ConstMemberIterator& memberItr );
inline void parseField( rapidjson::Value::ConstMemberIterator& memberItr, SimObject* pSimObject );
inline void parseChild( rapidjson::Value::ConstMemberIterator& memberItr, SimObject* pSimObject );
inline void parseCustom( rapidjson::Value::ConstMemberIterator& memberItr, SimObject* pSimObject, const char* pCustomNodeName, TamlCustomNodes& customNodes );
inline void parseCustomNode( rapidjson::Value::ConstMemberIterator& memberItr, TamlCustomNode* pCustomNode );
inline StringTableEntry getDemangledName( const char* pMangledName );
inline bool parseStringValue( char* pBuffer, const S32 bufferSize, const rapidjson::Value& value, const char* pName );
inline U32 getTamlRefId( const rapidjson::Value& value );
inline U32 getTamlRefToId( const rapidjson::Value& value );
inline const char* getTamlObjectName( const rapidjson::Value& value );
};
#endif // _TAML_JSONREADER_H_

View file

@ -0,0 +1,367 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2013 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "persistence/taml/json/tamlJSONWriter.h"
#include "core/stringTable.h"
#include "core/stream/fileStream.h"
// Debug Profiling.
#include "platform/profiler.h"
//-----------------------------------------------------------------------------
// These are the characters allowed that separate the type-name from the type.
// These separators can be used to ensure that each member in an object has
// a unique name.
//
// It is important to understand that TAML does not require entries to be unique
// but technically the RFC4627 spec states it as "should" be seems to be taken
// as MUST. See here: http://www.ietf.org/rfc/rfc4627.txt
//
// They can be placed as a suffix to the type-name. The very first occurance
// is used to split the type-name from the suffix so you can form whatever
// suffix you like to make entries unique.
// Examples are "Sprite 0", "Sprite*0", "Sprite[0]", "Sprite,0" etc.
//
// Type-names can legally consist of a-z, A-Z, 0-9 and "_" (underscore) so these
// characters cannot be used for mangling. Feel free to add any characters you
// require to this list.
StringTableEntry JSON_RFC4627_NAME_MANGLING_CHARACTERS = StringTable->insert(" !$%^&*()-+{}[]@:~#|\\/?<>,.\n\r\t");
// This is the "dSprintf" format that the JSON writer uses to encode each
// member if JSON_RFC4627 mode is on. You are free to change this as long as
// you ensure that it starts with the "%s" character (which represents the type name)
// and is immediately followed by at least a single mangling character and that the
// "%d" is present as that represents the automatically-added member index.
StringTableEntry JSON_RFC4627_NAME_MANGLING_FORMAT = StringTable->insert( "%s[%d]" );
//-----------------------------------------------------------------------------
bool TamlJSONWriter::write( FileStream& stream, const TamlWriteNode* pTamlWriteNode )
{
// Debug Profiling.
PROFILE_SCOPE(TamlJSONWriter_Write);
// Create document.
rapidjson::Document document;
document.SetObject();
// Compile the root type.
rapidjson::Value rootValue(rapidjson::kObjectType);
compileType( document, &rootValue, NULL, pTamlWriteNode, -1 );
// Write document to stream.
rapidjson::PrettyWriter<FileStream> jsonStreamWriter( stream );
document.Accept( jsonStreamWriter );
return true;
}
//-----------------------------------------------------------------------------
void TamlJSONWriter::compileType( rapidjson::Document& document, rapidjson::Value* pTypeValue, rapidjson::Value* pParentValue, const TamlWriteNode* pTamlWriteNode, const S32 memberIndex )
{
// Debug Profiling.
PROFILE_SCOPE(TamlJSONWriter_CompileType);
// Fetch the json document allocator.
rapidjson::Document::AllocatorType& allocator = document.GetAllocator();
// Fetch object.
SimObject* pSimObject = pTamlWriteNode->mpSimObject;
// Fetch JSON strict flag (don't use it if member index is set to not use it).
const bool jsonStrict = memberIndex == -1 ? false : mpTaml->getJSONStrict();
// Fetch element name (mangled or not).
StringTableEntry elementName = jsonStrict ? getManagedName( pSimObject->getClassName(), memberIndex ) : pSimObject->getClassName();
// Is there a parent value?
if ( pParentValue == NULL )
{
// No, so add as document root value member.
pTypeValue = &((document.AddMember( elementName, *pTypeValue, allocator ).MemberEnd()-1)->value);
}
else
{
// Yes, so add as a parent value member.
pTypeValue = &((pParentValue->AddMember( elementName, *pTypeValue, allocator ).MemberEnd()-1)->value);
}
// Fetch reference Id.
const U32 referenceId = pTamlWriteNode->mRefId;
// Do we have a reference Id?
if ( referenceId != 0 )
{
// Yes, so set reference Id.
rapidjson::Value value;
value.SetInt( referenceId );
pTypeValue->AddMember( tamlRefIdName, value, allocator );
}
// Do we have a reference to node?
else if ( pTamlWriteNode->mRefToNode != NULL )
{
// Yes, so fetch reference to Id.
const U32 referenceToId = pTamlWriteNode->mRefToNode->mRefId;
// Sanity!
AssertFatal( referenceToId != 0, "Taml: Invalid reference to Id." );
// Set reference to Id.
rapidjson::Value value;
value.SetInt( referenceToId );
pTypeValue->AddMember( tamlRefToIdName, value, allocator );
// Finish because we're a reference to another object.
return;
}
// Fetch object name.
const char* pObjectName = pTamlWriteNode->mpObjectName;
// Do we have a name?
if ( pObjectName != NULL )
{
// Yes, so set name.
rapidjson::Value value;
value.SetString( pObjectName, dStrlen(pObjectName), allocator );
pTypeValue->AddMember( tamlNamedObjectName, value, allocator );
}
// Compile field.
compileFields( document, pTypeValue, pTamlWriteNode );
// Fetch children.
Vector<TamlWriteNode*>* pChildren = pTamlWriteNode->mChildren;
// Do we have any children?
if ( pChildren )
{
S32 childMemberIndex = 0;
// Yes, so iterate children.
for( Vector<TamlWriteNode*>::iterator itr = pChildren->begin(); itr != pChildren->end(); ++itr )
{
// Compile child type.
rapidjson::Value childValue(rapidjson::kObjectType);
compileType( document, &childValue, pTypeValue, (*itr), childMemberIndex++ );
}
}
// Compile custom.
compileCustom( document, pTypeValue, pTamlWriteNode );
}
//-----------------------------------------------------------------------------
void TamlJSONWriter::compileFields( rapidjson::Document& document, rapidjson::Value* pTypeValue, const TamlWriteNode* pTamlWriteNode )
{
// Debug Profiling.
PROFILE_SCOPE(TamlJSONWriter_CompileFields);
// Fetch fields.
const Vector<TamlWriteNode::FieldValuePair*>& fields = pTamlWriteNode->mFields;
// Ignore if no fields.
if ( fields.size() == 0 )
return;
// Fetch the json document allocator.
rapidjson::Document::AllocatorType& allocator = document.GetAllocator();
// Iterate fields.
for( Vector<TamlWriteNode::FieldValuePair*>::const_iterator itr = fields.begin(); itr != fields.end(); ++itr )
{
// Fetch field/value pair.
TamlWriteNode::FieldValuePair* pFieldValue = (*itr);
// Set field attribute.
rapidjson::Value value;
value.SetString( pFieldValue->mpValue, dStrlen(pFieldValue->mpValue), allocator );
pTypeValue->AddMember( pFieldValue->mName, value, allocator );
}
}
//-----------------------------------------------------------------------------
void TamlJSONWriter::compileCustom( rapidjson::Document& document, rapidjson::Value* pTypeValue, const TamlWriteNode* pTamlWriteNode )
{
// Debug Profiling.
PROFILE_SCOPE(TamlJSONWriter_CompileCustom);
// Fetch custom nodes.
const TamlCustomNodes& customNodes = pTamlWriteNode->mCustomNodes;
// Fetch custom nodes.
const TamlCustomNodeVector& nodes = customNodes.getNodes();
// Finish if no custom nodes to process.
if ( nodes.size() == 0 )
return;
// Fetch the json document allocator.
rapidjson::Document::AllocatorType& allocator = document.GetAllocator();
// Fetch object.
SimObject* pSimObject = pTamlWriteNode->mpSimObject;
// Fetch element name.
const char* pElementName = pSimObject->getClassName();
// Iterate custom nodes.
for( TamlCustomNodeVector::const_iterator customNodesItr = nodes.begin(); customNodesItr != nodes.end(); ++customNodesItr )
{
// Fetch the custom node.
TamlCustomNode* pCustomNode = *customNodesItr;
// Format extended element name.
char extendedElementNameBuffer[256];
dSprintf( extendedElementNameBuffer, sizeof(extendedElementNameBuffer), "%s.%s", pElementName, pCustomNode->getNodeName() );
StringTableEntry elementNameEntry = StringTable->insert( extendedElementNameBuffer );
rapidjson::Value elementValue(rapidjson::kObjectType);
rapidjson::Value* pElementValue = &((pTypeValue->AddMember( elementNameEntry, elementValue, allocator ).MemberEnd()-1)->value);
// Fetch node children.
const TamlCustomNodeVector& nodeChildren = pCustomNode->getChildren();
S32 childMemberIndex = 0;
// Iterate children nodes.
for( TamlCustomNodeVector::const_iterator childNodeItr = nodeChildren.begin(); childNodeItr != nodeChildren.end(); ++childNodeItr )
{
// Fetch child node.
const TamlCustomNode* pChildNode = *childNodeItr;
// Compile the custom node.
compileCustomNode( document, pElementValue, pChildNode, childMemberIndex++ );
}
// Finish if the node is set to ignore if empty and it is empty.
if ( pCustomNode->getIgnoreEmpty() && pTypeValue->MemberBegin() == pTypeValue->MemberEnd() )
{
// Yes, so delete the member.
pElementValue->SetNull();
}
}
}
//-----------------------------------------------------------------------------
void TamlJSONWriter::compileCustomNode( rapidjson::Document& document, rapidjson::Value* pParentValue, const TamlCustomNode* pCustomNode, const S32 memberIndex )
{
// Debug Profiling.
PROFILE_SCOPE(TamlJSONWriter_CompileCustomNode);
// Finish if the node is set to ignore if empty and it is empty.
if ( pCustomNode->getIgnoreEmpty() && pCustomNode->isEmpty() )
return;
// Is the node a proxy object?
if ( pCustomNode->isProxyObject() )
{
// Yes, so write the proxy object.
rapidjson::Value proxyValue(rapidjson::kObjectType);
compileType( document, &proxyValue, pParentValue, pCustomNode->getProxyWriteNode(), memberIndex );
return;
}
// Fetch the json document allocator.
rapidjson::Document::AllocatorType& allocator = document.GetAllocator();
// Fetch fields.
const TamlCustomFieldVector& fields = pCustomNode->getFields();
// Fetch JSON strict flag (don't use it if member index is set to not use it).
const bool jsonStrict = memberIndex == -1 ? false : mpTaml->getJSONStrict();
// Fetch element name (mangled or not).
StringTableEntry nodeName = jsonStrict ? getManagedName( pCustomNode->getNodeName(), memberIndex ) : pCustomNode->getNodeName();
// Is there any node text?
if ( !pCustomNode->getNodeTextField().isValueEmpty() )
{
// Yes, so fetch text.
const char* pNodeText = pCustomNode->getNodeTextField().getFieldValue();
// Create custom value.
rapidjson::Value customTextValue(rapidjson::kArrayType);
customTextValue.PushBack( pNodeText, allocator );
pParentValue->AddMember( nodeName, customTextValue, allocator );
return;
}
// Create custom value.
rapidjson::Value customValue(rapidjson::kObjectType);
rapidjson::Value* pCustomValue = &((pParentValue->AddMember( nodeName, customValue, allocator ).MemberEnd()-1)->value);
// Iterate fields.
for ( TamlCustomFieldVector::const_iterator fieldItr = fields.begin(); fieldItr != fields.end(); ++fieldItr )
{
// Fetch field.
const TamlCustomField* pField = *fieldItr;
// Add a field.
rapidjson::Value fieldValue;
fieldValue.SetString( pField->getFieldValue(), dStrlen(pField->getFieldValue()), allocator );
pCustomValue->AddMember( pField->getFieldName(), fieldValue, allocator );
}
// Fetch node children.
const TamlCustomNodeVector& nodeChildren = pCustomNode->getChildren();
S32 childMemberIndex = 0;
// Iterate children nodes.
for( TamlCustomNodeVector::const_iterator childNodeItr = nodeChildren.begin(); childNodeItr != nodeChildren.end(); ++childNodeItr )
{
// Fetch child node.
const TamlCustomNode* pChildNode = *childNodeItr;
// Compile the child node.
compileCustomNode( document, pCustomValue, pChildNode, childMemberIndex++ );
}
// Finish if the node is set to ignore if empty and it is empty (including fields).
if ( pCustomNode->getIgnoreEmpty() && fields.size() == 0 && pCustomValue->MemberBegin() == pCustomValue->MemberEnd() )
{
// Yes, so delete the member.
pCustomValue->SetNull();
}
}
//-----------------------------------------------------------------------------
inline StringTableEntry TamlJSONWriter::getManagedName( const char* pName, const S32 memberIndex )
{
// Debug Profiling.
PROFILE_SCOPE(TamlJSONWriter_getManagedName);
char nameBuffer[1024];
// Format mangled name.
dSprintf( nameBuffer, sizeof(nameBuffer), JSON_RFC4627_NAME_MANGLING_FORMAT, pName, memberIndex );
return StringTable->insert( nameBuffer );
}

View file

@ -0,0 +1,66 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2013 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef _TAML_JSONWRITER_H_
#define _TAML_JSONWRITER_H_
#ifndef _TAML_H_
#include "persistence/taml/taml.h"
#endif
/// RapidJson.
#include "persistence/rapidjson/document.h"
#include "persistence/rapidjson/prettywriter.h"
//-----------------------------------------------------------------------------
extern StringTableEntry JSON_RFC4627_NAME_MANGLING_CHARACTERS;
extern StringTableEntry JSON_RFC4627_NAME_MANGLING_FORMAT;
//-----------------------------------------------------------------------------
/// @ingroup tamlGroup
/// @see tamlGroup
class TamlJSONWriter
{
public:
TamlJSONWriter( Taml* pTaml ) :
mpTaml( pTaml )
{}
virtual ~TamlJSONWriter() {}
/// Write.
bool write( FileStream& stream, const TamlWriteNode* pTamlWriteNode );
private:
Taml* mpTaml;
private:
void compileType( rapidjson::Document& document, rapidjson::Value* pTypeValue, rapidjson::Value* pParentValue, const TamlWriteNode* pTamlWriteNode, const S32 memberIndex );
void compileFields( rapidjson::Document& document, rapidjson::Value* pTypeValue, const TamlWriteNode* pTamlWriteNode );
void compileCustom( rapidjson::Document& document, rapidjson::Value* pTypeValue, const TamlWriteNode* pTamlWriteNode );
void compileCustomNode( rapidjson::Document& document, rapidjson::Value* pParentValue, const TamlCustomNode* pCustomNode, const S32 memberIndex );
inline StringTableEntry getManagedName(const char* pName, const S32 memberIndex );
};
#endif // _TAML_JSONWRITER_H_