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