Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/core/variant/variant_parser.cpp
9903 views
1
/**************************************************************************/
2
/* variant_parser.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 "variant_parser.h"
32
33
#include "core/crypto/crypto_core.h"
34
#include "core/io/resource_loader.h"
35
#include "core/io/resource_uid.h"
36
#include "core/object/script_language.h"
37
#include "core/string/string_buffer.h"
38
39
char32_t VariantParser::Stream::get_char() {
40
// is within buffer?
41
if (readahead_pointer < readahead_filled) {
42
return readahead_buffer[readahead_pointer++];
43
}
44
45
// attempt to readahead
46
readahead_filled = _read_buffer(readahead_buffer, readahead_enabled ? READAHEAD_SIZE : 1);
47
if (readahead_filled) {
48
readahead_pointer = 0;
49
} else {
50
// EOF
51
readahead_pointer = 1;
52
eof = true;
53
return 0;
54
}
55
return get_char();
56
}
57
58
bool VariantParser::Stream::is_eof() const {
59
if (readahead_enabled) {
60
return eof;
61
}
62
return _is_eof();
63
}
64
65
bool VariantParser::StreamFile::is_utf8() const {
66
return true;
67
}
68
69
bool VariantParser::StreamFile::_is_eof() const {
70
return f->eof_reached();
71
}
72
73
uint32_t VariantParser::StreamFile::_read_buffer(char32_t *p_buffer, uint32_t p_num_chars) {
74
// The buffer is assumed to include at least one character (for null terminator)
75
ERR_FAIL_COND_V(!p_num_chars, 0);
76
77
uint8_t *temp = (uint8_t *)alloca(p_num_chars);
78
uint64_t num_read = f->get_buffer(temp, p_num_chars);
79
ERR_FAIL_COND_V(num_read == UINT64_MAX, 0);
80
81
// translate to wchar
82
for (uint32_t n = 0; n < num_read; n++) {
83
p_buffer[n] = temp[n];
84
}
85
86
// could be less than p_num_chars, or zero
87
return num_read;
88
}
89
90
bool VariantParser::StreamString::is_utf8() const {
91
return false;
92
}
93
94
bool VariantParser::StreamString::_is_eof() const {
95
return pos > s.length();
96
}
97
98
uint32_t VariantParser::StreamString::_read_buffer(char32_t *p_buffer, uint32_t p_num_chars) {
99
// The buffer is assumed to include at least one character (for null terminator)
100
ERR_FAIL_COND_V(!p_num_chars, 0);
101
ERR_FAIL_NULL_V(p_buffer, 0);
102
103
int available = MAX(s.length() - pos, 0);
104
if (available >= (int)p_num_chars) {
105
const char32_t *src = s.ptr();
106
src += pos;
107
memcpy(p_buffer, src, p_num_chars * sizeof(char32_t));
108
pos += p_num_chars;
109
110
return p_num_chars;
111
}
112
113
// going to reach EOF
114
if (available) {
115
const char32_t *src = s.ptr();
116
src += pos;
117
memcpy(p_buffer, src, available * sizeof(char32_t));
118
pos += available;
119
}
120
121
// add a zero
122
p_buffer[available] = 0;
123
124
return available;
125
}
126
127
/////////////////////////////////////////////////////////////////////////////////////////////////
128
129
const char *VariantParser::tk_name[TK_MAX] = {
130
"'{'",
131
"'}'",
132
"'['",
133
"']'",
134
"'('",
135
"')'",
136
"identifier",
137
"string",
138
"string_name",
139
"number",
140
"color",
141
"':'",
142
"','",
143
"'.'",
144
"'='",
145
"EOF",
146
"ERROR"
147
};
148
149
static double stor_fix(const String &p_str) {
150
if (p_str == "inf") {
151
return Math::INF;
152
} else if (p_str == "-inf" || p_str == "inf_neg") {
153
// inf_neg kept for compatibility.
154
return -Math::INF;
155
} else if (p_str == "nan") {
156
return Math::NaN;
157
}
158
return -1;
159
}
160
161
Error VariantParser::get_token(Stream *p_stream, Token &r_token, int &line, String &r_err_str) {
162
bool string_name = false;
163
164
while (true) {
165
char32_t cchar;
166
if (p_stream->saved) {
167
cchar = p_stream->saved;
168
p_stream->saved = 0;
169
} else {
170
cchar = p_stream->get_char();
171
if (p_stream->is_eof()) {
172
r_token.type = TK_EOF;
173
return OK;
174
}
175
}
176
177
switch (cchar) {
178
case '\n': {
179
line++;
180
break;
181
}
182
case 0: {
183
r_token.type = TK_EOF;
184
return OK;
185
} break;
186
case '{': {
187
r_token.type = TK_CURLY_BRACKET_OPEN;
188
return OK;
189
}
190
case '}': {
191
r_token.type = TK_CURLY_BRACKET_CLOSE;
192
return OK;
193
}
194
case '[': {
195
r_token.type = TK_BRACKET_OPEN;
196
return OK;
197
}
198
case ']': {
199
r_token.type = TK_BRACKET_CLOSE;
200
return OK;
201
}
202
case '(': {
203
r_token.type = TK_PARENTHESIS_OPEN;
204
return OK;
205
}
206
case ')': {
207
r_token.type = TK_PARENTHESIS_CLOSE;
208
return OK;
209
}
210
case ':': {
211
r_token.type = TK_COLON;
212
return OK;
213
}
214
case ';': {
215
while (true) {
216
char32_t ch = p_stream->get_char();
217
if (p_stream->is_eof()) {
218
r_token.type = TK_EOF;
219
return OK;
220
}
221
if (ch == '\n') {
222
line++;
223
break;
224
}
225
}
226
227
break;
228
}
229
case ',': {
230
r_token.type = TK_COMMA;
231
return OK;
232
}
233
case '.': {
234
r_token.type = TK_PERIOD;
235
return OK;
236
}
237
case '=': {
238
r_token.type = TK_EQUAL;
239
return OK;
240
}
241
case '#': {
242
StringBuffer<> color_str;
243
color_str += '#';
244
while (true) {
245
char32_t ch = p_stream->get_char();
246
if (p_stream->is_eof()) {
247
r_token.type = TK_EOF;
248
return OK;
249
} else if (is_hex_digit(ch)) {
250
color_str += ch;
251
252
} else {
253
p_stream->saved = ch;
254
break;
255
}
256
}
257
258
r_token.value = Color::html(color_str.as_string());
259
r_token.type = TK_COLOR;
260
return OK;
261
}
262
#ifndef DISABLE_DEPRECATED
263
case '@': // Compatibility with 3.x StringNames.
264
#endif
265
case '&': { // StringName.
266
cchar = p_stream->get_char();
267
if (cchar != '"') {
268
r_err_str = "Expected '\"' after '&'";
269
r_token.type = TK_ERROR;
270
return ERR_PARSE_ERROR;
271
}
272
273
string_name = true;
274
[[fallthrough]];
275
}
276
case '"': {
277
String str;
278
char32_t prev = 0;
279
while (true) {
280
char32_t ch = p_stream->get_char();
281
282
if (ch == 0) {
283
r_err_str = "Unterminated string";
284
r_token.type = TK_ERROR;
285
return ERR_PARSE_ERROR;
286
} else if (ch == '"') {
287
break;
288
} else if (ch == '\\') {
289
//escaped characters...
290
char32_t next = p_stream->get_char();
291
if (next == 0) {
292
r_err_str = "Unterminated string";
293
r_token.type = TK_ERROR;
294
return ERR_PARSE_ERROR;
295
}
296
char32_t res = 0;
297
298
switch (next) {
299
case 'b':
300
res = 8;
301
break;
302
case 't':
303
res = 9;
304
break;
305
case 'n':
306
res = 10;
307
break;
308
case 'f':
309
res = 12;
310
break;
311
case 'r':
312
res = 13;
313
break;
314
case 'U':
315
case 'u': {
316
// Hexadecimal sequence.
317
int hex_len = (next == 'U') ? 6 : 4;
318
for (int j = 0; j < hex_len; j++) {
319
char32_t c = p_stream->get_char();
320
321
if (c == 0) {
322
r_err_str = "Unterminated string";
323
r_token.type = TK_ERROR;
324
return ERR_PARSE_ERROR;
325
}
326
if (!is_hex_digit(c)) {
327
r_err_str = "Malformed hex constant in string";
328
r_token.type = TK_ERROR;
329
return ERR_PARSE_ERROR;
330
}
331
char32_t v;
332
if (is_digit(c)) {
333
v = c - '0';
334
} else if (c >= 'a' && c <= 'f') {
335
v = c - 'a';
336
v += 10;
337
} else if (c >= 'A' && c <= 'F') {
338
v = c - 'A';
339
v += 10;
340
} else {
341
ERR_PRINT("Bug parsing hex constant.");
342
v = 0;
343
}
344
345
res <<= 4;
346
res |= v;
347
}
348
349
} break;
350
default: {
351
res = next;
352
} break;
353
}
354
355
// Parse UTF-16 pair.
356
if ((res & 0xfffffc00) == 0xd800) {
357
if (prev == 0) {
358
prev = res;
359
continue;
360
} else {
361
r_err_str = "Invalid UTF-16 sequence in string, unpaired lead surrogate";
362
r_token.type = TK_ERROR;
363
return ERR_PARSE_ERROR;
364
}
365
} else if ((res & 0xfffffc00) == 0xdc00) {
366
if (prev == 0) {
367
r_err_str = "Invalid UTF-16 sequence in string, unpaired trail surrogate";
368
r_token.type = TK_ERROR;
369
return ERR_PARSE_ERROR;
370
} else {
371
res = (prev << 10UL) + res - ((0xd800 << 10UL) + 0xdc00 - 0x10000);
372
prev = 0;
373
}
374
}
375
if (prev != 0) {
376
r_err_str = "Invalid UTF-16 sequence in string, unpaired lead surrogate";
377
r_token.type = TK_ERROR;
378
return ERR_PARSE_ERROR;
379
}
380
str += res;
381
} else {
382
if (prev != 0) {
383
r_err_str = "Invalid UTF-16 sequence in string, unpaired lead surrogate";
384
r_token.type = TK_ERROR;
385
return ERR_PARSE_ERROR;
386
}
387
if (ch == '\n') {
388
line++;
389
}
390
str += ch;
391
}
392
}
393
if (prev != 0) {
394
r_err_str = "Invalid UTF-16 sequence in string, unpaired lead surrogate";
395
r_token.type = TK_ERROR;
396
return ERR_PARSE_ERROR;
397
}
398
399
if (p_stream->is_utf8()) {
400
// Re-interpret the string we built as ascii.
401
CharString string_as_ascii = str.ascii(true);
402
str.clear();
403
str.append_utf8(string_as_ascii);
404
}
405
if (string_name) {
406
r_token.type = TK_STRING_NAME;
407
r_token.value = StringName(str);
408
} else {
409
r_token.type = TK_STRING;
410
r_token.value = str;
411
}
412
return OK;
413
414
} break;
415
default: {
416
if (cchar <= 32) {
417
break;
418
}
419
StringBuffer<> token_text;
420
if (cchar == '-') {
421
token_text += '-';
422
cchar = p_stream->get_char();
423
}
424
if (cchar >= '0' && cchar <= '9') {
425
//a number
426
#define READING_SIGN 0
427
#define READING_INT 1
428
#define READING_DEC 2
429
#define READING_EXP 3
430
#define READING_DONE 4
431
int reading = READING_INT;
432
433
char32_t c = cchar;
434
bool exp_sign = false;
435
bool exp_beg = false;
436
bool is_float = false;
437
438
while (true) {
439
switch (reading) {
440
case READING_INT: {
441
if (is_digit(c)) {
442
//pass
443
} else if (c == '.') {
444
reading = READING_DEC;
445
is_float = true;
446
} else if (c == 'e' || c == 'E') {
447
reading = READING_EXP;
448
is_float = true;
449
} else {
450
reading = READING_DONE;
451
}
452
453
} break;
454
case READING_DEC: {
455
if (is_digit(c)) {
456
} else if (c == 'e' || c == 'E') {
457
reading = READING_EXP;
458
} else {
459
reading = READING_DONE;
460
}
461
462
} break;
463
case READING_EXP: {
464
if (is_digit(c)) {
465
exp_beg = true;
466
467
} else if ((c == '-' || c == '+') && !exp_sign && !exp_beg) {
468
exp_sign = true;
469
470
} else {
471
reading = READING_DONE;
472
}
473
} break;
474
}
475
476
if (reading == READING_DONE) {
477
break;
478
}
479
token_text += c;
480
c = p_stream->get_char();
481
}
482
483
p_stream->saved = c;
484
485
r_token.type = TK_NUMBER;
486
487
if (is_float) {
488
r_token.value = token_text.as_double();
489
} else {
490
r_token.value = token_text.as_int();
491
}
492
return OK;
493
} else if (is_ascii_alphabet_char(cchar) || is_underscore(cchar)) {
494
bool first = true;
495
496
while (is_ascii_alphabet_char(cchar) || is_underscore(cchar) || (!first && is_digit(cchar))) {
497
token_text += cchar;
498
cchar = p_stream->get_char();
499
first = false;
500
}
501
502
p_stream->saved = cchar;
503
504
r_token.type = TK_IDENTIFIER;
505
r_token.value = token_text.as_string();
506
return OK;
507
} else {
508
r_err_str = "Unexpected character";
509
r_token.type = TK_ERROR;
510
return ERR_PARSE_ERROR;
511
}
512
}
513
}
514
}
515
516
r_err_str = "Unknown error getting token";
517
r_token.type = TK_ERROR;
518
return ERR_PARSE_ERROR;
519
}
520
521
Error VariantParser::_parse_enginecfg(Stream *p_stream, Vector<String> &strings, int &line, String &r_err_str) {
522
Token token;
523
get_token(p_stream, token, line, r_err_str);
524
if (token.type != TK_PARENTHESIS_OPEN) {
525
r_err_str = "Expected '(' in old-style project.godot construct";
526
return ERR_PARSE_ERROR;
527
}
528
529
String accum;
530
531
while (true) {
532
char32_t c = p_stream->get_char();
533
534
if (p_stream->is_eof()) {
535
r_err_str = "Unexpected EOF while parsing old-style project.godot construct";
536
return ERR_PARSE_ERROR;
537
}
538
539
if (c == ',') {
540
strings.push_back(accum.strip_edges());
541
accum = String();
542
} else if (c == ')') {
543
strings.push_back(accum.strip_edges());
544
return OK;
545
} else if (c == '\n') {
546
line++;
547
}
548
}
549
}
550
551
template <typename T>
552
Error VariantParser::_parse_construct(Stream *p_stream, Vector<T> &r_construct, int &line, String &r_err_str) {
553
Token token;
554
get_token(p_stream, token, line, r_err_str);
555
if (token.type != TK_PARENTHESIS_OPEN) {
556
r_err_str = "Expected '(' in constructor";
557
return ERR_PARSE_ERROR;
558
}
559
560
bool first = true;
561
while (true) {
562
if (!first) {
563
get_token(p_stream, token, line, r_err_str);
564
if (token.type == TK_COMMA) {
565
//do none
566
} else if (token.type == TK_PARENTHESIS_CLOSE) {
567
break;
568
} else {
569
r_err_str = "Expected ',' or ')' in constructor";
570
return ERR_PARSE_ERROR;
571
}
572
}
573
get_token(p_stream, token, line, r_err_str);
574
575
if (first && token.type == TK_PARENTHESIS_CLOSE) {
576
break;
577
} else if (token.type != TK_NUMBER) {
578
bool valid = false;
579
if (token.type == TK_IDENTIFIER) {
580
double real = stor_fix(token.value);
581
if (real != -1) {
582
token.type = TK_NUMBER;
583
token.value = real;
584
valid = true;
585
}
586
}
587
if (!valid) {
588
r_err_str = "Expected float in constructor";
589
return ERR_PARSE_ERROR;
590
}
591
}
592
593
r_construct.push_back(token.value);
594
first = false;
595
}
596
597
return OK;
598
}
599
600
Error VariantParser::_parse_byte_array(Stream *p_stream, Vector<uint8_t> &r_construct, int &line, String &r_err_str) {
601
Token token;
602
get_token(p_stream, token, line, r_err_str);
603
if (token.type != TK_PARENTHESIS_OPEN) {
604
r_err_str = "Expected '(' in constructor";
605
return ERR_PARSE_ERROR;
606
}
607
608
get_token(p_stream, token, line, r_err_str);
609
if (token.type == TK_STRING) {
610
// Base64 encoded array.
611
String base64_encoded_string = token.value;
612
int strlen = base64_encoded_string.length();
613
CharString cstr = base64_encoded_string.ascii();
614
615
size_t arr_len = 0;
616
r_construct.resize(strlen / 4 * 3 + 1);
617
uint8_t *w = r_construct.ptrw();
618
Error err = CryptoCore::b64_decode(&w[0], r_construct.size(), &arr_len, (unsigned char *)cstr.get_data(), strlen);
619
if (err) {
620
r_err_str = "Invalid base64-encoded string";
621
return ERR_PARSE_ERROR;
622
}
623
r_construct.resize(arr_len);
624
625
get_token(p_stream, token, line, r_err_str);
626
if (token.type != TK_PARENTHESIS_CLOSE) {
627
r_err_str = "Expected ')' in constructor";
628
return ERR_PARSE_ERROR;
629
}
630
631
} else if (token.type == TK_NUMBER || token.type == TK_IDENTIFIER) {
632
// Individual elements.
633
while (true) {
634
if (token.type != TK_NUMBER) {
635
bool valid = false;
636
if (token.type == TK_IDENTIFIER) {
637
double real = stor_fix(token.value);
638
if (real != -1) {
639
token.type = TK_NUMBER;
640
token.value = real;
641
valid = true;
642
}
643
}
644
if (!valid) {
645
r_err_str = "Expected number in constructor";
646
return ERR_PARSE_ERROR;
647
}
648
}
649
650
r_construct.push_back(token.value);
651
652
get_token(p_stream, token, line, r_err_str);
653
654
if (token.type == TK_COMMA) {
655
//do none
656
} else if (token.type == TK_PARENTHESIS_CLOSE) {
657
break;
658
} else {
659
r_err_str = "Expected ',' or ')' in constructor";
660
return ERR_PARSE_ERROR;
661
}
662
663
get_token(p_stream, token, line, r_err_str);
664
}
665
} else if (token.type == TK_PARENTHESIS_CLOSE) {
666
// Empty array.
667
return OK;
668
} else {
669
r_err_str = "Expected base64 string, or list of numbers in constructor";
670
return ERR_PARSE_ERROR;
671
}
672
673
return OK;
674
}
675
676
Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream, int &line, String &r_err_str, ResourceParser *p_res_parser) {
677
if (token.type == TK_CURLY_BRACKET_OPEN) {
678
Dictionary d;
679
Error err = _parse_dictionary(d, p_stream, line, r_err_str, p_res_parser);
680
if (err) {
681
return err;
682
}
683
value = d;
684
return OK;
685
} else if (token.type == TK_BRACKET_OPEN) {
686
Array a;
687
Error err = _parse_array(a, p_stream, line, r_err_str, p_res_parser);
688
if (err) {
689
return err;
690
}
691
value = a;
692
return OK;
693
} else if (token.type == TK_IDENTIFIER) {
694
String id = token.value;
695
if (id == "true") {
696
value = true;
697
} else if (id == "false") {
698
value = false;
699
} else if (id == "null" || id == "nil") {
700
value = Variant();
701
} else if (id == "inf") {
702
value = Math::INF;
703
} else if (id == "-inf" || id == "inf_neg") {
704
// inf_neg kept for compatibility.
705
value = -Math::INF;
706
} else if (id == "nan") {
707
value = Math::NaN;
708
} else if (id == "Vector2") {
709
Vector<real_t> args;
710
Error err = _parse_construct<real_t>(p_stream, args, line, r_err_str);
711
if (err) {
712
return err;
713
}
714
715
if (args.size() != 2) {
716
r_err_str = "Expected 2 arguments for constructor";
717
return ERR_PARSE_ERROR;
718
}
719
720
value = Vector2(args[0], args[1]);
721
} else if (id == "Vector2i") {
722
Vector<int32_t> args;
723
Error err = _parse_construct<int32_t>(p_stream, args, line, r_err_str);
724
if (err) {
725
return err;
726
}
727
728
if (args.size() != 2) {
729
r_err_str = "Expected 2 arguments for constructor";
730
return ERR_PARSE_ERROR;
731
}
732
733
value = Vector2i(args[0], args[1]);
734
} else if (id == "Rect2") {
735
Vector<real_t> args;
736
Error err = _parse_construct<real_t>(p_stream, args, line, r_err_str);
737
if (err) {
738
return err;
739
}
740
741
if (args.size() != 4) {
742
r_err_str = "Expected 4 arguments for constructor";
743
return ERR_PARSE_ERROR;
744
}
745
746
value = Rect2(args[0], args[1], args[2], args[3]);
747
} else if (id == "Rect2i") {
748
Vector<int32_t> args;
749
Error err = _parse_construct<int32_t>(p_stream, args, line, r_err_str);
750
if (err) {
751
return err;
752
}
753
754
if (args.size() != 4) {
755
r_err_str = "Expected 4 arguments for constructor";
756
return ERR_PARSE_ERROR;
757
}
758
759
value = Rect2i(args[0], args[1], args[2], args[3]);
760
} else if (id == "Vector3") {
761
Vector<real_t> args;
762
Error err = _parse_construct<real_t>(p_stream, args, line, r_err_str);
763
if (err) {
764
return err;
765
}
766
767
if (args.size() != 3) {
768
r_err_str = "Expected 3 arguments for constructor";
769
return ERR_PARSE_ERROR;
770
}
771
772
value = Vector3(args[0], args[1], args[2]);
773
} else if (id == "Vector3i") {
774
Vector<int32_t> args;
775
Error err = _parse_construct<int32_t>(p_stream, args, line, r_err_str);
776
if (err) {
777
return err;
778
}
779
780
if (args.size() != 3) {
781
r_err_str = "Expected 3 arguments for constructor";
782
return ERR_PARSE_ERROR;
783
}
784
785
value = Vector3i(args[0], args[1], args[2]);
786
} else if (id == "Vector4") {
787
Vector<real_t> args;
788
Error err = _parse_construct<real_t>(p_stream, args, line, r_err_str);
789
if (err) {
790
return err;
791
}
792
793
if (args.size() != 4) {
794
r_err_str = "Expected 4 arguments for constructor";
795
return ERR_PARSE_ERROR;
796
}
797
798
value = Vector4(args[0], args[1], args[2], args[3]);
799
} else if (id == "Vector4i") {
800
Vector<int32_t> args;
801
Error err = _parse_construct<int32_t>(p_stream, args, line, r_err_str);
802
if (err) {
803
return err;
804
}
805
806
if (args.size() != 4) {
807
r_err_str = "Expected 4 arguments for constructor";
808
return ERR_PARSE_ERROR;
809
}
810
811
value = Vector4i(args[0], args[1], args[2], args[3]);
812
} else if (id == "Transform2D" || id == "Matrix32") { //compatibility
813
Vector<real_t> args;
814
Error err = _parse_construct<real_t>(p_stream, args, line, r_err_str);
815
if (err) {
816
return err;
817
}
818
819
if (args.size() != 6) {
820
r_err_str = "Expected 6 arguments for constructor";
821
return ERR_PARSE_ERROR;
822
}
823
824
Transform2D m;
825
m[0] = Vector2(args[0], args[1]);
826
m[1] = Vector2(args[2], args[3]);
827
m[2] = Vector2(args[4], args[5]);
828
value = m;
829
} else if (id == "Plane") {
830
Vector<real_t> args;
831
Error err = _parse_construct<real_t>(p_stream, args, line, r_err_str);
832
if (err) {
833
return err;
834
}
835
836
if (args.size() != 4) {
837
r_err_str = "Expected 4 arguments for constructor";
838
return ERR_PARSE_ERROR;
839
}
840
841
value = Plane(args[0], args[1], args[2], args[3]);
842
} else if (id == "Quaternion" || id == "Quat") { // "Quat" kept for compatibility
843
Vector<real_t> args;
844
Error err = _parse_construct<real_t>(p_stream, args, line, r_err_str);
845
if (err) {
846
return err;
847
}
848
849
if (args.size() != 4) {
850
r_err_str = "Expected 4 arguments for constructor";
851
return ERR_PARSE_ERROR;
852
}
853
854
value = Quaternion(args[0], args[1], args[2], args[3]);
855
} else if (id == "AABB" || id == "Rect3") {
856
Vector<real_t> args;
857
Error err = _parse_construct<real_t>(p_stream, args, line, r_err_str);
858
if (err) {
859
return err;
860
}
861
862
if (args.size() != 6) {
863
r_err_str = "Expected 6 arguments for constructor";
864
return ERR_PARSE_ERROR;
865
}
866
867
value = AABB(Vector3(args[0], args[1], args[2]), Vector3(args[3], args[4], args[5]));
868
} else if (id == "Basis" || id == "Matrix3") { //compatibility
869
Vector<real_t> args;
870
Error err = _parse_construct<real_t>(p_stream, args, line, r_err_str);
871
if (err) {
872
return err;
873
}
874
875
if (args.size() != 9) {
876
r_err_str = "Expected 9 arguments for constructor";
877
return ERR_PARSE_ERROR;
878
}
879
880
value = Basis(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]);
881
} else if (id == "Transform3D" || id == "Transform") { // "Transform" kept for compatibility with Godot <4.
882
Vector<real_t> args;
883
Error err = _parse_construct<real_t>(p_stream, args, line, r_err_str);
884
if (err) {
885
return err;
886
}
887
888
if (args.size() != 12) {
889
r_err_str = "Expected 12 arguments for constructor";
890
return ERR_PARSE_ERROR;
891
}
892
893
value = Transform3D(Basis(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]), Vector3(args[9], args[10], args[11]));
894
} else if (id == "Projection") { // "Transform" kept for compatibility with Godot <4.
895
Vector<real_t> args;
896
Error err = _parse_construct<real_t>(p_stream, args, line, r_err_str);
897
if (err) {
898
return err;
899
}
900
901
if (args.size() != 16) {
902
r_err_str = "Expected 16 arguments for constructor";
903
return ERR_PARSE_ERROR;
904
}
905
906
value = Projection(Vector4(args[0], args[1], args[2], args[3]), Vector4(args[4], args[5], args[6], args[7]), Vector4(args[8], args[9], args[10], args[11]), Vector4(args[12], args[13], args[14], args[15]));
907
} else if (id == "Color") {
908
Vector<float> args;
909
Error err = _parse_construct<float>(p_stream, args, line, r_err_str);
910
if (err) {
911
return err;
912
}
913
914
if (args.size() != 4) {
915
r_err_str = "Expected 4 arguments for constructor";
916
return ERR_PARSE_ERROR;
917
}
918
919
value = Color(args[0], args[1], args[2], args[3]);
920
} else if (id == "NodePath") {
921
get_token(p_stream, token, line, r_err_str);
922
if (token.type != TK_PARENTHESIS_OPEN) {
923
r_err_str = "Expected '('";
924
return ERR_PARSE_ERROR;
925
}
926
927
get_token(p_stream, token, line, r_err_str);
928
if (token.type != TK_STRING) {
929
r_err_str = "Expected string as argument for NodePath()";
930
return ERR_PARSE_ERROR;
931
}
932
933
value = NodePath(String(token.value));
934
935
get_token(p_stream, token, line, r_err_str);
936
if (token.type != TK_PARENTHESIS_CLOSE) {
937
r_err_str = "Expected ')'";
938
return ERR_PARSE_ERROR;
939
}
940
} else if (id == "RID") {
941
get_token(p_stream, token, line, r_err_str);
942
if (token.type != TK_PARENTHESIS_OPEN) {
943
r_err_str = "Expected '('";
944
return ERR_PARSE_ERROR;
945
}
946
947
get_token(p_stream, token, line, r_err_str);
948
// Permit empty RID.
949
if (token.type == TK_PARENTHESIS_CLOSE) {
950
value = RID();
951
return OK;
952
} else if (token.type != TK_NUMBER) {
953
r_err_str = "Expected number as argument or ')'";
954
return ERR_PARSE_ERROR;
955
}
956
957
value = RID::from_uint64(token.value);
958
959
get_token(p_stream, token, line, r_err_str);
960
if (token.type != TK_PARENTHESIS_CLOSE) {
961
r_err_str = "Expected ')'";
962
return ERR_PARSE_ERROR;
963
}
964
} else if (id == "Signal") {
965
get_token(p_stream, token, line, r_err_str);
966
if (token.type != TK_PARENTHESIS_OPEN) {
967
r_err_str = "Expected '('";
968
return ERR_PARSE_ERROR;
969
}
970
971
// Load as empty.
972
value = Signal();
973
974
get_token(p_stream, token, line, r_err_str);
975
if (token.type != TK_PARENTHESIS_CLOSE) {
976
r_err_str = "Expected ')'";
977
return ERR_PARSE_ERROR;
978
}
979
} else if (id == "Callable") {
980
get_token(p_stream, token, line, r_err_str);
981
if (token.type != TK_PARENTHESIS_OPEN) {
982
r_err_str = "Expected '('";
983
return ERR_PARSE_ERROR;
984
}
985
986
// Load as empty.
987
value = Callable();
988
989
get_token(p_stream, token, line, r_err_str);
990
if (token.type != TK_PARENTHESIS_CLOSE) {
991
r_err_str = "Expected ')'";
992
return ERR_PARSE_ERROR;
993
}
994
} else if (id == "Object") {
995
get_token(p_stream, token, line, r_err_str);
996
if (token.type != TK_PARENTHESIS_OPEN) {
997
r_err_str = "Expected '('";
998
return ERR_PARSE_ERROR;
999
}
1000
1001
get_token(p_stream, token, line, r_err_str);
1002
1003
if (token.type != TK_IDENTIFIER) {
1004
r_err_str = "Expected identifier with type of object";
1005
return ERR_PARSE_ERROR;
1006
}
1007
1008
String type = token.value;
1009
1010
Object *obj = ClassDB::instantiate(type);
1011
1012
if (!obj) {
1013
r_err_str = vformat("Can't instantiate Object() of type '%s'", type);
1014
return ERR_PARSE_ERROR;
1015
}
1016
1017
Ref<RefCounted> ref = Ref<RefCounted>(Object::cast_to<RefCounted>(obj));
1018
1019
get_token(p_stream, token, line, r_err_str);
1020
if (token.type != TK_COMMA) {
1021
r_err_str = "Expected ',' after object type";
1022
return ERR_PARSE_ERROR;
1023
}
1024
1025
bool at_key = true;
1026
String key;
1027
bool need_comma = false;
1028
1029
while (true) {
1030
if (p_stream->is_eof()) {
1031
r_err_str = "Unexpected EOF while parsing Object()";
1032
return ERR_FILE_CORRUPT;
1033
}
1034
1035
if (at_key) {
1036
Error err = get_token(p_stream, token, line, r_err_str);
1037
if (err != OK) {
1038
return err;
1039
}
1040
1041
if (token.type == TK_PARENTHESIS_CLOSE) {
1042
value = ref.is_valid() ? Variant(ref) : Variant(obj);
1043
return OK;
1044
}
1045
1046
if (need_comma) {
1047
if (token.type != TK_COMMA) {
1048
r_err_str = "Expected '}' or ','";
1049
return ERR_PARSE_ERROR;
1050
} else {
1051
need_comma = false;
1052
continue;
1053
}
1054
}
1055
1056
if (token.type != TK_STRING) {
1057
r_err_str = "Expected property name as string";
1058
return ERR_PARSE_ERROR;
1059
}
1060
1061
key = token.value;
1062
1063
err = get_token(p_stream, token, line, r_err_str);
1064
1065
if (err != OK) {
1066
return err;
1067
}
1068
if (token.type != TK_COLON) {
1069
r_err_str = "Expected ':'";
1070
return ERR_PARSE_ERROR;
1071
}
1072
at_key = false;
1073
} else {
1074
Error err = get_token(p_stream, token, line, r_err_str);
1075
if (err != OK) {
1076
return err;
1077
}
1078
1079
Variant v;
1080
err = parse_value(token, v, p_stream, line, r_err_str, p_res_parser);
1081
if (err) {
1082
return err;
1083
}
1084
obj->set(key, v);
1085
need_comma = true;
1086
at_key = true;
1087
}
1088
}
1089
} else if (id == "Resource" || id == "SubResource" || id == "ExtResource") {
1090
get_token(p_stream, token, line, r_err_str);
1091
if (token.type != TK_PARENTHESIS_OPEN) {
1092
r_err_str = "Expected '('";
1093
return ERR_PARSE_ERROR;
1094
}
1095
1096
if (p_res_parser && id == "Resource" && p_res_parser->func) {
1097
Ref<Resource> res;
1098
Error err = p_res_parser->func(p_res_parser->userdata, p_stream, res, line, r_err_str);
1099
if (err) {
1100
return err;
1101
}
1102
1103
value = res;
1104
} else if (p_res_parser && id == "ExtResource" && p_res_parser->ext_func) {
1105
Ref<Resource> res;
1106
Error err = p_res_parser->ext_func(p_res_parser->userdata, p_stream, res, line, r_err_str);
1107
if (err) {
1108
// If the file is missing, the error can be ignored.
1109
if (err != ERR_FILE_NOT_FOUND && err != ERR_CANT_OPEN && err != ERR_FILE_CANT_OPEN) {
1110
return err;
1111
}
1112
}
1113
1114
value = res;
1115
} else if (p_res_parser && id == "SubResource" && p_res_parser->sub_func) {
1116
Ref<Resource> res;
1117
Error err = p_res_parser->sub_func(p_res_parser->userdata, p_stream, res, line, r_err_str);
1118
if (err) {
1119
return err;
1120
}
1121
1122
value = res;
1123
} else {
1124
get_token(p_stream, token, line, r_err_str);
1125
if (token.type == TK_STRING) {
1126
String path = token.value;
1127
String uid_string;
1128
1129
get_token(p_stream, token, line, r_err_str);
1130
1131
if (path.begins_with("uid://")) {
1132
uid_string = path;
1133
path = "";
1134
}
1135
if (token.type == TK_COMMA) {
1136
get_token(p_stream, token, line, r_err_str);
1137
if (token.type != TK_STRING) {
1138
r_err_str = "Expected string in Resource reference";
1139
return ERR_PARSE_ERROR;
1140
}
1141
String extra_path = token.value;
1142
if (extra_path.begins_with("uid://")) {
1143
if (!uid_string.is_empty()) {
1144
r_err_str = "Two uid:// paths in one Resource reference";
1145
return ERR_PARSE_ERROR;
1146
}
1147
uid_string = extra_path;
1148
} else {
1149
if (!path.is_empty()) {
1150
r_err_str = "Two non-uid paths in one Resource reference";
1151
return ERR_PARSE_ERROR;
1152
}
1153
path = extra_path;
1154
}
1155
get_token(p_stream, token, line, r_err_str);
1156
}
1157
1158
Ref<Resource> res;
1159
if (!uid_string.is_empty()) {
1160
ResourceUID::ID uid = ResourceUID::get_singleton()->text_to_id(uid_string);
1161
if (uid != ResourceUID::INVALID_ID && ResourceUID::get_singleton()->has_id(uid)) {
1162
const String id_path = ResourceUID::get_singleton()->get_id_path(uid);
1163
if (!id_path.is_empty()) {
1164
res = ResourceLoader::load(id_path);
1165
}
1166
}
1167
}
1168
if (res.is_null() && !path.is_empty()) {
1169
res = ResourceLoader::load(path);
1170
}
1171
if (res.is_null()) {
1172
r_err_str = "Can't load resource at path: " + path + " with uid: " + uid_string;
1173
return ERR_PARSE_ERROR;
1174
}
1175
1176
if (token.type != TK_PARENTHESIS_CLOSE) {
1177
r_err_str = "Expected ')'";
1178
return ERR_PARSE_ERROR;
1179
}
1180
1181
value = res;
1182
} else {
1183
r_err_str = "Expected string as argument for Resource()";
1184
return ERR_PARSE_ERROR;
1185
}
1186
}
1187
} else if (id == "Dictionary") {
1188
Error err = OK;
1189
1190
get_token(p_stream, token, line, r_err_str);
1191
if (token.type != TK_BRACKET_OPEN) {
1192
r_err_str = "Expected '['";
1193
return ERR_PARSE_ERROR;
1194
}
1195
1196
get_token(p_stream, token, line, r_err_str);
1197
if (token.type != TK_IDENTIFIER) {
1198
r_err_str = "Expected type identifier for key";
1199
return ERR_PARSE_ERROR;
1200
}
1201
1202
static HashMap<StringName, Variant::Type> builtin_types;
1203
if (builtin_types.is_empty()) {
1204
for (int i = 1; i < Variant::VARIANT_MAX; i++) {
1205
builtin_types[Variant::get_type_name((Variant::Type)i)] = (Variant::Type)i;
1206
}
1207
}
1208
1209
Dictionary dict;
1210
Variant::Type key_type = Variant::NIL;
1211
StringName key_class_name;
1212
Variant key_script;
1213
bool got_comma_token = false;
1214
if (builtin_types.has(token.value)) {
1215
key_type = builtin_types.get(token.value);
1216
} else if (token.value == "Resource" || token.value == "SubResource" || token.value == "ExtResource") {
1217
Variant resource;
1218
err = parse_value(token, resource, p_stream, line, r_err_str, p_res_parser);
1219
if (err) {
1220
if (token.value == "Resource" && err == ERR_PARSE_ERROR && r_err_str == "Expected '('" && token.type == TK_COMMA) {
1221
err = OK;
1222
r_err_str = String();
1223
key_type = Variant::OBJECT;
1224
key_class_name = token.value;
1225
got_comma_token = true;
1226
} else {
1227
return err;
1228
}
1229
} else {
1230
Ref<Script> script = resource;
1231
if (script.is_valid() && script->is_valid()) {
1232
key_type = Variant::OBJECT;
1233
key_class_name = script->get_instance_base_type();
1234
key_script = script;
1235
}
1236
}
1237
} else if (ClassDB::class_exists(token.value)) {
1238
key_type = Variant::OBJECT;
1239
key_class_name = token.value;
1240
}
1241
1242
if (!got_comma_token) {
1243
get_token(p_stream, token, line, r_err_str);
1244
if (token.type != TK_COMMA) {
1245
r_err_str = "Expected ',' after key type";
1246
return ERR_PARSE_ERROR;
1247
}
1248
}
1249
1250
get_token(p_stream, token, line, r_err_str);
1251
if (token.type != TK_IDENTIFIER) {
1252
r_err_str = "Expected type identifier for value";
1253
return ERR_PARSE_ERROR;
1254
}
1255
1256
Variant::Type value_type = Variant::NIL;
1257
StringName value_class_name;
1258
Variant value_script;
1259
bool got_bracket_token = false;
1260
if (builtin_types.has(token.value)) {
1261
value_type = builtin_types.get(token.value);
1262
} else if (token.value == "Resource" || token.value == "SubResource" || token.value == "ExtResource") {
1263
Variant resource;
1264
err = parse_value(token, resource, p_stream, line, r_err_str, p_res_parser);
1265
if (err) {
1266
if (token.value == "Resource" && err == ERR_PARSE_ERROR && r_err_str == "Expected '('" && token.type == TK_BRACKET_CLOSE) {
1267
err = OK;
1268
r_err_str = String();
1269
value_type = Variant::OBJECT;
1270
value_class_name = token.value;
1271
got_bracket_token = true;
1272
} else {
1273
return err;
1274
}
1275
} else {
1276
Ref<Script> script = resource;
1277
if (script.is_valid() && script->is_valid()) {
1278
value_type = Variant::OBJECT;
1279
value_class_name = script->get_instance_base_type();
1280
value_script = script;
1281
}
1282
}
1283
} else if (ClassDB::class_exists(token.value)) {
1284
value_type = Variant::OBJECT;
1285
value_class_name = token.value;
1286
}
1287
1288
if (key_type != Variant::NIL || value_type != Variant::NIL) {
1289
dict.set_typed(key_type, key_class_name, key_script, value_type, value_class_name, value_script);
1290
}
1291
1292
if (!got_bracket_token) {
1293
get_token(p_stream, token, line, r_err_str);
1294
if (token.type != TK_BRACKET_CLOSE) {
1295
r_err_str = "Expected ']'";
1296
return ERR_PARSE_ERROR;
1297
}
1298
}
1299
1300
get_token(p_stream, token, line, r_err_str);
1301
if (token.type != TK_PARENTHESIS_OPEN) {
1302
r_err_str = "Expected '('";
1303
return ERR_PARSE_ERROR;
1304
}
1305
1306
get_token(p_stream, token, line, r_err_str);
1307
if (token.type != TK_CURLY_BRACKET_OPEN) {
1308
r_err_str = "Expected '{'";
1309
return ERR_PARSE_ERROR;
1310
}
1311
1312
Dictionary values;
1313
err = _parse_dictionary(values, p_stream, line, r_err_str, p_res_parser);
1314
if (err) {
1315
return err;
1316
}
1317
1318
get_token(p_stream, token, line, r_err_str);
1319
if (token.type != TK_PARENTHESIS_CLOSE) {
1320
r_err_str = "Expected ')'";
1321
return ERR_PARSE_ERROR;
1322
}
1323
1324
dict.assign(values);
1325
1326
value = dict;
1327
} else if (id == "Array") {
1328
Error err = OK;
1329
1330
get_token(p_stream, token, line, r_err_str);
1331
if (token.type != TK_BRACKET_OPEN) {
1332
r_err_str = "Expected '['";
1333
return ERR_PARSE_ERROR;
1334
}
1335
1336
get_token(p_stream, token, line, r_err_str);
1337
if (token.type != TK_IDENTIFIER) {
1338
r_err_str = "Expected type identifier";
1339
return ERR_PARSE_ERROR;
1340
}
1341
1342
static HashMap<String, Variant::Type> builtin_types;
1343
if (builtin_types.is_empty()) {
1344
for (int i = 1; i < Variant::VARIANT_MAX; i++) {
1345
builtin_types[Variant::get_type_name((Variant::Type)i)] = (Variant::Type)i;
1346
}
1347
}
1348
1349
Array array = Array();
1350
bool got_bracket_token = false;
1351
if (builtin_types.has(token.value)) {
1352
array.set_typed(builtin_types.get(token.value), StringName(), Variant());
1353
} else if (token.value == "Resource" || token.value == "SubResource" || token.value == "ExtResource") {
1354
Variant resource;
1355
err = parse_value(token, resource, p_stream, line, r_err_str, p_res_parser);
1356
if (err) {
1357
if (token.value == "Resource" && err == ERR_PARSE_ERROR && r_err_str == "Expected '('" && token.type == TK_BRACKET_CLOSE) {
1358
err = OK;
1359
r_err_str = String();
1360
array.set_typed(Variant::OBJECT, token.value, Variant());
1361
got_bracket_token = true;
1362
} else {
1363
return err;
1364
}
1365
} else {
1366
Ref<Script> script = resource;
1367
if (script.is_valid() && script->is_valid()) {
1368
array.set_typed(Variant::OBJECT, script->get_instance_base_type(), script);
1369
}
1370
}
1371
} else if (ClassDB::class_exists(token.value)) {
1372
array.set_typed(Variant::OBJECT, token.value, Variant());
1373
}
1374
1375
if (!got_bracket_token) {
1376
get_token(p_stream, token, line, r_err_str);
1377
if (token.type != TK_BRACKET_CLOSE) {
1378
r_err_str = "Expected ']'";
1379
return ERR_PARSE_ERROR;
1380
}
1381
}
1382
1383
get_token(p_stream, token, line, r_err_str);
1384
if (token.type != TK_PARENTHESIS_OPEN) {
1385
r_err_str = "Expected '('";
1386
return ERR_PARSE_ERROR;
1387
}
1388
1389
get_token(p_stream, token, line, r_err_str);
1390
if (token.type != TK_BRACKET_OPEN) {
1391
r_err_str = "Expected '['";
1392
return ERR_PARSE_ERROR;
1393
}
1394
1395
Array values;
1396
err = _parse_array(values, p_stream, line, r_err_str, p_res_parser);
1397
if (err) {
1398
return err;
1399
}
1400
1401
get_token(p_stream, token, line, r_err_str);
1402
if (token.type != TK_PARENTHESIS_CLOSE) {
1403
r_err_str = "Expected ')'";
1404
return ERR_PARSE_ERROR;
1405
}
1406
1407
array.assign(values);
1408
1409
value = array;
1410
} else if (id == "PackedByteArray" || id == "PoolByteArray" || id == "ByteArray") {
1411
Vector<uint8_t> args;
1412
Error err = _parse_byte_array(p_stream, args, line, r_err_str);
1413
if (err) {
1414
return err;
1415
}
1416
1417
Vector<uint8_t> arr;
1418
{
1419
int len = args.size();
1420
arr.resize(len);
1421
uint8_t *w = arr.ptrw();
1422
for (int i = 0; i < len; i++) {
1423
w[i] = args[i];
1424
}
1425
}
1426
1427
value = arr;
1428
} else if (id == "PackedInt32Array" || id == "PackedIntArray" || id == "PoolIntArray" || id == "IntArray") {
1429
Vector<int32_t> args;
1430
Error err = _parse_construct<int32_t>(p_stream, args, line, r_err_str);
1431
if (err) {
1432
return err;
1433
}
1434
1435
Vector<int32_t> arr;
1436
{
1437
int32_t len = args.size();
1438
arr.resize(len);
1439
int32_t *w = arr.ptrw();
1440
for (int32_t i = 0; i < len; i++) {
1441
w[i] = int32_t(args[i]);
1442
}
1443
}
1444
1445
value = arr;
1446
} else if (id == "PackedInt64Array") {
1447
Vector<int64_t> args;
1448
Error err = _parse_construct<int64_t>(p_stream, args, line, r_err_str);
1449
if (err) {
1450
return err;
1451
}
1452
1453
Vector<int64_t> arr;
1454
{
1455
int64_t len = args.size();
1456
arr.resize(len);
1457
int64_t *w = arr.ptrw();
1458
for (int64_t i = 0; i < len; i++) {
1459
w[i] = int64_t(args[i]);
1460
}
1461
}
1462
1463
value = arr;
1464
} else if (id == "PackedFloat32Array" || id == "PackedRealArray" || id == "PoolRealArray" || id == "FloatArray") {
1465
Vector<float> args;
1466
Error err = _parse_construct<float>(p_stream, args, line, r_err_str);
1467
if (err) {
1468
return err;
1469
}
1470
1471
Vector<float> arr;
1472
{
1473
int len = args.size();
1474
arr.resize(len);
1475
float *w = arr.ptrw();
1476
for (int i = 0; i < len; i++) {
1477
w[i] = args[i];
1478
}
1479
}
1480
1481
value = arr;
1482
} else if (id == "PackedFloat64Array") {
1483
Vector<double> args;
1484
Error err = _parse_construct<double>(p_stream, args, line, r_err_str);
1485
if (err) {
1486
return err;
1487
}
1488
1489
Vector<double> arr;
1490
{
1491
int len = args.size();
1492
arr.resize(len);
1493
double *w = arr.ptrw();
1494
for (int i = 0; i < len; i++) {
1495
w[i] = args[i];
1496
}
1497
}
1498
1499
value = arr;
1500
} else if (id == "PackedStringArray" || id == "PoolStringArray" || id == "StringArray") {
1501
get_token(p_stream, token, line, r_err_str);
1502
if (token.type != TK_PARENTHESIS_OPEN) {
1503
r_err_str = "Expected '('";
1504
return ERR_PARSE_ERROR;
1505
}
1506
1507
Vector<String> cs;
1508
1509
bool first = true;
1510
while (true) {
1511
if (!first) {
1512
get_token(p_stream, token, line, r_err_str);
1513
if (token.type == TK_COMMA) {
1514
//do none
1515
} else if (token.type == TK_PARENTHESIS_CLOSE) {
1516
break;
1517
} else {
1518
r_err_str = "Expected ',' or ')'";
1519
return ERR_PARSE_ERROR;
1520
}
1521
}
1522
get_token(p_stream, token, line, r_err_str);
1523
1524
if (token.type == TK_PARENTHESIS_CLOSE) {
1525
break;
1526
} else if (token.type != TK_STRING) {
1527
r_err_str = "Expected string";
1528
return ERR_PARSE_ERROR;
1529
}
1530
1531
first = false;
1532
cs.push_back(token.value);
1533
}
1534
1535
Vector<String> arr;
1536
{
1537
int len = cs.size();
1538
arr.resize(len);
1539
String *w = arr.ptrw();
1540
for (int i = 0; i < len; i++) {
1541
w[i] = cs[i];
1542
}
1543
}
1544
1545
value = arr;
1546
} else if (id == "PackedVector2Array" || id == "PoolVector2Array" || id == "Vector2Array") {
1547
Vector<real_t> args;
1548
Error err = _parse_construct<real_t>(p_stream, args, line, r_err_str);
1549
if (err) {
1550
return err;
1551
}
1552
1553
Vector<Vector2> arr;
1554
{
1555
int len = args.size() / 2;
1556
arr.resize(len);
1557
Vector2 *w = arr.ptrw();
1558
for (int i = 0; i < len; i++) {
1559
w[i] = Vector2(args[i * 2 + 0], args[i * 2 + 1]);
1560
}
1561
}
1562
1563
value = arr;
1564
} else if (id == "PackedVector3Array" || id == "PoolVector3Array" || id == "Vector3Array") {
1565
Vector<real_t> args;
1566
Error err = _parse_construct<real_t>(p_stream, args, line, r_err_str);
1567
if (err) {
1568
return err;
1569
}
1570
1571
Vector<Vector3> arr;
1572
{
1573
int len = args.size() / 3;
1574
arr.resize(len);
1575
Vector3 *w = arr.ptrw();
1576
for (int i = 0; i < len; i++) {
1577
w[i] = Vector3(args[i * 3 + 0], args[i * 3 + 1], args[i * 3 + 2]);
1578
}
1579
}
1580
1581
value = arr;
1582
} else if (id == "PackedVector4Array" || id == "PoolVector4Array" || id == "Vector4Array") {
1583
Vector<real_t> args;
1584
Error err = _parse_construct<real_t>(p_stream, args, line, r_err_str);
1585
if (err) {
1586
return err;
1587
}
1588
1589
Vector<Vector4> arr;
1590
{
1591
int len = args.size() / 4;
1592
arr.resize(len);
1593
Vector4 *w = arr.ptrw();
1594
for (int i = 0; i < len; i++) {
1595
w[i] = Vector4(args[i * 4 + 0], args[i * 4 + 1], args[i * 4 + 2], args[i * 4 + 3]);
1596
}
1597
}
1598
1599
value = arr;
1600
} else if (id == "PackedColorArray" || id == "PoolColorArray" || id == "ColorArray") {
1601
Vector<float> args;
1602
Error err = _parse_construct<float>(p_stream, args, line, r_err_str);
1603
if (err) {
1604
return err;
1605
}
1606
1607
Vector<Color> arr;
1608
{
1609
int len = args.size() / 4;
1610
arr.resize(len);
1611
Color *w = arr.ptrw();
1612
for (int i = 0; i < len; i++) {
1613
w[i] = Color(args[i * 4 + 0], args[i * 4 + 1], args[i * 4 + 2], args[i * 4 + 3]);
1614
}
1615
}
1616
1617
value = arr;
1618
} else {
1619
r_err_str = vformat("Unexpected identifier '%s'", id);
1620
return ERR_PARSE_ERROR;
1621
}
1622
1623
// All above branches end up here unless they had an early return.
1624
return OK;
1625
} else if (token.type == TK_NUMBER) {
1626
value = token.value;
1627
return OK;
1628
} else if (token.type == TK_STRING) {
1629
value = token.value;
1630
return OK;
1631
} else if (token.type == TK_STRING_NAME) {
1632
value = token.value;
1633
return OK;
1634
} else if (token.type == TK_COLOR) {
1635
value = token.value;
1636
return OK;
1637
} else {
1638
r_err_str = vformat("Expected value, got '%s'", String(tk_name[token.type]));
1639
return ERR_PARSE_ERROR;
1640
}
1641
}
1642
1643
Error VariantParser::_parse_array(Array &array, Stream *p_stream, int &line, String &r_err_str, ResourceParser *p_res_parser) {
1644
Token token;
1645
bool need_comma = false;
1646
1647
while (true) {
1648
if (p_stream->is_eof()) {
1649
r_err_str = "Unexpected EOF while parsing array";
1650
return ERR_FILE_CORRUPT;
1651
}
1652
1653
Error err = get_token(p_stream, token, line, r_err_str);
1654
if (err != OK) {
1655
return err;
1656
}
1657
1658
if (token.type == TK_BRACKET_CLOSE) {
1659
return OK;
1660
}
1661
1662
if (need_comma) {
1663
if (token.type != TK_COMMA) {
1664
r_err_str = "Expected ','";
1665
return ERR_PARSE_ERROR;
1666
} else {
1667
need_comma = false;
1668
continue;
1669
}
1670
}
1671
1672
Variant v;
1673
err = parse_value(token, v, p_stream, line, r_err_str, p_res_parser);
1674
if (err) {
1675
return err;
1676
}
1677
1678
array.push_back(v);
1679
need_comma = true;
1680
}
1681
}
1682
1683
Error VariantParser::_parse_dictionary(Dictionary &object, Stream *p_stream, int &line, String &r_err_str, ResourceParser *p_res_parser) {
1684
bool at_key = true;
1685
Variant key;
1686
Token token;
1687
bool need_comma = false;
1688
1689
while (true) {
1690
if (p_stream->is_eof()) {
1691
r_err_str = "Unexpected EOF while parsing dictionary";
1692
return ERR_FILE_CORRUPT;
1693
}
1694
1695
if (at_key) {
1696
Error err = get_token(p_stream, token, line, r_err_str);
1697
if (err != OK) {
1698
return err;
1699
}
1700
1701
if (token.type == TK_CURLY_BRACKET_CLOSE) {
1702
return OK;
1703
}
1704
1705
if (need_comma) {
1706
if (token.type != TK_COMMA) {
1707
r_err_str = "Expected '}' or ','";
1708
return ERR_PARSE_ERROR;
1709
} else {
1710
need_comma = false;
1711
continue;
1712
}
1713
}
1714
1715
err = parse_value(token, key, p_stream, line, r_err_str, p_res_parser);
1716
1717
if (err) {
1718
return err;
1719
}
1720
1721
err = get_token(p_stream, token, line, r_err_str);
1722
1723
if (err != OK) {
1724
return err;
1725
}
1726
if (token.type != TK_COLON) {
1727
r_err_str = "Expected ':'";
1728
return ERR_PARSE_ERROR;
1729
}
1730
at_key = false;
1731
} else {
1732
Error err = get_token(p_stream, token, line, r_err_str);
1733
if (err != OK) {
1734
return err;
1735
}
1736
1737
Variant v;
1738
err = parse_value(token, v, p_stream, line, r_err_str, p_res_parser);
1739
if (err && err != ERR_FILE_MISSING_DEPENDENCIES) {
1740
return err;
1741
}
1742
object[key] = v;
1743
need_comma = true;
1744
at_key = true;
1745
}
1746
}
1747
}
1748
1749
Error VariantParser::_parse_tag(Token &token, Stream *p_stream, int &line, String &r_err_str, Tag &r_tag, ResourceParser *p_res_parser, bool p_simple_tag) {
1750
r_tag.fields.clear();
1751
1752
if (token.type != TK_BRACKET_OPEN) {
1753
r_err_str = "Expected '['";
1754
return ERR_PARSE_ERROR;
1755
}
1756
1757
if (p_simple_tag) {
1758
r_tag.name = "";
1759
r_tag.fields.clear();
1760
bool escaping = false;
1761
1762
if (p_stream->is_utf8()) {
1763
CharString cs;
1764
while (true) {
1765
char c = p_stream->get_char();
1766
if (p_stream->is_eof()) {
1767
r_err_str = "Unexpected EOF while parsing simple tag";
1768
return ERR_PARSE_ERROR;
1769
}
1770
if (c == ']') {
1771
if (escaping) {
1772
escaping = false;
1773
} else {
1774
break;
1775
}
1776
} else if (c == '\\') {
1777
escaping = true;
1778
} else {
1779
escaping = false;
1780
}
1781
cs += c;
1782
}
1783
r_tag.name.clear();
1784
r_tag.name.append_utf8(cs.get_data(), cs.length());
1785
} else {
1786
while (true) {
1787
char32_t c = p_stream->get_char();
1788
if (p_stream->is_eof()) {
1789
r_err_str = "Unexpected EOF while parsing simple tag";
1790
return ERR_PARSE_ERROR;
1791
}
1792
if (c == ']') {
1793
if (escaping) {
1794
escaping = false;
1795
} else {
1796
break;
1797
}
1798
} else if (c == '\\') {
1799
escaping = true;
1800
} else {
1801
escaping = false;
1802
}
1803
r_tag.name += c;
1804
}
1805
}
1806
1807
r_tag.name = r_tag.name.strip_edges();
1808
1809
return OK;
1810
}
1811
1812
get_token(p_stream, token, line, r_err_str);
1813
1814
if (token.type != TK_IDENTIFIER) {
1815
r_err_str = "Expected identifier (tag name)";
1816
return ERR_PARSE_ERROR;
1817
}
1818
1819
r_tag.name = token.value;
1820
bool parsing_tag = true;
1821
1822
while (true) {
1823
if (p_stream->is_eof()) {
1824
r_err_str = vformat("Unexpected EOF while parsing tag '%s'", r_tag.name);
1825
return ERR_FILE_CORRUPT;
1826
}
1827
1828
get_token(p_stream, token, line, r_err_str);
1829
if (token.type == TK_BRACKET_CLOSE) {
1830
break;
1831
}
1832
1833
if (parsing_tag && token.type == TK_PERIOD) {
1834
r_tag.name += "."; //support tags such as [someprop.Android] for specific platforms
1835
get_token(p_stream, token, line, r_err_str);
1836
} else if (parsing_tag && token.type == TK_COLON) {
1837
r_tag.name += ":"; //support tags such as [someprop.Android] for specific platforms
1838
get_token(p_stream, token, line, r_err_str);
1839
} else {
1840
parsing_tag = false;
1841
}
1842
1843
if (token.type != TK_IDENTIFIER) {
1844
r_err_str = "Expected identifier";
1845
return ERR_PARSE_ERROR;
1846
}
1847
1848
String id = token.value;
1849
1850
if (parsing_tag) {
1851
r_tag.name += id;
1852
continue;
1853
}
1854
1855
get_token(p_stream, token, line, r_err_str);
1856
if (token.type != TK_EQUAL) {
1857
r_err_str = "Expected '=' after identifier";
1858
return ERR_PARSE_ERROR;
1859
}
1860
1861
get_token(p_stream, token, line, r_err_str);
1862
Variant value;
1863
Error err = parse_value(token, value, p_stream, line, r_err_str, p_res_parser);
1864
if (err) {
1865
return err;
1866
}
1867
1868
r_tag.fields[id] = value;
1869
}
1870
1871
return OK;
1872
}
1873
1874
Error VariantParser::parse_tag(Stream *p_stream, int &line, String &r_err_str, Tag &r_tag, ResourceParser *p_res_parser, bool p_simple_tag) {
1875
Token token;
1876
get_token(p_stream, token, line, r_err_str);
1877
1878
if (token.type == TK_EOF) {
1879
return ERR_FILE_EOF;
1880
}
1881
1882
if (token.type != TK_BRACKET_OPEN) {
1883
r_err_str = "Expected '['";
1884
return ERR_PARSE_ERROR;
1885
}
1886
1887
return _parse_tag(token, p_stream, line, r_err_str, r_tag, p_res_parser, p_simple_tag);
1888
}
1889
1890
Error VariantParser::parse_tag_assign_eof(Stream *p_stream, int &line, String &r_err_str, Tag &r_tag, String &r_assign, Variant &r_value, ResourceParser *p_res_parser, bool p_simple_tag) {
1891
//assign..
1892
r_assign = "";
1893
String what;
1894
1895
while (true) {
1896
char32_t c;
1897
if (p_stream->saved) {
1898
c = p_stream->saved;
1899
p_stream->saved = 0;
1900
1901
} else {
1902
c = p_stream->get_char();
1903
}
1904
1905
if (p_stream->is_eof()) {
1906
return ERR_FILE_EOF;
1907
}
1908
1909
if (c == ';') { //comment
1910
while (true) {
1911
char32_t ch = p_stream->get_char();
1912
if (p_stream->is_eof()) {
1913
return ERR_FILE_EOF;
1914
}
1915
if (ch == '\n') {
1916
line++;
1917
break;
1918
}
1919
}
1920
continue;
1921
}
1922
1923
if (c == '[' && what.length() == 0) {
1924
//it's a tag!
1925
p_stream->saved = '['; //go back one
1926
1927
Error err = parse_tag(p_stream, line, r_err_str, r_tag, p_res_parser, p_simple_tag);
1928
1929
return err;
1930
}
1931
1932
if (c > 32) {
1933
if (c == '"') { //quoted
1934
p_stream->saved = '"';
1935
Token tk;
1936
Error err = get_token(p_stream, tk, line, r_err_str);
1937
if (err) {
1938
return err;
1939
}
1940
if (tk.type != TK_STRING) {
1941
r_err_str = "Error reading quoted string";
1942
return ERR_INVALID_DATA;
1943
}
1944
1945
what = tk.value;
1946
1947
} else if (c != '=') {
1948
what += c;
1949
} else {
1950
r_assign = what;
1951
Token token;
1952
get_token(p_stream, token, line, r_err_str);
1953
Error err = parse_value(token, r_value, p_stream, line, r_err_str, p_res_parser);
1954
return err;
1955
}
1956
} else if (c == '\n') {
1957
line++;
1958
}
1959
}
1960
}
1961
1962
Error VariantParser::parse(Stream *p_stream, Variant &r_ret, String &r_err_str, int &r_err_line, ResourceParser *p_res_parser) {
1963
Token token;
1964
Error err = get_token(p_stream, token, r_err_line, r_err_str);
1965
if (err) {
1966
return err;
1967
}
1968
1969
if (token.type == TK_EOF) {
1970
return ERR_FILE_EOF;
1971
}
1972
1973
return parse_value(token, r_ret, p_stream, r_err_line, r_err_str, p_res_parser);
1974
}
1975
1976
//////////////////////////////////////////////////////////////////////////////////
1977
//////////////////////////////////////////////////////////////////////////////////
1978
//////////////////////////////////////////////////////////////////////////////////
1979
1980
// These two functions serialize floats or doubles using num_scientific to ensure
1981
// it can be read back in the same way (except collapsing -0 to 0, and NaN values).
1982
static String rtos_fix(float p_value, bool p_compat) {
1983
if (p_value == 0.0f) {
1984
return "0"; // Avoid negative zero (-0) being written, which may annoy git, svn, etc. for changes when they don't exist.
1985
} else if (p_compat) {
1986
// Write old inf_neg for compatibility.
1987
if (std::isinf(p_value) && p_value < 0.0f) {
1988
return "inf_neg";
1989
}
1990
}
1991
return String::num_scientific(p_value);
1992
}
1993
1994
static String rtos_fix(double p_value, bool p_compat) {
1995
if (p_value == 0.0) {
1996
return "0"; // Avoid negative zero (-0) being written, which may annoy git, svn, etc. for changes when they don't exist.
1997
} else if (p_compat) {
1998
// Write old inf_neg for compatibility.
1999
if (std::isinf(p_value) && p_value < 0.0) {
2000
return "inf_neg";
2001
}
2002
}
2003
return String::num_scientific(p_value);
2004
}
2005
2006
static String encode_resource_reference(const String &path) {
2007
ResourceUID::ID uid = ResourceLoader::get_resource_uid(path);
2008
if (uid != ResourceUID::INVALID_ID) {
2009
return "Resource(\"" + ResourceUID::get_singleton()->id_to_text(uid) +
2010
"\", \"" + path.c_escape_multiline() + "\")";
2011
} else {
2012
return "Resource(\"" + path.c_escape_multiline() + "\")";
2013
}
2014
}
2015
2016
Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_string_func, void *p_store_string_ud, EncodeResourceFunc p_encode_res_func, void *p_encode_res_ud, int p_recursion_count, bool p_compat) {
2017
switch (p_variant.get_type()) {
2018
case Variant::NIL: {
2019
p_store_string_func(p_store_string_ud, "null");
2020
} break;
2021
case Variant::BOOL: {
2022
p_store_string_func(p_store_string_ud, p_variant.operator bool() ? "true" : "false");
2023
} break;
2024
case Variant::INT: {
2025
p_store_string_func(p_store_string_ud, itos(p_variant.operator int64_t()));
2026
} break;
2027
case Variant::FLOAT: {
2028
const double value = p_variant.operator double();
2029
String s;
2030
// Hack to avoid garbage digits when the underlying float is 32-bit.
2031
if ((double)(float)value == value) {
2032
s = rtos_fix((float)value, p_compat);
2033
} else {
2034
s = rtos_fix(value, p_compat);
2035
}
2036
// Append ".0" to floats to ensure they are float literals.
2037
if (s != "inf" && s != "-inf" && s != "nan" && !s.contains_char('.') && !s.contains_char('e') && !s.contains_char('E')) {
2038
s += ".0";
2039
}
2040
p_store_string_func(p_store_string_ud, s);
2041
} break;
2042
case Variant::STRING: {
2043
String str = p_variant;
2044
str = "\"" + str.c_escape_multiline() + "\"";
2045
p_store_string_func(p_store_string_ud, str);
2046
} break;
2047
2048
// Math types.
2049
case Variant::VECTOR2: {
2050
Vector2 v = p_variant;
2051
p_store_string_func(p_store_string_ud, "Vector2(" + rtos_fix(v.x, p_compat) + ", " + rtos_fix(v.y, p_compat) + ")");
2052
} break;
2053
case Variant::VECTOR2I: {
2054
Vector2i v = p_variant;
2055
p_store_string_func(p_store_string_ud, "Vector2i(" + itos(v.x) + ", " + itos(v.y) + ")");
2056
} break;
2057
case Variant::RECT2: {
2058
Rect2 aabb = p_variant;
2059
p_store_string_func(p_store_string_ud, "Rect2(" + rtos_fix(aabb.position.x, p_compat) + ", " + rtos_fix(aabb.position.y, p_compat) + ", " + rtos_fix(aabb.size.x, p_compat) + ", " + rtos_fix(aabb.size.y, p_compat) + ")");
2060
} break;
2061
case Variant::RECT2I: {
2062
Rect2i aabb = p_variant;
2063
p_store_string_func(p_store_string_ud, "Rect2i(" + itos(aabb.position.x) + ", " + itos(aabb.position.y) + ", " + itos(aabb.size.x) + ", " + itos(aabb.size.y) + ")");
2064
} break;
2065
case Variant::VECTOR3: {
2066
Vector3 v = p_variant;
2067
p_store_string_func(p_store_string_ud, "Vector3(" + rtos_fix(v.x, p_compat) + ", " + rtos_fix(v.y, p_compat) + ", " + rtos_fix(v.z, p_compat) + ")");
2068
} break;
2069
case Variant::VECTOR3I: {
2070
Vector3i v = p_variant;
2071
p_store_string_func(p_store_string_ud, "Vector3i(" + itos(v.x) + ", " + itos(v.y) + ", " + itos(v.z) + ")");
2072
} break;
2073
case Variant::VECTOR4: {
2074
Vector4 v = p_variant;
2075
p_store_string_func(p_store_string_ud, "Vector4(" + rtos_fix(v.x, p_compat) + ", " + rtos_fix(v.y, p_compat) + ", " + rtos_fix(v.z, p_compat) + ", " + rtos_fix(v.w, p_compat) + ")");
2076
} break;
2077
case Variant::VECTOR4I: {
2078
Vector4i v = p_variant;
2079
p_store_string_func(p_store_string_ud, "Vector4i(" + itos(v.x) + ", " + itos(v.y) + ", " + itos(v.z) + ", " + itos(v.w) + ")");
2080
} break;
2081
case Variant::PLANE: {
2082
Plane p = p_variant;
2083
p_store_string_func(p_store_string_ud, "Plane(" + rtos_fix(p.normal.x, p_compat) + ", " + rtos_fix(p.normal.y, p_compat) + ", " + rtos_fix(p.normal.z, p_compat) + ", " + rtos_fix(p.d, p_compat) + ")");
2084
} break;
2085
case Variant::AABB: {
2086
AABB aabb = p_variant;
2087
p_store_string_func(p_store_string_ud, "AABB(" + rtos_fix(aabb.position.x, p_compat) + ", " + rtos_fix(aabb.position.y, p_compat) + ", " + rtos_fix(aabb.position.z, p_compat) + ", " + rtos_fix(aabb.size.x, p_compat) + ", " + rtos_fix(aabb.size.y, p_compat) + ", " + rtos_fix(aabb.size.z, p_compat) + ")");
2088
} break;
2089
case Variant::QUATERNION: {
2090
Quaternion quaternion = p_variant;
2091
p_store_string_func(p_store_string_ud, "Quaternion(" + rtos_fix(quaternion.x, p_compat) + ", " + rtos_fix(quaternion.y, p_compat) + ", " + rtos_fix(quaternion.z, p_compat) + ", " + rtos_fix(quaternion.w, p_compat) + ")");
2092
} break;
2093
case Variant::TRANSFORM2D: {
2094
String s = "Transform2D(";
2095
Transform2D m3 = p_variant;
2096
for (int i = 0; i < 3; i++) {
2097
for (int j = 0; j < 2; j++) {
2098
if (i != 0 || j != 0) {
2099
s += ", ";
2100
}
2101
s += rtos_fix(m3.columns[i][j], p_compat);
2102
}
2103
}
2104
2105
p_store_string_func(p_store_string_ud, s + ")");
2106
} break;
2107
case Variant::BASIS: {
2108
String s = "Basis(";
2109
Basis m3 = p_variant;
2110
for (int i = 0; i < 3; i++) {
2111
for (int j = 0; j < 3; j++) {
2112
if (i != 0 || j != 0) {
2113
s += ", ";
2114
}
2115
s += rtos_fix(m3.rows[i][j], p_compat);
2116
}
2117
}
2118
2119
p_store_string_func(p_store_string_ud, s + ")");
2120
} break;
2121
case Variant::TRANSFORM3D: {
2122
String s = "Transform3D(";
2123
Transform3D t = p_variant;
2124
Basis &m3 = t.basis;
2125
for (int i = 0; i < 3; i++) {
2126
for (int j = 0; j < 3; j++) {
2127
if (i != 0 || j != 0) {
2128
s += ", ";
2129
}
2130
s += rtos_fix(m3.rows[i][j], p_compat);
2131
}
2132
}
2133
2134
s = s + ", " + rtos_fix(t.origin.x, p_compat) + ", " + rtos_fix(t.origin.y, p_compat) + ", " + rtos_fix(t.origin.z, p_compat);
2135
2136
p_store_string_func(p_store_string_ud, s + ")");
2137
} break;
2138
case Variant::PROJECTION: {
2139
String s = "Projection(";
2140
Projection t = p_variant;
2141
for (int i = 0; i < 4; i++) {
2142
for (int j = 0; j < 4; j++) {
2143
if (i != 0 || j != 0) {
2144
s += ", ";
2145
}
2146
s += rtos_fix(t.columns[i][j], p_compat);
2147
}
2148
}
2149
2150
p_store_string_func(p_store_string_ud, s + ")");
2151
} break;
2152
2153
// Misc types.
2154
case Variant::COLOR: {
2155
Color c = p_variant;
2156
p_store_string_func(p_store_string_ud, "Color(" + rtos_fix(c.r, p_compat) + ", " + rtos_fix(c.g, p_compat) + ", " + rtos_fix(c.b, p_compat) + ", " + rtos_fix(c.a, p_compat) + ")");
2157
} break;
2158
case Variant::STRING_NAME: {
2159
String str = p_variant;
2160
str = "&\"" + str.c_escape() + "\"";
2161
p_store_string_func(p_store_string_ud, str);
2162
} break;
2163
case Variant::NODE_PATH: {
2164
String str = p_variant;
2165
str = "NodePath(\"" + str.c_escape() + "\")";
2166
p_store_string_func(p_store_string_ud, str);
2167
} break;
2168
case Variant::RID: {
2169
RID rid = p_variant;
2170
if (rid == RID()) {
2171
p_store_string_func(p_store_string_ud, "RID()");
2172
} else {
2173
p_store_string_func(p_store_string_ud, "RID(" + itos(rid.get_id()) + ")");
2174
}
2175
} break;
2176
2177
// Do not really store these, but ensure that assignments are not empty.
2178
case Variant::SIGNAL: {
2179
p_store_string_func(p_store_string_ud, "Signal()");
2180
} break;
2181
case Variant::CALLABLE: {
2182
p_store_string_func(p_store_string_ud, "Callable()");
2183
} break;
2184
2185
case Variant::OBJECT: {
2186
if (unlikely(p_recursion_count > MAX_RECURSION)) {
2187
ERR_PRINT("Max recursion reached");
2188
p_store_string_func(p_store_string_ud, "null");
2189
return OK;
2190
}
2191
p_recursion_count++;
2192
2193
Object *obj = p_variant.get_validated_object();
2194
2195
if (!obj) {
2196
p_store_string_func(p_store_string_ud, "null");
2197
break; // don't save it
2198
}
2199
2200
Ref<Resource> res = p_variant;
2201
if (res.is_valid()) {
2202
String res_text;
2203
2204
// Try external function.
2205
if (p_encode_res_func) {
2206
res_text = p_encode_res_func(p_encode_res_ud, res);
2207
}
2208
2209
// Try path, because it's a file.
2210
if (res_text.is_empty() && res->get_path().is_resource_file()) {
2211
// External resource.
2212
String path = res->get_path();
2213
res_text = encode_resource_reference(path);
2214
}
2215
2216
// Could come up with some sort of text.
2217
if (!res_text.is_empty()) {
2218
p_store_string_func(p_store_string_ud, res_text);
2219
break;
2220
}
2221
}
2222
2223
//store as generic object
2224
2225
p_store_string_func(p_store_string_ud, "Object(" + obj->get_class() + ",");
2226
2227
List<PropertyInfo> props;
2228
obj->get_property_list(&props);
2229
bool first = true;
2230
for (const PropertyInfo &E : props) {
2231
if (E.usage & PROPERTY_USAGE_STORAGE || E.usage & PROPERTY_USAGE_SCRIPT_VARIABLE) {
2232
//must be serialized
2233
2234
if (first) {
2235
first = false;
2236
} else {
2237
p_store_string_func(p_store_string_ud, ",");
2238
}
2239
2240
p_store_string_func(p_store_string_ud, "\"" + E.name + "\":");
2241
write(obj->get(E.name), p_store_string_func, p_store_string_ud, p_encode_res_func, p_encode_res_ud, p_recursion_count, p_compat);
2242
}
2243
}
2244
2245
p_store_string_func(p_store_string_ud, ")\n");
2246
} break;
2247
2248
case Variant::DICTIONARY: {
2249
Dictionary dict = p_variant;
2250
2251
if (dict.is_typed()) {
2252
p_store_string_func(p_store_string_ud, "Dictionary[");
2253
2254
Variant::Type key_builtin_type = (Variant::Type)dict.get_typed_key_builtin();
2255
StringName key_class_name = dict.get_typed_key_class_name();
2256
Ref<Script> key_script = dict.get_typed_key_script();
2257
2258
if (key_script.is_valid()) {
2259
String resource_text;
2260
if (p_encode_res_func) {
2261
resource_text = p_encode_res_func(p_encode_res_ud, key_script);
2262
}
2263
if (resource_text.is_empty() && key_script->get_path().is_resource_file()) {
2264
resource_text = encode_resource_reference(key_script->get_path());
2265
}
2266
2267
if (!resource_text.is_empty()) {
2268
p_store_string_func(p_store_string_ud, resource_text);
2269
} else {
2270
ERR_PRINT("Failed to encode a path to a custom script for a dictionary key type.");
2271
p_store_string_func(p_store_string_ud, key_class_name);
2272
}
2273
} else if (key_class_name != StringName()) {
2274
p_store_string_func(p_store_string_ud, key_class_name);
2275
} else if (key_builtin_type == Variant::NIL) {
2276
p_store_string_func(p_store_string_ud, "Variant");
2277
} else {
2278
p_store_string_func(p_store_string_ud, Variant::get_type_name(key_builtin_type));
2279
}
2280
2281
p_store_string_func(p_store_string_ud, ", ");
2282
2283
Variant::Type value_builtin_type = (Variant::Type)dict.get_typed_value_builtin();
2284
StringName value_class_name = dict.get_typed_value_class_name();
2285
Ref<Script> value_script = dict.get_typed_value_script();
2286
2287
if (value_script.is_valid()) {
2288
String resource_text;
2289
if (p_encode_res_func) {
2290
resource_text = p_encode_res_func(p_encode_res_ud, value_script);
2291
}
2292
if (resource_text.is_empty() && value_script->get_path().is_resource_file()) {
2293
resource_text = encode_resource_reference(value_script->get_path());
2294
}
2295
2296
if (!resource_text.is_empty()) {
2297
p_store_string_func(p_store_string_ud, resource_text);
2298
} else {
2299
ERR_PRINT("Failed to encode a path to a custom script for a dictionary value type.");
2300
p_store_string_func(p_store_string_ud, value_class_name);
2301
}
2302
} else if (value_class_name != StringName()) {
2303
p_store_string_func(p_store_string_ud, value_class_name);
2304
} else if (value_builtin_type == Variant::NIL) {
2305
p_store_string_func(p_store_string_ud, "Variant");
2306
} else {
2307
p_store_string_func(p_store_string_ud, Variant::get_type_name(value_builtin_type));
2308
}
2309
2310
p_store_string_func(p_store_string_ud, "](");
2311
}
2312
2313
if (unlikely(p_recursion_count > MAX_RECURSION)) {
2314
ERR_PRINT("Max recursion reached");
2315
p_store_string_func(p_store_string_ud, "{}");
2316
} else {
2317
LocalVector<Variant> keys = dict.get_key_list();
2318
keys.sort_custom<StringLikeVariantOrder>();
2319
2320
if (keys.is_empty()) {
2321
// Avoid unnecessary line break.
2322
p_store_string_func(p_store_string_ud, "{}");
2323
} else {
2324
p_recursion_count++;
2325
2326
p_store_string_func(p_store_string_ud, "{\n");
2327
2328
for (uint32_t i = 0; i < keys.size(); i++) {
2329
const Variant &key = keys[i];
2330
write(key, p_store_string_func, p_store_string_ud, p_encode_res_func, p_encode_res_ud, p_recursion_count, p_compat);
2331
p_store_string_func(p_store_string_ud, ": ");
2332
write(dict[key], p_store_string_func, p_store_string_ud, p_encode_res_func, p_encode_res_ud, p_recursion_count, p_compat);
2333
if (i + 1 < keys.size()) {
2334
p_store_string_func(p_store_string_ud, ",\n");
2335
} else {
2336
p_store_string_func(p_store_string_ud, "\n");
2337
}
2338
}
2339
2340
p_store_string_func(p_store_string_ud, "}");
2341
}
2342
}
2343
2344
if (dict.is_typed()) {
2345
p_store_string_func(p_store_string_ud, ")");
2346
}
2347
} break;
2348
2349
case Variant::ARRAY: {
2350
Array array = p_variant;
2351
2352
if (array.is_typed()) {
2353
p_store_string_func(p_store_string_ud, "Array[");
2354
2355
Variant::Type builtin_type = (Variant::Type)array.get_typed_builtin();
2356
StringName class_name = array.get_typed_class_name();
2357
Ref<Script> script = array.get_typed_script();
2358
2359
if (script.is_valid()) {
2360
String resource_text = String();
2361
if (p_encode_res_func) {
2362
resource_text = p_encode_res_func(p_encode_res_ud, script);
2363
}
2364
if (resource_text.is_empty() && script->get_path().is_resource_file()) {
2365
resource_text = encode_resource_reference(script->get_path());
2366
}
2367
2368
if (!resource_text.is_empty()) {
2369
p_store_string_func(p_store_string_ud, resource_text);
2370
} else {
2371
ERR_PRINT("Failed to encode a path to a custom script for an array type.");
2372
p_store_string_func(p_store_string_ud, class_name);
2373
}
2374
} else if (class_name != StringName()) {
2375
p_store_string_func(p_store_string_ud, class_name);
2376
} else {
2377
p_store_string_func(p_store_string_ud, Variant::get_type_name(builtin_type));
2378
}
2379
2380
p_store_string_func(p_store_string_ud, "](");
2381
}
2382
2383
if (unlikely(p_recursion_count > MAX_RECURSION)) {
2384
ERR_PRINT("Max recursion reached");
2385
p_store_string_func(p_store_string_ud, "[]");
2386
} else {
2387
p_recursion_count++;
2388
2389
p_store_string_func(p_store_string_ud, "[");
2390
2391
bool first = true;
2392
for (const Variant &var : array) {
2393
if (first) {
2394
first = false;
2395
} else {
2396
p_store_string_func(p_store_string_ud, ", ");
2397
}
2398
write(var, p_store_string_func, p_store_string_ud, p_encode_res_func, p_encode_res_ud, p_recursion_count, p_compat);
2399
}
2400
2401
p_store_string_func(p_store_string_ud, "]");
2402
}
2403
2404
if (array.is_typed()) {
2405
p_store_string_func(p_store_string_ud, ")");
2406
}
2407
} break;
2408
2409
case Variant::PACKED_BYTE_ARRAY: {
2410
p_store_string_func(p_store_string_ud, "PackedByteArray(");
2411
Vector<uint8_t> data = p_variant;
2412
if (p_compat) {
2413
int len = data.size();
2414
const uint8_t *ptr = data.ptr();
2415
for (int i = 0; i < len; i++) {
2416
if (i > 0) {
2417
p_store_string_func(p_store_string_ud, ", ");
2418
}
2419
p_store_string_func(p_store_string_ud, itos(ptr[i]));
2420
}
2421
} else if (data.size() > 0) {
2422
p_store_string_func(p_store_string_ud, "\"");
2423
p_store_string_func(p_store_string_ud, CryptoCore::b64_encode_str(data.ptr(), data.size()));
2424
p_store_string_func(p_store_string_ud, "\"");
2425
}
2426
p_store_string_func(p_store_string_ud, ")");
2427
} break;
2428
case Variant::PACKED_INT32_ARRAY: {
2429
p_store_string_func(p_store_string_ud, "PackedInt32Array(");
2430
Vector<int32_t> data = p_variant;
2431
int32_t len = data.size();
2432
const int32_t *ptr = data.ptr();
2433
2434
for (int32_t i = 0; i < len; i++) {
2435
if (i > 0) {
2436
p_store_string_func(p_store_string_ud, ", ");
2437
}
2438
2439
p_store_string_func(p_store_string_ud, itos(ptr[i]));
2440
}
2441
2442
p_store_string_func(p_store_string_ud, ")");
2443
} break;
2444
case Variant::PACKED_INT64_ARRAY: {
2445
p_store_string_func(p_store_string_ud, "PackedInt64Array(");
2446
Vector<int64_t> data = p_variant;
2447
int64_t len = data.size();
2448
const int64_t *ptr = data.ptr();
2449
2450
for (int64_t i = 0; i < len; i++) {
2451
if (i > 0) {
2452
p_store_string_func(p_store_string_ud, ", ");
2453
}
2454
2455
p_store_string_func(p_store_string_ud, itos(ptr[i]));
2456
}
2457
2458
p_store_string_func(p_store_string_ud, ")");
2459
} break;
2460
case Variant::PACKED_FLOAT32_ARRAY: {
2461
p_store_string_func(p_store_string_ud, "PackedFloat32Array(");
2462
Vector<float> data = p_variant;
2463
int len = data.size();
2464
const float *ptr = data.ptr();
2465
2466
for (int i = 0; i < len; i++) {
2467
if (i > 0) {
2468
p_store_string_func(p_store_string_ud, ", ");
2469
}
2470
p_store_string_func(p_store_string_ud, rtos_fix(ptr[i], p_compat));
2471
}
2472
2473
p_store_string_func(p_store_string_ud, ")");
2474
} break;
2475
case Variant::PACKED_FLOAT64_ARRAY: {
2476
p_store_string_func(p_store_string_ud, "PackedFloat64Array(");
2477
Vector<double> data = p_variant;
2478
int len = data.size();
2479
const double *ptr = data.ptr();
2480
2481
for (int i = 0; i < len; i++) {
2482
if (i > 0) {
2483
p_store_string_func(p_store_string_ud, ", ");
2484
}
2485
p_store_string_func(p_store_string_ud, rtos_fix(ptr[i], p_compat));
2486
}
2487
2488
p_store_string_func(p_store_string_ud, ")");
2489
} break;
2490
case Variant::PACKED_STRING_ARRAY: {
2491
p_store_string_func(p_store_string_ud, "PackedStringArray(");
2492
Vector<String> data = p_variant;
2493
int len = data.size();
2494
const String *ptr = data.ptr();
2495
2496
for (int i = 0; i < len; i++) {
2497
if (i > 0) {
2498
p_store_string_func(p_store_string_ud, ", ");
2499
}
2500
p_store_string_func(p_store_string_ud, "\"" + ptr[i].c_escape() + "\"");
2501
}
2502
2503
p_store_string_func(p_store_string_ud, ")");
2504
} break;
2505
case Variant::PACKED_VECTOR2_ARRAY: {
2506
p_store_string_func(p_store_string_ud, "PackedVector2Array(");
2507
Vector<Vector2> data = p_variant;
2508
int len = data.size();
2509
const Vector2 *ptr = data.ptr();
2510
2511
for (int i = 0; i < len; i++) {
2512
if (i > 0) {
2513
p_store_string_func(p_store_string_ud, ", ");
2514
}
2515
p_store_string_func(p_store_string_ud, rtos_fix(ptr[i].x, p_compat) + ", " + rtos_fix(ptr[i].y, p_compat));
2516
}
2517
2518
p_store_string_func(p_store_string_ud, ")");
2519
} break;
2520
case Variant::PACKED_VECTOR3_ARRAY: {
2521
p_store_string_func(p_store_string_ud, "PackedVector3Array(");
2522
Vector<Vector3> data = p_variant;
2523
int len = data.size();
2524
const Vector3 *ptr = data.ptr();
2525
2526
for (int i = 0; i < len; i++) {
2527
if (i > 0) {
2528
p_store_string_func(p_store_string_ud, ", ");
2529
}
2530
p_store_string_func(p_store_string_ud, rtos_fix(ptr[i].x, p_compat) + ", " + rtos_fix(ptr[i].y, p_compat) + ", " + rtos_fix(ptr[i].z, p_compat));
2531
}
2532
2533
p_store_string_func(p_store_string_ud, ")");
2534
} break;
2535
case Variant::PACKED_COLOR_ARRAY: {
2536
p_store_string_func(p_store_string_ud, "PackedColorArray(");
2537
Vector<Color> data = p_variant;
2538
int len = data.size();
2539
const Color *ptr = data.ptr();
2540
2541
for (int i = 0; i < len; i++) {
2542
if (i > 0) {
2543
p_store_string_func(p_store_string_ud, ", ");
2544
}
2545
p_store_string_func(p_store_string_ud, rtos_fix(ptr[i].r, p_compat) + ", " + rtos_fix(ptr[i].g, p_compat) + ", " + rtos_fix(ptr[i].b, p_compat) + ", " + rtos_fix(ptr[i].a, p_compat));
2546
}
2547
2548
p_store_string_func(p_store_string_ud, ")");
2549
} break;
2550
case Variant::PACKED_VECTOR4_ARRAY: {
2551
p_store_string_func(p_store_string_ud, "PackedVector4Array(");
2552
Vector<Vector4> data = p_variant;
2553
int len = data.size();
2554
const Vector4 *ptr = data.ptr();
2555
2556
for (int i = 0; i < len; i++) {
2557
if (i > 0) {
2558
p_store_string_func(p_store_string_ud, ", ");
2559
}
2560
p_store_string_func(p_store_string_ud, rtos_fix(ptr[i].x, p_compat) + ", " + rtos_fix(ptr[i].y, p_compat) + ", " + rtos_fix(ptr[i].z, p_compat) + ", " + rtos_fix(ptr[i].w, p_compat));
2561
}
2562
2563
p_store_string_func(p_store_string_ud, ")");
2564
} break;
2565
2566
default: {
2567
ERR_PRINT("Unknown variant type");
2568
return ERR_BUG;
2569
}
2570
}
2571
2572
return OK;
2573
}
2574
2575
static Error _write_to_str(void *ud, const String &p_string) {
2576
String *str = (String *)ud;
2577
(*str) += p_string;
2578
return OK;
2579
}
2580
2581
Error VariantWriter::write_to_string(const Variant &p_variant, String &r_string, EncodeResourceFunc p_encode_res_func, void *p_encode_res_ud, bool p_compat) {
2582
r_string = String();
2583
2584
return write(p_variant, _write_to_str, &r_string, p_encode_res_func, p_encode_res_ud, 0, p_compat);
2585
}
2586
2587