Ver código fonte

Ability to save objects to binary format

Juan Linietsky 8 anos atrás
pai
commit
b7571582ed
4 arquivos alterados com 174 adições e 32 exclusões
  1. 153 30
      core/io/marshalls.cpp
  2. 1 1
      core/io/marshalls.h
  3. 15 1
      core/io/packet_peer.cpp
  4. 5 0
      core/io/packet_peer.h

+ 153 - 30
core/io/marshalls.cpp

@@ -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: {
 

+ 1 - 1
core/io/marshalls.h

@@ -183,7 +183,7 @@ static inline double decode_double(const uint8_t *p_arr) {
 	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);
 
 #endif

+ 15 - 1
core/io/packet_peer.cpp

@@ -35,9 +35,20 @@
 
 PacketPeer::PacketPeer() {
 
+	allow_object_decoding = false;
 	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 {
 
 	const uint8_t *buffer;
@@ -75,7 +86,7 @@ Error PacketPeer::get_var(Variant &r_variant) const {
 	if (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) {
@@ -126,6 +137,9 @@ void PacketPeer::_bind_methods() {
 	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_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);
 };
 
 /***************/

+ 5 - 0
core/io/packet_peer.h

@@ -48,6 +48,8 @@ class PacketPeer : public Reference {
 
 	mutable Error last_get_error;
 
+	bool allow_object_decoding;
+
 public:
 	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
@@ -63,6 +65,9 @@ public:
 	virtual Error get_var(Variant &r_variant) const;
 	virtual Error put_var(const Variant &p_packet);
 
+	void set_allow_object_decoding(bool p_enable);
+	bool is_object_decoding_allowed() const;
+
 	PacketPeer();
 	~PacketPeer() {}
 };