2014-12-07 19:09:38 -05:00
// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
2014-10-01 18:20:53 -04:00
# include "SerializationPrivatePCH.h"
# include "IStructDeserializerBackend.h"
# include "StructDeserializer.h"
/* Internal helpers
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
namespace StructDeserializer
{
2014-10-27 07:54:20 -04:00
/**
* Structure for the read state stack .
*/
2014-10-01 18:20:53 -04:00
struct FReadState
{
2014-10-27 07:54:20 -04:00
/** Holds the property's current array index. */
2014-10-01 18:20:53 -04:00
int32 ArrayIndex ;
2014-10-27 07:54:20 -04:00
/** Holds a pointer to the property's data. */
2014-10-01 18:20:53 -04:00
void * Data ;
2014-10-27 07:54:20 -04:00
/** Holds the property's meta data. */
2014-10-01 18:20:53 -04:00
UProperty * Property ;
2014-10-27 07:54:20 -04:00
/** Holds a pointer to the UStruct describing the data. */
2014-10-01 18:20:53 -04:00
UStruct * TypeInfo ;
} ;
2014-10-27 07:54:20 -04:00
/**
* Finds the class for the given stack state .
*
* @ param State The stack state to find the class for .
* @ return The class , if found .
*/
2014-10-01 18:20:53 -04:00
UStruct * FindClass ( const FReadState & State )
{
UStruct * Class = nullptr ;
if ( State . Property ! = nullptr )
{
UProperty * ParentProperty = State . Property ;
UArrayProperty * ArrayProperty = Cast < UArrayProperty > ( ParentProperty ) ;
if ( ArrayProperty ! = nullptr )
{
ParentProperty = ArrayProperty - > Inner ;
}
UStructProperty * StructProperty = Cast < UStructProperty > ( ParentProperty ) ;
UObjectPropertyBase * ObjectProperty = Cast < UObjectPropertyBase > ( ParentProperty ) ;
if ( StructProperty ! = nullptr )
{
Class = StructProperty - > Struct ;
}
else if ( ObjectProperty ! = nullptr )
{
Class = ObjectProperty - > PropertyClass ;
}
}
else
{
UObject * RootObject = static_cast < UObject * > ( State . Data ) ;
Class = RootObject - > GetClass ( ) ;
}
return Class ;
}
}
/* FStructDeserializer static interface
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool FStructDeserializer : : Deserialize ( void * OutStruct , UStruct & TypeInfo , IStructDeserializerBackend & Backend , const FStructDeserializerPolicies & Policies )
{
using namespace StructDeserializer ;
check ( OutStruct ! = nullptr ) ;
// initialize deserialization
FReadState CurrentState ;
{
CurrentState . ArrayIndex = 0 ;
CurrentState . Data = OutStruct ;
CurrentState . Property = nullptr ;
CurrentState . TypeInfo = & TypeInfo ;
}
TArray < FReadState > StateStack ;
EStructDeserializerBackendTokens Token ;
// process state stack
while ( Backend . GetNextToken ( Token ) )
{
FString PropertyName = Backend . GetCurrentPropertyName ( ) ;
switch ( Token )
{
case EStructDeserializerBackendTokens : : ArrayEnd :
{
if ( StateStack . Num ( ) = = 0 )
{
UE_LOG ( LogSerialization , Verbose , TEXT ( " Malformed input: Found ArrayEnd without matching ArrayStart " ) ) ;
return false ;
}
2015-03-27 20:05:10 -04:00
CurrentState = StateStack . Pop ( /*bAllowShrinking=*/ false ) ;
2014-10-01 18:20:53 -04:00
}
break ;
case EStructDeserializerBackendTokens : : ArrayStart :
{
FReadState NewState ;
NewState . Property = FindField < UProperty > ( CurrentState . TypeInfo , * PropertyName ) ;
if ( NewState . Property = = nullptr )
{
if ( Policies . MissingFields ! = EStructDeserializerErrorPolicies : : Ignore )
{
UE_LOG ( LogSerialization , Verbose , TEXT ( " The array property '%s' does not exist " ) , * PropertyName ) ;
}
if ( Policies . MissingFields = = EStructDeserializerErrorPolicies : : Error )
{
return false ;
}
Backend . SkipArray ( ) ;
}
else
{
NewState . ArrayIndex = 0 ;
NewState . Data = CurrentState . Data ;
NewState . TypeInfo = FindClass ( NewState ) ;
StateStack . Push ( CurrentState ) ;
CurrentState = NewState ;
}
}
break ;
case EStructDeserializerBackendTokens : : Error :
{
return false ;
}
case EStructDeserializerBackendTokens : : Property :
{
UProperty * Property = nullptr ;
if ( PropertyName . IsEmpty ( ) )
{
// handle array property
UArrayProperty * ArrayProperty = Cast < UArrayProperty > ( CurrentState . Property ) ;
if ( ArrayProperty ! = nullptr )
{
// dynamic array property
Property = ArrayProperty - > Inner ;
}
else
{
// static array property
Property = CurrentState . Property ;
}
if ( Property = = nullptr )
{
// error: no property for array element
if ( Policies . MissingFields ! = EStructDeserializerErrorPolicies : : Ignore )
{
UE_LOG ( LogSerialization , Verbose , TEXT ( " Failed to serialize array element %i " ) , CurrentState . ArrayIndex ) ;
}
return false ;
}
else if ( ! Backend . ReadProperty ( Property , CurrentState . Property , CurrentState . Data , CurrentState . ArrayIndex ) )
{
UE_LOG ( LogSerialization , Verbose , TEXT ( " The array element '%s[%i]' could not be read (%s) " ) , * PropertyName , CurrentState . ArrayIndex , * Backend . GetDebugString ( ) ) ;
}
+ + CurrentState . ArrayIndex ;
}
else
{
// handle scalar property
Property = FindField < UProperty > ( CurrentState . TypeInfo , * PropertyName ) ;
if ( Property = = nullptr )
{
// error: property not found
if ( Policies . MissingFields ! = EStructDeserializerErrorPolicies : : Ignore )
{
UE_LOG ( LogSerialization , Verbose , TEXT ( " The property '%s' does not exist " ) , * PropertyName ) ;
}
if ( Policies . MissingFields = = EStructDeserializerErrorPolicies : : Error )
{
return false ;
}
}
else if ( ! Backend . ReadProperty ( Property , CurrentState . Property , CurrentState . Data , CurrentState . ArrayIndex ) )
{
UE_LOG ( LogSerialization , Verbose , TEXT ( " The property '%s' could not be read (%s) " ) , * PropertyName , * Backend . GetDebugString ( ) ) ;
}
}
}
break ;
case EStructDeserializerBackendTokens : : StructureEnd :
{
if ( StateStack . Num ( ) = = 0 )
{
return true ;
}
2015-03-27 20:05:10 -04:00
CurrentState = StateStack . Pop ( /*bAllowShrinking=*/ false ) ;
2014-10-01 18:20:53 -04:00
}
break ;
case EStructDeserializerBackendTokens : : StructureStart :
{
FReadState NewState ;
if ( PropertyName . IsEmpty ( ) )
{
// skip root structure
if ( CurrentState . Property = = nullptr )
{
continue ;
}
// handle structured array element
UArrayProperty * ArrayProperty = Cast < UArrayProperty > ( CurrentState . Property ) ;
if ( ArrayProperty = = nullptr )
{
UE_LOG ( LogSerialization , Verbose , TEXT ( " Property %s is not an array " ) ) ;
return false ;
}
FScriptArrayHelper ArrayHelper ( ArrayProperty , ArrayProperty - > ContainerPtrToValuePtr < void > ( CurrentState . Data ) ) ;
const int32 ArrayIndex = ArrayHelper . AddValue ( ) ;
NewState . Property = ArrayProperty - > Inner ;
NewState . Data = ArrayHelper . GetRawPtr ( ArrayIndex ) ;
}
else
{
// handle structured property
NewState . Property = FindField < UProperty > ( CurrentState . TypeInfo , * PropertyName ) ;
if ( NewState . Property = = nullptr )
{
// error: structured property not found
if ( Policies . MissingFields ! = EStructDeserializerErrorPolicies : : Ignore )
{
UE_LOG ( LogSerialization , Verbose , TEXT ( " Structured property '%s' not found " ) , * PropertyName ) ;
}
if ( Policies . MissingFields = = EStructDeserializerErrorPolicies : : Error )
{
return false ;
}
}
else
{
NewState . Data = NewState . Property - > ContainerPtrToValuePtr < void > ( CurrentState . Data ) ;
}
}
if ( NewState . Property ! = nullptr )
{
NewState . ArrayIndex = 0 ;
NewState . TypeInfo = FindClass ( NewState ) ;
StateStack . Push ( CurrentState ) ;
CurrentState = NewState ;
}
else
{
// error: structured property not found
Backend . SkipStructure ( ) ;
if ( Policies . MissingFields ! = EStructDeserializerErrorPolicies : : Ignore )
{
UE_LOG ( LogSerialization , Verbose , TEXT ( " Structured property '%s' not found " ) , * PropertyName ) ;
}
if ( Policies . MissingFields = = EStructDeserializerErrorPolicies : : Error )
{
return false ;
}
}
}
default :
continue ;
}
}
// root structure not completed
return false ;
}