"Initial commit to Gerrit"
[profile/ivi/gpsd.git] / json.c
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 succeds, 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 dialect this parses has some limitations.  First, it cannot
24 recognize the JSON "null" value.  Secondly, arrays may only have
25 objects or strings - not reals or integers or floats - as elements
26 (this limitation could be easily removed if required). Third, all
27 elements of an array must be of the same type.
28
29    There are separata entry points for beginning a parse of either
30 JSON object or a JSON array. JSON "float" quantities are actually
31 stored as doubles.
32
33    This parser processes object arrays in one of two different ways,
34 defending on whether the array subtype is declared as object or
35 structobject.
36
37    Object arrays take one base address per object subfield, and are 
38 mapped into parallel C arrays (one per subfield).  Strings are not
39 supported in this kind of array, as the don't have a "natural" size
40 to use as an offset multiplier.
41
42    Structobjects arrays are a way to parse a list of objects to a set
43 of modifications to a corresponding array of C structs.  The trick is
44 that the array object initialization has to specify both the C struct
45 array's base address and the stride length (the size of the C struct).
46 If you initialize the offset fields with the correct offsetof() calls,
47 everything will work. Strings are suppported but all string storage
48 has to be inline in the struct.
49
50 PERMISSIONS
51    This file is Copyright (c) 2010 by the GPSD project
52    BSD terms apply: see the file COPYING in the distribution root for details.
53
54 ***************************************************************************/
55 #include <stdio.h>
56 #include <string.h>
57 #include <stdlib.h>
58 #include <stdarg.h>
59
60 #include "gpsd_config.h"        /* for strlcpy() prototype */
61 #include "json.h"
62
63 #ifdef CLIENTDEBUG_ENABLE
64 static int debuglevel = 0;
65 static FILE *debugfp;
66
67 void json_enable_debug(int level, FILE * fp)
68 /* control the level and destination of debug trace messages */
69 {
70     debuglevel = level;
71     debugfp = fp;
72 }
73
74 static void json_trace(int errlevel, const char *fmt, ...)
75 /* assemble command in printf(3) style */
76 {
77     if (errlevel <= debuglevel) {
78         char buf[BUFSIZ];
79         va_list ap;
80
81         (void)strlcpy(buf, "json: ", BUFSIZ);
82         va_start(ap, fmt);
83         (void)vsnprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), fmt,
84                         ap);
85         va_end(ap);
86
87         (void)fputs(buf, debugfp);
88     }
89 }
90
91 # define json_debug_trace(args) (void) json_trace args
92 #else
93 # define json_debug_trace(args) /*@i1@*/do { } while (0)
94 #endif /* CLIENTDEBUG_ENABLE */
95
96 /*@-immediatetrans -dependenttrans -usereleased -compdef@*/
97 static /*@null@*/ char *json_target_address(const struct json_attr_t *cursor,
98                                              /*@null@*/
99                                              const struct json_array_t
100                                              *parent, int offset)
101 {
102     char *targetaddr = NULL;
103     if (parent == NULL || parent->element_type != t_structobject) {
104         /* ordinary case - use the address in the cursor structure */
105         switch (cursor->type) {
106         case t_integer:
107             targetaddr = (char *)&cursor->addr.integer[offset];
108             break;
109         case t_uinteger:
110             targetaddr = (char *)&cursor->addr.uinteger[offset];
111             break;
112         case t_real:
113             targetaddr = (char *)&cursor->addr.real[offset];
114             break;
115         case t_string:
116             targetaddr = cursor->addr.string;
117             break;
118         case t_boolean:
119             targetaddr = (char *)&cursor->addr.boolean[offset];
120             break;
121         case t_character:
122             targetaddr = (char *)&cursor->addr.character[offset];
123             break;
124         default:
125             targetaddr = NULL;
126             break;
127         }
128     } else
129         /* tricky case - hacking a member in an array of structures */
130         targetaddr =
131             parent->arr.objects.base + (offset * parent->arr.objects.stride) +
132             cursor->addr.offset;
133     json_debug_trace((1, "Target address for %s (offset %d) is %p\n",
134                       cursor->attribute, offset, targetaddr));
135     return targetaddr;
136 }
137
138 /*@-immediatetrans -dependenttrans +usereleased +compdef@*/
139
140 static int json_internal_read_object(const char *cp,
141                                      const struct json_attr_t *attrs,
142                                      /*@null@*/
143                                      const struct json_array_t *parent,
144                                      int offset,
145                                      /*@null@*/ const char **end)
146 {
147     /*@ -nullstate -nullderef -mustfreefresh -nullpass -usedef @*/
148     enum
149     { init, await_attr, in_attr, await_value, in_val_string,
150         in_escape, in_val_token, post_val, post_array
151     } state = 0;
152 #ifdef CLIENTDEBUG_ENABLE
153     char *statenames[] = {
154         "init", "await_attr", "in_attr", "await_value", "in_val_string",
155         "in_escape", "in_val_token", "post_val", "post_array",
156     };
157 #endif /* CLIENTDEBUG_ENABLE */
158     char attrbuf[JSON_ATTR_MAX + 1], *pattr = NULL;
159     char valbuf[JSON_VAL_MAX + 1], *pval = NULL;
160     bool value_quoted = false;
161     char uescape[5];            /* enough space for 4 hex digits and a NUL */
162     const struct json_attr_t *cursor;
163     int substatus, n, maxlen = 0;
164     unsigned int u;
165     const struct json_enum_t *mp;
166     char *lptr;
167
168 #ifdef S_SPLINT_S
169     /* prevents gripes about buffers not being completely defined */
170     memset(valbuf, '\0', sizeof(valbuf));
171     memset(attrbuf, '\0', sizeof(attrbuf));
172 #endif /* S_SPLINT_S */
173
174     if (end != NULL)
175         *end = NULL;            /* give it a well-defined value on parse failure */
176
177     /* stuff fields with defaults in case they're omitted in the JSON input */
178     for (cursor = attrs; cursor->attribute != NULL; cursor++)
179         if (!cursor->nodefault) {
180             lptr = json_target_address(cursor, parent, offset);
181             if (lptr != NULL)
182                 switch (cursor->type) {
183                 case t_integer:
184                     *((int *)lptr) = cursor->dflt.integer;
185                     break;
186                 case t_uinteger:
187                     *((unsigned int *)lptr) = cursor->dflt.uinteger;
188                     break;
189                 case t_real:
190                     *((double *)lptr) = cursor->dflt.real;
191                     break;
192                 case t_string:
193                     if (parent != NULL
194                         && parent->element_type != t_structobject
195                         && offset > 0)
196                         return JSON_ERR_NOPARSTR;
197                     lptr[0] = '\0';
198                     break;
199                 case t_boolean:
200                     /* nullbool default says not to set the value at all */
201                     /*@+boolint@*/
202                     if (cursor->dflt.boolean != nullbool)
203                         *((bool *) lptr) = cursor->dflt.boolean;
204                     /*@-boolint@*/
205                     break;
206                 case t_character:
207                     lptr[0] = cursor->dflt.character;
208                     break;
209                 case t_object:  /* silences a compiler warning */
210                 case t_structobject:
211                 case t_array:
212                 case t_check:
213                     break;
214                 }
215         }
216
217     json_debug_trace((1, "JSON parse of '%s' begins.\n", cp));
218
219     /* parse input JSON */
220     for (; *cp != '\0'; cp++) {
221         json_debug_trace((2, "State %-14s, looking at '%c' (%p)\n",
222                           statenames[state], *cp, cp));
223         switch (state) {
224         case init:
225             if (isspace(*cp))
226                 continue;
227             else if (*cp == '{')
228                 state = await_attr;
229             else {
230                 json_debug_trace((1,
231                                   "Non-WS when expecting object start.\n"));
232                 return JSON_ERR_OBSTART;
233             }
234             break;
235         case await_attr:
236             if (isspace(*cp))
237                 continue;
238             else if (*cp == '"') {
239                 state = in_attr;
240                 pattr = attrbuf;
241             } else if (*cp == '}')
242                 break;
243             else {
244                 json_debug_trace((1, "Non-WS when expecting attribute.\n"));
245                 return JSON_ERR_ATTRSTART;
246             }
247             break;
248         case in_attr:
249             if (*cp == '"') {
250                 *pattr++ = '\0';
251                 json_debug_trace((1, "Collected attribute name %s\n",
252                                   attrbuf));
253                 for (cursor = attrs; cursor->attribute != NULL; cursor++) {
254                     json_debug_trace((2, "Checking against %s\n",
255                                       cursor->attribute));
256                     if (strcmp(cursor->attribute, attrbuf) == 0)
257                         break;
258                 }
259                 if (cursor->attribute == NULL) {
260                     json_debug_trace((1,
261                                       "Unknown attribute name '%s' (attributes begin with '%s').\n",
262                                       attrbuf, attrs->attribute));
263                     return JSON_ERR_BADATTR;
264                 }
265                 state = await_value;
266                 if (cursor->type == t_string)
267                     maxlen = (int)cursor->len - 1;
268                 else if (cursor->type == t_check)
269                     maxlen = (int)strlen(cursor->dflt.check);
270                 else if (cursor->map != NULL)
271                     maxlen = (int)sizeof(valbuf) - 1;
272                 pval = valbuf;
273             } else if (pattr >= attrbuf + JSON_ATTR_MAX - 1) {
274                 json_debug_trace((1, "Attribute name too long.\n"));
275                 return JSON_ERR_ATTRLEN;
276             } else
277                 *pattr++ = *cp;
278             break;
279         case await_value:
280             if (isspace(*cp) || *cp == ':')
281                 continue;
282             else if (*cp == '[') {
283                 if (cursor->type != t_array) {
284                     json_debug_trace((1,
285                                       "Saw [ when not expecting array.\n"));
286                     return JSON_ERR_NOARRAY;
287                 }
288                 substatus = json_read_array(cp, &cursor->addr.array, &cp);
289                 if (substatus != 0)
290                     return substatus;
291                 state = post_array;
292             } else if (cursor->type == t_array) {
293                 json_debug_trace((1,
294                                   "Array element was specified, but no [.\n"));
295                 return JSON_ERR_NOBRAK;
296             } else if (*cp == '"') {
297                 value_quoted = true;
298                 state = in_val_string;
299                 pval = valbuf;
300             } else {
301                 value_quoted = false;
302                 state = in_val_token;
303                 pval = valbuf;
304                 *pval++ = *cp;
305             }
306             break;
307         case in_val_string:
308             if (*cp == '\\')
309                 state = in_escape;
310             else if (*cp == '"') {
311                 *pval++ = '\0';
312                 json_debug_trace((1, "Collected string value %s\n", valbuf));
313                 state = post_val;
314             } else if (pval > valbuf + JSON_VAL_MAX - 1
315                        || pval > valbuf + maxlen) {
316                 json_debug_trace((1, "String value too long.\n"));
317                 return JSON_ERR_STRLONG;        /*  */
318             } else
319                 *pval++ = *cp;
320             break;
321         case in_escape:
322             switch (*cp) {
323             case 'b':
324                 *pval++ = '\b';
325                 break;
326             case 'f':
327                 *pval++ = '\f';
328                 break;
329             case 'n':
330                 *pval++ = '\n';
331                 break;
332             case 'r':
333                 *pval++ = '\r';
334                 break;
335             case 't':
336                 *pval++ = '\t';
337                 break;
338             case 'u':
339                 for (n = 0; n < 4 && cp[n] != '\0'; n++)
340                     uescape[n] = *cp++;
341                 --cp;
342                 (void)sscanf(uescape, "%04x", &u);
343                 *pval++ = (char)u;      /* will truncate values above 0xff */
344                 break;
345             default:            /* handles double quote and solidus */
346                 *pval++ = *cp;
347                 break;
348             }
349             state = in_val_string;
350             break;
351         case in_val_token:
352             if (isspace(*cp) || *cp == ',' || *cp == '}') {
353                 *pval = '\0';
354                 json_debug_trace((1, "Collected token value %s.\n", valbuf));
355                 state = post_val;
356                 if (*cp == '}' || *cp == ',')
357                     --cp;
358             } else if (pval > valbuf + JSON_VAL_MAX - 1) {
359                 json_debug_trace((1, "Token value too long.\n"));
360                 return JSON_ERR_TOKLONG;
361             } else
362                 *pval++ = *cp;
363             break;
364         case post_val:
365             if (value_quoted
366                 && (cursor->type != t_string && cursor->type != t_character
367                     && cursor->type != t_check && cursor->map == 0)) {
368                 json_debug_trace((1,
369                                   "Saw quoted value when expecting non-string.\n"));
370                 return JSON_ERR_QNONSTRING;
371             }
372             if (!value_quoted
373                 && (cursor->type == t_string || cursor->type == t_check
374                     || cursor->map != 0)) {
375                 json_debug_trace((1,
376                                   "Didn't see quoted value when expecting string.\n"));
377                 return JSON_ERR_NONQSTRING;
378             }
379             if (cursor->map != 0) {
380                 for (mp = cursor->map; mp->name != NULL; mp++)
381                     if (strcmp(mp->name, valbuf) == 0) {
382                         goto foundit;
383                     }
384                 json_debug_trace((1, "Invalid enumerated value string %s.\n",
385                                   valbuf));
386                 return JSON_ERR_BADENUM;
387               foundit:
388                 (void)snprintf(valbuf, sizeof(valbuf), "%d", mp->value);
389             }
390             lptr = json_target_address(cursor, parent, offset);
391             if (lptr != NULL)
392                 switch (cursor->type) {
393                 case t_integer:
394                     *((int *)lptr) = atoi(valbuf);
395                     break;
396                 case t_uinteger:
397                     *((unsigned int *)lptr) = (unsigned)atoi(valbuf);
398                     break;
399                 case t_real:
400                     *((double *)lptr) = atof(valbuf);
401                     break;
402                 case t_string:
403                     if (parent != NULL
404                         && parent->element_type != t_structobject
405                         && offset > 0)
406                         return JSON_ERR_NOPARSTR;
407                     (void)strncpy(lptr, valbuf, cursor->len);
408                     break;
409                 case t_boolean:
410                     *((bool *) lptr) = (strcmp(valbuf, "true") == 0);
411                     break;
412                 case t_character:
413                     if (strlen(valbuf) > 1)
414                         return JSON_ERR_STRLONG;
415                     else
416                         lptr[0] = valbuf[0];
417                     break;
418                 case t_object:  /* silences a compiler warning */
419                 case t_structobject:
420                 case t_array:
421                     break;
422                 case t_check:
423                     if (strcmp(cursor->dflt.check, valbuf) != 0) {
424                         json_debug_trace((1,
425                                           "Required attribute vakue %s not present.\n",
426                                           cursor->dflt.check));
427                         return JSON_ERR_CHECKFAIL;
428                     }
429                     break;
430                 }
431             /*@fallthrough@*/
432         case post_array:
433             if (isspace(*cp))
434                 continue;
435             else if (*cp == ',')
436                 state = await_attr;
437             else if (*cp == '}') {
438                 ++cp;
439                 goto good_parse;
440             } else {
441                 json_debug_trace((1, "Garbage while expecting comma or }\n"));
442                 return JSON_ERR_BADTRAIL;
443             }
444             break;
445         }
446     }
447
448   good_parse:
449     /* in case there's another object following, consune trailing WS */
450     while (isspace(*cp))
451         ++cp;
452     if (end != NULL)
453         *end = cp;
454     json_debug_trace((1, "JSON parse ends.\n"));
455     return 0;
456     /*@ +nullstate +nullderef +mustfreefresh +nullpass +usedef @*/
457 }
458
459 int json_read_array(const char *cp, const struct json_array_t *arr,
460                     const char **end)
461 {
462     /*@-nullstate -onlytrans@*/
463     int substatus, offset;
464     char *tp;
465
466     if (end != NULL)
467         *end = NULL;            /* give it a well-defined value on parse failure */
468
469     json_debug_trace((1, "Entered json_read_array()\n"));
470
471     while (isspace(*cp))
472         cp++;
473     if (*cp != '[') {
474         json_debug_trace((1, "Didn't find expected array start\n"));
475         return JSON_ERR_ARRAYSTART;
476     } else
477         cp++;
478
479     tp = arr->arr.strings.store;
480     if (arr->count != NULL)
481         *(arr->count) = 0;
482     for (offset = 0; offset < arr->maxlen; offset++) {
483         json_debug_trace((1, "Looking at %s\n", cp));
484         switch (arr->element_type) {
485         case t_string:
486             if (isspace(*cp))
487                 cp++;
488             if (*cp != '"')
489                 return JSON_ERR_BADSTRING;
490             else
491                 ++cp;
492             arr->arr.strings.ptrs[offset] = tp;
493             for (; tp - arr->arr.strings.store < arr->arr.strings.storelen;
494                  tp++)
495                 if (*cp == '"') {
496                     ++cp;
497                     *tp++ = '\0';
498                     goto stringend;
499                 } else if (*cp == '\0') {
500                     json_debug_trace((1,
501                                       "Bad string syntax in string list.\n"));
502                     return JSON_ERR_BADSTRING;
503                 } else {
504                     *tp = *cp++;
505                 }
506             json_debug_trace((1, "Bad string syntax in string list.\n"));
507             return JSON_ERR_BADSTRING;
508           stringend:
509             break;
510         case t_object:
511         case t_structobject:
512             substatus =
513                 json_internal_read_object(cp, arr->arr.objects.subtype, arr,
514                                           offset, &cp);
515             if (substatus != 0)
516                 return substatus;
517             break;
518         case t_integer:
519         case t_uinteger:
520         case t_real:
521         case t_boolean:
522         case t_character:
523         case t_array:
524         case t_check:
525             json_debug_trace((1, "Invalid array subtype.\n"));
526             return JSON_ERR_SUBTYPE;
527         }
528         if (arr->count != NULL)
529             (*arr->count)++;
530         if (isspace(*cp))
531             cp++;
532         if (*cp == ']') {
533             json_debug_trace((1, "End of array found.\n"));
534             goto breakout;
535         } else if (*cp == ',')
536             cp++;
537         else {
538             json_debug_trace((1, "Bad trailing syntax on array.\n"));
539             return JSON_ERR_BADSUBTRAIL;
540         }
541     }
542     json_debug_trace((1, "Too many elements in array.\n"));
543     return JSON_ERR_SUBTOOLONG;
544   breakout:
545     if (end != NULL)
546         *end = cp;
547     /*@ -nullderef @*/
548     json_debug_trace((1, "leaving json_read_array() with %d elements\n",
549                       *arr->count));
550     /*@ +nullderef @*/
551     return 0;
552     /*@+nullstate +onlytrans@*/
553 }
554
555 int json_read_object(const char *cp, const struct json_attr_t *attrs,
556                      /*@null@*/ const char **end)
557 {
558     json_debug_trace((1, "json_read_object() sees '%s'\n", cp));
559     return json_internal_read_object(cp, attrs, NULL, 0, end);
560 }
561
562 const /*@observer@*/ char *json_error_string(int err)
563 {
564     const char *errors[] = {
565         "unknown error while parsing JSON",
566         "non-whitespace when expecting object start",
567         "non-whitespace when expecting attribute start",
568         "unknown attribute name",
569         "attribute name too long",
570         "saw [ when not expecting array",
571         "array element specified, but no [",
572         "string value too long",
573         "token value too long",
574         "garbage while expecting , or }",
575         "didn't find expected array start",
576         "error while parsing object array",
577         "too many array elements",
578         "garbage while expecting array comma",
579         "unsupported array element type",
580         "error while string parsing",
581         "check attribute not matched",
582         "can't support strings in parallel arrays",
583         "invalid enumerated value",
584         "saw quoted value when expecting nonstring",
585         "didn't see quoted value when expecting string",
586         "other data conversion error",
587     };
588
589     if (err <= 0 || err >= (int)(sizeof(errors) / sizeof(errors[0])))
590         return errors[0];
591     else
592         return errors[err];
593 }