2 Copyright (C) 2006 Georgia Public Library Service
3 Bill Erickson <billserickson@gmail.com>
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
17 #include <opensrf/log.h>
18 #include <opensrf/osrf_json.h>
19 #include <opensrf/osrf_json_utils.h>
21 /* cleans up an object if it is morphing another object, also
22 * verifies that the appropriate storage container exists where appropriate */
23 #define JSON_INIT_CLEAR(_obj_, newtype) \
24 if( _obj_->type == JSON_HASH && newtype != JSON_HASH ) { \
25 osrfHashFree(_obj_->value.h); \
26 _obj_->value.h = NULL; \
27 } else if( _obj_->type == JSON_ARRAY && newtype != JSON_ARRAY ) { \
28 osrfListFree(_obj_->value.l); \
29 _obj_->value.l = NULL; \
30 } else if( _obj_->type == JSON_STRING && newtype != JSON_STRING ) { \
31 free(_obj_->value.s); \
32 _obj_->value.s = NULL; \
34 _obj_->type = newtype;\
35 if( newtype == JSON_HASH && _obj_->value.h == NULL ) { \
36 _obj_->value.h = osrfNewHash(); \
37 _obj_->value.h->freeItem = _jsonFreeHashItem; \
38 } else if( newtype == JSON_ARRAY && _obj_->value.l == NULL ) { \
39 _obj_->value.l = osrfNewList(); \
40 _obj_->value.l->freeItem = _jsonFreeListItem;\
43 static int unusedObjCapture = 0;
44 static int unusedObjRelease = 0;
45 static int mallocObjCreate = 0;
46 static int currentListLen = 0;
50 union unusedObjUnion* next;
53 typedef union unusedObjUnion unusedObj;
55 // We maintain a free list of jsonObjects that are available
56 // for use, in order to reduce the churning through
57 // malloc() and free().
59 static unusedObj* freeObjList = NULL;
61 static void add_json_to_buffer( const jsonObject* obj, growing_buffer * buf );
64 * Return all unused jsonObjects to the heap
67 void jsonObjectFreeUnused( void ) {
70 while( freeObjList ) {
71 temp = freeObjList->next;
77 jsonObject* jsonNewObject(const char* data) {
82 o = (jsonObject*) freeObjList;
83 freeObjList = freeObjList->next;
87 OSRF_MALLOC( o, sizeof(jsonObject) );
96 o->type = JSON_STRING;
97 o->value.s = strdup(data);
106 jsonObject* jsonNewObjectFmt(const char* data, ...) {
111 o = (jsonObject*) freeObjList;
112 freeObjList = freeObjList->next;
115 OSRF_MALLOC( o, sizeof(jsonObject) );
122 VA_LIST_TO_STRING(data);
123 o->type = JSON_STRING;
124 o->value.s = strdup(VA_BUF);
134 jsonObject* jsonNewNumberObject( double num ) {
135 jsonObject* o = jsonNewObject(NULL);
136 o->type = JSON_NUMBER;
141 jsonObject* jsonNewBoolObject(int val) {
142 jsonObject* o = jsonNewObject(NULL);
148 jsonObject* jsonNewObjectType(int type) {
149 jsonObject* o = jsonNewObject(NULL);
154 void jsonObjectFree( jsonObject* o ) {
156 if(!o || o->parent) return;
160 case JSON_HASH : osrfHashFree(o->value.h); break;
161 case JSON_ARRAY : osrfListFree(o->value.l); break;
162 case JSON_STRING : free(o->value.s); break;
165 // Stick the old jsonObject onto a free list
166 // for potential reuse
168 unusedObj* unused = (unusedObj*) o;
169 unused->next = freeObjList;
170 freeObjList = unused;
174 if (unusedObjCapture > 1 && !(unusedObjCapture % 1000))
175 osrfLogDebug( OSRF_LOG_MARK, "Objects malloc()'d: %d, Reusable objects captured: %d, Objects reused: %d, Current List Length: %d", mallocObjCreate, unusedObjCapture, unusedObjRelease, currentListLen );
178 static void _jsonFreeHashItem(char* key, void* item){
180 jsonObject* o = (jsonObject*) item;
181 o->parent = NULL; /* detach the item */
184 static void _jsonFreeListItem(void* item){
186 jsonObject* o = (jsonObject*) item;
187 o->parent = NULL; /* detach the item */
191 void jsonSetBool(jsonObject* bl, int val) {
193 JSON_INIT_CLEAR(bl, JSON_BOOL);
197 unsigned long jsonObjectPush(jsonObject* o, jsonObject* newo) {
199 if(!newo) newo = jsonNewObject(NULL);
200 JSON_INIT_CLEAR(o, JSON_ARRAY);
202 osrfListPush( o->value.l, newo );
203 o->size = o->value.l->size;
207 unsigned long jsonObjectSetIndex(jsonObject* dest, unsigned long index, jsonObject* newObj) {
209 if(!newObj) newObj = jsonNewObject(NULL);
210 JSON_INIT_CLEAR(dest, JSON_ARRAY);
211 newObj->parent = dest;
212 osrfListSet( dest->value.l, newObj, index );
213 dest->size = dest->value.l->size;
214 return dest->value.l->size;
217 unsigned long jsonObjectSetKey( jsonObject* o, const char* key, jsonObject* newo) {
219 if(!newo) newo = jsonNewObject(NULL);
220 JSON_INIT_CLEAR(o, JSON_HASH);
222 osrfHashSet( o->value.h, newo, key );
223 o->size = o->value.h->size;
227 jsonObject* jsonObjectGetKey( jsonObject* obj, const char* key ) {
228 if(!(obj && obj->type == JSON_HASH && obj->value.h && key)) return NULL;
229 return osrfHashGet( obj->value.h, key);
232 const jsonObject* jsonObjectGetKeyConst( const jsonObject* obj, const char* key ) {
233 if(!(obj && obj->type == JSON_HASH && obj->value.h && key)) return NULL;
234 return osrfHashGet( obj->value.h, key);
237 char* jsonObjectToJSON( const jsonObject* obj ) {
238 jsonObject* obj2 = jsonObjectEncodeClass( obj );
239 char* json = jsonObjectToJSONRaw(obj2);
240 jsonObjectFree(obj2);
244 char* jsonObjectToJSONRaw( const jsonObject* obj ) {
245 if(!obj) return NULL;
246 growing_buffer* buf = buffer_init(32);
247 add_json_to_buffer( obj, buf );
248 return buffer_release( buf );
251 static void add_json_to_buffer( const jsonObject* obj, growing_buffer * buf ) {
256 if(obj->value.b) OSRF_BUFFER_ADD(buf, "true");
257 else OSRF_BUFFER_ADD(buf, "false");
261 double x = obj->value.n;
262 if( x <= INT_MAX && x >= INT_MIN && x == (int) x ) {
263 INT_TO_STRING((int)x);
264 OSRF_BUFFER_ADD(buf, INTSTR);
268 OSRF_BUFFER_ADD(buf, DOUBLESTR);
274 OSRF_BUFFER_ADD(buf, "null");
278 OSRF_BUFFER_ADD_CHAR(buf, '"');
279 char* data = obj->value.s;
280 int len = strlen(data);
282 char* output = uescape(data, len, 1);
283 OSRF_BUFFER_ADD(buf, output);
285 OSRF_BUFFER_ADD_CHAR(buf, '"');
289 OSRF_BUFFER_ADD_CHAR(buf, '[');
292 for( i = 0; i != obj->value.l->size; i++ ) {
293 if(i > 0) OSRF_BUFFER_ADD(buf, ",");
294 add_json_to_buffer( OSRF_LIST_GET_INDEX(obj->value.l, i), buf );
297 OSRF_BUFFER_ADD_CHAR(buf, ']');
303 OSRF_BUFFER_ADD_CHAR(buf, '{');
304 osrfHashIterator* itr = osrfNewHashIterator(obj->value.h);
308 while( (item = osrfHashIteratorNext(itr)) ) {
309 if(i++ > 0) OSRF_BUFFER_ADD(buf, ",");
310 buffer_fadd(buf, "\"%s\":", itr->current);
311 add_json_to_buffer( item, buf );
314 osrfHashIteratorFree(itr);
315 OSRF_BUFFER_ADD_CHAR(buf, '}');
322 jsonIterator* jsonNewIterator(const jsonObject* obj) {
323 if(!obj) return NULL;
325 OSRF_MALLOC(itr, sizeof(jsonIterator));
327 itr->obj = (jsonObject*) obj;
331 if( obj->type == JSON_HASH )
332 itr->hashItr = osrfNewHashIterator(obj->value.h);
337 void jsonIteratorFree(jsonIterator* itr) {
340 osrfHashIteratorFree(itr->hashItr);
344 jsonObject* jsonIteratorNext(jsonIterator* itr) {
345 if(!(itr && itr->obj)) return NULL;
346 if( itr->obj->type == JSON_HASH ) {
347 if(!itr->hashItr) return NULL;
348 jsonObject* item = osrfHashIteratorNext(itr->hashItr);
350 itr->key = strdup(itr->hashItr->current);
353 return jsonObjectGetIndex( itr->obj, itr->index++ );
357 int jsonIteratorHasNext(const jsonIterator* itr) {
358 if(!(itr && itr->obj)) return 0;
359 if( itr->obj->type == JSON_HASH )
360 return osrfHashIteratorHasNext( itr->hashItr );
361 return (itr->index < itr->obj->size) ? 1 : 0;
364 jsonObject* jsonObjectGetIndex( const jsonObject* obj, unsigned long index ) {
365 if(!obj) return NULL;
366 return (obj->type == JSON_ARRAY) ?
367 (OSRF_LIST_GET_INDEX(obj->value.l, index)) : NULL;
372 unsigned long jsonObjectRemoveIndex(jsonObject* dest, unsigned long index) {
373 if( dest && dest->type == JSON_ARRAY ) {
374 osrfListRemove(dest->value.l, index);
375 return dest->value.l->size;
381 unsigned long jsonObjectRemoveKey( jsonObject* dest, const char* key) {
382 if( dest && key && dest->type == JSON_HASH ) {
383 osrfHashRemove(dest->value.h, key);
389 char* jsonObjectGetString(const jsonObject* obj) {
390 return (obj && obj->type == JSON_STRING) ? obj->value.s : NULL;
393 double jsonObjectGetNumber( const jsonObject* obj ) {
394 return (obj && obj->type == JSON_NUMBER) ? obj->value.n : 0;
397 void jsonObjectSetString(jsonObject* dest, const char* string) {
398 if(!(dest && string)) return;
399 JSON_INIT_CLEAR(dest, JSON_STRING);
401 dest->value.s = strdup(string);
404 void jsonObjectSetNumber(jsonObject* dest, double num) {
406 JSON_INIT_CLEAR(dest, JSON_NUMBER);
410 void jsonObjectSetClass(jsonObject* dest, const char* classname ) {
411 if(!(dest && classname)) return;
412 free(dest->classname);
413 dest->classname = strdup(classname);
415 const char* jsonObjectGetClass(const jsonObject* dest) {
416 if(!dest) return NULL;
417 return dest->classname;
420 jsonObject* jsonObjectClone( const jsonObject* o ) {
421 if(!o) return jsonNewObject(NULL);
428 jsonObject* result = NULL;
432 result = jsonNewObject(NULL);
435 result = jsonNewObject(jsonObjectGetString(o));
438 result = jsonNewNumberObject(jsonObjectGetNumber(o));
441 result = jsonNewBoolObject(jsonBoolIsTrue((jsonObject*) o));
444 arr = jsonNewObject(NULL);
445 arr->type = JSON_ARRAY;
446 for(i=0; i < o->size; i++)
447 jsonObjectPush(arr, jsonObjectClone(jsonObjectGetIndex(o, i)));
451 hash = jsonNewObject(NULL);
452 hash->type = JSON_HASH;
453 itr = jsonNewIterator(o);
454 while( (tmp = jsonIteratorNext(itr)) )
455 jsonObjectSetKey(hash, itr->key, jsonObjectClone(tmp));
456 jsonIteratorFree(itr);
461 jsonObjectSetClass(result, jsonObjectGetClass(o));
465 int jsonBoolIsTrue( const jsonObject* boolObj ) {
466 if( boolObj && boolObj->type == JSON_BOOL && boolObj->value.b )
472 char* jsonObjectToSimpleString( const jsonObject* o ) {
481 if( o->value.n == (int) o->value.n ) {
482 INT_TO_STRING((int) o->value.n);
483 value = strdup(INTSTR);
486 DOUBLE_TO_STRING(o->value.n);
487 value = strdup(DOUBLESTR);
494 value = strdup(o->value.s);