Update accessibiility operation
[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
23 #include <dlog.h>
24 #include <livebox-errno.h>
25
26 #include "debug.h"
27 #include "livebox.h"
28 #include "livebox_internal.h"
29 #include "desc_parser.h"
30 #include "dlist.h"
31 #include "util.h"
32 #include "critical_log.h"
33
34 #define TYPE_TEXT "text"
35 #define TYPE_IMAGE "image"
36 #define TYPE_EDJE "edje"
37 #define TYPE_SIGNAL "signal"
38 #define TYPE_INFO "info"
39 #define TYPE_DRAG "drag"
40 #define TYPE_ACCESS "access"
41 #define TYPE_OPERATE_ACCESS "access,operation"
42
43 #define INFO_SIZE "size"
44 #define INFO_CATEGORY "category"
45
46 struct block {
47         char *type;
48         int type_len;
49
50         char *part;
51         int part_len;
52
53         char *data;
54         int data_len;
55
56         char *file;
57         int file_len;
58
59         char *option;
60         int option_len;
61
62         char *id;
63         int id_len;
64 };
65
66 static int update_text(struct livebox *handle, struct block *block, int is_pd)
67 {
68         struct livebox_script_operators *ops;
69
70         if (!block || !block->part || !block->data) {
71                 ErrPrint("Invalid argument\n");
72                 return LB_STATUS_ERROR_INVALID;
73         }
74
75         ops = is_pd ? &handle->pd.data.ops : &handle->lb.data.ops;
76         if (ops->update_text) {
77                 ops->update_text(handle, (const char *)block->id, (const char *)block->part, (const char *)block->data);
78         }
79
80         return 0;
81 }
82
83 static int update_image(struct livebox *handle, struct block *block, int is_pd)
84 {
85         struct livebox_script_operators *ops;
86         if (!block || !block->part) {
87                 ErrPrint("Invalid argument\n");
88                 return LB_STATUS_ERROR_INVALID;
89         }
90
91         ops = is_pd ? &handle->pd.data.ops : &handle->lb.data.ops;
92         if (ops->update_image) {
93                 ops->update_image(handle, block->id, block->part, block->data, block->option);
94         }
95
96         return 0;
97 }
98
99 static int update_script(struct livebox *handle, struct block *block, int is_pd)
100 {
101         struct livebox_script_operators *ops;
102         if (!block || !block->part) {
103                 ErrPrint("Invalid argument\n");
104                 return LB_STATUS_ERROR_INVALID;
105         }
106
107         ops = is_pd ? &handle->pd.data.ops : &handle->lb.data.ops;
108         if (ops->update_script) {
109                 ops->update_script(handle, block->id, block->part, block->data, block->option);
110         }
111
112         return 0;
113 }
114
115 static int update_signal(struct livebox *handle, struct block *block, int is_pd)
116 {
117         struct livebox_script_operators *ops;
118
119         if (!block) {
120                 ErrPrint("Invalid argument\n");
121                 return LB_STATUS_ERROR_INVALID;
122         }
123
124         ops = is_pd ? &handle->pd.data.ops : &handle->lb.data.ops;
125         if (ops->update_signal) {
126                 ops->update_signal(handle, block->id, block->data, block->part);
127         }
128
129         return 0;
130 }
131
132 static int update_drag(struct livebox *handle, struct block *block, int is_pd)
133 {
134         double dx, dy;
135         struct livebox_script_operators *ops;
136
137         if (!block || !block->data || !block->part) {
138                 ErrPrint("Invalid argument\n");
139                 return LB_STATUS_ERROR_INVALID;
140         }
141
142         ops = is_pd ? &handle->pd.data.ops : &handle->lb.data.ops;
143
144         if (sscanf(block->data, "%lfx%lf", &dx, &dy) != 2) {
145                 ErrPrint("Invalid format of data\n");
146                 return LB_STATUS_ERROR_INVALID;
147         }
148
149         if (ops->update_drag) {
150                 ops->update_drag(handle, block->id, block->part, dx, dy);
151         }
152
153         return 0;
154 }
155
156 static int update_info(struct livebox *handle, struct block *block, int is_pd)
157 {
158         struct livebox_script_operators *ops;
159
160         if (!block || !block->part || !block->data) {
161                 ErrPrint("Invalid argument\n");
162                 return LB_STATUS_ERROR_INVALID;
163         }
164
165         ops = is_pd ? &handle->pd.data.ops : &handle->lb.data.ops;
166
167         if (!strcasecmp(block->part, INFO_SIZE)) {
168                 int w, h;
169
170                 if (sscanf(block->data, "%dx%d", &w, &h) != 2) {
171                         ErrPrint("Invalid format (%s)\n", block->data);
172                         return LB_STATUS_ERROR_INVALID;
173                 }
174
175                 if (ops->update_info_size) {
176                         ops->update_info_size(handle, block->id, w, h);
177                 }
178         } else if (!strcasecmp(block->part, INFO_CATEGORY)) {
179                 if (ops->update_info_category) {
180                         ops->update_info_category(handle, block->id, block->data);
181                 }
182         }
183
184         return 0;
185 }
186
187 static int update_access(struct livebox *handle, struct block *block, int is_pd)
188 {
189         struct livebox_script_operators *ops;
190
191         if (!block) {
192                 ErrPrint("Invalid argument\n");
193                 return LB_STATUS_ERROR_INVALID;
194         }
195
196         ops = is_pd ? &handle->pd.data.ops : &handle->lb.data.ops;
197         if (ops->update_access) {
198                 ops->update_access(handle, block->id, block->part, block->data, block->option);
199         }
200
201         return 0;
202 }
203
204 static int operate_access(struct livebox *handle, struct block *block, int is_pd)
205 {
206         struct livebox_script_operators *ops;
207
208         if (!block) {
209                 ErrPrint("Invalid argument\n");
210                 return LB_STATUS_ERROR_INVALID;
211         }
212
213         ops = is_pd ? &handle->pd.data.ops : &handle->lb.data.ops;
214         if (ops->operate_access) {
215                 ops->operate_access(handle, block->id, block->part, block->data, block->option);
216         }
217
218         return 0;
219 }
220
221 static inline int update_begin(struct livebox *handle, int is_pd)
222 {
223         struct livebox_script_operators *ops;
224
225         ops = is_pd ? &handle->pd.data.ops : &handle->lb.data.ops;
226
227         if (ops->update_begin) {
228                 ops->update_begin(handle);
229         }
230
231         return 0;
232 }
233
234 static inline int update_end(struct livebox *handle, int is_pd)
235 {
236         struct livebox_script_operators *ops;
237
238         ops = is_pd ? &handle->pd.data.ops : &handle->lb.data.ops;
239
240         if (ops->update_end) {
241                 ops->update_end(handle);
242         }
243
244         return 0;
245 }
246
247 int parse_desc(struct livebox *handle, const char *descfile, int is_pd)
248 {
249         FILE *fp;
250         int ch;
251         enum state {
252                 UNKNOWN = 0x10,
253                 BLOCK_OPEN = 0x11,
254                 FIELD = 0x12,
255                 VALUE = 0x13,
256                 BLOCK_CLOSE = 0x14,
257
258                 VALUE_TYPE = 0x00,
259                 VALUE_PART = 0x01,
260                 VALUE_DATA = 0x02,
261                 VALUE_FILE = 0x03,
262                 VALUE_OPTION = 0x04,
263                 VALUE_ID = 0x05
264         };
265         const char *field_name[] = {
266                 "type",
267                 "part",
268                 "data",
269                 "file",
270                 "option",
271                 "id",
272                 NULL
273         };
274         enum state state;
275         register int field_idx;
276         register int idx = 0;
277         register int i;
278         struct block *block;
279         struct {
280                 const char *type;
281                 int (*handler)(struct livebox *handle, struct block *block, int is_pd);
282         } handlers[] = {
283                 {
284                         .type = TYPE_TEXT,
285                         .handler = update_text,
286                 },
287                 {
288                         .type = TYPE_IMAGE,
289                         .handler = update_image,
290                 },
291                 {
292                         .type = TYPE_EDJE,
293                         .handler = update_script,
294                 },
295                 {
296                         .type = TYPE_SIGNAL,
297                         .handler = update_signal,
298                 },
299                 {
300                         .type = TYPE_DRAG,
301                         .handler = update_drag,
302                 },
303                 {
304                         .type = TYPE_INFO,
305                         .handler = update_info,
306                 },
307                 {
308                         .type = TYPE_ACCESS,
309                         .handler = update_access,
310                 },
311                 {
312                         .type = TYPE_OPERATE_ACCESS,
313                         .handler = operate_access,
314                 },
315                 {
316                         .type = NULL,
317                         .handler = NULL,
318                 },
319         };
320
321         fp = fopen(descfile, "rt");
322         if (!fp) {
323                 ErrPrint("Error: %s\n", strerror(errno));
324                 return LB_STATUS_ERROR_IO;
325         }
326
327         update_begin(handle, is_pd);
328
329         state = UNKNOWN;
330         field_idx = 0;
331
332         block = NULL;
333         while (!feof(fp)) {
334                 ch = getc(fp);
335
336                 switch (state) {
337                 case UNKNOWN:
338                         if (ch == '{') {
339                                 state = BLOCK_OPEN;
340                                 break;
341                         }
342
343                         if (!isspace(ch)) {
344                                 update_end(handle, is_pd);
345                                 if (fclose(fp) != 0) {
346                                         ErrPrint("fclose: %s\n", strerror(errno));
347                                 }
348                                 return LB_STATUS_ERROR_INVALID;
349                         }
350                         break;
351
352                 case BLOCK_OPEN:
353                         if (isblank(ch)) {
354                                 break;
355                         }
356
357                         if (ch != '\n') {
358                                 goto errout;
359                         }
360
361                         block = calloc(1, sizeof(*block));
362                         if (!block) {
363                                 CRITICAL_LOG("Heap: %s\n", strerror(errno));
364                                 update_end(handle, is_pd);
365                                 if (fclose(fp) != 0) {
366                                         ErrPrint("fclose: %s\n", strerror(errno));
367                                 }
368                                 return LB_STATUS_ERROR_MEMORY;
369                         }
370
371                         state = FIELD;
372                         idx = 0;
373                         field_idx = 0;
374                         break;
375
376                 case FIELD:
377                         if (isspace(ch)) {
378                                 break;
379                         }
380
381                         if (ch == '}') {
382                                 state = BLOCK_CLOSE;
383                                 break;
384                         }
385
386                         if (ch == '=') {
387                                 if (field_name[field_idx][idx] != '\0') {
388                                         goto errout;
389                                 }
390
391                                 switch (field_idx) {
392                                 case 0:
393                                         state = VALUE_TYPE;
394                                         if (block->type) {
395                                                 free(block->type);
396                                                 block->type = NULL;
397                                                 block->type_len = 0;
398                                         }
399                                         idx = 0;
400                                         break;
401                                 case 1:
402                                         state = VALUE_PART;
403                                         if (block->part) {
404                                                 free(block->part);
405                                                 block->part = NULL;
406                                                 block->part_len = 0;
407                                         }
408                                         idx = 0;
409                                         break;
410                                 case 2:
411                                         state = VALUE_DATA;
412                                         if (block->data) {
413                                                 free(block->data);
414                                                 block->data = NULL;
415                                                 block->data_len = 0;
416                                         }
417                                         idx = 0;
418                                         break;
419                                 case 3:
420                                         state = VALUE_FILE;
421                                         if (block->file) {
422                                                 free(block->file);
423                                                 block->file = NULL;
424                                                 block->file_len = 0;
425                                         }
426                                         idx = 0;
427                                         break;
428                                 case 4:
429                                         state = VALUE_OPTION;
430                                         if (block->option) {
431                                                 free(block->option);
432                                                 block->option = NULL;
433                                                 block->option_len = 0;
434                                         }
435                                         idx = 0;
436                                         break;
437                                 case 5:
438                                         state = VALUE_ID;
439                                         if (block->id) {
440                                                 free(block->id);
441                                                 block->id = NULL;
442                                                 block->id_len = 0;
443                                         }
444                                         idx = 0;
445                                         break;
446                                 default:
447                                         goto errout;
448                                 }
449
450                                 break;
451                         }
452
453                         if (ch == '\n') {
454                                 goto errout;
455                         }
456
457                         if (field_name[field_idx][idx] != ch) {
458                                 if (ungetc(ch, fp) != ch) {
459                                         ErrPrint("ungetc: %s\n", strerror(errno));
460                                 }
461
462                                 while (--idx >= 0) {
463                                         if (ungetc(field_name[field_idx][idx], fp) != field_name[field_idx][idx]) {
464                                                 ErrPrint("ungetc: %s\n", strerror(errno));
465                                         }
466                                 }
467
468                                 field_idx++;
469                                 if (field_name[field_idx] == NULL) {
470                                         goto errout;
471                                 }
472
473                                 idx = 0;
474                                 break;
475                         }
476
477                         idx++;
478                         break;
479
480                 case VALUE_TYPE:
481                         if (idx == block->type_len) {
482                                 block->type_len += 256;
483                                 block->type = realloc(block->type, block->type_len);
484                                 if (!block->type) {
485                                         CRITICAL_LOG("Heap: %s\n", strerror(errno));
486                                         goto errout;
487                                 }
488                         }
489
490                         if (ch == '\n') {
491                                 block->type[idx] = '\0';
492                                 state = FIELD;
493                                 idx = 0;
494                                 field_idx = 0;
495                                 break;
496                         }
497
498                         block->type[idx] = ch;
499                         idx++;
500                         break;
501
502                 case VALUE_PART:
503                         if (idx == block->part_len) {
504                                 block->part_len += 256;
505                                 block->part = realloc(block->part, block->part_len);
506                                 if (!block->part) {
507                                         CRITICAL_LOG("Heap: %s\n", strerror(errno));
508                                         goto errout;
509                                 }
510                         }
511
512                         if (ch == '\n') {
513                                 block->part[idx] = '\0';
514                                 state = FIELD;
515                                 idx = 0;
516                                 field_idx = 0;
517                                 break;
518                         }
519
520                         block->part[idx] = ch;
521                         idx++;
522                         break;
523
524                 case VALUE_DATA:
525                         if (idx == block->data_len) {
526                                 block->data_len += 256;
527                                 block->data = realloc(block->data, block->data_len);
528                                 if (!block->data) {
529                                         CRITICAL_LOG("Heap: %s\n", strerror(errno));
530                                         goto errout;
531                                 }
532                         }
533
534                         if (ch == '\n') {
535                                 block->data[idx] = '\0';
536                                 state = FIELD;
537                                 idx = 0;
538                                 field_idx = 0;
539                                 break;
540                         }
541
542                         block->data[idx] = ch;
543                         idx++;
544                         break;
545
546                 case VALUE_FILE:
547                         if (idx == block->file_len) {
548                                 block->file_len += 256;
549                                 block->file = realloc(block->file, block->file_len);
550                                 if (!block->file) {
551                                         CRITICAL_LOG("Heap: %s\n", strerror(errno));
552                                         goto errout;
553                                 }
554                         }
555
556                         if (ch == '\n') {
557                                 block->file[idx] = '\0';
558                                 state = FIELD;
559                                 idx = 0;
560                                 field_idx = 0;
561                                 break;
562                         }
563
564                         block->file[idx] = ch;
565                         idx++;
566                         break;
567
568                 case VALUE_OPTION:
569                         if (idx == block->option_len) {
570                                 block->option_len += 256;
571                                 block->option = realloc(block->option, block->option_len);
572                                 if (!block->option) {
573                                         CRITICAL_LOG("Heap: %s\n", strerror(errno));
574                                         goto errout;
575                                 }
576                         }
577
578                         if (ch == '\n') {
579                                 block->option[idx] = '\0';
580                                 state = FIELD;
581                                 idx = 0;
582                                 field_idx = 0;
583                                 break;
584                         }
585
586                         block->option[idx] = ch;
587                         idx++;
588                         break;
589                 case VALUE_ID:
590                         if (idx == block->id_len) {
591                                 block->id_len += 256;
592                                 block->id = realloc(block->id, block->id_len);
593                                 if (!block->id) {
594                                         CRITICAL_LOG("Heap: %s\n", strerror(errno));
595                                         goto errout;
596                                 }
597                         }
598
599                         if (ch == '\n') {
600                                 block->id[idx] = '\0';
601                                 state = FIELD;
602                                 idx = 0;
603                                 field_idx = 0;
604                                 break;
605                         }
606
607                         block->id[idx] = ch;
608                         idx++;
609                         break;
610                 case BLOCK_CLOSE:
611                         if (!block->file) {
612                                 block->file = strdup(util_uri_to_path(handle->id));
613                                 if (!block->file) {
614                                         goto errout;
615                                 }
616                         }
617
618                         i = 0;
619                         while (handlers[i].type) {
620                                 if (!strcasecmp(handlers[i].type, block->type)) {
621                                         handlers[i].handler(handle, block, is_pd);
622                                         break;
623                                 }
624                                 i++;
625                         }
626
627                         if (!handlers[i].type) {
628                                 ErrPrint("Unknown block type: %s\n", block->type);
629                         }
630
631                         free(block->file);
632                         free(block->type);
633                         free(block->part);
634                         free(block->data);
635                         free(block->option);
636                         free(block->id);
637                         free(block);
638                         block = NULL;
639
640                         state = UNKNOWN;
641                         break;
642
643                 default:
644                         break;
645                 } /* switch */
646         } /* while */
647
648         if (state != UNKNOWN) {
649                 goto errout;
650         }
651
652         update_end(handle, is_pd);
653
654         if (fclose(fp) != 0) {
655                 ErrPrint("fclose: %s\n", strerror(errno));
656         }
657         return 0;
658
659 errout:
660         ErrPrint("Parse error\n");
661         if (block) {
662                 free(block->file);
663                 free(block->type);
664                 free(block->part);
665                 free(block->data);
666                 free(block->option);
667                 free(block->id);
668                 free(block);
669         }
670
671         update_end(handle, is_pd);
672
673         if (fclose(fp) != 0) {
674                 ErrPrint("fclose: %s\n", strerror(errno));
675         }
676         return LB_STATUS_ERROR_INVALID;
677 }
678
679 /* End of a file */