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/>.
22 #include <sys/types.h>
37 static void inc_lines(unsigned *line, const char *s, size_t n) {
46 f = memchr(p, '\n', n);
56 static int unhex_ucs2(const char *c, uint16_t *ret) {
79 x = ((uint16_t) aa << 12) |
80 ((uint16_t) bb << 8) |
81 ((uint16_t) cc << 4) |
92 static int json_parse_string(const char **p, char **ret) {
93 _cleanup_free_ char *s = NULL;
94 size_t n = 0, allocated = 0;
115 /* Check for control characters 0x00..0x1f */
116 if (*c > 0 && *c < ' ')
119 /* Check for control character 0x7f */
145 if (IN_SET(*c, '"', '\\', '/'))
157 else if (*c == 'u') {
161 r = unhex_ucs2(c + 1, &x);
167 if (!GREEDY_REALLOC(s, allocated, n + 4))
170 if (!utf16_is_surrogate(x))
171 n += utf8_encode_unichar(s + n, x);
172 else if (utf16_is_trailing_surrogate(x))
177 if (c[0] != '\\' || c[1] != 'u')
180 r = unhex_ucs2(c + 2, &y);
186 if (!utf16_is_trailing_surrogate(y))
189 n += utf8_encode_unichar(s + n, utf16_surrogate_pair_to_unichar(x, y));
196 if (!GREEDY_REALLOC(s, allocated, n + 2))
204 len = utf8_encoded_valid_unichar(c);
208 if (!GREEDY_REALLOC(s, allocated, n + len + 1))
211 memcpy(s + n, c, len);
217 static int json_parse_number(const char **p, union json_value *ret) {
218 bool negative = false, exponent_negative = false, is_double = false;
219 double x = 0.0, y = 0.0, exponent = 0.0, shift = 1.0;
237 if (!strchr("123456789", *c) || *c == 0)
244 t = 10 * i + (*c - '0');
245 if (t < i) /* overflow */
251 x = 10.0 * x + (*c - '0');
253 } while (strchr("0123456789", *c) && *c != 0);
260 if (!strchr("0123456789", *c) || *c == 0)
264 y = 10.0 * y + (*c - '0');
265 shift = 10.0 * shift;
267 } while (strchr("0123456789", *c) && *c != 0);
270 if (*c == 'e' || *c == 'E') {
275 exponent_negative = true;
277 } else if (*c == '+')
280 if (!strchr("0123456789", *c) || *c == 0)
284 exponent = 10.0 * exponent + (*c - '0');
286 } while (strchr("0123456789", *c) && *c != 0);
295 ret->real = ((negative ? -1.0 : 1.0) * (x + (y / shift))) * exp10((exponent_negative ? -1.0 : 1.0) * exponent);
298 ret->integer = negative ? -i : i;
306 union json_value *ret_value,
320 t = PTR_TO_INT(*state);
323 if (t == STATE_NULL) {
332 b = c + strspn(c, WHITESPACE);
336 inc_lines(line, c, b - c);
345 *ret_value = JSON_VALUE_NULL;
347 *state = INT_TO_PTR(STATE_VALUE);
348 return JSON_OBJECT_OPEN;
350 } else if (*c == '}') {
352 *ret_value = JSON_VALUE_NULL;
354 *state = INT_TO_PTR(STATE_VALUE_POST);
355 return JSON_OBJECT_CLOSE;
357 } else if (*c == '[') {
359 *ret_value = JSON_VALUE_NULL;
361 *state = INT_TO_PTR(STATE_VALUE);
362 return JSON_ARRAY_OPEN;
364 } else if (*c == ']') {
366 *ret_value = JSON_VALUE_NULL;
368 *state = INT_TO_PTR(STATE_VALUE_POST);
369 return JSON_ARRAY_CLOSE;
371 } else if (*c == '"') {
372 r = json_parse_string(&c, ret_string);
376 *ret_value = JSON_VALUE_NULL;
378 *state = INT_TO_PTR(STATE_VALUE_POST);
381 } else if (strchr("-0123456789", *c)) {
382 r = json_parse_number(&c, ret_value);
388 *state = INT_TO_PTR(STATE_VALUE_POST);
391 } else if (startswith(c, "true")) {
393 ret_value->boolean = true;
395 *state = INT_TO_PTR(STATE_VALUE_POST);
398 } else if (startswith(c, "false")) {
400 ret_value->boolean = false;
402 *state = INT_TO_PTR(STATE_VALUE_POST);
405 } else if (startswith(c, "null")) {
407 *ret_value = JSON_VALUE_NULL;
409 *state = INT_TO_PTR(STATE_VALUE_POST);
415 case STATE_VALUE_POST:
419 *ret_value = JSON_VALUE_NULL;
421 *state = INT_TO_PTR(STATE_VALUE);
423 } else if (*c == ',') {
425 *ret_value = JSON_VALUE_NULL;
427 *state = INT_TO_PTR(STATE_VALUE);
429 } else if (*c == '}') {
431 *ret_value = JSON_VALUE_NULL;
433 *state = INT_TO_PTR(STATE_VALUE_POST);
434 return JSON_OBJECT_CLOSE;
435 } else if (*c == ']') {
437 *ret_value = JSON_VALUE_NULL;
439 *state = INT_TO_PTR(STATE_VALUE_POST);
440 return JSON_ARRAY_CLOSE;