|
@@ -30,12 +30,40 @@
|
|
|
#include "marshalls.h"
|
|
|
#include "os/keyboard.h"
|
|
|
#include "print_string.h"
|
|
|
+#include "reference.h"
|
|
|
#include <stdio.h>
|
|
|
|
|
|
#define ENCODE_MASK 0xFF
|
|
|
#define ENCODE_FLAG_64 1 << 16
|
|
|
|
|
|
-Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int *r_len) {
|
|
|
+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);
|
|
|
+
|
|
|
+ uint32_t strlen = decode_uint32(buf);
|
|
|
+ buf += 4;
|
|
|
+ len -= 4;
|
|
|
+ ERR_FAIL_COND_V((int)strlen > len, ERR_FILE_EOF);
|
|
|
+
|
|
|
+ String str;
|
|
|
+ str.parse_utf8((const char *)buf, strlen);
|
|
|
+ r_string = str;
|
|
|
+
|
|
|
+ //handle padding
|
|
|
+ if (strlen % 4) {
|
|
|
+ strlen += 4 - strlen % 4;
|
|
|
+ }
|
|
|
+
|
|
|
+ buf += strlen;
|
|
|
+ len -= strlen;
|
|
|
+
|
|
|
+ if (r_len) {
|
|
|
+ (*r_len) += 4 + strlen;
|
|
|
+ }
|
|
|
+
|
|
|
+ return OK;
|
|
|
+}
|
|
|
+
|
|
|
+Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int *r_len, bool p_allow_objects) {
|
|
|
|
|
|
const uint8_t *buf = p_buffer;
|
|
|
int len = p_len;
|
|
@@ -104,22 +132,12 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int
|
|
|
} break;
|
|
|
case Variant::STRING: {
|
|
|
|
|
|
- ERR_FAIL_COND_V(len < 4, ERR_INVALID_DATA);
|
|
|
- uint32_t strlen = decode_uint32(buf);
|
|
|
- buf += 4;
|
|
|
- len -= 4;
|
|
|
- ERR_FAIL_COND_V((int)strlen > len, ERR_INVALID_DATA);
|
|
|
-
|
|
|
String str;
|
|
|
- str.parse_utf8((const char *)buf, strlen);
|
|
|
+ Error err = _decode_string(buf, len, r_len, str);
|
|
|
+ if (err)
|
|
|
+ return err;
|
|
|
r_variant = str;
|
|
|
|
|
|
- if (r_len) {
|
|
|
- if (strlen % 4)
|
|
|
- (*r_len) += 4 - strlen % 4;
|
|
|
- (*r_len) += 4 + strlen;
|
|
|
- }
|
|
|
-
|
|
|
} break;
|
|
|
// math types
|
|
|
|
|
@@ -363,7 +381,59 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int
|
|
|
} break;
|
|
|
case Variant::OBJECT: {
|
|
|
|
|
|
- r_variant = (Object *)NULL;
|
|
|
+ ERR_FAIL_COND_V(!p_allow_objects, ERR_UNAUTHORIZED);
|
|
|
+
|
|
|
+ String str;
|
|
|
+ Error err = _decode_string(buf, len, r_len, str);
|
|
|
+ if (err)
|
|
|
+ return err;
|
|
|
+
|
|
|
+ if (str == String()) {
|
|
|
+ r_variant = (Object *)NULL;
|
|
|
+ } else {
|
|
|
+
|
|
|
+ Object *obj = ClassDB::instance(str);
|
|
|
+
|
|
|
+ ERR_FAIL_COND_V(!obj, ERR_UNAVAILABLE);
|
|
|
+ ERR_FAIL_COND_V(len < 4, ERR_INVALID_DATA);
|
|
|
+
|
|
|
+ int32_t count = decode_uint32(buf);
|
|
|
+ buf += 4;
|
|
|
+ len -= 4;
|
|
|
+ if (r_len) {
|
|
|
+ (*r_len) += 4;
|
|
|
+ }
|
|
|
+
|
|
|
+ for (int i = 0; i < count; i++) {
|
|
|
+
|
|
|
+ str = String();
|
|
|
+ err = _decode_string(buf, len, r_len, str);
|
|
|
+ if (err)
|
|
|
+ return err;
|
|
|
+
|
|
|
+ Variant value;
|
|
|
+ int used;
|
|
|
+ err = decode_variant(value, buf, len, &used, p_allow_objects);
|
|
|
+ if (err)
|
|
|
+ return err;
|
|
|
+
|
|
|
+ buf += used;
|
|
|
+ len -= used;
|
|
|
+ if (r_len) {
|
|
|
+ (*r_len) += used;
|
|
|
+ }
|
|
|
+
|
|
|
+ obj->set(str, value);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (obj->cast_to<Reference>()) {
|
|
|
+ REF ref = REF(obj->cast_to<Reference>());
|
|
|
+ r_variant = ref;
|
|
|
+ } else {
|
|
|
+ r_variant = obj;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
} break;
|
|
|
case Variant::DICTIONARY: {
|
|
|
|
|
@@ -386,7 +456,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int
|
|
|
Variant key, value;
|
|
|
|
|
|
int used;
|
|
|
- Error err = decode_variant(key, buf, len, &used);
|
|
|
+ Error err = decode_variant(key, buf, len, &used, p_allow_objects);
|
|
|
ERR_FAIL_COND_V(err, err);
|
|
|
|
|
|
buf += used;
|
|
@@ -395,7 +465,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int
|
|
|
(*r_len) += used;
|
|
|
}
|
|
|
|
|
|
- err = decode_variant(value, buf, len, &used);
|
|
|
+ err = decode_variant(value, buf, len, &used, p_allow_objects);
|
|
|
ERR_FAIL_COND_V(err, err);
|
|
|
|
|
|
buf += used;
|
|
@@ -430,7 +500,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int
|
|
|
|
|
|
int used = 0;
|
|
|
Variant v;
|
|
|
- Error err = decode_variant(v, buf, len, &used);
|
|
|
+ Error err = decode_variant(v, buf, len, &used, p_allow_objects);
|
|
|
ERR_FAIL_COND_V(err, err);
|
|
|
buf += used;
|
|
|
len -= used;
|
|
@@ -691,6 +761,21 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int
|
|
|
return OK;
|
|
|
}
|
|
|
|
|
|
+static void _encode_string(const String &p_string, uint8_t *&buf, int &r_len) {
|
|
|
+
|
|
|
+ CharString utf8 = p_string.utf8();
|
|
|
+
|
|
|
+ if (buf) {
|
|
|
+ encode_uint32(utf8.length(), buf);
|
|
|
+ buf += 4;
|
|
|
+ copymem(buf, utf8.get_data(), utf8.length());
|
|
|
+ }
|
|
|
+
|
|
|
+ r_len += 4 + utf8.length();
|
|
|
+ while (r_len % 4)
|
|
|
+ r_len++; //pad
|
|
|
+}
|
|
|
+
|
|
|
Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len) {
|
|
|
|
|
|
uint8_t *buf = r_buffer;
|
|
@@ -831,17 +916,7 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len) {
|
|
|
} break;
|
|
|
case Variant::STRING: {
|
|
|
|
|
|
- CharString utf8 = p_variant.operator String().utf8();
|
|
|
-
|
|
|
- if (buf) {
|
|
|
- encode_uint32(utf8.length(), buf);
|
|
|
- buf += 4;
|
|
|
- copymem(buf, utf8.get_data(), utf8.length());
|
|
|
- }
|
|
|
-
|
|
|
- r_len += 4 + utf8.length();
|
|
|
- while (r_len % 4)
|
|
|
- r_len++; //pad
|
|
|
+ _encode_string(p_variant, buf, r_len);
|
|
|
|
|
|
} break;
|
|
|
// math types
|
|
@@ -991,9 +1066,57 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len) {
|
|
|
ERR_EXPLAIN("Can't marshallize resources");
|
|
|
ERR_FAIL_V(ERR_INVALID_DATA); //no, i'm sorry, no go
|
|
|
} break;*/
|
|
|
- case Variant::_RID:
|
|
|
+ case Variant::_RID: {
|
|
|
+
|
|
|
+ } break;
|
|
|
case Variant::OBJECT: {
|
|
|
|
|
|
+ Object *obj = p_variant;
|
|
|
+ if (!obj) {
|
|
|
+ if (buf) {
|
|
|
+ encode_uint32(0, buf);
|
|
|
+ buf += 4;
|
|
|
+ r_len += 4;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ _encode_string(obj->get_class(), buf, r_len);
|
|
|
+
|
|
|
+ List<PropertyInfo> props;
|
|
|
+ obj->get_property_list(&props);
|
|
|
+
|
|
|
+ int pc = 0;
|
|
|
+ for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) {
|
|
|
+
|
|
|
+ if (!(E->get().usage & PROPERTY_USAGE_STORAGE))
|
|
|
+ continue;
|
|
|
+ pc++;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (buf) {
|
|
|
+ encode_uint32(pc, buf);
|
|
|
+ buf += 4;
|
|
|
+ }
|
|
|
+
|
|
|
+ r_len += 4;
|
|
|
+
|
|
|
+ for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) {
|
|
|
+
|
|
|
+ if (!(E->get().usage & PROPERTY_USAGE_STORAGE))
|
|
|
+ continue;
|
|
|
+
|
|
|
+ _encode_string(E->get().name, buf, r_len);
|
|
|
+
|
|
|
+ int len;
|
|
|
+ Error err = encode_variant(obj->get(E->get().name), buf, len);
|
|
|
+ if (err)
|
|
|
+ return err;
|
|
|
+ ERR_FAIL_COND_V(len % 4, ERR_BUG);
|
|
|
+ r_len += len;
|
|
|
+ if (buf)
|
|
|
+ buf += len;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
} break;
|
|
|
case Variant::DICTIONARY: {
|
|
|
|