Line data Source code
1 : /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2 :
3 : /***
4 : This file is part of systemd.
5 :
6 : Copyright 2014 Lennart Poettering
7 :
8 : systemd is free software; you can redistribute it and/or modify it
9 : under the terms of the GNU Lesser General Public License as published by
10 : the Free Software Foundation; either version 2.1 of the License, or
11 : (at your option) any later version.
12 :
13 : systemd is distributed in the hope that it will be useful, but
14 : WITHOUT ANY WARRANTY; without even the implied warranty of
15 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 : Lesser General Public License for more details.
17 :
18 : You should have received a copy of the GNU Lesser General Public License
19 : along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 : ***/
21 :
22 : #include <sys/types.h>
23 : #include <math.h>
24 : #include "macro.h"
25 : #include "utf8.h"
26 : #include "json.h"
27 :
28 55 : int json_variant_new(JsonVariant **ret, JsonVariantType type) {
29 : JsonVariant *v;
30 :
31 55 : v = new0(JsonVariant, 1);
32 55 : if (!v)
33 0 : return -ENOMEM;
34 55 : v->type = type;
35 55 : *ret = v;
36 55 : return 0;
37 : }
38 :
39 42 : static int json_variant_deep_copy(JsonVariant *ret, JsonVariant *variant) {
40 : int r;
41 :
42 42 : assert(ret);
43 42 : assert(variant);
44 :
45 42 : ret->type = variant->type;
46 42 : ret->size = variant->size;
47 :
48 42 : if (variant->type == JSON_VARIANT_STRING) {
49 17 : ret->string = memdup(variant->string, variant->size+1);
50 17 : if (!ret->string)
51 0 : return -ENOMEM;
52 33 : } else if (variant->type == JSON_VARIANT_ARRAY || variant->type == JSON_VARIANT_OBJECT) {
53 : size_t i;
54 :
55 8 : ret->objects = new0(JsonVariant, variant->size);
56 8 : if (!ret->objects)
57 0 : return -ENOMEM;
58 :
59 27 : for (i = 0; i < variant->size; ++i) {
60 19 : r = json_variant_deep_copy(&ret->objects[i], &variant->objects[i]);
61 19 : if (r < 0)
62 0 : return r;
63 : }
64 : } else
65 17 : ret->value = variant->value;
66 :
67 42 : return 0;
68 : }
69 :
70 : static JsonVariant *json_object_unref(JsonVariant *variant);
71 :
72 42 : static JsonVariant *json_variant_unref_inner(JsonVariant *variant) {
73 42 : if (!variant)
74 0 : return NULL;
75 :
76 42 : if (variant->type == JSON_VARIANT_ARRAY || variant->type == JSON_VARIANT_OBJECT)
77 8 : return json_object_unref(variant);
78 34 : else if (variant->type == JSON_VARIANT_STRING)
79 17 : free(variant->string);
80 :
81 34 : return NULL;
82 : }
83 :
84 0 : static JsonVariant *json_raw_unref(JsonVariant *variant, size_t size) {
85 0 : if (!variant)
86 0 : return NULL;
87 :
88 0 : for (size_t i = 0; i < size; ++i)
89 0 : json_variant_unref_inner(&variant[i]);
90 :
91 0 : free(variant);
92 0 : return NULL;
93 : }
94 :
95 15 : static JsonVariant *json_object_unref(JsonVariant *variant) {
96 : size_t i;
97 :
98 15 : assert(variant);
99 :
100 15 : if (!variant->objects)
101 0 : return NULL;
102 :
103 57 : for (i = 0; i < variant->size; ++i)
104 42 : json_variant_unref_inner(&variant->objects[i]);
105 :
106 15 : free(variant->objects);
107 15 : return NULL;
108 : }
109 :
110 2 : static JsonVariant **json_variant_array_unref(JsonVariant **variant) {
111 2 : size_t i = 0;
112 2 : JsonVariant *p = NULL;
113 :
114 2 : if (!variant)
115 0 : return NULL;
116 :
117 52 : while((p = (variant[i++])) != NULL) {
118 48 : if (p->type == JSON_VARIANT_STRING)
119 10 : free(p->string);
120 48 : free(p);
121 : }
122 :
123 2 : free(variant);
124 :
125 2 : return NULL;
126 : }
127 :
128 4 : DEFINE_TRIVIAL_CLEANUP_FUNC(JsonVariant **, json_variant_array_unref);
129 :
130 7 : JsonVariant *json_variant_unref(JsonVariant *variant) {
131 7 : if (!variant)
132 0 : return NULL;
133 :
134 7 : if (variant->type == JSON_VARIANT_ARRAY || variant->type == JSON_VARIANT_OBJECT)
135 7 : json_object_unref(variant);
136 0 : else if (variant->type == JSON_VARIANT_STRING)
137 0 : free(variant->string);
138 :
139 7 : free(variant);
140 :
141 7 : return NULL;
142 : }
143 :
144 3 : char *json_variant_string(JsonVariant *variant){
145 3 : assert(variant);
146 3 : assert(variant->type == JSON_VARIANT_STRING);
147 :
148 3 : return variant->string;
149 : }
150 :
151 0 : bool json_variant_bool(JsonVariant *variant) {
152 0 : assert(variant);
153 0 : assert(variant->type == JSON_VARIANT_BOOLEAN);
154 :
155 0 : return variant->value.boolean;
156 : }
157 :
158 5 : intmax_t json_variant_integer(JsonVariant *variant) {
159 5 : assert(variant);
160 5 : assert(variant->type == JSON_VARIANT_INTEGER);
161 :
162 5 : return variant->value.integer;
163 : }
164 :
165 1 : double json_variant_real(JsonVariant *variant) {
166 1 : assert(variant);
167 1 : assert(variant->type == JSON_VARIANT_REAL);
168 :
169 1 : return variant->value.real;
170 : }
171 :
172 9 : JsonVariant *json_variant_element(JsonVariant *variant, unsigned index) {
173 9 : assert(variant);
174 9 : assert(variant->type == JSON_VARIANT_ARRAY || variant->type == JSON_VARIANT_OBJECT);
175 9 : assert(index < variant->size);
176 9 : assert(variant->objects);
177 :
178 9 : return &variant->objects[index];
179 : }
180 :
181 7 : JsonVariant *json_variant_value(JsonVariant *variant, const char *key) {
182 : size_t i;
183 :
184 7 : assert(variant);
185 7 : assert(variant->type == JSON_VARIANT_OBJECT);
186 7 : assert(variant->objects);
187 :
188 11 : for (i = 0; i < variant->size; i += 2) {
189 11 : JsonVariant *p = &variant->objects[i];
190 11 : if (p->type == JSON_VARIANT_STRING && streq(key, p->string))
191 7 : return &variant->objects[i + 1];
192 : }
193 :
194 0 : return NULL;
195 : }
196 :
197 94 : static void inc_lines(unsigned *line, const char *s, size_t n) {
198 94 : const char *p = s;
199 :
200 94 : if (!line)
201 94 : return;
202 :
203 : for (;;) {
204 : const char *f;
205 :
206 0 : f = memchr(p, '\n', n);
207 0 : if (!f)
208 0 : return;
209 :
210 0 : n -= (f - p) + 1;
211 0 : p = f + 1;
212 0 : (*line)++;
213 0 : }
214 : }
215 :
216 6 : static int unhex_ucs2(const char *c, uint16_t *ret) {
217 : int aa, bb, cc, dd;
218 : uint16_t x;
219 :
220 6 : assert(c);
221 6 : assert(ret);
222 :
223 6 : aa = unhexchar(c[0]);
224 6 : if (aa < 0)
225 0 : return -EINVAL;
226 :
227 6 : bb = unhexchar(c[1]);
228 6 : if (bb < 0)
229 1 : return -EINVAL;
230 :
231 5 : cc = unhexchar(c[2]);
232 5 : if (cc < 0)
233 0 : return -EINVAL;
234 :
235 5 : dd = unhexchar(c[3]);
236 5 : if (dd < 0)
237 0 : return -EINVAL;
238 :
239 15 : x = ((uint16_t) aa << 12) |
240 5 : ((uint16_t) bb << 8) |
241 5 : ((uint16_t) cc << 4) |
242 : ((uint16_t) dd);
243 :
244 5 : if (x <= 0)
245 0 : return -EINVAL;
246 :
247 5 : *ret = x;
248 :
249 5 : return 0;
250 : }
251 :
252 22 : static int json_parse_string(const char **p, char **ret) {
253 44 : _cleanup_free_ char *s = NULL;
254 22 : size_t n = 0, allocated = 0;
255 : const char *c;
256 :
257 22 : assert(p);
258 22 : assert(*p);
259 22 : assert(ret);
260 :
261 22 : c = *p;
262 :
263 22 : if (*c != '"')
264 0 : return -EINVAL;
265 :
266 22 : c++;
267 :
268 : for (;;) {
269 : int len;
270 :
271 : /* Check for EOF */
272 68 : if (*c == 0)
273 0 : return -EINVAL;
274 :
275 : /* Check for control characters 0x00..0x1f */
276 68 : if (*c > 0 && *c < ' ')
277 0 : return -EINVAL;
278 :
279 : /* Check for control character 0x7f */
280 68 : if (*c == 0x7f)
281 0 : return -EINVAL;
282 :
283 68 : if (*c == '"') {
284 19 : if (!s) {
285 1 : s = strdup("");
286 1 : if (!s)
287 0 : return -ENOMEM;
288 : } else
289 18 : s[n] = 0;
290 :
291 19 : *p = c + 1;
292 :
293 19 : *ret = s;
294 19 : s = NULL;
295 19 : return JSON_STRING;
296 : }
297 :
298 49 : if (*c == '\\') {
299 6 : char ch = 0;
300 6 : c++;
301 :
302 6 : if (*c == 0)
303 0 : return -EINVAL;
304 :
305 6 : if (IN_SET(*c, '"', '\\', '/'))
306 0 : ch = *c;
307 6 : else if (*c == 'b')
308 0 : ch = '\b';
309 6 : else if (*c == 'f')
310 0 : ch = '\f';
311 6 : else if (*c == 'n')
312 1 : ch = '\n';
313 5 : else if (*c == 'r')
314 0 : ch = '\r';
315 5 : else if (*c == 't')
316 0 : ch = '\t';
317 5 : else if (*c == 'u') {
318 : uint16_t x;
319 : int r;
320 :
321 5 : r = unhex_ucs2(c + 1, &x);
322 5 : if (r < 0)
323 4 : return r;
324 :
325 4 : c += 5;
326 :
327 4 : if (!GREEDY_REALLOC(s, allocated, n + 4))
328 0 : return -ENOMEM;
329 :
330 4 : if (!utf16_is_surrogate(x))
331 1 : n += utf8_encode_unichar(s + n, x);
332 3 : else if (utf16_is_trailing_surrogate(x))
333 1 : return -EINVAL;
334 : else {
335 : uint16_t y;
336 :
337 2 : if (c[0] != '\\' || c[1] != 'u')
338 2 : return -EINVAL;
339 :
340 1 : r = unhex_ucs2(c + 2, &y);
341 1 : if (r < 0)
342 0 : return r;
343 :
344 1 : c += 6;
345 :
346 1 : if (!utf16_is_trailing_surrogate(y))
347 0 : return -EINVAL;
348 :
349 1 : n += utf8_encode_unichar(s + n, utf16_surrogate_pair_to_unichar(x, y));
350 : }
351 :
352 2 : continue;
353 : } else
354 0 : return -EINVAL;
355 :
356 1 : if (!GREEDY_REALLOC(s, allocated, n + 2))
357 0 : return -ENOMEM;
358 :
359 1 : s[n++] = ch;
360 1 : c ++;
361 1 : continue;
362 : }
363 :
364 43 : len = utf8_encoded_valid_unichar(c);
365 43 : if (len < 0)
366 0 : return len;
367 :
368 43 : if (!GREEDY_REALLOC(s, allocated, n + len + 1))
369 0 : return -ENOMEM;
370 :
371 43 : memcpy(s + n, c, len);
372 43 : n += len;
373 43 : c += len;
374 46 : }
375 : }
376 :
377 14 : static int json_parse_number(const char **p, union json_value *ret) {
378 14 : bool negative = false, exponent_negative = false, is_double = false;
379 14 : double x = 0.0, y = 0.0, exponent = 0.0, shift = 1.0;
380 14 : intmax_t i = 0;
381 : const char *c;
382 :
383 14 : assert(p);
384 14 : assert(*p);
385 14 : assert(ret);
386 :
387 14 : c = *p;
388 :
389 14 : if (*c == '-') {
390 1 : negative = true;
391 1 : c++;
392 : }
393 :
394 14 : if (*c == '0')
395 2 : c++;
396 : else {
397 12 : if (!strchr("123456789", *c) || *c == 0)
398 0 : return -EINVAL;
399 :
400 : do {
401 15 : if (!is_double) {
402 : int64_t t;
403 :
404 15 : t = 10 * i + (*c - '0');
405 15 : if (t < i) /* overflow */
406 0 : is_double = false;
407 : else
408 15 : i = t;
409 : }
410 :
411 15 : x = 10.0 * x + (*c - '0');
412 15 : c++;
413 15 : } while (strchr("0123456789", *c) && *c != 0);
414 : }
415 :
416 14 : if (*c == '.') {
417 3 : is_double = true;
418 3 : c++;
419 :
420 3 : if (!strchr("0123456789", *c) || *c == 0)
421 0 : return -EINVAL;
422 :
423 : do {
424 6 : y = 10.0 * y + (*c - '0');
425 6 : shift = 10.0 * shift;
426 6 : c++;
427 6 : } while (strchr("0123456789", *c) && *c != 0);
428 : }
429 :
430 14 : if (*c == 'e' || *c == 'E') {
431 2 : is_double = true;
432 2 : c++;
433 :
434 2 : if (*c == '-') {
435 1 : exponent_negative = true;
436 1 : c++;
437 1 : } else if (*c == '+')
438 0 : c++;
439 :
440 2 : if (!strchr("0123456789", *c) || *c == 0)
441 0 : return -EINVAL;
442 :
443 : do {
444 2 : exponent = 10.0 * exponent + (*c - '0');
445 2 : c++;
446 2 : } while (strchr("0123456789", *c) && *c != 0);
447 : }
448 :
449 14 : *p = c;
450 :
451 14 : if (is_double) {
452 5 : ret->real = ((negative ? -1.0 : 1.0) * (x + (y / shift))) * exp10((exponent_negative ? -1.0 : 1.0) * exponent);
453 5 : return JSON_REAL;
454 : } else {
455 9 : ret->integer = negative ? -i : i;
456 9 : return JSON_INTEGER;
457 : }
458 : }
459 :
460 120 : int json_tokenize(
461 : const char **p,
462 : char **ret_string,
463 : union json_value *ret_value,
464 : void **state,
465 : unsigned *line) {
466 :
467 : const char *c;
468 : int t;
469 : int r;
470 :
471 : enum {
472 : STATE_NULL,
473 : STATE_VALUE,
474 : STATE_VALUE_POST,
475 : };
476 :
477 120 : assert(p);
478 120 : assert(*p);
479 120 : assert(ret_string);
480 120 : assert(ret_value);
481 120 : assert(state);
482 :
483 120 : t = PTR_TO_INT(*state);
484 120 : c = *p;
485 :
486 120 : if (t == STATE_NULL) {
487 30 : if (line)
488 0 : *line = 1;
489 30 : t = STATE_VALUE;
490 : }
491 :
492 : for (;;) {
493 : const char *b;
494 :
495 120 : b = c + strspn(c, WHITESPACE);
496 120 : if (*b == 0)
497 26 : return JSON_END;
498 :
499 94 : inc_lines(line, c, b - c);
500 94 : c = b;
501 :
502 94 : switch (t) {
503 :
504 : case STATE_VALUE:
505 :
506 63 : if (*c == '{') {
507 8 : *ret_string = NULL;
508 8 : *ret_value = JSON_VALUE_NULL;
509 8 : *p = c + 1;
510 8 : *state = INT_TO_PTR(STATE_VALUE);
511 8 : return JSON_OBJECT_OPEN;
512 :
513 55 : } else if (*c == '}') {
514 2 : *ret_string = NULL;
515 2 : *ret_value = JSON_VALUE_NULL;
516 2 : *p = c + 1;
517 2 : *state = INT_TO_PTR(STATE_VALUE_POST);
518 2 : return JSON_OBJECT_CLOSE;
519 :
520 53 : } else if (*c == '[') {
521 7 : *ret_string = NULL;
522 7 : *ret_value = JSON_VALUE_NULL;
523 7 : *p = c + 1;
524 7 : *state = INT_TO_PTR(STATE_VALUE);
525 7 : return JSON_ARRAY_OPEN;
526 :
527 46 : } else if (*c == ']') {
528 2 : *ret_string = NULL;
529 2 : *ret_value = JSON_VALUE_NULL;
530 2 : *p = c + 1;
531 2 : *state = INT_TO_PTR(STATE_VALUE_POST);
532 2 : return JSON_ARRAY_CLOSE;
533 :
534 44 : } else if (*c == '"') {
535 22 : r = json_parse_string(&c, ret_string);
536 22 : if (r < 0)
537 3 : return r;
538 :
539 19 : *ret_value = JSON_VALUE_NULL;
540 19 : *p = c;
541 19 : *state = INT_TO_PTR(STATE_VALUE_POST);
542 19 : return r;
543 :
544 22 : } else if (strchr("-0123456789", *c)) {
545 14 : r = json_parse_number(&c, ret_value);
546 14 : if (r < 0)
547 0 : return r;
548 :
549 14 : *ret_string = NULL;
550 14 : *p = c;
551 14 : *state = INT_TO_PTR(STATE_VALUE_POST);
552 14 : return r;
553 :
554 8 : } else if (startswith(c, "true")) {
555 2 : *ret_string = NULL;
556 2 : ret_value->boolean = true;
557 2 : *p = c + 4;
558 2 : *state = INT_TO_PTR(STATE_VALUE_POST);
559 2 : return JSON_BOOLEAN;
560 :
561 6 : } else if (startswith(c, "false")) {
562 2 : *ret_string = NULL;
563 2 : ret_value->boolean = false;
564 2 : *p = c + 5;
565 2 : *state = INT_TO_PTR(STATE_VALUE_POST);
566 2 : return JSON_BOOLEAN;
567 :
568 4 : } else if (startswith(c, "null")) {
569 3 : *ret_string = NULL;
570 3 : *ret_value = JSON_VALUE_NULL;
571 3 : *p = c + 4;
572 3 : *state = INT_TO_PTR(STATE_VALUE_POST);
573 3 : return JSON_NULL;
574 :
575 : } else
576 1 : return -EINVAL;
577 :
578 : case STATE_VALUE_POST:
579 :
580 31 : if (*c == ':') {
581 9 : *ret_string = NULL;
582 9 : *ret_value = JSON_VALUE_NULL;
583 9 : *p = c + 1;
584 9 : *state = INT_TO_PTR(STATE_VALUE);
585 9 : return JSON_COLON;
586 22 : } else if (*c == ',') {
587 11 : *ret_string = NULL;
588 11 : *ret_value = JSON_VALUE_NULL;
589 11 : *p = c + 1;
590 11 : *state = INT_TO_PTR(STATE_VALUE);
591 11 : return JSON_COMMA;
592 11 : } else if (*c == '}') {
593 6 : *ret_string = NULL;
594 6 : *ret_value = JSON_VALUE_NULL;
595 6 : *p = c + 1;
596 6 : *state = INT_TO_PTR(STATE_VALUE_POST);
597 6 : return JSON_OBJECT_CLOSE;
598 5 : } else if (*c == ']') {
599 5 : *ret_string = NULL;
600 5 : *ret_value = JSON_VALUE_NULL;
601 5 : *p = c + 1;
602 5 : *state = INT_TO_PTR(STATE_VALUE_POST);
603 5 : return JSON_ARRAY_CLOSE;
604 : } else
605 0 : return -EINVAL;
606 : }
607 :
608 0 : }
609 : }
610 :
611 78 : static bool json_is_value(JsonVariant *var) {
612 78 : assert(var);
613 :
614 78 : return var->type != JSON_VARIANT_CONTROL;
615 : }
616 :
617 7 : static int json_scoped_parse(JsonVariant **tokens, size_t *i, size_t n, JsonVariant *scope) {
618 7 : bool arr = scope->type == JSON_VARIANT_ARRAY;
619 7 : int terminator = arr ? JSON_ARRAY_CLOSE : JSON_OBJECT_CLOSE;
620 7 : size_t allocated = 0, size = 0;
621 7 : JsonVariant *key = NULL, *value = NULL, *var = NULL, *items = NULL;
622 : enum {
623 : STATE_KEY,
624 : STATE_COLON,
625 : STATE_COMMA,
626 : STATE_VALUE
627 7 : } state = arr ? STATE_VALUE : STATE_KEY;
628 :
629 7 : assert(tokens);
630 7 : assert(i);
631 7 : assert(scope);
632 :
633 53 : while((var = *i < n ? tokens[(*i)++] : NULL) != NULL) {
634 : bool stopper;
635 : int r;
636 :
637 46 : stopper = !json_is_value(var) && var->value.integer == terminator;
638 :
639 46 : if (stopper) {
640 7 : if (state != STATE_COMMA && size > 0)
641 0 : goto error;
642 :
643 7 : goto out;
644 : }
645 :
646 39 : if (state == STATE_KEY) {
647 7 : if (var->type != JSON_VARIANT_STRING)
648 0 : goto error;
649 : else {
650 7 : key = var;
651 7 : state = STATE_COLON;
652 : }
653 : }
654 32 : else if (state == STATE_COLON) {
655 7 : if (key == NULL)
656 0 : goto error;
657 :
658 7 : if (json_is_value(var))
659 0 : goto error;
660 :
661 7 : if (var->value.integer != JSON_COLON)
662 0 : goto error;
663 :
664 7 : state = STATE_VALUE;
665 : }
666 25 : else if (state == STATE_VALUE) {
667 32 : _cleanup_json_variant_unref_ JsonVariant *v = NULL;
668 16 : size_t toadd = arr ? 1 : 2;
669 :
670 16 : if (!json_is_value(var)) {
671 5 : int type = (var->value.integer == JSON_ARRAY_OPEN) ? JSON_VARIANT_ARRAY : JSON_VARIANT_OBJECT;
672 :
673 5 : r = json_variant_new(&v, type);
674 5 : if (r < 0)
675 0 : goto error;
676 :
677 5 : r = json_scoped_parse(tokens, i, n, v);
678 5 : if (r < 0)
679 0 : goto error;
680 :
681 5 : value = v;
682 : }
683 : else
684 11 : value = var;
685 :
686 16 : if(!GREEDY_REALLOC(items, allocated, size + toadd))
687 0 : goto error;
688 :
689 16 : if (arr) {
690 9 : r = json_variant_deep_copy(&items[size], value);
691 9 : if (r < 0)
692 0 : goto error;
693 : } else {
694 7 : r = json_variant_deep_copy(&items[size], key);
695 7 : if (r < 0)
696 0 : goto error;
697 :
698 7 : r = json_variant_deep_copy(&items[size+1], value);
699 7 : if (r < 0)
700 0 : goto error;
701 : }
702 :
703 16 : size += toadd;
704 16 : state = STATE_COMMA;
705 : }
706 9 : else if (state == STATE_COMMA) {
707 9 : if (json_is_value(var))
708 0 : goto error;
709 :
710 9 : if (var->value.integer != JSON_COMMA)
711 0 : goto error;
712 :
713 9 : key = NULL;
714 9 : value = NULL;
715 :
716 9 : state = arr ? STATE_VALUE : STATE_KEY;
717 : }
718 : }
719 :
720 : error:
721 0 : json_raw_unref(items, size);
722 0 : return -EBADMSG;
723 :
724 : out:
725 7 : scope->size = size;
726 7 : scope->objects = items;
727 :
728 7 : return scope->type;
729 : }
730 :
731 2 : static int json_parse_tokens(JsonVariant **tokens, size_t ntokens, JsonVariant **rv) {
732 2 : size_t it = 0;
733 : int r;
734 : JsonVariant *e;
735 4 : _cleanup_json_variant_unref_ JsonVariant *p = NULL;
736 :
737 2 : assert(tokens);
738 2 : assert(ntokens);
739 :
740 2 : e = tokens[it++];
741 2 : r = json_variant_new(&p, JSON_VARIANT_OBJECT);
742 2 : if (r < 0)
743 0 : return r;
744 :
745 2 : if (e->type != JSON_VARIANT_CONTROL && e->value.integer != JSON_OBJECT_OPEN)
746 0 : return -EBADMSG;
747 :
748 2 : r = json_scoped_parse(tokens, &it, ntokens, p);
749 2 : if (r < 0)
750 0 : return r;
751 :
752 2 : *rv = p;
753 2 : p = NULL;
754 :
755 2 : return 0;
756 : }
757 :
758 2 : static int json_tokens(const char *string, size_t size, JsonVariant ***tokens, size_t *n) {
759 4 : _cleanup_free_ char *buf = NULL;
760 4 : _cleanup_(json_variant_array_unrefp) JsonVariant **items = NULL;
761 2 : union json_value v = {};
762 2 : void *json_state = NULL;
763 : const char *p;
764 : int t, r;
765 2 : size_t allocated = 0, s = 0;
766 :
767 2 : assert(string);
768 2 : assert(n);
769 :
770 2 : if (size <= 0)
771 0 : return -EBADMSG;
772 :
773 2 : buf = strndup(string, size);
774 2 : if (!buf)
775 0 : return -ENOMEM;
776 :
777 2 : p = buf;
778 : for (;;) {
779 100 : _cleanup_json_variant_unref_ JsonVariant *var = NULL;
780 100 : _cleanup_free_ char *rstr = NULL;
781 :
782 50 : t = json_tokenize(&p, &rstr, &v, &json_state, NULL);
783 :
784 50 : if (t < 0)
785 0 : return t;
786 50 : else if (t == JSON_END)
787 2 : break;
788 :
789 48 : if (t <= JSON_ARRAY_CLOSE) {
790 30 : r = json_variant_new(&var, JSON_VARIANT_CONTROL);
791 30 : if (r < 0)
792 0 : return r;
793 30 : var->value.integer = t;
794 : } else {
795 18 : switch (t) {
796 : case JSON_STRING:
797 10 : r = json_variant_new(&var, JSON_VARIANT_STRING);
798 10 : if (r < 0)
799 0 : return r;
800 10 : var->size = strlen(rstr);
801 10 : var->string = strdup(rstr);
802 10 : if (!var->string) {
803 0 : return -ENOMEM;
804 : }
805 10 : break;
806 : case JSON_INTEGER:
807 5 : r = json_variant_new(&var, JSON_VARIANT_INTEGER);
808 5 : if (r < 0)
809 0 : return r;
810 5 : var->value = v;
811 5 : break;
812 : case JSON_REAL:
813 1 : r = json_variant_new(&var, JSON_VARIANT_REAL);
814 1 : if (r < 0)
815 0 : return r;
816 1 : var->value = v;
817 1 : break;
818 : case JSON_BOOLEAN:
819 0 : r = json_variant_new(&var, JSON_VARIANT_BOOLEAN);
820 0 : if (r < 0)
821 0 : return r;
822 0 : var->value = v;
823 0 : break;
824 : case JSON_NULL:
825 2 : r = json_variant_new(&var, JSON_VARIANT_NULL);
826 2 : if (r < 0)
827 0 : return r;
828 2 : break;
829 : }
830 : }
831 :
832 48 : if (!GREEDY_REALLOC(items, allocated, s+2))
833 0 : return -ENOMEM;
834 :
835 48 : items[s++] = var;
836 48 : items[s] = NULL;
837 48 : var = NULL;
838 48 : }
839 :
840 2 : *n = s;
841 2 : *tokens = items;
842 2 : items = NULL;
843 :
844 2 : return 0;
845 : }
846 :
847 2 : int json_parse(const char *string, JsonVariant **rv) {
848 4 : _cleanup_(json_variant_array_unrefp) JsonVariant **s = NULL;
849 2 : JsonVariant *v = NULL;
850 2 : size_t n = 0;
851 : int r;
852 :
853 2 : assert(string);
854 2 : assert(rv);
855 :
856 2 : r = json_tokens(string, strlen(string), &s, &n);
857 2 : if (r < 0)
858 0 : return r;
859 :
860 2 : r = json_parse_tokens(s, n, &v);
861 2 : if (r < 0)
862 0 : return r;
863 :
864 2 : *rv = v;
865 2 : return 0;
866 : }
|