diff options
author | Juan Linietsky <reduzio@gmail.com> | 2014-02-09 22:10:30 -0300 |
---|---|---|
committer | Juan Linietsky <reduzio@gmail.com> | 2014-02-09 22:10:30 -0300 |
commit | 0b806ee0fc9097fa7bda7ac0109191c9c5e0a1ac (patch) | |
tree | 276c4d099e178eb67fbd14f61d77b05e3808e9e3 /core/packed_data_container.cpp | |
parent | 0e49da1687bc8192ed210947da52c9e5c5f301bb (diff) | |
download | redot-engine-0b806ee0fc9097fa7bda7ac0109191c9c5e0a1ac.tar.gz |
GODOT IS OPEN SOURCE
Diffstat (limited to 'core/packed_data_container.cpp')
-rw-r--r-- | core/packed_data_container.cpp | 437 |
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() { + +} |