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