mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-07-12 07:04:36 +00:00
Initial Implementation of the Taml, Asset and Modules systems.
Only has example and shape assets currently.
This commit is contained in:
parent
2044b2691e
commit
7a3b40a86d
123 changed files with 30435 additions and 181 deletions
258
Engine/source/persistence/taml/json/tamlJSONParser.cpp
Normal file
258
Engine/source/persistence/taml/json/tamlJSONParser.cpp
Normal 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;
|
||||
}
|
||||
|
||||
57
Engine/source/persistence/taml/json/tamlJSONParser.h
Normal file
57
Engine/source/persistence/taml/json/tamlJSONParser.h
Normal 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_
|
||||
686
Engine/source/persistence/taml/json/tamlJSONReader.cpp
Normal file
686
Engine/source/persistence/taml/json/tamlJSONReader.cpp
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
76
Engine/source/persistence/taml/json/tamlJSONReader.h
Normal file
76
Engine/source/persistence/taml/json/tamlJSONReader.h
Normal 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_
|
||||
367
Engine/source/persistence/taml/json/tamlJSONWriter.cpp
Normal file
367
Engine/source/persistence/taml/json/tamlJSONWriter.cpp
Normal 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 );
|
||||
}
|
||||
66
Engine/source/persistence/taml/json/tamlJSONWriter.h
Normal file
66
Engine/source/persistence/taml/json/tamlJSONWriter.h
Normal 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_
|
||||
Loading…
Add table
Add a link
Reference in a new issue