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 | }