diff options
Diffstat (limited to 'core/io/marshalls.cpp')
-rw-r--r-- | core/io/marshalls.cpp | 212 |
1 files changed, 169 insertions, 43 deletions
diff --git a/core/io/marshalls.cpp b/core/io/marshalls.cpp index bc2493d360..b25fcccd7f 100644 --- a/core/io/marshalls.cpp +++ b/core/io/marshalls.cpp @@ -30,7 +30,10 @@ #include "marshalls.h" +#include "core/core_string_names.h" +#include "core/io/resource_loader.h" #include "core/object/ref_counted.h" +#include "core/object/script_language.h" #include "core/os/keyboard.h" #include "core/string/print_string.h" @@ -55,9 +58,22 @@ ObjectID EncodedObjectAsID::get_object_id() const { #define ERR_FAIL_ADD_OF(a, b, err) ERR_FAIL_COND_V(((int32_t)(b)) < 0 || ((int32_t)(a)) < 0 || ((int32_t)(a)) > INT_MAX - ((int32_t)(b)), err) #define ERR_FAIL_MUL_OF(a, b, err) ERR_FAIL_COND_V(((int32_t)(a)) < 0 || ((int32_t)(b)) <= 0 || ((int32_t)(a)) > INT_MAX / ((int32_t)(b)), err) -#define ENCODE_MASK 0xFF -#define ENCODE_FLAG_64 1 << 16 -#define ENCODE_FLAG_OBJECT_AS_ID 1 << 16 +// Byte 0: `Variant::Type`, byte 1: unused, bytes 2 and 3: additional data. +#define HEADER_TYPE_MASK 0xFF + +// For `Variant::INT`, `Variant::FLOAT` and other math types. +#define HEADER_DATA_FLAG_64 (1 << 16) + +// For `Variant::OBJECT`. +#define HEADER_DATA_FLAG_OBJECT_AS_ID (1 << 16) + +// For `Variant::ARRAY`. +// Occupies bits 16 and 17. +#define HEADER_DATA_FIELD_TYPED_ARRAY_MASK (0b11 << 16) +#define HEADER_DATA_FIELD_TYPED_ARRAY_NONE (0b00 << 16) +#define HEADER_DATA_FIELD_TYPED_ARRAY_BUILTIN (0b01 << 16) +#define HEADER_DATA_FIELD_TYPED_ARRAY_CLASS_NAME (0b10 << 16) +#define HEADER_DATA_FIELD_TYPED_ARRAY_SCRIPT (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); @@ -101,9 +117,9 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int ERR_FAIL_COND_V(len < 4, ERR_INVALID_DATA); - uint32_t type = decode_uint32(buf); + uint32_t header = decode_uint32(buf); - ERR_FAIL_COND_V((type & ENCODE_MASK) >= Variant::VARIANT_MAX, ERR_INVALID_DATA); + ERR_FAIL_COND_V((header & HEADER_TYPE_MASK) >= Variant::VARIANT_MAX, ERR_INVALID_DATA); buf += 4; len -= 4; @@ -114,7 +130,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int // Note: We cannot use sizeof(real_t) for decoding, in case a different size is encoded. // Decoding math types always checks for the encoded size, while encoding always uses compilation setting. // This does lead to some code duplication for decoding, but compatibility is the priority. - switch (type & ENCODE_MASK) { + switch (header & HEADER_TYPE_MASK) { case Variant::NIL: { r_variant = Variant(); } break; @@ -127,7 +143,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int } } break; case Variant::INT: { - if (type & ENCODE_FLAG_64) { + if (header & HEADER_DATA_FLAG_64) { ERR_FAIL_COND_V(len < 8, ERR_INVALID_DATA); int64_t val = decode_uint64(buf); r_variant = val; @@ -146,7 +162,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int } break; case Variant::FLOAT: { - if (type & ENCODE_FLAG_64) { + if (header & HEADER_DATA_FLAG_64) { ERR_FAIL_COND_V((size_t)len < sizeof(double), ERR_INVALID_DATA); double val = decode_double(buf); r_variant = val; @@ -176,7 +192,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int // math types case Variant::VECTOR2: { Vector2 val; - if (type & ENCODE_FLAG_64) { + if (header & HEADER_DATA_FLAG_64) { ERR_FAIL_COND_V((size_t)len < sizeof(double) * 2, ERR_INVALID_DATA); val.x = decode_double(&buf[0]); val.y = decode_double(&buf[sizeof(double)]); @@ -210,7 +226,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int } break; case Variant::RECT2: { Rect2 val; - if (type & ENCODE_FLAG_64) { + if (header & HEADER_DATA_FLAG_64) { ERR_FAIL_COND_V((size_t)len < sizeof(double) * 4, ERR_INVALID_DATA); val.position.x = decode_double(&buf[0]); val.position.y = decode_double(&buf[sizeof(double)]); @@ -250,7 +266,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int } break; case Variant::VECTOR3: { Vector3 val; - if (type & ENCODE_FLAG_64) { + if (header & HEADER_DATA_FLAG_64) { ERR_FAIL_COND_V((size_t)len < sizeof(double) * 3, ERR_INVALID_DATA); val.x = decode_double(&buf[0]); val.y = decode_double(&buf[sizeof(double)]); @@ -287,7 +303,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int } break; case Variant::VECTOR4: { Vector4 val; - if (type & ENCODE_FLAG_64) { + if (header & HEADER_DATA_FLAG_64) { ERR_FAIL_COND_V((size_t)len < sizeof(double) * 4, ERR_INVALID_DATA); val.x = decode_double(&buf[0]); val.y = decode_double(&buf[sizeof(double)]); @@ -327,7 +343,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int } break; case Variant::TRANSFORM2D: { Transform2D val; - if (type & ENCODE_FLAG_64) { + if (header & HEADER_DATA_FLAG_64) { ERR_FAIL_COND_V((size_t)len < sizeof(double) * 6, ERR_INVALID_DATA); for (int i = 0; i < 3; i++) { for (int j = 0; j < 2; j++) { @@ -355,7 +371,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int } break; case Variant::PLANE: { Plane val; - if (type & ENCODE_FLAG_64) { + if (header & HEADER_DATA_FLAG_64) { ERR_FAIL_COND_V((size_t)len < sizeof(double) * 4, ERR_INVALID_DATA); val.normal.x = decode_double(&buf[0]); val.normal.y = decode_double(&buf[sizeof(double)]); @@ -381,7 +397,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int } break; case Variant::QUATERNION: { Quaternion val; - if (type & ENCODE_FLAG_64) { + if (header & HEADER_DATA_FLAG_64) { ERR_FAIL_COND_V((size_t)len < sizeof(double) * 4, ERR_INVALID_DATA); val.x = decode_double(&buf[0]); val.y = decode_double(&buf[sizeof(double)]); @@ -407,7 +423,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int } break; case Variant::AABB: { AABB val; - if (type & ENCODE_FLAG_64) { + if (header & HEADER_DATA_FLAG_64) { ERR_FAIL_COND_V((size_t)len < sizeof(double) * 6, ERR_INVALID_DATA); val.position.x = decode_double(&buf[0]); val.position.y = decode_double(&buf[sizeof(double)]); @@ -437,7 +453,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int } break; case Variant::BASIS: { Basis val; - if (type & ENCODE_FLAG_64) { + if (header & HEADER_DATA_FLAG_64) { ERR_FAIL_COND_V((size_t)len < sizeof(double) * 9, ERR_INVALID_DATA); for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { @@ -465,7 +481,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int } break; case Variant::TRANSFORM3D: { Transform3D val; - if (type & ENCODE_FLAG_64) { + if (header & HEADER_DATA_FLAG_64) { ERR_FAIL_COND_V((size_t)len < sizeof(double) * 12, ERR_INVALID_DATA); for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { @@ -499,7 +515,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int } break; case Variant::PROJECTION: { Projection val; - if (type & ENCODE_FLAG_64) { + if (header & HEADER_DATA_FLAG_64) { ERR_FAIL_COND_V((size_t)len < sizeof(double) * 16, ERR_INVALID_DATA); for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { @@ -560,12 +576,12 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int uint32_t namecount = strlen &= 0x7FFFFFFF; uint32_t subnamecount = decode_uint32(buf + 4); - uint32_t flags = decode_uint32(buf + 8); + uint32_t np_flags = decode_uint32(buf + 8); len -= 12; buf += 12; - if (flags & 2) { // Obsolete format with property separate from subpath + if (np_flags & 2) { // Obsolete format with property separate from subpath. subnamecount++; } @@ -589,7 +605,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int } } - r_variant = NodePath(names, subnames, flags & 1); + r_variant = NodePath(names, subnames, np_flags & 1); } else { //old format, just a string @@ -608,8 +624,8 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int r_variant = RID::from_uint64(id); } break; case Variant::OBJECT: { - if (type & ENCODE_FLAG_OBJECT_AS_ID) { - //this _is_ allowed + if (header & HEADER_DATA_FLAG_OBJECT_AS_ID) { + // This _is_ allowed. ERR_FAIL_COND_V(len < 8, ERR_INVALID_DATA); ObjectID val = ObjectID(decode_uint64(buf)); if (r_len) { @@ -625,7 +641,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); @@ -672,7 +687,16 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int (*r_len) += used; } - obj->set(str, value); + if (str == "script") { + ERR_FAIL_COND_V_MSG(value.get_type() != Variant::STRING, ERR_INVALID_DATA, "Invalid value for \"script\" property, expected script path as String."); + String path = value; + ERR_FAIL_COND_V_MSG(path.is_empty() || !path.begins_with("res://") || !ResourceLoader::exists(path, "Script"), ERR_INVALID_DATA, "Invalid script path: '" + path + "'."); + Ref<Script> script = ResourceLoader::load(path, "Script"); + ERR_FAIL_COND_V_MSG(script.is_null(), ERR_INVALID_DATA, "Can't load script at path: '" + path + "'."); + obj->set_script(script); + } else { + obj->set(str, value); + } } if (Object::cast_to<RefCounted>(obj)) { @@ -747,7 +771,60 @@ 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 (header & HEADER_DATA_FIELD_TYPED_ARRAY_MASK) { + case HEADER_DATA_FIELD_TYPED_ARRAY_NONE: + break; // Untyped array. + case HEADER_DATA_FIELD_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 HEADER_DATA_FIELD_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 HEADER_DATA_FIELD_TYPED_ARRAY_SCRIPT: { + ERR_FAIL_COND_V(!p_allow_objects, ERR_UNAUTHORIZED); + + String path; + Error err = _decode_string(buf, len, r_len, path); + if (err) { + return err; + } + ERR_FAIL_COND_V_MSG(path.is_empty() || !path.begins_with("res://") || !ResourceLoader::exists(path, "Script"), ERR_INVALID_DATA, "Invalid script path: '" + path + "'."); + script = ResourceLoader::load(path, "Script"); + ERR_FAIL_COND_V_MSG(script.is_null(), ERR_INVALID_DATA, "Can't load script at path: '" + path + "'."); + + builtin_type = Variant::OBJECT; + class_name = script->get_instance_base_type(); + } break; + default: + ERR_FAIL_V(ERR_INVALID_DATA); // Future proofing. + } + ERR_FAIL_COND_V(len < 4, ERR_INVALID_DATA); + int32_t count = decode_uint32(buf); // bool shared = count&0x80000000; count &= 0x7FFFFFFF; @@ -760,6 +837,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; @@ -936,7 +1016,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int Vector<Vector2> varray; - if (type & ENCODE_FLAG_64) { + if (header & HEADER_DATA_FLAG_64) { ERR_FAIL_MUL_OF(count, sizeof(double) * 2, ERR_INVALID_DATA); ERR_FAIL_COND_V(count < 0 || count * sizeof(double) * 2 > (size_t)len, ERR_INVALID_DATA); @@ -996,7 +1076,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int Vector<Vector3> varray; - if (type & ENCODE_FLAG_64) { + if (header & HEADER_DATA_FLAG_64) { ERR_FAIL_MUL_OF(count, sizeof(double) * 3, ERR_INVALID_DATA); ERR_FAIL_COND_V(count < 0 || count * sizeof(double) * 3 > (size_t)len, ERR_INVALID_DATA); @@ -1122,20 +1202,20 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo r_len = 0; - uint32_t flags = 0; + uint32_t header = p_variant.get_type(); switch (p_variant.get_type()) { case Variant::INT: { int64_t val = p_variant; if (val > (int64_t)INT_MAX || val < (int64_t)INT_MIN) { - flags |= ENCODE_FLAG_64; + header |= HEADER_DATA_FLAG_64; } } break; case Variant::FLOAT: { double d = p_variant; float f = d; if (double(f) != d) { - flags |= ENCODE_FLAG_64; + header |= HEADER_DATA_FLAG_64; } } break; case Variant::OBJECT: { @@ -1151,7 +1231,23 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo } if (!p_full_objects) { - flags |= ENCODE_FLAG_OBJECT_AS_ID; + header |= HEADER_DATA_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); + header |= HEADER_DATA_FIELD_TYPED_ARRAY_SCRIPT; + } else if (array.get_typed_class_name() != StringName()) { + ERR_FAIL_COND_V(!p_full_objects, ERR_UNAVAILABLE); + header |= HEADER_DATA_FIELD_TYPED_ARRAY_CLASS_NAME; + } else { + ERR_FAIL_COND_V(!p_full_objects && array.get_typed_builtin() == Variant::OBJECT, ERR_UNAVAILABLE); + header |= HEADER_DATA_FIELD_TYPED_ARRAY_BUILTIN; + } } } break; #ifdef REAL_T_IS_DOUBLE @@ -1168,7 +1264,7 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo case Variant::BASIS: case Variant::RECT2: case Variant::AABB: { - flags |= ENCODE_FLAG_64; + header |= HEADER_DATA_FLAG_64; } break; #endif // REAL_T_IS_DOUBLE default: { @@ -1176,7 +1272,7 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo } if (buf) { - encode_uint32(p_variant.get_type() | flags, buf); + encode_uint32(header, buf); buf += 4; } r_len += 4; @@ -1194,7 +1290,7 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo } break; case Variant::INT: { - if (flags & ENCODE_FLAG_64) { + if (header & HEADER_DATA_FLAG_64) { //64 bits if (buf) { encode_uint64(p_variant.operator int64_t(), buf); @@ -1210,7 +1306,7 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo } } break; case Variant::FLOAT: { - if (flags & ENCODE_FLAG_64) { + if (header & HEADER_DATA_FLAG_64) { if (buf) { encode_double(p_variant.operator double(), buf); } @@ -1523,8 +1619,21 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo _encode_string(E.name, buf, r_len); + Variant value; + + if (E.name == CoreStringNames::get_singleton()->_script) { + Ref<Script> script = obj->get_script(); + if (script.is_valid()) { + String path = script->get_path(); + ERR_FAIL_COND_V_MSG(path.is_empty() || !path.begins_with("res://"), ERR_UNAVAILABLE, "Failed to encode a path to a custom script."); + value = path; + } + } else { + value = obj->get(E.name); + } + int len; - Error err = encode_variant(obj->get(E.name), buf, len, p_full_objects, p_depth + 1); + Error err = encode_variant(value, 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; @@ -1594,24 +1703,41 @@ 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()) { + String path = script->get_path(); + ERR_FAIL_COND_V_MSG(path.is_empty() || !path.begins_with("res://"), ERR_UNAVAILABLE, "Failed to encode a path to a custom script for an array type."); + _encode_string(path, buf, r_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; |