tizen 2.4 release
[framework/context/context-common.git] / src / json.cpp
1 /*
2  * Copyright (c) 2015 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <string>
18 #include <sstream>
19 #include <locale>
20 #include <iomanip>
21 #include <json-glib/json-glib.h>
22 #include <json.h>
23
24 #define PATH_DELIM      '.'
25 #define GVAR_VALUES     "values"
26 #define GVAR_TYPES      "types"
27
28 static double string_to_double(const char* in)
29 {
30         IF_FAIL_RETURN_TAG(in, 0, _E, "Parameter NULL");
31
32         // Locale-independent string-to-double conversion
33         double out;
34         std::istringstream istr(in);
35         istr.imbue(std::locale("C"));
36         istr >> out;
37         return out;
38 }
39
40 static std::string double_to_string(double in, int prec)
41 {
42         // Locale-independent double-to-string conversion
43         std::ostringstream ostr;
44         ostr.imbue(std::locale("C"));
45         ostr << std::setprecision(prec) << std::fixed << in;
46         return ostr.str();
47 }
48
49 ctx::json::json()
50 {
51         JsonObject *obj = json_object_new();
52         IF_FAIL_VOID_TAG(obj, _E, "Json object construction failed");
53
54         json_node = json_node_new(JSON_NODE_OBJECT);
55         if (!json_node) {
56                 json_object_unref(obj);
57                 _E("Json object construction failed");
58         }
59
60         json_node_set_object(json_node, obj);
61         json_object_unref(obj);
62 }
63
64 ctx::json::json(const json& j)
65 {
66         json_node = json_node_copy(j.json_node);
67         IF_FAIL_VOID_TAG(json_node, _E, "Json object construction failed");
68 }
69
70 ctx::json::json(const char* s)
71 {
72         if (s) {
73                 parse(s);
74         } else {
75                 parse(EMPTY_JSON_OBJECT);
76         }
77 }
78
79 ctx::json::json(const std::string& s)
80 {
81         if (s.empty()) {
82                 parse(EMPTY_JSON_OBJECT);
83         } else {
84                 parse(s.c_str());
85         }
86 }
87
88 ctx::json::~json()
89 {
90         release();
91 }
92
93 void ctx::json::parse(const char* s)
94 {
95         gboolean result;
96         JsonParser *parser = NULL;
97         JsonNode *root = NULL;
98
99         parser = json_parser_new();
100         IF_FAIL_VOID_TAG(parser, _E, "Memory allocation failed");
101
102         result = json_parser_load_from_data(parser, s, -1, NULL);
103         IF_FAIL_CATCH_TAG(result, _E, "Parsing failed");
104
105         root = json_parser_get_root(parser);
106         IF_FAIL_CATCH_TAG(root, _E, "Getting root failed");
107
108         json_node = json_node_copy(root);
109         IF_FAIL_CATCH_TAG(json_node, _E, "Copying failed");
110
111 CATCH:
112         if (parser)
113                 g_object_unref(parser);
114 }
115
116 void ctx::json::release()
117 {
118         if (json_node) {
119                 json_node_free(json_node);
120                 json_node = NULL;
121         }
122 }
123
124 ctx::json& ctx::json::operator=(const json& j)
125 {
126         release();
127         json_node = json_node_copy(j.json_node);
128         if (!json_node) {
129                 _E("Json object copy failed");
130         }
131         return *this;
132 }
133
134 ctx::json& ctx::json::operator=(const char* s)
135 {
136         release();
137         if (s) {
138                 parse(s);
139         } else {
140                 parse(EMPTY_JSON_OBJECT);
141         }
142         return *this;
143 }
144
145 ctx::json& ctx::json::operator=(const std::string& s)
146 {
147         release();
148         if (s.empty()) {
149                 parse(EMPTY_JSON_OBJECT);
150         } else {
151                 parse(s.c_str());
152         }
153         return *this;
154 }
155
156 bool ctx::json::operator==(const json& rhs)
157 {
158         return node_equals(json_node, rhs.json_node);
159 }
160
161 bool ctx::json::operator!=(const json& rhs)
162 {
163         return !operator==(rhs);
164 }
165
166 /* TODO
167 bool ctx::json::contains(const json& subset) const
168 {
169         return false;
170 }
171 */
172
173 char* ctx::json::dup_cstr()
174 {
175         IF_FAIL_RETURN_TAG(json_node, NULL, _E, "Json object not initialized");
176
177         JsonGenerator *jgen = NULL;
178         char *output = NULL;
179
180         jgen = json_generator_new();
181         IF_FAIL_CATCH(jgen);
182
183         json_generator_set_root(jgen, json_node);
184         output = json_generator_to_data(jgen, NULL);
185         IF_FAIL_CATCH(output);
186
187         g_object_unref(jgen);
188         return output;
189
190 CATCH:
191         if (jgen) {
192                 g_object_unref(jgen);
193         }
194
195         _E("Memory allocation failed");
196         return NULL;
197 }
198
199 std::string ctx::json::str()
200 {
201         std::string output;
202         char *_s = dup_cstr();
203         IF_FAIL_RETURN(_s, output = EMPTY_JSON_OBJECT);
204
205         output = _s;
206         g_free(_s);
207
208         return output;
209 }
210
211 static char** tokenize_path(const char* path, int* length)
212 {
213         //TODO: Re-implement this tokenizer using C++ stuff
214         char** tokens;
215         const char* pch;
216         const char* begin;
217         int i;
218         int j;
219         int len;
220
221         if (path == NULL || strlen(path) == 0) {
222                 *length = 0;
223                 return NULL;
224         }
225
226         *length = 1;
227
228         for (pch = path; *pch != '\0'; pch++) {
229                 if (*pch == PATH_DELIM) {
230                         *length = *length + 1;
231                 }
232         }
233
234         tokens = static_cast<char**>(g_malloc((*length) * sizeof(char*)));
235         IF_FAIL_RETURN_TAG(tokens, NULL, _E, "Memory allocation failed");
236
237         begin = path;
238         i = 0;
239
240         for (pch = path; ; pch++) {
241                 if (*pch == PATH_DELIM || *pch == '\0') {
242                         len = pch - begin;
243                         tokens[i] = static_cast<char*>(g_malloc((len+1) * sizeof(char)));
244                         IF_FAIL_CATCH_TAG(tokens[i], _E, "Memory allocation failed");
245                         strncpy(tokens[i], begin, len);
246                         tokens[i][len] = '\0';
247                         i++;
248                         begin = pch + 1;
249                 }
250
251                 if (*pch == '\0') {
252                         break;
253                 }
254         }
255
256         return tokens;
257
258 CATCH:
259         for (j=0; j<i; j++) {
260                 g_free(tokens[j]);
261         }
262         g_free(tokens);
263         return NULL;
264 }
265
266 static void free_tokenized_path(int length, char** tokens)
267 {
268         int i;
269         if (tokens) {
270                 for (i=0; i<length; i++) {
271                         g_free(tokens[i]);
272                 }
273                 g_free(tokens);
274         }
275 }
276
277 static JsonObject* traverse(JsonNode* jnode, const char* path, bool force)
278 {
279         IF_FAIL_RETURN_TAG(jnode, NULL, _E, "Invalid parameter");
280
281         int length = 0;
282         int depth = 0;
283         char **path_token = NULL;
284         JsonObject *jobj = NULL;
285         JsonObject *child_obj = NULL;
286         JsonNode *child_node = NULL;
287
288         jobj = json_node_get_object(jnode);
289         IF_FAIL_RETURN(jobj, NULL);
290
291         if (path) {
292                 path_token = tokenize_path(path, &length);
293                 IF_FAIL_RETURN_TAG(path_token, NULL, _E, "Invalid path");
294         }
295
296         for (depth=0; depth<length; depth++) {
297                 if (!json_object_has_member(jobj, path_token[depth])) {
298                         if (force) {
299                                 child_obj = json_object_new();
300                                 IF_FAIL_CATCH_TAG(child_obj, _E, "Memory allocation failed");
301                                 json_object_set_object_member(jobj, path_token[depth], child_obj);
302                         } else {
303                                 goto CATCH;
304                         }
305                 }
306                 child_node = json_object_get_member(jobj, path_token[depth]);
307                 IF_FAIL_CATCH(child_node && json_node_get_node_type(child_node) == JSON_NODE_OBJECT);
308
309                 jobj = json_node_get_object(child_node);
310                 IF_FAIL_CATCH(jobj);
311         }
312
313         free_tokenized_path(length, path_token);
314         return jobj;
315
316 CATCH:
317         free_tokenized_path(length, path_token);
318         return NULL;
319 }
320
321 bool ctx::json::set(const char* path, const char* key, json& val)
322 {
323         IF_FAIL_RETURN_TAG(this->json_node, false, _E, "Json object not initialized");
324         IF_FAIL_RETURN_TAG(key && val.json_node, false, _E, "Invalid parameter");
325
326         JsonObject *jobj = traverse(json_node, path, true);
327         IF_FAIL_RETURN(jobj, false);
328
329         if (json_object_has_member(jobj, key))
330                 json_object_remove_member(jobj, key);
331
332         json_object_set_member(jobj, key, val.json_node);
333         val.json_node = NULL;
334         val = json();
335
336         return true;
337 }
338
339 bool ctx::json::set(const char* path, const char* key, int val)
340 {
341         return set(path, key, static_cast<int64_t>(val));
342 }
343
344 bool ctx::json::set(const char* path, const char* key, int64_t val)
345 {
346         IF_FAIL_RETURN_TAG(this->json_node, false, _E, "Json object not initialized");
347         IF_FAIL_RETURN_TAG(key, false, _E, "Invalid parameter");
348
349         JsonObject *jobj = traverse(json_node, path, true);
350         IF_FAIL_RETURN(jobj, false);
351
352         if (json_object_has_member(jobj, key))
353                 json_object_remove_member(jobj, key);
354
355         json_object_set_int_member(jobj, key, val);
356         return true;
357 }
358
359 bool ctx::json::set(const char* path, const char* key, double val, int prec)
360 {
361         IF_FAIL_RETURN_TAG(this->json_node, false, _E, "Json object not initialized");
362         IF_FAIL_RETURN_TAG(key, false, _E, "Invalid parameter");
363
364         JsonObject *jobj = traverse(json_node, path, true);
365         IF_FAIL_RETURN(jobj, false);
366
367         if (json_object_has_member(jobj, key)) {
368                 json_object_remove_member(jobj, key);
369         }
370
371         //NOTE: json-glib causes a precision issue while handling double values
372         json_object_set_string_member(jobj, key, double_to_string(val, prec).c_str());
373         return true;
374 }
375
376 bool ctx::json::set(const char* path, const char* key, std::string val)
377 {
378         IF_FAIL_RETURN_TAG(this->json_node, false, _E, "Json object not initialized");
379         IF_FAIL_RETURN_TAG(key, false, _E, "Invalid parameter");
380
381         JsonObject *jobj = traverse(json_node, path, true);
382         IF_FAIL_RETURN(jobj, false);
383
384         if (json_object_has_member(jobj, key)) {
385                 json_object_remove_member(jobj, key);
386         }
387
388         json_object_set_string_member(jobj, key, val.c_str());
389         return true;
390 }
391
392 bool ctx::json::set(const char* path, const char* key, GVariant *val)
393 {
394         IF_FAIL_RETURN_TAG(this->json_node, false, _E, "Json object not initialized");
395         IF_FAIL_RETURN_TAG(key && val, false, _E, "Invalid parameter");
396
397         const gchar *type_str = g_variant_get_type_string(val);
398         IF_FAIL_RETURN_TAG(type_str, false, _E, "GVariant manipulation failed");
399
400         json_node_t *node = json_gvariant_serialize(val);
401         IF_FAIL_RETURN_TAG(node, false, _E, "GVariant manipulation failed");
402
403         json gvar_json;
404         gvar_json.set(NULL, GVAR_TYPES, type_str);
405         json_object_set_member(json_node_get_object(gvar_json.json_node), GVAR_VALUES, node);
406
407         return set(path, key, gvar_json);
408 }
409
410 bool ctx::json::get(const char* path, const char* key, json* val)
411 {
412         IF_FAIL_RETURN_TAG(this->json_node, false, _E, "Json object not initialized");
413         IF_FAIL_RETURN_TAG(key && val, false, _E, "Invalid parameter");
414
415         JsonObject *jobj = NULL;
416         JsonNode *node = NULL;
417
418         jobj = traverse(json_node, path, false);
419         IF_FAIL_RETURN(jobj && json_object_has_member(jobj, key), false);
420
421         node = json_object_dup_member(jobj, key);
422         IF_FAIL_RETURN_TAG(node, false, _E, "Memory allocation failed");
423
424         if (val->json_node) {
425                 json_node_free(val->json_node);
426         }
427         val->json_node = node;
428
429         return true;
430 }
431
432 static JsonNode* search_value_node(JsonNode* jnode, const char* path, const char* key)
433 {
434         JsonNode *node = NULL;
435         JsonObject *jobj = NULL;
436         JsonNodeType ntype;
437
438         jobj = traverse(jnode, path, false);
439         IF_FAIL_RETURN(jobj && json_object_has_member(jobj, key), NULL);
440
441         node = json_object_get_member(jobj, key);
442         ntype = json_node_get_node_type(node);
443         IF_FAIL_RETURN(ntype == JSON_NODE_VALUE, NULL);
444
445         return node;
446 }
447
448 bool ctx::json::get(const char* path, const char* key, int* val)
449 {
450         IF_FAIL_RETURN_TAG(this->json_node, false, _E, "Json object not initialized");
451         IF_FAIL_RETURN_TAG(key && val, false, _E, "Invalid parameter");
452
453         int64_t v;
454
455         if (get(path, key, &v)) {
456                 *val = v;
457                 return true;
458         }
459
460         return false;
461 }
462
463 bool ctx::json::get(const char* path, const char* key, int64_t* val)
464 {
465         IF_FAIL_RETURN_TAG(this->json_node, false, _E, "Json object not initialized");
466         IF_FAIL_RETURN_TAG(key && val, false, _E, "Invalid parameter");
467
468         JsonNode *node = search_value_node(json_node, path, key);
469         IF_FAIL_RETURN(node, false);
470
471         GType vtype = json_node_get_value_type(node);
472         if (vtype == G_TYPE_INT64) {
473                 *val = json_node_get_int(node);
474         } else if (vtype == G_TYPE_STRING) {
475                 //TODO: if the string is not a number?
476                 *val = static_cast<int64_t>(string_to_double(json_node_get_string(node)));
477         } else {
478                 return false;
479         }
480
481         return true;
482 }
483
484 bool ctx::json::get(const char* path, const char* key, double* val)
485 {
486         IF_FAIL_RETURN_TAG(this->json_node, false, _E, "Json object not initialized");
487         IF_FAIL_RETURN_TAG(key && val, false, _E, "Invalid parameter");
488
489         JsonNode *node = search_value_node(json_node, path, key);
490         IF_FAIL_RETURN(node, false);
491
492         GType vtype = json_node_get_value_type(node);
493         if (vtype == G_TYPE_DOUBLE) {
494                 *val = json_node_get_double(node);
495         } else if (vtype == G_TYPE_INT64) {
496                 *val = json_node_get_int(node);
497         } else if (vtype == G_TYPE_STRING) {
498                 //NOTE: json-glib causes a precision issue while handling double values
499                 *val = string_to_double(json_node_get_string(node));
500         } else {
501                 return false;
502         }
503
504         return true;
505 }
506
507 bool ctx::json::get(const char* path, const char* key, std::string* val)
508 {
509         IF_FAIL_RETURN_TAG(this->json_node, false, _E, "Json object not initialized");
510         IF_FAIL_RETURN_TAG(key && val, false, _E, "Invalid parameter");
511
512         JsonNode *node = search_value_node(json_node, path, key);
513         IF_FAIL_RETURN(node, false);
514
515         GType vtype = json_node_get_value_type(node);
516         IF_FAIL_RETURN(vtype == G_TYPE_STRING, false);
517
518         const char *str_val = json_node_get_string(node);
519         IF_FAIL_RETURN_TAG(str_val, false, _E, "Getting string failed");
520
521         *val = str_val;
522         return true;
523 }
524
525 bool ctx::json::get(const char* path, const char* key, GVariant **val)
526 {
527         IF_FAIL_RETURN_TAG(this->json_node, false, _E, "Json object not initialized");
528         IF_FAIL_RETURN_TAG(key && val, false, _E, "Invalid parameter");
529
530         bool ret;
531         json gvar_json;
532         ret = get(path, key, &gvar_json);
533         IF_FAIL_RETURN(ret, false);
534
535         std::string gvar_types;
536         ret = gvar_json.get(NULL, GVAR_TYPES, &gvar_types);
537         IF_FAIL_RETURN(ret, false);
538
539         json gvar_values;
540         ret = gvar_json.get(NULL, GVAR_VALUES, &gvar_values);
541         IF_FAIL_RETURN(ret, false);
542
543         GError *gerr = NULL;
544         *val = json_gvariant_deserialize(gvar_values.json_node, gvar_types.c_str(), &gerr);
545         HANDLE_GERROR(gerr);
546         IF_FAIL_RETURN(*val, false);
547
548         return true;
549 }
550
551 static JsonArray* search_array(JsonNode* jnode, const char* path, const char* key, bool force)
552 {
553         JsonNode *node = NULL;
554         JsonArray *arr = NULL;
555         JsonObject *jobj = NULL;
556
557         jobj = traverse(jnode, path, force);
558         IF_FAIL_RETURN(jobj, NULL);
559
560         if (!json_object_has_member(jobj, key)) {
561                 if (force) {
562                         arr = json_array_new();
563                         IF_FAIL_RETURN_TAG(arr, NULL, _E, "Memory allocation failed");
564                         json_object_set_array_member(jobj, key, arr);
565                 } else {
566                         return NULL;
567                 }
568         }
569         node = json_object_get_member(jobj, key);
570         IF_FAIL_RETURN_TAG(node && json_node_get_node_type(node) == JSON_NODE_ARRAY,
571                         NULL, _W, "Type mismatched: %s", key);
572
573         return json_node_get_array(node);
574 }
575
576 int ctx::json::array_get_size(const char* path, const char* key)
577 {
578         IF_FAIL_RETURN_TAG(this->json_node, -1, _E, "Json object not initialized");
579         IF_FAIL_RETURN_TAG(key, -1, _E, "Invalid parameter");
580
581         JsonArray *jarr = search_array(json_node, path, key, false);
582         IF_FAIL_RETURN_TAG(jarr, -1, _D, "Mismatched data type");
583
584         return json_array_get_length(jarr);
585 }
586
587 bool ctx::json::array_append(const char* path, const char* key, json& val)
588 {
589         IF_FAIL_RETURN_TAG(this->json_node, false, _E, "Json object not initialized");
590         IF_FAIL_RETURN_TAG(key && val.json_node, false, _E, "Invalid parameter");
591
592         JsonArray *arr = search_array(json_node, path, key, true);
593         IF_FAIL_RETURN(arr, false);
594
595         json_array_add_element(arr, val.json_node);
596         val.json_node = NULL;
597         val = json();
598
599         return true;
600 }
601
602 bool ctx::json::array_append(const char* path, const char* key, int val)
603 {
604         return array_append(path, key, static_cast<int64_t>(val));
605 }
606
607 bool ctx::json::array_append(const char* path, const char* key, int64_t val)
608 {
609         IF_FAIL_RETURN_TAG(this->json_node, false, _E, "Json object not initialized");
610         IF_FAIL_RETURN_TAG(key, false, _E, "Invalid parameter");
611
612         JsonArray *arr = search_array(json_node, path, key, true);
613         IF_FAIL_RETURN(arr, false);
614
615         json_array_add_int_element(arr, val);
616         return true;
617 }
618
619 bool ctx::json::array_append(const char* path, const char* key, double val, int prec)
620 {
621         IF_FAIL_RETURN_TAG(this->json_node, false, _E, "Json object not initialized");
622         IF_FAIL_RETURN_TAG(key, false, _E, "Invalid parameter");
623
624         JsonArray *arr = search_array(json_node, path, key, true);
625         IF_FAIL_RETURN(arr, false);
626
627         //NOTE: json-glib causes a precision issue while handling double values
628         json_array_add_string_element(arr, double_to_string(val, prec).c_str());
629         return true;
630 }
631
632 bool ctx::json::array_append(const char* path, const char* key, std::string val)
633 {
634         IF_FAIL_RETURN_TAG(this->json_node, false, _E, "Json object not initialized");
635         IF_FAIL_RETURN_TAG(key, false, _E, "Invalid parameter");
636
637         JsonArray *arr = search_array(json_node, path, key, true);
638         IF_FAIL_RETURN(arr, false);
639
640         json_array_add_string_element(arr, val.c_str());
641         return true;
642 }
643
644 static JsonNode* search_array_elem(JsonNode* jnode, const char* path, const char* key, int index)
645 {
646         JsonArray *jarr = search_array(jnode, path, key, false);
647         IF_FAIL_RETURN_TAG(jarr, NULL, _W, "Mismatched data type");
648
649         int size = json_array_get_length(jarr);
650         IF_FAIL_RETURN(size > index, NULL);
651
652         JsonNode *node = json_array_get_element(jarr, index);
653         IF_FAIL_RETURN_TAG(node, NULL, _E, "Failed to get an array element");
654
655         return node;
656 }
657
658 bool ctx::json::array_set_at(const char* path, const char* key, int index, json& val)
659 {
660         IF_FAIL_RETURN_TAG(this->json_node, false, _E, "Json object not initialized");
661         IF_FAIL_RETURN_TAG(val.json_node && key && index >= 0, false, _E, "Invalid parameter");
662
663         JsonNode *node = search_array_elem(json_node, path, key, index);
664         IF_FAIL_RETURN_TAG(node, false, _W, "Out of range");
665         IF_FAIL_RETURN_TAG(json_node_get_node_type(node) == JSON_NODE_OBJECT, false, _E, "Type mismatched: %s[%d]", key, index);
666
667         JsonObject *obj = json_node_get_object(val.json_node);
668         IF_FAIL_RETURN_TAG(obj, false, _E, "Getting object failed");
669
670         json_node_set_object(node, obj);
671         json_node_free(val.json_node);
672         val.json_node = NULL;
673         val = json();
674
675         return true;
676 }
677
678 bool ctx::json::array_set_at(const char* path, const char* key, int index, int val)
679 {
680         return array_set_at(path, key, index, static_cast<int64_t>(val));
681 }
682
683 bool ctx::json::array_set_at(const char* path, const char* key, int index, int64_t val)
684 {
685         IF_FAIL_RETURN_TAG(this->json_node, false, _E, "Json object not initialized");
686         IF_FAIL_RETURN_TAG(key && index >= 0, false, _E, "Invalid parameter");
687
688         JsonNode *node = search_array_elem(json_node, path, key, index);
689         IF_FAIL_RETURN_TAG(node, false, _W, "Out of range");
690         IF_FAIL_RETURN_TAG(json_node_get_node_type(node) == JSON_NODE_VALUE, false, _E, "Type mismatched: %s[%d]", key, index);
691         IF_FAIL_RETURN_TAG(json_node_get_value_type(node) == G_TYPE_INT64, false, _E, "Type mismatched: %s[%d]", key, index);
692
693         json_node_set_int(node, val);
694         return true;
695 }
696
697 bool ctx::json::array_set_at(const char* path, const char* key, int index, double val, int prec)
698 {
699         IF_FAIL_RETURN_TAG(this->json_node, false, _E, "Json object not initialized");
700         IF_FAIL_RETURN_TAG(key && index >= 0, false, _E, "Invalid parameter");
701
702         JsonNode *node = search_array_elem(json_node, path, key, index);
703         IF_FAIL_RETURN_TAG(node, false, _W, "Out of range");
704         IF_FAIL_RETURN_TAG(json_node_get_node_type(node) == JSON_NODE_VALUE, false, _E, "Type mismatched: %s[%d]", key, index);
705         IF_FAIL_RETURN_TAG(json_node_get_value_type(node) == G_TYPE_STRING, false, _E, "Type mismatched: %s[%d]", key, index);
706
707         json_node_set_string(node, double_to_string(val, prec).c_str());
708         return true;
709 }
710
711 bool ctx::json::array_set_at(const char* path, const char* key, int index, std::string val)
712 {
713         IF_FAIL_RETURN_TAG(this->json_node, false, _E, "Json object not initialized");
714         IF_FAIL_RETURN_TAG(key && index >= 0, false, _E, "Invalid parameter");
715
716         JsonNode *node = search_array_elem(json_node, path, key, index);
717         IF_FAIL_RETURN_TAG(node, false, _W, "Out of range");
718         IF_FAIL_RETURN_TAG(json_node_get_node_type(node) == JSON_NODE_VALUE, false, _E, "Type mismatched: %s[%d]", key, index);
719         IF_FAIL_RETURN_TAG(json_node_get_value_type(node) == G_TYPE_STRING, false, _E, "Type mismatched: %s[%d]", key, index);
720
721         json_node_set_string(node, val.c_str());
722         return true;
723 }
724
725 bool ctx::json::get_array_elem(const char* path, const char* key, int index, json* val)
726 {
727         IF_FAIL_RETURN_TAG(this->json_node, false, _E, "Json object not initialized");
728         IF_FAIL_RETURN_TAG(key && val && index >= 0, false, _E, "Invalid parameter");
729
730         JsonNode *node = search_array_elem(json_node, path, key, index);
731         IF_FAIL_RETURN(node, false);
732
733         JsonNode *node_copy = json_node_copy(node);
734         IF_FAIL_RETURN_TAG(node_copy, false, _E, "Memory allocation failed");
735
736         if (val->json_node) {
737                 json_node_free(val->json_node);
738         }
739         val->json_node = node_copy;
740
741         return true;
742 }
743
744 bool ctx::json::get_array_elem(const char* path, const char* key, int index, int* val)
745 {
746         IF_FAIL_RETURN_TAG(this->json_node, false, _E, "Json object not initialized");
747         IF_FAIL_RETURN_TAG(key && val && index >= 0, false, _E, "Invalid parameter");
748
749         int64_t v;
750         if (get_array_elem(path, key, index, &v)) {
751                 *val = v;
752                 return true;
753         }
754
755         return false;
756 }
757
758 bool ctx::json::get_array_elem(const char* path, const char* key, int index, int64_t* val)
759 {
760         IF_FAIL_RETURN_TAG(this->json_node, false, _E, "Json object not initialized");
761         IF_FAIL_RETURN_TAG(key && val && index >= 0, false, _E, "Invalid parameter");
762
763         JsonNode *node = search_array_elem(json_node, path, key, index);
764         IF_FAIL_RETURN(node, false);
765
766         JsonNodeType ntype = json_node_get_node_type(node);
767         IF_FAIL_RETURN_TAG(ntype == JSON_NODE_VALUE, false, _E, "Type mismatched: %s", key);
768
769         GType vtype = json_node_get_value_type(node);
770         if (vtype == G_TYPE_INT64) {
771                 *val = json_node_get_int(node);
772         } else if (vtype == G_TYPE_STRING) {
773                 *val = static_cast<int64_t>(string_to_double(json_node_get_string(node)));
774         } else {
775                 _E("Type mismatched: %s", key);
776                 return false;
777         }
778
779         return true;
780 }
781
782 bool ctx::json::get_array_elem(const char* path, const char* key, int index, double* val)
783 {
784         IF_FAIL_RETURN_TAG(this->json_node, false, _E, "Json object not initialized");
785         IF_FAIL_RETURN_TAG(key && val && index >= 0, false, _E, "Invalid parameter");
786
787         JsonNode *node = search_array_elem(json_node, path, key, index);
788         IF_FAIL_RETURN(node, false);
789
790         JsonNodeType ntype = json_node_get_node_type(node);
791         IF_FAIL_RETURN_TAG(ntype == JSON_NODE_VALUE, false, _E, "Type mismatched: %s", key);
792
793         GType vtype = json_node_get_value_type(node);
794         if (vtype == G_TYPE_DOUBLE) {
795                 *val = json_node_get_double(node);
796         } else if (vtype == G_TYPE_INT64) {
797                 *val = json_node_get_int(node);
798         } else if (vtype == G_TYPE_STRING) {
799                 //NOTE: json-glib causes a precision issue while handling double values
800                 *val = string_to_double(json_node_get_string(node));
801         } else {
802                 _E("Type mismatched: %s", key);
803                 return false;
804         }
805
806         return true;
807 }
808
809 bool ctx::json::get_array_elem(const char* path, const char* key, int index, std::string* val)
810 {
811         IF_FAIL_RETURN_TAG(this->json_node, false, _E, "Json object not initialized");
812         IF_FAIL_RETURN_TAG(key && val && index >= 0, false, _E, "Invalid parameter");
813
814         JsonNode *node = search_array_elem(json_node, path, key, index);
815         IF_FAIL_RETURN(node, false);
816
817         JsonNodeType ntype = json_node_get_node_type(node);
818         IF_FAIL_RETURN_TAG(ntype == JSON_NODE_VALUE, false, _E, "Type mismatched: %s", key);
819
820         GType vtype = json_node_get_value_type(node);
821         IF_FAIL_RETURN_TAG(vtype == G_TYPE_STRING, false, _E, "Type mismatched: %s", key);
822
823         const char *str_val = json_node_get_string(node);
824         IF_FAIL_RETURN_TAG(str_val, false, _E, "Getting string failed");
825
826         *val = str_val;
827         return true;
828 }
829
830 bool ctx::json::get_member_list(json_node_t* node, std::list<std::string>& list)
831 {
832         IF_FAIL_RETURN(node, false);
833         list.clear();
834
835         JsonObject *jobj = json_node_get_object(node);
836         IF_FAIL_RETURN_TAG(jobj, false, _E, "Getting json object failed");
837
838         GList *members = json_object_get_members(jobj);
839         IF_FAIL_RETURN(members, true);
840
841         for (GList *it = g_list_first(members); it; it = g_list_next(it)) {
842                 const char *key = static_cast<const char*>(it->data);
843                 if (!key) {
844                         list.clear();
845                         g_list_free(members);
846                         _E("Member list extraction failed");
847                         return false;
848                 }
849
850                 list.push_back(key);
851         }
852
853         g_list_free(members);
854         return true;
855 }
856
857 bool ctx::json::get_keys(std::list<std::string>* list)
858 {
859         IF_FAIL_RETURN_TAG(list, false, _E, "Invalid parameter");
860         return get_member_list(json_node, *list);
861 }
862
863 bool ctx::json::node_equals(json_node_t* lhs, json_node_t* rhs)
864 {
865         IF_FAIL_RETURN(lhs && rhs, false);
866
867         JsonNodeType ltype = json_node_get_node_type(lhs);
868         JsonNodeType rtype = json_node_get_node_type(rhs);
869         IF_FAIL_RETURN(ltype == rtype, false);
870
871         switch (ltype) {
872                 case JSON_NODE_VALUE:
873                         IF_FAIL_RETURN(value_equals(lhs, rhs), false);
874                         break;
875                 case JSON_NODE_OBJECT:
876                         IF_FAIL_RETURN(object_equals(lhs, rhs), false);
877                         break;
878                 case JSON_NODE_ARRAY:
879                         IF_FAIL_RETURN(array_equals(lhs, rhs), false);
880                         break;
881                 default:
882                         _W("Unsupported type");
883                         return false;
884         }
885
886         return true;
887 }
888
889 bool ctx::json::value_equals(json_node_t* lhs, json_node_t* rhs)
890 {
891         GType ltype = json_node_get_value_type(lhs);
892         GType rtype = json_node_get_value_type(rhs);
893         IF_FAIL_RETURN(ltype == rtype, false);
894
895         switch (ltype) {
896                 case G_TYPE_INT64:
897                         return json_node_get_int(lhs) == json_node_get_int(rhs);
898                 case G_TYPE_DOUBLE:
899                         return json_node_get_double(lhs) == json_node_get_double(rhs);
900                 case G_TYPE_STRING:
901                         return STR_EQ(json_node_get_string(lhs), json_node_get_string(rhs));
902                 default:
903                         _W("Unsupported type");
904                         return false;
905         }
906 }
907
908 bool ctx::json::object_equals(json_node_t* lhs, json_node_t* rhs)
909 {
910         std::list<std::string> lm, rm;
911         IF_FAIL_RETURN(get_member_list(lhs, lm), false);
912         IF_FAIL_RETURN(get_member_list(rhs, rm), false);
913         IF_FAIL_RETURN(lm.size() == rm.size(), false);
914
915         lm.sort();
916         rm.sort();
917
918         std::list<std::string>::iterator lit, rit;
919         lit = lm.begin();
920         rit = rm.begin();
921
922         while (lit != lm.end()) {
923                 IF_FAIL_RETURN(*lit == *rit, false);
924
925                 json_node_t *lhs_child = json_object_get_member(json_node_get_object(lhs), (*lit).c_str());
926                 json_node_t *rhs_child = json_object_get_member(json_node_get_object(rhs), (*rit).c_str());
927                 IF_FAIL_RETURN(node_equals(lhs_child, rhs_child), false);
928
929                 ++lit;
930                 ++rit;
931         }
932
933         return true;
934 }
935
936 bool ctx::json::array_equals(json_node_t* lhs, json_node_t* rhs)
937 {
938         JsonArray *larr = json_node_get_array(lhs);
939         JsonArray *rarr = json_node_get_array(rhs);
940
941         int size = json_array_get_length(larr);
942         IF_FAIL_RETURN(size == static_cast<int>(json_array_get_length(rarr)), false);
943
944         for (int i=0; i<size; ++i) {
945                 json_node_t *lhs_child = json_array_get_element(larr, i);
946                 json_node_t *rhs_child = json_array_get_element(rarr, i);
947                 IF_FAIL_RETURN(node_equals(lhs_child, rhs_child), false);
948         }
949
950         return true;
951 }