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