// 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/Collections/Dictionary.h" #include "Engine/Content/Asset.h" #include "Engine/Core/Cache.h" #include "Engine/Debug/DebugLog.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(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(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 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(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::Color: ReadBytes(&data->AsData, sizeof(Color)); break; case VariantType::Guid: ReadBytes(&data->AsData, sizeof(Guid)); break; case VariantType::BoundingBox: ReadBytes(data->AsBlob.Data, 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->AsBlob.Data, sizeof(Ray)); break; case VariantType::Matrix: ReadBytes(data->AsBlob.Data, sizeof(Matrix)); break; case VariantType::Array: { int32 count; ReadInt32(&count); auto& array = *(Array*)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); Variant key, value; for (int32 i = 0; i < count; i++) { ReadVariant(&key); ReadVariant(&value); dictionary.Add(key, value); } 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(this)) { JsonSerializer::LoadFromBytes(obj, Span((byte*)memoryStream->Read(size), size), engineBuild); } else { void* data = Allocator::Allocate(size); ReadBytes(data, size); JsonSerializer::LoadFromBytes(obj, Span((byte*)data, size), engineBuild); Allocator::Free(data); } } else SetPosition(GetPosition() + size); } void WriteStream::WriteText(const StringView& text) { for (int32 i = 0; i < text.Length(); i++) WriteChar(text[i]); } void WriteStream::WriteText(const StringAnsiView& text) { for (int32 i = 0; i < text.Length(); i++) WriteChar(text[i]); } 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(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.AsBlob.Data, sizeof(BoundingBox)); break; case VariantType::Transform: WriteBytes(data.AsBlob.Data, sizeof(Transform)); break; case VariantType::Ray: WriteBytes(data.AsBlob.Data, 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: Write(data.AsData, sizeof(Vector2)); break; case VariantType::Vector3: Write(data.AsData, sizeof(Vector3)); break; case VariantType::Vector4: Write(data.AsData, sizeof(Vector4)); break; case VariantType::Color: Write(data.AsData, sizeof(Color)); break; case VariantType::Guid: Write(data.AsData, sizeof(Guid)); break; case VariantType::Quaternion: Write(data.AsData, sizeof(Quaternion)); break; case VariantType::Rectangle: Write(data.AsData, sizeof(Rectangle)); break; case VariantType::BoundingSphere: Write(data.AsData, sizeof(BoundingSphere)); break; case VariantType::Array: id.A = ((Array*)data.AsData)->Count(); WriteInt32(id.A); for (uint32 i = 0; i < id.A; i++) WriteVariant(((Array*)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 JsonSerializer::SaveToBytes(ISerializable* obj) { Array 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& 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); }