Socket's implementation of ref_state_set to return empty sets instead of NULL
[platform/core/uifw/at-spi2-atk.git] / dbind / dbind-any.c
1 /* type driven marshalling */
2 #include <stdio.h>
3 #include <glib.h>
4
5 #include "config.h"
6 #include "dbind-config.h"
7 #include "dbind-any.h"
8
9 #undef DEBUG
10
11 /*  Align a value upward to a boundary, expressed as a number of bytes.
12  *  E.g. align to an 8-byte boundary with argument of 8.
13  *
14  *   (this + boundary - 1)
15  *          &
16  *    ~(boundary - 1)
17  */
18 #define ALIGN_VALUE(this, boundary) \
19   (( ((gulong)(this)) + (((gulong)(boundary)) -1)) & (~(((gulong)(boundary))-1)))
20
21 #define ALIGN_ADDRESS(this, boundary) \
22   ((gpointer)ALIGN_VALUE(this, boundary))
23
24 #define PTR_PLUS(ptr, offset) \
25         ((gpointer) (((guchar *)(ptr)) + (offset)))
26
27 #define DBIND_POD_CASES \
28          DBUS_TYPE_BYTE: \
29     case DBUS_TYPE_INT16: \
30     case DBUS_TYPE_UINT16: \
31     case DBUS_TYPE_INT32: \
32     case DBUS_TYPE_UINT32: \
33     case DBUS_TYPE_BOOLEAN: \
34     case DBUS_TYPE_INT64: \
35     case DBUS_TYPE_UINT64: \
36     case DBUS_TYPE_DOUBLE
37
38 /*---------------------------------------------------------------------------*/
39
40 static void
41 warn_braces ()
42 {
43     fprintf (stderr, "Error: dbus flags structures & dicts with braces rather than "
44              " an explicit type member of 'struct'\n");
45 }
46
47 /*---------------------------------------------------------------------------*/
48
49 static unsigned int
50 dbind_find_c_alignment_r (const char **type)
51 {
52     unsigned int retval = 1;
53
54     char t = **type;
55     (*type)++;
56
57 #ifdef DEBUG
58     fprintf (stderr, "\tfind align for %c (0x%x)\n", t, t);
59 #endif
60
61         switch (t) {
62     case DBUS_TYPE_BYTE:
63         return DBIND_ALIGNOF_CHAR;
64     case DBUS_TYPE_BOOLEAN:
65         return DBIND_ALIGNOF_DBUS_BOOL_T;
66     case DBUS_TYPE_INT16:
67     case DBUS_TYPE_UINT16:
68         return DBIND_ALIGNOF_DBUS_INT16_T;
69     case DBUS_TYPE_INT32:
70     case DBUS_TYPE_UINT32:
71         return DBIND_ALIGNOF_DBUS_INT32_T;
72     case DBUS_TYPE_INT64:
73     case DBUS_TYPE_UINT64:
74         return DBIND_ALIGNOF_DBUS_INT64_T;
75     case DBUS_TYPE_DOUBLE:
76         return DBIND_ALIGNOF_DOUBLE;
77     /* ptr types */
78     case DBUS_TYPE_STRING:
79     case DBUS_TYPE_OBJECT_PATH:
80     case DBUS_TYPE_SIGNATURE:
81     case DBUS_TYPE_ARRAY:
82         return DBIND_ALIGNOF_DBIND_POINTER;
83     case DBUS_STRUCT_BEGIN_CHAR:
84 #if DBIND_ALIGNOF_DBIND_STRUCT > 1
85                 retval = MAX (retval, DBIND_ALIGNOF_DBIND_STRUCT);
86 #endif
87         while (**type != DBUS_STRUCT_END_CHAR) {
88             int elem_align = dbind_find_c_alignment_r (type);
89                         retval = MAX (retval, elem_align);
90         }
91         (*type)++;
92         return retval;
93     case DBUS_TYPE_STRUCT:
94     case DBUS_TYPE_DICT_ENTRY:
95         warn_braces ();
96         return DBIND_ALIGNOF_DBIND_POINTER;
97     case '\0':
98         g_assert_not_reached();
99         break;
100     default:
101                 return 1;
102   }
103 }
104
105 /*---------------------------------------------------------------------------*/
106
107 /* gather immediate allocation information for this type */
108 static size_t
109 dbind_gather_alloc_info_r (const char **type)
110 {
111   char t = **type;
112   (*type)++;
113   if (t == DBUS_TYPE_ARRAY)
114     {
115       switch (**type)
116         {
117           case DBUS_STRUCT_BEGIN_CHAR:
118               while (**type != DBUS_STRUCT_END_CHAR && **type != '\0') (*type)++;
119               if (**type != '\0') (*type)++;
120               break;
121           case '\0':
122               break;
123           default:
124               (*type)++;
125               break;
126         }
127     }
128
129   switch (t) {
130     case DBUS_TYPE_BYTE:
131         return sizeof (char);
132     case DBUS_TYPE_BOOLEAN:
133         return sizeof (dbus_bool_t);
134     case DBUS_TYPE_INT16:
135     case DBUS_TYPE_UINT16:
136         return sizeof (dbus_int16_t);
137     case DBUS_TYPE_INT32:
138     case DBUS_TYPE_UINT32:
139         return sizeof (dbus_int32_t);
140     case DBUS_TYPE_INT64:
141     case DBUS_TYPE_UINT64:
142         return sizeof (dbus_int64_t);
143     case DBUS_TYPE_DOUBLE:
144         return sizeof (double);
145     /* ptr types */
146     case DBUS_TYPE_STRING:
147     case DBUS_TYPE_OBJECT_PATH:
148     case DBUS_TYPE_SIGNATURE:
149     case DBUS_TYPE_ARRAY:
150         return sizeof (void *);
151     case DBUS_STRUCT_BEGIN_CHAR: {
152                 int sum = 0, stralign;
153
154         stralign = dbind_find_c_alignment (*type - 1);
155
156         while (**type != DBUS_STRUCT_END_CHAR) {
157                         sum = ALIGN_VALUE (sum, dbind_find_c_alignment (*type));
158                         sum += dbind_gather_alloc_info_r (type);
159         }
160                 sum = ALIGN_VALUE (sum, stralign);
161
162         g_assert (**type == DBUS_STRUCT_END_CHAR);
163         (*type)++;
164
165                 return sum;
166     }
167     case DBUS_TYPE_STRUCT:
168     case DBUS_TYPE_DICT_ENTRY:
169         warn_braces ();
170     default:
171         return 0;
172   }
173 }
174
175 static size_t
176 dbind_gather_alloc_info (const char *type)
177 {
178   return dbind_gather_alloc_info_r (&type);
179 }
180
181 /*---------------------------------------------------------------------------*/
182
183 static void
184 dbind_any_free_r (const char **type, void **data)
185 {
186 #ifdef DEBUG
187     fprintf (stderr, "any free '%c' to %p\n", **type, *data);
188 #endif
189
190     switch (**type) {
191     case DBIND_POD_CASES:
192         *data = ((guchar *)*data) + dbind_gather_alloc_info (*type);
193         (*type)++;
194         break;
195     case DBUS_TYPE_STRING:
196     case DBUS_TYPE_OBJECT_PATH:
197     case DBUS_TYPE_SIGNATURE:
198 #ifdef DEBUG
199         fprintf (stderr, "string free %p\n", **(void ***)data);
200 #endif
201         g_free (**(void ***)data);
202         *data = ((guchar *)*data) + dbind_gather_alloc_info (*type);
203         (*type)++;
204         break;
205     case DBUS_TYPE_ARRAY: {
206         int i;
207         GArray *vals = **(void ***)data;
208         size_t elem_size, elem_align;
209         const char *saved_child_type;
210
211         (*type)++;
212         saved_child_type = *type;
213
214         elem_size = dbind_gather_alloc_info (*type);
215         elem_align = dbind_find_c_alignment_r (type); 
216
217         for (i = 0; i < vals->len; i++) {
218             void *ptr = vals->data + elem_size * i;
219             *type = saved_child_type; /* rewind type info */
220             ptr = ALIGN_ADDRESS (ptr, elem_align);
221             dbind_any_free_r (type, &ptr);
222         }
223         g_array_free (vals, TRUE);
224         break;
225     }
226     case DBUS_STRUCT_BEGIN_CHAR: {
227                 gconstpointer data0 = *data;
228                 int offset = 0, stralign;
229
230         stralign = dbind_find_c_alignment (*type);
231         (*type)++;
232
233         offset = 0 ;
234         while (**type != DBUS_STRUCT_END_CHAR) {
235             const char *subt = *type;
236                         offset = ALIGN_VALUE (offset, dbind_find_c_alignment (*type));
237                         *data = PTR_PLUS (data0, offset);
238             dbind_any_free_r (type, data);
239             offset += dbind_gather_alloc_info (subt);
240         }
241
242                 offset = ALIGN_VALUE (offset, stralign);
243                 *data = PTR_PLUS (data0, offset);
244
245         g_assert (**type == DBUS_STRUCT_END_CHAR);
246         (*type)++;
247
248         break;
249     }
250     case DBUS_TYPE_STRUCT:
251     case DBUS_TYPE_DICT_ENTRY:
252         warn_braces ();
253         break;
254     }
255 }
256
257 /*---------------------------------------------------------------------------*/
258
259 void
260 dbind_any_marshal (DBusMessageIter *iter,
261                    const char           **type,
262                    void           **data)
263 {
264     size_t len;
265
266 #ifdef DEBUG
267     fprintf (stderr, "any marshal '%c' to %p\n", **type, *data);
268 #endif
269
270     switch (**type) {
271     case DBIND_POD_CASES:
272     case DBUS_TYPE_STRING:
273     case DBUS_TYPE_OBJECT_PATH:
274     case DBUS_TYPE_SIGNATURE:
275         len = dbind_gather_alloc_info (*type);
276         dbus_message_iter_append_basic (iter, **type, *data);
277         *data = ((guchar *)*data) + len;
278         (*type)++;
279         break;
280     case DBUS_TYPE_ARRAY: {
281         int i;
282         GArray *vals = **(void ***)data;
283         size_t elem_size, elem_align;
284         DBusMessageIter sub;
285         const char *saved_child_type;
286         char *child_type_string;
287
288         (*type)++;
289         saved_child_type = *type;
290
291         elem_size = dbind_gather_alloc_info (*type);
292         elem_align = dbind_find_c_alignment_r (type); 
293
294         /* wow this part of the API sucks too ... */
295         child_type_string = g_strndup (saved_child_type, *type - saved_child_type);
296         /* fprintf (stderr, "array child type '%s'\n", child_type_string); */
297         dbus_message_iter_open_container (iter, DBUS_TYPE_ARRAY,
298                                           child_type_string, &sub);
299         for (i = 0; i < vals->len; i++) {
300             void *ptr = vals->data + elem_size * i;
301             *type = saved_child_type; /* rewind type info */
302             ptr = ALIGN_ADDRESS (ptr, elem_align);
303             dbind_any_marshal (&sub, type, &ptr);
304         }
305
306         dbus_message_iter_close_container (iter, &sub);
307         g_free (child_type_string);
308         break;
309     }
310     case DBUS_STRUCT_BEGIN_CHAR: {
311                 gconstpointer data0 = *data;
312                 int offset = 0, stralign;
313         DBusMessageIter sub;
314
315         stralign = dbind_find_c_alignment (*type);
316
317         (*type)++;
318
319         dbus_message_iter_open_container (iter, DBUS_TYPE_STRUCT, NULL, &sub);
320
321         offset = 0 ;
322         while (**type != DBUS_STRUCT_END_CHAR) {
323             const char *subt = *type;
324                         offset = ALIGN_VALUE (offset, dbind_find_c_alignment (*type));
325                         *data = PTR_PLUS (data0, offset);
326             dbind_any_marshal (&sub, type, data);
327             offset += dbind_gather_alloc_info (subt);
328         }
329
330                 offset = ALIGN_VALUE (offset, stralign);
331                 *data = PTR_PLUS (data0, offset);
332
333         dbus_message_iter_close_container (iter, &sub);
334
335         g_assert (**type == DBUS_STRUCT_END_CHAR);
336         (*type)++;
337
338         break;
339     }
340     case DBUS_TYPE_STRUCT:
341     case DBUS_TYPE_DICT_ENTRY:
342         warn_braces ();
343         break;
344     }
345 }
346
347 /*---------------------------------------------------------------------------*/
348
349 void
350 dbind_any_marshal_va (DBusMessageIter *iter,
351                       const char           **arg_types,
352                       va_list          args)
353 {
354     const char *p = *arg_types;
355
356     /* Guard against null arg types 
357        Fix for - http://bugs.freedesktop.org/show_bug.cgi?id=23027
358      */
359     if (p == NULL)
360         p = "";
361
362     {
363         /* special case base-types since we need to walk the stack worse-luck */
364         for (;*p != '\0' && *p != '=';) {
365             int intarg;
366             void *ptrarg;
367             double doublearg;
368             dbus_int64_t int64arg;
369             void *arg = NULL;
370
371             switch (*p) {
372             case DBUS_TYPE_BYTE:
373             case DBUS_TYPE_BOOLEAN:
374             case DBUS_TYPE_INT16:
375             case DBUS_TYPE_UINT16:
376             case DBUS_TYPE_INT32:
377             case DBUS_TYPE_UINT32:
378                 intarg = va_arg (args, int);
379                 arg = &intarg;
380                 break;
381             case DBUS_TYPE_INT64:
382             case DBUS_TYPE_UINT64:
383                 int64arg = va_arg (args, dbus_int64_t);
384                 arg = &int64arg;
385                 break;
386             case DBUS_TYPE_DOUBLE:
387                 doublearg = va_arg (args, double);
388                 arg = &doublearg;
389                 break;
390             /* ptr types */
391             case DBUS_TYPE_STRING:
392             case DBUS_TYPE_OBJECT_PATH:
393             case DBUS_TYPE_SIGNATURE:
394             case DBUS_TYPE_ARRAY:
395             case DBUS_TYPE_DICT_ENTRY:
396                 ptrarg = va_arg (args, void *);
397                 arg = &ptrarg;
398                 break;
399             case DBUS_STRUCT_BEGIN_CHAR:
400                 ptrarg = va_arg (args, void *);
401                 arg = ptrarg;
402                 break;
403
404             case DBUS_TYPE_VARIANT:
405                 fprintf (stderr, "No variant support yet - very toolkit specific\n");
406                 ptrarg = va_arg (args, void *);
407                 arg = &ptrarg;
408                 break;
409             default:
410                 fprintf (stderr, "Unknown / invalid arg type %c\n", *p);
411                 break;
412             }
413             if (arg != NULL)
414                 dbind_any_marshal (iter, &p, &arg);
415             }
416     }
417 }
418
419 /*---------------------------------------------------------------------------*/
420
421 void
422 dbind_any_demarshal (DBusMessageIter *iter,
423                      const char           **type,
424                      void           **data)
425 {
426     size_t len;
427
428 #ifdef DEBUG
429     fprintf (stderr, "any demarshal '%c' to %p\n", **type, *data);
430 #endif
431
432     switch (**type) {
433     case DBIND_POD_CASES:
434         len = dbind_gather_alloc_info (*type);
435         dbus_message_iter_get_basic (iter, *data);
436         *data = ((guchar *)*data) + len;
437         (*type)++;
438         break;
439     case DBUS_TYPE_STRING:
440     case DBUS_TYPE_OBJECT_PATH:
441     case DBUS_TYPE_SIGNATURE:
442         len = dbind_gather_alloc_info (*type);
443         dbus_message_iter_get_basic (iter, *data);
444 #ifdef DEBUG
445         fprintf (stderr, "dup string '%s' (%p)\n", **(void ***)data, **(void ***)data);
446 #endif
447         **(void ***)data = g_strdup (**(void ***)data);
448         *data = ((guchar *)*data) + len;
449         (*type)++;
450         break;
451     case DBUS_TYPE_ARRAY: {
452         GArray *vals;
453         DBusMessageIter child;
454         size_t elem_size, elem_align;
455         const char *stored_child_type;
456         int i;
457
458         (*type)++;
459         stored_child_type = *type;
460
461         elem_size = dbind_gather_alloc_info (*type);
462         elem_align = dbind_find_c_alignment_r (type);
463         vals = g_array_new (FALSE, FALSE, elem_size);
464         (**(void ***)data) = vals;
465         *data = ((guchar *)*data) + sizeof (void *);
466
467         i = 0;
468         dbus_message_iter_recurse (iter, &child);
469         while (dbus_message_iter_get_arg_type (&child) != DBUS_TYPE_INVALID) {
470             void *ptr;
471             const char *subt = stored_child_type;
472             g_array_set_size (vals, i + 1);
473             ptr = vals->data + elem_size * i;
474             ptr = ALIGN_ADDRESS (ptr, elem_align);
475             dbind_any_demarshal (&child, &subt, &ptr);
476             i++;
477         };
478         break;
479     }
480     case DBUS_STRUCT_BEGIN_CHAR: {
481                 gconstpointer data0 = *data;
482                 int offset = 0, stralign;
483         DBusMessageIter child;
484
485         stralign = dbind_find_c_alignment (*type);
486
487         (*type)++;
488
489         dbus_message_iter_recurse (iter, &child);
490
491         while (**type != DBUS_STRUCT_END_CHAR) {
492             const char *subt = *type;
493                         offset = ALIGN_VALUE (offset, dbind_find_c_alignment (*type));
494                         *data = PTR_PLUS (data0, offset);
495             dbind_any_demarshal (&child, type, data);
496             offset += dbind_gather_alloc_info (subt);
497         }
498
499                 offset = ALIGN_VALUE (offset, stralign);
500                 *data = PTR_PLUS (data0, offset);
501
502         g_assert (**type == DBUS_STRUCT_END_CHAR);
503         (*type)++;
504
505         break;
506     }
507     case DBUS_TYPE_STRUCT:
508     case DBUS_TYPE_DICT_ENTRY:
509         warn_braces ();
510         break;
511     }
512     dbus_message_iter_next (iter);
513 }
514
515 /*---------------------------------------------------------------------------*/
516
517 void
518 dbind_any_demarshal_va (DBusMessageIter *iter,
519                         const char           **arg_types,
520                         va_list          args)
521 {
522     const char *p = *arg_types;
523     for (;*p != '\0';) {
524         void *arg = va_arg (args, void *);
525         dbind_any_demarshal (iter, &p, &arg);
526     }
527 }
528
529 /*---------------------------------------------------------------------------*/
530
531 /* nice deep free ... */
532 void
533 dbind_any_free (const char *type,
534                 void *ptr)
535 {
536     dbind_any_free_r (&type, &ptr);
537 }
538
539 /* should this be the default normalization ? */
540 void
541 dbind_any_free_ptr (const char *type, void *ptr)
542 {
543     dbind_any_free (type, &ptr);
544 }
545
546 /*---------------------------------------------------------------------------*/
547
548 unsigned int
549 dbind_find_c_alignment (const char *type)
550 {
551     return dbind_find_c_alignment_r (&type);
552 }
553
554 /*END------------------------------------------------------------------------*/