Backport changes from EFL
[platform/upstream/eldbus.git] / src / lib / eldbus_message_to_eina_value.c
1 #include "eldbus_private.h"
2 #include "eldbus_private_types.h"
3
4 static void _message_iter_basic_array_to_eina_value(char type, Eina_Value *value, Eldbus_Message_Iter *iter);
5
6 static const Eina_Value_Type *
7 _dbus_type_to_eina_value_type(char type)
8 {
9    switch (type)
10      {
11       case 'i':
12       case 'h':
13          return EINA_VALUE_TYPE_INT;
14       case 's':
15       case 'o':
16       case 'g':
17          return EINA_VALUE_TYPE_STRING;
18       case 'b':
19       case 'y':
20          return EINA_VALUE_TYPE_UCHAR;
21       case 'n':
22          return EINA_VALUE_TYPE_SHORT;
23       case 'q':
24          return EINA_VALUE_TYPE_USHORT;
25       case 'u':
26          return EINA_VALUE_TYPE_UINT;
27       case 'x':
28          return EINA_VALUE_TYPE_INT64;
29       case 't':
30          return EINA_VALUE_TYPE_UINT64;
31       case 'd':
32          return EINA_VALUE_TYPE_DOUBLE;
33       case 'a':
34          return EINA_VALUE_TYPE_ARRAY;
35       case '(':
36       case '{':
37       case 'e':
38       case 'r':
39       case 'v':
40          return EINA_VALUE_TYPE_STRUCT;
41       default:
42          ERR("Unknown type %c", type);
43          return NULL;
44      }
45 }
46
47 static unsigned int
48 _type_size(char type)
49 {
50    switch (type)
51      {
52       case 'i':
53       case 'h':
54       case 'u':
55          return(sizeof(int32_t));
56       case 's':
57       case 'o':
58       case 'g':
59          return(sizeof(char *));
60       case 'b':
61       case 'y':
62          return(sizeof(unsigned char));
63       case 'n':
64       case 'q':
65          return(sizeof(int16_t));
66       case 'x':
67       case 't':
68          return(sizeof(int64_t));
69       case 'd':
70          return(sizeof(double));
71       case 'a':
72          return(sizeof(Eina_Value_Array));
73       case '(':
74       case '{':
75       case 'e':
76       case 'r':
77       case 'v':
78          return(sizeof(Eina_Value_Struct));
79       default:
80          ERR("Unknown type %c", type);
81          return 0;
82      }
83 }
84
85 static unsigned int
86 _type_offset(char type, unsigned base)
87 {
88    unsigned size, padding;
89    size = _type_size(type);
90    if (!(base % size))
91      return base;
92    padding = abs(base - size);
93    return base + padding;
94 }
95
96 static Eina_Value *
97 _message_iter_array_to_eina_value(Eldbus_Message_Iter *iter)
98 {
99    Eina_Value *array_value;
100    char *sig;
101
102    sig = eldbus_message_iter_signature_get(iter);
103    DBG("array of %s", sig);
104    array_value = eina_value_array_new(_dbus_type_to_eina_value_type(sig[0]), 0);
105    if (sig[0] == '(' || sig[0] == '{' || sig[0] == 'v')
106      {
107         Eldbus_Message_Iter *entry;
108
109         if (sig[0] == '{')
110           sig[0] = 'e';
111         else if (sig[0] == '(')
112           sig[0] = 'r';
113
114         while (eldbus_message_iter_get_and_next(iter, sig[0], &entry))
115           {
116              Eina_Value *data = _message_iter_struct_to_eina_value(entry);
117              Eina_Value_Struct st;
118              eina_value_get(data, &st);
119              eina_value_array_append(array_value, st);
120           }
121      }
122    else if (sig[0] == 'a')
123      {
124         Eldbus_Message_Iter *entry;
125         while (eldbus_message_iter_get_and_next(iter, sig[0], &entry))
126           {
127              Eina_Value *data = _message_iter_array_to_eina_value(entry);
128              Eina_Value_Array inner_array;
129              eina_value_get(data, &inner_array);
130              eina_value_array_append(array_value, inner_array);
131           }
132      }
133    else
134      _message_iter_basic_array_to_eina_value(sig[0], array_value, iter);
135
136    DBG("return array of %s", sig);
137    free(sig);
138    return array_value;
139 }
140
141 static void
142 _message_iter_basic_array_to_eina_value(char type, Eina_Value *value, Eldbus_Message_Iter *iter)
143 {
144    switch (type)
145     {
146        case 'i':
147        case 'h'://fd
148          {
149             int32_t i;
150             while (eldbus_message_iter_get_and_next(iter, type, &i))
151               eina_value_array_append(value, i);
152             break;
153          }
154        case 's':
155        case 'o'://object path
156        case 'g'://signature
157          {
158             const char *txt;
159             while (eldbus_message_iter_get_and_next(iter, type, &txt))
160               eina_value_array_append(value, txt);
161             break;
162          }
163        case 'b'://boolean
164        case 'y'://byte
165          {
166             unsigned char byte;
167             while (eldbus_message_iter_get_and_next(iter, type, &byte))
168               eina_value_array_append(value, byte);
169             break;
170          }
171        case 'n'://int16
172          {
173             int16_t i;
174             while (eldbus_message_iter_get_and_next(iter, type, &i))
175               eina_value_array_append(value, i);
176             break;
177          }
178        case 'q'://uint16
179          {
180             uint16_t i;
181             while (eldbus_message_iter_get_and_next(iter, type, &i))
182               eina_value_array_append(value, i);
183             break;
184          }
185        case 'u'://uint32
186          {
187             uint32_t i;
188             while (eldbus_message_iter_get_and_next(iter, type, &i))
189               eina_value_array_append(value, i);
190             break;
191          }
192        case 'x'://int64
193          {
194             int64_t i;
195             while (eldbus_message_iter_get_and_next(iter, type, &i))
196               eina_value_array_append(value, i);
197             break;
198          }
199        case 't'://uint64
200          {
201             uint64_t i;
202             while (eldbus_message_iter_get_and_next(iter, type, &i))
203               eina_value_array_append(value, i);
204             break;
205          }
206        case 'd'://double
207          {
208             double d;
209             while (eldbus_message_iter_get_and_next(iter, type, &d))
210               eina_value_array_append(value, d);
211             break;
212          }
213     }
214 }
215
216 #define ARG "arg%u"
217
218 typedef struct _Eldbus_Struct_Desc
219 {
220    Eina_Value_Struct_Desc base;
221    int refcount;
222 } Eldbus_Struct_Desc;
223
224 static void *
225 _ops_malloc(const Eina_Value_Struct_Operations *ops EINA_UNUSED, const Eina_Value_Struct_Desc *desc)
226 {
227    Eldbus_Struct_Desc *edesc = (Eldbus_Struct_Desc*)desc;
228    edesc->refcount++;
229    DBG("%p refcount=%d", edesc, edesc->refcount);
230    return malloc(desc->size);
231 }
232
233 static void
234 _ops_free(const Eina_Value_Struct_Operations *ops EINA_UNUSED, const Eina_Value_Struct_Desc *desc, void *memory)
235 {
236    Eldbus_Struct_Desc *edesc = (Eldbus_Struct_Desc*) desc;
237    edesc->refcount--;
238    free(memory);
239    DBG("%p refcount=%d", edesc, edesc->refcount);
240    if (edesc->refcount <= 0)
241      {
242         unsigned i;
243         for (i = 0; i < edesc->base.member_count; i++)
244           free((char *)edesc->base.members[i].name);
245         free((Eina_Value_Struct_Member *)edesc->base.members);
246         free(edesc);
247      }
248 }
249
250 static Eina_Value_Struct_Operations operations =
251 {
252    EINA_VALUE_STRUCT_OPERATIONS_VERSION,
253    _ops_malloc,
254    _ops_free,
255    NULL,
256    NULL,
257    NULL
258 };
259
260 Eina_Value *
261 _message_iter_struct_to_eina_value(Eldbus_Message_Iter *iter)
262 {
263    int type;
264    Eina_Value *value_st = NULL;
265    Eina_Array *st_members = eina_array_new(1);
266    unsigned int offset = 0, z;
267    char name[7];//arg000 + \0
268    Eina_Value_Struct_Member *members;
269    Eldbus_Struct_Desc *st_desc;
270    Eina_Array *st_values = eina_array_new(1);
271
272    DBG("begin struct");
273    st_desc = calloc(1, sizeof(Eldbus_Struct_Desc));
274    st_desc->base.version = EINA_VALUE_STRUCT_DESC_VERSION;
275    st_desc->base.ops = &operations;
276
277    //create member list
278    z = 0;
279    while ((type = dbus_message_iter_get_arg_type(&iter->dbus_iterator)) != DBUS_TYPE_INVALID)
280      {
281         Eina_Value_Struct_Member *m;
282         Eina_Value *v;
283
284         m = calloc(1, sizeof(Eina_Value_Struct_Member));
285         snprintf(name, 7, ARG, z);
286         m->name = strdup(name);
287         offset = _type_offset(type, offset);
288         m->offset = offset;
289         offset += _type_size(type);
290         m->type = _dbus_type_to_eina_value_type(type);
291         eina_array_push(st_members, m);
292
293         DBG("type = %c", type);
294         switch (type)
295           {
296            case 'i'://int
297            case 'h'://fd
298              {
299                 int32_t i;
300                 v = eina_value_new(EINA_VALUE_TYPE_INT);
301                 eldbus_message_iter_basic_get(iter, &i);
302                 eina_value_set(v, i);
303                 break;
304              }
305            case 's':
306            case 'o'://object path
307            case 'g'://signature
308              {
309                 const char *txt;
310                 v = eina_value_new(EINA_VALUE_TYPE_STRING);
311                 eldbus_message_iter_basic_get(iter, &txt);
312                 eina_value_set(v, txt);
313                 break;
314              }
315            case 'b'://boolean
316            case 'y'://byte
317              {
318                 unsigned char byte;
319                 v = eina_value_new(EINA_VALUE_TYPE_UCHAR);
320                 eldbus_message_iter_basic_get(iter, &byte);
321                 eina_value_set(v, byte);
322                 break;
323              }
324            case 'n'://int16
325              {
326                 int16_t i;
327                 v = eina_value_new(EINA_VALUE_TYPE_SHORT);
328                 eldbus_message_iter_basic_get(iter, &i);
329                 eina_value_set(v, i);
330                 break;
331              }
332            case 'q'://uint16
333              {
334                 uint16_t i;
335                 v = eina_value_new(EINA_VALUE_TYPE_USHORT);
336                 eldbus_message_iter_basic_get(iter, &i);
337                 eina_value_set(v, i);
338                 break;
339              }
340            case 'u'://uint32
341              {
342                 uint32_t i;
343                 v = eina_value_new(EINA_VALUE_TYPE_UINT);
344                 eldbus_message_iter_basic_get(iter, &i);
345                 eina_value_set(v, i);
346                 break;
347              }
348            case 'x'://int64
349              {
350                 int64_t i;
351                 v = eina_value_new(EINA_VALUE_TYPE_INT64);
352                 eldbus_message_iter_basic_get(iter, &i);
353                 eina_value_set(v, i);
354                 break;
355              }
356            case 't'://uint64
357              {
358                 uint64_t i;
359                 v = eina_value_new(EINA_VALUE_TYPE_UINT64);
360                 eldbus_message_iter_basic_get(iter, &i);
361                 eina_value_set(v, i);
362                 break;
363              }
364            case 'd'://double
365              {
366                 double d;
367                 v = eina_value_new(EINA_VALUE_TYPE_DOUBLE);
368                 eldbus_message_iter_basic_get(iter, &d);
369                 eina_value_set(v, d);
370                 break;
371              }
372            case 'a'://array
373              {
374                 Eldbus_Message_Iter *dbus_array;
375                 dbus_array = eldbus_message_iter_sub_iter_get(iter);
376                 v = _message_iter_array_to_eina_value(dbus_array);
377                 break;
378              }
379            case '('://struct
380            case 'r'://struct
381            case 'v'://variant
382              {
383                 Eldbus_Message_Iter *dbus_st;
384                 dbus_st = eldbus_message_iter_sub_iter_get(iter);
385                 v = _message_iter_struct_to_eina_value(dbus_st);
386                 break;
387              }
388            default:
389              ERR("Unexpected type %c", type);
390              v = NULL;
391           }
392         eina_array_push(st_values, v);
393         eldbus_message_iter_next(iter);
394         z++;
395      }
396
397    if (!z)
398      {
399         free(st_desc);
400         goto end;
401      }
402
403    members = malloc(eina_array_count(st_members) * sizeof(Eina_Value_Struct_Member));
404    for (z = 0; z < eina_array_count(st_members); z++)
405      {
406         Eina_Value_Struct_Member *m = eina_array_data_get(st_members, z);
407         members[z].name = m->name;
408         members[z].offset = m->offset;
409         members[z].type = m->type;
410         free(m);
411      }
412
413    //setup
414    st_desc->base.members = members;
415    st_desc->base.member_count = eina_array_count(st_members);
416    st_desc->base.size = offset;
417    value_st = eina_value_struct_new((Eina_Value_Struct_Desc *)st_desc);
418
419    //filling with data
420    for (z = 0; z < eina_array_count(st_values); z++)
421      {
422         Eina_Value *v = eina_array_data_get(st_values, z);
423         sprintf(name, ARG, z);
424         eina_value_struct_value_set(value_st, name, v);
425         eina_value_free(v);
426      }
427
428 end:
429    eina_array_free(st_members);
430    eina_array_free(st_values);
431    DBG("end struct");
432    return value_st;
433 }
434
435 EAPI Eina_Value *
436 eldbus_message_to_eina_value(const Eldbus_Message *msg)
437 {
438    Eldbus_Message_Iter *iter;
439    EINA_SAFETY_ON_FALSE_RETURN_VAL(msg, NULL);
440    iter = eldbus_message_iter_get(msg);
441    EINA_SAFETY_ON_NULL_RETURN_VAL(iter, NULL);
442    return _message_iter_struct_to_eina_value(iter);
443 }
444
445 EAPI Eina_Value *
446 eldbus_message_iter_struct_like_to_eina_value(const Eldbus_Message_Iter *iter)
447 {
448    EINA_SAFETY_ON_NULL_RETURN_VAL(iter, NULL);
449    return _message_iter_struct_to_eina_value((Eldbus_Message_Iter *)iter);
450 }