From 6d188071f8067cadb79e1ee749b8b0b0b762418f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20Hj=C3=A4rtquist?= Date: Fri, 11 Aug 2023 10:13:01 +0200 Subject: [PATCH 1/4] Add stream to tree functionality --- src/yajl/yajl_common.h | 12 +++++ src/yajl/yajl_parse.h | 11 +---- src/yajl/yajl_tree.h | 50 ++++++++++++++++++-- src/yajl_gen.c | 1 + src/yajl_tree.c | 103 ++++++++++++++++++++++++++++++++++------- 5 files changed, 146 insertions(+), 31 deletions(-) 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..78af425 100644 --- a/src/yajl/yajl_tree.h +++ b/src/yajl/yajl_tree.h @@ -37,9 +37,6 @@ extern "C" { #endif -/*+ an optional hook to allow use of custom yajl_alloc_funcs with yajl_tree_parse() +*/ -extern yajl_alloc_funcs *yajl_tree_parse_afs; - /*+ possible data types that a yajl_val_s can hold +*/ typedef enum { yajl_t_string = 1, @@ -106,6 +103,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 +166,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 index 5672752..2234265 100644 --- 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,91 @@ yajl_val yajl_tree_parse (const char *input, /*+ Pointer to a null-terminated return (ctx.root); } + +/*+ + * Parse a string, piece by piece. + * + * Parses a null-terminated string containing JSON data. + * + * Returns a pointer to a yajl_val object which is the top-level value (root of + * the parse tree) or NULL on error. + * + * 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); + + static const yajl_alloc_funcs afs = { + .free = yajl_free, + .malloc = yajl_malloc, + .realloc = yajl_realloc + }; + + stream_ctx->handle = yajl_alloc (&callbacks, &afs, &stream_ctx->ctx); + yajl_config(stream_ctx->handle, yajl_allow_trailing_garbage, 1); + + return stream_ctx; +} + + +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); + + if (yajl_status_ok != stream_ctx->status){ + int i = 123; + } + + return stream_ctx->status; +} + + /*+ * Access a nested value inside a tree. * From e21104fd8d9b2bf74350cd58cf16b2f59b222908 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20Hj=C3=A4rtquist?= Date: Fri, 11 Aug 2023 12:13:59 +0200 Subject: [PATCH 2/4] Fix merge + compilation issues --- src/yajl/yajl_tree.h | 3 +++ src/yajl_tree.c | 25 +++++++------------------ 2 files changed, 10 insertions(+), 18 deletions(-) diff --git a/src/yajl/yajl_tree.h b/src/yajl/yajl_tree.h index 78af425..79cc85f 100644 --- a/src/yajl/yajl_tree.h +++ b/src/yajl/yajl_tree.h @@ -37,6 +37,9 @@ extern "C" { #endif +/*+ an optional hook to allow use of custom yajl_alloc_funcs with yajl_tree_parse() +*/ +extern yajl_alloc_funcs *yajl_tree_parse_afs; + /*+ possible data types that a yajl_val_s can hold +*/ typedef enum { yajl_t_string = 1, diff --git a/src/yajl_tree.c b/src/yajl_tree.c index 2234265..e0a952a 100644 --- a/src/yajl_tree.c +++ b/src/yajl_tree.c @@ -525,8 +525,8 @@ yajl_val yajl_tree_parse (const char *input, /*+ Pointer to a null-terminated * * Parses a null-terminated string containing JSON data. * - * Returns a pointer to a yajl_val object which is the top-level value (root of - * the parse tree) or NULL on error. + * 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 @@ -575,13 +575,7 @@ yajl_stream_context_t *yajl_tree_stream_parse_start ( if (error_buffer != NULL) memset (error_buffer, 0, error_buffer_size); - static const yajl_alloc_funcs afs = { - .free = yajl_free, - .malloc = yajl_malloc, - .realloc = yajl_realloc - }; - - stream_ctx->handle = yajl_alloc (&callbacks, &afs, &stream_ctx->ctx); + stream_ctx->handle = yajl_alloc(&callbacks, yajl_tree_parse_afs, &stream_ctx); yajl_config(stream_ctx->handle, yajl_allow_trailing_garbage, 1); return stream_ctx; @@ -589,17 +583,12 @@ yajl_stream_context_t *yajl_tree_stream_parse_start ( yajl_status yajl_tree_stream_parse_feed(yajl_stream_context_t *stream_ctx, - const unsigned char* input, - size_t input_len) { + const unsigned char* input, + size_t input_len) { stream_ctx->status = yajl_parse(stream_ctx->handle, - input, - input_len); - - if (yajl_status_ok != stream_ctx->status){ - int i = 123; - } - + input, + input_len); return stream_ctx->status; } From dcb22ca5c1b2b147d214f0e8acff87af29a3d729 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20Hj=C3=A4rtquist?= Date: Fri, 11 Aug 2023 13:19:37 +0200 Subject: [PATCH 3/4] Add stream finish function --- src/yajl_tree.c | 39 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) mode change 100644 => 100755 src/yajl_tree.c diff --git a/src/yajl_tree.c b/src/yajl_tree.c old mode 100644 new mode 100755 index e0a952a..82c25c9 --- a/src/yajl_tree.c +++ b/src/yajl_tree.c @@ -521,7 +521,7 @@ yajl_val yajl_tree_parse (const char *input, /*+ Pointer to a null-terminated /*+ - * Parse a string, piece by piece. + * Begin to parse a string, piece by piece. * * Parses a null-terminated string containing JSON data. * @@ -581,7 +581,9 @@ yajl_stream_context_t *yajl_tree_stream_parse_start ( 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) { @@ -592,6 +594,39 @@ yajl_status yajl_tree_stream_parse_feed(yajl_stream_context_t *stream_ctx, 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. From f2232dfee2917e01a00392d7c6643b869568baf0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20Hj=C3=A4rtquist?= Date: Mon, 2 Oct 2023 09:23:55 +0200 Subject: [PATCH 4/4] Fix bad pointer --- src/yajl_tree.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/yajl_tree.c b/src/yajl_tree.c index 82c25c9..26e439d 100755 --- a/src/yajl_tree.c +++ b/src/yajl_tree.c @@ -575,7 +575,7 @@ yajl_stream_context_t *yajl_tree_stream_parse_start ( if (error_buffer != NULL) memset (error_buffer, 0, error_buffer_size); - stream_ctx->handle = yajl_alloc(&callbacks, yajl_tree_parse_afs, &stream_ctx); + 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;