Increase size to 40 bytes to store Double3 without allocations Change Ray and BoundingBox to be stored inlined in BoundingBox Use safer accessors to read Variant explicit data type
842 lines
21 KiB
C++
842 lines
21 KiB
C++
// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
|
|
|
|
#include "ReadStream.h"
|
|
#include "WriteStream.h"
|
|
#include "JsonWriters.h"
|
|
#include "JsonSerializer.h"
|
|
#include "MemoryReadStream.h"
|
|
#include "Engine/Core/Types/CommonValue.h"
|
|
#include "Engine/Core/Types/Variant.h"
|
|
#include "Engine/Core/Math/Double2.h"
|
|
#include "Engine/Core/Math/Double3.h"
|
|
#include "Engine/Core/Math/Double4.h"
|
|
#include "Engine/Core/Collections/Dictionary.h"
|
|
#include "Engine/Content/Asset.h"
|
|
#include "Engine/Core/Cache.h"
|
|
#include "Engine/Debug/Exceptions/JsonParseException.h"
|
|
#include "Engine/Profiler/ProfilerCPU.h"
|
|
#include "Engine/Scripting/ManagedSerialization.h"
|
|
#include "Engine/Scripting/Scripting.h"
|
|
#include "Engine/Scripting/ScriptingObject.h"
|
|
#include "Engine/Scripting/ScriptingObjectReference.h"
|
|
#include "Engine/Scripting/ManagedCLR/MCore.h"
|
|
#include "Engine/Scripting/ManagedCLR/MUtils.h"
|
|
|
|
void ReadStream::ReadStringAnsi(StringAnsi* data)
|
|
{
|
|
int32 length;
|
|
ReadInt32(&length);
|
|
if (length < 0 || length > STREAM_MAX_STRING_LENGTH)
|
|
{
|
|
_hasError = true;
|
|
*data = "";
|
|
return;
|
|
}
|
|
|
|
data->ReserveSpace(length);
|
|
if (length == 0)
|
|
return;
|
|
char* ptr = data->Get();
|
|
ASSERT(ptr != nullptr);
|
|
Read(ptr, length);
|
|
}
|
|
|
|
void ReadStream::ReadStringAnsi(StringAnsi* data, int8 lock)
|
|
{
|
|
int32 length;
|
|
ReadInt32(&length);
|
|
if (length < 0 || length > STREAM_MAX_STRING_LENGTH)
|
|
{
|
|
_hasError = true;
|
|
*data = "";
|
|
return;
|
|
}
|
|
|
|
data->ReserveSpace(length);
|
|
if (length == 0)
|
|
return;
|
|
char* ptr = data->Get();
|
|
ASSERT(ptr != nullptr);
|
|
Read(ptr, length);
|
|
|
|
for (int32 i = 0; i < length; i++)
|
|
{
|
|
*ptr = *ptr ^ lock;
|
|
ptr++;
|
|
}
|
|
}
|
|
|
|
void ReadStream::ReadString(String* data)
|
|
{
|
|
int32 length;
|
|
ReadInt32(&length);
|
|
if (length <= 0 || length > STREAM_MAX_STRING_LENGTH)
|
|
{
|
|
if (length != 0)
|
|
_hasError = true;
|
|
data->Clear();
|
|
return;
|
|
}
|
|
|
|
data->ReserveSpace(length);
|
|
Char* ptr = data->Get();
|
|
ASSERT(ptr != nullptr);
|
|
Read(ptr, length);
|
|
}
|
|
|
|
void ReadStream::ReadString(String* data, int16 lock)
|
|
{
|
|
int32 length;
|
|
ReadInt32(&length);
|
|
if (length <= 0 || length > STREAM_MAX_STRING_LENGTH)
|
|
{
|
|
if (length != 0)
|
|
_hasError = true;
|
|
data->Clear();
|
|
return;
|
|
}
|
|
|
|
data->ReserveSpace(length);
|
|
Char* ptr = data->Get();
|
|
ASSERT(ptr != nullptr);
|
|
Read(ptr, length);
|
|
|
|
for (int32 i = 0; i < length; i++)
|
|
{
|
|
*ptr = *ptr ^ lock;
|
|
ptr++;
|
|
}
|
|
}
|
|
|
|
void ReadStream::ReadCommonValue(CommonValue* data)
|
|
{
|
|
byte type;
|
|
ReadByte(&type);
|
|
switch (static_cast<CommonType>(type))
|
|
{
|
|
case CommonType::Bool:
|
|
data->Set(ReadBool());
|
|
break;
|
|
case CommonType::Integer:
|
|
{
|
|
int32 v;
|
|
ReadInt32(&v);
|
|
data->Set(v);
|
|
}
|
|
break;
|
|
case CommonType::Float:
|
|
{
|
|
float v;
|
|
ReadFloat(&v);
|
|
data->Set(v);
|
|
}
|
|
break;
|
|
case CommonType::Vector2:
|
|
{
|
|
Vector2 v;
|
|
Read(&v);
|
|
data->Set(v);
|
|
}
|
|
break;
|
|
case CommonType::Vector3:
|
|
{
|
|
Vector3 v;
|
|
Read(&v);
|
|
data->Set(v);
|
|
}
|
|
break;
|
|
case CommonType::Vector4:
|
|
{
|
|
Vector4 v;
|
|
Read(&v);
|
|
data->Set(v);
|
|
}
|
|
break;
|
|
case CommonType::Color:
|
|
{
|
|
Color v;
|
|
Read(&v);
|
|
data->Set(v);
|
|
}
|
|
break;
|
|
case CommonType::Guid:
|
|
{
|
|
Guid v;
|
|
Read(&v);
|
|
data->Set(v);
|
|
}
|
|
break;
|
|
case CommonType::String:
|
|
{
|
|
String v;
|
|
ReadString(&v, 953);
|
|
data->Set(v);
|
|
}
|
|
break;
|
|
case CommonType::Box:
|
|
{
|
|
BoundingBox v;
|
|
Read(&v);
|
|
data->Set(v);
|
|
}
|
|
break;
|
|
case CommonType::Rotation:
|
|
{
|
|
Quaternion v;
|
|
Read(&v);
|
|
data->Set(v);
|
|
}
|
|
break;
|
|
case CommonType::Transform:
|
|
{
|
|
Transform v;
|
|
Read(&v);
|
|
data->Set(v);
|
|
}
|
|
break;
|
|
case CommonType::Sphere:
|
|
{
|
|
BoundingSphere v;
|
|
Read(&v);
|
|
data->Set(v);
|
|
}
|
|
break;
|
|
case CommonType::Rectangle:
|
|
{
|
|
Rectangle v;
|
|
Read(&v);
|
|
data->Set(v);
|
|
}
|
|
case CommonType::Ray:
|
|
{
|
|
Ray v;
|
|
Read(&v);
|
|
data->Set(v);
|
|
}
|
|
break;
|
|
case CommonType::Matrix:
|
|
{
|
|
Matrix v;
|
|
Read(&v);
|
|
data->Set(v);
|
|
}
|
|
break;
|
|
case CommonType::Blob:
|
|
{
|
|
int32 length;
|
|
Read(&length);
|
|
data->SetBlob(length);
|
|
if (length > 0)
|
|
{
|
|
ReadBytes(data->AsBlob.Data, length);
|
|
}
|
|
}
|
|
break;
|
|
default: CRASH;
|
|
}
|
|
}
|
|
|
|
void ReadStream::ReadVariantType(VariantType* data)
|
|
{
|
|
*data = VariantType((VariantType::Types)ReadByte());
|
|
int32 typeNameLength;
|
|
ReadInt32(&typeNameLength);
|
|
if (typeNameLength == MAX_int32)
|
|
{
|
|
ReadInt32(&typeNameLength);
|
|
if (typeNameLength == 0)
|
|
return;
|
|
data->TypeName = static_cast<char*>(Allocator::Allocate(typeNameLength + 1));
|
|
char* ptr = data->TypeName;
|
|
Read(ptr, typeNameLength);
|
|
for (int32 i = 0; i < typeNameLength; i++)
|
|
{
|
|
*ptr = *ptr ^ 77;
|
|
ptr++;
|
|
}
|
|
*ptr = 0;
|
|
}
|
|
else if (typeNameLength > 0)
|
|
{
|
|
// [Deprecated on 27.08.2020, expires on 27.08.2021]
|
|
ASSERT(typeNameLength < STREAM_MAX_STRING_LENGTH);
|
|
Array<Char> chars;
|
|
chars.Resize(typeNameLength + 1);
|
|
Char* ptr = chars.Get();
|
|
Read(ptr, typeNameLength);
|
|
for (int32 i = 0; i < typeNameLength; i++)
|
|
{
|
|
*ptr = *ptr ^ 77;
|
|
ptr++;
|
|
}
|
|
*ptr = 0;
|
|
data->TypeName = static_cast<char*>(Allocator::Allocate(typeNameLength + 1));
|
|
StringUtils::ConvertUTF162ANSI(chars.Get(), data->TypeName, typeNameLength);
|
|
data->TypeName[typeNameLength] = 0;
|
|
}
|
|
}
|
|
|
|
void ReadStream::ReadVariant(Variant* data)
|
|
{
|
|
VariantType type;
|
|
ReadVariantType(&type);
|
|
data->SetType(MoveTemp(type));
|
|
switch (data->Type.Type)
|
|
{
|
|
case VariantType::Null:
|
|
case VariantType::Void:
|
|
break;
|
|
case VariantType::Bool:
|
|
data->AsBool = ReadBool();
|
|
break;
|
|
case VariantType::Int16:
|
|
ReadInt16(&data->AsInt16);
|
|
break;
|
|
case VariantType::Uint16:
|
|
ReadUint16(&data->AsUint16);
|
|
break;
|
|
case VariantType::Int:
|
|
ReadInt32(&data->AsInt);
|
|
break;
|
|
case VariantType::Uint:
|
|
ReadUint32(&data->AsUint);
|
|
break;
|
|
case VariantType::Int64:
|
|
ReadInt64(&data->AsInt64);
|
|
break;
|
|
case VariantType::Uint64:
|
|
case VariantType::Enum:
|
|
ReadUint64(&data->AsUint64);
|
|
break;
|
|
case VariantType::Float:
|
|
ReadFloat(&data->AsFloat);
|
|
break;
|
|
case VariantType::Double:
|
|
ReadDouble(&data->AsDouble);
|
|
break;
|
|
case VariantType::Pointer:
|
|
{
|
|
uint64 asUint64;
|
|
ReadUint64(&asUint64);
|
|
data->AsPointer = (void*)(uintptr)asUint64;
|
|
break;
|
|
}
|
|
case VariantType::String:
|
|
{
|
|
int32 length;
|
|
ReadInt32(&length);
|
|
ASSERT(length < STREAM_MAX_STRING_LENGTH);
|
|
const int32 dataLength = length * sizeof(Char) + 2;
|
|
if (data->AsBlob.Length != dataLength)
|
|
{
|
|
Allocator::Free(data->AsBlob.Data);
|
|
data->AsBlob.Data = dataLength > 0 ? Allocator::Allocate(dataLength) : nullptr;
|
|
data->AsBlob.Length = dataLength;
|
|
}
|
|
Char* ptr = (Char*)data->AsBlob.Data;
|
|
Read(ptr, length);
|
|
for (int32 i = 0; i < length; i++)
|
|
{
|
|
*ptr = *ptr ^ -14;
|
|
ptr++;
|
|
}
|
|
*ptr = 0;
|
|
break;
|
|
}
|
|
case VariantType::Object:
|
|
{
|
|
Guid id;
|
|
Read(&id);
|
|
data->SetObject(FindObject(id, ScriptingObject::GetStaticClass()));
|
|
break;
|
|
}
|
|
case VariantType::ManagedObject:
|
|
case VariantType::Structure:
|
|
{
|
|
const byte format = ReadByte();
|
|
if (format == 0)
|
|
{
|
|
// No data
|
|
}
|
|
else if (format == 1)
|
|
{
|
|
// Json
|
|
StringAnsi json;
|
|
ReadStringAnsi(&json, -71);
|
|
#if USE_MONO
|
|
MCore::AttachThread();
|
|
MonoClass* klass = MUtils::GetClass(data->Type);
|
|
if (!klass)
|
|
{
|
|
LOG(Error, "Invalid variant type {0}", data->Type);
|
|
return;
|
|
}
|
|
MonoObject* obj = mono_object_new(mono_domain_get(), klass);
|
|
if (!obj)
|
|
{
|
|
LOG(Error, "Failed to managed instance of the variant type {0}", data->Type);
|
|
return;
|
|
}
|
|
if (!mono_class_is_valuetype(klass))
|
|
mono_runtime_object_init(obj);
|
|
ManagedSerialization::Deserialize(json, obj);
|
|
if (data->Type.Type == VariantType::ManagedObject)
|
|
data->SetManagedObject(obj);
|
|
else
|
|
*data = MUtils::UnboxVariant(obj);
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
LOG(Error, "Invalid Variant {0) format {1}", data->Type.ToString(), format);
|
|
}
|
|
break;
|
|
}
|
|
case VariantType::Blob:
|
|
{
|
|
int32 length;
|
|
ReadInt32(&length);
|
|
data->SetBlob(length);
|
|
ReadBytes(data->AsBlob.Data, length);
|
|
break;
|
|
}
|
|
case VariantType::Asset:
|
|
{
|
|
Guid id;
|
|
Read(&id);
|
|
data->SetAsset(LoadAsset(id, Asset::TypeInitializer));
|
|
break;
|
|
}
|
|
case VariantType::Vector2:
|
|
ReadBytes(&data->AsData, sizeof(Vector2));
|
|
break;
|
|
case VariantType::Vector3:
|
|
ReadBytes(&data->AsData, sizeof(Vector3));
|
|
break;
|
|
case VariantType::Vector4:
|
|
ReadBytes(&data->AsData, sizeof(Vector4));
|
|
break;
|
|
case VariantType::Double2:
|
|
ReadBytes(&data->AsData, sizeof(Double2));
|
|
break;
|
|
case VariantType::Double3:
|
|
ReadBytes(&data->AsData, sizeof(Double3));
|
|
break;
|
|
case VariantType::Double4:
|
|
ReadBytes(data->AsBlob.Data, sizeof(Double4));
|
|
break;
|
|
case VariantType::Color:
|
|
ReadBytes(&data->AsData, sizeof(Color));
|
|
break;
|
|
case VariantType::Guid:
|
|
ReadBytes(&data->AsData, sizeof(Guid));
|
|
break;
|
|
case VariantType::BoundingBox:
|
|
ReadBytes(&data->AsData, sizeof(BoundingBox));
|
|
break;
|
|
case VariantType::BoundingSphere:
|
|
ReadBytes(&data->AsData, sizeof(BoundingSphere));
|
|
break;
|
|
case VariantType::Quaternion:
|
|
ReadBytes(&data->AsData, sizeof(Quaternion));
|
|
break;
|
|
case VariantType::Transform:
|
|
ReadBytes(data->AsBlob.Data, sizeof(Transform));
|
|
break;
|
|
case VariantType::Rectangle:
|
|
ReadBytes(&data->AsData, sizeof(Rectangle));
|
|
break;
|
|
case VariantType::Ray:
|
|
ReadBytes(&data->AsData, sizeof(Ray));
|
|
break;
|
|
case VariantType::Matrix:
|
|
ReadBytes(data->AsBlob.Data, sizeof(Matrix));
|
|
break;
|
|
case VariantType::Array:
|
|
{
|
|
int32 count;
|
|
ReadInt32(&count);
|
|
auto& array = *(Array<Variant>*)data->AsData;
|
|
array.Resize(count);
|
|
for (int32 i = 0; i < count; i++)
|
|
ReadVariant(&array[i]);
|
|
break;
|
|
}
|
|
case VariantType::Dictionary:
|
|
{
|
|
int32 count;
|
|
ReadInt32(&count);
|
|
auto& dictionary = *data->AsDictionary;
|
|
dictionary.Clear();
|
|
dictionary.EnsureCapacity(count);
|
|
for (int32 i = 0; i < count; i++)
|
|
{
|
|
Variant key;
|
|
ReadVariant(&key);
|
|
ReadVariant(&dictionary[MoveTemp(key)]);
|
|
}
|
|
break;
|
|
}
|
|
case VariantType::Typename:
|
|
{
|
|
int32 length;
|
|
ReadInt32(&length);
|
|
ASSERT(length < STREAM_MAX_STRING_LENGTH);
|
|
const int32 dataLength = length + 1;
|
|
if (data->AsBlob.Length != dataLength)
|
|
{
|
|
Allocator::Free(data->AsBlob.Data);
|
|
data->AsBlob.Data = dataLength > 0 ? Allocator::Allocate(dataLength) : nullptr;
|
|
data->AsBlob.Length = dataLength;
|
|
}
|
|
char* ptr = (char*)data->AsBlob.Data;
|
|
Read(ptr, length);
|
|
for (int32 i = 0; i < length; i++)
|
|
{
|
|
*ptr = *ptr ^ -14;
|
|
ptr++;
|
|
}
|
|
*ptr = 0;
|
|
break;
|
|
}
|
|
default:
|
|
CRASH;
|
|
}
|
|
}
|
|
|
|
void ReadStream::ReadJson(ISerializable* obj)
|
|
{
|
|
int32 engineBuild, size;
|
|
ReadInt32(&engineBuild);
|
|
ReadInt32(&size);
|
|
if (obj)
|
|
{
|
|
if (const auto memoryStream = dynamic_cast<MemoryReadStream*>(this))
|
|
{
|
|
JsonSerializer::LoadFromBytes(obj, Span<byte>((byte*)memoryStream->Read(size), size), engineBuild);
|
|
}
|
|
else
|
|
{
|
|
void* data = Allocator::Allocate(size);
|
|
ReadBytes(data, size);
|
|
JsonSerializer::LoadFromBytes(obj, Span<byte>((byte*)data, size), engineBuild);
|
|
Allocator::Free(data);
|
|
}
|
|
}
|
|
else
|
|
SetPosition(GetPosition() + size);
|
|
}
|
|
|
|
void WriteStream::WriteText(const StringView& text)
|
|
{
|
|
WriteBytes(text.Get(), sizeof(Char) * text.Length());
|
|
}
|
|
|
|
void WriteStream::WriteText(const StringAnsiView& text)
|
|
{
|
|
WriteBytes(text.Get(), sizeof(char) * text.Length());
|
|
}
|
|
|
|
void WriteStream::WriteString(const StringView& data)
|
|
{
|
|
const int32 length = data.Length();
|
|
ASSERT(length < STREAM_MAX_STRING_LENGTH);
|
|
WriteInt32(length);
|
|
Write(*data, length);
|
|
}
|
|
|
|
void WriteStream::WriteString(const StringView& data, int16 lock)
|
|
{
|
|
ASSERT(data.Length() < STREAM_MAX_STRING_LENGTH);
|
|
WriteInt32(data.Length());
|
|
for (int32 i = 0; i < data.Length(); i++)
|
|
WriteUint16((uint16)((uint16)data[i] ^ lock));
|
|
}
|
|
|
|
void WriteStream::WriteStringAnsi(const StringAnsiView& data)
|
|
{
|
|
const int32 length = data.Length();
|
|
ASSERT(length < STREAM_MAX_STRING_LENGTH);
|
|
WriteInt32(length);
|
|
Write(data.Get(), length);
|
|
}
|
|
|
|
void WriteStream::WriteStringAnsi(const StringAnsiView& data, int8 lock)
|
|
{
|
|
const int32 length = data.Length();
|
|
ASSERT(length < STREAM_MAX_STRING_LENGTH);
|
|
WriteInt32(length);
|
|
for (int32 i = 0; i < length; i++)
|
|
WriteUint8((uint8)((uint8)data[i] ^ lock));
|
|
}
|
|
|
|
void WriteStream::WriteCommonValue(const CommonValue& data)
|
|
{
|
|
WriteByte(static_cast<byte>(data.Type));
|
|
switch (data.Type)
|
|
{
|
|
case CommonType::Bool:
|
|
WriteBool(data.AsBool);
|
|
break;
|
|
case CommonType::Integer:
|
|
WriteInt32(data.AsInteger);
|
|
break;
|
|
case CommonType::Float:
|
|
WriteFloat(data.AsFloat);
|
|
break;
|
|
case CommonType::Vector2:
|
|
Write(&data.AsVector2);
|
|
break;
|
|
case CommonType::Vector3:
|
|
Write(&data.AsVector3);
|
|
break;
|
|
case CommonType::Vector4:
|
|
Write(&data.AsVector4);
|
|
break;
|
|
case CommonType::Color:
|
|
Write(&data.AsColor);
|
|
break;
|
|
case CommonType::Guid:
|
|
Write(&data.AsGuid);
|
|
break;
|
|
case CommonType::String:
|
|
WriteString(data.AsString, 953);
|
|
break;
|
|
case CommonType::Box:
|
|
Write(&data.AsBox);
|
|
break;
|
|
case CommonType::Rotation:
|
|
Write(&data.AsRotation);
|
|
break;
|
|
case CommonType::Transform:
|
|
Write(&data.AsTransform);
|
|
break;
|
|
case CommonType::Sphere:
|
|
Write(&data.AsSphere);
|
|
break;
|
|
case CommonType::Rectangle:
|
|
Write(&data.AsRectangle);
|
|
break;
|
|
case CommonType::Ray:
|
|
Write(&data.AsRay);
|
|
break;
|
|
case CommonType::Matrix:
|
|
Write(&data.AsMatrix);
|
|
break;
|
|
case CommonType::Blob:
|
|
WriteInt32(data.AsBlob.Length);
|
|
if (data.AsBlob.Length > 0)
|
|
WriteBytes(data.AsBlob.Data, data.AsBlob.Length);
|
|
break;
|
|
default: CRASH;
|
|
}
|
|
}
|
|
|
|
void WriteStream::WriteVariantType(const VariantType& data)
|
|
{
|
|
WriteByte((byte)data.Type);
|
|
WriteInt32(MAX_int32);
|
|
WriteStringAnsi(StringAnsiView(data.TypeName), 77);
|
|
}
|
|
|
|
void WriteStream::WriteVariant(const Variant& data)
|
|
{
|
|
WriteVariantType(data.Type);
|
|
Guid id;
|
|
switch (data.Type.Type)
|
|
{
|
|
case VariantType::Null:
|
|
case VariantType::Void:
|
|
break;
|
|
case VariantType::Bool:
|
|
WriteBool(data.AsBool);
|
|
break;
|
|
case VariantType::Int16:
|
|
WriteInt16(data.AsInt16);
|
|
break;
|
|
case VariantType::Uint16:
|
|
WriteUint16(data.AsUint16);
|
|
break;
|
|
case VariantType::Int:
|
|
WriteInt32(data.AsInt);
|
|
break;
|
|
case VariantType::Uint:
|
|
WriteUint32(data.AsUint);
|
|
break;
|
|
case VariantType::Int64:
|
|
WriteInt64(data.AsInt64);
|
|
break;
|
|
case VariantType::Uint64:
|
|
case VariantType::Enum:
|
|
WriteUint64(data.AsUint64);
|
|
break;
|
|
case VariantType::Float:
|
|
WriteFloat(data.AsFloat);
|
|
break;
|
|
case VariantType::Double:
|
|
WriteDouble(data.AsDouble);
|
|
break;
|
|
case VariantType::Pointer:
|
|
WriteUint64((uint64)(uintptr)data.AsPointer);
|
|
break;
|
|
case VariantType::String:
|
|
WriteString((StringView)data, -14);
|
|
break;
|
|
case VariantType::Object:
|
|
id = data.AsObject ? data.AsObject->GetID() : Guid::Empty;
|
|
Write(&id);
|
|
break;
|
|
case VariantType::Blob:
|
|
WriteInt32(data.AsBlob.Length);
|
|
WriteBytes(data.AsBlob.Data, data.AsBlob.Length);
|
|
break;
|
|
case VariantType::BoundingBox:
|
|
WriteBytes(data.AsData, sizeof(BoundingBox));
|
|
break;
|
|
case VariantType::Transform:
|
|
WriteBytes(data.AsBlob.Data, sizeof(Transform));
|
|
break;
|
|
case VariantType::Ray:
|
|
WriteBytes(data.AsData, sizeof(Ray));
|
|
break;
|
|
case VariantType::Matrix:
|
|
WriteBytes(data.AsBlob.Data, sizeof(Matrix));
|
|
break;
|
|
case VariantType::Asset:
|
|
id = data.AsAsset ? data.AsAsset->GetID() : Guid::Empty;
|
|
Write(&id);
|
|
break;
|
|
case VariantType::Vector2:
|
|
WriteBytes(data.AsData, sizeof(Vector2));
|
|
break;
|
|
case VariantType::Vector3:
|
|
WriteBytes(data.AsData, sizeof(Vector3));
|
|
break;
|
|
case VariantType::Vector4:
|
|
WriteBytes(data.AsData, sizeof(Vector4));
|
|
break;
|
|
case VariantType::Double2:
|
|
WriteBytes(data.AsData, sizeof(Double2));
|
|
break;
|
|
case VariantType::Double3:
|
|
WriteBytes(data.AsData, sizeof(Double3));
|
|
break;
|
|
case VariantType::Double4:
|
|
WriteBytes(data.AsBlob.Data, sizeof(Double4));
|
|
break;
|
|
case VariantType::Color:
|
|
WriteBytes(data.AsData, sizeof(Color));
|
|
break;
|
|
case VariantType::Guid:
|
|
WriteBytes(data.AsData, sizeof(Guid));
|
|
break;
|
|
case VariantType::Quaternion:
|
|
WriteBytes(data.AsData, sizeof(Quaternion));
|
|
break;
|
|
case VariantType::Rectangle:
|
|
WriteBytes(data.AsData, sizeof(Rectangle));
|
|
break;
|
|
case VariantType::BoundingSphere:
|
|
WriteBytes(data.AsData, sizeof(BoundingSphere));
|
|
break;
|
|
case VariantType::Array:
|
|
id.A = ((Array<Variant>*)data.AsData)->Count();
|
|
WriteInt32(id.A);
|
|
for (uint32 i = 0; i < id.A; i++)
|
|
WriteVariant(((Array<Variant>*)data.AsData)->At(i));
|
|
break;
|
|
case VariantType::Dictionary:
|
|
WriteInt32(data.AsDictionary->Count());
|
|
for (auto i = data.AsDictionary->Begin(); i.IsNotEnd(); ++i)
|
|
{
|
|
WriteVariant(i->Key);
|
|
WriteVariant(i->Value);
|
|
}
|
|
break;
|
|
case VariantType::Typename:
|
|
WriteStringAnsi((StringAnsiView)data, -14);
|
|
break;
|
|
case VariantType::ManagedObject:
|
|
case VariantType::Structure:
|
|
{
|
|
#if USE_MONO
|
|
MonoObject* obj;
|
|
if (data.Type.Type == VariantType::Structure)
|
|
obj = MUtils::BoxVariant(data);
|
|
else
|
|
obj = (MonoObject*)data;
|
|
if (obj)
|
|
{
|
|
WriteByte(1);
|
|
rapidjson_flax::StringBuffer json;
|
|
CompactJsonWriter writerObj(json);
|
|
MCore::AttachThread();
|
|
ManagedSerialization::Serialize(writerObj, obj);
|
|
WriteStringAnsi(StringAnsiView(json.GetString(), (int32)json.GetSize()), -71);
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
WriteByte(0);
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
CRASH;
|
|
}
|
|
}
|
|
|
|
void WriteStream::WriteJson(ISerializable* obj, const void* otherObj)
|
|
{
|
|
WriteInt32(FLAXENGINE_VERSION_BUILD);
|
|
if (obj)
|
|
{
|
|
rapidjson_flax::StringBuffer buffer;
|
|
CompactJsonWriter writer(buffer);
|
|
writer.StartObject();
|
|
obj->Serialize(writer, otherObj);
|
|
writer.EndObject();
|
|
|
|
WriteInt32((int32)buffer.GetSize());
|
|
WriteBytes((byte*)buffer.GetString(), (int32)buffer.GetSize());
|
|
}
|
|
else
|
|
WriteInt32(0);
|
|
}
|
|
|
|
Array<byte> JsonSerializer::SaveToBytes(ISerializable* obj)
|
|
{
|
|
Array<byte> result;
|
|
if (obj)
|
|
{
|
|
rapidjson_flax::StringBuffer buffer;
|
|
CompactJsonWriter writer(buffer);
|
|
writer.StartObject();
|
|
obj->Serialize(writer, nullptr);
|
|
writer.EndObject();
|
|
result.Set((byte*)buffer.GetString(), (int32)buffer.GetSize());
|
|
}
|
|
return result;
|
|
}
|
|
|
|
void JsonSerializer::LoadFromBytes(ISerializable* obj, const Span<byte>& data, int32 engineBuild)
|
|
{
|
|
if (!obj || data.Length() == 0)
|
|
return;
|
|
|
|
ISerializable::SerializeDocument document;
|
|
{
|
|
PROFILE_CPU_NAMED("Json.Parse");
|
|
document.Parse((const char*)data.Get(), data.Length());
|
|
}
|
|
if (document.HasParseError())
|
|
{
|
|
Log::JsonParseException(document.GetParseError(), document.GetErrorOffset());
|
|
return;
|
|
}
|
|
|
|
auto modifier = Cache::ISerializeModifier.Get();
|
|
modifier->EngineBuild = engineBuild;
|
|
obj->Deserialize(document, modifier.Value);
|
|
}
|