1/**************************************************************************/
2/* packed_data_container.cpp */
3/**************************************************************************/
4/* This file is part of: */
5/* GODOT ENGINE */
6/* https://godotengine.org */
7/**************************************************************************/
8/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10/* */
11/* Permission is hereby granted, free of charge, to any person obtaining */
12/* a copy of this software and associated documentation files (the */
13/* "Software"), to deal in the Software without restriction, including */
14/* without limitation the rights to use, copy, modify, merge, publish, */
15/* distribute, sublicense, and/or sell copies of the Software, and to */
16/* permit persons to whom the Software is furnished to do so, subject to */
17/* the following conditions: */
18/* */
19/* The above copyright notice and this permission notice shall be */
20/* included in all copies or substantial portions of the Software. */
21/* */
22/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29/**************************************************************************/
30
31#include "packed_data_container.h"
32
33#include "core/core_string_names.h"
34#include "core/io/marshalls.h"
35
36Variant PackedDataContainer::getvar(const Variant &p_key, bool *r_valid) const {
37 bool err = false;
38 Variant ret = _key_at_ofs(0, p_key, err);
39 if (r_valid) {
40 *r_valid = !err;
41 }
42 if (err) {
43 return Object::getvar(p_key, r_valid);
44 }
45 return ret;
46}
47
48int PackedDataContainer::size() const {
49 return _size(0);
50}
51
52Variant PackedDataContainer::_iter_init_ofs(const Array &p_iter, uint32_t p_offset) {
53 Array ref = p_iter;
54 uint32_t size = _size(p_offset);
55 if (size == 0 || ref.size() != 1) {
56 return false;
57 } else {
58 ref[0] = 0;
59 return true;
60 }
61}
62
63Variant PackedDataContainer::_iter_next_ofs(const Array &p_iter, uint32_t p_offset) {
64 Array ref = p_iter;
65 int size = _size(p_offset);
66 if (ref.size() != 1) {
67 return false;
68 }
69 int pos = ref[0];
70 if (pos < 0 || pos >= size) {
71 return false;
72 }
73 pos += 1;
74 ref[0] = pos;
75 return pos != size;
76}
77
78Variant PackedDataContainer::_iter_get_ofs(const Variant &p_iter, uint32_t p_offset) {
79 int size = _size(p_offset);
80 int pos = p_iter;
81 if (pos < 0 || pos >= size) {
82 return Variant();
83 }
84
85 const uint8_t *rd = data.ptr();
86 const uint8_t *r = &rd[p_offset];
87 uint32_t type = decode_uint32(r);
88
89 bool err = false;
90 if (type == TYPE_ARRAY) {
91 uint32_t vpos = decode_uint32(rd + p_offset + 8 + pos * 4);
92 return _get_at_ofs(vpos, rd, err);
93
94 } else if (type == TYPE_DICT) {
95 uint32_t vpos = decode_uint32(rd + p_offset + 8 + pos * 12 + 4);
96 return _get_at_ofs(vpos, rd, err);
97 } else {
98 ERR_FAIL_V(Variant());
99 }
100}
101
102Variant PackedDataContainer::_get_at_ofs(uint32_t p_ofs, const uint8_t *p_buf, bool &err) const {
103 ERR_FAIL_COND_V(p_ofs + 4 > (uint32_t)data.size(), Variant());
104 uint32_t type = decode_uint32(p_buf + p_ofs);
105
106 if (type == TYPE_ARRAY || type == TYPE_DICT) {
107 Ref<PackedDataContainerRef> pdcr = memnew(PackedDataContainerRef);
108 Ref<PackedDataContainer> pdc = Ref<PackedDataContainer>(const_cast<PackedDataContainer *>(this));
109
110 pdcr->from = pdc;
111 pdcr->offset = p_ofs;
112 return pdcr;
113 } else {
114 Variant v;
115 Error rerr = decode_variant(v, p_buf + p_ofs, datalen - p_ofs, nullptr, false);
116
117 if (rerr != OK) {
118 err = true;
119 ERR_FAIL_COND_V_MSG(err != OK, Variant(), "Error when trying to decode Variant.");
120 }
121 return v;
122 }
123}
124
125uint32_t PackedDataContainer::_type_at_ofs(uint32_t p_ofs) const {
126 ERR_FAIL_COND_V(p_ofs + 4 > (uint32_t)data.size(), 0);
127 const uint8_t *rd = data.ptr();
128 ERR_FAIL_NULL_V(rd, 0);
129 const uint8_t *r = &rd[p_ofs];
130 uint32_t type = decode_uint32(r);
131
132 return type;
133}
134
135int PackedDataContainer::_size(uint32_t p_ofs) const {
136 ERR_FAIL_COND_V(p_ofs + 4 > (uint32_t)data.size(), 0);
137 const uint8_t *rd = data.ptr();
138 ERR_FAIL_NULL_V(rd, 0);
139 const uint8_t *r = &rd[p_ofs];
140 uint32_t type = decode_uint32(r);
141
142 if (type == TYPE_ARRAY) {
143 uint32_t len = decode_uint32(r + 4);
144 return len;
145
146 } else if (type == TYPE_DICT) {
147 uint32_t len = decode_uint32(r + 4);
148 return len;
149 }
150
151 return -1;
152}
153
154Variant PackedDataContainer::_key_at_ofs(uint32_t p_ofs, const Variant &p_key, bool &err) const {
155 ERR_FAIL_COND_V(p_ofs + 4 > (uint32_t)data.size(), Variant());
156 const uint8_t *rd = data.ptr();
157 if (!rd) {
158 err = true;
159 ERR_FAIL_NULL_V(rd, Variant());
160 }
161 const uint8_t *r = &rd[p_ofs];
162 uint32_t type = decode_uint32(r);
163
164 if (type == TYPE_ARRAY) {
165 if (p_key.is_num()) {
166 int idx = p_key;
167 int len = decode_uint32(r + 4);
168 if (idx < 0 || idx >= len) {
169 err = true;
170 return Variant();
171 }
172 uint32_t ofs = decode_uint32(r + 8 + 4 * idx);
173 return _get_at_ofs(ofs, rd, err);
174
175 } else {
176 err = true;
177 return Variant();
178 }
179
180 } else if (type == TYPE_DICT) {
181 uint32_t hash = p_key.hash();
182 uint32_t len = decode_uint32(r + 4);
183
184 bool found = false;
185 for (uint32_t i = 0; i < len; i++) {
186 uint32_t khash = decode_uint32(r + 8 + i * 12 + 0);
187 if (khash == hash) {
188 Variant key = _get_at_ofs(decode_uint32(r + 8 + i * 12 + 4), rd, err);
189 if (err) {
190 return Variant();
191 }
192 if (key == p_key) {
193 //key matches, return value
194 return _get_at_ofs(decode_uint32(r + 8 + i * 12 + 8), rd, err);
195 }
196 found = true;
197 } else {
198 if (found) {
199 break;
200 }
201 }
202 }
203
204 err = true;
205 return Variant();
206
207 } else {
208 err = true;
209 return Variant();
210 }
211}
212
213uint32_t PackedDataContainer::_pack(const Variant &p_data, Vector<uint8_t> &tmpdata, HashMap<String, uint32_t> &string_cache) {
214 switch (p_data.get_type()) {
215 case Variant::STRING: {
216 String s = p_data;
217 if (string_cache.has(s)) {
218 return string_cache[s];
219 }
220
221 string_cache[s] = tmpdata.size();
222
223 [[fallthrough]];
224 }
225 case Variant::NIL:
226 case Variant::BOOL:
227 case Variant::INT:
228 case Variant::FLOAT:
229 case Variant::VECTOR2:
230 case Variant::RECT2:
231 case Variant::VECTOR3:
232 case Variant::TRANSFORM2D:
233 case Variant::PLANE:
234 case Variant::QUATERNION:
235 case Variant::AABB:
236 case Variant::BASIS:
237 case Variant::TRANSFORM3D:
238 case Variant::PACKED_BYTE_ARRAY:
239 case Variant::PACKED_INT32_ARRAY:
240 case Variant::PACKED_INT64_ARRAY:
241 case Variant::PACKED_FLOAT32_ARRAY:
242 case Variant::PACKED_FLOAT64_ARRAY:
243 case Variant::PACKED_STRING_ARRAY:
244 case Variant::PACKED_VECTOR2_ARRAY:
245 case Variant::PACKED_VECTOR3_ARRAY:
246 case Variant::PACKED_COLOR_ARRAY:
247 case Variant::STRING_NAME:
248 case Variant::NODE_PATH: {
249 uint32_t pos = tmpdata.size();
250 int len;
251 encode_variant(p_data, nullptr, len, false);
252 tmpdata.resize(tmpdata.size() + len);
253 encode_variant(p_data, &tmpdata.write[pos], len, false);
254 return pos;
255
256 } break;
257 // misc types
258 case Variant::RID:
259 case Variant::OBJECT: {
260 return _pack(Variant(), tmpdata, string_cache);
261 } break;
262 case Variant::DICTIONARY: {
263 Dictionary d = p_data;
264 //size is known, use sort
265 uint32_t pos = tmpdata.size();
266 int len = d.size();
267 tmpdata.resize(tmpdata.size() + len * 12 + 8);
268 encode_uint32(TYPE_DICT, &tmpdata.write[pos + 0]);
269 encode_uint32(len, &tmpdata.write[pos + 4]);
270
271 List<Variant> keys;
272 d.get_key_list(&keys);
273 List<DictKey> sortk;
274
275 for (const Variant &key : keys) {
276 DictKey dk;
277 dk.hash = key.hash();
278 dk.key = key;
279 sortk.push_back(dk);
280 }
281
282 sortk.sort();
283
284 int idx = 0;
285 for (const DictKey &E : sortk) {
286 encode_uint32(E.hash, &tmpdata.write[pos + 8 + idx * 12 + 0]);
287 uint32_t ofs = _pack(E.key, tmpdata, string_cache);
288 encode_uint32(ofs, &tmpdata.write[pos + 8 + idx * 12 + 4]);
289 ofs = _pack(d[E.key], tmpdata, string_cache);
290 encode_uint32(ofs, &tmpdata.write[pos + 8 + idx * 12 + 8]);
291 idx++;
292 }
293
294 return pos;
295
296 } break;
297 case Variant::ARRAY: {
298 Array a = p_data;
299 //size is known, use sort
300 uint32_t pos = tmpdata.size();
301 int len = a.size();
302 tmpdata.resize(tmpdata.size() + len * 4 + 8);
303 encode_uint32(TYPE_ARRAY, &tmpdata.write[pos + 0]);
304 encode_uint32(len, &tmpdata.write[pos + 4]);
305
306 for (int i = 0; i < len; i++) {
307 uint32_t ofs = _pack(a[i], tmpdata, string_cache);
308 encode_uint32(ofs, &tmpdata.write[pos + 8 + i * 4]);
309 }
310
311 return pos;
312
313 } break;
314
315 default: {
316 }
317 }
318
319 return OK;
320}
321
322Error PackedDataContainer::pack(const Variant &p_data) {
323 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.");
324
325 Vector<uint8_t> tmpdata;
326 HashMap<String, uint32_t> string_cache;
327 _pack(p_data, tmpdata, string_cache);
328 datalen = tmpdata.size();
329 data.resize(tmpdata.size());
330 uint8_t *w = data.ptrw();
331 memcpy(w, tmpdata.ptr(), tmpdata.size());
332
333 return OK;
334}
335
336void PackedDataContainer::_set_data(const Vector<uint8_t> &p_data) {
337 data = p_data;
338 datalen = data.size();
339}
340
341Vector<uint8_t> PackedDataContainer::_get_data() const {
342 return data;
343}
344
345Variant PackedDataContainer::_iter_init(const Array &p_iter) {
346 return _iter_init_ofs(p_iter, 0);
347}
348
349Variant PackedDataContainer::_iter_next(const Array &p_iter) {
350 return _iter_next_ofs(p_iter, 0);
351}
352
353Variant PackedDataContainer::_iter_get(const Variant &p_iter) {
354 return _iter_get_ofs(p_iter, 0);
355}
356
357void PackedDataContainer::_bind_methods() {
358 ClassDB::bind_method(D_METHOD("_set_data", "data"), &PackedDataContainer::_set_data);
359 ClassDB::bind_method(D_METHOD("_get_data"), &PackedDataContainer::_get_data);
360 ClassDB::bind_method(D_METHOD("_iter_init"), &PackedDataContainer::_iter_init);
361 ClassDB::bind_method(D_METHOD("_iter_get"), &PackedDataContainer::_iter_get);
362 ClassDB::bind_method(D_METHOD("_iter_next"), &PackedDataContainer::_iter_next);
363 ClassDB::bind_method(D_METHOD("pack", "value"), &PackedDataContainer::pack);
364 ClassDB::bind_method(D_METHOD("size"), &PackedDataContainer::size);
365
366 BIND_METHOD_ERR_RETURN_DOC("pack", ERR_INVALID_DATA);
367
368 ADD_PROPERTY(PropertyInfo(Variant::PACKED_BYTE_ARRAY, "__data__", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL), "_set_data", "_get_data");
369}
370
371//////////////////
372
373Variant PackedDataContainerRef::_iter_init(const Array &p_iter) {
374 return from->_iter_init_ofs(p_iter, offset);
375}
376
377Variant PackedDataContainerRef::_iter_next(const Array &p_iter) {
378 return from->_iter_next_ofs(p_iter, offset);
379}
380
381Variant PackedDataContainerRef::_iter_get(const Variant &p_iter) {
382 return from->_iter_get_ofs(p_iter, offset);
383}
384
385void PackedDataContainerRef::_bind_methods() {
386 ClassDB::bind_method(D_METHOD("size"), &PackedDataContainerRef::size);
387 ClassDB::bind_method(D_METHOD("_iter_init"), &PackedDataContainerRef::_iter_init);
388 ClassDB::bind_method(D_METHOD("_iter_get"), &PackedDataContainerRef::_iter_get);
389 ClassDB::bind_method(D_METHOD("_iter_next"), &PackedDataContainerRef::_iter_next);
390}
391
392Variant PackedDataContainerRef::getvar(const Variant &p_key, bool *r_valid) const {
393 bool err = false;
394 Variant ret = from->_key_at_ofs(offset, p_key, err);
395 if (r_valid) {
396 *r_valid = !err;
397 }
398 return ret;
399}
400
401int PackedDataContainerRef::size() const {
402 return from->_size(offset);
403}
404