diff --git a/json.c b/json.c index edab1b7..e242df0 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,54 @@ 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; + int wrap_around = (parser->buffer_prev_data[offset] != '\0'); + + uint32_t i = 0; + if (wrap_around) { + 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]; + } + } + + 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]; + } + + // 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'; +} + /** 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 @@ -735,10 +797,33 @@ 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]; + 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) { @@ -940,7 +1025,7 @@ int json_print_args(json_printer *printer, { va_list ap; char *data; - uint32_t length; + int32_t length; int type, ret; ret = 0; @@ -1016,6 +1101,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 077d35b..be74151 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,14 @@ 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; + char buffer_first_data[LIBJSON_DEFAULT_BUFFER_PREV_DATA_SIZE]; + uint32_t buffer_first_data_lenght; } json_parser; typedef struct json_printer { @@ -157,6 +166,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); @@ -214,6 +234,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);