eet: fix possible wrong size decoding for simple type.
[profile/ivi/eet.git] / src / lib / eet_node.c
1 #ifdef HAVE_CONFIG_H
2 # include <config.h>
3 #endif /* ifdef HAVE_CONFIG_H */
4
5 #include <string.h>
6 #include <stdio.h>
7
8 #ifdef HAVE_EVIL
9 # include <Evil.h>
10 #endif /* ifdef HAVE_EVIL */
11
12 #include <Eina.h>
13
14 #include "Eet.h"
15 #include "Eet_private.h"
16
17 static Eina_Mempool *_eet_node_mp = NULL;
18
19 Eet_Node *
20 eet_node_new(void)
21 {
22    Eet_Node *result;
23
24    result = eina_mempool_malloc(_eet_node_mp, sizeof (Eet_Node));
25    if (!result)
26      return NULL;
27
28    memset(result, 0, sizeof (Eet_Node));
29    return result;
30 }
31
32 void
33 eet_node_free(Eet_Node *node)
34 {
35    eina_mempool_free(_eet_node_mp, node);
36 }
37
38 static Eet_Node *
39 _eet_node_new(const char *name,
40               int         type)
41 {
42    Eet_Node *n;
43
44    n = eet_node_new();
45    if (!n)
46      return NULL;
47
48    n->type = type;
49    n->name = eina_stringshare_add(name);
50
51    return n;
52 }
53
54 static void
55 _eet_node_append(Eet_Node  *n,
56                  Eina_List *nodes)
57 {
58    Eet_Node *value;
59    Eina_List *l;
60
61    EINA_LIST_REVERSE_FOREACH(nodes, l, value)
62      {
63         value->next = n->values;
64         n->values = value;
65      }
66 }
67
68 #define EET_NODE_NEW(Eet_type, Name, Value, Type)         \
69   EAPI Eet_Node *                                         \
70   eet_node_ ## Name ## _new(const char *name, Type Value) \
71   {                                                       \
72      Eet_Node *n;                                         \
73                                                           \
74      n = _eet_node_new(name, Eet_type);                   \
75      if (!n) { return NULL; }                             \
76                                                           \
77      n->data.value.Value = Value;                         \
78                                                           \
79      return n;                                            \
80   }
81
82 #define EET_NODE_STR_NEW(Eet_type, Name, Value, Type)     \
83   EAPI Eet_Node *                                         \
84   eet_node_ ## Name ## _new(const char *name, Type Value) \
85   {                                                       \
86      Eet_Node *n;                                         \
87                                                           \
88      n = _eet_node_new(name, Eet_type);                   \
89      if (!n) { return NULL; }                             \
90                                                           \
91      n->data.value.Value = eina_stringshare_add(Value);   \
92                                                           \
93      return n;                                            \
94   }
95
96 EET_NODE_NEW(EET_T_CHAR, char, c, char)
97 EET_NODE_NEW(EET_T_SHORT, short, s, short)
98 EET_NODE_NEW(EET_T_INT, int, i, int)
99 EET_NODE_NEW(EET_T_LONG_LONG, long_long, l, long long)
100 EET_NODE_NEW(EET_T_FLOAT, float, f, float)
101 EET_NODE_NEW(EET_T_DOUBLE, double, d, double)
102 EET_NODE_NEW(EET_T_UCHAR, unsigned_char, uc, unsigned char)
103 EET_NODE_NEW(EET_T_USHORT, unsigned_short, us, unsigned short)
104 EET_NODE_NEW(EET_T_UINT, unsigned_int, ui, unsigned int)
105 EET_NODE_NEW(EET_T_ULONG_LONG, unsigned_long_long, ul, unsigned long long)
106 EET_NODE_STR_NEW(EET_T_STRING, string, str, const char *)
107 EET_NODE_STR_NEW(EET_T_INLINED_STRING, inlined_string, str, const char *)
108
109 Eet_Node *
110 eet_node_null_new(const char *name)
111 {
112    Eet_Node *n;
113
114    n = _eet_node_new(name, EET_T_NULL);
115    if (!n)
116      return NULL;
117
118    n->data.value.str = NULL;
119
120    return n;
121 }
122
123 Eet_Node *
124 eet_node_list_new(const char *name,
125                   Eina_List  *nodes)
126 {
127    Eet_Node *n;
128
129    n = _eet_node_new(name, EET_G_LIST);
130    if (!n)
131      return NULL;
132
133    _eet_node_append(n, nodes);
134
135    return n;
136 }
137
138 Eet_Node *
139 eet_node_array_new(const char *name,
140                    int         count,
141                    Eina_List  *nodes)
142 {
143    Eet_Node *n;
144
145    n = _eet_node_new(name, EET_G_ARRAY);
146    if (!n)
147      return NULL;
148
149    n->count = count;
150
151    _eet_node_append(n, nodes);
152
153    return n;
154 }
155
156 Eet_Node *
157 eet_node_var_array_new(const char *name,
158                        Eina_List  *nodes)
159 {
160    Eet_Node *n;
161
162    n = _eet_node_new(name, EET_G_VAR_ARRAY);
163    if (!n)
164      return NULL;
165
166    n->count = eina_list_count(nodes);
167
168    _eet_node_append(n, nodes);
169
170    return n;
171 }
172
173 Eet_Node *
174 eet_node_hash_new(const char *name,
175                   const char *key,
176                   Eet_Node   *node)
177 {
178    Eina_List *nodes;
179    Eet_Node *n;
180
181    if (!node)
182      return NULL;
183
184    n = _eet_node_new(name, EET_G_HASH);
185    if (!n)
186      return NULL;
187
188    n->key = eina_stringshare_add(key);
189    nodes = eina_list_append(NULL, node);
190
191    _eet_node_append(n, nodes);
192
193    return n;
194 }
195
196 Eet_Node *
197 eet_node_struct_new(const char *name,
198                     Eina_List  *nodes)
199 {
200    Eet_Node *n;
201
202    n = _eet_node_new(name, EET_G_UNKNOWN);
203    if (!n)
204      return NULL;
205
206    _eet_node_append(n, nodes);
207
208    return n;
209 }
210
211 Eet_Node *
212 eet_node_struct_child_new(const char *parent,
213                           Eet_Node   *child)
214 {
215    Eet_Node *n;
216
217    if (!child) return NULL;
218
219    if (child->type != EET_G_UNKNOWN)
220      return child;
221
222    n = _eet_node_new(parent, EET_G_UNKNOWN);
223    if (!n)
224      return NULL;
225
226    _eet_node_append(n, eina_list_prepend(NULL, child));
227
228    return n;
229 }
230
231 Eet_Node *
232 eet_node_children_get(Eet_Node *node)
233 {
234    if (!node) return NULL;
235    return node->values;
236 }
237
238 Eet_Node *
239 eet_node_next_get(Eet_Node *node)
240 {
241    if (!node) return NULL;
242    return node->next;
243 }
244
245 Eet_Node *
246 eet_node_parent_get(Eet_Node *node)
247 {
248    if (!node) return NULL;
249    return node->parent;
250 }
251
252 void
253 eet_node_list_append(Eet_Node   *parent,
254                      const char *name,
255                      Eet_Node   *child)
256 {
257    const char *tmp;
258    Eet_Node *nn;
259
260    if ((!parent) || (!child)) return;
261    tmp = eina_stringshare_add(name);
262
263    for (nn = parent->values; nn; nn = nn->next)
264      if (nn->name == tmp && nn->type == EET_G_LIST)
265        {
266           Eet_Node *n;
267
268           if (!nn->values)
269             nn->values = child;
270           else
271             {
272                for (n = nn->values; n->next; n = n->next)
273                  ;
274                n->next = child;
275             }
276
277           child->next = NULL;
278
279           eina_stringshare_del(tmp);
280
281           return;
282        }
283
284    /* No list found, so create it. */
285    nn = eet_node_list_new(tmp, eina_list_append(NULL, child));
286
287    /* And add it to the parent. */
288    nn->next = parent->values;
289    parent->values = nn;
290
291    eina_stringshare_del(tmp);
292 }
293
294 void
295 eet_node_struct_append(Eet_Node   *parent,
296                        const char *name,
297                        Eet_Node   *child)
298 {
299    const char *tmp;
300    Eet_Node *prev;
301    Eet_Node *nn;
302
303    if ((!parent) || (!child)) return;
304    if (parent->type != EET_G_UNKNOWN)
305      {
306         ERR("[%s] is not a structure. Will not insert [%s] in it",
307             parent->name,
308             name);
309         eet_node_del(child);
310         return;
311      }
312
313    tmp = eina_stringshare_add(name);
314
315    for (prev = NULL, nn = parent->values; nn; prev = nn, nn = nn->next)
316      if (nn->name == tmp && nn->type == child->type)
317        {
318           if (prev)
319             prev->next = nn->next;
320           else
321             parent->values = nn->next;
322
323           nn->next = NULL;
324           eet_node_del(nn);
325
326           break;
327        }
328
329    if (prev)
330      {
331         prev->next = child;
332         child->next = NULL;
333      }
334    else
335      {
336         child->next = NULL;
337         parent->values = child;
338      }
339
340    eina_stringshare_del(tmp);
341 }
342
343 void
344 eet_node_hash_add(Eet_Node   *parent,
345                   const char *name,
346                   const char *key,
347                   Eet_Node   *child)
348 {
349    Eet_Node *nn;
350
351    if ((!parent) || (!child)) return;
352
353    /* No list found, so create it. */
354    nn = eet_node_hash_new(name, key, child);
355
356    /* And add it to the parent. */
357    nn->next = parent->values;
358    parent->values = nn;
359 }
360
361 int
362 eet_node_type_get(Eet_Node *node)
363 {
364    if (!node) return EET_T_UNKNOW;
365    return node->type;
366 }
367
368 Eet_Node_Data *
369 eet_node_value_get(Eet_Node *node)
370 {
371    if (!node) return NULL;
372    return &node->data;
373 }
374
375 const char *
376 eet_node_name_get(Eet_Node *node)
377 {
378    if (!node) return NULL;
379    return node->name;
380 }
381
382 void
383 eet_node_del(Eet_Node *n)
384 {
385    Eet_Node *nn;
386    Eet_Node *tmp;
387
388    if (!n)
389      return;
390
391    switch (n->type)
392      {
393       case EET_G_HASH:
394         eina_stringshare_del(n->key);
395
396       case EET_G_UNKNOWN:
397       case EET_G_VAR_ARRAY:
398       case EET_G_ARRAY:
399       case EET_G_LIST:
400         for (nn = n->values; nn; )
401           {
402              tmp = nn;
403              nn = nn->next;
404              eet_node_del(tmp);
405           }
406         break;
407
408       case EET_T_STRING:
409       case EET_T_INLINED_STRING:
410         eina_stringshare_del(n->data.value.str);
411         break;
412
413       case EET_T_CHAR:
414       case EET_T_SHORT:
415       case EET_T_INT:
416       case EET_T_LONG_LONG:
417       case EET_T_FLOAT:
418       case EET_T_DOUBLE:
419       case EET_T_UCHAR:
420       case EET_T_USHORT:
421       case EET_T_UINT:
422         break;
423      }
424
425    eina_stringshare_del(n->name);
426    eet_node_free(n);
427 }
428
429 static const char *eet_node_dump_g_name[6] = {
430    "struct",
431    "array",
432    "var_array",
433    "list",
434    "hash",
435    "???"
436 };
437
438 static const char *eet_node_dump_t_name[14][2] = {
439    { "???: ", "???" },
440    { "char: ", "%hhi" },
441    { "short: ", "%hi" },
442    { "int: ", "%i" },
443    { "long_long: ", "%lli" },
444    { "float: ", "%1.25f" },
445    { "double: ", "%1.25f" },
446    { "uchar: ", "%hhu" },
447    { "ushort: ", "%i" },
448    { "uint: ", "%u" },
449    { "ulong_long: ", "%llu" },
450    { "null", "" }
451 };
452
453 static void
454 eet_node_dump_level(int               level,
455                     Eet_Dump_Callback dumpfunc,
456                     void             *dumpdata)
457 {
458    int i;
459
460    for (i = 0; i < level; i++) dumpfunc(dumpdata, "  ");
461 }
462
463 static char *
464 eet_node_string_escape(const char *str)
465 {
466    char *s, *sp;
467    const char *strp;
468    int sz = 0;
469
470    for (strp = str; *strp; strp++)
471      {
472         if (*strp == '\"')
473           sz += 2;
474         else if (*strp == '\\')
475           sz += 2;
476         else if (*strp == '\n')
477           sz += 2;
478         else
479           sz += 1;
480      }
481    s = malloc(sz + 1);
482    if (!s)
483      return NULL;
484
485    for (strp = str, sp = s; *strp; strp++, sp++)
486      {
487         if (*strp == '\"'
488             || *strp == '\\'
489             || *strp == '\n')
490           {
491              *sp = '\\';
492              sp++;
493           }
494
495         if (*strp == '\n')
496           *sp = 'n';
497         else
498           *sp = *strp;
499      }
500    *sp = 0;
501    return s;
502 }
503
504 static void
505 eet_node_dump_string_escape(void             *dumpdata,
506                             Eet_Dump_Callback dumpfunc,
507                             const char       *str)
508 {
509    char *s;
510
511    s = eet_node_string_escape(str);
512    if (!s)
513      return;
514
515    dumpfunc(dumpdata, s);
516    free(s);
517 }
518
519 static void
520 eet_node_dump_simple_type(Eet_Node         *n,
521                           int               level,
522                           Eet_Dump_Callback dumpfunc,
523                           void             *dumpdata)
524 {
525    const char *type_name = NULL;
526    char tbuf[256];
527
528    eet_node_dump_level(level, dumpfunc, dumpdata);
529    dumpfunc(dumpdata, "value \"");
530    eet_node_dump_string_escape(dumpdata, dumpfunc, n->name);
531    dumpfunc(dumpdata, "\" ");
532
533 #ifdef EET_T_TYPE
534 # undef EET_T_TYPE
535 #endif /* ifdef EET_T_TYPE */
536
537 #define EET_T_TYPE(Eet_Type, Type)                        \
538 case Eet_Type:                                            \
539 {                                                         \
540    dumpfunc(dumpdata, eet_node_dump_t_name[Eet_Type][0]); \
541    snprintf(tbuf,                                         \
542             sizeof (tbuf),                                \
543             eet_node_dump_t_name[Eet_Type][1],            \
544             n->data.value.Type);                          \
545    dumpfunc(dumpdata, tbuf);                              \
546    break;                                                 \
547 }
548
549    switch (n->type)
550      {
551         EET_T_TYPE(EET_T_CHAR, c);
552         EET_T_TYPE(EET_T_SHORT, s);
553         EET_T_TYPE(EET_T_INT, i);
554         EET_T_TYPE(EET_T_LONG_LONG, l);
555         EET_T_TYPE(EET_T_FLOAT, f);
556         EET_T_TYPE(EET_T_DOUBLE, d);
557         EET_T_TYPE(EET_T_UCHAR, uc);
558         EET_T_TYPE(EET_T_USHORT, us);
559         EET_T_TYPE(EET_T_UINT, ui);
560         EET_T_TYPE(EET_T_ULONG_LONG, ul);
561
562       case EET_T_INLINED_STRING:
563         type_name = "inlined: \"";
564
565       case EET_T_STRING:
566         if (!type_name)
567           type_name = "string: \"";
568
569         dumpfunc(dumpdata, type_name);
570         eet_node_dump_string_escape(dumpdata, dumpfunc, n->data.value.str);
571         dumpfunc(dumpdata, "\"");
572         break;
573
574       case EET_T_NULL:
575         dumpfunc(dumpdata, "null");
576         break;
577
578       default:
579         dumpfunc(dumpdata, "???: ???");
580         break;
581      }
582
583    dumpfunc(dumpdata, ";\n");
584 }
585
586 static void
587 eet_node_dump_group_start(int               level,
588                           Eet_Dump_Callback dumpfunc,
589                           void             *dumpdata,
590                           int               group_type,
591                           const char       *name)
592 {
593    int chnk_type;
594
595    chnk_type = (group_type >= EET_G_UNKNOWN && group_type <= EET_G_HASH) ?
596      group_type : EET_G_LAST;
597
598    eet_node_dump_level(level, dumpfunc, dumpdata);
599    dumpfunc(dumpdata, "group \"");
600    eet_node_dump_string_escape(dumpdata, dumpfunc, name);
601    dumpfunc(dumpdata, "\" ");
602
603    dumpfunc(dumpdata, eet_node_dump_g_name[chnk_type - EET_G_UNKNOWN]);
604    dumpfunc(dumpdata, " {\n");
605 }
606
607 static void
608 eet_node_dump_group_end(int               level,
609                         Eet_Dump_Callback dumpfunc,
610                         void             *dumpdata)
611 {
612    eet_node_dump_level(level, dumpfunc, dumpdata);
613    dumpfunc(dumpdata, "}\n");
614 }
615
616 void
617 eet_node_dump(Eet_Node         *n,
618               int               dumplevel,
619               Eet_Dump_Callback dumpfunc,
620               void             *dumpdata)
621 {
622    Eet_Node *it;
623
624    if (!n)
625      return;
626
627    switch (n->type)
628      {
629       case EET_G_VAR_ARRAY:
630       case EET_G_ARRAY:
631       case EET_G_UNKNOWN:
632       case EET_G_HASH:
633       case EET_G_LIST:
634         eet_node_dump_group_start(dumplevel,
635                                   dumpfunc,
636                                   dumpdata,
637                                   n->type,
638                                   n->name);
639
640         if (n->type == EET_G_VAR_ARRAY
641             || n->type == EET_G_ARRAY)
642           {
643              char tbuf[256];
644
645              eet_node_dump_level(dumplevel, dumpfunc, dumpdata);
646              dumpfunc(dumpdata, "    count ");
647              eina_convert_itoa(n->count, tbuf);
648              dumpfunc(dumpdata, tbuf);
649              dumpfunc(dumpdata, ";\n");
650           }
651         else if (n->type == EET_G_HASH)
652           {
653              eet_node_dump_level(dumplevel, dumpfunc, dumpdata);
654              dumpfunc(dumpdata, "    key \"");
655              eet_node_dump_string_escape(dumpdata, dumpfunc, n->key);
656              dumpfunc(dumpdata, "\";\n");
657           }
658
659         for (it = n->values; it; it = it->next)
660           eet_node_dump(it, dumplevel + 2, dumpfunc, dumpdata);
661
662         eet_node_dump_group_end(dumplevel, dumpfunc, dumpdata);
663         break;
664
665       case EET_T_STRING:
666       case EET_T_INLINED_STRING:
667       case EET_T_CHAR:
668       case EET_T_SHORT:
669       case EET_T_INT:
670       case EET_T_LONG_LONG:
671       case EET_T_FLOAT:
672       case EET_T_DOUBLE:
673       case EET_T_UCHAR:
674       case EET_T_USHORT:
675       case EET_T_UINT:
676       case EET_T_ULONG_LONG:
677         eet_node_dump_simple_type(n, dumplevel, dumpfunc, dumpdata);
678         break;
679      }
680 }
681
682 void *
683 eet_node_walk(void          *parent,
684               const char    *name,
685               Eet_Node      *root,
686               Eet_Node_Walk *cb,
687               void          *user_data)
688 {
689    Eet_Node *it;
690    void *me = NULL;
691    int i;
692
693    if (!root)
694      {
695         if (parent)
696           cb->struct_add(parent, name, NULL, user_data);
697
698         return NULL;
699      }
700
701    switch (root->type)
702      {
703       case EET_G_UNKNOWN:
704         me = cb->struct_alloc(root->name, user_data);
705
706         for (it = root->values; it; it = it->next)
707           eet_node_walk(me, it->name, it, cb, user_data);
708
709         break;
710
711       case EET_G_VAR_ARRAY:
712       case EET_G_ARRAY:
713         me = cb->array(root->type == EET_G_VAR_ARRAY ? EINA_TRUE : EINA_FALSE,
714                        root->name, root->count, user_data);
715
716         for (i = 0, it = root->values; it; it = it->next)
717           cb->insert(me, i++, eet_node_walk(NULL,
718                                             NULL,
719                                             it,
720                                             cb,
721                                             user_data), user_data);
722
723         break;
724
725       case EET_G_LIST:
726         me = cb->list(root->name, user_data);
727
728         for (it = root->values; it; it = it->next)
729           cb->append(me, eet_node_walk(NULL,
730                                        NULL,
731                                        it,
732                                        cb,
733                                        user_data), user_data);
734
735         break;
736
737       case EET_G_HASH:
738         if (!parent)
739           return NULL;
740
741         return cb->hash(parent, root->name, root->key,
742                         eet_node_walk(NULL,
743                                       NULL,
744                                       root->values,
745                                       cb,
746                                       user_data), user_data);
747
748       case EET_T_STRING:
749       case EET_T_INLINED_STRING:
750       case EET_T_CHAR:
751       case EET_T_SHORT:
752       case EET_T_INT:
753       case EET_T_LONG_LONG:
754       case EET_T_FLOAT:
755       case EET_T_DOUBLE:
756       case EET_T_UCHAR:
757       case EET_T_USHORT:
758       case EET_T_UINT:
759       case EET_T_ULONG_LONG:
760         me = cb->simple(root->type, &root->data, user_data);
761         break;
762      }
763
764    if (parent)
765      cb->struct_add(parent, name, me, user_data);
766
767    return me;
768 }
769
770 int
771 eet_node_init(void)
772 {
773    const char *choice;
774    const char *tmp;
775
776 #ifdef EINA_DEFAULT_MEMPOOL
777    choice = "pass_through";
778 #else
779    choice = "chained_mempool";
780 #endif
781    tmp = getenv("EINA_MEMPOOL");
782    if (tmp && tmp[0])
783      choice = tmp;
784
785    _eet_node_mp =
786      eina_mempool_add(choice, "eet-node-alloc", NULL, sizeof(Eet_Node), 32);
787
788    return _eet_node_mp ? 1 : 0;
789 }
790
791 void
792 eet_node_shutdown(void)
793 {
794    eina_mempool_del(_eet_node_mp);
795    _eet_node_mp = NULL;
796 }
797