From 58004c9240fdd0251c0e85c6373b280e862d785c Mon Sep 17 00:00:00 2001 From: Marek Belisko Date: Wed, 27 Mar 2013 07:00:15 +0100 Subject: [PATCH 1/4] extend api to get error location and snippet. Signed-off-by: Marek Belisko --- json.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ json.h | 18 ++++++++++++++++ 2 files changed, 83 insertions(+) diff --git a/json.c b/json.c index edab1b7..c59f832 100644 --- a/json.c +++ b/json.c @@ -408,6 +408,13 @@ static int buffer_push(json_parser *parser, unsigned char c) return 0; } +static void buffer_push_prev_data(json_parser *parser, char c) +{ + parser->buffer_prev_data[parser->buffer_prev_data_offset] = c; + + parser->buffer_prev_data_offset = (parser->buffer_prev_data_offset + 1) % LIBJSON_DEFAULT_BUFFER_PREV_DATA_SIZE; +} + static int do_callback_withbuf(json_parser *parser, int type) { if (!parser->callback) @@ -701,6 +708,13 @@ int json_parser_init(json_parser *parser, json_config *config, free(parser->stack); return JSON_ERROR_NO_MEMORY; } + + /* initialize parser location data + buffer which hold previous parsed data */ + parser->line = 1; + parser->column = 0; + memset(parser->buffer_prev_data, '\0', sizeof(parser->buffer_prev_data)); + parser->buffer_prev_data_offset = 0; + return 0; } @@ -723,6 +737,45 @@ int json_parser_is_done(json_parser *parser) return parser->stack_offset == 0 && parser->state != STATE_GO; } +int json_parser_actual_line(json_parser *parser) +{ + return parser->line; +} + +int json_parser_actual_column(json_parser *parser) +{ + return parser->column; +} + +int json_parser_prev_data_len(json_parser *parser) +{ + return LIBJSON_DEFAULT_BUFFER_PREV_DATA_SIZE + 1; +} + +void json_parser_prev_data_snip(json_parser *parser, char *data, int maxlen) +{ + int len = LIBJSON_DEFAULT_BUFFER_PREV_DATA_SIZE + 1; + if (maxlen < len) { + len = maxlen; + } + + uint32_t offset = parser->buffer_prev_data_offset, i = 0; + int wrap_around = (parser->buffer_prev_data[offset] != '\0'); + + if (wrap_around) { + for (offset = parser->buffer_prev_data_offset, i = 0; + offset < LIBJSON_DEFAULT_BUFFER_PREV_DATA_SIZE && i <= LIBJSON_DEFAULT_BUFFER_PREV_DATA_SIZE; offset++, i++) { + data[i] = parser->buffer_prev_data[offset]; + } + } + + for (offset = 0; offset < parser->buffer_prev_data_offset && i <= LIBJSON_DEFAULT_BUFFER_PREV_DATA_SIZE; offset++, i++) { + data[i] = parser->buffer_prev_data[offset]; + } + + data[i] = '\0'; +} + /** json_parser_string append a string s with a specific length to the parser * return 0 if everything went ok, a JSON_ERROR_* otherwise. * the user can supplied a valid processed pointer that will @@ -739,6 +792,18 @@ int json_parser_string(json_parser *parser, const char *s, for (i = 0; i < length; i++) { unsigned char ch = s[i]; + if (ch == '\n') { + parser->line ++; + parser->column = 0; + } else { + parser->column ++; + } + /* store some last processed characters to temp buffer + * which can be retrieved to get snippet where + * error occured + */ + buffer_push_prev_data(parser, ch); + ret = 0; if (parser->utf8_multibyte_left > 0) { if (utf8_continuation_table[ch] != 0) { diff --git a/json.h b/json.h index 077d35b..791bb61 100644 --- a/json.h +++ b/json.h @@ -83,6 +83,7 @@ typedef enum #define LIBJSON_DEFAULT_STACK_SIZE 256 #define LIBJSON_DEFAULT_BUFFER_SIZE 4096 +#define LIBJSON_DEFAULT_BUFFER_PREV_DATA_SIZE 20 typedef int (*json_parser_callback)(void *userdata, int type, const char *data, uint32_t length); typedef int (*json_printer_callback)(void *userdata, const char *s, uint32_t length); @@ -121,6 +122,12 @@ typedef struct json_parser { char *buffer; uint32_t buffer_size; uint32_t buffer_offset; + + /* parser position */ + uint32_t line; + uint32_t column; + char buffer_prev_data[LIBJSON_DEFAULT_BUFFER_PREV_DATA_SIZE]; + uint32_t buffer_prev_data_offset; } json_parser; typedef struct json_printer { @@ -157,6 +164,17 @@ int json_parser_char(json_parser *parser, unsigned char next_char); /** json_parser_is_done return 0 is the parser isn't in a finish state. !0 if it is */ int json_parser_is_done(json_parser *parser); +/** return actual parsed line */ +int json_parser_actual_line(json_parser *parser); + +/** return actual parser column in document */ +int json_parser_actual_column(json_parser *parser); + +/** return length of stored previous parsed data snippet */ +int json_parser_prev_data_len(json_parser *parser); + +void json_parser_prev_data_snip(json_parser *parser, char *data, int maxlen); + /** json_print_init initialize a printer context. always succeed */ int json_print_init(json_printer *printer, json_printer_callback callback, void *userdata); From d3b71b272da91079ab750627ed3cd36a77949b0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jozef=20=C5=A0i=C5=A1ka?= Date: Tue, 4 Jun 2013 17:46:34 +0200 Subject: [PATCH 2/4] add json_parser_dom_finalize function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit needed to correctly dispose of objects allready on stack in case of errors Signed-off-by: Jozef Šiška --- json.c | 12 ++++++++++++ json.h | 4 ++++ 2 files changed, 16 insertions(+) diff --git a/json.c b/json.c index c59f832..c7f2353 100644 --- a/json.c +++ b/json.c @@ -1081,6 +1081,18 @@ int json_parser_dom_init(json_parser_dom *dom, return 0; } +int json_parser_dom_finalize(json_parser_dom *ctx) +{ + void *v; + struct stack_elem *stack = NULL; + + /* emulate JSON_OBJECT_END/JSON_ARRAY_END on all elements on stack */ + while (ctx->stack_offset>0) { + json_parser_dom_callback(ctx, JSON_OBJECT_END, NULL, 0); + } + return 0; +} + int json_parser_dom_free(json_parser_dom *dom) { free(dom->stack); diff --git a/json.h b/json.h index 791bb61..8bdc74c 100644 --- a/json.h +++ b/json.h @@ -232,6 +232,10 @@ int json_parser_dom_init(json_parser_dom *helper, json_parser_dom_create_structure create_structure, json_parser_dom_create_data create_data, json_parser_dom_append append); + +/** close still open arrays/objects on the stack */ +int json_parser_dom_finalize(json_parser_dom *ctx); + /** free memory allocated by the DOM callback helper */ int json_parser_dom_free(json_parser_dom *ctx); From 459368b37b48b211f4bfe7ee780b1be4564cc68f Mon Sep 17 00:00:00 2001 From: Martin Flaska Date: Fri, 13 Dec 2013 09:27:57 +0100 Subject: [PATCH 3/4] fix signed/unsigned conversion compiler warnings Signed-off-by: Martin Flaska --- json.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/json.c b/json.c index c7f2353..306a740 100644 --- a/json.c +++ b/json.c @@ -1005,7 +1005,7 @@ int json_print_args(json_printer *printer, { va_list ap; char *data; - uint32_t length; + int32_t length; int type, ret; ret = 0; From 74abff3d83cbf9efd5359b48b4102ccc526b6767 Mon Sep 17 00:00:00 2001 From: Martin Flaska Date: Fri, 13 Dec 2013 14:24:40 +0100 Subject: [PATCH 4/4] include also next data from buffer if parse error is at starting position If parsing error were at some first buffer position, only few previous chars would be put into snippet. Signed-off-by: Martin Flaska --- json.c | 24 ++++++++++++++++++++++-- json.h | 2 ++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/json.c b/json.c index 306a740..e242df0 100644 --- a/json.c +++ b/json.c @@ -759,11 +759,12 @@ void json_parser_prev_data_snip(json_parser *parser, char *data, int maxlen) len = maxlen; } - uint32_t offset = parser->buffer_prev_data_offset, i = 0; + uint32_t offset = parser->buffer_prev_data_offset; int wrap_around = (parser->buffer_prev_data[offset] != '\0'); + uint32_t i = 0; if (wrap_around) { - for (offset = parser->buffer_prev_data_offset, i = 0; + for (offset = parser->buffer_prev_data_offset; offset < LIBJSON_DEFAULT_BUFFER_PREV_DATA_SIZE && i <= LIBJSON_DEFAULT_BUFFER_PREV_DATA_SIZE; offset++, i++) { data[i] = parser->buffer_prev_data[offset]; } @@ -773,6 +774,14 @@ void json_parser_prev_data_snip(json_parser *parser, char *data, int maxlen) data[i] = parser->buffer_prev_data[offset]; } + // Append next characters if number of previously parsed chars + // is lesser than expected size of snipped data + while (i < LIBJSON_DEFAULT_BUFFER_PREV_DATA_SIZE + && parser->buffer_first_data_lenght > i) { + data[i] = parser->buffer_first_data[i]; + i++; + } + data[i] = '\0'; } @@ -788,6 +797,17 @@ int json_parser_string(json_parser *parser, const char *s, int buffer_policy; uint32_t i; + if (parser->buffer_first_data_lenght < LIBJSON_DEFAULT_BUFFER_PREV_DATA_SIZE) { + int addLen = + (length <= (LIBJSON_DEFAULT_BUFFER_PREV_DATA_SIZE - parser->buffer_first_data_lenght)) + ? length : (LIBJSON_DEFAULT_BUFFER_PREV_DATA_SIZE - parser->buffer_first_data_lenght); + + memcpy(parser->buffer_first_data + parser->buffer_first_data_lenght, + s, + addLen); + parser->buffer_first_data_lenght += addLen; + } + ret = 0; for (i = 0; i < length; i++) { unsigned char ch = s[i]; diff --git a/json.h b/json.h index 8bdc74c..be74151 100644 --- a/json.h +++ b/json.h @@ -128,6 +128,8 @@ typedef struct json_parser { uint32_t column; char buffer_prev_data[LIBJSON_DEFAULT_BUFFER_PREV_DATA_SIZE]; uint32_t buffer_prev_data_offset; + char buffer_first_data[LIBJSON_DEFAULT_BUFFER_PREV_DATA_SIZE]; + uint32_t buffer_first_data_lenght; } json_parser; typedef struct json_printer {