GCC Code Coverage Report


Directory: src/gate/
File: src/gate/encode/json.c
Date: 2025-12-12 23:40:09
Exec Total Coverage
Lines: 342 447 76.5%
Functions: 13 13 100.0%
Branches: 121 220 55.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/json.h"
30 #include "gate/results.h"
31 #include "gate/mathematics.h"
32 #include "gate/debugging.h"
33
34 static char const gate_json_escaped_chars[] = { 'r', 'n', 't', 'b', 'f', '\"', '\\' };
35 static char const gate_json_unescaped_chars[] = { '\r', '\n', '\t', '\b', '\f', '\"', '\\' };
36
37 static char const gate_json_array_open = '[';
38 static char const gate_json_array_close = ']';
39 static char const gate_json_object_open = '{';
40 static char const gate_json_object_close = '}';
41 static char const gate_json_comma = ',';
42 static char const gate_json_colon = ':';
43 static char const gate_json_dblquote = '\"';
44 static char const gate_json_quote = '\'';
45 static char const gate_json_space = ' ';
46 static char const gate_json_escape_char = '\\';
47
48 static gate_string_t const gate_json_null = GATE_STRING_INIT_STATIC("null");
49 static gate_string_t const gate_json_true = GATE_STRING_INIT_STATIC("true");
50 static gate_string_t const gate_json_false = GATE_STRING_INIT_STATIC("false");
51
52
53 2 gate_result_t gate_json_escape_text(gate_string_t const* source, gate_string_t* result)
54 {
55 2 gate_result_t ret = GATE_RESULT_FAILED;
56 2 gate_strbuilder_t builder = GATE_INIT_EMPTY;
57
58 do
59 {
60 2 char const* ptr = gate_string_ptr(source, 0);
61 2 gate_size_t length = gate_string_length(source);
62
63 char unicode_prefix[8];
64
65 2 unicode_prefix[0] = gate_json_escape_char;
66 2 unicode_prefix[1] = 'u';
67 2 gate_strbuilder_create(&builder, length);
68
69 2 ret = GATE_RESULT_OK;
70
71
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 2 times.
10 while (length != 0)
72 {
73 gate_size_t decoded;
74 char tmp_chr;
75 gate_size_t written;
76 8 gate_char32_t current_char = 0;
77
78 8 decoded = gate_char_read_utf8(ptr, length, &current_char);
79
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if (decoded == 0)
80 {
81 ret = GATE_RESULT_INVALIDINPUT;
82 break;
83 }
84 8 ptr += decoded;
85 8 length -= decoded;
86 8 written = 0;
87
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if (current_char >= 127)
88 {
89 /* non ASCII -> unicode */
90 if (current_char > 65535)
91 {
92 gate_str_print_hex_uint16(&unicode_prefix[2], sizeof(unicode_prefix) - 2, (gate_uint16_t)(current_char >> 16), false);
93 written += gate_strbuilder_append_text(&builder, unicode_prefix, 6);
94 current_char &= 0x0ffff;
95 }
96 gate_str_print_hex_uint16(&unicode_prefix[2], sizeof(unicode_prefix) - 2, (gate_uint16_t)current_char, false);
97 written += gate_strbuilder_append_text(&builder, unicode_prefix, 6);
98 }
99
2/4
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 8 times.
8 else if ((current_char < '0') || (current_char == '\\'))
100 {
101 /* outside of alphanumeric space */
102 gate_size_t pos;
103 tmp_chr = (char)current_char;
104 pos = gate_str_char_pos(gate_json_unescaped_chars, sizeof(gate_json_unescaped_chars), tmp_chr, 0);
105 if (pos != GATE_STR_NPOS)
106 {
107 /* char with special escape code */
108 written += gate_strbuilder_append_text(&builder, &gate_json_escape_char, 1);
109 written += gate_strbuilder_append_text(&builder, &gate_json_escaped_chars[pos], 1);
110 }
111 else if (current_char < 32)
112 {
113 /* control character -> encode as hex */
114 gate_str_print_hex_uint16(&unicode_prefix[2], sizeof(unicode_prefix) - 2, (gate_uint16_t)current_char, false);
115 written += gate_strbuilder_append_text(&builder, unicode_prefix, 6);
116 }
117 else
118 {
119 /* printable non-letter character like '$' or '%' */
120 written += gate_strbuilder_append_text(&builder, &tmp_chr, 1);
121 }
122 }
123 else
124 {
125 /* inside of alphanumeric space */
126 8 tmp_chr = (char)current_char;
127 8 written += gate_strbuilder_append_text(&builder, &tmp_chr, 1);
128 }
129
130
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if (written == 0)
131 {
132 ret = GATE_RESULT_OUTOFMEMORY;
133 break;
134 }
135 }
136
137
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (GATE_SUCCEEDED(ret))
138 {
139
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if (NULL == gate_strbuilder_to_string(&builder, result))
140 {
141 ret = GATE_RESULT_OUTOFMEMORY;
142 }
143 }
144 } while (0);
145
146 2 gate_strbuilder_release(&builder);
147 2 return ret;
148 }
149 346 gate_result_t gate_json_unescape_text(gate_string_t const* source, gate_string_t* result)
150 {
151 346 gate_result_t ret = GATE_RESULT_FAILED;
152 346 gate_strbuilder_t builder = GATE_INIT_EMPTY;
153
154 do
155 {
156 346 char const* ptr = gate_string_ptr(source, 0);
157 346 gate_size_t length = gate_string_length(source);
158
159 346 gate_strbuilder_create(&builder, length);
160
161 346 ret = GATE_RESULT_OK;
162
2/2
✓ Branch 0 taken 3773 times.
✓ Branch 1 taken 346 times.
4119 while (length != 0)
163 {
164 3773 gate_size_t written = 0;
165
1/2
✓ Branch 0 taken 3773 times.
✗ Branch 1 not taken.
3773 if (*ptr != gate_json_escape_char)
166 {
167 /* regular character */
168 3773 gate_strbuilder_append_text(&builder, ptr, 1);
169 3773 ++ptr;
170 3773 --length;
171 }
172 else
173 {
174 /* escaped character: */
175 gate_size_t pos;
176 if (--length == 0)
177 {
178 ret = GATE_RESULT_INVALIDINPUT;
179 break;
180 }
181 ++ptr;
182 pos = gate_str_char_pos(gate_json_escaped_chars, sizeof(gate_json_escaped_chars), *ptr, 0);
183 if (GATE_STR_NPOS != pos)
184 {
185 /* write known unescaped character */
186 written = gate_strbuilder_append_text(&builder, &gate_json_unescaped_chars[pos], 1);
187 }
188 else
189 {
190 /* unicode or unknown escaped character */
191 if (*ptr == 'u')
192 {
193 /* unicode char */
194 gate_uint64_t hex_chr;
195 gate_size_t encoded;
196 char unicode_buffer[8];
197
198 if (length < 5)
199 {
200 ret = GATE_RESULT_INVALIDINPUT;
201 break;
202 }
203 if (4 != gate_str_parse_hex_int(ptr + 1, 4, &hex_chr))
204 {
205 ret = GATE_RESULT_INVALIDINPUT;
206 break;
207 }
208 encoded = gate_char_write_utf8((gate_char32_t)hex_chr, unicode_buffer, sizeof(unicode_buffer));
209 written += gate_strbuilder_append_text(&builder, unicode_buffer, encoded);
210 ptr += 5;
211 length -= length;
212 }
213 else
214 {
215 /* unknown escape code -> just copy it to destination string */
216 written += gate_strbuilder_append_text(&builder, &gate_json_escape_char, 1);
217 written += gate_strbuilder_append_text(&builder, ptr, 1);
218 ++ptr;
219 --length;
220 }
221 }
222 }
223 } /* while(length != 0) */
224
225
1/2
✓ Branch 0 taken 346 times.
✗ Branch 1 not taken.
346 if (GATE_SUCCEEDED(ret))
226 {
227
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 346 times.
346 if (NULL == gate_strbuilder_to_string(&builder, result))
228 {
229 ret = GATE_RESULT_OUTOFMEMORY;
230 }
231 }
232
233 } while (0);
234
235 346 gate_strbuilder_release(&builder);
236 346 return ret;
237 }
238
239
240 346 static gate_result_t gate_json_parse_text(gate_string_t const* source, gate_string_t* dest, gate_size_t* chars_decoded)
241 {
242 346 gate_result_t ret = GATE_RESULT_NOMATCH; /* end-char not found*/
243 346 char const* ptr = source->str;
244 346 gate_size_t length = source->length;
245 346 char end_char = ptr[0];
246 346 gate_bool_t is_escaped = false;
247 346 gate_string_t content = GATE_STRING_INIT_EMPTY;
248 346 gate_size_t decoded = 0;
249
250 do
251 {
252
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 346 times.
346 if (length == 0)
253 {
254 ret = GATE_RESULT_INVALIDDATA;
255 break;
256 }
257
258 346 decoded = 1;
259 346 ++ptr;
260 346 --length;
261
1/2
✓ Branch 0 taken 4119 times.
✗ Branch 1 not taken.
4119 for (; length != 0; ++ptr, --length)
262 {
263 4119 ++decoded;
264
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4119 times.
4119 if (*ptr == gate_json_escape_char)
265 {
266 is_escaped = !is_escaped;
267 }
268 else
269 {
270
2/2
✓ Branch 0 taken 346 times.
✓ Branch 1 taken 3773 times.
4119 if (*ptr == end_char)
271 {
272
1/2
✓ Branch 0 taken 346 times.
✗ Branch 1 not taken.
346 if (!is_escaped)
273 {
274 /* end of string reached*/
275
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 346 times.
346 if (NULL == gate_string_substr(&content, source, 1, decoded - 2))
276 {
277 ret = GATE_RESULT_OUTOFMEMORY;
278 }
279 else
280 {
281 346 ret = gate_json_unescape_text(&content, dest);
282 }
283 346 break;
284 }
285 }
286 3773 is_escaped = false;
287 }
288 }
289
290
291 } while (0);
292
293
294
295
1/2
✓ Branch 0 taken 346 times.
✗ Branch 1 not taken.
346 if (chars_decoded != NULL)
296 {
297 346 *chars_decoded = decoded;
298 }
299
300 346 gate_string_release(&content);
301
302 346 return ret;
303 }
304
305 23 static gate_bool_t gate_json_is_numeric(gate_string_t const* text)
306 {
307 23 gate_bool_t ret = false;
308 23 char const* ptr = text->str;
309 23 gate_size_t length = text->length;
310
311 do
312 {
313
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
23 if (length == 0)
314 {
315 break;
316 }
317
2/4
✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 23 times.
23 if ((*ptr == '+') || (*ptr == '-'))
318 {
319 ++ptr;
320 --length;
321 if (length == 0)
322 {
323 break;
324 }
325 }
326
327 23 ret = gate_char_is_digit(*ptr);
328
329 } while (0);
330 23 return ret;
331 }
332
333 1181 static gate_size_t gate_json_ltrim(gate_string_t* text)
334 {
335 1181 gate_size_t trimmed = 0;
336 1181 gate_string_t new_text = GATE_STRING_INIT_EMPTY;
337
1/2
✓ Branch 1 taken 1181 times.
✗ Branch 2 not taken.
1181 if (NULL != gate_string_ltrim(&new_text, text))
338 {
339 1181 trimmed = new_text.str - text->str;
340 1181 gate_string_release(text);
341 1181 gate_string_duplicate(text, &new_text);
342 1181 gate_string_release(&new_text);
343 }
344 1181 return trimmed;
345 }
346 827 static gate_size_t gate_json_discard_chars(gate_string_t* text, gate_size_t char_count)
347 {
348 827 gate_size_t ret = 0;
349 827 gate_string_t tmp = GATE_STRING_INIT_EMPTY;
350 827 gate_size_t remove_length = gate_string_length(text);
351
1/2
✓ Branch 0 taken 827 times.
✗ Branch 1 not taken.
827 if (char_count < remove_length)
352 {
353 827 remove_length = char_count;
354 }
355
1/2
✓ Branch 1 taken 827 times.
✗ Branch 2 not taken.
827 if (NULL != gate_string_substr(&tmp, text, remove_length, GATE_STR_NPOS))
356 {
357 827 gate_string_release(text);
358 827 gate_string_duplicate(text, &tmp);
359 827 gate_string_release(&tmp);
360 827 ret = remove_length;
361 }
362 827 return ret;
363 }
364
365 10 static gate_result_t gate_json_parse_array(gate_string_t const* source, gate_property_t* target_prop, gate_json_result_t* result)
366 {
367 10 gate_result_t ret = GATE_RESULT_FAILED;
368 10 gate_string_t content = GATE_STRING_INIT_EMPTY;
369 10 gate_size_t used = 0;
370 gate_property_t item;
371 gate_json_result_t item_result;
372 gate_bool_t succeeded;
373
374 do
375 {
376
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
10 if (!gate_string_starts_with_char(source, gate_json_array_open))
377 {
378 ret = GATE_RESULT_INVALIDCONTENT;
379 break;
380 }
381
382
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 10 times.
10 if (NULL == gate_string_substr(&content, source, 1, gate_string_length(source) - 1))
383 {
384 ret = GATE_RESULT_OUTOFMEMORY;
385 break;
386 }
387 10 used += 1;
388
389 do
390 {
391 57 used += gate_json_ltrim(&content);
392
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 57 times.
57 if (gate_string_is_empty(&content))
393 {
394 ret = GATE_RESULT_INVALIDCONTENT;
395 break;
396 }
397
398
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 56 times.
57 if (gate_string_starts_with_char(&content, gate_json_array_close))
399 {
400 /* end of array reached */
401 1 ++used;
402 1 ret = GATE_RESULT_OK;
403 1 break;
404 }
405
406 56 ret = gate_json_parse_string(&content, &item, &item_result);
407
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 56 times.
56 if (GATE_FAILED(ret))
408 {
409 break;
410 }
411
412 56 used += item_result.chars_processed;
413 56 succeeded = (NULL != gate_property_array_add(target_prop, &item));
414 56 gate_property_destroy(&item);
415
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 56 times.
56 if (!succeeded)
416 {
417 ret = GATE_RESULT_OUTOFMEMORY;
418 break;
419 }
420 56 gate_json_discard_chars(&content, item_result.chars_processed);
421
422 56 used += gate_json_ltrim(&content);
423
424
2/2
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 47 times.
56 if (gate_string_starts_with_char(&content, gate_json_array_close))
425 {
426 /* end of array reached */
427 9 ++used;
428 9 ret = GATE_RESULT_OK;
429 9 break;
430 }
431
432
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 47 times.
47 if (!gate_string_starts_with_char(&content, gate_json_comma))
433 {
434 ret = GATE_RESULT_INVALIDCONTENT;
435 break;
436 }
437 47 used += gate_json_discard_chars(&content, 1);
438
1/2
✓ Branch 0 taken 47 times.
✗ Branch 1 not taken.
47 } while (GATE_SUCCEEDED(ret));
439
440 } while (0);
441
442 10 gate_string_release(&content);
443
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10 if (result != NULL)
444 {
445 10 result->succeeded = GATE_SUCCEEDED(ret);
446 10 result->chars_processed = used;
447 }
448 10 return ret;
449 }
450
451
452 82 static gate_result_t gate_json_parse_object(gate_string_t const* source, gate_property_t* target_prop, gate_json_result_t* result)
453 {
454 82 gate_result_t ret = GATE_RESULT_FAILED;
455 82 gate_size_t used = 0;
456 82 gate_string_t content = GATE_STRING_INIT_EMPTY;
457 82 gate_string_t prop_name = GATE_STRING_INIT_EMPTY;
458 82 gate_property_t prop_value = GATE_INIT_EMPTY;
459 gate_size_t item_chars_decoded;
460 82 gate_json_result_t prop_result = GATE_INIT_EMPTY;
461
462 do
463 {
464
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 82 times.
82 if (!gate_string_starts_with_char(source, gate_json_object_open))
465 {
466 ret = GATE_RESULT_INVALIDCONTENT;
467 break;
468 }
469
470
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 82 times.
82 if (NULL == gate_string_substr(&content, source, 1, gate_string_length(source) - 1))
471 {
472 ret = GATE_RESULT_OUTOFMEMORY;
473 break;
474 }
475 82 used += 1;
476
477 do
478 {
479 206 used += gate_json_ltrim(&content);
480
481
2/2
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 200 times.
206 if (gate_string_starts_with_char(&content, gate_json_object_close))
482 {
483 /* end of array reached */
484 6 ++used;
485 6 ret = GATE_RESULT_OK;
486 6 break;
487 }
488
489 200 item_chars_decoded = 0;
490 200 ret = gate_json_parse_text(&content, &prop_name, &item_chars_decoded);
491
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 200 times.
200 if (GATE_FAILED(ret))
492 {
493 break;
494 }
495 200 gate_json_discard_chars(&content, item_chars_decoded);
496 200 used += item_chars_decoded;
497
498 200 used += gate_json_ltrim(&content);
499
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 200 times.
200 if (!gate_string_starts_with_char(&content, gate_json_colon))
500 {
501 ret = GATE_RESULT_INVALIDCONTENT;
502 break;
503 }
504
505 200 used += gate_json_discard_chars(&content, 1);
506
507 200 used += gate_json_ltrim(&content);
508
509 200 ret = gate_json_parse_string(&content, &prop_value, &prop_result);
510
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 200 times.
200 if (GATE_FAILED(ret))
511 {
512 /* parsing failed */
513 break;
514 }
515
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 200 times.
200 if (NULL == gate_property_member_add(target_prop, &prop_name, &prop_value))
516 {
517 /* failed to add property as member to target (propably allocation trouble) */
518 ret = GATE_RESULT_OUTOFMEMORY;
519 break;
520 }
521
522 200 gate_json_discard_chars(&content, prop_result.chars_processed);
523 200 used += prop_result.chars_processed;
524
525 200 gate_string_release(&prop_name);
526 200 gate_property_destroy(&prop_value);
527
528 200 used += gate_json_ltrim(&content);
529
530
2/2
✓ Branch 1 taken 76 times.
✓ Branch 2 taken 124 times.
200 if (gate_string_starts_with_char(&content, gate_json_object_close))
531 {
532 /* end of object reached */
533 76 ++used;
534 76 ret = GATE_RESULT_OK;
535 76 break;
536 }
537
538
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 124 times.
124 if (!gate_string_starts_with_char(&content, gate_json_comma))
539 {
540 ret = GATE_RESULT_INVALIDCONTENT;
541 break;
542 }
543 124 used += gate_json_discard_chars(&content, 1);
544 /* ready to parse next member entry */
545
1/2
✓ Branch 0 taken 124 times.
✗ Branch 1 not taken.
124 } while (GATE_SUCCEEDED(ret));
546
547 } while (0);
548
549
1/2
✓ Branch 0 taken 82 times.
✗ Branch 1 not taken.
82 if (result != NULL)
550 {
551 82 result->succeeded = GATE_SUCCEEDED(ret);
552 82 result->chars_processed = used;
553 }
554
555 82 gate_string_release(&prop_name);
556 82 gate_property_destroy(&prop_value);
557 82 gate_string_release(&content);
558
559 82 return ret;
560 }
561
562
563 262 gate_result_t gate_json_parse_string(gate_string_t const* source, gate_property_t* prop, gate_json_result_t* result)
564 {
565 262 gate_result_t ret = GATE_RESULT_FAILED;
566 262 gate_size_t str_used = 0;
567 262 gate_string_t json = GATE_STRING_INIT_EMPTY;
568 262 gate_string_t tmp_str = GATE_STRING_INIT_EMPTY;
569 262 gate_size_t chars_decoded = 0;
570 262 gate_size_t chars_decoded2 = 0;
571 262 gate_json_result_t result_entry = GATE_INIT_EMPTY;
572 262 gate_int64_t i64 = 0;
573 262 gate_real64_t r64 = 0.0;
574
575 do
576 {
577
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 262 times.
262 if (NULL == gate_string_clone(&json, source))
578 {
579 ret = GATE_RESULT_OUTOFMEMORY;
580 break;
581 }
582
583 262 str_used += gate_json_ltrim(&json);
584
585
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 262 times.
262 if (gate_string_starts_with(&json, &gate_json_null))
586 {
587 /* NULL entry */
588 if (NULL == gate_property_create_empty(prop))
589 {
590 ret = GATE_RESULT_OUTOFMEMORY;
591 }
592 else
593 {
594 str_used += gate_string_length(&gate_json_null);
595 ret = GATE_RESULT_OK;
596 }
597 }
598
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 261 times.
262 else if (gate_string_starts_with(&json, &gate_json_true))
599 {
600 /* BOOLEAN TRUE entry */
601
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if (NULL == gate_property_create_bool(prop, true))
602 {
603 ret = GATE_RESULT_OUTOFMEMORY;
604 }
605 else
606 {
607 1 str_used += gate_string_length(&gate_json_true);
608 1 ret = GATE_RESULT_OK;
609 }
610 }
611
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 261 times.
261 else if (gate_string_starts_with(&json, &gate_json_false))
612 {
613 /* BOOLEAN FALSE entry */
614 if (NULL == gate_property_create_bool(prop, false))
615 {
616 ret = GATE_RESULT_OUTOFMEMORY;
617 }
618 else
619 {
620 str_used += gate_string_length(&gate_json_false);
621 ret = GATE_RESULT_OK;
622 }
623 }
624
3/4
✓ Branch 1 taken 115 times.
✓ Branch 2 taken 146 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 115 times.
261 else if (gate_string_starts_with_char(&json, gate_json_dblquote) || gate_string_starts_with_char(&json, gate_json_quote))
625 {
626 /* STRING entry */
627 146 ret = gate_json_parse_text(&json, &tmp_str, &chars_decoded);
628
1/2
✓ Branch 0 taken 146 times.
✗ Branch 1 not taken.
292 if (GATE_SUCCEEDED(ret))
629 {
630 146 str_used += chars_decoded;
631
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 146 times.
146 if (NULL == gate_property_create_string(prop, &tmp_str))
632 {
633 ret = GATE_RESULT_OUTOFMEMORY;
634 }
635 }
636 }
637
2/2
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 105 times.
115 else if (gate_string_starts_with_char(&json, gate_json_array_open))
638 {
639 /* ARRAY entry */
640
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
10 if (NULL == gate_property_create_array(prop, NULL, 0))
641 {
642 ret = GATE_RESULT_OUTOFMEMORY;
643 }
644 else
645 {
646 10 ret = gate_json_parse_array(&json, prop, &result_entry);
647
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10 if (GATE_SUCCEEDED(ret))
648 {
649 10 str_used += result_entry.chars_processed;
650 }
651 }
652 }
653
2/2
✓ Branch 1 taken 82 times.
✓ Branch 2 taken 23 times.
105 else if (gate_string_starts_with_char(&json, gate_json_object_open))
654 {
655 /* OBJECT entry */
656
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 82 times.
82 if (NULL == gate_property_create_object(prop))
657 {
658 ret = GATE_RESULT_OUTOFMEMORY;
659 }
660 else
661 {
662 82 ret = gate_json_parse_object(&json, prop, &result_entry);
663
1/2
✓ Branch 0 taken 82 times.
✗ Branch 1 not taken.
82 if (GATE_SUCCEEDED(ret))
664 {
665 82 str_used += result_entry.chars_processed;
666 }
667 }
668 }
669
2/2
✓ Branch 1 taken 21 times.
✓ Branch 2 taken 2 times.
23 else if (gate_json_is_numeric(&json))
670 {
671 /* NUMBER entry */
672 21 chars_decoded = gate_str_parse_int64(json.str, json.length, &i64);
673 21 chars_decoded2 = gate_str_parse_real(json.str, json.length, &r64);
674
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 21 times.
21 if (chars_decoded2 == 0)
675 {
676 ret = GATE_RESULT_INVALIDDATA;
677 }
678
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 13 times.
21 else if (chars_decoded2 > chars_decoded)
679 {
680 /* seems to be a REAL value */
681 8 str_used = chars_decoded2;
682
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
8 ret = (NULL == gate_property_create_real(prop, r64)) ? GATE_RESULT_OUTOFMEMORY : GATE_RESULT_OK;
683 }
684 else
685 {
686 /* seems to be an INT value */
687 13 str_used = chars_decoded;
688
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 13 times.
13 ret = (NULL == gate_property_create_int(prop, i64)) ? GATE_RESULT_OUTOFMEMORY : GATE_RESULT_OK;
689 }
690 }
691 else
692 {
693 /* unsupported or invalid data */
694 2 ret = GATE_RESULT_INVALIDDATA;
695 }
696
697 } while (0);
698
699 262 gate_string_release(&json);
700 262 gate_string_release(&tmp_str);
701
702
1/2
✓ Branch 0 taken 262 times.
✗ Branch 1 not taken.
262 if (result != NULL)
703 {
704 262 result->succeeded = GATE_SUCCEEDED(ret);
705 262 result->chars_processed = str_used;
706 }
707
708 262 return ret;
709 }
710
711 32 static gate_result_t gate_json_builder(gate_property_t const* prop, gate_strbuilder_t* dest_builder,
712 gate_uint32_t indent, gate_uint32_t indent_add, gate_bool_t is_member)
713 {
714 32 gate_result_t ret = GATE_RESULT_OK;
715 32 gate_uint32_t prop_type = gate_property_get_type(prop);
716 32 gate_size_t char_count = 0;
717 32 gate_bool_t bool_value = false;
718 32 gate_int64_t int_value = 0;
719 32 gate_real64_t real_value = 0.0;
720 32 gate_string_t string_value = GATE_STRING_INIT_EMPTY;
721 32 gate_string_t text = GATE_STRING_INIT_EMPTY;
722 32 gate_size_t index = 0, count = 0;
723 32 gate_property_t const* ptr_item = NULL;
724 32 gate_array_t names = GATE_INIT_EMPTY;
725 32 gate_string_t const* ptr_name = NULL;
726
727
4/4
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 10 times.
✓ Branch 3 taken 20 times.
32 if ((indent != 0) && !is_member)
728 {
729 10 char_count += gate_strbuilder_append_chars(dest_builder, indent, ' ');
730 }
731
732
6/8
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 16 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 4 times.
✓ Branch 6 taken 6 times.
✗ Branch 7 not taken.
32 switch (prop_type)
733 {
734 case GATE_PROPERTY_TYPE_EMPTY:
735 {
736 char_count += gate_strbuilder_append_string(dest_builder, &gate_json_null);
737 break;
738 }
739 2 case GATE_PROPERTY_TYPE_BOOL:
740 {
741 2 gate_property_get_bool(prop, &bool_value);
742
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (bool_value)
743 {
744 2 char_count += gate_strbuilder_append_string(dest_builder, &gate_json_true);
745 }
746 else
747 {
748 char_count += gate_strbuilder_append_string(dest_builder, &gate_json_false);
749 }
750 2 break;
751 }
752 16 case GATE_PROPERTY_TYPE_INT:
753 {
754 16 gate_property_get_int(prop, &int_value);
755 16 char_count += gate_strbuilder_append_int64(dest_builder, int_value);
756 16 break;
757 }
758 2 case GATE_PROPERTY_TYPE_REAL:
759 {
760 2 gate_property_get_real(prop, &real_value);
761 2 char_count += gate_strbuilder_append_real(dest_builder, real_value, 0, gate_math_decimal_length(real_value), 0);
762 2 break;
763 }
764 2 case GATE_PROPERTY_TYPE_STRING:
765 {
766 2 gate_property_get_string(prop, &string_value);
767 2 gate_json_escape_text(&string_value, &text);
768 2 char_count += gate_strbuilder_append_chars(dest_builder, 1, gate_json_dblquote);
769 2 char_count += gate_strbuilder_append_string(dest_builder, &text);
770 2 char_count += gate_strbuilder_append_chars(dest_builder, 1, gate_json_dblquote);
771 2 break;
772 }
773 4 case GATE_PROPERTY_TYPE_ARRAY:
774 {
775
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (is_member)
776 {
777 4 char_count += gate_strbuilder_append_text(dest_builder, GATE_STR_NEWLINE, GATE_STR_NEWLINE_LENGTH);
778 /*indent += indent_add;*/
779 4 char_count += gate_strbuilder_append_chars(dest_builder, indent, gate_json_space);
780 }
781 4 char_count += gate_strbuilder_append_chars(dest_builder, 1, gate_json_array_open);
782 4 count = gate_property_array_length(prop);
783
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (count != 0)
784 {
785
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 4 times.
14 for (index = 0; index != count; ++index)
786 {
787
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10 if (indent_add != 0)
788 {
789 10 char_count += gate_strbuilder_append_text(dest_builder, GATE_STR_NEWLINE, GATE_STR_NEWLINE_LENGTH);
790 }
791 10 ptr_item = gate_property_array_get(prop, index);
792 10 ret = gate_json_builder(ptr_item, dest_builder, indent + indent_add, indent_add, false);
793
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (GATE_FAILED(ret))
794 {
795 break;
796 }
797
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 4 times.
10 if (index + 1 < count)
798 {
799 6 char_count += gate_strbuilder_append_chars(dest_builder, 1, gate_json_comma);
800 }
801 }
802
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (indent_add != 0)
803 {
804 4 char_count += gate_strbuilder_append_text(dest_builder, GATE_STR_NEWLINE, GATE_STR_NEWLINE_LENGTH);
805 }
806
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (indent != 0)
807 {
808 4 char_count += gate_strbuilder_append_chars(dest_builder, indent, gate_json_space);
809 }
810 }
811 4 char_count += gate_strbuilder_append_chars(dest_builder, 1, gate_json_array_close);
812 4 break;
813 }
814 6 case GATE_PROPERTY_TYPE_OBJECT:
815 {
816
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (is_member)
817 {
818 char_count += gate_strbuilder_append_text(dest_builder, GATE_STR_NEWLINE, GATE_STR_NEWLINE_LENGTH);
819 /*indent += indent_add;*/
820 char_count += gate_strbuilder_append_chars(dest_builder, indent, gate_json_space);
821 }
822 6 char_count += gate_strbuilder_append_chars(dest_builder, 1, gate_json_object_open);
823
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 if (NULL != gate_property_member_names(prop, &names))
824 {
825 6 count = gate_array_length(&names);
826
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (count != 0)
827 {
828
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 6 times.
26 for (index = 0; index != count; ++index)
829 {
830
1/2
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
20 if (indent_add != 0)
831 {
832 20 char_count += gate_strbuilder_append_text(dest_builder, GATE_STR_NEWLINE, GATE_STR_NEWLINE_LENGTH);
833 20 char_count += gate_strbuilder_append_chars(dest_builder,
834 20 (gate_size_t)indent + (gate_size_t)indent_add,
835 gate_json_space);
836 }
837 20 char_count += gate_strbuilder_append_chars(dest_builder, 1, gate_json_dblquote);
838 20 ptr_name = (gate_string_t const*)gate_array_get(&names, index);
839
1/2
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
20 if (ptr_name)
840 {
841 20 gate_strbuilder_append_string(dest_builder, ptr_name);
842 }
843 20 char_count += gate_strbuilder_append_chars(dest_builder, 1, gate_json_dblquote);
844 20 char_count += gate_strbuilder_append_chars(dest_builder, 1, gate_json_colon);
845 20 char_count += gate_strbuilder_append_chars(dest_builder, 1, gate_json_space);
846
847 20 ptr_item = gate_property_member_get(prop, ptr_name);
848
849 20 ret = gate_json_builder(ptr_item, dest_builder, indent + indent_add, indent_add, true);
850
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
20 if (GATE_FAILED(ret))
851 {
852 break;
853 }
854
855
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 6 times.
20 if (index + 1 < count)
856 {
857 14 char_count += gate_strbuilder_append_chars(dest_builder, 1, gate_json_comma);
858 }
859 }
860
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (indent_add != 0)
861 {
862 6 char_count += gate_strbuilder_append_text(dest_builder, GATE_STR_NEWLINE, GATE_STR_NEWLINE_LENGTH);
863 }
864
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
6 if (indent != 0)
865 {
866 4 char_count += gate_strbuilder_append_chars(dest_builder, indent, gate_json_space);
867 }
868 }
869 }
870 6 char_count += gate_strbuilder_append_chars(dest_builder, 1, gate_json_object_close);
871 6 break;
872 }
873 default:
874 {
875 ret = GATE_RESULT_NOTSUPPORTED;
876 break;
877 }
878 }
879
880 32 gate_array_release(&names);
881 32 gate_string_release(&string_value);
882 32 gate_string_release(&text);
883
884
2/4
✓ Branch 0 taken 32 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 32 times.
32 if (GATE_SUCCEEDED(ret) && (char_count == 0))
885 {
886 ret = GATE_RESULT_OUTOFMEMORY;
887 }
888
889 32 return ret;
890 }
891
892
893 2 gate_result_t gate_json_build_string(gate_property_t const* prop, gate_strbuilder_t* dest_builder, gate_uint32_t line_indent)
894 {
895 2 return gate_json_builder(prop, dest_builder, 0, line_indent, false);
896 }
897
898 4 gate_result_t gate_json_parse(gate_stream_t* source, gate_property_t* target_prop, gate_json_result_t* result)
899 {
900 4 gate_result_t ret = GATE_RESULT_FAILED;
901 4 gate_stringstream_t* str_stream = NULL;
902 4 gate_string_t str = GATE_STRING_INIT_EMPTY;
903 do
904 {
905 4 str_stream = gate_stringstream_create(256);
906
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (str_stream == NULL)
907 {
908 ret = GATE_RESULT_OUTOFMEMORY;
909 break;
910 }
911 4 ret = gate_stream_transfer(source, (gate_stream_t*)str_stream);
912
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 GATE_BREAK_IF_FAILED(ret);
913
914 4 ret = gate_stringstream_get_current_view(str_stream, &str);
915
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 GATE_BREAK_IF_FAILED(ret);
916
917 4 ret = gate_json_parse_string(&str, target_prop, result);
918 } while (0);
919
920 4 gate_string_release(&str);
921
922
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (str_stream)
923 {
924 4 gate_object_release(str_stream);
925 }
926 4 return ret;
927 }
928
929 1 gate_result_t gate_json_build(gate_property_t const* prop, gate_stream_t* dest, gate_uint32_t line_indent)
930 {
931 1 gate_result_t ret = GATE_RESULT_FAILED;
932 1 gate_strbuilder_t builder = GATE_INIT_EMPTY;
933 1 gate_size_t written = 0;
934
935 do
936 {
937 1 gate_strbuilder_create(&builder, 256);
938 1 ret = gate_json_build_string(prop, &builder, line_indent);
939
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_BREAK_IF_FAILED(ret);
940
941 1 ret = gate_stream_write_block(dest, gate_strbuilder_ptr(&builder, 0), gate_strbuilder_length(&builder), &written);
942 } while (0);
943
944 1 gate_strbuilder_release(&builder);
945
946 1 return ret;
947 }
948