From f2852ebd11a2cf70a5a072b8c3c1feb448831f6d Mon Sep 17 00:00:00 2001 From: scottmk Date: Sat, 14 Aug 2010 11:09:47 +0000 Subject: [PATCH] Eliminate the old JSON parser, implemented in osrf_json_parser.c and the associated header osrf_json_utils.h. This parser has been completely replaced by a newer one implemented in osrf_parse_json.c, plus an incremental JSON parser (so far unused) in jsonpush.c.. The even older parser of JSON-with-comments is not affected. D include/opensrf/osrf_json_utils.h M include/opensrf/osrf_json.h D src/libopensrf/osrf_json_parser.c M src/libopensrf/osrf_json_object.c M src/libopensrf/Makefile.json M src/libopensrf/osrf_json_tools.c M src/libopensrf/Makefile.am M src/libopensrf/osrf_parse_json.c M Makefile.am git-svn-id: svn://svn.open-ils.org/OpenSRF/trunk@2000 9efc2488-bf62-4759-914b-345cdb29e865 --- Makefile.am | 1 - include/opensrf/osrf_json.h | 209 +-------- include/opensrf/osrf_json_utils.h | 108 ----- src/libopensrf/Makefile.am | 2 - src/libopensrf/Makefile.json | 10 +- src/libopensrf/osrf_json_object.c | 3 +- src/libopensrf/osrf_json_parser.c | 692 ------------------------------ src/libopensrf/osrf_json_tools.c | 1 - src/libopensrf/osrf_parse_json.c | 1 - 9 files changed, 8 insertions(+), 1019 deletions(-) delete mode 100644 include/opensrf/osrf_json_utils.h delete mode 100644 src/libopensrf/osrf_json_parser.c diff --git a/Makefile.am b/Makefile.am index fc5acc6..4e9abc1 100644 --- a/Makefile.am +++ b/Makefile.am @@ -95,7 +95,6 @@ opensrfinclude_HEADERS = $(OSRFINC)/log.h \ $(OSRFINC)/osrfConfig.h \ $(OSRFINC)/osrf_hash.h \ $(OSRFINC)/osrf_json.h \ - $(OSRFINC)/osrf_json_utils.h \ $(OSRFINC)/osrf_json_xml.h \ $(OSRFINC)/osrf_legacy_json.h \ $(OSRFINC)/osrf_list.h \ diff --git a/include/opensrf/osrf_json.h b/include/opensrf/osrf_json.h index 23eadee..4431ee3 100644 --- a/include/opensrf/osrf_json.h +++ b/include/opensrf/osrf_json.h @@ -56,55 +56,6 @@ GNU General Public License for more details. extern "C" { #endif -/* parser states */ -/** - @name Parser states - @brief Used internally by a JSON parser. - - A jsonParserContext stores these values in order to remember where the parser is in the - parsing. -*/ -/*@{*/ -#define JSON_STATE_IN_OBJECT 0x1 -#define JSON_STATE_IN_ARRAY 0x2 -#define JSON_STATE_IN_STRING 0x4 -#define JSON_STATE_IN_UTF 0x8 -#define JSON_STATE_IN_ESCAPE 0x10 -#define JSON_STATE_IN_KEY 0x20 -#define JSON_STATE_IN_NULL 0x40 -#define JSON_STATE_IN_TRUE 0x80 -#define JSON_STATE_IN_FALSE 0x100 -#define JSON_STATE_IN_NUMBER 0x200 -#define JSON_STATE_IS_INVALID 0x400 -#define JSON_STATE_IS_DONE 0x800 -#define JSON_STATE_START_COMMEN 0x1000 -#define JSON_STATE_IN_COMMENT 0x2000 -#define JSON_STATE_END_COMMENT 0x4000 -/*@}*/ - -/** - @name Parser state operations - @ Macros to manipulate the parser state in a jsonParserContext. -*/ -/*@{*/ -/** Set a state. */ -#define JSON_STATE_SET(ctx,s) ctx->state |= s; -/** Unset a state. */ -#define JSON_STATE_REMOVE(ctx,s) ctx->state &= ~s; -/** Check if a state is set. */ -#define JSON_STATE_CHECK(ctx,s) (ctx->state & s) ? 1 : 0 -/** Pop a state off the stack. */ -#define JSON_STATE_POP(ctx) osrfListPop( ctx->stateStack ); -/** Push a state on the stack. */ -#define JSON_STATE_PUSH(ctx, state) osrfListPush( ctx->stateStack,(void*) state ); -/** Check which container type we're currently in. */ -#define JSON_STATE_PEEK(ctx) osrfListGetIndex(ctx->stateStack, ctx->stateStack->size -1) -/** Compare stack values. */ -#define JSON_STATE_CHECK_STACK(ctx, s) (JSON_STATE_PEEK(ctx) == (void*) s ) ? 1 : 0 -/** Check if a parser state is set. */ -#define JSON_PARSE_FLAG_CHECK(ctx, f) (ctx->flags & f) ? 1 : 0 -/*@}*/ - /** @name JSON types @brief Macros defining types of jsonObject. @@ -121,12 +72,6 @@ extern "C" { #define JSON_BOOL 5 /*@}*/ -/** - This macro is used only by a JSON parser. It probably has no business being published - in a header. -*/ -#define JSON_PARSE_LAST_CHUNK 0x1 /* this is the last part of the string we're parsing */ - /** @name JSON extensions @@ -146,55 +91,6 @@ extern "C" { #endif /*@}*/ -/** - @brief Stores the current state of a JSON parser. - - One form of JSON parser operates as a finite state machine. It stores the various - JSON_STATE_* values in order to keep track of what it's doing. It also maintains a - stack of previous states in order to keep track of nesting. - - The internals of this struct are published in the header in order to provide the client - with a window into the operations of the parser. By installing its own callback functions, - and possibly by tinkering with the insides of the jsonParserContext, the client code can - customize the behavior of the parser. - - In practice only the default callbacks are ever installed, at this writing. The potential - for customized parsing is unused. -*/ -struct jsonParserContextStruct { - int state; /**< What are we currently parsing. */ - const char* chunk; /**< The chunk we're currently parsing. */ - int index; /**< Where we are in parsing the current chunk. */ - int chunksize; /**< Size of the current chunk. */ - int flags; /**< Parser flags. */ - osrfList* stateStack; /**< The nest of object/array states. */ - growing_buffer* buffer; /**< Buffer for building strings, numbers, and keywords. */ - growing_buffer* utfbuf; /**< Holds the current unicode characters. */ - void* userData; /**< Opaque user pointer. We ignore this. */ - const struct jsonParserHandlerStruct* handler; /**< The event handler struct. */ -}; -typedef struct jsonParserContextStruct jsonParserContext; - -/** - @brief A collection of function pointers for customizing parser behavior. - - The client code can install pointers to its own functions in this struct, in order to - customize the behavior of the parser at various points in the parsing. -*/ -struct jsonParserHandlerStruct { - void (*handleStartObject) (void* userData); - void (*handleObjectKey) (void* userData, char* key); - void (*handleEndObject) (void* userData); - void (*handleStartArray) (void* userData); - void (*handleEndArray) (void* userData); - void (*handleNull) (void* userData); - void (*handleString) (void* userData, char* string); - void (*handleBool) (void* userData, int boolval); - void (*handleNumber) (void* userData, const char* numstr); - void (*handleError) (void* userData, char* err, ...); -}; -typedef struct jsonParserHandlerStruct jsonParserHandler; - /** @brief Representation of a JSON string in memory @@ -238,109 +134,11 @@ struct _jsonIteratorStruct { }; typedef struct _jsonIteratorStruct jsonIterator; - - -/** - @brief Allocate a new parser context object. - @param handler Pointer to a collection of function pointers for callback functions. - @param userData Opaque user pointer which is available to callbacks; ignored by the parser. - @return An allocated parser context, or NULL on error. -*/ -jsonParserContext* jsonNewParser( const jsonParserHandler* handler, void* userData); - -/** - @brief Free a jsonParserContext. - @param ctx Pointer to the jsonParserContext to be freed. -*/ -void jsonParserFree( jsonParserContext* ctx ); - -/** - @brief Parse a chunk of data. - @param ctx Pointer to the parser context. - @param data Pointer the data to parse. - @param datalen The size of the chunk to parse. - @param flags Reserved. -*/ -int jsonParseChunk( jsonParserContext* ctx, const char* data, int datalen, int flags ); - -/** - @name Parsing functions - - There are two sets of parsing functions, which are mostly plug-compatible with each other. - The older series: - - - jsonParseString() - - jsonParseStringRaw() - - jsonParseStringFmt() - - ...and a newer series: - - - jsonParse(); - - jsonParseRaw(); - - jsonParseFmt(); - - The first series is based on a finite state machine. Its innards are accessible, in - theory, through the jsonParserContext structure and through callback functions. In - practice this flexibility is unused at this writing. - - The second series is based on recursive descent. It doesn't use the jsonParserContext - structure, nor does it accept callback functions. However it is faster than the first - parser. In addition its syntax checking is much stricter -- it catches many kinds of - syntax errors that slip through the first parser. -*/ -/*@{*/ -/** - @brief Parse a JSON string, with decoding of classname hints. - @param str Pointer to the JSON string to parse. - @return A pointer to the resulting JSON object, or NULL on error. - - If any node in the jsonObject tree is of type JSON_HASH, with a tag of JSON_CLASS_KEY - and another tag of JSON_DATA_KEY, the parser will collapse a level. The subobject - tagged with JSON_DATA_KEY will replace the JSON_HASH, and the string tagged as - JSON_CLASS_KEY will be stored as its classname. If there is no tag of JSON_DATA_KEY, - the hash will be replaced by a jsonObject of type JSON_NULL. - - The calling code is responsible for freeing the resulting jsonObject. -*/ -jsonObject* jsonParseString( const char* str ); - -/** - @brief Parse a JSON string, with no decoding of classname hints. - @param str Pointer to the JSON string to parse. - @return A pointer to the resulting JSON object, or NULL on error. - - This function is similar to jsonParseString(), except that it does not give any special - treatment to a JSON_HASH with the JSON_CLASS_KEY tag. - - The calling code is responsible for freeing the resulting jsonObject. -*/ -jsonObject* jsonParseStringRaw( const char* str ); - -/** - @brief Parse a JSON string received as a printf-style format string. - @param str A printf-style format string. Subsequent arguments, if any, are formatted - and inserted into the JSON string before parsing. - @return A pointer to the resulting JSON object, or NULL on error. - - Unlike jsonParseString(), this function does not give any special treatment to a - JSON_HASH with tags JSON_CLASS_KEY or JSON_DATA_KEY. - - The calling code is responsible for freeing the resulting jsonObject. -*/ -jsonObject* jsonParseStringFmt( const char* str, ... ); - jsonObject* jsonParse( const char* str ); + jsonObject* jsonParseRaw( const char* str ); -jsonObject* jsonParseFmt( const char* s, ... ); -/*@}*/ -/** - @brief Parses a JSON string, using a customized error handler. - @param errorHandler A function pointer to an error-handling function. - @param str The string to parse. - @return The resulting JSON object, or NULL on error. -*/ -jsonObject* jsonParseStringHandleError( void (*errorHandler) (const char*), char* str, ... ); +jsonObject* jsonParseFmt( const char* str, ... ); jsonObject* jsonNewObject(const char* data); @@ -444,9 +242,6 @@ jsonObject* jsonObjectFindPath( const jsonObject* obj, const char* path, ... ); */ char* jsonFormatString( const char* jsonString ); -/* sets the error handler for all parsers */ -void jsonSetGlobalErrorHandler(void (*errorHandler) (const char*)); - /* ------------------------------------------------------------------------- */ /* * The following methods provide a facility for serializing and diff --git a/include/opensrf/osrf_json_utils.h b/include/opensrf/osrf_json_utils.h deleted file mode 100644 index 5331574..0000000 --- a/include/opensrf/osrf_json_utils.h +++ /dev/null @@ -1,108 +0,0 @@ -/* -Copyright (C) 2006 Georgia Public Library Service -Bill Erickson - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. -*/ - -#ifndef OSRF_JSON_UTILS_H -#define OSRF_JSON_UTILS_H - -#ifdef __cplusplus -extern "C" { -#endif - -/* ----------------------------------------------------------------------- */ -/* Clients need not include this file. These are internal utilities only */ -/* ----------------------------------------------------------------------- */ - -#define JSON_EAT_WS(ctx) \ - while( ctx->index < ctx->chunksize ) { \ - if(!isspace(ctx->chunk[ctx->index])) break; \ - ctx->index++; \ - } \ - if( ctx->index >= ctx->chunksize ) return 0; \ - c = ctx->chunk[ctx->index]; - -#define JSON_CACHE_DATA(ctx, buf, size) \ - while( (buf->n_used < size) && (ctx->index < ctx->chunksize) ) \ - buffer_add_char(buf, ctx->chunk[ctx->index++]); - -#define JSON_LOG_MARK __FILE__,__LINE__ - -#define JSON_NUMBER_CHARS "0123456789.+-eE" - -/** - * These are the callbacks through which the top level parser - * builds objects via the push parser - */ -void _jsonHandleStartObject(void*); -void _jsonHandleObjectKey(void*, char* key); -void _jsonHandleEndObject(void*); -void _jsonHandleStartArray(void*); -void _jsonHandleEndArray(void*); -void _jsonHandleNull(void*); -void _jsonHandleString(void*, char* string); -void _jsonHandleBool(void*, int boolval); -void _jsonHandleNumber(void*, const char* numstr); -void _jsonHandleError(void*, char* str, ...); - -struct jsonInternalParserStruct { - jsonParserContext* ctx; - jsonObject* obj; - jsonObject* current; - char* lastkey; - void (*handleError) (const char*); -}; -typedef struct jsonInternalParserStruct jsonInternalParser; - -jsonInternalParser* _jsonNewInternalParser(); -void _jsonInternalParserFree(jsonInternalParser* p); - -/** - * Calls the defined error handler with the given error message. - * @return -1 - */ -int _jsonParserError( jsonParserContext* ctx, char* err, ... ); - - -/** - * - * @return 0 on continue, 1 if it goes past the end of the string, -1 on error - */ -int _jsonParserHandleUnicode( jsonParserContext* ctx ); - - -/** - * @param type 0 for null, 1 for true, 2 for false - * @return 0 on continue, 1 if it goes past the end of the string, -1 on error - */ -int _jsonParserHandleMatch( jsonParserContext* ctx, int type ); - -/** - * @return 0 on continue, 1 on end of chunk, -1 on error - */ -int _jsonParserHandleString( jsonParserContext* ctx ); - -/** - * @return 0 on continue, 1 on end of chunk, -1 on error - */ -int _jsonParserHandleNumber( jsonParserContext* ctx ); - - -void _jsonInsertParserItem( jsonInternalParser* p, jsonObject* newo ); - -#ifdef __cplusplus -} -#endif - -#endif - diff --git a/src/libopensrf/Makefile.am b/src/libopensrf/Makefile.am index c2429a5..c8e4f8b 100644 --- a/src/libopensrf/Makefile.am +++ b/src/libopensrf/Makefile.am @@ -65,12 +65,10 @@ TARGS_HEADS = $(OSRF_INC)/transport_message.h \ $(OSRF_INC)/socket_bundle.h \ $(OSRF_INC)/sha.h \ $(OSRF_INC)/string_array.h \ - $(OSRF_INC)/osrf_json_utils.h \ $(OSRF_INC)/osrf_json_xml.h JSON_TARGS = osrf_json_object.c\ osrf_parse_json.c \ - osrf_json_parser.c \ osrf_json_tools.c \ osrf_legacy_json.c \ osrf_json_xml.c diff --git a/src/libopensrf/Makefile.json b/src/libopensrf/Makefile.json index 8cbc312..46241b2 100644 --- a/src/libopensrf/Makefile.json +++ b/src/libopensrf/Makefile.json @@ -7,7 +7,7 @@ # OSRF_INC="../../include/opensrf" LDLIBS="-lxml2" \ # make -f Makefile.json standalone # ------------------------------------------------------------------ -TARGETS = osrf_json_object.o osrf_json_parser.o osrf_json_tools.o osrf_legacy_json.o osrf_json_xml.o +TARGETS = osrf_json_object.o osrf_parse_json.o osrf_json_tools.o osrf_legacy_json.o osrf_json_xml.o # these are only needed when compiling the standalone version EXT_TARGETS = osrf_list.o osrf_hash.o utils.o log.o md5.o string_array.o @@ -17,10 +17,10 @@ all: $(TARGETS) standalone: $(TARGETS) $(EXT_TARGETS) $(CC) -shared -W1 $(CFLAGS) $(LDFLAGS) $(LDLIBS) $(TARGETS) $(EXT_TARGETS) -o libosrf_json.so -osrf_json_object.o: osrf_json_object.c $(OSRF_INC)/osrf_json.h $(OSRF_INC)/osrf_json_utils.h -osrf_json_parser.o: osrf_json_parser.c $(OSRF_INC)/osrf_json.h $(OSRF_INC)/osrf_json_utils.h -osrf_json_tools.o: osrf_json_tools.c $(OSRF_INC)/osrf_json.h $(OSRF_INC)/osrf_json_utils.h -osrf_legacy_json.o: osrf_legacy_json.c $(OSRF_INC)/osrf_json.h $(OSRF_INC)/osrf_json_utils.h +osrf_json_object.o: osrf_json_object.c $(OSRF_INC)/osrf_json.h +osrf_parse_json.o: osrf_parse_json.c $(OSRF_INC)/osrf_json.h +osrf_json_tools.o: osrf_json_tools.c $(OSRF_INC)/osrf_json.h +osrf_legacy_json.o: osrf_legacy_json.c $(OSRF_INC)/osrf_json.h osrf_json_xml.o: osrf_json_xml.c $(OSRF_INC)/osrf_json.h $(OSRF_INC)/osrf_json_xml.h diff --git a/src/libopensrf/osrf_json_object.c b/src/libopensrf/osrf_json_object.c index 2ef6e3f..954bc8a 100644 --- a/src/libopensrf/osrf_json_object.c +++ b/src/libopensrf/osrf_json_object.c @@ -30,7 +30,6 @@ GNU General Public License for more details. #include #include #include -#include #include /* cleans up an object if it is morphing another object, also @@ -479,7 +478,7 @@ const jsonObject* jsonObjectGetKeyConst( const jsonObject* obj, const char* key @brief Recursively traverse a jsonObject, translating it into a JSON string. @param obj Pointer to the jsonObject to be translated. @param buf Pointer to a growing_buffer that will receive the JSON string. - @param do_classname Boolean; if true, expand class names. + @param do_classname Boolean; if true, expand (i.e. encode) class names. @param second_pass Boolean; should always be false except for some recursive calls. If @a do_classname is true, expand any class names, as described in the discussion of diff --git a/src/libopensrf/osrf_json_parser.c b/src/libopensrf/osrf_json_parser.c deleted file mode 100644 index fb6e61d..0000000 --- a/src/libopensrf/osrf_json_parser.c +++ /dev/null @@ -1,692 +0,0 @@ -/* -Copyright (C) 2006 Georgia Public Library Service -Bill Erickson - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. -*/ - -#include -#include -#include - - -/* if the client sets a global error handler, this will point to it */ -static void (*jsonClientErrorCallback) (const char*) = NULL; - -/* these are the handlers for our internal parser */ -static const jsonParserHandler jsonInternalParserHandler = { - _jsonHandleStartObject, - _jsonHandleObjectKey, - _jsonHandleEndObject, - _jsonHandleStartArray, - _jsonHandleEndArray, - _jsonHandleNull, - _jsonHandleString, - _jsonHandleBool, - _jsonHandleNumber, - _jsonHandleError -}; - -static jsonParserContext staticContext; -static int staticContextInUse = 0; // boolean - -static jsonInternalParser staticParser; -static int staticParserInUse = 0; // boolean - -jsonParserContext* jsonNewParser( const jsonParserHandler* handler, void* userData) { - jsonParserContext* ctx; - - // Use the static instance of jsonParserContext, - // if it's available - - if( staticContextInUse ) - OSRF_MALLOC(ctx, sizeof(jsonParserContext)); - else { - ctx = &staticContext; - staticContextInUse = 1; - } - - ctx->stateStack = osrfNewList(); - ctx->buffer = buffer_init(512); - ctx->utfbuf = buffer_init(5); - ctx->handler = handler; - ctx->state = 0; - ctx->index = 0; - ctx->chunksize = 0; - ctx->flags = 0; - ctx->chunk = NULL; - ctx->userData = userData; - return ctx; -} - -void jsonParserFree( jsonParserContext* ctx ) { - if(!ctx) return; - buffer_free(ctx->buffer); - buffer_free(ctx->utfbuf); - osrfListFree(ctx->stateStack); - - // if the jsonParserContext was allocated - // dynamically, then free it - - if( &staticContext == ctx ) - staticContextInUse = 0; - else - free(ctx); -} - - -void jsonSetGlobalErrorHandler(void (*errorHandler) (const char*)) { - jsonClientErrorCallback = errorHandler; -} - - -int _jsonParserError( jsonParserContext* ctx, char* err, ... ) { - if( ctx->handler->handleError ) { - VA_LIST_TO_STRING(err); - - // Determine the beginning and ending points of a JSON - // fragment to display, from the vicinity of the error - - int pre = ctx->index - 15; - if( pre < 0 ) pre = 0; - int post= ctx->index + 15; - if( post >= ctx->chunksize ) post = ctx->chunksize - 1; - - // Copy the fragment into a buffer - - int len = post - pre + 1; // length of fragment - char buf[len + 1]; - memcpy( buf, ctx->chunk + pre, len ); - buf[ len ] = '\0'; - - // Issue an error message - - ctx->handler->handleError( ctx->userData, - "*JSON Parser Error\n - char = %c\n " - "- index = %d\n - near => %s\n - %s", - ctx->chunk[ctx->index], ctx->index, buf, VA_BUF ); - } - JSON_STATE_SET(ctx, JSON_STATE_IS_INVALID); - return -1; -} - - -int _jsonParserHandleUnicode( jsonParserContext* ctx ) { - - /* collect as many of the utf characters as we can in this chunk */ - JSON_CACHE_DATA(ctx, ctx->utfbuf, 4); - - /* we ran off the end of the chunk */ - if( ctx->utfbuf->n_used < 4 ) { - JSON_STATE_SET(ctx, JSON_STATE_IN_UTF); - return 1; - } - - ctx->index--; /* push it back to index of the final utf char */ - - /* ----------------------------------------------------------------------- */ - /* We have all of the escaped unicode data. Write it to the buffer */ - /* The following chunk is used with permission from - * json-c http://oss.metaparadigm.com/json-c/ - */ - #define hexdigit(x) ( ((x) <= '9') ? (x) - '0' : ((x) & 7) + 9) - unsigned char utf_out[4]; - memset(utf_out, 0, sizeof(utf_out)); - char* buf = ctx->utfbuf->buf; - - unsigned int ucs_char = - (hexdigit(buf[0] ) << 12) + - (hexdigit(buf[1]) << 8) + - (hexdigit(buf[2]) << 4) + - hexdigit(buf[3]); - - if (ucs_char < 0x80) { - utf_out[0] = ucs_char; - OSRF_BUFFER_ADD(ctx->buffer, (char*)utf_out); - - } else if (ucs_char < 0x800) { - utf_out[0] = 0xc0 | (ucs_char >> 6); - utf_out[1] = 0x80 | (ucs_char & 0x3f); - OSRF_BUFFER_ADD(ctx->buffer, (char*)utf_out); - - } else { - utf_out[0] = 0xe0 | (ucs_char >> 12); - utf_out[1] = 0x80 | ((ucs_char >> 6) & 0x3f); - utf_out[2] = 0x80 | (ucs_char & 0x3f); - OSRF_BUFFER_ADD(ctx->buffer, (char*)utf_out); - } - /* ----------------------------------------------------------------------- */ - /* ----------------------------------------------------------------------- */ - - JSON_STATE_REMOVE(ctx, JSON_STATE_IN_UTF); - JSON_STATE_REMOVE(ctx, JSON_STATE_IN_ESCAPE); - OSRF_BUFFER_RESET(ctx->utfbuf); - return 0; -} - - - -/* type : 0=null, 1=true, 2=false */ -int _jsonParserHandleMatch( jsonParserContext* ctx, int type ) { - - switch(type) { - - case 0: /* JSON null */ - - /* first see if we have it all first */ - if( ctx->chunksize > (ctx->index + 3) ) { - if( strncasecmp(ctx->chunk + ctx->index, "null", 4) ) - return _jsonParserError(ctx, "Invalid JSON 'null' sequence"); - if( ctx->handler->handleNull ) - ctx->handler->handleNull(ctx->userData); - ctx->index += 4; - break; - } - - JSON_CACHE_DATA(ctx, ctx->buffer, 4); - if( ctx->buffer->n_used < 4 ) { - JSON_STATE_SET(ctx, JSON_STATE_IN_NULL); - return 1; - } - - if( strncasecmp(ctx->buffer->buf, "null", 4) ) - return _jsonParserError(ctx, "Invalid JSON 'null' sequence"); - if( ctx->handler->handleNull ) - ctx->handler->handleNull(ctx->userData); - break; - - case 1: /* JSON true */ - - /* see if we have it all first */ - if( ctx->chunksize > (ctx->index + 3) ) { - if( strncasecmp(ctx->chunk + ctx->index, "true", 4) ) - return _jsonParserError(ctx, "Invalid JSON 'true' sequence"); - if( ctx->handler->handleBool ) - ctx->handler->handleBool(ctx->userData, 1); - ctx->index += 4; - break; - } - - JSON_CACHE_DATA(ctx, ctx->buffer, 4); - if( ctx->buffer->n_used < 4 ) { - JSON_STATE_SET(ctx, JSON_STATE_IN_TRUE); - return 1; - } - if( strncasecmp( ctx->buffer->buf, "true", 4 ) ) { - return _jsonParserError(ctx, "Invalid JSON 'true' sequence"); - } - if( ctx->handler->handleBool ) - ctx->handler->handleBool(ctx->userData, 1); - break; - - case 2: /* JSON false */ - - /* see if we have it all first */ - if( ctx->chunksize > (ctx->index + 4) ) { - if( strncasecmp(ctx->chunk + ctx->index, "false", 5) ) - return _jsonParserError(ctx, "Invalid JSON 'false' sequence"); - if( ctx->handler->handleBool ) - ctx->handler->handleBool(ctx->userData, 0); - ctx->index += 5; - break; - } - - JSON_CACHE_DATA(ctx, ctx->buffer, 5); - if( ctx->buffer->n_used < 5 ) { - JSON_STATE_SET(ctx, JSON_STATE_IN_FALSE); - return 1; - } - if( strncasecmp( ctx->buffer->buf, "false", 5 ) ) - return _jsonParserError(ctx, "Invalid JSON 'false' sequence"); - if( ctx->handler->handleBool ) - ctx->handler->handleBool(ctx->userData, 0); - break; - - default: - fprintf(stderr, "Invalid type flag\n"); - return -1; - - } - - ctx->index--; /* set it back to the index of the final sequence character */ - OSRF_BUFFER_RESET(ctx->buffer); - JSON_STATE_REMOVE(ctx, JSON_STATE_IN_NULL); - JSON_STATE_REMOVE(ctx, JSON_STATE_IN_TRUE); - JSON_STATE_REMOVE(ctx, JSON_STATE_IN_FALSE); - - return 0; -} - - -int _jsonParserHandleString( jsonParserContext* ctx ) { - - char c = ctx->chunk[ctx->index]; - - if( JSON_STATE_CHECK(ctx, JSON_STATE_IN_ESCAPE) ) { - - if( JSON_STATE_CHECK(ctx, JSON_STATE_IN_UTF) ) { - - return _jsonParserHandleUnicode( ctx ); - - } else { - - switch(c) { - - /* handle all of the escape chars */ - case '\\': OSRF_BUFFER_ADD_CHAR( ctx->buffer, '\\' ); break; - case '"' : OSRF_BUFFER_ADD_CHAR( ctx->buffer, '\"' ); break; - case 't' : OSRF_BUFFER_ADD_CHAR( ctx->buffer, '\t' ); break; - case 'b' : OSRF_BUFFER_ADD_CHAR( ctx->buffer, '\b' ); break; - case 'f' : OSRF_BUFFER_ADD_CHAR( ctx->buffer, '\f' ); break; - case 'r' : OSRF_BUFFER_ADD_CHAR( ctx->buffer, '\r' ); break; - case 'n' : OSRF_BUFFER_ADD_CHAR( ctx->buffer, '\n' ); break; - case 'u' : - ctx->index++; /* progress to the first utf char */ - return _jsonParserHandleUnicode( ctx ); - default : OSRF_BUFFER_ADD_CHAR( ctx->buffer, c ); - } - } - - JSON_STATE_REMOVE(ctx, JSON_STATE_IN_ESCAPE); - return 0; - - } else { - - switch(c) { - - case '"' : /* this string is ending */ - if( JSON_STATE_CHECK(ctx, JSON_STATE_IN_KEY) ) { - - /* object key */ - if(ctx->handler->handleObjectKey) { - ctx->handler->handleObjectKey( - ctx->userData, ctx->buffer->buf); - } - - } else { /* regular json string */ - - if(ctx->handler->handleString) { - ctx->handler->handleString( - ctx->userData, ctx->buffer->buf ); - } - - } - - OSRF_BUFFER_RESET(ctx->buffer); /* flush the buffer and states */ - JSON_STATE_REMOVE(ctx, JSON_STATE_IN_STRING); - JSON_STATE_REMOVE(ctx, JSON_STATE_IN_KEY); - break; - - case '\\' : JSON_STATE_SET(ctx, JSON_STATE_IN_ESCAPE); break; - default : OSRF_BUFFER_ADD_CHAR( ctx->buffer, c ); - } - } - return 0; -} - - -int _jsonParserHandleNumber( jsonParserContext* ctx ) { - char c = ctx->chunk[ctx->index]; - - do { - OSRF_BUFFER_ADD_CHAR(ctx->buffer, c); - c = ctx->chunk[++(ctx->index)]; - } while( strchr(JSON_NUMBER_CHARS, c) && ctx->index < ctx->chunksize ); - - /* if we're run off the end of the chunk and we're not parsing the last chunk, - * save the number and the state */ - if( ctx->index >= ctx->chunksize && - ! JSON_PARSE_FLAG_CHECK(ctx, JSON_PARSE_LAST_CHUNK) ) { - JSON_STATE_SET(ctx, JSON_STATE_IN_NUMBER); - return 1; - } - - if(ctx->handler->handleNumber) - { - if( jsonIsNumeric( ctx->buffer->buf ) ) - ctx->handler->handleNumber( ctx->userData, ctx->buffer->buf ); - else { - // The number string is not numeric according to JSON rules. - // Scrub it into an acceptable format. - - char* scrubbed = jsonScrubNumber( ctx->buffer->buf ); - if( !scrubbed ) - return _jsonParserError(ctx, "Invalid number sequence"); - else { - ctx->handler->handleNumber( ctx->userData, scrubbed ); - free( scrubbed ); - } - } - } - - ctx->index--; /* scooch back to the first non-digit number */ - JSON_STATE_REMOVE(ctx, JSON_STATE_IN_NUMBER); - OSRF_BUFFER_RESET(ctx->buffer); - return 0; -} - -int jsonParseChunk( jsonParserContext* ctx, const char* data, int datalen, int flags ) { - - if( !( ctx && ctx->handler && data && datalen > 0 )) return -1; - ctx->chunksize = datalen; - ctx->chunk = data; - ctx->flags = flags; - char c; - - if( JSON_STATE_CHECK(ctx, JSON_STATE_IS_INVALID) ) - return _jsonParserError( ctx, "JSON Parser cannot continue after an error" ); - - if( JSON_STATE_CHECK(ctx, JSON_STATE_IS_DONE) ) - return _jsonParserError( ctx, "Extra content at end of JSON data" ); - - for( ctx->index = 0; (ctx->index < ctx->chunksize) && - (c = ctx->chunk[ctx->index]); ctx->index++ ) { - - /* middle of parsing a string */ - if( JSON_STATE_CHECK(ctx, JSON_STATE_IN_STRING)) { - if( _jsonParserHandleString(ctx) == -1 ) - return -1; - continue; - } - - /* middle of parsing a number */ - if( JSON_STATE_CHECK(ctx, JSON_STATE_IN_NUMBER) ) { - if( _jsonParserHandleNumber(ctx) == -1 ) - return -1; - continue; - } - - -#ifdef OSRF_JSON_ALLOW_COMMENTS - /* we just saw a bare '/' character */ - if( JSON_STATE_CHECK(ctx, JSON_STATE_START_COMMENT) ) { - if(c == '*') { - JSON_STATE_REMOVE(ctx, JSON_STATE_START_COMMENT); - JSON_STATE_SET(ctx, JSON_STATE_IN_COMMENT); - continue; - } else { - return _jsonParserError( ctx, "Invalid comment initializer" ); - } - } - - /* we're currently in the middle of a comment block */ - if( JSON_STATE_CHECK(ctx, JSON_STATE_IN_COMMENT) ) { - if(c == '*') { - JSON_STATE_REMOVE(ctx, JSON_STATE_IN_COMMENT); - JSON_STATE_SET(ctx, JSON_STATE_END_COMMENT); - continue; - } else { - continue; - } - } - - /* we're in a comment, and we just saw a '*' character */ - if( JSON_STATE_CHECK(ctx, JSON_STATE_END_COMMENT) ) { - if( c == '/' ) { /* comment is finished */ - JSON_STATE_REMOVE(ctx, JSON_STATE_END_COMMENT); - continue; - } else { - /* looks like this isn't the end of the comment after all */ - JSON_STATE_SET(ctx, JSON_STATE_IN_COMMENT); - JSON_STATE_REMOVE(ctx, JSON_STATE_END_COMMENT); - } - } -#endif - - /* if we're in the middle of parsing a null/true/false sequence */ - if( JSON_STATE_CHECK(ctx, (JSON_STATE_IN_NULL | - JSON_STATE_IN_TRUE | JSON_STATE_IN_FALSE)) ) { - - int type = (JSON_STATE_CHECK(ctx, JSON_STATE_IN_NULL)) ? 0 : - (JSON_STATE_CHECK(ctx, JSON_STATE_IN_TRUE)) ? 1 : 2; - - if( _jsonParserHandleMatch( ctx, type ) == -1 ) - return -1; - continue; - } - - JSON_EAT_WS(ctx); - - /* handle all of the top level characters */ - switch(c) { - - case '{' : /* starting an object */ - if( ctx->handler->handleStartObject) - ctx->handler->handleStartObject( ctx->userData ); - JSON_STATE_PUSH(ctx, JSON_STATE_IN_OBJECT); - JSON_STATE_SET(ctx, JSON_STATE_IN_KEY); - break; - - case '}' : /* ending an object */ - if( ctx->handler->handleEndObject) - ctx->handler->handleEndObject( ctx->userData ); - JSON_STATE_REMOVE(ctx, JSON_STATE_IN_KEY); - JSON_STATE_POP(ctx); - if( JSON_STATE_PEEK(ctx) == NULL ) - JSON_STATE_SET(ctx, JSON_STATE_IS_DONE); - break; - - case '[' : /* starting an array */ - if( ctx->handler->handleStartArray ) - ctx->handler->handleStartArray( ctx->userData ); - JSON_STATE_PUSH(ctx, JSON_STATE_IN_ARRAY); - break; - - case ']': /* ending an array */ - if( ctx->handler->handleEndArray ) - ctx->handler->handleEndArray( ctx->userData ); - JSON_STATE_POP(ctx); - if( JSON_STATE_PEEK(ctx) == NULL ) - JSON_STATE_SET(ctx, JSON_STATE_IS_DONE); - break; - - case ':' : /* done with the object key */ - JSON_STATE_REMOVE(ctx, JSON_STATE_IN_KEY); - break; - - case ',' : /* after object or array item */ - if( JSON_STATE_CHECK_STACK(ctx, JSON_STATE_IN_OBJECT) ) - JSON_STATE_SET(ctx, JSON_STATE_IN_KEY); - break; - - case 'n' : - case 'N' : /* null */ - if( _jsonParserHandleMatch( ctx, 0 ) == -1) - return -1; - break; - - case 't' : - case 'T' : - if( _jsonParserHandleMatch( ctx, 1 ) == -1 ) - return -1; - break; - - case 'f' : - case 'F' : - if( _jsonParserHandleMatch( ctx, 2 ) == -1) - return -1; - break; - - case '"' : - JSON_STATE_SET(ctx, JSON_STATE_IN_STRING); - break; - -#ifdef OSRF_JSON_ALLOW_COMMENTS - case '/' : - JSON_STATE_SET(ctx, JSON_STATE_START_COMMENT); - break; -#endif - - default: - if( strchr(JSON_NUMBER_CHARS, c) ) { - if( _jsonParserHandleNumber( ctx ) == -1 ) - return -1; - } else { - return _jsonParserError( ctx, "Invalid Token" ); - } - } - } - - return 0; -} - - -jsonInternalParser* _jsonNewInternalParser() { - jsonInternalParser* p; - - // Use the static instance of jsonInternalParser, - // if it's available - - if( staticParserInUse ) - OSRF_MALLOC(p, sizeof(jsonInternalParser)); - else { - p = &staticParser; - staticParserInUse = 1; - } - - p->ctx = jsonNewParser( &jsonInternalParserHandler, p ); - p->obj = NULL; - p->current = NULL; - p->lastkey = NULL; - p->handleError = NULL; - return p; -} - -void _jsonInternalParserFree(jsonInternalParser* p) { - if(!p) return; - jsonParserFree(p->ctx); - free(p->lastkey); - - // if the jsonInternalParser was allocated - // dynamically, then free it - - if( &staticParser == p ) - staticParserInUse = 0; - else - free(p); -} - -static jsonObject* _jsonParseStringImpl(const char* str, void (*errorHandler) (const char*) ) { - jsonInternalParser* parser = _jsonNewInternalParser(); - parser->handleError = errorHandler; - jsonParseChunk( parser->ctx, str, strlen(str), JSON_PARSE_LAST_CHUNK ); - jsonObject* obj = parser->obj; - _jsonInternalParserFree(parser); - return obj; -} - -jsonObject* jsonParseStringHandleError( - void (*errorHandler) (const char*), char* str, ... ) { - if(!str) return NULL; - VA_LIST_TO_STRING(str); - return _jsonParseStringImpl(VA_BUF, errorHandler); -} - -jsonObject* jsonParseString( const char* str ) { - if(!str) return NULL; - jsonObject* obj = _jsonParseStringImpl(str, NULL); - jsonObject* obj2 = jsonObjectDecodeClass(obj); - jsonObjectFree(obj); - return obj2; -} - -jsonObject* jsonParseStringRaw( const char* str ) { - if(!str) return NULL; - return _jsonParseStringImpl(str, NULL); -} - -jsonObject* jsonParseStringFmt( const char* str, ... ) { - if(!str) return NULL; - VA_LIST_TO_STRING(str); - return _jsonParseStringImpl(VA_BUF, NULL); -} - - -#define JSON_SHOVE_ITEM(ctx,type) \ - jsonInternalParser* p = (jsonInternalParser*) ctx;\ - _jsonInsertParserItem(p, jsonNewObjectType(type)); - -void _jsonHandleStartObject(void* ctx) { JSON_SHOVE_ITEM(ctx, JSON_HASH); } -void _jsonHandleStartArray(void* ctx) { JSON_SHOVE_ITEM(ctx, JSON_ARRAY); } -void _jsonHandleNull(void* ctx) { JSON_SHOVE_ITEM(ctx, JSON_NULL); } - -void _jsonHandleObjectKey(void* ctx, char* key) { - jsonInternalParser* p = (jsonInternalParser*) ctx; - free(p->lastkey); - p->lastkey = strdup(key); -} - -void _jsonHandleEndObject(void* ctx) { - jsonInternalParser* p = (jsonInternalParser*) ctx; - p->current = p->current->parent; -} - -void _jsonHandleEndArray(void* ctx) { - jsonInternalParser* p = (jsonInternalParser*) ctx; - p->current = p->current->parent; -} - -void _jsonHandleString(void* ctx, char* string) { - jsonInternalParser* p = (jsonInternalParser*) ctx; - _jsonInsertParserItem(p, jsonNewObject(string)); -} - -void _jsonHandleBool(void* ctx, int boolval) { - jsonInternalParser* p = (jsonInternalParser*) ctx; - jsonObject* obj = jsonNewObjectType(JSON_BOOL); - obj->value.b = boolval; - _jsonInsertParserItem(p, obj); -} - -void _jsonHandleNumber(void* ctx, const char* numstr) { - jsonObject* obj = jsonNewNumberStringObject(numstr); - jsonInternalParser* p = (jsonInternalParser*) ctx; - _jsonInsertParserItem(p, obj); -} - -void _jsonHandleError(void* ctx, char* str, ...) { - jsonInternalParser* p = (jsonInternalParser*) ctx; - VA_LIST_TO_STRING(str); - - if( p->handleError ) - p->handleError(VA_BUF); - else - if( jsonClientErrorCallback ) - jsonClientErrorCallback(VA_BUF); - - else fprintf(stderr, "%s\n", VA_BUF); - jsonObjectFree(p->obj); - p->obj = NULL; -} - - -void _jsonInsertParserItem( jsonInternalParser* p, jsonObject* newo ) { - - if( !p->obj ) { - - /* new parser, set the new object to our object */ - p->obj = p->current = newo; - - } else { - - /* insert the new object into the current container object */ - if(p->current->type == JSON_HASH) - jsonObjectSetKey(p->current, p->lastkey, newo); - else // assume it's a JSON_ARRAY; if it isn't, it'll become one - jsonObjectPush(p->current, newo); - - /* if the new object is a container object, make it our current container */ - if( newo->type == JSON_ARRAY || newo->type == JSON_HASH ) - p->current = newo; - } -} - - diff --git a/src/libopensrf/osrf_json_tools.c b/src/libopensrf/osrf_json_tools.c index e444db9..d88c827 100644 --- a/src/libopensrf/osrf_json_tools.c +++ b/src/libopensrf/osrf_json_tools.c @@ -15,7 +15,6 @@ GNU General Public License for more details. #include #include "opensrf/osrf_json.h" -#include "opensrf/osrf_json_utils.h" static jsonObject* findMultiPath( const jsonObject* o, const char* root, const char* path ); diff --git a/src/libopensrf/osrf_parse_json.c b/src/libopensrf/osrf_parse_json.c index fa05ac5..aef8a88 100644 --- a/src/libopensrf/osrf_parse_json.c +++ b/src/libopensrf/osrf_parse_json.c @@ -23,7 +23,6 @@ GNU General Public License for more details. #include #include #include -#include /** @brief A collection of things the parser uses to keep track of what it's doing. -- 2.43.2