static unusedObj* freeObjList = NULL;
-static void add_json_to_buffer( const jsonObject* obj, growing_buffer * buf );
+static void add_json_to_buffer( const jsonObject* obj,
+ growing_buffer * buf, int do_classname, int second_pass );
/**
* Return all unused jsonObjects to the heap
unusedObjCapture++;
currentListLen++;
if (unusedObjCapture > 1 && !(unusedObjCapture % 1000))
- osrfLogDebug( OSRF_LOG_MARK, "Objects malloc()'d: %d, Reusable objects captured: %d, Objects reused: %d, Current List Length: %d", mallocObjCreate, unusedObjCapture, unusedObjRelease, currentListLen );
+ osrfLogDebug( OSRF_LOG_MARK, "Objects malloc()'d: %d, "
+ "Reusable objects captured: %d, Objects reused: %d, "
+ "Current List Length: %d",
+ mallocObjCreate, unusedObjCapture, unusedObjRelease, currentListLen );
}
static void _jsonFreeHashItem(char* key, void* item){
return osrfHashGet( obj->value.h, key);
}
-char* jsonObjectToJSON( const jsonObject* obj ) {
- jsonObject* obj2 = jsonObjectEncodeClass( obj );
- char* json = jsonObjectToJSONRaw(obj2);
- jsonObjectFree(obj2);
- return json;
-}
+/**
+ * Recursively traverse a jsonObject, formatting it into a JSON string.
+ *
+ * The last two parameters are booleans.
+ *
+ * If do_classname is true, examine each node for a classname, and if you
+ * find one, pretend that the node is under an extra layer of JSON_HASH, with
+ * JSON_CLASS_KEY and JSON_DATA_KEY as keys.
+ *
+ * second_pass should always be false except for some recursive calls. It
+ * is used when expanding classnames, to distinguish between the first and
+ * second passes through a given node.
+ *
+ * @return Nothing
+ */
+static void add_json_to_buffer( const jsonObject* obj,
+ growing_buffer * buf, int do_classname, int second_pass ) {
-char* jsonObjectToJSONRaw( const jsonObject* obj ) {
- if(!obj) return NULL;
- growing_buffer* buf = buffer_init(32);
- add_json_to_buffer( obj, buf );
- return buffer_release( buf );
-}
+ if(NULL == obj) {
+ OSRF_BUFFER_ADD(buf, "null");
+ return;
+ }
-static void add_json_to_buffer( const jsonObject* obj, growing_buffer * buf ) {
+ if( obj->classname && do_classname )
+ {
+ if( second_pass )
+ second_pass = 0;
+ else
+ {
+ // Pretend we see an extra layer of JSON_HASH
+
+ OSRF_BUFFER_ADD( buf, "{\"" );
+ OSRF_BUFFER_ADD( buf, JSON_CLASS_KEY );
+ OSRF_BUFFER_ADD( buf, "\":\"" );
+ OSRF_BUFFER_ADD( buf, obj->classname );
+ OSRF_BUFFER_ADD( buf, "\",\"" );
+ OSRF_BUFFER_ADD( buf, JSON_DATA_KEY );
+ OSRF_BUFFER_ADD( buf, "\":" );
+ add_json_to_buffer( obj, buf, 1, 1 );
+ buffer_add_char( buf, '}' );
+ return;
+ }
+ }
switch(obj->type) {
else OSRF_BUFFER_ADD(buf, "false");
break;
- case JSON_NUMBER: {
- if(obj->value.s) OSRF_BUFFER_ADD( buf, obj->value.s );
- else OSRF_BUFFER_ADD_CHAR( buf, '0' );
- break;
- }
+ case JSON_NUMBER: {
+ if(obj->value.s) OSRF_BUFFER_ADD( buf, obj->value.s );
+ else OSRF_BUFFER_ADD_CHAR( buf, '0' );
+ break;
+ }
case JSON_NULL:
OSRF_BUFFER_ADD(buf, "null");
case JSON_STRING:
OSRF_BUFFER_ADD_CHAR(buf, '"');
- char* data = obj->value.s;
- int len = strlen(data);
-
- char* output = uescape(data, len, 1);
- OSRF_BUFFER_ADD(buf, output);
- free(output);
+ buffer_append_uescape(buf, obj->value.s);
OSRF_BUFFER_ADD_CHAR(buf, '"');
break;
int i;
for( i = 0; i != obj->value.l->size; i++ ) {
if(i > 0) OSRF_BUFFER_ADD(buf, ",");
- add_json_to_buffer( OSRF_LIST_GET_INDEX(obj->value.l, i), buf );
+ add_json_to_buffer(
+ OSRF_LIST_GET_INDEX(obj->value.l, i), buf, do_classname, second_pass );
}
}
OSRF_BUFFER_ADD_CHAR(buf, ']');
}
case JSON_HASH: {
-
+
OSRF_BUFFER_ADD_CHAR(buf, '{');
osrfHashIterator* itr = osrfNewHashIterator(obj->value.h);
jsonObject* item;
int i = 0;
while( (item = osrfHashIteratorNext(itr)) ) {
- if(i++ > 0) OSRF_BUFFER_ADD(buf, ",");
- buffer_fadd(buf, "\"%s\":", osrfHashIteratorKey(itr));
- add_json_to_buffer( item, buf );
+ if(i++ > 0) OSRF_BUFFER_ADD_CHAR(buf, ',');
+ OSRF_BUFFER_ADD_CHAR(buf, '"');
+ OSRF_BUFFER_ADD(buf, osrfHashIteratorKey(itr));
+ OSRF_BUFFER_ADD(buf, "\":");
+ add_json_to_buffer( item, buf, do_classname, second_pass );
}
osrfHashIteratorFree(itr);
}
}
+char* jsonObjectToJSONRaw( const jsonObject* obj ) {
+ if(!obj) return NULL;
+ growing_buffer* buf = buffer_init(32);
+ add_json_to_buffer( obj, buf, 0, 0 );
+ return buffer_release( buf );
+}
+
+char* jsonObjectToJSON( const jsonObject* obj ) {
+ if(!obj) return NULL;
+ growing_buffer* buf = buffer_init(32);
+ add_json_to_buffer( obj, buf, 1, 0 );
+ return buffer_release( buf );
+}
jsonIterator* jsonNewIterator(const jsonObject* obj) {
if(!obj) return NULL;
#include <opensrf/log.h>
#include <errno.h>
+static const char hex_chars[] = "0123456789abcdef";
+static unsigned char hex_code[7] = "\\u00";
+
inline void* safe_malloc( int size ) {
void* ptr = (void*) malloc( size );
if( ptr == NULL ) {
return buffer_release(buf);
}
+int buffer_append_uescape( growing_buffer* buf, const char* string ) {
+
+ if(NULL == string)
+ return 0; // Nothing to add? Nothing to do
+
+ if( NULL == buf )
+ return -1; // Nothing to add to
+
+ int idx = 0;
+ unsigned long int c;
+
+ while (string[idx]) {
+
+ c = 0x0;
+
+ if ((unsigned char)string[idx] >= 0x80) { // not ASCII
+
+ if ((unsigned char)string[idx] >= 0xC0 && (unsigned char)string[idx] <= 0xF4) { // starts a UTF8 string
+
+ int clen = 1;
+ if (((unsigned char)string[idx] & 0xF0) == 0xF0) {
+ clen = 3;
+ c = (unsigned char)string[idx] ^ 0xF0;
+
+ } else if (((unsigned char)string[idx] & 0xE0) == 0xE0) {
+ clen = 2;
+ c = (unsigned char)string[idx] ^ 0xE0;
+
+ } else if (((unsigned char)string[idx] & 0xC0) == 0xC0) {
+ clen = 1;
+ c = (unsigned char)string[idx] ^ 0xC0;
+ }
+
+ for (;clen;clen--) {
+
+ idx++; // look at the next byte
+ c = (c << 6) | ((unsigned char)string[idx] & 0x3F); // add this byte worth
+ }
+
+ buffer_fadd(buf, "\\u%04x", c);
+
+ } else {
+ return idx + 1;
+ }
+
+ } else if(string[idx] >= ' ' ) { // printable ASCII character
+
+ c = string[idx];
+ switch(c) {
+ case '"':
+ case '\\':
+ OSRF_BUFFER_ADD_CHAR(buf, '\\');
+ OSRF_BUFFER_ADD_CHAR(buf, c);
+ break;
+
+ default:
+ OSRF_BUFFER_ADD_CHAR(buf, c);
+ }
+
+ } else {
+ c = string[idx];
+
+ /* escape the usual suspects */
+ switch(c) {
+ case '\b':
+ OSRF_BUFFER_ADD_CHAR(buf, '\\');
+ OSRF_BUFFER_ADD_CHAR(buf, 'b');
+ break;
+
+ case '\f':
+ OSRF_BUFFER_ADD_CHAR(buf, '\\');
+ OSRF_BUFFER_ADD_CHAR(buf, 'f');
+ break;
+
+ case '\t':
+ OSRF_BUFFER_ADD_CHAR(buf, '\\');
+ OSRF_BUFFER_ADD_CHAR(buf, 't');
+ break;
+
+ case '\n':
+ OSRF_BUFFER_ADD_CHAR(buf, '\\');
+ OSRF_BUFFER_ADD_CHAR(buf, 'n');
+ break;
+
+ case '\r':
+ OSRF_BUFFER_ADD_CHAR(buf, '\\');
+ OSRF_BUFFER_ADD_CHAR(buf, 'r');
+ break;
+
+ default:
+ {
+ // Represent as \u followed by four hex characters
+ hex_code[ 4 ] = hex_chars[ c >> 4 ]; // high nybble
+ hex_code[ 5 ] = hex_chars[ c & 0x0F ]; // low nybble
+ hex_code[ 6 ] = '\0';
+ OSRF_BUFFER_ADD(buf, (char *) hex_code);
+ break;
+ }
+ }
+ }
+
+ idx++;
+ }
+
+ return 0;
+}
// A function to turn a process into a daemon
int daemonize( void ) {