Coverage Report

Created: 2026-01-15 06:08

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gpsd/gpsd-3.27.6~dev/libgps/json.c
Line
Count
Source
1
/****************************************************************************
2
3
NAME
4
   json.c - parse JSON into fixed-extent data structures
5
6
DESCRIPTION
7
   This module parses a large subset of JSON (JavaScript Object
8
Notation).  Unlike more general JSON parsers, it doesn't use malloc(3)
9
and doesn't support polymorphism; you need to give it a set of
10
template structures describing the expected shape of the incoming
11
JSON, and it will error out if that shape is not matched.  When the
12
parse succeeds, attribute values will be extracted into static
13
locations specified in the template structures.
14
15
   The "shape" of a JSON object in the type signature of its
16
attributes (and attribute values, and so on recursively down through
17
all nestings of objects and arrays).  This parser is indifferent to
18
the order of attributes at any level, but you have to tell it in
19
advance what the type of each attribute value will be and where the
20
parsed value will be stored. The template structures may supply
21
default values to be used when an expected attribute is omitted.
22
23
   The preceding paragraph told one fib.  A single attribute may
24
actually have a span of multiple specifications with different
25
syntactically distinguishable types (e.g. string vs. real vs. integer
26
vs. boolean, but not signed integer vs. unsigned integer).  The parser
27
will match the right spec against the actual data.
28
29
   The dialect this parses has some limitations.  First, it cannot
30
recognize the JSON "null" value.  Secondly, arrays may not have
31
character values as elements (this limitation could be easily removed
32
if required). Third, all elements of an array must be of the same
33
type.  Fourth, it can not handle NaN's in doubles (Issue 53150).
34
35
   There are separate entry points for beginning a parse of either
36
JSON object or a JSON array. JSON "float" quantities are actually
37
stored as doubles.
38
39
   This parser processes object arrays in one of two different ways,
40
defending on whether the array subtype is declared as object or
41
structobject.
42
43
   Object arrays take one base address per object subfield, and are
44
mapped into parallel C arrays (one per subfield).  Strings are not
45
supported in this kind of array, as they don't have a "natural" size
46
to use as an offset multiplier.
47
48
   Structobjects arrays are a way to parse a list of objects to a set
49
of modifications to a corresponding array of C structs.  The trick is
50
that the array object initialization has to specify both the C struct
51
array's base address and the stride length (the size of the C struct).
52
If you initialize the offset fields with the correct offsetof calls,
53
everything will work. Strings are supported but all string storage
54
has to be inline in the struct.
55
56
NOTE
57
   This code has been spun out, packaged, and documented as a
58
reusable module; search for "microjson".
59
60
PERMISSIONS
61
   This file is Copyright 2010 by the GPSD project
62
   SPDX-License-Identifier: BSD-2-clause
63
64
***************************************************************************/
65
#include "../include/gpsd_config.h"  // must be before all includes
66
67
#include <ctype.h>
68
#include <math.h>       // for HUGE_VAL
69
#include <stdarg.h>     // for va_arg(), etc.
70
#include <stdbool.h>
71
#include <stdio.h>
72
#include <stdlib.h>
73
#include <string.h>
74
75
#include "../include/compiler.h"   // for FALLTHROUGH
76
#include "../include/os_compat.h"
77
#include "../include/json.h"
78
79
#include "../include/gps.h"                // for safe_atof() prototype
80
#include "../include/strfuncs.h"
81
#include "../include/timespec.h"
82
83
static int debuglevel = 0;
84
static FILE *debugjsfp = NULL;
85
86
// control the level and destination of debug trace messages
87
void json_enable_debug(int level, FILE * fp)
88
0
{
89
0
    debuglevel = level;
90
0
    debugjsfp = fp;
91
0
}
92
93
static void json_trace(const char *, ...);
94
95
// assemble command in printf(3) style
96
static void json_trace(const char *fmt, ...)
97
0
{
98
0
    va_list ap;
99
100
0
    va_start(ap, fmt);
101
0
    (void)vfprintf(debugjsfp, fmt, ap);
102
0
    va_end(ap);
103
0
}
104
105
// HOTCODE!  Do not change without profiling.
106
// major speedup by checking debuglvl before callin json_trace()
107
#define json_debug_trace(lvl, fmt, ...)                \
108
1.17M
    do {                                              \
109
1.17M
        if (unlikely((lvl) <= debuglevel &&           \
110
1.17M
                      NULL != debugjsfp) ) {            \
111
0
            json_trace(fmt, __VA_ARGS__);              \
112
0
        }                                             \
113
1.17M
    } while (0)
114
115
116
static char *json_target_address(const struct json_attr_t *cursor,
117
                                 const struct json_array_t
118
                                 *parent, int offset)
119
175k
{
120
175k
    char *targetaddr = NULL;
121
175k
    if (NULL == parent ||
122
93.7k
        parent->element_type != t_structobject) {
123
        // ordinary case - use the address in the cursor structure
124
93.7k
        switch (cursor->type) {
125
0
        case t_byte:
126
0
            targetaddr = (char *)&cursor->addr.byte[offset];
127
0
            break;
128
869
        case t_ubyte:
129
869
            targetaddr = (char *)&cursor->addr.ubyte[offset];
130
869
            break;
131
19.4k
        case t_ignore:
132
19.4k
            targetaddr = NULL;
133
19.4k
            break;
134
16.6k
        case t_integer:
135
16.6k
            targetaddr = (char *)&cursor->addr.integer[offset];
136
16.6k
            break;
137
5.69k
        case t_uinteger:
138
5.69k
            targetaddr = (char *)&cursor->addr.uinteger[offset];
139
5.69k
            break;
140
0
        case t_longint:
141
0
            targetaddr = (char *)&cursor->addr.longint[offset];
142
0
            break;
143
561
        case t_ulongint:
144
561
            targetaddr = (char *)&cursor->addr.ulongint[offset];
145
561
            break;
146
0
        case t_short:
147
0
            targetaddr = (char *)&cursor->addr.shortint[offset];
148
0
            break;
149
0
        case t_ushort:
150
0
            targetaddr = (char *)&cursor->addr.ushortint[offset];
151
0
            break;
152
3.26k
        case t_time:
153
3.26k
            targetaddr = (char *)&cursor->addr.ts[offset];
154
3.26k
            break;
155
0
        case t_timespec:
156
0
            targetaddr = (char *)&cursor->addr.ts[offset];
157
0
            break;
158
32.8k
        case t_real:
159
32.8k
            targetaddr = (char *)&cursor->addr.real[offset];
160
32.8k
            break;
161
6.46k
        case t_string:
162
6.46k
            targetaddr = cursor->addr.string;
163
6.46k
            break;
164
1.64k
        case t_boolean:
165
1.64k
            targetaddr = (char *)&cursor->addr.boolean[offset];
166
1.64k
            break;
167
1.06k
        case t_character:
168
1.06k
            targetaddr = (char *)&cursor->addr.character[offset];
169
1.06k
            break;
170
5.25k
        default:
171
5.25k
            targetaddr = NULL;
172
5.25k
            break;
173
93.7k
        }
174
93.7k
    } else {
175
        // tricky case - hacking a member in an array of structures
176
81.9k
        targetaddr =
177
81.9k
            parent->arr.objects.base + (offset * parent->arr.objects.stride) +
178
81.9k
            cursor->addr.offset;
179
81.9k
    }
180
175k
    json_debug_trace(1, "json: Target address for %s (offset %d) is %p\n",
181
175k
                      cursor->attribute, offset, targetaddr);
182
175k
    return targetaddr;
183
175k
}
184
185
186
static int json_internal_read_object(const char *cp,
187
                                     const struct json_attr_t *attrs,
188
                                     const struct json_array_t *parent,
189
                                     int offset,
190
                                     const char **end)
191
9.92k
{
192
9.92k
    enum
193
9.92k
    { init, await_attr, in_attr, await_value, in_val_string,
194
9.92k
        in_escape, in_val_token, post_val, post_element
195
9.92k
    } state = 0;
196
9.92k
    char *statenames[] = {
197
9.92k
        "init", "await_attr", "in_attr", "await_value", "in_val_string",
198
9.92k
        "in_escape", "in_val_token", "post_val", "post_element",
199
9.92k
    };
200
9.92k
    char attrbuf[JSON_ATTR_MAX + 1], *pattr = NULL;
201
9.92k
    char valbuf[JSON_VAL_MAX + 1], *pval = NULL;
202
9.92k
    bool value_quoted = false;
203
9.92k
    char uescape[5];            // enough space for 4 hex digits and a NUL
204
9.92k
    const struct json_attr_t *cursor;
205
9.92k
    int substatus, maxlen = 0;
206
9.92k
    unsigned int u;
207
9.92k
    const struct json_enum_t *mp;
208
9.92k
    char *lptr;
209
210
9.92k
    if (NULL != end) {
211
5.20k
        *end = NULL;    // give it a well-defined value on parse failure
212
5.20k
    }
213
214
    // stuff fields with defaults in case they're omitted in the JSON input
215
150k
    for (cursor = attrs; cursor->attribute != NULL; cursor++)
216
140k
        if (!cursor->nodefault) {
217
140k
            lptr = json_target_address(cursor, parent, offset);
218
140k
            if (NULL != lptr)
219
131k
                switch (cursor->type) {
220
3.23k
                case t_byte:
221
3.23k
                    lptr[0] = cursor->dflt.byte;
222
3.23k
                    break;
223
19.7k
                case t_ubyte:
224
19.7k
                    lptr[0] = cursor->dflt.ubyte;
225
19.7k
                    break;
226
16.5k
                case t_integer:
227
16.5k
                    memcpy(lptr, &cursor->dflt.integer, sizeof(int));
228
16.5k
                    break;
229
7.51k
                case t_uinteger:
230
7.51k
                    memcpy(lptr, &cursor->dflt.uinteger, sizeof(unsigned int));
231
7.51k
                    break;
232
0
                case t_longint:
233
0
                    memcpy(lptr, &cursor->dflt.longint, sizeof(long));
234
0
                    break;
235
121
                case t_ulongint:
236
121
                    memcpy(lptr, &cursor->dflt.ulongint,
237
121
                           sizeof(unsigned long));
238
121
                    break;
239
3.23k
                case t_short:
240
3.23k
                    memcpy(lptr, &cursor->dflt.shortint, sizeof(short));
241
3.23k
                    break;
242
0
                case t_ushort:
243
0
                    memcpy(lptr, &cursor->dflt.ushortint,
244
0
                           sizeof(unsigned short));
245
0
                    break;
246
1.84k
                case t_time:
247
1.84k
                    memcpy(lptr, &cursor->dflt.ts, sizeof(timespec_t));
248
1.84k
                    break;
249
1.66k
                case t_timespec:
250
1.66k
                    memcpy(lptr, &cursor->dflt.ts, sizeof(timespec_t));
251
1.66k
                    break;
252
53.7k
                case t_real:
253
53.7k
                    memcpy(lptr, &cursor->dflt.real, sizeof(double));
254
53.7k
                    break;
255
11.9k
                case t_string:
256
11.9k
                    if (parent != NULL
257
6.12k
                        && parent->element_type != t_structobject
258
0
                        && offset > 0)
259
0
                        return JSON_ERR_NOPARSTR;
260
11.9k
                    lptr[0] = '\0';
261
11.9k
                    break;
262
4.29k
                case t_boolean:
263
4.29k
                    memcpy(lptr, &cursor->dflt.boolean, sizeof(bool));
264
4.29k
                    break;
265
1.33k
                case t_character:
266
1.33k
                    lptr[0] = cursor->dflt.character;
267
1.33k
                    break;
268
0
                case t_object:  // silences a compiler warning
269
0
                    FALLTHROUGH
270
0
                case t_structobject:
271
0
                    FALLTHROUGH
272
0
                case t_array:
273
0
                    FALLTHROUGH
274
832
                case t_check:
275
832
                    FALLTHROUGH
276
6.03k
                case t_ignore:
277
6.03k
                    break;
278
131k
                }
279
140k
        }
280
281
9.92k
    json_debug_trace(1, "json: JSON parse of '%s' begins.\n", cp);
282
283
    // parse input JSON
284
477k
    for (; *cp != '\0'; cp++) {
285
474k
        json_debug_trace(2, "json: State %-14s, looking at '%c' (%p)\n",
286
474k
                          statenames[state], *cp, cp);
287
474k
        switch (state) {
288
10.6k
        case init:
289
10.6k
            if (isspace((unsigned char) *cp)) {
290
769
                continue;
291
769
            }
292
9.89k
            if (*cp == '{') {
293
9.86k
                state = await_attr;
294
9.86k
            } else {
295
27
                json_debug_trace(1, "json: %s",
296
27
                                  "Non-WS when expecting object start.\n");
297
27
                if (NULL != end) {
298
27
                    *end = cp;
299
27
                }
300
27
                return JSON_ERR_OBSTART;
301
27
            }
302
9.86k
            break;
303
39.4k
        case await_attr:
304
39.4k
            if (isspace((unsigned char) *cp)) {
305
286
                continue;
306
286
            }
307
39.1k
            if (*cp == '"') {
308
38.8k
                state = in_attr;
309
38.8k
                pattr = attrbuf;
310
38.8k
                if (NULL != end) {
311
6.66k
                    *end = cp;
312
6.66k
                }
313
38.8k
            } else if (*cp == '}') {
314
214
                break;
315
214
            } else {
316
102
                json_debug_trace(1, "json: %s",
317
102
                          "Non-WS when expecting attribute.\n");
318
102
                if (NULL != end) {
319
10
                    *end = cp;
320
10
                }
321
102
                return JSON_ERR_ATTRSTART;
322
102
            }
323
38.8k
            break;
324
160k
        case in_attr:
325
160k
            if (NULL == pattr) {
326
                // don't update end here, leave at attribute start
327
0
                return JSON_ERR_NULLPTR;
328
0
            }
329
160k
            if (*cp == '"') {
330
38.8k
                *pattr++ = '\0';
331
38.8k
                json_debug_trace(1, "json: Collected attribute name %s\n",
332
38.8k
                                  attrbuf);
333
412k
                for (cursor = attrs; cursor->attribute != NULL; cursor++) {
334
412k
                    json_debug_trace(2, "json: Checking against %s\n",
335
412k
                                      cursor->attribute);
336
412k
                    if (strcmp(cursor->attribute, attrbuf) == 0) {
337
25.8k
                        break;
338
25.8k
                    }
339
386k
                    if (cursor->type == t_ignore &&
340
13.0k
                        strncmp(cursor->attribute, "", 1) == 0) {
341
12.8k
                        break;
342
12.8k
                    }
343
386k
                }
344
38.8k
                if (NULL == cursor->attribute) {
345
97
                    json_debug_trace(1,
346
97
                                      "json: Unknown attribute name '%s'"
347
97
                                      " (attributes begin with '%s').\n",
348
97
                                      attrbuf, attrs->attribute);
349
                    // don't update end here, leave at attribute start
350
97
                    return JSON_ERR_BADATTR;
351
97
                }
352
38.7k
                state = await_value;
353
38.7k
                if (cursor->type == t_string) {
354
1.11k
                    maxlen = (int)cursor->len - 1;
355
37.6k
                } else if (cursor->type == t_check) {
356
1.82k
                    maxlen = (int)strnlen(cursor->dflt.check, JSON_VAL_MAX);
357
35.7k
                } else if (cursor->type == t_time ||
358
33.3k
                           cursor->type == t_ignore) {
359
20.5k
                    maxlen = JSON_VAL_MAX;
360
20.5k
                } else if (NULL != cursor->map) {
361
479
                    maxlen = (int)sizeof(valbuf) - 1;
362
479
                }
363
38.7k
                pval = valbuf;
364
121k
            } else if (pattr >= attrbuf + JSON_ATTR_MAX - 1) {
365
6
                json_debug_trace(1, "json: %s","Attribute name too long.\n");
366
                // don't update end here, leave at attribute start
367
6
                return JSON_ERR_ATTRLEN;
368
121k
            } else {
369
121k
                *pattr++ = *cp;
370
121k
            }
371
160k
            break;
372
160k
        case await_value:
373
40.8k
            if (isspace((unsigned char) *cp) ||
374
40.6k
                *cp == ':') {
375
2.19k
                continue;
376
2.19k
            }
377
38.6k
            if (*cp == '[') {
378
1.37k
                if (cursor->type != t_array) {
379
347
                    json_debug_trace(1,"json: %s",
380
347
                                      "Saw [ when not expecting array.\n");
381
347
                    if (NULL != end) {
382
3
                        *end = cp;
383
3
                    }
384
347
                    return JSON_ERR_NOARRAY;
385
347
                }
386
1.03k
                substatus = json_read_array(cp, &cursor->addr.array, &cp);
387
1.03k
                if (substatus != 0) {
388
226
                    return substatus;
389
226
                }
390
806
                state = post_element;
391
37.2k
            } else if (cursor->type == t_array) {
392
2
                json_debug_trace(1, "json: %s",
393
2
                                  "Array element was specified, but no [.\n");
394
2
                if (NULL != end) {
395
0
                    *end = cp;
396
0
                }
397
2
                return JSON_ERR_NOBRAK;
398
37.2k
            } else if (*cp == '"') {
399
9.51k
                value_quoted = true;
400
9.51k
                state = in_val_string;
401
9.51k
                pval = valbuf;
402
27.7k
            } else {
403
27.7k
                value_quoted = false;
404
27.7k
                state = in_val_token;
405
27.7k
                pval = valbuf;
406
27.7k
                *pval++ = *cp;
407
27.7k
            }
408
38.0k
            break;
409
67.1k
        case in_val_string:
410
67.1k
            if (NULL == pval) {
411
                // don't update end here, leave at value start
412
0
                return JSON_ERR_NULLPTR;
413
0
            }
414
67.1k
            if (*cp == '\\') {
415
1.72k
                state = in_escape;
416
65.4k
            } else if (*cp == '"') {
417
9.10k
                *pval++ = '\0';
418
9.10k
                json_debug_trace(1, "json: Collected string value %s\n", valbuf);
419
9.10k
                state = post_val;
420
56.3k
            } else if (pval > valbuf + JSON_VAL_MAX - 1 ||
421
56.3k
                       pval > valbuf + maxlen - 1) {
422
122
                json_debug_trace(1, "json: %s",  "String value too long.\n");
423
                // don't update end here, leave at value start
424
122
                return JSON_ERR_STRLONG;
425
56.1k
            } else {
426
56.1k
                *pval++ = *cp;
427
56.1k
            }
428
67.0k
            break;
429
67.0k
        case in_escape:
430
1.72k
            if (NULL == pval) {
431
                /* don't update end here, leave at value start */
432
0
                return JSON_ERR_NULLPTR;
433
0
            }
434
1.72k
            if (pval > valbuf + JSON_VAL_MAX - 1 ||
435
1.71k
                pval > valbuf + maxlen) {
436
9
                json_debug_trace(1, "json: %s",  "String value too long.\n");
437
                // don't update end here, leave at value start
438
9
                return JSON_ERR_STRLONG;
439
9
            }
440
1.71k
            switch (*cp) {
441
196
            case 'b':
442
196
                *pval++ = '\b';
443
196
                break;
444
199
            case 'f':
445
199
                *pval++ = '\f';
446
199
                break;
447
200
            case 'n':
448
200
                *pval++ = '\n';
449
200
                break;
450
197
            case 'r':
451
197
                *pval++ = '\r';
452
197
                break;
453
433
            case 't':
454
433
                *pval++ = '\t';
455
433
                break;
456
269
            case 'u':
457
269
                {
458
269
                    unsigned n;
459
460
269
                    cp++;                   // skip the 'u'
461
                    // NetBSD 6 wants the cast
462
1.14k
                    for (n = 0; n < 4 && isxdigit((int)*cp); n++) {
463
872
                        uescape[n] = *cp++;
464
872
                    }
465
269
                    uescape[n] = '\0';      // terminate
466
269
                    --cp;
467
                    // ECMA-404 says JSON \u must have 4 hex digits
468
269
                    if ((4 != n) ||
469
200
                        (1 != sscanf(uescape, "%4x", &u))) {
470
69
                        return JSON_ERR_BADSTRING;
471
69
                    }
472
                    // truncate values above 0xff
473
200
                    *pval++ = (unsigned char)u;
474
200
                }
475
0
                break;
476
217
            default:            // handles double quote and solidus
477
217
                *pval++ = *cp;
478
217
                break;
479
1.71k
            }
480
1.64k
            state = in_val_string;
481
1.64k
            break;
482
117k
        case in_val_token:
483
117k
            if (NULL == pval) {
484
                // don't update end here, leave at value start
485
0
                return JSON_ERR_NULLPTR;
486
0
            }
487
117k
            if (isspace((unsigned char) *cp) ||
488
117k
                *cp == ',' ||
489
95.2k
                *cp == '}') {
490
27.5k
                *pval = '\0';
491
27.5k
                json_debug_trace(1, "json: Collected token valuen %s\n",
492
27.5k
                                 valbuf);
493
27.5k
                state = post_val;
494
27.5k
                if (*cp == '}' ||
495
27.1k
                    *cp == ',') {
496
27.1k
                    --cp;
497
27.1k
                }
498
89.9k
            } else if (pval > valbuf + JSON_VAL_MAX - 1) {
499
6
                json_debug_trace(1, "json: %s", "Token value too long.\n");
500
                // don't update end here, leave at value start
501
6
                return JSON_ERR_TOKLONG;
502
89.9k
            } else {
503
89.9k
                *pval++ = *cp;
504
89.9k
            }
505
117k
            break;
506
            // coverity[unterminated_case]
507
117k
        case post_val:
508
            // Ignore whitespace after either string or token values.
509
35.8k
    if (isspace((unsigned char) *cp)) {
510
673
                while (*cp != '\0' && isspace((unsigned char) *cp)) {
511
431
                    ++cp;
512
431
                }
513
242
                json_debug_trace(1,
514
242
                    "json: Skipped trailing whitespace: value \"%s\"\n", valbuf);
515
242
            }
516
            /*
517
             * We know that cursor points at the first spec matching
518
             * the current attribute.  We don't know that it's *the*
519
             * correct spec; our dialect allows there to be any number
520
             * of adjacent ones with the same attrname but different
521
             * types.  Here's where we try to seek forward for a
522
             * matching type/attr pair if we're not looking at one.
523
             */
524
36.0k
            for (;;) {
525
36.0k
                int seeking = cursor->type;
526
527
36.0k
                if (value_quoted &&
528
8.30k
                    (cursor->type == t_string ||
529
7.22k
                     cursor->type == t_time)) {
530
3.33k
                    break;
531
3.33k
                }
532
32.6k
                if ((strcmp(valbuf, "true") == 0 ||
533
30.9k
                     strcmp(valbuf, "false") == 0) &&
534
2.03k
                    seeking == t_boolean) {
535
1.50k
                    break;
536
1.50k
                }
537
31.1k
                if (isdigit((unsigned char) valbuf[0])) {
538
16.5k
                    bool decimal = strchr(valbuf, '.') != NULL;
539
540
16.5k
                    if (decimal &&
541
1.20k
                        seeking == t_real) {
542
369
                        break;
543
369
                    }
544
16.1k
                    if (!decimal && (seeking == t_byte ||
545
15.0k
                                     seeking == t_ubyte ||
546
14.6k
                                     seeking == t_integer ||
547
13.5k
                                     seeking == t_uinteger ||
548
12.8k
                                     seeking == t_longint ||
549
12.8k
                                     seeking == t_ulongint ||
550
12.3k
                                     seeking == t_short ||
551
10.5k
                                     seeking == t_ushort))
552
4.82k
                        break;
553
16.1k
                }
554
25.9k
                if (NULL == cursor[1].attribute) {  // out of possibilities
555
17.4k
                    break;
556
17.4k
                }
557
8.51k
                if (0 != strcmp(cursor[1].attribute, attrbuf)) {
558
8.31k
                    break;
559
8.31k
                }
560
198
                ++cursor;
561
198
            }
562
35.8k
            if (value_quoted &&
563
8.30k
                (cursor->type != t_string &&
564
7.22k
                 cursor->type != t_character &&
565
7.02k
                 cursor->type != t_check &&
566
6.31k
                 cursor->type != t_time &&
567
4.06k
                 cursor->type != t_ignore &&
568
488
                 cursor->map == 0)) {
569
17
                json_debug_trace(1, "json: %s", "Saw quoted value when expecting"
570
17
                                  " non-string.\n");
571
17
                return JSON_ERR_QNONSTRING;
572
17
            }
573
35.8k
            if (!value_quoted &&
574
27.5k
                (cursor->type == t_string ||
575
27.5k
                 cursor->type == t_check ||
576
27.4k
                 cursor->type == t_time ||
577
27.4k
                 cursor->map != 0)) {
578
60
                json_debug_trace(1, "json: %s",
579
60
                                 "Didn't see quoted value when expecting"
580
60
                                 " string.\n");
581
60
                return JSON_ERR_NONQSTRING;
582
60
            }
583
35.7k
            if (cursor->map != 0) {
584
914
                for (mp = cursor->map; mp->name != NULL; mp++)
585
849
                    if (strcmp(mp->name, valbuf) == 0) {
586
406
                        goto foundit;
587
406
                    }
588
65
                json_debug_trace(1,
589
65
                                 "json: Invalid enumerated value string %s.\n",
590
65
                                  valbuf);
591
65
                return JSON_ERR_BADENUM;
592
406
              foundit:
593
406
                (void)snprintf(valbuf, sizeof(valbuf), "%d", mp->value);
594
406
            }
595
35.6k
            if (cursor->type == t_check) {
596
712
                lptr = cursor->dflt.check;
597
34.9k
            } else {
598
34.9k
                lptr = json_target_address(cursor, parent, offset);
599
34.9k
            }
600
35.6k
            if (NULL != lptr) {
601
20.3k
                switch (cursor->type) {
602
409
                case t_byte:
603
409
                    {
604
409
                        int tmp = atoi(valbuf);
605
409
                        lptr[0] = (char)tmp;
606
409
                    }
607
409
                    break;
608
824
                case t_ubyte:
609
824
                    {
610
824
                        int tmp = atoi(valbuf);
611
824
                        lptr[0] = (unsigned char)tmp;
612
824
                    }
613
824
                    break;
614
1.74k
                case t_integer:
615
1.74k
                    {
616
1.74k
                        int tmp = atoi(valbuf);
617
1.74k
                        memcpy(lptr, &tmp, sizeof(int));
618
1.74k
                    }
619
1.74k
                    break;
620
1.00k
                case t_uinteger:
621
1.00k
                    {
622
1.00k
                        unsigned int tmp = (unsigned int)atol(valbuf);
623
1.00k
                        memcpy(lptr, &tmp, sizeof(unsigned int));
624
1.00k
                    }
625
1.00k
                    break;
626
0
                case t_longint:
627
0
                    {
628
0
                        long tmp = atol(valbuf);
629
0
                        memcpy(lptr, &tmp, sizeof(long));
630
0
                    }
631
0
                    break;
632
440
                case t_ulongint:
633
440
                    {
634
440
                        unsigned long tmp = (unsigned long)atoll(valbuf);
635
440
                        memcpy(lptr, &tmp, sizeof(unsigned long));
636
440
                    }
637
440
                    break;
638
1.88k
                case t_short:
639
1.88k
                    {
640
1.88k
                        short tmp = atoi(valbuf);
641
1.88k
                        memcpy(lptr, &tmp, sizeof(short));
642
1.88k
                    }
643
1.88k
                    break;
644
0
                case t_ushort:
645
0
                    {
646
0
                        unsigned short tmp = (unsigned int)atoi(valbuf);
647
0
                        memcpy(lptr, &tmp, sizeof(unsigned short));
648
0
                    }
649
0
                    break;
650
2.25k
                case t_time:
651
2.25k
                    {
652
2.25k
                        timespec_t ts_tmp = iso8601_to_timespec(valbuf);
653
2.25k
                        memcpy(lptr, &ts_tmp, sizeof(timespec_t));
654
2.25k
                    }
655
2.25k
                    break;
656
392
                case t_timespec:
657
392
                    {
658
392
                        double sec_tmp = safe_atof(valbuf);
659
392
                        timespec_t ts_tmp;
660
392
                        if (0 != isfinite(sec_tmp)) {
661
195
                            DTOTS(&ts_tmp, sec_tmp);
662
195
                            memcpy(lptr, &ts_tmp, sizeof(timespec_t));
663
195
                        } // else leave at .dflt
664
392
                    }
665
392
                    break;
666
5.14k
                case t_real:
667
5.14k
                    {
668
5.14k
                        double tmp = safe_atof(valbuf);
669
5.14k
                        if (0 != isfinite(tmp)) {
670
4.12k
                            memcpy(lptr, &tmp, sizeof(double));
671
4.12k
                        } // else leave at .dflt
672
5.14k
                    }
673
5.14k
                    break;
674
1.08k
                case t_string:
675
1.08k
                    if (NULL != parent &&
676
418
                        parent->element_type != t_structobject &&
677
0
                        offset > 0) {
678
0
                        return JSON_ERR_NOPARSTR;
679
0
                    }
680
1.08k
                    (void)strlcpy(lptr, valbuf, cursor->len);
681
1.08k
                    break;
682
1.89k
                case t_boolean:
683
1.89k
                    {
684
1.89k
                        bool tmp = (strcmp(valbuf, "true") == 0);
685
1.89k
                        memcpy(lptr, &tmp, sizeof(bool));
686
1.89k
                    }
687
1.89k
                    break;
688
564
                case t_character:
689
564
                    if (strnlen(valbuf, 2) > 1) {
690
                        // don't update end here, leave at value start
691
6
                        return JSON_ERR_STRLONG;
692
558
                    } else {
693
558
                        lptr[0] = valbuf[0];
694
558
                    }
695
558
                    break;
696
2.01k
                case t_ignore:  // silences a compiler warning
697
2.01k
                    FALLTHROUGH
698
2.01k
                case t_object:  // silences a compiler warning
699
2.01k
                    FALLTHROUGH
700
2.01k
                case t_structobject:
701
2.01k
                    FALLTHROUGH
702
2.01k
                case t_array:
703
2.01k
                    break;
704
712
                case t_check:
705
712
                    if (strcmp(cursor->dflt.check, valbuf) != 0) {
706
157
                        json_debug_trace(1, "json: Required attribute value %s"
707
157
                                          " not present.\n",
708
157
                                          cursor->dflt.check);
709
                        // don't update end here, leave at start of attribute
710
157
                        return JSON_ERR_CHECKFAIL;
711
157
                    }
712
555
                    break;
713
20.3k
                }
714
20.3k
            }
715
35.5k
            FALLTHROUGH
716
36.6k
        case post_element:
717
36.6k
            if (isspace((unsigned char) *cp)) {
718
397
                continue;
719
397
            }
720
36.2k
            if (*cp == ',') {
721
30.0k
                state = await_attr;
722
30.0k
            } else if (*cp == '}') {
723
5.59k
                ++cp;
724
5.59k
                goto good_parse;
725
5.59k
            } else {
726
622
                json_debug_trace(1, "json: %s",
727
622
                                "Garbage while expecting comma or }\n");
728
622
                if (NULL != end) {
729
15
                    *end = cp;
730
15
                }
731
622
                return JSON_ERR_BADTRAIL;
732
622
            }
733
30.0k
            break;
734
474k
        }
735
474k
    }
736
2.38k
    if (state == init) {
737
33
        json_debug_trace(1, "json: %s", "Input was empty or white-space only\n");
738
33
        return JSON_ERR_EMPTY;
739
33
    }
740
741
7.95k
  good_parse:
742
    // in case there's another object following, consume trailing WS
743
7.95k
    while (isspace((unsigned char)*cp)) {
744
200
        ++cp;
745
200
    }
746
7.95k
    if (NULL != end) {
747
5.10k
        *end = cp;
748
5.10k
    }
749
7.95k
    json_debug_trace(1, "%s", "json: JSON parse ends.\n");
750
7.95k
    return 0;
751
2.38k
}
752
753
int json_read_array(const char *cp, const struct json_array_t *arr,
754
                    const char **end)
755
1.03k
{
756
1.03k
    int substatus, offset, arrcount;
757
1.03k
    char *tp;
758
759
1.03k
    if (NULL != end)
760
1.03k
        *end = NULL;    // give it a well-defined value on parse failure
761
762
1.03k
    json_debug_trace(1, "json: %s", "Entered json_read_array()\n");
763
764
1.03k
    while (isspace((unsigned char)*cp)) {
765
0
        cp++;
766
0
    }
767
1.03k
    if (*cp != '[') {
768
0
        json_debug_trace(1, "json: %s", "Didn't find expected array start\n");
769
0
        return JSON_ERR_ARRAYSTART;
770
0
    }
771
1.03k
    cp++;
772
773
1.03k
    tp = arr->arr.strings.store;
774
1.03k
    arrcount = 0;
775
776
    // Check for empty array
777
1.03k
    while (isspace((unsigned char)*cp)) {
778
207
        cp++;
779
207
    }
780
1.03k
    if (*cp == ']') {
781
272
        goto breakout;
782
272
    }
783
784
7.88k
    for (offset = 0; offset < arr->maxlen; offset++) {
785
7.88k
        char *ep = NULL;
786
787
7.88k
        json_debug_trace(1, "json: Looking at %s\n", cp);
788
7.88k
        switch (arr->element_type) {
789
2.67k
        case t_string:
790
2.67k
            if (isspace((unsigned char) *cp)) {
791
197
                cp++;
792
197
            }
793
2.67k
            if (*cp != '"') {
794
10
                return JSON_ERR_BADSTRING;
795
2.66k
            } else {
796
2.66k
                ++cp;
797
2.66k
            }
798
2.66k
            arr->arr.strings.ptrs[offset] = tp;
799
8.39k
            for (; tp - arr->arr.strings.store < arr->arr.strings.storelen;
800
5.73k
                 tp++)
801
8.39k
                if (*cp == '"') {
802
2.65k
                    ++cp;
803
2.65k
                    *tp++ = '\0';
804
2.65k
                    goto stringend;
805
5.73k
                } else if (*cp == '\0') {
806
2
                    json_debug_trace(1, "json: %s",
807
2
                                      "Bad string syntax in string list.\n");
808
2
                    return JSON_ERR_BADSTRING;
809
5.73k
                } else {
810
5.73k
                    *tp = *cp++;
811
5.73k
                }
812
2
            json_debug_trace(1, "json: %s",
813
2
                             "Bad string syntax in string list.\n");
814
2
            return JSON_ERR_BADSTRING;
815
2.65k
          stringend:
816
2.65k
            break;
817
0
        case t_object:
818
0
            FALLTHROUGH
819
5.20k
        case t_structobject:
820
5.20k
            substatus =
821
5.20k
                json_internal_read_object(cp, arr->arr.objects.subtype, arr,
822
5.20k
                                          offset, &cp);
823
5.20k
            if (substatus != 0) {
824
105
                if (NULL != end) {
825
105
                    *end = cp;
826
105
                }
827
105
                return substatus;
828
105
            }
829
5.10k
            break;
830
5.10k
        case t_integer:
831
0
            arr->arr.integers.store[offset] = (int)strtol(cp, &ep, 0);
832
0
            if (ep == cp) {
833
0
                return JSON_ERR_BADNUM;
834
0
            }
835
0
            cp = ep;
836
0
            break;
837
0
        case t_uinteger:
838
0
            arr->arr.uintegers.store[offset] = (unsigned int)strtoul(cp,
839
0
                                                                     &ep, 0);
840
0
            if (ep == cp) {
841
0
                return JSON_ERR_BADNUM;
842
0
            }
843
0
            cp = ep;
844
0
            break;
845
0
        case t_longint:
846
0
            arr->arr.longint.store[offset] = strtol(cp, &ep, 0);
847
0
            if (ep == cp) {
848
0
                return JSON_ERR_BADNUM;
849
0
            }
850
0
            cp = ep;
851
0
            break;
852
0
        case t_ulongint:
853
0
            arr->arr.ulongint.store[offset] = strtoul(cp, &ep, 0);
854
0
            if (ep == cp) {
855
0
                return JSON_ERR_BADNUM;
856
0
            }
857
0
            cp = ep;
858
0
            break;
859
0
        case t_byte:
860
0
            arr->arr.bytes.store[offset] = (char)strtol(cp, &ep, 0);
861
0
            if (ep == cp) {
862
0
                return JSON_ERR_BADNUM;
863
0
            }
864
0
            cp = ep;
865
0
            break;
866
0
        case t_ubyte:
867
0
            arr->arr.ubytes.store[offset] = (unsigned char)strtoul(cp,
868
0
                                                                   &ep, 0);
869
0
            if (ep == cp) {
870
0
                return JSON_ERR_BADNUM;
871
0
            }
872
0
            cp = ep;
873
0
            break;
874
0
        case t_short:
875
0
            arr->arr.shorts.store[offset] = (short)strtol(cp, &ep, 0);
876
0
            if (ep == cp) {
877
0
                return JSON_ERR_BADNUM;
878
0
            }
879
0
            cp = ep;
880
0
            break;
881
0
        case t_ushort:
882
0
            arr->arr.ushorts.store[offset] = (unsigned short)strtoul(cp,
883
0
                                                                     &ep, 0);
884
0
            if (ep == cp) {
885
0
                return JSON_ERR_BADNUM;
886
0
            }
887
0
            cp = ep;
888
0
            break;
889
0
        case t_time:
890
0
            {
891
0
                timespec_t ts_tmp;
892
0
                if (*cp != '"') {
893
0
                    return JSON_ERR_BADSTRING;
894
0
                } else {
895
0
                    ++cp;
896
0
                }
897
0
                ts_tmp = iso8601_to_timespec(cp);
898
0
                arr->arr.timespecs.store[offset] = ts_tmp;
899
0
                while (*cp &&
900
0
                       *cp != '"') {
901
0
                    cp++;
902
0
                }
903
0
                if (*cp != '"') {
904
0
                    return JSON_ERR_BADSTRING;
905
0
                }
906
0
                ++cp;
907
0
            }
908
0
            break;
909
0
        case t_timespec:
910
            // TODO not sure how to implement this
911
0
            return JSON_ERR_BADNUM;
912
0
            break;
913
0
        case t_real:
914
0
            arr->arr.reals.store[offset] = strtod(cp, &ep);
915
0
            if (ep == cp) {
916
0
                return JSON_ERR_BADNUM;
917
0
            }
918
0
            cp = ep;
919
0
            break;
920
0
        case t_boolean:
921
0
            if (str_starts_with(cp, "true")) {
922
0
                arr->arr.booleans.store[offset] = true;
923
0
                cp += 4;
924
0
            } else if (str_starts_with(cp, "false")) {
925
0
                arr->arr.booleans.store[offset] = false;
926
0
                cp += 5;
927
0
            }
928
0
            break;
929
0
        case t_character:
930
0
            FALLTHROUGH
931
0
        case t_array:
932
0
            FALLTHROUGH
933
0
        case t_check:
934
0
            FALLTHROUGH
935
0
        case t_ignore:
936
0
            json_debug_trace(1, "json: %s", "Invalid array subtype.\n");
937
0
            return JSON_ERR_SUBTYPE;
938
7.88k
        }
939
7.76k
        arrcount++;
940
7.76k
        if (isspace((unsigned char)*cp)) {
941
219
            cp++;
942
219
        }
943
7.76k
        if (*cp == ']') {
944
534
            json_debug_trace(1, "json: %s", "End of array found.\n");
945
534
            goto breakout;
946
534
        }
947
7.22k
        if (*cp == ',') {
948
7.12k
            cp++;
949
7.12k
        } else {
950
103
            json_debug_trace(1, "json: %s", "Bad trailing syntax on array.\n");
951
103
            return JSON_ERR_BADSUBTRAIL;
952
103
        }
953
7.22k
    }
954
4
    json_debug_trace(1, "json: %s", "Too many elements in array.\n");
955
4
    if (NULL != end) {
956
4
        *end = cp;
957
4
    }
958
4
    return JSON_ERR_SUBTOOLONG;
959
806
  breakout:
960
806
    if (NULL != arr->count) {
961
806
        *(arr->count) = arrcount;
962
806
    }
963
806
    if (NULL != end) {
964
806
        *end = cp;
965
806
    }
966
806
    json_debug_trace(1, "json: leaving json_read_array() with %d elements\n",
967
806
                      arrcount);
968
806
    return 0;
969
760
}
970
971
int json_read_object(const char *cp, const struct json_attr_t *attrs,
972
                     const char **end)
973
4.71k
{
974
4.71k
    int st;
975
976
4.71k
    json_debug_trace(1, "json: json_read_object() sees '%s'\n", cp);
977
4.71k
    st = json_internal_read_object(cp, attrs, NULL, 0, end);
978
4.71k
    return st;
979
4.71k
}
980
981
const char *json_error_string(int err)
982
0
{
983
0
    const char *errors[] = {
984
0
        "unknown error while parsing JSON",
985
0
        "non-whitespace when expecting object start",
986
0
        "non-whitespace when expecting attribute start",
987
0
        "unknown attribute name",
988
0
        "attribute name too long",
989
0
        "saw [ when not expecting array",
990
0
        "array element specified, but no [",
991
0
        "string value too long",
992
0
        "token value too long",
993
0
        "garbage while expecting comma or } or ]",
994
0
        "didn't find expected array start",
995
0
        "error while parsing object array",
996
0
        "too many array elements",
997
0
        "garbage while expecting array comma",
998
0
        "unsupported array element type",
999
0
        "error while string parsing",
1000
0
        "check attribute not matched",
1001
0
        "can't support strings in parallel arrays",
1002
0
        "invalid enumerated value",
1003
0
        "saw quoted value when expecting nonstring",
1004
0
        "didn't see quoted value when expecting string",
1005
0
        "other data conversion error",
1006
0
        "unexpected null value or attribute pointer",
1007
0
        "object element specified, but no {",
1008
0
        "input was empty or white-space only",
1009
0
    };
1010
1011
0
    if (err <= 0 ||
1012
0
        err >= (int)(sizeof(errors) / sizeof(errors[0]))) {
1013
0
        return errors[0];
1014
0
    }
1015
0
    return errors[err];
1016
0
}
1017
1018
/* quote a JSON string so it can be used as a simple JSON string.
1019
 * Used to output the JSON as a literal JSON string
1020
 * escape control chars, escape double quote.
1021
 * stop at NUL, in_len or bad unicode char
1022
 */
1023
char *json_quote(const char *in_buffer, char *out_buffer, size_t in_len,
1024
                 size_t out_len)
1025
0
{
1026
0
    const char *escape_match = "'\"/\\\b\f\n\r\t";
1027
0
    const char *escaped_bit = "'\"/\\bfnrt";
1028
0
    unsigned out_index = 0;
1029
0
    const char *escape_ptr;
1030
0
    unsigned in_index = 0;
1031
0
    unsigned to_copy = 0;
1032
1033
0
    out_buffer[0] = '\0';
1034
1035
    // check in string, stop at NUL, done in_len, or out_buffer full
1036
0
    for (in_index = 0; in_buffer[in_index] != '\0'; in_index++) {
1037
1038
0
        if (in_index >= in_len) {
1039
            // got all from input buffer
1040
0
            break;
1041
0
        }
1042
1043
0
        if (out_index > (out_len - 8) ) {
1044
            /* output out_buffer full.  Not enough space for a 4-byte UTF + NUL,
1045
             * or \uxxxx + NUL.  Safer to check once, at the top,
1046
             * than a lot of specific size checks later in the loop.
1047
             */
1048
0
            break;
1049
0
        }
1050
1051
0
        if (in_buffer[in_index] & 0x80) {
1052
            // highbit set. assume unicode
1053
0
            to_copy = 0;    // always reset before use, to shut up coverity
1054
1055
            // check in_len so we don't overrun in_buffer
1056
0
            if ((in_len > (in_index + 1)) &&
1057
0
                (0xC0 == (0xE0 & (uint8_t)in_buffer[in_index])) &&
1058
0
                (0x80 == (0xC0 & (uint8_t)in_buffer[in_index + 1]))) {
1059
                // utf-8 ish 16bit rune - deg, plusm, mplus etc.
1060
0
                to_copy = 2;
1061
0
            } else if ((in_len > (in_index + 2)) &&
1062
0
                       (0xE0 == (0xF0 & (uint8_t)in_buffer[in_index])) &&
1063
0
                       (0x80 == (0xC0 & (uint8_t)in_buffer[in_index + 1])) &&
1064
0
                       (0x80 == (0xC0 & (uint8_t)in_buffer[in_index + 2]))) {
1065
                // utf-8 ish 24 bit rune - (double) prime etc.
1066
0
                to_copy = 3;
1067
0
            } else if ((in_len > (in_index + 3)) &&
1068
0
                       (0xF0 == (0xF8 & (uint8_t)in_buffer[in_index])) &&
1069
0
                       (0x80 == (0xC0 & (uint8_t)in_buffer[in_index + 1])) &&
1070
0
                       (0x80 == (0xC0 & (uint8_t)in_buffer[in_index + 2])) &&
1071
0
                       (0x80 == (0xC0 & (uint8_t)in_buffer[in_index + 3]))) {
1072
                // utf-8 ish 32 bit rune - musical symbol g clef etc.
1073
0
                to_copy = 4;
1074
0
            } else {
1075
                // WTF??  Short UTF?  Bad UTF?
1076
0
                str_appendf(out_buffer, out_len,
1077
0
                            "\\u%04x", in_buffer[in_index] & 0x0ff);
1078
0
                out_index += 6;
1079
0
                continue;
1080
0
            }
1081
1082
0
            memcpy(&out_buffer[out_index], &in_buffer[in_index], to_copy);
1083
0
            out_index += to_copy;
1084
            // minus one as the for loop does in_index++
1085
0
            in_index += to_copy - 1;
1086
0
            out_buffer[out_index] = '\0';
1087
0
            continue;
1088
0
        }
1089
1090
        /* Try to find current byte from in buffer in string escape
1091
         * match if it is there append '\', the corresponding byte
1092
         * from escaped bit, and a null byte to end of out buffer.
1093
         */
1094
0
        escape_ptr = strchr(escape_match, in_buffer[in_index]);
1095
0
        if (escape_ptr >= escape_match) {
1096
0
            out_buffer[out_index++] = '\\';
1097
0
            out_buffer[out_index++] = escaped_bit[escape_ptr-escape_match];
1098
0
            out_buffer[out_index]   = 0;
1099
0
            continue;
1100
0
        }
1101
1102
        // Escape 0-31 and 127 if not previously handled (0-x01f,x7f)
1103
0
        if ('\x1f' >= in_buffer[in_index] || '\x7f' == in_buffer[in_index]) {
1104
0
            str_appendf(out_buffer, out_len, "\\u%04x",
1105
0
                        in_buffer[in_index] & 0x0ff);
1106
0
            out_index += 6;
1107
0
            continue;
1108
0
        }
1109
        // pass through everything not escaped.
1110
0
        out_buffer[out_index++] = in_buffer[in_index];
1111
0
        out_buffer[out_index] = '\0';
1112
0
    }
1113
0
    return out_buffer;
1114
0
}
1115
1116
// vim: set expandtab shiftwidth=4