Initialize Tizen 2.3
[apps/livebox/livebox-viewer.git] / src / desc_parser.c
1 /*
2  * Copyright 2013  Samsung Electronics Co., Ltd
3  *
4  * Licensed under the Flora License, Version 1.1 (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://floralicense.org/license/
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 <stdio.h>
18 #include <errno.h>
19 #include <stdlib.h> /* malloc */
20 #include <string.h> /* strdup */
21 #include <ctype.h>
22 #include <fcntl.h>
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <unistd.h>
26
27 #include <gio/gio.h>
28 #include <dlog.h>
29 #include <livebox-errno.h>
30 #include <livebox-service.h>
31
32 #include "debug.h"
33 #include "livebox.h"
34 #include "livebox_internal.h"
35 #include "desc_parser.h"
36 #include "dlist.h"
37 #include "util.h"
38
39 #define INFO_SIZE "size"
40 #define INFO_CATEGORY "category"
41
42 static const char *type_list[] = {
43         "access",
44         "access,operation",
45         "color",
46         "drag",
47         "image",
48         "info",
49         "script",
50         "signal",
51         "text",
52         NULL
53 };
54
55 static const char *field_list[] = {
56         "type",
57         "part",
58         "data",
59         "option",
60         "id",
61         "target",
62         "file",
63         NULL
64 };
65
66 enum block_type {
67         TYPE_ACCESS,
68         TYPE_ACCESS_OP,
69         TYPE_COLOR,
70         TYPE_DRAG,
71         TYPE_IMAGE,
72         TYPE_INFO,
73         TYPE_SCRIPT,
74         TYPE_SIGNAL,
75         TYPE_TEXT,
76         TYPE_MAX
77 };
78
79 enum field_type {
80         FIELD_TYPE,
81         FIELD_PART,
82         FIELD_DATA,
83         FIELD_OPTION,
84         FIELD_ID,
85         FIELD_TARGET,
86         FIELD_FILE
87 };
88
89 struct block {
90         enum block_type type;
91         char *part;
92         char *data;
93         char *option;
94         char *id;
95         char *target;
96         char *file;
97
98         /* Should be released */
99         char *filebuf;
100         const char *filename;
101 };
102
103 static int update_text(struct livebox *handle, struct block *block, int is_pd)
104 {
105         struct livebox_script_operators *ops;
106
107         if (!block || !block->part || !block->data) {
108                 ErrPrint("Invalid argument\n");
109                 return LB_STATUS_ERROR_INVALID;
110         }
111
112         ops = is_pd ? &handle->cbs.pd_ops : &handle->cbs.lb_ops;
113         if (ops->update_text) {
114                 ops->update_text(handle, (const char *)block->id, (const char *)block->part, (const char *)block->data);
115         }
116
117         return 0;
118 }
119
120 static int update_image(struct livebox *handle, struct block *block, int is_pd)
121 {
122         struct livebox_script_operators *ops;
123
124         if (!block || !block->part) {
125                 ErrPrint("Invalid argument\n");
126                 return LB_STATUS_ERROR_INVALID;
127         }
128
129         ops = is_pd ? &handle->cbs.pd_ops : &handle->cbs.lb_ops;
130         if (ops->update_image) {
131                 ops->update_image(handle, block->id, block->part, block->data, block->option);
132         }
133
134         return 0;
135 }
136
137 static int update_script(struct livebox *handle, struct block *block, int is_pd)
138 {
139         struct livebox_script_operators *ops;
140
141         if (!block || !block->part) {
142                 ErrPrint("Invalid argument\n");
143                 return LB_STATUS_ERROR_INVALID;
144         }
145
146         ops = is_pd ? &handle->cbs.pd_ops : &handle->cbs.lb_ops;
147         if (ops->update_script) {
148                 ops->update_script(handle, block->id, block->target, block->part, block->data, block->option);
149         }
150
151         return 0;
152 }
153
154 static int update_signal(struct livebox *handle, struct block *block, int is_pd)
155 {
156         struct livebox_script_operators *ops;
157
158         if (!block) {
159                 ErrPrint("Invalid argument\n");
160                 return LB_STATUS_ERROR_INVALID;
161         }
162
163         ops = is_pd ? &handle->cbs.pd_ops : &handle->cbs.lb_ops;
164         if (ops->update_signal) {
165                 ops->update_signal(handle, block->id, block->data, block->part);
166         }
167
168         return 0;
169 }
170
171 static int update_drag(struct livebox *handle, struct block *block, int is_pd)
172 {
173         double dx, dy;
174         struct livebox_script_operators *ops;
175
176         if (!block || !block->data || !block->part) {
177                 ErrPrint("Invalid argument\n");
178                 return LB_STATUS_ERROR_INVALID;
179         }
180
181         if (sscanf(block->data, "%lfx%lf", &dx, &dy) != 2) {
182                 ErrPrint("Invalid format of data\n");
183                 return LB_STATUS_ERROR_INVALID;
184         }
185
186         ops = is_pd ? &handle->cbs.pd_ops : &handle->cbs.lb_ops;
187         if (ops->update_drag) {
188                 ops->update_drag(handle, block->id, block->part, dx, dy);
189         }
190
191         return 0;
192 }
193
194 static int update_info(struct livebox *handle, struct block *block, int is_pd)
195 {
196         struct livebox_script_operators *ops;
197
198         if (!block || !block->part || !block->data) {
199                 ErrPrint("Invalid argument\n");
200                 return LB_STATUS_ERROR_INVALID;
201         }
202
203         ops = is_pd ? &handle->cbs.pd_ops : &handle->cbs.lb_ops;
204         if (!strcasecmp(block->part, INFO_SIZE)) {
205                 int w, h;
206
207                 if (sscanf(block->data, "%dx%d", &w, &h) != 2) {
208                         ErrPrint("Invalid format (%s)\n", block->data);
209                         return LB_STATUS_ERROR_INVALID;
210                 }
211
212                 if (ops->update_info_size) {
213                         ops->update_info_size(handle, block->id, w, h);
214                 }
215         } else if (!strcasecmp(block->part, INFO_CATEGORY)) {
216                 if (ops->update_info_category) {
217                         ops->update_info_category(handle, block->id, block->data);
218                 }
219         }
220
221         return 0;
222 }
223
224 static int update_access(struct livebox *handle, struct block *block, int is_pd)
225 {
226         struct livebox_script_operators *ops;
227
228         if (!block) {
229                 ErrPrint("Invalid argument\n");
230                 return LB_STATUS_ERROR_INVALID;
231         }
232
233         ops = is_pd ? &handle->cbs.pd_ops : &handle->cbs.lb_ops;
234         if (ops->update_access) {
235                 ops->update_access(handle, block->id, block->part, block->data, block->option);
236         }
237
238         return 0;
239 }
240
241 static int operate_access(struct livebox *handle, struct block *block, int is_pd)
242 {
243         struct livebox_script_operators *ops;
244
245         if (!block) {
246                 ErrPrint("Invalid argument\n");
247                 return LB_STATUS_ERROR_INVALID;
248         }
249
250         ops = is_pd ? &handle->cbs.pd_ops : &handle->cbs.lb_ops;
251         if (ops->operate_access) {
252                 ops->operate_access(handle, block->id, block->part, block->data, block->option);
253         }
254
255         return 0;
256 }
257
258 static int update_color(struct livebox *handle, struct block *block, int is_pd)
259 {
260         struct livebox_script_operators *ops;
261
262         if (!block) {
263                 ErrPrint("Invalid argument\n");
264                 return LB_STATUS_ERROR_INVALID;
265         }
266
267         ops = is_pd ? &handle->cbs.pd_ops : &handle->cbs.lb_ops;
268         if (ops->update_color) {
269                 ops->update_color(handle, block->id, block->part, block->data);
270         }
271
272         return 0;
273 }
274
275 static inline int update_begin(struct livebox *handle, int is_pd)
276 {
277         struct livebox_script_operators *ops;
278
279         ops = is_pd ? &handle->cbs.pd_ops : &handle->cbs.lb_ops;
280         if (ops->update_begin) {
281                 ops->update_begin(handle);
282         }
283
284         return 0;
285 }
286
287 static inline int update_end(struct livebox *handle, int is_pd)
288 {
289         struct livebox_script_operators *ops;
290
291         ops = is_pd ? &handle->cbs.pd_ops : &handle->cbs.lb_ops;
292         if (ops->update_end) {
293                 ops->update_end(handle);
294         }
295
296         return 0;
297 }
298
299 static inline void delete_block(struct block *block)
300 {
301         free(block->filebuf);
302         free(block);
303 }
304
305 static inline void consuming_parsed_block(struct livebox *handle, int is_pd, struct block *block)
306 {
307         typedef int (*update_function_t)(struct livebox *handle, struct block *block, int is_pd);
308         static update_function_t updators[] = {
309                 update_access,
310                 operate_access,
311                 update_color,
312                 update_drag,
313                 update_image,
314                 update_info,
315                 update_script,
316                 update_signal,
317                 update_text,
318                 NULL
319         };
320
321         if (block->type >= 0 || block->type < TYPE_MAX) {
322                 (void)updators[block->type](handle, block, is_pd);
323         } else {
324                 ErrPrint("Block type[%d] is not valid\n", block->type);
325         }
326 }
327
328 static inline char *load_file(const char *filename)
329 {
330         char *filebuf = NULL;
331         int fd;
332         off_t filesize;
333         int ret;
334         size_t readsize = 0;
335
336         fd = open(filename, O_RDONLY);
337         if (fd < 0) {
338                 ErrPrint("open: %s\n", strerror(errno));
339                 return NULL;
340         }
341
342         filesize = lseek(fd, 0L, SEEK_END);
343         if (filesize == (off_t)-1) {
344                 ErrPrint("lseek: %s\n", strerror(errno));
345                 goto errout;
346         }
347
348         if (lseek(fd, 0L, SEEK_SET) < 0) {
349                 ErrPrint("lseek: %s\n", strerror(errno));
350                 goto errout;
351         }
352
353         filebuf = malloc(filesize + 1);
354         if (!filebuf) {
355                 ErrPrint("malloc: %s\n", strerror(errno));
356                 goto errout;
357         }
358
359         while (readsize < filesize) {
360                 ret = read(fd, filebuf + readsize, (size_t)filesize - readsize);
361                 if (ret < 0) {
362                         if (errno == EINTR) {
363                                 DbgPrint("Read is interrupted\n");
364                                 continue;
365                         }
366
367                         ErrPrint("read: %s\n", strerror(errno));
368                         free(filebuf);
369                         filebuf = NULL;
370                         break;
371                 }
372
373                 readsize += ret;
374         }
375
376         if (filebuf) {
377                 filebuf[readsize] = '\0';
378         }
379
380         /*!
381          * \note
382          * Now, we are ready to parse the filebuf.
383          */
384
385 errout:
386         if (close(fd) < 0) {
387                 ErrPrint("close: %s\n", strerror(errno));
388         }
389
390         return filebuf;
391 }
392
393 int parse_desc(struct livebox_common *common, const char *filename, int is_pd)
394 {
395         int type_idx = 0;
396         int type_len = 0;
397         int field_idx = 0;
398         int field_len = 0;
399         char *filebuf;
400         char *fileptr;
401         char *ptr = NULL;
402         struct block *block = NULL;
403         struct dlist *block_list = NULL;
404         struct dlist *l;
405         struct dlist *n;
406         struct dlist *handle_iterator;
407         struct livebox *handler;
408         enum state {
409                 BEGIN,
410                 FIELD,
411                 DATA,
412                 END,
413                 DONE,
414                 ERROR,
415         } state;
416
417         filebuf = load_file(filename);
418         if (!filebuf) {
419                 return LB_STATUS_ERROR_IO;
420         }
421
422         fileptr = filebuf;
423
424         state = BEGIN;
425         while (*fileptr && state != ERROR) {
426                 switch (state) {
427                 case BEGIN:
428                         if (*fileptr == '{') {
429                                 block = calloc(1, sizeof(*block));
430                                 if (!block) {
431                                         ErrPrint("calloc: %s\n", strerror(errno));
432                                         state = ERROR;
433                                         continue;
434                                 }
435                                 state = FIELD;
436                                 ptr = NULL;
437                         }
438                         break;
439                 case FIELD:
440                         if (isspace(*fileptr)) {
441                                 if (ptr != NULL) {
442                                         *fileptr = '\0';
443                                 }
444                         } else if (*fileptr == '=') {
445                                 *fileptr = '\0';
446                                 ptr = NULL;
447                                 state = DATA;
448                         } else if (ptr == NULL) {
449                                 ptr = fileptr;
450                                 field_idx = 0;
451                                 field_len = 0;
452
453                                 while (field_list[field_idx]) {
454                                         if (field_list[field_idx][field_len] == *fileptr) {
455                                                 break;
456                                         }
457                                         field_idx++;
458                                 }
459
460                                 if (!field_list[field_idx]) {
461                                         ErrPrint("Invalid field\n");
462                                         state = ERROR;
463                                         continue;
464                                 }
465
466                                 field_len++;
467                         } else {
468                                 if (field_list[field_idx][field_len] != *fileptr) {
469                                         field_idx++;
470                                         while (field_list[field_idx]) {
471                                                 if (!strncmp(field_list[field_idx], fileptr - field_len, field_len)) {
472                                                         break;
473                                                 } else {
474                                                         field_idx++;
475                                                 }
476                                         }
477
478                                         if (!field_list[field_idx]) {
479                                                 state = ERROR;
480                                                 ErrPrint("field is not valid\n");
481                                                 continue;
482                                         }
483                                 }
484
485                                 field_len++;
486                         }
487                         break;
488                 case DATA:
489                         switch (field_idx) {
490                         case FIELD_TYPE:
491                                 if (ptr == NULL) {
492                                         if (isspace(*fileptr)) {
493                                                 break;
494                                         }
495
496                                         if (*fileptr == '\0') {
497                                                 state = ERROR;
498                                                 ErrPrint("Type is not valid\n");
499                                                 continue;
500                                         }
501
502                                         ptr = fileptr;
503                                         type_idx = 0;
504                                         type_len = 0;
505                                 }
506
507                                 if (*fileptr && (*fileptr == '\n' || *fileptr == '\r' || *fileptr == '\f')) {
508                                         *fileptr = '\0';
509                                 }
510
511                                 if (type_list[type_idx][type_len] != *fileptr) {
512                                         type_idx++;
513                                         while (type_list[type_idx]) {
514                                                 if (!strncmp(type_list[type_idx], fileptr - type_len, type_len)) {
515                                                         break;
516                                                 } else {
517                                                         type_idx++;
518                                                 }
519                                         }
520
521                                         if (!type_list[type_idx]) {
522                                                 state = ERROR;
523                                                 ErrPrint("type is not valid (%s)\n", fileptr - type_len);
524                                                 continue;
525                                         }
526                                 }
527
528                                 if (!*fileptr) {
529                                         block->type = type_idx;
530                                         state = DONE;
531                                         ptr = NULL;
532                                 }
533
534                                 type_len++;
535                                 break;
536                         case FIELD_PART:
537                                 if (ptr == NULL) {
538                                         ptr = fileptr;
539                                 }
540
541                                 if (*fileptr && (*fileptr == '\n' || *fileptr == '\r' || *fileptr == '\f')) {
542                                         *fileptr = '\0';
543                                 }
544
545                                 if (!*fileptr) {
546                                         block->part = ptr;
547                                         state = DONE;
548                                         ptr = NULL;
549                                 }
550                                 break;
551                         case FIELD_DATA:
552                                 if (ptr == NULL) {
553                                         ptr = fileptr;
554                                 }
555
556                                 if (*fileptr && (*fileptr == '\n' || *fileptr == '\r' || *fileptr == '\f')) {
557                                         *fileptr = '\0';
558                                 }
559
560                                 if (!*fileptr) {
561                                         block->data = ptr;
562                                         state = DONE;
563                                         ptr = NULL;
564                                 }
565                                 break;
566                         case FIELD_OPTION:
567                                 if (ptr == NULL) {
568                                         ptr = fileptr;
569                                 }
570
571                                 if (*fileptr && (*fileptr == '\n' || *fileptr == '\r' || *fileptr == '\f')) {
572                                         *fileptr = '\0';
573                                 }
574
575                                 if (!*fileptr) {
576                                         block->option = ptr;
577                                         state = DONE;
578                                         ptr = NULL;
579                                 }
580                                 break;
581                         case FIELD_ID:
582                                 if (ptr == NULL) {
583                                         ptr = fileptr;
584                                 }
585
586                                 if (*fileptr && (*fileptr == '\n' || *fileptr == '\r' || *fileptr == '\f')) {
587                                         *fileptr = '\0';
588                                 }
589
590                                 if (!*fileptr) {
591                                         block->id = ptr;
592                                         state = DONE;
593                                         ptr = NULL;
594                                 }
595                                 break;
596                         case FIELD_TARGET:
597                                 if (ptr == NULL) {
598                                         ptr = fileptr;
599                                 }
600
601                                 if (*fileptr && (*fileptr == '\n' || *fileptr == '\r' || *fileptr == '\f')) {
602                                         *fileptr = '\0';
603                                 }
604
605                                 if (!*fileptr) {
606                                         block->target = ptr;
607                                         state = DONE;
608                                         ptr = NULL;
609                                 }
610                                 break;
611                         case FIELD_FILE:
612                                 if (ptr == NULL) {
613                                         ptr = fileptr;
614                                 }
615
616                                 if (*fileptr && (*fileptr == '\n' || *fileptr == '\r' || *fileptr == '\f')) {
617                                         *fileptr = '\0';
618                                 }
619
620                                 if (!*fileptr) {
621                                         block->target = ptr;
622                                         state = DONE;
623                                         ptr = NULL;
624                                 }
625                         default:
626                                 break;
627                         }
628
629                         break;
630                 case DONE:
631                         if (isspace(*fileptr)) {
632                         } else if (*fileptr == '}') {
633                                         state = BEGIN;
634                                         block->filename = filename;
635                                         block_list = dlist_append(block_list, block);
636                                         block = NULL;
637                         } else {
638                                 state = FIELD;
639                                 continue;
640                         }
641                         break;
642                 case END:
643                 default:
644                         break;
645                 }
646
647                 fileptr++;
648         }
649
650         if (state != BEGIN) {
651                 struct dlist *l;
652                 struct dlist *n;
653                 ErrPrint("State %d\n", state);
654
655                 free(filebuf);
656                 free(block);
657
658                 dlist_foreach_safe(block_list, l, n, block) {
659                         free(block);
660                         block_list = dlist_remove(block_list, l);
661                 }
662
663                 return LB_STATUS_ERROR_FAULT;
664         }
665
666                 
667         block = dlist_data(dlist_prev(block_list));
668         if (block) {
669                 block->filebuf = filebuf;
670         } else {
671                 ErrPrint("Last block is not exists (There is no parsed block)\n");
672                 free(filebuf);
673         }
674
675         ErrPrint("Begin: Set content for object\n");
676         dlist_foreach(common->livebox_list, l, handler) {
677                 update_begin(handler, is_pd);
678         }
679
680         dlist_foreach_safe(block_list, l, n, block) {
681                 dlist_foreach(common->livebox_list, handle_iterator, handler) {
682                         consuming_parsed_block(handler, is_pd, block);
683                 }
684
685                 block_list = dlist_remove(block_list, l);
686                 delete_block(block);
687         }
688
689         dlist_foreach(common->livebox_list, l, handler) {
690                 update_end(handler, is_pd);
691         }
692         ErrPrint("End: Set content for object\n");
693
694         return LB_STATUS_SUCCESS;
695 }
696
697 /* End of a file */