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