LCOV - code coverage report
Current view: top level - third_party/heimdal/lib/base - json.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 0 434 0.0 %
Date: 2024-06-13 04:01:37 Functions: 0 21 0.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2010 Kungliga Tekniska Högskolan
       3             :  * (Royal Institute of Technology, Stockholm, Sweden).
       4             :  * All rights reserved.
       5             :  *
       6             :  * Portions Copyright (c) 2010 Apple Inc. All rights reserved.
       7             :  *
       8             :  * Redistribution and use in source and binary forms, with or without
       9             :  * modification, are permitted provided that the following conditions
      10             :  * are met:
      11             :  *
      12             :  * 1. Redistributions of source code must retain the above copyright
      13             :  *    notice, this list of conditions and the following disclaimer.
      14             :  *
      15             :  * 2. Redistributions in binary form must reproduce the above copyright
      16             :  *    notice, this list of conditions and the following disclaimer in the
      17             :  *    documentation and/or other materials provided with the distribution.
      18             :  *
      19             :  * 3. Neither the name of the Institute nor the names of its contributors
      20             :  *    may be used to endorse or promote products derived from this software
      21             :  *    without specific prior written permission.
      22             :  *
      23             :  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
      24             :  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      25             :  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      26             :  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
      27             :  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
      28             :  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
      29             :  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
      30             :  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
      31             :  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
      32             :  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      33             :  * SUCH DAMAGE.
      34             :  */
      35             : 
      36             : #include "baselocl.h"
      37             : #include <ctype.h>
      38             : #include <base64.h>
      39             : 
      40             : static heim_base_once_t heim_json_once = HEIM_BASE_ONCE_INIT;
      41             : static heim_string_t heim_tid_data_uuid_key = NULL;
      42             : static const char base64_chars[] =
      43             :     "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
      44             : 
      45             : static void
      46           0 : json_init_once(void *arg)
      47             : {
      48           0 :     heim_tid_data_uuid_key = __heim_string_constant("heimdal-type-data-76d7fca2-d0da-4b20-a126-1a10f8a0eae6");
      49           0 : }
      50             : 
      51             : struct twojson {
      52             :     void *ctx;
      53             :     void (*out)(void *, const char *);
      54             :     size_t indent;
      55             :     heim_json_flags_t flags;
      56             :     int ret;
      57             :     int first;
      58             : };
      59             : 
      60             : struct heim_strbuf {
      61             :     char *str;
      62             :     size_t len;
      63             :     size_t alloced;
      64             :     int enomem;
      65             :     heim_json_flags_t flags;
      66             : };
      67             : 
      68             : static int
      69             : base2json(heim_object_t, struct twojson *);
      70             : 
      71             : static void
      72           0 : indent(struct twojson *j)
      73             : {
      74           0 :     size_t i = j->indent;
      75           0 :     if (j->flags & HEIM_JSON_F_ONE_LINE)
      76           0 :         return;
      77           0 :     while (i--)
      78           0 :         j->out(j->ctx, "\t");
      79             : }
      80             : 
      81             : static void
      82           0 : array2json(heim_object_t value, void *ctx, int *stop)
      83             : {
      84           0 :     struct twojson *j = ctx;
      85           0 :     if (j->ret)
      86           0 :         return;
      87           0 :     if (j->first) {
      88           0 :         j->first = 0;
      89             :     } else {
      90           0 :         j->out(j->ctx, NULL); /* eat previous '\n' if possible */
      91           0 :         j->out(j->ctx, ",\n");
      92             :     }
      93           0 :     j->ret = base2json(value, j);
      94             : }
      95             : 
      96             : static void
      97           0 : dict2json(heim_object_t key, heim_object_t value, void *ctx)
      98             : {
      99           0 :     struct twojson *j = ctx;
     100           0 :     if (j->ret)
     101           0 :         return;
     102           0 :     if (j->first) {
     103           0 :         j->first = 0;
     104             :     } else {
     105           0 :         j->out(j->ctx, NULL); /* eat previous '\n' if possible */
     106           0 :         j->out(j->ctx, ",\n");
     107             :     }
     108           0 :     j->ret = base2json(key, j);
     109           0 :     if (j->ret)
     110           0 :         return;
     111           0 :     j->out(j->ctx, " : \n");
     112           0 :     j->indent++;
     113           0 :     j->ret = base2json(value, j);
     114           0 :     if (j->ret)
     115           0 :         return;
     116           0 :     j->indent--;
     117             : }
     118             : 
     119             : static int
     120           0 : base2json(heim_object_t obj, struct twojson *j)
     121             : {
     122             :     heim_tid_t type;
     123           0 :     int first = 0;
     124             : 
     125           0 :     if (obj == NULL) {
     126           0 :         if (j->flags & HEIM_JSON_F_CNULL2JSNULL) {
     127           0 :             obj = heim_null_create();
     128           0 :         } else if (j->flags & HEIM_JSON_F_NO_C_NULL) {
     129           0 :             return EINVAL;
     130             :         } else {
     131           0 :             indent(j);
     132           0 :             j->out(j->ctx, "<NULL>\n"); /* This is NOT valid JSON! */
     133           0 :             return 0;
     134             :         }
     135             :     }
     136             : 
     137           0 :     type = heim_get_tid(obj);
     138           0 :     switch (type) {
     139           0 :     case HEIM_TID_ARRAY:
     140           0 :         indent(j);
     141           0 :         j->out(j->ctx, "[\n");
     142           0 :         j->indent++;
     143           0 :         first = j->first;
     144           0 :         j->first = 1;
     145           0 :         heim_array_iterate_f(obj, j, array2json);
     146           0 :         j->indent--;
     147           0 :         if (!j->first)
     148           0 :             j->out(j->ctx, "\n");
     149           0 :         indent(j);
     150           0 :         j->out(j->ctx, "]\n");
     151           0 :         j->first = first;
     152           0 :         break;
     153             : 
     154           0 :     case HEIM_TID_DICT:
     155           0 :         indent(j);
     156           0 :         j->out(j->ctx, "{\n");
     157           0 :         j->indent++;
     158           0 :         first = j->first;
     159           0 :         j->first = 1;
     160           0 :         heim_dict_iterate_f(obj, j, dict2json);
     161           0 :         j->indent--;
     162           0 :         if (!j->first)
     163           0 :             j->out(j->ctx, "\n");
     164           0 :         indent(j);
     165           0 :         j->out(j->ctx, "}\n");
     166           0 :         j->first = first;
     167           0 :         break;
     168             : 
     169           0 :     case HEIM_TID_STRING:
     170           0 :         indent(j);
     171           0 :         j->out(j->ctx, "\"");
     172           0 :         j->out(j->ctx, heim_string_get_utf8(obj));
     173           0 :         j->out(j->ctx, "\"");
     174           0 :         break;
     175             : 
     176           0 :     case HEIM_TID_DATA: {
     177             :         heim_dict_t d;
     178             :         heim_string_t v;
     179             :         const heim_octet_string *data;
     180           0 :         char *b64 = NULL;
     181             :         int ret;
     182             : 
     183           0 :         if (j->flags & HEIM_JSON_F_NO_DATA)
     184           0 :             return EINVAL; /* JSON doesn't do binary */
     185             : 
     186           0 :         data = heim_data_get_data(obj);
     187           0 :         ret = rk_base64_encode(data->data, data->length, &b64);
     188           0 :         if (ret < 0 || b64 == NULL)
     189           0 :             return ENOMEM;
     190             : 
     191           0 :         if (j->flags & HEIM_JSON_F_NO_DATA_DICT) {
     192           0 :             indent(j);
     193           0 :             j->out(j->ctx, "\"");
     194           0 :             j->out(j->ctx, b64); /* base64-encode; hope there's no aliasing */
     195           0 :             j->out(j->ctx, "\"");
     196           0 :             free(b64);
     197             :         } else {
     198             :             /*
     199             :              * JSON has no way to represent binary data, therefore the
     200             :              * following is a Heimdal-specific convention.
     201             :              *
     202             :              * We encode binary data as a dict with a single very magic
     203             :              * key with a base64-encoded value.  The magic key includes
     204             :              * a uuid, so we're not likely to alias accidentally.
     205             :              */
     206           0 :             d = heim_dict_create(2);
     207           0 :             if (d == NULL) {
     208           0 :                 free(b64);
     209           0 :                 return ENOMEM;
     210             :             }
     211           0 :             v = heim_string_ref_create(b64, free);
     212           0 :             if (v == NULL) {
     213           0 :                 free(b64);
     214           0 :                 heim_release(d);
     215           0 :                 return ENOMEM;
     216             :             }
     217           0 :             ret = heim_dict_set_value(d, heim_tid_data_uuid_key, v);
     218           0 :             heim_release(v);
     219           0 :             if (ret) {
     220           0 :                 heim_release(d);
     221           0 :                 return ENOMEM;
     222             :             }
     223           0 :             ret = base2json(d, j);
     224           0 :             heim_release(d);
     225           0 :             if (ret)
     226           0 :                 return ret;
     227             :         }
     228           0 :         break;
     229             :     }
     230             : 
     231           0 :     case HEIM_TID_NUMBER: {
     232             :         char num[32];
     233           0 :         indent(j);
     234           0 :         snprintf(num, sizeof (num), "%d", heim_number_get_int(obj));
     235           0 :         j->out(j->ctx, num);
     236           0 :         break;
     237             :     }
     238           0 :     case HEIM_TID_NULL:
     239           0 :         indent(j);
     240           0 :         j->out(j->ctx, "null");
     241           0 :         break;
     242           0 :     case HEIM_TID_BOOL:
     243           0 :         indent(j);
     244           0 :         j->out(j->ctx, heim_bool_val(obj) ? "true" : "false");
     245           0 :         break;
     246           0 :     default:
     247           0 :         return 1;
     248             :     }
     249           0 :     return 0;
     250             : }
     251             : 
     252             : static int
     253           0 : heim_base2json(heim_object_t obj, void *ctx, heim_json_flags_t flags,
     254             :                void (*out)(void *, const char *))
     255             : {
     256             :     struct twojson j;
     257             : 
     258           0 :     if (flags & HEIM_JSON_F_STRICT_STRINGS)
     259           0 :         return ENOTSUP; /* Sorry, not yet! */
     260             : 
     261           0 :     heim_base_once_f(&heim_json_once, NULL, json_init_once);
     262             : 
     263           0 :     j.indent = 0;
     264           0 :     j.ctx = ctx;
     265           0 :     j.out = out;
     266           0 :     j.flags = flags;
     267           0 :     j.ret = 0;
     268           0 :     j.first = 1;
     269             : 
     270           0 :     return base2json(obj, &j);
     271             : }
     272             : 
     273             : 
     274             : /*
     275             :  *
     276             :  */
     277             : 
     278             : struct parse_ctx {
     279             :     unsigned long lineno;
     280             :     const uint8_t *p;
     281             :     const uint8_t *pstart;
     282             :     const uint8_t *pend;
     283             :     heim_error_t error;
     284             :     size_t depth;
     285             :     heim_json_flags_t flags;
     286             : };
     287             : 
     288             : 
     289             : static heim_object_t
     290             : parse_value(struct parse_ctx *ctx);
     291             : 
     292             : /*
     293             :  * This function eats whitespace, but, critically, it also succeeds
     294             :  * only if there's anything left to parse.
     295             :  */
     296             : static int
     297           0 : white_spaces(struct parse_ctx *ctx)
     298             : {
     299           0 :     while (ctx->p < ctx->pend) {
     300           0 :         uint8_t c = *ctx->p;
     301           0 :         if (c == ' ' || c == '\t' || c == '\r') {
     302             : 
     303           0 :         } else if (c == '\n') {
     304           0 :             ctx->lineno++;
     305             :         } else
     306           0 :             return 0;
     307           0 :         (ctx->p)++;
     308             :     }
     309           0 :     return -1;
     310             : }
     311             : 
     312             : static int
     313           0 : is_number(uint8_t n)
     314             : {
     315           0 :     return ('0' <= n && n <= '9');
     316             : }
     317             : 
     318             : static heim_number_t
     319           0 : parse_number(struct parse_ctx *ctx)
     320             : {
     321           0 :     int number = 0, neg = 1;
     322             : 
     323           0 :     if (ctx->p >= ctx->pend)
     324           0 :         return NULL;
     325             : 
     326           0 :     if (*ctx->p == '-') {
     327           0 :         if (ctx->p + 1 >= ctx->pend)
     328           0 :             return NULL;
     329           0 :         neg = -1;
     330           0 :         ctx->p += 1;
     331             :     }
     332             : 
     333           0 :     while (ctx->p < ctx->pend) {
     334           0 :         if (is_number(*ctx->p)) {
     335           0 :             number = (number * 10) + (*ctx->p - '0');
     336             :         } else {
     337           0 :             break;
     338             :         }
     339           0 :         ctx->p += 1;
     340             :     }
     341             : 
     342           0 :     return heim_number_create(number * neg);
     343             : }
     344             : 
     345             : static heim_string_t
     346           0 : parse_string(struct parse_ctx *ctx)
     347             : {
     348             :     const uint8_t *start;
     349           0 :     int quote = 0;
     350             : 
     351           0 :     if (ctx->flags & HEIM_JSON_F_STRICT_STRINGS) {
     352           0 :         ctx->error = heim_error_create(EINVAL, "Strict JSON string encoding "
     353             :                                        "not yet supported");
     354           0 :         return NULL;
     355             :     }
     356             : 
     357           0 :     if (*ctx->p != '"') {
     358           0 :         ctx->error = heim_error_create(EINVAL, "Expected a JSON string but "
     359             :                                        "found something else at line %lu",
     360             :                                        ctx->lineno);
     361           0 :         return NULL;
     362             :     }
     363           0 :     start = ++ctx->p;
     364             : 
     365           0 :     while (ctx->p < ctx->pend) {
     366           0 :         if (*ctx->p == '\n') {
     367           0 :             ctx->lineno++;
     368           0 :         } else if (*ctx->p == '\\') {
     369           0 :             if (ctx->p + 1 == ctx->pend)
     370           0 :                 goto out;
     371           0 :             ctx->p++;
     372           0 :             quote = 1;
     373           0 :         } else if (*ctx->p == '"') {
     374             :             heim_object_t o;
     375             : 
     376           0 :             if (quote) {
     377             :                 char *p0, *p;
     378           0 :                 p = p0 = malloc(ctx->p - start);
     379           0 :                 if (p == NULL)
     380           0 :                     goto out;
     381           0 :                 while (start < ctx->p) {
     382           0 :                     if (*start == '\\') {
     383           0 :                         start++;
     384             :                         /* XXX validate quoted char */
     385             :                     }
     386           0 :                     *p++ = *start++;
     387             :                 }
     388           0 :                 o = heim_string_create_with_bytes(p0, p - p0);
     389           0 :                 free(p0);
     390             :             } else {
     391           0 :                 o = heim_string_create_with_bytes(start, ctx->p - start);
     392           0 :                 if (o == NULL) {
     393           0 :                     ctx->error = heim_error_create_enomem();
     394           0 :                     return NULL;
     395             :                 }
     396             : 
     397             :                 /* If we can decode as base64, then let's */
     398           0 :                 if (ctx->flags & HEIM_JSON_F_TRY_DECODE_DATA) {
     399             :                     void *buf;
     400             :                     size_t len;
     401             :                     const char *s;
     402             : 
     403           0 :                     s = heim_string_get_utf8(o);
     404           0 :                     len = strlen(s);
     405             : 
     406           0 :                     if (len >= 4 && strspn(s, base64_chars) >= len - 2) {
     407           0 :                         buf = malloc(len);
     408           0 :                         if (buf == NULL) {
     409           0 :                             heim_release(o);
     410           0 :                             ctx->error = heim_error_create_enomem();
     411           0 :                             return NULL;
     412             :                         }
     413           0 :                         len = rk_base64_decode(s, buf);
     414           0 :                         if (len == -1) {
     415           0 :                             free(buf);
     416           0 :                             return o;
     417             :                         }
     418           0 :                         heim_release(o);
     419           0 :                         o = heim_data_ref_create(buf, len, free);
     420             :                     }
     421             :                 }
     422             :             }
     423           0 :             ctx->p += 1;
     424             : 
     425           0 :             return o;
     426             :         }
     427           0 :         ctx->p += 1;
     428             :     }
     429           0 :     out:
     430           0 :     ctx->error = heim_error_create(EINVAL, "ran out of string");
     431           0 :     return NULL;
     432             : }
     433             : 
     434             : static int
     435           0 : parse_pair(heim_dict_t dict, struct parse_ctx *ctx)
     436             : {
     437             :     heim_string_t key;
     438             :     heim_object_t value;
     439             : 
     440           0 :     if (white_spaces(ctx))
     441           0 :         return -1;
     442             : 
     443           0 :     if (*ctx->p == '}') {
     444           0 :         ctx->p++;
     445           0 :         return 0;
     446             :     }
     447             : 
     448           0 :     if (ctx->flags & HEIM_JSON_F_STRICT_DICT)
     449             :         /* JSON allows only string keys */
     450           0 :         key = parse_string(ctx);
     451             :     else
     452             :         /* heim_dict_t allows any heim_object_t as key */
     453           0 :         key = parse_value(ctx);
     454           0 :     if (key == NULL)
     455             :         /* Even heim_dict_t does not allow C NULLs as keys though! */
     456           0 :         return -1;
     457             : 
     458           0 :     if (white_spaces(ctx)) {
     459           0 :         heim_release(key);
     460           0 :         return -1;
     461             :     }
     462             : 
     463           0 :     if (*ctx->p != ':') {
     464           0 :         heim_release(key);
     465           0 :         return -1;
     466             :     }
     467             : 
     468           0 :     ctx->p += 1; /* safe because we call white_spaces() next */
     469             : 
     470           0 :     if (white_spaces(ctx)) {
     471           0 :         heim_release(key);
     472           0 :         return -1;
     473             :     }
     474             : 
     475           0 :     value = parse_value(ctx);
     476           0 :     if (value == NULL &&
     477           0 :         (ctx->error != NULL || (ctx->flags & HEIM_JSON_F_NO_C_NULL))) {
     478           0 :         if (ctx->error == NULL)
     479           0 :             ctx->error = heim_error_create(EINVAL, "Invalid JSON encoding");
     480           0 :         heim_release(key);
     481           0 :         return -1;
     482             :     }
     483           0 :     heim_dict_set_value(dict, key, value);
     484           0 :     heim_release(key);
     485           0 :     heim_release(value);
     486             : 
     487           0 :     if (white_spaces(ctx))
     488           0 :         return -1;
     489             : 
     490           0 :     if (*ctx->p == '}') {
     491             :         /*
     492             :          * Return 1 but don't consume the '}' so we can count the one
     493             :          * pair in a one-pair dict
     494             :          */
     495           0 :         return 1;
     496           0 :     } else if (*ctx->p == ',') {
     497           0 :         ctx->p++;
     498           0 :         return 1;
     499             :     }
     500           0 :     return -1;
     501             : }
     502             : 
     503             : static heim_dict_t
     504           0 : parse_dict(struct parse_ctx *ctx)
     505             : {
     506             :     heim_dict_t dict;
     507           0 :     size_t count = 0;
     508             :     int ret;
     509             : 
     510           0 :     heim_assert(*ctx->p == '{', "string doesn't start with {");
     511             : 
     512           0 :     dict = heim_dict_create(11);
     513           0 :     if (dict == NULL) {
     514           0 :         ctx->error = heim_error_create_enomem();
     515           0 :         return NULL;
     516             :     }
     517             : 
     518           0 :     ctx->p += 1; /* safe because parse_pair() calls white_spaces() first */
     519             : 
     520           0 :     while ((ret = parse_pair(dict, ctx)) > 0)
     521           0 :         count++;
     522           0 :     if (ret < 0) {
     523           0 :         heim_release(dict);
     524           0 :         return NULL;
     525             :     }
     526           0 :     if (count == 1 && !(ctx->flags & HEIM_JSON_F_NO_DATA_DICT)) {
     527           0 :         heim_object_t v = heim_dict_copy_value(dict, heim_tid_data_uuid_key);
     528             : 
     529             :         /*
     530             :          * Binary data encoded as a dict with a single magic key with
     531             :          * base64-encoded value?  Decode as heim_data_t.
     532             :          */
     533           0 :         if (v != NULL && heim_get_tid(v) == HEIM_TID_STRING) {
     534             :             void *buf;
     535             :             size_t len;
     536             : 
     537           0 :             buf = malloc(strlen(heim_string_get_utf8(v)));
     538           0 :             if (buf == NULL) {
     539           0 :                 heim_release(dict);
     540           0 :                 heim_release(v);
     541           0 :                 ctx->error = heim_error_create_enomem();
     542           0 :                 return NULL;
     543             :             }
     544           0 :             len = rk_base64_decode(heim_string_get_utf8(v), buf);
     545           0 :             heim_release(v);
     546           0 :             if (len == -1) {
     547           0 :                 free(buf);
     548           0 :                 return dict; /* assume aliasing accident */
     549             :             }
     550           0 :             heim_release(dict);
     551           0 :             return (heim_dict_t)heim_data_ref_create(buf, len, free);
     552             :         }
     553             :     }
     554           0 :     return dict;
     555             : }
     556             : 
     557             : static int
     558           0 : parse_item(heim_array_t array, struct parse_ctx *ctx)
     559             : {
     560             :     heim_object_t value;
     561             : 
     562           0 :     if (white_spaces(ctx))
     563           0 :         return -1;
     564             : 
     565           0 :     if (*ctx->p == ']') {
     566           0 :         ctx->p++; /* safe because parse_value() calls white_spaces() first */
     567           0 :         return 0;
     568             :     }
     569             : 
     570           0 :     value = parse_value(ctx);
     571           0 :     if (value == NULL &&
     572           0 :         (ctx->error || (ctx->flags & HEIM_JSON_F_NO_C_NULL)))
     573           0 :         return -1;
     574             : 
     575           0 :     heim_array_append_value(array, value);
     576           0 :     heim_release(value);
     577             : 
     578           0 :     if (white_spaces(ctx))
     579           0 :         return -1;
     580             : 
     581           0 :     if (*ctx->p == ']') {
     582           0 :         ctx->p++;
     583           0 :         return 0;
     584           0 :     } else if (*ctx->p == ',') {
     585           0 :         ctx->p++;
     586           0 :         return 1;
     587             :     }
     588           0 :     return -1;
     589             : }
     590             : 
     591             : static heim_array_t
     592           0 : parse_array(struct parse_ctx *ctx)
     593             : {
     594           0 :     heim_array_t array = heim_array_create();
     595             :     int ret;
     596             : 
     597           0 :     heim_assert(*ctx->p == '[', "array doesn't start with [");
     598           0 :     ctx->p += 1;
     599             : 
     600           0 :     while ((ret = parse_item(array, ctx)) > 0)
     601             :         ;
     602           0 :     if (ret < 0) {
     603           0 :         heim_release(array);
     604           0 :         return NULL;
     605             :     }
     606           0 :     return array;
     607             : }
     608             : 
     609             : static heim_object_t
     610           0 : parse_value(struct parse_ctx *ctx)
     611             : {
     612             :     size_t len;
     613             :     heim_object_t o;
     614             : 
     615           0 :     if (white_spaces(ctx))
     616           0 :         return NULL;
     617             : 
     618           0 :     if (*ctx->p == '"') {
     619           0 :         return parse_string(ctx);
     620           0 :     } else if (*ctx->p == '{') {
     621           0 :         if (ctx->depth-- == 1) {
     622           0 :             ctx->error = heim_error_create(EINVAL, "JSON object too deep");
     623           0 :             return NULL;
     624             :         }
     625           0 :         o = parse_dict(ctx);
     626           0 :         ctx->depth++;
     627           0 :         return o;
     628           0 :     } else if (*ctx->p == '[') {
     629           0 :         if (ctx->depth-- == 1) {
     630           0 :             ctx->error = heim_error_create(EINVAL, "JSON object too deep");
     631           0 :             return NULL;
     632             :         }
     633           0 :         o = parse_array(ctx);
     634           0 :         ctx->depth++;
     635           0 :         return o;
     636           0 :     } else if (is_number(*ctx->p) || *ctx->p == '-') {
     637           0 :         return parse_number(ctx);
     638             :     }
     639             : 
     640           0 :     len = ctx->pend - ctx->p;
     641             : 
     642           0 :     if ((ctx->flags & HEIM_JSON_F_NO_C_NULL) == 0 &&
     643           0 :         len >= 6 && memcmp(ctx->p, "<NULL>", 6) == 0) {
     644           0 :         ctx->p += 6;
     645           0 :         return heim_null_create();
     646           0 :     } else if (len >= 4 && memcmp(ctx->p, "null", 4) == 0) {
     647           0 :         ctx->p += 4;
     648           0 :         return heim_null_create();
     649           0 :     } else if (len >= 4 && strncasecmp((char *)ctx->p, "true", 4) == 0) {
     650           0 :         ctx->p += 4;
     651           0 :         return heim_bool_create(1);
     652           0 :     } else if (len >= 5 && strncasecmp((char *)ctx->p, "false", 5) == 0) {
     653           0 :         ctx->p += 5;
     654           0 :         return heim_bool_create(0);
     655             :     }
     656             : 
     657           0 :     ctx->error = heim_error_create(EINVAL, "unknown char %c at %lu line %lu",
     658           0 :                                    (char)*ctx->p, 
     659           0 :                                    (unsigned long)(ctx->p - ctx->pstart),
     660             :                                    ctx->lineno);
     661           0 :     return NULL;
     662             : }
     663             : 
     664             : 
     665             : heim_object_t
     666           0 : heim_json_create(const char *string, size_t max_depth, heim_json_flags_t flags,
     667             :                  heim_error_t *error)
     668             : {
     669           0 :     return heim_json_create_with_bytes(string, strlen(string), max_depth, flags,
     670             :                                        error);
     671             : }
     672             : 
     673             : heim_object_t
     674           0 : heim_json_create_with_bytes(const void *data, size_t length, size_t max_depth,
     675             :                             heim_json_flags_t flags, heim_error_t *error)
     676             : {
     677             :     struct parse_ctx ctx;
     678             :     heim_object_t o;
     679             : 
     680           0 :     heim_base_once_f(&heim_json_once, NULL, json_init_once);
     681             : 
     682           0 :     ctx.lineno = 1;
     683           0 :     ctx.p = data;
     684           0 :     ctx.pstart = data;
     685           0 :     ctx.pend = ((uint8_t *)data) + length;
     686           0 :     ctx.error = NULL;
     687           0 :     ctx.flags = flags;
     688           0 :     ctx.depth = max_depth;
     689             : 
     690           0 :     o = parse_value(&ctx);
     691             : 
     692           0 :     if (o == NULL && error) {
     693           0 :         *error = ctx.error;
     694           0 :     } else if (ctx.error) {
     695           0 :         heim_release(ctx.error);
     696             :     }
     697             : 
     698           0 :     return o;
     699             : }
     700             : 
     701             : 
     702             : static void
     703           0 : show_printf(void *ctx, const char *str)
     704             : {
     705           0 :     if (str == NULL)
     706           0 :         return;
     707           0 :     fprintf(ctx, "%s", str);
     708             : }
     709             : 
     710             : /**
     711             :  * Dump a heimbase object to stderr (useful from the debugger!)
     712             :  *
     713             :  * @param obj object to dump using JSON or JSON-like format
     714             :  *
     715             :  * @addtogroup heimbase
     716             :  */
     717             : void
     718           0 : heim_show(heim_object_t obj)
     719             : {
     720           0 :     heim_base2json(obj, stderr, HEIM_JSON_F_NO_DATA_DICT, show_printf);
     721           0 : }
     722             : 
     723             : static void
     724           0 : strbuf_add(void *ctx, const char *str)
     725             : {
     726           0 :     struct heim_strbuf *strbuf = ctx;
     727             :     size_t len;
     728             : 
     729           0 :     if (strbuf->enomem)
     730           0 :         return;
     731             : 
     732           0 :     if (str == NULL) {
     733             :         /*
     734             :          * Eat the last '\n'; this is used when formatting dict pairs
     735             :          * and array items so that the ',' separating them is never
     736             :          * preceded by a '\n'.
     737             :          */
     738           0 :         if (strbuf->len > 0 && strbuf->str[strbuf->len - 1] == '\n')
     739           0 :             strbuf->len--;
     740           0 :         return;
     741             :     }
     742             : 
     743           0 :     len = strlen(str);
     744           0 :     if ((len + 1) > (strbuf->alloced - strbuf->len)) {
     745           0 :         size_t new_len = strbuf->alloced + (strbuf->alloced >> 2) + len + 1;
     746             :         char *s;
     747             : 
     748           0 :         s = realloc(strbuf->str, new_len);
     749           0 :         if (s == NULL) {
     750           0 :             strbuf->enomem = 1;
     751           0 :             return;
     752             :         }
     753           0 :         strbuf->str = s;
     754           0 :         strbuf->alloced = new_len;
     755             :     }
     756             :     /* +1 so we copy the NUL */
     757           0 :     (void) memcpy(strbuf->str + strbuf->len, str, len + 1);
     758           0 :     strbuf->len += len;
     759           0 :     if (strbuf->str[strbuf->len - 1] == '\n' && 
     760           0 :         strbuf->flags & HEIM_JSON_F_ONE_LINE)
     761           0 :         strbuf->len--;
     762             : }
     763             : 
     764             : #define STRBUF_INIT_SZ 64
     765             : 
     766             : heim_string_t
     767           0 : heim_json_copy_serialize(heim_object_t obj, heim_json_flags_t flags, heim_error_t *error)
     768             : {
     769             :     heim_string_t str;
     770             :     struct heim_strbuf strbuf;
     771             :     int ret;
     772             : 
     773           0 :     if (error)
     774           0 :         *error = NULL;
     775             : 
     776           0 :     memset(&strbuf, 0, sizeof (strbuf));
     777           0 :     strbuf.str = malloc(STRBUF_INIT_SZ);
     778           0 :     if (strbuf.str == NULL) {
     779           0 :         if (error)
     780           0 :             *error = heim_error_create_enomem();
     781           0 :         return NULL;
     782             :     }
     783           0 :     strbuf.len = 0;
     784           0 :     strbuf.alloced = STRBUF_INIT_SZ;
     785           0 :     strbuf.str[0] = '\0';
     786           0 :     strbuf.flags = flags;
     787             : 
     788           0 :     ret = heim_base2json(obj, &strbuf, flags, strbuf_add);
     789           0 :     if (ret || strbuf.enomem) {
     790           0 :         if (error) {
     791           0 :             if (strbuf.enomem || ret == ENOMEM)
     792           0 :                 *error = heim_error_create_enomem();
     793             :             else
     794           0 :                 *error = heim_error_create(1, "Impossible to JSON-encode "
     795             :                                            "object");
     796             :         }
     797           0 :         free(strbuf.str);
     798           0 :         return NULL;
     799             :     }
     800           0 :     if (flags & HEIM_JSON_F_ONE_LINE) {
     801           0 :         strbuf.flags &= ~HEIM_JSON_F_ONE_LINE;
     802           0 :         strbuf_add(&strbuf, "\n");
     803             :     }
     804           0 :     str = heim_string_ref_create(strbuf.str, free);
     805           0 :     if (str == NULL) {
     806           0 :         if (error)
     807           0 :             *error = heim_error_create_enomem();
     808           0 :         free(strbuf.str);
     809             :     }
     810           0 :     return str;
     811             : }

Generated by: LCOV version 1.13