64c8efd604ea3a0a0157c2d06574bf9737809160
[OpenSRF.git] / src / libopensrf / osrf_json_object.c
1 /*
2 Copyright (C) 2006  Georgia Public Library Service 
3 Bill Erickson <billserickson@gmail.com>
4
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.
9
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.
14 */
15
16 #include <limits.h>
17 #include <opensrf/osrf_json.h>
18 #include <opensrf/osrf_json_utils.h>
19
20 /* cleans up an object if it is morphing another object, also
21  * verifies that the appropriate storage container exists where appropriate */
22 #define JSON_INIT_CLEAR(_obj_, newtype)         \
23         if( _obj_->type == JSON_HASH && newtype != JSON_HASH ) {                        \
24                 osrfHashFree(_obj_->value.h);                   \
25                 _obj_->value.h = NULL;                                  \
26 } else if( _obj_->type == JSON_ARRAY && newtype != JSON_ARRAY ) {       \
27                 osrfListFree(_obj_->value.l);                   \
28                 _obj_->value.l = NULL;                                  \
29 } else if( _obj_->type == JSON_STRING && newtype != JSON_STRING ) { \
30                 free(_obj_->value.s);                                           \
31                 _obj_->value.s = NULL;                                  \
32 } \
33         _obj_->type = newtype;\
34         if( newtype == JSON_HASH && _obj_->value.h == NULL ) {  \
35                 _obj_->value.h = osrfNewHash();         \
36                 _obj_->value.h->freeItem = _jsonFreeHashItem; \
37 } else if( newtype == JSON_ARRAY && _obj_->value.l == NULL ) {  \
38                 _obj_->value.l = osrfNewList();         \
39                 _obj_->value.l->freeItem = _jsonFreeListItem;\
40 }
41
42 static void add_json_to_buffer( const jsonObject* obj, growing_buffer * buf );
43
44 jsonObject* jsonNewObject(const char* data) {
45
46         jsonObject* o;
47         OSRF_MALLOC(o, sizeof(jsonObject));
48         o->type = JSON_NULL;
49
50         if(data) {
51                 o->type = JSON_STRING;
52                 o->value.s = strdup(data);
53         }
54
55         return o;
56 }
57
58 jsonObject* jsonNewObjectFmt(const char* data, ...) {
59
60         jsonObject* o;
61         OSRF_MALLOC(o, sizeof(jsonObject));
62         o->type = JSON_NULL;
63
64         if(data) {
65                 VA_LIST_TO_STRING(data);
66                 o->type = JSON_STRING;
67                 o->value.s = strdup(VA_BUF);
68         }
69
70         return o;
71 }
72
73 jsonObject* jsonNewNumberObject( double num ) {
74         jsonObject* o = jsonNewObject(NULL);
75         o->type = JSON_NUMBER;
76         o->value.n = num;
77         return o;
78 }
79
80 jsonObject* jsonNewBoolObject(int val) {
81     jsonObject* o = jsonNewObject(NULL);
82     o->type = JSON_BOOL;
83     jsonSetBool(o, val);
84     return o;
85 }
86
87 jsonObject* jsonNewObjectType(int type) {
88         jsonObject* o = jsonNewObject(NULL);
89         o->type = type;
90         return o;
91 }
92
93 void jsonObjectFree( jsonObject* o ) {
94
95         if(!o || o->parent) return;
96         free(o->classname);
97
98         switch(o->type) {
99                 case JSON_HASH          : osrfHashFree(o->value.h); break;
100                 case JSON_ARRAY : osrfListFree(o->value.l); break;
101                 case JSON_STRING        : free(o->value.s); break;
102         }
103         free(o);
104 }
105
106 static void _jsonFreeHashItem(char* key, void* item){
107         if(!item) return;
108         jsonObject* o = (jsonObject*) item;
109         o->parent = NULL; /* detach the item */
110         jsonObjectFree(o);
111 }
112 static void _jsonFreeListItem(void* item){
113         if(!item) return;
114         jsonObject* o = (jsonObject*) item;
115         o->parent = NULL; /* detach the item */
116         jsonObjectFree(o);
117 }
118
119 void jsonSetBool(jsonObject* bl, int val) {
120     if(!bl) return;
121     JSON_INIT_CLEAR(bl, JSON_BOOL);
122     bl->value.b = val;
123 }
124
125 unsigned long jsonObjectPush(jsonObject* o, jsonObject* newo) {
126     if(!o) return -1;
127     if(!newo) newo = jsonNewObject(NULL);
128         JSON_INIT_CLEAR(o, JSON_ARRAY);
129         newo->parent = o;
130         osrfListPush( o->value.l, newo );
131         o->size = o->value.l->size;
132         return o->size;
133 }
134
135 unsigned long jsonObjectSetIndex(jsonObject* dest, unsigned long index, jsonObject* newObj) {
136     if(!dest) return -1;
137     if(!newObj) newObj = jsonNewObject(NULL);
138         JSON_INIT_CLEAR(dest, JSON_ARRAY);
139         newObj->parent = dest;
140         osrfListSet( dest->value.l, newObj, index );
141         dest->size = dest->value.l->size;
142         return dest->value.l->size;
143 }
144
145 unsigned long jsonObjectSetKey( jsonObject* o, const char* key, jsonObject* newo) {
146     if(!o) return -1;
147     if(!newo) newo = jsonNewObject(NULL);
148         JSON_INIT_CLEAR(o, JSON_HASH);
149         newo->parent = o;
150         osrfHashSet( o->value.h, newo, key );
151         o->size = o->value.h->size;
152         return o->size;
153 }
154
155 jsonObject* jsonObjectGetKey( const jsonObject* obj, const char* key ) {
156         if(!(obj && obj->type == JSON_HASH && obj->value.h && key)) return NULL;
157         return osrfHashGet( obj->value.h, key);
158 }
159
160 const jsonObject* jsonObjectGetKeyConst( const jsonObject* obj, const char* key ) {
161         if(!(obj && obj->type == JSON_HASH && obj->value.h && key)) return NULL;
162         return osrfHashGet( obj->value.h, key);
163 }
164
165 char* jsonObjectToJSON( const jsonObject* obj ) {
166         jsonObject* obj2 = jsonObjectEncodeClass( obj );
167         char* json = jsonObjectToJSONRaw(obj2);
168         jsonObjectFree(obj2);
169         return json;
170 }
171
172 char* jsonObjectToJSONRaw( const jsonObject* obj ) {
173         if(!obj) return NULL;
174         growing_buffer* buf = buffer_init(32);
175         add_json_to_buffer( obj, buf );
176         return buffer_release( buf );
177 }
178
179 static void add_json_to_buffer( const jsonObject* obj, growing_buffer * buf ) {
180
181         switch(obj->type) {
182
183                 case JSON_BOOL :
184                         if(obj->value.b) OSRF_BUFFER_ADD(buf, "true"); 
185                         else OSRF_BUFFER_ADD(buf, "false"); 
186                         break;
187
188                 case JSON_NUMBER: {
189                         double x = obj->value.n;
190                         if( x <= INT_MAX && x >= INT_MIN && x == (int) x ) {
191                                 INT_TO_STRING((int)x);
192                                 OSRF_BUFFER_ADD(buf, INTSTR);
193
194                         } else {
195                                 DOUBLE_TO_STRING(x);
196                                 OSRF_BUFFER_ADD(buf, DOUBLESTR);
197                         }
198                         break;
199                 }
200
201                 case JSON_NULL:
202                         OSRF_BUFFER_ADD(buf, "null");
203                         break;
204
205                 case JSON_STRING:
206                         OSRF_BUFFER_ADD_CHAR(buf, '"');
207                         char* data = obj->value.s;
208                         int len = strlen(data);
209                         
210                         char* output = uescape(data, len, 1);
211                         OSRF_BUFFER_ADD(buf, output);
212                         free(output);
213                         OSRF_BUFFER_ADD_CHAR(buf, '"');
214                         break;
215                         
216                 case JSON_ARRAY: {
217                         OSRF_BUFFER_ADD_CHAR(buf, '[');
218                         if( obj->value.l ) {
219                                 int i;
220                                 for( i = 0; i != obj->value.l->size; i++ ) {
221                                         if(i > 0) OSRF_BUFFER_ADD(buf, ",");
222                                         add_json_to_buffer( OSRF_LIST_GET_INDEX(obj->value.l, i), buf );
223                                 }
224                         }
225                         OSRF_BUFFER_ADD_CHAR(buf, ']');
226                         break;
227                 }
228
229                 case JSON_HASH: {
230
231                         OSRF_BUFFER_ADD_CHAR(buf, '{');
232                         osrfHashIterator* itr = osrfNewHashIterator(obj->value.h);
233                         jsonObject* item;
234                         int i = 0;
235
236                         while( (item = osrfHashIteratorNext(itr)) ) {
237                                 if(i++ > 0) OSRF_BUFFER_ADD(buf, ",");
238                                 buffer_fadd(buf, "\"%s\":", itr->current);
239                                 add_json_to_buffer( item, buf );
240                         }
241
242                         osrfHashIteratorFree(itr);
243                         OSRF_BUFFER_ADD_CHAR(buf, '}');
244                         break;
245                 }
246         }
247 }
248
249
250 jsonIterator* jsonNewIterator(const jsonObject* obj) {
251         if(!obj) return NULL;
252         jsonIterator* itr;
253         OSRF_MALLOC(itr, sizeof(jsonIterator));
254
255         itr->obj                = (jsonObject*) obj;
256         itr->index      = 0;
257         itr->key                = NULL;
258
259         if( obj->type == JSON_HASH )
260                 itr->hashItr = osrfNewHashIterator(obj->value.h);
261         
262         return itr;
263 }
264
265 void jsonIteratorFree(jsonIterator* itr) {
266         if(!itr) return;
267         free(itr->key);
268         osrfHashIteratorFree(itr->hashItr);
269         free(itr);
270 }
271
272 jsonObject* jsonIteratorNext(jsonIterator* itr) {
273         if(!(itr && itr->obj)) return NULL;
274         if( itr->obj->type == JSON_HASH ) {
275                 if(!itr->hashItr) return NULL;
276                 jsonObject* item = osrfHashIteratorNext(itr->hashItr);
277                 free(itr->key);
278                 itr->key = strdup(itr->hashItr->current);
279                 return item;
280         } else {
281                 return jsonObjectGetIndex( itr->obj, itr->index++ );
282         }
283 }
284
285 int jsonIteratorHasNext(const jsonIterator* itr) {
286         if(!(itr && itr->obj)) return 0;
287         if( itr->obj->type == JSON_HASH )
288                 return osrfHashIteratorHasNext( itr->hashItr );
289         return (itr->index < itr->obj->size) ? 1 : 0;
290 }
291
292 jsonObject* jsonObjectGetIndex( const jsonObject* obj, unsigned long index ) {
293         if(!obj) return NULL;
294         return (obj->type == JSON_ARRAY) ? 
295         (OSRF_LIST_GET_INDEX(obj->value.l, index)) : NULL;
296 }
297
298
299
300 unsigned long jsonObjectRemoveIndex(jsonObject* dest, unsigned long index) {
301         if( dest && dest->type == JSON_ARRAY ) {
302                 osrfListRemove(dest->value.l, index);
303                 return dest->value.l->size;
304         }
305         return -1;
306 }
307
308
309 unsigned long jsonObjectRemoveKey( jsonObject* dest, const char* key) {
310         if( dest && key && dest->type == JSON_HASH ) {
311                 osrfHashRemove(dest->value.h, key);
312                 return 1;
313         }
314         return -1;
315 }
316
317 char* jsonObjectGetString(const jsonObject* obj) {
318         return (obj && obj->type == JSON_STRING) ? obj->value.s : NULL;
319 }
320
321 double jsonObjectGetNumber( const jsonObject* obj ) {
322         return (obj && obj->type == JSON_NUMBER) ? obj->value.n : 0;
323 }
324
325 void jsonObjectSetString(jsonObject* dest, const char* string) {
326         if(!(dest && string)) return;
327         JSON_INIT_CLEAR(dest, JSON_STRING);
328         free(dest->value.s);
329         dest->value.s = strdup(string);
330 }
331
332 void jsonObjectSetNumber(jsonObject* dest, double num) {
333         if(!dest) return;
334         JSON_INIT_CLEAR(dest, JSON_NUMBER);
335         dest->value.n = num;
336 }
337
338 void jsonObjectSetClass(jsonObject* dest, const char* classname ) {
339         if(!(dest && classname)) return;
340         free(dest->classname);
341         dest->classname = strdup(classname);
342 }
343 const char* jsonObjectGetClass(const jsonObject* dest) {
344     if(!dest) return NULL;
345     return dest->classname;
346 }
347
348 jsonObject* jsonObjectClone( const jsonObject* o ) {
349     if(!o) return jsonNewObject(NULL);
350
351     int i;
352     jsonObject* arr; 
353     jsonObject* hash; 
354     jsonIterator* itr;
355     jsonObject* tmp;
356     jsonObject* result = NULL;
357
358     switch(o->type) {
359         case JSON_NULL:
360             result = jsonNewObject(NULL);
361             break;
362         case JSON_STRING:
363             result = jsonNewObject(jsonObjectGetString(o));
364             break;
365         case JSON_NUMBER:
366             result = jsonNewNumberObject(jsonObjectGetNumber(o));
367             break;
368         case JSON_BOOL:
369             result = jsonNewBoolObject(jsonBoolIsTrue((jsonObject*) o));
370             break;
371         case JSON_ARRAY:
372             arr = jsonNewObject(NULL);
373             arr->type = JSON_ARRAY;
374             for(i=0; i < o->size; i++) 
375                 jsonObjectPush(arr, jsonObjectClone(jsonObjectGetIndex(o, i)));
376             result = arr;
377             break;
378         case JSON_HASH:
379             hash = jsonNewObject(NULL);
380             hash->type = JSON_HASH;
381             itr = jsonNewIterator(o);
382             while( (tmp = jsonIteratorNext(itr)) )
383                 jsonObjectSetKey(hash, itr->key, jsonObjectClone(tmp));
384             jsonIteratorFree(itr);
385             result = hash;
386             break;
387     }
388
389     jsonObjectSetClass(result, jsonObjectGetClass(o));
390     return result;
391 }
392
393 int jsonBoolIsTrue( jsonObject* boolObj ) {
394     if( boolObj && boolObj->type == JSON_BOOL && boolObj->value.b )
395         return 1;
396     return 0;
397 }
398
399
400 char* jsonObjectToSimpleString( const jsonObject* o ) {
401         if(!o) return NULL;
402
403         char* value = NULL;
404
405         switch( o->type ) {
406
407                 case JSON_NUMBER: {
408
409                         if( o->value.n == (int) o->value.n ) {
410                                 INT_TO_STRING((int) o->value.n);        
411                                 value = strdup(INTSTR);
412
413                         } else {
414                                 DOUBLE_TO_STRING(o->value.n);
415                                 value = strdup(DOUBLESTR);
416                         }
417
418                         break;
419                 }
420
421                 case JSON_STRING:
422                         value = strdup(o->value.s);
423         }
424
425         return value;
426 }
427
428