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-any.h"
29 /* Align a value upward to a boundary, expressed as a number of bytes.
30 * E.g. align to an 8-byte boundary with argument of 8.
32 * (this + boundary - 1)
36 #define ALIGN_VALUE(this, boundary) \
37 (( ((gulong)(this)) + (((gulong)(boundary)) -1)) & (~(((gulong)(boundary))-1)))
39 #define ALIGN_ADDRESS(this, boundary) \
40 ((gpointer)ALIGN_VALUE(this, boundary))
42 #define PTR_PLUS(ptr, offset) \
43 ((gpointer) (((guchar *)(ptr)) + (offset)))
45 #define DBIND_POD_CASES \
47 case DBUS_TYPE_INT16: \
48 case DBUS_TYPE_UINT16: \
49 case DBUS_TYPE_INT32: \
50 case DBUS_TYPE_UINT32: \
51 case DBUS_TYPE_BOOLEAN: \
52 case DBUS_TYPE_INT64: \
53 case DBUS_TYPE_UINT64: \
56 /*---------------------------------------------------------------------------*/
61 fprintf (stderr, "Error: dbus flags structures & dicts with braces rather than "
62 " an explicit type member of 'struct'\n");
65 /*---------------------------------------------------------------------------*/
68 dbind_find_c_alignment_r (const char **type)
70 unsigned int retval = 1;
76 fprintf (stderr, "\tfind align for %c (0x%x)\n", t, t);
82 case DBUS_TYPE_BOOLEAN:
83 return ALIGNOF_DBUS_BOOL_T;
85 case DBUS_TYPE_UINT16:
86 return ALIGNOF_DBUS_INT16_T;
88 case DBUS_TYPE_UINT32:
89 return ALIGNOF_DBUS_INT32_T;
91 case DBUS_TYPE_UINT64:
92 return ALIGNOF_DBUS_INT64_T;
93 case DBUS_TYPE_DOUBLE:
94 return ALIGNOF_DOUBLE;
96 case DBUS_TYPE_STRING:
97 case DBUS_TYPE_OBJECT_PATH:
98 case DBUS_TYPE_SIGNATURE:
100 return ALIGNOF_DBIND_POINTER;
101 case DBUS_STRUCT_BEGIN_CHAR:
102 /* TODO: I think this would break with a nested struct */
103 #if ALIGNOF_DBIND_STRUCT > 1
104 retval = MAX (retval, ALIGNOF_DBIND_STRUCT);
106 while (**type != DBUS_STRUCT_END_CHAR) {
107 int elem_align = dbind_find_c_alignment_r (type);
108 retval = MAX (retval, elem_align);
112 case DBUS_DICT_ENTRY_BEGIN_CHAR:
113 #if ALIGNOF_DBIND_STRUCT > 1
114 retval = MAX (retval, ALIGNOF_DBIND_STRUCT);
116 while (**type != DBUS_DICT_ENTRY_END_CHAR) {
117 int elem_align = dbind_find_c_alignment_r (type);
118 retval = MAX (retval, elem_align);
122 case DBUS_TYPE_STRUCT:
123 case DBUS_TYPE_DICT_ENTRY:
125 return ALIGNOF_DBIND_POINTER;
127 g_assert_not_reached();
134 /*---------------------------------------------------------------------------*/
136 /* gather immediate allocation information for this type */
138 dbind_gather_alloc_info_r (const char **type)
142 if (t == DBUS_TYPE_ARRAY)
146 case DBUS_STRUCT_BEGIN_CHAR:
147 while (**type != DBUS_STRUCT_END_CHAR && **type != '\0') (*type)++;
148 if (**type != '\0') (*type)++;
150 case DBUS_DICT_ENTRY_BEGIN_CHAR:
151 while (**type != DBUS_DICT_ENTRY_END_CHAR && **type != '\0') (*type)++;
152 if (**type != '\0') (*type)++;
164 return sizeof (char);
165 case DBUS_TYPE_BOOLEAN:
166 return sizeof (dbus_bool_t);
167 case DBUS_TYPE_INT16:
168 case DBUS_TYPE_UINT16:
169 return sizeof (dbus_int16_t);
170 case DBUS_TYPE_INT32:
171 case DBUS_TYPE_UINT32:
172 return sizeof (dbus_int32_t);
173 case DBUS_TYPE_INT64:
174 case DBUS_TYPE_UINT64:
175 return sizeof (dbus_int64_t);
176 case DBUS_TYPE_DOUBLE:
177 return sizeof (double);
179 case DBUS_TYPE_STRING:
180 case DBUS_TYPE_OBJECT_PATH:
181 case DBUS_TYPE_SIGNATURE:
182 case DBUS_TYPE_ARRAY:
183 return sizeof (void *);
184 case DBUS_STRUCT_BEGIN_CHAR: {
185 int sum = 0, stralign;
187 stralign = dbind_find_c_alignment (*type - 1);
189 while (**type != DBUS_STRUCT_END_CHAR) {
190 sum = ALIGN_VALUE (sum, dbind_find_c_alignment (*type));
191 sum += dbind_gather_alloc_info_r (type);
193 sum = ALIGN_VALUE (sum, stralign);
195 g_assert (**type == DBUS_STRUCT_END_CHAR);
200 case DBUS_DICT_ENTRY_BEGIN_CHAR: {
201 int sum = 0, stralign;
203 stralign = dbind_find_c_alignment (*type - 1);
205 while (**type != DBUS_DICT_ENTRY_END_CHAR) {
206 sum = ALIGN_VALUE (sum, dbind_find_c_alignment (*type));
207 sum += dbind_gather_alloc_info_r (type);
209 sum = ALIGN_VALUE (sum, stralign);
211 g_assert (**type == DBUS_DICT_ENTRY_END_CHAR);
216 case DBUS_TYPE_STRUCT:
217 case DBUS_TYPE_DICT_ENTRY:
225 dbind_gather_alloc_info (const char *type)
227 return dbind_gather_alloc_info_r (&type);
230 /*---------------------------------------------------------------------------*/
233 dbind_any_free_r (const char **type, void **data)
236 fprintf (stderr, "any free '%c' to %p\n", **type, *data);
240 case DBIND_POD_CASES:
241 *data = ((guchar *)*data) + dbind_gather_alloc_info (*type);
244 case DBUS_TYPE_STRING:
245 case DBUS_TYPE_OBJECT_PATH:
246 case DBUS_TYPE_SIGNATURE:
248 fprintf (stderr, "string free %p\n", **(void ***)data);
250 g_free (**(void ***)data);
251 *data = ((guchar *)*data) + dbind_gather_alloc_info (*type);
254 case DBUS_TYPE_ARRAY: {
256 GArray *vals = **(void ***)data;
257 size_t elem_size, elem_align;
258 const char *saved_child_type;
261 saved_child_type = *type;
263 elem_size = dbind_gather_alloc_info (*type);
264 elem_align = dbind_find_c_alignment_r (type);
266 for (i = 0; i < vals->len; i++) {
267 void *ptr = vals->data + elem_size * i;
268 *type = saved_child_type; /* rewind type info */
269 ptr = ALIGN_ADDRESS (ptr, elem_align);
270 dbind_any_free_r (type, &ptr);
272 g_array_free (vals, TRUE);
275 case DBUS_STRUCT_BEGIN_CHAR: {
276 gconstpointer data0 = *data;
277 int offset = 0, stralign;
279 stralign = dbind_find_c_alignment (*type);
283 while (**type != DBUS_STRUCT_END_CHAR) {
284 const char *subt = *type;
285 offset = ALIGN_VALUE (offset, dbind_find_c_alignment (*type));
286 *data = PTR_PLUS (data0, offset);
287 dbind_any_free_r (type, data);
288 offset += dbind_gather_alloc_info (subt);
291 offset = ALIGN_VALUE (offset, stralign);
292 *data = PTR_PLUS (data0, offset);
294 g_assert (**type == DBUS_STRUCT_END_CHAR);
299 case DBUS_DICT_ENTRY_BEGIN_CHAR: {
300 gconstpointer data0 = *data;
301 int offset = 0, stralign;
303 stralign = dbind_find_c_alignment (*type);
307 while (**type != DBUS_DICT_ENTRY_END_CHAR) {
308 const char *subt = *type;
309 offset = ALIGN_VALUE (offset, dbind_find_c_alignment (*type));
310 *data = PTR_PLUS (data0, offset);
311 dbind_any_free_r (type, data);
312 offset += dbind_gather_alloc_info (subt);
315 offset = ALIGN_VALUE (offset, stralign);
316 *data = PTR_PLUS (data0, offset);
318 g_assert (**type == DBUS_DICT_ENTRY_END_CHAR);
323 case DBUS_TYPE_STRUCT:
324 case DBUS_TYPE_DICT_ENTRY:
330 /*---------------------------------------------------------------------------*/
333 dbind_any_marshal (DBusMessageIter *iter,
340 fprintf (stderr, "any marshal '%c' to %p\n", **type, *data);
344 case DBIND_POD_CASES:
345 case DBUS_TYPE_STRING:
346 case DBUS_TYPE_OBJECT_PATH:
347 case DBUS_TYPE_SIGNATURE:
348 len = dbind_gather_alloc_info (*type);
349 dbus_message_iter_append_basic (iter, **type, *data);
350 *data = ((guchar *)*data) + len;
353 case DBUS_TYPE_ARRAY: {
355 GArray *vals = **(void ***)data;
356 size_t elem_size, elem_align;
358 const char *saved_child_type;
359 char *child_type_string;
362 saved_child_type = *type;
364 elem_size = dbind_gather_alloc_info (*type);
365 elem_align = dbind_find_c_alignment_r (type);
367 /* wow this part of the API sucks too ... */
368 child_type_string = g_strndup (saved_child_type, *type - saved_child_type);
369 /* fprintf (stderr, "array child type '%s'\n", child_type_string); */
370 dbus_message_iter_open_container (iter, DBUS_TYPE_ARRAY,
371 child_type_string, &sub);
372 for (i = 0; i < vals->len; i++) {
373 void *ptr = vals->data + elem_size * i;
374 *type = saved_child_type; /* rewind type info */
375 ptr = ALIGN_ADDRESS (ptr, elem_align);
376 dbind_any_marshal (&sub, type, &ptr);
379 dbus_message_iter_close_container (iter, &sub);
380 g_free (child_type_string);
383 case DBUS_STRUCT_BEGIN_CHAR: {
384 gconstpointer data0 = *data;
385 int offset = 0, stralign;
388 stralign = dbind_find_c_alignment (*type);
392 dbus_message_iter_open_container (iter, DBUS_TYPE_STRUCT, NULL, &sub);
395 while (**type != DBUS_STRUCT_END_CHAR) {
396 const char *subt = *type;
397 offset = ALIGN_VALUE (offset, dbind_find_c_alignment (*type));
398 *data = PTR_PLUS (data0, offset);
399 dbind_any_marshal (&sub, type, data);
400 offset += dbind_gather_alloc_info (subt);
403 offset = ALIGN_VALUE (offset, stralign);
404 *data = PTR_PLUS (data0, offset);
406 dbus_message_iter_close_container (iter, &sub);
408 g_assert (**type == DBUS_STRUCT_END_CHAR);
413 case DBUS_DICT_ENTRY_BEGIN_CHAR: {
414 gconstpointer data0 = *data;
415 int offset = 0, stralign;
418 stralign = dbind_find_c_alignment (*type);
422 dbus_message_iter_open_container (iter, DBUS_TYPE_DICT_ENTRY, NULL, &sub);
425 while (**type != DBUS_DICT_ENTRY_END_CHAR) {
426 const char *subt = *type;
427 offset = ALIGN_VALUE (offset, dbind_find_c_alignment (*type));
428 *data = PTR_PLUS (data0, offset);
429 dbind_any_marshal (&sub, type, data);
430 offset += dbind_gather_alloc_info (subt);
433 offset = ALIGN_VALUE (offset, stralign);
434 *data = PTR_PLUS (data0, offset);
436 dbus_message_iter_close_container (iter, &sub);
438 g_assert (**type == DBUS_DICT_ENTRY_END_CHAR);
443 case DBUS_TYPE_STRUCT:
444 case DBUS_TYPE_DICT_ENTRY:
450 /*---------------------------------------------------------------------------*/
453 dbind_any_marshal_va (DBusMessageIter *iter,
454 const char **arg_types,
457 const char *p = *arg_types;
459 /* Guard against null arg types
460 Fix for - http://bugs.freedesktop.org/show_bug.cgi?id=23027
466 /* special case base-types since we need to walk the stack worse-luck */
467 for (;*p != '\0' && *p != '=';) {
471 dbus_int64_t int64arg;
476 case DBUS_TYPE_BOOLEAN:
477 case DBUS_TYPE_INT16:
478 case DBUS_TYPE_UINT16:
479 case DBUS_TYPE_INT32:
480 case DBUS_TYPE_UINT32:
481 intarg = va_arg (args, int);
484 case DBUS_TYPE_INT64:
485 case DBUS_TYPE_UINT64:
486 int64arg = va_arg (args, dbus_int64_t);
489 case DBUS_TYPE_DOUBLE:
490 doublearg = va_arg (args, double);
494 case DBUS_TYPE_STRING:
495 case DBUS_TYPE_OBJECT_PATH:
496 case DBUS_TYPE_SIGNATURE:
497 case DBUS_TYPE_ARRAY:
498 case DBUS_TYPE_DICT_ENTRY:
499 ptrarg = va_arg (args, void *);
502 case DBUS_STRUCT_BEGIN_CHAR:
503 ptrarg = va_arg (args, void *);
506 case DBUS_DICT_ENTRY_BEGIN_CHAR:
507 ptrarg = va_arg (args, void *);
511 case DBUS_TYPE_VARIANT:
512 fprintf (stderr, "No variant support yet - very toolkit specific\n");
513 ptrarg = va_arg (args, void *);
517 fprintf (stderr, "Unknown / invalid arg type %c\n", *p);
521 dbind_any_marshal (iter, &p, &arg);
528 /*---------------------------------------------------------------------------*/
531 dbind_any_demarshal (DBusMessageIter *iter,
538 fprintf (stderr, "any demarshal '%c' to %p\n", **type, *data);
542 case DBIND_POD_CASES:
543 len = dbind_gather_alloc_info (*type);
544 dbus_message_iter_get_basic (iter, *data);
545 *data = ((guchar *)*data) + len;
548 case DBUS_TYPE_STRING:
549 case DBUS_TYPE_OBJECT_PATH:
550 case DBUS_TYPE_SIGNATURE:
551 len = dbind_gather_alloc_info (*type);
552 dbus_message_iter_get_basic (iter, *data);
554 fprintf (stderr, "dup string '%s' (%p)\n", **(void ***)data, **(void ***)data);
556 **(void ***)data = g_strdup (**(void ***)data);
557 *data = ((guchar *)*data) + len;
560 case DBUS_TYPE_ARRAY: {
562 DBusMessageIter child;
563 size_t elem_size, elem_align;
564 const char *stored_child_type;
568 stored_child_type = *type;
570 elem_size = dbind_gather_alloc_info (*type);
571 elem_align = dbind_find_c_alignment_r (type);
572 vals = g_array_new (FALSE, FALSE, elem_size);
573 (**(void ***)data) = vals;
574 *data = ((guchar *)*data) + sizeof (void *);
577 dbus_message_iter_recurse (iter, &child);
578 while (dbus_message_iter_get_arg_type (&child) != DBUS_TYPE_INVALID) {
580 const char *subt = stored_child_type;
581 g_array_set_size (vals, i + 1);
582 ptr = vals->data + elem_size * i;
583 ptr = ALIGN_ADDRESS (ptr, elem_align);
584 dbind_any_demarshal (&child, &subt, &ptr);
589 case DBUS_STRUCT_BEGIN_CHAR: {
590 gconstpointer data0 = *data;
591 int offset = 0, stralign;
592 DBusMessageIter child;
594 stralign = dbind_find_c_alignment (*type);
598 dbus_message_iter_recurse (iter, &child);
600 while (**type != DBUS_STRUCT_END_CHAR) {
601 const char *subt = *type;
602 offset = ALIGN_VALUE (offset, dbind_find_c_alignment (*type));
603 *data = PTR_PLUS (data0, offset);
604 dbind_any_demarshal (&child, type, data);
605 offset += dbind_gather_alloc_info (subt);
608 offset = ALIGN_VALUE (offset, stralign);
609 *data = PTR_PLUS (data0, offset);
611 g_assert (**type == DBUS_STRUCT_END_CHAR);
616 case DBUS_DICT_ENTRY_BEGIN_CHAR: {
617 gconstpointer data0 = *data;
618 int offset = 0, stralign;
619 DBusMessageIter child;
621 stralign = dbind_find_c_alignment (*type);
625 dbus_message_iter_recurse (iter, &child);
627 while (**type != DBUS_DICT_ENTRY_END_CHAR) {
628 const char *subt = *type;
629 offset = ALIGN_VALUE (offset, dbind_find_c_alignment (*type));
630 *data = PTR_PLUS (data0, offset);
631 dbind_any_demarshal (&child, type, data);
632 offset += dbind_gather_alloc_info (subt);
635 offset = ALIGN_VALUE (offset, stralign);
636 *data = PTR_PLUS (data0, offset);
638 g_assert (**type == DBUS_DICT_ENTRY_END_CHAR);
642 case DBUS_TYPE_VARIANT:
643 /* skip; unimplemented for now */
647 case DBUS_TYPE_STRUCT:
648 case DBUS_TYPE_DICT_ENTRY:
652 dbus_message_iter_next (iter);
656 pass_complex_arg (const char *p, char begin, char end)
661 while (*p && level > 0)
675 pass_arg (const char *p)
680 return pass_complex_arg (p, '(', ')');
682 return pass_complex_arg (p, '{', '}');
684 return pass_arg (p+1);
690 /*---------------------------------------------------------------------------*/
693 dbind_any_demarshal_va (DBusMessageIter *iter,
694 const char **arg_types,
697 const char *p = *arg_types;
700 for (;*p != '\0' && *p != '=';) {
704 dbus_int64_t int64arg;
709 case DBUS_TYPE_BOOLEAN:
710 case DBUS_TYPE_INT16:
711 case DBUS_TYPE_UINT16:
712 case DBUS_TYPE_INT32:
713 case DBUS_TYPE_UINT32:
714 intarg = va_arg (args, int);
716 case DBUS_TYPE_INT64:
717 case DBUS_TYPE_UINT64:
718 int64arg = va_arg (args, dbus_int64_t);
720 case DBUS_TYPE_DOUBLE:
721 doublearg = va_arg (args, double);
724 case DBUS_TYPE_STRING:
725 case DBUS_TYPE_OBJECT_PATH:
726 case DBUS_TYPE_SIGNATURE:
727 case DBUS_TYPE_ARRAY:
728 case DBUS_TYPE_DICT_ENTRY:
729 ptrarg = va_arg (args, void *);
731 case DBUS_STRUCT_BEGIN_CHAR:
732 ptrarg = va_arg (args, void *);
734 case DBUS_DICT_ENTRY_BEGIN_CHAR:
735 ptrarg = va_arg (args, void *);
738 case DBUS_TYPE_VARIANT:
739 fprintf (stderr, "No variant support yet - very toolkit specific\n");
740 ptrarg = va_arg (args, void *);
743 fprintf (stderr, "Unknown / invalid arg type %c\n", *p);
749 if (p [0] == '=' && p[1] == '>')
753 void *arg = va_arg (args, void *);
754 dbind_any_demarshal (iter, &p, &arg);
758 /*---------------------------------------------------------------------------*/
760 /* nice deep free ... */
762 dbind_any_free (const char *type,
765 dbind_any_free_r (&type, &ptr);
768 /* should this be the default normalization ? */
770 dbind_any_free_ptr (const char *type, void *ptr)
772 dbind_any_free (type, &ptr);
775 /*---------------------------------------------------------------------------*/
778 dbind_find_c_alignment (const char *type)
780 return dbind_find_c_alignment_r (&type);
783 /*END------------------------------------------------------------------------*/