2023-01-05 13:25:55 +01:00
/**************************************************************************/
/* packed_data_container.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* 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. */
/**************************************************************************/
2018-01-05 00:50:27 +01:00
2014-02-09 22:10:30 -03:00
# include "packed_data_container.h"
2017-01-16 08:04:19 +01:00
2018-09-11 18:13:45 +02:00
# include "core/core_string_names.h"
# include "core/io/marshalls.h"
2014-02-09 22:10:30 -03:00
Variant PackedDataContainer : : getvar ( const Variant & p_key , bool * r_valid ) const {
bool err = false ;
Variant ret = _key_at_ofs ( 0 , p_key , err ) ;
2020-05-14 16:41:43 +02:00
if ( r_valid ) {
2014-02-09 22:10:30 -03:00
* r_valid = ! err ;
2020-05-14 16:41:43 +02:00
}
2020-11-06 22:29:22 -03:00
if ( err ) {
return Object : : getvar ( p_key , r_valid ) ;
}
2014-02-09 22:10:30 -03:00
return ret ;
}
int PackedDataContainer : : size ( ) const {
return _size ( 0 ) ;
2020-05-19 15:46:49 +02:00
}
2014-02-09 22:10:30 -03:00
Variant PackedDataContainer : : _iter_init_ofs ( const Array & p_iter , uint32_t p_offset ) {
Array ref = p_iter ;
uint32_t size = _size ( p_offset ) ;
2020-05-14 16:41:43 +02:00
if ( size = = 0 | | ref . size ( ) ! = 1 ) {
2014-02-09 22:10:30 -03:00
return false ;
2020-05-14 16:41:43 +02:00
} else {
2014-02-09 22:10:30 -03:00
ref [ 0 ] = 0 ;
return true ;
}
}
Variant PackedDataContainer : : _iter_next_ofs ( const Array & p_iter , uint32_t p_offset ) {
Array ref = p_iter ;
2017-08-31 23:30:35 +02:00
int size = _size ( p_offset ) ;
2020-05-14 16:41:43 +02:00
if ( ref . size ( ) ! = 1 ) {
2014-02-09 22:10:30 -03:00
return false ;
2020-05-14 16:41:43 +02:00
}
2014-02-09 22:10:30 -03:00
int pos = ref [ 0 ] ;
2020-05-14 16:41:43 +02:00
if ( pos < 0 | | pos > = size ) {
2014-02-09 22:10:30 -03:00
return false ;
2020-05-14 16:41:43 +02:00
}
2014-02-09 22:10:30 -03:00
pos + = 1 ;
ref [ 0 ] = pos ;
return pos ! = size ;
}
Variant PackedDataContainer : : _iter_get_ofs ( const Variant & p_iter , uint32_t p_offset ) {
2017-08-31 23:30:35 +02:00
int size = _size ( p_offset ) ;
2014-02-09 22:10:30 -03:00
int pos = p_iter ;
2020-05-14 16:41:43 +02:00
if ( pos < 0 | | pos > = size ) {
2014-02-09 22:10:30 -03:00
return Variant ( ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-09 22:10:30 -03:00
2020-02-17 18:06:54 -03:00
const uint8_t * rd = data . ptr ( ) ;
2014-02-09 22:10:30 -03:00
const uint8_t * r = & rd [ p_offset ] ;
uint32_t type = decode_uint32 ( r ) ;
bool err = false ;
if ( type = = TYPE_ARRAY ) {
2020-02-17 18:06:54 -03:00
uint32_t vpos = decode_uint32 ( rd + p_offset + 8 + pos * 4 ) ;
return _get_at_ofs ( vpos , rd , err ) ;
2014-02-09 22:10:30 -03:00
} else if ( type = = TYPE_DICT ) {
2020-02-17 18:06:54 -03:00
uint32_t vpos = decode_uint32 ( rd + p_offset + 8 + pos * 12 + 4 ) ;
return _get_at_ofs ( vpos , rd , err ) ;
2014-02-09 22:10:30 -03:00
} else {
ERR_FAIL_V ( Variant ( ) ) ;
}
}
Variant PackedDataContainer : : _get_at_ofs ( uint32_t p_ofs , const uint8_t * p_buf , bool & err ) const {
2021-11-21 20:14:59 +08:00
ERR_FAIL_COND_V ( p_ofs + 4 > ( uint32_t ) data . size ( ) , Variant ( ) ) ;
2014-02-09 22:10:30 -03:00
uint32_t type = decode_uint32 ( p_buf + p_ofs ) ;
if ( type = = TYPE_ARRAY | | type = = TYPE_DICT ) {
Ref < PackedDataContainerRef > pdcr = memnew ( PackedDataContainerRef ) ;
2022-04-05 13:40:26 +03:00
Ref < PackedDataContainer > pdc = Ref < PackedDataContainer > ( const_cast < PackedDataContainer * > ( this ) ) ;
2014-02-09 22:10:30 -03:00
pdcr - > from = pdc ;
pdcr - > offset = p_ofs ;
return pdcr ;
} else {
Variant v ;
2020-04-02 01:20:12 +02:00
Error rerr = decode_variant ( v , p_buf + p_ofs , datalen - p_ofs , nullptr , false ) ;
2014-02-09 22:10:30 -03:00
if ( rerr ! = OK ) {
err = true ;
2019-09-25 10:28:50 +02:00
ERR_FAIL_COND_V_MSG ( err ! = OK , Variant ( ) , " Error when trying to decode Variant. " ) ;
2014-02-09 22:10:30 -03:00
}
return v ;
}
}
2014-06-11 10:41:03 -03:00
uint32_t PackedDataContainer : : _type_at_ofs ( uint32_t p_ofs ) const {
2021-11-21 20:14:59 +08:00
ERR_FAIL_COND_V ( p_ofs + 4 > ( uint32_t ) data . size ( ) , 0 ) ;
2020-02-17 18:06:54 -03:00
const uint8_t * rd = data . ptr ( ) ;
2021-05-05 21:17:49 +05:00
ERR_FAIL_COND_V ( ! rd , 0 ) ;
2014-06-11 10:41:03 -03:00
const uint8_t * r = & rd [ p_ofs ] ;
uint32_t type = decode_uint32 ( r ) ;
return type ;
2020-05-19 15:46:49 +02:00
}
2014-06-11 10:41:03 -03:00
2014-02-09 22:10:30 -03:00
int PackedDataContainer : : _size ( uint32_t p_ofs ) const {
2021-11-21 20:14:59 +08:00
ERR_FAIL_COND_V ( p_ofs + 4 > ( uint32_t ) data . size ( ) , 0 ) ;
2020-02-17 18:06:54 -03:00
const uint8_t * rd = data . ptr ( ) ;
ERR_FAIL_COND_V ( ! rd , 0 ) ;
2014-02-09 22:10:30 -03:00
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 ;
2020-05-19 15:46:49 +02:00
}
2014-02-09 22:10:30 -03:00
return - 1 ;
2020-05-19 15:46:49 +02:00
}
2014-02-09 22:10:30 -03:00
Variant PackedDataContainer : : _key_at_ofs ( uint32_t p_ofs , const Variant & p_key , bool & err ) const {
2021-11-21 20:14:59 +08:00
ERR_FAIL_COND_V ( p_ofs + 4 > ( uint32_t ) data . size ( ) , Variant ( ) ) ;
2020-02-17 18:06:54 -03:00
const uint8_t * rd = data . ptr ( ) ;
2021-05-05 21:17:49 +05:00
if ( ! rd ) {
err = true ;
ERR_FAIL_COND_V ( ! rd , Variant ( ) ) ;
}
2014-02-09 22:10:30 -03:00
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 ;
2017-08-31 23:30:35 +02:00
int len = decode_uint32 ( r + 4 ) ;
2014-02-09 22:10:30 -03:00
if ( idx < 0 | | idx > = len ) {
err = true ;
return Variant ( ) ;
}
uint32_t ofs = decode_uint32 ( r + 8 + 4 * idx ) ;
2020-02-17 18:06:54 -03:00
return _get_at_ofs ( ofs , rd , err ) ;
2014-02-09 22:10:30 -03:00
} else {
err = true ;
return Variant ( ) ;
}
2016-03-09 00:00:52 +01:00
2014-02-09 22:10:30 -03:00
} else if ( type = = TYPE_DICT ) {
uint32_t hash = p_key . hash ( ) ;
uint32_t len = decode_uint32 ( r + 4 ) ;
2016-03-09 00:00:52 +01:00
2014-02-09 22:10:30 -03:00
bool found = false ;
2017-08-31 23:30:35 +02:00
for ( uint32_t i = 0 ; i < len ; i + + ) {
2014-02-09 22:10:30 -03:00
uint32_t khash = decode_uint32 ( r + 8 + i * 12 + 0 ) ;
if ( khash = = hash ) {
2020-02-17 18:06:54 -03:00
Variant key = _get_at_ofs ( decode_uint32 ( r + 8 + i * 12 + 4 ) , rd , err ) ;
2020-05-14 16:41:43 +02:00
if ( err ) {
2014-02-09 22:10:30 -03:00
return Variant ( ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-09 22:10:30 -03:00
if ( key = = p_key ) {
//key matches, return value
2020-02-17 18:06:54 -03:00
return _get_at_ofs ( decode_uint32 ( r + 8 + i * 12 + 8 ) , rd , err ) ;
2014-02-09 22:10:30 -03:00
}
found = true ;
} else {
2020-05-14 16:41:43 +02:00
if ( found ) {
2014-02-09 22:10:30 -03:00
break ;
2020-05-14 16:41:43 +02:00
}
2014-02-09 22:10:30 -03:00
}
}
err = true ;
return Variant ( ) ;
} else {
err = true ;
return Variant ( ) ;
}
}
2022-05-13 15:04:37 +02:00
uint32_t PackedDataContainer : : _pack ( const Variant & p_data , Vector < uint8_t > & tmpdata , HashMap < String , uint32_t > & string_cache ) {
2014-02-09 22:10:30 -03:00
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 ( ) ;
2020-02-22 20:47:50 +01:00
[[fallthrough]] ;
}
2014-02-09 22:10:30 -03:00
case Variant : : NIL :
case Variant : : BOOL :
case Variant : : INT :
2020-02-24 15:20:53 -03:00
case Variant : : FLOAT :
2014-02-09 22:10:30 -03:00
case Variant : : VECTOR2 :
case Variant : : RECT2 :
case Variant : : VECTOR3 :
2017-01-11 00:52:51 -03:00
case Variant : : TRANSFORM2D :
2014-02-09 22:10:30 -03:00
case Variant : : PLANE :
2021-01-20 07:02:02 +00:00
case Variant : : QUATERNION :
2017-11-16 21:09:00 -05:00
case Variant : : AABB :
2017-01-11 00:52:51 -03:00
case Variant : : BASIS :
2021-04-28 03:36:08 -04:00
case Variant : : TRANSFORM3D :
2020-02-17 18:06:54 -03:00
case Variant : : PACKED_BYTE_ARRAY :
2020-02-24 15:20:53 -03:00
case Variant : : PACKED_INT32_ARRAY :
case Variant : : PACKED_INT64_ARRAY :
case Variant : : PACKED_FLOAT32_ARRAY :
case Variant : : PACKED_FLOAT64_ARRAY :
2020-02-17 18:06:54 -03:00
case Variant : : PACKED_STRING_ARRAY :
case Variant : : PACKED_VECTOR2_ARRAY :
case Variant : : PACKED_VECTOR3_ARRAY :
case Variant : : PACKED_COLOR_ARRAY :
2020-02-20 18:58:05 -03:00
case Variant : : STRING_NAME :
2014-02-09 22:10:30 -03:00
case Variant : : NODE_PATH : {
uint32_t pos = tmpdata . size ( ) ;
int len ;
2020-04-02 01:20:12 +02:00
encode_variant ( p_data , nullptr , len , false ) ;
2014-02-09 22:10:30 -03:00
tmpdata . resize ( tmpdata . size ( ) + len ) ;
2019-03-26 16:52:42 +01:00
encode_variant ( p_data , & tmpdata . write [ pos ] , len , false ) ;
2014-02-09 22:10:30 -03:00
return pos ;
} break ;
// misc types
2020-11-09 14:53:05 +01:00
case Variant : : RID :
2014-02-09 22:10:30 -03:00
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 ) ;
2018-07-25 03:11:03 +02:00
encode_uint32 ( TYPE_DICT , & tmpdata . write [ pos + 0 ] ) ;
encode_uint32 ( len , & tmpdata . write [ pos + 4 ] ) ;
2014-02-09 22:10:30 -03:00
List < Variant > keys ;
d . get_key_list ( & keys ) ;
List < DictKey > sortk ;
2021-07-24 15:46:25 +02:00
for ( const Variant & key : keys ) {
2014-02-09 22:10:30 -03:00
DictKey dk ;
2021-07-15 23:45:57 -04:00
dk . hash = key . hash ( ) ;
dk . key = key ;
2014-02-09 22:10:30 -03:00
sortk . push_back ( dk ) ;
}
sortk . sort ( ) ;
int idx = 0 ;
2021-07-24 15:46:25 +02:00
for ( const DictKey & E : sortk ) {
2021-07-15 23:45:57 -04:00
encode_uint32 ( E . hash , & tmpdata . write [ pos + 8 + idx * 12 + 0 ] ) ;
uint32_t ofs = _pack ( E . key , tmpdata , string_cache ) ;
2018-07-25 03:11:03 +02:00
encode_uint32 ( ofs , & tmpdata . write [ pos + 8 + idx * 12 + 4 ] ) ;
2021-07-15 23:45:57 -04:00
ofs = _pack ( d [ E . key ] , tmpdata , string_cache ) ;
2018-07-25 03:11:03 +02:00
encode_uint32 ( ofs , & tmpdata . write [ pos + 8 + idx * 12 + 8 ] ) ;
2014-02-09 22:10:30 -03:00
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 ) ;
2018-07-25 03:11:03 +02:00
encode_uint32 ( TYPE_ARRAY , & tmpdata . write [ pos + 0 ] ) ;
encode_uint32 ( len , & tmpdata . write [ pos + 4 ] ) ;
2014-02-09 22:10:30 -03:00
for ( int i = 0 ; i < len ; i + + ) {
uint32_t ofs = _pack ( a [ i ] , tmpdata , string_cache ) ;
2018-07-25 03:11:03 +02:00
encode_uint32 ( ofs , & tmpdata . write [ pos + 8 + i * 4 ] ) ;
2014-02-09 22:10:30 -03:00
}
return pos ;
} break ;
2019-04-09 17:08:36 +02:00
default : {
}
2014-02-09 22:10:30 -03:00
}
return OK ;
}
Error PackedDataContainer : : pack ( const Variant & p_data ) {
2023-04-29 00:05:16 +02:00
ERR_FAIL_COND_V_MSG ( p_data . get_type ( ) ! = Variant : : ARRAY & & p_data . get_type ( ) ! = Variant : : DICTIONARY , ERR_INVALID_DATA , " PackedDataContainer can pack only Array and Dictionary type. " ) ;
2014-02-09 22:10:30 -03:00
Vector < uint8_t > tmpdata ;
2022-05-13 15:04:37 +02:00
HashMap < String , uint32_t > string_cache ;
2014-02-09 22:10:30 -03:00
_pack ( p_data , tmpdata , string_cache ) ;
datalen = tmpdata . size ( ) ;
data . resize ( tmpdata . size ( ) ) ;
2020-02-17 18:06:54 -03:00
uint8_t * w = data . ptrw ( ) ;
2021-04-27 16:19:21 +02:00
memcpy ( w , tmpdata . ptr ( ) , tmpdata . size ( ) ) ;
2014-02-09 22:10:30 -03:00
return OK ;
}
2020-02-17 18:06:54 -03:00
void PackedDataContainer : : _set_data ( const Vector < uint8_t > & p_data ) {
2014-02-09 22:10:30 -03:00
data = p_data ;
datalen = data . size ( ) ;
}
2020-02-17 18:06:54 -03:00
Vector < uint8_t > PackedDataContainer : : _get_data ( ) const {
2014-02-09 22:10:30 -03:00
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 ) ;
}
2020-05-14 14:29:06 +02:00
2014-02-09 22:10:30 -03:00
Variant PackedDataContainer : : _iter_get ( const Variant & p_iter ) {
return _iter_get_ofs ( p_iter , 0 ) ;
}
void PackedDataContainer : : _bind_methods ( ) {
2022-08-08 15:18:26 +03:00
ClassDB : : bind_method ( D_METHOD ( " _set_data " , " data " ) , & PackedDataContainer : : _set_data ) ;
2017-02-13 12:47:24 +01:00
ClassDB : : bind_method ( D_METHOD ( " _get_data " ) , & PackedDataContainer : : _get_data ) ;
ClassDB : : bind_method ( D_METHOD ( " _iter_init " ) , & PackedDataContainer : : _iter_init ) ;
ClassDB : : bind_method ( D_METHOD ( " _iter_get " ) , & PackedDataContainer : : _iter_get ) ;
ClassDB : : bind_method ( D_METHOD ( " _iter_next " ) , & PackedDataContainer : : _iter_next ) ;
2017-08-09 13:19:41 +02:00
ClassDB : : bind_method ( D_METHOD ( " pack " , " value " ) , & PackedDataContainer : : pack ) ;
2017-02-13 12:47:24 +01:00
ClassDB : : bind_method ( D_METHOD ( " size " ) , & PackedDataContainer : : size ) ;
2014-02-09 22:10:30 -03:00
2023-04-29 00:05:16 +02:00
BIND_METHOD_ERR_RETURN_DOC ( " pack " , ERR_INVALID_DATA ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : PACKED_BYTE_ARRAY , " __data__ " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL ) , " _set_data " , " _get_data " ) ;
2014-02-09 22:10:30 -03:00
}
//////////////////
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 ) ;
}
2020-05-14 14:29:06 +02:00
2014-02-09 22:10:30 -03:00
Variant PackedDataContainerRef : : _iter_get ( const Variant & p_iter ) {
return from - > _iter_get_ofs ( p_iter , offset ) ;
}
void PackedDataContainerRef : : _bind_methods ( ) {
2017-02-13 12:47:24 +01:00
ClassDB : : bind_method ( D_METHOD ( " size " ) , & PackedDataContainerRef : : size ) ;
ClassDB : : bind_method ( D_METHOD ( " _iter_init " ) , & PackedDataContainerRef : : _iter_init ) ;
ClassDB : : bind_method ( D_METHOD ( " _iter_get " ) , & PackedDataContainerRef : : _iter_get ) ;
ClassDB : : bind_method ( D_METHOD ( " _iter_next " ) , & PackedDataContainerRef : : _iter_next ) ;
2014-02-09 22:10:30 -03:00
}
Variant PackedDataContainerRef : : getvar ( const Variant & p_key , bool * r_valid ) const {
bool err = false ;
Variant ret = from - > _key_at_ofs ( offset , p_key , err ) ;
2020-05-14 16:41:43 +02:00
if ( r_valid ) {
2014-02-09 22:10:30 -03:00
* r_valid = ! err ;
2020-05-14 16:41:43 +02:00
}
2014-02-09 22:10:30 -03:00
return ret ;
}
int PackedDataContainerRef : : size ( ) const {
return from - > _size ( offset ) ;
2020-05-19 15:46:49 +02:00
}