Goran Lazarevski 669cf5383b Lucky World source code
2025-03-18 19:25:25 +01:00

802 lines
18 KiB
C++

// Copyright 2014-2019 Vladimir Alyamkin. All Rights Reserved.
#include "VaRestJsonObject.h"
#include "VaRestDefines.h"
#include "VaRestJsonParser.h"
#include "VaRestJsonValue.h"
#include "HAL/FileManager.h"
#include "Misc/Paths.h"
#include "Policies/CondensedJsonPrintPolicy.h"
#include "Serialization/JsonSerializer.h"
#include "Serialization/JsonWriter.h"
typedef TJsonWriterFactory<TCHAR, TCondensedJsonPrintPolicy<TCHAR>> FCondensedJsonStringWriterFactory;
typedef TJsonWriter<TCHAR, TCondensedJsonPrintPolicy<TCHAR>> FCondensedJsonStringWriter;
UVaRestJsonObject::UVaRestJsonObject(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
, JsonObj(MakeShared<FJsonObject>())
{
}
void UVaRestJsonObject::Reset()
{
JsonObj = MakeShared<FJsonObject>();
}
TSharedRef<FJsonObject>& UVaRestJsonObject::GetRootObject()
{
return JsonObj;
}
void UVaRestJsonObject::SetRootObject(const TSharedPtr<FJsonObject>& JsonObject)
{
if (JsonObject.IsValid())
{
JsonObj = JsonObject.ToSharedRef();
}
else
{
UE_LOG(LogVaRest, Error, TEXT("%s: Trying to set invalid json object as root one. Reset now."), *VA_FUNC_LINE);
Reset();
}
}
//////////////////////////////////////////////////////////////////////////
// Serialization
FString UVaRestJsonObject::EncodeJson() const
{
FString OutputString;
const auto Writer = TJsonWriterFactory<>::Create(&OutputString);
FJsonSerializer::Serialize(JsonObj, Writer);
return OutputString;
}
FString UVaRestJsonObject::EncodeJsonToSingleString() const
{
FString OutputString;
const auto Writer = FCondensedJsonStringWriterFactory::Create(&OutputString);
FJsonSerializer::Serialize(JsonObj, Writer);
return OutputString;
}
bool UVaRestJsonObject::DecodeJson(const FString& JsonString, bool bUseIncrementalParser)
{
if (bUseIncrementalParser)
{
const int32 BytesRead = DeserializeFromTCHARBytes(JsonString.GetCharArray().GetData(), JsonString.Len());
// JsonObj is always valid, but read bytes is zero when something went wrong
if (BytesRead > 0)
{
return true;
}
}
else
{
const TSharedRef<TJsonReader<>> Reader = TJsonReaderFactory<>::Create(*JsonString);
TSharedPtr<FJsonObject> OutJsonObj;
if (FJsonSerializer::Deserialize(Reader, OutJsonObj))
{
JsonObj = OutJsonObj.ToSharedRef();
return true;
}
}
// If we've failed to deserialize the string, we should clear our internal data
Reset();
UE_LOG(LogVaRest, Error, TEXT("Json decoding failed for: %s"), *JsonString);
return false;
}
//////////////////////////////////////////////////////////////////////////
// FJsonObject API
FString UVaRestJsonObject::GetFieldTypeString(const FString& FieldName) const
{
if (!JsonObj->HasTypedField<EJson::Null>(FieldName))
{
return TEXT("Null");
}
else if (!JsonObj->HasTypedField<EJson::String>(FieldName))
{
return TEXT("String");
}
else if (!JsonObj->HasTypedField<EJson::Number>(FieldName))
{
return TEXT("Number");
}
else if (!JsonObj->HasTypedField<EJson::Boolean>(FieldName))
{
return TEXT("Boolean");
}
else if (!JsonObj->HasTypedField<EJson::Object>(FieldName))
{
return TEXT("Object");
}
else if (!JsonObj->HasTypedField<EJson::Array>(FieldName))
{
return TEXT("Array");
}
UE_LOG(LogVaRest, Warning, TEXT("Field with name %s type unknown"), *FieldName);
return "";
}
TArray<FString> UVaRestJsonObject::GetFieldNames() const
{
TArray<FString> Result;
JsonObj->Values.GetKeys(Result);
return Result;
}
bool UVaRestJsonObject::HasField(const FString& FieldName) const
{
if (FieldName.IsEmpty())
{
return false;
}
return JsonObj->HasField(FieldName);
}
void UVaRestJsonObject::RemoveField(const FString& FieldName)
{
if (FieldName.IsEmpty())
{
return;
}
JsonObj->RemoveField(FieldName);
}
UVaRestJsonValue* UVaRestJsonObject::GetField(const FString& FieldName) const
{
if (FieldName.IsEmpty())
{
return nullptr;
}
TSharedPtr<FJsonValue> NewVal = JsonObj->TryGetField(FieldName);
if (NewVal.IsValid())
{
UVaRestJsonValue* NewValue = NewObject<UVaRestJsonValue>();
NewValue->SetRootValue(NewVal);
return NewValue;
}
return nullptr;
}
void UVaRestJsonObject::SetField(const FString& FieldName, UVaRestJsonValue* JsonValue)
{
if (FieldName.IsEmpty())
{
return;
}
JsonObj->SetField(FieldName, JsonValue->GetRootValue());
}
//////////////////////////////////////////////////////////////////////////
// FJsonObject API Helpers (easy to use with simple Json objects)
float UVaRestJsonObject::GetNumberField(const FString& FieldName) const
{
if (!JsonObj->HasTypedField<EJson::Number>(FieldName))
{
UE_LOG(LogVaRest, Warning, TEXT("No field with name %s of type Number"), *FieldName);
return 0.0f;
}
return JsonObj->GetNumberField(FieldName);
}
void UVaRestJsonObject::SetNumberField(const FString& FieldName, float Number)
{
if (FieldName.IsEmpty())
{
return;
}
JsonObj->SetNumberField(FieldName, Number);
}
void UVaRestJsonObject::SetNumberFieldDouble(const FString& FieldName, double Number)
{
if (FieldName.IsEmpty())
{
return;
}
JsonObj->SetNumberField(FieldName, Number);
}
int32 UVaRestJsonObject::GetIntegerField(const FString& FieldName) const
{
if (!JsonObj->HasTypedField<EJson::Number>(FieldName))
{
UE_LOG(LogVaRest, Warning, TEXT("No field with name %s of type Number"), *FieldName);
return 0;
}
return JsonObj->GetIntegerField(FieldName);
}
void UVaRestJsonObject::SetIntegerField(const FString& FieldName, int32 Number)
{
if (FieldName.IsEmpty())
{
return;
}
JsonObj->SetNumberField(FieldName, Number);
}
int64 UVaRestJsonObject::GetInt64Field(const FString& FieldName) const
{
if (!JsonObj->HasTypedField<EJson::Number>(FieldName))
{
UE_LOG(LogVaRest, Warning, TEXT("No field with name %s of type Number"), *FieldName);
return 0;
}
return static_cast<int64>(JsonObj->GetNumberField(FieldName));
}
void UVaRestJsonObject::SetInt64Field(const FString& FieldName, int64 Number)
{
if (FieldName.IsEmpty())
{
return;
}
JsonObj->SetNumberField(FieldName, Number);
}
FString UVaRestJsonObject::GetStringField(const FString& FieldName) const
{
if (!JsonObj->HasTypedField<EJson::String>(FieldName))
{
UE_LOG(LogVaRest, Warning, TEXT("No field with name %s of type String"), *FieldName);
return TEXT("");
}
return JsonObj->GetStringField(FieldName);
}
void UVaRestJsonObject::SetStringField(const FString& FieldName, const FString& StringValue)
{
if (FieldName.IsEmpty())
{
return;
}
JsonObj->SetStringField(FieldName, StringValue);
}
bool UVaRestJsonObject::GetBoolField(const FString& FieldName) const
{
if (!JsonObj->HasTypedField<EJson::Boolean>(FieldName))
{
UE_LOG(LogVaRest, Warning, TEXT("No field with name %s of type Boolean"), *FieldName);
return false;
}
return JsonObj->GetBoolField(FieldName);
}
void UVaRestJsonObject::SetBoolField(const FString& FieldName, bool InValue)
{
if (FieldName.IsEmpty())
{
return;
}
JsonObj->SetBoolField(FieldName, InValue);
}
TArray<UVaRestJsonValue*> UVaRestJsonObject::GetArrayField(const FString& FieldName) const
{
TArray<UVaRestJsonValue*> OutArray;
if (FieldName.IsEmpty())
{
return OutArray;
}
if (!JsonObj->HasTypedField<EJson::Array>(FieldName))
{
UE_LOG(LogVaRest, Warning, TEXT("%s: No field with name %s of type Array"), *VA_FUNC_LINE, *FieldName);
return OutArray;
}
TArray<TSharedPtr<FJsonValue>> ValArray = JsonObj->GetArrayField(FieldName);
for (auto Value : ValArray)
{
UVaRestJsonValue* NewValue = NewObject<UVaRestJsonValue>();
NewValue->SetRootValue(Value);
OutArray.Add(NewValue);
}
return OutArray;
}
void UVaRestJsonObject::SetArrayField(const FString& FieldName, const TArray<UVaRestJsonValue*>& InArray)
{
if (FieldName.IsEmpty())
{
return;
}
TArray<TSharedPtr<FJsonValue>> ValArray;
// Process input array and COPY original values
for (auto InVal : InArray)
{
if (InVal == nullptr)
continue;
const TSharedPtr<FJsonValue> JsonVal = InVal->GetRootValue();
switch (InVal->GetType())
{
case EVaJson::None:
break;
case EVaJson::Null:
ValArray.Add(MakeShareable(new FJsonValueNull()));
break;
case EVaJson::String:
ValArray.Add(MakeShareable(new FJsonValueString(JsonVal->AsString())));
break;
case EVaJson::Number:
ValArray.Add(MakeShareable(new FJsonValueNumber(JsonVal->AsNumber())));
break;
case EVaJson::Boolean:
ValArray.Add(MakeShareable(new FJsonValueBoolean(JsonVal->AsBool())));
break;
case EVaJson::Array:
ValArray.Add(MakeShareable(new FJsonValueArray(JsonVal->AsArray())));
break;
case EVaJson::Object:
ValArray.Add(MakeShareable(new FJsonValueObject(JsonVal->AsObject())));
break;
default:
break;
}
}
JsonObj->SetArrayField(FieldName, ValArray);
}
void UVaRestJsonObject::MergeJsonObject(UVaRestJsonObject* InJsonObject, bool Overwrite)
{
if (!InJsonObject || !InJsonObject->IsValidLowLevel())
{
return;
}
TArray<FString> Keys = InJsonObject->GetFieldNames();
for (auto Key : Keys)
{
if (Overwrite == false && HasField(Key))
{
continue;
}
SetField(Key, InJsonObject->GetField(Key));
}
}
UVaRestJsonObject* UVaRestJsonObject::GetObjectField(const FString& FieldName) const
{
if (!JsonObj->HasTypedField<EJson::Object>(FieldName))
{
UE_LOG(LogVaRest, Warning, TEXT("%s: No field with name %s of type Object"), *VA_FUNC_LINE, *FieldName);
return nullptr;
}
const TSharedPtr<FJsonObject> JsonObjField = JsonObj->GetObjectField(FieldName);
UVaRestJsonObject* OutRestJsonObj = NewObject<UVaRestJsonObject>();
OutRestJsonObj->SetRootObject(JsonObjField);
return OutRestJsonObj;
}
void UVaRestJsonObject::SetObjectField(const FString& FieldName, UVaRestJsonObject* JsonObject)
{
if (FieldName.IsEmpty() || !JsonObject || !JsonObject->IsValidLowLevel())
{
return;
}
JsonObj->SetObjectField(FieldName, JsonObject->GetRootObject());
}
void UVaRestJsonObject::SetMapFields_string(const TMap<FString, FString>& Fields)
{
for (auto& field : Fields)
{
SetStringField(field.Key, field.Value);
}
}
void UVaRestJsonObject::SetMapFields_uint8(const TMap<FString, uint8>& Fields)
{
SetMapFields_Impl(Fields);
}
void UVaRestJsonObject::SetMapFields_int32(const TMap<FString, int32>& Fields)
{
SetMapFields_Impl(Fields);
}
void UVaRestJsonObject::SetMapFields_int64(const TMap<FString, int64>& Fields)
{
SetMapFields_Impl(Fields);
}
void UVaRestJsonObject::SetMapFields_bool(const TMap<FString, bool>& Fields)
{
SetMapFields_Impl(Fields);
}
//////////////////////////////////////////////////////////////////////////
// Array fields helpers (uniform arrays)
TArray<float> UVaRestJsonObject::GetNumberArrayField(const FString& FieldName) const
{
return GetTypeArrayField<float>(FieldName);
}
TArray<int32> UVaRestJsonObject::GetIntegerArrayField(const FString& FieldName) const
{
return GetTypeArrayField<int32>(FieldName);
}
void UVaRestJsonObject::SetNumberArrayField(const FString& FieldName, const TArray<float>& NumberArray)
{
if (FieldName.IsEmpty())
{
return;
}
TArray<TSharedPtr<FJsonValue>> EntriesArray;
for (auto Number : NumberArray)
{
EntriesArray.Add(MakeShareable(new FJsonValueNumber(Number)));
}
JsonObj->SetArrayField(FieldName, EntriesArray);
}
void UVaRestJsonObject::SetNumberArrayFieldDouble(const FString& FieldName, const TArray<double>& NumberArray)
{
if (FieldName.IsEmpty())
{
return;
}
TArray<TSharedPtr<FJsonValue>> EntriesArray;
for (auto Number : NumberArray)
{
EntriesArray.Add(MakeShareable(new FJsonValueNumber(Number)));
}
JsonObj->SetArrayField(FieldName, EntriesArray);
}
TArray<FString> UVaRestJsonObject::GetStringArrayField(const FString& FieldName) const
{
TArray<FString> StringArray;
if (!JsonObj->HasTypedField<EJson::Array>(FieldName) || FieldName.IsEmpty())
{
UE_LOG(LogVaRest, Warning, TEXT("%s: No field with name %s of type Array"), *VA_FUNC_LINE, *FieldName);
return StringArray;
}
const TArray<TSharedPtr<FJsonValue>> JsonArrayValues = JsonObj->GetArrayField(FieldName);
for (TArray<TSharedPtr<FJsonValue>>::TConstIterator It(JsonArrayValues); It; ++It)
{
const auto Value = (*It).Get();
if (Value->Type != EJson::String)
{
UE_LOG(LogVaRest, Error, TEXT("Not String element in array with field name %s"), *FieldName);
}
StringArray.Add((*It)->AsString());
}
return StringArray;
}
void UVaRestJsonObject::SetStringArrayField(const FString& FieldName, const TArray<FString>& StringArray)
{
if (FieldName.IsEmpty())
{
return;
}
TArray<TSharedPtr<FJsonValue>> EntriesArray;
for (auto String : StringArray)
{
EntriesArray.Add(MakeShareable(new FJsonValueString(String)));
}
JsonObj->SetArrayField(FieldName, EntriesArray);
}
TArray<bool> UVaRestJsonObject::GetBoolArrayField(const FString& FieldName) const
{
TArray<bool> BoolArray;
if (!JsonObj->HasTypedField<EJson::Array>(FieldName) || FieldName.IsEmpty())
{
UE_LOG(LogVaRest, Warning, TEXT("%s: No field with name %s of type Array"), *VA_FUNC_LINE, *FieldName);
return BoolArray;
}
const TArray<TSharedPtr<FJsonValue>> JsonArrayValues = JsonObj->GetArrayField(FieldName);
for (TArray<TSharedPtr<FJsonValue>>::TConstIterator It(JsonArrayValues); It; ++It)
{
const auto Value = (*It).Get();
if (Value->Type != EJson::Boolean)
{
UE_LOG(LogVaRest, Error, TEXT("Not Boolean element in array with field name %s"), *FieldName);
}
BoolArray.Add((*It)->AsBool());
}
return BoolArray;
}
void UVaRestJsonObject::SetBoolArrayField(const FString& FieldName, const TArray<bool>& BoolArray)
{
if (FieldName.IsEmpty())
{
return;
}
TArray<TSharedPtr<FJsonValue>> EntriesArray;
for (auto Boolean : BoolArray)
{
EntriesArray.Add(MakeShareable(new FJsonValueBoolean(Boolean)));
}
JsonObj->SetArrayField(FieldName, EntriesArray);
}
TArray<UVaRestJsonObject*> UVaRestJsonObject::GetObjectArrayField(const FString& FieldName) const
{
TArray<UVaRestJsonObject*> OutArray;
if (!JsonObj->HasTypedField<EJson::Array>(FieldName) || FieldName.IsEmpty())
{
UE_LOG(LogVaRest, Warning, TEXT("%s: No field with name %s of type Array"), *VA_FUNC_LINE, *FieldName);
return OutArray;
}
TArray<TSharedPtr<FJsonValue>> ValArray = JsonObj->GetArrayField(FieldName);
for (const auto& Value : ValArray)
{
if (Value->Type != EJson::Object)
{
UE_LOG(LogVaRest, Error, TEXT("Not Object element in array with field name %s"), *FieldName);
}
TSharedPtr<FJsonObject> NewObj = Value->AsObject();
UVaRestJsonObject* NewJson = NewObject<UVaRestJsonObject>();
NewJson->SetRootObject(NewObj);
OutArray.Add(NewJson);
}
return OutArray;
}
void UVaRestJsonObject::SetObjectArrayField(const FString& FieldName, const TArray<UVaRestJsonObject*>& ObjectArray)
{
if (FieldName.IsEmpty())
{
return;
}
TArray<TSharedPtr<FJsonValue>> EntriesArray;
for (auto Value : ObjectArray)
{
if (Value == nullptr)
continue;
EntriesArray.Add(MakeShareable(new FJsonValueObject(Value->GetRootObject())));
}
JsonObj->SetArrayField(FieldName, EntriesArray);
}
//////////////////////////////////////////////////////////////////////////
// Deserialize
int32 UVaRestJsonObject::DeserializeFromUTF8Bytes(const ANSICHAR* Bytes, int32 Size)
{
FJSONReader Reader;
const ANSICHAR* EndByte = Bytes + Size;
while (Bytes < EndByte)
{
TCHAR Char = FUtf8Helper::CodepointFromUtf8(Bytes, EndByte - Bytes);
if (Char > 0xFFFF)
{
Char = UNICODE_BOGUS_CHAR_CODEPOINT;
}
if (!Reader.Read(Char))
{
break;
}
}
SetRootObject(Reader.State.Root);
return Reader.State.Size;
}
int32 UVaRestJsonObject::DeserializeFromTCHARBytes(const TCHAR* Bytes, int32 Size)
{
FJSONReader Reader;
int32 i = 0;
while (i < Size)
{
if (!Reader.Read(Bytes[i++]))
{
break;
}
}
SetRootObject(Reader.State.Root);
return Reader.State.Size;
}
void UVaRestJsonObject::DecodeFromArchive(TUniquePtr<FArchive>& Reader)
{
FArchive& Ar = (*Reader.Get());
uint8 SymbolBytes[2];
// Read first two bytes
Ar << SymbolBytes[0];
Ar << SymbolBytes[1];
bool bIsIntelByteOrder = true;
if (SymbolBytes[0] == 0xff && SymbolBytes[1] == 0xfe)
{
// Unicode Intel byte order. Less 1 for the FFFE header, additional 1 for null terminator.
bIsIntelByteOrder = true;
}
else if (SymbolBytes[0] == 0xfe && SymbolBytes[1] == 0xff)
{
// Unicode non-Intel byte order. Less 1 for the FFFE header, additional 1 for null terminator.
bIsIntelByteOrder = false;
}
FJSONReader JsonReader;
TCHAR Char;
while (!Ar.AtEnd())
{
Ar << SymbolBytes[0];
if (Ar.AtEnd())
{
break;
}
Ar << SymbolBytes[1];
if (bIsIntelByteOrder)
{
Char = CharCast<TCHAR>(static_cast<UCS2CHAR>(static_cast<uint16>(SymbolBytes[0]) + static_cast<uint16>(SymbolBytes[1]) * 256));
}
else
{
Char = CharCast<TCHAR>(static_cast<UCS2CHAR>(static_cast<uint16>(SymbolBytes[1]) + static_cast<uint16>(SymbolBytes[0]) * 256));
}
if (!JsonReader.Read(Char))
{
break;
}
}
SetRootObject(JsonReader.State.Root);
if (!Ar.Close())
{
UE_LOG(LogVaRest, Error, TEXT("UVaRestJsonObject::DecodeFromArchive: Error! Can't close file!"));
}
}
//////////////////////////////////////////////////////////////////////////
// Serialize
bool UVaRestJsonObject::WriteToFile(const FString& Path) const
{
TUniquePtr<FArchive> FileWriter(IFileManager::Get().CreateFileWriter(*Path));
if (!FileWriter)
{
return false;
}
FArchive& Ar = *FileWriter.Get();
UCS2CHAR BOM = UNICODE_BOM;
Ar.Serialize(&BOM, sizeof(UCS2CHAR));
FString Str = FString(TEXT("{"));
WriteStringToArchive(Ar, *Str, Str.Len());
int32 ElementCount = 0;
FJSONWriter JsonWriter;
for (auto JsonObjectValuePair : JsonObj->Values)
{
Str = FString(TEXT("\""));
WriteStringToArchive(Ar, *Str, Str.Len());
const TCHAR* BufferPtr = *JsonObjectValuePair.Key;
for (int i = 0; i < JsonObjectValuePair.Key.Len(); ++i)
{
Str = FString(1, &BufferPtr[i]);
WriteStringToArchive(Ar, *Str, Str.Len());
}
Str = FString(TEXT("\""));
WriteStringToArchive(Ar, *Str, Str.Len());
Str = FString(TEXT(":"));
WriteStringToArchive(Ar, *Str, Str.Len());
++ElementCount;
JsonWriter.Write(JsonObjectValuePair.Value, FileWriter.Get(), ElementCount >= JsonObj->Values.Num());
}
Str = FString(TEXT("}"));
WriteStringToArchive(Ar, *Str, Str.Len());
FileWriter->Close();
return true;
}
bool UVaRestJsonObject::WriteToFilePath(const FString& Path, const bool bIsRelativeToProjectDir)
{
return WriteToFile(bIsRelativeToProjectDir ? FPaths::ProjectDir() / Path : Path);
}
bool UVaRestJsonObject::WriteStringToArchive(FArchive& Ar, const TCHAR* StrPtr, int64 Len)
{
const auto Src = StringCast<UCS2CHAR>(StrPtr, Len);
Ar.Serialize(const_cast<UCS2CHAR*>(Src.Get()), Src.Length() * sizeof(UCS2CHAR));
return true;
}