Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 98 additions & 1 deletion json.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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;
}

Expand All @@ -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
Expand All @@ -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) {
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down
24 changes: 24 additions & 0 deletions json.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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);

Expand Down