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 #include <stdlib.h>
18 #include <stdio.h>
19 #include <string.h>
20 #include <errno.h>
21 #include <assert.h>
22
23 #include "api/yajl_tree.h"
24 #include "api/yajl_parse.h"
25
26 #include "yajl_parser.h"
27
28 #if defined(_WIN32) || defined(WIN32)
29 #define snprintf sprintf_s
30 #endif
31
32 #define STATUS_CONTINUE 1
33 #define STATUS_ABORT 0
34
35 struct stack_elem_s;
36 typedef struct stack_elem_s stack_elem_t;
37 struct stack_elem_s
38 {
39 char * key;
40 yajl_val value;
41 stack_elem_t *next;
42 };
43
44 struct context_s
45 {
46 stack_elem_t *stack;
47 yajl_val root;
48 char *errbuf;
49 size_t errbuf_size;
50 };
51 typedef struct context_s context_t;
52
53 #define RETURN_ERROR(ctx,retval,...) { \
54 if ((ctx)->errbuf != NULL) \
55 snprintf ((ctx)->errbuf, (ctx)->errbuf_size, __VA_ARGS__); \
56 return (retval); \
57 }
58
value_alloc(yajl_type type)59 static yajl_val value_alloc (yajl_type type)
60 {
61 yajl_val v;
62
63 v = malloc (sizeof (*v));
64 if (v == NULL) return (NULL);
65 memset (v, 0, sizeof (*v));
66 v->type = type;
67
68 return (v);
69 }
70
yajl_object_free(yajl_val v)71 static void yajl_object_free (yajl_val v)
72 {
73 size_t i;
74
75 if (!YAJL_IS_OBJECT(v)) return;
76
77 for (i = 0; i < v->u.object.len; i++)
78 {
79 free((char *) v->u.object.keys[i]);
80 v->u.object.keys[i] = NULL;
81 yajl_tree_free (v->u.object.values[i]);
82 v->u.object.values[i] = NULL;
83 }
84
85 free((void*) v->u.object.keys);
86 free(v->u.object.values);
87 free(v);
88 }
89
yajl_array_free(yajl_val v)90 static void yajl_array_free (yajl_val v)
91 {
92 size_t i;
93
94 if (!YAJL_IS_ARRAY(v)) return;
95
96 for (i = 0; i < v->u.array.len; i++)
97 {
98 yajl_tree_free (v->u.array.values[i]);
99 v->u.array.values[i] = NULL;
100 }
101
102 free(v->u.array.values);
103 free(v);
104 }
105
106 /*
107 * Parsing nested objects and arrays is implemented using a stack. When a new
108 * object or array starts (a curly or a square opening bracket is read), an
109 * appropriate value is pushed on the stack. When the end of the object is
110 * reached (an appropriate closing bracket has been read), the value is popped
111 * off the stack and added to the enclosing object using "context_add_value".
112 */
context_push(context_t * ctx,yajl_val v)113 static int context_push(context_t *ctx, yajl_val v)
114 {
115 stack_elem_t *stack;
116
117 stack = malloc (sizeof (*stack));
118 if (stack == NULL)
119 RETURN_ERROR (ctx, ENOMEM, "Out of memory");
120 memset (stack, 0, sizeof (*stack));
121
122 assert ((ctx->stack == NULL)
123 || YAJL_IS_OBJECT (v)
124 || YAJL_IS_ARRAY (v));
125
126 stack->value = v;
127 stack->next = ctx->stack;
128 ctx->stack = stack;
129
130 return (0);
131 }
132
context_pop(context_t * ctx)133 static yajl_val context_pop(context_t *ctx)
134 {
135 stack_elem_t *stack;
136 yajl_val v;
137
138 if (ctx->stack == NULL)
139 RETURN_ERROR (ctx, NULL, "context_pop: "
140 "Bottom of stack reached prematurely");
141
142 stack = ctx->stack;
143 ctx->stack = stack->next;
144
145 v = stack->value;
146
147 free (stack);
148
149 return (v);
150 }
151
object_add_keyval(context_t * ctx,yajl_val obj,char * key,yajl_val value)152 static int object_add_keyval(context_t *ctx,
153 yajl_val obj, char *key, yajl_val value)
154 {
155 const char **tmpk;
156 yajl_val *tmpv;
157
158 /* We're checking for NULL in "context_add_value" or its callers. */
159 assert (ctx != NULL);
160 assert (obj != NULL);
161 assert (key != NULL);
162 assert (value != NULL);
163
164 /* We're assuring that "obj" is an object in "context_add_value". */
165 assert(YAJL_IS_OBJECT(obj));
166
167 tmpk = realloc((void *) obj->u.object.keys, sizeof(*(obj->u.object.keys)) * (obj->u.object.len + 1));
168 if (tmpk == NULL)
169 RETURN_ERROR(ctx, ENOMEM, "Out of memory");
170 obj->u.object.keys = tmpk;
171
172 tmpv = realloc(obj->u.object.values, sizeof (*obj->u.object.values) * (obj->u.object.len + 1));
173 if (tmpv == NULL)
174 RETURN_ERROR(ctx, ENOMEM, "Out of memory");
175 obj->u.object.values = tmpv;
176
177 obj->u.object.keys[obj->u.object.len] = key;
178 obj->u.object.values[obj->u.object.len] = value;
179 obj->u.object.len++;
180
181 return (0);
182 }
183
array_add_value(context_t * ctx,yajl_val array,yajl_val value)184 static int array_add_value (context_t *ctx,
185 yajl_val array, yajl_val value)
186 {
187 yajl_val *tmp;
188
189 /* We're checking for NULL pointers in "context_add_value" or its
190 * callers. */
191 assert (ctx != NULL);
192 assert (array != NULL);
193 assert (value != NULL);
194
195 /* "context_add_value" will only call us with array values. */
196 assert(YAJL_IS_ARRAY(array));
197
198 tmp = realloc(array->u.array.values,
199 sizeof(*(array->u.array.values)) * (array->u.array.len + 1));
200 if (tmp == NULL)
201 RETURN_ERROR(ctx, ENOMEM, "Out of memory");
202 array->u.array.values = tmp;
203 array->u.array.values[array->u.array.len] = value;
204 array->u.array.len++;
205
206 return 0;
207 }
208
209 /*
210 * Add a value to the value on top of the stack or the "root" member in the
211 * context if the end of the parsing process is reached.
212 */
context_add_value(context_t * ctx,yajl_val v)213 static int context_add_value (context_t *ctx, yajl_val v)
214 {
215 /* We're checking for NULL values in all the calling functions. */
216 assert (ctx != NULL);
217 assert (v != NULL);
218
219 /*
220 * There are three valid states in which this function may be called:
221 * - There is no value on the stack => This is the only value. This is the
222 * last step done when parsing a document. We assign the value to the
223 * "root" member and return.
224 * - The value on the stack is an object. In this case store the key on the
225 * stack or, if the key has already been read, add key and value to the
226 * object.
227 * - The value on the stack is an array. In this case simply add the value
228 * and return.
229 */
230 if (ctx->stack == NULL)
231 {
232 assert (ctx->root == NULL);
233 ctx->root = v;
234 return (0);
235 }
236 else if (YAJL_IS_OBJECT (ctx->stack->value))
237 {
238 if (ctx->stack->key == NULL)
239 {
240 if (!YAJL_IS_STRING (v))
241 RETURN_ERROR (ctx, EINVAL, "context_add_value: "
242 "Object key is not a string (%#04x)",
243 v->type);
244
245 ctx->stack->key = v->u.string;
246 v->u.string = NULL;
247 free(v);
248 return (0);
249 }
250 else /* if (ctx->key != NULL) */
251 {
252 char * key;
253
254 key = ctx->stack->key;
255 ctx->stack->key = NULL;
256 return (object_add_keyval (ctx, ctx->stack->value, key, v));
257 }
258 }
259 else if (YAJL_IS_ARRAY (ctx->stack->value))
260 {
261 return (array_add_value (ctx, ctx->stack->value, v));
262 }
263 else
264 {
265 RETURN_ERROR (ctx, EINVAL, "context_add_value: Cannot add value to "
266 "a value of type %#04x (not a composite type)",
267 ctx->stack->value->type);
268 }
269 }
270
handle_string(void * ctx,const unsigned char * string,size_t string_length)271 static int handle_string (void *ctx,
272 const unsigned char *string, size_t string_length)
273 {
274 yajl_val v;
275
276 v = value_alloc (yajl_t_string);
277 if (v == NULL)
278 RETURN_ERROR ((context_t *) ctx, STATUS_ABORT, "Out of memory");
279
280 v->u.string = malloc (string_length + 1);
281 if (v->u.string == NULL)
282 {
283 free (v);
284 RETURN_ERROR ((context_t *) ctx, STATUS_ABORT, "Out of memory");
285 }
286 memcpy(v->u.string, string, string_length);
287 v->u.string[string_length] = 0;
288
289 return ((context_add_value (ctx, v) == 0) ? STATUS_CONTINUE : STATUS_ABORT);
290 }
291
handle_number(void * ctx,const char * string,size_t string_length)292 static int handle_number (void *ctx, const char *string, size_t string_length)
293 {
294 yajl_val v;
295 char *endptr;
296
297 v = value_alloc(yajl_t_number);
298 if (v == NULL)
299 RETURN_ERROR((context_t *) ctx, STATUS_ABORT, "Out of memory");
300
301 v->u.number.r = malloc(string_length + 1);
302 if (v->u.number.r == NULL)
303 {
304 free(v);
305 RETURN_ERROR((context_t *) ctx, STATUS_ABORT, "Out of memory");
306 }
307 memcpy(v->u.number.r, string, string_length);
308 v->u.number.r[string_length] = 0;
309
310 v->u.number.flags = 0;
311
312 errno = 0;
313 v->u.number.i = yajl_parse_integer((const unsigned char *) v->u.number.r,
314 strlen(v->u.number.r));
315 if (errno == 0)
316 v->u.number.flags |= YAJL_NUMBER_INT_VALID;
317
318 endptr = NULL;
319 errno = 0;
320 v->u.number.d = strtod(v->u.number.r, &endptr);
321 if ((errno == 0) && (endptr != NULL) && (*endptr == 0))
322 v->u.number.flags |= YAJL_NUMBER_DOUBLE_VALID;
323
324 return ((context_add_value(ctx, v) == 0) ? STATUS_CONTINUE : STATUS_ABORT);
325 }
326
handle_start_map(void * ctx)327 static int handle_start_map (void *ctx)
328 {
329 yajl_val v;
330
331 v = value_alloc(yajl_t_object);
332 if (v == NULL)
333 RETURN_ERROR ((context_t *) ctx, STATUS_ABORT, "Out of memory");
334
335 v->u.object.keys = NULL;
336 v->u.object.values = NULL;
337 v->u.object.len = 0;
338
339 return ((context_push (ctx, v) == 0) ? STATUS_CONTINUE : STATUS_ABORT);
340 }
341
handle_end_map(void * ctx)342 static int handle_end_map (void *ctx)
343 {
344 yajl_val v;
345
346 v = context_pop (ctx);
347 if (v == NULL)
348 return (STATUS_ABORT);
349
350 return ((context_add_value (ctx, v) == 0) ? STATUS_CONTINUE : STATUS_ABORT);
351 }
352
handle_start_array(void * ctx)353 static int handle_start_array (void *ctx)
354 {
355 yajl_val v;
356
357 v = value_alloc(yajl_t_array);
358 if (v == NULL)
359 RETURN_ERROR ((context_t *) ctx, STATUS_ABORT, "Out of memory");
360
361 v->u.array.values = NULL;
362 v->u.array.len = 0;
363
364 return ((context_push (ctx, v) == 0) ? STATUS_CONTINUE : STATUS_ABORT);
365 }
366
handle_end_array(void * ctx)367 static int handle_end_array (void *ctx)
368 {
369 yajl_val v;
370
371 v = context_pop (ctx);
372 if (v == NULL)
373 return (STATUS_ABORT);
374
375 return ((context_add_value (ctx, v) == 0) ? STATUS_CONTINUE : STATUS_ABORT);
376 }
377
handle_boolean(void * ctx,int boolean_value)378 static int handle_boolean (void *ctx, int boolean_value)
379 {
380 yajl_val v;
381
382 v = value_alloc (boolean_value ? yajl_t_true : yajl_t_false);
383 if (v == NULL)
384 RETURN_ERROR ((context_t *) ctx, STATUS_ABORT, "Out of memory");
385
386 return ((context_add_value (ctx, v) == 0) ? STATUS_CONTINUE : STATUS_ABORT);
387 }
388
handle_null(void * ctx)389 static int handle_null (void *ctx)
390 {
391 yajl_val v;
392
393 v = value_alloc (yajl_t_null);
394 if (v == NULL)
395 RETURN_ERROR ((context_t *) ctx, STATUS_ABORT, "Out of memory");
396
397 return ((context_add_value (ctx, v) == 0) ? STATUS_CONTINUE : STATUS_ABORT);
398 }
399
400 /*
401 * Public functions
402 */
yajl_tree_parse(const char * input,char * error_buffer,size_t error_buffer_size)403 yajl_val yajl_tree_parse (const char *input,
404 char *error_buffer, size_t error_buffer_size)
405 {
406 static const yajl_callbacks callbacks =
407 {
408 /* null = */ handle_null,
409 /* boolean = */ handle_boolean,
410 /* integer = */ NULL,
411 /* double = */ NULL,
412 /* number = */ handle_number,
413 /* string = */ handle_string,
414 /* start map = */ handle_start_map,
415 /* map key = */ handle_string,
416 /* end map = */ handle_end_map,
417 /* start array = */ handle_start_array,
418 /* end array = */ handle_end_array
419 };
420
421 yajl_handle handle;
422 yajl_status status;
423 char * internal_err_str;
424 context_t ctx = { NULL, NULL, NULL, 0 };
425
426 ctx.errbuf = error_buffer;
427 ctx.errbuf_size = error_buffer_size;
428
429 if (error_buffer != NULL)
430 memset (error_buffer, 0, error_buffer_size);
431
432 handle = yajl_alloc (&callbacks, NULL, &ctx);
433 yajl_config(handle, yajl_allow_comments, 1);
434
435 status = yajl_parse(handle,
436 (unsigned char *) input,
437 strlen (input));
438 status = yajl_complete_parse (handle);
439 if (status != yajl_status_ok) {
440 if (error_buffer != NULL && error_buffer_size > 0) {
441 internal_err_str = (char *) yajl_get_error(handle, 1,
442 (const unsigned char *) input,
443 strlen(input));
444 snprintf(error_buffer, error_buffer_size, "%s", internal_err_str);
445 YA_FREE(&(handle->alloc), internal_err_str);
446 }
447 yajl_free (handle);
448 return NULL;
449 }
450
451 yajl_free (handle);
452 return (ctx.root);
453 }
454
yajl_tree_get(yajl_val n,const char ** path,yajl_type type)455 yajl_val yajl_tree_get(yajl_val n, const char ** path, yajl_type type)
456 {
457 if (!path) return NULL;
458 while (n && *path) {
459 size_t i;
460 size_t len;
461
462 if (n->type != yajl_t_object) return NULL;
463 len = n->u.object.len;
464 for (i = 0; i < len; i++) {
465 if (!strcmp(*path, n->u.object.keys[i])) {
466 n = n->u.object.values[i];
467 break;
468 }
469 }
470 if (i == len) return NULL;
471 path++;
472 }
473 if (n && type != yajl_t_any && type != n->type) n = NULL;
474 return n;
475 }
476
yajl_tree_free(yajl_val v)477 void yajl_tree_free (yajl_val v)
478 {
479 if (v == NULL) return;
480
481 if (YAJL_IS_STRING(v))
482 {
483 free(v->u.string);
484 free(v);
485 }
486 else if (YAJL_IS_NUMBER(v))
487 {
488 free(v->u.number.r);
489 free(v);
490 }
491 else if (YAJL_GET_OBJECT(v))
492 {
493 yajl_object_free(v);
494 }
495 else if (YAJL_GET_ARRAY(v))
496 {
497 yajl_array_free(v);
498 }
499 else /* if (yajl_t_true or yajl_t_false or yajl_t_null) */
500 {
501 free(v);
502 }
503 }
504