-
-#include <string.h>
-#include <stdio.h>
-
-/* the JSON parser, so we can read the response we're XMLizing */
-#include <objson/object.h>
-#include <objson/json_parser.h>
-#include <opensrf/utils.h>
-
-char* jsonObjectToXML(jsonObject*);
+/*
+ * Header to support legacy objson library
+ */
+#ifndef OBJSON_JSON2XML_H
+#define OBJSON_JSON2XML_H
+#include <opensrf/osrf_json.h>
+#include <opensrf/osrf_json_xml.h>
+#include <opensrf/osrf_legacy_json.h>
+#endif
/*
-Copyright (C) 2005 Georgia Public Library Service
-Bill Erickson <highfalutin@gmail.com>
-
-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.
-*/
-
-
-
-
-/* ---------------------------------------------------------------------------------------
- JSON parser.
- * --------------------------------------------------------------------------------------- */
-#ifndef JSON_PARSER_H
-#define JSON_PARSER_H
-
-#include <stdio.h>
-#include <ctype.h>
-#include <objson/object.h>
-#include <opensrf/utils.h>
-
-
-
-/* Parses the given JSON string and returns the built object.
- * returns NULL (and prints parser error to stderr) on error.
+ * Header to support legacy objson library
*/
-
-jsonObject* json_parse_string(char* string);
-
-jsonObject* jsonParseString(char* string);
-jsonObject* jsonParseStringFmt( char* string, ... );
-
-jsonObject* json_parse_file( const char* filename );
-
-jsonObject* jsonParseFile( const char* string );
-
-
-
-/* does the actual parsing work. returns 0 on success. -1 on error and
- * -2 if there was no object to build (string was all comments)
- */
-int _json_parse_string(char* string, unsigned long* index, jsonObject* obj, int current_strlen);
-
-/* returns 0 on success and turns obj into a string object */
-int json_parse_json_string(char* string, unsigned long* index, jsonObject* obj, int current_strlen);
-
-/* returns 0 on success and turns obj into a number or double object */
-int json_parse_json_number(char* string, unsigned long* index, jsonObject* obj, int current_strlen);
-
-/* returns 0 on success and turns obj into an 'object' object */
-int json_parse_json_object(char* string, unsigned long* index, jsonObject* obj, int current_strlen);
-
-/* returns 0 on success and turns object into an array object */
-int json_parse_json_array(char* string, unsigned long* index, jsonObject* obj, int current_strlen);
-
-/* churns through whitespace and increments index as it goes.
- * eat_all == true means we should eat newlines, tabs
- */
-void json_eat_ws(char* string, unsigned long* index, int eat_all, int current_strlen);
-
-int json_parse_json_bool(char* string, unsigned long* index, jsonObject* obj, int current_strlen);
-
-/* removes comments from a json string. if the comment contains a class hint
- * and class_hint isn't NULL, an allocated char* with the class name will be
- * shoved into *class_hint. returns 0 on success, -1 on parse error.
- * 'index' is assumed to be at the second character (*) of the comment
- */
-int json_eat_comment(char* string, unsigned long* index, char** class_hint, int parse_class, int current_strlen);
-
-/* prints a useful error message to stderr. always returns -1 */
-int json_handle_error(char* string, unsigned long* index, char* err_msg);
-
-int json_parse_json_null(char* string, unsigned long* index, jsonObject* obj, int current_strlen);
-
-
+#ifndef OBJSON_XML2JSON_H
+#define OBJSON_XML2JSON_H
+#include <opensrf/osrf_json.h>
+#include <opensrf/osrf_json_xml.h>
+#include <opensrf/osrf_legacy_json.h>
#endif
/*
-Copyright (C) 2005 Georgia Public Library Service
-Bill Erickson <highfalutin@gmail.com>
-
-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.
-*/
-
-
-/* ---------------------------------------------------------------------------------------
- libjson
- * --------------------------------------------------------------------------------------- */
-
-#ifndef _JSON_OBJECT_H
-#define _JSON_OBJECT_H
-
-#include <stdio.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <opensrf/utils.h>
-
-/* json object types */
-#define JSON_HASH 0
-#define JSON_ARRAY 1
-#define JSON_STRING 2
-#define JSON_NUMBER 3
-#define JSON_NULL 4
-#define JSON_BOOL 5
-
-
-/* top level generic object structure */
-struct _jsonObjectStruct {
-
- /* how many sub-objects do we contain if we're an array or an object.
- Note that this includes null array elements in sparse arrays */
- unsigned long size;
-
- /* optional class hint */
- char* classname;
-
- /* see JSON types above */
- int type;
-
-
- /* our cargo */
- union _jsonObjectValue {
- struct _jsonObjectNodeStruct* c; /* our list of sub-objects if we're an array or a hash */
- char* s; /* string */
- int b; /* bool */
- double n; /* number */
- } value;
-
-
- /* client may provide a comment string which will be
- * added to the object when stringified */
- char* comment;
-
-};
-typedef struct _jsonObjectStruct jsonObject;
-
-
-/**
- String parsing function. This is assigned by the json_parser code.
- to avoid circular dependency, declare the parse function here,
- and have the json parse code set the variable to a real function
-*/
-//jsonObject* (*jsonParseString) (char* str);
-
-
-/* this contains a single element of the object along with the elements
- * index (if this object is an array) and key (if this object is a hash)
+ * Header to support legacy objson library
*/
-struct _jsonObjectNodeStruct {
-
- unsigned long index; /* our array position */
- char* key; /* our hash key */
-
- jsonObject* item; /* our object */
- struct _jsonObjectNodeStruct* next; /* pointer to the next object node */
-};
-typedef struct _jsonObjectNodeStruct jsonObjectNode;
-
-
-
-/* utility object for iterating over hash objects */
-struct _jsonObjectIteratorStruct {
- const jsonObject* obj; /* the topic object */
- jsonObjectNode* current; /* the current node within the object */
-};
-typedef struct _jsonObjectIteratorStruct jsonObjectIterator;
-
-
-/** Allocates a new iterator
- @param obj The object over which to iterate.
-*/
-jsonObjectIterator* jsonNewObjectIterator(const jsonObject* obj);
-
-/**
- De-allocates an iterator
- @param iter The iterator object to free
-*/
-void jsonObjectIteratorFree(jsonObjectIterator* iter);
-
-/**
- Returns the object_node currently pointed to by the iterator
- and increments the pointer to the next node
- @param iter The iterator in question.
- */
-jsonObjectNode* jsonObjectIteratorNext(jsonObjectIterator* iter);
-
-/**
- @param iter The iterator.
- @return True if there is another node after the current node.
- */
-int jsonObjectIteratorHasNext(const jsonObjectIterator* iter);
-
-
-/**
- Allocates a new object.
- @param string The string data if this object is to be a string.
- if not, string should be NULL
- @return The newly allocated object or NULL on memory error.
-*/
-jsonObject* jsonNewObjectFmt(const char* string, ...);
-jsonObject* jsonNewObject(const char* string);
-
-/**
- Allocates a new JSON number object.
- @param num The number this object is to hold
- @return The newly allocated object.
-*/
-jsonObject* jsonNewNumberObject( double num );
-
-
-/**
- Returns a pointer to the object at the given index. This call is
- only valid if the object has a type of JSON_ARRAY.
- @param obj The object
- @param index The position within the object
- @return The object at the given index.
-*/
-jsonObject* jsonObjectGetIndex( const jsonObject* obj, unsigned long index );
-
-
-/**
- Returns a pointer to the object with the given key
- @param obj The object
- @param key The key
- @return The object with the given key.
-*/
-jsonObject* jsonObjectGetKey( const jsonObject* obj, const char* key );
-
-/**
- De-allocates an object. Note that this function should only be called
- on objects that are _not_ children of other objects or there will be
- double-free's
- @param obj The object to free.
-*/
-void jsonObjectFree(jsonObject* obj);
-
-
-/**
- Allocates a new object node.
- @param obj The object to which the node will be appended.
- @return The new object node.
-*/
-jsonObjectNode* jsonNewObjectNode(jsonObject* obj);
-
-/**
- De-allocates an object node
- @param obj The object node to de-allocate.
-*/
-void jsonObjectNodeFree(jsonObjectNode* obj);
-
-
-/**
- Pushes the given object onto the end of the list. This coerces an object
- into becoming an array. _Only_ use this function on objects that you
- want to become an array.
- If obj is NULL, inserts a new NULL object into the list.
- @return array size on success, -1 on error
- */
-unsigned long jsonObjectPush(jsonObject* dest, jsonObject* newObj);
-
-/* removes (and deallocates) the object at the given index (if one exists) and inserts
- * the new one. returns the size on success, -1 on error
- * If obj is NULL, inserts a new object into the list with is_null set to true
- */
-unsigned long jsonObjectSetIndex(jsonObject* dest, unsigned long index, jsonObject* newObj);
-
-/* inserts the new object, overwriting (removing, deallocating) any
- * previous object with the given key.
- * returns the size on success, -1 on error
- * if 'obj' is NULL, a new object is inserted at key 'key' with 'is_null'
- * set to true
- */
-unsigned long jsonObjectSetKey(jsonObject* dest, const char* key, jsonObject* newObj);
-
-/* removes the object at the given index and, if more items exist,
- * re-indexes (shifts down by 1) the rest of the objects in the array
- */
-unsigned long jsonObjectRemoveIndex(jsonObject* dest, unsigned long index);
-
-/* removes (and deallocates) the object with key 'key' if it exists */
-unsigned long jsonObjectRemoveKey( jsonObject* dest, const char* key);
-
-/* returns a pointer to the string data held by this object if this object
- is a string. Otherwise returns NULL*/
-char* jsonObjectGetString(const jsonObject*);
-
-double jsonObjectGetNumber( const jsonObject* obj );
-
-/* sets the string data */
-void jsonObjectSetString(jsonObject* dest, const char* string);
-
-/* sets the number value for the object */
-void jsonObjectSetNumber(jsonObject* dest, double num);
-
-/* sets the class hint for this object */
-void jsonObjectSetClass(jsonObject* dest, const char* classname );
-
-/* converts an object to a json string. client is responsible for freeing the return string */
-char* jsonObjectToJSON( const jsonObject* obj );
-
-/* set this object's comment string */
-void jsonObjectSetComment(jsonObject* dest, const char* classname);
-
-/* utility method. starting at index 'index', shifts all indices down by one and
- * decrements the objects size by 1
- */
-void _jsonObjectShiftIndex(jsonObject* dest, unsigned long index);
-
-/* formats a JSON string from printing. User must free returned string */
-char* jsonFormatString( const char* jsonString );
-
-jsonObject* jsonObjectClone( const jsonObject* o );
-
-/* tries to extract the string data from an object.
- if object -> NULL (the C NULL)
- if array -> NULL (the C NULL)
- if null -> NULL (the C NULL)
- if true/false -> true/false
- if string/number/double the string version of either of those
- The caller is responsible for freeing the returned string
- */
-char* jsonObjectToSimpleString( const jsonObject* o );
-
-int jsonBoolIsTrue( const jsonObject* o );
-
-
-/* ------------------------------------------------------------------------ */
-/* XPATH */
-
-/* provides an XPATH style search interface (e.g. /some/node/here) and
- return the object at that location if one exists. Naturally,
- every element in the path must be a proper object ("hash" / {}).
- Returns NULL if the specified node is not found
- Note also that the object returned is a clone and
- must be freed by the caller
-*/
-jsonObject* jsonObjectFindPath( const jsonObject* obj, char* path, ... );
-
-
-/* Utility method. finds any object in the tree that matches the path.
- Use this for finding paths that start with '//' */
-jsonObject* _jsonObjectFindPathRecurse( const jsonObject* o, char* root, char* path );
-
-/* returns a list of object whose key is 'root'. These are used as
- potential objects when doing a // search */
-jsonObject* __jsonObjectFindPathRecurse( const jsonObject* o, char* root );
-
-/* ------------------------------------------------------------------------ */
-
-
+#ifndef OBJSON_OBJECT_H
+#define OBJSON_OBJECT_H
+#include <opensrf/osrf_json.h>
+#include <opensrf/osrf_legacy_json.h>
#endif
-
-
-
-#include <stdio.h>
-#include <string.h>
-#include <libxml/globals.h>
-#include <libxml/xmlerror.h>
-#include <libxml/parser.h>
-#include <libxml/tree.h>
-#include <libxml/xmlmemory.h>
-
-#include <objson/object.h>
-#include <objson/json_parser.h>
-#include <opensrf/utils.h>
-#include <opensrf/osrf_list.h>
-
-
-jsonObject* jsonXMLToJSONObject(const char* xml);
-
+/*
+ * Header to support legacy objson library
+ */
+#ifndef OBJSON_XML2JSON_H
+#define OBJSON_XML2JSON_H
+#include <opensrf/osrf_json.h>
+#include <opensrf/osrf_json_xml.h>
+#include <opensrf/osrf_legacy_json.h>
+#endif
#include <opensrf/xml_utils.h>
#include <opensrf/utils.h>
#include <opensrf/string_array.h>
-#include <objson/object.h>
+#include <opensrf/osrf_json.h>
typedef struct {
jsonObject* config;
#include <opensrf/osrf_hash.h>
#include <opensrf/osrf_list.h>
-#include <objson/object.h>
-#include <objson/json_parser.h>
+#include <opensrf/osrf_json.h>
#include <opensrf/osrf_app_session.h>
#include <opensrf/osrf_hash.h>
-#include <objson/object.h>
+#include <opensrf/osrf_json.h>
#include <stdio.h>
#include <dlfcn.h>
*/
-#include <objson/object.h>
-#include <objson/json_parser.h>
+#include <opensrf/osrf_json.h>
#include <memcache.h>
#include <opensrf/log.h>
--- /dev/null
+/*
+Copyright (C) 2006 Georgia Public Library Service
+Bill Erickson <billserickson@gmail.com>
+
+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 <opensrf/utils.h>
+#include <opensrf/osrf_list.h>
+#include <opensrf/osrf_hash.h>
+
+#ifndef _JSON_H
+#define _JSON_H
+
+
+/* parser states */
+#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
+
+
+/* object and array (container) states are pushed onto a stack so we
+ * can keep track of the object nest. All other states are
+ * simply stored in the state field of the parser */
+#define JSON_STATE_SET(ctx,s) ctx->state |= s; /* set a state */
+#define JSON_STATE_REMOVE(ctx,s) ctx->state &= ~s; /* unset a state */
+#define JSON_STATE_CHECK(ctx,s) (ctx->state & s) ? 1 : 0 /* check if a state is set */
+#define JSON_STATE_POP(ctx) osrfListPop( ctx->stateStack ); /* remove a state from the stack */
+#define JSON_STATE_PUSH(ctx, state) osrfListPush( ctx->stateStack,(void*) state );/* push a state on the stack */
+#define JSON_STATE_PEEK(ctx) osrfListGetIndex(ctx->stateStack, ctx->stateStack->size -1) /* check which container type we're currently in */
+#define JSON_STATE_CHECK_STACK(ctx, s) (JSON_STATE_PEEK(ctx) == (void*) s ) ? 1 : 0 /* compare stack values */
+
+/* JSON types */
+#define JSON_HASH 0
+#define JSON_ARRAY 1
+#define JSON_STRING 2
+#define JSON_NUMBER 3
+#define JSON_NULL 4
+#define JSON_BOOL 5
+
+#define JSON_PARSE_LAST_CHUNK 0x1 /* this is the last part of the string we're parsing */
+
+#define JSON_PARSE_FLAG_CHECK(ctx, f) (ctx->flags & f) ? 1 : 0 /* check if a parser state is set */
+
+#ifndef JSON_CLASS_KEY
+#define JSON_CLASS_KEY "__c"
+#endif
+#ifndef JSON_DATA_KEY
+#define JSON_DATA_KEY "__p"
+#endif
+
+
+struct jsonParserContextStruct {
+ int state; /* what are we currently parsing */
+ char* chunk; /* the chunk we're currently parsing */
+ int index; /* where we are in parsing the current chunk */
+ int chunksize; /* the size of the current chunk */
+ int flags; /* parser flags */
+ osrfList* stateStack; /* represents the nest of object/array states */
+ growing_buffer* buffer; /* used to hold JSON strings, number, true, false, and null sequences */
+ growing_buffer* utfbuf; /* holds the current unicode characters */
+ void* userData; /* opaque user pointer. we ignore this */
+ struct jsonParserHandlerStruct* handler; /* the event handler struct */
+};
+typedef struct jsonParserContextStruct jsonParserContext;
+
+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, double num);
+ void (*handleError) (void* userData, char* err, ...);
+};
+typedef struct jsonParserHandlerStruct jsonParserHandler;
+
+struct _jsonObjectStruct {
+ unsigned long size; /* number of sub-items */
+ char* classname; /* optional class hint (not part of the JSON spec) */
+ int type; /* JSON type */
+ struct _jsonObjectStruct* parent; /* who we're attached to */
+ union __jsonValue { /* cargo */
+ osrfHash* h; /* object container */
+ osrfList* l; /* array container */
+ char* s; /* string */
+ int b; /* bool */
+// double n; /* number */
+ double n; /* number */
+ } value;
+};
+typedef struct _jsonObjectStruct jsonObject;
+
+struct _jsonIteratorStruct {
+ jsonObject* obj; /* the object we're traversing */
+ osrfHashIterator* hashItr; /* the iterator for this hash */
+ char* key; /* if this object is an object, the current key */
+ unsigned long index; /* if this object is an array, the index */
+};
+typedef struct _jsonIteratorStruct jsonIterator;
+
+
+
+/**
+ * Allocates a new parser context object
+ * @param handler The event handler struct
+ * @param userData Opaque user pointer which is available in callbacks
+ * and ignored by the parser
+ * @return An allocated parser context, NULL on error
+ */
+jsonParserContext* jsonNewParser( jsonParserHandler* handler, void* userData);
+
+/**
+ * Deallocates a parser context
+ * @param ctx The context object
+ */
+void jsonParserFree( jsonParserContext* ctx );
+
+/**
+ * Parse a chunk of data.
+ * @param ctx The parser context
+ * @param data The data to parse
+ * @param datalen The size of the chunk to parser
+ * @param flags Reserved
+ */
+int jsonParseChunk( jsonParserContext* ctx, char* data, int datalen, int flags );
+
+
+/**
+ * Parses a JSON string;
+ * @param str The string to parser
+ * @return The resulting JSON object or NULL on error
+ */
+jsonObject* jsonParseString( char* str );
+jsonObject* jsonParseStringRaw( char* str );
+
+jsonObject* jsonParseStringFmt( char* str, ... );
+
+/**
+ * Parses a JSON string;
+ * @param str The string to parser
+ * @return The resulting JSON object or NULL on error
+ */
+jsonObject* jsonParseStringHandleError( void (*errorHandler) (const char*), char* str, ... );
+
+
+
+/**
+ * Creates a new json object
+ * @param data The string data this object will hold if
+ * this object happens to be a JSON_STRING, NULL otherwise
+ * @return The allocated json object. Must be freed with
+ * jsonObjectFree()
+ */
+jsonObject* jsonNewObject(const char* data);
+jsonObject* jsonNewObjectFmt(const char* data, ...);
+
+/**
+ * Creates a new object of the given type
+ */
+jsonObject* jsonNewObjectType(int type);
+
+/**
+ * Creates a new number object
+ */
+jsonObject* jsonNewNumberObject( double num );
+
+
+/**
+ * Creates a new json bool
+ */
+jsonObject* jsonNewBoolObject(int val);
+
+/**
+ * Deallocates an object
+ */
+void jsonObjectFree( jsonObject* o );
+
+/**
+ * Forces the given object to become an array (if it isn't already one)
+ * and pushes the new object into the array
+ */
+unsigned long jsonObjectPush(jsonObject* o, jsonObject* newo);
+
+/**
+ * Forces the given object to become a hash (if it isn't already one)
+ * and assigns the new object to the key of the hash
+ */
+unsigned long jsonObjectSetKey(
+ jsonObject* o, const char* key, jsonObject* newo);
+
+
+/**
+ * Turns the object into a JSON string. The string must be freed by the caller */
+char* jsonObjectToJSON( const jsonObject* obj );
+char* jsonObjectToJSONRaw( const jsonObject* obj );
+
+
+/**
+ * Retrieves the object at the given key
+ */
+jsonObject* jsonObjectGetKey( const jsonObject* obj, const char* key );
+
+
+
+
+
+
+/** Allocates a new iterator
+ @param obj The object over which to iterate.
+*/
+jsonIterator* jsonNewIterator(const jsonObject* obj);
+
+
+/**
+ De-allocates an iterator
+ @param iter The iterator object to free
+*/
+void jsonIteratorFree(jsonIterator* iter);
+
+/**
+ Returns the object_node currently pointed to by the iterator
+ and increments the pointer to the next node
+ @param iter The iterator in question.
+ */
+jsonObject* jsonIteratorNext(jsonIterator* iter);
+
+
+/**
+ @param iter The iterator.
+ @return True if there is another node after the current node.
+ */
+int jsonIteratorHasNext(const jsonIterator* iter);
+
+
+/**
+ Returns a pointer to the object at the given index. This call is
+ only valid if the object has a type of JSON_ARRAY.
+ @param obj The object
+ @param index The position within the object
+ @return The object at the given index.
+*/
+jsonObject* jsonObjectGetIndex( const jsonObject* obj, unsigned long index );
+
+
+/* removes (and deallocates) the object at the given index (if one exists) and inserts
+ * the new one. returns the size on success, -1 on error
+ * If obj is NULL, inserts a new object into the list with is_null set to true
+ */
+unsigned long jsonObjectSetIndex(jsonObject* dest, unsigned long index, jsonObject* newObj);
+
+/* removes the object at the given index and, if more items exist,
+ * re-indexes (shifts down by 1) the rest of the objects in the array
+ */
+unsigned long jsonObjectRemoveIndex(jsonObject* dest, unsigned long index);
+
+/* removes (and deallocates) the object with key 'key' if it exists */
+unsigned long jsonObjectRemoveKey( jsonObject* dest, const char* key);
+
+/* returns a pointer to the string data held by this object if this object
+ is a string. Otherwise returns NULL*/
+char* jsonObjectGetString(const jsonObject*);
+
+double jsonObjectGetNumber( const jsonObject* obj );
+
+/* sets the string data */
+void jsonObjectSetString(jsonObject* dest, const char* string);
+
+/* sets the number value for the object */
+void jsonObjectSetNumber(jsonObject* dest, double num);
+
+/* sets the class hint for this object */
+void jsonObjectSetClass(jsonObject* dest, const char* classname );
+const char* jsonObjectGetClass(const jsonObject* dest);
+
+int jsonBoolIsTrue( jsonObject* boolObj );
+
+void jsonSetBool(jsonObject* bl, int val);
+
+jsonObject* jsonObjectClone( const jsonObject* o );
+
+
+/* tries to extract the string data from an object.
+ if object -> NULL (the C NULL)
+ if array -> NULL
+ if null -> NULL
+ if bool -> NULL
+ if string/number the string version of either of those
+ The caller is responsible for freeing the returned string
+ */
+char* jsonObjectToSimpleString( const jsonObject* o );
+
+
+
+/* provides an XPATH style search interface (e.g. /some/node/here) and
+ return the object at that location if one exists. Naturally,
+ every element in the path must be a proper object ("hash" / {}).
+ Returns NULL if the specified node is not found
+ Note also that the object returned is a clone and
+ must be freed by the caller
+*/
+jsonObject* jsonObjectFindPath( const jsonObject* obj, char* path, ... );
+
+
+/* formats a JSON string from printing. User must free returned string */
+char* jsonFormatString( const char* jsonString );
+
+/* sets the error handler for all parsers */
+void jsonSetGlobalErrorHandler(void (*errorHandler) (const char*));
+
+jsonObject* jsonParseFile( char* filename );
+
+/* ------------------------------------------------------------------------- */
+/**
+ * The following methods provide a ficility for serializing and
+ * deserializing "classed" JSON objects. To give a JSON object a
+ * class, simply call jsonObjectSetClass().
+ * Then, calling jsonObjectEncodeClass() will convert the JSON
+ * object (and any sub-objects) to a JSON object with class
+ * wrapper objects like so:
+ * { _c : "classname", _d : <json_thing> }
+ * In this example _c is the class key and _d is the data (object)
+ * key. The keys are defined by the constants
+ * OSRF_JSON_CLASS_KEY and OSRF_JSON_DATA_KEY
+ * To revive a serialized object, simply call
+ * jsonObjectDecodeClass()
+ */
+
+
+/** Converts a class-wrapped object into an object with the
+ * classname set
+ * Caller must free the returned object
+ */
+jsonObject* jsonObjectDecodeClass( jsonObject* obj );
+
+
+/** Converts an object with a classname into a
+ * class-wrapped (serialized) object
+ * Caller must free the returned object
+ */
+jsonObject* jsonObjectEncodeClass( jsonObject* obj );
+
+/* ------------------------------------------------------------------------- */
+
+
+/**
+ * Generates an XML representation of a JSON object */
+char* jsonObjectToXML(jsonObject*);
+
+
+/*
+ * Builds a JSON object from the provided XML
+ */
+jsonObject* jsonXMLToJSONObject(const char* xml);
+
+
+#endif
--- /dev/null
+/*
+Copyright (C) 2006 Georgia Public Library Service
+Bill Erickson <billserickson@gmail.com>
+
+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.
+*/
+
+
+/* ----------------------------------------------------------------------- */
+/* 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.+-e"
+
+
+/* cleans up an object if it is morphing another object, also
+ * verifies that the appropriate storage container exists where appropriate */
+#define JSON_INIT_CLEAR(_obj_, newtype) \
+ if( _obj_->type == JSON_HASH && newtype != JSON_HASH ) { \
+ osrfHashFree(_obj_->value.h); \
+ _obj_->value.h = NULL; \
+ } else if( _obj_->type == JSON_ARRAY && newtype != JSON_ARRAY ) { \
+ osrfListFree(_obj_->value.l); \
+ _obj_->value.l = NULL; \
+ } else if( _obj_->type == JSON_STRING && newtype != JSON_STRING ) { \
+ free(_obj_->value.s); \
+ _obj_->value.s = NULL; \
+ } \
+ _obj_->type = newtype;\
+ if( newtype == JSON_HASH && _obj_->value.h == NULL ) { \
+ _obj_->value.h = osrfNewHash(); \
+ _obj_->value.h->freeItem = _jsonFreeHashItem; \
+ } else if( newtype == JSON_ARRAY && _obj_->value.l == NULL ) { \
+ _obj_->value.l = osrfNewList(); \
+ _obj_->value.l->freeItem = _jsonFreeListItem;\
+ } \
+
+
+/**
+ * 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*, double num);
+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 );
+
+
+/* Utility method. finds any object in the tree that matches the path.
+ Use this for finding paths that start with '//' */
+jsonObject* _jsonObjectFindPathRecurse( const jsonObject* o, char* root, char* path );
+
+
+/* returns a list of object whose key is 'root'. These are used as
+ potential objects when doing a // search */
+jsonObject* __jsonObjectFindPathRecurse( const jsonObject* o, char* root );
+
+
--- /dev/null
+#ifdef OSRF_JSON_ENABLE_XML_UTILS
+
+#include <stdio.h>
+#include <string.h>
+#include <libxml/globals.h>
+#include <libxml/xmlerror.h>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <libxml/xmlmemory.h>
+
+#include <opensrf/osrf_json.h>
+#include <opensrf/utils.h>
+#include <opensrf/osrf_list.h>
+
+
+/**
+ * Generates an XML representation of a JSON object */
+char* jsonObjectToXML(jsonObject*);
+
+
+/*
+ * Builds a JSON object from the provided XML
+ */
+jsonObject* jsonXMLToJSONObject(const char* xml);
+
+#endif
--- /dev/null
+/*
+Copyright (C) 2005 Georgia Public Library Service
+Bill Erickson <highfalutin@gmail.com>
+
+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.
+*/
+
+
+
+
+/* ---------------------------------------------------------------------------------------
+ JSON parser.
+ * --------------------------------------------------------------------------------------- */
+#ifndef LEGACY_JSON_H
+#define LEGACY_JSON_H
+
+#include <opensrf/osrf_json.h>
+#include <ctype.h>
+
+
+
+/* Parses the given JSON string and returns the built object.
+ * returns NULL (and prints parser error to stderr) on error.
+ */
+
+jsonObject* json_parse_string(char* string);
+
+jsonObject* legacy_jsonParseString(char* string);
+jsonObject* legacy_jsonParseStringFmt( char* string, ... );
+
+jsonObject* json_parse_file( const char* filename );
+
+jsonObject* legacy_jsonParseFile( const char* string );
+
+
+
+/* does the actual parsing work. returns 0 on success. -1 on error and
+ * -2 if there was no object to build (string was all comments)
+ */
+int _json_parse_string(char* string, unsigned long* index, jsonObject* obj, int current_strlen);
+
+/* returns 0 on success and turns obj into a string object */
+int json_parse_json_string(char* string, unsigned long* index, jsonObject* obj, int current_strlen);
+
+/* returns 0 on success and turns obj into a number or double object */
+int json_parse_json_number(char* string, unsigned long* index, jsonObject* obj, int current_strlen);
+
+/* returns 0 on success and turns obj into an 'object' object */
+int json_parse_json_object(char* string, unsigned long* index, jsonObject* obj, int current_strlen);
+
+/* returns 0 on success and turns object into an array object */
+int json_parse_json_array(char* string, unsigned long* index, jsonObject* obj, int current_strlen);
+
+/* churns through whitespace and increments index as it goes.
+ * eat_all == true means we should eat newlines, tabs
+ */
+void json_eat_ws(char* string, unsigned long* index, int eat_all, int current_strlen);
+
+int json_parse_json_bool(char* string, unsigned long* index, jsonObject* obj, int current_strlen);
+
+/* removes comments from a json string. if the comment contains a class hint
+ * and class_hint isn't NULL, an allocated char* with the class name will be
+ * shoved into *class_hint. returns 0 on success, -1 on parse error.
+ * 'index' is assumed to be at the second character (*) of the comment
+ */
+int json_eat_comment(char* string, unsigned long* index, char** class_hint, int parse_class, int current_strlen);
+
+/* prints a useful error message to stderr. always returns -1 */
+int json_handle_error(char* string, unsigned long* index, char* err_msg);
+
+int json_parse_json_null(char* string, unsigned long* index, jsonObject* obj, int current_strlen);
+
+
+char* legacy_jsonObjectToJSON( const jsonObject* obj );
+
+
+
+/* LEGACY ITERATOR CODE ---------------------------------------------------
+ ------------------------------------------------------------------------ */
+
+struct _jsonObjectNodeStruct {
+ unsigned long index; /* our array position */
+ char* key; /* our hash key */
+ jsonObject* item; /* our object */
+};
+typedef struct _jsonObjectNodeStruct jsonObjectNode;
+
+
+
+/* utility object for iterating over hash objects */
+struct _jsonObjectIteratorStruct {
+ jsonIterator* iterator;
+ const jsonObject* obj; /* the topic object */
+ jsonObjectNode* current; /* the current node within the object */
+ int done;
+};
+typedef struct _jsonObjectIteratorStruct jsonObjectIterator;
+
+
+/** Allocates a new iterator
+ @param obj The object over which to iterate.
+*/
+jsonObjectIterator* jsonNewObjectIterator(const jsonObject* obj);
+
+/**
+ De-allocates an iterator
+ @param iter The iterator object to free
+*/
+void jsonObjectIteratorFree(jsonObjectIterator* iter);
+
+/**
+ Returns the object_node currently pointed to by the iterator
+ and increments the pointer to the next node
+ @param iter The iterator in question.
+ */
+jsonObjectNode* jsonObjectIteratorNext(jsonObjectIterator* iter);
+
+/**
+ @param iter The iterator.
+ @return True if there is another node after the current node.
+ */
+int jsonObjectIteratorHasNext(const jsonObjectIterator* iter);
+
+
+#endif
+
+
#include <opensrf/string_array.h>
#include <opensrf/utils.h>
#include <opensrf/log.h>
-#include <objson/object.h>
-#include <objson/json_parser.h>
+#include <opensrf/osrf_json.h>
/* libxml stuff for the config reader */
#include <opensrf/utils.h>
#include <opensrf/osrf_app_session.h>
-#include <objson/object.h>
-#include <objson/json_parser.h>
+#include <opensrf/osrf_json.h>
typedef struct {
char* hostname;
#include <opensrf/utils.h>
#include <opensrf/log.h>
+#include <opensrf/osrf_list.h>
-#define STRING_ARRAY_MAX_SIZE 1024
+#define STRING_ARRAY_MAX_SIZE 4096
#ifndef STRING_ARRAY_H
#define STRING_ARRAY_H
+#define OSRF_STRING_ARRAY_FREE(arr)\
+ if(arr) {osrfListFree(arr->list); free(arr);}
+
+
struct string_array_struct {
- char** array;
- int size;
- int arr_size;
- int total_string_size;
+ osrfList* list;
+ int size;
};
typedef struct string_array_struct string_array;
typedef struct string_array_struct osrfStringArray;
}\
}while(0)
+#define OSRF_BUFFER_RESET(gb) \
+ memset(gb->buf, 0, gb->size);\
+ gb->n_used = 0;
+
#ifndef _XML_UTILS_H
#define _XML_UTILS_H
-#include <objson/object.h>
+#include <opensrf/osrf_json.h>
#include <libxml/parser.h>
#include <libxml/tree.h>
export APACHE2_HEADERS=/usr/include/apache2
export APR_HEADERS=/usr/include/apr-1.0/
export LIBXML2_HEADERS=/usr/include/libxml2/
+export OSRF_LEGACY_JSON=1
# TOP level 'src' makefile for OpenSRF
-export TMPDIR = $(TMP)/opensrf
-export OPENSRF = opensrf
-export BINDIR = $(PREFIX)/bin
-export LIBDIR = $(PREFIX)/lib
-export PERLDIR = $(LIBDIR)/perl5
-export INCLUDEDIR = $(PREFIX)/include
-
-export LDLIBS +=
-export LDFLAGS += -Wl,-rpath=$(LIBDIR) -L $(TMPDIR) -L .
-export CFLAGS += -pipe -g -Wall -O2 -fPIC -I ../../include/ -I$(LIBXML2_HEADERS) -I$(APACHE2_HEADERS) \
- -I$(LIBXML2_HEADERS)/libxml -I$(APR_HEADERS)
+export TMPDIR = $(TMP)/opensrf
+export OPENSRF = opensrf
+export BINDIR = $(PREFIX)/bin
+export LIBDIR = $(PREFIX)/lib
+export PERLDIR = $(LIBDIR)/perl5
+export INCLUDEDIR= $(PREFIX)/include
+
+export LDLIBS +=
+export LDFLAGS += -Wl,-rpath=$(LIBDIR) -L $(TMPDIR) -L .
+export CFLAGS += -pipe -g -Wall -O2 -fPIC -I ../../include/ -I$(LIBXML2_HEADERS) -I$(APACHE2_HEADERS) -I$(APR_HEADERS)
+
+ifeq ($(OSRF_LEGACY_JSON), 1)
+export LDLIBS += -lobjson
+endif
all: prep \
opensrf \
router-install \
srfsh-install \
jserver-install \
- perl-install \
- objson-install
+ perl-install
# --------------------------------------------------------------------------------
prep:
mkdir -p $(TMPDIR)
-objson/libobjson.so: prep
- @echo $@
- make -C objson
-
-opensrf: objson/libobjson.so
+opensrf: prep
make -C libopensrf
make -C c-apps
mkdir -p $(INCLUDEDIR)
mkdir -p $(ETCDIR)
-objson-install: install-prep
- @echo $@
- make -C objson install
-
# installs libopensrf.so, opensrf-c, headers, example configs, and osrf_ctl.sh
-opensrf-install: objson-install
+opensrf-install: install-prep
@echo $@
cp $(TMPDIR)/libopensrf.so $(LIBDIR)/libopensrf.so
cp -r ../include/opensrf $(INCLUDEDIR)
cp ../examples/opensrf.xml.example $(ETCDIR)
cp ../examples/opensrf_core.xml.example $(ETCDIR)
cp ../examples/srfsh.xml.example $(ETCDIR)
+ if [ ! -z "$(OSRF_LEGACY_JSON)" ]; then\
+ cp -r ../include/objson $(INCLUDEDIR);\
+ cp $(TMPDIR)/libobjson.so $(LIBDIR);\
+ fi
gateway-install: install-prep opensrf-install
@echo $@
make -C router clean
make -C gateway clean
make -C jserver clean
- make -C objson clean
make -C srfsh clean
make -C c-apps clean
/bin/rm -rf $(TMPDIR) *.o
-LDLIBS += -lobjson -lopensrf
+LDLIBS += -lopensrf
CFLAGS += -DOSRF_LOG_PARAMS
all: osrf_math.so osrf_dbmath.so osrf_version.so
-#include "opensrf/osrf_app_session.h"
-#include "opensrf/osrf_application.h"
-#include "objson/object.h"
-#include "opensrf/log.h"
+#include <opensrf/osrf_app_session.h>
+#include <opensrf/osrf_application.h>
+#include <opensrf/osrf_json.h>
+#include <opensrf/log.h>
#define MODULENAME "opensrf.dbmath"
-#include "opensrf/osrf_app_session.h"
-#include "opensrf/osrf_application.h"
-#include "objson/object.h"
-#include "opensrf/log.h"
+#include <opensrf/osrf_app_session.h>
+#include <opensrf/osrf_application.h>
+#include <opensrf/osrf_json.h>
+#include <opensrf/log.h>
#define MODULENAME "opensrf.math"
#include "opensrf/osrf_app_session.h"
#include "opensrf/osrf_application.h"
-#include "objson/object.h"
+#include "opensrf/osrf_json.h"
#include "opensrf/utils.h"
#include "opensrf/log.h"
#CFLAGS += -DASSUME_STATELESS -DOSRF_GATEWAY_NASTY_DEBUG
CFLAGS += -DASSUME_STATELESS
-LDLIBS += -lobjson -lopensrf
+LDLIBS += -lopensrf
all: osrf_json_gateway.so copy
#include "opensrf/osrf_app_session.h"
#include "opensrf/osrf_system.h"
#include "opensrf/osrfConfig.h"
-#include "objson/object.h"
-#include "objson/json2xml.h"
-#include "objson/xml2json.h"
+#include <opensrf/osrf_json.h>
+#include <opensrf/osrf_json_xml.h>
+#include <opensrf/osrf_legacy_json.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <unistd.h>
#define MODULE_NAME "osrf_json_gateway_module"
#define GATEWAY_CONFIG "OSRFGatewayConfig"
#define CONFIG_CONTEXT "gateway"
+#define JSON_PROTOCOL "OSRFGatewayLegacyJSON"
+#define GATEWAY_USE_LEGACY_JSON 1
#define GATEWAY_DEFAULT_CONFIG "/openils/conf/opensrf_core.xml"
char* configfile; /* our bootstrap config file */
} osrf_json_gateway_config;
+typedef struct {
+ int legacyJSON;
+} osrf_json_gateway_dir_config;
+
+
module AP_MODULE_DECLARE_DATA osrf_json_gateway_module;
char* osrf_json_gateway_config_file = NULL;
return NULL;
}
+static const char* osrf_json_gateway_set_json_proto(cmd_parms *parms, void *config, const char *arg) {
+ osrf_json_gateway_dir_config* cfg = (osrf_json_gateway_dir_config*) config;
+ cfg->legacyJSON = (!strcasecmp((char*) arg, "false")) ? 0 : 1;
+ return NULL;
+}
+
/* tell apache about our commands */
static const command_rec osrf_json_gateway_cmds[] = {
AP_INIT_TAKE1( GATEWAY_CONFIG, osrf_json_gateway_set_config,
NULL, RSRC_CONF, "osrf json gateway config file"),
+ AP_INIT_TAKE1( JSON_PROTOCOL, osrf_json_gateway_set_json_proto,
+ NULL, ACCESS_CONF, "osrf json gateway config file"),
{NULL}
};
return (void*) cfg;
}
+static void* osrf_json_gateway_create_dir_config( apr_pool_t* p, char* dir) {
+ osrf_json_gateway_dir_config* cfg = (osrf_json_gateway_dir_config*)
+ apr_palloc(p, sizeof(osrf_json_gateway_dir_config));
+ cfg->legacyJSON = GATEWAY_USE_LEGACY_JSON;
+ return (void*) cfg;
+}
+
static void osrf_json_gateway_child_init(apr_pool_t *p, server_rec *s) {
/* make sure we're needed first thing*/
if (strcmp(r->handler, MODULE_NAME )) return DECLINED;
+
+ osrf_json_gateway_dir_config* dir_conf =
+ ap_get_module_config(r->per_dir_config, &osrf_json_gateway_module);
+
+
+ /* provide 2 different JSON parsers and serializers to support legacy JSON */
+ jsonObject* (*parseJSONFunc) (char*) = legacy_jsonParseString;
+ char* (*jsonToStringFunc) (const jsonObject*) = legacy_jsonObjectToJSON;
+
+ if(dir_conf->legacyJSON) {
+ ap_log_rerror( APLOG_MARK, APLOG_INFO, 0, r, "Using legacy JSON");
+
+ } else {
+ ap_log_rerror( APLOG_MARK, APLOG_INFO, 0, r, "Not using legacy JSON");
+ parseJSONFunc = jsonParseString;
+ jsonToStringFunc = jsonObjectToJSON;
+ }
+
+
osrfLogDebug(OSRF_LOG_MARK, "osrf gateway: entered request handler");
/* verify we are connected */
int req_id = -1;
if(!strcasecmp(input_format, "json")) {
- req_id = osrf_app_session_make_req( session, NULL, method, api_level, mparams );
+ jsonObject * arr = jsonNewObject(NULL);
+ char* str;
+ int i = 0;
+ while( (str = osrfStringArrayGetString(mparams, i++)) )
+ jsonObjectPush(arr, parseJSONFunc(str));
+
+ req_id = osrf_app_session_make_req( session, arr, method, api_level, NULL );
} else {
if (isXML) {
output = jsonObjectToXML( res );
} else {
- output = jsonObjectToJSON( res );
+ //output = jsonObjectToJSON( res );
+ output = jsonToStringFunc( res );
if( morethan1 ) ap_rputs(",", r); /* comma between JSON array items */
}
ap_rputs(output, r);
bzero(bb, l);
snprintf(bb, l, "%s : %s", statusname, statustext);
jsonObject* tmp = jsonNewObject(bb);
- char* j = jsonObjectToJSON(tmp);
+ char* j = jsonToStringFunc(tmp);
+ //char* j = jsonObjectToJSON(tmp);
snprintf( buf, l, ",\"debug\": %s", j);
free(j);
jsonObjectFree(tmp);
module AP_MODULE_DECLARE_DATA osrf_json_gateway_module = {
STANDARD20_MODULE_STUFF,
- NULL,
+ osrf_json_gateway_create_dir_config,
NULL,
osrf_json_gateway_create_config,
NULL,
-LDLIBS += -lopensrf -lobjson -lxml2
+LDLIBS += -lopensrf -lxml2
CFLAGS += -D_GNU_SOURCE
all: chopchop
-# OSRF_LOG_PARAMS log all incoming method params at OSRF_INFO log level.
-# OSRF_STRICT_PARAMS instructs the app handler to return an error if the number of method arguments
-# provided to any method is not at least as large as the 'argc' setting for the method
+# ------------------------------------------------------------------
+# To build the standalone JSON lib libosrf_json.so:
+# $ make libosrf_json.so
+# To build the standalone JSON lib libosrf_json.so with XML utils
+# support, use something like the following:
+# $ CFLAGS="-DOSRF_JSON_ENABLE_XML_UTILS -I/usr/include/libxml2" LDLIBS=-lxml2 make libosrf_json.so
+#
+# The compiler flag -DOSRF_JSON_ALLOW_COMMENTS tells the parser to
+# allow legacy JSON comments like /* comment */
+# ------------------------------------------------------------------
-CFLAGS += -DASSUME_STATELESS -DOSRF_LOG_PARAMS -DOSRF_STRICT_PARAMS -rdynamic -fno-strict-aliasing
-LDLIBS += -lxml2 -lobjson -ldl -lmemcache
-OSRF_INC = ../../include/opensrf/
+CFLAGS += -DASSUME_STATELESS -DOSRF_STRICT_PARAMS -rdynamic -fno-strict-aliasing -I../../include -fPIC -Wall -DOSRF_JSON_ENABLE_XML_UTILS
+LDLIBS += -lxml2 -ldl -lmemcache
+export OSRF_INC = ../../include/opensrf/
TARGETS = osrf_message.o \
osrf_app_session.o \
utils.o\
socket_bundle.o\
sha.o\
- string_array.o
+ string_array.o
+JSON_TARGETS = osrf_json_object.o\
+ osrf_json_parser.o \
+ osrf_json_tools.o \
+ osrf_legacy_json.o \
+ osrf_json_xml.o
-all: opensrf
+# use these when building the standalone JSON module
+JSON_DEPS = osrf_list.o\
+ osrf_hash.o\
+ utils.o\
+ log.o\
+ md5.o\
+ string_array.o
+all: opensrf
# Build the OpenSRF C binary
opensrf: opensrf.o libopensrf.so
# Build the OpenSRF library
-libopensrf.so: $(TARGETS)
- $(CC) -shared -W1 $(LDFLAGS) $(LDLIBS) $(TARGETS) -o $(TMPDIR)/libopensrf.so
+libopensrf.so: $(TARGETS) json
+ if [ ! -z "$(OSRF_LEGACY_JSON)" ]; then\
+ $(CC) -shared -W1 $(LDFLAGS) $(LDLIBS) $(TARGETS) -o $(TMPDIR)/libopensrf.so;\
+ else\
+ $(CC) -shared -W1 $(LDFLAGS) $(LDLIBS) $(TARGETS) $(JSON_TARGETS) -o $(TMPDIR)/libopensrf.so;\
+ fi;
+
+
+json: $(JSON_TARGETS) $(JSON_DEPS)
+ if [ ! -z "$(OSRF_LEGACY_JSON)" ]; then \
+ $(CC) -shared -W1 $(CFLAGS) \
+ $(LDFLAGS) $(JSON_TARGETS) $(JSON_DEPS) -o $(TMPDIR)/libobjson.so;\
+ fi;
+
+libosrf_json.so: $(JSON_TARGETS) $(JSON_DEPS)
+ $(CC) -shared -W1 $(CFLAGS) \
+ $(LDFLAGS) $(LDLIBS) $(JSON_TARGETS) $(JSON_DEPS) -o $@
+
+
+osrf_json_test: osrf_json_test.o $(JSON_TARGETS) $(JSON_DEPS)
opensrf.o: opensrf.c
socket_bundle.o: socket_bundle.c $(OSRF_INC)/socket_bundle.h
sha.o: sha.c $(OSRF_INC)/sha.h
string_array.o: string_array.c $(OSRF_INC)/string_array.h
+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_xml.o: osrf_json_xml.c $(OSRF_INC)/osrf_json.h $(OSRF_INC)/osrf_json_xml.h
+osrf_json_test.o: osrf_json_test.c
clean:
- /bin/rm -f *.o libopensrf.so opensrf
+ /bin/rm -f *.o *.so opensrf osrf_json_test
+
+
+
--- /dev/null
+#-DOSRF_JSON_ALLOW_COMMENTS
+
+# ------------------------------------------------------------------
+# To build a standalone version of libosrf_json, something
+# like the following should work:
+# $ CFLAGS="-fPIC -I /usr/include/libxml2 -I ../../include" \
+# 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
+
+# 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
+
+all: $(TARGETS)
+ if [ ! -z "$(OSRF_LEGACY_JSON)" ]; then \
+ $(CC) -shared -W1 $(LDFLAGS) $(TARGETS) -o $(TMPDIR)/libobjson.so;\
+ fi;
+
+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_xml.o: osrf_json_xml.c $(OSRF_INC)/osrf_json.h $(OSRF_INC)/osrf_json_xml.h
+
+
+osrf_list.o: osrf_list.c $(OSRF_INC)/osrf_list.h
+osrf_hash.o: osrf_hash.c $(OSRF_INC)/osrf_hash.h
+utils.o: utils.c $(OSRF_INC)/utils.h
+md5.o: md5.c $(OSRF_INC)/md5.h
+log.o: log.c $(OSRF_INC)/log.h
+string_array.o: string_array.c $(OSRF_INC)/string_array.h
+
+
+clean:
+ rm -f osrf_json*.o osrf_legacy_json.o libosrf_json.so
+
#include <opensrf/osrf_application.h>
-#include <objson/object.h>
-
-//osrfApplication* __osrfAppList = NULL;
osrfHash* __osrfAppHash = NULL;
-
int osrfAppRegisterApplication( char* appName, char* soFile ) {
if(!appName || ! soFile) return -1;
char* error;
}
osrfListFree(hash->hash);
- osrfStringArrayFree(hash->keys);
+ OSRF_STRING_ARRAY_FREE(hash->keys);
free(hash);
}
osrfHashIterator* osrfNewHashIterator( osrfHash* hash ) {
if(!hash) return NULL;
- //osrfHashIterator* itr = safe_malloc(sizeof(osrfHashIterator));
osrfHashIterator* itr;
OSRF_MALLOC(itr, sizeof(osrfHashIterator));
itr->hash = hash;
if(!(itr && itr->hash)) return NULL;
if( itr->currentIdx >= itr->keys->size ) return NULL;
free(itr->current);
- itr->current = strdup(
- osrfStringArrayGetString(itr->keys, itr->currentIdx++));
+ itr->current = strdup(osrfStringArrayGetString(itr->keys, itr->currentIdx++));
char* val = osrfHashGet( itr->hash, itr->current );
return val;
}
void osrfHashIteratorFree( osrfHashIterator* itr ) {
if(!itr) return;
free(itr->current);
- //osrfStringArrayFree(itr->keys);
free(itr);
}
void osrfHashIteratorReset( osrfHashIterator* itr ) {
if(!itr) return;
free(itr->current);
- //osrfStringArrayFree(itr->keys);
itr->keys = osrfHashKeysInc(itr->hash);
itr->currentIdx = 0;
itr->current = NULL;
--- /dev/null
+/*
+Copyright (C) 2006 Georgia Public Library Service
+Bill Erickson <billserickson@gmail.com>
+
+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 <opensrf/osrf_json.h>
+#include <opensrf/osrf_json_utils.h>
+
+jsonObject* jsonNewObject(const char* data) {
+
+ jsonObject* o;
+ OSRF_MALLOC(o, sizeof(jsonObject));
+ o->type = JSON_NULL;
+
+ if(data) {
+ o->type = JSON_STRING;
+ o->value.s = strdup(data);
+ }
+
+ return o;
+}
+
+jsonObject* jsonNewObjectFmt(const char* data, ...) {
+
+ jsonObject* o;
+ OSRF_MALLOC(o, sizeof(jsonObject));
+ o->type = JSON_NULL;
+
+ if(data) {
+ VA_LIST_TO_STRING(data);
+ o->type = JSON_STRING;
+ o->value.s = strdup(VA_BUF);
+ }
+
+ return o;
+}
+
+jsonObject* jsonNewNumberObject( double num ) {
+ jsonObject* o = jsonNewObject(NULL);
+ o->type = JSON_NUMBER;
+ o->value.n = num;
+ return o;
+}
+
+jsonObject* jsonNewBoolObject(int val) {
+ jsonObject* o = jsonNewObject(NULL);
+ o->type = JSON_BOOL;
+ jsonSetBool(o, val);
+ return o;
+}
+
+jsonObject* jsonNewObjectType(int type) {
+ jsonObject* o = jsonNewObject(NULL);
+ o->type = type;
+ return o;
+}
+
+void jsonObjectFree( jsonObject* o ) {
+
+ if(!o || o->parent) return;
+ free(o->classname);
+
+ switch(o->type) {
+ case JSON_HASH : osrfHashFree(o->value.h); break;
+ case JSON_ARRAY : osrfListFree(o->value.l); break;
+ case JSON_STRING : free(o->value.s); break;
+ }
+ free(o);
+}
+
+static void _jsonFreeHashItem(char* key, void* item){
+ if(!item) return;
+ jsonObject* o = (jsonObject*) item;
+ o->parent = NULL; /* detach the item */
+ jsonObjectFree(o);
+}
+static void _jsonFreeListItem(void* item){
+ if(!item) return;
+ jsonObject* o = (jsonObject*) item;
+ o->parent = NULL; /* detach the item */
+ jsonObjectFree(o);
+}
+
+void jsonSetBool(jsonObject* bl, int val) {
+ if(!bl) return;
+ JSON_INIT_CLEAR(bl, JSON_BOOL);
+ bl->value.b = val;
+}
+
+unsigned long jsonObjectPush(jsonObject* o, jsonObject* newo) {
+ if(!o) return -1;
+ if(!newo) newo = jsonNewObject(NULL);
+ JSON_INIT_CLEAR(o, JSON_ARRAY);
+ newo->parent = o;
+ osrfListPush( o->value.l, newo );
+ o->size = o->value.l->size;
+ return o->size;
+}
+
+unsigned long jsonObjectSetIndex(jsonObject* dest, unsigned long index, jsonObject* newObj) {
+ if(!dest) return -1;
+ if(!newObj) newObj = jsonNewObject(NULL);
+ JSON_INIT_CLEAR(dest, JSON_ARRAY);
+ newObj->parent = dest;
+ osrfListSet( dest->value.l, newObj, index );
+ dest->size = dest->value.l->size;
+ return dest->value.l->size;
+}
+
+unsigned long jsonObjectSetKey( jsonObject* o, const char* key, jsonObject* newo) {
+ if(!o) return -1;
+ if(!newo) newo = jsonNewObject(NULL);
+ JSON_INIT_CLEAR(o, JSON_HASH);
+ newo->parent = o;
+ osrfHashSet( o->value.h, newo, key );
+ o->size = o->value.h->size;
+ return o->size;
+}
+
+jsonObject* jsonObjectGetKey( const jsonObject* obj, const char* key ) {
+ if(!(obj && obj->type == JSON_HASH && obj->value.h && key)) return NULL;
+ return osrfHashGet( obj->value.h, key);
+}
+
+char* jsonObjectToJSON( const jsonObject* obj ) {
+ jsonObject* obj2 = jsonObjectEncodeClass( (jsonObject*) obj);
+ char* json = jsonObjectToJSONRaw(obj2);
+ jsonObjectFree(obj2);
+ return json;
+}
+
+char* jsonObjectToJSONRaw( const jsonObject* obj ) {
+ if(!obj) return NULL;
+ growing_buffer* buf = buffer_init(32);
+ int i;
+ char* json;
+
+ switch(obj->type) {
+
+ case JSON_BOOL :
+ if(obj->value.b) OSRF_BUFFER_ADD(buf, "true");
+ else OSRF_BUFFER_ADD(buf, "false");
+ break;
+
+ case JSON_NUMBER: {
+ double x = obj->value.n;
+ if( x == (int) x ) {
+ INT_TO_STRING((int)x);
+ OSRF_BUFFER_ADD(buf, INTSTR);
+
+ } else {
+ DOUBLE_TO_STRING(x);
+ OSRF_BUFFER_ADD(buf, DOUBLESTR);
+ }
+ break;
+ }
+
+ case JSON_NULL:
+ OSRF_BUFFER_ADD(buf, "null");
+ break;
+
+ case JSON_STRING:
+ OSRF_BUFFER_ADD_CHAR(buf, '"');
+ char* data = obj->value.s;
+ int len = strlen(data);
+
+ char* output = uescape(data, len, 1);
+ OSRF_BUFFER_ADD(buf, output);
+ free(output);
+ OSRF_BUFFER_ADD_CHAR(buf, '"');
+ break;
+
+ case JSON_ARRAY: {
+ OSRF_BUFFER_ADD_CHAR(buf, '[');
+ if( obj->value.l ) {
+ for( i = 0; i != obj->value.l->size; i++ ) {
+ json = jsonObjectToJSONRaw(OSRF_LIST_GET_INDEX(obj->value.l, i));
+ if(i > 0) OSRF_BUFFER_ADD(buf, ",");
+ OSRF_BUFFER_ADD(buf, json);
+ free(json);
+ }
+ }
+ OSRF_BUFFER_ADD_CHAR(buf, ']');
+ break;
+ }
+
+ case JSON_HASH: {
+
+ OSRF_BUFFER_ADD_CHAR(buf, '{');
+ osrfHashIterator* itr = osrfNewHashIterator(obj->value.h);
+ jsonObject* item;
+ int i = 0;
+
+ while( (item = osrfHashIteratorNext(itr)) ) {
+ if(i++ > 0) OSRF_BUFFER_ADD(buf, ",");
+ buffer_fadd(buf, "\"%s\":", itr->current);
+ char* json = jsonObjectToJSONRaw(item);
+ OSRF_BUFFER_ADD(buf, json);
+ free(json);
+ }
+
+ osrfHashIteratorFree(itr);
+ OSRF_BUFFER_ADD_CHAR(buf, '}');
+ break;
+ }
+ }
+
+ return buffer_release(buf);
+}
+
+
+jsonIterator* jsonNewIterator(const jsonObject* obj) {
+ if(!obj) return NULL;
+ jsonIterator* itr;
+ OSRF_MALLOC(itr, sizeof(jsonIterator));
+
+ itr->obj = (jsonObject*) obj;
+ itr->index = 0;
+ itr->key = NULL;
+
+ if( obj->type == JSON_HASH )
+ itr->hashItr = osrfNewHashIterator(obj->value.h);
+
+ return itr;
+}
+
+void jsonIteratorFree(jsonIterator* itr) {
+ if(!itr) return;
+ free(itr->key);
+ osrfHashIteratorFree(itr->hashItr);
+ free(itr);
+}
+
+jsonObject* jsonIteratorNext(jsonIterator* itr) {
+ if(!(itr && itr->obj)) return NULL;
+ if( itr->obj->type == JSON_HASH ) {
+ if(!itr->hashItr) return NULL;
+ jsonObject* item = osrfHashIteratorNext(itr->hashItr);
+ free(itr->key);
+ itr->key = strdup(itr->hashItr->current);
+ return item;
+ } else {
+ return jsonObjectGetIndex( itr->obj, itr->index++ );
+ }
+}
+
+int jsonIteratorHasNext(const jsonIterator* itr) {
+ if(!(itr && itr->obj)) return 0;
+ if( itr->obj->type == JSON_HASH )
+ return osrfHashIteratorHasNext( itr->hashItr );
+ return (itr->index < itr->obj->size) ? 1 : 0;
+}
+
+jsonObject* jsonObjectGetIndex( const jsonObject* obj, unsigned long index ) {
+ if(!obj) return NULL;
+ return (obj->type == JSON_ARRAY) ?
+ (OSRF_LIST_GET_INDEX(obj->value.l, index)) : NULL;
+}
+
+
+
+unsigned long jsonObjectRemoveIndex(jsonObject* dest, unsigned long index) {
+ if( dest && dest->type == JSON_ARRAY ) {
+ osrfListRemove(dest->value.l, index);
+ return dest->value.l->size;
+ }
+ return -1;
+}
+
+
+unsigned long jsonObjectRemoveKey( jsonObject* dest, const char* key) {
+ if( dest && key && dest->type == JSON_HASH ) {
+ osrfHashRemove(dest->value.h, key);
+ return 1;
+ }
+ return -1;
+}
+
+char* jsonObjectGetString(const jsonObject* obj) {
+ return (obj && obj->type == JSON_STRING) ? obj->value.s : NULL;
+}
+
+double jsonObjectGetNumber( const jsonObject* obj ) {
+ return (obj && obj->type == JSON_NUMBER) ? obj->value.n : 0;
+}
+
+void jsonObjectSetString(jsonObject* dest, const char* string) {
+ if(!(dest && string)) return;
+ JSON_INIT_CLEAR(dest, JSON_STRING);
+ free(dest->value.s);
+ dest->value.s = strdup(string);
+}
+
+void jsonObjectSetNumber(jsonObject* dest, double num) {
+ if(!dest) return;
+ JSON_INIT_CLEAR(dest, JSON_NUMBER);
+ dest->value.n = num;
+}
+
+void jsonObjectSetClass(jsonObject* dest, const char* classname ) {
+ if(!(dest && classname)) return;
+ free(dest->classname);
+ dest->classname = strdup(classname);
+}
+const char* jsonObjectGetClass(const jsonObject* dest) {
+ if(!dest) return NULL;
+ return dest->classname;
+}
+
+jsonObject* jsonObjectClone( const jsonObject* o ) {
+ if(!o) return jsonNewObject(NULL);
+
+ int i;
+ jsonObject* arr;
+ jsonObject* hash;
+ jsonIterator* itr;
+ jsonObject* tmp;
+ jsonObject* result = NULL;
+
+ switch(o->type) {
+ case JSON_NULL:
+ result = jsonNewObject(NULL);
+ break;
+ case JSON_STRING:
+ result = jsonNewObject(jsonObjectGetString(o));
+ break;
+ case JSON_NUMBER:
+ result = jsonNewNumberObject(jsonObjectGetNumber(o));
+ break;
+ case JSON_BOOL:
+ result = jsonNewBoolObject(jsonBoolIsTrue((jsonObject*) o));
+ break;
+ case JSON_ARRAY:
+ arr = jsonNewObject(NULL);
+ arr->type = JSON_ARRAY;
+ for(i=0; i < o->size; i++)
+ jsonObjectPush(arr, jsonObjectClone(jsonObjectGetIndex(o, i)));
+ result = arr;
+ break;
+ case JSON_HASH:
+ hash = jsonNewObject(NULL);
+ hash->type = JSON_HASH;
+ itr = jsonNewIterator(o);
+ while( (tmp = jsonIteratorNext(itr)) )
+ jsonObjectSetKey(hash, itr->key, jsonObjectClone(tmp));
+ jsonIteratorFree(itr);
+ result = hash;
+ break;
+ }
+
+ jsonObjectSetClass(result, jsonObjectGetClass(o));
+ return result;
+}
+
+int jsonBoolIsTrue( jsonObject* boolObj ) {
+ if( boolObj && boolObj->type == JSON_BOOL && boolObj->value.b )
+ return 1;
+ return 0;
+}
+
+
+char* jsonObjectToSimpleString( const jsonObject* o ) {
+ if(!o) return NULL;
+
+ char* value = NULL;
+
+ switch( o->type ) {
+
+ case JSON_NUMBER: {
+
+ if( o->value.n == (int) o->value.n ) {
+ INT_TO_STRING((int) o->value.n);
+ value = strdup(INTSTR);
+
+ } else {
+ DOUBLE_TO_STRING(o->value.n);
+ value = strdup(DOUBLESTR);
+ }
+
+ break;
+ }
+
+ case JSON_STRING:
+ value = strdup(o->value.s);
+ }
+
+ return value;
+}
+
+
--- /dev/null
+/*
+Copyright (C) 2006 Georgia Public Library Service
+Bill Erickson <billserickson@gmail.com>
+
+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 <opensrf/osrf_json.h>
+#include <opensrf/osrf_json_utils.h>
+#include <ctype.h>
+
+
+/* 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 jsonParserHandler jsonInternalParserHandlerStruct = {
+ _jsonHandleStartObject,
+ _jsonHandleObjectKey,
+ _jsonHandleEndObject,
+ _jsonHandleStartArray,
+ _jsonHandleEndArray,
+ _jsonHandleNull,
+ _jsonHandleString,
+ _jsonHandleBool,
+ _jsonHandleNumber,
+ _jsonHandleError
+};
+static jsonParserHandler*
+ jsonInternalParserHandler = &jsonInternalParserHandlerStruct;
+
+
+jsonParserContext* jsonNewParser( jsonParserHandler* handler, void* userData) {
+ jsonParserContext* ctx;
+ OSRF_MALLOC(ctx, sizeof(jsonParserContext));
+ ctx->stateStack = osrfNewList();
+ ctx->buffer = buffer_init(512);
+ ctx->utfbuf = buffer_init(5);
+ ctx->handler = handler;
+ ctx->state = 0;
+ ctx->index = 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);
+ 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);
+ int pre = ctx->index - 15;
+ int post= ctx->index + 15;
+ while( pre < 0 ) pre++;
+ while( post >= ctx->chunksize ) post--;
+ int l = post - pre;
+ char buf[l];
+ memset(buf, 0, l);
+ snprintf(buf, l, ctx->chunk + pre);
+ 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,4);
+ 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;
+ }
+
+ /* make me more strict */
+ char* err = NULL;
+ double d = strtod(ctx->buffer->buf, &err);
+ if(err && err[0] != '\0')
+ return _jsonParserError(ctx, "Invalid number sequence");
+ JSON_STATE_REMOVE(ctx, JSON_STATE_IN_NUMBER);
+ OSRF_BUFFER_RESET(ctx->buffer);
+ if(ctx->handler->handleNumber)
+ ctx->handler->handleNumber( ctx->userData, d );
+ ctx->index--; /* scooch back to the first non-digit number */
+ return 0;
+}
+
+
+
+
+int jsonParseChunk( jsonParserContext* ctx, 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_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;
+ OSRF_MALLOC(p, sizeof(jsonInternalParser));
+ p->ctx = jsonNewParser( jsonInternalParserHandler, p );
+ p->obj = NULL;
+ p->lastkey = NULL;
+ return p;
+}
+
+void _jsonInternalParserFree(jsonInternalParser* p) {
+ if(!p) return;
+ jsonParserFree(p->ctx);
+ free(p->lastkey);
+ free(p);
+}
+
+static jsonObject* _jsonParseStringImpl(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( char* str ) {
+ if(!str) return NULL;
+ jsonObject* obj = _jsonParseStringImpl(str, NULL);
+ jsonObject* obj2 = jsonObjectDecodeClass(obj);
+ jsonObjectFree(obj);
+ return obj2;
+}
+
+jsonObject* jsonParseStringRaw( char* str ) {
+ if(!str) return NULL;
+ return _jsonParseStringImpl(str, NULL);
+}
+
+jsonObject* jsonParseStringFmt( 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, double num) {
+ jsonInternalParser* p = (jsonInternalParser*) ctx;
+ _jsonInsertParserItem(p, jsonNewNumberObject(num));
+}
+
+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 */
+ switch(p->current->type) {
+ case JSON_HASH : jsonObjectSetKey(p->current, p->lastkey, newo); break;
+ case JSON_ARRAY: jsonObjectPush(p->current, newo); break;
+ default: fprintf(stderr, "%s:%d -> how?\n", JSON_LOG_MARK);
+ }
+
+ /* 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;
+ }
+}
+
+
--- /dev/null
+/*
+ * Basic JSON test module. Needs more strenous tests....
+ *
+ */
+#include <stdio.h>
+#include <opensrf/osrf_json.h>
+
+static void speedTest();
+
+
+int main(int argc, char* argv[]) {
+ /* XXX add support for command line test type specification */
+ speedTest();
+ return 0;
+}
+
+
+
+static void speedTest() {
+
+ /* creates a giant json object, generating JSON strings
+ * of subobjects as it goes. */
+
+ int i,k;
+ int count = 50;
+ char buf[16];
+ char* jsonString;
+
+ jsonObject* array;
+ jsonObject* dupe;
+ jsonObject* hash = jsonNewObject(NULL);
+
+ for(i = 0; i < count; i++) {
+
+ memset(buf, 0, 16);
+ snprintf(buf, 16, "key_%d", i);
+
+ array = jsonNewObject(NULL);
+ for(k = 0; k < count + i; k++) {
+ jsonObjectPush(array, jsonNewNumberObject(k));
+ jsonObjectPush(array, jsonNewObject(NULL));
+ jsonObjectPush(array, jsonNewObjectFmt("str %d-%d", i, k));
+ }
+ jsonObjectSetKey(hash, buf, array);
+
+ jsonString = jsonObjectToJSON(hash);
+ printf("%s\n\n", jsonString);
+ dupe = jsonParseString(jsonString);
+
+ jsonObjectFree(dupe);
+ free(jsonString);
+ }
+
+ jsonObjectFree(hash);
+}
+
--- /dev/null
+/*
+Copyright (C) 2006 Georgia Public Library Service
+Bill Erickson <billserickson@gmail.com>
+
+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 <opensrf/osrf_json.h>
+
+jsonObject* _jsonObjectEncodeClass( jsonObject* obj, int ignoreClass );
+
+
+jsonObject* jsonObjectFindPath( const jsonObject* obj, char* path, ...);
+jsonObject* _jsonObjectFindPathRecurse(const jsonObject* obj, char* root, char* path);
+jsonObject* __jsonObjectFindPathRecurse(const jsonObject* obj, char* root);
+
+
+static char* __tabs(int count) {
+ growing_buffer* buf = buffer_init(24);
+ int i;
+ for(i=0;i<count;i++) OSRF_BUFFER_ADD(buf, " ");
+ return buffer_release(buf);
+}
+
+char* jsonFormatString( const char* string ) {
+ if(!string) return strdup("");
+
+ growing_buffer* buf = buffer_init(64);
+ int i;
+ int depth = 0;
+ char* tab = NULL;
+
+ char c;
+ for(i=0; i!= strlen(string); i++) {
+ c = string[i];
+
+ if( c == '{' || c == '[' ) {
+
+ tab = __tabs(++depth);
+ buffer_fadd( buf, "%c\n%s", c, tab);
+ free(tab);
+
+ } else if( c == '}' || c == ']' ) {
+
+ tab = __tabs(--depth);
+ buffer_fadd( buf, "\n%s%c", tab, c);
+ free(tab);
+
+ if(string[i+1] != ',') {
+ tab = __tabs(depth);
+ buffer_fadd( buf, "%s", tab );
+ free(tab);
+ }
+
+ } else if( c == ',' ) {
+
+ tab = __tabs(depth);
+ buffer_fadd(buf, ",\n%s", tab);
+ free(tab);
+
+ } else { buffer_add_char(buf, c); }
+
+ }
+
+ return buffer_release(buf);
+}
+
+
+
+jsonObject* jsonObjectDecodeClass( jsonObject* obj ) {
+ if(!obj) return jsonNewObject(NULL);
+
+ jsonObject* newObj = NULL;
+ jsonObject* classObj = NULL;
+ jsonObject* payloadObj = NULL;
+ int i;
+
+ if( obj->type == JSON_HASH ) {
+
+ /* are we a special class object? */
+ if( (classObj = jsonObjectGetKey( obj, JSON_CLASS_KEY )) ) {
+
+ /* do we have a payload */
+ if( (payloadObj = jsonObjectGetKey( obj, JSON_DATA_KEY )) ) {
+ newObj = jsonObjectDecodeClass( payloadObj );
+ jsonObjectSetClass( newObj, jsonObjectGetString(classObj) );
+
+ } else { /* class is defined but there is no payload */
+ return NULL;
+ }
+
+ } else { /* we're a regular hash */
+
+ jsonIterator* itr = jsonNewIterator(obj);
+ jsonObject* tmp;
+ newObj = jsonNewObjectType(JSON_HASH);
+ while( (tmp = jsonIteratorNext(itr)) ) {
+ jsonObject* o = jsonObjectDecodeClass(tmp);
+ jsonObjectSetKey( newObj, itr->key, o );
+ }
+ jsonIteratorFree(itr);
+ }
+
+ } else {
+
+ if( obj->type == JSON_ARRAY ) { /* we're an array */
+ newObj = jsonNewObjectType(JSON_ARRAY);
+ for( i = 0; i != obj->size; i++ ) {
+ jsonObject* tmp = jsonObjectDecodeClass(jsonObjectGetIndex( obj, i ) );
+ jsonObjectSetIndex( newObj, i, tmp );
+ }
+
+ } else { /* not an aggregate type */
+ newObj = jsonObjectClone(obj);
+ }
+ }
+
+ return newObj;
+}
+
+jsonObject* jsonObjectEncodeClass( jsonObject* obj ) {
+ return _jsonObjectEncodeClass( obj, 0 );
+}
+
+jsonObject* _jsonObjectEncodeClass( jsonObject* obj, int ignoreClass ) {
+
+ //if(!obj) return NULL;
+ if(!obj) return jsonNewObject(NULL);
+ jsonObject* newObj = NULL;
+
+ if( obj->classname && ! ignoreClass ) {
+ newObj = jsonNewObjectType(JSON_HASH);
+
+ jsonObjectSetKey( newObj,
+ JSON_CLASS_KEY, jsonNewObject(obj->classname) );
+
+ jsonObjectSetKey( newObj,
+ JSON_DATA_KEY, _jsonObjectEncodeClass(obj, 1));
+
+ } else if( obj->type == JSON_HASH ) {
+
+ jsonIterator* itr = jsonNewIterator(obj);
+ jsonObject* tmp;
+ newObj = jsonNewObjectType(JSON_HASH);
+
+ while( (tmp = jsonIteratorNext(itr)) ) {
+ jsonObjectSetKey( newObj, itr->key,
+ _jsonObjectEncodeClass(tmp, 0));
+ }
+ jsonIteratorFree(itr);
+
+ } else if( obj->type == JSON_ARRAY ) {
+
+ newObj = jsonNewObjectType(JSON_ARRAY);
+ int i;
+ for( i = 0; i != obj->size; i++ ) {
+ jsonObjectSetIndex( newObj, i,
+ _jsonObjectEncodeClass(jsonObjectGetIndex( obj, i ), 0 ));
+ }
+
+ } else {
+ newObj = jsonObjectClone(obj);
+ }
+
+ return newObj;
+}
+
+jsonObject* jsonParseFile( char* filename ) {
+ if(!filename) return NULL;
+ char* data = file_to_string(filename);
+ jsonObject* o = jsonParseString(data);
+ free(data);
+ return o;
+}
+
+
+
+jsonObject* jsonObjectFindPath( const jsonObject* obj, char* format, ...) {
+ if(!obj || !format || strlen(format) < 1) return NULL;
+
+ VA_LIST_TO_STRING(format);
+ char* buf = VA_BUF;
+ char* token = NULL;
+ char* t = buf;
+ char* tt; /* strtok storage */
+
+ /* copy the path before strtok_r destroys it */
+ char* pathcopy = strdup(buf);
+
+ /* grab the root of the path */
+ token = strtok_r(t, "/", &tt);
+ if(!token) return NULL;
+
+ /* special case where path starts with // (start anywhere) */
+ if(strlen(pathcopy) > 2 && pathcopy[0] == '/' && pathcopy[1] == '/') {
+ jsonObject* it = _jsonObjectFindPathRecurse(obj, token, pathcopy + 1);
+ free(pathcopy);
+ return it;
+ }
+
+ free(pathcopy);
+
+ t = NULL;
+ do {
+ obj = jsonObjectGetKey(obj, token);
+ } while( (token = strtok_r(NULL, "/", &tt)) && obj);
+
+ return jsonObjectClone(obj);
+}
+
+/* --------------------------------------------------------------- */
+
+
+
+jsonObject* _jsonObjectFindPathRecurse(const jsonObject* obj, char* root, char* path) {
+
+ if(!obj || ! root || !path) return NULL;
+
+ /* collect all of the potential objects */
+ jsonObject* arr = __jsonObjectFindPathRecurse(obj, root);
+
+ /* container for fully matching objects */
+ jsonObject* newarr = jsonParseString("[]");
+ int i;
+
+ /* path is just /root or /root/ */
+ if( strlen(root) + 2 >= strlen(path) ) {
+ return arr;
+
+ } else {
+
+ /* gather all of the sub-objects that match the full path */
+ for( i = 0; i < arr->size; i++ ) {
+ jsonObject* a = jsonObjectGetIndex(arr, i);
+ jsonObject* thing = jsonObjectFindPath(a , path + strlen(root) + 1);
+
+ if(thing) { //jsonObjectPush(newarr, thing);
+ if(thing->type == JSON_ARRAY) {
+ int i;
+ for( i = 0; i != thing->size; i++ )
+ jsonObjectPush(newarr, jsonObjectClone(jsonObjectGetIndex(thing,i)));
+ jsonObjectFree(thing);
+
+ } else {
+ jsonObjectPush(newarr, thing);
+ }
+ }
+ }
+ }
+
+ jsonObjectFree(arr);
+ return newarr;
+}
+
+jsonObject* __jsonObjectFindPathRecurse(const jsonObject* obj, char* root) {
+
+ jsonObject* arr = jsonParseString("[]");
+ if(!obj) return arr;
+
+ int i;
+
+ /* if the current object has a node that matches, add it */
+
+ jsonObject* o = jsonObjectGetKey(obj, root);
+ if(o) jsonObjectPush( arr, jsonObjectClone(o) );
+
+ jsonObject* tmp = NULL;
+ jsonObject* childarr;
+ jsonIterator* itr = jsonNewIterator(obj);
+
+ /* recurse through the children and find all potential nodes */
+ while( (tmp = jsonIteratorNext(itr)) ) {
+ childarr = __jsonObjectFindPathRecurse(tmp, root);
+ if(childarr && childarr->size > 0) {
+ for( i = 0; i!= childarr->size; i++ ) {
+ jsonObjectPush( arr, jsonObjectClone(jsonObjectGetIndex(childarr, i)) );
+ }
+ }
+ jsonObjectFree(childarr);
+ }
+
+ jsonIteratorFree(itr);
+
+ return arr;
+}
+
+
+
+
--- /dev/null
+#include <opensrf/osrf_json_xml.h>
+
+#ifdef OSRF_JSON_ENABLE_XML_UTILS
+
+struct osrfXMLGatewayParserStruct {
+ osrfList* objStack;
+ osrfList* keyStack;
+ jsonObject* obj;
+ short inString;
+ short inNumber;
+ short error;
+};
+typedef struct osrfXMLGatewayParserStruct osrfXMLGatewayParser;
+
+/** returns the attribute value with the given attribute name */
+static char* getXMLAttr(const xmlChar** atts, char* attr_name) {
+ int i;
+ if (atts != NULL) {
+ for(i = 0; (atts[i] != NULL); i++) {
+ if(strcmp((char*) atts[i++], attr_name) == 0) {
+ if(atts[i] != NULL)
+ return (char*) atts[i];
+ }
+ }
+ }
+ return NULL;
+}
+
+
+static void appendChild(osrfXMLGatewayParser* p, jsonObject* obj) {
+
+ if(p->obj == NULL)
+ p->obj = obj;
+
+ if(p->objStack->size == 0)
+ return;
+
+ jsonObject* parent = OSRF_LIST_GET_INDEX(p->objStack, p->objStack->size - 1);
+
+ if(parent->type == JSON_ARRAY) {
+ jsonObjectPush(parent, obj);
+ } else {
+ char* key = osrfListPop(p->keyStack);
+ jsonObjectSetKey(parent, key, obj);
+ free(key); /* the list is not setup for auto-freeing */
+ }
+}
+
+
+
+static void startElementHandler(
+ void *parser, const xmlChar *name, const xmlChar **atts) {
+
+ osrfXMLGatewayParser* p = (osrfXMLGatewayParser*) parser;
+ jsonObject* obj;
+
+ char* hint = getXMLAttr(atts, "class_hint");
+
+ if(!strcmp((char*) name, "null")) {
+ appendChild(p, jsonNewObject(NULL));
+ return;
+ }
+
+ if(!strcmp((char*) name, "string")) {
+ p->inString = 1;
+ return;
+ }
+
+ if(!strcmp((char*) name, "element")) {
+ osrfListPush(p->keyStack, strdup(getXMLAttr(atts, "key")));
+ return;
+ }
+
+ if(!strcmp((char*) name, "object")) {
+ obj = jsonNewObject(NULL);
+ jsonObjectSetClass(obj, hint); /* OK if hint is NULL */
+ obj->type = JSON_HASH;
+ appendChild(p, obj);
+ osrfListPush(p->objStack, obj);
+ return;
+ }
+
+ if(!strcmp((char*) name, "array")) {
+ obj = jsonNewObject(NULL);
+ jsonObjectSetClass(obj, hint); /* OK if hint is NULL */
+ obj->type = JSON_ARRAY;
+ appendChild(p, obj);
+ osrfListPush(p->objStack, obj);
+ return;
+ }
+
+
+ if(!strcmp((char*) name, "number")) {
+ p->inNumber = 1;
+ return;
+ }
+
+ if(!strcmp((char*) name, "boolean")) {
+ obj = jsonNewObject(NULL);
+ obj->type = JSON_BOOL;
+ char* val = getXMLAttr(atts, "value");
+ if(val && !strcmp(val, "true"))
+ obj->value.b = 1;
+
+ return;
+ }
+}
+
+static void endElementHandler( void *parser, const xmlChar *name) {
+ if(!strcmp((char*) name, "array") || !strcmp((char*) name, "object")) {
+ osrfXMLGatewayParser* p = (osrfXMLGatewayParser*) parser;
+ osrfListPop(p->objStack);
+ }
+}
+
+static void characterHandler(void *parser, const xmlChar *ch, int len) {
+
+ char data[len+1];
+ strncpy(data, (char*) ch, len);
+ data[len] = '\0';
+ osrfXMLGatewayParser* p = (osrfXMLGatewayParser*) parser;
+
+ if(p->inString) {
+ appendChild(p, jsonNewObject(data));
+ p->inString = 0;
+ return;
+ }
+
+ if(p->inNumber) {
+ appendChild(p, jsonNewNumberObject(atof(data)));
+ p->inNumber = 0;
+ return;
+ }
+}
+
+static void parseWarningHandler(void *parser, const char* msg, ...) {
+ VA_LIST_TO_STRING(msg);
+ fprintf(stderr, "Parser warning %s\n", VA_BUF);
+ fflush(stderr);
+}
+
+static void parseErrorHandler(void *parser, const char* msg, ...) {
+
+ VA_LIST_TO_STRING(msg);
+ fprintf(stderr, "Parser error %s\n", VA_BUF);
+ fflush(stderr);
+
+ osrfXMLGatewayParser* p = (osrfXMLGatewayParser*) parser;
+
+ /* keyStack as strdup'ed strings. The list may
+ * not be empty, so tell it to free the items
+ * when it's freed (from the main routine)
+ */
+ osrfListSetDefaultFree(p->keyStack);
+ jsonObjectFree(p->obj);
+
+ p->obj = NULL;
+ p->error = 1;
+}
+
+
+
+
+static xmlSAXHandler SAXHandlerStruct = {
+ NULL, /* internalSubset */
+ NULL, /* isStandalone */
+ NULL, /* hasInternalSubset */
+ NULL, /* hasExternalSubset */
+ NULL, /* resolveEntity */
+ NULL, /* getEntity */
+ NULL, /* entityDecl */
+ NULL, /* notationDecl */
+ NULL, /* attributeDecl */
+ NULL, /* elementDecl */
+ NULL, /* unparsedEntityDecl */
+ NULL, /* setDocumentLocator */
+ NULL, /* startDocument */
+ NULL, /* endDocument */
+ startElementHandler, /* startElement */
+ endElementHandler, /* endElement */
+ NULL, /* reference */
+ characterHandler, /* characters */
+ NULL, /* ignorableWhitespace */
+ NULL, /* processingInstruction */
+ NULL, /* comment */
+ parseWarningHandler, /* xmlParserWarning */
+ parseErrorHandler, /* xmlParserError */
+ NULL, /* xmlParserFatalError : unused */
+ NULL, /* getParameterEntity */
+ NULL, /* cdataBlock; */
+ NULL, /* externalSubset; */
+ 1,
+ NULL,
+ NULL, /* startElementNs */
+ NULL, /* endElementNs */
+ NULL /* xmlStructuredErrorFunc */
+};
+
+static const xmlSAXHandlerPtr SAXHandler = &SAXHandlerStruct;
+
+jsonObject* jsonXMLToJSONObject(const char* xml) {
+
+ osrfXMLGatewayParser parser;
+
+ /* don't define freeItem, since objects will be cleaned by freeing the parent */
+ parser.objStack = osrfNewList();
+ /* don't define freeItem, since the list eill end up empty if there are no errors*/
+ parser.keyStack = osrfNewList();
+ parser.obj = NULL;
+ parser.inString = 0;
+ parser.inNumber = 0;
+
+ xmlParserCtxtPtr ctxt = xmlCreatePushParserCtxt(SAXHandler, &parser, "", 0, NULL);
+ xmlParseChunk(ctxt, xml, strlen(xml), 1);
+
+ osrfListFree(parser.objStack);
+ osrfListFree(parser.keyStack);
+ xmlFreeParserCtxt(ctxt);
+ xmlCleanupCharEncodingHandlers();
+ xmlDictCleanup();
+ xmlCleanupParser();
+
+ return parser.obj;
+}
+
+
+
+
+
+
+static char* _escape_xml (char*);
+static int _recurse_jsonObjectToXML(jsonObject*, growing_buffer*);
+
+char* jsonObjectToXML(jsonObject* obj) {
+
+ growing_buffer * res_xml;
+ char * output;
+
+ res_xml = buffer_init(1024);
+
+ if (!obj)
+ return strdup("<null/>");
+
+ _recurse_jsonObjectToXML( obj, res_xml );
+ output = buffer_data(res_xml);
+
+ buffer_free(res_xml);
+
+ return output;
+
+}
+
+int _recurse_jsonObjectToXML(jsonObject* obj, growing_buffer* res_xml) {
+
+ char * hint = NULL;
+ char * bool_val = NULL;
+ int i = 0;
+
+ if (obj->classname)
+ hint = strdup(obj->classname);
+
+ if(obj->type == JSON_NULL) {
+
+ if (hint)
+ buffer_fadd(res_xml, "<null class_hint=\"%s\"/>",hint);
+ else
+ buffer_add(res_xml, "<null/>");
+
+ } else if(obj->type == JSON_BOOL) {
+
+ if (obj->value.b)
+ bool_val = strdup("true");
+ else
+ bool_val = strdup("false");
+
+ if (hint)
+ buffer_fadd(res_xml, "<boolean value=\"%s\" class_hint=\"%s\"/>", bool_val, hint);
+ else
+ buffer_fadd(res_xml, "<boolean value=\"%s\"/>", bool_val);
+
+ free(bool_val);
+
+ } else if (obj->type == JSON_STRING) {
+ if (hint) {
+ char * t = _escape_xml(jsonObjectGetString(obj));
+ buffer_fadd(res_xml,"<string class_hint=\"%s\">%s</string>", hint, t);
+ free(t);
+ } else {
+ char * t = _escape_xml(jsonObjectGetString(obj));
+ buffer_fadd(res_xml,"<string>%s</string>", t);
+ free(t);
+ }
+
+ } else if(obj->type == JSON_NUMBER) {
+ double x = jsonObjectGetNumber(obj);
+ if (hint) {
+ if (x == (int)x)
+ buffer_fadd(res_xml,"<number class_hint=\"%s\">%d</number>", hint, (int)x);
+ else
+ buffer_fadd(res_xml,"<number class_hint=\"%s\">%lf</number>", hint, x);
+ } else {
+ if (x == (int)x)
+ buffer_fadd(res_xml,"<number>%d</number>", (int)x);
+ else
+ buffer_fadd(res_xml,"<number>%lf</number>", x);
+ }
+
+ } else if (obj->type == JSON_ARRAY) {
+
+ if (hint)
+ buffer_fadd(res_xml,"<array class_hint=\"%s\">", hint);
+ else
+ buffer_add(res_xml,"<array>");
+
+ for ( i = 0; i!= obj->size; i++ )
+ _recurse_jsonObjectToXML(jsonObjectGetIndex(obj,i), res_xml);
+
+ buffer_add(res_xml,"</array>");
+
+ } else if (obj->type == JSON_HASH) {
+
+ if (hint)
+ buffer_fadd(res_xml,"<object class_hint=\"%s\">", hint);
+ else
+ buffer_add(res_xml,"<object>");
+
+ jsonIterator* itr = jsonNewIterator(obj);
+ jsonObject* tmp;
+ while( (tmp = jsonIteratorNext(itr)) ) {
+ buffer_fadd(res_xml,"<element key=\"%s\">",itr->key);
+ _recurse_jsonObjectToXML(tmp, res_xml);
+ buffer_add(res_xml,"</element>");
+ }
+ jsonIteratorFree(itr);
+
+ buffer_add(res_xml,"</object>");
+ }
+
+ if (hint)
+ free(hint);
+
+ return 1;
+}
+
+char* _escape_xml (char* text) {
+ char* out;
+ growing_buffer* b = buffer_init(256);
+ int len = strlen(text);
+ int i;
+ for (i = 0; i < len; i++) {
+ if (text[i] == '&')
+ buffer_add(b,"&");
+ else if (text[i] == '<')
+ buffer_add(b,"<");
+ else if (text[i] == '>')
+ buffer_add(b,">");
+ else
+ buffer_add_char(b,text[i]);
+ }
+ out = buffer_data(b);
+ buffer_free(b);
+ return out;
+}
+
+#endif
--- /dev/null
+/*
+Copyright (C) 2006 Georgia Public Library Service
+Bill Erickson <billserickson@gmail.com>
+
+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 <opensrf/osrf_legacy_json.h>
+
+/* keep a copy of the length of the current json string so we don't
+ * have to calculate it in each function
+ */
+int current_strlen;
+
+
+jsonObject* legacy_jsonParseString( char* string) {
+ return json_parse_string( string );
+}
+
+jsonObject* legacy_jsonParseStringFmt( char* string, ... ) {
+ VA_LIST_TO_STRING(string);
+ return json_parse_string( VA_BUF );
+}
+
+
+jsonObject* json_parse_string(char* string) {
+
+ if(string == NULL) return NULL;
+
+ current_strlen = strlen(string);
+
+ if(current_strlen == 0)
+ return NULL;
+
+ unsigned long index = 0;
+
+ json_eat_ws(string, &index, 1, current_strlen); /* remove leading whitespace */
+ if(index == current_strlen) return NULL;
+
+ jsonObject* obj = jsonNewObject(NULL);
+
+ int status = _json_parse_string(string, &index, obj, current_strlen);
+ if(!status) return obj;
+
+ if(status == -2) {
+ jsonObjectFree(obj);
+ return NULL;
+ }
+
+ return NULL;
+}
+
+
+int _json_parse_string(char* string, unsigned long* index, jsonObject* obj, int current_strlen) {
+ if( !string || !index || *index >= current_strlen) return -2;
+
+ int status = 0; /* return code from parsing routines */
+ char* classname = NULL; /* object class hint */
+ json_eat_ws(string, index, 1, current_strlen); /* remove leading whitespace */
+
+ char c = string[*index];
+
+ /* remove any leading comments */
+ if( c == '/' ) {
+
+ while(1) {
+ (*index)++; /* move to second comment char */
+ status = json_eat_comment(string, index, &classname, 1, current_strlen);
+ if(status) return status;
+
+ json_eat_ws(string, index, 1, current_strlen);
+ c = string[*index];
+ if(c != '/')
+ break;
+ }
+ }
+
+ json_eat_ws(string, index, 1, current_strlen); /* remove leading whitespace */
+
+ if(*index >= current_strlen)
+ return -2;
+
+ switch(c) {
+
+ /* json string */
+ case '"':
+ (*index)++;
+ status = json_parse_json_string(string, index, obj, current_strlen); break;
+
+ /* json array */
+ case '[':
+ (*index)++;
+ status = json_parse_json_array(string, index, obj, current_strlen);
+ break;
+
+ /* json object */
+ case '{':
+ (*index)++;
+ status = json_parse_json_object(string, index, obj, current_strlen);
+ break;
+
+ /* NULL */
+ case 'n':
+ case 'N':
+ status = json_parse_json_null(string, index, obj, current_strlen);
+ break;
+
+
+ /* true, false */
+ case 'f':
+ case 'F':
+ case 't':
+ case 'T':
+ status = json_parse_json_bool(string, index, obj, current_strlen);
+ break;
+
+ default:
+ if(isdigit(c) || c == '.' || c == '-') { /* are we a number? */
+ status = json_parse_json_number(string, index, obj, current_strlen);
+ if(status) return status;
+ break;
+ }
+
+ (*index)--;
+ /* we should never get here */
+ return json_handle_error(string, index, "_json_parse_string() final switch clause");
+ }
+
+ if(status) return status;
+
+ json_eat_ws(string, index, 1, current_strlen);
+
+ if( *index < current_strlen ) {
+ /* remove any trailing comments */
+ c = string[*index];
+ if( c == '/' ) {
+ (*index)++;
+ status = json_eat_comment(string, index, NULL, 0, current_strlen);
+ if(status) return status;
+ }
+ }
+
+ if(classname){
+ jsonObjectSetClass(obj, classname);
+ free(classname);
+ }
+
+ return 0;
+}
+
+
+int json_parse_json_null(char* string, unsigned long* index, jsonObject* obj, int current_strlen) {
+
+ if(*index >= (current_strlen - 3)) {
+ return json_handle_error(string, index,
+ "_parse_json_null(): invalid null" );
+ }
+
+ if(!strncasecmp(string + (*index), "null", 4)) {
+ (*index) += 4;
+ obj->type = JSON_NULL;
+ return 0;
+ } else {
+ return json_handle_error(string, index,
+ "_parse_json_null(): invalid null" );
+ }
+}
+
+/* should be at the first character of the bool at this point */
+int json_parse_json_bool(char* string, unsigned long* index, jsonObject* obj, int current_strlen) {
+ if( ! string || ! obj || *index >= current_strlen ) return -1;
+
+ char* ret = "json_parse_json_bool(): truncated bool";
+
+ if( *index >= (current_strlen - 5))
+ return json_handle_error(string, index, ret);
+
+ if(!strncasecmp( string + (*index), "false", 5)) {
+ (*index) += 5;
+ obj->value.b = 0;
+ obj->type = JSON_BOOL;
+ return 0;
+ }
+
+ if( *index >= (current_strlen - 4))
+ return json_handle_error(string, index, ret);
+
+ if(!strncasecmp( string + (*index), "true", 4)) {
+ (*index) += 4;
+ obj->value.b = 1;
+ obj->type = JSON_BOOL;
+ return 0;
+ }
+
+ return json_handle_error(string, index, ret);
+}
+
+
+/* expecting the first character of the number */
+int json_parse_json_number(char* string, unsigned long* index, jsonObject* obj, int current_strlen) {
+ if( ! string || ! obj || *index >= current_strlen ) return -1;
+
+ growing_buffer* buf = buffer_init(64);
+ char c = string[*index];
+
+ int done = 0;
+ int dot_seen = 0;
+
+ /* negative number? */
+ if(c == '-') { buffer_add(buf, "-"); (*index)++; }
+
+ c = string[*index];
+
+ while(*index < current_strlen) {
+
+ if(isdigit(c)) {
+ buffer_add_char(buf, c);
+ }
+
+ else if( c == '.' ) {
+ if(dot_seen) {
+ buffer_free(buf);
+ return json_handle_error(string, index,
+ "json_parse_json_number(): malformed json number");
+ }
+ dot_seen = 1;
+ buffer_add_char(buf, c);
+ } else {
+ done = 1; break;
+ }
+
+ (*index)++;
+ c = string[*index];
+ if(done) break;
+ }
+
+ obj->type = JSON_NUMBER;
+ obj->value.n = strtod(buf->buf, NULL);
+ buffer_free(buf);
+ return 0;
+}
+
+/* index should point to the character directly following the '['. when done
+ * index will point to the character directly following the ']' character
+ */
+int json_parse_json_array(char* string, unsigned long* index, jsonObject* obj, int current_strlen) {
+
+ if( ! string || ! obj || ! index || *index >= current_strlen ) return -1;
+
+ int status = 0;
+ int in_parse = 0; /* true if this array already contains one item */
+ obj->type = JSON_ARRAY;
+ int set = 0;
+ int done = 0;
+
+ while(*index < current_strlen) {
+
+ json_eat_ws(string, index, 1, current_strlen);
+
+ if(string[*index] == ']') {
+ (*index)++;
+ done = 1;
+ break;
+ }
+
+ if(in_parse) {
+ json_eat_ws(string, index, 1, current_strlen);
+ if(string[*index] != ',') {
+ return json_handle_error(string, index,
+ "json_parse_json_array(): array item not followed by a ','");
+ }
+ (*index)++;
+ json_eat_ws(string, index, 1, current_strlen);
+ }
+
+ jsonObject* item = jsonNewObject(NULL);
+
+ #ifndef STRICT_JSON_READ
+ if(*index < current_strlen) {
+ if(string[*index] == ',' || string[*index] == ']') {
+ status = 0;
+ set = 1;
+ }
+ }
+ if(!set) status = _json_parse_string(string, index, item, current_strlen);
+
+ #else
+ status = _json_parse_string(string, index, item, current_strlen);
+ #endif
+
+ if(status) { jsonObjectFree(item); return status; }
+ jsonObjectPush(obj, item);
+ in_parse = 1;
+ set = 0;
+ }
+
+ if(!done)
+ return json_handle_error(string, index,
+ "json_parse_json_array(): array not closed");
+
+ return 0;
+}
+
+
+/* index should point to the character directly following the '{'. when done
+ * index will point to the character directly following the '}'
+ */
+int json_parse_json_object(char* string, unsigned long* index, jsonObject* obj, int current_strlen) {
+ if( ! string || !obj || ! index || *index >= current_strlen ) return -1;
+
+ obj->type = JSON_HASH;
+ int status;
+ int in_parse = 0; /* true if we've already added one item to this object */
+ int set = 0;
+ int done = 0;
+
+ while(*index < current_strlen) {
+
+ json_eat_ws(string, index, 1, current_strlen);
+
+ if(string[*index] == '}') {
+ (*index)++;
+ done = 1;
+ break;
+ }
+
+ if(in_parse) {
+ if(string[*index] != ',') {
+ return json_handle_error(string, index,
+ "json_parse_json_object(): object missing ',' between elements" );
+ }
+ (*index)++;
+ json_eat_ws(string, index, 1, current_strlen);
+ }
+
+ /* first we grab the hash key */
+ jsonObject* key_obj = jsonNewObject(NULL);
+ status = _json_parse_string(string, index, key_obj, current_strlen);
+ if(status) return status;
+
+ if(key_obj->type != JSON_STRING) {
+ return json_handle_error(string, index,
+ "_json_parse_json_object(): hash key not a string");
+ }
+
+ char* key = key_obj->value.s;
+
+ json_eat_ws(string, index, 1, current_strlen);
+
+ if(string[*index] != ':') {
+ return json_handle_error(string, index,
+ "json_parse_json_object(): hash key not followed by ':' character");
+ }
+
+ (*index)++;
+
+ /* now grab the value object */
+ json_eat_ws(string, index, 1, current_strlen);
+ jsonObject* value_obj = jsonNewObject(NULL);
+
+#ifndef STRICT_JSON_READ
+ if(*index < current_strlen) {
+ if(string[*index] == ',' || string[*index] == '}') {
+ status = 0;
+ set = 1;
+ }
+ }
+ if(!set)
+ status = _json_parse_string(string, index, value_obj, current_strlen);
+
+#else
+ status = _json_parse_string(string, index, value_obj, current_strlen);
+#endif
+
+ if(status) return status;
+
+ /* put the data into the object and continue */
+ jsonObjectSetKey(obj, key, value_obj);
+ jsonObjectFree(key_obj);
+ in_parse = 1;
+ set = 0;
+ }
+
+ if(!done)
+ return json_handle_error(string, index,
+ "json_parse_json_object(): object not closed");
+
+ return 0;
+}
+
+
+
+/* when done, index will point to the character after the closing quote */
+int json_parse_json_string(char* string, unsigned long* index, jsonObject* obj, int current_strlen) {
+ if( ! string || ! index || *index >= current_strlen ) return -1;
+
+ int in_escape = 0;
+ int done = 0;
+ growing_buffer* buf = buffer_init(64);
+
+ while(*index < current_strlen) {
+
+ char c = string[*index];
+
+ switch(c) {
+
+ case '\\':
+ if(in_escape) {
+ buffer_add(buf, "\\");
+ in_escape = 0;
+ } else
+ in_escape = 1;
+ break;
+
+ case '"':
+ if(in_escape) {
+ buffer_add(buf, "\"");
+ in_escape = 0;
+ } else
+ done = 1;
+ break;
+
+ case 't':
+ if(in_escape) {
+ buffer_add(buf,"\t");
+ in_escape = 0;
+ } else
+ buffer_add_char(buf, c);
+ break;
+
+ case 'b':
+ if(in_escape) {
+ buffer_add(buf,"\b");
+ in_escape = 0;
+ } else
+ buffer_add_char(buf, c);
+ break;
+
+ case 'f':
+ if(in_escape) {
+ buffer_add(buf,"\f");
+ in_escape = 0;
+ } else
+ buffer_add_char(buf, c);
+ break;
+
+ case 'r':
+ if(in_escape) {
+ buffer_add(buf,"\r");
+ in_escape = 0;
+ } else
+ buffer_add_char(buf, c);
+ break;
+
+ case 'n':
+ if(in_escape) {
+ buffer_add(buf,"\n");
+ in_escape = 0;
+ } else
+ buffer_add_char(buf, c);
+ break;
+
+ case 'u':
+ if(in_escape) {
+ (*index)++;
+
+ if(*index >= (current_strlen - 4)) {
+ buffer_free(buf);
+ return json_handle_error(string, index,
+ "json_parse_json_string(): truncated escaped unicode"); }
+
+ char buff[5];
+ memset(buff,0,5);
+ memcpy(buff, string + (*index), 4);
+
+
+ /* ----------------------------------------------------------------------- */
+ /* ----------------------------------------------------------------------- */
+ /* The following chunk was borrowed with permission from
+ json-c http://oss.metaparadigm.com/json-c/ */
+ unsigned char utf_out[3];
+ memset(utf_out,0,3);
+
+ #define hexdigit(x) ( ((x) <= '9') ? (x) - '0' : ((x) & 7) + 9)
+
+ unsigned int ucs_char =
+ (hexdigit(string[*index] ) << 12) +
+ (hexdigit(string[*index + 1]) << 8) +
+ (hexdigit(string[*index + 2]) << 4) +
+ hexdigit(string[*index + 3]);
+
+ if (ucs_char < 0x80) {
+ utf_out[0] = ucs_char;
+ buffer_add(buf, (char*) utf_out);
+
+ } else if (ucs_char < 0x800) {
+ utf_out[0] = 0xc0 | (ucs_char >> 6);
+ utf_out[1] = 0x80 | (ucs_char & 0x3f);
+ buffer_add(buf, (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);
+ buffer_add(buf, (char*) utf_out);
+ }
+ /* ----------------------------------------------------------------------- */
+ /* ----------------------------------------------------------------------- */
+
+ (*index) += 3;
+ in_escape = 0;
+
+ } else {
+
+ buffer_add_char(buf, c);
+ }
+
+ break;
+
+ default:
+ buffer_add_char(buf, c);
+ }
+
+ (*index)++;
+ if(done) break;
+ }
+
+ jsonObjectSetString(obj, buf->buf);
+ buffer_free(buf);
+ return 0;
+}
+
+
+void json_eat_ws(char* string, unsigned long* index, int eat_all, int current_strlen) {
+ if( ! string || ! index ) return;
+ if(*index >= current_strlen)
+ return;
+
+ if( eat_all ) { /* removes newlines, etc */
+ while(string[*index] == ' ' ||
+ string[*index] == '\n' ||
+ string[*index] == '\t')
+ (*index)++;
+ }
+
+ else
+ while(string[*index] == ' ') (*index)++;
+}
+
+
+/* index should be at the '*' character at the beginning of the comment.
+ * when done, index will point to the first character after the final /
+ */
+int json_eat_comment(char* string, unsigned long* index, char** buffer, int parse_class, int current_strlen) {
+ if( ! string || ! index || *index >= current_strlen ) return -1;
+
+
+ if(string[*index] != '*' && string[*index] != '/' )
+ return json_handle_error(string, index,
+ "json_eat_comment(): invalid character after /");
+
+ /* chop out any // style comments */
+ if(string[*index] == '/') {
+ (*index)++;
+ char c = string[*index];
+ while(*index < current_strlen) {
+ (*index)++;
+ if(c == '\n')
+ return 0;
+ c = string[*index];
+ }
+ return 0;
+ }
+
+ (*index)++;
+
+ int on_star = 0; /* true if we just saw a '*' character */
+
+ /* we're just past the '*' */
+ if(!parse_class) { /* we're not concerned with class hints */
+ while(*index < current_strlen) {
+ if(string[*index] == '/') {
+ if(on_star) {
+ (*index)++;
+ return 0;
+ }
+ }
+
+ if(string[*index] == '*') on_star = 1;
+ else on_star = 0;
+
+ (*index)++;
+ }
+ return 0;
+ }
+
+
+
+ growing_buffer* buf = buffer_init(64);
+
+ int first_dash = 0;
+ int second_dash = 0;
+ int third_dash = 0;
+ int fourth_dash = 0;
+
+ int in_hint = 0;
+ int done = 0;
+
+ /*--S hint--*/ /* <-- Hints look like this */
+ /*--E hint--*/
+
+ while(*index < current_strlen) {
+ char c = string[*index];
+
+ switch(c) {
+
+ case '-':
+ on_star = 0;
+ if(third_dash) fourth_dash = 1;
+ else if(in_hint) third_dash = 1;
+ else if(first_dash) second_dash = 1;
+ else first_dash = 1;
+ break;
+
+ case 'S':
+ on_star = 0;
+ if(second_dash && !in_hint) {
+ (*index)++;
+ json_eat_ws(string, index, 1, current_strlen);
+ (*index)--; /* this will get incremented at the bottom of the loop */
+ in_hint = 1;
+ break;
+ }
+
+ if(second_dash && in_hint) {
+ buffer_add_char(buf, c);
+ break;
+ }
+
+ case 'E':
+ on_star = 0;
+ if(second_dash && !in_hint) {
+ (*index)++;
+ json_eat_ws(string, index, 1, current_strlen);
+ (*index)--; /* this will get incremented at the bottom of the loop */
+ in_hint = 1;
+ break;
+ }
+
+ if(second_dash && in_hint) {
+ buffer_add_char(buf, c);
+ break;
+ }
+
+ case '*':
+ on_star = 1;
+ break;
+
+ case '/':
+ if(on_star)
+ done = 1;
+ else
+ on_star = 0;
+ break;
+
+ default:
+ on_star = 0;
+ if(in_hint)
+ buffer_add_char(buf, c);
+ }
+
+ (*index)++;
+ if(done) break;
+ }
+
+ if( buf->n_used > 0 && buffer)
+ *buffer = buffer_data(buf);
+
+ buffer_free(buf);
+ return 0;
+}
+
+int json_handle_error(char* string, unsigned long* index, char* err_msg) {
+
+ char buf[60];
+ memset(buf, 0, 60);
+
+ if(*index > 30)
+ strncpy( buf, string + (*index - 30), 59 );
+ else
+ strncpy( buf, string, 59 );
+
+ fprintf(stderr,
+ "\nError parsing json string at charracter %c "
+ "(code %d) and index %ld\nString length: %d\nMsg:\t%s\nNear:\t%s\nFull String:\t%s\n",
+ string[*index], string[*index], *index, current_strlen, err_msg, buf, string );
+
+ return -1;
+}
+
+
+jsonObject* legacy_jsonParseFile( const char* filename ) {
+ return json_parse_file( filename );
+}
+
+jsonObject* json_parse_file(const char* filename) {
+ if(!filename) return NULL;
+ char* data = file_to_string(filename);
+ jsonObject* o = json_parse_string(data);
+ free(data);
+ return o;
+}
+
+
+
+char* legacy_jsonObjectToJSON( const jsonObject* obj ) {
+
+ if(obj == NULL) return strdup("null");
+
+ growing_buffer* buf = buffer_init(64);
+
+ /* add class hints if we have a class name */
+ if(obj->classname) {
+ buffer_add(buf,"/*--S ");
+ buffer_add(buf,obj->classname);
+ buffer_add(buf, "--*/");
+ }
+
+ switch( obj->type ) {
+
+ case JSON_BOOL:
+ if(obj->value.b) buffer_add(buf, "true");
+ else buffer_add(buf, "false");
+ break;
+
+ case JSON_NUMBER: {
+ double x = obj->value.n;
+
+ /* if the number does not need to be a double,
+ turn it into an int on the way out */
+ if( x == (int) x ) {
+ INT_TO_STRING((int)x);
+ buffer_add(buf, INTSTR);
+
+ } else {
+ DOUBLE_TO_STRING(x);
+ buffer_add(buf, DOUBLESTR);
+ }
+ break;
+ }
+
+ case JSON_NULL:
+ buffer_add(buf, "null");
+ break;
+
+ case JSON_STRING:
+ buffer_add(buf, "\"");
+ char* data = obj->value.s;
+ int len = strlen(data);
+
+ char* output = uescape(data, len, 1);
+ buffer_add(buf, output);
+ free(output);
+ buffer_add(buf, "\"");
+ break;
+
+ case JSON_ARRAY:
+ buffer_add(buf, "[");
+ int i;
+ for( i = 0; i!= obj->size; i++ ) {
+ const jsonObject* x = jsonObjectGetIndex(obj,i);
+ char* data = legacy_jsonObjectToJSON(x);
+ buffer_add(buf, data);
+ free(data);
+ if(i != obj->size - 1)
+ buffer_add(buf, ",");
+ }
+ buffer_add(buf, "]");
+ break;
+
+ case JSON_HASH:
+
+ buffer_add(buf, "{");
+ jsonIterator* itr = jsonNewIterator(obj);
+ jsonObject* tmp;
+
+ while( (tmp = jsonIteratorNext(itr)) ) {
+
+ buffer_add(buf, "\"");
+
+ char* key = itr->key;
+ int len = strlen(key);
+ char* output = uescape(key, len, 1);
+ buffer_add(buf, output);
+ free(output);
+
+ buffer_add(buf, "\":");
+ char* data = legacy_jsonObjectToJSON(tmp);
+ buffer_add(buf, data);
+ if(jsonIteratorHasNext(itr))
+ buffer_add(buf, ",");
+ free(data);
+ }
+
+ jsonIteratorFree(itr);
+ buffer_add(buf, "}");
+ break;
+
+ default:
+ fprintf(stderr, "Unknown object type %d\n", obj->type);
+ break;
+
+ }
+
+ /* close out the object hint */
+ if(obj->classname) {
+ buffer_add(buf, "/*--E ");
+ buffer_add(buf, obj->classname);
+ buffer_add(buf, "--*/");
+ }
+
+ char* data = buffer_data(buf);
+ buffer_free(buf);
+ return data;
+}
+
+
+
+static jsonObjectNode* makeNode(jsonObject* obj, unsigned long index, char* key) {
+ jsonObjectNode* node = safe_malloc(sizeof(jsonObjectNode));
+ node->item = obj;
+ node->index = index;
+ node->key = key;
+ return node;
+}
+
+jsonObjectIterator* jsonNewObjectIterator(const jsonObject* obj) {
+ if(!obj) return NULL;
+ jsonObjectIterator* itr = safe_malloc(sizeof(jsonObjectIterator));
+ itr->iterator = jsonNewIterator(obj);
+ itr->obj = obj;
+ itr->done = 0;
+ itr->current = NULL;
+ return itr;
+}
+
+jsonObjectNode* jsonObjectIteratorNext( jsonObjectIterator* itr ) {
+ if(itr == NULL || itr->done) return NULL;
+
+ if(itr->current) free(itr->current);
+ jsonObject* next = jsonIteratorNext(itr->iterator);
+ if(next == NULL) {
+ itr->current = NULL;
+ itr->done = 1;
+ return NULL;
+ }
+ itr->current = makeNode(next, itr->iterator->index, itr->iterator->key);
+ return itr->current;
+}
+
+void jsonObjectIteratorFree(jsonObjectIterator* iter) {
+ if(iter->current) free(iter->current);
+ jsonIteratorFree(iter->iterator);
+ free(iter);
+}
+
+int jsonObjectIteratorHasNext(const jsonObjectIterator* itr) {
+ return (itr && itr->current);
+}
+
+
if(size > STRING_ARRAY_MAX_SIZE)
osrfLogError( OSRF_LOG_MARK, "init_string_array size is too large");
- /*
- string_array* arr =
- (string_array*) safe_malloc(sizeof(string_array));
- */
string_array* arr;
OSRF_MALLOC( arr, sizeof(string_array));
-
- //arr->array = (char**) safe_malloc(size * sizeof(char*));
- OSRF_MALLOC(arr->array, size * sizeof(char*));
-
+ arr->list = osrfNewListSize(size);
+ osrfListSetDefaultFree(arr->list);
arr->size = 0;
- arr->arr_size = size;
return arr;
}
void string_array_add(string_array* arr, char* str) {
if(arr == NULL || str == NULL ) return;
- if( strlen(str) < 1 ) return;
-
- arr->size++;
-
if( arr->size > STRING_ARRAY_MAX_SIZE )
osrfLogError( OSRF_LOG_MARK, "string_array_add size is too large");
-
- /* if necessary, double capacity */
- if(arr->size >= arr->arr_size) {
- arr->arr_size *= 2;
- //char** tmp = (char**) safe_malloc(arr->arr_size * sizeof(char*));
- char** tmp;
- OSRF_MALLOC( tmp, arr->arr_size * sizeof(char*));
- int i;
-
- /* copy the string pointers over */
- for( i = 0; i!= arr->size; i++ )
- tmp[i] = arr->array[i];
-
- free(arr->array);
- arr->array = tmp;
- }
-
- arr->array[arr->size - 1] = strdup(str);
+ osrfListPush(arr->list, strdup(str));
+ arr->size = arr->list->size;
}
char* osrfStringArrayGetString(osrfStringArray* arr, int index) {
- return string_array_get_string(arr, index);
+ if(!arr) return NULL;
+ return OSRF_LIST_GET_INDEX(arr->list, index);
}
char* string_array_get_string(string_array* arr, int index) {
- if(!arr || index < 0 || index >= arr->size ) return NULL;
- return arr->array[index];
+ if(!arr) return NULL;
+ return OSRF_LIST_GET_INDEX(arr->list, index);
}
void osrfStringArrayFree(osrfStringArray* arr) {
- string_array_destroy(arr);
+ OSRF_STRING_ARRAY_FREE(arr);
}
void string_array_destroy(string_array* arr) {
- if(arr) {
- int i = 0;
- while( i < arr->size ) free(arr->array[i++]);
- free(arr->array);
- free(arr);
- }
+ OSRF_STRING_ARRAY_FREE(arr);
}
int osrfStringArrayContains( osrfStringArray* arr, char* string ) {
if(!(arr && string)) return 0;
-
int i;
- for( i = 0; i != arr->size; i++ ) {
- char* str = osrfStringArrayGetString(arr, i);
- if(str) {
- if(!strcmp(str, string)) return 1;
- }
+ for( i = 0; i < arr->size; i++ ) {
+ char* str = OSRF_LIST_GET_INDEX(arr->list, i);
+ if(str && !strcmp(str, string))
+ return 1;
}
return 0;
void osrfStringArrayRemove( osrfStringArray* arr, char* tstr) {
if(!(arr && tstr)) return;
int i;
- for( i = 0; i != arr->size; i++ ) {
- char* str = osrfStringArrayGetString(arr, i);
- if(str) {
- if(!strcmp(str, tstr)) {
- free(arr->array[i]);
- arr->array[i] = NULL;
- break;
- }
+ char* str;
+
+ for( i = 0; i < arr->size; i++ ) {
+ /* find and remove the string */
+ str = OSRF_LIST_GET_INDEX(arr->list, i);
+ if(str && !strcmp(str, tstr)) {
+ osrfListRemove(arr->list, i);
+ break;
}
}
- for( ; i != arr->size; i++ )
- arr->array[i] = arr->array[i+1];
+ /* disable automatic item freeing on delete and shift
+ * items up in the array to fill in the gap
+ */
+ arr->list->freeItem = NULL;
+ for( ; i < arr->size - 1; i++ )
+ osrfListSet(arr->list, OSRF_LIST_GET_INDEX(arr->list, i+1) , i);
+
+ /* remove the last item since it was shifted up */
+ osrfListRemove(arr->list, i);
+
+ /* re-enable automatic item freeing in delete */
+ osrfListSetDefaultFree(arr->list);
arr->size--;
}
return $hint;
}
+
+my $JSON_CLASS_KEY = '__c';
+my $JSON_PAYLOAD_KEY = '__p';
+
sub JSON2perl {
+ my( $class, $string ) = @_;
+ my $perl = $class->rawJSON2perl($string);
+ return $class->JSONObject2Perl($perl);
+}
+
+sub perl2JSON {
+ my( $class, $obj ) = @_;
+ my $json = $class->perl2JSONObject($obj);
+ return $class->rawPerl2JSON($json);
+}
+
+sub JSONObject2Perl {
+ my $class = shift;
+ my $obj = shift;
+ my $ref = ref($obj);
+ if( $ref eq 'HASH' ) {
+ if( defined($obj->{$JSON_CLASS_KEY})) {
+ my $cls = $obj->{$JSON_CLASS_KEY};
+ $cls =~ s/^\s+//o;
+ $cls =~ s/\s+$//o;
+ if( $obj = $class->JSONObject2Perl($obj->{$JSON_PAYLOAD_KEY}) ) {
+ $cls = $class->lookup_class($cls) || $cls;
+ return bless(\$obj, $cls) unless ref($obj);
+ return bless($obj, $cls);
+ }
+ return undef;
+ }
+ $obj->{$_} = $class->JSONObject2Perl($obj->{$_}) for (keys %$obj);
+ } elsif( $ref eq 'ARRAY' ) {
+ $obj->[$_] = $class->JSONObject2Perl($obj->[$_]) for(0..scalar(@$obj) - 1);
+ }
+ return $obj;
+}
+
+sub perl2JSONObject {
+ my $class = shift;
+ my $obj = shift;
+ my $ref = ref($obj);
+
+ return $obj unless $ref;
+ my $newobj;
+
+ if( $ref eq 'HASH' ) {
+ $newobj = {};
+ $newobj->{$_} = $class->perl2JSONObject( $obj->{$_} ) for (keys %$obj);
+ } elsif( $ref eq 'ARRAY' ) {
+ $newobj = [];
+ $newobj->[$_] = $class->perl2JSONObject( $obj->[$_] ) for(0..scalar(@$obj) - 1 );
+ } elsif( $ref ) {
+ if(UNIVERSAL::isa($obj, 'HASH')) {
+ $newobj = {};
+ $newobj->{$_} = $class->perl2JSONObject( $obj->{$_} ) for (keys %$obj);
+ bless( $newobj, ref($obj) );
+ #bless($obj, 'HASH'); # so our parser won't add the hints
+ } elsif(UNIVERSAL::isa($obj, 'ARRAY')) {
+ $newobj = [];
+ $newobj->[$_] = $class->perl2JSONObject( $obj->[$_] ) for(0..scalar(@$obj) - 1);
+ bless( $newobj, ref($obj) );
+ #bless($obj, 'ARRAY'); # so our parser won't add the hints
+ }
+ $ref = $class->lookup_hint($ref) || $ref;
+ $newobj = { $JSON_CLASS_KEY => $ref, $JSON_PAYLOAD_KEY => $newobj };
+ }
+ return $newobj;
+}
+
+
+sub rawJSON2perl {
my $class = shift;
local $_ = shift;
s/\\u([0-9a-fA-F]{4})/chr(hex($1))/esog;
# handle class blessings
- s/\/\*--\s*S\w*?\s+\S+\s*--\*\// bless(/sog;
- s/(\]|\}|")\s*\/\*--\s*E\w*?\s+(\S+)\s*--\*\//$1 => _json_hint_to_class("$1", "$2")) /sog;
+# s/\/\*--\s*S\w*?\s+\S+\s*--\*\// bless(/sog;
+# s/(\]|\}|")\s*\/\*--\s*E\w*?\s+(\S+)\s*--\*\//$1 => _json_hint_to_class("$1", "$2")) /sog;
my $re = qr/((?<!\\)"(?>(?<=\\)"|[^"])*(?<!\\)")/;
# Grab strings...
s/:/ => /sog;
# Do numbers...
- #s/\b(-?\d+\.?\d*)\b/ OpenSRF::Utils::JSON::number::new($1) /sog;
+ #s/\b(-?\d+\.?\d*)\b/ JSON::number::new($1) /sog;
# Change javascript stuff to perl...
s/null/ undef /sog;
- s/true/ bless( {}, "OpenSRF::Utils::JSON::bool::true") /sog;
- s/false/ bless( {}, "OpenSRF::Utils::JSON::bool::false") /sog;
+ s/true/ bless( {}, "JSON::bool::true") /sog;
+ s/false/ bless( {}, "JSON::bool::false") /sog;
my $ret;
return eval '$ret = '.$_;
}
+
my $_json_index;
sub ___JSON2perl {
my $class = shift;
} elsif ($element =~ /^\/\*/) {
next;
} elsif ($element =~ /^\d/) {
- $output .= "do { OpenSRF::Utils::JSON::number::new($element) }";
+ $output .= "do { JSON::number::new($element) }";
next;
} elsif ($element eq '{' or $element eq '[') {
$casting_depth++;
$output .= ' => ';
next;
} elsif ($element eq 'true') {
- $output .= 'bless( {}, "OpenSRF::Utils::JSON::bool::true")';
+ $output .= 'bless( {}, "JSON::bool::true")';
next;
} elsif ($element eq 'false') {
- $output .= 'bless( {}, "OpenSRF::Utils::JSON::bool::false")';
+ $output .= 'bless( {}, "JSON::bool::false")';
next;
}
return eval $output;
}
-sub perl2JSON {
+
+sub rawPerl2JSON {
my ($class, $perl, $strict) = @_;
my $output = '';
if (!defined($perl)) {
$output = '' if $strict;
$output = 'null' unless $strict;
- } elsif (ref($perl) and ref($perl) =~ /^OpenSRF::Utils::JSON/) {
+ } elsif (ref($perl) and ref($perl) =~ /^JSON/) {
$output .= $perl;
- } elsif ( ref($perl) && exists($_class_map{classes}{ref($perl)}) ) {
- $output .= '/*--S '.$_class_map{classes}{ref($perl)}{hint}.'--*/';
- if (lc($_class_map{classes}{ref($perl)}{type}) eq 'hash') {
- my %hash = %$perl;
- $output .= perl2JSON(undef,\%hash, $strict);
- } elsif (lc($_class_map{classes}{ref($perl)}{type}) eq 'array') {
- my @array = @$perl;
- $output .= perl2JSON(undef,\@array, $strict);
- }
- $output .= '/*--E '.$_class_map{classes}{ref($perl)}{hint}.'--*/';
- } elsif (ref($perl) and ref($perl) =~ /HASH/) {
+# } elsif ( ref($perl) && exists($_class_map{classes}{ref($perl)}) ) {
+# $output .= '/*--S '.$_class_map{classes}{ref($perl)}{hint}.'--*/';
+# if (lc($_class_map{classes}{ref($perl)}{type}) eq 'hash') {
+# my %hash = %$perl;
+# $output .= rawPerl2JSON(undef,\%hash, $strict);
+# } elsif (lc($_class_map{classes}{ref($perl)}{type}) eq 'array') {
+# my @array = @$perl;
+# $output .= rawPerl2JSON(undef,\@array, $strict);
+# }
+# $output .= '/*--E '.$_class_map{classes}{ref($perl)}{hint}.'--*/';
+# } elsif (ref($perl) and ref($perl) =~ /HASH/) {
+ } elsif (UNIVERSAL::isa($perl, 'HASH')) {
$output .= '{';
my $c = 0;
for my $key (sort keys %$perl) {
$outkey =~ s/\n/\\n/sgo;
$outkey =~ s/([\x{0080}-\x{fffd}])/sprintf('\u%0.4x',ord($1))/sgoe;
- $output .= '"'.$outkey.'":'. perl2JSON(undef,$$perl{$key}, $strict);
+ $output .= '"'.$outkey.'":'. rawPerl2JSON(undef,$$perl{$key}, $strict);
$c++;
}
$output .= '}';
- } elsif (ref($perl) and ref($perl) =~ /ARRAY/) {
+# } elsif (ref($perl) and ref($perl) =~ /ARRAY/) {
+ } elsif (UNIVERSAL::isa($perl, 'ARRAY')) {
$output .= '[';
my $c = 0;
for my $part (@$perl) {
$output .= ',' if ($c);
- $output .= perl2JSON(undef,$part, $strict);
+ $output .= rawPerl2JSON(undef,$part, $strict);
$c++;
}
$output .= ']';
} elsif (ref($perl) and ref($perl) =~ /CODE/) {
- $output .= perl2JSON(undef,$perl->(), $strict);
+ $output .= rawPerl2JSON(undef,$perl->(), $strict);
} elsif (ref($perl) and ("$perl" =~ /^([^=]+)=(\w+)/o)) {
my $type = $2;
my $name = $1;
OpenSRF::Utils::JSON->register_class_hint(name => $name, hint => $name, type => lc($type));
- $output .= perl2JSON(undef,$perl, $strict);
+ $output .= rawPerl2JSON(undef,$perl, $strict);
} else {
$perl = NFC($perl);
$perl =~ s{\\}{\\\\}sgo;
if (!defined($perl)) {
$output = " "x$depth unless($nospace);
$output .= 'null';
- } elsif (ref($perl) and ref($perl) =~ /^OpenSRF::Utils::JSON/) {
+ } elsif (ref($perl) and ref($perl) =~ /^JSON/) {
$output = " "x$depth unless($nospace);
$output .= $perl;
} elsif ( ref($perl) && exists($_class_map{classes}{ref($perl)}) ) {
#MALLOC_CHECK_=1 # XXX debug only
-LDLIBS += -lxml2 -lopensrf -lobjson
+LDLIBS += -lxml2 -lopensrf
CFLAGS += -D_ROUTER
all: opensrf_router
# if EXEC_DEFAULT is defined, then srfsh will send all unknown commands to the shell for execution
-LDLIBS += -lobjson -lreadline -lxml2 -lopensrf -lncurses
+LDLIBS += -lreadline -lxml2 -lopensrf -lncurses
LDFLAGS += -DEXEC_DEFAULT
all: srfsh
jsonObject* params = NULL;
if( !relay ) {
if( buffer != NULL && buffer->n_used > 0 )
- params = json_parse_string(buffer->buf);
+ params = jsonParseString(buffer->buf);
} else {
if(!last_result || ! last_result->_result_content) {
printf("We're not going to call 'relay' with no result params\n");
osrf_app_session* session = osrf_app_client_session_init( "opensrf.math" );
osrf_app_session_connect(session);
- jsonObject* params = json_parse_string("[]");
+ jsonObject* params = jsonParseString("[]");
jsonObjectPush(params,jsonNewObject("1"));
jsonObjectPush(params,jsonNewObject("2"));