Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/core/io/json.cpp
9973 views
1
/**************************************************************************/
2
/* json.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 "json.h"
32
33
#include "core/config/engine.h"
34
#include "core/object/script_language.h"
35
#include "core/variant/container_type_validate.h"
36
37
const char *JSON::tk_name[TK_MAX] = {
38
"'{'",
39
"'}'",
40
"'['",
41
"']'",
42
"identifier",
43
"string",
44
"number",
45
"':'",
46
"','",
47
"EOF",
48
};
49
50
void JSON::_add_indent(String &r_result, const String &p_indent, int p_size) {
51
for (int i = 0; i < p_size; i++) {
52
r_result += p_indent;
53
}
54
}
55
56
void JSON::_stringify(String &r_result, const Variant &p_var, const String &p_indent, int p_cur_indent, bool p_sort_keys, HashSet<const void *> &p_markers, bool p_full_precision) {
57
if (p_cur_indent > Variant::MAX_RECURSION_DEPTH) {
58
r_result += "...";
59
ERR_FAIL_MSG("JSON structure is too deep. Bailing.");
60
}
61
62
const char *colon = p_indent.is_empty() ? ":" : ": ";
63
const char *end_statement = p_indent.is_empty() ? "" : "\n";
64
65
switch (p_var.get_type()) {
66
case Variant::NIL:
67
r_result += "null";
68
return;
69
case Variant::BOOL:
70
r_result += p_var.operator bool() ? "true" : "false";
71
return;
72
case Variant::INT:
73
r_result += itos(p_var);
74
return;
75
case Variant::FLOAT: {
76
const double num = p_var;
77
78
// Only for exactly 0. If we have approximately 0 let the user decide how much
79
// precision they want.
80
if (num == double(0.0)) {
81
r_result += "0.0";
82
return;
83
}
84
85
const double magnitude = std::log10(Math::abs(num));
86
const int total_digits = p_full_precision ? 17 : 14;
87
const int precision = MAX(1, total_digits - (int)Math::floor(magnitude));
88
89
r_result += String::num(num, precision);
90
return;
91
}
92
case Variant::PACKED_INT32_ARRAY:
93
case Variant::PACKED_INT64_ARRAY:
94
case Variant::PACKED_FLOAT32_ARRAY:
95
case Variant::PACKED_FLOAT64_ARRAY:
96
case Variant::PACKED_STRING_ARRAY:
97
case Variant::ARRAY: {
98
Array a = p_var;
99
if (p_markers.has(a.id())) {
100
r_result += "\"[...]\"";
101
ERR_FAIL_MSG("Converting circular structure to JSON.");
102
}
103
104
if (a.is_empty()) {
105
r_result += "[]";
106
return;
107
}
108
109
r_result += '[';
110
r_result += end_statement;
111
112
p_markers.insert(a.id());
113
114
bool first = true;
115
for (const Variant &var : a) {
116
if (first) {
117
first = false;
118
} else {
119
r_result += ',';
120
r_result += end_statement;
121
}
122
_add_indent(r_result, p_indent, p_cur_indent + 1);
123
_stringify(r_result, var, p_indent, p_cur_indent + 1, p_sort_keys, p_markers, p_full_precision);
124
}
125
r_result += end_statement;
126
_add_indent(r_result, p_indent, p_cur_indent);
127
r_result += ']';
128
p_markers.erase(a.id());
129
return;
130
}
131
case Variant::DICTIONARY: {
132
Dictionary d = p_var;
133
if (p_markers.has(d.id())) {
134
r_result += "\"{...}\"";
135
ERR_FAIL_MSG("Converting circular structure to JSON.");
136
}
137
138
r_result += '{';
139
r_result += end_statement;
140
p_markers.insert(d.id());
141
142
LocalVector<Variant> keys = d.get_key_list();
143
144
if (p_sort_keys) {
145
keys.sort_custom<StringLikeVariantOrder>();
146
}
147
148
bool first_key = true;
149
for (const Variant &key : keys) {
150
if (first_key) {
151
first_key = false;
152
} else {
153
r_result += ',';
154
r_result += end_statement;
155
}
156
_add_indent(r_result, p_indent, p_cur_indent + 1);
157
_stringify(r_result, String(key), p_indent, p_cur_indent + 1, p_sort_keys, p_markers, p_full_precision);
158
r_result += colon;
159
_stringify(r_result, d[key], p_indent, p_cur_indent + 1, p_sort_keys, p_markers, p_full_precision);
160
}
161
162
r_result += end_statement;
163
_add_indent(r_result, p_indent, p_cur_indent);
164
r_result += '}';
165
p_markers.erase(d.id());
166
return;
167
}
168
default:
169
r_result += '"';
170
r_result += String(p_var).json_escape();
171
r_result += '"';
172
return;
173
}
174
}
175
176
Error JSON::_get_token(const char32_t *p_str, int &index, int p_len, Token &r_token, int &line, String &r_err_str) {
177
while (p_len > 0) {
178
switch (p_str[index]) {
179
case '\n': {
180
line++;
181
index++;
182
break;
183
}
184
case 0: {
185
r_token.type = TK_EOF;
186
return OK;
187
} break;
188
case '{': {
189
r_token.type = TK_CURLY_BRACKET_OPEN;
190
index++;
191
return OK;
192
}
193
case '}': {
194
r_token.type = TK_CURLY_BRACKET_CLOSE;
195
index++;
196
return OK;
197
}
198
case '[': {
199
r_token.type = TK_BRACKET_OPEN;
200
index++;
201
return OK;
202
}
203
case ']': {
204
r_token.type = TK_BRACKET_CLOSE;
205
index++;
206
return OK;
207
}
208
case ':': {
209
r_token.type = TK_COLON;
210
index++;
211
return OK;
212
}
213
case ',': {
214
r_token.type = TK_COMMA;
215
index++;
216
return OK;
217
}
218
case '"': {
219
index++;
220
String str;
221
while (true) {
222
if (p_str[index] == 0) {
223
r_err_str = "Unterminated string";
224
return ERR_PARSE_ERROR;
225
} else if (p_str[index] == '"') {
226
index++;
227
break;
228
} else if (p_str[index] == '\\') {
229
//escaped characters...
230
index++;
231
char32_t next = p_str[index];
232
if (next == 0) {
233
r_err_str = "Unterminated string";
234
return ERR_PARSE_ERROR;
235
}
236
char32_t res = 0;
237
238
switch (next) {
239
case 'b':
240
res = 8;
241
break;
242
case 't':
243
res = 9;
244
break;
245
case 'n':
246
res = 10;
247
break;
248
case 'f':
249
res = 12;
250
break;
251
case 'r':
252
res = 13;
253
break;
254
case 'u': {
255
// hex number
256
for (int j = 0; j < 4; j++) {
257
char32_t c = p_str[index + j + 1];
258
if (c == 0) {
259
r_err_str = "Unterminated string";
260
return ERR_PARSE_ERROR;
261
}
262
if (!is_hex_digit(c)) {
263
r_err_str = "Malformed hex constant in string";
264
return ERR_PARSE_ERROR;
265
}
266
char32_t v;
267
if (is_digit(c)) {
268
v = c - '0';
269
} else if (c >= 'a' && c <= 'f') {
270
v = c - 'a';
271
v += 10;
272
} else if (c >= 'A' && c <= 'F') {
273
v = c - 'A';
274
v += 10;
275
} else {
276
ERR_PRINT("Bug parsing hex constant.");
277
v = 0;
278
}
279
280
res <<= 4;
281
res |= v;
282
}
283
index += 4; //will add at the end anyway
284
285
if ((res & 0xfffffc00) == 0xd800) {
286
if (p_str[index + 1] != '\\' || p_str[index + 2] != 'u') {
287
r_err_str = "Invalid UTF-16 sequence in string, unpaired lead surrogate";
288
return ERR_PARSE_ERROR;
289
}
290
index += 2;
291
char32_t trail = 0;
292
for (int j = 0; j < 4; j++) {
293
char32_t c = p_str[index + j + 1];
294
if (c == 0) {
295
r_err_str = "Unterminated string";
296
return ERR_PARSE_ERROR;
297
}
298
if (!is_hex_digit(c)) {
299
r_err_str = "Malformed hex constant in string";
300
return ERR_PARSE_ERROR;
301
}
302
char32_t v;
303
if (is_digit(c)) {
304
v = c - '0';
305
} else if (c >= 'a' && c <= 'f') {
306
v = c - 'a';
307
v += 10;
308
} else if (c >= 'A' && c <= 'F') {
309
v = c - 'A';
310
v += 10;
311
} else {
312
ERR_PRINT("Bug parsing hex constant.");
313
v = 0;
314
}
315
316
trail <<= 4;
317
trail |= v;
318
}
319
if ((trail & 0xfffffc00) == 0xdc00) {
320
res = (res << 10UL) + trail - ((0xd800 << 10UL) + 0xdc00 - 0x10000);
321
index += 4; //will add at the end anyway
322
} else {
323
r_err_str = "Invalid UTF-16 sequence in string, unpaired lead surrogate";
324
return ERR_PARSE_ERROR;
325
}
326
} else if ((res & 0xfffffc00) == 0xdc00) {
327
r_err_str = "Invalid UTF-16 sequence in string, unpaired trail surrogate";
328
return ERR_PARSE_ERROR;
329
}
330
331
} break;
332
case '"':
333
case '\\':
334
case '/': {
335
res = next;
336
} break;
337
default: {
338
r_err_str = "Invalid escape sequence";
339
return ERR_PARSE_ERROR;
340
}
341
}
342
343
str += res;
344
345
} else {
346
if (p_str[index] == '\n') {
347
line++;
348
}
349
str += p_str[index];
350
}
351
index++;
352
}
353
354
r_token.type = TK_STRING;
355
r_token.value = str;
356
return OK;
357
358
} break;
359
default: {
360
if (p_str[index] <= 32) {
361
index++;
362
break;
363
}
364
365
if (p_str[index] == '-' || is_digit(p_str[index])) {
366
//a number
367
const char32_t *rptr;
368
double number = String::to_float(&p_str[index], &rptr);
369
index += (rptr - &p_str[index]);
370
r_token.type = TK_NUMBER;
371
r_token.value = number;
372
return OK;
373
374
} else if (is_ascii_alphabet_char(p_str[index])) {
375
String id;
376
377
while (is_ascii_alphabet_char(p_str[index])) {
378
id += p_str[index];
379
index++;
380
}
381
382
r_token.type = TK_IDENTIFIER;
383
r_token.value = id;
384
return OK;
385
} else {
386
r_err_str = "Unexpected character";
387
return ERR_PARSE_ERROR;
388
}
389
}
390
}
391
}
392
393
r_err_str = "Unknown error getting token";
394
return ERR_PARSE_ERROR;
395
}
396
397
Error JSON::_parse_value(Variant &value, Token &token, const char32_t *p_str, int &index, int p_len, int &line, int p_depth, String &r_err_str) {
398
if (p_depth > Variant::MAX_RECURSION_DEPTH) {
399
r_err_str = "JSON structure is too deep";
400
return ERR_OUT_OF_MEMORY;
401
}
402
403
if (token.type == TK_CURLY_BRACKET_OPEN) {
404
Dictionary d;
405
Error err = _parse_object(d, p_str, index, p_len, line, p_depth + 1, r_err_str);
406
if (err) {
407
return err;
408
}
409
value = d;
410
} else if (token.type == TK_BRACKET_OPEN) {
411
Array a;
412
Error err = _parse_array(a, p_str, index, p_len, line, p_depth + 1, r_err_str);
413
if (err) {
414
return err;
415
}
416
value = a;
417
} else if (token.type == TK_IDENTIFIER) {
418
String id = token.value;
419
if (id == "true") {
420
value = true;
421
} else if (id == "false") {
422
value = false;
423
} else if (id == "null") {
424
value = Variant();
425
} else {
426
r_err_str = vformat("Expected 'true', 'false', or 'null', got '%s'", id);
427
return ERR_PARSE_ERROR;
428
}
429
} else if (token.type == TK_NUMBER) {
430
value = token.value;
431
} else if (token.type == TK_STRING) {
432
value = token.value;
433
} else {
434
r_err_str = vformat("Expected value, got '%s'", String(tk_name[token.type]));
435
return ERR_PARSE_ERROR;
436
}
437
438
return OK;
439
}
440
441
Error JSON::_parse_array(Array &array, const char32_t *p_str, int &index, int p_len, int &line, int p_depth, String &r_err_str) {
442
Token token;
443
bool need_comma = false;
444
445
while (index < p_len) {
446
Error err = _get_token(p_str, index, p_len, token, line, r_err_str);
447
if (err != OK) {
448
return err;
449
}
450
451
if (token.type == TK_BRACKET_CLOSE) {
452
return OK;
453
}
454
455
if (need_comma) {
456
if (token.type != TK_COMMA) {
457
r_err_str = "Expected ','";
458
return ERR_PARSE_ERROR;
459
} else {
460
need_comma = false;
461
continue;
462
}
463
}
464
465
Variant v;
466
err = _parse_value(v, token, p_str, index, p_len, line, p_depth, r_err_str);
467
if (err) {
468
return err;
469
}
470
471
array.push_back(v);
472
need_comma = true;
473
}
474
475
r_err_str = "Expected ']'";
476
return ERR_PARSE_ERROR;
477
}
478
479
Error JSON::_parse_object(Dictionary &object, const char32_t *p_str, int &index, int p_len, int &line, int p_depth, String &r_err_str) {
480
bool at_key = true;
481
String key;
482
Token token;
483
bool need_comma = false;
484
485
while (index < p_len) {
486
if (at_key) {
487
Error err = _get_token(p_str, index, p_len, token, line, r_err_str);
488
if (err != OK) {
489
return err;
490
}
491
492
if (token.type == TK_CURLY_BRACKET_CLOSE) {
493
return OK;
494
}
495
496
if (need_comma) {
497
if (token.type != TK_COMMA) {
498
r_err_str = "Expected '}' or ','";
499
return ERR_PARSE_ERROR;
500
} else {
501
need_comma = false;
502
continue;
503
}
504
}
505
506
if (token.type != TK_STRING) {
507
r_err_str = "Expected key";
508
return ERR_PARSE_ERROR;
509
}
510
511
key = token.value;
512
err = _get_token(p_str, index, p_len, token, line, r_err_str);
513
if (err != OK) {
514
return err;
515
}
516
if (token.type != TK_COLON) {
517
r_err_str = "Expected ':'";
518
return ERR_PARSE_ERROR;
519
}
520
at_key = false;
521
} else {
522
Error err = _get_token(p_str, index, p_len, token, line, r_err_str);
523
if (err != OK) {
524
return err;
525
}
526
527
Variant v;
528
err = _parse_value(v, token, p_str, index, p_len, line, p_depth, r_err_str);
529
if (err) {
530
return err;
531
}
532
object[key] = v;
533
need_comma = true;
534
at_key = true;
535
}
536
}
537
538
r_err_str = "Expected '}'";
539
return ERR_PARSE_ERROR;
540
}
541
542
void JSON::set_data(const Variant &p_data) {
543
data = p_data;
544
text.clear();
545
}
546
547
Error JSON::_parse_string(const String &p_json, Variant &r_ret, String &r_err_str, int &r_err_line) {
548
const char32_t *str = p_json.ptr();
549
int idx = 0;
550
int len = p_json.length();
551
Token token;
552
r_err_line = 0;
553
String aux_key;
554
555
Error err = _get_token(str, idx, len, token, r_err_line, r_err_str);
556
if (err) {
557
return err;
558
}
559
560
err = _parse_value(r_ret, token, str, idx, len, r_err_line, 0, r_err_str);
561
562
// Check if EOF is reached
563
// or it's a type of the next token.
564
if (err == OK && idx < len) {
565
err = _get_token(str, idx, len, token, r_err_line, r_err_str);
566
567
if (err || token.type != TK_EOF) {
568
r_err_str = "Expected 'EOF'";
569
// Reset return value to empty `Variant`
570
r_ret = Variant();
571
return ERR_PARSE_ERROR;
572
}
573
}
574
575
return err;
576
}
577
578
Error JSON::parse(const String &p_json_string, bool p_keep_text) {
579
Error err = _parse_string(p_json_string, data, err_str, err_line);
580
if (err == Error::OK) {
581
err_line = 0;
582
}
583
if (p_keep_text) {
584
text = p_json_string;
585
}
586
return err;
587
}
588
589
String JSON::get_parsed_text() const {
590
return text;
591
}
592
593
String JSON::stringify(const Variant &p_var, const String &p_indent, bool p_sort_keys, bool p_full_precision) {
594
String result;
595
HashSet<const void *> markers;
596
_stringify(result, p_var, p_indent, 0, p_sort_keys, markers, p_full_precision);
597
return result;
598
}
599
600
Variant JSON::parse_string(const String &p_json_string) {
601
Ref<JSON> json;
602
json.instantiate();
603
Error error = json->parse(p_json_string);
604
ERR_FAIL_COND_V_MSG(error != Error::OK, Variant(), vformat("Parse JSON failed. Error at line %d: %s", json->get_error_line(), json->get_error_message()));
605
return json->get_data();
606
}
607
608
void JSON::_bind_methods() {
609
ClassDB::bind_static_method("JSON", D_METHOD("stringify", "data", "indent", "sort_keys", "full_precision"), &JSON::stringify, DEFVAL(""), DEFVAL(true), DEFVAL(false));
610
ClassDB::bind_static_method("JSON", D_METHOD("parse_string", "json_string"), &JSON::parse_string);
611
ClassDB::bind_method(D_METHOD("parse", "json_text", "keep_text"), &JSON::parse, DEFVAL(false));
612
613
ClassDB::bind_method(D_METHOD("get_data"), &JSON::get_data);
614
ClassDB::bind_method(D_METHOD("set_data", "data"), &JSON::set_data);
615
ClassDB::bind_method(D_METHOD("get_parsed_text"), &JSON::get_parsed_text);
616
ClassDB::bind_method(D_METHOD("get_error_line"), &JSON::get_error_line);
617
ClassDB::bind_method(D_METHOD("get_error_message"), &JSON::get_error_message);
618
619
ClassDB::bind_static_method("JSON", D_METHOD("from_native", "variant", "full_objects"), &JSON::from_native, DEFVAL(false));
620
ClassDB::bind_static_method("JSON", D_METHOD("to_native", "json", "allow_objects"), &JSON::to_native, DEFVAL(false));
621
622
ADD_PROPERTY(PropertyInfo(Variant::NIL, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT), "set_data", "get_data"); // Ensures that it can be serialized as binary.
623
}
624
625
#define TYPE "type"
626
#define ELEM_TYPE "elem_type"
627
#define KEY_TYPE "key_type"
628
#define VALUE_TYPE "value_type"
629
#define ARGS "args"
630
#define PROPS "props"
631
632
static bool _encode_container_type(Dictionary &r_dict, const String &p_key, const ContainerType &p_type, bool p_full_objects) {
633
if (p_type.builtin_type != Variant::NIL) {
634
if (p_type.script.is_valid()) {
635
ERR_FAIL_COND_V(!p_full_objects, false);
636
const String path = p_type.script->get_path();
637
ERR_FAIL_COND_V_MSG(path.is_empty() || !path.begins_with("res://"), false, "Failed to encode a path to a custom script for a container type.");
638
r_dict[p_key] = path;
639
} else if (p_type.class_name != StringName()) {
640
ERR_FAIL_COND_V(!p_full_objects, false);
641
r_dict[p_key] = String(p_type.class_name);
642
} else {
643
// No need to check `p_full_objects` since `class_name` should be non-empty for `builtin_type == Variant::OBJECT`.
644
r_dict[p_key] = Variant::get_type_name(p_type.builtin_type);
645
}
646
}
647
return true;
648
}
649
650
Variant JSON::_from_native(const Variant &p_variant, bool p_full_objects, int p_depth) {
651
#define RETURN_ARGS \
652
Dictionary ret; \
653
ret[TYPE] = Variant::get_type_name(p_variant.get_type()); \
654
ret[ARGS] = args; \
655
return ret
656
657
switch (p_variant.get_type()) {
658
case Variant::NIL:
659
case Variant::BOOL: {
660
return p_variant;
661
} break;
662
663
case Variant::INT: {
664
return "i:" + String(p_variant);
665
} break;
666
case Variant::FLOAT: {
667
return "f:" + String(p_variant);
668
} break;
669
case Variant::STRING: {
670
return "s:" + String(p_variant);
671
} break;
672
case Variant::STRING_NAME: {
673
return "sn:" + String(p_variant);
674
} break;
675
case Variant::NODE_PATH: {
676
return "np:" + String(p_variant);
677
} break;
678
679
case Variant::RID:
680
case Variant::CALLABLE:
681
case Variant::SIGNAL: {
682
Dictionary ret;
683
ret[TYPE] = Variant::get_type_name(p_variant.get_type());
684
return ret;
685
} break;
686
687
case Variant::VECTOR2: {
688
const Vector2 v = p_variant;
689
Array args = { v.x, v.y };
690
RETURN_ARGS;
691
} break;
692
case Variant::VECTOR2I: {
693
const Vector2i v = p_variant;
694
Array args = { v.x, v.y };
695
RETURN_ARGS;
696
} break;
697
case Variant::RECT2: {
698
const Rect2 r = p_variant;
699
Array args = { r.position.x, r.position.y, r.size.width, r.size.height };
700
RETURN_ARGS;
701
} break;
702
case Variant::RECT2I: {
703
const Rect2i r = p_variant;
704
Array args = { r.position.x, r.position.y, r.size.width, r.size.height };
705
RETURN_ARGS;
706
} break;
707
case Variant::VECTOR3: {
708
const Vector3 v = p_variant;
709
Array args = { v.x, v.y, v.z };
710
RETURN_ARGS;
711
} break;
712
case Variant::VECTOR3I: {
713
const Vector3i v = p_variant;
714
Array args = { v.x, v.y, v.z };
715
RETURN_ARGS;
716
} break;
717
case Variant::TRANSFORM2D: {
718
const Transform2D t = p_variant;
719
Array args = { t[0].x, t[0].y, t[1].x, t[1].y, t[2].x, t[2].y };
720
RETURN_ARGS;
721
} break;
722
case Variant::VECTOR4: {
723
const Vector4 v = p_variant;
724
Array args = { v.x, v.y, v.z, v.w };
725
RETURN_ARGS;
726
} break;
727
case Variant::VECTOR4I: {
728
const Vector4i v = p_variant;
729
Array args = { v.x, v.y, v.z, v.w };
730
RETURN_ARGS;
731
} break;
732
case Variant::PLANE: {
733
const Plane p = p_variant;
734
Array args = { p.normal.x, p.normal.y, p.normal.z, p.d };
735
RETURN_ARGS;
736
} break;
737
case Variant::QUATERNION: {
738
const Quaternion q = p_variant;
739
Array args = { q.x, q.y, q.z, q.w };
740
RETURN_ARGS;
741
} break;
742
case Variant::AABB: {
743
const AABB aabb = p_variant;
744
Array args = { aabb.position.x, aabb.position.y, aabb.position.z, aabb.size.x, aabb.size.y, aabb.size.z };
745
RETURN_ARGS;
746
} break;
747
case Variant::BASIS: {
748
const Basis b = p_variant;
749
750
Array args = { b.get_column(0).x, b.get_column(0).y, b.get_column(0).z,
751
b.get_column(1).x, b.get_column(1).y, b.get_column(1).z,
752
b.get_column(2).x, b.get_column(2).y, b.get_column(2).z };
753
754
RETURN_ARGS;
755
} break;
756
case Variant::TRANSFORM3D: {
757
const Transform3D t = p_variant;
758
759
Array args = { t.basis.get_column(0).x, t.basis.get_column(0).y, t.basis.get_column(0).z,
760
t.basis.get_column(1).x, t.basis.get_column(1).y, t.basis.get_column(1).z,
761
t.basis.get_column(2).x, t.basis.get_column(2).y, t.basis.get_column(2).z,
762
t.origin.x, t.origin.y, t.origin.z };
763
764
RETURN_ARGS;
765
} break;
766
case Variant::PROJECTION: {
767
const Projection p = p_variant;
768
769
Array args = { p[0].x, p[0].y, p[0].z, p[0].w,
770
p[1].x, p[1].y, p[1].z, p[1].w,
771
p[2].x, p[2].y, p[2].z, p[2].w,
772
p[3].x, p[3].y, p[3].z, p[3].w };
773
774
RETURN_ARGS;
775
} break;
776
case Variant::COLOR: {
777
const Color c = p_variant;
778
Array args = { c.r, c.g, c.b, c.a };
779
RETURN_ARGS;
780
} break;
781
782
case Variant::OBJECT: {
783
ERR_FAIL_COND_V(!p_full_objects, Variant());
784
785
ERR_FAIL_COND_V_MSG(p_depth > Variant::MAX_RECURSION_DEPTH, Variant(), "Variant is too deep. Bailing.");
786
787
const Object *obj = p_variant.get_validated_object();
788
if (obj == nullptr) {
789
return Variant();
790
}
791
792
ERR_FAIL_COND_V(!ClassDB::can_instantiate(obj->get_class()), Variant());
793
794
List<PropertyInfo> prop_list;
795
obj->get_property_list(&prop_list);
796
797
Array props;
798
for (const PropertyInfo &pi : prop_list) {
799
if (!(pi.usage & PROPERTY_USAGE_STORAGE)) {
800
continue;
801
}
802
803
Variant value;
804
if (pi.name == CoreStringName(script)) {
805
const Ref<Script> script = obj->get_script();
806
if (script.is_valid()) {
807
const String path = script->get_path();
808
ERR_FAIL_COND_V_MSG(path.is_empty() || !path.begins_with("res://"), Variant(), "Failed to encode a path to a custom script.");
809
value = path;
810
}
811
} else {
812
value = obj->get(pi.name);
813
}
814
815
props.push_back(pi.name);
816
props.push_back(_from_native(value, p_full_objects, p_depth + 1));
817
}
818
819
Dictionary ret;
820
ret[TYPE] = obj->get_class();
821
ret[PROPS] = props;
822
return ret;
823
} break;
824
825
case Variant::DICTIONARY: {
826
const Dictionary dict = p_variant;
827
828
Array args;
829
830
Dictionary ret;
831
ret[TYPE] = Variant::get_type_name(p_variant.get_type());
832
if (!_encode_container_type(ret, KEY_TYPE, dict.get_key_type(), p_full_objects)) {
833
return Variant();
834
}
835
if (!_encode_container_type(ret, VALUE_TYPE, dict.get_value_type(), p_full_objects)) {
836
return Variant();
837
}
838
ret[ARGS] = args;
839
840
ERR_FAIL_COND_V_MSG(p_depth > Variant::MAX_RECURSION_DEPTH, ret, "Variant is too deep. Bailing.");
841
842
for (const KeyValue<Variant, Variant> &kv : dict) {
843
args.push_back(_from_native(kv.key, p_full_objects, p_depth + 1));
844
args.push_back(_from_native(kv.value, p_full_objects, p_depth + 1));
845
}
846
847
return ret;
848
} break;
849
850
case Variant::ARRAY: {
851
const Array arr = p_variant;
852
853
Variant ret;
854
Array args;
855
856
if (arr.is_typed()) {
857
Dictionary d;
858
d[TYPE] = Variant::get_type_name(p_variant.get_type());
859
if (!_encode_container_type(d, ELEM_TYPE, arr.get_element_type(), p_full_objects)) {
860
return Variant();
861
}
862
d[ARGS] = args;
863
ret = d;
864
} else {
865
ret = args;
866
}
867
868
ERR_FAIL_COND_V_MSG(p_depth > Variant::MAX_RECURSION_DEPTH, ret, "Variant is too deep. Bailing.");
869
870
for (int i = 0; i < arr.size(); i++) {
871
args.push_back(_from_native(arr[i], p_full_objects, p_depth + 1));
872
}
873
874
return ret;
875
} break;
876
877
case Variant::PACKED_BYTE_ARRAY: {
878
const PackedByteArray arr = p_variant;
879
880
Array args;
881
for (int i = 0; i < arr.size(); i++) {
882
args.push_back(arr[i]);
883
}
884
885
RETURN_ARGS;
886
} break;
887
case Variant::PACKED_INT32_ARRAY: {
888
const PackedInt32Array arr = p_variant;
889
890
Array args;
891
for (int i = 0; i < arr.size(); i++) {
892
args.push_back(arr[i]);
893
}
894
895
RETURN_ARGS;
896
} break;
897
case Variant::PACKED_INT64_ARRAY: {
898
const PackedInt64Array arr = p_variant;
899
900
Array args;
901
for (int i = 0; i < arr.size(); i++) {
902
args.push_back(arr[i]);
903
}
904
905
RETURN_ARGS;
906
} break;
907
case Variant::PACKED_FLOAT32_ARRAY: {
908
const PackedFloat32Array arr = p_variant;
909
910
Array args;
911
for (int i = 0; i < arr.size(); i++) {
912
args.push_back(arr[i]);
913
}
914
915
RETURN_ARGS;
916
} break;
917
case Variant::PACKED_FLOAT64_ARRAY: {
918
const PackedFloat64Array arr = p_variant;
919
920
Array args;
921
for (int i = 0; i < arr.size(); i++) {
922
args.push_back(arr[i]);
923
}
924
925
RETURN_ARGS;
926
} break;
927
case Variant::PACKED_STRING_ARRAY: {
928
const PackedStringArray arr = p_variant;
929
930
Array args;
931
for (int i = 0; i < arr.size(); i++) {
932
args.push_back(arr[i]);
933
}
934
935
RETURN_ARGS;
936
} break;
937
case Variant::PACKED_VECTOR2_ARRAY: {
938
const PackedVector2Array arr = p_variant;
939
940
Array args;
941
for (int i = 0; i < arr.size(); i++) {
942
Vector2 v = arr[i];
943
args.push_back(v.x);
944
args.push_back(v.y);
945
}
946
947
RETURN_ARGS;
948
} break;
949
case Variant::PACKED_VECTOR3_ARRAY: {
950
const PackedVector3Array arr = p_variant;
951
952
Array args;
953
for (int i = 0; i < arr.size(); i++) {
954
Vector3 v = arr[i];
955
args.push_back(v.x);
956
args.push_back(v.y);
957
args.push_back(v.z);
958
}
959
960
RETURN_ARGS;
961
} break;
962
case Variant::PACKED_COLOR_ARRAY: {
963
const PackedColorArray arr = p_variant;
964
965
Array args;
966
for (int i = 0; i < arr.size(); i++) {
967
Color v = arr[i];
968
args.push_back(v.r);
969
args.push_back(v.g);
970
args.push_back(v.b);
971
args.push_back(v.a);
972
}
973
974
RETURN_ARGS;
975
} break;
976
case Variant::PACKED_VECTOR4_ARRAY: {
977
const PackedVector4Array arr = p_variant;
978
979
Array args;
980
for (int i = 0; i < arr.size(); i++) {
981
Vector4 v = arr[i];
982
args.push_back(v.x);
983
args.push_back(v.y);
984
args.push_back(v.z);
985
args.push_back(v.w);
986
}
987
988
RETURN_ARGS;
989
} break;
990
991
case Variant::VARIANT_MAX: {
992
// Nothing to do.
993
} break;
994
}
995
996
#undef RETURN_ARGS
997
998
ERR_FAIL_V_MSG(Variant(), vformat(R"(Unhandled Variant type "%s".)", Variant::get_type_name(p_variant.get_type())));
999
}
1000
1001
static bool _decode_container_type(const Dictionary &p_dict, const String &p_key, ContainerType &r_type, bool p_allow_objects) {
1002
if (!p_dict.has(p_key)) {
1003
return true;
1004
}
1005
1006
const String type_name = p_dict[p_key];
1007
1008
const Variant::Type builtin_type = Variant::get_type_by_name(type_name);
1009
if (builtin_type < Variant::VARIANT_MAX && builtin_type != Variant::OBJECT) {
1010
r_type.builtin_type = builtin_type;
1011
return true;
1012
}
1013
1014
if (ClassDB::class_exists(type_name)) {
1015
ERR_FAIL_COND_V(!p_allow_objects, false);
1016
1017
r_type.builtin_type = Variant::OBJECT;
1018
r_type.class_name = type_name;
1019
return true;
1020
}
1021
1022
if (type_name.begins_with("res://")) {
1023
ERR_FAIL_COND_V(!p_allow_objects, false);
1024
1025
ERR_FAIL_COND_V_MSG(!ResourceLoader::exists(type_name, "Script"), false, vformat(R"(Invalid script path "%s".)", type_name));
1026
const Ref<Script> script = ResourceLoader::load(type_name, "Script");
1027
ERR_FAIL_COND_V_MSG(script.is_null(), false, vformat(R"(Can't load script at path "%s".)", type_name));
1028
1029
r_type.builtin_type = Variant::OBJECT;
1030
r_type.class_name = script->get_instance_base_type();
1031
r_type.script = script;
1032
return true;
1033
}
1034
1035
ERR_FAIL_V_MSG(false, vformat(R"(Invalid type "%s".)", type_name));
1036
}
1037
1038
Variant JSON::_to_native(const Variant &p_json, bool p_allow_objects, int p_depth) {
1039
switch (p_json.get_type()) {
1040
case Variant::NIL:
1041
case Variant::BOOL: {
1042
return p_json;
1043
} break;
1044
1045
case Variant::STRING: {
1046
const String s = p_json;
1047
1048
if (s.begins_with("i:")) {
1049
return s.substr(2).to_int();
1050
} else if (s.begins_with("f:")) {
1051
return s.substr(2).to_float();
1052
} else if (s.begins_with("s:")) {
1053
return s.substr(2);
1054
} else if (s.begins_with("sn:")) {
1055
return StringName(s.substr(3));
1056
} else if (s.begins_with("np:")) {
1057
return NodePath(s.substr(3));
1058
}
1059
1060
ERR_FAIL_V_MSG(Variant(), "Invalid string, the type prefix is not recognized.");
1061
} break;
1062
1063
case Variant::DICTIONARY: {
1064
const Dictionary dict = p_json;
1065
1066
ERR_FAIL_COND_V(!dict.has(TYPE), Variant());
1067
1068
#define LOAD_ARGS() \
1069
ERR_FAIL_COND_V(!dict.has(ARGS), Variant()); \
1070
const Array args = dict[ARGS]
1071
1072
#define LOAD_ARGS_CHECK_SIZE(m_size) \
1073
ERR_FAIL_COND_V(!dict.has(ARGS), Variant()); \
1074
const Array args = dict[ARGS]; \
1075
ERR_FAIL_COND_V(args.size() != (m_size), Variant())
1076
1077
#define LOAD_ARGS_CHECK_FACTOR(m_factor) \
1078
ERR_FAIL_COND_V(!dict.has(ARGS), Variant()); \
1079
const Array args = dict[ARGS]; \
1080
ERR_FAIL_COND_V(args.size() % (m_factor) != 0, Variant())
1081
1082
switch (Variant::get_type_by_name(dict[TYPE])) {
1083
case Variant::NIL:
1084
case Variant::BOOL: {
1085
ERR_FAIL_V_MSG(Variant(), vformat(R"(Unexpected "%s": Variant type "%s" is JSON-compliant.)", TYPE, dict[TYPE]));
1086
} break;
1087
1088
case Variant::INT:
1089
case Variant::FLOAT:
1090
case Variant::STRING:
1091
case Variant::STRING_NAME:
1092
case Variant::NODE_PATH: {
1093
ERR_FAIL_V_MSG(Variant(), vformat(R"(Unexpected "%s": Variant type "%s" must be represented as a string.)", TYPE, dict[TYPE]));
1094
} break;
1095
1096
case Variant::RID: {
1097
return RID();
1098
} break;
1099
case Variant::CALLABLE: {
1100
return Callable();
1101
} break;
1102
case Variant::SIGNAL: {
1103
return Signal();
1104
} break;
1105
1106
case Variant::VECTOR2: {
1107
LOAD_ARGS_CHECK_SIZE(2);
1108
1109
Vector2 v;
1110
v.x = args[0];
1111
v.y = args[1];
1112
1113
return v;
1114
} break;
1115
case Variant::VECTOR2I: {
1116
LOAD_ARGS_CHECK_SIZE(2);
1117
1118
Vector2i v;
1119
v.x = args[0];
1120
v.y = args[1];
1121
1122
return v;
1123
} break;
1124
case Variant::RECT2: {
1125
LOAD_ARGS_CHECK_SIZE(4);
1126
1127
Rect2 r;
1128
r.position = Point2(args[0], args[1]);
1129
r.size = Size2(args[2], args[3]);
1130
1131
return r;
1132
} break;
1133
case Variant::RECT2I: {
1134
LOAD_ARGS_CHECK_SIZE(4);
1135
1136
Rect2i r;
1137
r.position = Point2i(args[0], args[1]);
1138
r.size = Size2i(args[2], args[3]);
1139
1140
return r;
1141
} break;
1142
case Variant::VECTOR3: {
1143
LOAD_ARGS_CHECK_SIZE(3);
1144
1145
Vector3 v;
1146
v.x = args[0];
1147
v.y = args[1];
1148
v.z = args[2];
1149
1150
return v;
1151
} break;
1152
case Variant::VECTOR3I: {
1153
LOAD_ARGS_CHECK_SIZE(3);
1154
1155
Vector3i v;
1156
v.x = args[0];
1157
v.y = args[1];
1158
v.z = args[2];
1159
1160
return v;
1161
} break;
1162
case Variant::TRANSFORM2D: {
1163
LOAD_ARGS_CHECK_SIZE(6);
1164
1165
Transform2D t;
1166
t[0] = Vector2(args[0], args[1]);
1167
t[1] = Vector2(args[2], args[3]);
1168
t[2] = Vector2(args[4], args[5]);
1169
1170
return t;
1171
} break;
1172
case Variant::VECTOR4: {
1173
LOAD_ARGS_CHECK_SIZE(4);
1174
1175
Vector4 v;
1176
v.x = args[0];
1177
v.y = args[1];
1178
v.z = args[2];
1179
v.w = args[3];
1180
1181
return v;
1182
} break;
1183
case Variant::VECTOR4I: {
1184
LOAD_ARGS_CHECK_SIZE(4);
1185
1186
Vector4i v;
1187
v.x = args[0];
1188
v.y = args[1];
1189
v.z = args[2];
1190
v.w = args[3];
1191
1192
return v;
1193
} break;
1194
case Variant::PLANE: {
1195
LOAD_ARGS_CHECK_SIZE(4);
1196
1197
Plane p;
1198
p.normal = Vector3(args[0], args[1], args[2]);
1199
p.d = args[3];
1200
1201
return p;
1202
} break;
1203
case Variant::QUATERNION: {
1204
LOAD_ARGS_CHECK_SIZE(4);
1205
1206
Quaternion q;
1207
q.x = args[0];
1208
q.y = args[1];
1209
q.z = args[2];
1210
q.w = args[3];
1211
1212
return q;
1213
} break;
1214
case Variant::AABB: {
1215
LOAD_ARGS_CHECK_SIZE(6);
1216
1217
AABB aabb;
1218
aabb.position = Vector3(args[0], args[1], args[2]);
1219
aabb.size = Vector3(args[3], args[4], args[5]);
1220
1221
return aabb;
1222
} break;
1223
case Variant::BASIS: {
1224
LOAD_ARGS_CHECK_SIZE(9);
1225
1226
Basis b;
1227
b.set_column(0, Vector3(args[0], args[1], args[2]));
1228
b.set_column(1, Vector3(args[3], args[4], args[5]));
1229
b.set_column(2, Vector3(args[6], args[7], args[8]));
1230
1231
return b;
1232
} break;
1233
case Variant::TRANSFORM3D: {
1234
LOAD_ARGS_CHECK_SIZE(12);
1235
1236
Transform3D t;
1237
t.basis.set_column(0, Vector3(args[0], args[1], args[2]));
1238
t.basis.set_column(1, Vector3(args[3], args[4], args[5]));
1239
t.basis.set_column(2, Vector3(args[6], args[7], args[8]));
1240
t.origin = Vector3(args[9], args[10], args[11]);
1241
1242
return t;
1243
} break;
1244
case Variant::PROJECTION: {
1245
LOAD_ARGS_CHECK_SIZE(16);
1246
1247
Projection p;
1248
p[0] = Vector4(args[0], args[1], args[2], args[3]);
1249
p[1] = Vector4(args[4], args[5], args[6], args[7]);
1250
p[2] = Vector4(args[8], args[9], args[10], args[11]);
1251
p[3] = Vector4(args[12], args[13], args[14], args[15]);
1252
1253
return p;
1254
} break;
1255
case Variant::COLOR: {
1256
LOAD_ARGS_CHECK_SIZE(4);
1257
1258
Color c;
1259
c.r = args[0];
1260
c.g = args[1];
1261
c.b = args[2];
1262
c.a = args[3];
1263
1264
return c;
1265
} break;
1266
1267
case Variant::OBJECT: {
1268
// Nothing to do at this stage. `Object` should be treated as a class, not as a built-in type.
1269
} break;
1270
1271
case Variant::DICTIONARY: {
1272
LOAD_ARGS_CHECK_FACTOR(2);
1273
1274
ContainerType key_type;
1275
if (!_decode_container_type(dict, KEY_TYPE, key_type, p_allow_objects)) {
1276
return Variant();
1277
}
1278
1279
ContainerType value_type;
1280
if (!_decode_container_type(dict, VALUE_TYPE, value_type, p_allow_objects)) {
1281
return Variant();
1282
}
1283
1284
Dictionary ret;
1285
1286
if (key_type.builtin_type != Variant::NIL || value_type.builtin_type != Variant::NIL) {
1287
ret.set_typed(key_type, value_type);
1288
}
1289
1290
ERR_FAIL_COND_V_MSG(p_depth > Variant::MAX_RECURSION_DEPTH, ret, "Variant is too deep. Bailing.");
1291
1292
for (int i = 0; i < args.size() / 2; i++) {
1293
ret[_to_native(args[i * 2 + 0], p_allow_objects, p_depth + 1)] = _to_native(args[i * 2 + 1], p_allow_objects, p_depth + 1);
1294
}
1295
1296
return ret;
1297
} break;
1298
1299
case Variant::ARRAY: {
1300
LOAD_ARGS();
1301
1302
ContainerType elem_type;
1303
if (!_decode_container_type(dict, ELEM_TYPE, elem_type, p_allow_objects)) {
1304
return Variant();
1305
}
1306
1307
Array ret;
1308
1309
if (elem_type.builtin_type != Variant::NIL) {
1310
ret.set_typed(elem_type);
1311
}
1312
1313
ERR_FAIL_COND_V_MSG(p_depth > Variant::MAX_RECURSION_DEPTH, ret, "Variant is too deep. Bailing.");
1314
1315
ret.resize(args.size());
1316
for (int i = 0; i < args.size(); i++) {
1317
ret[i] = _to_native(args[i], p_allow_objects, p_depth + 1);
1318
}
1319
1320
return ret;
1321
} break;
1322
1323
case Variant::PACKED_BYTE_ARRAY: {
1324
LOAD_ARGS();
1325
1326
PackedByteArray arr;
1327
arr.resize(args.size());
1328
for (int i = 0; i < arr.size(); i++) {
1329
arr.write[i] = args[i];
1330
}
1331
1332
return arr;
1333
} break;
1334
case Variant::PACKED_INT32_ARRAY: {
1335
LOAD_ARGS();
1336
1337
PackedInt32Array arr;
1338
arr.resize(args.size());
1339
for (int i = 0; i < arr.size(); i++) {
1340
arr.write[i] = args[i];
1341
}
1342
1343
return arr;
1344
} break;
1345
case Variant::PACKED_INT64_ARRAY: {
1346
LOAD_ARGS();
1347
1348
PackedInt64Array arr;
1349
arr.resize(args.size());
1350
for (int i = 0; i < arr.size(); i++) {
1351
arr.write[i] = args[i];
1352
}
1353
1354
return arr;
1355
} break;
1356
case Variant::PACKED_FLOAT32_ARRAY: {
1357
LOAD_ARGS();
1358
1359
PackedFloat32Array arr;
1360
arr.resize(args.size());
1361
for (int i = 0; i < arr.size(); i++) {
1362
arr.write[i] = args[i];
1363
}
1364
1365
return arr;
1366
} break;
1367
case Variant::PACKED_FLOAT64_ARRAY: {
1368
LOAD_ARGS();
1369
1370
PackedFloat64Array arr;
1371
arr.resize(args.size());
1372
for (int i = 0; i < arr.size(); i++) {
1373
arr.write[i] = args[i];
1374
}
1375
1376
return arr;
1377
} break;
1378
case Variant::PACKED_STRING_ARRAY: {
1379
LOAD_ARGS();
1380
1381
PackedStringArray arr;
1382
arr.resize(args.size());
1383
for (int i = 0; i < arr.size(); i++) {
1384
arr.write[i] = args[i];
1385
}
1386
1387
return arr;
1388
} break;
1389
case Variant::PACKED_VECTOR2_ARRAY: {
1390
LOAD_ARGS_CHECK_FACTOR(2);
1391
1392
PackedVector2Array arr;
1393
arr.resize(args.size() / 2);
1394
for (int i = 0; i < arr.size(); i++) {
1395
arr.write[i] = Vector2(args[i * 2 + 0], args[i * 2 + 1]);
1396
}
1397
1398
return arr;
1399
} break;
1400
case Variant::PACKED_VECTOR3_ARRAY: {
1401
LOAD_ARGS_CHECK_FACTOR(3);
1402
1403
PackedVector3Array arr;
1404
arr.resize(args.size() / 3);
1405
for (int i = 0; i < arr.size(); i++) {
1406
arr.write[i] = Vector3(args[i * 3 + 0], args[i * 3 + 1], args[i * 3 + 2]);
1407
}
1408
1409
return arr;
1410
} break;
1411
case Variant::PACKED_COLOR_ARRAY: {
1412
LOAD_ARGS_CHECK_FACTOR(4);
1413
1414
PackedColorArray arr;
1415
arr.resize(args.size() / 4);
1416
for (int i = 0; i < arr.size(); i++) {
1417
arr.write[i] = Color(args[i * 4 + 0], args[i * 4 + 1], args[i * 4 + 2], args[i * 4 + 3]);
1418
}
1419
1420
return arr;
1421
} break;
1422
case Variant::PACKED_VECTOR4_ARRAY: {
1423
LOAD_ARGS_CHECK_FACTOR(4);
1424
1425
PackedVector4Array arr;
1426
arr.resize(args.size() / 4);
1427
for (int i = 0; i < arr.size(); i++) {
1428
arr.write[i] = Vector4(args[i * 4 + 0], args[i * 4 + 1], args[i * 4 + 2], args[i * 4 + 3]);
1429
}
1430
1431
return arr;
1432
} break;
1433
1434
case Variant::VARIANT_MAX: {
1435
// Nothing to do.
1436
} break;
1437
}
1438
1439
#undef LOAD_ARGS
1440
#undef LOAD_ARGS_CHECK_SIZE
1441
#undef LOAD_ARGS_CHECK_FACTOR
1442
1443
if (ClassDB::class_exists(dict[TYPE])) {
1444
ERR_FAIL_COND_V(!p_allow_objects, Variant());
1445
1446
ERR_FAIL_COND_V_MSG(p_depth > Variant::MAX_RECURSION_DEPTH, Variant(), "Variant is too deep. Bailing.");
1447
1448
ERR_FAIL_COND_V(!dict.has(PROPS), Variant());
1449
const Array props = dict[PROPS];
1450
ERR_FAIL_COND_V(props.size() % 2 != 0, Variant());
1451
1452
ERR_FAIL_COND_V(!ClassDB::can_instantiate(dict[TYPE]), Variant());
1453
1454
Object *obj = ClassDB::instantiate(dict[TYPE]);
1455
ERR_FAIL_NULL_V(obj, Variant());
1456
1457
// Avoid premature free `RefCounted`. This must be done before properties are initialized,
1458
// since script functions (setters, implicit initializer) may be called. See GH-68666.
1459
Variant variant;
1460
if (Object::cast_to<RefCounted>(obj)) {
1461
const Ref<RefCounted> ref = Ref<RefCounted>(Object::cast_to<RefCounted>(obj));
1462
variant = ref;
1463
} else {
1464
variant = obj;
1465
}
1466
1467
for (int i = 0; i < props.size() / 2; i++) {
1468
const StringName name = props[i * 2 + 0];
1469
const Variant value = _to_native(props[i * 2 + 1], p_allow_objects, p_depth + 1);
1470
1471
if (name == CoreStringName(script) && value.get_type() != Variant::NIL) {
1472
const String path = value;
1473
ERR_FAIL_COND_V_MSG(path.is_empty() || !path.begins_with("res://") || !ResourceLoader::exists(path, "Script"),
1474
Variant(),
1475
vformat(R"(Invalid script path "%s".)", path));
1476
1477
const Ref<Script> script = ResourceLoader::load(path, "Script");
1478
ERR_FAIL_COND_V_MSG(script.is_null(), Variant(), vformat(R"(Can't load script at path "%s".)", path));
1479
1480
obj->set_script(script);
1481
} else {
1482
obj->set(name, value);
1483
}
1484
}
1485
1486
return variant;
1487
}
1488
1489
ERR_FAIL_V_MSG(Variant(), vformat(R"(Invalid type "%s".)", dict[TYPE]));
1490
} break;
1491
1492
case Variant::ARRAY: {
1493
ERR_FAIL_COND_V_MSG(p_depth > Variant::MAX_RECURSION_DEPTH, Array(), "Variant is too deep. Bailing.");
1494
1495
const Array arr = p_json;
1496
1497
Array ret;
1498
ret.resize(arr.size());
1499
for (int i = 0; i < arr.size(); i++) {
1500
ret[i] = _to_native(arr[i], p_allow_objects, p_depth + 1);
1501
}
1502
1503
return ret;
1504
} break;
1505
1506
default: {
1507
// Nothing to do.
1508
} break;
1509
}
1510
1511
ERR_FAIL_V_MSG(Variant(), vformat(R"(Variant type "%s" is not JSON-compliant.)", Variant::get_type_name(p_json.get_type())));
1512
}
1513
1514
#undef TYPE
1515
#undef ELEM_TYPE
1516
#undef KEY_TYPE
1517
#undef VALUE_TYPE
1518
#undef ARGS
1519
#undef PROPS
1520
1521
////////////
1522
1523
Ref<Resource> ResourceFormatLoaderJSON::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
1524
if (r_error) {
1525
*r_error = ERR_FILE_CANT_OPEN;
1526
}
1527
1528
if (!FileAccess::exists(p_path)) {
1529
*r_error = ERR_FILE_NOT_FOUND;
1530
return Ref<Resource>();
1531
}
1532
1533
Ref<JSON> json;
1534
json.instantiate();
1535
1536
Error err = json->parse(FileAccess::get_file_as_string(p_path), Engine::get_singleton()->is_editor_hint());
1537
if (err != OK) {
1538
String err_text = "Error parsing JSON file at '" + p_path + "', on line " + itos(json->get_error_line()) + ": " + json->get_error_message();
1539
1540
if (Engine::get_singleton()->is_editor_hint()) {
1541
// If running on editor, still allow opening the JSON so the code editor can edit it.
1542
WARN_PRINT(err_text);
1543
} else {
1544
if (r_error) {
1545
*r_error = err;
1546
}
1547
ERR_PRINT(err_text);
1548
return Ref<Resource>();
1549
}
1550
}
1551
1552
if (r_error) {
1553
*r_error = OK;
1554
}
1555
1556
return json;
1557
}
1558
1559
void ResourceFormatLoaderJSON::get_recognized_extensions(List<String> *p_extensions) const {
1560
p_extensions->push_back("json");
1561
}
1562
1563
bool ResourceFormatLoaderJSON::handles_type(const String &p_type) const {
1564
return (p_type == "JSON");
1565
}
1566
1567
String ResourceFormatLoaderJSON::get_resource_type(const String &p_path) const {
1568
String el = p_path.get_extension().to_lower();
1569
if (el == "json") {
1570
return "JSON";
1571
}
1572
return "";
1573
}
1574
1575
Error ResourceFormatSaverJSON::save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags) {
1576
Ref<JSON> json = p_resource;
1577
ERR_FAIL_COND_V(json.is_null(), ERR_INVALID_PARAMETER);
1578
1579
String source = json->get_parsed_text().is_empty() ? JSON::stringify(json->get_data(), "\t", false, true) : json->get_parsed_text();
1580
1581
Error err;
1582
Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::WRITE, &err);
1583
1584
ERR_FAIL_COND_V_MSG(err, err, vformat("Cannot save json '%s'.", p_path));
1585
1586
file->store_string(source);
1587
if (file->get_error() != OK && file->get_error() != ERR_FILE_EOF) {
1588
return ERR_CANT_CREATE;
1589
}
1590
1591
return OK;
1592
}
1593
1594
void ResourceFormatSaverJSON::get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const {
1595
Ref<JSON> json = p_resource;
1596
if (json.is_valid()) {
1597
p_extensions->push_back("json");
1598
}
1599
}
1600
1601
bool ResourceFormatSaverJSON::recognize(const Ref<Resource> &p_resource) const {
1602
return p_resource->get_class_name() == "JSON"; //only json, not inherited
1603
}
1604
1605