715 lines
24 KiB
C++
715 lines
24 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#pragma once
|
|
|
|
#include "CoreMinimal.h"
|
|
|
|
#include "HAL/Platform.h"
|
|
|
|
#include "IStructSerializerBackend.h"
|
|
#include "IStructDeserializerBackend.h"
|
|
#include "Serialization/JsonWriter.h"
|
|
#include "Serialization/JsonReader.h"
|
|
|
|
#include "UObject/Class.h"
|
|
#include "UObject/UnrealType.h"
|
|
#include "UObject/EnumProperty.h"
|
|
#include "UObject/TextProperty.h"
|
|
|
|
// This file is largely copied from JsonStructSerializerBackend / JsonStructDeserializerBackend.
|
|
// The primary difference is that it exposes template args for which character encoding to use,
|
|
// as well as our printing policy.
|
|
|
|
namespace Metasound
|
|
{
|
|
typedef ANSICHAR DefaultCharType;
|
|
|
|
struct StructDeserializerBackendUtilities
|
|
{
|
|
/**
|
|
* Clears the value of the given property.
|
|
*
|
|
* @param Property The property to clear.
|
|
* @param Outer The property that contains the property to be cleared, if any.
|
|
* @param Data A pointer to the memory holding the property's data.
|
|
* @param ArrayIndex The index of the element to clear (if the property is an array).
|
|
* @return true on success, false otherwise.
|
|
* @see SetPropertyValue
|
|
*/
|
|
static bool ClearPropertyValue(FProperty* Property, FProperty* Outer, void* Data, int32 ArrayIndex)
|
|
{
|
|
FArrayProperty* ArrayProperty = CastField<FArrayProperty>(Outer);
|
|
|
|
if (ArrayProperty != nullptr)
|
|
{
|
|
if (ArrayProperty->Inner != Property)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
FScriptArrayHelper ArrayHelper(ArrayProperty, ArrayProperty->template ContainerPtrToValuePtr<void>(Data));
|
|
ArrayIndex = ArrayHelper.AddValue();
|
|
}
|
|
|
|
Property->ClearValue_InContainer(Data, ArrayIndex);
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
/**
|
|
* Gets a pointer to object of the given property.
|
|
*
|
|
* @param Property The property to get.
|
|
* @param Outer The property that contains the property to be get, if any.
|
|
* @param Data A pointer to the memory holding the property's data.
|
|
* @param ArrayIndex The index of the element to set (if the property is an array).
|
|
* @return A pointer to the object represented by the property, null otherwise..
|
|
* @see ClearPropertyValue
|
|
*/
|
|
static void* GetPropertyValuePtr(FProperty* Property, FProperty* Outer, void* Data, int32 ArrayIndex)
|
|
{
|
|
check(Property);
|
|
|
|
if (FArrayProperty* ArrayProperty = CastField<FArrayProperty>(Outer))
|
|
{
|
|
if (ArrayProperty->Inner != Property)
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
FScriptArrayHelper ArrayHelper(ArrayProperty, ArrayProperty->template ContainerPtrToValuePtr<void>(Data));
|
|
int32 Index = ArrayHelper.AddValue();
|
|
|
|
return ArrayHelper.GetRawPtr(Index);
|
|
}
|
|
|
|
if (ArrayIndex >= Property->ArrayDim)
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
return Property->template ContainerPtrToValuePtr<void>(Data, ArrayIndex);
|
|
}
|
|
|
|
/**
|
|
* Sets the value of the given property.
|
|
*
|
|
* @param Property The property to set.
|
|
* @param Outer The property that contains the property to be set, if any.
|
|
* @param Data A pointer to the memory holding the property's data.
|
|
* @param ArrayIndex The index of the element to set (if the property is an array).
|
|
* @return true on success, false otherwise.
|
|
* @see ClearPropertyValue
|
|
*/
|
|
template<typename PropertyType, typename ValueType>
|
|
static bool SetPropertyValue(PropertyType* Property, FProperty* Outer, void* Data, int32 ArrayIndex, const ValueType& Value)
|
|
{
|
|
if (void* Ptr = GetPropertyValuePtr(Property, Outer, Data, ArrayIndex))
|
|
{
|
|
Property->SetPropertyValue(Ptr, Value);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
};
|
|
|
|
namespace JsonStructSerializerBackend
|
|
{
|
|
// Writes a property value to the serialization output.
|
|
template<typename JsonWriterType, typename ValueType>
|
|
static void WritePropertyValue(const TSharedRef<JsonWriterType> JsonWriter, const FStructSerializerState& State, const ValueType& Value)
|
|
{
|
|
if ((State.ValueProperty == nullptr) ||
|
|
(State.ValueProperty->ArrayDim > 1) ||
|
|
State.ValueProperty->GetOwner<FArrayProperty>() ||
|
|
State.ValueProperty->GetOwner<FSetProperty>())
|
|
{
|
|
JsonWriter->WriteValue(Value);
|
|
}
|
|
else if (State.KeyProperty != nullptr)
|
|
{
|
|
FString KeyString;
|
|
State.KeyProperty->ExportTextItem_Direct(KeyString, State.KeyData, nullptr, nullptr, PPF_None);
|
|
JsonWriter->WriteValue(KeyString, Value);
|
|
}
|
|
else
|
|
{
|
|
JsonWriter->WriteValue(State.ValueProperty->GetName(), Value);
|
|
}
|
|
}
|
|
|
|
// Writes a null value to the serialization output.
|
|
static void WriteNull(const TSharedRef<TJsonWriter<UCS2CHAR>> JsonWriter, const FStructSerializerState& State)
|
|
{
|
|
if ((State.ValueProperty == nullptr) ||
|
|
(State.ValueProperty->ArrayDim > 1) ||
|
|
State.ValueProperty->GetOwner<FArrayProperty>() ||
|
|
State.ValueProperty->GetOwner<FSetProperty>())
|
|
{
|
|
JsonWriter->WriteNull();
|
|
}
|
|
else if (State.KeyProperty != nullptr)
|
|
{
|
|
FString KeyString;
|
|
State.KeyProperty->ExportTextItem_Direct(KeyString, State.KeyData, nullptr, nullptr, PPF_None);
|
|
JsonWriter->WriteNull(KeyString);
|
|
}
|
|
else
|
|
{
|
|
JsonWriter->WriteNull(State.ValueProperty->GetName());
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Implements a writer for UStruct serialization using Json.
|
|
*
|
|
* Optionally, CharType and PrettyPrintPolicy can be subsituted using template arguments.
|
|
*/
|
|
template <class CharType, class PrintPolicy = TPrettyJsonPrintPolicy<CharType>>
|
|
class TJsonStructSerializerBackend
|
|
: public IStructSerializerBackend
|
|
{
|
|
public:
|
|
|
|
/**
|
|
* Creates and initializes a new legacy instance.
|
|
* @note Deprecated, use the two-parameter constructor with EStructSerializerBackendFlags::Legacy if you need backwards compatibility with code compiled prior to 4.22.
|
|
*
|
|
* @param InArchive The archive to serialize into.
|
|
*/
|
|
UE_DEPRECATED(4.22, "Use the two-parameter constructor with EStructSerializerBackendFlags::Legacy only if you need backwards compatibility with code compiled prior to 4.22; otherwise use EStructSerializerBackendFlags::Default.")
|
|
TJsonStructSerializerBackend(FArchive& InArchive)
|
|
: JsonWriter(TJsonWriter<CharType, PrintPolicy>::Create(&InArchive))
|
|
, Flags(EStructSerializerBackendFlags::Legacy)
|
|
{ }
|
|
|
|
/**
|
|
* Creates and initializes a new instance with the given flags.
|
|
*
|
|
* @param InArchive The archive to serialize into.
|
|
* @param InFlags The flags that control the serialization behavior (typically EStructSerializerBackendFlags::Default).
|
|
*/
|
|
TJsonStructSerializerBackend(FArchive& InArchive, const EStructSerializerBackendFlags InFlags)
|
|
: JsonWriter(TJsonWriter<CharType, PrintPolicy>::Create(&InArchive))
|
|
, Flags(InFlags)
|
|
{ }
|
|
|
|
~TJsonStructSerializerBackend() = default;
|
|
|
|
public:
|
|
|
|
// IStructSerializerBackend interface
|
|
|
|
virtual void BeginArray(const FStructSerializerState& State) override
|
|
{
|
|
if (State.ValueProperty->GetOwner<FArrayProperty>())
|
|
{
|
|
JsonWriter->WriteArrayStart();
|
|
}
|
|
else if (State.KeyProperty != nullptr)
|
|
{
|
|
FString KeyString;
|
|
State.KeyProperty->ExportTextItem_Direct(KeyString, State.KeyData, nullptr, nullptr, PPF_None);
|
|
JsonWriter->WriteArrayStart(KeyString);
|
|
}
|
|
else
|
|
{
|
|
JsonWriter->WriteArrayStart(State.ValueProperty->GetName());
|
|
}
|
|
}
|
|
|
|
virtual void BeginStructure(const FStructSerializerState& State) override
|
|
{
|
|
if (State.ValueProperty != nullptr)
|
|
{
|
|
if (State.ValueProperty->GetOwner<FArrayProperty>() || State.ValueProperty->GetOwner<FSetProperty>())
|
|
{
|
|
JsonWriter->WriteObjectStart();
|
|
}
|
|
else if (State.KeyProperty != nullptr)
|
|
{
|
|
FString KeyString;
|
|
State.KeyProperty->ExportTextItem_Direct(KeyString, State.KeyData, nullptr, nullptr, PPF_None);
|
|
JsonWriter->WriteObjectStart(KeyString);
|
|
}
|
|
else
|
|
{
|
|
JsonWriter->WriteObjectStart(State.ValueProperty->GetName());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
JsonWriter->WriteObjectStart();
|
|
}
|
|
}
|
|
|
|
virtual void EndArray(const FStructSerializerState& State) override
|
|
{
|
|
JsonWriter->WriteArrayEnd();
|
|
}
|
|
|
|
virtual void EndStructure(const FStructSerializerState& State) override
|
|
{
|
|
JsonWriter->WriteObjectEnd();
|
|
}
|
|
|
|
virtual void WriteComment(const FString& Comment) override
|
|
{
|
|
// Json does not support comments
|
|
}
|
|
|
|
virtual void WriteProperty(const FStructSerializerState& State, int32 ArrayIndex = 0) override
|
|
{
|
|
using namespace JsonStructSerializerBackend;
|
|
|
|
// booleans
|
|
if (State.FieldType == FBoolProperty::StaticClass())
|
|
{
|
|
WritePropertyValue(JsonWriter, State, CastFieldChecked<FBoolProperty>(State.ValueProperty)->GetPropertyValue_InContainer(State.ValueData, ArrayIndex));
|
|
}
|
|
|
|
// unsigned bytes & enumerations
|
|
else if (State.FieldType == FEnumProperty::StaticClass())
|
|
{
|
|
FEnumProperty* EnumProperty = CastFieldChecked<FEnumProperty>(State.ValueProperty);
|
|
|
|
WritePropertyValue(JsonWriter, State, EnumProperty->GetEnum()->GetNameStringByValue(EnumProperty->GetUnderlyingProperty()->GetSignedIntPropertyValue(EnumProperty->ContainerPtrToValuePtr<void>(State.ValueData, ArrayIndex))));
|
|
}
|
|
else if (State.FieldType == FByteProperty::StaticClass())
|
|
{
|
|
FByteProperty* ByteProperty = CastFieldChecked<FByteProperty>(State.ValueProperty);
|
|
|
|
if (ByteProperty->IsEnum())
|
|
{
|
|
WritePropertyValue(JsonWriter, State, ByteProperty->Enum->GetNameStringByValue(ByteProperty->GetPropertyValue_InContainer(State.ValueData, ArrayIndex)));
|
|
}
|
|
else
|
|
{
|
|
WritePropertyValue(JsonWriter, State, (double)ByteProperty->GetPropertyValue_InContainer(State.ValueData, ArrayIndex));
|
|
}
|
|
}
|
|
|
|
// floating point numbers
|
|
else if (State.FieldType == FDoubleProperty::StaticClass())
|
|
{
|
|
WritePropertyValue(JsonWriter, State, CastFieldChecked<FDoubleProperty>(State.ValueProperty)->GetPropertyValue_InContainer(State.ValueData, ArrayIndex));
|
|
}
|
|
else if (State.FieldType == FFloatProperty::StaticClass())
|
|
{
|
|
WritePropertyValue(JsonWriter, State, CastFieldChecked<FFloatProperty>(State.ValueProperty)->GetPropertyValue_InContainer(State.ValueData, ArrayIndex));
|
|
}
|
|
|
|
// signed integers
|
|
else if (State.FieldType == FIntProperty::StaticClass())
|
|
{
|
|
WritePropertyValue(JsonWriter, State, (double)CastFieldChecked<FIntProperty>(State.ValueProperty)->GetPropertyValue_InContainer(State.ValueData, ArrayIndex));
|
|
}
|
|
else if (State.FieldType == FInt8Property::StaticClass())
|
|
{
|
|
WritePropertyValue(JsonWriter, State, (double)CastFieldChecked<FInt8Property>(State.ValueProperty)->GetPropertyValue_InContainer(State.ValueData, ArrayIndex));
|
|
}
|
|
else if (State.FieldType == FInt16Property::StaticClass())
|
|
{
|
|
WritePropertyValue(JsonWriter, State, (double)CastFieldChecked<FInt16Property>(State.ValueProperty)->GetPropertyValue_InContainer(State.ValueData, ArrayIndex));
|
|
}
|
|
else if (State.FieldType == FInt64Property::StaticClass())
|
|
{
|
|
WritePropertyValue(JsonWriter, State, (double)CastFieldChecked<FInt64Property>(State.ValueProperty)->GetPropertyValue_InContainer(State.ValueData, ArrayIndex));
|
|
}
|
|
|
|
// unsigned integers
|
|
else if (State.FieldType == FUInt16Property::StaticClass())
|
|
{
|
|
WritePropertyValue(JsonWriter, State, (double)CastFieldChecked<FUInt16Property>(State.ValueProperty)->GetPropertyValue_InContainer(State.ValueData, ArrayIndex));
|
|
}
|
|
else if (State.FieldType == FUInt32Property::StaticClass())
|
|
{
|
|
WritePropertyValue(JsonWriter, State, (double)CastFieldChecked<FUInt32Property>(State.ValueProperty)->GetPropertyValue_InContainer(State.ValueData, ArrayIndex));
|
|
}
|
|
else if (State.FieldType == FUInt64Property::StaticClass())
|
|
{
|
|
WritePropertyValue(JsonWriter, State, (double)CastFieldChecked<FUInt64Property>(State.ValueProperty)->GetPropertyValue_InContainer(State.ValueData, ArrayIndex));
|
|
}
|
|
|
|
// names, strings & text
|
|
else if (State.FieldType == FNameProperty::StaticClass())
|
|
{
|
|
WritePropertyValue(JsonWriter, State, CastFieldChecked<FNameProperty>(State.ValueProperty)->GetPropertyValue_InContainer(State.ValueData, ArrayIndex).ToString());
|
|
}
|
|
else if (State.FieldType == FStrProperty::StaticClass())
|
|
{
|
|
WritePropertyValue(JsonWriter, State, CastFieldChecked<FStrProperty>(State.ValueProperty)->GetPropertyValue_InContainer(State.ValueData, ArrayIndex));
|
|
}
|
|
else if (State.FieldType == FTextProperty::StaticClass())
|
|
{
|
|
const FText& TextValue = CastFieldChecked<FTextProperty>(State.ValueProperty)->GetPropertyValue_InContainer(State.ValueData, ArrayIndex);
|
|
if (EnumHasAnyFlags(Flags, EStructSerializerBackendFlags::WriteTextAsComplexString))
|
|
{
|
|
FString TextValueString;
|
|
FTextStringHelper::WriteToBuffer(TextValueString, TextValue);
|
|
WritePropertyValue(JsonWriter, State, TextValueString);
|
|
}
|
|
else
|
|
{
|
|
WritePropertyValue(JsonWriter, State, TextValue.ToString());
|
|
}
|
|
}
|
|
|
|
// classes & objects
|
|
else if (State.FieldType == FSoftClassProperty::StaticClass())
|
|
{
|
|
FSoftObjectPtr const& Value = CastFieldChecked<FSoftClassProperty>(State.ValueProperty)->GetPropertyValue_InContainer(State.ValueData, ArrayIndex);
|
|
WritePropertyValue(JsonWriter, State, Value.IsValid() ? Value->GetPathName() : FString());
|
|
}
|
|
else if (State.FieldType == FWeakObjectProperty::StaticClass())
|
|
{
|
|
FWeakObjectPtr const& Value = CastFieldChecked<FWeakObjectProperty>(State.ValueProperty)->GetPropertyValue_InContainer(State.ValueData, ArrayIndex);
|
|
WritePropertyValue(JsonWriter, State, Value.IsValid() ? Value.Get()->GetPathName() : FString());
|
|
}
|
|
else if (State.FieldType == FSoftObjectProperty::StaticClass())
|
|
{
|
|
FSoftObjectPtr const& Value = CastFieldChecked<FSoftObjectProperty>(State.ValueProperty)->GetPropertyValue_InContainer(State.ValueData, ArrayIndex);
|
|
WritePropertyValue(JsonWriter, State, Value.ToString());
|
|
}
|
|
else if (FObjectProperty* ObjectProperty = CastField<FObjectProperty>(State.ValueProperty))
|
|
{
|
|
// @TODO: Could this be expanded to include everything derived from FObjectPropertyBase?
|
|
// Generic handling for a property type derived from FObjectProperty that is obtainable as a pointer and will be stored using its path.
|
|
// This must come after all the more specialized handlers for object property types.
|
|
UObject* const Value = ObjectProperty->GetObjectPropertyValue_InContainer(State.ValueData, ArrayIndex);
|
|
WritePropertyValue(JsonWriter, State, Value ? Value->GetPathName() : FString());
|
|
}
|
|
|
|
// unsupported property type
|
|
else
|
|
{
|
|
UE_LOG(LogSerialization, Verbose, TEXT("FJsonStructSerializerBackend: Property %s cannot be serialized, because its type (%s) is not supported"), *State.ValueProperty->GetFName().ToString(), *State.ValueType->GetFName().ToString());
|
|
}
|
|
}
|
|
|
|
protected:
|
|
|
|
// Allow access to the internal JsonWriter to subclasses
|
|
TSharedRef<TJsonWriter<CharType, PrintPolicy>>& GetWriter()
|
|
{
|
|
return JsonWriter;
|
|
}
|
|
|
|
private:
|
|
|
|
/** Holds the Json writer used for the actual serialization. */
|
|
TSharedRef<TJsonWriter<CharType, PrintPolicy>> JsonWriter;
|
|
|
|
/** Flags controlling the serialization behavior. */
|
|
EStructSerializerBackendFlags Flags;
|
|
};
|
|
|
|
|
|
/**
|
|
* Implements a reader for UStruct deserialization using Json.
|
|
*
|
|
* Optionally, CharType that we're decoding from can be substituted using the CharType template argument.
|
|
*/
|
|
template <class CharType>
|
|
class TJsonStructDeserializerBackend
|
|
: public IStructDeserializerBackend
|
|
{
|
|
public:
|
|
|
|
/**
|
|
* Creates and initializes a new instance.
|
|
*
|
|
* @param Archive The archive to deserialize from.
|
|
*/
|
|
TJsonStructDeserializerBackend(FArchive& Archive)
|
|
: JsonReader(TJsonReader<CharType>::Create(&Archive))
|
|
{ }
|
|
|
|
~TJsonStructDeserializerBackend() = default;
|
|
|
|
public:
|
|
|
|
// IStructDeserializerBackend interface
|
|
|
|
virtual const FString& GetCurrentPropertyName() const override
|
|
{
|
|
return JsonReader->GetIdentifier();
|
|
}
|
|
|
|
virtual FString GetDebugString() const override
|
|
{
|
|
return FString::Printf(TEXT("Line: %u, Ch: %u"), JsonReader->GetLineNumber(), JsonReader->GetCharacterNumber());
|
|
}
|
|
|
|
virtual const FString& GetLastErrorMessage() const override
|
|
{
|
|
return JsonReader->GetErrorMessage();
|
|
}
|
|
|
|
virtual bool GetNextToken(EStructDeserializerBackendTokens& OutToken) override
|
|
{
|
|
if (!JsonReader->ReadNext(LastNotation))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
switch (LastNotation)
|
|
{
|
|
case EJsonNotation::ArrayEnd:
|
|
OutToken = EStructDeserializerBackendTokens::ArrayEnd;
|
|
break;
|
|
|
|
case EJsonNotation::ArrayStart:
|
|
OutToken = EStructDeserializerBackendTokens::ArrayStart;
|
|
break;
|
|
|
|
case EJsonNotation::Boolean:
|
|
case EJsonNotation::Null:
|
|
case EJsonNotation::Number:
|
|
case EJsonNotation::String:
|
|
{
|
|
OutToken = EStructDeserializerBackendTokens::Property;
|
|
}
|
|
break;
|
|
|
|
case EJsonNotation::Error:
|
|
OutToken = EStructDeserializerBackendTokens::Error;
|
|
break;
|
|
|
|
case EJsonNotation::ObjectEnd:
|
|
OutToken = EStructDeserializerBackendTokens::StructureEnd;
|
|
break;
|
|
|
|
case EJsonNotation::ObjectStart:
|
|
OutToken = EStructDeserializerBackendTokens::StructureStart;
|
|
break;
|
|
|
|
default:
|
|
OutToken = EStructDeserializerBackendTokens::None;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
virtual bool ReadProperty(FProperty* Property, FProperty* Outer, void* Data, int32 ArrayIndex) override
|
|
{
|
|
switch (LastNotation)
|
|
{
|
|
// boolean values
|
|
case EJsonNotation::Boolean:
|
|
{
|
|
bool BoolValue = JsonReader->GetValueAsBoolean();
|
|
|
|
if (FBoolProperty* BoolProperty = CastField<FBoolProperty>(Property))
|
|
{
|
|
return StructDeserializerBackendUtilities::SetPropertyValue(BoolProperty, Outer, Data, ArrayIndex, BoolValue);
|
|
}
|
|
|
|
const FCoreTexts& CoreTexts = FCoreTexts::Get();
|
|
|
|
UE_LOG(LogSerialization, Verbose, TEXT("Boolean field %s with value '%s' is not supported in FProperty type %s (%s)"), *Property->GetFName().ToString(), BoolValue ? *(CoreTexts.True.ToString()) : *(CoreTexts.False.ToString()), *Property->GetClass()->GetName(), *GetDebugString());
|
|
|
|
return false;
|
|
}
|
|
break;
|
|
|
|
// numeric values
|
|
case EJsonNotation::Number:
|
|
{
|
|
double NumericValue = JsonReader->GetValueAsNumber();
|
|
|
|
if (FByteProperty* ByteProperty = CastField<FByteProperty>(Property))
|
|
{
|
|
return StructDeserializerBackendUtilities::SetPropertyValue(ByteProperty, Outer, Data, ArrayIndex, (int8)NumericValue);
|
|
}
|
|
|
|
if (FDoubleProperty* DoubleProperty = CastField<FDoubleProperty>(Property))
|
|
{
|
|
return StructDeserializerBackendUtilities::SetPropertyValue(DoubleProperty, Outer, Data, ArrayIndex, (double)NumericValue);
|
|
}
|
|
|
|
if (FFloatProperty* FloatProperty = CastField<FFloatProperty>(Property))
|
|
{
|
|
return StructDeserializerBackendUtilities::SetPropertyValue(FloatProperty, Outer, Data, ArrayIndex, (float)NumericValue);
|
|
}
|
|
|
|
if (FIntProperty* IntProperty = CastField<FIntProperty>(Property))
|
|
{
|
|
return StructDeserializerBackendUtilities::SetPropertyValue(IntProperty, Outer, Data, ArrayIndex, (int32)NumericValue);
|
|
}
|
|
|
|
if (FUInt32Property* UInt32Property = CastField<FUInt32Property>(Property))
|
|
{
|
|
return StructDeserializerBackendUtilities::SetPropertyValue(UInt32Property, Outer, Data, ArrayIndex, (uint32)NumericValue);
|
|
}
|
|
|
|
if (FInt16Property* Int16Property = CastField<FInt16Property>(Property))
|
|
{
|
|
return StructDeserializerBackendUtilities::SetPropertyValue(Int16Property, Outer, Data, ArrayIndex, (int16)NumericValue);
|
|
}
|
|
|
|
if (FUInt16Property* FInt16Property = CastField<FUInt16Property>(Property))
|
|
{
|
|
return StructDeserializerBackendUtilities::SetPropertyValue(FInt16Property, Outer, Data, ArrayIndex, (uint16)NumericValue);
|
|
}
|
|
|
|
if (FInt64Property* Int64Property = CastField<FInt64Property>(Property))
|
|
{
|
|
return StructDeserializerBackendUtilities::SetPropertyValue(Int64Property, Outer, Data, ArrayIndex, (int64)NumericValue);
|
|
}
|
|
|
|
if (FUInt64Property* FInt64Property = CastField<FUInt64Property>(Property))
|
|
{
|
|
return StructDeserializerBackendUtilities::SetPropertyValue(FInt64Property, Outer, Data, ArrayIndex, (uint64)NumericValue);
|
|
}
|
|
|
|
if (FInt8Property* Int8Property = CastField<FInt8Property>(Property))
|
|
{
|
|
return StructDeserializerBackendUtilities::SetPropertyValue(Int8Property, Outer, Data, ArrayIndex, (int8)NumericValue);
|
|
}
|
|
|
|
UE_LOG(LogSerialization, Verbose, TEXT("Numeric field %s with value '%f' is not supported in FProperty type %s (%s)"), *Property->GetFName().ToString(), NumericValue, *Property->GetClass()->GetName(), *GetDebugString());
|
|
|
|
return false;
|
|
}
|
|
break;
|
|
|
|
// null values
|
|
case EJsonNotation::Null:
|
|
return StructDeserializerBackendUtilities::ClearPropertyValue(Property, Outer, Data, ArrayIndex);
|
|
|
|
// strings, names, enumerations & object/class reference
|
|
case EJsonNotation::String:
|
|
{
|
|
const FString& StringValue = JsonReader->GetValueAsString();
|
|
|
|
if (FStrProperty* StrProperty = CastField<FStrProperty>(Property))
|
|
{
|
|
return StructDeserializerBackendUtilities::SetPropertyValue(StrProperty, Outer, Data, ArrayIndex, StringValue);
|
|
}
|
|
|
|
if (FNameProperty* NameProperty = CastField<FNameProperty>(Property))
|
|
{
|
|
return StructDeserializerBackendUtilities::SetPropertyValue(NameProperty, Outer, Data, ArrayIndex, FName(*StringValue));
|
|
}
|
|
|
|
if (FTextProperty* TextProperty = CastField<FTextProperty>(Property))
|
|
{
|
|
FText TextValue;
|
|
if (!FTextStringHelper::ReadFromBuffer(*StringValue, TextValue))
|
|
{
|
|
TextValue = FText::FromString(StringValue);
|
|
}
|
|
return StructDeserializerBackendUtilities::SetPropertyValue(TextProperty, Outer, Data, ArrayIndex, TextValue);
|
|
}
|
|
|
|
if (FByteProperty* ByteProperty = CastField<FByteProperty>(Property))
|
|
{
|
|
if (!ByteProperty->Enum)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
int32 Value = ByteProperty->Enum->GetValueByName(*StringValue);
|
|
if (Value == INDEX_NONE)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return StructDeserializerBackendUtilities::SetPropertyValue(ByteProperty, Outer, Data, ArrayIndex, (uint8)Value);
|
|
}
|
|
|
|
if (FEnumProperty* EnumProperty = CastField<FEnumProperty>(Property))
|
|
{
|
|
int64 Value = EnumProperty->GetEnum()->GetValueByName(*StringValue);
|
|
if (Value == INDEX_NONE)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (void* ElementPtr = StructDeserializerBackendUtilities::GetPropertyValuePtr(EnumProperty, Outer, Data, ArrayIndex))
|
|
{
|
|
EnumProperty->GetUnderlyingProperty()->SetIntPropertyValue(ElementPtr, Value);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
if (FClassProperty* ClassProperty = CastField<FClassProperty>(Property))
|
|
{
|
|
return StructDeserializerBackendUtilities::SetPropertyValue(ClassProperty, Outer, Data, ArrayIndex, LoadObject<UClass>(nullptr, *StringValue, nullptr, LOAD_NoWarn));
|
|
}
|
|
|
|
if (FSoftClassProperty* SoftClassProperty = CastField<FSoftClassProperty>(Property))
|
|
{
|
|
return StructDeserializerBackendUtilities::SetPropertyValue(SoftClassProperty, Outer, Data, ArrayIndex, FSoftObjectPtr(LoadObject<UClass>(nullptr, *StringValue, nullptr, LOAD_NoWarn)));
|
|
}
|
|
|
|
if (FObjectProperty* ObjectProperty = CastField<FObjectProperty>(Property))
|
|
{
|
|
return StructDeserializerBackendUtilities::SetPropertyValue(ObjectProperty, Outer, Data, ArrayIndex, StaticFindObject(ObjectProperty->PropertyClass, nullptr, *StringValue));
|
|
}
|
|
|
|
if (FWeakObjectProperty* WeakObjectProperty = CastField<FWeakObjectProperty>(Property))
|
|
{
|
|
return StructDeserializerBackendUtilities::SetPropertyValue(WeakObjectProperty, Outer, Data, ArrayIndex, FWeakObjectPtr(StaticFindObject(WeakObjectProperty->PropertyClass, nullptr, *StringValue)));
|
|
}
|
|
|
|
if (FSoftObjectProperty* SoftObjectProperty = CastField<FSoftObjectProperty>(Property))
|
|
{
|
|
return StructDeserializerBackendUtilities::SetPropertyValue(SoftObjectProperty, Outer, Data, ArrayIndex, FSoftObjectPtr(FSoftObjectPath(StringValue)));
|
|
}
|
|
|
|
UE_LOG(LogSerialization, Verbose, TEXT("String field %s with value '%s' is not supported in FProperty type %s (%s)"), *Property->GetFName().ToString(), *StringValue, *Property->GetClass()->GetName(), *GetDebugString());
|
|
|
|
return false;
|
|
}
|
|
break;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
virtual void SkipArray() override
|
|
{
|
|
JsonReader->SkipArray();
|
|
}
|
|
|
|
virtual void SkipStructure() override
|
|
{
|
|
JsonReader->SkipObject();
|
|
}
|
|
|
|
protected:
|
|
FString& GetLastIdentifier()
|
|
{
|
|
return LastIdentifier;
|
|
}
|
|
|
|
EJsonNotation GetLastNotation()
|
|
{
|
|
return LastNotation;
|
|
}
|
|
|
|
TSharedRef<TJsonReader<CharType>>& GetReader()
|
|
{
|
|
return JsonReader;
|
|
}
|
|
|
|
private:
|
|
|
|
/** Holds the name of the last read Json identifier. */
|
|
FString LastIdentifier;
|
|
|
|
/** Holds the last read Json notation. */
|
|
EJsonNotation LastNotation;
|
|
|
|
/** Holds the Json reader used for the actual reading of the archive. */
|
|
TSharedRef<TJsonReader<CharType>> JsonReader;
|
|
};
|
|
}
|