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/string/print_string.h"
35
36const char *JSON::tk_name[TK_MAX] = {
37 "'{'",
38 "'}'",
39 "'['",
40 "']'",
41 "identifier",
42 "string",
43 "number",
44 "':'",
45 "','",
46 "EOF",
47};
48
49String JSON::_make_indent(const String &p_indent, int p_size) {
50 return p_indent.repeat(p_size);
51}
52
53String JSON::_stringify(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) {
54 ERR_FAIL_COND_V_MSG(p_cur_indent > Variant::MAX_RECURSION_DEPTH, "...", "JSON structure is too deep. Bailing.");
55
56 String colon = ":";
57 String end_statement = "";
58
59 if (!p_indent.is_empty()) {
60 colon += " ";
61 end_statement += "\n";
62 }
63
64 switch (p_var.get_type()) {
65 case Variant::NIL:
66 return "null";
67 case Variant::BOOL:
68 return p_var.operator bool() ? "true" : "false";
69 case Variant::INT:
70 return itos(p_var);
71 case Variant::FLOAT: {
72 double num = p_var;
73 if (p_full_precision) {
74 // Store unreliable digits (17) instead of just reliable
75 // digits (14) so that the value can be decoded exactly.
76 return String::num(num, 17 - (int)floor(log10(num)));
77 } else {
78 // Store only reliable digits (14) by default.
79 return String::num(num, 14 - (int)floor(log10(num)));
80 }
81 }
82 case Variant::PACKED_INT32_ARRAY:
83 case Variant::PACKED_INT64_ARRAY:
84 case Variant::PACKED_FLOAT32_ARRAY:
85 case Variant::PACKED_FLOAT64_ARRAY:
86 case Variant::PACKED_STRING_ARRAY:
87 case Variant::ARRAY: {
88 Array a = p_var;
89 if (a.size() == 0) {
90 return "[]";
91 }
92 String s = "[";
93 s += end_statement;
94
95 ERR_FAIL_COND_V_MSG(p_markers.has(a.id()), "\"[...]\"", "Converting circular structure to JSON.");
96 p_markers.insert(a.id());
97
98 for (int i = 0; i < a.size(); i++) {
99 if (i > 0) {
100 s += ",";
101 s += end_statement;
102 }
103 s += _make_indent(p_indent, p_cur_indent + 1) + _stringify(a[i], p_indent, p_cur_indent + 1, p_sort_keys, p_markers);
104 }
105 s += end_statement + _make_indent(p_indent, p_cur_indent) + "]";
106 p_markers.erase(a.id());
107 return s;
108 }
109 case Variant::DICTIONARY: {
110 String s = "{";
111 s += end_statement;
112 Dictionary d = p_var;
113
114 ERR_FAIL_COND_V_MSG(p_markers.has(d.id()), "\"{...}\"", "Converting circular structure to JSON.");
115 p_markers.insert(d.id());
116
117 List<Variant> keys;
118 d.get_key_list(&keys);
119
120 if (p_sort_keys) {
121 keys.sort();
122 }
123
124 bool first_key = true;
125 for (const Variant &E : keys) {
126 if (first_key) {
127 first_key = false;
128 } else {
129 s += ",";
130 s += end_statement;
131 }
132 s += _make_indent(p_indent, p_cur_indent + 1) + _stringify(String(E), p_indent, p_cur_indent + 1, p_sort_keys, p_markers);
133 s += colon;
134 s += _stringify(d[E], p_indent, p_cur_indent + 1, p_sort_keys, p_markers);
135 }
136
137 s += end_statement + _make_indent(p_indent, p_cur_indent) + "}";
138 p_markers.erase(d.id());
139 return s;
140 }
141 default:
142 return "\"" + String(p_var).json_escape() + "\"";
143 }
144}
145
146Error JSON::_get_token(const char32_t *p_str, int &index, int p_len, Token &r_token, int &line, String &r_err_str) {
147 while (p_len > 0) {
148 switch (p_str[index]) {
149 case '\n': {
150 line++;
151 index++;
152 break;
153 }
154 case 0: {
155 r_token.type = TK_EOF;
156 return OK;
157 } break;
158 case '{': {
159 r_token.type = TK_CURLY_BRACKET_OPEN;
160 index++;
161 return OK;
162 }
163 case '}': {
164 r_token.type = TK_CURLY_BRACKET_CLOSE;
165 index++;
166 return OK;
167 }
168 case '[': {
169 r_token.type = TK_BRACKET_OPEN;
170 index++;
171 return OK;
172 }
173 case ']': {
174 r_token.type = TK_BRACKET_CLOSE;
175 index++;
176 return OK;
177 }
178 case ':': {
179 r_token.type = TK_COLON;
180 index++;
181 return OK;
182 }
183 case ',': {
184 r_token.type = TK_COMMA;
185 index++;
186 return OK;
187 }
188 case '"': {
189 index++;
190 String str;
191 while (true) {
192 if (p_str[index] == 0) {
193 r_err_str = "Unterminated String";
194 return ERR_PARSE_ERROR;
195 } else if (p_str[index] == '"') {
196 index++;
197 break;
198 } else if (p_str[index] == '\\') {
199 //escaped characters...
200 index++;
201 char32_t next = p_str[index];
202 if (next == 0) {
203 r_err_str = "Unterminated String";
204 return ERR_PARSE_ERROR;
205 }
206 char32_t res = 0;
207
208 switch (next) {
209 case 'b':
210 res = 8;
211 break;
212 case 't':
213 res = 9;
214 break;
215 case 'n':
216 res = 10;
217 break;
218 case 'f':
219 res = 12;
220 break;
221 case 'r':
222 res = 13;
223 break;
224 case 'u': {
225 // hex number
226 for (int j = 0; j < 4; j++) {
227 char32_t c = p_str[index + j + 1];
228 if (c == 0) {
229 r_err_str = "Unterminated String";
230 return ERR_PARSE_ERROR;
231 }
232 if (!is_hex_digit(c)) {
233 r_err_str = "Malformed hex constant in string";
234 return ERR_PARSE_ERROR;
235 }
236 char32_t v;
237 if (is_digit(c)) {
238 v = c - '0';
239 } else if (c >= 'a' && c <= 'f') {
240 v = c - 'a';
241 v += 10;
242 } else if (c >= 'A' && c <= 'F') {
243 v = c - 'A';
244 v += 10;
245 } else {
246 ERR_PRINT("Bug parsing hex constant.");
247 v = 0;
248 }
249
250 res <<= 4;
251 res |= v;
252 }
253 index += 4; //will add at the end anyway
254
255 if ((res & 0xfffffc00) == 0xd800) {
256 if (p_str[index + 1] != '\\' || p_str[index + 2] != 'u') {
257 r_err_str = "Invalid UTF-16 sequence in string, unpaired lead surrogate";
258 return ERR_PARSE_ERROR;
259 }
260 index += 2;
261 char32_t trail = 0;
262 for (int j = 0; j < 4; j++) {
263 char32_t c = p_str[index + j + 1];
264 if (c == 0) {
265 r_err_str = "Unterminated String";
266 return ERR_PARSE_ERROR;
267 }
268 if (!is_hex_digit(c)) {
269 r_err_str = "Malformed hex constant in string";
270 return ERR_PARSE_ERROR;
271 }
272 char32_t v;
273 if (is_digit(c)) {
274 v = c - '0';
275 } else if (c >= 'a' && c <= 'f') {
276 v = c - 'a';
277 v += 10;
278 } else if (c >= 'A' && c <= 'F') {
279 v = c - 'A';
280 v += 10;
281 } else {
282 ERR_PRINT("Bug parsing hex constant.");
283 v = 0;
284 }
285
286 trail <<= 4;
287 trail |= v;
288 }
289 if ((trail & 0xfffffc00) == 0xdc00) {
290 res = (res << 10UL) + trail - ((0xd800 << 10UL) + 0xdc00 - 0x10000);
291 index += 4; //will add at the end anyway
292 } else {
293 r_err_str = "Invalid UTF-16 sequence in string, unpaired lead surrogate";
294 return ERR_PARSE_ERROR;
295 }
296 } else if ((res & 0xfffffc00) == 0xdc00) {
297 r_err_str = "Invalid UTF-16 sequence in string, unpaired trail surrogate";
298 return ERR_PARSE_ERROR;
299 }
300
301 } break;
302 case '"':
303 case '\\':
304 case '/': {
305 res = next;
306 } break;
307 default: {
308 r_err_str = "Invalid escape sequence.";
309 return ERR_PARSE_ERROR;
310 }
311 }
312
313 str += res;
314
315 } else {
316 if (p_str[index] == '\n') {
317 line++;
318 }
319 str += p_str[index];
320 }
321 index++;
322 }
323
324 r_token.type = TK_STRING;
325 r_token.value = str;
326 return OK;
327
328 } break;
329 default: {
330 if (p_str[index] <= 32) {
331 index++;
332 break;
333 }
334
335 if (p_str[index] == '-' || is_digit(p_str[index])) {
336 //a number
337 const char32_t *rptr;
338 double number = String::to_float(&p_str[index], &rptr);
339 index += (rptr - &p_str[index]);
340 r_token.type = TK_NUMBER;
341 r_token.value = number;
342 return OK;
343
344 } else if (is_ascii_char(p_str[index])) {
345 String id;
346
347 while (is_ascii_char(p_str[index])) {
348 id += p_str[index];
349 index++;
350 }
351
352 r_token.type = TK_IDENTIFIER;
353 r_token.value = id;
354 return OK;
355 } else {
356 r_err_str = "Unexpected character.";
357 return ERR_PARSE_ERROR;
358 }
359 }
360 }
361 }
362
363 return ERR_PARSE_ERROR;
364}
365
366Error 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) {
367 if (p_depth > Variant::MAX_RECURSION_DEPTH) {
368 r_err_str = "JSON structure is too deep. Bailing.";
369 return ERR_OUT_OF_MEMORY;
370 }
371
372 if (token.type == TK_CURLY_BRACKET_OPEN) {
373 Dictionary d;
374 Error err = _parse_object(d, p_str, index, p_len, line, p_depth + 1, r_err_str);
375 if (err) {
376 return err;
377 }
378 value = d;
379 } else if (token.type == TK_BRACKET_OPEN) {
380 Array a;
381 Error err = _parse_array(a, p_str, index, p_len, line, p_depth + 1, r_err_str);
382 if (err) {
383 return err;
384 }
385 value = a;
386 } else if (token.type == TK_IDENTIFIER) {
387 String id = token.value;
388 if (id == "true") {
389 value = true;
390 } else if (id == "false") {
391 value = false;
392 } else if (id == "null") {
393 value = Variant();
394 } else {
395 r_err_str = "Expected 'true','false' or 'null', got '" + id + "'.";
396 return ERR_PARSE_ERROR;
397 }
398 } else if (token.type == TK_NUMBER) {
399 value = token.value;
400 } else if (token.type == TK_STRING) {
401 value = token.value;
402 } else {
403 r_err_str = "Expected value, got " + String(tk_name[token.type]) + ".";
404 return ERR_PARSE_ERROR;
405 }
406
407 return OK;
408}
409
410Error JSON::_parse_array(Array &array, const char32_t *p_str, int &index, int p_len, int &line, int p_depth, String &r_err_str) {
411 Token token;
412 bool need_comma = false;
413
414 while (index < p_len) {
415 Error err = _get_token(p_str, index, p_len, token, line, r_err_str);
416 if (err != OK) {
417 return err;
418 }
419
420 if (token.type == TK_BRACKET_CLOSE) {
421 return OK;
422 }
423
424 if (need_comma) {
425 if (token.type != TK_COMMA) {
426 r_err_str = "Expected ','";
427 return ERR_PARSE_ERROR;
428 } else {
429 need_comma = false;
430 continue;
431 }
432 }
433
434 Variant v;
435 err = _parse_value(v, token, p_str, index, p_len, line, p_depth, r_err_str);
436 if (err) {
437 return err;
438 }
439
440 array.push_back(v);
441 need_comma = true;
442 }
443
444 r_err_str = "Expected ']'";
445 return ERR_PARSE_ERROR;
446}
447
448Error JSON::_parse_object(Dictionary &object, const char32_t *p_str, int &index, int p_len, int &line, int p_depth, String &r_err_str) {
449 bool at_key = true;
450 String key;
451 Token token;
452 bool need_comma = false;
453
454 while (index < p_len) {
455 if (at_key) {
456 Error err = _get_token(p_str, index, p_len, token, line, r_err_str);
457 if (err != OK) {
458 return err;
459 }
460
461 if (token.type == TK_CURLY_BRACKET_CLOSE) {
462 return OK;
463 }
464
465 if (need_comma) {
466 if (token.type != TK_COMMA) {
467 r_err_str = "Expected '}' or ','";
468 return ERR_PARSE_ERROR;
469 } else {
470 need_comma = false;
471 continue;
472 }
473 }
474
475 if (token.type != TK_STRING) {
476 r_err_str = "Expected key";
477 return ERR_PARSE_ERROR;
478 }
479
480 key = token.value;
481 err = _get_token(p_str, index, p_len, token, line, r_err_str);
482 if (err != OK) {
483 return err;
484 }
485 if (token.type != TK_COLON) {
486 r_err_str = "Expected ':'";
487 return ERR_PARSE_ERROR;
488 }
489 at_key = false;
490 } else {
491 Error err = _get_token(p_str, index, p_len, token, line, r_err_str);
492 if (err != OK) {
493 return err;
494 }
495
496 Variant v;
497 err = _parse_value(v, token, p_str, index, p_len, line, p_depth, r_err_str);
498 if (err) {
499 return err;
500 }
501 object[key] = v;
502 need_comma = true;
503 at_key = true;
504 }
505 }
506
507 r_err_str = "Expected '}'";
508 return ERR_PARSE_ERROR;
509}
510
511void JSON::set_data(const Variant &p_data) {
512 data = p_data;
513 text.clear();
514}
515
516Error JSON::_parse_string(const String &p_json, Variant &r_ret, String &r_err_str, int &r_err_line) {
517 const char32_t *str = p_json.ptr();
518 int idx = 0;
519 int len = p_json.length();
520 Token token;
521 r_err_line = 0;
522 String aux_key;
523
524 Error err = _get_token(str, idx, len, token, r_err_line, r_err_str);
525 if (err) {
526 return err;
527 }
528
529 err = _parse_value(r_ret, token, str, idx, len, r_err_line, 0, r_err_str);
530
531 // Check if EOF is reached
532 // or it's a type of the next token.
533 if (err == OK && idx < len) {
534 err = _get_token(str, idx, len, token, r_err_line, r_err_str);
535
536 if (err || token.type != TK_EOF) {
537 r_err_str = "Expected 'EOF'";
538 // Reset return value to empty `Variant`
539 r_ret = Variant();
540 return ERR_PARSE_ERROR;
541 }
542 }
543
544 return err;
545}
546
547Error JSON::parse(const String &p_json_string, bool p_keep_text) {
548 Error err = _parse_string(p_json_string, data, err_str, err_line);
549 if (err == Error::OK) {
550 err_line = 0;
551 }
552 if (p_keep_text) {
553 text = p_json_string;
554 }
555 return err;
556}
557
558String JSON::get_parsed_text() const {
559 return text;
560}
561
562String JSON::stringify(const Variant &p_var, const String &p_indent, bool p_sort_keys, bool p_full_precision) {
563 Ref<JSON> jason;
564 jason.instantiate();
565 HashSet<const void *> markers;
566 return jason->_stringify(p_var, p_indent, 0, p_sort_keys, markers, p_full_precision);
567}
568
569Variant JSON::parse_string(const String &p_json_string) {
570 Ref<JSON> jason;
571 jason.instantiate();
572 Error error = jason->parse(p_json_string);
573 ERR_FAIL_COND_V_MSG(error != Error::OK, Variant(), vformat("Parse JSON failed. Error at line %d: %s", jason->get_error_line(), jason->get_error_message()));
574 return jason->get_data();
575}
576
577void JSON::_bind_methods() {
578 ClassDB::bind_static_method("JSON", D_METHOD("stringify", "data", "indent", "sort_keys", "full_precision"), &JSON::stringify, DEFVAL(""), DEFVAL(true), DEFVAL(false));
579 ClassDB::bind_static_method("JSON", D_METHOD("parse_string", "json_string"), &JSON::parse_string);
580 ClassDB::bind_method(D_METHOD("parse", "json_text", "keep_text"), &JSON::parse, DEFVAL(false));
581
582 ClassDB::bind_method(D_METHOD("get_data"), &JSON::get_data);
583 ClassDB::bind_method(D_METHOD("set_data", "data"), &JSON::set_data);
584 ClassDB::bind_method(D_METHOD("get_parsed_text"), &JSON::get_parsed_text);
585 ClassDB::bind_method(D_METHOD("get_error_line"), &JSON::get_error_line);
586 ClassDB::bind_method(D_METHOD("get_error_message"), &JSON::get_error_message);
587
588 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.
589}
590
591////
592
593////////////
594
595Ref<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) {
596 if (r_error) {
597 *r_error = ERR_FILE_CANT_OPEN;
598 }
599
600 if (!FileAccess::exists(p_path)) {
601 *r_error = ERR_FILE_NOT_FOUND;
602 return Ref<Resource>();
603 }
604
605 Ref<JSON> json;
606 json.instantiate();
607
608 Error err = json->parse(FileAccess::get_file_as_string(p_path), Engine::get_singleton()->is_editor_hint());
609 if (err != OK) {
610 String err_text = "Error parsing JSON file at '" + p_path + "', on line " + itos(json->get_error_line()) + ": " + json->get_error_message();
611
612 if (Engine::get_singleton()->is_editor_hint()) {
613 // If running on editor, still allow opening the JSON so the code editor can edit it.
614 WARN_PRINT(err_text);
615 } else {
616 if (r_error) {
617 *r_error = err;
618 }
619 ERR_PRINT(err_text);
620 return Ref<Resource>();
621 }
622 }
623
624 if (r_error) {
625 *r_error = OK;
626 }
627
628 return json;
629}
630
631void ResourceFormatLoaderJSON::get_recognized_extensions(List<String> *p_extensions) const {
632 p_extensions->push_back("json");
633}
634
635bool ResourceFormatLoaderJSON::handles_type(const String &p_type) const {
636 return (p_type == "JSON");
637}
638
639String ResourceFormatLoaderJSON::get_resource_type(const String &p_path) const {
640 String el = p_path.get_extension().to_lower();
641 if (el == "json") {
642 return "JSON";
643 }
644 return "";
645}
646
647Error ResourceFormatSaverJSON::save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags) {
648 Ref<JSON> json = p_resource;
649 ERR_FAIL_COND_V(json.is_null(), ERR_INVALID_PARAMETER);
650
651 String source = json->get_parsed_text().is_empty() ? JSON::stringify(json->get_data(), "\t", false, true) : json->get_parsed_text();
652
653 Error err;
654 Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::WRITE, &err);
655
656 ERR_FAIL_COND_V_MSG(err, err, "Cannot save json '" + p_path + "'.");
657
658 file->store_string(source);
659 if (file->get_error() != OK && file->get_error() != ERR_FILE_EOF) {
660 return ERR_CANT_CREATE;
661 }
662
663 return OK;
664}
665
666void ResourceFormatSaverJSON::get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const {
667 Ref<JSON> json = p_resource;
668 if (json.is_valid()) {
669 p_extensions->push_back("json");
670 }
671}
672
673bool ResourceFormatSaverJSON::recognize(const Ref<Resource> &p_resource) const {
674 return p_resource->get_class_name() == "JSON"; //only json, not inherited
675}
676