1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2014 Lennart Poettering
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.
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.
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/>.
23 #include <sys/types.h>
25 #include "alloc-util.h"
28 #include "hexdecoct.h"
29 #include "string-util.h"
32 int json_variant_new(JsonVariant
**ret
, JsonVariantType type
) {
35 v
= new0(JsonVariant
, 1);
43 static int json_variant_deep_copy(JsonVariant
*ret
, JsonVariant
*variant
) {
49 ret
->type
= variant
->type
;
50 ret
->size
= variant
->size
;
52 if (variant
->type
== JSON_VARIANT_STRING
) {
53 ret
->string
= memdup(variant
->string
, variant
->size
+1);
56 } else if (variant
->type
== JSON_VARIANT_ARRAY
|| variant
->type
== JSON_VARIANT_OBJECT
) {
59 ret
->objects
= new0(JsonVariant
, variant
->size
);
63 for (i
= 0; i
< variant
->size
; ++i
) {
64 r
= json_variant_deep_copy(&ret
->objects
[i
], &variant
->objects
[i
]);
69 ret
->value
= variant
->value
;
74 static JsonVariant
*json_object_unref(JsonVariant
*variant
);
76 static JsonVariant
*json_variant_unref_inner(JsonVariant
*variant
) {
80 if (variant
->type
== JSON_VARIANT_ARRAY
|| variant
->type
== JSON_VARIANT_OBJECT
)
81 return json_object_unref(variant
);
82 else if (variant
->type
== JSON_VARIANT_STRING
)
83 free(variant
->string
);
88 static JsonVariant
*json_raw_unref(JsonVariant
*variant
, size_t size
) {
92 for (size_t i
= 0; i
< size
; ++i
)
93 json_variant_unref_inner(&variant
[i
]);
99 static JsonVariant
*json_object_unref(JsonVariant
*variant
) {
104 if (!variant
->objects
)
107 for (i
= 0; i
< variant
->size
; ++i
)
108 json_variant_unref_inner(&variant
->objects
[i
]);
110 free(variant
->objects
);
114 static JsonVariant
**json_variant_array_unref(JsonVariant
**variant
) {
116 JsonVariant
*p
= NULL
;
121 while((p
= (variant
[i
++])) != NULL
) {
122 if (p
->type
== JSON_VARIANT_STRING
)
132 DEFINE_TRIVIAL_CLEANUP_FUNC(JsonVariant
**, json_variant_array_unref
);
134 JsonVariant
*json_variant_unref(JsonVariant
*variant
) {
138 if (variant
->type
== JSON_VARIANT_ARRAY
|| variant
->type
== JSON_VARIANT_OBJECT
)
139 json_object_unref(variant
);
140 else if (variant
->type
== JSON_VARIANT_STRING
)
141 free(variant
->string
);
148 char *json_variant_string(JsonVariant
*variant
){
150 assert(variant
->type
== JSON_VARIANT_STRING
);
152 return variant
->string
;
155 bool json_variant_bool(JsonVariant
*variant
) {
157 assert(variant
->type
== JSON_VARIANT_BOOLEAN
);
159 return variant
->value
.boolean
;
162 intmax_t json_variant_integer(JsonVariant
*variant
) {
164 assert(variant
->type
== JSON_VARIANT_INTEGER
);
166 return variant
->value
.integer
;
169 double json_variant_real(JsonVariant
*variant
) {
171 assert(variant
->type
== JSON_VARIANT_REAL
);
173 return variant
->value
.real
;
176 JsonVariant
*json_variant_element(JsonVariant
*variant
, unsigned index
) {
178 assert(variant
->type
== JSON_VARIANT_ARRAY
|| variant
->type
== JSON_VARIANT_OBJECT
);
179 assert(index
< variant
->size
);
180 assert(variant
->objects
);
182 return &variant
->objects
[index
];
185 JsonVariant
*json_variant_value(JsonVariant
*variant
, const char *key
) {
189 assert(variant
->type
== JSON_VARIANT_OBJECT
);
190 assert(variant
->objects
);
192 for (i
= 0; i
< variant
->size
; i
+= 2) {
193 JsonVariant
*p
= &variant
->objects
[i
];
194 if (p
->type
== JSON_VARIANT_STRING
&& streq(key
, p
->string
))
195 return &variant
->objects
[i
+ 1];
201 static void inc_lines(unsigned *line
, const char *s
, size_t n
) {
210 f
= memchr(p
, '\n', n
);
220 static int unhex_ucs2(const char *c
, uint16_t *ret
) {
227 aa
= unhexchar(c
[0]);
231 bb
= unhexchar(c
[1]);
235 cc
= unhexchar(c
[2]);
239 dd
= unhexchar(c
[3]);
243 x
= ((uint16_t) aa
<< 12) |
244 ((uint16_t) bb
<< 8) |
245 ((uint16_t) cc
<< 4) |
256 static int json_parse_string(const char **p
, char **ret
) {
257 _cleanup_free_
char *s
= NULL
;
258 size_t n
= 0, allocated
= 0;
279 /* Check for control characters 0x00..0x1f */
280 if (*c
> 0 && *c
< ' ')
283 /* Check for control character 0x7f */
309 if (IN_SET(*c
, '"', '\\', '/'))
321 else if (*c
== 'u') {
325 r
= unhex_ucs2(c
+ 1, &x
);
331 if (!GREEDY_REALLOC(s
, allocated
, n
+ 4))
334 if (!utf16_is_surrogate(x
))
335 n
+= utf8_encode_unichar(s
+ n
, x
);
336 else if (utf16_is_trailing_surrogate(x
))
341 if (c
[0] != '\\' || c
[1] != 'u')
344 r
= unhex_ucs2(c
+ 2, &y
);
350 if (!utf16_is_trailing_surrogate(y
))
353 n
+= utf8_encode_unichar(s
+ n
, utf16_surrogate_pair_to_unichar(x
, y
));
360 if (!GREEDY_REALLOC(s
, allocated
, n
+ 2))
368 len
= utf8_encoded_valid_unichar(c
);
372 if (!GREEDY_REALLOC(s
, allocated
, n
+ len
+ 1))
375 memcpy(s
+ n
, c
, len
);
381 static 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;
401 if (!strchr("123456789", *c
) || *c
== 0)
408 t
= 10 * i
+ (*c
- '0');
409 if (t
< i
) /* overflow */
415 x
= 10.0 * x
+ (*c
- '0');
417 } while (strchr("0123456789", *c
) && *c
!= 0);
424 if (!strchr("0123456789", *c
) || *c
== 0)
428 y
= 10.0 * y
+ (*c
- '0');
429 shift
= 10.0 * shift
;
431 } while (strchr("0123456789", *c
) && *c
!= 0);
434 if (*c
== 'e' || *c
== 'E') {
439 exponent_negative
= true;
441 } else if (*c
== '+')
444 if (!strchr("0123456789", *c
) || *c
== 0)
448 exponent
= 10.0 * exponent
+ (*c
- '0');
450 } while (strchr("0123456789", *c
) && *c
!= 0);
456 ret
->real
= ((negative
? -1.0 : 1.0) * (x
+ (y
/ shift
))) * exp10((exponent_negative
? -1.0 : 1.0) * exponent
);
459 ret
->integer
= negative
? -i
: i
;
467 union json_value
*ret_value
,
487 t
= PTR_TO_INT(*state
);
490 if (t
== STATE_NULL
) {
499 b
= c
+ strspn(c
, WHITESPACE
);
503 inc_lines(line
, c
, b
- c
);
512 *ret_value
= JSON_VALUE_NULL
;
514 *state
= INT_TO_PTR(STATE_VALUE
);
515 return JSON_OBJECT_OPEN
;
517 } else if (*c
== '}') {
519 *ret_value
= JSON_VALUE_NULL
;
521 *state
= INT_TO_PTR(STATE_VALUE_POST
);
522 return JSON_OBJECT_CLOSE
;
524 } else if (*c
== '[') {
526 *ret_value
= JSON_VALUE_NULL
;
528 *state
= INT_TO_PTR(STATE_VALUE
);
529 return JSON_ARRAY_OPEN
;
531 } else if (*c
== ']') {
533 *ret_value
= JSON_VALUE_NULL
;
535 *state
= INT_TO_PTR(STATE_VALUE_POST
);
536 return JSON_ARRAY_CLOSE
;
538 } else if (*c
== '"') {
539 r
= json_parse_string(&c
, ret_string
);
543 *ret_value
= JSON_VALUE_NULL
;
545 *state
= INT_TO_PTR(STATE_VALUE_POST
);
548 } else if (strchr("-0123456789", *c
)) {
549 r
= json_parse_number(&c
, ret_value
);
555 *state
= INT_TO_PTR(STATE_VALUE_POST
);
558 } else if (startswith(c
, "true")) {
560 ret_value
->boolean
= true;
562 *state
= INT_TO_PTR(STATE_VALUE_POST
);
565 } else if (startswith(c
, "false")) {
567 ret_value
->boolean
= false;
569 *state
= INT_TO_PTR(STATE_VALUE_POST
);
572 } else if (startswith(c
, "null")) {
574 *ret_value
= JSON_VALUE_NULL
;
576 *state
= INT_TO_PTR(STATE_VALUE_POST
);
582 case STATE_VALUE_POST
:
586 *ret_value
= JSON_VALUE_NULL
;
588 *state
= INT_TO_PTR(STATE_VALUE
);
590 } else if (*c
== ',') {
592 *ret_value
= JSON_VALUE_NULL
;
594 *state
= INT_TO_PTR(STATE_VALUE
);
596 } else if (*c
== '}') {
598 *ret_value
= JSON_VALUE_NULL
;
600 *state
= INT_TO_PTR(STATE_VALUE_POST
);
601 return JSON_OBJECT_CLOSE
;
602 } else if (*c
== ']') {
604 *ret_value
= JSON_VALUE_NULL
;
606 *state
= INT_TO_PTR(STATE_VALUE_POST
);
607 return JSON_ARRAY_CLOSE
;
615 static bool json_is_value(JsonVariant
*var
) {
618 return var
->type
!= JSON_VARIANT_CONTROL
;
621 static 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
;
631 } state
= arr
? STATE_VALUE
: STATE_KEY
;
637 while((var
= *i
< n
? tokens
[(*i
)++] : NULL
) != NULL
) {
641 stopper
= !json_is_value(var
) && var
->value
.integer
== terminator
;
644 if (state
!= STATE_COMMA
&& size
> 0)
650 if (state
== STATE_KEY
) {
651 if (var
->type
!= JSON_VARIANT_STRING
)
658 else if (state
== STATE_COLON
) {
662 if (json_is_value(var
))
665 if (var
->value
.integer
!= JSON_COLON
)
670 else if (state
== STATE_VALUE
) {
671 _cleanup_json_variant_unref_ JsonVariant
*v
= NULL
;
672 size_t toadd
= arr
? 1 : 2;
674 if (!json_is_value(var
)) {
675 int type
= (var
->value
.integer
== JSON_ARRAY_OPEN
) ? JSON_VARIANT_ARRAY
: JSON_VARIANT_OBJECT
;
677 r
= json_variant_new(&v
, type
);
681 r
= json_scoped_parse(tokens
, i
, n
, v
);
690 if(!GREEDY_REALLOC(items
, allocated
, size
+ toadd
))
694 r
= json_variant_deep_copy(&items
[size
], value
);
698 r
= json_variant_deep_copy(&items
[size
], key
);
702 r
= json_variant_deep_copy(&items
[size
+1], value
);
710 else if (state
== STATE_COMMA
) {
711 if (json_is_value(var
))
714 if (var
->value
.integer
!= JSON_COMMA
)
720 state
= arr
? STATE_VALUE
: STATE_KEY
;
725 json_raw_unref(items
, size
);
730 scope
->objects
= items
;
735 static int json_parse_tokens(JsonVariant
**tokens
, size_t ntokens
, JsonVariant
**rv
) {
739 _cleanup_json_variant_unref_ JsonVariant
*p
= NULL
;
745 r
= json_variant_new(&p
, JSON_VARIANT_OBJECT
);
749 if (e
->type
!= JSON_VARIANT_CONTROL
&& e
->value
.integer
!= JSON_OBJECT_OPEN
)
752 r
= json_scoped_parse(tokens
, &it
, ntokens
, p
);
762 static 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
;
769 size_t allocated
= 0, s
= 0;
777 buf
= strndup(string
, size
);
783 _cleanup_json_variant_unref_ JsonVariant
*var
= NULL
;
784 _cleanup_free_
char *rstr
= NULL
;
786 t
= json_tokenize(&p
, &rstr
, &v
, &json_state
, NULL
);
790 else if (t
== JSON_END
)
793 if (t
<= JSON_ARRAY_CLOSE
) {
794 r
= json_variant_new(&var
, JSON_VARIANT_CONTROL
);
797 var
->value
.integer
= t
;
801 r
= json_variant_new(&var
, JSON_VARIANT_STRING
);
804 var
->size
= strlen(rstr
);
805 var
->string
= strdup(rstr
);
811 r
= json_variant_new(&var
, JSON_VARIANT_INTEGER
);
817 r
= json_variant_new(&var
, JSON_VARIANT_REAL
);
823 r
= json_variant_new(&var
, JSON_VARIANT_BOOLEAN
);
829 r
= json_variant_new(&var
, JSON_VARIANT_NULL
);
836 if (!GREEDY_REALLOC(items
, allocated
, s
+2))
851 int json_parse(const char *string
, JsonVariant
**rv
) {
852 _cleanup_(json_variant_array_unrefp
) JsonVariant
**s
= NULL
;
853 JsonVariant
*v
= NULL
;
860 r
= json_tokens(string
, strlen(string
), &s
, &n
);
864 r
= json_parse_tokens(s
, n
, &v
);