1    | /*
2    |  * Copyright (c) 2010-2011  Florian Forster  <ff at octo.it>
3    |  *
4    |  * Permission to use, copy, modify, and/or distribute this software for any
5    |  * purpose with or without fee is hereby granted, provided that the above
6    |  * copyright notice and this permission notice appear in all copies.
7    |  *
8    |  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9    |  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10   |  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11   |  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12   |  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13   |  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14   |  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15   |  */
16   | 
17   | /**
18   |  * Parses JSON data and returns the data in tree form.
19   |  *
20   |  * Writtan by Florian Forster
21   |  *
22   |  * August 2010
23   |  *
24   |  * This interface makes quick parsing and extraction of smallish JSON docs
25   |  * trivial, as shown in the following example:
26   |  *
27   |  * +html+ <a href="../example/parse_config.c.html#file">example/parse_config.c</a><br>
28   |  **/
29   | 
30   | #include <stdint.h>
31   | #include <stdio.h>
32   | #include <string.h>
33   | #include <stdlib.h>
34   | #include <errno.h>
35   | #include <assert.h>
36   | 
37   | #include "yajl/yajl_tree.h"
38   | #include "yajl/yajl_parse.h"
39   | 
40   | #include "yajl_parser.h"
41   | 
42   | #if defined(_WIN32) || defined(WIN32)
43   | #define snprintf sprintf_s
44   | #endif
45   | 
46   | #define STATUS_CONTINUE 1
47   | #define STATUS_ABORT    0
48   | 
49   | struct stack_elem_s;
50   | typedef struct stack_elem_s stack_elem_t;
51   | struct stack_elem_s
52   | {
53   |     char * key;
54   |     yajl_val value;
55   |     stack_elem_t *next;
56   | };
57   | 
58   | struct context_s
59   | {
60   |     stack_elem_t *stack;
61   |     yajl_val root;
62   |     char *errbuf;
63   |     size_t errbuf_size;
64   | };
65   | typedef struct context_s context_t;
66   | 
67   | #define RETURN_ERROR(ctx,retval,...) {                                  \
68   |         if ((ctx)->errbuf != NULL)                                      \
69   |             snprintf ((ctx)->errbuf, (ctx)->errbuf_size, __VA_ARGS__);  \
70   |         return (retval);                                                \
71   |     }
72   | 
73   | static yajl_val value_alloc (yajl_type type)
74   | {
75   |     yajl_val v;
76   | 
77   |     v = malloc (sizeof (*v));
78   |     if (v == NULL) return (NULL);
79   |     memset (v, 0, sizeof (*v));
80   |     v->type = type;
81   | 
82   |     return (v);
83   | }
84   | 
85   | static void yajl_object_free (yajl_val v)
86   | {
87   |     size_t i;
88   | 
89   |     if (!YAJL_IS_OBJECT(v)) return;
90   | 
91   |     for (i = 0; i < v->u.object.len; i++)
92   |     {
93   |         /* __UNCONST() */
94   |         free((void *)(uintmax_t)(const void *) v->u.object.keys[i]);
95   |         v->u.object.keys[i] = NULL;
96   |         yajl_tree_free (v->u.object.values[i]);
97   |         v->u.object.values[i] = NULL;
98   |     }
99   | 
100  |     free((void*) v->u.object.keys);
101  |     free(v->u.object.values);
102  |     free(v);
103  | }
104  | 
105  | static void yajl_array_free (yajl_val v)
106  | {
107  |     size_t i;
108  | 
109  |     if (!YAJL_IS_ARRAY(v)) return;
110  | 
111  |     for (i = 0; i < v->u.array.len; i++)
112  |     {
113  |         yajl_tree_free (v->u.array.values[i]);
114  |         v->u.array.values[i] = NULL;
115  |     }
116  | 
117  |     free(v->u.array.values);
118  |     free(v);
119  | }
120  | 
121  | /*
122  |  * Parsing nested objects and arrays is implemented using a stack. When a new
123  |  * object or array starts (a curly or a square opening bracket is read), an
124  |  * appropriate value is pushed on the stack. When the end of the object is
125  |  * reached (an appropriate closing bracket has been read), the value is popped
126  |  * off the stack and added to the enclosing object using "context_add_value".
127  |  */
128  | static int context_push(context_t *ctx, yajl_val v)
129  | {
130  |     stack_elem_t *stack;
131  | 
132  |     stack = malloc (sizeof (*stack));
133  |     if (stack == NULL)
134  |         RETURN_ERROR (ctx, ENOMEM, "Out of memory");
135  |     memset (stack, 0, sizeof (*stack));
136  | 
137  |     assert ((ctx->stack == NULL)
138  |             || YAJL_IS_OBJECT (v)
139  |             || YAJL_IS_ARRAY (v));
140  | 
141  |     stack->value = v;
142  |     stack->next = ctx->stack;
143  |     ctx->stack = stack;
144  | 
145  |     return (0);
146  | }
147  | 
148  | static yajl_val context_pop(context_t *ctx)
149  | {
150  |     stack_elem_t *stack;
151  |     yajl_val v;
152  | 
153  |     if (ctx->stack == NULL)
154  |         RETURN_ERROR (ctx, NULL, "context_pop: "
155  |                       "Bottom of stack reached prematurely");
156  | 
157  |     stack = ctx->stack;
158  |     ctx->stack = stack->next;
159  | 
160  |     v = stack->value;
161  | 
162  |     free (stack);
163  | 
164  |     return (v);
165  | }
166  | 
167  | static int object_add_keyval(context_t *ctx,
168  |                              yajl_val obj, char *key, yajl_val value)
169  | {
170  |     const char **tmpk;
171  |     yajl_val *tmpv;
172  | 
173  |     /* We're checking for NULL in "context_add_value" or its callers. */
174  |     assert (ctx != NULL);
175  |     assert (obj != NULL);
176  |     assert (key != NULL);
177  |     assert (value != NULL);
178  | 
179  |     /* We're assuring that "obj" is an object in "context_add_value". */
180  |     assert(YAJL_IS_OBJECT(obj));
181  | 
182  |     tmpk = realloc((void *) obj->u.object.keys, sizeof(*(obj->u.object.keys)) * (obj->u.object.len + 1));
183  |     if (tmpk == NULL)
184  |         RETURN_ERROR(ctx, ENOMEM, "Out of memory");
185  |     obj->u.object.keys = tmpk;
186  | 
187  |     tmpv = realloc(obj->u.object.values, sizeof (*obj->u.object.values) * (obj->u.object.len + 1));
188  |     if (tmpv == NULL)
189  |         RETURN_ERROR(ctx, ENOMEM, "Out of memory");
190  |     obj->u.object.values = tmpv;
191  | 
192  |     obj->u.object.keys[obj->u.object.len] = key;
193  |     obj->u.object.values[obj->u.object.len] = value;
194  |     obj->u.object.len++;
195  | 
196  |     return (0);
197  | }
198  | 
199  | static int array_add_value (context_t *ctx,
200  |                             yajl_val array, yajl_val value)
201  | {
202  |     yajl_val *tmp;
203  | 
204  |     /* We're checking for NULL pointers in "context_add_value" or its
205  |      * callers. */
206  |     assert (ctx != NULL);
207  |     assert (array != NULL);
208  |     assert (value != NULL);
209  | 
210  |     /* "context_add_value" will only call us with array values. */
211  |     assert(YAJL_IS_ARRAY(array));
212  | 
213  |     tmp = realloc(array->u.array.values,
214  |                   sizeof(*(array->u.array.values)) * (array->u.array.len + 1));
215  |     if (tmp == NULL)
216  |         RETURN_ERROR(ctx, ENOMEM, "Out of memory");
217  |     array->u.array.values = tmp;
218  |     array->u.array.values[array->u.array.len] = value;
219  |     array->u.array.len++;
220  | 
221  |     return 0;
222  | }
223  | 
224  | /*
225  |  * Add a value to the value on top of the stack or the "root" member in the
226  |  * context if the end of the parsing process is reached.
227  |  */
228  | static int context_add_value (context_t *ctx, yajl_val v)
229  | {
230  |     /* We're checking for NULL values in all the calling functions. */
231  |     assert (ctx != NULL);
232  |     assert (v != NULL);
233  | 
234  |     /*
235  |      * There are three valid states in which this function may be called:
236  |      *   - There is no value on the stack => This is the only value. This is the
237  |      *     last step done when parsing a document. We assign the value to the
238  |      *     "root" member and return.
239  |      *   - The value on the stack is an object. In this case store the key on the
240  |      *     stack or, if the key has already been read, add key and value to the
241  |      *     object.
242  |      *   - The value on the stack is an array. In this case simply add the value
243  |      *     and return.
244  |      */
245  |     if (ctx->stack == NULL)
246  |     {
247  |         assert (ctx->root == NULL);
248  |         ctx->root = v;
249  |         return (0);
250  |     }
251  |     else if (YAJL_IS_OBJECT (ctx->stack->value))
252  |     {
253  |         if (ctx->stack->key == NULL)
254  |         {
255  |             if (!YAJL_IS_STRING (v))
256  |                 RETURN_ERROR (ctx, EINVAL, "context_add_value: "
257  |                               "Object key is not a string (%#04x)",
258  |                               v->type);
259  | 
260  |             ctx->stack->key = v->u.string;
261  |             v->u.string = NULL;
262  |             free(v);
263  |             return (0);
264  |         }
265  |         else /* if (ctx->key != NULL) */
266  |         {
267  |             char * key;
268  | 
269  |             key = ctx->stack->key;
270  |             ctx->stack->key = NULL;
271  |             return (object_add_keyval (ctx, ctx->stack->value, key, v));
272  |         }
273  |     }
274  |     else if (YAJL_IS_ARRAY (ctx->stack->value))
275  |     {
276  |         return (array_add_value (ctx, ctx->stack->value, v));
277  |     }
278  |     else
279  |     {
280  |         RETURN_ERROR (ctx, EINVAL, "context_add_value: Cannot add value to "
281  |                       "a value of type %#04x (not a composite type)",
282  |                       ctx->stack->value->type);
283  |     }
284  | }
285  | 
286  | static int handle_string (void *ctx,
287  |                           const unsigned char *string, size_t string_length)
288  | {
289  |     yajl_val v;
290  | 
291  |     v = value_alloc (yajl_t_string);
292  |     if (v == NULL)
293  |         RETURN_ERROR ((context_t *) ctx, STATUS_ABORT, "Out of memory");
294  | 
295  |     v->u.string = malloc (string_length + 1);
296  |     if (v->u.string == NULL)
297  |     {
298  |         free (v);
299  |         RETURN_ERROR ((context_t *) ctx, STATUS_ABORT, "Out of memory");
300  |     }
301  |     memcpy(v->u.string, string, string_length);
302  |     v->u.string[string_length] = 0;
303  | 
304  |     return ((context_add_value (ctx, v) == 0) ? STATUS_CONTINUE : STATUS_ABORT);
305  | }
306  | 
307  | static int handle_number (void *ctx, const char *string, size_t string_length)
308  | {
309  |     yajl_val v;
310  |     char *endptr;
311  | 
312  |     v = value_alloc(yajl_t_number);
313  |     if (v == NULL)
314  |         RETURN_ERROR((context_t *) ctx, STATUS_ABORT, "Out of memory");
315  | 
316  |     v->u.number.r = malloc(string_length + 1);
317  |     if (v->u.number.r == NULL)
318  |     {
319  |         free(v);
320  |         RETURN_ERROR((context_t *) ctx, STATUS_ABORT, "Out of memory");
321  |     }
322  |     memcpy(v->u.number.r, string, string_length);
323  |     v->u.number.r[string_length] = 0;
324  | 
325  |     v->u.number.flags = 0;
326  | 
327  |     errno = 0;
328  |     v->u.number.i = yajl_parse_integer((const unsigned char *) v->u.number.r,
329  |                                        strlen(v->u.number.r));
330  |     if (errno == 0)
331  |         v->u.number.flags |= YAJL_NUMBER_INT_VALID;
332  | 
333  |     endptr = NULL;
334  |     errno = 0;
335  |     v->u.number.d = strtod(v->u.number.r, &endptr);
336  |     if ((errno == 0) && (endptr != NULL) && (*endptr == 0))
337  |         v->u.number.flags |= YAJL_NUMBER_DOUBLE_VALID;
338  | 
339  |     return ((context_add_value(ctx, v) == 0) ? STATUS_CONTINUE : STATUS_ABORT);
340  | }
341  | 
342  | static int handle_start_map (void *ctx)
343  | {
344  |     yajl_val v;
345  | 
346  |     v = value_alloc(yajl_t_object);
347  |     if (v == NULL)
348  |         RETURN_ERROR ((context_t *) ctx, STATUS_ABORT, "Out of memory");
349  | 
350  |     v->u.object.keys = NULL;
351  |     v->u.object.values = NULL;
352  |     v->u.object.len = 0;
353  | 
354  |     return ((context_push (ctx, v) == 0) ? STATUS_CONTINUE : STATUS_ABORT);
355  | }
356  | 
357  | static int handle_end_map (void *ctx)
358  | {
359  |     yajl_val v;
360  | 
361  |     v = context_pop (ctx);
362  |     if (v == NULL)
363  |         return (STATUS_ABORT);
364  | 
365  |     return ((context_add_value (ctx, v) == 0) ? STATUS_CONTINUE : STATUS_ABORT);
366  | }
367  | 
368  | static int handle_start_array (void *ctx)
369  | {
370  |     yajl_val v;
371  | 
372  |     v = value_alloc(yajl_t_array);
373  |     if (v == NULL)
374  |         RETURN_ERROR ((context_t *) ctx, STATUS_ABORT, "Out of memory");
375  | 
376  |     v->u.array.values = NULL;
377  |     v->u.array.len = 0;
378  | 
379  |     return ((context_push (ctx, v) == 0) ? STATUS_CONTINUE : STATUS_ABORT);
380  | }
381  | 
382  | static int handle_end_array (void *ctx)
383  | {
384  |     yajl_val v;
385  | 
386  |     v = context_pop (ctx);
387  |     if (v == NULL)
388  |         return (STATUS_ABORT);
389  | 
390  |     return ((context_add_value (ctx, v) == 0) ? STATUS_CONTINUE : STATUS_ABORT);
391  | }
392  | 
393  | static int handle_boolean (void *ctx, int boolean_value)
394  | {
395  |     yajl_val v;
396  | 
397  |     v = value_alloc (boolean_value ? yajl_t_true : yajl_t_false);
398  |     if (v == NULL)
399  |         RETURN_ERROR ((context_t *) ctx, STATUS_ABORT, "Out of memory");
400  | 
401  |     return ((context_add_value (ctx, v) == 0) ? STATUS_CONTINUE : STATUS_ABORT);
402  | }
403  | 
404  | static int handle_null (void *ctx)
405  | {
406  |     yajl_val v;
407  | 
408  |     v = value_alloc (yajl_t_null);
409  |     if (v == NULL)
410  |         RETURN_ERROR ((context_t *) ctx, STATUS_ABORT, "Out of memory");
411  | 
412  |     return ((context_add_value (ctx, v) == 0) ? STATUS_CONTINUE : STATUS_ABORT);
413  | }
414  | 
415  | /*
416  |  * Public functions
417  |  */
418  | /*+
419  |  * Parse a string.
420  |  *
421  |  * Parses a null-terminated string containing JSON data.
422  |  *
423  |  * Returns a pointer to a yajl_val object which is the top-level value (root of
424  |  * the parse tree) or NULL on error.
425  |  *
426  |  * The memory pointed to must be freed using yajl_tree_free().  In case of an
427  |  * error, a null terminated message describing the error in more detail is
428  |  * stored in error_buffer if it is not NULL.
429  |  +*/
430  | yajl_val yajl_tree_parse (const char *input, /*+ Pointer to a null-terminated
431  |                                               *  utf8 string containing JSON
432  |                                               *  data. +*/
433  |                           char *error_buffer, /*+ Pointer to a buffer in which
434  |                                                * an error message will be stored
435  |                                                * if yajl_tree_parse() fails, or
436  |                                                * NULL. The buffer will be
437  |                                                * initialized before parsing, so
438  |                                                * its content will be destroyed
439  |                                                * even if yajl_tree_parse()
440  |                                                * succeeds. +*/
441  |                           size_t error_buffer_size) /*+ Size of the memory area
442  |                                                      * pointed to by
443  |                                                      * error_buffer_size.  If
444  |                                                      * error_buffer_size is
445  |                                                      * NULL, this argument is
446  |                                                      * ignored. +*/
447  | {
448  |     /* pointers to parsing callbacks */
449  |     static const yajl_callbacks callbacks =
450  |         {
451  |             /* null        = */ handle_null,
452  |             /* boolean     = */ handle_boolean,
453  |             /* integer     = */ NULL,
454  |             /* double      = */ NULL,
455  |             /* number      = */ handle_number,
456  |             /* string      = */ handle_string,
457  |             /* start map   = */ handle_start_map,
458  |             /* map key     = */ handle_string,
459  |             /* end map     = */ handle_end_map,
460  |             /* start array = */ handle_start_array,
461  |             /* end array   = */ handle_end_array
462  |         };
463  | 
464  |     yajl_handle handle;
465  |     yajl_status status;
466  |     char * internal_err_str;
467  | 	context_t ctx = { NULL, NULL, NULL, 0 };
468  | 
469  | 	ctx.errbuf = error_buffer;
470  | 	ctx.errbuf_size = error_buffer_size;
471  | 
472  |     if (error_buffer != NULL)
473  |         memset (error_buffer, 0, error_buffer_size);
474  | 
475  |     handle = yajl_alloc (&callbacks, NULL, &ctx);
476  |     yajl_config(handle, yajl_allow_comments, 1);
477  | 
478  |     status = yajl_parse(handle,
479  |                         (const unsigned char *) input,
480  |                         strlen (input));
481  |     if (status != yajl_status_ok) {
482  |         if (error_buffer != NULL && error_buffer_size > 0) {
483  |                internal_err_str = (char *) yajl_get_error(handle, 1,
484  |                      (const unsigned char *) input,
485  |                      strlen(input));
486  |              snprintf(error_buffer, error_buffer_size, "%s", internal_err_str);
487  |              YA_FREE(&(handle->alloc), internal_err_str);
488  |         }
489  |         while (ctx.stack) {
490  |             yajl_tree_free(context_pop(&ctx));
491  |         }
492  |         yajl_free (handle);
493  |         return NULL;
494  |     }
495  |     yajl_complete_parse (handle);
496  | 
497  |     yajl_free (handle);
498  |     return (ctx.root);
499  | }
500  | 
501  | /*+
502  |  * Access a nested value inside a tree.
503  |  *
504  |  * Returns a pointer to the found value, or NULL if we came up empty.
505  |  +*/
506  | /*
507  |  * Future Ideas:  it'd be nice to move path to a string and implement support for
508  |  * a teeny tiny micro language here, so you can extract array elements, do things
509  |  * like .first and .last, even .length.  Inspiration from JSONPath and css selectors?
510  |  * No it wouldn't be fast, but that's not what this API is about.
511  |  */
512  | yajl_val yajl_tree_get(yajl_val n,      /*+ the node under which you'd like to extract values. +*/
513  |                        const char ** path, /*+ A null terminated array of strings, each the name of an object key +*/
514  |                        yajl_type type)     /*+ the yajl_type of the object you seek, or yajl_t_any if any will do. +*/
515  | {
516  |     if (!path) return NULL;
517  |     while (n && *path) {
518  |         size_t i;
519  |         size_t len;
520  | 
521  |         if (n->type != yajl_t_object) return NULL;
522  |         len = n->u.object.len;
523  |         for (i = 0; i < len; i++) {
524  |             if (!strcmp(*path, n->u.object.keys[i])) {
525  |                 n = n->u.object.values[i];
526  |                 break;
527  |             }
528  |         }
529  |         if (i == len) return NULL;
530  |         path++;
531  |     }
532  |     if (n && type != yajl_t_any && type != n->type) n = NULL;
533  |     return n;
534  | }
535  | 
536  | /*+
537  |  * Free a parse tree returned by yajl_tree_parse().
538  |  +*/
539  | void yajl_tree_free (yajl_val v)        /*+ Pointer to a JSON value returned by
540  |                                          * "yajl_tree_parse".  Passing NULL is
541  |                                          * valid and results in a no-op. +*/
542  | {
543  |     if (v == NULL) return;
544  | 
545  |     if (YAJL_IS_STRING(v))
546  |     {
547  |         free(v->u.string);
548  |         free(v);
549  |     }
550  |     else if (YAJL_IS_NUMBER(v))
551  |     {
552  |         free(v->u.number.r);
553  |         free(v);
554  |     }
555  |     else if (YAJL_GET_OBJECT(v))
556  |     {
557  |         yajl_object_free(v);
558  |     }
559  |     else if (YAJL_GET_ARRAY(v))
560  |     {
561  |         yajl_array_free(v);
562  |     }
563  |     else /* if (yajl_t_true or yajl_t_false or yajl_t_null) */
564  |     {
565  |         free(v);
566  |     }
567  | }