GCC Code Coverage Report


Directory: src/gate/
File: src/gate/encode/json.c
Date: 2025-09-14 13:10:38
Exec Total Coverage
Lines: 331 446 74.2%
Functions: 12 13 92.3%
Branches: 119 220 54.1%

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