diff --git a/src/yajl/yajl_common.h b/src/yajl/yajl_common.h index a18ebd8..8bfdbe5 100644 --- a/src/yajl/yajl_common.h +++ b/src/yajl/yajl_common.h @@ -50,6 +50,18 @@ extern "C" { # endif #endif +/*+ error codes returned from this interface +*/ +typedef enum { + /*+ no error was encountered +*/ + yajl_status_ok, + /*+ a client callback returned zero, stopping the parse +*/ + yajl_status_client_canceled, + /*+ An error occurred during the parse. Call yajl_get_error for + * more information about the encountered error +*/ + yajl_status_error +} yajl_status; + + /*+ * A pointer to a malloc() function. +*/ diff --git a/src/yajl/yajl_parse.h b/src/yajl/yajl_parse.h index 8153b6c..332411c 100644 --- a/src/yajl/yajl_parse.h +++ b/src/yajl/yajl_parse.h @@ -28,16 +28,7 @@ #ifdef __cplusplus extern "C" { #endif - /*+ error codes returned from this interface +*/ - typedef enum { - /*+ no error was encountered +*/ - yajl_status_ok, - /*+ a client callback returned zero, stopping the parse +*/ - yajl_status_client_canceled, - /*+ An error occurred during the parse. Call yajl_get_error for - * more information about the encountered error +*/ - yajl_status_error - } yajl_status; + /*+ attain a human readable, english, string for an error +*/ YAJL_API const char * yajl_status_to_string(yajl_status code); diff --git a/src/yajl/yajl_tree.h b/src/yajl/yajl_tree.h index 9ab1206..79cc85f 100644 --- a/src/yajl/yajl_tree.h +++ b/src/yajl/yajl_tree.h @@ -106,6 +106,31 @@ struct yajl_val_s } u; }; +struct stack_elem_s; +typedef struct stack_elem_s stack_elem_t; +struct stack_elem_s +{ + char * key; + yajl_val value; + stack_elem_t *next; +}; + +struct context_s +{ + stack_elem_t *stack; + yajl_val root; + char *errbuf; + size_t errbuf_size; +}; +typedef struct context_s context_t; + + +typedef struct yajl_stream_context_t { + context_t ctx; + struct yajl_handle_t * handle; + yajl_status status; +} yajl_stream_context_t; + YAJL_API yajl_val yajl_tree_parse (const char *input, char *error_buffer, size_t error_buffer_size); YAJL_API void yajl_tree_free (yajl_val v); @@ -144,6 +169,28 @@ YAJL_API yajl_val yajl_tree_get(yajl_val parent, const char ** path, yajl_type t /*+ Get a pointer to a yajl_val_array or NULL if the value is not an object. +*/ #define YAJL_GET_ARRAY(v) (YAJL_IS_ARRAY(v) ? &(v)->u.array : NULL) + +yajl_stream_context_t *yajl_tree_stream_parse_start ( + char *error_buffer, /*+ Pointer to a buffer in which + * an error message will be stored + * if yajl_tree_parse() fails, or + * NULL. The buffer will be + * initialized before parsing, so + * its content will be destroyed + * even if yajl_tree_parse() + * succeeds. +*/ + size_t error_buffer_size); /*+ Size of the memory area + * pointed to by + * error_buffer_size. If + * error_buffer_size is + * NULL, this argument is + * ignored. +*/ +yajl_status yajl_tree_stream_parse_feed(yajl_stream_context_t *stream_ctx, + const unsigned char* input, + size_t input_len); + +yajl_val yajl_tree_stream_parse_finish(yajl_stream_context_t *stream_ctx); + #ifdef __cplusplus } #endif diff --git a/src/yajl_gen.c b/src/yajl_gen.c index 582fdff..8af4aaf 100644 --- a/src/yajl_gen.c +++ b/src/yajl_gen.c @@ -270,6 +270,7 @@ yajl_gen_free(yajl_gen g) case yajl_gen_map_val: \ g->state[g->depth] = yajl_gen_map_key; \ break; \ + case yajl_gen_complete: \ default: \ break; \ } diff --git a/src/yajl_tree.c b/src/yajl_tree.c old mode 100644 new mode 100755 index 5672752..26e439d --- a/src/yajl_tree.c +++ b/src/yajl_tree.c @@ -49,24 +49,6 @@ yajl_alloc_funcs *yajl_tree_parse_afs = NULL; -struct stack_elem_s; -typedef struct stack_elem_s stack_elem_t; -struct stack_elem_s -{ - char * key; - yajl_val value; - stack_elem_t *next; -}; - -struct context_s -{ - stack_elem_t *stack; - yajl_val root; - char *errbuf; - size_t errbuf_size; -}; -typedef struct context_s context_t; - #define RETURN_ERROR(ctx,retval,...) { \ if ((ctx)->errbuf != NULL) \ snprintf ((ctx)->errbuf, (ctx)->errbuf_size, __VA_ARGS__); \ @@ -537,6 +519,115 @@ yajl_val yajl_tree_parse (const char *input, /*+ Pointer to a null-terminated return (ctx.root); } + +/*+ + * Begin to parse a string, piece by piece. + * + * Parses a null-terminated string containing JSON data. + * + * Returns a pointer to a yajl_stream_context_t object that shall be + * passed to the function consuming the json data. + * + * The memory pointed to must be freed using yajl_tree_free(). In case of an + * error, a null terminated message describing the error in more detail is + * stored in error_buffer if it is not NULL. + +*/ +yajl_stream_context_t *yajl_tree_stream_parse_start ( + char *error_buffer, /*+ Pointer to a buffer in which + * an error message will be stored + * if yajl_tree_parse() fails, or + * NULL. The buffer will be + * initialized before parsing, so + * its content will be destroyed + * even if yajl_tree_parse() + * succeeds. +*/ + size_t error_buffer_size) /*+ Size of the memory area + * pointed to by + * error_buffer_size. If + * error_buffer_size is + * NULL, this argument is + * ignored. +*/ +{ + /* pointers to parsing callbacks */ + static const yajl_callbacks callbacks = + { + /* null = */ handle_null, + /* boolean = */ handle_boolean, + /* integer = */ NULL, + /* double = */ NULL, + /* number = */ handle_number, + /* string = */ handle_string, + /* start map = */ handle_start_map, + /* map key = */ handle_string, + /* end map = */ handle_end_map, + /* start array = */ handle_start_array, + /* end array = */ handle_end_array + }; + + + yajl_stream_context_t *stream_ctx = malloc(sizeof(*stream_ctx)); + + stream_ctx->ctx.stack = 0; + stream_ctx->ctx.root = 0; + stream_ctx->ctx.errbuf = error_buffer; + stream_ctx->ctx.errbuf_size = error_buffer_size; + + if (error_buffer != NULL) + memset (error_buffer, 0, error_buffer_size); + + stream_ctx->handle = yajl_alloc(&callbacks, yajl_tree_parse_afs, &stream_ctx->ctx); + yajl_config(stream_ctx->handle, yajl_allow_trailing_garbage, 1); + + return stream_ctx; +} + +/*+ + * Input one or more bytes of json data + +*/ +yajl_status yajl_tree_stream_parse_feed(yajl_stream_context_t *stream_ctx, + const unsigned char* input, + size_t input_len) { + + stream_ctx->status = yajl_parse(stream_ctx->handle, + input, + input_len); + return stream_ctx->status; +} + +/*+ + * Finish a stream of json data. + * + * Returns the tree corresponding to the json input. ++*/ +yajl_val yajl_tree_stream_parse_finish(yajl_stream_context_t *stream_ctx) { + + char * internal_err_str; + + if (stream_ctx->status != yajl_status_ok) { + if (stream_ctx->ctx.errbuf != NULL && stream_ctx->ctx.errbuf_size > 0) { + internal_err_str = (char *) yajl_get_error(stream_ctx->handle, 1, + "unknown", strlen("unknown")); + + snprintf(stream_ctx->ctx.errbuf, stream_ctx->ctx.errbuf_size, "%s", internal_err_str); + YA_FREE(&(stream_ctx->handle->alloc), internal_err_str); + } + while (stream_ctx->ctx.stack) { + yajl_tree_free(context_pop(&stream_ctx->ctx)); + } + yajl_free (stream_ctx->handle); + return NULL; + } + yajl_complete_parse (stream_ctx->handle); + + yajl_free (stream_ctx->handle); + yajl_val root = stream_ctx->ctx.root; + + free(stream_ctx); + + return root; +} + + /*+ * Access a nested value inside a tree. *