2 * Copyright 2008-2011 Novell, Inc.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
20 /* type driven marshalling */
25 #include "dbind-config.h"
26 #include "dbind-any.h"
30 /* Align a value upward to a boundary, expressed as a number of bytes.
31 * E.g. align to an 8-byte boundary with argument of 8.
33 * (this + boundary - 1)
37 #define ALIGN_VALUE(this, boundary) \
38 (( ((gulong)(this)) + (((gulong)(boundary)) -1)) & (~(((gulong)(boundary))-1)))
40 #define ALIGN_ADDRESS(this, boundary) \
41 ((gpointer)ALIGN_VALUE(this, boundary))
43 #define PTR_PLUS(ptr, offset) \
44 ((gpointer) (((guchar *)(ptr)) + (offset)))
46 #define DBIND_POD_CASES \
48 case DBUS_TYPE_INT16: \
49 case DBUS_TYPE_UINT16: \
50 case DBUS_TYPE_INT32: \
51 case DBUS_TYPE_UINT32: \
52 case DBUS_TYPE_BOOLEAN: \
53 case DBUS_TYPE_INT64: \
54 case DBUS_TYPE_UINT64: \
57 /*---------------------------------------------------------------------------*/
62 fprintf (stderr, "Error: dbus flags structures & dicts with braces rather than "
63 " an explicit type member of 'struct'\n");
66 /*---------------------------------------------------------------------------*/
69 dbind_find_c_alignment_r (const char **type)
71 unsigned int retval = 1;
77 fprintf (stderr, "\tfind align for %c (0x%x)\n", t, t);
82 return DBIND_ALIGNOF_CHAR;
83 case DBUS_TYPE_BOOLEAN:
84 return DBIND_ALIGNOF_DBUS_BOOL_T;
86 case DBUS_TYPE_UINT16:
87 return DBIND_ALIGNOF_DBUS_INT16_T;
89 case DBUS_TYPE_UINT32:
90 return DBIND_ALIGNOF_DBUS_INT32_T;
92 case DBUS_TYPE_UINT64:
93 return DBIND_ALIGNOF_DBUS_INT64_T;
94 case DBUS_TYPE_DOUBLE:
95 return DBIND_ALIGNOF_DOUBLE;
97 case DBUS_TYPE_STRING:
98 case DBUS_TYPE_OBJECT_PATH:
99 case DBUS_TYPE_SIGNATURE:
100 case DBUS_TYPE_ARRAY:
101 return DBIND_ALIGNOF_DBIND_POINTER;
102 case DBUS_STRUCT_BEGIN_CHAR:
103 /* TODO: I think this would break with a nested struct */
104 #if DBIND_ALIGNOF_DBIND_STRUCT > 1
105 retval = MAX (retval, DBIND_ALIGNOF_DBIND_STRUCT);
107 while (**type != DBUS_STRUCT_END_CHAR) {
108 int elem_align = dbind_find_c_alignment_r (type);
109 retval = MAX (retval, elem_align);
113 case DBUS_DICT_ENTRY_BEGIN_CHAR:
114 #if DBIND_ALIGNOF_DBIND_STRUCT > 1
115 retval = MAX (retval, DBIND_ALIGNOF_DBIND_STRUCT);
117 while (**type != DBUS_DICT_ENTRY_END_CHAR) {
118 int elem_align = dbind_find_c_alignment_r (type);
119 retval = MAX (retval, elem_align);
123 case DBUS_TYPE_STRUCT:
124 case DBUS_TYPE_DICT_ENTRY:
126 return DBIND_ALIGNOF_DBIND_POINTER;
128 g_assert_not_reached();
135 /*---------------------------------------------------------------------------*/
137 /* gather immediate allocation information for this type */
139 dbind_gather_alloc_info_r (const char **type)
143 if (t == DBUS_TYPE_ARRAY)
147 case DBUS_STRUCT_BEGIN_CHAR:
148 while (**type != DBUS_STRUCT_END_CHAR && **type != '\0') (*type)++;
149 if (**type != '\0') (*type)++;
151 case DBUS_DICT_ENTRY_BEGIN_CHAR:
152 while (**type != DBUS_DICT_ENTRY_END_CHAR && **type != '\0') (*type)++;
153 if (**type != '\0') (*type)++;
165 return sizeof (char);
166 case DBUS_TYPE_BOOLEAN:
167 return sizeof (dbus_bool_t);
168 case DBUS_TYPE_INT16:
169 case DBUS_TYPE_UINT16:
170 return sizeof (dbus_int16_t);
171 case DBUS_TYPE_INT32:
172 case DBUS_TYPE_UINT32:
173 return sizeof (dbus_int32_t);
174 case DBUS_TYPE_INT64:
175 case DBUS_TYPE_UINT64:
176 return sizeof (dbus_int64_t);
177 case DBUS_TYPE_DOUBLE:
178 return sizeof (double);
180 case DBUS_TYPE_STRING:
181 case DBUS_TYPE_OBJECT_PATH:
182 case DBUS_TYPE_SIGNATURE:
183 case DBUS_TYPE_ARRAY:
184 return sizeof (void *);
185 case DBUS_STRUCT_BEGIN_CHAR: {
186 int sum = 0, stralign;
188 stralign = dbind_find_c_alignment (*type - 1);
190 while (**type != DBUS_STRUCT_END_CHAR) {
191 sum = ALIGN_VALUE (sum, dbind_find_c_alignment (*type));
192 sum += dbind_gather_alloc_info_r (type);
194 sum = ALIGN_VALUE (sum, stralign);
196 g_assert (**type == DBUS_STRUCT_END_CHAR);
201 case DBUS_DICT_ENTRY_BEGIN_CHAR: {
202 int sum = 0, stralign;
204 stralign = dbind_find_c_alignment (*type - 1);
206 while (**type != DBUS_DICT_ENTRY_END_CHAR) {
207 sum = ALIGN_VALUE (sum, dbind_find_c_alignment (*type));
208 sum += dbind_gather_alloc_info_r (type);
210 sum = ALIGN_VALUE (sum, stralign);
212 g_assert (**type == DBUS_DICT_ENTRY_END_CHAR);
217 case DBUS_TYPE_STRUCT:
218 case DBUS_TYPE_DICT_ENTRY:
226 dbind_gather_alloc_info (const char *type)
228 return dbind_gather_alloc_info_r (&type);
231 /*---------------------------------------------------------------------------*/
234 dbind_any_free_r (const char **type, void **data)
237 fprintf (stderr, "any free '%c' to %p\n", **type, *data);
241 case DBIND_POD_CASES:
242 *data = ((guchar *)*data) + dbind_gather_alloc_info (*type);
245 case DBUS_TYPE_STRING:
246 case DBUS_TYPE_OBJECT_PATH:
247 case DBUS_TYPE_SIGNATURE:
249 fprintf (stderr, "string free %p\n", **(void ***)data);
251 g_free (**(void ***)data);
252 *data = ((guchar *)*data) + dbind_gather_alloc_info (*type);
255 case DBUS_TYPE_ARRAY: {
257 GArray *vals = **(void ***)data;
258 size_t elem_size, elem_align;
259 const char *saved_child_type;
262 saved_child_type = *type;
264 elem_size = dbind_gather_alloc_info (*type);
265 elem_align = dbind_find_c_alignment_r (type);
267 for (i = 0; i < vals->len; i++) {
268 void *ptr = vals->data + elem_size * i;
269 *type = saved_child_type; /* rewind type info */
270 ptr = ALIGN_ADDRESS (ptr, elem_align);
271 dbind_any_free_r (type, &ptr);
273 g_array_free (vals, TRUE);
276 case DBUS_STRUCT_BEGIN_CHAR: {
277 gconstpointer data0 = *data;
278 int offset = 0, stralign;
280 stralign = dbind_find_c_alignment (*type);
284 while (**type != DBUS_STRUCT_END_CHAR) {
285 const char *subt = *type;
286 offset = ALIGN_VALUE (offset, dbind_find_c_alignment (*type));
287 *data = PTR_PLUS (data0, offset);
288 dbind_any_free_r (type, data);
289 offset += dbind_gather_alloc_info (subt);
292 offset = ALIGN_VALUE (offset, stralign);
293 *data = PTR_PLUS (data0, offset);
295 g_assert (**type == DBUS_STRUCT_END_CHAR);
300 case DBUS_DICT_ENTRY_BEGIN_CHAR: {
301 gconstpointer data0 = *data;
302 int offset = 0, stralign;
304 stralign = dbind_find_c_alignment (*type);
308 while (**type != DBUS_DICT_ENTRY_END_CHAR) {
309 const char *subt = *type;
310 offset = ALIGN_VALUE (offset, dbind_find_c_alignment (*type));
311 *data = PTR_PLUS (data0, offset);
312 dbind_any_free_r (type, data);
313 offset += dbind_gather_alloc_info (subt);
316 offset = ALIGN_VALUE (offset, stralign);
317 *data = PTR_PLUS (data0, offset);
319 g_assert (**type == DBUS_DICT_ENTRY_END_CHAR);
324 case DBUS_TYPE_STRUCT:
325 case DBUS_TYPE_DICT_ENTRY:
331 /*---------------------------------------------------------------------------*/
334 dbind_any_marshal (DBusMessageIter *iter,
341 fprintf (stderr, "any marshal '%c' to %p\n", **type, *data);
345 case DBIND_POD_CASES:
346 case DBUS_TYPE_STRING:
347 case DBUS_TYPE_OBJECT_PATH:
348 case DBUS_TYPE_SIGNATURE:
349 len = dbind_gather_alloc_info (*type);
350 dbus_message_iter_append_basic (iter, **type, *data);
351 *data = ((guchar *)*data) + len;
354 case DBUS_TYPE_ARRAY: {
356 GArray *vals = **(void ***)data;
357 size_t elem_size, elem_align;
359 const char *saved_child_type;
360 char *child_type_string;
363 saved_child_type = *type;
365 elem_size = dbind_gather_alloc_info (*type);
366 elem_align = dbind_find_c_alignment_r (type);
368 /* wow this part of the API sucks too ... */
369 child_type_string = g_strndup (saved_child_type, *type - saved_child_type);
370 /* fprintf (stderr, "array child type '%s'\n", child_type_string); */
371 dbus_message_iter_open_container (iter, DBUS_TYPE_ARRAY,
372 child_type_string, &sub);
373 for (i = 0; i < vals->len; i++) {
374 void *ptr = vals->data + elem_size * i;
375 *type = saved_child_type; /* rewind type info */
376 ptr = ALIGN_ADDRESS (ptr, elem_align);
377 dbind_any_marshal (&sub, type, &ptr);
380 dbus_message_iter_close_container (iter, &sub);
381 g_free (child_type_string);
384 case DBUS_STRUCT_BEGIN_CHAR: {
385 gconstpointer data0 = *data;
386 int offset = 0, stralign;
389 stralign = dbind_find_c_alignment (*type);
393 dbus_message_iter_open_container (iter, DBUS_TYPE_STRUCT, NULL, &sub);
396 while (**type != DBUS_STRUCT_END_CHAR) {
397 const char *subt = *type;
398 offset = ALIGN_VALUE (offset, dbind_find_c_alignment (*type));
399 *data = PTR_PLUS (data0, offset);
400 dbind_any_marshal (&sub, type, data);
401 offset += dbind_gather_alloc_info (subt);
404 offset = ALIGN_VALUE (offset, stralign);
405 *data = PTR_PLUS (data0, offset);
407 dbus_message_iter_close_container (iter, &sub);
409 g_assert (**type == DBUS_STRUCT_END_CHAR);
414 case DBUS_DICT_ENTRY_BEGIN_CHAR: {
415 gconstpointer data0 = *data;
416 int offset = 0, stralign;
419 stralign = dbind_find_c_alignment (*type);
423 dbus_message_iter_open_container (iter, DBUS_TYPE_DICT_ENTRY, NULL, &sub);
426 while (**type != DBUS_DICT_ENTRY_END_CHAR) {
427 const char *subt = *type;
428 offset = ALIGN_VALUE (offset, dbind_find_c_alignment (*type));
429 *data = PTR_PLUS (data0, offset);
430 dbind_any_marshal (&sub, type, data);
431 offset += dbind_gather_alloc_info (subt);
434 offset = ALIGN_VALUE (offset, stralign);
435 *data = PTR_PLUS (data0, offset);
437 dbus_message_iter_close_container (iter, &sub);
439 g_assert (**type == DBUS_DICT_ENTRY_END_CHAR);
444 case DBUS_TYPE_STRUCT:
445 case DBUS_TYPE_DICT_ENTRY:
451 /*---------------------------------------------------------------------------*/
454 dbind_any_marshal_va (DBusMessageIter *iter,
455 const char **arg_types,
458 const char *p = *arg_types;
460 /* Guard against null arg types
461 Fix for - http://bugs.freedesktop.org/show_bug.cgi?id=23027
467 /* special case base-types since we need to walk the stack worse-luck */
468 for (;*p != '\0' && *p != '=';) {
472 dbus_int64_t int64arg;
477 case DBUS_TYPE_BOOLEAN:
478 case DBUS_TYPE_INT16:
479 case DBUS_TYPE_UINT16:
480 case DBUS_TYPE_INT32:
481 case DBUS_TYPE_UINT32:
482 intarg = va_arg (args, int);
485 case DBUS_TYPE_INT64:
486 case DBUS_TYPE_UINT64:
487 int64arg = va_arg (args, dbus_int64_t);
490 case DBUS_TYPE_DOUBLE:
491 doublearg = va_arg (args, double);
495 case DBUS_TYPE_STRING:
496 case DBUS_TYPE_OBJECT_PATH:
497 case DBUS_TYPE_SIGNATURE:
498 case DBUS_TYPE_ARRAY:
499 case DBUS_TYPE_DICT_ENTRY:
500 ptrarg = va_arg (args, void *);
503 case DBUS_STRUCT_BEGIN_CHAR:
504 ptrarg = va_arg (args, void *);
507 case DBUS_DICT_ENTRY_BEGIN_CHAR:
508 ptrarg = va_arg (args, void *);
512 case DBUS_TYPE_VARIANT:
513 fprintf (stderr, "No variant support yet - very toolkit specific\n");
514 ptrarg = va_arg (args, void *);
518 fprintf (stderr, "Unknown / invalid arg type %c\n", *p);
522 dbind_any_marshal (iter, &p, &arg);
529 /*---------------------------------------------------------------------------*/
532 dbind_any_demarshal (DBusMessageIter *iter,
539 fprintf (stderr, "any demarshal '%c' to %p\n", **type, *data);
543 case DBIND_POD_CASES:
544 len = dbind_gather_alloc_info (*type);
545 dbus_message_iter_get_basic (iter, *data);
546 *data = ((guchar *)*data) + len;
549 case DBUS_TYPE_STRING:
550 case DBUS_TYPE_OBJECT_PATH:
551 case DBUS_TYPE_SIGNATURE:
552 len = dbind_gather_alloc_info (*type);
553 dbus_message_iter_get_basic (iter, *data);
555 fprintf (stderr, "dup string '%s' (%p)\n", **(void ***)data, **(void ***)data);
557 **(void ***)data = g_strdup (**(void ***)data);
558 *data = ((guchar *)*data) + len;
561 case DBUS_TYPE_ARRAY: {
563 DBusMessageIter child;
564 size_t elem_size, elem_align;
565 const char *stored_child_type;
569 stored_child_type = *type;
571 elem_size = dbind_gather_alloc_info (*type);
572 elem_align = dbind_find_c_alignment_r (type);
573 vals = g_array_new (FALSE, FALSE, elem_size);
574 (**(void ***)data) = vals;
575 *data = ((guchar *)*data) + sizeof (void *);
578 dbus_message_iter_recurse (iter, &child);
579 while (dbus_message_iter_get_arg_type (&child) != DBUS_TYPE_INVALID) {
581 const char *subt = stored_child_type;
582 g_array_set_size (vals, i + 1);
583 ptr = vals->data + elem_size * i;
584 ptr = ALIGN_ADDRESS (ptr, elem_align);
585 dbind_any_demarshal (&child, &subt, &ptr);
590 case DBUS_STRUCT_BEGIN_CHAR: {
591 gconstpointer data0 = *data;
592 int offset = 0, stralign;
593 DBusMessageIter child;
595 stralign = dbind_find_c_alignment (*type);
599 dbus_message_iter_recurse (iter, &child);
601 while (**type != DBUS_STRUCT_END_CHAR) {
602 const char *subt = *type;
603 offset = ALIGN_VALUE (offset, dbind_find_c_alignment (*type));
604 *data = PTR_PLUS (data0, offset);
605 dbind_any_demarshal (&child, type, data);
606 offset += dbind_gather_alloc_info (subt);
609 offset = ALIGN_VALUE (offset, stralign);
610 *data = PTR_PLUS (data0, offset);
612 g_assert (**type == DBUS_STRUCT_END_CHAR);
617 case DBUS_DICT_ENTRY_BEGIN_CHAR: {
618 gconstpointer data0 = *data;
619 int offset = 0, stralign;
620 DBusMessageIter child;
622 stralign = dbind_find_c_alignment (*type);
626 dbus_message_iter_recurse (iter, &child);
628 while (**type != DBUS_DICT_ENTRY_END_CHAR) {
629 const char *subt = *type;
630 offset = ALIGN_VALUE (offset, dbind_find_c_alignment (*type));
631 *data = PTR_PLUS (data0, offset);
632 dbind_any_demarshal (&child, type, data);
633 offset += dbind_gather_alloc_info (subt);
636 offset = ALIGN_VALUE (offset, stralign);
637 *data = PTR_PLUS (data0, offset);
639 g_assert (**type == DBUS_DICT_ENTRY_END_CHAR);
643 case DBUS_TYPE_VARIANT:
644 /* skip; unimplemented for now */
648 case DBUS_TYPE_STRUCT:
649 case DBUS_TYPE_DICT_ENTRY:
653 dbus_message_iter_next (iter);
657 pass_complex_arg (const char *p, char begin, char end)
662 while (*p && level > 0)
676 pass_arg (const char *p)
681 return pass_complex_arg (p, '(', ')');
683 return pass_complex_arg (p, '{', '}');
685 return pass_arg (p+1);
691 /*---------------------------------------------------------------------------*/
694 dbind_any_demarshal_va (DBusMessageIter *iter,
695 const char **arg_types,
698 const char *p = *arg_types;
701 for (;*p != '\0' && *p != '=';) {
705 dbus_int64_t int64arg;
710 case DBUS_TYPE_BOOLEAN:
711 case DBUS_TYPE_INT16:
712 case DBUS_TYPE_UINT16:
713 case DBUS_TYPE_INT32:
714 case DBUS_TYPE_UINT32:
715 intarg = va_arg (args, int);
717 case DBUS_TYPE_INT64:
718 case DBUS_TYPE_UINT64:
719 int64arg = va_arg (args, dbus_int64_t);
721 case DBUS_TYPE_DOUBLE:
722 doublearg = va_arg (args, double);
725 case DBUS_TYPE_STRING:
726 case DBUS_TYPE_OBJECT_PATH:
727 case DBUS_TYPE_SIGNATURE:
728 case DBUS_TYPE_ARRAY:
729 case DBUS_TYPE_DICT_ENTRY:
730 ptrarg = va_arg (args, void *);
732 case DBUS_STRUCT_BEGIN_CHAR:
733 ptrarg = va_arg (args, void *);
735 case DBUS_DICT_ENTRY_BEGIN_CHAR:
736 ptrarg = va_arg (args, void *);
739 case DBUS_TYPE_VARIANT:
740 fprintf (stderr, "No variant support yet - very toolkit specific\n");
741 ptrarg = va_arg (args, void *);
744 fprintf (stderr, "Unknown / invalid arg type %c\n", *p);
750 if (p [0] == '=' && p[1] == '>')
754 void *arg = va_arg (args, void *);
755 dbind_any_demarshal (iter, &p, &arg);
759 /*---------------------------------------------------------------------------*/
761 /* nice deep free ... */
763 dbind_any_free (const char *type,
766 dbind_any_free_r (&type, &ptr);
769 /* should this be the default normalization ? */
771 dbind_any_free_ptr (const char *type, void *ptr)
773 dbind_any_free (type, &ptr);
776 /*---------------------------------------------------------------------------*/
779 dbind_find_c_alignment (const char *type)
781 return dbind_find_c_alignment_r (&type);
784 /*END------------------------------------------------------------------------*/