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