]> git.evergreen-ils.org Git - Evergreen.git/blob - OpenSRF/src/libjson/json_object.c
updated to newest code, made my usual usability changes.
[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 "libjson/debug.h"
24 #include "libjson/printbuf.h"
25 #include "libjson/linkhash.h"
26 #include "libjson/arraylist.h"
27 #include "libjson/json_object.h"
28 #include "libjson/ossupport.h"
29 #include "libjson/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       if(pos - start_offset > 0)
97         printbuf_memappend(pb, str + start_offset, pos - start_offset);
98       if(c == '\b') printbuf_memappend(pb, "\\b", 2);
99       else if(c == '\n') printbuf_memappend(pb, "\\n", 2);
100       else if(c == '\r') printbuf_memappend(pb, "\\r", 2);
101       else if(c == '\t') printbuf_memappend(pb, "\\t", 2);
102       else if(c == '"') printbuf_memappend(pb, "\\\"", 2);
103       start_offset = ++pos;
104       break;
105     default:
106       if(c && c < ' ') {
107         if(pos - start_offset > 0)
108           printbuf_memappend(pb, str + start_offset, pos - start_offset);
109         sprintbuf(pb, "\\u00%c%c",
110                   json_hex_chars[c >> 4],
111                   json_hex_chars[c & 0xf]);
112         start_offset = ++pos;
113       } else if(c) pos++;
114     }
115   } while(c);
116   if(pos - start_offset > 0)
117     printbuf_memappend(pb, str + start_offset, pos - start_offset);
118   return 0;
119 }
120
121
122 /* reference counting */
123
124 extern struct json_object* json_object_get(struct json_object *this)
125 {
126   if(this) {
127     this->_ref_count++;
128   }
129   return this;
130 }
131
132 extern void json_object_put(struct json_object *this)
133 {
134   if(this) {
135     this->_ref_count--;
136     if(!this->_ref_count) this->_delete(this);
137   }
138 }
139
140
141 /* generic object construction and destruction parts */
142
143 static void json_object_generic_delete(struct json_object* this)
144 {
145 #ifdef REFCOUNT_DEBUG
146   mc_debug("json_object_delete_%s: %p\n",
147            json_type_name[this->o_type], this);
148   lh_table_delete(json_object_table, this);
149 #endif
150   printbuf_free(this->_pb);
151   free(this);
152 }
153
154 static struct json_object* json_object_new(enum json_type o_type)
155 {
156   struct json_object *this = calloc(sizeof(struct json_object), 1);
157   if(!this) return NULL;
158   this->o_type = o_type;
159   this->_ref_count = 1;
160   this->_delete = &json_object_generic_delete;
161 #ifdef REFCOUNT_DEBUG
162   lh_table_insert(json_object_table, this, this);
163   mc_debug("json_object_new_%s: %p\n", json_type_name[this->o_type], this);
164 #endif
165   return this;
166 }
167
168
169 /* type checking functions */
170
171 int json_object_is_type(struct json_object *this, enum json_type type)
172 {
173   return (this->o_type == type);
174 }
175
176 enum json_type json_object_get_type(struct json_object *this)
177 {
178   return this->o_type;
179 }
180
181
182 /* json_object_to_json_string */
183
184 char* json_object_to_json_string(struct json_object *this)
185 {
186   if(!this) return "null";
187   if(!this->_pb) {
188     if(!(this->_pb = printbuf_new())) return NULL;
189   } else {
190     printbuf_reset(this->_pb);
191   }
192   if(this->_to_json_string(this, this->_pb) < 0) return NULL;
193   return this->_pb->buf;
194 }
195
196
197 /* json_object_object */
198
199 static int json_object_object_to_json_string(struct json_object* this,
200                                              struct printbuf *pb)
201 {
202   int i=0;
203   sprintbuf(pb, "{");
204   json_object_object_foreach(this, key, val) {
205     if(i) sprintbuf(pb, ",");
206     sprintbuf(pb, " \"");
207     json_escape_str(pb, key);
208     sprintbuf(pb, "\": ");
209     if(val == NULL) sprintbuf(pb, "null");
210     else val->_to_json_string(val, pb);
211     i++;
212   }
213   return sprintbuf(pb, " }");
214 }
215
216 static void json_object_lh_entry_free(struct lh_entry *ent)
217 {
218   free(ent->k);
219   json_object_put((struct json_object*)ent->v);
220 }
221
222 static void json_object_object_delete(struct json_object* this)
223 {
224   lh_table_free(this->o.c_object);
225   json_object_generic_delete(this);
226 }
227
228 struct json_object* json_object_new_object()
229 {
230   struct json_object *this = json_object_new(json_type_object);
231   if(!this) return NULL;
232   this->_delete = &json_object_object_delete;
233   this->_to_json_string = &json_object_object_to_json_string;
234   this->o.c_object = lh_kchar_table_new(JSON_OBJECT_DEF_HASH_ENTIRES,
235                                         NULL, &json_object_lh_entry_free);
236   return this;
237 }
238
239 struct lh_table* json_object_get_object(struct json_object *this)
240 {
241   if(!this) return NULL;
242   switch(this->o_type) {
243   case json_type_object:
244     return this->o.c_object;
245   default:
246     return NULL;
247   }
248 }
249
250 void json_object_object_add(struct json_object* this, char *key,
251                             struct json_object *val)
252 {
253   lh_table_delete(this->o.c_object, key);
254   lh_table_insert(this->o.c_object, strdup(key), val);
255 }
256
257 struct json_object* json_object_object_get(struct json_object* this, char *key)
258 {
259   return (struct json_object*) lh_table_lookup(this->o.c_object, key);
260 }
261
262 void json_object_object_del(struct json_object* this, char *key)
263 {
264   lh_table_delete(this->o.c_object, key);
265 }
266
267
268 /* json_object_boolean */
269
270 static int json_object_boolean_to_json_string(struct json_object* this,
271                                               struct printbuf *pb)
272 {
273   if(this->o.c_boolean) return sprintbuf(pb, "true");
274   else return sprintbuf(pb, "false");
275 }
276
277 struct json_object* json_object_new_boolean(boolean b)
278 {
279   struct json_object *this = json_object_new(json_type_boolean);
280   if(!this) return NULL;
281   this->_to_json_string = &json_object_boolean_to_json_string;
282   this->o.c_boolean = b;
283   return this;
284 }
285
286 boolean json_object_get_boolean(struct json_object *this)
287 {
288   if(!this) return FALSE;
289   switch(this->o_type) {
290   case json_type_boolean:
291     return this->o.c_boolean;
292   case json_type_int:
293     return (this->o.c_int != 0);
294   case json_type_double:
295     return (this->o.c_double != 0);
296   case json_type_string:
297     if(strlen(this->o.c_string)) return TRUE;
298   default:
299     return TRUE;
300   }
301 }
302
303
304 /* json_object_int */
305
306 static int json_object_int_to_json_string(struct json_object* this,
307                                           struct printbuf *pb)
308 {
309   return sprintbuf(pb, "%d", this->o.c_int);
310 }
311
312 struct json_object* json_object_new_int(int i)
313 {
314   struct json_object *this = json_object_new(json_type_int);
315   if(!this) return NULL;
316   this->_to_json_string = &json_object_int_to_json_string;
317   this->o.c_int = i;
318   return this;
319 }
320
321 int json_object_get_int(struct json_object *this)
322 {
323   int cint;
324
325   if(!this) return 0;
326   switch(this->o_type) {
327   case json_type_int:
328     return this->o.c_int;
329   case json_type_double:
330     return this->o.c_double;
331   case json_type_boolean:
332     return this->o.c_boolean;
333   case json_type_string:
334     if(sscanf(this->o.c_string, "%d", &cint) == 1) return cint;
335   default:
336     return 0;
337   }
338 }
339
340
341 /* json_object_double */
342
343 static int json_object_double_to_json_string(struct json_object* this,
344                                              struct printbuf *pb)
345 {
346   return sprintbuf(pb, "%lf", this->o.c_double);
347 }
348
349 struct json_object* json_object_new_double(double d)
350 {
351   struct json_object *this = json_object_new(json_type_double);
352   if(!this) return NULL;
353   this->_to_json_string = &json_object_double_to_json_string;
354   this->o.c_double = d;
355   return this;
356 }
357
358 double json_object_get_double(struct json_object *this)
359 {
360   double cdouble;
361
362   if(!this) return 0.0;
363   switch(this->o_type) {
364   case json_type_double:
365     return this->o.c_double;
366   case json_type_int:
367     return this->o.c_int;
368   case json_type_boolean:
369     return this->o.c_boolean;
370   case json_type_string:
371     if(sscanf(this->o.c_string, "%lf", &cdouble) == 1) return cdouble;
372   default:
373     return 0.0;
374   }
375 }
376
377
378 /* json_object_string */
379
380 static int json_object_string_to_json_string(struct json_object* this,
381                                              struct printbuf *pb)
382 {
383   sprintbuf(pb, "\"");
384   json_escape_str(pb, this->o.c_string);
385   sprintbuf(pb, "\"");
386   return 0;
387 }
388
389 static void json_object_string_delete(struct json_object* this)
390 {
391   free(this->o.c_string);
392   json_object_generic_delete(this);
393 }
394
395 struct json_object* json_object_new_string(char *s)
396 {
397   struct json_object *this = json_object_new(json_type_string);
398   if(!this) return NULL;
399   this->_delete = &json_object_string_delete;
400   this->_to_json_string = &json_object_string_to_json_string;
401   this->o.c_string = strdup(s);
402   return this;
403 }
404
405 struct json_object* json_object_new_string_len(char *s, int len)
406 {
407   struct json_object *this = json_object_new(json_type_string);
408   if(!this) return NULL;
409   this->_delete = &json_object_string_delete;
410   this->_to_json_string = &json_object_string_to_json_string;
411   this->o.c_string = strndup(s, len);
412   return this;
413 }
414
415 char* json_object_get_string(struct json_object *this)
416 {
417   if(!this) return NULL;
418   switch(this->o_type) {
419   case json_type_string:
420     return this->o.c_string;
421   default:
422     return json_object_to_json_string(this);
423   }
424 }
425
426
427 /* json_object_array */
428
429 static int json_object_array_to_json_string(struct json_object* this,
430                                             struct printbuf *pb)
431 {
432   sprintbuf(pb, "[");
433   for(int i=0; i < json_object_array_length(this); i++) {
434     if(i) sprintbuf(pb, ", ");
435     else sprintbuf(pb, " ");
436     struct json_object *val = json_object_array_get_idx(this, i);
437     if(val == NULL) sprintbuf(pb, "null");
438     else val->_to_json_string(val, pb);
439   }
440   return sprintbuf(pb, " ]");
441 }
442
443 static void json_object_array_entry_free(void *data)
444 {
445   json_object_put((struct json_object*)data);
446 }
447
448 static void json_object_array_delete(struct json_object* this)
449 {
450   array_list_free(this->o.c_array);
451   json_object_generic_delete(this);
452 }
453
454 struct json_object* json_object_new_array()
455 {
456   struct json_object *this = json_object_new(json_type_array);
457   if(!this) return NULL;
458   this->_delete = &json_object_array_delete;
459   this->_to_json_string = &json_object_array_to_json_string;
460   this->o.c_array = array_list_new(&json_object_array_entry_free);
461   return this;
462 }
463
464 struct array_list* json_object_get_array(struct json_object *this)
465 {
466   if(!this) return NULL;
467   switch(this->o_type) {
468   case json_type_array:
469     return this->o.c_array;
470   default:
471     return NULL;
472   }
473 }
474
475 int json_object_array_length(struct json_object *this)
476 {
477   return array_list_length(this->o.c_array);
478 }
479
480 int json_object_array_add(struct json_object *this,struct json_object *val)
481 {
482   return array_list_add(this->o.c_array, val);
483 }
484
485 int json_object_array_put_idx(struct json_object *this, int idx,
486                               struct json_object *val)
487 {
488   return array_list_put_idx(this->o.c_array, idx, val);
489 }
490
491 struct json_object* json_object_array_get_idx(struct json_object *this,
492                                               int idx)
493 {
494   return (struct json_object*)array_list_get_idx(this->o.c_array, idx);
495 }
496