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