From cf623e290a143965727e748e8d668fdf74a654a0 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Fri, 27 Apr 2012 13:21:31 -0400 Subject: [PATCH] Upgraded to yajl version 1.0.9. --- src/libCom/yajl/yajl.c | 13 ++++-- src/libCom/yajl/yajl_encode.c | 15 +++++-- src/libCom/yajl/yajl_encode.h | 6 +++ src/libCom/yajl/yajl_gen.c | 81 ++++++++++++++++++++++------------- src/libCom/yajl/yajl_gen.h | 38 +++++++++++++++- src/libCom/yajl/yajl_parse.h | 18 +++++++- src/libCom/yajl/yajl_parser.c | 11 +++-- src/libCom/yajl/yajl_parser.h | 9 ++-- 8 files changed, 145 insertions(+), 46 deletions(-) diff --git a/src/libCom/yajl/yajl.c b/src/libCom/yajl/yajl.c index 0f32eea05..f353598d8 100644 --- a/src/libCom/yajl/yajl.c +++ b/src/libCom/yajl/yajl.c @@ -96,7 +96,7 @@ yajl_alloc(const yajl_callbacks * callbacks, hand->callbacks = callbacks; hand->ctx = ctx; hand->lexer = yajl_lex_alloc(&(hand->alloc), allowComments, validateUTF8); - hand->errorOffset = 0; + hand->bytesConsumed = 0; hand->decodeBuf = yajl_buf_alloc(&(hand->alloc)); yajl_bs_init(hand->stateStack, &(hand->alloc)); @@ -118,9 +118,8 @@ yajl_status yajl_parse(yajl_handle hand, const unsigned char * jsonText, unsigned int jsonTextLen) { - unsigned int offset = 0; yajl_status status; - status = yajl_do_parse(hand, &offset, jsonText, jsonTextLen); + status = yajl_do_parse(hand, jsonText, jsonTextLen); return status; } @@ -143,6 +142,14 @@ yajl_get_error(yajl_handle hand, int verbose, return yajl_render_error_string(hand, jsonText, jsonTextLen, verbose); } +unsigned int +yajl_get_bytes_consumed(yajl_handle hand) +{ + if (!hand) return 0; + else return hand->bytesConsumed; +} + + void yajl_free_error(yajl_handle hand, unsigned char * str) { diff --git a/src/libCom/yajl/yajl_encode.c b/src/libCom/yajl/yajl_encode.c index fb85d73d3..0d7007da0 100644 --- a/src/libCom/yajl/yajl_encode.c +++ b/src/libCom/yajl/yajl_encode.c @@ -48,6 +48,15 @@ static void CharToHex(unsigned char c, char * hexBuf) void yajl_string_encode(yajl_buf buf, const unsigned char * str, unsigned int len) +{ + yajl_string_encode2((const yajl_print_t) &yajl_buf_append, buf, str, len); +} + +void +yajl_string_encode2(const yajl_print_t print, + void * ctx, + const unsigned char * str, + unsigned int len) { unsigned int beg = 0; unsigned int end = 0; @@ -74,14 +83,14 @@ yajl_string_encode(yajl_buf buf, const unsigned char * str, break; } if (escaped != NULL) { - yajl_buf_append(buf, str + beg, end - beg); - yajl_buf_append(buf, escaped, strlen(escaped)); + print(ctx, (const char *) (str + beg), end - beg); + print(ctx, escaped, strlen(escaped)); beg = ++end; } else { ++end; } } - yajl_buf_append(buf, str + beg, end - beg); + print(ctx, (const char *) (str + beg), end - beg); } static void hexToDigit(unsigned int * val, const unsigned char * hex) diff --git a/src/libCom/yajl/yajl_encode.h b/src/libCom/yajl/yajl_encode.h index 8bd01af5a..d478baa19 100644 --- a/src/libCom/yajl/yajl_encode.h +++ b/src/libCom/yajl/yajl_encode.h @@ -34,6 +34,12 @@ #define __YAJL_ENCODE_H__ #include "yajl_buf.h" +#include "yajl_gen.h" + +void yajl_string_encode2(const yajl_print_t printer, + void * ctx, + const unsigned char * str, + unsigned int length); void yajl_string_encode(yajl_buf buf, const unsigned char * str, unsigned int length); diff --git a/src/libCom/yajl/yajl_gen.c b/src/libCom/yajl/yajl_gen.c index 7e353db42..a10d08297 100644 --- a/src/libCom/yajl/yajl_gen.c +++ b/src/libCom/yajl/yajl_gen.c @@ -35,6 +35,7 @@ #include #define epicsExportSharedSymbols +#include "epicsMath.h" #include "yajl_gen.h" #include "yajl_buf.h" #include "yajl_encode.h" @@ -56,7 +57,8 @@ struct yajl_gen_t unsigned int pretty; const char * indentString; yajl_gen_state state[YAJL_MAX_DEPTH]; - yajl_buf buf; + yajl_print_t print; + void * ctx; /* yajl_buf */ /* memory allocation routines */ yajl_alloc_funcs alloc; }; @@ -64,6 +66,15 @@ struct yajl_gen_t yajl_gen yajl_gen_alloc(const yajl_gen_config * config, const yajl_alloc_funcs * afs) +{ + return yajl_gen_alloc2(NULL, config, afs, NULL); +} + +yajl_gen +yajl_gen_alloc2(const yajl_print_t callback, + const yajl_gen_config * config, + const yajl_alloc_funcs * afs, + void * ctx) { yajl_gen g = NULL; yajl_alloc_funcs afsBuffer; @@ -88,7 +99,14 @@ yajl_gen_alloc(const yajl_gen_config * config, g->pretty = config->beautify; g->indentString = config->indentString ? config->indentString : " "; } - g->buf = yajl_buf_alloc(&(g->alloc)); + + if (callback) { + g->print = callback; + g->ctx = ctx; + } else { + g->print = (yajl_print_t)&yajl_buf_append; + g->ctx = yajl_buf_alloc(&(g->alloc)); + } return g; } @@ -96,18 +114,18 @@ yajl_gen_alloc(const yajl_gen_config * config, void yajl_gen_free(yajl_gen g) { - yajl_buf_free(g->buf); + if (g->print == (yajl_print_t)&yajl_buf_append) yajl_buf_free((yajl_buf)g->ctx); YA_FREE(&(g->alloc), g); } #define INSERT_SEP \ if (g->state[g->depth] == yajl_gen_map_key || \ g->state[g->depth] == yajl_gen_in_array) { \ - yajl_buf_append(g->buf, ",", 1); \ - if (g->pretty) yajl_buf_append(g->buf, "\n", 1); \ + g->print(g->ctx, ",", 1); \ + if (g->pretty) g->print(g->ctx, "\n", 1); \ } else if (g->state[g->depth] == yajl_gen_map_val) { \ - yajl_buf_append(g->buf, ":", 1); \ - if (g->pretty) yajl_buf_append(g->buf, " ", 1); \ + g->print(g->ctx, ":", 1); \ + if (g->pretty) g->print(g->ctx, " ", 1); \ } #define INSERT_WHITESPACE \ @@ -115,8 +133,8 @@ yajl_gen_free(yajl_gen g) if (g->state[g->depth] != yajl_gen_map_val) { \ unsigned int _i; \ for (_i=0;_idepth;_i++) \ - yajl_buf_append(g->buf, g->indentString, \ - strlen(g->indentString)); \ + g->print(g->ctx, g->indentString, \ + strlen(g->indentString)); \ } \ } @@ -158,7 +176,7 @@ yajl_gen_free(yajl_gen g) #define FINAL_NEWLINE \ if (g->pretty && g->state[g->depth] == yajl_gen_complete) \ - yajl_buf_append(g->buf, "\n", 1); + g->print(g->ctx, "\n", 1); yajl_gen_status yajl_gen_integer(yajl_gen g, long int number) @@ -166,7 +184,7 @@ yajl_gen_integer(yajl_gen g, long int number) char i[32]; ENSURE_VALID_STATE; ENSURE_NOT_KEY; INSERT_SEP; INSERT_WHITESPACE; sprintf(i, "%ld", number); - yajl_buf_append(g->buf, i, strlen(i)); + g->print(g->ctx, i, strlen(i)); APPENDED_ATOM; FINAL_NEWLINE; return yajl_gen_status_ok; @@ -176,9 +194,11 @@ yajl_gen_status yajl_gen_double(yajl_gen g, double number) { char i[32]; - ENSURE_VALID_STATE; ENSURE_NOT_KEY; INSERT_SEP; INSERT_WHITESPACE; + ENSURE_VALID_STATE; ENSURE_NOT_KEY; + if (isnan(number) || isinf(number)) return yajl_gen_invalid_number; + INSERT_SEP; INSERT_WHITESPACE; sprintf(i, "%g", number); - yajl_buf_append(g->buf, i, strlen(i)); + g->print(g->ctx, i, strlen(i)); APPENDED_ATOM; FINAL_NEWLINE; return yajl_gen_status_ok; @@ -188,7 +208,7 @@ yajl_gen_status yajl_gen_number(yajl_gen g, const char * s, unsigned int l) { ENSURE_VALID_STATE; ENSURE_NOT_KEY; INSERT_SEP; INSERT_WHITESPACE; - yajl_buf_append(g->buf, s, l); + g->print(g->ctx, s, l); APPENDED_ATOM; FINAL_NEWLINE; return yajl_gen_status_ok; @@ -199,9 +219,9 @@ yajl_gen_string(yajl_gen g, const unsigned char * str, unsigned int len) { ENSURE_VALID_STATE; INSERT_SEP; INSERT_WHITESPACE; - yajl_buf_append(g->buf, "\"", 1); - yajl_string_encode(g->buf, str, len); - yajl_buf_append(g->buf, "\"", 1); + g->print(g->ctx, "\"", 1); + yajl_string_encode2(g->print, g->ctx, str, len); + g->print(g->ctx, "\"", 1); APPENDED_ATOM; FINAL_NEWLINE; return yajl_gen_status_ok; @@ -211,7 +231,7 @@ yajl_gen_status yajl_gen_null(yajl_gen g) { ENSURE_VALID_STATE; ENSURE_NOT_KEY; INSERT_SEP; INSERT_WHITESPACE; - yajl_buf_append(g->buf, "null", strlen("null")); + g->print(g->ctx, "null", strlen("null")); APPENDED_ATOM; FINAL_NEWLINE; return yajl_gen_status_ok; @@ -223,7 +243,7 @@ yajl_gen_bool(yajl_gen g, int boolean) const char * val = boolean ? "true" : "false"; ENSURE_VALID_STATE; ENSURE_NOT_KEY; INSERT_SEP; INSERT_WHITESPACE; - yajl_buf_append(g->buf, val, strlen(val)); + g->print(g->ctx, val, strlen(val)); APPENDED_ATOM; FINAL_NEWLINE; return yajl_gen_status_ok; @@ -236,8 +256,8 @@ yajl_gen_map_open(yajl_gen g) INCREMENT_DEPTH; g->state[g->depth] = yajl_gen_map_start; - yajl_buf_append(g->buf, "{", 1); - if (g->pretty) yajl_buf_append(g->buf, "\n", 1); + g->print(g->ctx, "{", 1); + if (g->pretty) g->print(g->ctx, "\n", 1); FINAL_NEWLINE; return yajl_gen_status_ok; } @@ -247,10 +267,10 @@ yajl_gen_map_close(yajl_gen g) { ENSURE_VALID_STATE; (g->depth)--; - if (g->pretty) yajl_buf_append(g->buf, "\n", 1); + if (g->pretty) g->print(g->ctx, "\n", 1); APPENDED_ATOM; INSERT_WHITESPACE; - yajl_buf_append(g->buf, "}", 1); + g->print(g->ctx, "}", 1); FINAL_NEWLINE; return yajl_gen_status_ok; } @@ -261,8 +281,8 @@ yajl_gen_array_open(yajl_gen g) ENSURE_VALID_STATE; ENSURE_NOT_KEY; INSERT_SEP; INSERT_WHITESPACE; INCREMENT_DEPTH; g->state[g->depth] = yajl_gen_array_start; - yajl_buf_append(g->buf, "[", 1); - if (g->pretty) yajl_buf_append(g->buf, "\n", 1); + g->print(g->ctx, "[", 1); + if (g->pretty) g->print(g->ctx, "\n", 1); FINAL_NEWLINE; return yajl_gen_status_ok; } @@ -271,11 +291,11 @@ yajl_gen_status yajl_gen_array_close(yajl_gen g) { ENSURE_VALID_STATE; - if (g->pretty) yajl_buf_append(g->buf, "\n", 1); + if (g->pretty) g->print(g->ctx, "\n", 1); (g->depth)--; APPENDED_ATOM; INSERT_WHITESPACE; - yajl_buf_append(g->buf, "]", 1); + g->print(g->ctx, "]", 1); FINAL_NEWLINE; return yajl_gen_status_ok; } @@ -284,13 +304,14 @@ yajl_gen_status yajl_gen_get_buf(yajl_gen g, const unsigned char ** buf, unsigned int * len) { - *buf = yajl_buf_data(g->buf); - *len = yajl_buf_len(g->buf); + if (g->print != (yajl_print_t)&yajl_buf_append) return yajl_gen_no_buf; + *buf = yajl_buf_data((yajl_buf)g->ctx); + *len = yajl_buf_len((yajl_buf)g->ctx); return yajl_gen_status_ok; } void yajl_gen_clear(yajl_gen g) { - yajl_buf_clear(g->buf); + if (g->print == (yajl_print_t)&yajl_buf_append) yajl_buf_clear((yajl_buf)g->ctx); } diff --git a/src/libCom/yajl/yajl_gen.h b/src/libCom/yajl/yajl_gen.h index 1ae320eae..8efabd073 100644 --- a/src/libCom/yajl/yajl_gen.h +++ b/src/libCom/yajl/yajl_gen.h @@ -57,12 +57,23 @@ extern "C" { * state */ yajl_gen_in_error_state, /** A complete JSON document has been generated */ - yajl_gen_generation_complete + yajl_gen_generation_complete, + /** yajl_gen_double was passed an invalid floating point value + * (infinity or NaN). */ + yajl_gen_invalid_number, + /** A print callback was passed in, so there is no internal + * buffer to get from */ + yajl_gen_no_buf } yajl_gen_status; /** an opaque handle to a generator */ typedef struct yajl_gen_t * yajl_gen; + /** a callback used for "printing" the results. */ + typedef void (*yajl_print_t)(void * ctx, + const char * str, + unsigned int len); + /** configuration structure for the generator */ typedef struct { /** generate indented (beautiful) output */ @@ -86,10 +97,35 @@ extern "C" { YAJL_API yajl_gen yajl_gen_alloc(const yajl_gen_config * config, const yajl_alloc_funcs * allocFuncs); + /** allocate a generator handle that will print to the specified + * callback rather than storing the results in an internal buffer. + * \param callback a pointer to a printer function. May be NULL + * in which case, the results will be store in an + * internal buffer. + * \param config a pointer to a structure containing parameters + * which configure the behavior of the json + * generator. + * \param allocFuncs an optional pointer to a structure which allows + * the client to overide the memory allocation + * used by yajl. May be NULL, in which case + * malloc/free/realloc will be used. + * \param ctx a context pointer that will be passed to the + * printer callback. + * + * \returns an allocated handle on success, NULL on failure (bad params) + */ + YAJL_API yajl_gen yajl_gen_alloc2(const yajl_print_t callback, + const yajl_gen_config * config, + const yajl_alloc_funcs * allocFuncs, + void * ctx); + /** free a generator handle */ YAJL_API void yajl_gen_free(yajl_gen handle); YAJL_API yajl_gen_status yajl_gen_integer(yajl_gen hand, long int number); + /** generate a floating point number. number may not be infinity or + * NaN, as these have no representation in JSON. In these cases the + * generator will return 'yajl_gen_invalid_number' */ YAJL_API yajl_gen_status yajl_gen_double(yajl_gen hand, double number); YAJL_API yajl_gen_status yajl_gen_number(yajl_gen hand, const char * num, diff --git a/src/libCom/yajl/yajl_parse.h b/src/libCom/yajl/yajl_parse.h index d6b26baa7..b4de64bbd 100644 --- a/src/libCom/yajl/yajl_parse.h +++ b/src/libCom/yajl/yajl_parse.h @@ -153,7 +153,7 @@ extern "C" { * * \param hand - a handle to the json parser allocated with yajl_alloc */ - yajl_status yajl_parse_complete(yajl_handle hand); + YAJL_API yajl_status yajl_parse_complete(yajl_handle hand); /** get an error string describing the state of the * parse. @@ -162,13 +162,27 @@ extern "C" { * text where the error occured, along with an arrow pointing to * the specific char. * - * A dynamically allocated string will be returned which should + * \returns A dynamically allocated string will be returned which should * be freed with yajl_free_error */ YAJL_API unsigned char * yajl_get_error(yajl_handle hand, int verbose, const unsigned char * jsonText, unsigned int jsonTextLength); + /** + * get the amount of data consumed from the last chunk passed to YAJL. + * + * In the case of a successful parse this can help you understand if + * the entire buffer was consumed (which will allow you to handle + * "junk at end of input". + * + * In the event an error is encountered during parsing, this function + * affords the client a way to get the offset into the most recent + * chunk where the error occured. 0 will be returned if no error + * was encountered. + */ + YAJL_API unsigned int yajl_get_bytes_consumed(yajl_handle hand); + /** free an error returned from yajl_get_error */ YAJL_API void yajl_free_error(yajl_handle hand, unsigned char * str); diff --git a/src/libCom/yajl/yajl_parser.c b/src/libCom/yajl/yajl_parser.c index e1d5f2bf1..1c15f8e1e 100644 --- a/src/libCom/yajl/yajl_parser.c +++ b/src/libCom/yajl/yajl_parser.c @@ -49,7 +49,7 @@ unsigned char * yajl_render_error_string(yajl_handle hand, const unsigned char * jsonText, unsigned int jsonTextLen, int verbose) { - unsigned int offset = hand->errorOffset; + unsigned int offset = hand->bytesConsumed; unsigned char * str; const char * errorType = NULL; const char * errorText = NULL; @@ -137,12 +137,16 @@ yajl_render_error_string(yajl_handle hand, const unsigned char * jsonText, yajl_status -yajl_do_parse(yajl_handle hand, unsigned int * offset, - const unsigned char * jsonText, unsigned int jsonTextLen) +yajl_do_parse(yajl_handle hand, const unsigned char * jsonText, + unsigned int jsonTextLen) { yajl_tok tok; const unsigned char * buf; unsigned int bufLen; + unsigned int * offset = &(hand->bytesConsumed); + + *offset = 0; + around_again: switch (yajl_bs_current(hand->stateStack)) { @@ -150,7 +154,6 @@ yajl_do_parse(yajl_handle hand, unsigned int * offset, return yajl_status_ok; case yajl_state_lexical_error: case yajl_state_parse_error: - hand->errorOffset = *offset; return yajl_status_error; case yajl_state_start: case yajl_state_map_need_val: diff --git a/src/libCom/yajl/yajl_parser.h b/src/libCom/yajl/yajl_parser.h index f8bc8ee9a..c9d29d436 100644 --- a/src/libCom/yajl/yajl_parser.h +++ b/src/libCom/yajl/yajl_parser.h @@ -58,7 +58,10 @@ struct yajl_handle_t { void * ctx; yajl_lexer lexer; const char * parseError; - unsigned int errorOffset; + /* the number of bytes consumed from the last client buffer, + * in the case of an error this will be an error offset, in the + * case of an error this can be used as the error offset */ + unsigned int bytesConsumed; /* temporary storage for decoded strings */ yajl_buf decodeBuf; /* a stack of states. access with yajl_state_XXX routines */ @@ -68,8 +71,8 @@ struct yajl_handle_t { }; yajl_status -yajl_do_parse(yajl_handle handle, unsigned int * offset, - const unsigned char * jsonText, unsigned int jsonTextLen); +yajl_do_parse(yajl_handle handle, const unsigned char * jsonText, + unsigned int jsonTextLen); unsigned char * yajl_render_error_string(yajl_handle hand, const unsigned char * jsonText,