[Opensrf-commits] SPAM: r1007 - in branches/new-json2: . include/objson include/opensrf src src/c-apps src/gateway src/jserver src/libopensrf src/perlmods/OpenSRF/Utils src/router src/srfsh

svn at svn.open-ils.org svn at svn.open-ils.org
Fri Jul 6 16:40:42 EDT 2007


Author: erickson
Date: 2007-07-06 16:36:37 -0400 (Fri, 06 Jul 2007)
New Revision: 1007

Added:
   branches/new-json2/include/opensrf/osrf_json.h
   branches/new-json2/include/opensrf/osrf_json_utils.h
   branches/new-json2/include/opensrf/osrf_json_xml.h
   branches/new-json2/include/opensrf/osrf_legacy_json.h
   branches/new-json2/src/libopensrf/Makefile.json
   branches/new-json2/src/libopensrf/osrf_json_object.c
   branches/new-json2/src/libopensrf/osrf_json_parser.c
   branches/new-json2/src/libopensrf/osrf_json_tools.c
   branches/new-json2/src/libopensrf/osrf_json_xml.c
   branches/new-json2/src/libopensrf/osrf_legacy_json.c
Modified:
   branches/new-json2/include/objson/json2xml.h
   branches/new-json2/include/objson/json_parser.h
   branches/new-json2/include/objson/object.h
   branches/new-json2/include/objson/xml2json.h
   branches/new-json2/include/opensrf/osrfConfig.h
   branches/new-json2/include/opensrf/osrf_app_session.h
   branches/new-json2/include/opensrf/osrf_application.h
   branches/new-json2/include/opensrf/osrf_cache.h
   branches/new-json2/include/opensrf/osrf_message.h
   branches/new-json2/include/opensrf/osrf_settings.h
   branches/new-json2/include/opensrf/xml_utils.h
   branches/new-json2/install.conf
   branches/new-json2/src/Makefile
   branches/new-json2/src/c-apps/Makefile
   branches/new-json2/src/c-apps/osrf_dbmath.c
   branches/new-json2/src/c-apps/osrf_math.c
   branches/new-json2/src/c-apps/osrf_version.c
   branches/new-json2/src/gateway/Makefile
   branches/new-json2/src/gateway/osrf_json_gateway.c
   branches/new-json2/src/jserver/Makefile
   branches/new-json2/src/libopensrf/Makefile
   branches/new-json2/src/libopensrf/osrf_application.c
   branches/new-json2/src/perlmods/OpenSRF/Utils/JSON.pm
   branches/new-json2/src/router/Makefile
   branches/new-json2/src/srfsh/Makefile
   branches/new-json2/src/srfsh/srfsh.c
Log:

adding new-json protocol code
added in new build config var OSRF_LEGACY_JSON, which, when set, tells the compiler to build the JSON code as a standlone .so called libobjson.so for legacy support
this flag also copies the objson headers into place.  the objson headers are how just dummy wrappers around the osrf_json headers. 
added jsonObjectIterator/jsonObjectNode legacy code





Modified: branches/new-json2/include/objson/json2xml.h
===================================================================
--- branches/new-json2/include/objson/json2xml.h	2007-07-06 16:56:32 UTC (rev 1006)
+++ branches/new-json2/include/objson/json2xml.h	2007-07-06 20:36:37 UTC (rev 1007)
@@ -1,11 +1,10 @@
+/*
+ * 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
 
-#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*);
-

Modified: branches/new-json2/include/objson/json_parser.h
===================================================================
--- branches/new-json2/include/objson/json_parser.h	2007-07-06 16:56:32 UTC (rev 1006)
+++ branches/new-json2/include/objson/json_parser.h	2007-07-06 20:36:37 UTC (rev 1007)
@@ -1,84 +1,9 @@
 /*
-Copyright (C) 2005  Georgia Public Library Service 
-Bill Erickson <highfalutin at 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

Modified: branches/new-json2/include/objson/object.h
===================================================================
--- branches/new-json2/include/objson/object.h	2007-07-06 16:56:32 UTC (rev 1006)
+++ branches/new-json2/include/objson/object.h	2007-07-06 20:36:37 UTC (rev 1007)
@@ -1,286 +1,8 @@
 /*
-Copyright (C) 2005  Georgia Public Library Service 
-Bill Erickson <highfalutin at 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
-
-

Modified: branches/new-json2/include/objson/xml2json.h
===================================================================
--- branches/new-json2/include/objson/xml2json.h	2007-07-06 16:56:32 UTC (rev 1006)
+++ branches/new-json2/include/objson/xml2json.h	2007-07-06 20:36:37 UTC (rev 1007)
@@ -1,19 +1,11 @@
+/*
+ * 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 <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);
-
-
-

Modified: branches/new-json2/include/opensrf/osrfConfig.h
===================================================================
--- branches/new-json2/include/opensrf/osrfConfig.h	2007-07-06 16:56:32 UTC (rev 1006)
+++ branches/new-json2/include/opensrf/osrfConfig.h	2007-07-06 20:36:37 UTC (rev 1007)
@@ -19,7 +19,7 @@
 #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;

Modified: branches/new-json2/include/opensrf/osrf_app_session.h
===================================================================
--- branches/new-json2/include/opensrf/osrf_app_session.h	2007-07-06 16:56:32 UTC (rev 1006)
+++ branches/new-json2/include/opensrf/osrf_app_session.h	2007-07-06 20:36:37 UTC (rev 1007)
@@ -9,8 +9,7 @@
 #include <opensrf/osrf_hash.h>
 #include <opensrf/osrf_list.h>
 
-#include <objson/object.h>
-#include <objson/json_parser.h>
+#include <opensrf/osrf_json.h>
 
 
 

Modified: branches/new-json2/include/opensrf/osrf_application.h
===================================================================
--- branches/new-json2/include/opensrf/osrf_application.h	2007-07-06 16:56:32 UTC (rev 1006)
+++ branches/new-json2/include/opensrf/osrf_application.h	2007-07-06 20:36:37 UTC (rev 1007)
@@ -3,7 +3,7 @@
 #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>
 

Modified: branches/new-json2/include/opensrf/osrf_cache.h
===================================================================
--- branches/new-json2/include/opensrf/osrf_cache.h	2007-07-06 16:56:32 UTC (rev 1006)
+++ branches/new-json2/include/opensrf/osrf_cache.h	2007-07-06 20:36:37 UTC (rev 1007)
@@ -14,8 +14,7 @@
 */
 
 
-#include <objson/object.h>
-#include <objson/json_parser.h>
+#include <opensrf/osrf_json.h>
 #include <memcache.h>
 #include <opensrf/log.h>
 

Added: branches/new-json2/include/opensrf/osrf_json.h
===================================================================
--- branches/new-json2/include/opensrf/osrf_json.h	                        (rev 0)
+++ branches/new-json2/include/opensrf/osrf_json.h	2007-07-06 20:36:37 UTC (rev 1007)
@@ -0,0 +1,372 @@
+/*
+Copyright (C) 2006  Georgia Public Library Service 
+Bill Erickson <billserickson at 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, long 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 */
+		long 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( long double num );
+
+/**
+ * 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*);
+
+long 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 );
+
+int jsonBoolIsTrue( jsonObject* boolObj );
+
+
+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

Added: branches/new-json2/include/opensrf/osrf_json_utils.h
===================================================================
--- branches/new-json2/include/opensrf/osrf_json_utils.h	                        (rev 0)
+++ branches/new-json2/include/opensrf/osrf_json_utils.h	2007-07-06 20:36:37 UTC (rev 1007)
@@ -0,0 +1,131 @@
+/*
+Copyright (C) 2006  Georgia Public Library Service 
+Bill Erickson <billserickson at 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*, long 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 );
+
+

Added: branches/new-json2/include/opensrf/osrf_json_xml.h
===================================================================
--- branches/new-json2/include/opensrf/osrf_json_xml.h	                        (rev 0)
+++ branches/new-json2/include/opensrf/osrf_json_xml.h	2007-07-06 20:36:37 UTC (rev 1007)
@@ -0,0 +1,23 @@
+#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);
+

Added: branches/new-json2/include/opensrf/osrf_legacy_json.h
===================================================================
--- branches/new-json2/include/opensrf/osrf_legacy_json.h	                        (rev 0)
+++ branches/new-json2/include/opensrf/osrf_legacy_json.h	2007-07-06 20:36:37 UTC (rev 1007)
@@ -0,0 +1,137 @@
+/*
+Copyright (C) 2005  Georgia Public Library Service 
+Bill Erickson <highfalutin at 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>
+
+
+
+/* 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);
+
+/* returns true if c is 0-9 */
+int is_number(char c);
+
+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
+
+

Modified: branches/new-json2/include/opensrf/osrf_message.h
===================================================================
--- branches/new-json2/include/opensrf/osrf_message.h	2007-07-06 16:56:32 UTC (rev 1006)
+++ branches/new-json2/include/opensrf/osrf_message.h	2007-07-06 20:36:37 UTC (rev 1007)
@@ -1,8 +1,7 @@
 #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 */

Modified: branches/new-json2/include/opensrf/osrf_settings.h
===================================================================
--- branches/new-json2/include/opensrf/osrf_settings.h	2007-07-06 16:56:32 UTC (rev 1006)
+++ branches/new-json2/include/opensrf/osrf_settings.h	2007-07-06 20:36:37 UTC (rev 1007)
@@ -12,8 +12,7 @@
 #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; 

Modified: branches/new-json2/include/opensrf/xml_utils.h
===================================================================
--- branches/new-json2/include/opensrf/xml_utils.h	2007-07-06 16:56:32 UTC (rev 1006)
+++ branches/new-json2/include/opensrf/xml_utils.h	2007-07-06 20:36:37 UTC (rev 1007)
@@ -1,7 +1,7 @@
 #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>
 

Modified: branches/new-json2/install.conf
===================================================================
--- branches/new-json2/install.conf	2007-07-06 16:56:32 UTC (rev 1006)
+++ branches/new-json2/install.conf	2007-07-06 20:36:37 UTC (rev 1007)
@@ -12,3 +12,4 @@
 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

Modified: branches/new-json2/src/Makefile
===================================================================
--- branches/new-json2/src/Makefile	2007-07-06 16:56:32 UTC (rev 1006)
+++ branches/new-json2/src/Makefile	2007-07-06 20:36:37 UTC (rev 1007)
@@ -1,18 +1,21 @@
 # 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 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 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 \
@@ -26,8 +29,7 @@
 		router-install \
 		srfsh-install \
 		jserver-install \
-		perl-install \
-		objson-install
+		perl-install 
 
 
 # --------------------------------------------------------------------------------
@@ -37,11 +39,7 @@
 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
 
@@ -75,12 +73,8 @@
 	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)
@@ -90,6 +84,10 @@
 	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 $@
@@ -120,7 +118,6 @@
 	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

Modified: branches/new-json2/src/c-apps/Makefile
===================================================================
--- branches/new-json2/src/c-apps/Makefile	2007-07-06 16:56:32 UTC (rev 1006)
+++ branches/new-json2/src/c-apps/Makefile	2007-07-06 20:36:37 UTC (rev 1007)
@@ -1,4 +1,4 @@
-LDLIBS += -lobjson -lopensrf
+LDLIBS += -lopensrf
 CFLAGS += -DOSRF_LOG_PARAMS
 
 all:	osrf_math.so osrf_dbmath.so osrf_version.so

Modified: branches/new-json2/src/c-apps/osrf_dbmath.c
===================================================================
--- branches/new-json2/src/c-apps/osrf_dbmath.c	2007-07-06 16:56:32 UTC (rev 1006)
+++ branches/new-json2/src/c-apps/osrf_dbmath.c	2007-07-06 20:36:37 UTC (rev 1007)
@@ -1,7 +1,7 @@
-#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"
 

Modified: branches/new-json2/src/c-apps/osrf_math.c
===================================================================
--- branches/new-json2/src/c-apps/osrf_math.c	2007-07-06 16:56:32 UTC (rev 1006)
+++ branches/new-json2/src/c-apps/osrf_math.c	2007-07-06 20:36:37 UTC (rev 1007)
@@ -1,7 +1,7 @@
-#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"
 

Modified: branches/new-json2/src/c-apps/osrf_version.c
===================================================================
--- branches/new-json2/src/c-apps/osrf_version.c	2007-07-06 16:56:32 UTC (rev 1006)
+++ branches/new-json2/src/c-apps/osrf_version.c	2007-07-06 20:36:37 UTC (rev 1007)
@@ -1,6 +1,6 @@
 #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"
 

Modified: branches/new-json2/src/gateway/Makefile
===================================================================
--- branches/new-json2/src/gateway/Makefile	2007-07-06 16:56:32 UTC (rev 1006)
+++ branches/new-json2/src/gateway/Makefile	2007-07-06 20:36:37 UTC (rev 1007)
@@ -1,6 +1,6 @@
 #CFLAGS	+= -DASSUME_STATELESS -DOSRF_GATEWAY_NASTY_DEBUG
 CFLAGS	+= -DASSUME_STATELESS 
-LDLIBS	+= -lobjson -lopensrf
+LDLIBS	+= -lopensrf
 
 all: osrf_json_gateway.so copy
 

Modified: branches/new-json2/src/gateway/osrf_json_gateway.c
===================================================================
--- branches/new-json2/src/gateway/osrf_json_gateway.c	2007-07-06 16:56:32 UTC (rev 1006)
+++ branches/new-json2/src/gateway/osrf_json_gateway.c	2007-07-06 20:36:37 UTC (rev 1007)
@@ -2,9 +2,9 @@
 #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>

Modified: branches/new-json2/src/jserver/Makefile
===================================================================
--- branches/new-json2/src/jserver/Makefile	2007-07-06 16:56:32 UTC (rev 1006)
+++ branches/new-json2/src/jserver/Makefile	2007-07-06 20:36:37 UTC (rev 1007)
@@ -1,4 +1,4 @@
-LDLIBS	+= -lopensrf -lobjson -lxml2
+LDLIBS	+= -lopensrf  -lxml2
 CFLAGS	+= -D_GNU_SOURCE
 
 all: chopchop

Modified: branches/new-json2/src/libopensrf/Makefile
===================================================================
--- branches/new-json2/src/libopensrf/Makefile	2007-07-06 16:56:32 UTC (rev 1006)
+++ branches/new-json2/src/libopensrf/Makefile	2007-07-06 20:36:37 UTC (rev 1007)
@@ -1,11 +1,7 @@
-# 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
+CFLAGS	+=  -DASSUME_STATELESS  -DOSRF_STRICT_PARAMS -rdynamic -fno-strict-aliasing #-DOSRF_JSON_ALLOW_COMMENTS 
+LDLIBS	+= -lxml2 -ldl -lmemcache 
+export OSRF_INC = ../../include/opensrf/
 
-CFLAGS	+=  -DASSUME_STATELESS  -DOSRF_LOG_PARAMS -DOSRF_STRICT_PARAMS -rdynamic -fno-strict-aliasing
-LDLIBS	+= -lxml2 -lobjson -ldl -lmemcache 
-OSRF_INC = ../../include/opensrf/
-
 TARGETS = 	osrf_message.o \
 			osrf_app_session.o \
 			osrf_stack.o \
@@ -27,13 +23,12 @@
 			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
 
-
-
 # Build the OpenSRF C binary
 opensrf:	opensrf.o libopensrf.so
 	@echo $@
@@ -41,8 +36,13 @@
 
 
 # Build the OpenSRF library
-libopensrf.so:	$(TARGETS)
-	$(CC) -shared -W1 $(LDFLAGS) $(LDLIBS) $(TARGETS) -o $(TMPDIR)/libopensrf.so
+libopensrf.so:	$(TARGETS) 
+	make -f Makefile.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; 
 
 
 opensrf.o:	opensrf.c
@@ -67,7 +67,6 @@
 sha.o:	sha.c $(OSRF_INC)/sha.h
 string_array.o:	string_array.c $(OSRF_INC)/string_array.h
 
-
 clean:
-	/bin/rm -f *.o libopensrf.so opensrf
+	/bin/rm -f *.o *.so opensrf
 

Added: branches/new-json2/src/libopensrf/Makefile.json
===================================================================
--- branches/new-json2/src/libopensrf/Makefile.json	                        (rev 0)
+++ branches/new-json2/src/libopensrf/Makefile.json	2007-07-06 20:36:37 UTC (rev 1007)
@@ -0,0 +1,17 @@
+#-DOSRF_JSON_ALLOW_COMMENTS 
+TARGETS = osrf_json_object.o osrf_json_parser.o osrf_json_tools.o osrf_legacy_json.o osrf_json_xml.o
+
+all:	$(TARGETS)
+	if [ ! -z "$(OSRF_LEGACY_JSON)" ]; then \
+		$(CC) -shared -W1 $(LDFLAGS) $(TARGETS) -o $(TMPDIR)/libobjson.so;\
+	fi;
+
+standalone:
+	$(CC) -shared -W1 $(LDFLAGS) $(LDLIBS) $(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
+

Modified: branches/new-json2/src/libopensrf/osrf_application.c
===================================================================
--- branches/new-json2/src/libopensrf/osrf_application.c	2007-07-06 16:56:32 UTC (rev 1006)
+++ branches/new-json2/src/libopensrf/osrf_application.c	2007-07-06 20:36:37 UTC (rev 1007)
@@ -1,11 +1,7 @@
 #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;

Added: branches/new-json2/src/libopensrf/osrf_json_object.c
===================================================================
--- branches/new-json2/src/libopensrf/osrf_json_object.c	                        (rev 0)
+++ branches/new-json2/src/libopensrf/osrf_json_object.c	2007-07-06 20:36:37 UTC (rev 1007)
@@ -0,0 +1,348 @@
+/*
+Copyright (C) 2006  Georgia Public Library Service 
+Bill Erickson <billserickson at 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( long double num ) {
+	jsonObject* o = jsonNewObject(NULL);
+	o->type = JSON_NUMBER;
+	o->value.n = num;
+	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);
+}
+
+
+unsigned long jsonObjectPush(jsonObject* o, jsonObject* newo) {
+	if(!(o && newo)) return -1;
+	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 && newObj)) return -1;
+	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 && key && newo)) return -1;
+	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);
+
+	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: {
+			long double x = obj->value.n;
+			if( x == (long) x ) {
+				LONG_TO_STRING((long)x);	
+				OSRF_BUFFER_ADD(buf, LONGSTR);
+
+			} else {
+				LONG_DOUBLE_TO_STRING(x);
+				OSRF_BUFFER_ADD(buf, LONGDOUBLESTR);
+			}
+			break;
+		}
+
+		case JSON_NULL:
+			OSRF_BUFFER_ADD(buf, "null");
+			break;
+
+		case JSON_STRING:
+			OSRF_BUFFER_ADD(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(buf, "\"");
+			break;
+			
+		case JSON_ARRAY: {
+			OSRF_BUFFER_ADD(buf, "[");
+			if( obj->value.l ) {
+				int i;
+				for( i = 0; i != obj->value.l->size; i++ ) {
+					char* json = jsonObjectToJSON(osrfListGetIndex(obj->value.l, i));
+					if(i > 0) OSRF_BUFFER_ADD(buf, ",");
+					OSRF_BUFFER_ADD(buf, json);
+					free(json);
+				}
+			} 
+			OSRF_BUFFER_ADD(buf, "]");
+			break;
+		}
+
+		case JSON_HASH: {
+
+			OSRF_BUFFER_ADD(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 = jsonObjectToJSON(item);
+				OSRF_BUFFER_ADD(buf, json);
+				free(json);
+			}
+
+			osrfHashIteratorFree(itr);
+			OSRF_BUFFER_ADD(buf, "}");
+			break;
+		}
+	}
+
+	char* data = buffer_data(buf);
+	buffer_free(buf);
+	return data;
+}
+
+
+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) ? 
+		osrfListGetIndex(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;
+}
+
+long 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);
+}
+
+jsonObject* jsonObjectClone( const jsonObject* o ) {
+	if(!o) return NULL;
+	char* json = jsonObjectToJSONRaw(o);
+	jsonObject* oo = jsonParseStringRaw(json);
+	oo->type = o->type;
+	jsonObjectSetClass(oo, o->classname);
+	free(json);
+	return oo;
+}
+
+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 ) {
+				LONG_TO_STRING((long) o->value.n);	
+				value = strdup(LONGSTR);
+
+			} else {
+				LONG_DOUBLE_TO_STRING(o->value.n);
+				value = strdup(LONGDOUBLESTR);
+			}
+
+			break;
+		}
+
+		case JSON_STRING:
+			value = strdup(o->value.s);
+	}
+
+	return value;
+}
+
+

Added: branches/new-json2/src/libopensrf/osrf_json_parser.c
===================================================================
--- branches/new-json2/src/libopensrf/osrf_json_parser.c	                        (rev 0)
+++ branches/new-json2/src/libopensrf/osrf_json_parser.c	2007-07-06 20:36:37 UTC (rev 1007)
@@ -0,0 +1,632 @@
+/*
+Copyright (C) 2006  Georgia Public Library Service 
+Bill Erickson <billserickson at 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);
+	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 */
+	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 );
+					}
+
+				}
+
+				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;
+	long 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);
+	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_IGNORE_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, long 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;	
+	}
+}
+
+

Added: branches/new-json2/src/libopensrf/osrf_json_tools.c
===================================================================
--- branches/new-json2/src/libopensrf/osrf_json_tools.c	                        (rev 0)
+++ branches/new-json2/src/libopensrf/osrf_json_tools.c	2007-07-06 20:36:37 UTC (rev 1007)
@@ -0,0 +1,441 @@
+/*
+Copyright (C) 2006  Georgia Public Library Service 
+Bill Erickson <billserickson at 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, "  ");
+	char* final = buffer_data( buf );
+	buffer_free( buf );
+	return final;
+}
+
+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); }
+
+	}
+
+	char* result = buffer_data(buf);
+	buffer_free(buf);
+	return result;
+}
+
+
+
+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;
+}
+
+
+
+
+/*
+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,"&amp;");
+		else if (text[i] == '<')
+			buffer_add(b,"&lt;");
+		else if (text[i] == '>')
+			buffer_add(b,"&gt;");
+		else
+			buffer_add_char(b,text[i]);
+	}
+	out = buffer_data(b);
+	buffer_free(b);
+	return out;
+}
+
+*/
+
+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;
+}
+
+
+
+

Added: branches/new-json2/src/libopensrf/osrf_json_xml.c
===================================================================
--- branches/new-json2/src/libopensrf/osrf_json_xml.c	                        (rev 0)
+++ branches/new-json2/src/libopensrf/osrf_json_xml.c	2007-07-06 20:36:37 UTC (rev 1007)
@@ -0,0 +1,363 @@
+#include <opensrf/osrf_json_xml.h>
+
+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,"&amp;");
+		else if (text[i] == '<')
+			buffer_add(b,"&lt;");
+		else if (text[i] == '>')
+			buffer_add(b,"&gt;");
+		else
+			buffer_add_char(b,text[i]);
+	}
+	out = buffer_data(b);
+	buffer_free(b);
+	return out;
+}
+
+

Added: branches/new-json2/src/libopensrf/osrf_legacy_json.c
===================================================================
--- branches/new-json2/src/libopensrf/osrf_legacy_json.c	                        (rev 0)
+++ branches/new-json2/src/libopensrf/osrf_legacy_json.c	2007-07-06 20:36:37 UTC (rev 1007)
@@ -0,0 +1,897 @@
+/*
+Copyright (C) 2006  Georgia Public Library Service 
+Bill Erickson <billserickson at 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(is_number(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(is_number(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 is_number(char c) {
+	switch(c) {
+		case '0':
+		case '1':
+		case '2':
+		case '3':
+		case '4':
+		case '5':
+		case '6':
+		case '7':
+		case '8':
+		case '9':
+			return 1;
+	}
+	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);
+}
+
+

Modified: branches/new-json2/src/perlmods/OpenSRF/Utils/JSON.pm
===================================================================
--- branches/new-json2/src/perlmods/OpenSRF/Utils/JSON.pm	2007-07-06 16:56:32 UTC (rev 1006)
+++ branches/new-json2/src/perlmods/OpenSRF/Utils/JSON.pm	2007-07-06 20:36:37 UTC (rev 1007)
@@ -85,8 +85,78 @@
 	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};
+			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/(?<!\\)\$/\\\$/gmo; # fixup $ for later
@@ -97,8 +167,8 @@
 	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...
@@ -112,17 +182,18 @@
 	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;
@@ -638,7 +709,7 @@
 		} 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++;
@@ -654,10 +725,10 @@
 			$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;
 		}
 		
@@ -667,26 +738,28 @@
 	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) {
@@ -701,27 +774,28 @@
 			$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;
@@ -750,7 +824,7 @@
 	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)}) ) {

Modified: branches/new-json2/src/router/Makefile
===================================================================
--- branches/new-json2/src/router/Makefile	2007-07-06 16:56:32 UTC (rev 1006)
+++ branches/new-json2/src/router/Makefile	2007-07-06 20:36:37 UTC (rev 1007)
@@ -1,6 +1,6 @@
 #MALLOC_CHECK_=1 # XXX debug only
 
-LDLIBS	+= -lxml2 -lopensrf -lobjson
+LDLIBS	+= -lxml2 -lopensrf 
 CFLAGS	+= -D_ROUTER
 
 all: opensrf_router 

Modified: branches/new-json2/src/srfsh/Makefile
===================================================================
--- branches/new-json2/src/srfsh/Makefile	2007-07-06 16:56:32 UTC (rev 1006)
+++ branches/new-json2/src/srfsh/Makefile	2007-07-06 20:36:37 UTC (rev 1007)
@@ -1,6 +1,6 @@
 # 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

Modified: branches/new-json2/src/srfsh/srfsh.c
===================================================================
--- branches/new-json2/src/srfsh/srfsh.c	2007-07-06 16:56:32 UTC (rev 1006)
+++ branches/new-json2/src/srfsh/srfsh.c	2007-07-06 20:36:37 UTC (rev 1007)
@@ -514,7 +514,7 @@
 	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");
@@ -802,7 +802,7 @@
 	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"));
 



More information about the opensrf-commits mailing list