make possible build without OpenSAML and/or Shib
[moonshot.git] / moonshot / mech_eap / 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 <new>
44
45 #define JSON_INIT(obj) do {                                     \
46         if ((obj) == NULL)                                      \
47             throw std::bad_alloc();                             \
48         m_obj = (obj);                                          \
49     } while (0)
50
51 #define JSON_CHECK_CONTAINER() do {                             \
52         if (!json_is_object(m_obj) && !json_is_array(m_obj)) {  \
53             std::string s("JSONObject is not a container");     \
54             throw JSONException(m_obj);                         \
55         }                                                       \
56     } while (0)
57
58 #define JSON_CHECK_OBJECT() do {                                \
59         if (!json_is_object(m_obj)) {                           \
60             std::string s("JSONObject is not a dictionary");    \
61             throw JSONException(m_obj, JSON_OBJECT);            \
62         }                                                       \
63     } while (0)
64
65 #define JSON_CHECK_ARRAY() do {                                 \
66         if (!json_is_array(m_obj)) {                            \
67             throw JSONException(m_obj, JSON_ARRAY);             \
68         }                                                       \
69     } while (0)
70
71 #define JSON_CHECK(s) do {                                      \
72         if ((s) != 0)                                           \
73             throw JSONException();                              \
74     } while (0)
75
76 JSONObject
77 JSONObject::load(const char *input, size_t flags, json_error_t *error)
78 {
79     json_t *obj;
80
81     obj = json_loads(input, flags, error);
82
83     return JSONObject(obj, false);
84 }
85
86 JSONObject
87 JSONObject::load(FILE *fp, size_t flags, json_error_t *error)
88 {
89     json_t *obj;
90
91     obj = json_loadf(fp, flags, error);
92
93     return JSONObject(obj, false);
94 }
95
96 char *
97 JSONObject::dump(size_t flags) const
98 {
99     char *s = json_dumps(m_obj, flags);
100
101     if (s == NULL)
102         throw std::bad_alloc();
103
104     return s;
105 }
106
107 void
108 JSONObject::dump(FILE *fp, size_t flags) const
109 {
110     int r = json_dumpf(m_obj, fp, flags);
111
112     if (r != 0)
113         throw std::bad_alloc();
114 }
115
116 size_t
117 JSONObject::size(void) const
118 {
119     if (json_is_object(m_obj))
120         return json_object_size(m_obj);
121     else if (json_is_array(m_obj))
122         return json_array_size(m_obj);
123     else
124         return 0;
125 }
126
127 JSONObject::JSONObject(json_t *obj, bool retain)
128 {
129     if (retain)
130         json_incref(obj);
131     JSON_INIT(obj);
132 }
133
134 JSONObject::JSONObject(const char *value)
135 {
136     json_t *obj = json_string(value);
137
138     JSON_INIT(obj);
139 }
140
141 JSONObject::JSONObject(json_int_t value)
142 {
143     json_t *obj = json_integer(value);
144
145     JSON_INIT(obj);
146 }
147
148 JSONObject::JSONObject(double value)
149 {
150     json_t *obj = json_real(value);
151
152     JSON_INIT(obj);
153 }
154
155 JSONObject::JSONObject(bool value)
156 {
157     json_t *obj = value ? json_true() : json_false();
158
159     JSON_INIT(obj);
160 }
161
162 JSONObject::JSONObject(void)
163 {
164     json_t *obj = json_object();
165
166     JSON_INIT(obj);
167 }
168
169 JSONObject
170 JSONObject::object(void)
171 {
172     return JSONObject();
173 }
174
175 JSONObject
176 JSONObject::null(void)
177 {
178     return JSONObject(json_null(), false);
179 }
180
181 JSONObject
182 JSONObject::array(void)
183 {
184     return JSONObject(json_array(), false);
185 }
186
187 void
188 JSONObject::set(const char *key, JSONObject &value)
189 {
190     JSON_CHECK_OBJECT();
191     JSON_CHECK(json_object_set_new(m_obj, key, value.get()));
192 }
193
194 void
195 JSONObject::set(const char *key, const char *value)
196 {
197     JSONObject jobj(value);
198     set(key, jobj);
199 }
200
201 void
202 JSONObject::set(const char *key, json_int_t value)
203 {
204     JSONObject jobj(value);
205     set(key, jobj);
206 }
207
208 void
209 JSONObject::del(const char *key)
210 {
211     json_object_del(m_obj, key);
212 }
213
214 JSONObject
215 JSONObject::get(const char *key) const
216 {
217     json_t *obj;
218
219     obj = json_object_get(m_obj, key);
220     if (obj == NULL)
221         return JSONObject::null();
222
223     return JSONObject(obj, true);
224 }
225
226 JSONObject
227 JSONObject::get(size_t index) const
228 {
229     json_t *obj;
230
231     obj = json_array_get(m_obj, index);
232     if (obj == NULL)
233         return JSONObject::null();
234
235     return JSONObject(obj, true);
236 }
237
238 void
239 JSONObject::update(JSONObject &value)
240 {
241     JSON_CHECK_OBJECT();
242     json_t *other = value.get();
243     JSON_CHECK(json_object_update(m_obj, other));
244     json_decref(other);
245 }
246
247 JSONObject
248 JSONObject::operator[](size_t index) const
249 {
250     return get(index);
251 }
252
253 JSONObject
254 JSONObject::operator[](const char *key) const
255 {
256     return get(key);
257 }
258
259 void
260 JSONObject::append(JSONObject &value)
261 {
262     JSON_CHECK_ARRAY();
263     JSON_CHECK(json_array_append_new(m_obj, value.get()));
264 }
265
266 void
267 JSONObject::insert(size_t index, JSONObject &value)
268 {
269     JSON_CHECK_ARRAY();
270     JSON_CHECK(json_array_insert_new(m_obj, index, value.get()));
271 }
272
273 void
274 JSONObject::remove(size_t index)
275 {
276     JSON_CHECK_ARRAY();
277     JSON_CHECK(json_array_remove(m_obj, index));
278 }
279
280 void
281 JSONObject::clear(void)
282 {
283     JSON_CHECK_CONTAINER();
284
285     if (json_is_object(m_obj)) {
286         JSON_CHECK(json_object_clear(m_obj));
287     } else if (json_is_array(m_obj)) {
288         JSON_CHECK(json_array_clear(m_obj));
289     }
290 }
291
292 void
293 JSONObject::extend(JSONObject &value)
294 {
295     JSON_CHECK_ARRAY();
296     json_t *other = value.get();
297     JSON_CHECK(json_array_extend(m_obj, other));
298     json_decref(other);
299 }
300
301 const char *
302 JSONObject::string(void) const
303 {
304     return json_string_value(m_obj);
305 }
306
307 json_int_t
308 JSONObject::integer(void) const
309 {
310     return json_integer_value(m_obj);
311 }
312
313 double
314 JSONObject::real(void) const
315 {
316     return json_real_value(m_obj);
317 }
318
319 double
320 JSONObject::number(void) const
321 {
322     return json_number_value(m_obj);
323 }
324
325 #ifdef HAVE_SHIBRESOLVER
326 JSONObject
327 JSONObject::ddf(DDF &ddf)
328 {
329     if (ddf.isstruct()) {
330         DDF elem = ddf.first();
331         JSONObject jobj = JSONObject::object();
332
333         while (!elem.isnull()) {
334             JSONObject jtmp = JSONObject::ddf(elem);
335             jobj.set(elem.name(), jtmp);
336             elem = ddf.next();
337         }
338
339         return jobj;
340     } else if (ddf.islist()) {
341         DDF elem = ddf.first();
342         JSONObject jobj = JSONObject::array();
343
344         while (!elem.isnull()) {
345             JSONObject jtmp = JSONObject::ddf(elem);
346             jobj.append(jtmp);
347             elem = ddf.next();
348         }
349
350         return jobj;
351     } else if (ddf.isstring()) {
352         return JSONObject(ddf.string());
353     } else if (ddf.isint()) {
354         return JSONObject((json_int_t)ddf.integer());
355     } else if (ddf.isfloat()) {
356         return JSONObject(ddf.floating());
357     } else if (ddf.isempty() || ddf.ispointer()) {
358         return JSONObject::object();
359     } else if (ddf.isnull()) {
360         return JSONObject::null();
361     }
362
363     std::string s("Unbridgeable DDF object");
364     throw JSONException();
365 }
366
367 DDF
368 JSONObject::ddf(void) const
369 {
370     DDF ddf(NULL);
371
372     switch (type()) {
373     case JSON_OBJECT: {
374         JSONIterator iter = iterator();
375
376         do {
377             const char *key = iter.key();
378             DDF value = iter.value().ddf();
379             ddf.addmember(key).swap(value);
380         } while (iter.next());
381         break;
382     }
383     case JSON_ARRAY: {
384         size_t i, nelems = size();
385
386         for (i = 0; i < nelems; i++) {
387             DDF value = get(i).ddf();
388             ddf.add(value);
389         }
390         break;
391     }
392     case JSON_STRING:
393         ddf.string(string());
394         break;
395     case JSON_INTEGER:
396         ddf.integer(integer());
397         break;
398     case JSON_REAL:
399         ddf.floating(real());
400         break;
401     case JSON_TRUE:
402         ddf.integer(1L);
403         break;
404     case JSON_FALSE:
405         ddf.integer(0L);
406         break;
407     case JSON_NULL:
408         break;
409     }
410
411     return ddf;
412 }
413 #endif /* HAVE_SHIBRESOLVER */
414
415 bool JSONObject::isObject(void) const
416 {
417     return json_is_object(m_obj);
418 }
419
420 bool JSONObject::isArray(void) const
421 {
422     return json_is_array(m_obj);
423 }
424
425 bool JSONObject::isString(void) const
426 {
427     return json_is_string(m_obj);
428 }
429
430 bool JSONObject::isInteger(void) const
431 {
432     return json_is_integer(m_obj);
433 }
434
435 bool JSONObject::isNumber(void) const
436 {
437     return json_is_number(m_obj);
438 }
439
440 bool JSONObject::isBoolean(void) const
441 {
442     return json_is_boolean(m_obj);
443 }
444
445 bool JSONObject::isNull(void) const
446 {
447     return json_is_null(m_obj);
448 }
449
450 JSONIterator::JSONIterator(const JSONObject &obj)
451 {
452     m_obj = obj.get();
453     m_iter = json_object_iter(m_obj);
454 }
455
456 JSONIterator::~JSONIterator(void)
457 {
458     json_decref(m_obj);
459 }
460
461 const char *
462 JSONIterator::key(void) const
463 {
464     return json_object_iter_key(m_iter);
465 }
466
467 JSONObject
468 JSONIterator::value(void) const
469 {
470     return JSONObject(json_object_iter_value(m_iter));
471 }
472
473 bool
474 JSONIterator::next(void)
475 {
476     m_iter = json_object_iter_next(m_obj, m_iter);
477     return m_iter != NULL;
478 }
479
480 JSONException::JSONException(json_t *obj, json_type type)
481 {
482     char *s = NULL;
483     const char *t;
484
485     m_obj = json_incref(obj);
486     m_type = type;
487
488     if (obj != NULL)
489         s = json_dumps(m_obj, 0);
490
491     switch (type) {
492     case JSON_OBJECT:   t = "OBJECT";   break;
493     case JSON_ARRAY:    t = "ARRAY";    break;
494     case JSON_STRING:   t = "STRING";   break;
495     case JSON_INTEGER:  t = "INTEGER";  break;
496     case JSON_REAL:     t = "REAL";     break;
497     case JSON_TRUE:     t = "TRUE";     break;
498     case JSON_FALSE:    t = "FALSE";    break;
499     case JSON_NULL:     t = "NULL";     break;
500     default:            t = "UNKNOWN";  break;
501     }
502
503     if (obj != NULL) {
504         m_reason = "Invalid JSON object: " + std::string(s);
505         if (type != JSON_NULL)
506             m_reason += " (excepted type " + std::string(t) + ")";
507     } else {
508         m_reason = "Internal JSON error";
509     }
510
511     if (s != NULL)
512         GSSEAP_FREE(s);
513 }