Coverage Report

Created: 2025-10-13 07:02

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gpsd/gpsd-3.26.2~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.15M
    do {                                              \
109
1.15M
        if (unlikely((lvl) <= debuglevel &&           \
110
1.15M
                      NULL != debugjsfp) ) {            \
111
0
            json_trace(fmt, __VA_ARGS__);              \
112
0
        }                                             \
113
1.15M
    } 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
163k
{
120
163k
    char *targetaddr = NULL;
121
163k
    if (NULL == parent ||
122
93.8k
        parent->element_type != t_structobject) {
123
        // ordinary case - use the address in the cursor structure
124
93.8k
        switch (cursor->type) {
125
0
        case t_byte:
126
0
            targetaddr = (char *)&cursor->addr.byte[offset];
127
0
            break;
128
863
        case t_ubyte:
129
863
            targetaddr = (char *)&cursor->addr.ubyte[offset];
130
863
            break;
131
19.1k
        case t_ignore:
132
19.1k
            targetaddr = NULL;
133
19.1k
            break;
134
16.3k
        case t_integer:
135
16.3k
            targetaddr = (char *)&cursor->addr.integer[offset];
136
16.3k
            break;
137
5.62k
        case t_uinteger:
138
5.62k
            targetaddr = (char *)&cursor->addr.uinteger[offset];
139
5.62k
            break;
140
0
        case t_longint:
141
0
            targetaddr = (char *)&cursor->addr.longint[offset];
142
0
            break;
143
534
        case t_ulongint:
144
534
            targetaddr = (char *)&cursor->addr.ulongint[offset];
145
534
            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.57k
        case t_time:
153
3.57k
            targetaddr = (char *)&cursor->addr.ts[offset];
154
3.57k
            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.91k
        case t_string:
162
6.91k
            targetaddr = cursor->addr.string;
163
6.91k
            break;
164
1.63k
        case t_boolean:
165
1.63k
            targetaddr = (char *)&cursor->addr.boolean[offset];
166
1.63k
            break;
167
1.10k
        case t_character:
168
1.10k
            targetaddr = (char *)&cursor->addr.character[offset];
169
1.10k
            break;
170
5.29k
        default:
171
5.29k
            targetaddr = NULL;
172
5.29k
            break;
173
93.8k
        }
174
93.8k
    } else {
175
        // tricky case - hacking a member in an array of structures
176
69.3k
        targetaddr =
177
69.3k
            parent->arr.objects.base + (offset * parent->arr.objects.stride) +
178
69.3k
            cursor->addr.offset;
179
69.3k
    }
180
163k
    json_debug_trace(1, "json: Target address for %s (offset %d) is %p\n",
181
163k
                      cursor->attribute, offset, targetaddr);
182
163k
    return targetaddr;
183
163k
}
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.16k
{
192
9.16k
    enum
193
9.16k
    { init, await_attr, in_attr, await_value, in_val_string,
194
9.16k
        in_escape, in_val_token, post_val, post_element
195
9.16k
    } state = 0;
196
9.16k
    char *statenames[] = {
197
9.16k
        "init", "await_attr", "in_attr", "await_value", "in_val_string",
198
9.16k
        "in_escape", "in_val_token", "post_val", "post_element",
199
9.16k
    };
200
9.16k
    char attrbuf[JSON_ATTR_MAX + 1], *pattr = NULL;
201
9.16k
    char valbuf[JSON_VAL_MAX + 1], *pval = NULL;
202
9.16k
    bool value_quoted = false;
203
9.16k
    char uescape[5];            // enough space for 4 hex digits and a NUL
204
9.16k
    const struct json_attr_t *cursor;
205
9.16k
    int substatus, maxlen = 0;
206
9.16k
    unsigned int u;
207
9.16k
    const struct json_enum_t *mp;
208
9.16k
    char *lptr;
209
210
9.16k
    if (NULL != end) {
211
4.42k
        *end = NULL;    // give it a well-defined value on parse failure
212
4.42k
    }
213
214
    // stuff fields with defaults in case they're omitted in the JSON input
215
138k
    for (cursor = attrs; cursor->attribute != NULL; cursor++)
216
129k
        if (!cursor->nodefault) {
217
129k
            lptr = json_target_address(cursor, parent, offset);
218
129k
            if (NULL != lptr)
219
119k
                switch (cursor->type) {
220
3.05k
                case t_byte:
221
3.05k
                    lptr[0] = cursor->dflt.byte;
222
3.05k
                    break;
223
16.7k
                case t_ubyte:
224
16.7k
                    lptr[0] = cursor->dflt.ubyte;
225
16.7k
                    break;
226
15.8k
                case t_integer:
227
15.8k
                    memcpy(lptr, &cursor->dflt.integer, sizeof(int));
228
15.8k
                    break;
229
6.65k
                case t_uinteger:
230
6.65k
                    memcpy(lptr, &cursor->dflt.uinteger, sizeof(unsigned int));
231
6.65k
                    break;
232
0
                case t_longint:
233
0
                    memcpy(lptr, &cursor->dflt.longint, sizeof(long));
234
0
                    break;
235
126
                case t_ulongint:
236
126
                    memcpy(lptr, &cursor->dflt.ulongint,
237
126
                           sizeof(unsigned long));
238
126
                    break;
239
3.05k
                case t_short:
240
3.05k
                    memcpy(lptr, &cursor->dflt.shortint, sizeof(short));
241
3.05k
                    break;
242
0
                case t_ushort:
243
0
                    memcpy(lptr, &cursor->dflt.ushortint,
244
0
                           sizeof(unsigned short));
245
0
                    break;
246
1.62k
                case t_time:
247
1.62k
                    memcpy(lptr, &cursor->dflt.ts, sizeof(timespec_t));
248
1.62k
                    break;
249
1.23k
                case t_timespec:
250
1.23k
                    memcpy(lptr, &cursor->dflt.ts, sizeof(timespec_t));
251
1.23k
                    break;
252
50.9k
                case t_real:
253
50.9k
                    memcpy(lptr, &cursor->dflt.real, sizeof(double));
254
50.9k
                    break;
255
10.3k
                case t_string:
256
10.3k
                    if (parent != NULL
257
4.44k
                        && parent->element_type != t_structobject
258
0
                        && offset > 0)
259
0
                        return JSON_ERR_NOPARSTR;
260
10.3k
                    lptr[0] = '\0';
261
10.3k
                    break;
262
4.11k
                case t_boolean:
263
4.11k
                    memcpy(lptr, &cursor->dflt.boolean, sizeof(bool));
264
4.11k
                    break;
265
1.13k
                case t_character:
266
1.13k
                    lptr[0] = cursor->dflt.character;
267
1.13k
                    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
617
                case t_check:
275
617
                    FALLTHROUGH
276
5.03k
                case t_ignore:
277
5.03k
                    break;
278
119k
                }
279
129k
        }
280
281
9.16k
    json_debug_trace(1, "json: JSON parse of '%s' begins.\n", cp);
282
283
    // parse input JSON
284
469k
    for (; *cp != '\0'; cp++) {
285
466k
        json_debug_trace(2, "json: State %-14s, looking at '%c' (%p)\n",
286
466k
                          statenames[state], *cp, cp);
287
466k
        switch (state) {
288
9.76k
        case init:
289
9.76k
            if (isspace((unsigned char) *cp)) {
290
638
                continue;
291
638
            }
292
9.12k
            if (*cp == '{') {
293
9.10k
                state = await_attr;
294
9.10k
            } 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.10k
            break;
303
38.3k
        case await_attr:
304
38.3k
            if (isspace((unsigned char) *cp)) {
305
214
                continue;
306
214
            }
307
38.1k
            if (*cp == '"') {
308
37.8k
                state = in_attr;
309
37.8k
                pattr = attrbuf;
310
37.8k
                if (NULL != end) {
311
5.63k
                    *end = cp;
312
5.63k
                }
313
37.8k
            } else if (*cp == '}') {
314
206
                break;
315
206
            } else {
316
86
                json_debug_trace(1, "json: %s",
317
86
                          "Non-WS when expecting attribute.\n");
318
86
                if (NULL != end) {
319
2
                    *end = cp;
320
2
                }
321
86
                return JSON_ERR_ATTRSTART;
322
86
            }
323
37.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
37.8k
                *pattr++ = '\0';
331
37.8k
                json_debug_trace(1, "json: Collected attribute name %s\n",
332
37.8k
                                  attrbuf);
333
422k
                for (cursor = attrs; cursor->attribute != NULL; cursor++) {
334
422k
                    json_debug_trace(2, "json: Checking against %s\n",
335
422k
                                      cursor->attribute);
336
422k
                    if (strcmp(cursor->attribute, attrbuf) == 0) {
337
24.9k
                        break;
338
24.9k
                    }
339
397k
                    if (cursor->type == t_ignore &&
340
13.0k
                        strncmp(cursor->attribute, "", 1) == 0) {
341
12.8k
                        break;
342
12.8k
                    }
343
397k
                }
344
37.8k
                if (NULL == cursor->attribute) {
345
77
                    json_debug_trace(1,
346
77
                                      "json: Unknown attribute name '%s'"
347
77
                                      " (attributes begin with '%s').\n",
348
77
                                      attrbuf, attrs->attribute);
349
                    // don't update end here, leave at attribute start
350
77
                    return JSON_ERR_BADATTR;
351
77
                }
352
37.7k
                state = await_value;
353
37.7k
                if (cursor->type == t_string) {
354
1.35k
                    maxlen = (int)cursor->len - 1;
355
36.3k
                } else if (cursor->type == t_check) {
356
2.05k
                    maxlen = (int)strnlen(cursor->dflt.check, JSON_VAL_MAX);
357
34.3k
                } else if (cursor->type == t_time ||
358
31.5k
                           cursor->type == t_ignore) {
359
20.0k
                    maxlen = JSON_VAL_MAX;
360
20.0k
                } else if (NULL != cursor->map) {
361
446
                    maxlen = (int)sizeof(valbuf) - 1;
362
446
                }
363
37.7k
                pval = valbuf;
364
122k
            } else if (pattr >= attrbuf + JSON_ATTR_MAX - 1) {
365
8
                json_debug_trace(1, "json: %s","Attribute name too long.\n");
366
                // don't update end here, leave at attribute start
367
8
                return JSON_ERR_ATTRLEN;
368
122k
            } else {
369
122k
                *pattr++ = *cp;
370
122k
            }
371
160k
            break;
372
160k
        case await_value:
373
40.0k
            if (isspace((unsigned char) *cp) ||
374
39.8k
                *cp == ':') {
375
2.40k
                continue;
376
2.40k
            }
377
37.6k
            if (*cp == '[') {
378
1.24k
                if (cursor->type != t_array) {
379
356
                    json_debug_trace(1,"json: %s",
380
356
                                      "Saw [ when not expecting array.\n");
381
356
                    if (NULL != end) {
382
3
                        *end = cp;
383
3
                    }
384
356
                    return JSON_ERR_NOARRAY;
385
356
                }
386
889
                substatus = json_read_array(cp, &cursor->addr.array, &cp);
387
889
                if (substatus != 0) {
388
235
                    return substatus;
389
235
                }
390
654
                state = post_element;
391
36.3k
            } else if (cursor->type == t_array) {
392
1
                json_debug_trace(1, "json: %s",
393
1
                                  "Array element was specified, but no [.\n");
394
1
                if (NULL != end) {
395
0
                    *end = cp;
396
0
                }
397
1
                return JSON_ERR_NOBRAK;
398
36.3k
            } else if (*cp == '"') {
399
10.8k
                value_quoted = true;
400
10.8k
                state = in_val_string;
401
10.8k
                pval = valbuf;
402
25.5k
            } else {
403
25.5k
                value_quoted = false;
404
25.5k
                state = in_val_token;
405
25.5k
                pval = valbuf;
406
25.5k
                *pval++ = *cp;
407
25.5k
            }
408
37.0k
            break;
409
79.3k
        case in_val_string:
410
79.3k
            if (NULL == pval) {
411
                // don't update end here, leave at value start
412
0
                return JSON_ERR_NULLPTR;
413
0
            }
414
79.3k
            if (*cp == '\\') {
415
1.81k
                state = in_escape;
416
77.4k
            } else if (*cp == '"') {
417
10.3k
                *pval++ = '\0';
418
10.3k
                json_debug_trace(1, "json: Collected string value %s\n", valbuf);
419
10.3k
                state = post_val;
420
67.1k
            } else if (pval > valbuf + JSON_VAL_MAX - 1 ||
421
67.1k
                       pval > valbuf + maxlen - 1) {
422
135
                json_debug_trace(1, "json: %s",  "String value too long.\n");
423
                // don't update end here, leave at value start
424
135
                return JSON_ERR_STRLONG;
425
66.9k
            } else {
426
66.9k
                *pval++ = *cp;
427
66.9k
            }
428
79.1k
            break;
429
79.1k
        case in_escape:
430
1.81k
            if (NULL == pval) {
431
                /* don't update end here, leave at value start */
432
0
                return JSON_ERR_NULLPTR;
433
0
            }
434
1.81k
            if (pval > valbuf + JSON_VAL_MAX - 1 ||
435
1.81k
                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.80k
            switch (*cp) {
441
205
            case 'b':
442
205
                *pval++ = '\b';
443
205
                break;
444
194
            case 'f':
445
194
                *pval++ = '\f';
446
194
                break;
447
198
            case 'n':
448
198
                *pval++ = '\n';
449
198
                break;
450
194
            case 'r':
451
194
                *pval++ = '\r';
452
194
                break;
453
255
            case 't':
454
255
                *pval++ = '\t';
455
255
                break;
456
268
            case 'u':
457
268
                {
458
268
                    unsigned n;
459
460
268
                    cp++;                   // skip the 'u'
461
                    // NetBSD 6 wants the cast
462
1.13k
                    for (n = 0; n < 4 && isxdigit((int)*cp); n++) {
463
862
                        uescape[n] = *cp++;
464
862
                    }
465
268
                    uescape[n] = '\0';      // terminate
466
268
                    --cp;
467
                    // ECMA-404 says JSON \u must have 4 hex digits
468
268
                    if ((4 != n) ||
469
204
                        (1 != sscanf(uescape, "%4x", &u))) {
470
64
                        return JSON_ERR_BADSTRING;
471
64
                    }
472
                    // truncate values above 0xff
473
204
                    *pval++ = (unsigned char)u;
474
204
                }
475
0
                break;
476
491
            default:            // handles double quote and solidus
477
491
                *pval++ = *cp;
478
491
                break;
479
1.80k
            }
480
1.74k
            state = in_val_string;
481
1.74k
            break;
482
100k
        case in_val_token:
483
100k
            if (NULL == pval) {
484
                // don't update end here, leave at value start
485
0
                return JSON_ERR_NULLPTR;
486
0
            }
487
100k
            if (isspace((unsigned char) *cp) ||
488
100k
                *cp == ',' ||
489
79.9k
                *cp == '}') {
490
25.4k
                *pval = '\0';
491
25.4k
                json_debug_trace(1, "json: Collected token valuen %s\n",
492
25.4k
                                 valbuf);
493
25.4k
                state = post_val;
494
25.4k
                if (*cp == '}' ||
495
24.9k
                    *cp == ',') {
496
24.9k
                    --cp;
497
24.9k
                }
498
75.5k
            } 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
75.5k
            } else {
503
75.5k
                *pval++ = *cp;
504
75.5k
            }
505
100k
            break;
506
            // coverity[unterminated_case]
507
100k
        case post_val:
508
            // Ignore whitespace after either string or token values.
509
34.7k
    if (isspace((unsigned char) *cp)) {
510
917
                while (*cp != '\0' && isspace((unsigned char) *cp)) {
511
563
                    ++cp;
512
563
                }
513
354
                json_debug_trace(1,
514
354
                    "json: Skipped trailing whitespace: value \"%s\"\n", valbuf);
515
354
            }
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
34.9k
            for (;;) {
525
34.9k
                int seeking = cursor->type;
526
527
34.9k
                if (value_quoted &&
528
9.38k
                    (cursor->type == t_string ||
529
8.06k
                     cursor->type == t_time)) {
530
3.88k
                    break;
531
3.88k
                }
532
31.0k
                if ((strcmp(valbuf, "true") == 0 ||
533
29.2k
                     strcmp(valbuf, "false") == 0) &&
534
2.03k
                    seeking == t_boolean) {
535
1.49k
                    break;
536
1.49k
                }
537
29.5k
                if (isdigit((unsigned char) valbuf[0])) {
538
15.3k
                    bool decimal = strchr(valbuf, '.') != NULL;
539
540
15.3k
                    if (decimal &&
541
850
                        seeking == t_real) {
542
216
                        break;
543
216
                    }
544
15.1k
                    if (!decimal && (seeking == t_byte ||
545
14.2k
                                     seeking == t_ubyte ||
546
13.8k
                                     seeking == t_integer ||
547
12.7k
                                     seeking == t_uinteger ||
548
12.0k
                                     seeking == t_longint ||
549
12.0k
                                     seeking == t_ulongint ||
550
11.6k
                                     seeking == t_short ||
551
10.0k
                                     seeking == t_ushort))
552
4.46k
                        break;
553
15.1k
                }
554
24.9k
                if (NULL == cursor[1].attribute) {  // out of possibilities
555
16.6k
                    break;
556
16.6k
                }
557
8.26k
                if (0 != strcmp(cursor[1].attribute, attrbuf)) {
558
8.06k
                    break;
559
8.06k
                }
560
194
                ++cursor;
561
194
            }
562
34.7k
            if (value_quoted &&
563
9.38k
                (cursor->type != t_string &&
564
8.06k
                 cursor->type != t_character &&
565
7.84k
                 cursor->type != t_check &&
566
7.10k
                 cursor->type != t_time &&
567
4.53k
                 cursor->type != t_ignore &&
568
453
                 cursor->map == 0)) {
569
14
                json_debug_trace(1, "json: %s", "Saw quoted value when expecting"
570
14
                                  " non-string.\n");
571
14
                return JSON_ERR_QNONSTRING;
572
14
            }
573
34.7k
            if (!value_quoted &&
574
25.3k
                (cursor->type == t_string ||
575
25.3k
                 cursor->type == t_check ||
576
25.3k
                 cursor->type == t_time ||
577
25.3k
                 cursor->map != 0)) {
578
63
                json_debug_trace(1, "json: %s",
579
63
                                 "Didn't see quoted value when expecting"
580
63
                                 " string.\n");
581
63
                return JSON_ERR_NONQSTRING;
582
63
            }
583
34.7k
            if (cursor->map != 0) {
584
882
                for (mp = cursor->map; mp->name != NULL; mp++)
585
817
                    if (strcmp(mp->name, valbuf) == 0) {
586
374
                        goto foundit;
587
374
                    }
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
374
              foundit:
593
374
                (void)snprintf(valbuf, sizeof(valbuf), "%d", mp->value);
594
374
            }
595
34.6k
            if (cursor->type == t_check) {
596
743
                lptr = cursor->dflt.check;
597
33.8k
            } else {
598
33.8k
                lptr = json_target_address(cursor, parent, offset);
599
33.8k
            }
600
34.6k
            if (NULL != lptr) {
601
19.5k
                switch (cursor->type) {
602
366
                case t_byte:
603
366
                    {
604
366
                        int tmp = atoi(valbuf);
605
366
                        lptr[0] = (char)tmp;
606
366
                    }
607
366
                    break;
608
820
                case t_ubyte:
609
820
                    {
610
820
                        int tmp = atoi(valbuf);
611
820
                        lptr[0] = (unsigned char)tmp;
612
820
                    }
613
820
                    break;
614
1.69k
                case t_integer:
615
1.69k
                    {
616
1.69k
                        int tmp = atoi(valbuf);
617
1.69k
                        memcpy(lptr, &tmp, sizeof(int));
618
1.69k
                    }
619
1.69k
                    break;
620
977
                case t_uinteger:
621
977
                    {
622
977
                        unsigned int tmp = (unsigned int)atol(valbuf);
623
977
                        memcpy(lptr, &tmp, sizeof(unsigned int));
624
977
                    }
625
977
                    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
408
                case t_ulongint:
633
408
                    {
634
408
                        unsigned long tmp = (unsigned long)atoll(valbuf);
635
408
                        memcpy(lptr, &tmp, sizeof(unsigned long));
636
408
                    }
637
408
                    break;
638
1.58k
                case t_short:
639
1.58k
                    {
640
1.58k
                        short tmp = atoi(valbuf);
641
1.58k
                        memcpy(lptr, &tmp, sizeof(short));
642
1.58k
                    }
643
1.58k
                    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.56k
                case t_time:
651
2.56k
                    {
652
2.56k
                        timespec_t ts_tmp = iso8601_to_timespec(valbuf);
653
2.56k
                        memcpy(lptr, &ts_tmp, sizeof(timespec_t));
654
2.56k
                    }
655
2.56k
                    break;
656
390
                case t_timespec:
657
390
                    {
658
390
                        double sec_tmp = safe_atof(valbuf);
659
390
                        timespec_t ts_tmp;
660
390
                        if (0 != isfinite(sec_tmp)) {
661
196
                            DTOTS(&ts_tmp, sec_tmp);
662
196
                            memcpy(lptr, &ts_tmp, sizeof(timespec_t));
663
196
                        } // else leave at .dflt
664
390
                    }
665
390
                    break;
666
4.75k
                case t_real:
667
4.75k
                    {
668
4.75k
                        double tmp = safe_atof(valbuf);
669
4.75k
                        if (0 != isfinite(tmp)) {
670
3.72k
                            memcpy(lptr, &tmp, sizeof(double));
671
3.72k
                        } // else leave at .dflt
672
4.75k
                    }
673
4.75k
                    break;
674
1.32k
                case t_string:
675
1.32k
                    if (NULL != parent &&
676
267
                        parent->element_type != t_structobject &&
677
0
                        offset > 0) {
678
0
                        return JSON_ERR_NOPARSTR;
679
0
                    }
680
1.32k
                    (void)strlcpy(lptr, valbuf, cursor->len);
681
1.32k
                    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
583
                case t_character:
689
583
                    if (strnlen(valbuf, 2) > 1) {
690
                        // don't update end here, leave at value start
691
8
                        return JSON_ERR_STRLONG;
692
575
                    } else {
693
575
                        lptr[0] = valbuf[0];
694
575
                    }
695
575
                    break;
696
1.49k
                case t_ignore:  // silences a compiler warning
697
1.49k
                    FALLTHROUGH
698
1.49k
                case t_object:  // silences a compiler warning
699
1.49k
                    FALLTHROUGH
700
1.49k
                case t_structobject:
701
1.49k
                    FALLTHROUGH
702
1.49k
                case t_array:
703
1.49k
                    break;
704
743
                case t_check:
705
743
                    if (strcmp(cursor->dflt.check, valbuf) != 0) {
706
170
                        json_debug_trace(1, "json: Required attribute value %s"
707
170
                                          " not present.\n",
708
170
                                          cursor->dflt.check);
709
                        // don't update end here, leave at start of attribute
710
170
                        return JSON_ERR_CHECKFAIL;
711
170
                    }
712
573
                    break;
713
19.5k
                }
714
19.5k
            }
715
34.4k
            FALLTHROUGH
716
35.5k
        case post_element:
717
35.5k
            if (isspace((unsigned char) *cp)) {
718
448
                continue;
719
448
            }
720
35.0k
            if (*cp == ',') {
721
29.6k
                state = await_attr;
722
29.6k
            } else if (*cp == '}') {
723
4.66k
                ++cp;
724
4.66k
                goto good_parse;
725
4.66k
            } else {
726
715
                json_debug_trace(1, "json: %s",
727
715
                                "Garbage while expecting comma or }\n");
728
715
                if (NULL != end) {
729
25
                    *end = cp;
730
25
                }
731
715
                return JSON_ERR_BADTRAIL;
732
715
            }
733
29.6k
            break;
734
466k
        }
735
466k
    }
736
2.45k
    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.09k
  good_parse:
742
    // in case there's another object following, consume trailing WS
743
7.09k
    while (isspace((unsigned char)*cp)) {
744
200
        ++cp;
745
200
    }
746
7.09k
    if (NULL != end) {
747
4.31k
        *end = cp;
748
4.31k
    }
749
7.09k
    json_debug_trace(1, "%s", "json: JSON parse ends.\n");
750
7.09k
    return 0;
751
2.45k
}
752
753
int json_read_array(const char *cp, const struct json_array_t *arr,
754
                    const char **end)
755
889
{
756
889
    int substatus, offset, arrcount;
757
889
    char *tp;
758
759
889
    if (NULL != end)
760
889
        *end = NULL;    // give it a well-defined value on parse failure
761
762
889
    json_debug_trace(1, "json: %s", "Entered json_read_array()\n");
763
764
889
    while (isspace((unsigned char)*cp)) {
765
0
        cp++;
766
0
    }
767
889
    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
889
    cp++;
772
773
889
    tp = arr->arr.strings.store;
774
889
    arrcount = 0;
775
776
    // Check for empty array
777
889
    while (isspace((unsigned char)*cp)) {
778
254
        cp++;
779
254
    }
780
889
    if (*cp == ']') {
781
219
        goto breakout;
782
219
    }
783
784
7.48k
    for (offset = 0; offset < arr->maxlen; offset++) {
785
7.47k
        char *ep = NULL;
786
787
7.47k
        json_debug_trace(1, "json: Looking at %s\n", cp);
788
7.47k
        switch (arr->element_type) {
789
3.05k
        case t_string:
790
3.05k
            if (isspace((unsigned char) *cp)) {
791
216
                cp++;
792
216
            }
793
3.05k
            if (*cp != '"') {
794
14
                return JSON_ERR_BADSTRING;
795
3.04k
            } else {
796
3.04k
                ++cp;
797
3.04k
            }
798
3.04k
            arr->arr.strings.ptrs[offset] = tp;
799
9.97k
            for (; tp - arr->arr.strings.store < arr->arr.strings.storelen;
800
6.93k
                 tp++)
801
9.97k
                if (*cp == '"') {
802
3.03k
                    ++cp;
803
3.03k
                    *tp++ = '\0';
804
3.03k
                    goto stringend;
805
6.93k
                } else if (*cp == '\0') {
806
1
                    json_debug_trace(1, "json: %s",
807
1
                                      "Bad string syntax in string list.\n");
808
1
                    return JSON_ERR_BADSTRING;
809
6.93k
                } else {
810
6.93k
                    *tp = *cp++;
811
6.93k
                }
812
2
            json_debug_trace(1, "json: %s",
813
2
                             "Bad string syntax in string list.\n");
814
2
            return JSON_ERR_BADSTRING;
815
3.03k
          stringend:
816
3.03k
            break;
817
0
        case t_object:
818
0
            FALLTHROUGH
819
4.42k
        case t_structobject:
820
4.42k
            substatus =
821
4.42k
                json_internal_read_object(cp, arr->arr.objects.subtype, arr,
822
4.42k
                                          offset, &cp);
823
4.42k
            if (substatus != 0) {
824
106
                if (NULL != end) {
825
106
                    *end = cp;
826
106
                }
827
106
                return substatus;
828
106
            }
829
4.31k
            break;
830
4.31k
        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.47k
        }
939
7.35k
        arrcount++;
940
7.35k
        if (isspace((unsigned char)*cp)) {
941
220
            cp++;
942
220
        }
943
7.35k
        if (*cp == ']') {
944
435
            json_debug_trace(1, "json: %s", "End of array found.\n");
945
435
            goto breakout;
946
435
        }
947
6.92k
        if (*cp == ',') {
948
6.81k
            cp++;
949
6.81k
        } else {
950
111
            json_debug_trace(1, "json: %s", "Bad trailing syntax on array.\n");
951
111
            return JSON_ERR_BADSUBTRAIL;
952
111
        }
953
6.92k
    }
954
1
    json_debug_trace(1, "json: %s", "Too many elements in array.\n");
955
1
    if (NULL != end) {
956
1
        *end = cp;
957
1
    }
958
1
    return JSON_ERR_SUBTOOLONG;
959
654
  breakout:
960
654
    if (NULL != arr->count) {
961
654
        *(arr->count) = arrcount;
962
654
    }
963
654
    if (NULL != end) {
964
654
        *end = cp;
965
654
    }
966
654
    json_debug_trace(1, "json: leaving json_read_array() with %d elements\n",
967
654
                      arrcount);
968
654
    return 0;
969
670
}
970
971
int json_read_object(const char *cp, const struct json_attr_t *attrs,
972
                     const char **end)
973
4.73k
{
974
4.73k
    int st;
975
976
4.73k
    json_debug_trace(1, "json: json_read_object() sees '%s'\n", cp);
977
4.73k
    st = json_internal_read_object(cp, attrs, NULL, 0, end);
978
4.73k
    return st;
979
4.73k
}
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