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