1 /* type driven marshalling */
6 #include "dbind-config.h"
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.
14 * (this + boundary - 1)
18 #define ALIGN_VALUE(this, boundary) \
19 (( ((gulong)(this)) + (((gulong)(boundary)) -1)) & (~(((gulong)(boundary))-1)))
21 #define ALIGN_ADDRESS(this, boundary) \
22 ((gpointer)ALIGN_VALUE(this, boundary))
24 #define PTR_PLUS(ptr, offset) \
25 ((gpointer) (((guchar *)(ptr)) + (offset)))
27 #define DBIND_POD_CASES \
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: \
38 /*---------------------------------------------------------------------------*/
43 fprintf (stderr, "Error: dbus flags structures & dicts with braces rather than "
44 " an explicit type member of 'struct'\n");
47 /*---------------------------------------------------------------------------*/
50 dbind_find_c_alignment_r (const char **type)
52 unsigned int retval = 1;
58 fprintf (stderr, "\tfind align for %c (0x%x)\n", t, t);
63 return DBIND_ALIGNOF_CHAR;
64 case DBUS_TYPE_BOOLEAN:
65 return DBIND_ALIGNOF_DBUS_BOOL_T;
67 case DBUS_TYPE_UINT16:
68 return DBIND_ALIGNOF_DBUS_INT16_T;
70 case DBUS_TYPE_UINT32:
71 return DBIND_ALIGNOF_DBUS_INT32_T;
73 case DBUS_TYPE_UINT64:
74 return DBIND_ALIGNOF_DBUS_INT64_T;
75 case DBUS_TYPE_DOUBLE:
76 return DBIND_ALIGNOF_DOUBLE;
78 case DBUS_TYPE_STRING:
79 case DBUS_TYPE_OBJECT_PATH:
80 case DBUS_TYPE_SIGNATURE:
82 return DBIND_ALIGNOF_DBIND_POINTER;
83 case DBUS_STRUCT_BEGIN_CHAR:
84 /* TODO: I think this would break with a nested struct */
85 #if DBIND_ALIGNOF_DBIND_STRUCT > 1
86 retval = MAX (retval, DBIND_ALIGNOF_DBIND_STRUCT);
88 while (**type != DBUS_STRUCT_END_CHAR) {
89 int elem_align = dbind_find_c_alignment_r (type);
90 retval = MAX (retval, elem_align);
94 case DBUS_DICT_ENTRY_BEGIN_CHAR:
95 #if DBIND_ALIGNOF_DBIND_STRUCT > 1
96 retval = MAX (retval, DBIND_ALIGNOF_DBIND_STRUCT);
98 while (**type != DBUS_DICT_ENTRY_END_CHAR) {
99 int elem_align = dbind_find_c_alignment_r (type);
100 retval = MAX (retval, elem_align);
104 case DBUS_TYPE_STRUCT:
105 case DBUS_TYPE_DICT_ENTRY:
107 return DBIND_ALIGNOF_DBIND_POINTER;
109 g_assert_not_reached();
116 /*---------------------------------------------------------------------------*/
118 /* gather immediate allocation information for this type */
120 dbind_gather_alloc_info_r (const char **type)
124 if (t == DBUS_TYPE_ARRAY)
128 case DBUS_STRUCT_BEGIN_CHAR:
129 while (**type != DBUS_STRUCT_END_CHAR && **type != '\0') (*type)++;
130 if (**type != '\0') (*type)++;
132 case DBUS_DICT_ENTRY_BEGIN_CHAR:
133 while (**type != DBUS_DICT_ENTRY_END_CHAR && **type != '\0') (*type)++;
134 if (**type != '\0') (*type)++;
146 return sizeof (char);
147 case DBUS_TYPE_BOOLEAN:
148 return sizeof (dbus_bool_t);
149 case DBUS_TYPE_INT16:
150 case DBUS_TYPE_UINT16:
151 return sizeof (dbus_int16_t);
152 case DBUS_TYPE_INT32:
153 case DBUS_TYPE_UINT32:
154 return sizeof (dbus_int32_t);
155 case DBUS_TYPE_INT64:
156 case DBUS_TYPE_UINT64:
157 return sizeof (dbus_int64_t);
158 case DBUS_TYPE_DOUBLE:
159 return sizeof (double);
161 case DBUS_TYPE_STRING:
162 case DBUS_TYPE_OBJECT_PATH:
163 case DBUS_TYPE_SIGNATURE:
164 case DBUS_TYPE_ARRAY:
165 return sizeof (void *);
166 case DBUS_STRUCT_BEGIN_CHAR: {
167 int sum = 0, stralign;
169 stralign = dbind_find_c_alignment (*type - 1);
171 while (**type != DBUS_STRUCT_END_CHAR) {
172 sum = ALIGN_VALUE (sum, dbind_find_c_alignment (*type));
173 sum += dbind_gather_alloc_info_r (type);
175 sum = ALIGN_VALUE (sum, stralign);
177 g_assert (**type == DBUS_STRUCT_END_CHAR);
182 case DBUS_DICT_ENTRY_BEGIN_CHAR: {
183 int sum = 0, stralign;
185 stralign = dbind_find_c_alignment (*type - 1);
187 while (**type != DBUS_DICT_ENTRY_END_CHAR) {
188 sum = ALIGN_VALUE (sum, dbind_find_c_alignment (*type));
189 sum += dbind_gather_alloc_info_r (type);
191 sum = ALIGN_VALUE (sum, stralign);
193 g_assert (**type == DBUS_DICT_ENTRY_END_CHAR);
198 case DBUS_TYPE_STRUCT:
199 case DBUS_TYPE_DICT_ENTRY:
207 dbind_gather_alloc_info (const char *type)
209 return dbind_gather_alloc_info_r (&type);
212 /*---------------------------------------------------------------------------*/
215 dbind_any_free_r (const char **type, void **data)
218 fprintf (stderr, "any free '%c' to %p\n", **type, *data);
222 case DBIND_POD_CASES:
223 *data = ((guchar *)*data) + dbind_gather_alloc_info (*type);
226 case DBUS_TYPE_STRING:
227 case DBUS_TYPE_OBJECT_PATH:
228 case DBUS_TYPE_SIGNATURE:
230 fprintf (stderr, "string free %p\n", **(void ***)data);
232 g_free (**(void ***)data);
233 *data = ((guchar *)*data) + dbind_gather_alloc_info (*type);
236 case DBUS_TYPE_ARRAY: {
238 GArray *vals = **(void ***)data;
239 size_t elem_size, elem_align;
240 const char *saved_child_type;
243 saved_child_type = *type;
245 elem_size = dbind_gather_alloc_info (*type);
246 elem_align = dbind_find_c_alignment_r (type);
248 for (i = 0; i < vals->len; i++) {
249 void *ptr = vals->data + elem_size * i;
250 *type = saved_child_type; /* rewind type info */
251 ptr = ALIGN_ADDRESS (ptr, elem_align);
252 dbind_any_free_r (type, &ptr);
254 g_array_free (vals, TRUE);
257 case DBUS_STRUCT_BEGIN_CHAR: {
258 gconstpointer data0 = *data;
259 int offset = 0, stralign;
261 stralign = dbind_find_c_alignment (*type);
265 while (**type != DBUS_STRUCT_END_CHAR) {
266 const char *subt = *type;
267 offset = ALIGN_VALUE (offset, dbind_find_c_alignment (*type));
268 *data = PTR_PLUS (data0, offset);
269 dbind_any_free_r (type, data);
270 offset += dbind_gather_alloc_info (subt);
273 offset = ALIGN_VALUE (offset, stralign);
274 *data = PTR_PLUS (data0, offset);
276 g_assert (**type == DBUS_STRUCT_END_CHAR);
281 case DBUS_DICT_ENTRY_BEGIN_CHAR: {
282 gconstpointer data0 = *data;
283 int offset = 0, stralign;
285 stralign = dbind_find_c_alignment (*type);
289 while (**type != DBUS_DICT_ENTRY_END_CHAR) {
291 offset = ALIGN_VALUE (offset, dbind_find_c_alignment (*type));
292 *data = PTR_PLUS (data0, offset);
293 dbind_any_free_r (type, data);
294 offset += dbind_gather_alloc_info (subt);
297 offset = ALIGN_VALUE (offset, stralign);
298 *data = PTR_PLUS (data0, offset);
300 g_assert (**type == DBUS_DICT_ENTRY_END_CHAR);
305 case DBUS_TYPE_STRUCT:
306 case DBUS_TYPE_DICT_ENTRY:
312 /*---------------------------------------------------------------------------*/
315 dbind_any_marshal (DBusMessageIter *iter,
322 fprintf (stderr, "any marshal '%c' to %p\n", **type, *data);
326 case DBIND_POD_CASES:
327 case DBUS_TYPE_STRING:
328 case DBUS_TYPE_OBJECT_PATH:
329 case DBUS_TYPE_SIGNATURE:
330 len = dbind_gather_alloc_info (*type);
331 dbus_message_iter_append_basic (iter, **type, *data);
332 *data = ((guchar *)*data) + len;
335 case DBUS_TYPE_ARRAY: {
337 GArray *vals = **(void ***)data;
338 size_t elem_size, elem_align;
340 const char *saved_child_type;
341 char *child_type_string;
344 saved_child_type = *type;
346 elem_size = dbind_gather_alloc_info (*type);
347 elem_align = dbind_find_c_alignment_r (type);
349 /* wow this part of the API sucks too ... */
350 child_type_string = g_strndup (saved_child_type, *type - saved_child_type);
351 /* fprintf (stderr, "array child type '%s'\n", child_type_string); */
352 dbus_message_iter_open_container (iter, DBUS_TYPE_ARRAY,
353 child_type_string, &sub);
354 for (i = 0; i < vals->len; i++) {
355 void *ptr = vals->data + elem_size * i;
356 *type = saved_child_type; /* rewind type info */
357 ptr = ALIGN_ADDRESS (ptr, elem_align);
358 dbind_any_marshal (&sub, type, &ptr);
361 dbus_message_iter_close_container (iter, &sub);
362 g_free (child_type_string);
365 case DBUS_STRUCT_BEGIN_CHAR: {
366 gconstpointer data0 = *data;
367 int offset = 0, stralign;
370 stralign = dbind_find_c_alignment (*type);
374 dbus_message_iter_open_container (iter, DBUS_TYPE_STRUCT, NULL, &sub);
377 while (**type != DBUS_STRUCT_END_CHAR) {
378 const char *subt = *type;
379 offset = ALIGN_VALUE (offset, dbind_find_c_alignment (*type));
380 *data = PTR_PLUS (data0, offset);
381 dbind_any_marshal (&sub, type, data);
382 offset += dbind_gather_alloc_info (subt);
385 offset = ALIGN_VALUE (offset, stralign);
386 *data = PTR_PLUS (data0, offset);
388 dbus_message_iter_close_container (iter, &sub);
390 g_assert (**type == DBUS_STRUCT_END_CHAR);
395 case DBUS_DICT_ENTRY_BEGIN_CHAR: {
396 gconstpointer data0 = *data;
397 int offset = 0, stralign;
400 stralign = dbind_find_c_alignment (*type);
404 dbus_message_iter_open_container (iter, DBUS_TYPE_DICT_ENTRY, NULL, &sub);
407 while (**type != DBUS_DICT_ENTRY_END_CHAR) {
409 offset = ALIGN_VALUE (offset, dbind_find_c_alignment (*type));
410 *data = PTR_PLUS (data0, offset);
411 dbind_any_marshal (&sub, type, data);
412 offset += dbind_gather_alloc_info (subt);
415 offset = ALIGN_VALUE (offset, stralign);
416 *data = PTR_PLUS (data0, offset);
418 dbus_message_iter_close_container (iter, &sub);
420 g_assert (**type == DBUS_DICT_ENTRY_END_CHAR);
425 case DBUS_TYPE_STRUCT:
426 case DBUS_TYPE_DICT_ENTRY:
432 /*---------------------------------------------------------------------------*/
435 dbind_any_marshal_va (DBusMessageIter *iter,
436 const char **arg_types,
439 const char *p = *arg_types;
441 /* Guard against null arg types
442 Fix for - http://bugs.freedesktop.org/show_bug.cgi?id=23027
448 /* special case base-types since we need to walk the stack worse-luck */
449 for (;*p != '\0' && *p != '=';) {
453 dbus_int64_t int64arg;
458 case DBUS_TYPE_BOOLEAN:
459 case DBUS_TYPE_INT16:
460 case DBUS_TYPE_UINT16:
461 case DBUS_TYPE_INT32:
462 case DBUS_TYPE_UINT32:
463 intarg = va_arg (args, int);
466 case DBUS_TYPE_INT64:
467 case DBUS_TYPE_UINT64:
468 int64arg = va_arg (args, dbus_int64_t);
471 case DBUS_TYPE_DOUBLE:
472 doublearg = va_arg (args, double);
476 case DBUS_TYPE_STRING:
477 case DBUS_TYPE_OBJECT_PATH:
478 case DBUS_TYPE_SIGNATURE:
479 case DBUS_TYPE_ARRAY:
480 case DBUS_TYPE_DICT_ENTRY:
481 ptrarg = va_arg (args, void *);
484 case DBUS_STRUCT_BEGIN_CHAR:
485 ptrarg = va_arg (args, void *);
488 case DBUS_DICT_ENTRY_BEGIN_CHAR:
489 ptrarg = va_arg (args, void *);
493 case DBUS_TYPE_VARIANT:
494 fprintf (stderr, "No variant support yet - very toolkit specific\n");
495 ptrarg = va_arg (args, void *);
499 fprintf (stderr, "Unknown / invalid arg type %c\n", *p);
503 dbind_any_marshal (iter, &p, &arg);
508 /*---------------------------------------------------------------------------*/
511 dbind_any_demarshal (DBusMessageIter *iter,
518 fprintf (stderr, "any demarshal '%c' to %p\n", **type, *data);
522 case DBIND_POD_CASES:
523 len = dbind_gather_alloc_info (*type);
524 dbus_message_iter_get_basic (iter, *data);
525 *data = ((guchar *)*data) + len;
528 case DBUS_TYPE_STRING:
529 case DBUS_TYPE_OBJECT_PATH:
530 case DBUS_TYPE_SIGNATURE:
531 len = dbind_gather_alloc_info (*type);
532 dbus_message_iter_get_basic (iter, *data);
534 fprintf (stderr, "dup string '%s' (%p)\n", **(void ***)data, **(void ***)data);
536 **(void ***)data = g_strdup (**(void ***)data);
537 *data = ((guchar *)*data) + len;
540 case DBUS_TYPE_ARRAY: {
542 DBusMessageIter child;
543 size_t elem_size, elem_align;
544 const char *stored_child_type;
548 stored_child_type = *type;
550 elem_size = dbind_gather_alloc_info (*type);
551 elem_align = dbind_find_c_alignment_r (type);
552 vals = g_array_new (FALSE, FALSE, elem_size);
553 (**(void ***)data) = vals;
554 *data = ((guchar *)*data) + sizeof (void *);
557 dbus_message_iter_recurse (iter, &child);
558 while (dbus_message_iter_get_arg_type (&child) != DBUS_TYPE_INVALID) {
560 const char *subt = stored_child_type;
561 g_array_set_size (vals, i + 1);
562 ptr = vals->data + elem_size * i;
563 ptr = ALIGN_ADDRESS (ptr, elem_align);
564 dbind_any_demarshal (&child, &subt, &ptr);
569 case DBUS_STRUCT_BEGIN_CHAR: {
570 gconstpointer data0 = *data;
571 int offset = 0, stralign;
572 DBusMessageIter child;
574 stralign = dbind_find_c_alignment (*type);
578 dbus_message_iter_recurse (iter, &child);
580 while (**type != DBUS_STRUCT_END_CHAR) {
581 const char *subt = *type;
582 offset = ALIGN_VALUE (offset, dbind_find_c_alignment (*type));
583 *data = PTR_PLUS (data0, offset);
584 dbind_any_demarshal (&child, type, data);
585 offset += dbind_gather_alloc_info (subt);
588 offset = ALIGN_VALUE (offset, stralign);
589 *data = PTR_PLUS (data0, offset);
591 g_assert (**type == DBUS_STRUCT_END_CHAR);
596 case DBUS_DICT_ENTRY_BEGIN_CHAR: {
597 gconstpointer data0 = *data;
598 int offset = 0, stralign;
599 DBusMessageIter child;
601 stralign = dbind_find_c_alignment (*type);
605 dbus_message_iter_recurse (iter, &child);
607 while (**type != DBUS_DICT_ENTRY_END_CHAR) {
609 offset = ALIGN_VALUE (offset, dbind_find_c_alignment (*type));
610 *data = PTR_PLUS (data0, offset);
611 dbind_any_demarshal (&child, type, data);
612 offset += dbind_gather_alloc_info (subt);
615 offset = ALIGN_VALUE (offset, stralign);
616 *data = PTR_PLUS (data0, offset);
618 g_assert (**type == DBUS_DICT_ENTRY_END_CHAR);
623 case DBUS_TYPE_STRUCT:
624 case DBUS_TYPE_DICT_ENTRY:
628 dbus_message_iter_next (iter);
631 /*---------------------------------------------------------------------------*/
634 dbind_any_demarshal_va (DBusMessageIter *iter,
635 const char **arg_types,
638 const char *p = *arg_types;
640 void *arg = va_arg (args, void *);
641 dbind_any_demarshal (iter, &p, &arg);
645 /*---------------------------------------------------------------------------*/
647 /* nice deep free ... */
649 dbind_any_free (const char *type,
652 dbind_any_free_r (&type, &ptr);
655 /* should this be the default normalization ? */
657 dbind_any_free_ptr (const char *type, void *ptr)
659 dbind_any_free (type, &ptr);
662 /*---------------------------------------------------------------------------*/
665 dbind_find_c_alignment (const char *type)
667 return dbind_find_c_alignment_r (&type);
670 /*END------------------------------------------------------------------------*/