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