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