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>
26 #include "string-util.h"
30 int json_variant_new(JsonVariant
**ret
, JsonVariantType type
) {
33 v
= new0(JsonVariant
, 1);
41 static int json_variant_deep_copy(JsonVariant
*ret
, JsonVariant
*variant
) {
47 ret
->type
= variant
->type
;
48 ret
->size
= variant
->size
;
50 if (variant
->type
== JSON_VARIANT_STRING
) {
51 ret
->string
= memdup(variant
->string
, variant
->size
+1);
54 } else if (variant
->type
== JSON_VARIANT_ARRAY
|| variant
->type
== JSON_VARIANT_OBJECT
) {
57 ret
->objects
= new0(JsonVariant
, variant
->size
);
61 for (i
= 0; i
< variant
->size
; ++i
) {
62 r
= json_variant_deep_copy(&ret
->objects
[i
], &variant
->objects
[i
]);
67 ret
->value
= variant
->value
;
72 static JsonVariant
*json_object_unref(JsonVariant
*variant
);
74 static JsonVariant
*json_variant_unref_inner(JsonVariant
*variant
) {
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
);
86 static JsonVariant
*json_raw_unref(JsonVariant
*variant
, size_t size
) {
90 for (size_t i
= 0; i
< size
; ++i
)
91 json_variant_unref_inner(&variant
[i
]);
97 static JsonVariant
*json_object_unref(JsonVariant
*variant
) {
102 if (!variant
->objects
)
105 for (i
= 0; i
< variant
->size
; ++i
)
106 json_variant_unref_inner(&variant
->objects
[i
]);
108 free(variant
->objects
);
112 static JsonVariant
**json_variant_array_unref(JsonVariant
**variant
) {
114 JsonVariant
*p
= NULL
;
119 while((p
= (variant
[i
++])) != NULL
) {
120 if (p
->type
== JSON_VARIANT_STRING
)
130 DEFINE_TRIVIAL_CLEANUP_FUNC(JsonVariant
**, json_variant_array_unref
);
132 JsonVariant
*json_variant_unref(JsonVariant
*variant
) {
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
);
146 char *json_variant_string(JsonVariant
*variant
){
148 assert(variant
->type
== JSON_VARIANT_STRING
);
150 return variant
->string
;
153 bool json_variant_bool(JsonVariant
*variant
) {
155 assert(variant
->type
== JSON_VARIANT_BOOLEAN
);
157 return variant
->value
.boolean
;
160 intmax_t json_variant_integer(JsonVariant
*variant
) {
162 assert(variant
->type
== JSON_VARIANT_INTEGER
);
164 return variant
->value
.integer
;
167 double json_variant_real(JsonVariant
*variant
) {
169 assert(variant
->type
== JSON_VARIANT_REAL
);
171 return variant
->value
.real
;
174 JsonVariant
*json_variant_element(JsonVariant
*variant
, unsigned index
) {
176 assert(variant
->type
== JSON_VARIANT_ARRAY
|| variant
->type
== JSON_VARIANT_OBJECT
);
177 assert(index
< variant
->size
);
178 assert(variant
->objects
);
180 return &variant
->objects
[index
];
183 JsonVariant
*json_variant_value(JsonVariant
*variant
, const char *key
) {
187 assert(variant
->type
== JSON_VARIANT_OBJECT
);
188 assert(variant
->objects
);
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];
199 static void inc_lines(unsigned *line
, const char *s
, size_t n
) {
208 f
= memchr(p
, '\n', n
);
218 static int unhex_ucs2(const char *c
, uint16_t *ret
) {
225 aa
= unhexchar(c
[0]);
229 bb
= unhexchar(c
[1]);
233 cc
= unhexchar(c
[2]);
237 dd
= unhexchar(c
[3]);
241 x
= ((uint16_t) aa
<< 12) |
242 ((uint16_t) bb
<< 8) |
243 ((uint16_t) cc
<< 4) |
254 static int json_parse_string(const char **p
, char **ret
) {
255 _cleanup_free_
char *s
= NULL
;
256 size_t n
= 0, allocated
= 0;
277 /* Check for control characters 0x00..0x1f */
278 if (*c
> 0 && *c
< ' ')
281 /* Check for control character 0x7f */
307 if (IN_SET(*c
, '"', '\\', '/'))
319 else if (*c
== 'u') {
323 r
= unhex_ucs2(c
+ 1, &x
);
329 if (!GREEDY_REALLOC(s
, allocated
, n
+ 4))
332 if (!utf16_is_surrogate(x
))
333 n
+= utf8_encode_unichar(s
+ n
, x
);
334 else if (utf16_is_trailing_surrogate(x
))
339 if (c
[0] != '\\' || c
[1] != 'u')
342 r
= unhex_ucs2(c
+ 2, &y
);
348 if (!utf16_is_trailing_surrogate(y
))
351 n
+= utf8_encode_unichar(s
+ n
, utf16_surrogate_pair_to_unichar(x
, y
));
358 if (!GREEDY_REALLOC(s
, allocated
, n
+ 2))
366 len
= utf8_encoded_valid_unichar(c
);
370 if (!GREEDY_REALLOC(s
, allocated
, n
+ len
+ 1))
373 memcpy(s
+ n
, c
, len
);
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;
399 if (!strchr("123456789", *c
) || *c
== 0)
406 t
= 10 * i
+ (*c
- '0');
407 if (t
< i
) /* overflow */
413 x
= 10.0 * x
+ (*c
- '0');
415 } while (strchr("0123456789", *c
) && *c
!= 0);
422 if (!strchr("0123456789", *c
) || *c
== 0)
426 y
= 10.0 * y
+ (*c
- '0');
427 shift
= 10.0 * shift
;
429 } while (strchr("0123456789", *c
) && *c
!= 0);
432 if (*c
== 'e' || *c
== 'E') {
437 exponent_negative
= true;
439 } else if (*c
== '+')
442 if (!strchr("0123456789", *c
) || *c
== 0)
446 exponent
= 10.0 * exponent
+ (*c
- '0');
448 } while (strchr("0123456789", *c
) && *c
!= 0);
454 ret
->real
= ((negative
? -1.0 : 1.0) * (x
+ (y
/ shift
))) * exp10((exponent_negative
? -1.0 : 1.0) * exponent
);
457 ret
->integer
= negative
? -i
: i
;
465 union json_value
*ret_value
,
485 t
= PTR_TO_INT(*state
);
488 if (t
== STATE_NULL
) {
497 b
= c
+ strspn(c
, WHITESPACE
);
501 inc_lines(line
, c
, b
- c
);
510 *ret_value
= JSON_VALUE_NULL
;
512 *state
= INT_TO_PTR(STATE_VALUE
);
513 return JSON_OBJECT_OPEN
;
515 } else if (*c
== '}') {
517 *ret_value
= JSON_VALUE_NULL
;
519 *state
= INT_TO_PTR(STATE_VALUE_POST
);
520 return JSON_OBJECT_CLOSE
;
522 } else if (*c
== '[') {
524 *ret_value
= JSON_VALUE_NULL
;
526 *state
= INT_TO_PTR(STATE_VALUE
);
527 return JSON_ARRAY_OPEN
;
529 } else if (*c
== ']') {
531 *ret_value
= JSON_VALUE_NULL
;
533 *state
= INT_TO_PTR(STATE_VALUE_POST
);
534 return JSON_ARRAY_CLOSE
;
536 } else if (*c
== '"') {
537 r
= json_parse_string(&c
, ret_string
);
541 *ret_value
= JSON_VALUE_NULL
;
543 *state
= INT_TO_PTR(STATE_VALUE_POST
);
546 } else if (strchr("-0123456789", *c
)) {
547 r
= json_parse_number(&c
, ret_value
);
553 *state
= INT_TO_PTR(STATE_VALUE_POST
);
556 } else if (startswith(c
, "true")) {
558 ret_value
->boolean
= true;
560 *state
= INT_TO_PTR(STATE_VALUE_POST
);
563 } else if (startswith(c
, "false")) {
565 ret_value
->boolean
= false;
567 *state
= INT_TO_PTR(STATE_VALUE_POST
);
570 } else if (startswith(c
, "null")) {
572 *ret_value
= JSON_VALUE_NULL
;
574 *state
= INT_TO_PTR(STATE_VALUE_POST
);
580 case STATE_VALUE_POST
:
584 *ret_value
= JSON_VALUE_NULL
;
586 *state
= INT_TO_PTR(STATE_VALUE
);
588 } else if (*c
== ',') {
590 *ret_value
= JSON_VALUE_NULL
;
592 *state
= INT_TO_PTR(STATE_VALUE
);
594 } else if (*c
== '}') {
596 *ret_value
= JSON_VALUE_NULL
;
598 *state
= INT_TO_PTR(STATE_VALUE_POST
);
599 return JSON_OBJECT_CLOSE
;
600 } else if (*c
== ']') {
602 *ret_value
= JSON_VALUE_NULL
;
604 *state
= INT_TO_PTR(STATE_VALUE_POST
);
605 return JSON_ARRAY_CLOSE
;
613 static bool json_is_value(JsonVariant
*var
) {
616 return var
->type
!= JSON_VARIANT_CONTROL
;
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
;
629 } state
= arr
? STATE_VALUE
: STATE_KEY
;
635 while((var
= *i
< n
? tokens
[(*i
)++] : NULL
) != NULL
) {
639 stopper
= !json_is_value(var
) && var
->value
.integer
== terminator
;
642 if (state
!= STATE_COMMA
&& size
> 0)
648 if (state
== STATE_KEY
) {
649 if (var
->type
!= JSON_VARIANT_STRING
)
656 else if (state
== STATE_COLON
) {
660 if (json_is_value(var
))
663 if (var
->value
.integer
!= JSON_COLON
)
668 else if (state
== STATE_VALUE
) {
669 _cleanup_json_variant_unref_ JsonVariant
*v
= NULL
;
670 size_t toadd
= arr
? 1 : 2;
672 if (!json_is_value(var
)) {
673 int type
= (var
->value
.integer
== JSON_ARRAY_OPEN
) ? JSON_VARIANT_ARRAY
: JSON_VARIANT_OBJECT
;
675 r
= json_variant_new(&v
, type
);
679 r
= json_scoped_parse(tokens
, i
, n
, v
);
688 if(!GREEDY_REALLOC(items
, allocated
, size
+ toadd
))
692 r
= json_variant_deep_copy(&items
[size
], value
);
696 r
= json_variant_deep_copy(&items
[size
], key
);
700 r
= json_variant_deep_copy(&items
[size
+1], value
);
708 else if (state
== STATE_COMMA
) {
709 if (json_is_value(var
))
712 if (var
->value
.integer
!= JSON_COMMA
)
718 state
= arr
? STATE_VALUE
: STATE_KEY
;
723 json_raw_unref(items
, size
);
728 scope
->objects
= items
;
733 static int json_parse_tokens(JsonVariant
**tokens
, size_t ntokens
, JsonVariant
**rv
) {
737 _cleanup_json_variant_unref_ JsonVariant
*p
= NULL
;
743 r
= json_variant_new(&p
, JSON_VARIANT_OBJECT
);
747 if (e
->type
!= JSON_VARIANT_CONTROL
&& e
->value
.integer
!= JSON_OBJECT_OPEN
)
750 r
= json_scoped_parse(tokens
, &it
, ntokens
, p
);
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
;
767 size_t allocated
= 0, s
= 0;
775 buf
= strndup(string
, size
);
781 _cleanup_json_variant_unref_ JsonVariant
*var
= NULL
;
782 _cleanup_free_
char *rstr
= NULL
;
784 t
= json_tokenize(&p
, &rstr
, &v
, &json_state
, NULL
);
788 else if (t
== JSON_END
)
791 if (t
<= JSON_ARRAY_CLOSE
) {
792 r
= json_variant_new(&var
, JSON_VARIANT_CONTROL
);
795 var
->value
.integer
= t
;
799 r
= json_variant_new(&var
, JSON_VARIANT_STRING
);
802 var
->size
= strlen(rstr
);
803 var
->string
= strdup(rstr
);
809 r
= json_variant_new(&var
, JSON_VARIANT_INTEGER
);
815 r
= json_variant_new(&var
, JSON_VARIANT_REAL
);
821 r
= json_variant_new(&var
, JSON_VARIANT_BOOLEAN
);
827 r
= json_variant_new(&var
, JSON_VARIANT_NULL
);
834 if (!GREEDY_REALLOC(items
, allocated
, s
+2))
849 int json_parse(const char *string
, JsonVariant
**rv
) {
850 _cleanup_(json_variant_array_unrefp
) JsonVariant
**s
= NULL
;
851 JsonVariant
*v
= NULL
;
858 r
= json_tokens(string
, strlen(string
), &s
, &n
);
862 r
= json_parse_tokens(s
, n
, &v
);