]> git.evergreen-ils.org Git - Evergreen.git/blob - OpenSRF/src/libjson/json_object.c
0694fa41f71a5136f3ace405ad045b2ba379d6c3
[Evergreen.git] / OpenSRF / src / libjson / json_object.c
1 /*
2  * $Id$
3  *
4  * Copyright Metaparadigm Pte. Ltd. 2004.
5  * Michael Clark <michael@metaparadigm.com>
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public (LGPL)
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details: http://www.gnu.org/
16  *
17  */
18
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22
23 #include "debug.h"
24 #include "printbuf.h"
25 #include "linkhash.h"
26 #include "arraylist.h"
27 #include "json_object.h"
28 #include "ossupport.h"
29 #include "json_object_private.h"
30
31
32 /* #define REFCOUNT_DEBUG */
33
34 char *json_number_chars = "0123456789.+-e";
35 char *json_hex_chars = "0123456789abcdef";
36
37 #ifdef REFCOUNT_DEBUG
38 static char* json_type_name[] = {
39   "null",
40   "boolean",
41   "double",
42   "int",
43   "object",
44   "array",
45   "string",
46 };
47 #endif
48
49 static void json_object_generic_delete(struct json_object* this);
50 static struct json_object* json_object_new(enum json_type o_type);
51
52
53 /* ref count debugging */
54
55 #ifdef REFCOUNT_DEBUG
56
57 static struct lh_table *json_object_table;
58
59 static void json_object_init() __attribute__ ((constructor));
60 static void json_object_init() {
61   mc_debug("json_object_init: creating object table\n");
62   json_object_table = lh_kptr_table_new(128, "json_object_table", NULL);
63 }
64
65 static void json_object_fini() __attribute__ ((destructor));
66 static void json_object_fini() {
67   struct lh_entry *ent;
68   if(mc_get_debug() && json_object_table->count) {
69     mc_debug("json_object_fini: %d referenced objects at exit\n",
70              json_object_table->count);
71     lh_foreach(json_object_table, ent) {
72       struct json_object* obj = (struct json_object*)ent->v;
73       mc_debug("\t%s:%p\n", json_type_name[obj->o_type], obj);
74     }
75   }
76   mc_debug("json_object_fini: freeing object table\n");
77   lh_table_free(json_object_table);
78 }
79 #endif
80
81
82 /* string escaping */
83
84 static int json_escape_str(struct printbuf *pb, char *str)
85 {
86   int pos = 0, start_offset = 0;
87   char c;
88   do {
89     c = str[pos];
90     switch(c) {
91                 case '\b':
92                 case '\n':
93                 case '\r':
94                 case '\t':
95                 case '"':
96
97                         if(pos - start_offset > 0)
98                                 printbuf_memappend(pb, str + start_offset, pos - start_offset);
99
100                         if(c == '\b')                   printbuf_memappend(pb, "\\b", 2);
101                         else if(c == '\n')      printbuf_memappend(pb, "\\n", 2);
102                         else if(c == '\r')      printbuf_memappend(pb, "\\r", 2);
103                         else if(c == '\t')      printbuf_memappend(pb, "\\t", 2);
104                         else if(c == '"')               printbuf_memappend(pb, "\\\"", 2);
105
106       start_offset = ++pos;
107       break;
108
109     default:
110       if(c && c < ' ') {
111                         if(pos - start_offset > 0)
112                                 printbuf_memappend(pb, str + start_offset, pos - start_offset);
113
114                         sprintbuf(pb, "\\u00%c%c",
115                                 json_hex_chars[c >> 4], json_hex_chars[c & 0xf]);
116
117                         start_offset = ++pos;
118
119       } else if(c) pos++;
120     }
121   } while(c);
122
123   if(pos - start_offset > 0)
124     printbuf_memappend(pb, str + start_offset, pos - start_offset);
125
126   return 0;
127 }
128
129
130 /* reference counting */
131
132 extern struct json_object* json_object_get(struct json_object *this)
133 {
134   if(this) {
135     this->_ref_count++;
136   }
137   return this;
138 }
139
140 extern void json_object_put(struct json_object *this)
141 {
142   if(this) {
143     this->_ref_count--;
144     if(!this->_ref_count) this->_delete(this);
145   }
146 }
147
148
149 /* generic object construction and destruction parts */
150
151 static void json_object_generic_delete(struct json_object* this)
152 {
153 #ifdef REFCOUNT_DEBUG
154   mc_debug("json_object_delete_%s: %p\n",
155            json_type_name[this->o_type], this);
156   lh_table_delete(json_object_table, this);
157 #endif
158   printbuf_free(this->_pb);
159   free(this);
160 }
161
162 static struct json_object* json_object_new(enum json_type o_type)
163 {
164   struct json_object *this = calloc(sizeof(struct json_object), 1);
165   if(!this) return NULL;
166   this->o_type = o_type;
167   this->_ref_count = 1;
168   this->_delete = &json_object_generic_delete;
169 #ifdef REFCOUNT_DEBUG
170   lh_table_insert(json_object_table, this, this);
171   mc_debug("json_object_new_%s: %p\n", json_type_name[this->o_type], this);
172 #endif
173   return this;
174 }
175
176
177 /* type checking functions */
178
179 int json_object_is_type(struct json_object *this, enum json_type type)
180 {
181   return (this->o_type == type);
182 }
183
184 enum json_type json_object_get_type(struct json_object *this)
185 {
186   return this->o_type;
187 }
188
189
190 /* json_object_to_json_string */
191
192 char* json_object_to_json_string(struct json_object *this)
193 {
194   if(!this) return "null";
195   if(!this->_pb) {
196     if(!(this->_pb = printbuf_new())) return NULL;
197   } else {
198     printbuf_reset(this->_pb);
199   }
200   if(this->_to_json_string(this, this->_pb) < 0) return NULL;
201   return this->_pb->buf;
202 }
203
204
205 /* json_object_object */
206
207 static int json_object_object_to_json_string(struct json_object* this,
208                                              struct printbuf *pb)
209 {
210   int i=0;
211   sprintbuf(pb, "{");
212   json_object_object_foreach(this, key, val) {
213     if(i) sprintbuf(pb, ",");
214     sprintbuf(pb, " \"");
215     json_escape_str(pb, key);
216     sprintbuf(pb, "\": ");
217     if(val == NULL) sprintbuf(pb, "null");
218     else val->_to_json_string(val, pb);
219     i++;
220   }
221   return sprintbuf(pb, " }");
222 }
223
224 static void json_object_lh_entry_free(struct lh_entry *ent)
225 {
226   free(ent->k);
227   json_object_put((struct json_object*)ent->v);
228 }
229
230 static void json_object_object_delete(struct json_object* this)
231 {
232   lh_table_free(this->o.c_object);
233   json_object_generic_delete(this);
234 }
235
236 struct json_object* json_object_new_object()
237 {
238   struct json_object *this = json_object_new(json_type_object);
239   if(!this) return NULL;
240   this->_delete = &json_object_object_delete;
241   this->_to_json_string = &json_object_object_to_json_string;
242   this->o.c_object = lh_kchar_table_new(JSON_OBJECT_DEF_HASH_ENTIRES,
243                                         NULL, &json_object_lh_entry_free);
244   return this;
245 }
246
247 struct lh_table* json_object_get_object(struct json_object *this)
248 {
249   if(!this) return NULL;
250   switch(this->o_type) {
251   case json_type_object:
252     return this->o.c_object;
253   default:
254     return NULL;
255   }
256 }
257
258 void json_object_object_add(struct json_object* this, char *key,
259                             struct json_object *val)
260 {
261   lh_table_delete(this->o.c_object, key);
262   lh_table_insert(this->o.c_object, strdup(key), val);
263 }
264
265 struct json_object* json_object_object_get(struct json_object* this, char *key)
266 {
267   return (struct json_object*) lh_table_lookup(this->o.c_object, key);
268 }
269
270 void json_object_object_del(struct json_object* this, char *key)
271 {
272   lh_table_delete(this->o.c_object, key);
273 }
274
275
276 /* json_object_boolean */
277
278 static int json_object_boolean_to_json_string(struct json_object* this,
279                                               struct printbuf *pb)
280 {
281   if(this->o.c_boolean) return sprintbuf(pb, "true");
282   else return sprintbuf(pb, "false");
283 }
284
285 struct json_object* json_object_new_boolean(boolean b)
286 {
287   struct json_object *this = json_object_new(json_type_boolean);
288   if(!this) return NULL;
289   this->_to_json_string = &json_object_boolean_to_json_string;
290   this->o.c_boolean = b;
291   return this;
292 }
293
294 boolean json_object_get_boolean(struct json_object *this)
295 {
296   if(!this) return FALSE;
297   switch(this->o_type) {
298   case json_type_boolean:
299     return this->o.c_boolean;
300   case json_type_int:
301     return (this->o.c_int != 0);
302   case json_type_double:
303     return (this->o.c_double != 0);
304   case json_type_string:
305     if(strlen(this->o.c_string)) return TRUE;
306   default:
307     return TRUE;
308   }
309 }
310
311
312 /* json_object_int */
313
314 static int json_object_int_to_json_string(struct json_object* this,
315                                           struct printbuf *pb)
316 {
317   return sprintbuf(pb, "%d", this->o.c_int);
318 }
319
320 struct json_object* json_object_new_int(int i)
321 {
322   struct json_object *this = json_object_new(json_type_int);
323   if(!this) return NULL;
324   this->_to_json_string = &json_object_int_to_json_string;
325   this->o.c_int = i;
326   return this;
327 }
328
329 int json_object_get_int(struct json_object *this)
330 {
331   int cint;
332
333   if(!this) return 0;
334   switch(this->o_type) {
335   case json_type_int:
336     return this->o.c_int;
337   case json_type_double:
338     return this->o.c_double;
339   case json_type_boolean:
340     return this->o.c_boolean;
341   case json_type_string:
342     if(sscanf(this->o.c_string, "%d", &cint) == 1) return cint;
343   default:
344     return 0;
345   }
346 }
347
348
349 /* json_object_double */
350
351 static int json_object_double_to_json_string(struct json_object* this,
352                                              struct printbuf *pb)
353 {
354   return sprintbuf(pb, "%lf", this->o.c_double);
355 }
356
357 struct json_object* json_object_new_double(double d)
358 {
359   struct json_object *this = json_object_new(json_type_double);
360   if(!this) return NULL;
361   this->_to_json_string = &json_object_double_to_json_string;
362   this->o.c_double = d;
363   return this;
364 }
365
366 double json_object_get_double(struct json_object *this)
367 {
368   double cdouble;
369
370   if(!this) return 0.0;
371   switch(this->o_type) {
372   case json_type_double:
373     return this->o.c_double;
374   case json_type_int:
375     return this->o.c_int;
376   case json_type_boolean:
377     return this->o.c_boolean;
378   case json_type_string:
379     if(sscanf(this->o.c_string, "%lf", &cdouble) == 1) return cdouble;
380   default:
381     return 0.0;
382   }
383 }
384
385
386 /* json_object_string */
387
388 static int json_object_string_to_json_string(struct json_object* this,
389                                              struct printbuf *pb)
390 {
391   sprintbuf(pb, "\"");
392   json_escape_str(pb, this->o.c_string);
393   sprintbuf(pb, "\"");
394   return 0;
395 }
396
397 static void json_object_string_delete(struct json_object* this)
398 {
399   free(this->o.c_string);
400   json_object_generic_delete(this);
401 }
402
403 struct json_object* json_object_new_string(char *s)
404 {
405   struct json_object *this = json_object_new(json_type_string);
406   if(!this) return NULL;
407   this->_delete = &json_object_string_delete;
408   this->_to_json_string = &json_object_string_to_json_string;
409   this->o.c_string = strdup(s);
410   return this;
411 }
412
413 struct json_object* json_object_new_string_len(char *s, int len)
414 {
415   struct json_object *this = json_object_new(json_type_string);
416   if(!this) return NULL;
417   this->_delete = &json_object_string_delete;
418   this->_to_json_string = &json_object_string_to_json_string;
419   this->o.c_string = strndup(s, len);
420   return this;
421 }
422
423 char* json_object_get_string(struct json_object *this)
424 {
425   if(!this) return NULL;
426   switch(this->o_type) {
427   case json_type_string:
428     return this->o.c_string;
429   default:
430     return json_object_to_json_string(this);
431   }
432 }
433
434
435 /* json_object_array */
436
437 static int json_object_array_to_json_string(struct json_object* this,
438                                             struct printbuf *pb)
439 {
440   sprintbuf(pb, "[");
441   for(int i=0; i < json_object_array_length(this); i++) {
442     if(i) sprintbuf(pb, ", ");
443     else sprintbuf(pb, " ");
444     struct json_object *val = json_object_array_get_idx(this, i);
445     if(val == NULL) sprintbuf(pb, "null");
446     else val->_to_json_string(val, pb);
447   }
448   return sprintbuf(pb, " ]");
449 }
450
451 static void json_object_array_entry_free(void *data)
452 {
453   json_object_put((struct json_object*)data);
454 }
455
456 static void json_object_array_delete(struct json_object* this)
457 {
458   array_list_free(this->o.c_array);
459   json_object_generic_delete(this);
460 }
461
462 struct json_object* json_object_new_array()
463 {
464   struct json_object *this = json_object_new(json_type_array);
465   if(!this) return NULL;
466   this->_delete = &json_object_array_delete;
467   this->_to_json_string = &json_object_array_to_json_string;
468   this->o.c_array = array_list_new(&json_object_array_entry_free);
469   return this;
470 }
471
472 struct array_list* json_object_get_array(struct json_object *this)
473 {
474   if(!this) return NULL;
475   switch(this->o_type) {
476   case json_type_array:
477     return this->o.c_array;
478   default:
479     return NULL;
480   }
481 }
482
483 int json_object_array_length(struct json_object *this)
484 {
485   return array_list_length(this->o.c_array);
486 }
487
488 int json_object_array_add(struct json_object *this,struct json_object *val)
489 {
490   return array_list_add(this->o.c_array, val);
491 }
492
493 int json_object_array_put_idx(struct json_object *this, int idx,
494                               struct json_object *val)
495 {
496   return array_list_put_idx(this->o.c_array, idx, val);
497 }
498
499 struct json_object* json_object_array_get_idx(struct json_object *this,
500                                               int idx)
501 {
502   return (struct json_object*)array_list_get_idx(this->o.c_array, idx);
503 }
504