// Copyright Epic Games, Inc. All Rights Reserved. #include "JsonUtils/JsonConversion.h" #include "Dom/JsonValue.h" #include "Dom/JsonObject.h" #include "Logging/StructuredLog.h" #include "Logging/LogMacros.h" DEFINE_LOG_CATEGORY_STATIC(LogJsonConversion, Display, All); namespace UE { namespace Json { namespace Private { static TOptional ConvertToRapidJsonValueInternal(const FJsonValue& SrcValue, FDocument::AllocatorType& Allocator) { switch (SrcValue.Type) { case EJson::None: return {}; case EJson::Null: return {FValue(rapidjson::kNullType)}; case EJson::String: { FString SrcString; if (ensure(SrcValue.TryGetString(SrcString))) { FValue Result(rapidjson::kStringType); Result.SetString(*SrcString, Allocator); return {MoveTemp(Result)}; } } return {}; case EJson::Number: { // all values in shared json discard their original types and are stored as doubles, this means that the reader functions have to do type conversions from doubles // to mimic the legacy behaviour as long as a legacy API exists. double SrcNumber = 0.0; if (ensure(SrcValue.TryGetNumber(SrcNumber))) { FValue Result(rapidjson::kNumberType); Result.SetDouble(SrcNumber); return {MoveTemp(Result)}; } } return {}; case EJson::Boolean: { bool SrcBool = false; if (ensure(SrcValue.TryGetBool(SrcBool))) { return {FValue(SrcBool)}; } } return {}; case EJson::Array: { const TArray>* SrcArray = nullptr; if (SrcValue.TryGetArray(SrcArray)) { FValue DstArray(rapidjson::kArrayType); for (const TSharedPtr& SrcArrayValue : *SrcArray) { TOptional DstArrayValue = ConvertToRapidJsonValueInternal(*SrcArrayValue, Allocator); if (DstArrayValue.IsSet()) { DstArray.PushBack(MoveTemp(*DstArrayValue), Allocator); } else { // should have logged already return {}; } } return {MoveTemp(DstArray)}; } } return {}; case EJson::Object: { const TSharedPtr* SrcObject = nullptr; if (SrcValue.TryGetObject(SrcObject)) { FValue DstObject(rapidjson::kObjectType); for (const TPair>& Member : (*SrcObject)->Values) { TOptional DstMember = ConvertToRapidJsonValueInternal(*Member.Value, Allocator); if (DstMember.IsSet()) { FValue KeyType(rapidjson::kStringType); KeyType.SetString(*Member.Key, Allocator); DstObject.AddMember(MoveTemp(KeyType), MoveTemp(*DstMember), Allocator); } else { // should have been logged already return {}; } } return {MoveTemp(DstObject)}; } } return {}; } UE_LOG(LogJsonConversion, Error, TEXT("UE::Json::Private::ConvertToRapidJsonValueInternal Unable to convert unknown default Json type %d"), SrcValue.Type); return {}; } } TSharedPtr ConvertRapidJsonToSharedJsonValue(const FValue& Value) { switch (Value.GetType()) { case rapidjson::kNullType: return MakeShared(); case rapidjson::kFalseType: return MakeShared(false); case rapidjson::kTrueType: return MakeShared(true); case rapidjson::kObjectType: { TSharedPtr DstObject = MakeShared(); FConstObject SrcObject = Value.GetObject(); for (FValue::ConstMemberIterator It = SrcObject.MemberBegin(); It != SrcObject.MemberEnd(); ++It) { TSharedPtr ChildValue = ConvertRapidJsonToSharedJsonValue(It->value); if (ChildValue.IsValid()) { DstObject->SetField(It->name.GetString(), MoveTemp(ChildValue)); } } return MakeShared(MoveTemp(DstObject)); } case rapidjson::kArrayType: { TArray> DstArray; for (const FValue& SrcValue : Value.GetArray()) { TSharedPtr DstValue = ConvertRapidJsonToSharedJsonValue(SrcValue); if (DstValue.IsValid()) { DstArray.Add(MoveTemp(DstValue)); } } return MakeShared(MoveTemp(DstArray)); } case rapidjson::kStringType: return MakeShared(Value.GetString()); case rapidjson::kNumberType: if (Value.IsDouble()) { return MakeShared(Value.GetDouble()); } else if (Value.IsInt64()) { return MakeShared(static_cast(Value.GetInt64())); } else if (Value.IsUint64()) { return MakeShared(static_cast(Value.GetUint64())); } } UE_LOG(LogJsonConversion, Warning, TEXT("UE::Json::ConvertRapidJsonToSharedJsonValue Unhandled value type %d"), int32(Value.GetType())); return {}; } TSharedPtr ConvertRapidJsonToSharedJsonObject(FConstObject Object) { TSharedPtr ResultValue = ConvertRapidJsonToSharedJsonValue(Object); if (!ResultValue.IsValid() || ResultValue->Type != EJson::Object) { UE_LOG(LogJsonConversion, Error, TEXT("UE::Json::ConvertRapidJsonToSharedJsonObject unable to convert JSON object")); return {}; } return ResultValue->AsObject(); } TOptional ConvertSharedJsonToRapidJsonDocument(const FJsonObject& SrcObject) { FDocument DstDocument; DstDocument.SetObject(); FDocument::AllocatorType& Allocator = DstDocument.GetAllocator(); for (const TPair>& SrcField : SrcObject.Values) { TOptional DstMember = Private::ConvertToRapidJsonValueInternal(*SrcField.Value, Allocator); if (DstMember.IsSet()) { FValue KeyType(rapidjson::kStringType); KeyType.SetString(*SrcField.Key, Allocator); DstDocument.AddMember(MoveTemp(KeyType), MoveTemp(*DstMember), Allocator); } } return MoveTemp(DstDocument); } }} // namespace UE::Json