GCC Code Coverage Report


Directory: src/gate/
File: src/gate/encode/yaml.c
Date: 2025-09-22 22:57:09
Exec Total Coverage
Lines: 0 898 0.0%
Functions: 0 28 0.0%
Branches: 0 456 0.0%

Line Branch Exec Source
1 /* GATE PROJECT LICENSE:
2 +----------------------------------------------------------------------------+
3 | Copyright(c) 2018-2025, Stefan Meislinger <sm@opengate.at> |
4 | All rights reserved. |
5 | |
6 | Redistribution and use in source and binary forms, with or without |
7 | modification, are permitted provided that the following conditions are met:|
8 | |
9 | 1. Redistributions of source code must retain the above copyright notice, |
10 | this list of conditions and the following disclaimer. |
11 | 2. Redistributions in binary form must reproduce the above copyright |
12 | notice, this list of conditions and the following disclaimer in the |
13 | documentation and/or other materials provided with the distribution. |
14 | |
15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"|
16 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
17 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
18 | ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
19 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
20 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
21 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
22 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
23 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
24 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
25 | THE POSSIBILITY OF SUCH DAMAGE. |
26 +----------------------------------------------------------------------------+
27 */
28
29 #include "gate/encode/yaml.h"
30 #include "gate/results.h"
31 #include "gate/mathematics.h"
32 #include "gate/debugging.h"
33
34 static gate_string_t const indention_chars = GATE_STRING_INIT_STATIC(" \t");
35
36 #define LINE_TYPE_UNKNOWN 0
37 #define LINE_TYPE_EMPTY 1
38 #define LINE_TYPE_VALUE 2
39 #define LINE_TYPE_KEY 3 /* key-only entry, eg. "'key':" */
40 #define LINE_TYPE_MEMBER 4 /* key-value entry, eg. "'key': 'value'" */
41 #define LINE_TYPE_ARRAY_VALUE 5 /* array entry value, eg. "- 'value'" */
42 #define LINE_TYPE_ARRAY_KEY 6 /* array entry key-only, eg. "- 'key':" */
43 #define LINE_TYPE_ARRAY_MEMBER 7 /* array entry key-value, eg. "- 'key': 'value'" */
44
45
46 static char const* gate_yaml_bool_true_values[] =
47 {
48 "y", "Y", "yes", "Yes", "YES",
49 "true", "True", "TRUE",
50 "on", "On", "ON"
51 };
52
53 static char const* gate_yaml_bool_false_values[] =
54 {
55 "n", "N", "no", "No", "NO",
56 "false", "False", "FALSE",
57 "off", "Off", "OFF"
58 };
59
60 ✗ static gate_bool_t is_yaml_bool_true(gate_string_t const* str)
61 {
62 gate_size_t index;
63 ✗ gate_size_t len = sizeof(gate_yaml_bool_true_values) / sizeof(gate_yaml_bool_true_values[0]);
64 ✗ for (index = 0; index != len; ++index)
65 {
66 ✗ if (gate_string_equals_str(str, gate_yaml_bool_true_values[index]))
67 {
68 ✗ return true;
69 }
70 }
71 ✗ return false;
72 }
73 ✗ static gate_bool_t is_yaml_bool_false(gate_string_t const* str)
74 {
75 gate_size_t index;
76 ✗ gate_size_t len = sizeof(gate_yaml_bool_false_values) / sizeof(gate_yaml_bool_false_values[0]);
77 ✗ for (index = 0; index != len; ++index)
78 {
79 ✗ if (gate_string_equals_str(str, gate_yaml_bool_false_values[index]))
80 {
81 ✗ return true;
82 }
83 }
84 ✗ return false;
85 }
86 ✗ static gate_bool_t is_yaml_int(gate_string_t const* str, gate_int64_t* int_value)
87 {
88 ✗ gate_size_t len_parsed = gate_str_parse_int64(str->str, str->length, int_value);
89 ✗ return (len_parsed == str->length);
90 }
91 ✗ static gate_bool_t is_yaml_real(gate_string_t const* str, gate_real64_t* real_value)
92 {
93 ✗ gate_size_t len_parsed = gate_str_parse_real(str->str, str->length, real_value);
94 ✗ return (len_parsed == str->length);
95 }
96
97
98 ✗ static gate_size_t parse_quoted_string(gate_string_t const* source, gate_string_t* text)
99 {
100 ✗ gate_size_t parsed = 0;
101 ✗ char const* ptr = source->str;
102 ✗ gate_size_t len = source->length;
103 ✗ gate_strbuilder_t builder = GATE_INIT_EMPTY;
104 char quote_char;
105
106 do
107 {
108 ✗ quote_char = *ptr;
109 ✗ ++ptr;
110 ✗ --len;
111 ✗ ++parsed;
112
113 ✗ gate_strbuilder_create(&builder, len);
114
115 ✗ while (len != 0)
116 {
117 ✗ if (*ptr == '\\')
118 {
119 ✗ ++ptr;
120 ✗ --len;
121 ✗ ++parsed;
122 ✗ switch (*ptr)
123 {
124 ✗ case '\\':
125 ✗ gate_strbuilder_append_chars(&builder, 1, '\\');
126 ✗ break;
127 ✗ case '\"':
128 ✗ gate_strbuilder_append_chars(&builder, 1, '\"');
129 ✗ break;
130 ✗ case '\'':
131 ✗ gate_strbuilder_append_chars(&builder, 1, '\'');
132 ✗ break;
133 ✗ case 'r':
134 ✗ gate_strbuilder_append_chars(&builder, 1, '\r');
135 ✗ break;
136 ✗ case 'n':
137 ✗ gate_strbuilder_append_chars(&builder, 1, '\n');
138 ✗ break;
139 ✗ case 't':
140 ✗ gate_strbuilder_append_chars(&builder, 1, '\t');
141 ✗ break;
142 ✗ case 'v':
143 ✗ gate_strbuilder_append_chars(&builder, 1, '\v');
144 ✗ break;
145 ✗ case 'b':
146 ✗ gate_strbuilder_append_chars(&builder, 1, '\b');
147 ✗ break;
148 ✗ default:
149 ✗ gate_strbuilder_append_chars(&builder, 1, '\\');
150 ✗ gate_strbuilder_append_chars(&builder, 1, *ptr);
151 ✗ break;
152 }
153 }
154 else
155 {
156 ✗ if (*ptr == quote_char)
157 {
158 /* end of string reached */
159 ✗ ++parsed;
160 ✗ break;
161 }
162 else
163 {
164 ✗ gate_strbuilder_append_chars(&builder, 1, *ptr);
165 }
166 }
167
168 ✗ ++ptr;
169 ✗ --len;
170 ✗ ++parsed;
171 }
172 } while (0);
173
174 ✗ if (NULL == gate_strbuilder_to_string(&builder, text))
175 {
176 ✗ parsed = 0;
177 }
178 ✗ gate_strbuilder_release(&builder);
179
180 ✗ return parsed;
181 }
182
183 ✗ static gate_size_t skip_whitespaces(gate_string_t* text)
184 {
185 static gate_string_t white_spaces = GATE_STRING_INIT_STATIC(GATE_STR_WHITESPACES);
186 ✗ gate_size_t ret = gate_string_find_first_not_of(text, &white_spaces, 0);
187 ✗ if (ret == GATE_STR_NPOS)
188 {
189 ✗ ret = gate_string_length(text);
190 ✗ gate_string_release(text);
191 }
192 else
193 {
194 ✗ gate_string_substr(text, text, ret, GATE_STR_NPOS);
195 }
196 ✗ return ret;
197 }
198
199 static gate_size_t gate_yaml_parse_inline_object(gate_string_t const* token, gate_property_t* prop);
200 static gate_size_t gate_yaml_parse_inline_array(gate_string_t* token, gate_property_t* prop);
201
202
203 ✗ static gate_size_t gate_yaml_parse_inline_item(gate_string_t const* token, gate_property_t* prop, gate_string_t const* terminator_chars)
204 {
205 ✗ gate_size_t ret = 0;
206 ✗ gate_string_t text = GATE_STRING_INIT_EMPTY;
207 ✗ gate_string_t value = GATE_STRING_INIT_EMPTY;
208 ✗ gate_size_t pos = 0;
209 ✗ gate_int64_t i64 = 0;
210 ✗ gate_real64_t r64 = 0.0;
211 char chr;
212
213 do
214 {
215 ✗ gate_string_duplicate(&text, token);
216 ✗ ret += skip_whitespaces(&text);
217
218 ✗ if (gate_string_is_empty(&text))
219 {
220 ✗ ret = 0;
221 ✗ break;
222 }
223 ✗ chr = gate_string_char_at(&text, 0);
224 ✗ if ((chr == '\"') || (chr == '\''))
225 {
226 /* quoted string */
227 ✗ pos = parse_quoted_string(&text, &value);
228 ✗ if (pos == 0)
229 {
230 /* failed to parse quoted string */
231 ✗ GATE_DEBUG_TRACE("Failed to parse quoted YAML string");
232 ✗ ret = 0;
233 ✗ break;
234 }
235 ✗ if (NULL == gate_property_create_string(prop, &value))
236 {
237 ✗ GATE_DEBUG_TRACE("Failed to create string property object");
238 ✗ ret = 0;
239 ✗ break;
240 }
241 ✗ ret += pos;
242 }
243 ✗ else if (chr == '{')
244 {
245 /* inline object */
246 ✗ pos = gate_yaml_parse_inline_object(&text, prop);
247 ✗ if (pos == 0)
248 {
249 ✗ GATE_DEBUG_TRACE("Failed to parse inline YAML object");
250 ✗ ret = 0;
251 ✗ break;
252 }
253 ✗ ret += pos;
254 }
255 ✗ else if (chr == '[')
256 {
257 /* inline array */
258 ✗ pos = gate_yaml_parse_inline_array(&text, prop);
259 ✗ if (pos == 0)
260 {
261 ✗ GATE_DEBUG_TRACE("Failed to parse inline YAML array");
262 ✗ ret = 0;
263 ✗ break;
264 }
265 ✗ ret += pos;
266 }
267 else
268 {
269 /* primitive elment */
270 ✗ pos = gate_string_find_first_of(&text, terminator_chars, 0);
271 ✗ if (pos == GATE_STR_NPOS)
272 {
273 /* possibly the last element in document */
274 ✗ pos = gate_string_length(&text);
275 }
276 ✗ gate_string_substr(&value, &text, 0, pos);
277 ✗ ret += pos;
278 ✗ gate_string_trim(&value, &value);
279
280 ✗ if (is_yaml_bool_true(&value))
281 {
282 ✗ if (NULL == gate_property_create_bool(prop, true))
283 {
284 ✗ GATE_DEBUG_TRACE("Failed to create bool property ojbect");
285 ✗ ret = 0;
286 ✗ break;
287 }
288 }
289 ✗ else if (is_yaml_bool_false(&value))
290 {
291 ✗ if (NULL == gate_property_create_bool(prop, false))
292 {
293 ✗ GATE_DEBUG_TRACE("Failed to create bool property ojbect");
294 ✗ ret = 0;
295 ✗ break;
296 }
297 }
298 ✗ else if (is_yaml_int(&value, &i64))
299 {
300 ✗ if (NULL == gate_property_create_int(prop, i64))
301 {
302 ✗ GATE_DEBUG_TRACE("Failed to create integer property ojbect");
303 ✗ ret = 0;
304 ✗ break;
305 }
306 }
307 ✗ else if (is_yaml_real(&value, &r64))
308 {
309 ✗ if (NULL == gate_property_create_real(prop, r64))
310 {
311 ✗ GATE_DEBUG_TRACE("Failed to create real property ojbect");
312 ✗ ret = 0;
313 ✗ break;
314 }
315 }
316 else
317 {
318 /* OK, it is just a string */
319 ✗ if (NULL == gate_property_create_string(prop, &value))
320 {
321 ✗ GATE_DEBUG_TRACE("Failed to create string property ojbect");
322 ✗ ret = 0;
323 ✗ break;
324 }
325 }
326 }
327 } while (0);
328
329 ✗ gate_string_release(&text);
330 ✗ gate_string_release(&value);
331
332 ✗ return ret;
333 }
334
335 ✗ static gate_size_t gate_yaml_parse_inline_object(gate_string_t const* token, gate_property_t* prop)
336 {
337 static gate_string_t obj_item_terminator_chars = GATE_STRING_INIT_STATIC(",}");
338 ✗ gate_size_t ret = 0;
339 ✗ gate_string_t text = GATE_STRING_INIT_EMPTY;
340 ✗ gate_string_t member_name = GATE_STRING_INIT_EMPTY;
341 ✗ gate_string_t member_value = GATE_STRING_INIT_EMPTY;
342 ✗ gate_string_t tmp = GATE_STRING_INIT_EMPTY;
343 gate_bool_t succeeded;
344 gate_bool_t tmp_empty;
345 ✗ gate_property_t member_prop = GATE_INIT_EMPTY;
346 gate_size_t pos;
347 ✗ gate_string_duplicate(&text, token);
348
349 ✗ ret += skip_whitespaces(&text);
350
351 do
352 {
353 ✗ gate_mem_clear(prop, sizeof(gate_property_t));
354
355 ✗ if (!gate_string_starts_with_char(&text, '{'))
356 {
357 /* token does not start with object indicator */
358 ✗ GATE_DEBUG_TRACE("Missing YAML object indicator");
359 ✗ ret = 0;
360 ✗ break;
361 }
362 ✗ gate_string_substr(&text, &text, 1, GATE_STR_NPOS);
363 ✗ ++ret;
364
365 ✗ if (NULL == gate_property_create_object(prop))
366 {
367 /* failed to create property object */
368 ✗ GATE_DEBUG_TRACE("Failed to create object property object");
369 ✗ ret = 0;
370 ✗ break;
371 }
372
373 for (;;)
374 {
375 ✗ ret += skip_whitespaces(&text);
376 ✗ if (gate_string_is_empty(&text))
377 {
378 /* missing object content */
379 ✗ GATE_DEBUG_TRACE("Missing YAML object content");
380 ✗ ret = 0;
381 ✗ break;
382 }
383 ✗ if (gate_string_starts_with_char(&text, '}'))
384 {
385 /* end of object reached */
386 ✗ ++ret;
387 ✗ break;
388 }
389
390 /* parse key:*/
391 ✗ if (gate_string_starts_with_char(&text, '\"'))
392 {
393 ✗ pos = parse_quoted_string(&text, &member_name);
394 ✗ if (pos == 0)
395 {
396 ✗ GATE_DEBUG_TRACE("Failed to parse quoted YAML string");
397 ✗ ret = 0;
398 ✗ break;
399 }
400 ✗ ret += pos;
401 ✗ gate_string_substr(&text, &text, pos, GATE_STR_NPOS);
402 ✗ pos = gate_string_char_pos(&text, ':', 0);
403 ✗ if (pos == GATE_STR_NPOS)
404 {
405 ✗ GATE_DEBUG_TRACE("Missing YAML object key/value separator");
406 ✗ ret = 0;
407 ✗ break;
408 }
409 ✗ gate_string_substr(&text, &text, pos + 1, GATE_STR_NPOS);
410 ✗ ret += (pos + 1);
411 }
412 else
413 {
414 ✗ pos = gate_string_char_pos(&text, ':', 0);
415 ✗ if (pos == GATE_STR_NPOS)
416 {
417 ✗ GATE_DEBUG_TRACE("Missing YAML object key/value separator");
418 ✗ ret = 0;
419 ✗ break;
420 }
421 ✗ gate_string_substr(&member_name, &text, 0, pos);
422 ✗ gate_string_substr(&text, &text, pos + 1, GATE_STR_NPOS);
423 ✗ ret += (pos + 1);
424 }
425
426 /* parse value: */
427 ✗ ret += skip_whitespaces(&text);
428 ✗ pos = gate_yaml_parse_inline_item(&text, &member_prop, &obj_item_terminator_chars);
429 ✗ if (pos == 0)
430 {
431 /* failed to parse member property */
432 ✗ GATE_DEBUG_TRACE("Failed to parse YAML object member value");
433 ✗ ret = 0;
434 ✗ break;
435 }
436 ✗ ret += pos;
437 ✗ gate_string_substr(&text, &text, pos, GATE_STR_NPOS);
438
439 ✗ succeeded = (NULL != gate_property_member_add(prop, &member_name, &member_prop));
440 ✗ gate_string_release(&member_name);
441 ✗ gate_property_destroy(&member_prop);
442 ✗ if (!succeeded)
443 {
444 /* failed to add new property to object */
445 ✗ GATE_DEBUG_TRACE("Failed to add key/value member to property object");
446 ✗ ret = 0;
447 ✗ break;
448 }
449
450 ✗ pos = gate_string_find_first_of(&text, &obj_item_terminator_chars, 0);
451 ✗ if (pos == GATE_STR_NPOS)
452 {
453 /* broken object -> corruption */
454 ✗ GATE_DEBUG_TRACE("Missing YAML object member seperator or terminator");
455 ✗ ret = 0;
456 ✗ break;
457 }
458 ✗ gate_string_substr(&tmp, &text, 0, pos);
459 ✗ ret += pos;
460 ✗ gate_string_substr(&text, &text, pos, GATE_STR_NPOS);
461
462 ✗ skip_whitespaces(&tmp);
463 ✗ tmp_empty = gate_string_is_empty(&tmp);
464 ✗ gate_string_release(&tmp);
465 ✗ if (!tmp_empty)
466 {
467 /* no non-whitespace-chars allowed until terminator chars show up */
468 ✗ GATE_DEBUG_TRACE("Unexpected characters after YAML member value detected");
469 ✗ ret = 0;
470 ✗ break;
471 }
472 ✗ if (gate_string_starts_with_char(&text, '}'))
473 {
474 /* end of object reached */
475 ✗ ++ret;
476 ✗ break;
477 }
478 ✗ if (!gate_string_starts_with_char(&text, ','))
479 {
480 /* object corrupted */
481 ✗ GATE_DEBUG_TRACE("Missing YAML object member separator");
482 ✗ ret = 0;
483 ✗ break;
484 }
485 else
486 {
487 /* another key/value pair is showing up */
488 ✗ ++ret;
489 ✗ gate_string_substr(&text, &text, 1, GATE_STR_NPOS);
490 }
491 }
492 } while (0);
493
494 ✗ if (ret == 0)
495 {
496 ✗ gate_property_destroy(prop);
497 }
498
499 ✗ gate_string_release(&tmp);
500 ✗ gate_string_release(&member_name);
501 ✗ gate_string_release(&member_value);
502 ✗ gate_property_destroy(&member_prop);
503 ✗ gate_string_release(&text);
504 ✗ return ret;
505 }
506 ✗ static gate_size_t gate_yaml_parse_inline_array(gate_string_t* token, gate_property_t* prop)
507 {
508 static gate_string_t arr_item_terminator_chars = GATE_STRING_INIT_STATIC(",]");
509 ✗ gate_size_t ret = 0;
510 ✗ gate_string_t text = GATE_STRING_INIT_EMPTY;
511 ✗ gate_string_t tmp = GATE_STRING_INIT_EMPTY;
512 gate_bool_t succeeded;
513 gate_bool_t tmp_empty;
514 ✗ gate_property_t item_prop = GATE_INIT_EMPTY;
515 gate_size_t pos;
516 ✗ gate_string_duplicate(&text, token);
517
518 ✗ ret += skip_whitespaces(&text);
519
520 do
521 {
522 ✗ gate_mem_clear(prop, sizeof(gate_property_t));
523
524 ✗ if (!gate_string_starts_with_char(&text, '['))
525 {
526 /* token does not start with an array indicator */
527 ✗ GATE_DEBUG_TRACE("Missing YAML array indicator");
528 ✗ ret = 0;
529 ✗ break;
530 }
531 ✗ gate_string_substr(&text, &text, 1, GATE_STR_NPOS);
532 ✗ ++ret;
533
534 ✗ if (NULL == gate_property_create_array(prop, NULL, 0))
535 {
536 ✗ GATE_DEBUG_TRACE("Failed to create array property object");
537 ✗ ret = 0;
538 ✗ break;
539 }
540
541 for (;;)
542 {
543 ✗ ret += skip_whitespaces(&text);
544 ✗ if (gate_string_is_empty(&text))
545 {
546 /* missing array content */
547 ✗ GATE_DEBUG_TRACE("Missing YAML array content");
548 ✗ ret = 0;
549 ✗ break;
550 }
551 ✗ if (gate_string_starts_with_char(&text, ']'))
552 {
553 /* end of array reached */
554 ✗ ++ret;
555 ✗ break;
556 }
557
558 /* parse value: */
559 ✗ ret += skip_whitespaces(&text);
560 ✗ pos = gate_yaml_parse_inline_item(&text, &item_prop, &arr_item_terminator_chars);
561 ✗ if (pos == 0)
562 {
563 ✗ GATE_DEBUG_TRACE("Failed to parse YAML array item");
564 /* failed to parse member property */
565 ✗ ret = 0;
566 ✗ break;
567 }
568 ✗ ret += pos;
569 ✗ gate_string_substr(&text, &text, pos, GATE_STR_NPOS);
570
571 ✗ succeeded = (NULL != gate_property_array_add(prop, &item_prop));
572 ✗ gate_property_destroy(&item_prop);
573 ✗ if (!succeeded)
574 {
575 ✗ GATE_DEBUG_TRACE("Failed to add item to array property object");
576 /* failed to add new item to array */
577 ✗ ret = 0;
578 ✗ break;
579 }
580
581 ✗ pos = gate_string_find_first_of(&text, &arr_item_terminator_chars, 0);
582 ✗ if (pos == GATE_STR_NPOS)
583 {
584 ✗ GATE_DEBUG_TRACE("Missing YAML array item separator or terminator");
585 /* broken array -> corruption */
586 ✗ ret = 0;
587 ✗ break;
588 }
589 ✗ gate_string_substr(&tmp, &text, 0, pos);
590 ✗ ret += pos;
591 ✗ gate_string_substr(&text, &text, pos, GATE_STR_NPOS);
592
593 ✗ skip_whitespaces(&tmp);
594 ✗ tmp_empty = gate_string_is_empty(&tmp);
595 ✗ gate_string_release(&tmp);
596 ✗ if (!tmp_empty)
597 {
598 ✗ GATE_DEBUG_TRACE("Unexpected characters after YAML array item detected");
599 /* no non-whitespace-chars allowed until terminator chars show up */
600 ✗ ret = 0;
601 ✗ break;
602 }
603 ✗ if (gate_string_starts_with_char(&text, ']'))
604 {
605 /* end of object reached */
606 ✗ ++ret;
607 ✗ break;
608 }
609 ✗ if (!gate_string_starts_with_char(&text, ','))
610 {
611 ✗ GATE_DEBUG_TRACE("Missing YAML array separator");
612 /* object corrupted */
613 ✗ ret = 0;
614 ✗ break;
615 }
616 else
617 {
618 /* another key/value pair is showing up */
619 ✗ ++ret;
620 ✗ gate_string_substr(&text, &text, 1, GATE_STR_NPOS);
621 }
622 }
623 } while (0);
624
625 ✗ if (ret == 0)
626 {
627 ✗ gate_property_destroy(prop);
628 }
629
630 ✗ gate_string_release(&tmp);
631 ✗ gate_property_destroy(&item_prop);
632 ✗ gate_string_release(&text);
633 ✗ return ret;
634 }
635
636 /*
637 static gate_property_t* gate_yaml_parse_inline(gate_string_t* line, gate_property_t* prop)
638 {
639 gate_property_t* ret = NULL;
640 gate_size_t parsed = 0;
641
642 if(gate_string_starts_with_char(line, '{'))
643 {
644 parsed = gate_yaml_parse_inline_object(line, prop);
645 if(parsed != 0)
646 {
647 ret = prop;
648 }
649 }
650 else if(gate_string_starts_with_char(line, '['))
651 {
652 parsed = gate_yaml_parse_inline_array(line, prop);
653 if(parsed != 0)
654 {
655 ret = prop;
656 }
657 }
658
659 return ret;
660 }
661 */
662
663 ✗ static gate_property_t* gate_yaml_parse_entry(gate_string_t* line, gate_property_t* prop, gate_bool_t* incomplete)
664 {
665 static gate_string_t end_of_line = GATE_STRING_INIT_STATIC("\n");
666 ✗ gate_property_t* ret = NULL;
667 ✗ gate_string_t text = GATE_STRING_INIT_EMPTY;
668 ✗ gate_property_t subprop = GATE_INIT_EMPTY;
669 gate_size_t parsed;
670 gate_size_t pos;
671 ✗ gate_bool_t valueonly = false;
672 ✗ gate_bool_t keyonly = false;
673 ✗ gate_bool_t keyvalue = false;
674 ✗ gate_bool_t subprop_incomplete = false;
675 ✗ gate_bool_t quoted_value = false;
676 ✗ gate_int64_t i64 = 0;
677 ✗ gate_real64_t r64 = 0.0;
678 do
679 {
680 ✗ gate_string_ltrim(line, line);
681 ✗ if (gate_string_is_empty(line))
682 {
683 ✗ GATE_DEBUG_TRACE("Missing YAML line content");
684 /* error, nothing to parse */
685 ✗ break;
686 }
687
688 ✗ if (gate_string_starts_with_char(line, '{') || gate_string_starts_with_char(line, '['))
689 {
690 /* inline object or inline array */
691 ✗ *incomplete = false;
692 ✗ pos = gate_yaml_parse_inline_item(line, prop, &end_of_line);
693 ✗ if (pos == 0)
694 {
695 ✗ GATE_DEBUG_TRACE("Failed to parse inline YAML entry");
696 ✗ ret = NULL;
697 }
698 else
699 {
700 ✗ ret = prop;
701 }
702 ✗ break;
703 }
704
705 ✗ if (gate_string_starts_with_char(line, '\"') || gate_string_starts_with_char(line, '\''))
706 {
707 /* quoted string */
708 ✗ parsed = parse_quoted_string(line, &text);
709 ✗ if (parsed == 0)
710 {
711 ✗ GATE_DEBUG_TRACE("Failed to parse quoted YAML string");
712 ✗ break;
713 }
714 ✗ gate_string_substr(line, line, parsed, GATE_STR_NPOS);
715 ✗ gate_string_ltrim(line, line);
716 ✗ if (gate_string_starts_with_char(line, ':'))
717 {
718 /* key - value pair: */
719 ✗ gate_string_substr(line, line, 1, GATE_STR_NPOS);
720 ✗ gate_string_ltrim(line, line);
721 ✗ if (gate_string_is_empty(line))
722 {
723 ✗ keyonly = true;
724 }
725 else
726 {
727 ✗ if (NULL == gate_yaml_parse_entry(line, &subprop, &subprop_incomplete))
728 {
729 ✗ GATE_DEBUG_TRACE("Failed to parse YAML entry member value");
730 /* error case: failed to parse sub-property */
731 ✗ break;
732 }
733 ✗ if (subprop_incomplete)
734 {
735 ✗ GATE_DEBUG_TRACE("Incomplete sub property dtected");
736 /* error case: sub-property is incomplete*/
737 ✗ break;
738 }
739 ✗ keyvalue = true;
740 }
741 }
742 else
743 {
744 /* value-only */
745 ✗ valueonly = true;
746 ✗ quoted_value = true;
747 }
748 }
749 else
750 {
751 ✗ pos = gate_string_char_pos(line, ':', 0);
752 ✗ if (pos == GATE_STR_NPOS)
753 {
754 ✗ gate_string_duplicate(&text, line);
755 ✗ valueonly = true;
756 /* value only */
757 }
758 else
759 {
760 ✗ gate_string_substr(&text, line, 0, pos);
761 ✗ gate_string_ltrim(&text, &text);
762 ✗ gate_string_substr(line, line, pos + 1, GATE_STR_NPOS);
763 ✗ gate_string_ltrim(line, line);
764
765 ✗ if (gate_string_is_empty(line))
766 {
767 ✗ keyonly = true;
768 }
769 else
770 {
771 ✗ if (NULL == gate_yaml_parse_entry(line, &subprop, &subprop_incomplete))
772 {
773 ✗ GATE_DEBUG_TRACE("Failed to parse YAML entry member value");
774 /* error case: failed to parse sub-property */
775 ✗ break;
776 }
777 ✗ if (subprop_incomplete)
778 {
779 ✗ GATE_DEBUG_TRACE("Incomplete sub property dtected");
780 /* error case: sub-property is incomplete*/
781 ✗ break;
782 }
783 ✗ keyvalue = true;
784 }
785 }
786 }
787
788 ✗ *incomplete = keyonly;
789
790 ✗ if (valueonly)
791 {
792 ✗ switch (gate_property_get_type(prop))
793 {
794 ✗ case GATE_PROPERTY_TYPE_ARRAY:
795 {
796 ✗ GATE_DEBUG_TRACE("Internal error, property of type array detected");
797 /* error case: arrays are handled outside */
798 ✗ break;
799 }
800 ✗ case GATE_PROPERTY_TYPE_OBJECT:
801 {
802 ✗ GATE_DEBUG_TRACE("Internal error, property of type object detected");
803 /* error case: cannot attach value-only to object*/
804 ✗ break;
805 }
806 ✗ default:
807 {
808 ✗ gate_property_destroy(prop);
809 ✗ if (quoted_value)
810 {
811 ✗ ret = gate_property_create_string(prop, &text);
812 }
813 else
814 {
815 ✗ if (is_yaml_bool_true(&text))
816 {
817 ✗ ret = gate_property_create_bool(prop, true);
818 }
819 ✗ else if (is_yaml_bool_false(&text))
820 {
821 ✗ ret = gate_property_create_bool(prop, false);
822 }
823 ✗ else if (is_yaml_int(&text, &i64))
824 {
825 ✗ ret = gate_property_create_int(prop, i64);
826 }
827 ✗ else if (is_yaml_real(&text, &r64))
828 {
829 ✗ ret = gate_property_create_real(prop, r64);
830 }
831 else
832 {
833 ✗ ret = gate_property_create_string(prop, &text);
834 }
835 }
836
837 ✗ break;
838 }
839 }
840 }
841 ✗ else if (keyonly || keyvalue)
842 {
843 ✗ switch (gate_property_get_type(prop))
844 {
845 ✗ case GATE_PROPERTY_TYPE_ARRAY:
846 {
847 ✗ GATE_DEBUG_TRACE("Internal error, property of type array detected");
848 /* error case: arrays are handled outside */
849 ✗ break;
850 }
851 ✗ case GATE_PROPERTY_TYPE_OBJECT:
852 {
853 ✗ ret = gate_property_member_add(prop, &text, &subprop);
854 ✗ break;
855 }
856 ✗ default:
857 {
858 ✗ gate_property_destroy(prop);
859 ✗ ret = gate_property_create_object(prop);
860 ✗ if (ret != NULL)
861 {
862 ✗ if (NULL == gate_property_member_add(prop, &text, &subprop))
863 {
864 ✗ gate_property_destroy(prop);
865 ✗ ret = NULL;
866 }
867 }
868 ✗ break;
869 }
870 }
871 ✗ }
872 else
873 {
874 /* error case: unsupported behavior */
875 break;
876 }
877
878 } while (0);
879
880 ✗ gate_string_release(&text);
881 ✗ gate_property_destroy(&subprop);
882
883 ✗ return ret;
884 }
885
886 ✗ static gate_result_t gate_yaml_parse_indent(gate_string_t* line, gate_uint16_t* indent)
887 {
888 ✗ gate_result_t ret = GATE_RESULT_FAILED;
889 gate_size_t pos;
890 ✗ pos = gate_string_find_first_not_of(line, &indention_chars, 0);
891 ✗ if (pos == GATE_STR_NPOS)
892 {
893 /* impossible, should be detected by is_empty() */
894 ✗ GATE_DEBUG_TRACE("Internal error, missing indention");
895 ✗ ret = GATE_RESULT_CRITICALERROR;
896 }
897 else
898 {
899 ✗ *indent = (gate_uint16_t)pos;
900 ✗ gate_string_substr(line, line, pos, GATE_STR_NPOS);
901 ✗ ret = GATE_RESULT_OK;
902 }
903 ✗ return ret;
904 }
905
906
907 #define GATE_YAML_MAX_LEVELS 64
908 #define GATE_YAML_UNKNOWN_INDENTION ((gate_uint16_t)(-1))
909
910 ✗ static gate_result_t gate_yaml_merge_properties(gate_property_t* target, gate_property_t const* source, gate_bool_t source_is_array_entry)
911 {
912 ✗ gate_result_t ret = GATE_RESULT_FAILED;
913 ✗ gate_uint32_t target_type = gate_property_get_type(target);
914 ✗ gate_uint32_t source_type = gate_property_get_type(source);
915 gate_size_t index;
916 gate_size_t len;
917 ✗ gate_array_t name_array = GATE_INIT_EMPTY;
918 gate_string_t const* ptr_name;
919 gate_property_t const* ptr_prop;
920
921 ✗ if (source_type == GATE_PROPERTY_TYPE_EMPTY)
922 {
923 /* nothing to do */
924 ✗ ret = GATE_RESULT_OK;
925 }
926 ✗ switch (target_type)
927 {
928 ✗ case GATE_PROPERTY_TYPE_EMPTY:
929 {
930 ✗ if (source_is_array_entry)
931 {
932 ✗ if (NULL == gate_property_create_array(target, source, 1))
933 {
934 ✗ ret = GATE_RESULT_OUTOFMEMORY;
935 }
936 else
937 {
938 ✗ ret = GATE_RESULT_OK;
939 }
940 }
941 else
942 {
943 ✗ if (NULL == gate_property_copy(target, source))
944 {
945 ✗ ret = GATE_RESULT_OUTOFMEMORY;
946 }
947 else
948 {
949 ✗ ret = GATE_RESULT_OK;
950 }
951 }
952 ✗ break;
953 }
954 ✗ case GATE_PROPERTY_TYPE_BOOL:
955 case GATE_PROPERTY_TYPE_INT:
956 case GATE_PROPERTY_TYPE_REAL:
957 {
958 ✗ if (source_type == target_type)
959 {
960 ✗ if (NULL == gate_property_copy(target, source))
961 {
962 ✗ ret = GATE_RESULT_OUTOFMEMORY;
963 }
964 else
965 {
966 ✗ ret = GATE_RESULT_OK;
967 }
968 }
969 else
970 {
971 ✗ ret = GATE_RESULT_INCORRECTTYPE;
972 }
973 ✗ break;
974 }
975 ✗ case GATE_PROPERTY_TYPE_STRING:
976 {
977 ✗ if (source_type == target_type)
978 {
979 ✗ ret = gate_property_set_string(target, &source->data.string_value);
980 }
981 else
982 {
983 ✗ ret = GATE_RESULT_INCORRECTTYPE;
984 }
985 ✗ break;
986 }
987 ✗ case GATE_PROPERTY_TYPE_ARRAY:
988 {
989 ✗ if (!source_is_array_entry && (source_type == GATE_PROPERTY_TYPE_OBJECT))
990 {
991 /* this might be an additional object member entry for the previously added object */
992 ✗ len = gate_property_array_length(target);
993 ✗ if (len > 0)
994 {
995 ✗ ptr_prop = gate_property_array_get(target, len - 1);
996 ✗ if (ptr_prop)
997 {
998 ✗ if (gate_property_get_type(ptr_prop) == GATE_PROPERTY_TYPE_OBJECT)
999 {
1000 /* add new member to last object-entry in array */
1001 ✗ ret = gate_yaml_merge_properties((gate_property_t*)ptr_prop, source, false);
1002 ✗ break;
1003 }
1004 }
1005 }
1006
1007 }
1008 /* otherwise just add array item */
1009 ✗ if (NULL == gate_property_array_add(target, source))
1010 {
1011 ✗ ret = GATE_RESULT_OUTOFMEMORY;
1012 }
1013 else
1014 {
1015 ✗ ret = GATE_RESULT_OK;
1016 }
1017 ✗ break;
1018 }
1019 ✗ case GATE_PROPERTY_TYPE_OBJECT:
1020 {
1021 ✗ if (source_is_array_entry)
1022 {
1023 ✗ ret = GATE_RESULT_INCORRECTTYPE;
1024 ✗ break;
1025 }
1026 ✗ if (NULL == gate_property_member_names(source, &name_array))
1027 {
1028 ✗ ret = GATE_RESULT_OUTOFMEMORY;
1029 }
1030 else
1031 {
1032 ✗ ret = GATE_RESULT_OK;
1033 ✗ len = gate_array_length(&name_array);
1034 ✗ for (index = 0; index != len; ++index)
1035 {
1036 ✗ ptr_name = gate_array_get(&name_array, index);
1037 ✗ if (ptr_name)
1038 {
1039 ✗ ptr_prop = gate_property_member_get(source, ptr_name);
1040 ✗ if (ptr_prop)
1041 {
1042 ✗ if (NULL == gate_property_member_add(target, ptr_name, ptr_prop))
1043 {
1044 ✗ ret = GATE_RESULT_FAILED;
1045 ✗ break;
1046 }
1047 }
1048 }
1049 }
1050 ✗ gate_array_release(&name_array);
1051 }
1052 ✗ break;
1053 }
1054 ✗ default:
1055 {
1056 ✗ ret = GATE_RESULT_NOTSUPPORTED;
1057 ✗ break;
1058 }
1059 }
1060 ✗ return ret;
1061 }
1062
1063 ✗ static gate_result_t gate_yaml_integrate(gate_property_t* target, gate_string_t const* key, gate_property_t const* source)
1064 {
1065 ✗ gate_uint32_t target_type = gate_property_get_type(target);
1066 gate_size_t len;
1067 gate_property_t* ptr_prop;
1068
1069 ✗ if (target_type == GATE_PROPERTY_TYPE_EMPTY)
1070 {
1071 ✗ if (NULL == gate_property_create_object(target))
1072 {
1073 ✗ return GATE_RESULT_OUTOFMEMORY;
1074 }
1075 ✗ target_type = GATE_PROPERTY_TYPE_OBJECT;
1076 }
1077
1078 ✗ switch (target_type)
1079 {
1080 ✗ case GATE_PROPERTY_TYPE_ARRAY:
1081 {
1082 /* check if target is an array of objects -> add member to last object */
1083 ✗ len = gate_property_array_length(target);
1084 ✗ if (len > 0)
1085 {
1086 ✗ ptr_prop = (gate_property_t*)gate_property_array_get(target, len - 1);
1087 ✗ if (ptr_prop)
1088 {
1089 ✗ if (gate_property_get_type(ptr_prop) == GATE_PROPERTY_TYPE_OBJECT)
1090 {
1091 ✗ if (NULL != gate_property_member_add(ptr_prop, key, source))
1092 {
1093 ✗ return GATE_RESULT_OK;
1094 }
1095 else
1096 {
1097 ✗ return GATE_RESULT_OUTOFMEMORY;
1098 }
1099 }
1100 }
1101 }
1102 ✗ return GATE_RESULT_INVALIDSTATE;
1103 }
1104 ✗ case GATE_PROPERTY_TYPE_OBJECT:
1105 {
1106 ✗ if (NULL != gate_property_member_add(target, key, source))
1107 {
1108 ✗ return GATE_RESULT_OK;
1109 }
1110 else
1111 {
1112 ✗ return GATE_RESULT_OUTOFMEMORY;
1113 }
1114 }
1115 ✗ default:
1116 {
1117 ✗ return GATE_RESULT_INCORRECTTYPE;
1118 }
1119 }
1120 }
1121
1122 ✗ static gate_result_t gate_yaml_extract_name_of_incomplete_object(gate_property_t const* prop, gate_string_t* name)
1123 {
1124 ✗ gate_result_t ret = GATE_RESULT_FAILED;
1125 gate_uint32_t prop_type;
1126 gate_array_t prop_names;
1127 gate_string_t const* ptr_name;
1128 do
1129 {
1130 ✗ prop_type = gate_property_get_type(prop);
1131 ✗ switch (prop_type)
1132 {
1133 ✗ case GATE_PROPERTY_TYPE_OBJECT:
1134 {
1135 ✗ if (NULL != gate_property_member_names(prop, &prop_names))
1136 {
1137 ✗ ptr_name = gate_array_get(&prop_names, 0);
1138 ✗ if (ptr_name)
1139 {
1140 ✗ if (NULL != gate_string_duplicate(name, ptr_name))
1141 {
1142 ✗ ret = GATE_RESULT_OK;
1143 }
1144 }
1145 ✗ gate_array_release(&prop_names);
1146 }
1147 ✗ break;
1148 }
1149 ✗ case GATE_PROPERTY_TYPE_STRING:
1150 {
1151 ✗ ret = gate_property_get_string(prop, name);
1152 ✗ break;
1153 }
1154 ✗ default:
1155 {
1156 ✗ ret = GATE_RESULT_INCORRECTTYPE;
1157 ✗ break;
1158 }
1159 }
1160 } while (0);
1161
1162 ✗ return ret;
1163 }
1164
1165 #define GATE_YAML_UNKNOWN_NEXT_INDENT 65535
1166
1167
1168 ✗ gate_result_t gate_yaml_parse_string(gate_string_t const* source, gate_property_t* target_prop, gate_yaml_result_t* result)
1169 {
1170 gate_property_t levels[GATE_YAML_MAX_LEVELS];
1171 ✗ gate_uint16_t indents[GATE_YAML_MAX_LEVELS] = GATE_INIT_EMPTY;
1172 ✗ gate_string_t keys[GATE_YAML_MAX_LEVELS] = GATE_INIT_EMPTY;
1173 ✗ gate_size_t const max_levels = GATE_YAML_MAX_LEVELS;
1174 ✗ gate_size_t current_level = 0;
1175 gate_size_t index;
1176 ✗ gate_result_t ret = GATE_RESULT_NOTIMPLEMENTED;
1177 ✗ gate_string_t line = GATE_STRING_INIT_EMPTY;
1178 ✗ gate_string_t yaml = GATE_STRING_INIT_EMPTY;
1179 gate_uint16_t current_indent;
1180 ✗ gate_property_t entry_prop = GATE_INIT_EMPTY;
1181 ✗ gate_bool_t entry_incomplete = false;
1182 ✗ gate_bool_t entry_is_array = false;
1183 ✗ gate_uint16_t array_indent = 0;
1184 gate_size_t pos;
1185 ✗ gate_size_t lines_parsed = 0;
1186
1187 do
1188 {
1189 ✗ gate_mem_clear(levels, sizeof(levels));
1190 ✗ gate_mem_clear(result, sizeof(gate_yaml_result_t));
1191
1192 ✗ if (NULL == gate_string_duplicate(&yaml, source))
1193 {
1194 ✗ ret = GATE_RESULT_OUTOFMEMORY;
1195 ✗ break;
1196 }
1197
1198 ✗ indents[0] = GATE_YAML_UNKNOWN_NEXT_INDENT;
1199 ✗ current_level = 0;
1200
1201 ✗ while (gate_string_read_line(&line, &yaml, &yaml))
1202 {
1203 ✗ ++lines_parsed;
1204 ✗ gate_string_rtrim(&line, &line);
1205 ✗ if (gate_string_is_empty(&line))
1206 {
1207 /* skip empty lines */
1208 ✗ continue;
1209 }
1210
1211 ✗ ret = gate_yaml_parse_indent(&line, &current_indent);
1212 ✗ GATE_BREAK_IF_FAILED(ret);
1213
1214 ✗ entry_is_array = false;
1215 ✗ if (gate_string_starts_with_char(&line, '-'))
1216 {
1217 /* array entry: */
1218 ✗ pos = gate_string_find_first_not_of(&line, &indention_chars, 1);
1219 ✗ if (pos == GATE_STR_NPOS)
1220 {
1221 /* error case: empty array entry */
1222 ✗ ret = GATE_RESULT_INVALIDDATA;
1223 ✗ break;
1224 }
1225 ✗ entry_is_array = true;
1226 ✗ array_indent = current_indent;
1227 ✗ current_indent += (gate_uint16_t)pos;
1228 ✗ gate_string_substr(&line, &line, pos, GATE_STR_NPOS);
1229 }
1230
1231 ✗ if (NULL == gate_yaml_parse_entry(&line, &entry_prop, &entry_incomplete))
1232 {
1233 ✗ ret = GATE_RESULT_FAILED;
1234 ✗ break;
1235 }
1236
1237 ✗ if (indents[current_level] == GATE_YAML_UNKNOWN_NEXT_INDENT)
1238 {
1239 ✗ if ((current_level > 0) && (current_indent < indents[current_level - 1]))
1240 {
1241 /* new advanced indention must be greater than parent element */
1242 ✗ ret = GATE_RESULT_INVALIDHEADER;
1243 ✗ break;
1244 }
1245 ✗ indents[current_level] = current_indent;
1246 }
1247
1248
1249 ✗ while (current_indent < indents[current_level])
1250 {
1251 ✗ if (current_level == 0)
1252 {
1253 ✗ ret = GATE_RESULT_CRITICALERROR;
1254 ✗ break;
1255 }
1256
1257 ✗ ret = gate_yaml_integrate(&levels[current_level - 1], &keys[current_level], &levels[current_level]);
1258 ✗ GATE_BREAK_IF_FAILED(ret);
1259 ✗ gate_property_destroy(&levels[current_level]);
1260 ✗ gate_string_release(&keys[current_level]);
1261 ✗ indents[current_level] = GATE_YAML_UNKNOWN_NEXT_INDENT;
1262 ✗ --current_level;
1263 }
1264 ✗ GATE_BREAK_IF_FAILED(ret);
1265
1266 ✗ if (current_indent > indents[current_level])
1267 {
1268 /* unexpected indention */
1269 ✗ ret = GATE_RESULT_INVALIDHEADER;
1270 ✗ break;
1271 }
1272
1273 ✗ if (entry_incomplete)
1274 {
1275 ✗ ++current_level;
1276 ✗ gate_property_create_empty(&levels[current_level]);
1277 ✗ indents[current_level] = GATE_YAML_UNKNOWN_NEXT_INDENT;
1278 ✗ ret = gate_yaml_extract_name_of_incomplete_object(&entry_prop, &keys[current_level]);
1279 }
1280 else
1281 {
1282 ✗ ret = gate_yaml_merge_properties(&levels[current_level], &entry_prop, entry_is_array);
1283 }
1284 ✗ GATE_BREAK_IF_FAILED(ret);
1285
1286 ✗ gate_property_destroy(&entry_prop);
1287 ✗ gate_string_release(&line);
1288 }
1289
1290 } while (0);
1291
1292 ✗ if (GATE_SUCCEEDED(ret))
1293 {
1294 ✗ while (current_level > 0)
1295 {
1296 ✗ ret = gate_yaml_integrate(&levels[current_level - 1], &keys[current_level], &levels[current_level]);
1297 ✗ GATE_BREAK_IF_FAILED(ret);
1298 ✗ gate_property_destroy(&levels[current_level]);
1299 ✗ gate_string_release(&keys[current_level]);
1300 ✗ indents[current_level] = GATE_YAML_UNKNOWN_NEXT_INDENT;
1301 ✗ --current_level;
1302 }
1303 ✗ if (GATE_SUCCEEDED(ret))
1304 {
1305 ✗ gate_mem_copy(target_prop, &levels[0], sizeof(gate_property_t));
1306 ✗ gate_mem_clear(&levels[0], sizeof(gate_property_t));
1307 }
1308 }
1309
1310 ✗ if (result != NULL)
1311 {
1312 ✗ gate_mem_clear(result, sizeof(gate_yaml_result_t));
1313 ✗ if (GATE_SUCCEEDED(ret))
1314 {
1315 ✗ result->succeeded = true;
1316 }
1317 ✗ result->lines_processed = lines_parsed;
1318 ✗ result->chars_processed = 0;
1319 }
1320
1321 ✗ gate_property_destroy(&entry_prop);
1322 ✗ gate_string_release(&line);
1323 ✗ gate_string_release(&yaml);
1324
1325 ✗ for (index = 0; index != max_levels; ++index)
1326 {
1327 ✗ gate_property_destroy(&levels[index]);
1328 ✗ gate_string_release(&keys[index]);
1329 }
1330 ✗ return ret;
1331 }
1332
1333 ✗ gate_result_t gate_yaml_parse(gate_stream_t* input_source, gate_property_t* target_prop, gate_yaml_result_t* result)
1334 {
1335 ✗ gate_result_t ret = GATE_RESULT_FAILED;
1336 ✗ gate_stringstream_t* str_stream = NULL;
1337 ✗ gate_string_t str = GATE_STRING_INIT_EMPTY;
1338 do
1339 {
1340 ✗ str_stream = gate_stringstream_create(256);
1341 ✗ if (str_stream == NULL)
1342 {
1343 ✗ ret = GATE_RESULT_OUTOFMEMORY;
1344 ✗ break;
1345 }
1346 ✗ ret = gate_stream_transfer(input_source, (gate_stream_t*)str_stream);
1347 ✗ GATE_BREAK_IF_FAILED(ret);
1348
1349 ✗ ret = gate_stringstream_to_string(str_stream, &str);
1350 ✗ GATE_BREAK_IF_FAILED(ret);
1351
1352 ✗ ret = gate_yaml_parse_string(&str, target_prop, result);
1353 } while (0);
1354
1355 ✗ gate_string_release(&str);
1356
1357 ✗ if (str_stream != NULL)
1358 {
1359 ✗ gate_object_release(str_stream);
1360 }
1361 ✗ return ret;
1362 }
1363
1364
1365
1366 ✗ static gate_result_t gate_yaml_print_bool(gate_stream_t* stream, gate_bool_t value)
1367 {
1368 ✗ return gate_stream_print_cstr(stream, value ? "true" : "false");
1369 }
1370
1371 ✗ static gate_result_t gate_yaml_print_int(gate_stream_t* stream, gate_int64_t value)
1372 {
1373 ✗ return gate_stream_print_int64(stream, value);
1374 }
1375
1376 ✗ static gate_result_t gate_yaml_print_real(gate_stream_t* stream, gate_real64_t value)
1377 {
1378 ✗ return gate_stream_print_real(stream, value, 0, gate_math_decimal_length(value), 0);
1379 }
1380
1381 ✗ static gate_result_t gate_yaml_print_string(gate_stream_t* stream, gate_string_t const* value)
1382 {
1383 ✗ gate_result_t ret = GATE_RESULT_FAILED;
1384 char const* ptr;
1385 gate_size_t len;
1386 gate_size_t written;
1387 char chr;
1388
1389 ✗ if (gate_string_count_chars(value, ' ')
1390 ✗ + gate_string_count_chars(value, ':')
1391 ✗ + gate_string_count_chars(value, '\"')
1392 ✗ + gate_string_count_chars(value, '\'')
1393 ✗ + gate_string_count_chars(value, '\n')
1394 )
1395 {
1396 do
1397 {
1398 ✗ ret = gate_stream_write(stream, "\"", 1, &written);
1399 ✗ GATE_BREAK_IF_FAILED(ret);
1400
1401 ✗ if (value)
1402 {
1403 ✗ ptr = value->str;
1404 ✗ len = value->length;
1405 ✗ while (len-- != 0)
1406 {
1407 ✗ chr = *ptr;
1408 ✗ switch (chr)
1409 {
1410 ✗ case '\"':
1411 case '\'':
1412 ✗ ret = gate_stream_write_block(stream, "\\", 1, &written);
1413 ✗ break;
1414 ✗ case '\r':
1415 ✗ ret = gate_stream_write_block(stream, "\\", 1, &written);
1416 ✗ chr = 'r';
1417 ✗ break;
1418 ✗ case '\n':
1419 ✗ ret = gate_stream_write_block(stream, "\\", 1, &written);
1420 ✗ chr = 'n';
1421 ✗ break;
1422 ✗ default:
1423 ✗ break;
1424 }
1425 ✗ ret = gate_stream_write(stream, &chr, 1, &written);
1426 ✗ ++ptr;
1427 }
1428 }
1429
1430 ✗ ret = gate_stream_write(stream, "\"", 1, &written);
1431 ✗ GATE_BREAK_IF_FAILED(ret);
1432 } while (0);
1433 ✗ return ret;
1434 }
1435 else
1436 {
1437 ✗ return gate_stream_print_string(stream, value);
1438 }
1439 }
1440
1441 static gate_result_t gate_yaml_print_inline(gate_property_t const* prop, gate_stream_t* stream);
1442
1443 ✗ static gate_result_t gate_yaml_print_array(gate_stream_t* stream, gate_arraylist_t value)
1444 {
1445 gate_result_t ret;
1446 ✗ gate_size_t count = gate_arraylist_length(value);
1447 gate_size_t index;
1448 gate_property_t const* prop;
1449 do
1450 {
1451 ✗ ret = gate_stream_print_cstr(stream, "[ ");
1452 ✗ GATE_BREAK_IF_FAILED(ret);
1453
1454 ✗ for (index = 0; index != count; ++index)
1455 {
1456 ✗ if (index != 0)
1457 {
1458 ✗ ret = gate_stream_print_cstr(stream, ", ");
1459 ✗ GATE_BREAK_IF_FAILED(ret);
1460 }
1461
1462 ✗ prop = (gate_property_t const*)gate_arraylist_get(value, index);
1463 ✗ if (prop != NULL)
1464 {
1465 ✗ ret = gate_yaml_print_inline(prop, stream);
1466 ✗ GATE_BREAK_IF_FAILED(ret);
1467 }
1468 }
1469 ✗ GATE_BREAK_IF_FAILED(ret);
1470
1471 ✗ ret = gate_stream_print_cstr(stream, " ]");
1472 ✗ GATE_BREAK_IF_FAILED(ret);
1473
1474 } while (0);
1475 ✗ return ret;
1476 }
1477
1478 ✗ static gate_result_t gate_yaml_print_object(gate_stream_t* stream, gate_property_t const* value)
1479 {
1480 gate_result_t ret;
1481 gate_size_t count;
1482 gate_size_t index;
1483 ✗ gate_array_t names = GATE_INIT_EMPTY;
1484 gate_property_t const* prop;
1485 gate_string_t const* ptr_name;
1486
1487 do
1488 {
1489 ✗ if (!gate_property_member_names(value, &names))
1490 {
1491 ✗ ret = GATE_RESULT_INVALIDCONTENT;
1492 ✗ break;
1493 }
1494
1495 ✗ count = gate_array_length(&names);
1496
1497 ✗ ret = gate_stream_print_cstr(stream, "{ ");
1498 ✗ GATE_BREAK_IF_FAILED(ret);
1499
1500 ✗ for (index = 0; index != count; ++index)
1501 {
1502 ✗ ptr_name = (gate_string_t const*)gate_array_get(&names, index);
1503 ✗ if (ptr_name)
1504 {
1505 ✗ prop = gate_property_member_get(value, ptr_name);
1506 ✗ if (prop)
1507 {
1508 ✗ if (index != 0)
1509 {
1510 ✗ ret = gate_stream_print_cstr(stream, ", ");
1511 ✗ GATE_BREAK_IF_FAILED(ret);
1512 }
1513 ✗ ret = gate_yaml_print_string(stream, ptr_name);
1514 ✗ GATE_BREAK_IF_FAILED(ret);
1515 ✗ ret = gate_stream_print_cstr(stream, ": ");
1516 ✗ GATE_BREAK_IF_FAILED(ret);
1517 ✗ ret = gate_yaml_print_inline(prop, stream);
1518 ✗ GATE_BREAK_IF_FAILED(ret);
1519 }
1520 }
1521 }
1522 ✗ GATE_BREAK_IF_FAILED(ret);
1523
1524 ✗ ret = gate_stream_print_cstr(stream, " }");
1525 ✗ GATE_BREAK_IF_FAILED(ret);
1526
1527 } while (0);
1528
1529 ✗ gate_array_release(&names);
1530 ✗ return ret;
1531 }
1532
1533 /*
1534 static gate_result_t gate_yaml_indent(gate_stream_t* stream, char const* spaces, gate_uint16_t* indent_stack, gate_size_t indent_index)
1535 {
1536 gate_string_t sp;
1537 gate_string_create_static_len(&sp, spaces, indent_stack[indent_index]);
1538 return gate_stream_print_string(stream, &sp);
1539 }
1540 */
1541
1542 ✗ static gate_result_t gate_yaml_print_inline(gate_property_t const* prop, gate_stream_t* stream)
1543 {
1544 ✗ gate_result_t ret = GATE_RESULT_FAILED;
1545 ✗ gate_uint32_t prop_type = gate_property_get_type(prop);
1546 ✗ switch (prop_type)
1547 {
1548 ✗ case GATE_PROPERTY_TYPE_EMPTY:
1549 {
1550 ✗ break;
1551 }
1552 ✗ case GATE_PROPERTY_TYPE_BOOL:
1553 {
1554 ✗ ret = gate_yaml_print_bool(stream, prop->data.bool_value);
1555 ✗ break;
1556 }
1557 ✗ case GATE_PROPERTY_TYPE_INT:
1558 {
1559 ✗ ret = gate_yaml_print_int(stream, prop->data.int_value);
1560 ✗ break;
1561 }
1562 ✗ case GATE_PROPERTY_TYPE_REAL:
1563 {
1564 ✗ ret = gate_yaml_print_real(stream, prop->data.real_value);
1565 ✗ break;
1566 }
1567 ✗ case GATE_PROPERTY_TYPE_STRING:
1568 {
1569 ✗ ret = gate_yaml_print_string(stream, &prop->data.string_value);
1570 ✗ break;
1571 }
1572 ✗ case GATE_PROPERTY_TYPE_ARRAY:
1573 {
1574 ✗ ret = gate_yaml_print_array(stream, prop->data.array_value);
1575 ✗ break;
1576 }
1577 ✗ case GATE_PROPERTY_TYPE_OBJECT:
1578 {
1579 ✗ ret = gate_yaml_print_object(stream, prop);
1580 ✗ break;
1581 }
1582 ✗ default:
1583 {
1584 ✗ ret = GATE_RESULT_NOTSUPPORTED;
1585 ✗ break;
1586 }
1587 }
1588 ✗ return ret;
1589 }
1590
1591 ✗ static gate_result_t gate_yaml_print_spaces(gate_size_t count, gate_stream_t* stream)
1592 {
1593 static gate_string_t const spaces = GATE_STRING_INIT_STATIC(" ");
1594 ✗ gate_result_t ret = GATE_RESULT_OK;
1595 gate_size_t len;
1596 gate_size_t lenwritten;
1597 ✗ while (count > 0)
1598 {
1599 ✗ len = (count > spaces.length) ? spaces.length : count;
1600 ✗ ret = gate_stream_write_block(stream, spaces.str, len, &lenwritten);
1601 ✗ GATE_BREAK_IF_FAILED(ret);
1602 ✗ count -= lenwritten;
1603 }
1604 ✗ return ret;
1605 }
1606
1607 ✗ static gate_result_t gate_yaml_print_indention(gate_stream_t* stream, gate_size_t spaces, gate_bool_t array_indicator)
1608 {
1609 gate_result_t ret;
1610 do
1611 {
1612 ✗ if ((spaces < 2) && array_indicator)
1613 {
1614 ✗ ret = GATE_RESULT_INVALIDSTATE;
1615 ✗ break;
1616 }
1617 ✗ if (array_indicator)
1618 {
1619 ✗ ret = gate_yaml_print_spaces(spaces - 2, stream);
1620 ✗ GATE_BREAK_IF_FAILED(ret);
1621 ✗ ret = gate_stream_print_cstr(stream, "- ");
1622 ✗ GATE_BREAK_IF_FAILED(ret);
1623 }
1624 else
1625 {
1626 ✗ ret = gate_yaml_print_spaces(spaces, stream);
1627 ✗ GATE_BREAK_IF_FAILED(ret);
1628 }
1629 } while (0);
1630 ✗ return ret;
1631 }
1632
1633 ✗ static gate_result_t gate_yaml_print(gate_property_t const* prop, gate_stream_t* stream, gate_size_t spaces, gate_bool_t array_indicator)
1634 {
1635 ✗ gate_result_t ret = GATE_RESULT_FAILED;
1636 ✗ gate_uint32_t prop_type = gate_property_get_type(prop);
1637 gate_property_t const* ptr_item;
1638 gate_size_t count, index;
1639 ✗ gate_array_t names = GATE_INIT_EMPTY;
1640 gate_string_t const* ptr_name;
1641
1642 do
1643 {
1644 ✗ switch (prop_type)
1645 {
1646 ✗ case GATE_PROPERTY_TYPE_BOOL:
1647 {
1648 ✗ ret = gate_yaml_print_indention(stream, spaces, array_indicator);
1649 ✗ GATE_BREAK_IF_FAILED(ret);
1650 ✗ ret = gate_yaml_print_bool(stream, prop->data.bool_value);
1651 ✗ GATE_BREAK_IF_FAILED(ret);
1652 ✗ ret = gate_stream_println_cstr(stream, NULL);
1653 ✗ break;
1654 }
1655 ✗ case GATE_PROPERTY_TYPE_INT:
1656 {
1657 ✗ ret = gate_yaml_print_indention(stream, spaces, array_indicator);
1658 ✗ GATE_BREAK_IF_FAILED(ret);
1659 ✗ ret = gate_yaml_print_int(stream, prop->data.int_value);
1660 ✗ GATE_BREAK_IF_FAILED(ret);
1661 ✗ ret = gate_stream_println_cstr(stream, NULL);
1662 ✗ break;
1663 }
1664 ✗ case GATE_PROPERTY_TYPE_REAL:
1665 {
1666 ✗ ret = gate_yaml_print_indention(stream, spaces, array_indicator);
1667 ✗ GATE_BREAK_IF_FAILED(ret);
1668 ✗ ret = gate_yaml_print_real(stream, prop->data.real_value);
1669 ✗ GATE_BREAK_IF_FAILED(ret);
1670 ✗ ret = gate_stream_println_cstr(stream, NULL);
1671 ✗ break;
1672 }
1673 ✗ case GATE_PROPERTY_TYPE_STRING:
1674 {
1675 ✗ ret = gate_yaml_print_indention(stream, spaces, array_indicator);
1676 ✗ GATE_BREAK_IF_FAILED(ret);
1677 ✗ ret = gate_yaml_print_string(stream, &prop->data.string_value);
1678 ✗ GATE_BREAK_IF_FAILED(ret);
1679 ✗ ret = gate_stream_println_cstr(stream, NULL);
1680 ✗ break;
1681 }
1682 ✗ case GATE_PROPERTY_TYPE_ARRAY:
1683 {
1684 ✗ count = gate_property_array_length(prop);
1685 ✗ if (count == 0)
1686 {
1687 ✗ ret = gate_yaml_print_indention(stream, spaces, array_indicator);
1688 ✗ GATE_BREAK_IF_FAILED(ret);
1689 ✗ ret = gate_stream_println_cstr(stream, "[]");
1690 }
1691 else
1692 {
1693 ✗ for (index = 0; index != count; ++index)
1694 {
1695 ✗ ptr_item = gate_property_array_get(prop, index);
1696 ✗ if (ptr_item)
1697 {
1698 ✗ ret = gate_yaml_print(ptr_item, stream, spaces + 2, true);
1699 ✗ GATE_BREAK_IF_FAILED(ret);
1700 }
1701 }
1702 }
1703 ✗ break;
1704 }
1705 ✗ case GATE_PROPERTY_TYPE_OBJECT:
1706 {
1707 ✗ if (NULL == gate_property_member_names(prop, &names))
1708 {
1709 ✗ ret = GATE_RESULT_FAILED;
1710 ✗ break;
1711 }
1712 ✗ count = gate_array_length(&names);
1713 ✗ if (count == 0)
1714 {
1715 ✗ ret = gate_yaml_print_indention(stream, spaces, array_indicator);
1716 ✗ GATE_BREAK_IF_FAILED(ret);
1717 ✗ ret = gate_stream_print_cstr(stream, "{}");
1718 ✗ GATE_BREAK_IF_FAILED(ret);
1719 }
1720 else
1721 {
1722 ✗ for (index = 0; index != count; ++index)
1723 {
1724 ✗ ptr_name = (gate_string_t const*)gate_array_get(&names, index);
1725 ✗ if (!ptr_name)
1726 {
1727 ✗ continue;
1728 }
1729 ✗ ptr_item = gate_property_member_get(prop, ptr_name);
1730 ✗ if (!ptr_item)
1731 {
1732 ✗ continue;
1733 }
1734 ✗ ret = gate_yaml_print_indention(stream, spaces, array_indicator);
1735 ✗ GATE_BREAK_IF_FAILED(ret);
1736 ✗ ret = gate_yaml_print_string(stream, ptr_name);
1737 ✗ GATE_BREAK_IF_FAILED(ret);
1738 ✗ ret = gate_stream_print_cstr(stream, ": ");
1739 ✗ GATE_BREAK_IF_FAILED(ret);
1740 ✗ switch (gate_property_get_type(ptr_item))
1741 {
1742 ✗ case GATE_PROPERTY_TYPE_BOOL:
1743 case GATE_PROPERTY_TYPE_INT:
1744 case GATE_PROPERTY_TYPE_REAL:
1745 case GATE_PROPERTY_TYPE_STRING:
1746 {
1747 ✗ ret = gate_yaml_print_inline(ptr_item, stream);
1748 ✗ GATE_BREAK_IF_FAILED(ret);
1749 ✗ ret = gate_stream_println_cstr(stream, NULL);
1750 ✗ break;
1751 }
1752 ✗ case GATE_PROPERTY_TYPE_ARRAY:
1753 {
1754 ✗ if (gate_property_array_length(ptr_item) == 0)
1755 {
1756 ✗ ret = gate_yaml_print_inline(ptr_item, stream);
1757 ✗ GATE_BREAK_IF_FAILED(ret);
1758 ✗ ret = gate_stream_println_cstr(stream, NULL);
1759 }
1760 else
1761 {
1762 ✗ ret = gate_stream_println_cstr(stream, NULL);
1763 ✗ GATE_BREAK_IF_FAILED(ret);
1764 ✗ ret = gate_yaml_print(ptr_item, stream, spaces + 2, false);
1765 }
1766 ✗ break;
1767 }
1768 ✗ case GATE_PROPERTY_TYPE_OBJECT:
1769 {
1770 ✗ if (gate_property_member_count(ptr_item) == 0)
1771 {
1772 ✗ ret = gate_yaml_print_inline(ptr_item, stream);
1773 ✗ GATE_BREAK_IF_FAILED(ret);
1774 ✗ ret = gate_stream_println_cstr(stream, NULL);
1775 }
1776 else
1777 {
1778 ✗ ret = gate_stream_println_cstr(stream, NULL);
1779 ✗ GATE_BREAK_IF_FAILED(ret);
1780 ✗ ret = gate_yaml_print(ptr_item, stream, spaces + 2, false);
1781 }
1782 ✗ break;
1783 }
1784 }
1785 ✗ GATE_BREAK_IF_FAILED(ret);
1786 ✗ array_indicator = false;
1787 } /* for() */
1788 }
1789 ✗ break;
1790 }
1791 ✗ case GATE_PROPERTY_TYPE_EMPTY:
1792 default:
1793 {
1794 ✗ ret = GATE_RESULT_NOTSUPPORTED;
1795 ✗ break;
1796 }
1797 }
1798 } while (0);
1799
1800 ✗ gate_array_release(&names);
1801
1802 ✗ return ret;
1803 }
1804
1805 ✗ gate_result_t gate_yaml_build(gate_property_t const* prop, gate_stream_t* dest_builder)
1806 {
1807 ✗ gate_result_t ret = GATE_RESULT_NOTIMPLEMENTED;
1808
1809 char spaces[4096 * 2];
1810 gate_uint16_t indent_stack[1024];
1811
1812 ✗ gate_mem_fill(spaces, ' ', sizeof(spaces));
1813 ✗ gate_mem_clear(indent_stack, sizeof(indent_stack));
1814
1815 ✗ ret = gate_yaml_print(prop, dest_builder, 0, false);
1816
1817 ✗ return ret;
1818 }
1819
1820 ✗ gate_result_t gate_yaml_build_string(gate_property_t const* prop, gate_string_t* output)
1821 {
1822 ✗ gate_result_t ret = GATE_RESULT_FAILED;
1823 ✗ gate_stringstream_t* str_stream = NULL;
1824
1825 do
1826 {
1827 ✗ str_stream = gate_stringstream_create(256);
1828 ✗ if (str_stream == NULL)
1829 {
1830 ✗ ret = GATE_RESULT_OUTOFMEMORY;
1831 ✗ break;
1832 }
1833
1834 ✗ ret = gate_yaml_build(prop, (gate_stream_t*)str_stream);
1835 ✗ GATE_BREAK_IF_FAILED(ret);
1836
1837 ✗ ret = gate_stringstream_to_string(str_stream, output);
1838 } while (0);
1839
1840 ✗ if (str_stream)
1841 {
1842 ✗ gate_object_release(str_stream);
1843 }
1844 ✗ return ret;
1845 }
1846