Skip to content

Commit

Permalink
Core: Add typed array support for binary serialization
Browse files Browse the repository at this point in the history
  • Loading branch information
dalexeev committed Jun 14, 2023
1 parent 824c139 commit 8dac994
Showing 1 changed file with 115 additions and 8 deletions.
123 changes: 115 additions & 8 deletions core/io/marshalls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include "marshalls.h"

#include "core/object/ref_counted.h"
#include "core/object/script_language.h"
#include "core/os/keyboard.h"
#include "core/string/print_string.h"

Expand Down Expand Up @@ -59,6 +60,13 @@ ObjectID EncodedObjectAsID::get_object_id() const {
#define ENCODE_FLAG_64 1 << 16
#define ENCODE_FLAG_OBJECT_AS_ID 1 << 16

// Actually, these are not flags.
#define ENCODE_FLAG_TYPED_ARRAY_BUILTIN 1 << 16
#define ENCODE_FLAG_TYPED_ARRAY_CLASS_NAME 2 << 16
#define ENCODE_FLAG_TYPED_ARRAY_SCRIPT 3 << 16
// Occupies bits 16 and 17. If we need more flags, we can place them after.
#define ENCODE_FLAG_TYPED_ARRAY_MASK 0b11 << 16

static Error _decode_string(const uint8_t *&buf, int &len, int *r_len, String &r_string) {
ERR_FAIL_COND_V(len < 4, ERR_INVALID_DATA);

Expand Down Expand Up @@ -609,7 +617,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int
} break;
case Variant::OBJECT: {
if (type & ENCODE_FLAG_OBJECT_AS_ID) {
//this _is_ allowed
// This _is_ allowed.
ERR_FAIL_COND_V(len < 8, ERR_INVALID_DATA);
ObjectID val = ObjectID(decode_uint64(buf));
if (r_len) {
Expand All @@ -625,7 +633,6 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int

r_variant = obj_as_id;
}

} else {
ERR_FAIL_COND_V(!p_allow_objects, ERR_UNAUTHORIZED);

Expand Down Expand Up @@ -745,7 +752,66 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int

} break;
case Variant::ARRAY: {
Variant::Type builtin_type = Variant::VARIANT_MAX;
StringName class_name;
Ref<Script> script;

switch (type & ENCODE_FLAG_TYPED_ARRAY_MASK) {
case 0:
break; // Untyped array.
case ENCODE_FLAG_TYPED_ARRAY_BUILTIN: {
ERR_FAIL_COND_V(len < 4, ERR_INVALID_DATA);

int32_t bt = decode_uint32(buf);
buf += 4;
len -= 4;
if (r_len) {
(*r_len) += 4;
}

ERR_FAIL_INDEX_V(bt, Variant::VARIANT_MAX, ERR_INVALID_DATA);
builtin_type = (Variant::Type)bt;
ERR_FAIL_COND_V(!p_allow_objects && builtin_type == Variant::OBJECT, ERR_UNAUTHORIZED);
} break;
case ENCODE_FLAG_TYPED_ARRAY_CLASS_NAME: {
ERR_FAIL_COND_V(!p_allow_objects, ERR_UNAUTHORIZED);

String str;
Error err = _decode_string(buf, len, r_len, str);
if (err) {
return err;
}

builtin_type = Variant::OBJECT;
class_name = str;
} break;
case ENCODE_FLAG_TYPED_ARRAY_SCRIPT: {
ERR_FAIL_COND_V(!p_allow_objects, ERR_UNAUTHORIZED);

Variant variant;
int used;
Error err = decode_variant(variant, buf, len, &used, p_allow_objects, p_depth + 1);
if (err) {
return err;
}

buf += used;
len -= used;
if (r_len) {
(*r_len) += used;
}

builtin_type = Variant::OBJECT;
script = variant;
ERR_FAIL_COND_V(script.is_null(), ERR_INVALID_DATA);
class_name = script->get_instance_base_type();
} break;
default:
ERR_FAIL_V(ERR_INVALID_DATA);
}

ERR_FAIL_COND_V(len < 4, ERR_INVALID_DATA);

int32_t count = decode_uint32(buf);
// bool shared = count&0x80000000;
count &= 0x7FFFFFFF;
Expand All @@ -758,6 +824,9 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int
}

Array varr;
if (builtin_type != Variant::VARIANT_MAX) {
varr.set_typed(builtin_type, class_name, script);
}

for (int i = 0; i < count; i++) {
int used = 0;
Expand Down Expand Up @@ -1152,6 +1221,22 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo
flags |= ENCODE_FLAG_OBJECT_AS_ID;
}
} break;
case Variant::ARRAY: {
Array array = p_variant;
if (array.is_typed()) {
Ref<Script> script = array.get_typed_script();
if (script.is_valid()) {
ERR_FAIL_COND_V(!p_full_objects, ERR_UNAVAILABLE);
flags |= ENCODE_FLAG_TYPED_ARRAY_SCRIPT;
} else if (array.get_typed_class_name() != StringName()) {
ERR_FAIL_COND_V(!p_full_objects, ERR_UNAVAILABLE);
flags |= ENCODE_FLAG_TYPED_ARRAY_CLASS_NAME;
} else {
ERR_FAIL_COND_V(!p_full_objects && array.get_typed_builtin() == Variant::OBJECT, ERR_UNAVAILABLE);
flags |= ENCODE_FLAG_TYPED_ARRAY_BUILTIN;
}
}
} break;
#ifdef REAL_T_IS_DOUBLE
case Variant::VECTOR2:
case Variant::VECTOR3:
Expand Down Expand Up @@ -1588,24 +1673,46 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo

} break;
case Variant::ARRAY: {
Array v = p_variant;
Array array = p_variant;

if (array.is_typed()) {
Variant variant = array.get_typed_script();
Ref<Script> script = variant;
if (script.is_valid()) {
int len;
Error err = encode_variant(script, buf, len, p_full_objects, p_depth + 1);
ERR_FAIL_COND_V(err, err);
ERR_FAIL_COND_V(len % 4, ERR_BUG);
if (buf) {
buf += len;
}
r_len += len;
} else if (array.get_typed_class_name() != StringName()) {
_encode_string(array.get_typed_class_name(), buf, r_len);
} else {
if (buf) {
encode_uint32(array.get_typed_builtin(), buf);
buf += 4;
}
r_len += 4;
}
}

if (buf) {
encode_uint32(uint32_t(v.size()), buf);
encode_uint32(uint32_t(array.size()), buf);
buf += 4;
}

r_len += 4;

for (int i = 0; i < v.size(); i++) {
for (int i = 0; i < array.size(); i++) {
int len;
Error err = encode_variant(v.get(i), buf, len, p_full_objects, p_depth + 1);
Error err = encode_variant(array.get(i), buf, len, p_full_objects, p_depth + 1);
ERR_FAIL_COND_V(err, err);
ERR_FAIL_COND_V(len % 4, ERR_BUG);
r_len += len;
if (buf) {
buf += len;
}
r_len += len;
}

} break;
Expand Down

0 comments on commit 8dac994

Please sign in to comment.