Merge branch 'master' of ssh://git.samba.org/data/git/samba into selftest
[samba.git] / source4 / lib / json / json_object.c
1 /*
2  * $Id: json_object.c,v 1.15 2006/01/30 23:07:57 mclark Exp $
3  *
4  * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
5  * Michael Clark <michael@metaparadigm.com>
6  *
7  * This library is free software; you can redistribute it and/or modify
8  * it under the terms of the MIT license. See COPYING for details.
9  *
10  */
11
12 #include "config.h"
13
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17
18 #include "debug.h"
19 #include "printbuf.h"
20 #include "linkhash.h"
21 #include "arraylist.h"
22 #include "json_object.h"
23 #include "json_object_private.h"
24 #include "json_tokener.h"
25
26 #if !HAVE_STRNDUP
27   char* strndup(const char* str, size_t n);
28 #endif /* !HAVE_STRNDUP */
29
30 /* #define REFCOUNT_DEBUG 1 */
31
32 char *json_number_chars = "0123456789.+-e";
33 char *json_hex_chars = "0123456789abcdef";
34
35 #ifdef REFCOUNT_DEBUG
36 static char* json_type_name[] = {
37   "null",
38   "boolean",
39   "double",
40   "int",
41   "object",
42   "array",
43   "string",
44 };
45 #endif /* REFCOUNT_DEBUG */
46
47 static void json_object_generic_delete(struct json_object* this);
48 static struct json_object* json_object_new(enum json_type o_type);
49
50
51 /* ref count debugging */
52
53 #ifdef REFCOUNT_DEBUG
54
55 static struct lh_table *json_object_table;
56
57 static void json_object_init() __attribute__ ((constructor));
58 static void json_object_init() {
59   mc_debug("json_object_init: creating object table\n");
60   json_object_table = lh_kptr_table_new(128, "json_object_table", NULL);
61 }
62
63 static void json_object_fini() __attribute__ ((destructor));
64 static void json_object_fini() {
65   struct lh_entry *ent;
66   if(mc_get_debug() && json_object_table->count) {
67     mc_debug("json_object_fini: %d referenced objects at exit\n",
68              json_object_table->count);
69     lh_foreach(json_object_table, ent) {
70       struct json_object* obj = (struct json_object*)ent->v;
71       mc_debug("\t%s:%p\n", json_type_name[obj->o_type], obj);
72     }
73   }
74   mc_debug("json_object_fini: freeing object table\n");
75   lh_table_free(json_object_table);
76 }
77 #endif /* REFCOUNT_DEBUG */
78
79
80 /* string escaping */
81
82 static int json_escape_str(struct printbuf *pb, char *str)
83 {
84   int pos = 0, start_offset = 0;
85   unsigned char c;
86   do {
87     c = str[pos];
88     switch(c) {
89     case '\0':
90       break;
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 < ' ') {
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 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 /* REFCOUNT_DEBUG */
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 /* REFCOUNT_DEBUG */
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   struct json_object_iter iter;
204   sprintbuf(pb, "{");
205
206   /* CAW: scope operator to make ANSI correctness */
207   /* CAW: switched to json_object_object_foreachC which uses an iterator struct */
208         json_object_object_foreachC(this, iter) {
209                         if(i) sprintbuf(pb, ",");
210                         sprintbuf(pb, " \"");
211                         json_escape_str(pb, iter.key);
212                         sprintbuf(pb, "\": ");
213                         if(iter.val == NULL) sprintbuf(pb, "null");
214                         else iter.val->_to_json_string(iter.val, pb);
215                         i++;
216         }
217
218   return sprintbuf(pb, " }");
219 }
220
221 static void json_object_lh_entry_free(struct lh_entry *ent)
222 {
223   free(ent->k);
224   json_object_put((struct json_object*)ent->v);
225 }
226
227 static void json_object_object_delete(struct json_object* this)
228 {
229   lh_table_free(this->o.c_object);
230   json_object_generic_delete(this);
231 }
232
233 struct json_object* json_object_new_object()
234 {
235   struct json_object *this = json_object_new(json_type_object);
236   if(!this) return NULL;
237   this->_delete = &json_object_object_delete;
238   this->_to_json_string = &json_object_object_to_json_string;
239   this->o.c_object = lh_kchar_table_new(JSON_OBJECT_DEF_HASH_ENTIRES,
240                                         NULL, &json_object_lh_entry_free);
241   return this;
242 }
243
244 struct lh_table* json_object_get_object(struct json_object *this)
245 {
246   if(!this) return NULL;
247   switch(this->o_type) {
248   case json_type_object:
249     return this->o.c_object;
250   default:
251     return NULL;
252   }
253 }
254
255 void json_object_object_add(struct json_object* this, char *key,
256                             struct json_object *val)
257 {
258   lh_table_delete(this->o.c_object, key);
259   lh_table_insert(this->o.c_object, strdup(key), val);
260 }
261
262 struct json_object* json_object_object_get(struct json_object* this, char *key)
263 {
264   return (struct json_object*) lh_table_lookup(this->o.c_object, key);
265 }
266
267 void json_object_object_del(struct json_object* this, char *key)
268 {
269   lh_table_delete(this->o.c_object, key);
270 }
271
272
273 /* json_object_boolean */
274
275 static int json_object_boolean_to_json_string(struct json_object* this,
276                                               struct printbuf *pb)
277 {
278   if(this->o.c_boolean) return sprintbuf(pb, "true");
279   else return sprintbuf(pb, "false");
280 }
281
282 struct json_object* json_object_new_boolean(boolean b)
283 {
284   struct json_object *this = json_object_new(json_type_boolean);
285   if(!this) return NULL;
286   this->_to_json_string = &json_object_boolean_to_json_string;
287   this->o.c_boolean = b;
288   return this;
289 }
290
291 boolean json_object_get_boolean(struct json_object *this)
292 {
293   if(!this) return FALSE;
294   switch(this->o_type) {
295   case json_type_boolean:
296     return this->o.c_boolean;
297   case json_type_int:
298     return (this->o.c_int != 0);
299   case json_type_double:
300     return (this->o.c_double != 0);
301   case json_type_string:
302     if(strlen(this->o.c_string)) return TRUE;
303   default:
304     return TRUE;
305   }
306 }
307
308
309 /* json_object_int */
310
311 static int json_object_int_to_json_string(struct json_object* this,
312                                           struct printbuf *pb)
313 {
314   return sprintbuf(pb, "%d", this->o.c_int);
315 }
316
317 struct json_object* json_object_new_int(int i)
318 {
319   struct json_object *this = json_object_new(json_type_int);
320   if(!this) return NULL;
321   this->_to_json_string = &json_object_int_to_json_string;
322   this->o.c_int = i;
323   return this;
324 }
325
326 int json_object_get_int(struct json_object *this)
327 {
328   int cint;
329
330   if(!this) return 0;
331   switch(this->o_type) {
332   case json_type_int:
333     return this->o.c_int;
334   case json_type_double:
335     return (int)this->o.c_double;
336   case json_type_boolean:
337     return this->o.c_boolean;
338   case json_type_string:
339     if(sscanf(this->o.c_string, "%d", &cint) == 1) return cint;
340   default:
341     return 0;
342   }
343 }
344
345
346 /* json_object_double */
347
348 static int json_object_double_to_json_string(struct json_object* this,
349                                              struct printbuf *pb)
350 {
351   return sprintbuf(pb, "%lf", this->o.c_double);
352 }
353
354 struct json_object* json_object_new_double(double d)
355 {
356   struct json_object *this = json_object_new(json_type_double);
357   if(!this) return NULL;
358   this->_to_json_string = &json_object_double_to_json_string;
359   this->o.c_double = d;
360   return this;
361 }
362
363 double json_object_get_double(struct json_object *this)
364 {
365   double cdouble;
366
367   if(!this) return 0.0;
368   switch(this->o_type) {
369   case json_type_double:
370     return this->o.c_double;
371   case json_type_int:
372     return this->o.c_int;
373   case json_type_boolean:
374     return this->o.c_boolean;
375   case json_type_string:
376     if(sscanf(this->o.c_string, "%lf", &cdouble) == 1) return cdouble;
377   default:
378     return 0.0;
379   }
380 }
381
382
383 /* json_object_string */
384
385 static int json_object_string_to_json_string(struct json_object* this,
386                                              struct printbuf *pb)
387 {
388   sprintbuf(pb, "\"");
389   json_escape_str(pb, this->o.c_string);
390   sprintbuf(pb, "\"");
391   return 0;
392 }
393
394 static void json_object_string_delete(struct json_object* this)
395 {
396   free(this->o.c_string);
397   json_object_generic_delete(this);
398 }
399
400 struct json_object* json_object_new_string(char *s)
401 {
402   struct json_object *this = json_object_new(json_type_string);
403   if(!this) return NULL;
404   this->_delete = &json_object_string_delete;
405   this->_to_json_string = &json_object_string_to_json_string;
406   this->o.c_string = strdup(s);
407   return this;
408 }
409
410 struct json_object* json_object_new_string_len(char *s, int len)
411 {
412   struct json_object *this = json_object_new(json_type_string);
413   if(!this) return NULL;
414   this->_delete = &json_object_string_delete;
415   this->_to_json_string = &json_object_string_to_json_string;
416   this->o.c_string = strndup(s, len);
417   return this;
418 }
419
420 char* json_object_get_string(struct json_object *this)
421 {
422   if(!this) return NULL;
423   switch(this->o_type) {
424   case json_type_string:
425     return this->o.c_string;
426   default:
427     return json_object_to_json_string(this);
428   }
429 }
430
431
432 /* json_object_array */
433
434 static int json_object_array_to_json_string(struct json_object* this,
435                                             struct printbuf *pb)
436 {
437   int i;
438   sprintbuf(pb, "[");
439   for(i=0; i < json_object_array_length(this); i++) {
440           struct json_object *val;
441           if(i) { sprintbuf(pb, ", "); }
442           else { sprintbuf(pb, " "); }
443
444       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