uber-patch from Scott McKellar cleans up large amounts of const-correctness issues...
[OpenSRF.git] / src / libopensrf / osrf_json_tools.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 static jsonObject* _jsonObjectEncodeClass( const jsonObject* obj, int ignoreClass );
20
21 static char* _tabs(int count) {
22         growing_buffer* buf = buffer_init(24);
23         int i;
24         for(i=0;i<count;i++) OSRF_BUFFER_ADD(buf, "  ");
25     return buffer_release(buf);
26 }
27
28 char* jsonFormatString( const char* string ) {
29         if(!string) return strdup("");
30
31         growing_buffer* buf = buffer_init(64);
32         int i;
33         int depth = 0;
34         char* tab = NULL;
35
36         char c;
37         for(i=0; i!= strlen(string); i++) {
38                 c = string[i];
39
40                 if( c == '{' || c == '[' ) {
41
42                         tab = _tabs(++depth);
43                         buffer_fadd( buf, "%c\n%s", c, tab);
44                         free(tab);
45
46                 } else if( c == '}' || c == ']' ) {
47
48                         tab = _tabs(--depth);
49                         buffer_fadd( buf, "\n%s%c", tab, c);
50                         free(tab);
51
52                         if(string[i+1] != ',') {
53                                 tab = _tabs(depth);
54                                 buffer_fadd( buf, "%s", tab );  
55                                 free(tab);
56                         }
57
58                 } else if( c == ',' ) {
59
60                         tab = _tabs(depth);
61                         buffer_fadd(buf, ",\n%s", tab);
62                         free(tab);
63
64                 } else { buffer_add_char(buf, c); }
65
66         }
67
68     return buffer_release(buf);
69 }
70
71
72
73 jsonObject* jsonObjectDecodeClass( const jsonObject* obj ) {
74         if(!obj) return jsonNewObject(NULL);
75
76         jsonObject* newObj                       = NULL; 
77         const jsonObject* classObj       = NULL;
78         const jsonObject* payloadObj = NULL;
79         int i;
80
81         if( obj->type == JSON_HASH ) {
82
83                 /* are we a special class object? */
84                 if( (classObj = jsonObjectGetKeyConst( obj, JSON_CLASS_KEY )) ) {
85
86                         /* do we have a payload */
87                         if( (payloadObj = jsonObjectGetKeyConst( obj, JSON_DATA_KEY )) ) {
88                                 newObj = jsonObjectDecodeClass( payloadObj ); 
89                                 jsonObjectSetClass( newObj, jsonObjectGetString(classObj) );
90
91                         } else { /* class is defined but there is no payload */
92                                 return NULL;
93                         }
94
95                 } else { /* we're a regular hash */
96
97                         jsonIterator* itr = jsonNewIterator(obj);
98                         jsonObject* tmp;
99                         newObj = jsonNewObjectType(JSON_HASH);
100                         while( (tmp = jsonIteratorNext(itr)) ) {
101                                 jsonObject* o = jsonObjectDecodeClass(tmp);
102                                 jsonObjectSetKey( newObj, itr->key, o );
103                         }
104                         jsonIteratorFree(itr);
105                 }
106
107         } else {
108
109                 if( obj->type == JSON_ARRAY ) { /* we're an array */
110                         newObj = jsonNewObjectType(JSON_ARRAY);
111                         for( i = 0; i != obj->size; i++ ) {
112                                 jsonObject* tmp = jsonObjectDecodeClass(jsonObjectGetIndex( obj, i ) );
113                                 jsonObjectSetIndex( newObj, i, tmp );
114                         }
115
116                 } else { /* not an aggregate type */
117                         newObj = jsonObjectClone(obj);
118                 }
119         }
120                 
121         return newObj;
122 }
123
124 jsonObject* jsonObjectEncodeClass( const jsonObject* obj ) {
125         return _jsonObjectEncodeClass( obj, 0 );
126 }
127
128 static jsonObject* _jsonObjectEncodeClass( const jsonObject* obj, int ignoreClass ) {
129
130         //if(!obj) return NULL;
131         if(!obj) return jsonNewObject(NULL);
132         jsonObject* newObj = NULL;
133
134         if( obj->classname && ! ignoreClass ) {
135                 newObj = jsonNewObjectType(JSON_HASH);
136
137                 jsonObjectSetKey( newObj, 
138                         JSON_CLASS_KEY, jsonNewObject(obj->classname) ); 
139
140                 jsonObjectSetKey( newObj, 
141                         JSON_DATA_KEY, _jsonObjectEncodeClass(obj, 1));
142
143         } else if( obj->type == JSON_HASH ) {
144
145                 jsonIterator* itr = jsonNewIterator(obj);
146                 jsonObject* tmp;
147                 newObj = jsonNewObjectType(JSON_HASH);
148
149                 while( (tmp = jsonIteratorNext(itr)) ) {
150                         jsonObjectSetKey( newObj, itr->key, 
151                                         _jsonObjectEncodeClass(tmp, 0));
152                 }
153                 jsonIteratorFree(itr);
154
155         } else if( obj->type == JSON_ARRAY ) {
156
157                 newObj = jsonNewObjectType(JSON_ARRAY);
158                 int i;
159                 for( i = 0; i != obj->size; i++ ) {
160                         jsonObjectSetIndex( newObj, i, 
161                                 _jsonObjectEncodeClass(jsonObjectGetIndex( obj, i ), 0 ));
162                 }
163
164         } else {
165                 newObj = jsonObjectClone(obj);
166         }
167
168         return newObj;
169 }
170
171 jsonObject* jsonParseFile( char* filename ) {
172         if(!filename) return NULL;
173         char* data = file_to_string(filename);
174         jsonObject* o = jsonParseString(data);
175         free(data);
176         return o;
177 }
178
179
180
181 jsonObject* jsonObjectFindPath( const jsonObject* obj, char* format, ...) {
182         if(!obj || !format || strlen(format) < 1) return NULL;  
183
184         VA_LIST_TO_STRING(format);
185         char* buf = VA_BUF;
186         char* token = NULL;
187         char* t = buf;
188         char* tt; /* strtok storage */
189
190         /* copy the path before strtok_r destroys it */
191         char* pathcopy = strdup(buf);
192
193         /* grab the root of the path */
194         token = strtok_r(t, "/", &tt);
195         if(!token) return NULL;
196
197         /* special case where path starts with //  (start anywhere) */
198         if(strlen(pathcopy) > 2 && pathcopy[0] == '/' && pathcopy[1] == '/') {
199                 jsonObject* it = _jsonObjectFindPathRecurse(obj, token, pathcopy + 1);
200                 free(pathcopy);
201                 return it;
202         }
203
204         free(pathcopy);
205
206         t = NULL;
207         do { 
208                 obj = jsonObjectGetKeyConst(obj, token);
209         } while( (token = strtok_r(NULL, "/", &tt)) && obj);
210
211         return jsonObjectClone(obj);
212 }
213
214 /* --------------------------------------------------------------- */
215
216
217
218 jsonObject* _jsonObjectFindPathRecurse(const jsonObject* obj, char* root, char* path) {
219
220         if(!obj || ! root || !path) return NULL;
221
222         /* collect all of the potential objects */
223         jsonObject* arr = __jsonObjectFindPathRecurse(obj, root);
224
225         /* container for fully matching objects */
226         jsonObject* newarr = jsonParseString("[]");
227         int i;
228
229         /* path is just /root or /root/ */
230         if( strlen(root) + 2 >= strlen(path) ) {
231                 return arr;
232
233         } else {
234
235                 /* gather all of the sub-objects that match the full path */
236                 for( i = 0; i < arr->size; i++ ) {
237                         const jsonObject* a = jsonObjectGetIndex(arr, i);
238                         jsonObject* thing = jsonObjectFindPath(a , path + strlen(root) + 1); 
239
240                         if(thing) { //jsonObjectPush(newarr, thing);
241                 if(thing->type == JSON_ARRAY) {
242                 int i;
243                                         for( i = 0; i != thing->size; i++ )
244                                                 jsonObjectPush(newarr, jsonObjectClone(jsonObjectGetIndex(thing,i)));
245                                         jsonObjectFree(thing);
246
247                                 } else {
248                                         jsonObjectPush(newarr, thing);
249                                 }                                               
250                         }
251                 }
252         }
253         
254         jsonObjectFree(arr);
255         return newarr;
256 }
257
258 jsonObject* __jsonObjectFindPathRecurse(const jsonObject* obj, char* root) {
259
260         jsonObject* arr = jsonParseString("[]");
261         if(!obj) return arr;
262
263         int i;
264
265         /* if the current object has a node that matches, add it */
266
267         const jsonObject* o = jsonObjectGetKeyConst(obj, root);
268         if(o) jsonObjectPush( arr, jsonObjectClone(o) );
269
270         jsonObject* tmp = NULL;
271         jsonObject* childarr;
272         jsonIterator* itr = jsonNewIterator(obj);
273
274         /* recurse through the children and find all potential nodes */
275         while( (tmp = jsonIteratorNext(itr)) ) {
276                 childarr = __jsonObjectFindPathRecurse(tmp, root);
277                 if(childarr && childarr->size > 0) {
278                         for( i = 0; i!= childarr->size; i++ ) {
279                                 jsonObjectPush( arr, jsonObjectClone(jsonObjectGetIndex(childarr, i)) );
280                         }
281                 }
282                 jsonObjectFree(childarr);
283         }
284
285         jsonIteratorFree(itr);
286
287         return arr;
288 }
289
290
291
292