Path: blob/main/crypto/krb5/src/util/support/json.c
34889 views
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */1/* util/support/json.c - JSON parser and unparser */2/*3* Copyright (c) 2010 Kungliga Tekniska Högskolan4* (Royal Institute of Technology, Stockholm, Sweden).5* All rights reserved.6*7* Portions Copyright (c) 2010 Apple Inc. All rights reserved.8*9* Redistribution and use in source and binary forms, with or without10* modification, are permitted provided that the following conditions11* are met:12*13* 1. Redistributions of source code must retain the above copyright14* notice, this list of conditions and the following disclaimer.15*16* 2. Redistributions in binary form must reproduce the above copyright17* notice, this list of conditions and the following disclaimer in the18* documentation and/or other materials provided with the distribution.19*20* 3. Neither the name of the Institute nor the names of its contributors21* may be used to endorse or promote products derived from this software22* without specific prior written permission.23*24* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND25* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE26* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE27* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE28* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL29* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS30* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)31* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT32* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY33* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF34* SUCH DAMAGE.35*/36/*37* Copyright (C) 2012 by the Massachusetts Institute of Technology.38* All rights reserved.39*40* Redistribution and use in source and binary forms, with or without41* modification, are permitted provided that the following conditions42* are met:43*44* * Redistributions of source code must retain the above copyright45* notice, this list of conditions and the following disclaimer.46*47* * Redistributions in binary form must reproduce the above copyright48* notice, this list of conditions and the following disclaimer in49* the documentation and/or other materials provided with the50* distribution.51*52* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS53* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT54* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS55* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE56* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,57* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES58* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR59* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)60* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,61* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)62* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED63* OF THE POSSIBILITY OF SUCH DAMAGE.64*/6566/*67* This file implements a minimal dynamic type system for JSON values and a68* JSON encoder and decoder. It is loosely based on the heimbase code from69* Heimdal.70*/7172#include <k5-platform.h>73#include <k5-base64.h>74#include <k5-json.h>75#include <k5-buf.h>7677#define MAX_DECODE_DEPTH 6478#define MIN_ALLOC_SLOT 167980typedef void (*type_dealloc_fn)(void *val);8182typedef struct json_type_st {83k5_json_tid tid;84const char *name;85type_dealloc_fn dealloc;86} *json_type;8788struct value_base {89json_type isa;90unsigned int ref_cnt;91};9293#define PTR2BASE(ptr) (((struct value_base *)ptr) - 1)94#define BASE2PTR(ptr) ((void *)(((struct value_base *)ptr) + 1))9596k5_json_value97k5_json_retain(k5_json_value val)98{99struct value_base *p;100101if (val == NULL)102return val;103p = PTR2BASE(val);104assert(p->ref_cnt != 0);105p->ref_cnt++;106return val;107}108109void110k5_json_release(k5_json_value val)111{112struct value_base *p;113114if (val == NULL)115return;116p = PTR2BASE(val);117assert(p->ref_cnt != 0);118p->ref_cnt--;119if (p->ref_cnt == 0) {120if (p->isa->dealloc != NULL)121p->isa->dealloc(val);122free(p);123}124}125126/* Get the type description of a k5_json_value. */127static json_type128get_isa(k5_json_value val)129{130struct value_base *p = PTR2BASE(val);131132return p->isa;133}134135k5_json_tid136k5_json_get_tid(k5_json_value val)137{138json_type isa = get_isa(val);139140return isa->tid;141}142143static k5_json_value144alloc_value(json_type type, size_t size)145{146struct value_base *p = calloc(1, size + sizeof(*p));147148if (p == NULL)149return NULL;150p->isa = type;151p->ref_cnt = 1;152153return BASE2PTR(p);154}155156/*** Null type ***/157158static struct json_type_st null_type = { K5_JSON_TID_NULL, "null", NULL };159160int161k5_json_null_create(k5_json_null *val_out)162{163*val_out = alloc_value(&null_type, 0);164return (*val_out == NULL) ? ENOMEM : 0;165}166167int168k5_json_null_create_val(k5_json_value *val_out)169{170*val_out = alloc_value(&null_type, 0);171return (*val_out == NULL) ? ENOMEM : 0;172}173174/*** Boolean type ***/175176static struct json_type_st bool_type = { K5_JSON_TID_BOOL, "bool", NULL };177178int179k5_json_bool_create(int truth, k5_json_bool *val_out)180{181k5_json_bool b;182183*val_out = NULL;184b = alloc_value(&bool_type, 1);185if (b == NULL)186return ENOMEM;187*(unsigned char *)b = !!truth;188*val_out = b;189return 0;190}191192int193k5_json_bool_value(k5_json_bool bval)194{195return *(unsigned char *)bval;196}197198/*** Array type ***/199200struct k5_json_array_st {201k5_json_value *values;202size_t len;203size_t allocated;204};205206static void207array_dealloc(void *ptr)208{209k5_json_array array = ptr;210size_t i;211212for (i = 0; i < array->len; i++)213k5_json_release(array->values[i]);214free(array->values);215}216217static struct json_type_st array_type = {218K5_JSON_TID_ARRAY, "array", array_dealloc219};220221int222k5_json_array_create(k5_json_array *val_out)223{224*val_out = alloc_value(&array_type, sizeof(struct k5_json_array_st));225return (*val_out == NULL) ? ENOMEM : 0;226}227228int229k5_json_array_add(k5_json_array array, k5_json_value val)230{231k5_json_value *ptr;232size_t new_alloc;233234if (array->len >= array->allocated) {235/* Increase the number of slots by 50% (MIN_ALLOC_SLOT minimum). */236new_alloc = array->len + 1 + (array->len >> 1);237if (new_alloc < MIN_ALLOC_SLOT)238new_alloc = MIN_ALLOC_SLOT;239ptr = realloc(array->values, new_alloc * sizeof(*array->values));240if (ptr == NULL)241return ENOMEM;242array->values = ptr;243array->allocated = new_alloc;244}245array->values[array->len++] = k5_json_retain(val);246return 0;247}248249size_t250k5_json_array_length(k5_json_array array)251{252return array->len;253}254255k5_json_value256k5_json_array_get(k5_json_array array, size_t idx)257{258if (idx >= array->len)259abort();260return array->values[idx];261}262263void264k5_json_array_set(k5_json_array array, size_t idx, k5_json_value val)265{266if (idx >= array->len)267abort();268k5_json_release(array->values[idx]);269array->values[idx] = k5_json_retain(val);270}271272int273k5_json_array_fmt(k5_json_array *array_out, const char *template, ...)274{275const char *p;276va_list ap;277const char *cstring;278unsigned char *data;279size_t len;280long long nval;281k5_json_array array;282k5_json_value val;283k5_json_number num;284k5_json_string str;285k5_json_bool b;286k5_json_null null;287int truth, ret;288289*array_out = NULL;290if (k5_json_array_create(&array))291return ENOMEM;292va_start(ap, template);293for (p = template; *p != '\0'; p++) {294switch (*p) {295case 'v':296val = k5_json_retain(va_arg(ap, k5_json_value));297break;298case 'n':299if (k5_json_null_create(&null))300goto err;301val = null;302break;303case 'b':304truth = va_arg(ap, int);305if (k5_json_bool_create(truth, &b))306goto err;307val = b;308break;309case 'i':310nval = va_arg(ap, int);311if (k5_json_number_create(nval, &num))312goto err;313val = num;314break;315case 'L':316nval = va_arg(ap, long long);317if (k5_json_number_create(nval, &num))318goto err;319val = num;320break;321case 's':322cstring = va_arg(ap, const char *);323if (cstring == NULL) {324if (k5_json_null_create(&null))325goto err;326val = null;327} else {328if (k5_json_string_create(cstring, &str))329goto err;330val = str;331}332break;333case 'B':334data = va_arg(ap, unsigned char *);335len = va_arg(ap, size_t);336if (k5_json_string_create_base64(data, len, &str))337goto err;338val = str;339break;340default:341goto err;342}343ret = k5_json_array_add(array, val);344k5_json_release(val);345if (ret)346goto err;347}348va_end(ap);349*array_out = array;350return 0;351352err:353va_end(ap);354k5_json_release(array);355return ENOMEM;356}357358/*** Object type (string:value mapping) ***/359360struct entry {361char *key;362k5_json_value value;363};364365struct k5_json_object_st {366struct entry *entries;367size_t len;368size_t allocated;369};370371static void372object_dealloc(void *ptr)373{374k5_json_object obj = ptr;375size_t i;376377for (i = 0; i < obj->len; i++) {378free(obj->entries[i].key);379k5_json_release(obj->entries[i].value);380}381free(obj->entries);382}383384static struct json_type_st object_type = {385K5_JSON_TID_OBJECT, "object", object_dealloc386};387388int389k5_json_object_create(k5_json_object *val_out)390{391*val_out = alloc_value(&object_type, sizeof(struct k5_json_object_st));392return (*val_out == NULL) ? ENOMEM : 0;393}394395size_t396k5_json_object_count(k5_json_object obj)397{398return obj->len;399}400401/* Return the entry for key within obj, or NULL if none exists. */402static struct entry *403object_search(k5_json_object obj, const char *key)404{405size_t i;406407for (i = 0; i < obj->len; i++) {408if (strcmp(key, obj->entries[i].key) == 0)409return &obj->entries[i];410}411return NULL;412}413414k5_json_value415k5_json_object_get(k5_json_object obj, const char *key)416{417struct entry *ent;418419ent = object_search(obj, key);420if (ent == NULL)421return NULL;422return ent->value;423}424425int426k5_json_object_set(k5_json_object obj, const char *key, k5_json_value val)427{428struct entry *ent, *ptr;429size_t new_alloc, i;430431ent = object_search(obj, key);432if (ent != NULL) {433k5_json_release(ent->value);434if (val == NULL) {435/* Remove this key. */436free(ent->key);437for (i = ent - obj->entries; i < obj->len - 1; i++)438obj->entries[i] = obj->entries[i + 1];439obj->len--;440} else {441/* Overwrite this key's value with the new one. */442ent->value = k5_json_retain(val);443}444return 0;445}446447/* If didn't find a key the caller asked to remove, do nothing. */448if (val == NULL)449return 0;450451if (obj->len >= obj->allocated) {452/* Increase the number of slots by 50% (MIN_ALLOC_SLOT minimum). */453new_alloc = obj->len + 1 + (obj->len >> 1);454if (new_alloc < MIN_ALLOC_SLOT)455new_alloc = MIN_ALLOC_SLOT;456ptr = realloc(obj->entries, new_alloc * sizeof(*obj->entries));457if (ptr == NULL)458return ENOMEM;459obj->entries = ptr;460obj->allocated = new_alloc;461}462obj->entries[obj->len].key = strdup(key);463if (obj->entries[obj->len].key == NULL)464return ENOMEM;465obj->entries[obj->len].value = k5_json_retain(val);466obj->len++;467return 0;468}469470void471k5_json_object_iterate(k5_json_object obj, k5_json_object_iterator_fn func,472void *arg)473{474size_t i;475476for (i = 0; i < obj->len; i++)477func(arg, obj->entries[i].key, obj->entries[i].value);478}479480/*** String type ***/481482static struct json_type_st string_type = {483K5_JSON_TID_STRING, "string", NULL484};485486int487k5_json_string_create(const char *cstring, k5_json_string *val_out)488{489return k5_json_string_create_len(cstring, strlen(cstring), val_out);490}491492int493k5_json_string_create_len(const void *data, size_t len,494k5_json_string *val_out)495{496char *s;497498*val_out = NULL;499s = alloc_value(&string_type, len + 1);500if (s == NULL)501return ENOMEM;502if (len > 0)503memcpy(s, data, len);504s[len] = '\0';505*val_out = (k5_json_string)s;506return 0;507}508509int510k5_json_string_create_base64(const void *data, size_t len,511k5_json_string *val_out)512{513char *base64;514int ret;515516*val_out = NULL;517base64 = k5_base64_encode(data, len);518if (base64 == NULL)519return ENOMEM;520ret = k5_json_string_create(base64, val_out);521free(base64);522return ret;523}524525const char *526k5_json_string_utf8(k5_json_string string)527{528return (const char *)string;529}530531int532k5_json_string_unbase64(k5_json_string string, unsigned char **data_out,533size_t *len_out)534{535unsigned char *data;536size_t len;537538*data_out = NULL;539*len_out = 0;540data = k5_base64_decode((const char *)string, &len);541if (data == NULL)542return (len == 0) ? ENOMEM : EINVAL;543*data_out = data;544*len_out = len;545return 0;546}547548/*** Number type ***/549550static struct json_type_st number_type = {551K5_JSON_TID_NUMBER, "number", NULL552};553554int555k5_json_number_create(long long number, k5_json_number *val_out)556{557k5_json_number n;558559*val_out = NULL;560n = alloc_value(&number_type, sizeof(long long));561if (n == NULL)562return ENOMEM;563*((long long *)n) = number;564*val_out = n;565return 0;566}567568long long569k5_json_number_value(k5_json_number number)570{571return *(long long *)number;572}573574/*** JSON encoding ***/575576static const char quotemap_json[] = "\"\\/bfnrt";577static const char quotemap_c[] = "\"\\/\b\f\n\r\t";578static const char needs_quote[] = "\\\"\1\2\3\4\5\6\7\10\11\12\13\14\15\16\17"579"\20\21\22\23\24\25\26\27\30\31\32\33\34\35\36\37";580581static int encode_value(struct k5buf *buf, k5_json_value val);582583static void584encode_string(struct k5buf *buf, const char *str)585{586size_t n;587const char *p;588589k5_buf_add(buf, "\"");590while (*str != '\0') {591n = strcspn(str, needs_quote);592k5_buf_add_len(buf, str, n);593str += n;594if (*str == '\0')595break;596k5_buf_add(buf, "\\");597p = strchr(quotemap_c, *str);598if (p != NULL)599k5_buf_add_len(buf, quotemap_json + (p - quotemap_c), 1);600else601k5_buf_add_fmt(buf, "u00%02X", (unsigned int)*str);602str++;603}604k5_buf_add(buf, "\"");605}606607struct obj_ctx {608struct k5buf *buf;609int ret;610int first;611};612613static void614encode_obj_entry(void *ctx, const char *key, k5_json_value value)615{616struct obj_ctx *j = ctx;617618if (j->ret)619return;620if (j->first)621j->first = 0;622else623k5_buf_add(j->buf, ",");624encode_string(j->buf, key);625k5_buf_add(j->buf, ":");626j->ret = encode_value(j->buf, value);627}628629static int630encode_value(struct k5buf *buf, k5_json_value val)631{632k5_json_tid type;633int ret;634size_t i, len;635struct obj_ctx ctx;636637if (val == NULL)638return EINVAL;639640type = k5_json_get_tid(val);641switch (type) {642case K5_JSON_TID_ARRAY:643k5_buf_add(buf, "[");644len = k5_json_array_length(val);645for (i = 0; i < len; i++) {646if (i != 0)647k5_buf_add(buf, ",");648ret = encode_value(buf, k5_json_array_get(val, i));649if (ret)650return ret;651}652k5_buf_add(buf, "]");653return 0;654655case K5_JSON_TID_OBJECT:656k5_buf_add(buf, "{");657ctx.buf = buf;658ctx.ret = 0;659ctx.first = 1;660k5_json_object_iterate(val, encode_obj_entry, &ctx);661k5_buf_add(buf, "}");662return ctx.ret;663664case K5_JSON_TID_STRING:665encode_string(buf, k5_json_string_utf8(val));666return 0;667668case K5_JSON_TID_NUMBER:669k5_buf_add_fmt(buf, "%lld", k5_json_number_value(val));670return 0;671672case K5_JSON_TID_NULL:673k5_buf_add(buf, "null");674return 0;675676case K5_JSON_TID_BOOL:677k5_buf_add(buf, k5_json_bool_value(val) ? "true" : "false");678return 0;679680default:681return EINVAL;682}683}684685int686k5_json_encode(k5_json_value val, char **json_out)687{688struct k5buf buf;689int ret;690691*json_out = NULL;692k5_buf_init_dynamic(&buf);693ret = encode_value(&buf, val);694if (ret) {695k5_buf_free(&buf);696return ret;697}698*json_out = k5_buf_cstring(&buf);699return (*json_out == NULL) ? ENOMEM : 0;700}701702/*** JSON decoding ***/703704struct decode_ctx {705const unsigned char *p;706size_t depth;707};708709static int parse_value(struct decode_ctx *ctx, k5_json_value *val_out);710711/* Consume whitespace. Return 0 if there is anything left to parse after the712* whitespace, -1 if not. */713static int714white_spaces(struct decode_ctx *ctx)715{716unsigned char c;717718for (; *ctx->p != '\0'; ctx->p++) {719c = *ctx->p;720if (c != ' ' && c != '\t' && c != '\r' && c != '\n')721return 0;722}723return -1;724}725726/* Return true if c is a decimal digit. */727static inline int728is_digit(unsigned char c)729{730return ('0' <= c && c <= '9');731}732733/* Return true if c is a hexadecimal digit (per RFC 5234 HEXDIG). */734static inline int735is_hex_digit(unsigned char c)736{737return is_digit(c) || ('A' <= c && c <= 'F');738}739740/* Return the numeric value of a hex digit; aborts if c is not a hex digit. */741static inline unsigned int742hexval(unsigned char c)743{744if (is_digit(c))745return c - '0';746else if ('A' <= c && c <= 'F')747return c - 'A' + 10;748abort();749}750751/* Parse a JSON number (which must be an integer in the signed 64-bit range; we752* do not allow floating-point numbers). */753static int754parse_number(struct decode_ctx *ctx, k5_json_number *val_out)755{756const unsigned long long umax = ~0ULL, smax = (1ULL << 63) - 1;757unsigned long long number = 0;758int neg = 1;759760*val_out = NULL;761762if (*ctx->p == '-') {763neg = -1;764ctx->p++;765}766767if (!is_digit(*ctx->p))768return EINVAL;769770/* Read the number into an unsigned 64-bit container, ensuring that we771* don't overflow it. */772while (is_digit(*ctx->p)) {773if (number + 1 > umax / 10)774return EOVERFLOW;775number = (number * 10) + (*ctx->p - '0');776ctx->p++;777}778779/* Make sure the unsigned 64-bit value fits in the signed 64-bit range. */780if (number > smax + 1 || (number > smax && neg == 1))781return EOVERFLOW;782783return k5_json_number_create(number * neg, val_out);784}785786/* Parse a JSON string (which must not quote Unicode code points above 256). */787static int788parse_string(struct decode_ctx *ctx, char **str_out)789{790const unsigned char *p, *start, *end = NULL;791const char *q;792char *buf, *pos;793unsigned int code;794795*str_out = NULL;796797/* Find the start and end of the string. */798if (*ctx->p != '"')799return EINVAL;800start = ++ctx->p;801for (; *ctx->p != '\0'; ctx->p++) {802if (*ctx->p == '\\') {803ctx->p++;804if (*ctx->p == '\0')805return EINVAL;806} else if (*ctx->p == '"') {807end = ctx->p++;808break;809}810}811if (end == NULL)812return EINVAL;813814pos = buf = malloc(end - start + 1);815if (buf == NULL)816return ENOMEM;817for (p = start; p < end;) {818if (*p == '\\') {819p++;820if (*p == 'u' && is_hex_digit(p[1]) && is_hex_digit(p[2]) &&821is_hex_digit(p[3]) && is_hex_digit(p[4])) {822code = (hexval(p[1]) << 12) | (hexval(p[2]) << 8) |823(hexval(p[3]) << 4) | hexval(p[4]);824if (code <= 0xff) {825*pos++ = code;826} else {827/* Code points above 0xff don't need to be quoted, so we828* don't implement translating those into UTF-8. */829free(buf);830return EINVAL;831}832p += 5;833} else {834q = strchr(quotemap_json, *p);835if (q != NULL) {836*pos++ = quotemap_c[q - quotemap_json];837} else {838free(buf);839return EINVAL;840}841p++;842}843} else {844*pos++ = *p++;845}846}847*pos = '\0';848*str_out = buf;849return 0;850}851852/* Parse an object association and place it into obj. */853static int854parse_object_association(k5_json_object obj, struct decode_ctx *ctx)855{856char *key = NULL;857k5_json_value val;858int ret;859860/* Parse the key and value. */861ret = parse_string(ctx, &key);862if (ret)863return ret;864if (white_spaces(ctx))865goto invalid;866if (*ctx->p != ':')867goto invalid;868ctx->p++;869if (white_spaces(ctx))870goto invalid;871ret = parse_value(ctx, &val);872if (ret) {873free(key);874return ret;875}876877/* Add the key and value to obj. */878ret = k5_json_object_set(obj, key, val);879free(key);880k5_json_release(val);881return ret;882883invalid:884free(key);885return EINVAL;886}887888/* Parse a JSON object. */889static int890parse_object(struct decode_ctx *ctx, k5_json_object *val_out)891{892k5_json_object obj = NULL;893int ret;894895*val_out = NULL;896897/* Parse past the opening brace. */898if (*ctx->p != '{')899return EINVAL;900ctx->p++;901if (white_spaces(ctx))902return EINVAL;903904ret = k5_json_object_create(&obj);905if (ret)906return ret;907908/* Pairs associations until we reach the terminating brace. */909if (*ctx->p != '}') {910while (1) {911ret = parse_object_association(obj, ctx);912if (ret) {913k5_json_release(obj);914return ret;915}916if (white_spaces(ctx))917goto invalid;918if (*ctx->p == '}')919break;920if (*ctx->p != ',')921goto invalid;922ctx->p++;923if (white_spaces(ctx))924goto invalid;925}926}927ctx->p++;928*val_out = obj;929return 0;930931invalid:932k5_json_release(obj);933return EINVAL;934}935936/* Parse an value and place it into array. */937static int938parse_array_item(k5_json_array array, struct decode_ctx *ctx)939{940k5_json_value val;941int ret;942943ret = parse_value(ctx, &val);944if (ret)945return ret;946ret = k5_json_array_add(array, val);947k5_json_release(val);948return ret;949}950951/* Parse a JSON array. */952static int953parse_array(struct decode_ctx *ctx, k5_json_array *val_out)954{955k5_json_array array = NULL;956int ret;957958*val_out = NULL;959960/* Parse past the opening bracket. */961if (*ctx->p != '[')962return EINVAL;963ctx->p++;964if (white_spaces(ctx))965return EINVAL;966967ret = k5_json_array_create(&array);968if (ret)969return ret;970971/* Pairs values until we reach the terminating bracket. */972if (*ctx->p != ']') {973while (1) {974ret = parse_array_item(array, ctx);975if (ret) {976k5_json_release(array);977return ret;978}979if (white_spaces(ctx))980goto invalid;981if (*ctx->p == ']')982break;983if (*ctx->p != ',')984goto invalid;985ctx->p++;986if (white_spaces(ctx))987goto invalid;988}989}990ctx->p++;991*val_out = array;992return 0;993994invalid:995k5_json_release(array);996return EINVAL;997}998999/* Parse a JSON value of any type. */1000static int1001parse_value(struct decode_ctx *ctx, k5_json_value *val_out)1002{1003k5_json_null null;1004k5_json_bool bval;1005k5_json_number num;1006k5_json_string str;1007k5_json_object obj;1008k5_json_array array;1009char *cstring;1010int ret;10111012*val_out = NULL;10131014if (white_spaces(ctx))1015return EINVAL;10161017if (*ctx->p == '"') {1018ret = parse_string(ctx, &cstring);1019if (ret)1020return ret;1021ret = k5_json_string_create(cstring, &str);1022free(cstring);1023if (ret)1024return ret;1025*val_out = str;1026} else if (*ctx->p == '{') {1027if (ctx->depth-- == 1)1028return EINVAL;1029ret = parse_object(ctx, &obj);1030if (ret)1031return ret;1032ctx->depth++;1033*val_out = obj;1034} else if (*ctx->p == '[') {1035if (ctx->depth-- == 1)1036return EINVAL;1037ret = parse_array(ctx, &array);1038ctx->depth++;1039*val_out = array;1040} else if (is_digit(*ctx->p) || *ctx->p == '-') {1041ret = parse_number(ctx, &num);1042if (ret)1043return ret;1044*val_out = num;1045} else if (strncmp((char *)ctx->p, "null", 4) == 0) {1046ctx->p += 4;1047ret = k5_json_null_create(&null);1048if (ret)1049return ret;1050*val_out = null;1051} else if (strncmp((char *)ctx->p, "true", 4) == 0) {1052ctx->p += 4;1053ret = k5_json_bool_create(1, &bval);1054if (ret)1055return ret;1056*val_out = bval;1057} else if (strncmp((char *)ctx->p, "false", 5) == 0) {1058ctx->p += 5;1059ret = k5_json_bool_create(0, &bval);1060if (ret)1061return ret;1062*val_out = bval;1063} else {1064return EINVAL;1065}10661067return 0;1068}10691070int1071k5_json_decode(const char *string, k5_json_value *val_out)1072{1073struct decode_ctx ctx;1074k5_json_value val;1075int ret;10761077*val_out = NULL;1078ctx.p = (unsigned char *)string;1079ctx.depth = MAX_DECODE_DEPTH;1080ret = parse_value(&ctx, &val);1081if (ret)1082return ret;1083if (white_spaces(&ctx) == 0) {1084k5_json_release(val);1085return EINVAL;1086}1087*val_out = val;1088return 0;1089}109010911092