Ability to save objects to binary format
This commit is contained in:
parent
9575dbdf78
commit
b7571582ed
@ -30,12 +30,40 @@
|
|||||||
#include "marshalls.h"
|
#include "marshalls.h"
|
||||||
#include "os/keyboard.h"
|
#include "os/keyboard.h"
|
||||||
#include "print_string.h"
|
#include "print_string.h"
|
||||||
|
#include "reference.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#define ENCODE_MASK 0xFF
|
#define ENCODE_MASK 0xFF
|
||||||
#define ENCODE_FLAG_64 1 << 16
|
#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;
|
const uint8_t *buf = p_buffer;
|
||||||
int len = p_len;
|
int len = p_len;
|
||||||
@ -104,22 +132,12 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int
|
|||||||
} break;
|
} break;
|
||||||
case Variant::STRING: {
|
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;
|
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;
|
r_variant = str;
|
||||||
|
|
||||||
if (r_len) {
|
|
||||||
if (strlen % 4)
|
|
||||||
(*r_len) += 4 - strlen % 4;
|
|
||||||
(*r_len) += 4 + strlen;
|
|
||||||
}
|
|
||||||
|
|
||||||
} break;
|
} break;
|
||||||
// math types
|
// math types
|
||||||
|
|
||||||
@ -363,7 +381,59 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int
|
|||||||
} break;
|
} break;
|
||||||
case Variant::OBJECT: {
|
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;
|
} break;
|
||||||
case Variant::DICTIONARY: {
|
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;
|
Variant key, value;
|
||||||
|
|
||||||
int used;
|
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);
|
ERR_FAIL_COND_V(err, err);
|
||||||
|
|
||||||
buf += used;
|
buf += used;
|
||||||
@ -395,7 +465,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int
|
|||||||
(*r_len) += used;
|
(*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);
|
ERR_FAIL_COND_V(err, err);
|
||||||
|
|
||||||
buf += used;
|
buf += used;
|
||||||
@ -430,7 +500,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int
|
|||||||
|
|
||||||
int used = 0;
|
int used = 0;
|
||||||
Variant v;
|
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);
|
ERR_FAIL_COND_V(err, err);
|
||||||
buf += used;
|
buf += used;
|
||||||
len -= used;
|
len -= used;
|
||||||
@ -691,6 +761,21 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int
|
|||||||
return OK;
|
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) {
|
Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len) {
|
||||||
|
|
||||||
uint8_t *buf = r_buffer;
|
uint8_t *buf = r_buffer;
|
||||||
@ -831,17 +916,7 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len) {
|
|||||||
} break;
|
} break;
|
||||||
case Variant::STRING: {
|
case Variant::STRING: {
|
||||||
|
|
||||||
CharString utf8 = p_variant.operator String().utf8();
|
_encode_string(p_variant, buf, r_len);
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
} break;
|
} break;
|
||||||
// math types
|
// 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_EXPLAIN("Can't marshallize resources");
|
||||||
ERR_FAIL_V(ERR_INVALID_DATA); //no, i'm sorry, no go
|
ERR_FAIL_V(ERR_INVALID_DATA); //no, i'm sorry, no go
|
||||||
} break;*/
|
} break;*/
|
||||||
case Variant::_RID:
|
case Variant::_RID: {
|
||||||
|
|
||||||
|
} break;
|
||||||
case Variant::OBJECT: {
|
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;
|
} break;
|
||||||
case Variant::DICTIONARY: {
|
case Variant::DICTIONARY: {
|
||||||
|
|
||||||
|
@ -183,7 +183,7 @@ static inline double decode_double(const uint8_t *p_arr) {
|
|||||||
return md.d;
|
return md.d;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int *r_len = NULL);
|
Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int *r_len = NULL, bool p_allow_objects=true);
|
||||||
Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len);
|
Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -35,9 +35,20 @@
|
|||||||
|
|
||||||
PacketPeer::PacketPeer() {
|
PacketPeer::PacketPeer() {
|
||||||
|
|
||||||
|
allow_object_decoding = false;
|
||||||
last_get_error = OK;
|
last_get_error = OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PacketPeer::set_allow_object_decoding(bool p_enable) {
|
||||||
|
|
||||||
|
allow_object_decoding = p_enable;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PacketPeer::is_object_decoding_allowed() const {
|
||||||
|
|
||||||
|
return allow_object_decoding;
|
||||||
|
}
|
||||||
|
|
||||||
Error PacketPeer::get_packet_buffer(PoolVector<uint8_t> &r_buffer) const {
|
Error PacketPeer::get_packet_buffer(PoolVector<uint8_t> &r_buffer) const {
|
||||||
|
|
||||||
const uint8_t *buffer;
|
const uint8_t *buffer;
|
||||||
@ -75,7 +86,7 @@ Error PacketPeer::get_var(Variant &r_variant) const {
|
|||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
return decode_variant(r_variant, buffer, buffer_size);
|
return decode_variant(r_variant, buffer, buffer_size, NULL, allow_object_decoding);
|
||||||
}
|
}
|
||||||
|
|
||||||
Error PacketPeer::put_var(const Variant &p_packet) {
|
Error PacketPeer::put_var(const Variant &p_packet) {
|
||||||
@ -126,6 +137,9 @@ void PacketPeer::_bind_methods() {
|
|||||||
ClassDB::bind_method(D_METHOD("put_packet", "buffer"), &PacketPeer::_put_packet);
|
ClassDB::bind_method(D_METHOD("put_packet", "buffer"), &PacketPeer::_put_packet);
|
||||||
ClassDB::bind_method(D_METHOD("get_packet_error"), &PacketPeer::_get_packet_error);
|
ClassDB::bind_method(D_METHOD("get_packet_error"), &PacketPeer::_get_packet_error);
|
||||||
ClassDB::bind_method(D_METHOD("get_available_packet_count"), &PacketPeer::get_available_packet_count);
|
ClassDB::bind_method(D_METHOD("get_available_packet_count"), &PacketPeer::get_available_packet_count);
|
||||||
|
|
||||||
|
ClassDB::bind_method(D_METHOD("set_allow_object_decoding", "enable"), &PacketPeer::set_allow_object_decoding);
|
||||||
|
ClassDB::bind_method(D_METHOD("is_object_decoding_allowed"), &PacketPeer::is_object_decoding_allowed);
|
||||||
};
|
};
|
||||||
|
|
||||||
/***************/
|
/***************/
|
||||||
|
@ -48,6 +48,8 @@ class PacketPeer : public Reference {
|
|||||||
|
|
||||||
mutable Error last_get_error;
|
mutable Error last_get_error;
|
||||||
|
|
||||||
|
bool allow_object_decoding;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual int get_available_packet_count() const = 0;
|
virtual int get_available_packet_count() const = 0;
|
||||||
virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size) const = 0; ///< buffer is GONE after next get_packet
|
virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size) const = 0; ///< buffer is GONE after next get_packet
|
||||||
@ -63,6 +65,9 @@ public:
|
|||||||
virtual Error get_var(Variant &r_variant) const;
|
virtual Error get_var(Variant &r_variant) const;
|
||||||
virtual Error put_var(const Variant &p_packet);
|
virtual Error put_var(const Variant &p_packet);
|
||||||
|
|
||||||
|
void set_allow_object_decoding(bool p_enable);
|
||||||
|
bool is_object_decoding_allowed() const;
|
||||||
|
|
||||||
PacketPeer();
|
PacketPeer();
|
||||||
~PacketPeer() {}
|
~PacketPeer() {}
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user