add JSON utility class
[mech_eap.orig] / util_json.cpp
1 /*
2  * Copyright (c) 2011, JANET(UK)
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  *
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * 3. Neither the name of JANET(UK) nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32
33 /*
34  * JSONObject utilities.
35  */
36
37 #include "gssapiP_eap.h"
38
39 #include <typeinfo>
40 #include <string>
41 #include <sstream>
42 #include <exception>
43 #include <stdexcept>
44 #include <new>
45
46 #define JSON_INIT(obj) do {                                     \
47         if ((obj) == NULL)                                      \
48             throw new std::bad_alloc;                           \
49         m_obj = (obj);                                          \
50     } while (0)
51
52 #define JSON_CHECK_CONTAINER() do {                             \
53         if (!json_is_object(m_obj) && !json_is_array(m_obj)) {  \
54             std::string s("JSONObject object is not a container");   \
55             throw new std::runtime_error(s);                    \
56         }                                                       \
57     } while (0)
58 #define JSON_CHECK_OBJECT() do {                                \
59         if (!json_is_object(m_obj)) {                           \
60             std::string s("JSONObject object is not a dictionary");   \
61             throw new std::runtime_error(s);                    \
62         }                                                       \
63     } while (0)
64
65 #define JSON_CHECK_ARRAY() do {                                 \
66         if (!json_is_array(m_obj)) {                            \
67             std::string s("JSONObject object is not an array");       \
68             throw new std::runtime_error(s);                    \
69         }                                                       \
70     } while (0)
71
72 #define JSON_CHECK(s) do {              \
73         if ((s) != 0)                   \
74             throw new std::bad_alloc;   \
75     } while (0)
76
77 JSONObject
78 JSONObject::load(const char *input, size_t flags, json_error_t *error)
79 {
80     json_t *obj;
81
82     obj = json_loads(input, flags, error);
83
84     return JSONObject(obj, false);
85 }
86
87 JSONObject
88 JSONObject::load(FILE *fp, size_t flags, json_error_t *error)
89 {
90     json_t *obj;
91
92     obj = json_loadf(fp, flags, error);
93
94     return JSONObject(obj, false);
95 }
96
97 char *
98 JSONObject::dump(size_t flags) const
99 {
100     char *s = json_dumps(m_obj, flags);
101
102     if (s == NULL)
103         throw new std::bad_alloc;
104
105     return s;
106 }
107
108 void
109 JSONObject::dump(FILE *fp, size_t flags) const
110 {
111     int r = json_dumpf(m_obj, fp, flags);
112
113     if (r != 0)
114         throw new std::bad_alloc;
115 }
116
117 size_t
118 JSONObject::size(void) const
119 {
120     if (json_is_object(m_obj))
121         return json_object_size(m_obj);
122     else if (json_is_array(m_obj))
123         return json_array_size(m_obj);
124     else
125         return 0;
126 }
127
128 JSONObject::JSONObject(json_t *obj, bool retain)
129 {
130     if (retain)
131         json_incref(obj);
132     JSON_INIT(obj);
133 }
134
135 JSONObject::JSONObject(const char *value)
136 {
137     json_t *obj = json_string(value);
138
139     JSON_INIT(obj);
140 }
141
142 JSONObject::JSONObject(json_int_t value)
143 {
144     json_t *obj = json_integer(value);
145
146     JSON_INIT(obj);
147 }
148
149 JSONObject::JSONObject(double value)
150 {
151     json_t *obj = json_real(value);
152
153     JSON_INIT(obj);
154 }
155
156 JSONObject::JSONObject(bool value)
157 {
158     json_t *obj = value ? json_true() : json_false();
159
160     JSON_INIT(obj);
161 }
162
163 JSONObject::JSONObject(void)
164 {
165     json_t *obj = json_object();
166
167     JSON_INIT(obj);
168 }
169
170 JSONObject
171 JSONObject::object(void)
172 {
173     return JSONObject();
174 }
175
176 JSONObject
177 JSONObject::null(void)
178 {
179     return JSONObject(json_null(), false);
180 }
181
182 JSONObject
183 JSONObject::array(void)
184 {
185     return JSONObject(json_array(), false);
186 }
187
188 void
189 JSONObject::set(const char *key, JSONObject &value)
190 {
191     JSON_CHECK_OBJECT();
192     JSON_CHECK(json_object_set_new(m_obj, key, value.get()));
193 }
194
195 void
196 JSONObject::set(const char *key, const char *value)
197 {
198     JSONObject jobj(value);
199     set(key, jobj);
200 }
201
202 void
203 JSONObject::set(const char *key, json_int_t value)
204 {
205     JSONObject jobj(value);
206     set(key, jobj);
207 }
208
209 void
210 JSONObject::del(const char *key)
211 {
212     json_object_del(m_obj, key);
213 }
214
215 JSONObject
216 JSONObject::get(const char *key) const
217 {
218     json_t *obj;
219
220     obj = json_object_get(m_obj, key);
221     if (obj == NULL)
222         return JSONObject::null();
223
224     return JSONObject(obj, true);
225 }
226
227 JSONObject
228 JSONObject::get(size_t index) const
229 {
230     json_t *obj;
231
232     obj = json_array_get(m_obj, index);
233     if (obj == NULL)
234         return JSONObject::null();
235
236     return JSONObject(obj, true);
237 }
238
239 void
240 JSONObject::update(JSONObject &value)
241 {
242     JSON_CHECK_OBJECT();
243     json_t *other = value.get();
244     JSON_CHECK(json_object_update(m_obj, other));
245     json_decref(other);
246 }
247
248 JSONObject
249 JSONObject::operator[](size_t index) const
250 {
251     return get(index);
252 }
253
254 JSONObject
255 JSONObject::operator[](const char *key) const
256 {
257     return get(key);
258 }
259
260 void
261 JSONObject::append(JSONObject &value)
262 {
263     JSON_CHECK_ARRAY();
264     JSON_CHECK(json_array_append_new(m_obj, value.get()));
265 }
266
267 void
268 JSONObject::insert(size_t index, JSONObject &value)
269 {
270     JSON_CHECK_ARRAY();
271     JSON_CHECK(json_array_insert_new(m_obj, index, value.get()));
272 }
273
274 void
275 JSONObject::remove(size_t index)
276 {
277     JSON_CHECK_ARRAY();
278     JSON_CHECK(json_array_remove(m_obj, index));
279 }
280
281 void
282 JSONObject::clear(void)
283 {
284     JSON_CHECK_CONTAINER();
285
286     if (json_is_object(m_obj)) {
287         JSON_CHECK(json_object_clear(m_obj));
288     } else if (json_is_array(m_obj)) {
289         JSON_CHECK(json_array_clear(m_obj));
290     }
291 }
292
293 void
294 JSONObject::extend(JSONObject &value)
295 {
296     JSON_CHECK_ARRAY();
297     json_t *other = value.get();
298     JSON_CHECK(json_array_extend(m_obj, other));
299     json_decref(other);
300 }
301
302 const char *
303 JSONObject::string(void) const
304 {
305     return json_string_value(m_obj);
306 }
307
308 json_int_t
309 JSONObject::integer(void) const
310 {
311     return json_integer_value(m_obj);
312 }
313
314 double
315 JSONObject::real(void) const
316 {
317     return json_real_value(m_obj);
318 }
319
320 double
321 JSONObject::number(void) const
322 {
323     return json_number_value(m_obj);
324 }
325
326 bool
327 JSONObject::isnull(void) const
328 {
329     return json_is_null(m_obj);
330 }
331
332 JSONObject::JSONObject(DDF &ddf)
333 {
334     if (ddf.isstruct()) {
335         DDF elem = ddf.first();
336         JSONObject jobj = JSONObject::array();
337
338         while (!elem.isnull()) {
339             JSONObject jtmp(elem);
340             jobj.append(jtmp);
341             elem = ddf.next();
342         }
343     } else if (ddf.islist()) {
344         DDF elem = ddf.first();
345         JSONObject jobj = JSONObject::object();
346
347         while (!elem.isnull()) {
348             JSONObject jtmp(elem);
349             jobj.set(elem.name(), jtmp);
350             elem = ddf.next();
351         }
352     } else if (ddf.isstring()) {
353         JSONObject(ddf.string());
354     } else if (ddf.isint()) {
355         JSONObject((json_int_t)ddf.integer());
356     } else if (ddf.isfloat()) {
357         JSONObject(ddf.floating());
358     } else if (ddf.isempty() || ddf.ispointer()) {
359         JSONObject::object();
360     } else if (ddf.isnull()) {
361         JSONObject::null();
362     }
363
364     std::string s("Unbridgeable DDF object");
365     throw new std::runtime_error(s);
366 }
367
368 DDF
369 JSONObject::ddf(void) const
370 {
371     DDF ddf(NULL);
372
373     switch (type()) {
374     case JSON_OBJECT: {
375         JSONIterator iter = iterator();
376
377         do {
378             const char *key = iter.key();
379             DDF value = iter.value().ddf();
380             ddf.add(value.name(key));
381         } while (iter.next());
382         break;
383     }
384     case JSON_ARRAY: {
385         size_t i, nelems = size();
386
387         for (i = 0; i < nelems; i++) {
388             DDF value = get(i).ddf();
389             ddf.add(value);
390         }
391         break;
392     }
393     case JSON_STRING:
394         ddf.string(string());
395         break;
396     case JSON_INTEGER:
397         ddf.integer(integer());
398         break;
399     case JSON_REAL:
400         ddf.floating(real());
401         break;
402     case JSON_TRUE:
403         ddf.integer(1L);
404         break;
405     case JSON_FALSE:
406         ddf.integer(0L);
407         break;
408     case JSON_NULL:
409         break;
410     }
411
412     return DDF(NULL);
413 }
414
415 JSONIterator::JSONIterator(const JSONObject &obj)
416 {
417     m_obj = obj.get();
418     m_iter = json_object_iter(m_obj);
419 }
420
421 JSONIterator::~JSONIterator(void)
422 {
423     json_decref(m_obj);
424 }
425
426 const char *
427 JSONIterator::key(void) const
428 {
429     return json_object_iter_key(m_iter);
430 }
431
432 JSONObject
433 JSONIterator::value(void) const
434 {
435     return JSONObject(json_object_iter_value(m_iter));
436 }
437
438 bool
439 JSONIterator::next(void)
440 {
441     m_iter = json_object_iter_next(m_obj, m_iter);
442     return m_iter != NULL;
443 }