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