1/**************************************************************************/
2/* plist.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 "plist.h"
32
33PList::PLNodeType PListNode::get_type() const {
34 return data_type;
35}
36
37Variant PListNode::get_value() const {
38 switch (data_type) {
39 case PList::PL_NODE_TYPE_NIL: {
40 return Variant();
41 } break;
42 case PList::PL_NODE_TYPE_STRING: {
43 return String::utf8(data_string.get_data());
44 } break;
45 case PList::PL_NODE_TYPE_ARRAY: {
46 Array arr;
47 for (const Ref<PListNode> &E : data_array) {
48 arr.push_back(E);
49 }
50 return arr;
51 } break;
52 case PList::PL_NODE_TYPE_DICT: {
53 Dictionary dict;
54 for (const KeyValue<String, Ref<PListNode>> &E : data_dict) {
55 dict[E.key] = E.value;
56 }
57 return dict;
58 } break;
59 case PList::PL_NODE_TYPE_BOOLEAN: {
60 return data_bool;
61 } break;
62 case PList::PL_NODE_TYPE_INTEGER: {
63 return data_int;
64 } break;
65 case PList::PL_NODE_TYPE_REAL: {
66 return data_real;
67 } break;
68 case PList::PL_NODE_TYPE_DATA: {
69 int strlen = data_string.length();
70
71 size_t arr_len = 0;
72 Vector<uint8_t> buf;
73 {
74 buf.resize(strlen / 4 * 3 + 1);
75 uint8_t *w = buf.ptrw();
76
77 ERR_FAIL_COND_V(CryptoCore::b64_decode(&w[0], buf.size(), &arr_len, (unsigned char *)data_string.get_data(), strlen) != OK, Vector<uint8_t>());
78 }
79 buf.resize(arr_len);
80 return buf;
81 } break;
82 case PList::PL_NODE_TYPE_DATE: {
83 return String(data_string.get_data());
84 } break;
85 }
86 return Variant();
87}
88
89Ref<PListNode> PListNode::new_node(const Variant &p_value) {
90 Ref<PListNode> node;
91 node.instantiate();
92
93 switch (p_value.get_type()) {
94 case Variant::NIL: {
95 node->data_type = PList::PL_NODE_TYPE_NIL;
96 } break;
97 case Variant::BOOL: {
98 node->data_type = PList::PL_NODE_TYPE_BOOLEAN;
99 node->data_bool = p_value;
100 } break;
101 case Variant::INT: {
102 node->data_type = PList::PL_NODE_TYPE_INTEGER;
103 node->data_int = p_value;
104 } break;
105 case Variant::FLOAT: {
106 node->data_type = PList::PL_NODE_TYPE_REAL;
107 node->data_real = p_value;
108 } break;
109 case Variant::STRING_NAME:
110 case Variant::STRING: {
111 node->data_type = PList::PL_NODE_TYPE_STRING;
112 node->data_string = p_value.operator String().utf8();
113 } break;
114 case Variant::DICTIONARY: {
115 node->data_type = PList::PL_NODE_TYPE_DICT;
116 Dictionary dict = p_value;
117 const Variant *next = dict.next(nullptr);
118 while (next) {
119 Ref<PListNode> sub_node = dict[*next];
120 ERR_FAIL_COND_V_MSG(sub_node.is_null(), Ref<PListNode>(), "Invalid dictionary element, should be PListNode.");
121 node->data_dict[*next] = sub_node;
122 next = dict.next(next);
123 }
124 } break;
125 case Variant::ARRAY: {
126 node->data_type = PList::PL_NODE_TYPE_ARRAY;
127 Array ar = p_value;
128 for (int i = 0; i < ar.size(); i++) {
129 Ref<PListNode> sub_node = ar[i];
130 ERR_FAIL_COND_V_MSG(sub_node.is_null(), Ref<PListNode>(), "Invalid array element, should be PListNode.");
131 node->data_array.push_back(sub_node);
132 }
133 } break;
134 case Variant::PACKED_BYTE_ARRAY: {
135 node->data_type = PList::PL_NODE_TYPE_DATA;
136 PackedByteArray buf = p_value;
137 node->data_string = CryptoCore::b64_encode_str(buf.ptr(), buf.size()).utf8();
138 } break;
139 default: {
140 ERR_FAIL_V_MSG(Ref<PListNode>(), "Unsupported data type.");
141 } break;
142 }
143 return node;
144}
145
146Ref<PListNode> PListNode::new_array() {
147 Ref<PListNode> node = memnew(PListNode());
148 ERR_FAIL_COND_V(node.is_null(), Ref<PListNode>());
149 node->data_type = PList::PLNodeType::PL_NODE_TYPE_ARRAY;
150 return node;
151}
152
153Ref<PListNode> PListNode::new_dict() {
154 Ref<PListNode> node = memnew(PListNode());
155 ERR_FAIL_COND_V(node.is_null(), Ref<PListNode>());
156 node->data_type = PList::PLNodeType::PL_NODE_TYPE_DICT;
157 return node;
158}
159
160Ref<PListNode> PListNode::new_string(const String &p_string) {
161 Ref<PListNode> node = memnew(PListNode());
162 ERR_FAIL_COND_V(node.is_null(), Ref<PListNode>());
163 node->data_type = PList::PLNodeType::PL_NODE_TYPE_STRING;
164 node->data_string = p_string.utf8();
165 return node;
166}
167
168Ref<PListNode> PListNode::new_data(const String &p_string) {
169 Ref<PListNode> node = memnew(PListNode());
170 ERR_FAIL_COND_V(node.is_null(), Ref<PListNode>());
171 node->data_type = PList::PLNodeType::PL_NODE_TYPE_DATA;
172 node->data_string = p_string.utf8();
173 return node;
174}
175
176Ref<PListNode> PListNode::new_date(const String &p_string) {
177 Ref<PListNode> node = memnew(PListNode());
178 ERR_FAIL_COND_V(node.is_null(), Ref<PListNode>());
179 node->data_type = PList::PLNodeType::PL_NODE_TYPE_DATE;
180 node->data_string = p_string.utf8();
181 node->data_real = (double)Time::get_singleton()->get_unix_time_from_datetime_string(p_string) - 978307200.0;
182 return node;
183}
184
185Ref<PListNode> PListNode::new_bool(bool p_bool) {
186 Ref<PListNode> node = memnew(PListNode());
187 ERR_FAIL_COND_V(node.is_null(), Ref<PListNode>());
188 node->data_type = PList::PLNodeType::PL_NODE_TYPE_BOOLEAN;
189 node->data_bool = p_bool;
190 return node;
191}
192
193Ref<PListNode> PListNode::new_int(int64_t p_int) {
194 Ref<PListNode> node = memnew(PListNode());
195 ERR_FAIL_COND_V(node.is_null(), Ref<PListNode>());
196 node->data_type = PList::PLNodeType::PL_NODE_TYPE_INTEGER;
197 node->data_int = p_int;
198 return node;
199}
200
201Ref<PListNode> PListNode::new_real(double p_real) {
202 Ref<PListNode> node = memnew(PListNode());
203 ERR_FAIL_COND_V(node.is_null(), Ref<PListNode>());
204 node->data_type = PList::PLNodeType::PL_NODE_TYPE_REAL;
205 node->data_real = p_real;
206 return node;
207}
208
209bool PListNode::push_subnode(const Ref<PListNode> &p_node, const String &p_key) {
210 ERR_FAIL_COND_V(p_node.is_null(), false);
211 if (data_type == PList::PLNodeType::PL_NODE_TYPE_DICT) {
212 ERR_FAIL_COND_V(p_key.is_empty(), false);
213 ERR_FAIL_COND_V(data_dict.has(p_key), false);
214 data_dict[p_key] = p_node;
215 return true;
216 } else if (data_type == PList::PLNodeType::PL_NODE_TYPE_ARRAY) {
217 data_array.push_back(p_node);
218 return true;
219 } else {
220 ERR_FAIL_V_MSG(false, "PList: Invalid parent node type, should be DICT or ARRAY.");
221 }
222}
223
224size_t PListNode::get_asn1_size(uint8_t p_len_octets) const {
225 // Get size of all data, excluding type and size information.
226 switch (data_type) {
227 case PList::PLNodeType::PL_NODE_TYPE_NIL: {
228 return 0;
229 } break;
230 case PList::PLNodeType::PL_NODE_TYPE_DATA:
231 case PList::PLNodeType::PL_NODE_TYPE_DATE: {
232 ERR_FAIL_V_MSG(0, "PList: DATE and DATA nodes are not supported by ASN.1 serialization.");
233 } break;
234 case PList::PLNodeType::PL_NODE_TYPE_STRING: {
235 return data_string.length();
236 } break;
237 case PList::PLNodeType::PL_NODE_TYPE_BOOLEAN: {
238 return 1;
239 } break;
240 case PList::PLNodeType::PL_NODE_TYPE_INTEGER:
241 case PList::PLNodeType::PL_NODE_TYPE_REAL: {
242 return 4;
243 } break;
244 case PList::PLNodeType::PL_NODE_TYPE_ARRAY: {
245 size_t size = 0;
246 for (int i = 0; i < data_array.size(); i++) {
247 size += 1 + _asn1_size_len(p_len_octets) + data_array[i]->get_asn1_size(p_len_octets);
248 }
249 return size;
250 } break;
251 case PList::PLNodeType::PL_NODE_TYPE_DICT: {
252 size_t size = 0;
253
254 for (const KeyValue<String, Ref<PListNode>> &E : data_dict) {
255 size += 1 + _asn1_size_len(p_len_octets); // Sequence.
256 size += 1 + _asn1_size_len(p_len_octets) + E.key.utf8().length(); //Key.
257 size += 1 + _asn1_size_len(p_len_octets) + E.value->get_asn1_size(p_len_octets); // Value.
258 }
259 return size;
260 } break;
261 default: {
262 return 0;
263 } break;
264 }
265}
266
267int PListNode::_asn1_size_len(uint8_t p_len_octets) {
268 if (p_len_octets > 1) {
269 return p_len_octets + 1;
270 } else {
271 return 1;
272 }
273}
274
275void PListNode::store_asn1_size(PackedByteArray &p_stream, uint8_t p_len_octets) const {
276 uint32_t size = get_asn1_size(p_len_octets);
277 if (p_len_octets > 1) {
278 p_stream.push_back(0x80 + p_len_octets);
279 }
280 for (int i = p_len_octets - 1; i >= 0; i--) {
281 uint8_t x = (size >> i * 8) & 0xFF;
282 p_stream.push_back(x);
283 }
284}
285
286bool PListNode::store_asn1(PackedByteArray &p_stream, uint8_t p_len_octets) const {
287 // Convert to binary ASN1 stream.
288 bool valid = true;
289 switch (data_type) {
290 case PList::PLNodeType::PL_NODE_TYPE_NIL: {
291 // Nothing to store.
292 } break;
293 case PList::PLNodeType::PL_NODE_TYPE_DATE:
294 case PList::PLNodeType::PL_NODE_TYPE_DATA: {
295 ERR_FAIL_V_MSG(false, "PList: DATE and DATA nodes are not supported by ASN.1 serialization.");
296 } break;
297 case PList::PLNodeType::PL_NODE_TYPE_STRING: {
298 p_stream.push_back(0x0C);
299 store_asn1_size(p_stream, p_len_octets);
300 for (int i = 0; i < data_string.size(); i++) {
301 p_stream.push_back(data_string[i]);
302 }
303 } break;
304 case PList::PLNodeType::PL_NODE_TYPE_BOOLEAN: {
305 p_stream.push_back(0x01);
306 store_asn1_size(p_stream, p_len_octets);
307 if (data_bool) {
308 p_stream.push_back(0x01);
309 } else {
310 p_stream.push_back(0x00);
311 }
312 } break;
313 case PList::PLNodeType::PL_NODE_TYPE_INTEGER: {
314 p_stream.push_back(0x02);
315 store_asn1_size(p_stream, p_len_octets);
316 for (int i = 4; i >= 0; i--) {
317 uint8_t x = (data_int >> i * 8) & 0xFF;
318 p_stream.push_back(x);
319 }
320 } break;
321 case PList::PLNodeType::PL_NODE_TYPE_REAL: {
322 p_stream.push_back(0x03);
323 store_asn1_size(p_stream, p_len_octets);
324 for (int i = 4; i >= 0; i--) {
325 uint8_t x = (data_int >> i * 8) & 0xFF;
326 p_stream.push_back(x);
327 }
328 } break;
329 case PList::PLNodeType::PL_NODE_TYPE_ARRAY: {
330 p_stream.push_back(0x30); // Sequence.
331 store_asn1_size(p_stream, p_len_octets);
332 for (int i = 0; i < data_array.size(); i++) {
333 valid = valid && data_array[i]->store_asn1(p_stream, p_len_octets);
334 }
335 } break;
336 case PList::PLNodeType::PL_NODE_TYPE_DICT: {
337 p_stream.push_back(0x31); // Set.
338 store_asn1_size(p_stream, p_len_octets);
339 for (const KeyValue<String, Ref<PListNode>> &E : data_dict) {
340 CharString cs = E.key.utf8();
341 uint32_t size = cs.length();
342
343 // Sequence.
344 p_stream.push_back(0x30);
345 uint32_t seq_size = 2 * (1 + _asn1_size_len(p_len_octets)) + size + E.value->get_asn1_size(p_len_octets);
346 if (p_len_octets > 1) {
347 p_stream.push_back(0x80 + p_len_octets);
348 }
349 for (int i = p_len_octets - 1; i >= 0; i--) {
350 uint8_t x = (seq_size >> i * 8) & 0xFF;
351 p_stream.push_back(x);
352 }
353 // Key.
354 p_stream.push_back(0x0C);
355 if (p_len_octets > 1) {
356 p_stream.push_back(0x80 + p_len_octets);
357 }
358 for (int i = p_len_octets - 1; i >= 0; i--) {
359 uint8_t x = (size >> i * 8) & 0xFF;
360 p_stream.push_back(x);
361 }
362 for (uint32_t i = 0; i < size; i++) {
363 p_stream.push_back(cs[i]);
364 }
365 // Value.
366 valid = valid && E.value->store_asn1(p_stream, p_len_octets);
367 }
368 } break;
369 }
370 return valid;
371}
372
373void PListNode::store_text(String &p_stream, uint8_t p_indent) const {
374 // Convert to text XML stream.
375 switch (data_type) {
376 case PList::PLNodeType::PL_NODE_TYPE_NIL: {
377 // Nothing to store.
378 } break;
379 case PList::PLNodeType::PL_NODE_TYPE_DATA: {
380 p_stream += String("\t").repeat(p_indent);
381 p_stream += "<data>\n";
382 p_stream += String("\t").repeat(p_indent);
383 p_stream += data_string + "\n";
384 p_stream += String("\t").repeat(p_indent);
385 p_stream += "</data>\n";
386 } break;
387 case PList::PLNodeType::PL_NODE_TYPE_DATE: {
388 p_stream += String("\t").repeat(p_indent);
389 p_stream += "<date>";
390 p_stream += data_string;
391 p_stream += "</date>\n";
392 } break;
393 case PList::PLNodeType::PL_NODE_TYPE_STRING: {
394 p_stream += String("\t").repeat(p_indent);
395 p_stream += "<string>";
396 p_stream += String::utf8(data_string);
397 p_stream += "</string>\n";
398 } break;
399 case PList::PLNodeType::PL_NODE_TYPE_BOOLEAN: {
400 p_stream += String("\t").repeat(p_indent);
401 if (data_bool) {
402 p_stream += "<true/>\n";
403 } else {
404 p_stream += "<false/>\n";
405 }
406 } break;
407 case PList::PLNodeType::PL_NODE_TYPE_INTEGER: {
408 p_stream += String("\t").repeat(p_indent);
409 p_stream += "<integer>";
410 p_stream += itos(data_int);
411 p_stream += "</integer>\n";
412 } break;
413 case PList::PLNodeType::PL_NODE_TYPE_REAL: {
414 p_stream += String("\t").repeat(p_indent);
415 p_stream += "<real>";
416 p_stream += rtos(data_real);
417 p_stream += "</real>\n";
418 } break;
419 case PList::PLNodeType::PL_NODE_TYPE_ARRAY: {
420 p_stream += String("\t").repeat(p_indent);
421 p_stream += "<array>\n";
422 for (int i = 0; i < data_array.size(); i++) {
423 data_array[i]->store_text(p_stream, p_indent + 1);
424 }
425 p_stream += String("\t").repeat(p_indent);
426 p_stream += "</array>\n";
427 } break;
428 case PList::PLNodeType::PL_NODE_TYPE_DICT: {
429 p_stream += String("\t").repeat(p_indent);
430 p_stream += "<dict>\n";
431 for (const KeyValue<String, Ref<PListNode>> &E : data_dict) {
432 p_stream += String("\t").repeat(p_indent + 1);
433 p_stream += "<key>";
434 p_stream += E.key;
435 p_stream += "</key>\n";
436 E.value->store_text(p_stream, p_indent + 1);
437 }
438 p_stream += String("\t").repeat(p_indent);
439 p_stream += "</dict>\n";
440 } break;
441 }
442}
443
444/*************************************************************************/
445
446PList::PList() {
447 root = PListNode::new_dict();
448}
449
450PList::PList(const String &p_string) {
451 load_string(p_string);
452}
453
454uint64_t PList::read_bplist_var_size_int(Ref<FileAccess> p_file, uint8_t p_size) {
455 uint64_t pos = p_file->get_position();
456 uint64_t ret = 0;
457 switch (p_size) {
458 case 1: {
459 ret = p_file->get_8();
460 } break;
461 case 2: {
462 ret = BSWAP16(p_file->get_16());
463 } break;
464 case 3: {
465 ret = BSWAP32(p_file->get_32() & 0x00FFFFFF);
466 } break;
467 case 4: {
468 ret = BSWAP32(p_file->get_32());
469 } break;
470 case 5: {
471 ret = BSWAP64(p_file->get_64() & 0x000000FFFFFFFFFF);
472 } break;
473 case 6: {
474 ret = BSWAP64(p_file->get_64() & 0x0000FFFFFFFFFFFF);
475 } break;
476 case 7: {
477 ret = BSWAP64(p_file->get_64() & 0x00FFFFFFFFFFFFFF);
478 } break;
479 case 8: {
480 ret = BSWAP64(p_file->get_64());
481 } break;
482 default: {
483 ret = 0;
484 }
485 }
486 p_file->seek(pos + p_size);
487
488 return ret;
489}
490
491Ref<PListNode> PList::read_bplist_obj(Ref<FileAccess> p_file, uint64_t p_offset_idx) {
492 Ref<PListNode> node;
493 node.instantiate();
494
495 uint64_t ot_off = trailer.offset_table_start + p_offset_idx * trailer.offset_size;
496 p_file->seek(ot_off);
497 uint64_t marker_off = read_bplist_var_size_int(p_file, trailer.offset_size);
498 ERR_FAIL_COND_V_MSG(marker_off == 0, Ref<PListNode>(), "Invalid marker size.");
499
500 p_file->seek(marker_off);
501 uint8_t marker = p_file->get_8();
502 uint8_t marker_type = marker & 0xF0;
503 uint64_t marker_size = marker & 0x0F;
504
505 switch (marker_type) {
506 case 0x00: {
507 if (marker_size == 0x00) {
508 node->data_type = PL_NODE_TYPE_NIL;
509 } else if (marker_size == 0x08) {
510 node->data_type = PL_NODE_TYPE_BOOLEAN;
511 node->data_bool = false;
512 } else if (marker_size == 0x09) {
513 node->data_type = PL_NODE_TYPE_BOOLEAN;
514 node->data_bool = true;
515 } else {
516 ERR_FAIL_V_MSG(Ref<PListNode>(), "Invalid nil/bool marker value.");
517 }
518 } break;
519 case 0x10: {
520 node->data_type = PL_NODE_TYPE_INTEGER;
521 node->data_int = static_cast<int64_t>(read_bplist_var_size_int(p_file, pow(2, marker_size)));
522 } break;
523 case 0x20: {
524 node->data_type = PL_NODE_TYPE_REAL;
525 node->data_int = static_cast<int64_t>(read_bplist_var_size_int(p_file, pow(2, marker_size)));
526 } break;
527 case 0x30: {
528 node->data_type = PL_NODE_TYPE_DATE;
529 node->data_int = BSWAP64(p_file->get_64());
530 node->data_string = Time::get_singleton()->get_datetime_string_from_unix_time(node->data_real + 978307200.0).utf8();
531 } break;
532 case 0x40: {
533 if (marker_size == 0x0F) {
534 uint8_t ext = p_file->get_8() & 0xF;
535 marker_size = read_bplist_var_size_int(p_file, pow(2, ext));
536 }
537 node->data_type = PL_NODE_TYPE_DATA;
538 PackedByteArray buf;
539 buf.resize(marker_size + 1);
540 p_file->get_buffer(reinterpret_cast<uint8_t *>(buf.ptrw()), marker_size);
541 node->data_string = CryptoCore::b64_encode_str(buf.ptr(), buf.size()).utf8();
542 } break;
543 case 0x50: {
544 if (marker_size == 0x0F) {
545 uint8_t ext = p_file->get_8() & 0xF;
546 marker_size = read_bplist_var_size_int(p_file, pow(2, ext));
547 }
548 node->data_type = PL_NODE_TYPE_STRING;
549 node->data_string.resize(marker_size + 1);
550 p_file->get_buffer(reinterpret_cast<uint8_t *>(node->data_string.ptrw()), marker_size);
551 } break;
552 case 0x60: {
553 if (marker_size == 0x0F) {
554 uint8_t ext = p_file->get_8() & 0xF;
555 marker_size = read_bplist_var_size_int(p_file, pow(2, ext));
556 }
557 Char16String cs16;
558 cs16.resize(marker_size + 1);
559 for (uint64_t i = 0; i < marker_size; i++) {
560 cs16[i] = BSWAP16(p_file->get_16());
561 }
562 node->data_type = PL_NODE_TYPE_STRING;
563 node->data_string = String::utf16(cs16.ptr(), cs16.length()).utf8();
564 } break;
565 case 0x80: {
566 node->data_type = PL_NODE_TYPE_INTEGER;
567 node->data_int = static_cast<int64_t>(read_bplist_var_size_int(p_file, marker_size + 1));
568 } break;
569 case 0xA0:
570 case 0xC0: {
571 if (marker_size == 0x0F) {
572 uint8_t ext = p_file->get_8() & 0xF;
573 marker_size = read_bplist_var_size_int(p_file, pow(2, ext));
574 }
575 uint64_t pos = p_file->get_position();
576
577 node->data_type = PL_NODE_TYPE_ARRAY;
578 for (uint64_t i = 0; i < marker_size; i++) {
579 p_file->seek(pos + trailer.ref_size * i);
580 uint64_t ref = read_bplist_var_size_int(p_file, trailer.ref_size);
581
582 Ref<PListNode> element = read_bplist_obj(p_file, ref);
583 ERR_FAIL_COND_V(element.is_null(), Ref<PListNode>());
584 node->data_array.push_back(element);
585 }
586 } break;
587 case 0xD0: {
588 if (marker_size == 0x0F) {
589 uint8_t ext = p_file->get_8() & 0xF;
590 marker_size = read_bplist_var_size_int(p_file, pow(2, ext));
591 }
592 uint64_t pos = p_file->get_position();
593
594 node->data_type = PL_NODE_TYPE_DICT;
595 for (uint64_t i = 0; i < marker_size; i++) {
596 p_file->seek(pos + trailer.ref_size * i);
597 uint64_t key_ref = read_bplist_var_size_int(p_file, trailer.ref_size);
598
599 p_file->seek(pos + trailer.ref_size * (i + marker_size));
600 uint64_t obj_ref = read_bplist_var_size_int(p_file, trailer.ref_size);
601
602 Ref<PListNode> element_key = read_bplist_obj(p_file, key_ref);
603 ERR_FAIL_COND_V(element_key.is_null() || element_key->data_type != PL_NODE_TYPE_STRING, Ref<PListNode>());
604 Ref<PListNode> element = read_bplist_obj(p_file, obj_ref);
605 ERR_FAIL_COND_V(element.is_null(), Ref<PListNode>());
606 node->data_dict[String::utf8(element_key->data_string.ptr(), element_key->data_string.length())] = element;
607 }
608 } break;
609 default: {
610 ERR_FAIL_V_MSG(Ref<PListNode>(), "Invalid marker type.");
611 }
612 }
613 return node;
614}
615
616bool PList::load_file(const String &p_filename) {
617 root = Ref<PListNode>();
618
619 Ref<FileAccess> fb = FileAccess::open(p_filename, FileAccess::READ);
620 if (fb.is_null()) {
621 return false;
622 }
623
624 unsigned char magic[8];
625 fb->get_buffer(magic, 8);
626
627 if (String((const char *)magic, 8) == "bplist00") {
628 fb->seek_end(-26);
629 trailer.offset_size = fb->get_8();
630 trailer.ref_size = fb->get_8();
631 trailer.object_num = BSWAP64(fb->get_64());
632 trailer.root_offset_idx = BSWAP64(fb->get_64());
633 trailer.offset_table_start = BSWAP64(fb->get_64());
634 root = read_bplist_obj(fb, trailer.root_offset_idx);
635
636 return root.is_valid();
637 } else {
638 // Load text plist.
639 Error err;
640 Vector<uint8_t> array = FileAccess::get_file_as_bytes(p_filename, &err);
641 ERR_FAIL_COND_V(err != OK, false);
642
643 String ret;
644 ret.parse_utf8((const char *)array.ptr(), array.size());
645 return load_string(ret);
646 }
647}
648
649bool PList::load_string(const String &p_string) {
650 root = Ref<PListNode>();
651
652 int pos = 0;
653 bool in_plist = false;
654 bool done_plist = false;
655 List<Ref<PListNode>> stack;
656 String key;
657 while (pos >= 0) {
658 int open_token_s = p_string.find("<", pos);
659 if (open_token_s == -1) {
660 ERR_FAIL_V_MSG(false, "PList: Unexpected end of data. No tags found.");
661 }
662 int open_token_e = p_string.find(">", open_token_s);
663 pos = open_token_e;
664
665 String token = p_string.substr(open_token_s + 1, open_token_e - open_token_s - 1);
666 if (token.is_empty()) {
667 ERR_FAIL_V_MSG(false, "PList: Invalid token name.");
668 }
669 String value;
670 if (token[0] == '?' || token[0] == '!') { // Skip <?xml ... ?> and <!DOCTYPE ... >
671 int end_token_e = p_string.find(">", open_token_s);
672 pos = end_token_e;
673 continue;
674 }
675
676 if (token.find("plist", 0) == 0) {
677 in_plist = true;
678 continue;
679 }
680
681 if (token == "/plist") {
682 done_plist = true;
683 break;
684 }
685
686 if (!in_plist) {
687 ERR_FAIL_V_MSG(false, "PList: Node outside of <plist> tag.");
688 }
689
690 if (token == "dict") {
691 if (!stack.is_empty()) {
692 // Add subnode end enter it.
693 Ref<PListNode> dict = PListNode::new_dict();
694 dict->data_type = PList::PLNodeType::PL_NODE_TYPE_DICT;
695 if (!stack.back()->get()->push_subnode(dict, key)) {
696 ERR_FAIL_V_MSG(false, "PList: Can't push subnode, invalid parent type.");
697 }
698 stack.push_back(dict);
699 } else {
700 // Add root node.
701 if (!root.is_null()) {
702 ERR_FAIL_V_MSG(false, "PList: Root node already set.");
703 }
704 Ref<PListNode> dict = PListNode::new_dict();
705 stack.push_back(dict);
706 root = dict;
707 }
708 continue;
709 }
710
711 if (token == "/dict") {
712 // Exit current dict.
713 if (stack.is_empty() || stack.back()->get()->data_type != PList::PLNodeType::PL_NODE_TYPE_DICT) {
714 ERR_FAIL_V_MSG(false, "PList: Mismatched </dict> tag.");
715 }
716 stack.pop_back();
717 continue;
718 }
719
720 if (token == "array") {
721 if (!stack.is_empty()) {
722 // Add subnode end enter it.
723 Ref<PListNode> arr = PListNode::new_array();
724 if (!stack.back()->get()->push_subnode(arr, key)) {
725 ERR_FAIL_V_MSG(false, "PList: Can't push subnode, invalid parent type.");
726 }
727 stack.push_back(arr);
728 } else {
729 // Add root node.
730 if (!root.is_null()) {
731 ERR_FAIL_V_MSG(false, "PList: Root node already set.");
732 }
733 Ref<PListNode> arr = PListNode::new_array();
734 stack.push_back(arr);
735 root = arr;
736 }
737 continue;
738 }
739
740 if (token == "/array") {
741 // Exit current array.
742 if (stack.is_empty() || stack.back()->get()->data_type != PList::PLNodeType::PL_NODE_TYPE_ARRAY) {
743 ERR_FAIL_V_MSG(false, "PList: Mismatched </array> tag.");
744 }
745 stack.pop_back();
746 continue;
747 }
748
749 if (token[token.length() - 1] == '/') {
750 token = token.substr(0, token.length() - 1);
751 } else {
752 int end_token_s = p_string.find("</", pos);
753 if (end_token_s == -1) {
754 ERR_FAIL_V_MSG(false, vformat("PList: Mismatched <%s> tag.", token));
755 }
756 int end_token_e = p_string.find(">", end_token_s);
757 pos = end_token_e;
758 String end_token = p_string.substr(end_token_s + 2, end_token_e - end_token_s - 2);
759 if (end_token != token) {
760 ERR_FAIL_V_MSG(false, vformat("PList: Mismatched <%s> and <%s> token pair.", token, end_token));
761 }
762 value = p_string.substr(open_token_e + 1, end_token_s - open_token_e - 1);
763 }
764 if (token == "key") {
765 key = value;
766 } else {
767 Ref<PListNode> var = nullptr;
768 if (token == "true") {
769 var = PListNode::new_bool(true);
770 } else if (token == "false") {
771 var = PListNode::new_bool(false);
772 } else if (token == "integer") {
773 var = PListNode::new_int(value.to_int());
774 } else if (token == "real") {
775 var = PListNode::new_real(value.to_float());
776 } else if (token == "string") {
777 var = PListNode::new_string(value);
778 } else if (token == "data") {
779 var = PListNode::new_data(value);
780 } else if (token == "date") {
781 var = PListNode::new_date(value);
782 } else {
783 ERR_FAIL_V_MSG(false, "PList: Invalid value type.");
784 }
785 if (stack.is_empty() || !stack.back()->get()->push_subnode(var, key)) {
786 ERR_FAIL_V_MSG(false, "PList: Can't push subnode, invalid parent type.");
787 }
788 }
789 }
790 if (!stack.is_empty() || !done_plist) {
791 ERR_FAIL_V_MSG(false, "PList: Unexpected end of data. Root node is not closed.");
792 }
793 return true;
794}
795
796PackedByteArray PList::save_asn1() const {
797 if (root == nullptr) {
798 ERR_FAIL_V_MSG(PackedByteArray(), "PList: Invalid PList, no root node.");
799 }
800 size_t size = root->get_asn1_size(1);
801 uint8_t len_octets = 0;
802 if (size < 0x80) {
803 len_octets = 1;
804 } else {
805 size = root->get_asn1_size(2);
806 if (size < 0xFFFF) {
807 len_octets = 2;
808 } else {
809 size = root->get_asn1_size(3);
810 if (size < 0xFFFFFF) {
811 len_octets = 3;
812 } else {
813 size = root->get_asn1_size(4);
814 if (size < 0xFFFFFFFF) {
815 len_octets = 4;
816 } else {
817 ERR_FAIL_V_MSG(PackedByteArray(), "PList: Data is too big for ASN.1 serializer, should be < 4 GiB.");
818 }
819 }
820 }
821 }
822
823 PackedByteArray ret;
824 if (!root->store_asn1(ret, len_octets)) {
825 ERR_FAIL_V_MSG(PackedByteArray(), "PList: ASN.1 serializer error.");
826 }
827 return ret;
828}
829
830String PList::save_text() const {
831 if (root == nullptr) {
832 ERR_FAIL_V_MSG(String(), "PList: Invalid PList, no root node.");
833 }
834
835 String ret;
836 ret += "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
837 ret += "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n";
838 ret += "<plist version=\"1.0\">\n";
839
840 root->store_text(ret, 0);
841
842 ret += "</plist>\n\n";
843 return ret;
844}
845
846Ref<PListNode> PList::get_root() {
847 return root;
848}
849