summaryrefslogtreecommitdiffstats
path: root/core/packed_data_container.cpp
diff options
context:
space:
mode:
authorJuan Linietsky <reduzio@gmail.com>2014-02-09 22:10:30 -0300
committerJuan Linietsky <reduzio@gmail.com>2014-02-09 22:10:30 -0300
commit0b806ee0fc9097fa7bda7ac0109191c9c5e0a1ac (patch)
tree276c4d099e178eb67fbd14f61d77b05e3808e9e3 /core/packed_data_container.cpp
parent0e49da1687bc8192ed210947da52c9e5c5f301bb (diff)
downloadredot-engine-0b806ee0fc9097fa7bda7ac0109191c9c5e0a1ac.tar.gz
GODOT IS OPEN SOURCE
Diffstat (limited to 'core/packed_data_container.cpp')
-rw-r--r--core/packed_data_container.cpp437
1 files changed, 437 insertions, 0 deletions
diff --git a/core/packed_data_container.cpp b/core/packed_data_container.cpp
new file mode 100644
index 0000000000..31be886721
--- /dev/null
+++ b/core/packed_data_container.cpp
@@ -0,0 +1,437 @@
+/*************************************************************************/
+/* packed_data_container.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include "packed_data_container.h"
+#include "io/marshalls.h"
+#include "core_string_names.h"
+
+
+
+Variant PackedDataContainer::getvar(const Variant& p_key, bool *r_valid) const {
+
+ bool err=false;
+ Variant ret = _key_at_ofs(0,p_key,err);
+ if (r_valid)
+ *r_valid=!err;
+ return ret;
+}
+
+int PackedDataContainer::size() const {
+
+ return _size(0);
+};
+
+Variant PackedDataContainer::_iter_init_ofs(const Array& p_iter,uint32_t p_offset) {
+
+ Array ref=p_iter;
+ uint32_t size = _size(p_offset);
+ if (size==0 || ref.size()!=1)
+ return false;
+ else {
+ ref[0]=0;
+ return true;
+ }
+
+
+}
+
+Variant PackedDataContainer::_iter_next_ofs(const Array& p_iter,uint32_t p_offset){
+
+ Array ref=p_iter;
+ uint32_t size = _size(p_offset);
+ if (ref.size()!=1)
+ return false;
+ int pos = ref[0];
+ if (pos<0 || pos>=size)
+ return false;
+ pos+=1;
+ ref[0]=pos;
+ return pos!=size;
+
+}
+
+Variant PackedDataContainer::_iter_get_ofs(const Variant& p_iter,uint32_t p_offset){
+
+ uint32_t size = _size(p_offset);
+ int pos=p_iter;
+ if (pos<0 || pos>=size)
+ return Variant();
+
+ DVector<uint8_t>::Read rd=data.read();
+ const uint8_t *r=&rd[p_offset];
+ uint32_t type = decode_uint32(r);
+
+ bool err=false;
+ if (type==TYPE_ARRAY) {
+
+ return _get_at_ofs(p_offset+8+pos*4,rd.ptr(),err);
+
+ } else if (type==TYPE_DICT) {
+
+ return _get_at_ofs(p_offset+8+pos*12+8,rd.ptr(),err);
+ } else {
+ ERR_FAIL_V(Variant());
+ }
+}
+
+
+Variant PackedDataContainer::_get_at_ofs(uint32_t p_ofs,const uint8_t *p_buf,bool &err) const {
+
+ uint32_t type = decode_uint32(p_buf + p_ofs);
+
+ if (type==TYPE_ARRAY || type==TYPE_DICT) {
+
+ Ref<PackedDataContainerRef> pdcr = memnew( PackedDataContainerRef );
+ Ref<PackedDataContainer> pdc = Ref<PackedDataContainer>((PackedDataContainer*)this);
+
+ pdcr->from=pdc;
+ pdcr->offset=p_ofs;
+ return pdcr;
+ } else {
+
+ Variant v;
+ Error rerr = decode_variant(v,p_buf + p_ofs,datalen-p_ofs,NULL);
+
+ if (rerr!=OK) {
+
+ err=true;
+ ERR_FAIL_COND_V(err!=OK,Variant());
+ }
+ return v;
+ }
+
+}
+
+int PackedDataContainer::_size(uint32_t p_ofs) const {
+
+ DVector<uint8_t>::Read rd=data.read();
+ const uint8_t *r=&rd[p_ofs];
+ uint32_t type = decode_uint32(r);
+
+ if (type==TYPE_ARRAY) {
+
+ uint32_t len = decode_uint32(r+4);
+ return len;
+
+ } else if (type==TYPE_DICT) {
+
+ uint32_t len = decode_uint32(r+4);
+ return len;
+ };
+
+ return -1;
+};
+
+Variant PackedDataContainer::_key_at_ofs(uint32_t p_ofs,const Variant& p_key,bool &err) const {
+
+ DVector<uint8_t>::Read rd=data.read();
+ const uint8_t *r=&rd[p_ofs];
+ uint32_t type = decode_uint32(r);
+
+
+ if (type==TYPE_ARRAY) {
+
+ if (p_key.is_num()) {
+
+ int idx=p_key;
+ uint32_t len = decode_uint32(r+4);
+ if (idx<0 || idx>=len) {
+ err=true;
+ return Variant();
+ }
+ uint32_t ofs = decode_uint32(r+8+4*idx);
+ return _get_at_ofs(ofs,rd.ptr(),err);
+
+ } else {
+ err=true;
+ return Variant();
+ }
+
+ } else if (type==TYPE_DICT) {
+
+ uint32_t hash=p_key.hash();
+ uint32_t len = decode_uint32(r+4);
+
+ bool found=false;
+ for(int i=0;i<len;i++) {
+ uint32_t khash=decode_uint32(r+8+i*12+0);
+ if (khash==hash) {
+ Variant key = _get_at_ofs(decode_uint32(r+8+i*12+4),rd.ptr(),err);
+ if (err)
+ return Variant();
+ if (key==p_key) {
+ //key matches, return value
+ return _get_at_ofs(decode_uint32(r+8+i*12+8),rd.ptr(),err);
+ }
+ found=true;
+ } else {
+ if (found)
+ break;
+ }
+ }
+
+ err=true;
+ return Variant();
+
+ } else {
+
+ err=true;
+ return Variant();
+ }
+
+
+}
+
+uint32_t PackedDataContainer::_pack(const Variant& p_data, Vector<uint8_t>& tmpdata, Map<String,uint32_t>& string_cache) {
+
+ switch(p_data.get_type()) {
+
+ case Variant::STRING: {
+
+ String s = p_data;
+ if (string_cache.has(s)) {
+ return string_cache[s];
+ }
+
+ string_cache[s]=tmpdata.size();
+
+ }; //fallthrough
+ case Variant::NIL:
+ case Variant::BOOL:
+ case Variant::INT:
+ case Variant::REAL:
+ case Variant::VECTOR2:
+ case Variant::RECT2:
+ case Variant::VECTOR3:
+ case Variant::MATRIX32:
+ case Variant::PLANE:
+ case Variant::QUAT:
+ case Variant::_AABB:
+ case Variant::MATRIX3:
+ case Variant::TRANSFORM:
+ case Variant::IMAGE:
+ case Variant::INPUT_EVENT:
+ case Variant::RAW_ARRAY:
+ case Variant::INT_ARRAY:
+ case Variant::REAL_ARRAY:
+ case Variant::STRING_ARRAY:
+ case Variant::VECTOR2_ARRAY:
+ case Variant::VECTOR3_ARRAY:
+ case Variant::COLOR_ARRAY:
+ case Variant::NODE_PATH: {
+
+ uint32_t pos = tmpdata.size();
+ int len;
+ encode_variant(p_data,NULL,len);
+ tmpdata.resize(tmpdata.size()+len);
+ encode_variant(p_data,&tmpdata[pos],len);
+ return pos;
+
+ } break;
+ // misc types
+ case Variant::_RID:
+ case Variant::OBJECT: {
+
+ return _pack(Variant(),tmpdata,string_cache);
+ } break;
+ case Variant::DICTIONARY: {
+
+ Dictionary d=p_data;
+ //size is known, use sort
+ uint32_t pos = tmpdata.size();
+ int len=d.size();
+ tmpdata.resize(tmpdata.size()+len*12+8);
+ encode_uint32(TYPE_DICT,&tmpdata[pos+0]);
+ encode_uint32(len,&tmpdata[pos+4]);
+
+ List<Variant> keys;
+ d.get_key_list(&keys);
+ List<DictKey> sortk;
+
+ for(List<Variant>::Element *E=keys.front();E;E=E->next()) {
+
+ DictKey dk;
+ dk.hash=E->get().hash();
+ dk.key=E->get();
+ sortk.push_back(dk);
+ }
+
+ sortk.sort();
+
+ int idx=0;
+ for(List<DictKey>::Element *E=sortk.front();E;E=E->next()) {
+
+ encode_uint32(E->get().hash,&tmpdata[pos+8+idx*12+0]);
+ uint32_t ofs = _pack(E->get().key,tmpdata,string_cache);
+ encode_uint32(ofs,&tmpdata[pos+8+idx*12+4]);
+ ofs = _pack(d[E->get().key],tmpdata,string_cache);
+ encode_uint32(ofs,&tmpdata[pos+8+idx*12+8]);
+ idx++;
+ }
+
+ return pos;
+
+
+
+ } break;
+ case Variant::ARRAY: {
+
+ Array a=p_data;
+ //size is known, use sort
+ uint32_t pos = tmpdata.size();
+ int len=a.size();
+ tmpdata.resize(tmpdata.size()+len*4+8);
+ encode_uint32(TYPE_ARRAY,&tmpdata[pos+0]);
+ encode_uint32(len,&tmpdata[pos+4]);
+
+ for(int i=0;i<len;i++) {
+
+ uint32_t ofs = _pack(a[i],tmpdata,string_cache);
+ encode_uint32(ofs,&tmpdata[pos+8+i*4]);
+ }
+
+ return pos;
+
+
+ } break;
+
+ default: {}
+ }
+
+ return OK;
+}
+
+Error PackedDataContainer::pack(const Variant& p_data) {
+
+ Vector<uint8_t> tmpdata;
+ Map<String,uint32_t> string_cache;
+ _pack(p_data,tmpdata,string_cache);
+ datalen=tmpdata.size();
+ data.resize(tmpdata.size());
+ DVector<uint8_t>::Write w = data.write();
+ copymem(w.ptr(),tmpdata.ptr(),tmpdata.size());
+
+ return OK;
+}
+
+
+void PackedDataContainer::_set_data(const DVector<uint8_t>& p_data) {
+
+ data=p_data;
+ datalen=data.size();
+
+}
+
+DVector<uint8_t> PackedDataContainer::_get_data() const {
+ return data;
+}
+
+
+Variant PackedDataContainer::_iter_init(const Array& p_iter) {
+
+
+ return _iter_init_ofs(p_iter,0);
+}
+
+Variant PackedDataContainer::_iter_next(const Array& p_iter){
+
+ return _iter_next_ofs(p_iter,0);
+
+}
+Variant PackedDataContainer::_iter_get(const Variant& p_iter){
+
+ return _iter_get_ofs(p_iter,0);
+}
+
+
+void PackedDataContainer::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("_set_data"),&PackedDataContainer::_set_data);
+ ObjectTypeDB::bind_method(_MD("_get_data"),&PackedDataContainer::_get_data);
+ ObjectTypeDB::bind_method(_MD("_iter_init"),&PackedDataContainer::_iter_init);
+ ObjectTypeDB::bind_method(_MD("_iter_get"),&PackedDataContainer::_iter_get);
+ ObjectTypeDB::bind_method(_MD("_iter_next"),&PackedDataContainer::_iter_next);
+ ObjectTypeDB::bind_method(_MD("pack:Error","value"),&PackedDataContainer::pack);
+ ObjectTypeDB::bind_method(_MD("size"),&PackedDataContainer::size);
+
+ ADD_PROPERTY( PropertyInfo(Variant::RAW_ARRAY,"__data__"),_SCS("_set_data"),_SCS("_get_data"));
+}
+
+
+PackedDataContainer::PackedDataContainer() {
+
+ datalen=0;
+}
+
+
+//////////////////
+
+
+Variant PackedDataContainerRef::_iter_init(const Array& p_iter) {
+
+
+ return from->_iter_init_ofs(p_iter,offset);
+}
+
+Variant PackedDataContainerRef::_iter_next(const Array& p_iter){
+
+ return from->_iter_next_ofs(p_iter,offset);
+
+}
+Variant PackedDataContainerRef::_iter_get(const Variant& p_iter){
+
+ return from->_iter_get_ofs(p_iter,offset);
+}
+
+
+void PackedDataContainerRef::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("size"),&PackedDataContainerRef::size);
+ ObjectTypeDB::bind_method(_MD("_iter_init"),&PackedDataContainerRef::_iter_init);
+ ObjectTypeDB::bind_method(_MD("_iter_get"),&PackedDataContainerRef::_iter_get);
+ ObjectTypeDB::bind_method(_MD("_iter_next"),&PackedDataContainerRef::_iter_next);
+}
+
+
+Variant PackedDataContainerRef::getvar(const Variant& p_key, bool *r_valid) const {
+
+ bool err=false;
+ Variant ret = from->_key_at_ofs(offset,p_key,err);
+ if (r_valid)
+ *r_valid=!err;
+ return ret;
+}
+
+int PackedDataContainerRef::size() const {
+
+ return from->_size(offset);
+};
+
+PackedDataContainerRef::PackedDataContainerRef() {
+
+}