xref: /freebsd/crypto/krb5/src/util/support/json.c (revision 7f2fe78b9dd5f51c821d771b63d2e096f6fd49e9)
1*7f2fe78bSCy Schubert /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2*7f2fe78bSCy Schubert /* util/support/json.c - JSON parser and unparser */
3*7f2fe78bSCy Schubert /*
4*7f2fe78bSCy Schubert  * Copyright (c) 2010 Kungliga Tekniska Högskolan
5*7f2fe78bSCy Schubert  * (Royal Institute of Technology, Stockholm, Sweden).
6*7f2fe78bSCy Schubert  * All rights reserved.
7*7f2fe78bSCy Schubert  *
8*7f2fe78bSCy Schubert  * Portions Copyright (c) 2010 Apple Inc. All rights reserved.
9*7f2fe78bSCy Schubert  *
10*7f2fe78bSCy Schubert  * Redistribution and use in source and binary forms, with or without
11*7f2fe78bSCy Schubert  * modification, are permitted provided that the following conditions
12*7f2fe78bSCy Schubert  * are met:
13*7f2fe78bSCy Schubert  *
14*7f2fe78bSCy Schubert  * 1. Redistributions of source code must retain the above copyright
15*7f2fe78bSCy Schubert  *    notice, this list of conditions and the following disclaimer.
16*7f2fe78bSCy Schubert  *
17*7f2fe78bSCy Schubert  * 2. Redistributions in binary form must reproduce the above copyright
18*7f2fe78bSCy Schubert  *    notice, this list of conditions and the following disclaimer in the
19*7f2fe78bSCy Schubert  *    documentation and/or other materials provided with the distribution.
20*7f2fe78bSCy Schubert  *
21*7f2fe78bSCy Schubert  * 3. Neither the name of the Institute nor the names of its contributors
22*7f2fe78bSCy Schubert  *    may be used to endorse or promote products derived from this software
23*7f2fe78bSCy Schubert  *    without specific prior written permission.
24*7f2fe78bSCy Schubert  *
25*7f2fe78bSCy Schubert  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
26*7f2fe78bSCy Schubert  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27*7f2fe78bSCy Schubert  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28*7f2fe78bSCy Schubert  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
29*7f2fe78bSCy Schubert  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30*7f2fe78bSCy Schubert  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31*7f2fe78bSCy Schubert  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32*7f2fe78bSCy Schubert  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33*7f2fe78bSCy Schubert  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34*7f2fe78bSCy Schubert  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35*7f2fe78bSCy Schubert  * SUCH DAMAGE.
36*7f2fe78bSCy Schubert  */
37*7f2fe78bSCy Schubert /*
38*7f2fe78bSCy Schubert  * Copyright (C) 2012 by the Massachusetts Institute of Technology.
39*7f2fe78bSCy Schubert  * All rights reserved.
40*7f2fe78bSCy Schubert  *
41*7f2fe78bSCy Schubert  * Redistribution and use in source and binary forms, with or without
42*7f2fe78bSCy Schubert  * modification, are permitted provided that the following conditions
43*7f2fe78bSCy Schubert  * are met:
44*7f2fe78bSCy Schubert  *
45*7f2fe78bSCy Schubert  * * Redistributions of source code must retain the above copyright
46*7f2fe78bSCy Schubert  *   notice, this list of conditions and the following disclaimer.
47*7f2fe78bSCy Schubert  *
48*7f2fe78bSCy Schubert  * * Redistributions in binary form must reproduce the above copyright
49*7f2fe78bSCy Schubert  *   notice, this list of conditions and the following disclaimer in
50*7f2fe78bSCy Schubert  *   the documentation and/or other materials provided with the
51*7f2fe78bSCy Schubert  *   distribution.
52*7f2fe78bSCy Schubert  *
53*7f2fe78bSCy Schubert  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
54*7f2fe78bSCy Schubert  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
55*7f2fe78bSCy Schubert  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
56*7f2fe78bSCy Schubert  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
57*7f2fe78bSCy Schubert  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
58*7f2fe78bSCy Schubert  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
59*7f2fe78bSCy Schubert  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
60*7f2fe78bSCy Schubert  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
61*7f2fe78bSCy Schubert  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
62*7f2fe78bSCy Schubert  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
63*7f2fe78bSCy Schubert  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
64*7f2fe78bSCy Schubert  * OF THE POSSIBILITY OF SUCH DAMAGE.
65*7f2fe78bSCy Schubert  */
66*7f2fe78bSCy Schubert 
67*7f2fe78bSCy Schubert /*
68*7f2fe78bSCy Schubert  * This file implements a minimal dynamic type system for JSON values and a
69*7f2fe78bSCy Schubert  * JSON encoder and decoder.  It is loosely based on the heimbase code from
70*7f2fe78bSCy Schubert  * Heimdal.
71*7f2fe78bSCy Schubert  */
72*7f2fe78bSCy Schubert 
73*7f2fe78bSCy Schubert #include <k5-platform.h>
74*7f2fe78bSCy Schubert #include <k5-base64.h>
75*7f2fe78bSCy Schubert #include <k5-json.h>
76*7f2fe78bSCy Schubert #include <k5-buf.h>
77*7f2fe78bSCy Schubert 
78*7f2fe78bSCy Schubert #define MAX_DECODE_DEPTH 64
79*7f2fe78bSCy Schubert #define MIN_ALLOC_SLOT   16
80*7f2fe78bSCy Schubert 
81*7f2fe78bSCy Schubert typedef void (*type_dealloc_fn)(void *val);
82*7f2fe78bSCy Schubert 
83*7f2fe78bSCy Schubert typedef struct json_type_st {
84*7f2fe78bSCy Schubert     k5_json_tid tid;
85*7f2fe78bSCy Schubert     const char *name;
86*7f2fe78bSCy Schubert     type_dealloc_fn dealloc;
87*7f2fe78bSCy Schubert } *json_type;
88*7f2fe78bSCy Schubert 
89*7f2fe78bSCy Schubert struct value_base {
90*7f2fe78bSCy Schubert     json_type isa;
91*7f2fe78bSCy Schubert     unsigned int ref_cnt;
92*7f2fe78bSCy Schubert };
93*7f2fe78bSCy Schubert 
94*7f2fe78bSCy Schubert #define PTR2BASE(ptr) (((struct value_base *)ptr) - 1)
95*7f2fe78bSCy Schubert #define BASE2PTR(ptr) ((void *)(((struct value_base *)ptr) + 1))
96*7f2fe78bSCy Schubert 
97*7f2fe78bSCy Schubert k5_json_value
k5_json_retain(k5_json_value val)98*7f2fe78bSCy Schubert k5_json_retain(k5_json_value val)
99*7f2fe78bSCy Schubert {
100*7f2fe78bSCy Schubert     struct value_base *p;
101*7f2fe78bSCy Schubert 
102*7f2fe78bSCy Schubert     if (val == NULL)
103*7f2fe78bSCy Schubert         return val;
104*7f2fe78bSCy Schubert     p = PTR2BASE(val);
105*7f2fe78bSCy Schubert     assert(p->ref_cnt != 0);
106*7f2fe78bSCy Schubert     p->ref_cnt++;
107*7f2fe78bSCy Schubert     return val;
108*7f2fe78bSCy Schubert }
109*7f2fe78bSCy Schubert 
110*7f2fe78bSCy Schubert void
k5_json_release(k5_json_value val)111*7f2fe78bSCy Schubert k5_json_release(k5_json_value val)
112*7f2fe78bSCy Schubert {
113*7f2fe78bSCy Schubert     struct value_base *p;
114*7f2fe78bSCy Schubert 
115*7f2fe78bSCy Schubert     if (val == NULL)
116*7f2fe78bSCy Schubert         return;
117*7f2fe78bSCy Schubert     p = PTR2BASE(val);
118*7f2fe78bSCy Schubert     assert(p->ref_cnt != 0);
119*7f2fe78bSCy Schubert     p->ref_cnt--;
120*7f2fe78bSCy Schubert     if (p->ref_cnt == 0) {
121*7f2fe78bSCy Schubert         if (p->isa->dealloc != NULL)
122*7f2fe78bSCy Schubert             p->isa->dealloc(val);
123*7f2fe78bSCy Schubert         free(p);
124*7f2fe78bSCy Schubert     }
125*7f2fe78bSCy Schubert }
126*7f2fe78bSCy Schubert 
127*7f2fe78bSCy Schubert /* Get the type description of a k5_json_value. */
128*7f2fe78bSCy Schubert static json_type
get_isa(k5_json_value val)129*7f2fe78bSCy Schubert get_isa(k5_json_value val)
130*7f2fe78bSCy Schubert {
131*7f2fe78bSCy Schubert     struct value_base *p = PTR2BASE(val);
132*7f2fe78bSCy Schubert 
133*7f2fe78bSCy Schubert     return p->isa;
134*7f2fe78bSCy Schubert }
135*7f2fe78bSCy Schubert 
136*7f2fe78bSCy Schubert k5_json_tid
k5_json_get_tid(k5_json_value val)137*7f2fe78bSCy Schubert k5_json_get_tid(k5_json_value val)
138*7f2fe78bSCy Schubert {
139*7f2fe78bSCy Schubert     json_type isa = get_isa(val);
140*7f2fe78bSCy Schubert 
141*7f2fe78bSCy Schubert     return isa->tid;
142*7f2fe78bSCy Schubert }
143*7f2fe78bSCy Schubert 
144*7f2fe78bSCy Schubert static k5_json_value
alloc_value(json_type type,size_t size)145*7f2fe78bSCy Schubert alloc_value(json_type type, size_t size)
146*7f2fe78bSCy Schubert {
147*7f2fe78bSCy Schubert     struct value_base *p = calloc(1, size + sizeof(*p));
148*7f2fe78bSCy Schubert 
149*7f2fe78bSCy Schubert     if (p == NULL)
150*7f2fe78bSCy Schubert         return NULL;
151*7f2fe78bSCy Schubert     p->isa = type;
152*7f2fe78bSCy Schubert     p->ref_cnt = 1;
153*7f2fe78bSCy Schubert 
154*7f2fe78bSCy Schubert     return BASE2PTR(p);
155*7f2fe78bSCy Schubert }
156*7f2fe78bSCy Schubert 
157*7f2fe78bSCy Schubert /*** Null type ***/
158*7f2fe78bSCy Schubert 
159*7f2fe78bSCy Schubert static struct json_type_st null_type = { K5_JSON_TID_NULL, "null", NULL };
160*7f2fe78bSCy Schubert 
161*7f2fe78bSCy Schubert int
k5_json_null_create(k5_json_null * val_out)162*7f2fe78bSCy Schubert k5_json_null_create(k5_json_null *val_out)
163*7f2fe78bSCy Schubert {
164*7f2fe78bSCy Schubert     *val_out = alloc_value(&null_type, 0);
165*7f2fe78bSCy Schubert     return (*val_out == NULL) ? ENOMEM : 0;
166*7f2fe78bSCy Schubert }
167*7f2fe78bSCy Schubert 
168*7f2fe78bSCy Schubert int
k5_json_null_create_val(k5_json_value * val_out)169*7f2fe78bSCy Schubert k5_json_null_create_val(k5_json_value *val_out)
170*7f2fe78bSCy Schubert {
171*7f2fe78bSCy Schubert     *val_out = alloc_value(&null_type, 0);
172*7f2fe78bSCy Schubert     return (*val_out == NULL) ? ENOMEM : 0;
173*7f2fe78bSCy Schubert }
174*7f2fe78bSCy Schubert 
175*7f2fe78bSCy Schubert /*** Boolean type ***/
176*7f2fe78bSCy Schubert 
177*7f2fe78bSCy Schubert static struct json_type_st bool_type = { K5_JSON_TID_BOOL, "bool", NULL };
178*7f2fe78bSCy Schubert 
179*7f2fe78bSCy Schubert int
k5_json_bool_create(int truth,k5_json_bool * val_out)180*7f2fe78bSCy Schubert k5_json_bool_create(int truth, k5_json_bool *val_out)
181*7f2fe78bSCy Schubert {
182*7f2fe78bSCy Schubert     k5_json_bool b;
183*7f2fe78bSCy Schubert 
184*7f2fe78bSCy Schubert     *val_out = NULL;
185*7f2fe78bSCy Schubert     b = alloc_value(&bool_type, 1);
186*7f2fe78bSCy Schubert     if (b == NULL)
187*7f2fe78bSCy Schubert         return ENOMEM;
188*7f2fe78bSCy Schubert     *(unsigned char *)b = !!truth;
189*7f2fe78bSCy Schubert     *val_out = b;
190*7f2fe78bSCy Schubert     return 0;
191*7f2fe78bSCy Schubert }
192*7f2fe78bSCy Schubert 
193*7f2fe78bSCy Schubert int
k5_json_bool_value(k5_json_bool bval)194*7f2fe78bSCy Schubert k5_json_bool_value(k5_json_bool bval)
195*7f2fe78bSCy Schubert {
196*7f2fe78bSCy Schubert     return *(unsigned char *)bval;
197*7f2fe78bSCy Schubert }
198*7f2fe78bSCy Schubert 
199*7f2fe78bSCy Schubert /*** Array type ***/
200*7f2fe78bSCy Schubert 
201*7f2fe78bSCy Schubert struct k5_json_array_st {
202*7f2fe78bSCy Schubert     k5_json_value *values;
203*7f2fe78bSCy Schubert     size_t len;
204*7f2fe78bSCy Schubert     size_t allocated;
205*7f2fe78bSCy Schubert };
206*7f2fe78bSCy Schubert 
207*7f2fe78bSCy Schubert static void
array_dealloc(void * ptr)208*7f2fe78bSCy Schubert array_dealloc(void *ptr)
209*7f2fe78bSCy Schubert {
210*7f2fe78bSCy Schubert     k5_json_array array = ptr;
211*7f2fe78bSCy Schubert     size_t i;
212*7f2fe78bSCy Schubert 
213*7f2fe78bSCy Schubert     for (i = 0; i < array->len; i++)
214*7f2fe78bSCy Schubert         k5_json_release(array->values[i]);
215*7f2fe78bSCy Schubert     free(array->values);
216*7f2fe78bSCy Schubert }
217*7f2fe78bSCy Schubert 
218*7f2fe78bSCy Schubert static struct json_type_st array_type = {
219*7f2fe78bSCy Schubert     K5_JSON_TID_ARRAY, "array", array_dealloc
220*7f2fe78bSCy Schubert };
221*7f2fe78bSCy Schubert 
222*7f2fe78bSCy Schubert int
k5_json_array_create(k5_json_array * val_out)223*7f2fe78bSCy Schubert k5_json_array_create(k5_json_array *val_out)
224*7f2fe78bSCy Schubert {
225*7f2fe78bSCy Schubert     *val_out = alloc_value(&array_type, sizeof(struct k5_json_array_st));
226*7f2fe78bSCy Schubert     return (*val_out == NULL) ? ENOMEM : 0;
227*7f2fe78bSCy Schubert }
228*7f2fe78bSCy Schubert 
229*7f2fe78bSCy Schubert int
k5_json_array_add(k5_json_array array,k5_json_value val)230*7f2fe78bSCy Schubert k5_json_array_add(k5_json_array array, k5_json_value val)
231*7f2fe78bSCy Schubert {
232*7f2fe78bSCy Schubert     k5_json_value *ptr;
233*7f2fe78bSCy Schubert     size_t new_alloc;
234*7f2fe78bSCy Schubert 
235*7f2fe78bSCy Schubert     if (array->len >= array->allocated) {
236*7f2fe78bSCy Schubert         /* Increase the number of slots by 50% (MIN_ALLOC_SLOT minimum). */
237*7f2fe78bSCy Schubert         new_alloc = array->len + 1 + (array->len >> 1);
238*7f2fe78bSCy Schubert         if (new_alloc < MIN_ALLOC_SLOT)
239*7f2fe78bSCy Schubert             new_alloc = MIN_ALLOC_SLOT;
240*7f2fe78bSCy Schubert         ptr = realloc(array->values, new_alloc * sizeof(*array->values));
241*7f2fe78bSCy Schubert         if (ptr == NULL)
242*7f2fe78bSCy Schubert             return ENOMEM;
243*7f2fe78bSCy Schubert         array->values = ptr;
244*7f2fe78bSCy Schubert         array->allocated = new_alloc;
245*7f2fe78bSCy Schubert     }
246*7f2fe78bSCy Schubert     array->values[array->len++] = k5_json_retain(val);
247*7f2fe78bSCy Schubert     return 0;
248*7f2fe78bSCy Schubert }
249*7f2fe78bSCy Schubert 
250*7f2fe78bSCy Schubert size_t
k5_json_array_length(k5_json_array array)251*7f2fe78bSCy Schubert k5_json_array_length(k5_json_array array)
252*7f2fe78bSCy Schubert {
253*7f2fe78bSCy Schubert     return array->len;
254*7f2fe78bSCy Schubert }
255*7f2fe78bSCy Schubert 
256*7f2fe78bSCy Schubert k5_json_value
k5_json_array_get(k5_json_array array,size_t idx)257*7f2fe78bSCy Schubert k5_json_array_get(k5_json_array array, size_t idx)
258*7f2fe78bSCy Schubert {
259*7f2fe78bSCy Schubert     if (idx >= array->len)
260*7f2fe78bSCy Schubert         abort();
261*7f2fe78bSCy Schubert     return array->values[idx];
262*7f2fe78bSCy Schubert }
263*7f2fe78bSCy Schubert 
264*7f2fe78bSCy Schubert void
k5_json_array_set(k5_json_array array,size_t idx,k5_json_value val)265*7f2fe78bSCy Schubert k5_json_array_set(k5_json_array array, size_t idx, k5_json_value val)
266*7f2fe78bSCy Schubert {
267*7f2fe78bSCy Schubert     if (idx >= array->len)
268*7f2fe78bSCy Schubert         abort();
269*7f2fe78bSCy Schubert     k5_json_release(array->values[idx]);
270*7f2fe78bSCy Schubert     array->values[idx] = k5_json_retain(val);
271*7f2fe78bSCy Schubert }
272*7f2fe78bSCy Schubert 
273*7f2fe78bSCy Schubert int
k5_json_array_fmt(k5_json_array * array_out,const char * template,...)274*7f2fe78bSCy Schubert k5_json_array_fmt(k5_json_array *array_out, const char *template, ...)
275*7f2fe78bSCy Schubert {
276*7f2fe78bSCy Schubert     const char *p;
277*7f2fe78bSCy Schubert     va_list ap;
278*7f2fe78bSCy Schubert     const char *cstring;
279*7f2fe78bSCy Schubert     unsigned char *data;
280*7f2fe78bSCy Schubert     size_t len;
281*7f2fe78bSCy Schubert     long long nval;
282*7f2fe78bSCy Schubert     k5_json_array array;
283*7f2fe78bSCy Schubert     k5_json_value val;
284*7f2fe78bSCy Schubert     k5_json_number num;
285*7f2fe78bSCy Schubert     k5_json_string str;
286*7f2fe78bSCy Schubert     k5_json_bool b;
287*7f2fe78bSCy Schubert     k5_json_null null;
288*7f2fe78bSCy Schubert     int truth, ret;
289*7f2fe78bSCy Schubert 
290*7f2fe78bSCy Schubert     *array_out = NULL;
291*7f2fe78bSCy Schubert     if (k5_json_array_create(&array))
292*7f2fe78bSCy Schubert         return ENOMEM;
293*7f2fe78bSCy Schubert     va_start(ap, template);
294*7f2fe78bSCy Schubert     for (p = template; *p != '\0'; p++) {
295*7f2fe78bSCy Schubert         switch (*p) {
296*7f2fe78bSCy Schubert         case 'v':
297*7f2fe78bSCy Schubert             val = k5_json_retain(va_arg(ap, k5_json_value));
298*7f2fe78bSCy Schubert             break;
299*7f2fe78bSCy Schubert         case 'n':
300*7f2fe78bSCy Schubert             if (k5_json_null_create(&null))
301*7f2fe78bSCy Schubert                 goto err;
302*7f2fe78bSCy Schubert             val = null;
303*7f2fe78bSCy Schubert             break;
304*7f2fe78bSCy Schubert         case 'b':
305*7f2fe78bSCy Schubert             truth = va_arg(ap, int);
306*7f2fe78bSCy Schubert             if (k5_json_bool_create(truth, &b))
307*7f2fe78bSCy Schubert                 goto err;
308*7f2fe78bSCy Schubert             val = b;
309*7f2fe78bSCy Schubert             break;
310*7f2fe78bSCy Schubert         case 'i':
311*7f2fe78bSCy Schubert             nval = va_arg(ap, int);
312*7f2fe78bSCy Schubert             if (k5_json_number_create(nval, &num))
313*7f2fe78bSCy Schubert                 goto err;
314*7f2fe78bSCy Schubert             val = num;
315*7f2fe78bSCy Schubert             break;
316*7f2fe78bSCy Schubert         case 'L':
317*7f2fe78bSCy Schubert             nval = va_arg(ap, long long);
318*7f2fe78bSCy Schubert             if (k5_json_number_create(nval, &num))
319*7f2fe78bSCy Schubert                 goto err;
320*7f2fe78bSCy Schubert             val = num;
321*7f2fe78bSCy Schubert             break;
322*7f2fe78bSCy Schubert         case 's':
323*7f2fe78bSCy Schubert             cstring = va_arg(ap, const char *);
324*7f2fe78bSCy Schubert             if (cstring == NULL) {
325*7f2fe78bSCy Schubert                 if (k5_json_null_create(&null))
326*7f2fe78bSCy Schubert                     goto err;
327*7f2fe78bSCy Schubert                 val = null;
328*7f2fe78bSCy Schubert             } else {
329*7f2fe78bSCy Schubert                 if (k5_json_string_create(cstring, &str))
330*7f2fe78bSCy Schubert                     goto err;
331*7f2fe78bSCy Schubert                 val = str;
332*7f2fe78bSCy Schubert             }
333*7f2fe78bSCy Schubert             break;
334*7f2fe78bSCy Schubert         case 'B':
335*7f2fe78bSCy Schubert             data = va_arg(ap, unsigned char *);
336*7f2fe78bSCy Schubert             len = va_arg(ap, size_t);
337*7f2fe78bSCy Schubert             if (k5_json_string_create_base64(data, len, &str))
338*7f2fe78bSCy Schubert                 goto err;
339*7f2fe78bSCy Schubert             val = str;
340*7f2fe78bSCy Schubert             break;
341*7f2fe78bSCy Schubert         default:
342*7f2fe78bSCy Schubert             goto err;
343*7f2fe78bSCy Schubert         }
344*7f2fe78bSCy Schubert         ret = k5_json_array_add(array, val);
345*7f2fe78bSCy Schubert         k5_json_release(val);
346*7f2fe78bSCy Schubert         if (ret)
347*7f2fe78bSCy Schubert             goto err;
348*7f2fe78bSCy Schubert     }
349*7f2fe78bSCy Schubert     va_end(ap);
350*7f2fe78bSCy Schubert     *array_out = array;
351*7f2fe78bSCy Schubert     return 0;
352*7f2fe78bSCy Schubert 
353*7f2fe78bSCy Schubert err:
354*7f2fe78bSCy Schubert     va_end(ap);
355*7f2fe78bSCy Schubert     k5_json_release(array);
356*7f2fe78bSCy Schubert     return ENOMEM;
357*7f2fe78bSCy Schubert }
358*7f2fe78bSCy Schubert 
359*7f2fe78bSCy Schubert /*** Object type (string:value mapping) ***/
360*7f2fe78bSCy Schubert 
361*7f2fe78bSCy Schubert struct entry {
362*7f2fe78bSCy Schubert     char *key;
363*7f2fe78bSCy Schubert     k5_json_value value;
364*7f2fe78bSCy Schubert };
365*7f2fe78bSCy Schubert 
366*7f2fe78bSCy Schubert struct k5_json_object_st {
367*7f2fe78bSCy Schubert     struct entry *entries;
368*7f2fe78bSCy Schubert     size_t len;
369*7f2fe78bSCy Schubert     size_t allocated;
370*7f2fe78bSCy Schubert };
371*7f2fe78bSCy Schubert 
372*7f2fe78bSCy Schubert static void
object_dealloc(void * ptr)373*7f2fe78bSCy Schubert object_dealloc(void *ptr)
374*7f2fe78bSCy Schubert {
375*7f2fe78bSCy Schubert     k5_json_object obj = ptr;
376*7f2fe78bSCy Schubert     size_t i;
377*7f2fe78bSCy Schubert 
378*7f2fe78bSCy Schubert     for (i = 0; i < obj->len; i++) {
379*7f2fe78bSCy Schubert         free(obj->entries[i].key);
380*7f2fe78bSCy Schubert         k5_json_release(obj->entries[i].value);
381*7f2fe78bSCy Schubert     }
382*7f2fe78bSCy Schubert     free(obj->entries);
383*7f2fe78bSCy Schubert }
384*7f2fe78bSCy Schubert 
385*7f2fe78bSCy Schubert static struct json_type_st object_type = {
386*7f2fe78bSCy Schubert     K5_JSON_TID_OBJECT, "object", object_dealloc
387*7f2fe78bSCy Schubert };
388*7f2fe78bSCy Schubert 
389*7f2fe78bSCy Schubert int
k5_json_object_create(k5_json_object * val_out)390*7f2fe78bSCy Schubert k5_json_object_create(k5_json_object *val_out)
391*7f2fe78bSCy Schubert {
392*7f2fe78bSCy Schubert     *val_out = alloc_value(&object_type, sizeof(struct k5_json_object_st));
393*7f2fe78bSCy Schubert     return (*val_out == NULL) ? ENOMEM : 0;
394*7f2fe78bSCy Schubert }
395*7f2fe78bSCy Schubert 
396*7f2fe78bSCy Schubert size_t
k5_json_object_count(k5_json_object obj)397*7f2fe78bSCy Schubert k5_json_object_count(k5_json_object obj)
398*7f2fe78bSCy Schubert {
399*7f2fe78bSCy Schubert     return obj->len;
400*7f2fe78bSCy Schubert }
401*7f2fe78bSCy Schubert 
402*7f2fe78bSCy Schubert /* Return the entry for key within obj, or NULL if none exists. */
403*7f2fe78bSCy Schubert static struct entry *
object_search(k5_json_object obj,const char * key)404*7f2fe78bSCy Schubert object_search(k5_json_object obj, const char *key)
405*7f2fe78bSCy Schubert {
406*7f2fe78bSCy Schubert     size_t i;
407*7f2fe78bSCy Schubert 
408*7f2fe78bSCy Schubert     for (i = 0; i < obj->len; i++) {
409*7f2fe78bSCy Schubert         if (strcmp(key, obj->entries[i].key) == 0)
410*7f2fe78bSCy Schubert             return &obj->entries[i];
411*7f2fe78bSCy Schubert     }
412*7f2fe78bSCy Schubert     return NULL;
413*7f2fe78bSCy Schubert }
414*7f2fe78bSCy Schubert 
415*7f2fe78bSCy Schubert k5_json_value
k5_json_object_get(k5_json_object obj,const char * key)416*7f2fe78bSCy Schubert k5_json_object_get(k5_json_object obj, const char *key)
417*7f2fe78bSCy Schubert {
418*7f2fe78bSCy Schubert     struct entry *ent;
419*7f2fe78bSCy Schubert 
420*7f2fe78bSCy Schubert     ent = object_search(obj, key);
421*7f2fe78bSCy Schubert     if (ent == NULL)
422*7f2fe78bSCy Schubert         return NULL;
423*7f2fe78bSCy Schubert     return ent->value;
424*7f2fe78bSCy Schubert }
425*7f2fe78bSCy Schubert 
426*7f2fe78bSCy Schubert int
k5_json_object_set(k5_json_object obj,const char * key,k5_json_value val)427*7f2fe78bSCy Schubert k5_json_object_set(k5_json_object obj, const char *key, k5_json_value val)
428*7f2fe78bSCy Schubert {
429*7f2fe78bSCy Schubert     struct entry *ent, *ptr;
430*7f2fe78bSCy Schubert     size_t new_alloc, i;
431*7f2fe78bSCy Schubert 
432*7f2fe78bSCy Schubert     ent = object_search(obj, key);
433*7f2fe78bSCy Schubert     if (ent != NULL) {
434*7f2fe78bSCy Schubert         k5_json_release(ent->value);
435*7f2fe78bSCy Schubert         if (val == NULL) {
436*7f2fe78bSCy Schubert             /* Remove this key. */
437*7f2fe78bSCy Schubert             free(ent->key);
438*7f2fe78bSCy Schubert             for (i = ent - obj->entries; i < obj->len - 1; i++)
439*7f2fe78bSCy Schubert                 obj->entries[i] = obj->entries[i + 1];
440*7f2fe78bSCy Schubert             obj->len--;
441*7f2fe78bSCy Schubert         } else {
442*7f2fe78bSCy Schubert             /* Overwrite this key's value with the new one. */
443*7f2fe78bSCy Schubert             ent->value = k5_json_retain(val);
444*7f2fe78bSCy Schubert         }
445*7f2fe78bSCy Schubert         return 0;
446*7f2fe78bSCy Schubert     }
447*7f2fe78bSCy Schubert 
448*7f2fe78bSCy Schubert     /* If didn't find a key the caller asked to remove, do nothing. */
449*7f2fe78bSCy Schubert     if (val == NULL)
450*7f2fe78bSCy Schubert         return 0;
451*7f2fe78bSCy Schubert 
452*7f2fe78bSCy Schubert     if (obj->len >= obj->allocated) {
453*7f2fe78bSCy Schubert         /* Increase the number of slots by 50% (MIN_ALLOC_SLOT minimum). */
454*7f2fe78bSCy Schubert         new_alloc = obj->len + 1 + (obj->len >> 1);
455*7f2fe78bSCy Schubert         if (new_alloc < MIN_ALLOC_SLOT)
456*7f2fe78bSCy Schubert             new_alloc = MIN_ALLOC_SLOT;
457*7f2fe78bSCy Schubert         ptr = realloc(obj->entries, new_alloc * sizeof(*obj->entries));
458*7f2fe78bSCy Schubert         if (ptr == NULL)
459*7f2fe78bSCy Schubert             return ENOMEM;
460*7f2fe78bSCy Schubert         obj->entries = ptr;
461*7f2fe78bSCy Schubert         obj->allocated = new_alloc;
462*7f2fe78bSCy Schubert     }
463*7f2fe78bSCy Schubert     obj->entries[obj->len].key = strdup(key);
464*7f2fe78bSCy Schubert     if (obj->entries[obj->len].key == NULL)
465*7f2fe78bSCy Schubert         return ENOMEM;
466*7f2fe78bSCy Schubert     obj->entries[obj->len].value = k5_json_retain(val);
467*7f2fe78bSCy Schubert     obj->len++;
468*7f2fe78bSCy Schubert     return 0;
469*7f2fe78bSCy Schubert }
470*7f2fe78bSCy Schubert 
471*7f2fe78bSCy Schubert void
k5_json_object_iterate(k5_json_object obj,k5_json_object_iterator_fn func,void * arg)472*7f2fe78bSCy Schubert k5_json_object_iterate(k5_json_object obj, k5_json_object_iterator_fn func,
473*7f2fe78bSCy Schubert                        void *arg)
474*7f2fe78bSCy Schubert {
475*7f2fe78bSCy Schubert     size_t i;
476*7f2fe78bSCy Schubert 
477*7f2fe78bSCy Schubert     for (i = 0; i < obj->len; i++)
478*7f2fe78bSCy Schubert         func(arg, obj->entries[i].key, obj->entries[i].value);
479*7f2fe78bSCy Schubert }
480*7f2fe78bSCy Schubert 
481*7f2fe78bSCy Schubert /*** String type ***/
482*7f2fe78bSCy Schubert 
483*7f2fe78bSCy Schubert static struct json_type_st string_type = {
484*7f2fe78bSCy Schubert     K5_JSON_TID_STRING, "string", NULL
485*7f2fe78bSCy Schubert };
486*7f2fe78bSCy Schubert 
487*7f2fe78bSCy Schubert int
k5_json_string_create(const char * cstring,k5_json_string * val_out)488*7f2fe78bSCy Schubert k5_json_string_create(const char *cstring, k5_json_string *val_out)
489*7f2fe78bSCy Schubert {
490*7f2fe78bSCy Schubert     return k5_json_string_create_len(cstring, strlen(cstring), val_out);
491*7f2fe78bSCy Schubert }
492*7f2fe78bSCy Schubert 
493*7f2fe78bSCy Schubert int
k5_json_string_create_len(const void * data,size_t len,k5_json_string * val_out)494*7f2fe78bSCy Schubert k5_json_string_create_len(const void *data, size_t len,
495*7f2fe78bSCy Schubert                           k5_json_string *val_out)
496*7f2fe78bSCy Schubert {
497*7f2fe78bSCy Schubert     char *s;
498*7f2fe78bSCy Schubert 
499*7f2fe78bSCy Schubert     *val_out = NULL;
500*7f2fe78bSCy Schubert     s = alloc_value(&string_type, len + 1);
501*7f2fe78bSCy Schubert     if (s == NULL)
502*7f2fe78bSCy Schubert         return ENOMEM;
503*7f2fe78bSCy Schubert     if (len > 0)
504*7f2fe78bSCy Schubert         memcpy(s, data, len);
505*7f2fe78bSCy Schubert     s[len] = '\0';
506*7f2fe78bSCy Schubert     *val_out = (k5_json_string)s;
507*7f2fe78bSCy Schubert     return 0;
508*7f2fe78bSCy Schubert }
509*7f2fe78bSCy Schubert 
510*7f2fe78bSCy Schubert int
k5_json_string_create_base64(const void * data,size_t len,k5_json_string * val_out)511*7f2fe78bSCy Schubert k5_json_string_create_base64(const void *data, size_t len,
512*7f2fe78bSCy Schubert                              k5_json_string *val_out)
513*7f2fe78bSCy Schubert {
514*7f2fe78bSCy Schubert     char *base64;
515*7f2fe78bSCy Schubert     int ret;
516*7f2fe78bSCy Schubert 
517*7f2fe78bSCy Schubert     *val_out = NULL;
518*7f2fe78bSCy Schubert     base64 = k5_base64_encode(data, len);
519*7f2fe78bSCy Schubert     if (base64 == NULL)
520*7f2fe78bSCy Schubert         return ENOMEM;
521*7f2fe78bSCy Schubert     ret = k5_json_string_create(base64, val_out);
522*7f2fe78bSCy Schubert     free(base64);
523*7f2fe78bSCy Schubert     return ret;
524*7f2fe78bSCy Schubert }
525*7f2fe78bSCy Schubert 
526*7f2fe78bSCy Schubert const char *
k5_json_string_utf8(k5_json_string string)527*7f2fe78bSCy Schubert k5_json_string_utf8(k5_json_string string)
528*7f2fe78bSCy Schubert {
529*7f2fe78bSCy Schubert     return (const char *)string;
530*7f2fe78bSCy Schubert }
531*7f2fe78bSCy Schubert 
532*7f2fe78bSCy Schubert int
k5_json_string_unbase64(k5_json_string string,unsigned char ** data_out,size_t * len_out)533*7f2fe78bSCy Schubert k5_json_string_unbase64(k5_json_string string, unsigned char **data_out,
534*7f2fe78bSCy Schubert                         size_t *len_out)
535*7f2fe78bSCy Schubert {
536*7f2fe78bSCy Schubert     unsigned char *data;
537*7f2fe78bSCy Schubert     size_t len;
538*7f2fe78bSCy Schubert 
539*7f2fe78bSCy Schubert     *data_out = NULL;
540*7f2fe78bSCy Schubert     *len_out = 0;
541*7f2fe78bSCy Schubert     data = k5_base64_decode((const char *)string, &len);
542*7f2fe78bSCy Schubert     if (data == NULL)
543*7f2fe78bSCy Schubert         return (len == 0) ? ENOMEM : EINVAL;
544*7f2fe78bSCy Schubert     *data_out = data;
545*7f2fe78bSCy Schubert     *len_out = len;
546*7f2fe78bSCy Schubert     return 0;
547*7f2fe78bSCy Schubert }
548*7f2fe78bSCy Schubert 
549*7f2fe78bSCy Schubert /*** Number type ***/
550*7f2fe78bSCy Schubert 
551*7f2fe78bSCy Schubert static struct json_type_st number_type = {
552*7f2fe78bSCy Schubert     K5_JSON_TID_NUMBER, "number", NULL
553*7f2fe78bSCy Schubert };
554*7f2fe78bSCy Schubert 
555*7f2fe78bSCy Schubert int
k5_json_number_create(long long number,k5_json_number * val_out)556*7f2fe78bSCy Schubert k5_json_number_create(long long number, k5_json_number *val_out)
557*7f2fe78bSCy Schubert {
558*7f2fe78bSCy Schubert     k5_json_number n;
559*7f2fe78bSCy Schubert 
560*7f2fe78bSCy Schubert     *val_out = NULL;
561*7f2fe78bSCy Schubert     n = alloc_value(&number_type, sizeof(long long));
562*7f2fe78bSCy Schubert     if (n == NULL)
563*7f2fe78bSCy Schubert         return ENOMEM;
564*7f2fe78bSCy Schubert     *((long long *)n) = number;
565*7f2fe78bSCy Schubert     *val_out = n;
566*7f2fe78bSCy Schubert     return 0;
567*7f2fe78bSCy Schubert }
568*7f2fe78bSCy Schubert 
569*7f2fe78bSCy Schubert long long
k5_json_number_value(k5_json_number number)570*7f2fe78bSCy Schubert k5_json_number_value(k5_json_number number)
571*7f2fe78bSCy Schubert {
572*7f2fe78bSCy Schubert     return *(long long *)number;
573*7f2fe78bSCy Schubert }
574*7f2fe78bSCy Schubert 
575*7f2fe78bSCy Schubert /*** JSON encoding ***/
576*7f2fe78bSCy Schubert 
577*7f2fe78bSCy Schubert static const char quotemap_json[] = "\"\\/bfnrt";
578*7f2fe78bSCy Schubert static const char quotemap_c[] = "\"\\/\b\f\n\r\t";
579*7f2fe78bSCy Schubert static const char needs_quote[] = "\\\"\1\2\3\4\5\6\7\10\11\12\13\14\15\16\17"
580*7f2fe78bSCy Schubert     "\20\21\22\23\24\25\26\27\30\31\32\33\34\35\36\37";
581*7f2fe78bSCy Schubert 
582*7f2fe78bSCy Schubert static int encode_value(struct k5buf *buf, k5_json_value val);
583*7f2fe78bSCy Schubert 
584*7f2fe78bSCy Schubert static void
encode_string(struct k5buf * buf,const char * str)585*7f2fe78bSCy Schubert encode_string(struct k5buf *buf, const char *str)
586*7f2fe78bSCy Schubert {
587*7f2fe78bSCy Schubert     size_t n;
588*7f2fe78bSCy Schubert     const char *p;
589*7f2fe78bSCy Schubert 
590*7f2fe78bSCy Schubert     k5_buf_add(buf, "\"");
591*7f2fe78bSCy Schubert     while (*str != '\0') {
592*7f2fe78bSCy Schubert         n = strcspn(str, needs_quote);
593*7f2fe78bSCy Schubert         k5_buf_add_len(buf, str, n);
594*7f2fe78bSCy Schubert         str += n;
595*7f2fe78bSCy Schubert         if (*str == '\0')
596*7f2fe78bSCy Schubert             break;
597*7f2fe78bSCy Schubert         k5_buf_add(buf, "\\");
598*7f2fe78bSCy Schubert         p = strchr(quotemap_c, *str);
599*7f2fe78bSCy Schubert         if (p != NULL)
600*7f2fe78bSCy Schubert             k5_buf_add_len(buf, quotemap_json + (p - quotemap_c), 1);
601*7f2fe78bSCy Schubert         else
602*7f2fe78bSCy Schubert             k5_buf_add_fmt(buf, "u00%02X", (unsigned int)*str);
603*7f2fe78bSCy Schubert         str++;
604*7f2fe78bSCy Schubert     }
605*7f2fe78bSCy Schubert     k5_buf_add(buf, "\"");
606*7f2fe78bSCy Schubert }
607*7f2fe78bSCy Schubert 
608*7f2fe78bSCy Schubert struct obj_ctx {
609*7f2fe78bSCy Schubert     struct k5buf *buf;
610*7f2fe78bSCy Schubert     int ret;
611*7f2fe78bSCy Schubert     int first;
612*7f2fe78bSCy Schubert };
613*7f2fe78bSCy Schubert 
614*7f2fe78bSCy Schubert static void
encode_obj_entry(void * ctx,const char * key,k5_json_value value)615*7f2fe78bSCy Schubert encode_obj_entry(void *ctx, const char *key, k5_json_value value)
616*7f2fe78bSCy Schubert {
617*7f2fe78bSCy Schubert     struct obj_ctx *j = ctx;
618*7f2fe78bSCy Schubert 
619*7f2fe78bSCy Schubert     if (j->ret)
620*7f2fe78bSCy Schubert         return;
621*7f2fe78bSCy Schubert     if (j->first)
622*7f2fe78bSCy Schubert         j->first = 0;
623*7f2fe78bSCy Schubert     else
624*7f2fe78bSCy Schubert         k5_buf_add(j->buf, ",");
625*7f2fe78bSCy Schubert     encode_string(j->buf, key);
626*7f2fe78bSCy Schubert     k5_buf_add(j->buf, ":");
627*7f2fe78bSCy Schubert     j->ret = encode_value(j->buf, value);
628*7f2fe78bSCy Schubert }
629*7f2fe78bSCy Schubert 
630*7f2fe78bSCy Schubert static int
encode_value(struct k5buf * buf,k5_json_value val)631*7f2fe78bSCy Schubert encode_value(struct k5buf *buf, k5_json_value val)
632*7f2fe78bSCy Schubert {
633*7f2fe78bSCy Schubert     k5_json_tid type;
634*7f2fe78bSCy Schubert     int ret;
635*7f2fe78bSCy Schubert     size_t i, len;
636*7f2fe78bSCy Schubert     struct obj_ctx ctx;
637*7f2fe78bSCy Schubert 
638*7f2fe78bSCy Schubert     if (val == NULL)
639*7f2fe78bSCy Schubert         return EINVAL;
640*7f2fe78bSCy Schubert 
641*7f2fe78bSCy Schubert     type = k5_json_get_tid(val);
642*7f2fe78bSCy Schubert     switch (type) {
643*7f2fe78bSCy Schubert     case K5_JSON_TID_ARRAY:
644*7f2fe78bSCy Schubert         k5_buf_add(buf, "[");
645*7f2fe78bSCy Schubert         len = k5_json_array_length(val);
646*7f2fe78bSCy Schubert         for (i = 0; i < len; i++) {
647*7f2fe78bSCy Schubert             if (i != 0)
648*7f2fe78bSCy Schubert                 k5_buf_add(buf, ",");
649*7f2fe78bSCy Schubert             ret = encode_value(buf, k5_json_array_get(val, i));
650*7f2fe78bSCy Schubert             if (ret)
651*7f2fe78bSCy Schubert                 return ret;
652*7f2fe78bSCy Schubert         }
653*7f2fe78bSCy Schubert         k5_buf_add(buf, "]");
654*7f2fe78bSCy Schubert         return 0;
655*7f2fe78bSCy Schubert 
656*7f2fe78bSCy Schubert     case K5_JSON_TID_OBJECT:
657*7f2fe78bSCy Schubert         k5_buf_add(buf, "{");
658*7f2fe78bSCy Schubert         ctx.buf = buf;
659*7f2fe78bSCy Schubert         ctx.ret = 0;
660*7f2fe78bSCy Schubert         ctx.first = 1;
661*7f2fe78bSCy Schubert         k5_json_object_iterate(val, encode_obj_entry, &ctx);
662*7f2fe78bSCy Schubert         k5_buf_add(buf, "}");
663*7f2fe78bSCy Schubert         return ctx.ret;
664*7f2fe78bSCy Schubert 
665*7f2fe78bSCy Schubert     case K5_JSON_TID_STRING:
666*7f2fe78bSCy Schubert         encode_string(buf, k5_json_string_utf8(val));
667*7f2fe78bSCy Schubert         return 0;
668*7f2fe78bSCy Schubert 
669*7f2fe78bSCy Schubert     case K5_JSON_TID_NUMBER:
670*7f2fe78bSCy Schubert         k5_buf_add_fmt(buf, "%lld", k5_json_number_value(val));
671*7f2fe78bSCy Schubert         return 0;
672*7f2fe78bSCy Schubert 
673*7f2fe78bSCy Schubert     case K5_JSON_TID_NULL:
674*7f2fe78bSCy Schubert         k5_buf_add(buf, "null");
675*7f2fe78bSCy Schubert         return 0;
676*7f2fe78bSCy Schubert 
677*7f2fe78bSCy Schubert     case K5_JSON_TID_BOOL:
678*7f2fe78bSCy Schubert         k5_buf_add(buf, k5_json_bool_value(val) ? "true" : "false");
679*7f2fe78bSCy Schubert         return 0;
680*7f2fe78bSCy Schubert 
681*7f2fe78bSCy Schubert     default:
682*7f2fe78bSCy Schubert         return EINVAL;
683*7f2fe78bSCy Schubert     }
684*7f2fe78bSCy Schubert }
685*7f2fe78bSCy Schubert 
686*7f2fe78bSCy Schubert int
k5_json_encode(k5_json_value val,char ** json_out)687*7f2fe78bSCy Schubert k5_json_encode(k5_json_value val, char **json_out)
688*7f2fe78bSCy Schubert {
689*7f2fe78bSCy Schubert     struct k5buf buf;
690*7f2fe78bSCy Schubert     int ret;
691*7f2fe78bSCy Schubert 
692*7f2fe78bSCy Schubert     *json_out = NULL;
693*7f2fe78bSCy Schubert     k5_buf_init_dynamic(&buf);
694*7f2fe78bSCy Schubert     ret = encode_value(&buf, val);
695*7f2fe78bSCy Schubert     if (ret) {
696*7f2fe78bSCy Schubert         k5_buf_free(&buf);
697*7f2fe78bSCy Schubert         return ret;
698*7f2fe78bSCy Schubert     }
699*7f2fe78bSCy Schubert     *json_out = k5_buf_cstring(&buf);
700*7f2fe78bSCy Schubert     return (*json_out == NULL) ? ENOMEM : 0;
701*7f2fe78bSCy Schubert }
702*7f2fe78bSCy Schubert 
703*7f2fe78bSCy Schubert /*** JSON decoding ***/
704*7f2fe78bSCy Schubert 
705*7f2fe78bSCy Schubert struct decode_ctx {
706*7f2fe78bSCy Schubert     const unsigned char *p;
707*7f2fe78bSCy Schubert     size_t depth;
708*7f2fe78bSCy Schubert };
709*7f2fe78bSCy Schubert 
710*7f2fe78bSCy Schubert static int parse_value(struct decode_ctx *ctx, k5_json_value *val_out);
711*7f2fe78bSCy Schubert 
712*7f2fe78bSCy Schubert /* Consume whitespace.  Return 0 if there is anything left to parse after the
713*7f2fe78bSCy Schubert  * whitespace, -1 if not. */
714*7f2fe78bSCy Schubert static int
white_spaces(struct decode_ctx * ctx)715*7f2fe78bSCy Schubert white_spaces(struct decode_ctx *ctx)
716*7f2fe78bSCy Schubert {
717*7f2fe78bSCy Schubert     unsigned char c;
718*7f2fe78bSCy Schubert 
719*7f2fe78bSCy Schubert     for (; *ctx->p != '\0'; ctx->p++) {
720*7f2fe78bSCy Schubert         c = *ctx->p;
721*7f2fe78bSCy Schubert         if (c != ' ' && c != '\t' && c != '\r' && c != '\n')
722*7f2fe78bSCy Schubert             return 0;
723*7f2fe78bSCy Schubert     }
724*7f2fe78bSCy Schubert     return -1;
725*7f2fe78bSCy Schubert }
726*7f2fe78bSCy Schubert 
727*7f2fe78bSCy Schubert /* Return true if c is a decimal digit. */
728*7f2fe78bSCy Schubert static inline int
is_digit(unsigned char c)729*7f2fe78bSCy Schubert is_digit(unsigned char c)
730*7f2fe78bSCy Schubert {
731*7f2fe78bSCy Schubert     return ('0' <= c && c <= '9');
732*7f2fe78bSCy Schubert }
733*7f2fe78bSCy Schubert 
734*7f2fe78bSCy Schubert /* Return true if c is a hexadecimal digit (per RFC 5234 HEXDIG). */
735*7f2fe78bSCy Schubert static inline int
is_hex_digit(unsigned char c)736*7f2fe78bSCy Schubert is_hex_digit(unsigned char c)
737*7f2fe78bSCy Schubert {
738*7f2fe78bSCy Schubert     return is_digit(c) || ('A' <= c && c <= 'F');
739*7f2fe78bSCy Schubert }
740*7f2fe78bSCy Schubert 
741*7f2fe78bSCy Schubert /* Return the numeric value of a hex digit; aborts if c is not a hex digit. */
742*7f2fe78bSCy Schubert static inline unsigned int
hexval(unsigned char c)743*7f2fe78bSCy Schubert hexval(unsigned char c)
744*7f2fe78bSCy Schubert {
745*7f2fe78bSCy Schubert     if (is_digit(c))
746*7f2fe78bSCy Schubert         return c - '0';
747*7f2fe78bSCy Schubert     else if ('A' <= c && c <= 'F')
748*7f2fe78bSCy Schubert         return c - 'A' + 10;
749*7f2fe78bSCy Schubert     abort();
750*7f2fe78bSCy Schubert }
751*7f2fe78bSCy Schubert 
752*7f2fe78bSCy Schubert /* Parse a JSON number (which must be an integer in the signed 64-bit range; we
753*7f2fe78bSCy Schubert  * do not allow floating-point numbers). */
754*7f2fe78bSCy Schubert static int
parse_number(struct decode_ctx * ctx,k5_json_number * val_out)755*7f2fe78bSCy Schubert parse_number(struct decode_ctx *ctx, k5_json_number *val_out)
756*7f2fe78bSCy Schubert {
757*7f2fe78bSCy Schubert     const unsigned long long umax = ~0ULL, smax = (1ULL << 63) - 1;
758*7f2fe78bSCy Schubert     unsigned long long number = 0;
759*7f2fe78bSCy Schubert     int neg = 1;
760*7f2fe78bSCy Schubert 
761*7f2fe78bSCy Schubert     *val_out = NULL;
762*7f2fe78bSCy Schubert 
763*7f2fe78bSCy Schubert     if (*ctx->p == '-') {
764*7f2fe78bSCy Schubert         neg = -1;
765*7f2fe78bSCy Schubert         ctx->p++;
766*7f2fe78bSCy Schubert     }
767*7f2fe78bSCy Schubert 
768*7f2fe78bSCy Schubert     if (!is_digit(*ctx->p))
769*7f2fe78bSCy Schubert         return EINVAL;
770*7f2fe78bSCy Schubert 
771*7f2fe78bSCy Schubert     /* Read the number into an unsigned 64-bit container, ensuring that we
772*7f2fe78bSCy Schubert      * don't overflow it. */
773*7f2fe78bSCy Schubert     while (is_digit(*ctx->p)) {
774*7f2fe78bSCy Schubert         if (number + 1 > umax / 10)
775*7f2fe78bSCy Schubert             return EOVERFLOW;
776*7f2fe78bSCy Schubert         number = (number * 10) + (*ctx->p - '0');
777*7f2fe78bSCy Schubert         ctx->p++;
778*7f2fe78bSCy Schubert     }
779*7f2fe78bSCy Schubert 
780*7f2fe78bSCy Schubert     /* Make sure the unsigned 64-bit value fits in the signed 64-bit range. */
781*7f2fe78bSCy Schubert     if (number > smax + 1 || (number > smax && neg == 1))
782*7f2fe78bSCy Schubert         return EOVERFLOW;
783*7f2fe78bSCy Schubert 
784*7f2fe78bSCy Schubert     return k5_json_number_create(number * neg, val_out);
785*7f2fe78bSCy Schubert }
786*7f2fe78bSCy Schubert 
787*7f2fe78bSCy Schubert /* Parse a JSON string (which must not quote Unicode code points above 256). */
788*7f2fe78bSCy Schubert static int
parse_string(struct decode_ctx * ctx,char ** str_out)789*7f2fe78bSCy Schubert parse_string(struct decode_ctx *ctx, char **str_out)
790*7f2fe78bSCy Schubert {
791*7f2fe78bSCy Schubert     const unsigned char *p, *start, *end = NULL;
792*7f2fe78bSCy Schubert     const char *q;
793*7f2fe78bSCy Schubert     char *buf, *pos;
794*7f2fe78bSCy Schubert     unsigned int code;
795*7f2fe78bSCy Schubert 
796*7f2fe78bSCy Schubert     *str_out = NULL;
797*7f2fe78bSCy Schubert 
798*7f2fe78bSCy Schubert     /* Find the start and end of the string. */
799*7f2fe78bSCy Schubert     if (*ctx->p != '"')
800*7f2fe78bSCy Schubert         return EINVAL;
801*7f2fe78bSCy Schubert     start = ++ctx->p;
802*7f2fe78bSCy Schubert     for (; *ctx->p != '\0'; ctx->p++) {
803*7f2fe78bSCy Schubert         if (*ctx->p == '\\') {
804*7f2fe78bSCy Schubert             ctx->p++;
805*7f2fe78bSCy Schubert             if (*ctx->p == '\0')
806*7f2fe78bSCy Schubert                 return EINVAL;
807*7f2fe78bSCy Schubert         } else if (*ctx->p == '"') {
808*7f2fe78bSCy Schubert             end = ctx->p++;
809*7f2fe78bSCy Schubert             break;
810*7f2fe78bSCy Schubert         }
811*7f2fe78bSCy Schubert     }
812*7f2fe78bSCy Schubert     if (end == NULL)
813*7f2fe78bSCy Schubert         return EINVAL;
814*7f2fe78bSCy Schubert 
815*7f2fe78bSCy Schubert     pos = buf = malloc(end - start + 1);
816*7f2fe78bSCy Schubert     if (buf == NULL)
817*7f2fe78bSCy Schubert         return ENOMEM;
818*7f2fe78bSCy Schubert     for (p = start; p < end;) {
819*7f2fe78bSCy Schubert         if (*p == '\\') {
820*7f2fe78bSCy Schubert             p++;
821*7f2fe78bSCy Schubert             if (*p == 'u' && is_hex_digit(p[1]) && is_hex_digit(p[2]) &&
822*7f2fe78bSCy Schubert                 is_hex_digit(p[3]) && is_hex_digit(p[4])) {
823*7f2fe78bSCy Schubert                 code = (hexval(p[1]) << 12) | (hexval(p[2]) << 8) |
824*7f2fe78bSCy Schubert                     (hexval(p[3]) << 4) | hexval(p[4]);
825*7f2fe78bSCy Schubert                 if (code <= 0xff) {
826*7f2fe78bSCy Schubert                     *pos++ = code;
827*7f2fe78bSCy Schubert                 } else {
828*7f2fe78bSCy Schubert                     /* Code points above 0xff don't need to be quoted, so we
829*7f2fe78bSCy Schubert                      * don't implement translating those into UTF-8. */
830*7f2fe78bSCy Schubert                     free(buf);
831*7f2fe78bSCy Schubert                     return EINVAL;
832*7f2fe78bSCy Schubert                 }
833*7f2fe78bSCy Schubert                 p += 5;
834*7f2fe78bSCy Schubert             } else {
835*7f2fe78bSCy Schubert                 q = strchr(quotemap_json, *p);
836*7f2fe78bSCy Schubert                 if (q != NULL) {
837*7f2fe78bSCy Schubert                     *pos++ = quotemap_c[q - quotemap_json];
838*7f2fe78bSCy Schubert                 } else {
839*7f2fe78bSCy Schubert                     free(buf);
840*7f2fe78bSCy Schubert                     return EINVAL;
841*7f2fe78bSCy Schubert                 }
842*7f2fe78bSCy Schubert                 p++;
843*7f2fe78bSCy Schubert             }
844*7f2fe78bSCy Schubert         } else {
845*7f2fe78bSCy Schubert             *pos++ = *p++;
846*7f2fe78bSCy Schubert         }
847*7f2fe78bSCy Schubert     }
848*7f2fe78bSCy Schubert     *pos = '\0';
849*7f2fe78bSCy Schubert     *str_out = buf;
850*7f2fe78bSCy Schubert     return 0;
851*7f2fe78bSCy Schubert }
852*7f2fe78bSCy Schubert 
853*7f2fe78bSCy Schubert /* Parse an object association and place it into obj. */
854*7f2fe78bSCy Schubert static int
parse_object_association(k5_json_object obj,struct decode_ctx * ctx)855*7f2fe78bSCy Schubert parse_object_association(k5_json_object obj, struct decode_ctx *ctx)
856*7f2fe78bSCy Schubert {
857*7f2fe78bSCy Schubert     char *key = NULL;
858*7f2fe78bSCy Schubert     k5_json_value val;
859*7f2fe78bSCy Schubert     int ret;
860*7f2fe78bSCy Schubert 
861*7f2fe78bSCy Schubert     /* Parse the key and value. */
862*7f2fe78bSCy Schubert     ret = parse_string(ctx, &key);
863*7f2fe78bSCy Schubert     if (ret)
864*7f2fe78bSCy Schubert         return ret;
865*7f2fe78bSCy Schubert     if (white_spaces(ctx))
866*7f2fe78bSCy Schubert         goto invalid;
867*7f2fe78bSCy Schubert     if (*ctx->p != ':')
868*7f2fe78bSCy Schubert         goto invalid;
869*7f2fe78bSCy Schubert     ctx->p++;
870*7f2fe78bSCy Schubert     if (white_spaces(ctx))
871*7f2fe78bSCy Schubert         goto invalid;
872*7f2fe78bSCy Schubert     ret = parse_value(ctx, &val);
873*7f2fe78bSCy Schubert     if (ret) {
874*7f2fe78bSCy Schubert         free(key);
875*7f2fe78bSCy Schubert         return ret;
876*7f2fe78bSCy Schubert     }
877*7f2fe78bSCy Schubert 
878*7f2fe78bSCy Schubert     /* Add the key and value to obj. */
879*7f2fe78bSCy Schubert     ret = k5_json_object_set(obj, key, val);
880*7f2fe78bSCy Schubert     free(key);
881*7f2fe78bSCy Schubert     k5_json_release(val);
882*7f2fe78bSCy Schubert     return ret;
883*7f2fe78bSCy Schubert 
884*7f2fe78bSCy Schubert invalid:
885*7f2fe78bSCy Schubert     free(key);
886*7f2fe78bSCy Schubert     return EINVAL;
887*7f2fe78bSCy Schubert }
888*7f2fe78bSCy Schubert 
889*7f2fe78bSCy Schubert /* Parse a JSON object. */
890*7f2fe78bSCy Schubert static int
parse_object(struct decode_ctx * ctx,k5_json_object * val_out)891*7f2fe78bSCy Schubert parse_object(struct decode_ctx *ctx, k5_json_object *val_out)
892*7f2fe78bSCy Schubert {
893*7f2fe78bSCy Schubert     k5_json_object obj = NULL;
894*7f2fe78bSCy Schubert     int ret;
895*7f2fe78bSCy Schubert 
896*7f2fe78bSCy Schubert     *val_out = NULL;
897*7f2fe78bSCy Schubert 
898*7f2fe78bSCy Schubert     /* Parse past the opening brace. */
899*7f2fe78bSCy Schubert     if (*ctx->p != '{')
900*7f2fe78bSCy Schubert         return EINVAL;
901*7f2fe78bSCy Schubert     ctx->p++;
902*7f2fe78bSCy Schubert     if (white_spaces(ctx))
903*7f2fe78bSCy Schubert         return EINVAL;
904*7f2fe78bSCy Schubert 
905*7f2fe78bSCy Schubert     ret = k5_json_object_create(&obj);
906*7f2fe78bSCy Schubert     if (ret)
907*7f2fe78bSCy Schubert         return ret;
908*7f2fe78bSCy Schubert 
909*7f2fe78bSCy Schubert     /* Pairs associations until we reach the terminating brace. */
910*7f2fe78bSCy Schubert     if (*ctx->p != '}') {
911*7f2fe78bSCy Schubert         while (1) {
912*7f2fe78bSCy Schubert             ret = parse_object_association(obj, ctx);
913*7f2fe78bSCy Schubert             if (ret) {
914*7f2fe78bSCy Schubert                 k5_json_release(obj);
915*7f2fe78bSCy Schubert                 return ret;
916*7f2fe78bSCy Schubert             }
917*7f2fe78bSCy Schubert             if (white_spaces(ctx))
918*7f2fe78bSCy Schubert                 goto invalid;
919*7f2fe78bSCy Schubert             if (*ctx->p == '}')
920*7f2fe78bSCy Schubert                 break;
921*7f2fe78bSCy Schubert             if (*ctx->p != ',')
922*7f2fe78bSCy Schubert                 goto invalid;
923*7f2fe78bSCy Schubert             ctx->p++;
924*7f2fe78bSCy Schubert             if (white_spaces(ctx))
925*7f2fe78bSCy Schubert                 goto invalid;
926*7f2fe78bSCy Schubert         }
927*7f2fe78bSCy Schubert     }
928*7f2fe78bSCy Schubert     ctx->p++;
929*7f2fe78bSCy Schubert     *val_out = obj;
930*7f2fe78bSCy Schubert     return 0;
931*7f2fe78bSCy Schubert 
932*7f2fe78bSCy Schubert invalid:
933*7f2fe78bSCy Schubert     k5_json_release(obj);
934*7f2fe78bSCy Schubert     return EINVAL;
935*7f2fe78bSCy Schubert }
936*7f2fe78bSCy Schubert 
937*7f2fe78bSCy Schubert /* Parse an value and place it into array. */
938*7f2fe78bSCy Schubert static int
parse_array_item(k5_json_array array,struct decode_ctx * ctx)939*7f2fe78bSCy Schubert parse_array_item(k5_json_array array, struct decode_ctx *ctx)
940*7f2fe78bSCy Schubert {
941*7f2fe78bSCy Schubert     k5_json_value val;
942*7f2fe78bSCy Schubert     int ret;
943*7f2fe78bSCy Schubert 
944*7f2fe78bSCy Schubert     ret = parse_value(ctx, &val);
945*7f2fe78bSCy Schubert     if (ret)
946*7f2fe78bSCy Schubert         return ret;
947*7f2fe78bSCy Schubert     ret = k5_json_array_add(array, val);
948*7f2fe78bSCy Schubert     k5_json_release(val);
949*7f2fe78bSCy Schubert     return ret;
950*7f2fe78bSCy Schubert }
951*7f2fe78bSCy Schubert 
952*7f2fe78bSCy Schubert /* Parse a JSON array. */
953*7f2fe78bSCy Schubert static int
parse_array(struct decode_ctx * ctx,k5_json_array * val_out)954*7f2fe78bSCy Schubert parse_array(struct decode_ctx *ctx, k5_json_array *val_out)
955*7f2fe78bSCy Schubert {
956*7f2fe78bSCy Schubert     k5_json_array array = NULL;
957*7f2fe78bSCy Schubert     int ret;
958*7f2fe78bSCy Schubert 
959*7f2fe78bSCy Schubert     *val_out = NULL;
960*7f2fe78bSCy Schubert 
961*7f2fe78bSCy Schubert     /* Parse past the opening bracket. */
962*7f2fe78bSCy Schubert     if (*ctx->p != '[')
963*7f2fe78bSCy Schubert         return EINVAL;
964*7f2fe78bSCy Schubert     ctx->p++;
965*7f2fe78bSCy Schubert     if (white_spaces(ctx))
966*7f2fe78bSCy Schubert         return EINVAL;
967*7f2fe78bSCy Schubert 
968*7f2fe78bSCy Schubert     ret = k5_json_array_create(&array);
969*7f2fe78bSCy Schubert     if (ret)
970*7f2fe78bSCy Schubert         return ret;
971*7f2fe78bSCy Schubert 
972*7f2fe78bSCy Schubert     /* Pairs values until we reach the terminating bracket. */
973*7f2fe78bSCy Schubert     if (*ctx->p != ']') {
974*7f2fe78bSCy Schubert         while (1) {
975*7f2fe78bSCy Schubert             ret = parse_array_item(array, ctx);
976*7f2fe78bSCy Schubert             if (ret) {
977*7f2fe78bSCy Schubert                 k5_json_release(array);
978*7f2fe78bSCy Schubert                 return ret;
979*7f2fe78bSCy Schubert             }
980*7f2fe78bSCy Schubert             if (white_spaces(ctx))
981*7f2fe78bSCy Schubert                 goto invalid;
982*7f2fe78bSCy Schubert             if (*ctx->p == ']')
983*7f2fe78bSCy Schubert                 break;
984*7f2fe78bSCy Schubert             if (*ctx->p != ',')
985*7f2fe78bSCy Schubert                 goto invalid;
986*7f2fe78bSCy Schubert             ctx->p++;
987*7f2fe78bSCy Schubert             if (white_spaces(ctx))
988*7f2fe78bSCy Schubert                 goto invalid;
989*7f2fe78bSCy Schubert         }
990*7f2fe78bSCy Schubert     }
991*7f2fe78bSCy Schubert     ctx->p++;
992*7f2fe78bSCy Schubert     *val_out = array;
993*7f2fe78bSCy Schubert     return 0;
994*7f2fe78bSCy Schubert 
995*7f2fe78bSCy Schubert invalid:
996*7f2fe78bSCy Schubert     k5_json_release(array);
997*7f2fe78bSCy Schubert     return EINVAL;
998*7f2fe78bSCy Schubert }
999*7f2fe78bSCy Schubert 
1000*7f2fe78bSCy Schubert /* Parse a JSON value of any type. */
1001*7f2fe78bSCy Schubert static int
parse_value(struct decode_ctx * ctx,k5_json_value * val_out)1002*7f2fe78bSCy Schubert parse_value(struct decode_ctx *ctx, k5_json_value *val_out)
1003*7f2fe78bSCy Schubert {
1004*7f2fe78bSCy Schubert     k5_json_null null;
1005*7f2fe78bSCy Schubert     k5_json_bool bval;
1006*7f2fe78bSCy Schubert     k5_json_number num;
1007*7f2fe78bSCy Schubert     k5_json_string str;
1008*7f2fe78bSCy Schubert     k5_json_object obj;
1009*7f2fe78bSCy Schubert     k5_json_array array;
1010*7f2fe78bSCy Schubert     char *cstring;
1011*7f2fe78bSCy Schubert     int ret;
1012*7f2fe78bSCy Schubert 
1013*7f2fe78bSCy Schubert     *val_out = NULL;
1014*7f2fe78bSCy Schubert 
1015*7f2fe78bSCy Schubert     if (white_spaces(ctx))
1016*7f2fe78bSCy Schubert         return EINVAL;
1017*7f2fe78bSCy Schubert 
1018*7f2fe78bSCy Schubert     if (*ctx->p == '"') {
1019*7f2fe78bSCy Schubert         ret = parse_string(ctx, &cstring);
1020*7f2fe78bSCy Schubert         if (ret)
1021*7f2fe78bSCy Schubert             return ret;
1022*7f2fe78bSCy Schubert         ret = k5_json_string_create(cstring, &str);
1023*7f2fe78bSCy Schubert         free(cstring);
1024*7f2fe78bSCy Schubert         if (ret)
1025*7f2fe78bSCy Schubert             return ret;
1026*7f2fe78bSCy Schubert         *val_out = str;
1027*7f2fe78bSCy Schubert     } else if (*ctx->p == '{') {
1028*7f2fe78bSCy Schubert         if (ctx->depth-- == 1)
1029*7f2fe78bSCy Schubert             return EINVAL;
1030*7f2fe78bSCy Schubert         ret = parse_object(ctx, &obj);
1031*7f2fe78bSCy Schubert         if (ret)
1032*7f2fe78bSCy Schubert             return ret;
1033*7f2fe78bSCy Schubert         ctx->depth++;
1034*7f2fe78bSCy Schubert         *val_out = obj;
1035*7f2fe78bSCy Schubert     } else if (*ctx->p == '[') {
1036*7f2fe78bSCy Schubert         if (ctx->depth-- == 1)
1037*7f2fe78bSCy Schubert             return EINVAL;
1038*7f2fe78bSCy Schubert         ret = parse_array(ctx, &array);
1039*7f2fe78bSCy Schubert         ctx->depth++;
1040*7f2fe78bSCy Schubert         *val_out = array;
1041*7f2fe78bSCy Schubert     } else if (is_digit(*ctx->p) || *ctx->p == '-') {
1042*7f2fe78bSCy Schubert         ret = parse_number(ctx, &num);
1043*7f2fe78bSCy Schubert         if (ret)
1044*7f2fe78bSCy Schubert             return ret;
1045*7f2fe78bSCy Schubert         *val_out = num;
1046*7f2fe78bSCy Schubert     } else if (strncmp((char *)ctx->p, "null", 4) == 0) {
1047*7f2fe78bSCy Schubert         ctx->p += 4;
1048*7f2fe78bSCy Schubert         ret = k5_json_null_create(&null);
1049*7f2fe78bSCy Schubert         if (ret)
1050*7f2fe78bSCy Schubert             return ret;
1051*7f2fe78bSCy Schubert         *val_out = null;
1052*7f2fe78bSCy Schubert     } else if (strncmp((char *)ctx->p, "true", 4) == 0) {
1053*7f2fe78bSCy Schubert         ctx->p += 4;
1054*7f2fe78bSCy Schubert         ret = k5_json_bool_create(1, &bval);
1055*7f2fe78bSCy Schubert         if (ret)
1056*7f2fe78bSCy Schubert             return ret;
1057*7f2fe78bSCy Schubert         *val_out = bval;
1058*7f2fe78bSCy Schubert     } else if (strncmp((char *)ctx->p, "false", 5) == 0) {
1059*7f2fe78bSCy Schubert         ctx->p += 5;
1060*7f2fe78bSCy Schubert         ret = k5_json_bool_create(0, &bval);
1061*7f2fe78bSCy Schubert         if (ret)
1062*7f2fe78bSCy Schubert             return ret;
1063*7f2fe78bSCy Schubert         *val_out = bval;
1064*7f2fe78bSCy Schubert     } else {
1065*7f2fe78bSCy Schubert         return EINVAL;
1066*7f2fe78bSCy Schubert     }
1067*7f2fe78bSCy Schubert 
1068*7f2fe78bSCy Schubert     return 0;
1069*7f2fe78bSCy Schubert }
1070*7f2fe78bSCy Schubert 
1071*7f2fe78bSCy Schubert int
k5_json_decode(const char * string,k5_json_value * val_out)1072*7f2fe78bSCy Schubert k5_json_decode(const char *string, k5_json_value *val_out)
1073*7f2fe78bSCy Schubert {
1074*7f2fe78bSCy Schubert     struct decode_ctx ctx;
1075*7f2fe78bSCy Schubert     k5_json_value val;
1076*7f2fe78bSCy Schubert     int ret;
1077*7f2fe78bSCy Schubert 
1078*7f2fe78bSCy Schubert     *val_out = NULL;
1079*7f2fe78bSCy Schubert     ctx.p = (unsigned char *)string;
1080*7f2fe78bSCy Schubert     ctx.depth = MAX_DECODE_DEPTH;
1081*7f2fe78bSCy Schubert     ret = parse_value(&ctx, &val);
1082*7f2fe78bSCy Schubert     if (ret)
1083*7f2fe78bSCy Schubert         return ret;
1084*7f2fe78bSCy Schubert     if (white_spaces(&ctx) == 0) {
1085*7f2fe78bSCy Schubert         k5_json_release(val);
1086*7f2fe78bSCy Schubert         return EINVAL;
1087*7f2fe78bSCy Schubert     }
1088*7f2fe78bSCy Schubert     *val_out = val;
1089*7f2fe78bSCy Schubert     return 0;
1090*7f2fe78bSCy Schubert }
1091