Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/krb5/src/util/support/json.c
34889 views
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
#define MAX_DECODE_DEPTH 64
79
#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
#define PTR2BASE(ptr) (((struct value_base *)ptr) - 1)
95
#define BASE2PTR(ptr) ((void *)(((struct value_base *)ptr) + 1))
96
97
k5_json_value
98
k5_json_retain(k5_json_value val)
99
{
100
struct value_base *p;
101
102
if (val == NULL)
103
return val;
104
p = PTR2BASE(val);
105
assert(p->ref_cnt != 0);
106
p->ref_cnt++;
107
return val;
108
}
109
110
void
111
k5_json_release(k5_json_value val)
112
{
113
struct value_base *p;
114
115
if (val == NULL)
116
return;
117
p = PTR2BASE(val);
118
assert(p->ref_cnt != 0);
119
p->ref_cnt--;
120
if (p->ref_cnt == 0) {
121
if (p->isa->dealloc != NULL)
122
p->isa->dealloc(val);
123
free(p);
124
}
125
}
126
127
/* Get the type description of a k5_json_value. */
128
static json_type
129
get_isa(k5_json_value val)
130
{
131
struct value_base *p = PTR2BASE(val);
132
133
return p->isa;
134
}
135
136
k5_json_tid
137
k5_json_get_tid(k5_json_value val)
138
{
139
json_type isa = get_isa(val);
140
141
return isa->tid;
142
}
143
144
static k5_json_value
145
alloc_value(json_type type, size_t size)
146
{
147
struct value_base *p = calloc(1, size + sizeof(*p));
148
149
if (p == NULL)
150
return NULL;
151
p->isa = type;
152
p->ref_cnt = 1;
153
154
return BASE2PTR(p);
155
}
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
{
164
*val_out = alloc_value(&null_type, 0);
165
return (*val_out == NULL) ? ENOMEM : 0;
166
}
167
168
int
169
k5_json_null_create_val(k5_json_value *val_out)
170
{
171
*val_out = alloc_value(&null_type, 0);
172
return (*val_out == NULL) ? ENOMEM : 0;
173
}
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
{
182
k5_json_bool b;
183
184
*val_out = NULL;
185
b = alloc_value(&bool_type, 1);
186
if (b == NULL)
187
return ENOMEM;
188
*(unsigned char *)b = !!truth;
189
*val_out = b;
190
return 0;
191
}
192
193
int
194
k5_json_bool_value(k5_json_bool bval)
195
{
196
return *(unsigned char *)bval;
197
}
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
{
210
k5_json_array array = ptr;
211
size_t i;
212
213
for (i = 0; i < array->len; i++)
214
k5_json_release(array->values[i]);
215
free(array->values);
216
}
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
{
225
*val_out = alloc_value(&array_type, sizeof(struct k5_json_array_st));
226
return (*val_out == NULL) ? ENOMEM : 0;
227
}
228
229
int
230
k5_json_array_add(k5_json_array array, k5_json_value val)
231
{
232
k5_json_value *ptr;
233
size_t new_alloc;
234
235
if (array->len >= array->allocated) {
236
/* Increase the number of slots by 50% (MIN_ALLOC_SLOT minimum). */
237
new_alloc = array->len + 1 + (array->len >> 1);
238
if (new_alloc < MIN_ALLOC_SLOT)
239
new_alloc = MIN_ALLOC_SLOT;
240
ptr = realloc(array->values, new_alloc * sizeof(*array->values));
241
if (ptr == NULL)
242
return ENOMEM;
243
array->values = ptr;
244
array->allocated = new_alloc;
245
}
246
array->values[array->len++] = k5_json_retain(val);
247
return 0;
248
}
249
250
size_t
251
k5_json_array_length(k5_json_array array)
252
{
253
return array->len;
254
}
255
256
k5_json_value
257
k5_json_array_get(k5_json_array array, size_t idx)
258
{
259
if (idx >= array->len)
260
abort();
261
return array->values[idx];
262
}
263
264
void
265
k5_json_array_set(k5_json_array array, size_t idx, k5_json_value val)
266
{
267
if (idx >= array->len)
268
abort();
269
k5_json_release(array->values[idx]);
270
array->values[idx] = k5_json_retain(val);
271
}
272
273
int
274
k5_json_array_fmt(k5_json_array *array_out, const char *template, ...)
275
{
276
const char *p;
277
va_list ap;
278
const char *cstring;
279
unsigned char *data;
280
size_t len;
281
long long nval;
282
k5_json_array array;
283
k5_json_value val;
284
k5_json_number num;
285
k5_json_string str;
286
k5_json_bool b;
287
k5_json_null null;
288
int truth, ret;
289
290
*array_out = NULL;
291
if (k5_json_array_create(&array))
292
return ENOMEM;
293
va_start(ap, template);
294
for (p = template; *p != '\0'; p++) {
295
switch (*p) {
296
case 'v':
297
val = k5_json_retain(va_arg(ap, k5_json_value));
298
break;
299
case 'n':
300
if (k5_json_null_create(&null))
301
goto err;
302
val = null;
303
break;
304
case 'b':
305
truth = va_arg(ap, int);
306
if (k5_json_bool_create(truth, &b))
307
goto err;
308
val = b;
309
break;
310
case 'i':
311
nval = va_arg(ap, int);
312
if (k5_json_number_create(nval, &num))
313
goto err;
314
val = num;
315
break;
316
case 'L':
317
nval = va_arg(ap, long long);
318
if (k5_json_number_create(nval, &num))
319
goto err;
320
val = num;
321
break;
322
case 's':
323
cstring = va_arg(ap, const char *);
324
if (cstring == NULL) {
325
if (k5_json_null_create(&null))
326
goto err;
327
val = null;
328
} else {
329
if (k5_json_string_create(cstring, &str))
330
goto err;
331
val = str;
332
}
333
break;
334
case 'B':
335
data = va_arg(ap, unsigned char *);
336
len = va_arg(ap, size_t);
337
if (k5_json_string_create_base64(data, len, &str))
338
goto err;
339
val = str;
340
break;
341
default:
342
goto err;
343
}
344
ret = k5_json_array_add(array, val);
345
k5_json_release(val);
346
if (ret)
347
goto err;
348
}
349
va_end(ap);
350
*array_out = array;
351
return 0;
352
353
err:
354
va_end(ap);
355
k5_json_release(array);
356
return ENOMEM;
357
}
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
{
375
k5_json_object obj = ptr;
376
size_t i;
377
378
for (i = 0; i < obj->len; i++) {
379
free(obj->entries[i].key);
380
k5_json_release(obj->entries[i].value);
381
}
382
free(obj->entries);
383
}
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
{
392
*val_out = alloc_value(&object_type, sizeof(struct k5_json_object_st));
393
return (*val_out == NULL) ? ENOMEM : 0;
394
}
395
396
size_t
397
k5_json_object_count(k5_json_object obj)
398
{
399
return obj->len;
400
}
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
{
406
size_t i;
407
408
for (i = 0; i < obj->len; i++) {
409
if (strcmp(key, obj->entries[i].key) == 0)
410
return &obj->entries[i];
411
}
412
return NULL;
413
}
414
415
k5_json_value
416
k5_json_object_get(k5_json_object obj, const char *key)
417
{
418
struct entry *ent;
419
420
ent = object_search(obj, key);
421
if (ent == NULL)
422
return NULL;
423
return ent->value;
424
}
425
426
int
427
k5_json_object_set(k5_json_object obj, const char *key, k5_json_value val)
428
{
429
struct entry *ent, *ptr;
430
size_t new_alloc, i;
431
432
ent = object_search(obj, key);
433
if (ent != NULL) {
434
k5_json_release(ent->value);
435
if (val == NULL) {
436
/* Remove this key. */
437
free(ent->key);
438
for (i = ent - obj->entries; i < obj->len - 1; i++)
439
obj->entries[i] = obj->entries[i + 1];
440
obj->len--;
441
} else {
442
/* Overwrite this key's value with the new one. */
443
ent->value = k5_json_retain(val);
444
}
445
return 0;
446
}
447
448
/* If didn't find a key the caller asked to remove, do nothing. */
449
if (val == NULL)
450
return 0;
451
452
if (obj->len >= obj->allocated) {
453
/* Increase the number of slots by 50% (MIN_ALLOC_SLOT minimum). */
454
new_alloc = obj->len + 1 + (obj->len >> 1);
455
if (new_alloc < MIN_ALLOC_SLOT)
456
new_alloc = MIN_ALLOC_SLOT;
457
ptr = realloc(obj->entries, new_alloc * sizeof(*obj->entries));
458
if (ptr == NULL)
459
return ENOMEM;
460
obj->entries = ptr;
461
obj->allocated = new_alloc;
462
}
463
obj->entries[obj->len].key = strdup(key);
464
if (obj->entries[obj->len].key == NULL)
465
return ENOMEM;
466
obj->entries[obj->len].value = k5_json_retain(val);
467
obj->len++;
468
return 0;
469
}
470
471
void
472
k5_json_object_iterate(k5_json_object obj, k5_json_object_iterator_fn func,
473
void *arg)
474
{
475
size_t i;
476
477
for (i = 0; i < obj->len; i++)
478
func(arg, obj->entries[i].key, obj->entries[i].value);
479
}
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
{
490
return k5_json_string_create_len(cstring, strlen(cstring), val_out);
491
}
492
493
int
494
k5_json_string_create_len(const void *data, size_t len,
495
k5_json_string *val_out)
496
{
497
char *s;
498
499
*val_out = NULL;
500
s = alloc_value(&string_type, len + 1);
501
if (s == NULL)
502
return ENOMEM;
503
if (len > 0)
504
memcpy(s, data, len);
505
s[len] = '\0';
506
*val_out = (k5_json_string)s;
507
return 0;
508
}
509
510
int
511
k5_json_string_create_base64(const void *data, size_t len,
512
k5_json_string *val_out)
513
{
514
char *base64;
515
int ret;
516
517
*val_out = NULL;
518
base64 = k5_base64_encode(data, len);
519
if (base64 == NULL)
520
return ENOMEM;
521
ret = k5_json_string_create(base64, val_out);
522
free(base64);
523
return ret;
524
}
525
526
const char *
527
k5_json_string_utf8(k5_json_string string)
528
{
529
return (const char *)string;
530
}
531
532
int
533
k5_json_string_unbase64(k5_json_string string, unsigned char **data_out,
534
size_t *len_out)
535
{
536
unsigned char *data;
537
size_t len;
538
539
*data_out = NULL;
540
*len_out = 0;
541
data = k5_base64_decode((const char *)string, &len);
542
if (data == NULL)
543
return (len == 0) ? ENOMEM : EINVAL;
544
*data_out = data;
545
*len_out = len;
546
return 0;
547
}
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
{
558
k5_json_number n;
559
560
*val_out = NULL;
561
n = alloc_value(&number_type, sizeof(long long));
562
if (n == NULL)
563
return ENOMEM;
564
*((long long *)n) = number;
565
*val_out = n;
566
return 0;
567
}
568
569
long long
570
k5_json_number_value(k5_json_number number)
571
{
572
return *(long long *)number;
573
}
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
{
587
size_t n;
588
const char *p;
589
590
k5_buf_add(buf, "\"");
591
while (*str != '\0') {
592
n = strcspn(str, needs_quote);
593
k5_buf_add_len(buf, str, n);
594
str += n;
595
if (*str == '\0')
596
break;
597
k5_buf_add(buf, "\\");
598
p = strchr(quotemap_c, *str);
599
if (p != NULL)
600
k5_buf_add_len(buf, quotemap_json + (p - quotemap_c), 1);
601
else
602
k5_buf_add_fmt(buf, "u00%02X", (unsigned int)*str);
603
str++;
604
}
605
k5_buf_add(buf, "\"");
606
}
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
{
617
struct obj_ctx *j = ctx;
618
619
if (j->ret)
620
return;
621
if (j->first)
622
j->first = 0;
623
else
624
k5_buf_add(j->buf, ",");
625
encode_string(j->buf, key);
626
k5_buf_add(j->buf, ":");
627
j->ret = encode_value(j->buf, value);
628
}
629
630
static int
631
encode_value(struct k5buf *buf, k5_json_value val)
632
{
633
k5_json_tid type;
634
int ret;
635
size_t i, len;
636
struct obj_ctx ctx;
637
638
if (val == NULL)
639
return EINVAL;
640
641
type = k5_json_get_tid(val);
642
switch (type) {
643
case K5_JSON_TID_ARRAY:
644
k5_buf_add(buf, "[");
645
len = k5_json_array_length(val);
646
for (i = 0; i < len; i++) {
647
if (i != 0)
648
k5_buf_add(buf, ",");
649
ret = encode_value(buf, k5_json_array_get(val, i));
650
if (ret)
651
return ret;
652
}
653
k5_buf_add(buf, "]");
654
return 0;
655
656
case K5_JSON_TID_OBJECT:
657
k5_buf_add(buf, "{");
658
ctx.buf = buf;
659
ctx.ret = 0;
660
ctx.first = 1;
661
k5_json_object_iterate(val, encode_obj_entry, &ctx);
662
k5_buf_add(buf, "}");
663
return ctx.ret;
664
665
case K5_JSON_TID_STRING:
666
encode_string(buf, k5_json_string_utf8(val));
667
return 0;
668
669
case K5_JSON_TID_NUMBER:
670
k5_buf_add_fmt(buf, "%lld", k5_json_number_value(val));
671
return 0;
672
673
case K5_JSON_TID_NULL:
674
k5_buf_add(buf, "null");
675
return 0;
676
677
case K5_JSON_TID_BOOL:
678
k5_buf_add(buf, k5_json_bool_value(val) ? "true" : "false");
679
return 0;
680
681
default:
682
return EINVAL;
683
}
684
}
685
686
int
687
k5_json_encode(k5_json_value val, char **json_out)
688
{
689
struct k5buf buf;
690
int ret;
691
692
*json_out = NULL;
693
k5_buf_init_dynamic(&buf);
694
ret = encode_value(&buf, val);
695
if (ret) {
696
k5_buf_free(&buf);
697
return ret;
698
}
699
*json_out = k5_buf_cstring(&buf);
700
return (*json_out == NULL) ? ENOMEM : 0;
701
}
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
{
717
unsigned char c;
718
719
for (; *ctx->p != '\0'; ctx->p++) {
720
c = *ctx->p;
721
if (c != ' ' && c != '\t' && c != '\r' && c != '\n')
722
return 0;
723
}
724
return -1;
725
}
726
727
/* Return true if c is a decimal digit. */
728
static inline int
729
is_digit(unsigned char c)
730
{
731
return ('0' <= c && c <= '9');
732
}
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
{
738
return is_digit(c) || ('A' <= c && c <= 'F');
739
}
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
{
745
if (is_digit(c))
746
return c - '0';
747
else if ('A' <= c && c <= 'F')
748
return c - 'A' + 10;
749
abort();
750
}
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
{
757
const unsigned long long umax = ~0ULL, smax = (1ULL << 63) - 1;
758
unsigned long long number = 0;
759
int neg = 1;
760
761
*val_out = NULL;
762
763
if (*ctx->p == '-') {
764
neg = -1;
765
ctx->p++;
766
}
767
768
if (!is_digit(*ctx->p))
769
return EINVAL;
770
771
/* Read the number into an unsigned 64-bit container, ensuring that we
772
* don't overflow it. */
773
while (is_digit(*ctx->p)) {
774
if (number + 1 > umax / 10)
775
return EOVERFLOW;
776
number = (number * 10) + (*ctx->p - '0');
777
ctx->p++;
778
}
779
780
/* Make sure the unsigned 64-bit value fits in the signed 64-bit range. */
781
if (number > smax + 1 || (number > smax && neg == 1))
782
return EOVERFLOW;
783
784
return k5_json_number_create(number * neg, val_out);
785
}
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
{
791
const unsigned char *p, *start, *end = NULL;
792
const char *q;
793
char *buf, *pos;
794
unsigned int code;
795
796
*str_out = NULL;
797
798
/* Find the start and end of the string. */
799
if (*ctx->p != '"')
800
return EINVAL;
801
start = ++ctx->p;
802
for (; *ctx->p != '\0'; ctx->p++) {
803
if (*ctx->p == '\\') {
804
ctx->p++;
805
if (*ctx->p == '\0')
806
return EINVAL;
807
} else if (*ctx->p == '"') {
808
end = ctx->p++;
809
break;
810
}
811
}
812
if (end == NULL)
813
return EINVAL;
814
815
pos = buf = malloc(end - start + 1);
816
if (buf == NULL)
817
return ENOMEM;
818
for (p = start; p < end;) {
819
if (*p == '\\') {
820
p++;
821
if (*p == 'u' && is_hex_digit(p[1]) && is_hex_digit(p[2]) &&
822
is_hex_digit(p[3]) && is_hex_digit(p[4])) {
823
code = (hexval(p[1]) << 12) | (hexval(p[2]) << 8) |
824
(hexval(p[3]) << 4) | hexval(p[4]);
825
if (code <= 0xff) {
826
*pos++ = code;
827
} else {
828
/* Code points above 0xff don't need to be quoted, so we
829
* don't implement translating those into UTF-8. */
830
free(buf);
831
return EINVAL;
832
}
833
p += 5;
834
} else {
835
q = strchr(quotemap_json, *p);
836
if (q != NULL) {
837
*pos++ = quotemap_c[q - quotemap_json];
838
} else {
839
free(buf);
840
return EINVAL;
841
}
842
p++;
843
}
844
} else {
845
*pos++ = *p++;
846
}
847
}
848
*pos = '\0';
849
*str_out = buf;
850
return 0;
851
}
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
{
857
char *key = NULL;
858
k5_json_value val;
859
int ret;
860
861
/* Parse the key and value. */
862
ret = parse_string(ctx, &key);
863
if (ret)
864
return ret;
865
if (white_spaces(ctx))
866
goto invalid;
867
if (*ctx->p != ':')
868
goto invalid;
869
ctx->p++;
870
if (white_spaces(ctx))
871
goto invalid;
872
ret = parse_value(ctx, &val);
873
if (ret) {
874
free(key);
875
return ret;
876
}
877
878
/* Add the key and value to obj. */
879
ret = k5_json_object_set(obj, key, val);
880
free(key);
881
k5_json_release(val);
882
return ret;
883
884
invalid:
885
free(key);
886
return EINVAL;
887
}
888
889
/* Parse a JSON object. */
890
static int
891
parse_object(struct decode_ctx *ctx, k5_json_object *val_out)
892
{
893
k5_json_object obj = NULL;
894
int ret;
895
896
*val_out = NULL;
897
898
/* Parse past the opening brace. */
899
if (*ctx->p != '{')
900
return EINVAL;
901
ctx->p++;
902
if (white_spaces(ctx))
903
return EINVAL;
904
905
ret = k5_json_object_create(&obj);
906
if (ret)
907
return ret;
908
909
/* Pairs associations until we reach the terminating brace. */
910
if (*ctx->p != '}') {
911
while (1) {
912
ret = parse_object_association(obj, ctx);
913
if (ret) {
914
k5_json_release(obj);
915
return ret;
916
}
917
if (white_spaces(ctx))
918
goto invalid;
919
if (*ctx->p == '}')
920
break;
921
if (*ctx->p != ',')
922
goto invalid;
923
ctx->p++;
924
if (white_spaces(ctx))
925
goto invalid;
926
}
927
}
928
ctx->p++;
929
*val_out = obj;
930
return 0;
931
932
invalid:
933
k5_json_release(obj);
934
return EINVAL;
935
}
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
{
941
k5_json_value val;
942
int ret;
943
944
ret = parse_value(ctx, &val);
945
if (ret)
946
return ret;
947
ret = k5_json_array_add(array, val);
948
k5_json_release(val);
949
return ret;
950
}
951
952
/* Parse a JSON array. */
953
static int
954
parse_array(struct decode_ctx *ctx, k5_json_array *val_out)
955
{
956
k5_json_array array = NULL;
957
int ret;
958
959
*val_out = NULL;
960
961
/* Parse past the opening bracket. */
962
if (*ctx->p != '[')
963
return EINVAL;
964
ctx->p++;
965
if (white_spaces(ctx))
966
return EINVAL;
967
968
ret = k5_json_array_create(&array);
969
if (ret)
970
return ret;
971
972
/* Pairs values until we reach the terminating bracket. */
973
if (*ctx->p != ']') {
974
while (1) {
975
ret = parse_array_item(array, ctx);
976
if (ret) {
977
k5_json_release(array);
978
return ret;
979
}
980
if (white_spaces(ctx))
981
goto invalid;
982
if (*ctx->p == ']')
983
break;
984
if (*ctx->p != ',')
985
goto invalid;
986
ctx->p++;
987
if (white_spaces(ctx))
988
goto invalid;
989
}
990
}
991
ctx->p++;
992
*val_out = array;
993
return 0;
994
995
invalid:
996
k5_json_release(array);
997
return EINVAL;
998
}
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
{
1004
k5_json_null null;
1005
k5_json_bool bval;
1006
k5_json_number num;
1007
k5_json_string str;
1008
k5_json_object obj;
1009
k5_json_array array;
1010
char *cstring;
1011
int ret;
1012
1013
*val_out = NULL;
1014
1015
if (white_spaces(ctx))
1016
return EINVAL;
1017
1018
if (*ctx->p == '"') {
1019
ret = parse_string(ctx, &cstring);
1020
if (ret)
1021
return ret;
1022
ret = k5_json_string_create(cstring, &str);
1023
free(cstring);
1024
if (ret)
1025
return ret;
1026
*val_out = str;
1027
} else if (*ctx->p == '{') {
1028
if (ctx->depth-- == 1)
1029
return EINVAL;
1030
ret = parse_object(ctx, &obj);
1031
if (ret)
1032
return ret;
1033
ctx->depth++;
1034
*val_out = obj;
1035
} else if (*ctx->p == '[') {
1036
if (ctx->depth-- == 1)
1037
return EINVAL;
1038
ret = parse_array(ctx, &array);
1039
ctx->depth++;
1040
*val_out = array;
1041
} else if (is_digit(*ctx->p) || *ctx->p == '-') {
1042
ret = parse_number(ctx, &num);
1043
if (ret)
1044
return ret;
1045
*val_out = num;
1046
} else if (strncmp((char *)ctx->p, "null", 4) == 0) {
1047
ctx->p += 4;
1048
ret = k5_json_null_create(&null);
1049
if (ret)
1050
return ret;
1051
*val_out = null;
1052
} else if (strncmp((char *)ctx->p, "true", 4) == 0) {
1053
ctx->p += 4;
1054
ret = k5_json_bool_create(1, &bval);
1055
if (ret)
1056
return ret;
1057
*val_out = bval;
1058
} else if (strncmp((char *)ctx->p, "false", 5) == 0) {
1059
ctx->p += 5;
1060
ret = k5_json_bool_create(0, &bval);
1061
if (ret)
1062
return ret;
1063
*val_out = bval;
1064
} else {
1065
return EINVAL;
1066
}
1067
1068
return 0;
1069
}
1070
1071
int
1072
k5_json_decode(const char *string, k5_json_value *val_out)
1073
{
1074
struct decode_ctx ctx;
1075
k5_json_value val;
1076
int ret;
1077
1078
*val_out = NULL;
1079
ctx.p = (unsigned char *)string;
1080
ctx.depth = MAX_DECODE_DEPTH;
1081
ret = parse_value(&ctx, &val);
1082
if (ret)
1083
return ret;
1084
if (white_spaces(&ctx) == 0) {
1085
k5_json_release(val);
1086
return EINVAL;
1087
}
1088
*val_out = val;
1089
return 0;
1090
}
1091
1092