a5df74565b19a15f82f0e8c9d16722bd68cf5586
[profile/tv/apps/native/settings.git] / src / parser.c
1 /*
2  * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
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 <Eina.h>
18 #include "parser.h"
19 #include "dbg.h"
20 #include "stdlib.h"
21
22 struct json_parser {
23         JsonParser *parser;
24         JsonReader *reader;
25         JsonGenerator *generator;
26 };
27
28 /**
29 *  This is an Internal function, it is used to restore JsonReader location.
30 *
31 *  The numbers that restored JsonReader location is as same as the numbers moved it.
32 *
33 *  @param jparser [in] The json_parser data pointer.
34 *  @param cnt [in] The numbers that need to restore.
35 *  @return void.
36 */
37 static void _restore_json_reader_location(struct json_parser *jparser,
38                 int cnt)
39 {
40         if (!jparser || !jparser->reader) {
41                 _ERR("Invalid argument");
42                 return;
43         }
44
45         while (cnt > 0) {
46                 json_reader_end_member(jparser->reader);
47                 cnt--;
48         }
49 }
50
51 /**
52 *  This is an Internal function, it is used to get json property value with certain json path.
53 *
54 *  Use json-glib to create JsonPath variable and load the path to find property
55 *  location, then output property value.
56 *
57 *  @param jparser [in] The json_parser data pointer.
58 *  @param path [in] The json path.
59 *  @return the property value, NULL on error.
60 */
61 static gchar *_get_jsonpath_result(struct json_parser *jparser,
62                 const char *path)
63 {
64         JsonPath *jpath;
65         JsonNode *node;
66         gchar *output;
67
68         if (!jparser || !path) {
69                 _ERR("Invalid argument!\n");
70                 return NULL;
71         }
72
73         jpath = json_path_new();
74         json_path_compile(jpath, path, NULL);
75         node = json_path_match(jpath, json_parser_get_root(jparser->parser));
76
77         json_generator_set_root(jparser->generator, node);
78         output = json_generator_to_data(jparser->generator, NULL);
79
80         g_object_unref(jpath);
81         json_node_free(node);
82
83         return output;
84 }
85
86 /**
87 *  Create and init a json_parser data with given json file path.
88 *
89 *  @param path [in] The json file path.
90 *  @return json_parser data pointer, NULL on error.
91 */
92 struct json_parser *parser_init(const char *path)
93 {
94         struct json_parser *jparser;
95         GError *error;
96         JsonParser *parser;
97         JsonReader *reader;
98         JsonGenerator *gen;
99
100         if (!path) {
101                 _ERR("Invalid argument!\n");
102                 return NULL;
103         }
104
105         jparser = calloc(1, sizeof(*jparser));
106         if (!jparser)
107                 return NULL;
108
109         parser = json_parser_new();
110         if (!parser) {
111                 _ERR("json_parser_new failed\n");
112                 free(jparser);
113                 return NULL;
114         }
115
116         reader = json_reader_new(NULL);
117         if (!reader) {
118                 _ERR("json_reader_new failed\n");
119                 free(jparser);
120                 g_object_unref(parser);
121                 return NULL;
122         }
123
124         gen = json_generator_new();
125         if (!gen) {
126                 _ERR("json_reader_new failed\n");
127                 free(jparser);
128                 g_object_unref(parser);
129                 g_object_unref(reader);
130                 return NULL;
131         }
132
133         error = NULL;
134         json_parser_load_from_file(parser, path, &error);
135         if (error) {
136                 _ERR("json file error: %s", error->message);
137                 free(jparser);
138                 g_error_free(error);
139                 g_object_unref(parser);
140                 g_object_unref(reader);
141                 g_object_unref(gen);
142                 return NULL;
143         }
144
145         json_reader_set_root(reader, json_parser_get_root(parser));
146
147         jparser->parser = parser;
148         jparser->reader = reader;
149         jparser->generator = gen;
150
151         return jparser;
152 }
153
154 /**
155 *  Destroy and release given json_parser data.
156 *
157 *  @param jparser [in] The json_parser data pointer to be release.
158 *  @return void.
159 */
160 void parser_fini(struct json_parser *jparser)
161 {
162         if (!jparser)
163                 return;
164
165         g_object_unref(jparser->parser);
166         g_object_unref(jparser->reader);
167         g_object_unref(jparser->generator);
168         free(jparser);
169 }
170
171 /**
172 *  Release given json property key-value pair list.
173 *
174 *  @param list [in] The given property key-value pair list array.
175 *  @return void.
176 */
177 void parser_release_member_list(char **list)
178 {
179         if (!list)
180                 return;
181
182         g_strfreev(list);
183 }
184
185 /**
186 *  Get JsonReader pointer from given json_parser data.
187 *
188 *  @param jparser [in] The json_parser data pointer.
189 *  @return JsonReader pointer, NULL on error.
190 */
191 JsonReader *parser_get_json_reader(struct json_parser *jparser)
192 {
193         if (!jparser) {
194                 _ERR("Parameter error!");
195                 return NULL;
196         }
197
198         return jparser->reader;
199 }
200
201 /**
202 *  Get JsonParser pointer from given json_parser data.
203 *
204 *  @param jparser [in] The json_parser data pointer.
205 *  @return JsonParser pointer, NULL on error.
206 */
207 JsonParser *parser_get_json_parser(struct json_parser *jparser)
208 {
209         if (!jparser) {
210                 _ERR("Parameter error!");
211                 return NULL;
212         }
213
214         return jparser->parser;
215 }
216
217 /**
218 *  Get JsonGenerator pointer from given json_parser data.
219 *
220 *  @param jparser [in] The json_parser data pointer.
221 *  @return JsonGenerator pointer, NULL on error.
222 */
223 JsonGenerator *parser_get_json_generator(struct json_parser *jparser)
224 {
225         if (!jparser) {
226                 _ERR("Parameter error!");
227                 return NULL;
228         }
229
230         return jparser->generator;
231 }
232
233 /**
234 *  Retrieve given item property key-value pair list from json file.
235 *
236 *  According to info_type value to determine to locate either settingitems or settingtree json object,
237 *  then retrieve given item property key-value pair list.
238 *
239 *  @param jparser [in] The json_parser data pointer.
240 *  @param name [in] The item name.
241 *  @param cnt [out] The property key-value pair numbers.
242 *  @param flag [in] The info type, it stand for "settingitems" or "settingtree".
243 *  @return given property key-value pair list, NULL on error.
244 */
245 char **parser_get_itemlist_from_json(struct json_parser *jparser,
246                 const char *name, int *cnt, enum info_type flag)
247 {
248         char **list;
249         int cursor;
250
251         if (!jparser || !name || !cnt) {
252                 _ERR("Invalid argument!");
253                 return NULL;
254         }
255
256         cursor = 0;
257
258         // For Debugging
259         //_DBG("[START][ name = %s ][Parser = %x][Reader = %x]",name, jparser, jparser->reader);
260         //_DBG("Member cnt = %d", json_reader_count_members(jparser->reader));
261         //_DBG("Current Member = %s", json_reader_get_member_name(jparser->reader));
262         if (flag == DRAWING_INFO) {
263                 if (!json_reader_read_member(jparser->reader, JSONSTR_SETTING_ITEMS))
264                 {
265                         cursor++;
266                         goto error;
267                 }
268         } else if (flag == SUBMENU_INFO) {
269                 if (!json_reader_read_member(jparser->reader, JSONSTR_SETTING_TREE))
270                 {
271                         cursor++;
272                         goto error;
273                 }
274         } else {
275                 goto error;
276         }
277
278         cursor++;
279
280         if (!json_reader_read_member(jparser->reader, name))
281         {
282                 cursor++;
283                 goto error;
284         }
285
286         cursor++;
287
288         *cnt = json_reader_count_members(jparser->reader);
289         list = json_reader_list_members(jparser->reader);
290         _restore_json_reader_location(jparser, cursor);
291
292         return list;
293
294 error:
295         _restore_json_reader_location(jparser, cursor);
296         *cnt = 0;
297
298         return NULL;
299 }
300
301 /**
302 *  Retrieve given item setting UI args property key-value pair list from json file.
303 *
304 *  According to name value to locate given item of settingitems object,
305 *  then retrieve setting UI args property key-value pair list.
306 *
307 *  @param jparser [in] The json_parser data pointer.
308 *  @param name [in] The item name.
309 *  @param pnode [in] The args's parent json node name.
310 *  @param cnt [out] The property key-value pair numbers.
311 *  @return given property key-value pair list, NULL on error.
312 */
313 char **parser_get_settingui_args_from_json(struct json_parser *jparser,
314                 const char *name, const char *pnode, int *cnt)
315 {
316         char **list;
317         int cursor;
318
319         if (!jparser || !name || !cnt || !pnode)
320                 return NULL;
321
322         cursor = 0;
323
324         if (!json_reader_read_member(jparser->reader, JSONSTR_SETTING_ITEMS))
325         {
326                 cursor++;
327                 _DBG("[%s] Fail to read member from json", JSONSTR_SETTING_ITEMS);
328                 goto error;
329         }
330
331         cursor++;
332
333         if (!json_reader_read_member(jparser->reader, name))
334         {
335                 cursor++;
336                 _DBG("[%s] Fail to read member from json", name);
337                 goto error;
338         }
339
340         cursor++;
341
342         if (!json_reader_read_member(jparser->reader, pnode))
343         {
344                 cursor++;
345                 _DBG("[%s] Fail to read member from json", pnode);
346                 goto error;
347         }
348
349         cursor++;
350
351         if (!json_reader_read_member(jparser->reader, JSONSTR_SETTINGUI_ARGS))
352         {
353                 cursor++;
354                 _DBG("[%s] Fail to read member from json", JSONSTR_SETTINGUI_ARGS);
355                 goto error;
356         }
357
358         cursor++;
359
360         *cnt = json_reader_count_members(jparser->reader);
361         list = json_reader_list_members(jparser->reader);
362         _restore_json_reader_location(jparser, cursor);
363
364         return list;
365
366 error:
367         _restore_json_reader_location(jparser, cursor);
368         *cnt = 0;
369
370         return NULL;
371 }
372
373 /**
374 *  Retrieve given item data property key-value pair list from json file.
375 *
376 *  According to name value to locate given item of settingitems object,
377 *  then retrieve data property key-value pair list.
378 *
379 *  @param jparser [in] The json_parser data pointer.
380 *  @param name [in] The item name.
381 *  @param cnt [out] The property key-value pair numbers.
382 *  @return given property key-value pair list, NULL on error.
383 */
384 char **parser_get_data_list_from_json(struct json_parser *jparser,
385                 const char *name, int *cnt)
386 {
387         char **list;
388         int cursor;
389
390         if (!jparser || !name || !cnt)
391                 return NULL;
392
393         cursor = 0;
394
395         if (!json_reader_read_member(jparser->reader, JSONSTR_SETTING_ITEMS))
396         {
397                 cursor++;
398                 _DBG("[%s] Fail to read member from json", JSONSTR_SETTING_ITEMS);
399                 goto error;
400         }
401         cursor++;
402
403         if (!json_reader_read_member(jparser->reader, name))
404         {
405                 cursor++;
406                 _DBG("[%s] Fail to read member from json", name);
407                 goto error;
408         }
409         cursor++;
410
411         if (!json_reader_read_member(jparser->reader, JSONSTR_DATA))
412         {
413                 cursor++;
414                 _DBG("[%s] Fail to read member from json", JSONSTR_DATA);
415                 goto error;
416         }
417         cursor++;
418
419         *cnt = json_reader_count_members(jparser->reader);
420         list = json_reader_list_members(jparser->reader);
421         _restore_json_reader_location(jparser, cursor);
422
423         return list;
424
425 error:
426         _restore_json_reader_location(jparser, cursor);
427         *cnt = 0;
428
429         return NULL;
430 }
431
432 /**
433 *  Retrieve property value with given json path.
434 *
435 *  Get property raw value with given json path, then trim raw value and copy it to buffer
436 *  and return buffer pointer.
437 *
438 *  @param jparser [in] The json_parser data pointer.
439 *  @param path [in] The json path.
440 *  @return given property string value, NULL on error.
441 */
442 char *parser_get_string_value_from_json(struct json_parser *jparser,
443                 const char *path)
444 {
445         gchar *output;
446         char *result;
447         char **arr;
448         unsigned int cnt;
449
450         if (!jparser || !path) {
451                 _ERR("Invalid argument!\n");
452                 return NULL;
453         }
454
455         output = _get_jsonpath_result(jparser, path);
456         if (!output) {
457                 _ERR("WRONG PATH:%s", path);
458                 return NULL;
459         }
460
461         if (!strcmp(output, "[]") ||
462                         !strncmp(output, "[\n]", strlen(output))) {
463                 g_free(output);
464                 return NULL;
465         }
466
467         result = calloc(1, sizeof(char) * ARRAY_SIZE);
468         if (!result) {
469                 g_free(output);
470                 return NULL;
471         }
472
473         cnt = 0;
474         arr = eina_str_split_full(output, "\"", 0, &cnt);
475
476         if (cnt == 3)
477                 strncpy(result, arr[1], ARRAY_SIZE - 1);
478         else if (cnt > 3)
479                 _ERR("Wrong API called %d", cnt);
480
481         free(arr[0]);
482         free(arr);
483         g_free(output);
484
485         return result;
486 }
487
488 /**
489 *  Retrieve property array value with given json path.
490 *
491 *  Get property raw array value with given json path, then trim raw array value and iterate it
492 *  to get every string value and store them into eina list.
493 *
494 *  @param jparser [in] The json_parser data pointer.
495 *  @param path [in] The json path.
496 *  @return given property string value eina list, NULL on error.
497 */
498 Eina_List *parser_get_string_list_from_json(struct json_parser *jparser,
499                 const char *path)
500 {
501         gchar *output;
502         char **arr;
503         unsigned int i, cnt;
504         Eina_List *list;
505         char *result;
506
507         if (!jparser || !path)
508                 return NULL;
509
510         output = _get_jsonpath_result(jparser, path);
511
512         if (!output) {
513                 _ERR("Data from json is NULL");
514                 return NULL;
515         }
516
517         if (!strncmp(output, "[]", strlen(output)) ||
518                         !strncmp(output, "[\n]", strlen(output))) {
519                 g_free(output);
520                 return NULL;
521         }
522
523         cnt = 0;
524         arr = eina_str_split_full(output, "\"", 0, &cnt);
525         cnt /= 2;
526
527         list = NULL;
528         for (i = 0; i < cnt; i++) {
529                 result = calloc(1, sizeof(char) * ARRAY_SIZE);
530                 if (!result) {
531                         free(arr[0]);
532                         free(arr);
533                         g_free(output);
534                         return NULL;
535                 }
536
537                 strncpy(result, arr[2*i+1], ARRAY_SIZE - 1);
538                 list = eina_list_append(list, result);
539         }
540
541         free(arr[0]);
542         free(arr);
543         g_free(output);
544
545         return list;
546 }
547
548 /**
549 *  Retrieve property array length with given json path.
550 *
551 *  According to path to locate json property node, then get the given node's array length.
552 *
553 *  @param jparser [in] The json_parser data pointer.
554 *  @param path [in] The json path.
555 *  @return given property array length, 0 on error.
556 */
557 int parser_get_array_length_from_json(struct json_parser *jparser,
558                 const char *path)
559 {
560         unsigned int i, cnt;
561         int len;
562         char **arr;
563
564         if (!jparser || !path)
565                 return 0;
566
567         cnt = 0;
568         arr = eina_str_split_full(path, ".", 0, &cnt);
569
570         for (i = 1; i < cnt; i++) {
571                 if (!json_reader_read_member(jparser->reader, arr[i])) {
572                         while(i){
573                                 json_reader_end_member(jparser->reader);
574                                 i--;
575                         }
576
577                         free(arr[0]);
578                         free(arr);
579                         return 0;
580                 }
581         }
582
583         len = 0;
584         if (json_reader_is_array(jparser->reader))
585                 len = json_reader_count_elements(jparser->reader);
586
587         for (i = 1; i < cnt; i++)
588                 json_reader_end_member(jparser->reader);
589
590         free(arr[0]);
591         free(arr);
592
593         return len;
594 }
595
596 /**
597 *  check raw property value wether correct or not.
598 *
599 *  @param jparser [in] The json_parser data pointer.
600 *  @param path [in] The json path.
601 *  @return true if correct, false if error.
602 */
603 bool parser_check_json_path(struct json_parser *jparser, const char *path)
604 {
605         char *output;
606
607         if (!jparser || !path)
608                 return false;
609
610         output = _get_jsonpath_result(jparser, path);
611         if (!output) {
612                 _ERR("WRONG PATH:%s", path);
613                 return false;
614         }
615
616         if (!strncmp(output, "[]", strlen(output)) ||
617                         !strncmp(output, "[\n]", strlen(output))) {
618                 g_free(output);
619                 return false;
620         }
621
622         g_free(output);
623
624         return true;
625 }
626
627 /**
628 *  Get given item's parent item name value with given json file path.
629 *
630 *  @param path [in] The json file path.
631 *  @param name [in] The given item name.
632 *  @return given item's parent item name string value, NULL on error.
633 */
634 char *parser_get_parent_item_name(const char *path, const char *name)
635 {
636         struct json_parser *jparser;
637         char buf[ARRAY_SIZE];
638         char *val;
639
640         jparser = parser_init(path);
641         if (!jparser) {
642                 _ERR("json parser init failed.");
643                 return NULL;
644         }
645
646         snprintf(buf, sizeof(buf), "$.%s", name);
647
648         val = parser_get_string_value_from_json(jparser, buf);
649         if (!val) {
650                 _ERR("json parser get string value failed.");
651                 parser_fini(jparser);
652                 return NULL;
653         }
654
655         parser_fini(jparser);
656
657         return val;
658 }