Coverage Report

Created: 2026-02-26 06:49

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