blob: d6c56dcc8659eb38b3afbe8f279656bccfd759d0 [file] [log] [blame]
Michael Clarkf0d08882007-03-13 08:26:18 +00001/*
Michael Clarka850f8e2007-03-13 08:26:26 +00002 * $Id: json_object.c,v 1.17 2006/07/25 03:24:50 mclark Exp $
Michael Clarkf0d08882007-03-13 08:26:18 +00003 *
Michael Clarkf6a6e482007-03-13 08:26:23 +00004 * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
Michael Clarkf0d08882007-03-13 08:26:18 +00005 * Michael Clark <michael@metaparadigm.com>
6 *
Michael Clarkf6a6e482007-03-13 08:26:23 +00007 * 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.
Michael Clarkf0d08882007-03-13 08:26:18 +00009 *
10 */
11
Michael Clark4504df72007-03-13 08:26:20 +000012#include "config.h"
13
Michael Clarkf0d08882007-03-13 08:26:18 +000014#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"
Michael Clark4504df72007-03-13 08:26:20 +000024#include "json_tokener.h"
Michael Clarkf0d08882007-03-13 08:26:18 +000025
Michael Clark837240f2007-03-13 08:26:25 +000026#if !HAVE_STRNDUP
27 char* strndup(const char* str, size_t n);
28#endif /* !HAVE_STRNDUP */
29
Michael Clark4504df72007-03-13 08:26:20 +000030/* #define REFCOUNT_DEBUG 1 */
Michael Clarkf0d08882007-03-13 08:26:18 +000031
32char *json_number_chars = "0123456789.+-e";
33char *json_hex_chars = "0123456789abcdef";
34
35#ifdef REFCOUNT_DEBUG
36static char* json_type_name[] = {
37 "null",
38 "boolean",
39 "double",
40 "int",
41 "object",
42 "array",
43 "string",
44};
Michael Clark4504df72007-03-13 08:26:20 +000045#endif /* REFCOUNT_DEBUG */
Michael Clarkf0d08882007-03-13 08:26:18 +000046
47static void json_object_generic_delete(struct json_object* this);
48static struct json_object* json_object_new(enum json_type o_type);
49
50
51/* ref count debugging */
52
53#ifdef REFCOUNT_DEBUG
54
55static struct lh_table *json_object_table;
56
57static void json_object_init() __attribute__ ((constructor));
58static 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
63static void json_object_fini() __attribute__ ((destructor));
64static 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}
Michael Clark4504df72007-03-13 08:26:20 +000077#endif /* REFCOUNT_DEBUG */
Michael Clarkf0d08882007-03-13 08:26:18 +000078
79
80/* string escaping */
81
82static int json_escape_str(struct printbuf *pb, char *str)
83{
84 int pos = 0, start_offset = 0;
Michael Clark837240f2007-03-13 08:26:25 +000085 unsigned char c;
Michael Clarkf0d08882007-03-13 08:26:18 +000086 do {
87 c = str[pos];
88 switch(c) {
Michael Clark837240f2007-03-13 08:26:25 +000089 case '\0':
90 break;
Michael Clarkf0d08882007-03-13 08:26:18 +000091 case '\b':
92 case '\n':
93 case '\r':
94 case '\t':
Michael Clark4504df72007-03-13 08:26:20 +000095 case '"':
Michael Clarka850f8e2007-03-13 08:26:26 +000096 case '\\':
97 case '/':
Michael Clarkf0d08882007-03-13 08:26:18 +000098 if(pos - start_offset > 0)
99 printbuf_memappend(pb, str + start_offset, pos - start_offset);
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);
Michael Clark4504df72007-03-13 08:26:20 +0000104 else if(c == '"') printbuf_memappend(pb, "\\\"", 2);
Michael Clarka850f8e2007-03-13 08:26:26 +0000105 else if(c == '\\') printbuf_memappend(pb, "\\\\", 2);
106 else if(c == '/') printbuf_memappend(pb, "\\/", 2);
Michael Clarkf0d08882007-03-13 08:26:18 +0000107 start_offset = ++pos;
108 break;
109 default:
Michael Clark837240f2007-03-13 08:26:25 +0000110 if(c < ' ') {
Michael Clarkf0d08882007-03-13 08:26:18 +0000111 if(pos - start_offset > 0)
112 printbuf_memappend(pb, str + start_offset, pos - start_offset);
113 sprintbuf(pb, "\\u00%c%c",
114 json_hex_chars[c >> 4],
115 json_hex_chars[c & 0xf]);
116 start_offset = ++pos;
Michael Clark837240f2007-03-13 08:26:25 +0000117 } else pos++;
Michael Clarkf0d08882007-03-13 08:26:18 +0000118 }
119 } while(c);
120 if(pos - start_offset > 0)
121 printbuf_memappend(pb, str + start_offset, pos - start_offset);
122 return 0;
123}
124
125
126/* reference counting */
127
128extern struct json_object* json_object_get(struct json_object *this)
129{
130 if(this) {
131 this->_ref_count++;
132 }
133 return this;
134}
135
136extern void json_object_put(struct json_object *this)
137{
138 if(this) {
139 this->_ref_count--;
140 if(!this->_ref_count) this->_delete(this);
141 }
142}
143
144
145/* generic object construction and destruction parts */
146
147static void json_object_generic_delete(struct json_object* this)
148{
149#ifdef REFCOUNT_DEBUG
150 mc_debug("json_object_delete_%s: %p\n",
151 json_type_name[this->o_type], this);
152 lh_table_delete(json_object_table, this);
Michael Clark4504df72007-03-13 08:26:20 +0000153#endif /* REFCOUNT_DEBUG */
Michael Clarkf0d08882007-03-13 08:26:18 +0000154 printbuf_free(this->_pb);
155 free(this);
156}
157
158static struct json_object* json_object_new(enum json_type o_type)
159{
160 struct json_object *this = calloc(sizeof(struct json_object), 1);
161 if(!this) return NULL;
162 this->o_type = o_type;
163 this->_ref_count = 1;
164 this->_delete = &json_object_generic_delete;
165#ifdef REFCOUNT_DEBUG
166 lh_table_insert(json_object_table, this, this);
167 mc_debug("json_object_new_%s: %p\n", json_type_name[this->o_type], this);
Michael Clark4504df72007-03-13 08:26:20 +0000168#endif /* REFCOUNT_DEBUG */
Michael Clarkf0d08882007-03-13 08:26:18 +0000169 return this;
170}
171
172
173/* type checking functions */
174
175int json_object_is_type(struct json_object *this, enum json_type type)
176{
177 return (this->o_type == type);
178}
179
180enum json_type json_object_get_type(struct json_object *this)
181{
182 return this->o_type;
183}
184
185
186/* json_object_to_json_string */
187
188char* json_object_to_json_string(struct json_object *this)
189{
190 if(!this) return "null";
191 if(!this->_pb) {
192 if(!(this->_pb = printbuf_new())) return NULL;
193 } else {
194 printbuf_reset(this->_pb);
195 }
196 if(this->_to_json_string(this, this->_pb) < 0) return NULL;
197 return this->_pb->buf;
198}
199
200
201/* json_object_object */
202
203static int json_object_object_to_json_string(struct json_object* this,
204 struct printbuf *pb)
205{
206 int i=0;
Michael Clark4504df72007-03-13 08:26:20 +0000207 struct json_object_iter iter;
Michael Clarkf0d08882007-03-13 08:26:18 +0000208 sprintbuf(pb, "{");
Michael Clark4504df72007-03-13 08:26:20 +0000209
210 /* CAW: scope operator to make ANSI correctness */
211 /* CAW: switched to json_object_object_foreachC which uses an iterator struct */
212 json_object_object_foreachC(this, iter) {
213 if(i) sprintbuf(pb, ",");
214 sprintbuf(pb, " \"");
215 json_escape_str(pb, iter.key);
216 sprintbuf(pb, "\": ");
217 if(iter.val == NULL) sprintbuf(pb, "null");
218 else iter.val->_to_json_string(iter.val, pb);
219 i++;
220 }
221
Michael Clarkf0d08882007-03-13 08:26:18 +0000222 return sprintbuf(pb, " }");
223}
224
225static void json_object_lh_entry_free(struct lh_entry *ent)
226{
227 free(ent->k);
228 json_object_put((struct json_object*)ent->v);
229}
230
231static void json_object_object_delete(struct json_object* this)
232{
233 lh_table_free(this->o.c_object);
234 json_object_generic_delete(this);
235}
236
237struct json_object* json_object_new_object()
238{
239 struct json_object *this = json_object_new(json_type_object);
240 if(!this) return NULL;
241 this->_delete = &json_object_object_delete;
242 this->_to_json_string = &json_object_object_to_json_string;
243 this->o.c_object = lh_kchar_table_new(JSON_OBJECT_DEF_HASH_ENTIRES,
244 NULL, &json_object_lh_entry_free);
245 return this;
246}
247
248struct lh_table* json_object_get_object(struct json_object *this)
249{
250 if(!this) return NULL;
251 switch(this->o_type) {
252 case json_type_object:
253 return this->o.c_object;
254 default:
255 return NULL;
256 }
257}
258
259void json_object_object_add(struct json_object* this, char *key,
260 struct json_object *val)
261{
262 lh_table_delete(this->o.c_object, key);
263 lh_table_insert(this->o.c_object, strdup(key), val);
264}
265
266struct json_object* json_object_object_get(struct json_object* this, char *key)
267{
268 return (struct json_object*) lh_table_lookup(this->o.c_object, key);
269}
270
271void json_object_object_del(struct json_object* this, char *key)
272{
273 lh_table_delete(this->o.c_object, key);
274}
275
276
277/* json_object_boolean */
278
279static int json_object_boolean_to_json_string(struct json_object* this,
280 struct printbuf *pb)
281{
282 if(this->o.c_boolean) return sprintbuf(pb, "true");
283 else return sprintbuf(pb, "false");
284}
285
286struct json_object* json_object_new_boolean(boolean b)
287{
288 struct json_object *this = json_object_new(json_type_boolean);
289 if(!this) return NULL;
290 this->_to_json_string = &json_object_boolean_to_json_string;
291 this->o.c_boolean = b;
292 return this;
293}
294
295boolean json_object_get_boolean(struct json_object *this)
296{
297 if(!this) return FALSE;
298 switch(this->o_type) {
299 case json_type_boolean:
300 return this->o.c_boolean;
301 case json_type_int:
302 return (this->o.c_int != 0);
303 case json_type_double:
304 return (this->o.c_double != 0);
305 case json_type_string:
306 if(strlen(this->o.c_string)) return TRUE;
307 default:
308 return TRUE;
309 }
310}
311
312
313/* json_object_int */
314
315static int json_object_int_to_json_string(struct json_object* this,
316 struct printbuf *pb)
317{
318 return sprintbuf(pb, "%d", this->o.c_int);
319}
320
321struct json_object* json_object_new_int(int i)
322{
323 struct json_object *this = json_object_new(json_type_int);
324 if(!this) return NULL;
325 this->_to_json_string = &json_object_int_to_json_string;
326 this->o.c_int = i;
327 return this;
328}
329
330int json_object_get_int(struct json_object *this)
331{
332 int cint;
333
334 if(!this) return 0;
335 switch(this->o_type) {
336 case json_type_int:
337 return this->o.c_int;
338 case json_type_double:
Michael Clark4504df72007-03-13 08:26:20 +0000339 return (int)this->o.c_double;
Michael Clarkf0d08882007-03-13 08:26:18 +0000340 case json_type_boolean:
341 return this->o.c_boolean;
342 case json_type_string:
343 if(sscanf(this->o.c_string, "%d", &cint) == 1) return cint;
344 default:
345 return 0;
346 }
347}
348
349
350/* json_object_double */
351
352static int json_object_double_to_json_string(struct json_object* this,
353 struct printbuf *pb)
354{
355 return sprintbuf(pb, "%lf", this->o.c_double);
356}
357
358struct json_object* json_object_new_double(double d)
359{
360 struct json_object *this = json_object_new(json_type_double);
361 if(!this) return NULL;
362 this->_to_json_string = &json_object_double_to_json_string;
363 this->o.c_double = d;
364 return this;
365}
366
367double json_object_get_double(struct json_object *this)
368{
369 double cdouble;
370
371 if(!this) return 0.0;
372 switch(this->o_type) {
373 case json_type_double:
374 return this->o.c_double;
375 case json_type_int:
376 return this->o.c_int;
377 case json_type_boolean:
378 return this->o.c_boolean;
379 case json_type_string:
380 if(sscanf(this->o.c_string, "%lf", &cdouble) == 1) return cdouble;
381 default:
382 return 0.0;
383 }
384}
385
386
387/* json_object_string */
388
389static int json_object_string_to_json_string(struct json_object* this,
390 struct printbuf *pb)
391{
392 sprintbuf(pb, "\"");
393 json_escape_str(pb, this->o.c_string);
394 sprintbuf(pb, "\"");
395 return 0;
396}
397
398static void json_object_string_delete(struct json_object* this)
399{
400 free(this->o.c_string);
401 json_object_generic_delete(this);
402}
403
404struct json_object* json_object_new_string(char *s)
405{
406 struct json_object *this = json_object_new(json_type_string);
407 if(!this) return NULL;
408 this->_delete = &json_object_string_delete;
409 this->_to_json_string = &json_object_string_to_json_string;
410 this->o.c_string = strdup(s);
411 return this;
412}
413
414struct json_object* json_object_new_string_len(char *s, int len)
415{
416 struct json_object *this = json_object_new(json_type_string);
417 if(!this) return NULL;
418 this->_delete = &json_object_string_delete;
419 this->_to_json_string = &json_object_string_to_json_string;
420 this->o.c_string = strndup(s, len);
421 return this;
422}
423
424char* json_object_get_string(struct json_object *this)
425{
426 if(!this) return NULL;
427 switch(this->o_type) {
428 case json_type_string:
429 return this->o.c_string;
430 default:
431 return json_object_to_json_string(this);
432 }
433}
434
435
436/* json_object_array */
437
438static int json_object_array_to_json_string(struct json_object* this,
439 struct printbuf *pb)
440{
Michael Clark4504df72007-03-13 08:26:20 +0000441 int i;
Michael Clarkf0d08882007-03-13 08:26:18 +0000442 sprintbuf(pb, "[");
Michael Clark4504df72007-03-13 08:26:20 +0000443 for(i=0; i < json_object_array_length(this); i++) {
444 struct json_object *val;
445 if(i) { sprintbuf(pb, ", "); }
446 else { sprintbuf(pb, " "); }
447
448 val = json_object_array_get_idx(this, i);
449 if(val == NULL) { sprintbuf(pb, "null"); }
450 else { val->_to_json_string(val, pb); }
Michael Clarkf0d08882007-03-13 08:26:18 +0000451 }
452 return sprintbuf(pb, " ]");
453}
454
455static void json_object_array_entry_free(void *data)
456{
457 json_object_put((struct json_object*)data);
458}
459
460static void json_object_array_delete(struct json_object* this)
461{
462 array_list_free(this->o.c_array);
463 json_object_generic_delete(this);
464}
465
466struct json_object* json_object_new_array()
467{
468 struct json_object *this = json_object_new(json_type_array);
469 if(!this) return NULL;
470 this->_delete = &json_object_array_delete;
471 this->_to_json_string = &json_object_array_to_json_string;
472 this->o.c_array = array_list_new(&json_object_array_entry_free);
473 return this;
474}
475
476struct array_list* json_object_get_array(struct json_object *this)
477{
478 if(!this) return NULL;
479 switch(this->o_type) {
480 case json_type_array:
481 return this->o.c_array;
482 default:
483 return NULL;
484 }
485}
486
487int json_object_array_length(struct json_object *this)
488{
489 return array_list_length(this->o.c_array);
490}
491
492int json_object_array_add(struct json_object *this,struct json_object *val)
493{
494 return array_list_add(this->o.c_array, val);
495}
496
497int json_object_array_put_idx(struct json_object *this, int idx,
498 struct json_object *val)
499{
500 return array_list_put_idx(this->o.c_array, idx, val);
501}
502
503struct json_object* json_object_array_get_idx(struct json_object *this,
504 int idx)
505{
506 return (struct json_object*)array_list_get_idx(this->o.c_array, idx);
507}
508