1 /*************************************************************************/
2 /* variant_parser.cpp */
3 /*************************************************************************/
4 /* This file is part of: */
5 /* GODOT ENGINE */
6 /* https://godotengine.org */
7 /*************************************************************************/
8 /* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
9 /* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
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/io/resource_loader.h"
34 #include "core/os/input_event.h"
35 #include "core/os/keyboard.h"
36 #include "core/string_buffer.h"
37
get_char()38 CharType VariantParser::StreamFile::get_char() {
39
40 return f->get_8();
41 }
42
is_utf8() const43 bool VariantParser::StreamFile::is_utf8() const {
44
45 return true;
46 }
is_eof() const47 bool VariantParser::StreamFile::is_eof() const {
48
49 return f->eof_reached();
50 }
51
get_char()52 CharType VariantParser::StreamString::get_char() {
53
54 if (pos > s.length()) {
55 return 0;
56 } else if (pos == s.length()) {
57 // You need to try to read again when you have reached the end for EOF to be reported,
58 // so this works the same as files (like StreamFile does)
59 pos++;
60 return 0;
61 } else {
62 return s[pos++];
63 }
64 }
65
is_utf8() const66 bool VariantParser::StreamString::is_utf8() const {
67 return false;
68 }
is_eof() const69 bool VariantParser::StreamString::is_eof() const {
70 return pos > s.length();
71 }
72
73 /////////////////////////////////////////////////////////////////////////////////////////////////
74
75 const char *VariantParser::tk_name[TK_MAX] = {
76 "'{'",
77 "'}'",
78 "'['",
79 "']'",
80 "'('",
81 "')'",
82 "identifier",
83 "string",
84 "number",
85 "color",
86 "':'",
87 "','",
88 "'.'",
89 "'='",
90 "EOF",
91 "ERROR"
92 };
93
get_token(Stream * p_stream,Token & r_token,int & line,String & r_err_str)94 Error VariantParser::get_token(Stream *p_stream, Token &r_token, int &line, String &r_err_str) {
95
96 while (true) {
97
98 CharType cchar;
99 if (p_stream->saved) {
100 cchar = p_stream->saved;
101 p_stream->saved = 0;
102 } else {
103 cchar = p_stream->get_char();
104 if (p_stream->is_eof()) {
105 r_token.type = TK_EOF;
106 return OK;
107 }
108 }
109
110 switch (cchar) {
111
112 case '\n': {
113
114 line++;
115 break;
116 };
117 case 0: {
118 r_token.type = TK_EOF;
119 return OK;
120 } break;
121 case '{': {
122
123 r_token.type = TK_CURLY_BRACKET_OPEN;
124 return OK;
125 };
126 case '}': {
127
128 r_token.type = TK_CURLY_BRACKET_CLOSE;
129 return OK;
130 };
131 case '[': {
132
133 r_token.type = TK_BRACKET_OPEN;
134 return OK;
135 };
136 case ']': {
137
138 r_token.type = TK_BRACKET_CLOSE;
139 return OK;
140 };
141 case '(': {
142
143 r_token.type = TK_PARENTHESIS_OPEN;
144 return OK;
145 };
146 case ')': {
147
148 r_token.type = TK_PARENTHESIS_CLOSE;
149 return OK;
150 };
151 case ':': {
152
153 r_token.type = TK_COLON;
154 return OK;
155 };
156 case ';': {
157
158 while (true) {
159 CharType ch = p_stream->get_char();
160 if (p_stream->is_eof()) {
161 r_token.type = TK_EOF;
162 return OK;
163 }
164 if (ch == '\n')
165 break;
166 }
167
168 break;
169 };
170 case ',': {
171
172 r_token.type = TK_COMMA;
173 return OK;
174 };
175 case '.': {
176
177 r_token.type = TK_PERIOD;
178 return OK;
179 };
180 case '=': {
181
182 r_token.type = TK_EQUAL;
183 return OK;
184 };
185 case '#': {
186
187 StringBuffer<> color_str;
188 color_str += '#';
189 while (true) {
190 CharType ch = p_stream->get_char();
191 if (p_stream->is_eof()) {
192 r_token.type = TK_EOF;
193 return OK;
194 } else if ((ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F')) {
195 color_str += ch;
196
197 } else {
198 p_stream->saved = ch;
199 break;
200 }
201 }
202
203 r_token.value = Color::html(color_str.as_string());
204 r_token.type = TK_COLOR;
205 return OK;
206 };
207 case '"': {
208
209 String str;
210 while (true) {
211
212 CharType ch = p_stream->get_char();
213
214 if (ch == 0) {
215 r_err_str = "Unterminated String";
216 r_token.type = TK_ERROR;
217 return ERR_PARSE_ERROR;
218 } else if (ch == '"') {
219 break;
220 } else if (ch == '\\') {
221 //escaped characters...
222 CharType next = p_stream->get_char();
223 if (next == 0) {
224 r_err_str = "Unterminated String";
225 r_token.type = TK_ERROR;
226 return ERR_PARSE_ERROR;
227 }
228 CharType res = 0;
229
230 switch (next) {
231
232 case 'b': res = 8; break;
233 case 't': res = 9; break;
234 case 'n': res = 10; break;
235 case 'f': res = 12; break;
236 case 'r': res = 13; break;
237 case 'u': {
238 //hexnumbarh - oct is deprecated
239
240 for (int j = 0; j < 4; j++) {
241 CharType c = p_stream->get_char();
242 if (c == 0) {
243 r_err_str = "Unterminated String";
244 r_token.type = TK_ERROR;
245 return ERR_PARSE_ERROR;
246 }
247 if (!((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'))) {
248
249 r_err_str = "Malformed hex constant in string";
250 r_token.type = TK_ERROR;
251 return ERR_PARSE_ERROR;
252 }
253 CharType v;
254 if (c >= '0' && c <= '9') {
255 v = c - '0';
256 } else if (c >= 'a' && c <= 'f') {
257 v = c - 'a';
258 v += 10;
259 } else if (c >= 'A' && c <= 'F') {
260 v = c - 'A';
261 v += 10;
262 } else {
263 ERR_PRINT("BUG");
264 v = 0;
265 }
266
267 res <<= 4;
268 res |= v;
269 }
270
271 } break;
272 //case '\"': res='\"'; break;
273 //case '\\': res='\\'; break;
274 //case '/': res='/'; break;
275 default: {
276 res = next;
277 //r_err_str="Invalid escape sequence";
278 //return ERR_PARSE_ERROR;
279 } break;
280 }
281
282 str += res;
283
284 } else {
285 if (ch == '\n')
286 line++;
287 str += ch;
288 }
289 }
290
291 if (p_stream->is_utf8()) {
292 str.parse_utf8(str.ascii(true).get_data());
293 }
294 r_token.type = TK_STRING;
295 r_token.value = str;
296 return OK;
297
298 } break;
299 default: {
300
301 if (cchar <= 32) {
302 break;
303 }
304
305 if (cchar == '-' || (cchar >= '0' && cchar <= '9')) {
306 //a number
307
308 StringBuffer<> num;
309 #define READING_SIGN 0
310 #define READING_INT 1
311 #define READING_DEC 2
312 #define READING_EXP 3
313 #define READING_DONE 4
314 int reading = READING_INT;
315
316 if (cchar == '-') {
317 num += '-';
318 cchar = p_stream->get_char();
319 }
320
321 CharType c = cchar;
322 bool exp_sign = false;
323 bool exp_beg = false;
324 bool is_float = false;
325
326 while (true) {
327
328 switch (reading) {
329 case READING_INT: {
330
331 if (c >= '0' && c <= '9') {
332 //pass
333 } else if (c == '.') {
334 reading = READING_DEC;
335 is_float = true;
336 } else if (c == 'e') {
337 reading = READING_EXP;
338 is_float = true;
339 } else {
340 reading = READING_DONE;
341 }
342
343 } break;
344 case READING_DEC: {
345
346 if (c >= '0' && c <= '9') {
347
348 } else if (c == 'e') {
349 reading = READING_EXP;
350 } else {
351 reading = READING_DONE;
352 }
353
354 } break;
355 case READING_EXP: {
356
357 if (c >= '0' && c <= '9') {
358 exp_beg = true;
359
360 } else if ((c == '-' || c == '+') && !exp_sign && !exp_beg) {
361 exp_sign = true;
362
363 } else {
364 reading = READING_DONE;
365 }
366 } break;
367 }
368
369 if (reading == READING_DONE)
370 break;
371 num += c;
372 c = p_stream->get_char();
373 }
374
375 p_stream->saved = c;
376
377 r_token.type = TK_NUMBER;
378
379 if (is_float)
380 r_token.value = num.as_double();
381 else
382 r_token.value = num.as_int();
383 return OK;
384
385 } else if ((cchar >= 'A' && cchar <= 'Z') || (cchar >= 'a' && cchar <= 'z') || cchar == '_') {
386
387 StringBuffer<> id;
388 bool first = true;
389
390 while ((cchar >= 'A' && cchar <= 'Z') || (cchar >= 'a' && cchar <= 'z') || cchar == '_' || (!first && cchar >= '0' && cchar <= '9')) {
391
392 id += cchar;
393 cchar = p_stream->get_char();
394 first = false;
395 }
396
397 p_stream->saved = cchar;
398
399 r_token.type = TK_IDENTIFIER;
400 r_token.value = id.as_string();
401 return OK;
402 } else {
403 r_err_str = "Unexpected character.";
404 r_token.type = TK_ERROR;
405 return ERR_PARSE_ERROR;
406 }
407 }
408 }
409 }
410
411 r_token.type = TK_ERROR;
412 return ERR_PARSE_ERROR;
413 }
414
_parse_enginecfg(Stream * p_stream,Vector<String> & strings,int & line,String & r_err_str)415 Error VariantParser::_parse_enginecfg(Stream *p_stream, Vector<String> &strings, int &line, String &r_err_str) {
416
417 Token token;
418 get_token(p_stream, token, line, r_err_str);
419 if (token.type != TK_PARENTHESIS_OPEN) {
420 r_err_str = "Expected '(' in old-style project.godot construct";
421 return ERR_PARSE_ERROR;
422 }
423
424 String accum;
425
426 while (true) {
427
428 CharType c = p_stream->get_char();
429
430 if (p_stream->is_eof()) {
431 r_err_str = "Unexpected EOF while parsing old-style project.godot construct";
432 return ERR_PARSE_ERROR;
433 }
434
435 if (c == ',') {
436 strings.push_back(accum.strip_edges());
437 accum = String();
438 } else if (c == ')') {
439 strings.push_back(accum.strip_edges());
440 return OK;
441 } else if (c == '\n') {
442 line++;
443 }
444 }
445 }
446
447 template <class T>
_parse_construct(Stream * p_stream,Vector<T> & r_construct,int & line,String & r_err_str)448 Error VariantParser::_parse_construct(Stream *p_stream, Vector<T> &r_construct, int &line, String &r_err_str) {
449
450 Token token;
451 get_token(p_stream, token, line, r_err_str);
452 if (token.type != TK_PARENTHESIS_OPEN) {
453 r_err_str = "Expected '(' in constructor";
454 return ERR_PARSE_ERROR;
455 }
456
457 bool first = true;
458 while (true) {
459
460 if (!first) {
461 get_token(p_stream, token, line, r_err_str);
462 if (token.type == TK_COMMA) {
463 //do none
464 } else if (token.type == TK_PARENTHESIS_CLOSE) {
465 break;
466 } else {
467 r_err_str = "Expected ',' or ')' in constructor";
468 return ERR_PARSE_ERROR;
469 }
470 }
471 get_token(p_stream, token, line, r_err_str);
472
473 if (first && token.type == TK_PARENTHESIS_CLOSE) {
474 break;
475 } else if (token.type != TK_NUMBER) {
476 r_err_str = "Expected float in constructor";
477 return ERR_PARSE_ERROR;
478 }
479
480 r_construct.push_back(token.value);
481 first = false;
482 }
483
484 return OK;
485 }
486
parse_value(Token & token,Variant & value,Stream * p_stream,int & line,String & r_err_str,ResourceParser * p_res_parser)487 Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream, int &line, String &r_err_str, ResourceParser *p_res_parser) {
488 if (token.type == TK_CURLY_BRACKET_OPEN) {
489
490 Dictionary d;
491 Error err = _parse_dictionary(d, p_stream, line, r_err_str, p_res_parser);
492 if (err)
493 return err;
494 value = d;
495 return OK;
496 } else if (token.type == TK_BRACKET_OPEN) {
497
498 Array a;
499 Error err = _parse_array(a, p_stream, line, r_err_str, p_res_parser);
500 if (err)
501 return err;
502 value = a;
503 return OK;
504 } else if (token.type == TK_IDENTIFIER) {
505
506 String id = token.value;
507 if (id == "true")
508 value = true;
509 else if (id == "false")
510 value = false;
511 else if (id == "null" || id == "nil")
512 value = Variant();
513 else if (id == "inf")
514 value = Math_INF;
515 else if (id == "nan")
516 value = Math_NAN;
517 else if (id == "Vector2") {
518
519 Vector<float> args;
520 Error err = _parse_construct<float>(p_stream, args, line, r_err_str);
521 if (err)
522 return err;
523
524 if (args.size() != 2) {
525 r_err_str = "Expected 2 arguments for constructor";
526 return ERR_PARSE_ERROR;
527 }
528
529 value = Vector2(args[0], args[1]);
530 } else if (id == "Rect2") {
531
532 Vector<float> args;
533 Error err = _parse_construct<float>(p_stream, args, line, r_err_str);
534 if (err)
535 return err;
536
537 if (args.size() != 4) {
538 r_err_str = "Expected 4 arguments for constructor";
539 return ERR_PARSE_ERROR;
540 }
541
542 value = Rect2(args[0], args[1], args[2], args[3]);
543 } else if (id == "Vector3") {
544
545 Vector<float> args;
546 Error err = _parse_construct<float>(p_stream, args, line, r_err_str);
547 if (err)
548 return err;
549
550 if (args.size() != 3) {
551 r_err_str = "Expected 3 arguments for constructor";
552 return ERR_PARSE_ERROR;
553 }
554
555 value = Vector3(args[0], args[1], args[2]);
556 } else if (id == "Transform2D" || id == "Matrix32") { //compatibility
557 Vector<float> args;
558 Error err = _parse_construct<float>(p_stream, args, line, r_err_str);
559 if (err)
560 return err;
561
562 if (args.size() != 6) {
563 r_err_str = "Expected 6 arguments for constructor";
564 return ERR_PARSE_ERROR;
565 }
566
567 Transform2D m;
568 m[0] = Vector2(args[0], args[1]);
569 m[1] = Vector2(args[2], args[3]);
570 m[2] = Vector2(args[4], args[5]);
571 value = m;
572 } else if (id == "Plane") {
573
574 Vector<float> args;
575 Error err = _parse_construct<float>(p_stream, args, line, r_err_str);
576 if (err)
577 return err;
578
579 if (args.size() != 4) {
580 r_err_str = "Expected 4 arguments for constructor";
581 return ERR_PARSE_ERROR;
582 }
583
584 value = Plane(args[0], args[1], args[2], args[3]);
585 } else if (id == "Quat") {
586
587 Vector<float> args;
588 Error err = _parse_construct<float>(p_stream, args, line, r_err_str);
589 if (err)
590 return err;
591
592 if (args.size() != 4) {
593 r_err_str = "Expected 4 arguments for constructor";
594 return ERR_PARSE_ERROR;
595 }
596
597 value = Quat(args[0], args[1], args[2], args[3]);
598 } else if (id == "AABB" || id == "Rect3") {
599
600 Vector<float> args;
601 Error err = _parse_construct<float>(p_stream, args, line, r_err_str);
602 if (err)
603 return err;
604
605 if (args.size() != 6) {
606 r_err_str = "Expected 6 arguments for constructor";
607 return ERR_PARSE_ERROR;
608 }
609
610 value = AABB(Vector3(args[0], args[1], args[2]), Vector3(args[3], args[4], args[5]));
611 } else if (id == "Basis" || id == "Matrix3") { //compatibility
612 Vector<float> args;
613 Error err = _parse_construct<float>(p_stream, args, line, r_err_str);
614 if (err)
615 return err;
616
617 if (args.size() != 9) {
618 r_err_str = "Expected 9 arguments for constructor";
619 return ERR_PARSE_ERROR;
620 }
621
622 value = Basis(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]);
623 } else if (id == "Transform") {
624
625 Vector<float> args;
626 Error err = _parse_construct<float>(p_stream, args, line, r_err_str);
627 if (err)
628 return err;
629
630 if (args.size() != 12) {
631 r_err_str = "Expected 12 arguments for constructor";
632 return ERR_PARSE_ERROR;
633 }
634
635 value = Transform(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]));
636 } else if (id == "Color") {
637
638 Vector<float> args;
639 Error err = _parse_construct<float>(p_stream, args, line, r_err_str);
640 if (err)
641 return err;
642
643 if (args.size() != 4) {
644 r_err_str = "Expected 4 arguments for constructor";
645 return ERR_PARSE_ERROR;
646 }
647
648 value = Color(args[0], args[1], args[2], args[3]);
649 } else if (id == "NodePath") {
650
651 get_token(p_stream, token, line, r_err_str);
652 if (token.type != TK_PARENTHESIS_OPEN) {
653 r_err_str = "Expected '('";
654 return ERR_PARSE_ERROR;
655 }
656
657 get_token(p_stream, token, line, r_err_str);
658 if (token.type != TK_STRING) {
659 r_err_str = "Expected string as argument for NodePath()";
660 return ERR_PARSE_ERROR;
661 }
662
663 value = NodePath(String(token.value));
664
665 get_token(p_stream, token, line, r_err_str);
666 if (token.type != TK_PARENTHESIS_CLOSE) {
667 r_err_str = "Expected ')'";
668 return ERR_PARSE_ERROR;
669 }
670 } else if (id == "RID") {
671
672 get_token(p_stream, token, line, r_err_str);
673 if (token.type != TK_PARENTHESIS_OPEN) {
674 r_err_str = "Expected '('";
675 return ERR_PARSE_ERROR;
676 }
677
678 get_token(p_stream, token, line, r_err_str);
679 if (token.type != TK_NUMBER) {
680 r_err_str = "Expected number as argument";
681 return ERR_PARSE_ERROR;
682 }
683
684 value = token.value;
685
686 get_token(p_stream, token, line, r_err_str);
687 if (token.type != TK_PARENTHESIS_CLOSE) {
688 r_err_str = "Expected ')'";
689 return ERR_PARSE_ERROR;
690 }
691 } else if (id == "Object") {
692
693 get_token(p_stream, token, line, r_err_str);
694 if (token.type != TK_PARENTHESIS_OPEN) {
695 r_err_str = "Expected '('";
696 return ERR_PARSE_ERROR;
697 }
698
699 get_token(p_stream, token, line, r_err_str);
700
701 if (token.type != TK_IDENTIFIER) {
702 r_err_str = "Expected identifier with type of object";
703 return ERR_PARSE_ERROR;
704 }
705
706 String type = token.value;
707
708 Object *obj = ClassDB::instance(type);
709
710 if (!obj) {
711 r_err_str = "Can't instance Object() of type: " + type;
712 return ERR_PARSE_ERROR;
713 }
714
715 get_token(p_stream, token, line, r_err_str);
716 if (token.type != TK_COMMA) {
717 r_err_str = "Expected ',' after object type";
718 return ERR_PARSE_ERROR;
719 }
720
721 bool at_key = true;
722 String key;
723 Token token2;
724 bool need_comma = false;
725
726 while (true) {
727
728 if (p_stream->is_eof()) {
729 r_err_str = "Unexpected End of File while parsing Object()";
730 return ERR_FILE_CORRUPT;
731 }
732
733 if (at_key) {
734
735 Error err = get_token(p_stream, token2, line, r_err_str);
736 if (err != OK)
737 return err;
738
739 if (token2.type == TK_PARENTHESIS_CLOSE) {
740 Reference *reference = Object::cast_to<Reference>(obj);
741 if (reference) {
742 value = REF(reference);
743 } else {
744 value = obj;
745 }
746 return OK;
747 }
748
749 if (need_comma) {
750
751 if (token2.type != TK_COMMA) {
752
753 r_err_str = "Expected '}' or ','";
754 return ERR_PARSE_ERROR;
755 } else {
756 need_comma = false;
757 continue;
758 }
759 }
760
761 if (token2.type != TK_STRING) {
762 r_err_str = "Expected property name as string";
763 return ERR_PARSE_ERROR;
764 }
765
766 key = token2.value;
767
768 err = get_token(p_stream, token2, line, r_err_str);
769
770 if (err != OK)
771 return err;
772 if (token2.type != TK_COLON) {
773
774 r_err_str = "Expected ':'";
775 return ERR_PARSE_ERROR;
776 }
777 at_key = false;
778 } else {
779
780 Error err = get_token(p_stream, token2, line, r_err_str);
781 if (err != OK)
782 return err;
783
784 Variant v;
785 err = parse_value(token2, v, p_stream, line, r_err_str, p_res_parser);
786 if (err)
787 return err;
788 obj->set(key, v);
789 need_comma = true;
790 at_key = true;
791 }
792 }
793 } else if (id == "Resource" || id == "SubResource" || id == "ExtResource") {
794
795 get_token(p_stream, token, line, r_err_str);
796 if (token.type != TK_PARENTHESIS_OPEN) {
797 r_err_str = "Expected '('";
798 return ERR_PARSE_ERROR;
799 }
800
801 if (p_res_parser && id == "Resource" && p_res_parser->func) {
802
803 RES res;
804 Error err = p_res_parser->func(p_res_parser->userdata, p_stream, res, line, r_err_str);
805 if (err)
806 return err;
807
808 value = res;
809 } else if (p_res_parser && id == "ExtResource" && p_res_parser->ext_func) {
810
811 RES res;
812 Error err = p_res_parser->ext_func(p_res_parser->userdata, p_stream, res, line, r_err_str);
813 if (err)
814 return err;
815
816 value = res;
817 } else if (p_res_parser && id == "SubResource" && p_res_parser->sub_func) {
818
819 RES res;
820 Error err = p_res_parser->sub_func(p_res_parser->userdata, p_stream, res, line, r_err_str);
821 if (err)
822 return err;
823
824 value = res;
825 } else {
826
827 get_token(p_stream, token, line, r_err_str);
828 if (token.type == TK_STRING) {
829 String path = token.value;
830 RES res = ResourceLoader::load(path);
831 if (res.is_null()) {
832 r_err_str = "Can't load resource at path: '" + path + "'.";
833 return ERR_PARSE_ERROR;
834 }
835
836 get_token(p_stream, token, line, r_err_str);
837 if (token.type != TK_PARENTHESIS_CLOSE) {
838 r_err_str = "Expected ')'";
839 return ERR_PARSE_ERROR;
840 }
841
842 value = res;
843 } else {
844 r_err_str = "Expected string as argument for Resource().";
845 return ERR_PARSE_ERROR;
846 }
847 }
848 #ifndef DISABLE_DEPRECATED
849 } else if (id == "InputEvent") {
850
851 get_token(p_stream, token, line, r_err_str);
852 if (token.type != TK_PARENTHESIS_OPEN) {
853 r_err_str = "Expected '('";
854 return ERR_PARSE_ERROR;
855 }
856
857 get_token(p_stream, token, line, r_err_str);
858
859 if (token.type != TK_IDENTIFIER) {
860 r_err_str = "Expected identifier";
861 return ERR_PARSE_ERROR;
862 }
863
864 String id2 = token.value;
865
866 Ref<InputEvent> ie;
867
868 if (id2 == "NONE") {
869
870 get_token(p_stream, token, line, r_err_str);
871
872 if (token.type != TK_PARENTHESIS_CLOSE) {
873 r_err_str = "Expected ')'";
874 return ERR_PARSE_ERROR;
875 }
876
877 } else if (id2 == "KEY") {
878
879 Ref<InputEventKey> key;
880 key.instance();
881 ie = key;
882
883 get_token(p_stream, token, line, r_err_str);
884 if (token.type != TK_COMMA) {
885 r_err_str = "Expected ','";
886 return ERR_PARSE_ERROR;
887 }
888
889 get_token(p_stream, token, line, r_err_str);
890 if (token.type == TK_IDENTIFIER) {
891 String name = token.value;
892 key->set_scancode(find_keycode(name));
893 } else if (token.type == TK_NUMBER) {
894
895 key->set_scancode(token.value);
896 } else {
897
898 r_err_str = "Expected string or integer for keycode";
899 return ERR_PARSE_ERROR;
900 }
901
902 get_token(p_stream, token, line, r_err_str);
903
904 if (token.type == TK_COMMA) {
905
906 get_token(p_stream, token, line, r_err_str);
907
908 if (token.type != TK_IDENTIFIER) {
909 r_err_str = "Expected identifier with modifier flas";
910 return ERR_PARSE_ERROR;
911 }
912
913 String mods = token.value;
914
915 if (mods.findn("C") != -1)
916 key->set_control(true);
917 if (mods.findn("A") != -1)
918 key->set_alt(true);
919 if (mods.findn("S") != -1)
920 key->set_shift(true);
921 if (mods.findn("M") != -1)
922 key->set_metakey(true);
923
924 get_token(p_stream, token, line, r_err_str);
925 if (token.type != TK_PARENTHESIS_CLOSE) {
926 r_err_str = "Expected ')'";
927 return ERR_PARSE_ERROR;
928 }
929
930 } else if (token.type != TK_PARENTHESIS_CLOSE) {
931
932 r_err_str = "Expected ')' or modifier flags.";
933 return ERR_PARSE_ERROR;
934 }
935
936 } else if (id2 == "MBUTTON") {
937
938 Ref<InputEventMouseButton> mb;
939 mb.instance();
940 ie = mb;
941
942 get_token(p_stream, token, line, r_err_str);
943 if (token.type != TK_COMMA) {
944 r_err_str = "Expected ','";
945 return ERR_PARSE_ERROR;
946 }
947
948 get_token(p_stream, token, line, r_err_str);
949 if (token.type != TK_NUMBER) {
950 r_err_str = "Expected button index";
951 return ERR_PARSE_ERROR;
952 }
953
954 mb->set_button_index(token.value);
955
956 get_token(p_stream, token, line, r_err_str);
957 if (token.type != TK_PARENTHESIS_CLOSE) {
958 r_err_str = "Expected ')'";
959 return ERR_PARSE_ERROR;
960 }
961
962 } else if (id2 == "JBUTTON") {
963
964 Ref<InputEventJoypadButton> jb;
965 jb.instance();
966 ie = jb;
967
968 get_token(p_stream, token, line, r_err_str);
969 if (token.type != TK_COMMA) {
970 r_err_str = "Expected ','";
971 return ERR_PARSE_ERROR;
972 }
973
974 get_token(p_stream, token, line, r_err_str);
975 if (token.type != TK_NUMBER) {
976 r_err_str = "Expected button index";
977 return ERR_PARSE_ERROR;
978 }
979
980 jb->set_button_index(token.value);
981
982 get_token(p_stream, token, line, r_err_str);
983 if (token.type != TK_PARENTHESIS_CLOSE) {
984 r_err_str = "Expected ')'";
985 return ERR_PARSE_ERROR;
986 }
987
988 } else if (id2 == "JAXIS") {
989
990 Ref<InputEventJoypadMotion> jm;
991 jm.instance();
992 ie = jm;
993
994 get_token(p_stream, token, line, r_err_str);
995 if (token.type != TK_COMMA) {
996 r_err_str = "Expected ','";
997 return ERR_PARSE_ERROR;
998 }
999
1000 get_token(p_stream, token, line, r_err_str);
1001 if (token.type != TK_NUMBER) {
1002 r_err_str = "Expected axis index";
1003 return ERR_PARSE_ERROR;
1004 }
1005
1006 jm->set_axis(token.value);
1007
1008 get_token(p_stream, token, line, r_err_str);
1009
1010 if (token.type != TK_COMMA) {
1011 r_err_str = "Expected ',' after axis index";
1012 return ERR_PARSE_ERROR;
1013 }
1014
1015 get_token(p_stream, token, line, r_err_str);
1016 if (token.type != TK_NUMBER) {
1017 r_err_str = "Expected axis sign";
1018 return ERR_PARSE_ERROR;
1019 }
1020
1021 jm->set_axis_value(token.value);
1022
1023 get_token(p_stream, token, line, r_err_str);
1024
1025 if (token.type != TK_PARENTHESIS_CLOSE) {
1026 r_err_str = "Expected ')' for jaxis";
1027 return ERR_PARSE_ERROR;
1028 }
1029
1030 } else {
1031
1032 r_err_str = "Invalid input event type.";
1033 return ERR_PARSE_ERROR;
1034 }
1035
1036 value = ie;
1037 #endif
1038 } else if (id == "PoolByteArray" || id == "ByteArray") {
1039
1040 Vector<uint8_t> args;
1041 Error err = _parse_construct<uint8_t>(p_stream, args, line, r_err_str);
1042 if (err)
1043 return err;
1044
1045 PoolVector<uint8_t> arr;
1046 {
1047 int len = args.size();
1048 arr.resize(len);
1049 PoolVector<uint8_t>::Write w = arr.write();
1050 for (int i = 0; i < len; i++) {
1051 w[i] = args[i];
1052 }
1053 }
1054
1055 value = arr;
1056
1057 } else if (id == "PoolIntArray" || id == "IntArray") {
1058
1059 Vector<int> args;
1060 Error err = _parse_construct<int>(p_stream, args, line, r_err_str);
1061 if (err)
1062 return err;
1063
1064 PoolVector<int> arr;
1065 {
1066 int len = args.size();
1067 arr.resize(len);
1068 PoolVector<int>::Write w = arr.write();
1069 for (int i = 0; i < len; i++) {
1070 w[i] = int(args[i]);
1071 }
1072 }
1073
1074 value = arr;
1075
1076 } else if (id == "PoolRealArray" || id == "FloatArray") {
1077
1078 Vector<float> args;
1079 Error err = _parse_construct<float>(p_stream, args, line, r_err_str);
1080 if (err)
1081 return err;
1082
1083 PoolVector<float> arr;
1084 {
1085 int len = args.size();
1086 arr.resize(len);
1087 PoolVector<float>::Write w = arr.write();
1088 for (int i = 0; i < len; i++) {
1089 w[i] = args[i];
1090 }
1091 }
1092
1093 value = arr;
1094
1095 } else if (id == "PoolStringArray" || id == "StringArray") {
1096
1097 get_token(p_stream, token, line, r_err_str);
1098 if (token.type != TK_PARENTHESIS_OPEN) {
1099 r_err_str = "Expected '('";
1100 return ERR_PARSE_ERROR;
1101 }
1102
1103 Vector<String> cs;
1104
1105 bool first = true;
1106 while (true) {
1107
1108 if (!first) {
1109 get_token(p_stream, token, line, r_err_str);
1110 if (token.type == TK_COMMA) {
1111 //do none
1112 } else if (token.type == TK_PARENTHESIS_CLOSE) {
1113 break;
1114 } else {
1115 r_err_str = "Expected ',' or ')'";
1116 return ERR_PARSE_ERROR;
1117 }
1118 }
1119 get_token(p_stream, token, line, r_err_str);
1120
1121 if (token.type == TK_PARENTHESIS_CLOSE) {
1122 break;
1123 } else if (token.type != TK_STRING) {
1124 r_err_str = "Expected string";
1125 return ERR_PARSE_ERROR;
1126 }
1127
1128 first = false;
1129 cs.push_back(token.value);
1130 }
1131
1132 PoolVector<String> arr;
1133 {
1134 int len = cs.size();
1135 arr.resize(len);
1136 PoolVector<String>::Write w = arr.write();
1137 for (int i = 0; i < len; i++) {
1138 w[i] = cs[i];
1139 }
1140 }
1141
1142 value = arr;
1143
1144 } else if (id == "PoolVector2Array" || id == "Vector2Array") {
1145
1146 Vector<float> args;
1147 Error err = _parse_construct<float>(p_stream, args, line, r_err_str);
1148 if (err)
1149 return err;
1150
1151 PoolVector<Vector2> arr;
1152 {
1153 int len = args.size() / 2;
1154 arr.resize(len);
1155 PoolVector<Vector2>::Write w = arr.write();
1156 for (int i = 0; i < len; i++) {
1157 w[i] = Vector2(args[i * 2 + 0], args[i * 2 + 1]);
1158 }
1159 }
1160
1161 value = arr;
1162
1163 } else if (id == "PoolVector3Array" || id == "Vector3Array") {
1164
1165 Vector<float> args;
1166 Error err = _parse_construct<float>(p_stream, args, line, r_err_str);
1167 if (err)
1168 return err;
1169
1170 PoolVector<Vector3> arr;
1171 {
1172 int len = args.size() / 3;
1173 arr.resize(len);
1174 PoolVector<Vector3>::Write w = arr.write();
1175 for (int i = 0; i < len; i++) {
1176 w[i] = Vector3(args[i * 3 + 0], args[i * 3 + 1], args[i * 3 + 2]);
1177 }
1178 }
1179
1180 value = arr;
1181
1182 } else if (id == "PoolColorArray" || id == "ColorArray") {
1183
1184 Vector<float> args;
1185 Error err = _parse_construct<float>(p_stream, args, line, r_err_str);
1186 if (err)
1187 return err;
1188
1189 PoolVector<Color> arr;
1190 {
1191 int len = args.size() / 4;
1192 arr.resize(len);
1193 PoolVector<Color>::Write w = arr.write();
1194 for (int i = 0; i < len; i++) {
1195 w[i] = Color(args[i * 4 + 0], args[i * 4 + 1], args[i * 4 + 2], args[i * 4 + 3]);
1196 }
1197 }
1198
1199 value = arr;
1200 } else {
1201 r_err_str = "Unexpected identifier: '" + id + "'.";
1202 return ERR_PARSE_ERROR;
1203 }
1204
1205 // All above branches end up here unless they had an early return.
1206 return OK;
1207 } else if (token.type == TK_NUMBER) {
1208
1209 value = token.value;
1210 return OK;
1211 } else if (token.type == TK_STRING) {
1212
1213 value = token.value;
1214 return OK;
1215 } else if (token.type == TK_COLOR) {
1216
1217 value = token.value;
1218 return OK;
1219 } else {
1220 r_err_str = "Expected value, got " + String(tk_name[token.type]) + ".";
1221 return ERR_PARSE_ERROR;
1222 }
1223 }
1224
_parse_array(Array & array,Stream * p_stream,int & line,String & r_err_str,ResourceParser * p_res_parser)1225 Error VariantParser::_parse_array(Array &array, Stream *p_stream, int &line, String &r_err_str, ResourceParser *p_res_parser) {
1226
1227 Token token;
1228 bool need_comma = false;
1229
1230 while (true) {
1231
1232 if (p_stream->is_eof()) {
1233 r_err_str = "Unexpected End of File while parsing array";
1234 return ERR_FILE_CORRUPT;
1235 }
1236
1237 Error err = get_token(p_stream, token, line, r_err_str);
1238 if (err != OK)
1239 return err;
1240
1241 if (token.type == TK_BRACKET_CLOSE) {
1242
1243 return OK;
1244 }
1245
1246 if (need_comma) {
1247
1248 if (token.type != TK_COMMA) {
1249
1250 r_err_str = "Expected ','";
1251 return ERR_PARSE_ERROR;
1252 } else {
1253 need_comma = false;
1254 continue;
1255 }
1256 }
1257
1258 Variant v;
1259 err = parse_value(token, v, p_stream, line, r_err_str, p_res_parser);
1260 if (err)
1261 return err;
1262
1263 array.push_back(v);
1264 need_comma = true;
1265 }
1266 }
1267
_parse_dictionary(Dictionary & object,Stream * p_stream,int & line,String & r_err_str,ResourceParser * p_res_parser)1268 Error VariantParser::_parse_dictionary(Dictionary &object, Stream *p_stream, int &line, String &r_err_str, ResourceParser *p_res_parser) {
1269
1270 bool at_key = true;
1271 Variant key;
1272 Token token;
1273 bool need_comma = false;
1274
1275 while (true) {
1276
1277 if (p_stream->is_eof()) {
1278 r_err_str = "Unexpected End of File while parsing dictionary";
1279 return ERR_FILE_CORRUPT;
1280 }
1281
1282 if (at_key) {
1283
1284 Error err = get_token(p_stream, token, line, r_err_str);
1285 if (err != OK)
1286 return err;
1287
1288 if (token.type == TK_CURLY_BRACKET_CLOSE) {
1289
1290 return OK;
1291 }
1292
1293 if (need_comma) {
1294
1295 if (token.type != TK_COMMA) {
1296
1297 r_err_str = "Expected '}' or ','";
1298 return ERR_PARSE_ERROR;
1299 } else {
1300 need_comma = false;
1301 continue;
1302 }
1303 }
1304
1305 err = parse_value(token, key, p_stream, line, r_err_str, p_res_parser);
1306
1307 if (err)
1308 return err;
1309
1310 err = get_token(p_stream, token, line, r_err_str);
1311
1312 if (err != OK)
1313 return err;
1314 if (token.type != TK_COLON) {
1315
1316 r_err_str = "Expected ':'";
1317 return ERR_PARSE_ERROR;
1318 }
1319 at_key = false;
1320 } else {
1321
1322 Error err = get_token(p_stream, token, line, r_err_str);
1323 if (err != OK)
1324 return err;
1325
1326 Variant v;
1327 err = parse_value(token, v, p_stream, line, r_err_str, p_res_parser);
1328 if (err)
1329 return err;
1330 object[key] = v;
1331 need_comma = true;
1332 at_key = true;
1333 }
1334 }
1335 }
1336
_parse_tag(Token & token,Stream * p_stream,int & line,String & r_err_str,Tag & r_tag,ResourceParser * p_res_parser,bool p_simple_tag)1337 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) {
1338
1339 r_tag.fields.clear();
1340
1341 if (token.type != TK_BRACKET_OPEN) {
1342 r_err_str = "Expected '['";
1343 return ERR_PARSE_ERROR;
1344 }
1345
1346 if (p_simple_tag) {
1347
1348 r_tag.name = "";
1349 r_tag.fields.clear();
1350
1351 while (true) {
1352
1353 CharType c = p_stream->get_char();
1354 if (p_stream->is_eof()) {
1355 r_err_str = "Unexpected EOF while parsing simple tag";
1356 return ERR_PARSE_ERROR;
1357 }
1358 if (c == ']')
1359 break;
1360 r_tag.name += String::chr(c);
1361 }
1362
1363 r_tag.name = r_tag.name.strip_edges();
1364
1365 return OK;
1366 }
1367
1368 get_token(p_stream, token, line, r_err_str);
1369
1370 if (token.type != TK_IDENTIFIER) {
1371 r_err_str = "Expected identifier (tag name)";
1372 return ERR_PARSE_ERROR;
1373 }
1374
1375 r_tag.name = token.value;
1376 bool parsing_tag = true;
1377
1378 while (true) {
1379
1380 if (p_stream->is_eof()) {
1381 r_err_str = "Unexpected End of File while parsing tag: " + r_tag.name;
1382 return ERR_FILE_CORRUPT;
1383 }
1384
1385 get_token(p_stream, token, line, r_err_str);
1386 if (token.type == TK_BRACKET_CLOSE)
1387 break;
1388
1389 if (parsing_tag && token.type == TK_PERIOD) {
1390 r_tag.name += "."; //support tags such as [someprop.Android] for specific platforms
1391 get_token(p_stream, token, line, r_err_str);
1392 } else if (parsing_tag && token.type == TK_COLON) {
1393 r_tag.name += ":"; //support tags such as [someprop.Android] for specific platforms
1394 get_token(p_stream, token, line, r_err_str);
1395 } else {
1396 parsing_tag = false;
1397 }
1398
1399 if (token.type != TK_IDENTIFIER) {
1400 r_err_str = "Expected Identifier";
1401 return ERR_PARSE_ERROR;
1402 }
1403
1404 String id = token.value;
1405
1406 if (parsing_tag) {
1407 r_tag.name += id;
1408 continue;
1409 }
1410
1411 get_token(p_stream, token, line, r_err_str);
1412 if (token.type != TK_EQUAL) {
1413 return ERR_PARSE_ERROR;
1414 }
1415
1416 get_token(p_stream, token, line, r_err_str);
1417 Variant value;
1418 Error err = parse_value(token, value, p_stream, line, r_err_str, p_res_parser);
1419 if (err)
1420 return err;
1421
1422 r_tag.fields[id] = value;
1423 }
1424
1425 return OK;
1426 }
1427
parse_tag(Stream * p_stream,int & line,String & r_err_str,Tag & r_tag,ResourceParser * p_res_parser,bool p_simple_tag)1428 Error VariantParser::parse_tag(Stream *p_stream, int &line, String &r_err_str, Tag &r_tag, ResourceParser *p_res_parser, bool p_simple_tag) {
1429
1430 Token token;
1431 get_token(p_stream, token, line, r_err_str);
1432
1433 if (token.type == TK_EOF) {
1434 return ERR_FILE_EOF;
1435 }
1436
1437 if (token.type != TK_BRACKET_OPEN) {
1438 r_err_str = "Expected '['";
1439 return ERR_PARSE_ERROR;
1440 }
1441
1442 return _parse_tag(token, p_stream, line, r_err_str, r_tag, p_res_parser, p_simple_tag);
1443 }
1444
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)1445 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) {
1446
1447 //assign..
1448 r_assign = "";
1449 String what;
1450
1451 while (true) {
1452
1453 CharType c;
1454 if (p_stream->saved) {
1455 c = p_stream->saved;
1456 p_stream->saved = 0;
1457
1458 } else {
1459 c = p_stream->get_char();
1460 }
1461
1462 if (p_stream->is_eof())
1463 return ERR_FILE_EOF;
1464
1465 if (c == ';') { //comment
1466 while (true) {
1467 CharType ch = p_stream->get_char();
1468 if (p_stream->is_eof()) {
1469 return ERR_FILE_EOF;
1470 }
1471 if (ch == '\n')
1472 break;
1473 }
1474 continue;
1475 }
1476
1477 if (c == '[' && what.length() == 0) {
1478 //it's a tag!
1479 p_stream->saved = '['; //go back one
1480
1481 Error err = parse_tag(p_stream, line, r_err_str, r_tag, p_res_parser, p_simple_tag);
1482
1483 return err;
1484 }
1485
1486 if (c > 32) {
1487 if (c == '"') { //quoted
1488 p_stream->saved = '"';
1489 Token tk;
1490 Error err = get_token(p_stream, tk, line, r_err_str);
1491 if (err)
1492 return err;
1493 if (tk.type != TK_STRING) {
1494 r_err_str = "Error reading quoted string";
1495 return ERR_INVALID_DATA;
1496 }
1497
1498 what = tk.value;
1499
1500 } else if (c != '=') {
1501 what += String::chr(c);
1502 } else {
1503 r_assign = what;
1504 Token token;
1505 get_token(p_stream, token, line, r_err_str);
1506 Error err = parse_value(token, r_value, p_stream, line, r_err_str, p_res_parser);
1507 return err;
1508 }
1509 } else if (c == '\n') {
1510 line++;
1511 }
1512 }
1513 }
1514
parse(Stream * p_stream,Variant & r_ret,String & r_err_str,int & r_err_line,ResourceParser * p_res_parser)1515 Error VariantParser::parse(Stream *p_stream, Variant &r_ret, String &r_err_str, int &r_err_line, ResourceParser *p_res_parser) {
1516
1517 Token token;
1518 Error err = get_token(p_stream, token, r_err_line, r_err_str);
1519 if (err)
1520 return err;
1521
1522 if (token.type == TK_EOF) {
1523 return ERR_FILE_EOF;
1524 }
1525
1526 return parse_value(token, r_ret, p_stream, r_err_line, r_err_str, p_res_parser);
1527 }
1528
1529 //////////////////////////////////////////////////////////////////////////////////
1530 //////////////////////////////////////////////////////////////////////////////////
1531 ////////////////////////////////////////////////////////////////////////////////
1532
rtosfix(double p_value)1533 static String rtosfix(double p_value) {
1534
1535 if (p_value == 0.0)
1536 return "0"; //avoid negative zero (-0) being written, which may annoy git, svn, etc. for changes when they don't exist.
1537 else
1538 return rtoss(p_value);
1539 }
1540
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)1541 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) {
1542
1543 switch (p_variant.get_type()) {
1544
1545 case Variant::NIL: {
1546 p_store_string_func(p_store_string_ud, "null");
1547 } break;
1548 case Variant::BOOL: {
1549
1550 p_store_string_func(p_store_string_ud, p_variant.operator bool() ? "true" : "false");
1551 } break;
1552 case Variant::INT: {
1553
1554 p_store_string_func(p_store_string_ud, itos(p_variant.operator int64_t()));
1555 } break;
1556 case Variant::REAL: {
1557
1558 String s = rtosfix(p_variant.operator real_t());
1559 if (s != "inf" && s != "nan") {
1560 if (s.find(".") == -1 && s.find("e") == -1)
1561 s += ".0";
1562 }
1563 p_store_string_func(p_store_string_ud, s);
1564 } break;
1565 case Variant::STRING: {
1566
1567 String str = p_variant;
1568
1569 str = "\"" + str.c_escape_multiline() + "\"";
1570 p_store_string_func(p_store_string_ud, str);
1571 } break;
1572 case Variant::VECTOR2: {
1573
1574 Vector2 v = p_variant;
1575 p_store_string_func(p_store_string_ud, "Vector2( " + rtosfix(v.x) + ", " + rtosfix(v.y) + " )");
1576 } break;
1577 case Variant::RECT2: {
1578
1579 Rect2 aabb = p_variant;
1580 p_store_string_func(p_store_string_ud, "Rect2( " + rtosfix(aabb.position.x) + ", " + rtosfix(aabb.position.y) + ", " + rtosfix(aabb.size.x) + ", " + rtosfix(aabb.size.y) + " )");
1581
1582 } break;
1583 case Variant::VECTOR3: {
1584
1585 Vector3 v = p_variant;
1586 p_store_string_func(p_store_string_ud, "Vector3( " + rtosfix(v.x) + ", " + rtosfix(v.y) + ", " + rtosfix(v.z) + " )");
1587 } break;
1588 case Variant::PLANE: {
1589
1590 Plane p = p_variant;
1591 p_store_string_func(p_store_string_ud, "Plane( " + rtosfix(p.normal.x) + ", " + rtosfix(p.normal.y) + ", " + rtosfix(p.normal.z) + ", " + rtosfix(p.d) + " )");
1592
1593 } break;
1594 case Variant::AABB: {
1595
1596 AABB aabb = p_variant;
1597 p_store_string_func(p_store_string_ud, "AABB( " + rtosfix(aabb.position.x) + ", " + rtosfix(aabb.position.y) + ", " + rtosfix(aabb.position.z) + ", " + rtosfix(aabb.size.x) + ", " + rtosfix(aabb.size.y) + ", " + rtosfix(aabb.size.z) + " )");
1598
1599 } break;
1600 case Variant::QUAT: {
1601
1602 Quat quat = p_variant;
1603 p_store_string_func(p_store_string_ud, "Quat( " + rtosfix(quat.x) + ", " + rtosfix(quat.y) + ", " + rtosfix(quat.z) + ", " + rtosfix(quat.w) + " )");
1604
1605 } break;
1606 case Variant::TRANSFORM2D: {
1607
1608 String s = "Transform2D( ";
1609 Transform2D m3 = p_variant;
1610 for (int i = 0; i < 3; i++) {
1611 for (int j = 0; j < 2; j++) {
1612
1613 if (i != 0 || j != 0)
1614 s += ", ";
1615 s += rtosfix(m3.elements[i][j]);
1616 }
1617 }
1618
1619 p_store_string_func(p_store_string_ud, s + " )");
1620
1621 } break;
1622 case Variant::BASIS: {
1623
1624 String s = "Basis( ";
1625 Basis m3 = p_variant;
1626 for (int i = 0; i < 3; i++) {
1627 for (int j = 0; j < 3; j++) {
1628
1629 if (i != 0 || j != 0)
1630 s += ", ";
1631 s += rtosfix(m3.elements[i][j]);
1632 }
1633 }
1634
1635 p_store_string_func(p_store_string_ud, s + " )");
1636
1637 } break;
1638 case Variant::TRANSFORM: {
1639
1640 String s = "Transform( ";
1641 Transform t = p_variant;
1642 Basis &m3 = t.basis;
1643 for (int i = 0; i < 3; i++) {
1644 for (int j = 0; j < 3; j++) {
1645
1646 if (i != 0 || j != 0)
1647 s += ", ";
1648 s += rtosfix(m3.elements[i][j]);
1649 }
1650 }
1651
1652 s = s + ", " + rtosfix(t.origin.x) + ", " + rtosfix(t.origin.y) + ", " + rtosfix(t.origin.z);
1653
1654 p_store_string_func(p_store_string_ud, s + " )");
1655 } break;
1656
1657 // misc types
1658 case Variant::COLOR: {
1659
1660 Color c = p_variant;
1661 p_store_string_func(p_store_string_ud, "Color( " + rtosfix(c.r) + ", " + rtosfix(c.g) + ", " + rtosfix(c.b) + ", " + rtosfix(c.a) + " )");
1662
1663 } break;
1664 case Variant::NODE_PATH: {
1665
1666 String str = p_variant;
1667
1668 str = "NodePath(\"" + str.c_escape() + "\")";
1669 p_store_string_func(p_store_string_ud, str);
1670
1671 } break;
1672
1673 case Variant::OBJECT: {
1674
1675 Object *obj = p_variant;
1676
1677 if (!obj) {
1678 p_store_string_func(p_store_string_ud, "null");
1679 break; // don't save it
1680 }
1681
1682 RES res = p_variant;
1683 if (res.is_valid()) {
1684 //is resource
1685 String res_text;
1686
1687 //try external function
1688 if (p_encode_res_func) {
1689
1690 res_text = p_encode_res_func(p_encode_res_ud, res);
1691 }
1692
1693 //try path because it's a file
1694 if (res_text == String() && res->get_path().is_resource_file()) {
1695
1696 //external resource
1697 String path = res->get_path();
1698 res_text = "Resource( \"" + path + "\")";
1699 }
1700
1701 //could come up with some sort of text
1702 if (res_text != String()) {
1703 p_store_string_func(p_store_string_ud, res_text);
1704 break;
1705 }
1706 }
1707
1708 //store as generic object
1709
1710 p_store_string_func(p_store_string_ud, "Object(" + obj->get_class() + ",");
1711
1712 List<PropertyInfo> props;
1713 obj->get_property_list(&props);
1714 bool first = true;
1715 for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) {
1716
1717 if (E->get().usage & PROPERTY_USAGE_STORAGE || E->get().usage & PROPERTY_USAGE_SCRIPT_VARIABLE) {
1718 //must be serialized
1719
1720 if (first) {
1721 first = false;
1722 } else {
1723 p_store_string_func(p_store_string_ud, ",");
1724 }
1725
1726 p_store_string_func(p_store_string_ud, "\"" + E->get().name + "\":");
1727 write(obj->get(E->get().name), p_store_string_func, p_store_string_ud, p_encode_res_func, p_encode_res_ud);
1728 }
1729 }
1730
1731 p_store_string_func(p_store_string_ud, ")\n");
1732
1733 } break;
1734
1735 case Variant::DICTIONARY: {
1736
1737 Dictionary dict = p_variant;
1738
1739 List<Variant> keys;
1740 dict.get_key_list(&keys);
1741 keys.sort();
1742
1743 p_store_string_func(p_store_string_ud, "{\n");
1744 for (List<Variant>::Element *E = keys.front(); E; E = E->next()) {
1745
1746 /*
1747 if (!_check_type(dict[E->get()]))
1748 continue;
1749 */
1750 write(E->get(), p_store_string_func, p_store_string_ud, p_encode_res_func, p_encode_res_ud);
1751 p_store_string_func(p_store_string_ud, ": ");
1752 write(dict[E->get()], p_store_string_func, p_store_string_ud, p_encode_res_func, p_encode_res_ud);
1753 if (E->next())
1754 p_store_string_func(p_store_string_ud, ",\n");
1755 }
1756
1757 p_store_string_func(p_store_string_ud, "\n}");
1758
1759 } break;
1760 case Variant::ARRAY: {
1761
1762 p_store_string_func(p_store_string_ud, "[ ");
1763 Array array = p_variant;
1764 int len = array.size();
1765 for (int i = 0; i < len; i++) {
1766
1767 if (i > 0)
1768 p_store_string_func(p_store_string_ud, ", ");
1769 write(array[i], p_store_string_func, p_store_string_ud, p_encode_res_func, p_encode_res_ud);
1770 }
1771 p_store_string_func(p_store_string_ud, " ]");
1772
1773 } break;
1774
1775 case Variant::POOL_BYTE_ARRAY: {
1776
1777 p_store_string_func(p_store_string_ud, "PoolByteArray( ");
1778 String s;
1779 PoolVector<uint8_t> data = p_variant;
1780 int len = data.size();
1781 PoolVector<uint8_t>::Read r = data.read();
1782 const uint8_t *ptr = r.ptr();
1783 for (int i = 0; i < len; i++) {
1784
1785 if (i > 0)
1786 p_store_string_func(p_store_string_ud, ", ");
1787
1788 p_store_string_func(p_store_string_ud, itos(ptr[i]));
1789 }
1790
1791 p_store_string_func(p_store_string_ud, " )");
1792
1793 } break;
1794 case Variant::POOL_INT_ARRAY: {
1795
1796 p_store_string_func(p_store_string_ud, "PoolIntArray( ");
1797 PoolVector<int> data = p_variant;
1798 int len = data.size();
1799 PoolVector<int>::Read r = data.read();
1800 const int *ptr = r.ptr();
1801
1802 for (int i = 0; i < len; i++) {
1803
1804 if (i > 0)
1805 p_store_string_func(p_store_string_ud, ", ");
1806
1807 p_store_string_func(p_store_string_ud, itos(ptr[i]));
1808 }
1809
1810 p_store_string_func(p_store_string_ud, " )");
1811
1812 } break;
1813 case Variant::POOL_REAL_ARRAY: {
1814
1815 p_store_string_func(p_store_string_ud, "PoolRealArray( ");
1816 PoolVector<real_t> data = p_variant;
1817 int len = data.size();
1818 PoolVector<real_t>::Read r = data.read();
1819 const real_t *ptr = r.ptr();
1820
1821 for (int i = 0; i < len; i++) {
1822
1823 if (i > 0)
1824 p_store_string_func(p_store_string_ud, ", ");
1825 p_store_string_func(p_store_string_ud, rtosfix(ptr[i]));
1826 }
1827
1828 p_store_string_func(p_store_string_ud, " )");
1829
1830 } break;
1831 case Variant::POOL_STRING_ARRAY: {
1832
1833 p_store_string_func(p_store_string_ud, "PoolStringArray( ");
1834 PoolVector<String> data = p_variant;
1835 int len = data.size();
1836 PoolVector<String>::Read r = data.read();
1837 const String *ptr = r.ptr();
1838 String s;
1839 //write_string("\n");
1840
1841 for (int i = 0; i < len; i++) {
1842
1843 if (i > 0)
1844 p_store_string_func(p_store_string_ud, ", ");
1845 String str = ptr[i];
1846 p_store_string_func(p_store_string_ud, "\"" + str.c_escape() + "\"");
1847 }
1848
1849 p_store_string_func(p_store_string_ud, " )");
1850
1851 } break;
1852 case Variant::POOL_VECTOR2_ARRAY: {
1853
1854 p_store_string_func(p_store_string_ud, "PoolVector2Array( ");
1855 PoolVector<Vector2> data = p_variant;
1856 int len = data.size();
1857 PoolVector<Vector2>::Read r = data.read();
1858 const Vector2 *ptr = r.ptr();
1859
1860 for (int i = 0; i < len; i++) {
1861
1862 if (i > 0)
1863 p_store_string_func(p_store_string_ud, ", ");
1864 p_store_string_func(p_store_string_ud, rtosfix(ptr[i].x) + ", " + rtosfix(ptr[i].y));
1865 }
1866
1867 p_store_string_func(p_store_string_ud, " )");
1868
1869 } break;
1870 case Variant::POOL_VECTOR3_ARRAY: {
1871
1872 p_store_string_func(p_store_string_ud, "PoolVector3Array( ");
1873 PoolVector<Vector3> data = p_variant;
1874 int len = data.size();
1875 PoolVector<Vector3>::Read r = data.read();
1876 const Vector3 *ptr = r.ptr();
1877
1878 for (int i = 0; i < len; i++) {
1879
1880 if (i > 0)
1881 p_store_string_func(p_store_string_ud, ", ");
1882 p_store_string_func(p_store_string_ud, rtosfix(ptr[i].x) + ", " + rtosfix(ptr[i].y) + ", " + rtosfix(ptr[i].z));
1883 }
1884
1885 p_store_string_func(p_store_string_ud, " )");
1886
1887 } break;
1888 case Variant::POOL_COLOR_ARRAY: {
1889
1890 p_store_string_func(p_store_string_ud, "PoolColorArray( ");
1891
1892 PoolVector<Color> data = p_variant;
1893 int len = data.size();
1894 PoolVector<Color>::Read r = data.read();
1895 const Color *ptr = r.ptr();
1896
1897 for (int i = 0; i < len; i++) {
1898
1899 if (i > 0)
1900 p_store_string_func(p_store_string_ud, ", ");
1901
1902 p_store_string_func(p_store_string_ud, rtosfix(ptr[i].r) + ", " + rtosfix(ptr[i].g) + ", " + rtosfix(ptr[i].b) + ", " + rtosfix(ptr[i].a));
1903 }
1904 p_store_string_func(p_store_string_ud, " )");
1905
1906 } break;
1907 default: {
1908 }
1909 }
1910
1911 return OK;
1912 }
1913
_write_to_str(void * ud,const String & p_string)1914 static Error _write_to_str(void *ud, const String &p_string) {
1915
1916 String *str = (String *)ud;
1917 (*str) += p_string;
1918 return OK;
1919 }
1920
write_to_string(const Variant & p_variant,String & r_string,EncodeResourceFunc p_encode_res_func,void * p_encode_res_ud)1921 Error VariantWriter::write_to_string(const Variant &p_variant, String &r_string, EncodeResourceFunc p_encode_res_func, void *p_encode_res_ud) {
1922
1923 r_string = String();
1924
1925 return write(p_variant, _write_to_str, &r_string, p_encode_res_func, p_encode_res_ud);
1926 }
1927