LCOV - code coverage report
Current view: top level - basic - json.c (source / functions) Hit Total Coverage
Test: systemd test coverage Lines: 438 533 82.2 %
Date: 2015-07-29 18:47:03 Functions: 22 24 91.7 %

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

Generated by: LCOV version 1.11