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-09-09 20:32:05 -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 ) ;
2015-09-09 20:32:05 -04:00
if ( NewState . Property ! = nullptr )
2014-10-01 18:20:53 -04:00
{
2015-09-09 20:32:05 -04:00
// handle array property
if ( Policies . PropertyFilter & & Policies . PropertyFilter ( NewState . Property , CurrentState . Property ) )
{
continue ;
}
NewState . ArrayIndex = 0 ;
NewState . Data = CurrentState . Data ;
NewState . TypeInfo = FindClass ( NewState ) ;
StateStack . Push ( CurrentState ) ;
CurrentState = NewState ;
}
else
{
// error: array property not found
2014-10-01 18:20:53 -04:00
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 ( ) ;
}
}
break ;
case EStructDeserializerBackendTokens : : Error :
{
return false ;
}
case EStructDeserializerBackendTokens : : Property :
{
if ( PropertyName . IsEmpty ( ) )
{
2015-09-09 20:32:05 -04:00
// handle array element
2014-10-01 18:20:53 -04:00
UArrayProperty * ArrayProperty = Cast < UArrayProperty > ( CurrentState . Property ) ;
2015-09-09 20:32:05 -04:00
UProperty * Property = nullptr ;
2014-10-01 18:20:53 -04:00
if ( ArrayProperty ! = nullptr )
{
2015-09-09 20:32:05 -04:00
// dynamic array element
2014-10-01 18:20:53 -04:00
Property = ArrayProperty - > Inner ;
}
else
{
2015-09-09 20:32:05 -04:00
// static array element
2014-10-01 18:20:53 -04:00
Property = CurrentState . Property ;
}
if ( Property = = nullptr )
{
2015-09-09 20:32:05 -04:00
// error: no meta data for array element
2014-10-01 18:20:53 -04:00
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 ;
}
2015-09-09 20:32:05 -04:00
else if ( ( CurrentState . Property ! = nullptr ) & & ( CurrentState . Property - > GetClass ( ) = = UMapProperty : : StaticClass ( ) ) )
{
// handle map element
UMapProperty * MapProperty = Cast < UMapProperty > ( CurrentState . Property ) ;
FScriptMapHelper MapHelper ( MapProperty , MapProperty - > ContainerPtrToValuePtr < void > ( CurrentState . Data ) ) ;
UProperty * Property = MapProperty - > ValueProp ;
int32 PairIndex = MapHelper . AddDefaultValue_Invalid_NeedsRehash ( ) ;
uint8 * PairPtr = MapHelper . GetPairPtr ( PairIndex ) ;
MapProperty - > KeyProp - > ImportText ( * PropertyName , PairPtr + MapProperty - > MapLayout . KeyOffset , PPF_Delimited , nullptr ) ;
if ( ! Backend . ReadProperty ( Property , CurrentState . Property , PairPtr , CurrentState . ArrayIndex ) )
{
UE_LOG ( LogSerialization , Verbose , TEXT ( " An item in map '%s' could not be read (%s) " ) , * PropertyName , * Backend . GetDebugString ( ) ) ;
}
}
2014-10-01 18:20:53 -04:00
else
{
// handle scalar property
2015-09-09 20:32:05 -04:00
UProperty * Property = FindField < UProperty > ( CurrentState . TypeInfo , * PropertyName ) ;
2014-10-01 18:20:53 -04:00
2015-09-09 20:32:05 -04:00
if ( Property ! = nullptr )
2014-10-01 18:20:53 -04:00
{
2015-07-17 17:27:47 -04:00
if ( Policies . PropertyFilter & & Policies . PropertyFilter ( Property , CurrentState . Property ) )
{
continue ;
}
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 ( ) ) ;
}
2014-10-01 18:20:53 -04:00
}
2015-09-09 20:32:05 -04:00
else
{
// error: scalar 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 ;
}
}
2014-10-01 18:20:53 -04:00
}
}
break ;
case EStructDeserializerBackendTokens : : StructureEnd :
{
2015-09-09 20:32:05 -04:00
// rehash if value was a map
UMapProperty * MapProperty = Cast < UMapProperty > ( CurrentState . Property ) ;
if ( MapProperty ! = nullptr )
{
FScriptMapHelper MapHelper ( MapProperty , CurrentState . Data ) ;
MapHelper . Rehash ( ) ;
}
2014-10-01 18:20:53 -04:00
if ( StateStack . Num ( ) = = 0 )
{
return true ;
}
2015-09-09 20:32:05 -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 ;
}
2015-09-09 20:32:05 -04:00
// handle struct element inside array
2014-10-01 18:20:53 -04:00
UArrayProperty * ArrayProperty = Cast < UArrayProperty > ( CurrentState . Property ) ;
if ( ArrayProperty = = nullptr )
{
2015-09-09 20:32:05 -04:00
UE_LOG ( LogSerialization , Verbose , TEXT ( " Found unnamed value outside of array " ) ) ;
2014-10-01 18:20:53 -04:00
return false ;
}
FScriptArrayHelper ArrayHelper ( ArrayProperty , ArrayProperty - > ContainerPtrToValuePtr < void > ( CurrentState . Data ) ) ;
const int32 ArrayIndex = ArrayHelper . AddValue ( ) ;
NewState . Property = ArrayProperty - > Inner ;
NewState . Data = ArrayHelper . GetRawPtr ( ArrayIndex ) ;
}
2015-09-09 20:32:05 -04:00
else if ( ( CurrentState . Property ! = nullptr ) & & ( CurrentState . Property - > GetClass ( ) = = UMapProperty : : StaticClass ( ) ) )
{
// handle map or struct element inside map
UMapProperty * MapProperty = Cast < UMapProperty > ( CurrentState . Property ) ;
FScriptMapHelper MapHelper ( MapProperty , CurrentState . Data ) ;
int32 PairIndex = MapHelper . AddDefaultValue_Invalid_NeedsRehash ( ) ;
uint8 * PairPtr = MapHelper . GetPairPtr ( PairIndex ) ;
NewState . Data = PairPtr + MapHelper . MapLayout . ValueOffset ;
NewState . Property = MapProperty - > ValueProp ;
MapProperty - > KeyProp - > ImportText ( * PropertyName , PairPtr + MapProperty - > MapLayout . KeyOffset , PPF_None , nullptr ) ;
}
2014-10-01 18:20:53 -04:00
else
{
NewState . Property = FindField < UProperty > ( CurrentState . TypeInfo , * PropertyName ) ;
if ( NewState . Property = = nullptr )
{
2015-09-09 20:32:05 -04:00
// error: map or struct property not found
2014-10-01 18:20:53 -04:00
if ( Policies . MissingFields ! = EStructDeserializerErrorPolicies : : Ignore )
{
2015-09-09 20:32:05 -04:00
UE_LOG ( LogSerialization , Verbose , TEXT ( " Map or struct property '%s' not found " ) , * PropertyName ) ;
2014-10-01 18:20:53 -04:00
}
if ( Policies . MissingFields = = EStructDeserializerErrorPolicies : : Error )
{
return false ;
}
}
2015-09-09 20:32:05 -04:00
else if ( NewState . Property - > GetClass ( ) = = UMapProperty : : StaticClass ( ) )
{
// handle map property
UMapProperty * MapProperty = Cast < UMapProperty > ( NewState . Property ) ;
NewState . Data = MapProperty - > ContainerPtrToValuePtr < void > ( CurrentState . Data , CurrentState . ArrayIndex ) ;
FScriptMapHelper MapHelper ( MapProperty , NewState . Data ) ;
MapHelper . EmptyValues ( ) ;
}
2014-10-01 18:20:53 -04:00
else
{
2015-09-09 20:32:05 -04:00
// handle struct property
2014-10-01 18:20:53 -04:00
NewState . Data = NewState . Property - > ContainerPtrToValuePtr < void > ( CurrentState . Data ) ;
}
}
if ( NewState . Property ! = nullptr )
{
2015-09-09 20:32:05 -04:00
// skip struct property if property filter is set and rejects it
2015-07-17 17:27:47 -04:00
if ( Policies . PropertyFilter & & ! Policies . PropertyFilter ( NewState . Property , CurrentState . Property ) )
{
Backend . SkipStructure ( ) ;
continue ;
}
2014-10-01 18:20:53 -04:00
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 ;
}