summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Doffman <mark.doffman@codethink.co.uk>2009-11-07 17:49:15 +0000
committerMark Doffman <mark.doffman@codethink.co.uk>2009-11-07 17:49:15 +0000
commitf35ba2e4b28768ab3f6a07403a3bd360162094ed (patch)
treef2dd59c2a771b2d93da7bd4a1e4662ca0f077fa9
parentbeccc6ec73af048833f1b95b4b7e6e29cfabce13 (diff)
downloadat-spi2-atk-f35ba2e4b28768ab3f6a07403a3bd360162094ed.tar.gz
Add the droute and dbind libraries as static libraries within this repository.
Previously these were shared libraries in at-spi2-core.
-rw-r--r--Makefile.am2
-rw-r--r--README16
-rw-r--r--atk-adaptor/Makefile.am2
-rw-r--r--atk-adaptor/accessible-adaptor.c24
-rw-r--r--common/Makefile.am27
-rw-r--r--configure.ac24
-rw-r--r--cspi/Makefile.am2
-rw-r--r--dbind/Makefile.am22
-rw-r--r--dbind/dbind-any.c553
-rw-r--r--dbind/dbind-any.h31
-rw-r--r--dbind/dbind.c230
-rw-r--r--dbind/dbind.h46
-rw-r--r--dbind/dbtest.c403
-rw-r--r--droute/Makefile.am28
-rw-r--r--droute/droute-pairhash.c87
-rw-r--r--droute/droute-pairhash.h41
-rw-r--r--droute/droute-test.c243
-rw-r--r--droute/droute-variant.c118
-rw-r--r--droute/droute-variant.h35
-rw-r--r--droute/droute.c598
-rw-r--r--droute/droute.h95
-rw-r--r--droute/test.interface.One15
-rw-r--r--droute/test.interface.Two15
23 files changed, 2621 insertions, 36 deletions
diff --git a/Makefile.am b/Makefile.am
index a05ffab..305d97d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1 +1 @@
-SUBDIRS=common atk-adaptor tests
+SUBDIRS=droute dbind common atk-adaptor tests
diff --git a/README b/README
index 5fb501f..21e57d0 100644
--- a/README
+++ b/README
@@ -69,6 +69,22 @@ The directories within this package are arranged as follows:
the ATK adaptor and 'Cspi'.
Structures are mainly related to events.
+ droute
+
+ Contains a framework for registering objects
+ with a D-Bus connection and for routing messages to
+ the implementing object.
+
+ Used by the ATK adaptor.
+
+ dbind
+
+ Library to ease making D-Bus method calls, contains
+ marshalling code to convert function arguments
+ and a provided D-Bus signature into a D-Bus message.
+
+ Used by cspi.
+
atk-adaptor
This directory contains code that bridges
diff --git a/atk-adaptor/Makefile.am b/atk-adaptor/Makefile.am
index 5d89a2d..f345355 100644
--- a/atk-adaptor/Makefile.am
+++ b/atk-adaptor/Makefile.am
@@ -21,6 +21,8 @@ libatk_bridge_la_LIBADD = $(DBUS_GLIB_LIBS) \
$(ATK_LIBS) \
$(DBIND_LIBS) \
$(DROUTE_LIBS) \
+ $(top_builddir)/droute/libdroute.la \
+ $(top_builddir)/dbind/libdbind.la \
$(top_builddir)/common/libspicommon.la
libatk_bridge_la_SOURCES = \
diff --git a/atk-adaptor/accessible-adaptor.c b/atk-adaptor/accessible-adaptor.c
index c59f39e..1940d9b 100644
--- a/atk-adaptor/accessible-adaptor.c
+++ b/atk-adaptor/accessible-adaptor.c
@@ -495,19 +495,27 @@ impl_getState (DBusConnection *bus,
void *user_data)
{
AtkObject *object = (AtkObject *) user_data;
- dbus_uint32_t rv[2];
- dbus_uint32_t *array = rv;
- DBusMessage *reply;
+
+ DBusMessage *reply = NULL;
+ DBusMessageIter iter, iter_array;
+
+ dbus_uint32_t states [2];
+
+ guint count;
g_return_val_if_fail (ATK_IS_OBJECT (user_data),
droute_not_yet_handled_error (message));
- spi_atk_state_to_dbus_array (object, rv);
+
reply = dbus_message_new_method_return (message);
- if (reply)
+ dbus_message_iter_init_append (reply, &iter);
+
+ spi_atk_state_to_dbus_array (object, states);
+ dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "u", &iter_array);
+ for (count = 0; count < 2; count++)
{
- dbus_message_append_args (reply, DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &array,
- 2, DBUS_TYPE_INVALID);
+ dbus_message_iter_append_basic (&iter_array, DBUS_TYPE_UINT32, &states[count]);
}
+ dbus_message_iter_close_container (&iter, &iter_array);
return reply;
}
@@ -517,7 +525,7 @@ impl_getAttributes (DBusConnection *bus,
void *user_data)
{
AtkObject *object = (AtkObject *) user_data;
- DBusMessage *reply;
+ DBusMessage *reply = NULL;
AtkAttributeSet *attributes;
DBusMessageIter iter;
diff --git a/common/Makefile.am b/common/Makefile.am
index cbf5671..066c30c 100644
--- a/common/Makefile.am
+++ b/common/Makefile.am
@@ -8,30 +8,19 @@ libspicommon_la_CFLAGS = $(DBUS_GLIB_CFLAGS)\
libspicommon_la_LIBADD = $(DBUS_GLIB_LIBS)
-#spicommonincludedir = $(includedir)/at-spi-1.0/libspi
-#
-#spicommoninclude_HEADERS = \
-# bitarray.h \
-# event-types.h \
-# generated-types.h \
-# keymasks.h \
-# spi-dbus.h \
-# spi-stateset.h \
-# spi-types.h
-
-#BUILT_SOURCES = generated-types.h
-#CLEANFILES = generated-types.h
-
-nodist_libspicommon_la_SOURCES = generated-types.h
-
libspicommon_la_SOURCES = \
- bitarray.h \
+ bitarray.h \
+ keymasks.h \
+ generated-types.h \
event-types.h \
spi-types.h \
spi-dbus.h \
- spi-dbus.c \
- spi-stateset.h \
+ spi-dbus.c \
+ spi-stateset.h \
spi-stateset.c
+#BUILT_SOURCES = generated-types.h
+#CLEANFILES = generated-types.h
+
#generated-types.h: $(top_srcdir)/xml/spec.xml $(top_srcdir)/tools/c-constants-generator.xsl
# xsltproc --stringparam mixed-case-prefix Accessibility_ $(top_srcdir)/tools/c-constants-generator.xsl $< >$@
diff --git a/configure.ac b/configure.ac
index 81e2af0..e27f605 100644
--- a/configure.ac
+++ b/configure.ac
@@ -33,14 +33,6 @@ PKG_CHECK_MODULES(DBUS, [dbus-1 >= 1.0])
AC_SUBST(DBUS_LIBS)
AC_SUBST(DBUS_CFLAGS)
-PKG_CHECK_MODULES(DROUTE, [droute-0.1 >= 0.1])
-AC_SUBST(DROUTE_LIBS)
-AC_SUBST(DROUTE_CFLAGS)
-
-PKG_CHECK_MODULES(DBIND, [dbind-0.1 >= 0.1])
-AC_SUBST(DBIND_LIBS)
-AC_SUBST(DBIND_CFLAGS)
-
PKG_CHECK_MODULES(GLIB, [glib-2.0])
AC_SUBST(GLIB_LIBS)
AC_SUBST(GLIB_CFLAGS)
@@ -98,7 +90,23 @@ else
fi
AC_SUBST(EXTRA_SOCKET_LIBS)
+dnl find sizes & alignments
+orig_CPPFLAGS=$CPPFLAGS
+CPPFLAGS="$CPPFLAGS $DBUS_CFLAGS"
+DBIND_CHECK_ALIGNOF(char)
+DBIND_CHECK_ALIGNOF(dbus_bool_t)
+DBIND_CHECK_ALIGNOF(dbus_int16_t)
+DBIND_CHECK_ALIGNOF(dbus_int32_t)
+DBIND_CHECK_ALIGNOF(dbus_int64_t)
+DBIND_CHECK_ALIGNOF(double)
+DBIND_CHECK_ALIGNOF(dbind_pointer)
+DBIND_CHECK_ALIGNOF(dbind_struct)
+CPPFLAGS=$orig_CPPFLAGS
+
AC_CONFIG_FILES([Makefile
+ droute/Makefile
+ dbind/Makefile
+ dbind/dbind-config.h
common/Makefile
atk-adaptor/Makefile
tests/Makefile
diff --git a/cspi/Makefile.am b/cspi/Makefile.am
index 2ce79ef..49a56e6 100644
--- a/cspi/Makefile.am
+++ b/cspi/Makefile.am
@@ -44,4 +44,6 @@ libcspi_la_LIBADD = \
$(X_LIBS) \
$(DBUS_GLIB_LIBS) \
$(ATK_LIBS) \
+ $(top_builddir)/droute/libdbind.la \
+ $(top_builddir)/droute/libdroute.la \
$(top_builddir)/common/libspicommon.la
diff --git a/dbind/Makefile.am b/dbind/Makefile.am
new file mode 100644
index 0000000..f7e6f53
--- /dev/null
+++ b/dbind/Makefile.am
@@ -0,0 +1,22 @@
+noinst_LTLIBRARIES = libdbind.la
+
+AM_CPPFLAGS = \
+ -DG_LOG_DOMAIN=\"dbind\" \
+ -I$(top_srcdir) \
+ $(WARN_CFLAGS) \
+ $(DBUS_CFLAGS) \
+ $(GLIB_CFLAGS)
+
+libdbind_la_SOURCES = \
+ dbind-config.h \
+ dbind.h \
+ dbind.c \
+ dbind-any.h \
+ dbind-any.c
+libdbind_la_LIBADD = $(DBUS_LIBS) $(GLIB_LIBS)
+
+TESTS = dbtest
+
+check_PROGRAMS = dbtest
+dbtest_SOURCES = dbtest.c
+dbtest_LDFLAGS = libdbind.la
diff --git a/dbind/dbind-any.c b/dbind/dbind-any.c
new file mode 100644
index 0000000..79a8832
--- /dev/null
+++ b/dbind/dbind-any.c
@@ -0,0 +1,553 @@
+/* type driven marshalling */
+#include <stdio.h>
+#include <glib.h>
+
+#include "config.h"
+#include "dbind-config.h"
+#include "dbind-any.h"
+
+#undef DEBUG
+
+/* Align a value upward to a boundary, expressed as a number of bytes.
+ * E.g. align to an 8-byte boundary with argument of 8.
+ *
+ * (this + boundary - 1)
+ * &
+ * ~(boundary - 1)
+ */
+#define ALIGN_VALUE(this, boundary) \
+ (( ((gulong)(this)) + (((gulong)(boundary)) -1)) & (~(((gulong)(boundary))-1)))
+
+#define ALIGN_ADDRESS(this, boundary) \
+ ((gpointer)ALIGN_VALUE(this, boundary))
+
+#define PTR_PLUS(ptr, offset) \
+ ((gpointer) (((guchar *)(ptr)) + (offset)))
+
+#define DBIND_POD_CASES \
+ DBUS_TYPE_BYTE: \
+ case DBUS_TYPE_INT16: \
+ case DBUS_TYPE_UINT16: \
+ case DBUS_TYPE_INT32: \
+ case DBUS_TYPE_UINT32: \
+ case DBUS_TYPE_BOOLEAN: \
+ case DBUS_TYPE_INT64: \
+ case DBUS_TYPE_UINT64: \
+ case DBUS_TYPE_DOUBLE
+
+/*---------------------------------------------------------------------------*/
+
+static void
+warn_braces ()
+{
+ fprintf (stderr, "Error: dbus flags structures & dicts with braces rather than "
+ " an explicit type member of 'struct'\n");
+}
+
+/*---------------------------------------------------------------------------*/
+
+static unsigned int
+dbind_find_c_alignment_r (char **type)
+{
+ unsigned int retval = 1;
+
+ char t = **type;
+ (*type)++;
+
+#ifdef DEBUG
+ fprintf (stderr, "\tfind align for %c (0x%x)\n", t, t);
+#endif
+
+ switch (t) {
+ case DBUS_TYPE_BYTE:
+ return DBIND_ALIGNOF_CHAR;
+ case DBUS_TYPE_BOOLEAN:
+ return DBIND_ALIGNOF_DBUS_BOOL_T;
+ case DBUS_TYPE_INT16:
+ case DBUS_TYPE_UINT16:
+ return DBIND_ALIGNOF_DBUS_INT16_T;
+ case DBUS_TYPE_INT32:
+ case DBUS_TYPE_UINT32:
+ return DBIND_ALIGNOF_DBUS_INT32_T;
+ case DBUS_TYPE_INT64:
+ case DBUS_TYPE_UINT64:
+ return DBIND_ALIGNOF_DBUS_INT64_T;
+ case DBUS_TYPE_DOUBLE:
+ return DBIND_ALIGNOF_DOUBLE;
+ /* ptr types */
+ case DBUS_TYPE_STRING:
+ case DBUS_TYPE_OBJECT_PATH:
+ case DBUS_TYPE_SIGNATURE:
+ case DBUS_TYPE_ARRAY:
+ return DBIND_ALIGNOF_DBIND_POINTER;
+ case DBUS_STRUCT_BEGIN_CHAR:
+#if DBIND_ALIGNOF_DBIND_STRUCT > 1
+ retval = MAX (retval, DBIND_ALIGNOF_DBIND_STRUCT);
+#endif
+ while (**type != DBUS_STRUCT_END_CHAR) {
+ int elem_align = dbind_find_c_alignment_r (type);
+ retval = MAX (retval, elem_align);
+ }
+ (*type)++;
+ return retval;
+ case DBUS_TYPE_STRUCT:
+ case DBUS_TYPE_DICT_ENTRY:
+ warn_braces ();
+ return DBIND_ALIGNOF_DBIND_POINTER;
+ case '\0':
+ g_assert_not_reached();
+ break;
+ default:
+ return 1;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+
+/* gather immediate allocation information for this type */
+static size_t
+dbind_gather_alloc_info_r (char **type)
+{
+ char t = **type;
+ (*type)++;
+ if (t == DBUS_TYPE_ARRAY)
+ {
+ switch (**type)
+ {
+ case DBUS_STRUCT_BEGIN_CHAR:
+ while (**type != DBUS_STRUCT_END_CHAR && **type != '\0') (*type)++;
+ if (**type != '\0') (*type)++;
+ break;
+ case '\0':
+ break;
+ default:
+ (*type)++;
+ break;
+ }
+ }
+
+ switch (t) {
+ case DBUS_TYPE_BYTE:
+ return sizeof (char);
+ case DBUS_TYPE_BOOLEAN:
+ return sizeof (dbus_bool_t);
+ case DBUS_TYPE_INT16:
+ case DBUS_TYPE_UINT16:
+ return sizeof (dbus_int16_t);
+ case DBUS_TYPE_INT32:
+ case DBUS_TYPE_UINT32:
+ return sizeof (dbus_int32_t);
+ case DBUS_TYPE_INT64:
+ case DBUS_TYPE_UINT64:
+ return sizeof (dbus_int64_t);
+ case DBUS_TYPE_DOUBLE:
+ return sizeof (double);
+ /* ptr types */
+ case DBUS_TYPE_STRING:
+ case DBUS_TYPE_OBJECT_PATH:
+ case DBUS_TYPE_SIGNATURE:
+ case DBUS_TYPE_ARRAY:
+ return sizeof (void *);
+ case DBUS_STRUCT_BEGIN_CHAR: {
+ int sum = 0, stralign;
+
+ stralign = dbind_find_c_alignment (*type - 1);
+
+ while (**type != DBUS_STRUCT_END_CHAR) {
+ sum = ALIGN_VALUE (sum, dbind_find_c_alignment (*type));
+ sum += dbind_gather_alloc_info_r (type);
+ }
+ sum = ALIGN_VALUE (sum, stralign);
+
+ g_assert (**type == DBUS_STRUCT_END_CHAR);
+ (*type)++;
+
+ return sum;
+ }
+ case DBUS_TYPE_STRUCT:
+ case DBUS_TYPE_DICT_ENTRY:
+ warn_braces ();
+ default:
+ return 0;
+ }
+}
+
+static size_t
+dbind_gather_alloc_info (char *type)
+{
+ return dbind_gather_alloc_info_r (&type);
+}
+
+/*---------------------------------------------------------------------------*/
+
+static void
+dbind_any_free_r (char **type, void **data)
+{
+#ifdef DEBUG
+ fprintf (stderr, "any free '%c' to %p\n", **type, *data);
+#endif
+
+ switch (**type) {
+ case DBIND_POD_CASES:
+ *data = ((guchar *)*data) + dbind_gather_alloc_info (*type);
+ (*type)++;
+ break;
+ case DBUS_TYPE_STRING:
+ case DBUS_TYPE_OBJECT_PATH:
+ case DBUS_TYPE_SIGNATURE:
+#ifdef DEBUG
+ fprintf (stderr, "string free %p\n", **(void ***)data);
+#endif
+ g_free (**(void ***)data);
+ *data = ((guchar *)*data) + dbind_gather_alloc_info (*type);
+ (*type)++;
+ break;
+ case DBUS_TYPE_ARRAY: {
+ int i;
+ GArray *vals = **(void ***)data;
+ size_t elem_size, elem_align;
+ char *saved_child_type;
+
+ (*type)++;
+ saved_child_type = *type;
+
+ elem_size = dbind_gather_alloc_info (*type);
+ elem_align = dbind_find_c_alignment_r (type);
+
+ for (i = 0; i < vals->len; i++) {
+ void *ptr = vals->data + elem_size * i;
+ *type = saved_child_type; /* rewind type info */
+ ptr = ALIGN_ADDRESS (ptr, elem_align);
+ dbind_any_free_r (type, &ptr);
+ }
+ g_array_free (vals, TRUE);
+ break;
+ }
+ case DBUS_STRUCT_BEGIN_CHAR: {
+ gconstpointer data0 = *data;
+ int offset = 0, stralign;
+
+ stralign = dbind_find_c_alignment (*type);
+ (*type)++;
+
+ offset = 0 ;
+ while (**type != DBUS_STRUCT_END_CHAR) {
+ char *subt = *type;
+ offset = ALIGN_VALUE (offset, dbind_find_c_alignment (*type));
+ *data = PTR_PLUS (data0, offset);
+ dbind_any_free_r (type, data);
+ offset += dbind_gather_alloc_info (subt);
+ }
+
+ offset = ALIGN_VALUE (offset, stralign);
+ *data = PTR_PLUS (data0, offset);
+
+ g_assert (**type == DBUS_STRUCT_END_CHAR);
+ (*type)++;
+
+ break;
+ }
+ case DBUS_TYPE_STRUCT:
+ case DBUS_TYPE_DICT_ENTRY:
+ warn_braces ();
+ break;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+
+void
+dbind_any_marshal (DBusMessageIter *iter,
+ char **type,
+ void **data)
+{
+ size_t len;
+
+#ifdef DEBUG
+ fprintf (stderr, "any marshal '%c' to %p\n", **type, *data);
+#endif
+
+ switch (**type) {
+ case DBIND_POD_CASES:
+ case DBUS_TYPE_STRING:
+ case DBUS_TYPE_OBJECT_PATH:
+ case DBUS_TYPE_SIGNATURE:
+ len = dbind_gather_alloc_info (*type);
+ dbus_message_iter_append_basic (iter, **type, *data);
+ *data = ((guchar *)*data) + len;
+ (*type)++;
+ break;
+ case DBUS_TYPE_ARRAY: {
+ int i;
+ GArray *vals = **(void ***)data;
+ size_t elem_size, elem_align;
+ DBusMessageIter sub;
+ char *saved_child_type, *child_type_string;
+
+ (*type)++;
+ saved_child_type = *type;
+
+ elem_size = dbind_gather_alloc_info (*type);
+ elem_align = dbind_find_c_alignment_r (type);
+
+ /* wow this part of the API sucks too ... */
+ child_type_string = g_strndup (saved_child_type, *type - saved_child_type);
+ /* fprintf (stderr, "array child type '%s'\n", child_type_string); */
+ dbus_message_iter_open_container (iter, DBUS_TYPE_ARRAY,
+ child_type_string, &sub);
+ for (i = 0; i < vals->len; i++) {
+ void *ptr = vals->data + elem_size * i;
+ *type = saved_child_type; /* rewind type info */
+ ptr = ALIGN_ADDRESS (ptr, elem_align);
+ dbind_any_marshal (&sub, type, &ptr);
+ }
+
+ dbus_message_iter_close_container (iter, &sub);
+ g_free (child_type_string);
+ break;
+ }
+ case DBUS_STRUCT_BEGIN_CHAR: {
+ gconstpointer data0 = *data;
+ int offset = 0, stralign;
+ DBusMessageIter sub;
+
+ stralign = dbind_find_c_alignment (*type);
+
+ (*type)++;
+
+ dbus_message_iter_open_container (iter, DBUS_TYPE_STRUCT, NULL, &sub);
+
+ offset = 0 ;
+ while (**type != DBUS_STRUCT_END_CHAR) {
+ char *subt = *type;
+ offset = ALIGN_VALUE (offset, dbind_find_c_alignment (*type));
+ *data = PTR_PLUS (data0, offset);
+ dbind_any_marshal (&sub, type, data);
+ offset += dbind_gather_alloc_info (subt);
+ }
+
+ offset = ALIGN_VALUE (offset, stralign);
+ *data = PTR_PLUS (data0, offset);
+
+ dbus_message_iter_close_container (iter, &sub);
+
+ g_assert (**type == DBUS_STRUCT_END_CHAR);
+ (*type)++;
+
+ break;
+ }
+ case DBUS_TYPE_STRUCT:
+ case DBUS_TYPE_DICT_ENTRY:
+ warn_braces ();
+ break;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+
+void
+dbind_any_marshal_va (DBusMessageIter *iter,
+ char **arg_types,
+ va_list args)
+{
+ char *p = *arg_types;
+
+ /* Guard against null arg types
+ Fix for - http://bugs.freedesktop.org/show_bug.cgi?id=23027
+ */
+ if (p == NULL)
+ p = "";
+
+ {
+ /* special case base-types since we need to walk the stack worse-luck */
+ for (;*p != '\0' && *p != '=';) {
+ int intarg;
+ void *ptrarg;
+ double doublearg;
+ dbus_int64_t int64arg;
+ void *arg = NULL;
+
+ switch (*p) {
+ case DBUS_TYPE_BYTE:
+ case DBUS_TYPE_BOOLEAN:
+ case DBUS_TYPE_INT16:
+ case DBUS_TYPE_UINT16:
+ case DBUS_TYPE_INT32:
+ case DBUS_TYPE_UINT32:
+ intarg = va_arg (args, int);
+ arg = &intarg;
+ break;
+ case DBUS_TYPE_INT64:
+ case DBUS_TYPE_UINT64:
+ int64arg = va_arg (args, dbus_int64_t);
+ arg = &int64arg;
+ break;
+ case DBUS_TYPE_DOUBLE:
+ doublearg = va_arg (args, double);
+ arg = &doublearg;
+ break;
+ /* ptr types */
+ case DBUS_TYPE_STRING:
+ case DBUS_TYPE_OBJECT_PATH:
+ case DBUS_TYPE_SIGNATURE:
+ case DBUS_TYPE_ARRAY:
+ case DBUS_TYPE_DICT_ENTRY:
+ ptrarg = va_arg (args, void *);
+ arg = &ptrarg;
+ break;
+ case DBUS_STRUCT_BEGIN_CHAR:
+ ptrarg = va_arg (args, void *);
+ arg = ptrarg;
+ break;
+
+ case DBUS_TYPE_VARIANT:
+ fprintf (stderr, "No variant support yet - very toolkit specific\n");
+ ptrarg = va_arg (args, void *);
+ arg = &ptrarg;
+ break;
+ default:
+ fprintf (stderr, "Unknown / invalid arg type %c\n", *p);
+ break;
+ }
+ if (arg != NULL)
+ dbind_any_marshal (iter, &p, &arg);
+ }
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+
+void
+dbind_any_demarshal (DBusMessageIter *iter,
+ char **type,
+ void **data)
+{
+ size_t len;
+
+#ifdef DEBUG
+ fprintf (stderr, "any demarshal '%c' to %p\n", **type, *data);
+#endif
+
+ switch (**type) {
+ case DBIND_POD_CASES:
+ len = dbind_gather_alloc_info (*type);
+ dbus_message_iter_get_basic (iter, *data);
+ *data = ((guchar *)*data) + len;
+ (*type)++;
+ break;
+ case DBUS_TYPE_STRING:
+ case DBUS_TYPE_OBJECT_PATH:
+ case DBUS_TYPE_SIGNATURE:
+ len = dbind_gather_alloc_info (*type);
+ dbus_message_iter_get_basic (iter, *data);
+#ifdef DEBUG
+ fprintf (stderr, "dup string '%s' (%p)\n", **(void ***)data, **(void ***)data);
+#endif
+ **(void ***)data = g_strdup (**(void ***)data);
+ *data = ((guchar *)*data) + len;
+ (*type)++;
+ break;
+ case DBUS_TYPE_ARRAY: {
+ GArray *vals;
+ DBusMessageIter child;
+ size_t elem_size, elem_align;
+ char *stored_child_type;
+ int i;
+
+ (*type)++;
+ stored_child_type = *type;
+
+ elem_size = dbind_gather_alloc_info (*type);
+ elem_align = dbind_find_c_alignment_r (type);
+ vals = g_array_new (FALSE, FALSE, elem_size);
+ (**(void ***)data) = vals;
+ *data = ((guchar *)*data) + sizeof (void *);
+
+ i = 0;
+ dbus_message_iter_recurse (iter, &child);
+ while (dbus_message_iter_get_arg_type (&child) != DBUS_TYPE_INVALID) {
+ void *ptr;
+ char *subt = stored_child_type;
+ g_array_set_size (vals, i + 1);
+ ptr = vals->data + elem_size * i;
+ ptr = ALIGN_ADDRESS (ptr, elem_align);
+ dbind_any_demarshal (&child, &subt, &ptr);
+ i++;
+ };
+ break;
+ }
+ case DBUS_STRUCT_BEGIN_CHAR: {
+ gconstpointer data0 = *data;
+ int offset = 0, stralign;
+ DBusMessageIter child;
+
+ stralign = dbind_find_c_alignment (*type);
+
+ (*type)++;
+
+ dbus_message_iter_recurse (iter, &child);
+
+ while (**type != DBUS_STRUCT_END_CHAR) {
+ char *subt = *type;
+ offset = ALIGN_VALUE (offset, dbind_find_c_alignment (*type));
+ *data = PTR_PLUS (data0, offset);
+ dbind_any_demarshal (&child, type, data);
+ offset += dbind_gather_alloc_info (subt);
+ }
+
+ offset = ALIGN_VALUE (offset, stralign);
+ *data = PTR_PLUS (data0, offset);
+
+ g_assert (**type == DBUS_STRUCT_END_CHAR);
+ (*type)++;
+
+ break;
+ }
+ case DBUS_TYPE_STRUCT:
+ case DBUS_TYPE_DICT_ENTRY:
+ warn_braces ();
+ break;
+ }
+ dbus_message_iter_next (iter);
+}
+
+/*---------------------------------------------------------------------------*/
+
+void
+dbind_any_demarshal_va (DBusMessageIter *iter,
+ char **arg_types,
+ va_list args)
+{
+ char *p = *arg_types;
+ for (;*p != '\0';) {
+ void *arg = va_arg (args, void *);
+ dbind_any_demarshal (iter, &p, &arg);
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+
+/* nice deep free ... */
+void
+dbind_any_free (char *type,
+ void *ptr)
+{
+ dbind_any_free_r (&type, &ptr);
+}
+
+/* should this be the default normalization ? */
+void
+dbind_any_free_ptr (char *type, void *ptr)
+{
+ dbind_any_free (type, &ptr);
+}
+
+/*---------------------------------------------------------------------------*/
+
+unsigned int
+dbind_find_c_alignment (char *type)
+{
+ return dbind_find_c_alignment_r (&type);
+}
+
+/*END------------------------------------------------------------------------*/
diff --git a/dbind/dbind-any.h b/dbind/dbind-any.h
new file mode 100644
index 0000000..975b244
--- /dev/null
+++ b/dbind/dbind-any.h
@@ -0,0 +1,31 @@
+#ifndef _DBIND_ANY_H_
+#define _DBIND_ANY_H_
+
+#define DBUS_API_SUBJECT_TO_CHANGE
+#include <dbus/dbus.h>
+
+unsigned int dbind_find_c_alignment (char *type);
+
+void dbind_any_marshal (DBusMessageIter *iter,
+ char **type,
+ void **val);
+
+void dbind_any_marshal_va (DBusMessageIter *iter,
+ char **arg_types,
+ va_list args);
+
+void dbind_any_demarshal (DBusMessageIter *iter,
+ char **type,
+ void **val);
+
+void dbind_any_demarshal_va (DBusMessageIter *iter,
+ char **arg_types,
+ va_list args);
+
+void dbind_any_free (char *type,
+ void *ptr_to_ptr);
+
+void dbind_any_free_ptr (char *type,
+ void *ptr);
+
+#endif /* _DBIND_ANY_H_ */
diff --git a/dbind/dbind.c b/dbind/dbind.c
new file mode 100644
index 0000000..f405888
--- /dev/null
+++ b/dbind/dbind.c
@@ -0,0 +1,230 @@
+
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <glib.h>
+
+#include "config.h"
+#include "dbind/dbind.h"
+
+/*
+ * FIXME: compare types - to ensure they match &
+ * do dynamic padding of structures etc.
+ */
+
+/*---------------------------------------------------------------------------*/
+
+static void
+set_reply (DBusPendingCall *pending, void *user_data)
+{
+ void **replyptr = (void **)user_data;
+
+ *replyptr = dbus_pending_call_steal_reply (pending);
+}
+
+static DBusMessage *
+send_and_allow_reentry (DBusConnection *bus, DBusMessage *message, DBusError *error)
+{
+ DBusPendingCall *pending;
+ DBusMessage *reply = NULL;
+
+ if (!dbus_connection_send_with_reply (bus, message, &pending, -1))
+ {
+ return NULL;
+ }
+ dbus_pending_call_set_notify (pending, set_reply, (void *)&reply, NULL);
+ while (!reply)
+ {
+ if (!dbus_connection_read_write_dispatch (bus, -1)) return NULL;
+ }
+ return reply;
+}
+
+dbus_bool_t
+dbind_method_call_reentrant_va (DBusConnection *cnx,
+ const char *bus_name,
+ const char *path,
+ const char *interface,
+ const char *method,
+ DBusError *opt_error,
+ const char *arg_types,
+ va_list args)
+{
+ dbus_bool_t success = FALSE;
+ DBusMessage *msg = NULL, *reply = NULL;
+ DBusMessageIter iter;
+ DBusError *err, real_err;
+ const char *p;
+
+ if (opt_error)
+ err = opt_error;
+ else {
+ dbus_error_init (&real_err);
+ err = &real_err;
+ }
+
+ msg = dbus_message_new_method_call (bus_name, path, interface, method);
+ if (!msg)
+ goto out;
+
+ p = arg_types;
+ dbus_message_iter_init_append (msg, &iter);
+ dbind_any_marshal_va (&iter, &p, args);
+
+ reply = send_and_allow_reentry (cnx, msg, err);
+ if (!reply)
+ goto out;
+
+ if (dbus_message_get_type (reply) == DBUS_MESSAGE_TYPE_ERROR)
+ {
+ const char *name = dbus_message_get_error_name (reply);
+ dbus_set_error (err, name, g_strdup (""));
+ goto out;
+ }
+ /* demarshal */
+ if (p[0] == '=' && p[1] == '>')
+ {
+ DBusMessageIter iter;
+ p += 2;
+ dbus_message_iter_init (reply, &iter);
+ dbind_any_demarshal_va (&iter, &p, args);
+ }
+
+ success = TRUE;
+out:
+ if (msg)
+ dbus_message_unref (msg);
+
+ if (reply)
+ dbus_message_unref (reply);
+
+ if (err == &real_err)
+ dbus_error_free (err);
+
+ return success;
+}
+
+/**
+ * dbind_method_call_reentrant:
+ *
+ * @cnx: A D-Bus Connection used to make the method call.
+ * @bus_name: The D-Bus bus name of the program where the method call should
+ * be made.
+ * @path: The D-Bus object path that should handle the method.
+ * @interface: The D-Bus interface used to scope the method name.
+ * @method: Method to be invoked.
+ * @opt_error: D-Bus error.
+ * @arg_types: Variable length arguments interleaving D-Bus argument types
+ * and pointers to argument data.
+ *
+ * Makes a D-Bus method call using the supplied location data, method name and
+ * argument data.This function is re-entrant. It continuously reads from the D-Bus
+ * bus and dispatches messages until a reply has been recieved.
+ **/
+dbus_bool_t
+dbind_method_call_reentrant (DBusConnection *cnx,
+ const char *bus_name,
+ const char *path,
+ const char *interface,
+ const char *method,
+ DBusError *opt_error,
+ const char *arg_types,
+ ...)
+{
+ dbus_bool_t success = FALSE;
+ va_list args;
+
+ va_start (args, arg_types);
+ success = dbind_method_call_reentrant_va (cnx,
+ bus_name,
+ path,
+ interface,
+ method,
+ opt_error,
+ arg_types,
+ args);
+ va_end (args);
+
+ return success;
+}
+
+/*---------------------------------------------------------------------------*/
+
+dbus_bool_t
+dbind_emit_signal_va (DBusConnection *cnx,
+ const char *path,
+ const char *interface,
+ const char *signal,
+ DBusError *opt_error,
+ const char *arg_types,
+ va_list args)
+{
+ dbus_bool_t success = FALSE;
+ DBusMessage *msg = NULL;
+ DBusMessageIter iter;
+ DBusError *err, real_err;
+ char *p;
+
+ if (opt_error)
+ err = opt_error;
+ else {
+ dbus_error_init (&real_err);
+ err = &real_err;
+ }
+
+ msg = dbus_message_new_signal (path, interface, signal);
+ if (!msg)
+ goto out;
+
+ p = arg_types;
+ dbus_message_iter_init_append (msg, &iter);
+ dbind_any_marshal_va (&iter, &p, args);
+
+ if (!dbus_connection_send (cnx, msg, NULL))
+ goto out;
+
+ success = TRUE;
+out:
+
+ if (msg)
+ dbus_message_unref (msg);
+
+ if (err == &real_err)
+ dbus_error_free (err);
+
+ return success;
+}
+
+/**
+ * dbind_emit_signal:
+ *
+ * @cnx: A D-Bus Connection used to make the method call.
+ * @path: The D-Bus object path that this signal is emitted from.
+ * @interface: The D-Bus interface used to scope the method name.
+ * @signal: Name of signal to emit.
+ * @opt_error: D-Bus error.
+ * @arg_types: Variable length arguments interleaving D-Bus argument types
+ * and pointers to argument data.
+ *
+ * Emits a D-Bus signal using the supplied signal name and argument data.
+ **/
+dbus_bool_t
+dbind_emit_signal (DBusConnection *cnx,
+ const char *path,
+ const char *interface,
+ const char *signal,
+ DBusError *opt_error,
+ const char *arg_types,
+ ...)
+{
+ dbus_bool_t success = FALSE;
+ va_list args;
+
+ va_start (args, arg_types);
+ success = dbind_emit_signal_va (cnx, path, interface, signal, opt_error, arg_types, args);
+ va_end (args);
+
+ return success;
+}
+
+/*END------------------------------------------------------------------------*/
diff --git a/dbind/dbind.h b/dbind/dbind.h
new file mode 100644
index 0000000..cc318c4
--- /dev/null
+++ b/dbind/dbind.h
@@ -0,0 +1,46 @@
+#ifndef _DBIND_H_
+#define _DBIND_H_
+
+#define DBUS_API_SUBJECT_TO_CHANGE
+#include <dbus/dbus.h>
+#include <dbind/dbind-any.h>
+
+dbus_bool_t
+dbind_method_call_reentrant_va (DBusConnection *cnx,
+ const char *bus_name,
+ const char *path,
+ const char *interface,
+ const char *method,
+ DBusError *opt_error,
+ const char *arg_types,
+ va_list args);
+
+dbus_bool_t
+dbind_method_call_reentrant (DBusConnection *cnx,
+ const char *bus_name,
+ const char *path,
+ const char *interface,
+ const char *method,
+ DBusError *opt_error,
+ const char *arg_types,
+ ...);
+
+dbus_bool_t
+dbind_emit_signal_va (DBusConnection *cnx,
+ const char *path,
+ const char *interface,
+ const char *signal,
+ DBusError *opt_error,
+ const char *arg_types,
+ va_list args);
+
+dbus_bool_t
+dbind_emit_signal (DBusConnection *cnx,
+ const char *path,
+ const char *interface,
+ const char *signal,
+ DBusError *opt_error,
+ const char *arg_types,
+ ...);
+
+#endif /* _DBIND_H_ */
diff --git a/dbind/dbtest.c b/dbind/dbtest.c
new file mode 100644
index 0000000..d00486a
--- /dev/null
+++ b/dbind/dbtest.c
@@ -0,0 +1,403 @@
+#include <stdio.h>
+#include <glib.h>
+#include <string.h>
+#include <dbind/dbind.h>
+
+/* Wow! dbus is unpleasant to use */
+
+#define DESKICE_PATH "/Novell/ICEDesktop/Daemon"
+#define DESKICE_NAMESPACE "Novell.ICEDesktop.Daemon"
+
+void marshal (DBusMessage *msg, char *type, void *ptr)
+{
+ DBusMessageIter iter;
+
+ dbus_message_iter_init_append (msg, &iter);
+ dbind_any_marshal (&iter, &type, &ptr);
+}
+
+void demarshal (DBusMessage *msg, char *type, void *ptr)
+{
+ DBusMessageIter iter;
+
+ if (!dbus_message_iter_init (msg, &iter))
+ fprintf (stderr, "no data in msg\n");
+ else
+ dbind_any_demarshal (&iter, &type, &ptr);
+}
+
+#if 0
+dbus_bool_t dbus_message_marshal (DBusMessage *msg,
+ char **marshalled_data_p,
+ int *len_p);
+
+void dump_msg (DBusMessage *msg)
+{
+ char *data = NULL;
+ int len, i, j;
+
+ dbus_message_marshal (msg, &data, &len);
+ for (i = 0; i < (len+15)/16; i++) {
+ fprintf (stderr, "%4.d | ", i * 16);
+ for (j = 0; j < 16; j++) {
+ unsigned char c = (i*16+j <= len) ? data[i*16+j] : 0;
+ fprintf (stderr, "0x%.2x ", c);
+ }
+ fprintf (stderr, " | ");
+ for (j = 0; j < 16; j++) {
+ char c = (i*16+j <= len) ? data[i*16+j] : '\0';
+ fprintf (stderr, "%c", g_ascii_isprint (c) ? c : '.');
+ }
+ }
+}
+#endif
+
+void test_simple ()
+{
+ dbus_int32_t v1, v2;
+ DBusMessage *msg;
+
+ msg = dbus_message_new (DBUS_MESSAGE_TYPE_METHOD_CALL);
+ v1 = 42;
+ marshal (msg, "i", &v1);
+ demarshal (msg, "i", &v2);
+ g_assert (v2 == 42);
+ g_assert (v1 == v2);
+
+ dbind_any_free ("i", &v2); /* nop */
+ dbus_message_unref (msg);
+
+ fprintf (stderr, "simple ok\n");
+}
+
+void test_array ()
+{
+ GArray *a1, *a2;
+ DBusMessage *msg;
+
+ /* pod types */
+ a1 = g_array_new (FALSE, FALSE, sizeof (dbus_int32_t));
+ g_array_set_size (a1, 4);
+ g_array_index (a1, dbus_int32_t, 0) = 42;
+ g_array_index (a1, dbus_int32_t, 1) = 17;
+ g_array_index (a1, dbus_int32_t, 2) = 26;
+ g_array_index (a1, dbus_int32_t, 3) = 38;
+
+ msg = dbus_message_new (DBUS_MESSAGE_TYPE_METHOD_CALL);
+ marshal (msg, "ai", &a1);
+ demarshal (msg, "ai", &a2);
+
+ g_assert (a2 != NULL);
+ g_assert (a2->len == 4);
+ g_assert (g_array_index (a2, dbus_int32_t, 0) == 42);
+ g_assert (g_array_index (a2, dbus_int32_t, 1) == 17);
+ g_assert (g_array_index (a2, dbus_int32_t, 2) == 26);
+ g_assert (g_array_index (a2, dbus_int32_t, 3) == 38);
+ g_array_free (a1, TRUE);
+
+ dbind_any_free ("ai", &a2);
+ dbus_message_unref (msg);
+
+ fprintf (stderr, "array ok\n");
+}
+
+/* this taught me that the struct type is a mis-nomer,
+ it is generated by brackets */
+void test_struct_native ()
+{
+ DBusMessage *msg;
+ DBusMessageIter iter, arr, str;
+
+ /* manually create ar(ss) */
+ msg = dbus_message_new (DBUS_MESSAGE_TYPE_METHOD_CALL);
+
+ dbus_message_iter_init_append (msg, &iter);
+
+ dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "(ss)", &arr);
+ {
+ char *foo;
+ dbus_message_iter_open_container (&arr, DBUS_TYPE_STRUCT, NULL, &str);
+
+ foo = "foo";
+ dbus_message_iter_append_basic (&str, DBUS_TYPE_STRING, &foo);
+ foo = "baa";
+ dbus_message_iter_append_basic (&str, DBUS_TYPE_STRING, &foo);
+
+ dbus_message_iter_close_container (&arr, &str);
+ }
+ dbus_message_iter_close_container (&iter, &arr);
+
+ fprintf (stderr, "native struct marshalling ok\n");
+
+ dbus_message_unref (msg);
+}
+
+
+void test_struct_simple ()
+{
+ typedef struct {
+ char *foo;
+ char *baa;
+ char *baz;
+ } FooBaa;
+ GArray *a1 = NULL, *a2 = NULL;
+ DBusMessage *msg;
+
+ a1 = g_array_new (FALSE, FALSE, sizeof (FooBaa));
+ g_array_set_size (a1, 2);
+ g_array_index (a1, FooBaa, 0).foo = "foo";
+ g_array_index (a1, FooBaa, 0).baa = "baa";
+ g_array_index (a1, FooBaa, 0).baz = "baz";
+ g_array_index (a1, FooBaa, 1).foo = "Foo";
+ g_array_index (a1, FooBaa, 1).baa = "baA";
+ g_array_index (a1, FooBaa, 1).baz = "BaZ";
+
+ msg = dbus_message_new (DBUS_MESSAGE_TYPE_METHOD_CALL);
+ marshal (msg, "a(sss)", &a1);
+ demarshal (msg, "a(sss)", &a2);
+
+ g_assert (a2 != NULL);
+ g_assert (a2 != a1);
+ g_assert (a2->len == 2);
+ g_assert (!strcmp (g_array_index (a2, FooBaa, 0).foo, "foo"));
+ g_assert (!strcmp (g_array_index (a2, FooBaa, 0).baa, "baa"));
+ g_assert (!strcmp (g_array_index (a2, FooBaa, 0).baz, "baz"));
+ g_assert (!strcmp (g_array_index (a2, FooBaa, 1).foo, "Foo"));
+ g_assert (!strcmp (g_array_index (a2, FooBaa, 1).baa, "baA"));
+ g_assert (!strcmp (g_array_index (a2, FooBaa, 1).baz, "BaZ"));
+
+ fprintf (stderr, "simple struct ok\n");
+
+ dbind_any_free ("a(sss)", &a2);
+ dbus_message_unref (msg);
+}
+
+void test_struct_complex ()
+{
+ typedef struct {
+ dbus_int32_t x, y;
+ } Point;
+ typedef struct {
+ unsigned char pad1;
+ double val;
+ Point tl, br;
+ char pad2;
+ char *name;
+ } Complex;
+#define TYPEOF_POINT \
+ DBUS_STRUCT_BEGIN_CHAR_AS_STRING \
+ DBUS_TYPE_INT32_AS_STRING \
+ DBUS_TYPE_INT32_AS_STRING \
+ DBUS_STRUCT_END_CHAR_AS_STRING
+#define TYPEOF_COMPLEX \
+ DBUS_STRUCT_BEGIN_CHAR_AS_STRING \
+ DBUS_TYPE_BYTE_AS_STRING \
+ DBUS_TYPE_DOUBLE_AS_STRING \
+ TYPEOF_POINT \
+ TYPEOF_POINT \
+ DBUS_TYPE_BYTE_AS_STRING \
+ DBUS_TYPE_STRING_AS_STRING \
+ DBUS_STRUCT_END_CHAR_AS_STRING
+
+
+ DBusMessage *msg;
+ Complex c1, c2;
+
+ memset (&c1, 0, sizeof (c1));
+ memset (&c2, 0, sizeof (c2));
+
+ c1.pad1 = 2;
+ c1.val = 0.1327569;
+ c1.tl.x = 1;
+ c1.tl.y = 17;
+ c1.br.x = 2587;
+ c1.br.y = -1;
+ c1.pad2 = 1;
+ c1.name = "stroustrup";
+
+ msg = dbus_message_new (DBUS_MESSAGE_TYPE_METHOD_CALL);
+ marshal (msg, TYPEOF_COMPLEX, &c1);
+ demarshal (msg, TYPEOF_COMPLEX, &c2);
+
+ g_assert (c2.pad1 == 2);
+ g_assert (c2.val == c1.val);
+ g_assert (c2.val != 0);
+ g_assert (c2.tl.x == 1);
+ g_assert (c2.tl.y == 17);
+ g_assert (c2.br.x == 2587);
+ g_assert (c2.br.y == -1);
+ g_assert (c2.pad2 == 1);
+ g_assert (!strcmp (c1.name, "stroustrup"));
+
+ fprintf (stderr, "complex struct ok\n");
+
+ dbind_any_free (TYPEOF_COMPLEX, &c2);
+ dbus_message_unref (msg);
+}
+
+void test_struct_with_array ()
+{
+ typedef struct {
+ GArray *vals;
+ unsigned char pad1;
+ } ArrayStruct;
+#define TYPEOF_ARRAYSTRUCT \
+ DBUS_TYPE_ARRAY_AS_STRING \
+ DBUS_STRUCT_BEGIN_CHAR_AS_STRING \
+ DBUS_TYPE_ARRAY_AS_STRING \
+ DBUS_TYPE_UINT32_AS_STRING \
+ DBUS_TYPE_BYTE_AS_STRING \
+ DBUS_STRUCT_END_CHAR_AS_STRING
+
+
+ DBusMessage *msg;
+ GArray *a1, *a2;
+ ArrayStruct *p, *q;
+
+
+ a1 = g_array_new (FALSE, FALSE, sizeof (ArrayStruct));
+ g_array_set_size (a1, 2);
+ p = &g_array_index (a1, ArrayStruct, 0);
+ p[0].vals = g_array_new (FALSE, FALSE, sizeof (dbus_uint32_t));
+ g_array_set_size (p[0].vals, 2);
+ g_array_index (p[0].vals, dbus_uint32_t, 0) = 1;
+ g_array_index (p[0].vals, dbus_uint32_t, 1) = 1000;
+ p[0].pad1 = 2;
+ p[1].vals = g_array_new (FALSE, FALSE, sizeof (dbus_uint32_t));
+ g_array_set_size (p[1].vals, 2);
+ g_array_index (p[1].vals, dbus_uint32_t, 0) = 1000000;
+ g_array_index (p[1].vals, dbus_uint32_t, 1) = 1000000000;
+ p[1].pad1 = 8;
+
+ msg = dbus_message_new (DBUS_MESSAGE_TYPE_METHOD_CALL);
+ marshal (msg, TYPEOF_ARRAYSTRUCT, &a1);
+ demarshal (msg, TYPEOF_ARRAYSTRUCT, &a2);
+
+ q = &g_array_index (a2, ArrayStruct, 0);
+ g_assert (p[0].pad1 == 2);
+ g_assert (g_array_index (p[1].vals, dbus_uint32_t, 1) == 1000000000);
+
+ fprintf (stderr, "struct with array ok\n");
+
+ dbind_any_free (TYPEOF_ARRAYSTRUCT, &a2);
+ dbus_message_unref (msg);
+ g_array_free (p[0].vals, TRUE);
+ g_array_free (p[1].vals, TRUE);
+}
+
+void test_twovals ()
+{
+ typedef struct {
+ dbus_int32_t v1;
+ dbus_int32_t v2;
+ } TwoVal;
+#define TYPEOF_TWOVAL \
+ DBUS_TYPE_INT32_AS_STRING \
+ DBUS_TYPE_INT32_AS_STRING \
+
+ DBusMessage *msg;
+ DBusMessageIter iter;
+ TwoVal i, o;
+ char *type_twoval = TYPEOF_TWOVAL;
+ char *type;
+ void *ptr;
+
+ msg = dbus_message_new (DBUS_MESSAGE_TYPE_METHOD_CALL);
+ i.v1 = 42;
+ i.v2 = 1764;
+ dbus_message_iter_init_append (msg, &iter);
+ type = type_twoval;
+ ptr = &i;
+ dbind_any_marshal (&iter, &type, &ptr);
+ dbind_any_marshal (&iter, &type, &ptr);
+ dbus_message_iter_init (msg, &iter);
+ type = type_twoval;
+ ptr = &o;
+ dbind_any_demarshal (&iter, &type, &ptr);
+ dbind_any_demarshal (&iter, &type, &ptr);
+ g_assert (o.v1 == 42);
+ g_assert (o.v2 == 1764);
+ g_assert (i.v1 == o.v1);
+ g_assert (i.v2 == o.v2);
+
+ dbind_any_free ("ii", &o); /* nop */
+ dbus_message_unref (msg);
+
+ fprintf (stderr, "two-val ok\n");
+}
+
+void test_marshalling ()
+{
+ test_simple ();
+ test_array ();
+ test_struct_native ();
+ test_struct_simple ();
+ test_struct_complex ();
+ test_struct_with_array ();
+ test_twovals ();
+
+ fprintf (stderr, "Marshalling ok\n");
+}
+
+void test_teamspaces (DBusConnection *bus)
+{
+ GArray *spaces;
+ DBusError error;
+ int i;
+ typedef struct {
+ char *name;
+ char *id;
+ char *url;
+ } TeamSpace;
+
+ dbus_error_init (&error);
+ if (!dbind_method_call_reentrant (bus,
+ NULL,
+ DESKICE_PATH,
+ DESKICE_NAMESPACE,
+ "GetTeamList",
+ &error,
+ "=>a(sss)",
+ &spaces)) {
+ fprintf (stderr, "Error getting team spaces %s: %s\n",
+ error.name, error.message);
+ dbus_error_free (&error);
+ return;
+ }
+
+ if (!spaces) {
+ fprintf (stderr, "no teamspaces\n");
+ return;
+ }
+ fprintf (stderr, "%d teamspace(s)\n", spaces->len);
+ for (i = 0; i < spaces->len; i++) {
+ TeamSpace *space = &g_array_index (spaces, TeamSpace, i);
+ fprintf (stderr, "\t%d: %s, %s, %s\n", i, space->name, space->id, space->url);
+ }
+
+ dbind_any_free_ptr ("a(sss)", spaces);
+}
+
+void test_helpers ()
+{
+ dbind_find_c_alignment ("(sss)");
+ dbind_find_c_alignment ("a(sss)");
+ dbind_find_c_alignment ("(s(s)yd(d)s)");
+ fprintf (stderr, "helpers passed\n");
+}
+
+int main (int argc, char **argv)
+{
+ DBusConnection *bus;
+ DBusError err;
+
+ dbus_error_init (&err);
+
+ bus = dbus_bus_get (DBUS_BUS_SESSION, &err);
+
+ test_helpers ();
+ test_marshalling ();
+ test_teamspaces (bus);
+
+ return 0;
+}
diff --git a/droute/Makefile.am b/droute/Makefile.am
new file mode 100644
index 0000000..1c4b8e3
--- /dev/null
+++ b/droute/Makefile.am
@@ -0,0 +1,28 @@
+noinst_LTLIBRARIES = libdroute.la
+
+libdroute_la_CFLAGS = $(DBUS_GLIB_CFLAGS) \
+ -DATSPI_INTROSPECTION_PATH=\"$(pkgdatadir)/$(DEFAULT_ATSPI_INTROSPECTION_PATH)\"\
+ -I$(top_builddir)\
+ -I$(top_srcdir)
+
+libdroute_la_SOURCES =\
+ droute.c\
+ droute.h\
+ droute-variant.c\
+ droute-variant.h\
+ droute-pairhash.c\
+ droute-pairhash.h
+libdroute_la_LIBADD = $(DBUS_GLIB_LIBS)
+
+TESTS = droute-test
+
+check_PROGRAMS = droute-test
+droute_test_SOURCES = droute-test.c
+droute_test_CFLAGS = $(DBUS_GLIB_CFLAGS) \
+ -I$(top_builddir)\
+ -I$(top_srcdir)\
+ -DTEST_INTROSPECTION_DIRECTORY=\"$(top_srcdir)/droute\"
+
+droute_test_LDFLAGS = $(top_builddir)/dbind/libdbind.la\
+ libdroute.la\
+ $(DBUS_GLIB_LIBS)
diff --git a/droute/droute-pairhash.c b/droute/droute-pairhash.c
new file mode 100644
index 0000000..f3b8da2
--- /dev/null
+++ b/droute/droute-pairhash.c
@@ -0,0 +1,87 @@
+/*
+ * AT-SPI - Assistive Technology Service Provider Interface
+ * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
+ *
+ * Copyright 2008 Codethink Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "droute-pairhash.h"
+
+/*---------------------------------------------------------------------------*/
+
+static guint
+str_hash (guint32 h, const char *p)
+{
+ for (p += 1; *p != '\0'; p++)
+ h = (h << 5) - h + *p;
+
+ return h;
+}
+
+/*---------------------------------------------------------------------------*/
+
+StrPair *
+str_pair_new (const gchar *one, const gchar *two)
+{
+ StrPair *pair;
+
+ pair = g_new (StrPair, 1);
+ pair->one = one;
+ pair->two = two;
+ return pair;
+}
+
+guint
+str_pair_hash (gconstpointer key)
+{
+ StrPair *pair = (StrPair *) key;
+ guint hash = 0;
+
+ /*g_return_val_if_fail (pair != NULL, 0);
+ g_return_val_if_fail (pair->one != NULL, 0);
+ g_return_val_if_fail (pair->two != NULL, 0);
+ */
+
+ if (*(pair->two) != '\0')
+ {
+ hash = *(pair->two);
+ hash = str_hash (hash, ++(pair->two));
+ hash = str_hash (hash, pair->one);
+ }
+
+ return hash;
+}
+
+gboolean
+str_pair_equal (gconstpointer a, gconstpointer b)
+{
+ StrPair *ap = (StrPair *) a;
+ StrPair *bp = (StrPair *) b;
+
+ if (g_str_equal (ap->one, bp->one) &&
+ g_str_equal (ap->two, bp->two))
+ {
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
+/*END------------------------------------------------------------------------*/
diff --git a/droute/droute-pairhash.h b/droute/droute-pairhash.h
new file mode 100644
index 0000000..1491c2d
--- /dev/null
+++ b/droute/droute-pairhash.h
@@ -0,0 +1,41 @@
+/*
+ * AT-SPI - Assistive Technology Service Provider Interface
+ * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
+ *
+ * Copyright 2008 Codethink Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#ifndef _DROUTE_PAIRHASH_H
+#define _DROUTE_PAIRHASH_H
+
+#include <glib.h>
+
+typedef struct _StrPair StrPair;
+struct _StrPair
+{
+ const gchar *one;
+ const gchar *two;
+};
+
+StrPair *str_pair_new (const gchar *one,
+ const gchar *two);
+
+guint str_pair_hash (gconstpointer key);
+gboolean str_pair_equal (gconstpointer a,
+ gconstpointer b);
+
+#endif /* _DROUTE_PAIRHASH_H */
diff --git a/droute/droute-test.c b/droute/droute-test.c
new file mode 100644
index 0000000..8b3fb7c
--- /dev/null
+++ b/droute/droute-test.c
@@ -0,0 +1,243 @@
+#include <stdio.h>
+#include <glib.h>
+#include <string.h>
+#include <droute/droute.h>
+#include <dbind/dbind.h>
+
+#include "dbus/dbus-glib-lowlevel.h"
+
+#define TEST_OBJECT_PATH "/test/object"
+#define TEST_INTERFACE_ONE "test.interface.One"
+#define TEST_INTERFACE_TWO "test.interface.Two"
+
+#define OBJECT_ONE "ObjectOne";
+#define OBJECT_TWO "ObjectTwo";
+
+#if !defined TEST_INTROSPECTION_DIRECTORY
+ #error "No introspection XML directory defined"
+#endif
+
+#define STRING_ONE "StringOne"
+#define STRING_TWO "StringTwo"
+
+#define INT_ONE 0
+#define INT_TWO 456
+
+#define NONE_REPLY_STRING "NoneMethod"
+
+typedef struct _AnObject
+{
+ gchar *astring;
+ guint *anint;
+} AnObject;
+
+static DBusConnection *bus;
+static GMainLoop *main_loop;
+static gboolean success = TRUE;
+
+static DBusMessage *
+impl_null (DBusConnection *bus, DBusMessage *message, void *user_data)
+{
+ DBusMessage *reply;
+
+ reply = dbus_message_new_method_return (message);
+ return reply;
+}
+
+static DBusMessage *
+impl_getInt (DBusConnection *bus, DBusMessage *message, void *user_data)
+{
+ AnObject *object = (AnObject *) user_data;
+ DBusMessage *reply;
+ DBusError error;
+
+ dbus_error_init (&error);
+
+ reply = dbus_message_new_method_return (message);
+ dbus_message_append_args (reply, DBUS_TYPE_INT32, &(object->anint), DBUS_TYPE_INVALID);
+ return reply;
+}
+
+static DBusMessage *
+impl_setInt (DBusConnection *bus, DBusMessage *message, void *user_data)
+{
+ AnObject *object = (AnObject *) user_data;
+ DBusMessage *reply;
+ DBusError error;
+
+ dbus_error_init (&error);
+
+ dbus_message_get_args (message, &error, DBUS_TYPE_INT32, &(object->anint), DBUS_TYPE_INVALID);
+
+ reply = dbus_message_new_method_return (message);
+ return reply;
+}
+
+static DBusMessage *
+impl_getString (DBusConnection *bus, DBusMessage *message, void *user_data)
+{
+ AnObject *object = (AnObject *) user_data;
+ DBusMessage *reply;
+ DBusError error;
+
+ dbus_error_init (&error);
+
+ reply = dbus_message_new_method_return (message);
+ dbus_message_append_args (reply, DBUS_TYPE_STRING, &(object->astring), DBUS_TYPE_INVALID);
+ return reply;
+}
+
+static DBusMessage *
+impl_setString (DBusConnection *bus, DBusMessage *message, void *user_data)
+{
+ AnObject *object = (AnObject *) user_data;
+ DBusMessage *reply;
+ DBusError error;
+
+ dbus_error_init (&error);
+
+ g_free (object->astring);
+ dbus_message_get_args (message, &error, DBUS_TYPE_STRING, &(object->astring), DBUS_TYPE_INVALID);
+
+ reply = dbus_message_new_method_return (message);
+ return reply;
+}
+
+static DBusMessage *
+impl_getInterfaceOne (DBusConnection *bus, DBusMessage *message, void *user_data)
+{
+ DBusMessage *reply;
+ DBusError error;
+ gchar *itf = TEST_INTERFACE_ONE;
+
+ dbus_error_init (&error);
+
+ reply = dbus_message_new_method_return (message);
+ dbus_message_append_args (reply, DBUS_TYPE_STRING, &itf, DBUS_TYPE_INVALID);
+ return reply;
+}
+
+static DBusMessage *
+impl_getInterfaceTwo (DBusConnection *bus, DBusMessage *message, void *user_data)
+{
+ DBusMessage *reply;
+ DBusError error;
+ gchar *itf = TEST_INTERFACE_TWO;
+
+ dbus_error_init (&error);
+
+ reply = dbus_message_new_method_return (message);
+ dbus_message_append_args (reply, DBUS_TYPE_STRING, &itf, DBUS_TYPE_INVALID);
+ return reply;
+}
+
+static DRouteMethod test_methods_one[] = {
+ {impl_null, "null"},
+ {impl_getInt, "getInt"},
+ {impl_setInt, "setInt"},
+ {impl_getString, "getString"},
+ {impl_setString, "setString"},
+ {impl_getInterfaceOne, "getInterfaceOne"},
+ {NULL, NULL}
+};
+
+static DRouteMethod test_methods_two[] = {
+ {impl_null, "null"},
+ {impl_getInt, "getInt"},
+ {impl_setInt, "setInt"},
+ {impl_getString, "getString"},
+ {impl_setString, "setString"},
+ {impl_getInterfaceTwo, "getInterfaceTwo"},
+ {NULL, NULL}
+};
+
+static DRouteProperty test_properties[] = {
+ {NULL, NULL, NULL}
+};
+
+gboolean
+do_tests_func (gpointer data)
+{
+ DBusError error;
+ const gchar *bus_name;
+
+ gchar *expected_string;
+ gchar *result_string;
+
+ dbus_error_init (&error);
+ bus_name = dbus_bus_get_unique_name (bus);
+
+ /* --------------------------------------------------------*/
+
+ dbind_method_call_reentrant (bus,
+ bus_name,
+ TEST_OBJECT_PATH,
+ TEST_INTERFACE_ONE,
+ "null",
+ NULL,
+ "");
+
+ /* --------------------------------------------------------*/
+
+ expected_string = TEST_INTERFACE_ONE;
+ result_string = NULL;
+ dbind_method_call_reentrant (bus,
+ bus_name,
+ TEST_OBJECT_PATH,
+ TEST_INTERFACE_ONE,
+ "getInterfaceOne",
+ NULL,
+ "=>s",
+ &result_string);
+ if (g_strcmp0(expected_string, result_string))
+ {
+ g_print ("Failed: reply to getInterfaceOne not as expected\n");
+ goto out;
+ }
+
+ /* --------------------------------------------------------*/
+
+out:
+ g_main_loop_quit (main_loop);
+ return FALSE;
+}
+
+
+int main (int argc, char **argv)
+{
+ DRouteContext *cnx;
+ DRoutePath *path;
+ AnObject *object;
+ DBusError error;
+
+ /* Setup some server object */
+
+ object = g_new0(AnObject, 1);
+ object->astring = g_strdup (STRING_ONE);
+ object->anint = INT_ONE;
+
+ dbus_error_init (&error);
+ main_loop = g_main_loop_new(NULL, FALSE);
+ bus = dbus_bus_get (DBUS_BUS_SESSION, &error);
+ dbus_connection_setup_with_g_main(bus, g_main_context_default());
+
+ cnx = droute_new (bus, TEST_INTROSPECTION_DIRECTORY);
+ path = droute_add_one (cnx, TEST_OBJECT_PATH, object);
+
+ droute_path_add_interface (path,
+ TEST_INTERFACE_ONE,
+ test_methods_one,
+ test_properties);
+
+ droute_path_add_interface (path,
+ TEST_INTERFACE_TWO,
+ test_methods_two,
+ test_properties);
+
+ g_idle_add (do_tests_func, NULL);
+ g_main_run(main_loop);
+ if (success)
+ return 0;
+ else
+ return 1;
+}
diff --git a/droute/droute-variant.c b/droute/droute-variant.c
new file mode 100644
index 0000000..d4b5ca6
--- /dev/null
+++ b/droute/droute-variant.c
@@ -0,0 +1,118 @@
+/*
+ * AT-SPI - Assistive Technology Service Provider Interface
+ * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
+ *
+ * Copyright 2008 Novell, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "droute-variant.h"
+
+/*---------------------------------------------------------------------------*/
+
+dbus_bool_t
+droute_return_v_int32 (DBusMessageIter *iter, dbus_int32_t val)
+{
+ DBusMessageIter sub;
+
+ if (!dbus_message_iter_open_container
+ (iter, DBUS_TYPE_VARIANT, DBUS_TYPE_INT32_AS_STRING, &sub))
+ {
+ return FALSE;
+ }
+ dbus_message_iter_append_basic (&sub, DBUS_TYPE_INT32, &val);
+ dbus_message_iter_close_container (iter, &sub);
+ return TRUE;
+}
+
+dbus_bool_t
+droute_return_v_double (DBusMessageIter *iter, double val)
+{
+ DBusMessageIter sub;
+
+ if (!dbus_message_iter_open_container
+ (iter, DBUS_TYPE_VARIANT, DBUS_TYPE_DOUBLE_AS_STRING, &sub))
+ {
+ return FALSE;
+ }
+ dbus_message_iter_append_basic (&sub, DBUS_TYPE_DOUBLE, &val);
+ dbus_message_iter_close_container (iter, &sub);
+ return TRUE;
+}
+
+dbus_bool_t
+droute_return_v_string (DBusMessageIter *iter, const char *val)
+{
+ DBusMessageIter sub;
+
+ if (!val)
+ val = "";
+ if (!dbus_message_iter_open_container
+ (iter, DBUS_TYPE_VARIANT, DBUS_TYPE_STRING_AS_STRING, &sub))
+ {
+ return FALSE;
+ }
+ dbus_message_iter_append_basic (&sub, DBUS_TYPE_STRING, &val);
+ dbus_message_iter_close_container (iter, &sub);
+ return TRUE;
+}
+
+dbus_bool_t
+droute_return_v_object (DBusMessageIter *iter, const char *path)
+{
+ DBusMessageIter sub;
+
+ if (!dbus_message_iter_open_container
+ (iter, DBUS_TYPE_VARIANT, DBUS_TYPE_OBJECT_PATH_AS_STRING, &sub))
+ {
+ return FALSE;
+ }
+ dbus_message_iter_append_basic (&sub, DBUS_TYPE_OBJECT_PATH, &path);
+ dbus_message_iter_close_container (iter, &sub);
+ return TRUE;
+}
+
+/*---------------------------------------------------------------------------*/
+
+dbus_int32_t
+droute_get_v_int32 (DBusMessageIter *iter)
+{
+ DBusMessageIter sub;
+ dbus_int32_t rv;
+
+ // TODO- ensure we have the correct type
+ dbus_message_iter_recurse (iter, &sub);
+ dbus_message_iter_get_basic (&sub, &rv);
+ return rv;
+}
+
+const char *
+droute_get_v_string (DBusMessageIter *iter)
+{
+ DBusMessageIter sub;
+ char *rv;
+
+ // TODO- ensure we have the correct type
+ dbus_message_iter_recurse (iter, &sub);
+ dbus_message_iter_get_basic (&sub, &rv);
+ return rv;
+}
+
+/*END------------------------------------------------------------------------*/
diff --git a/droute/droute-variant.h b/droute/droute-variant.h
new file mode 100644
index 0000000..47feb96
--- /dev/null
+++ b/droute/droute-variant.h
@@ -0,0 +1,35 @@
+/*
+ * AT-SPI - Assistive Technology Service Provider Interface
+ * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
+ *
+ * Copyright 2008 Novell, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#ifndef _DROUTE_VARIANT_H
+#define _DROUTE_VARIANT_H
+
+#include <dbus/dbus.h>
+
+dbus_bool_t droute_return_v_int32 (DBusMessageIter *iter, dbus_int32_t val);
+dbus_bool_t droute_return_v_double (DBusMessageIter *iter, double val);
+dbus_bool_t droute_return_v_string (DBusMessageIter *iter, const char *val);
+dbus_bool_t droute_return_v_object (DBusMessageIter *iter, const char *path);
+
+dbus_int32_t droute_get_v_int32 (DBusMessageIter *iter);
+const char *droute_get_v_string (DBusMessageIter *iter);
+
+#endif /* _DROUTE_VARIANT_H */
diff --git a/droute/droute.c b/droute/droute.c
new file mode 100644
index 0000000..0cec8be
--- /dev/null
+++ b/droute/droute.c
@@ -0,0 +1,598 @@
+/*
+ * AT-SPI - Assistive Technology Service Provider Interface
+ * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
+ *
+ * Copyright 2008 Novell, Inc.
+ * Copyright 2008 Codethink Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "droute.h"
+#include "droute-pairhash.h"
+
+#define CHUNKS_DEFAULT (512)
+
+#define oom() g_error ("D-Bus out of memory, this message will fail anyway")
+
+#if defined DROUTE_DEBUG
+ #define _DROUTE_DEBUG(format, args...) g_print (format , ## args)
+#else
+ #define _DROUTE_DEBUG(format, args...)
+#endif
+
+struct _DRouteContext
+{
+ DBusConnection *bus;
+ GPtrArray *registered_paths;
+
+ gchar *introspect_dir;
+};
+
+struct _DRoutePath
+{
+ DRouteContext *cnx;
+ GStringChunk *chunks;
+ GPtrArray *interfaces;
+ GHashTable *methods;
+ GHashTable *properties;
+
+ void *user_data;
+ DRouteGetDatumFunction get_datum;
+};
+
+/*---------------------------------------------------------------------------*/
+
+typedef struct PropertyPair
+{
+ DRoutePropertyFunction get;
+ DRoutePropertyFunction set;
+} PropertyPair;
+
+/*---------------------------------------------------------------------------*/
+
+static DBusHandlerResult
+handle_message (DBusConnection *bus, DBusMessage *message, void *user_data);
+
+/*---------------------------------------------------------------------------*/
+
+static DRoutePath *
+path_new (DRouteContext *cnx,
+ void *user_data,
+ DRouteGetDatumFunction get_datum)
+{
+ DRoutePath *new_path;
+
+ new_path = g_new0 (DRoutePath, 1);
+ new_path->cnx = cnx;
+ new_path->chunks = g_string_chunk_new (CHUNKS_DEFAULT);
+ new_path->interfaces = g_ptr_array_new ();
+
+ new_path->methods = g_hash_table_new_full ((GHashFunc)str_pair_hash,
+ str_pair_equal,
+ g_free,
+ NULL);
+
+ new_path->properties = g_hash_table_new_full ((GHashFunc)str_pair_hash,
+ str_pair_equal,
+ g_free,
+ NULL);
+
+ new_path->user_data = user_data;
+ new_path->get_datum = get_datum;
+
+ return new_path;
+}
+
+static void
+path_free (DRoutePath *path, gpointer user_data)
+{
+ g_string_chunk_free (path->chunks);
+ g_ptr_array_free (path->interfaces, TRUE);
+ g_hash_table_destroy (path->methods);
+ g_hash_table_destroy (path->properties);
+}
+
+static void *
+path_get_datum (DRoutePath *path, const gchar *pathstr)
+{
+ if (path->get_datum != NULL)
+ return (path->get_datum) (pathstr, path->user_data);
+ else
+ return path->user_data;
+}
+
+/*---------------------------------------------------------------------------*/
+
+DRouteContext *
+droute_new (DBusConnection *bus, const char *introspect_dir)
+{
+ DRouteContext *cnx;
+
+ cnx = g_new0 (DRouteContext, 1);
+ cnx->bus = bus;
+ cnx->registered_paths = g_ptr_array_new ();
+ cnx->introspect_dir = g_strdup(introspect_dir);
+
+ return cnx;
+}
+
+void
+droute_free (DRouteContext *cnx)
+{
+ g_ptr_array_foreach (cnx->registered_paths, (GFunc) path_free, NULL);
+ g_free (cnx->introspect_dir);
+ g_free (cnx);
+}
+
+/*---------------------------------------------------------------------------*/
+
+DBusConnection *
+droute_get_bus (DRouteContext *cnx)
+{
+ return cnx->bus;
+}
+
+/*---------------------------------------------------------------------------*/
+
+static DBusObjectPathVTable droute_vtable =
+{
+ NULL,
+ &handle_message,
+ NULL, NULL, NULL, NULL
+};
+
+DRoutePath *
+droute_add_one (DRouteContext *cnx,
+ const char *path,
+ const void *data)
+{
+ DRoutePath *new_path;
+ gboolean registered;
+
+ new_path = path_new (cnx, (void *) data, NULL);
+
+ registered = dbus_connection_register_object_path (cnx->bus, path, &droute_vtable, new_path);
+ if (!registered)
+ oom();
+
+ g_ptr_array_add (cnx->registered_paths, new_path);
+ return new_path;
+}
+
+DRoutePath *
+droute_add_many (DRouteContext *cnx,
+ const char *path,
+ const void *data,
+ const DRouteGetDatumFunction get_datum)
+{
+ DRoutePath *new_path;
+
+ new_path = path_new (cnx, (void *) data, get_datum);
+
+ if (!dbus_connection_register_fallback (cnx->bus, path, &droute_vtable, new_path))
+ oom();
+
+ g_ptr_array_add (cnx->registered_paths, new_path);
+ return new_path;
+}
+
+/*---------------------------------------------------------------------------*/
+
+void
+droute_path_add_interface(DRoutePath *path,
+ const char *name,
+ const DRouteMethod *methods,
+ const DRouteProperty *properties)
+{
+ gchar *itf;
+
+ g_return_if_fail (name != NULL);
+
+ itf = g_string_chunk_insert (path->chunks, name);
+ g_ptr_array_add (path->interfaces, itf);
+
+ for (; methods != NULL && methods->name != NULL; methods++)
+ {
+ gchar *meth;
+
+ meth = g_string_chunk_insert (path->chunks, methods->name);
+ g_hash_table_insert (path->methods, str_pair_new (itf, meth), methods->func);
+ }
+
+ for (; properties != NULL && properties->name != NULL; properties++)
+ {
+ gchar *prop;
+ PropertyPair *pair;
+
+ prop = g_string_chunk_insert (path->chunks, properties->name);
+ pair = g_new (PropertyPair, 1);
+ pair->get = properties->get;
+ pair->set = properties->set;
+ g_hash_table_insert (path->properties, str_pair_new (itf, prop), pair);
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+
+/* The data structures don't support an efficient implementation of GetAll
+ * and I don't really care.
+ */
+static DBusMessage *
+impl_prop_GetAll (DBusMessage *message,
+ DRoutePath *path,
+ const char *pathstr)
+{
+ DBusMessageIter iter, iter_dict, iter_dict_entry;
+ DBusMessage *reply;
+ DBusError error;
+ GHashTableIter prop_iter;
+
+ StrPair *key;
+ PropertyPair *value;
+ gchar *iface;
+
+ void *datum = path_get_datum (path, pathstr);
+
+ dbus_error_init (&error);
+ if (!dbus_message_get_args
+ (message, &error, DBUS_TYPE_STRING, &iface, DBUS_TYPE_INVALID))
+ return dbus_message_new_error (message, DBUS_ERROR_FAILED, error.message);
+
+ reply = dbus_message_new_method_return (message);
+ if (!reply)
+ oom ();
+
+ dbus_message_iter_init_append (reply, &iter);
+ if (!dbus_message_iter_open_container
+ (&iter, DBUS_TYPE_ARRAY, "{sv}", &iter_dict))
+ oom ();
+
+ g_hash_table_iter_init (&prop_iter, path->properties);
+ while (g_hash_table_iter_next (&prop_iter, (gpointer*)&key, (gpointer*)&value))
+ {
+ if (!g_strcmp0 (key->one, iface))
+ {
+ if (!value->get)
+ continue;
+ if (!dbus_message_iter_open_container
+ (&iter_dict, DBUS_TYPE_DICT_ENTRY, NULL, &iter_dict_entry))
+ oom ();
+ dbus_message_iter_append_basic (&iter_dict_entry, DBUS_TYPE_STRING,
+ key->two);
+ (value->get) (&iter_dict_entry, datum);
+ if (!dbus_message_iter_close_container (&iter_dict, &iter_dict_entry))
+ oom ();
+ }
+ }
+
+ if (!dbus_message_iter_close_container (&iter, &iter_dict))
+ oom ();
+ return reply;
+}
+
+static DBusMessage *
+impl_prop_GetSet (DBusMessage *message,
+ DRoutePath *path,
+ const char *pathstr,
+ gboolean get)
+{
+ DBusMessage *reply = NULL;
+ DBusError error;
+
+ StrPair pair;
+ PropertyPair *prop_funcs = NULL;
+
+
+ dbus_error_init (&error);
+ if (!dbus_message_get_args (message,
+ &error,
+ DBUS_TYPE_STRING,
+ &(pair.one),
+ DBUS_TYPE_STRING,
+ &(pair.two),
+ DBUS_TYPE_INVALID))
+ return dbus_message_new_error (message, DBUS_ERROR_FAILED, error.message);
+
+ _DROUTE_DEBUG ("DRoute (handle prop): %s|%s on %s\n", pair.one, pair.two, pathstr);
+
+ prop_funcs = (PropertyPair *) g_hash_table_lookup (path->properties, &pair);
+ if (!prop_funcs)
+ return dbus_message_new_error (message, DBUS_ERROR_FAILED, "Property unavailable");
+
+ if (get && prop_funcs->get)
+ {
+ void *datum = path_get_datum (path, pathstr);
+ DBusMessageIter iter;
+
+ _DROUTE_DEBUG ("DRoute (handle prop Get): %s|%s on %s\n", pair.one, pair.two, pathstr);
+
+ reply = dbus_message_new_method_return (message);
+ dbus_message_iter_init_append (reply, &iter);
+ if (!(prop_funcs->get) (&iter, datum))
+ {
+ dbus_message_unref (reply);
+ reply = dbus_message_new_error (message, DBUS_ERROR_FAILED, "Get failed");
+ }
+ }
+ else if (!get && prop_funcs->set)
+ {
+ void *datum = path_get_datum (path, pathstr);
+ DBusMessageIter iter;
+
+ _DROUTE_DEBUG ("DRoute (handle prop Get): %s|%s on %s\n", pair.one, pair.two, pathstr);
+
+ dbus_message_iter_init (message, &iter);
+ /* Skip the interface and property name */
+ dbus_message_iter_next(&iter);
+ dbus_message_iter_next(&iter);
+ (prop_funcs->set) (&iter, datum);
+
+ reply = dbus_message_new_method_return (message);
+ }
+ else
+ {
+ reply = dbus_message_new_error (message, DBUS_ERROR_FAILED, "Getter or setter unavailable");
+ }
+
+ return reply;
+}
+
+static DBusHandlerResult
+handle_properties (DBusConnection *bus,
+ DBusMessage *message,
+ DRoutePath *path,
+ const gchar *iface,
+ const gchar *member,
+ const gchar *pathstr)
+{
+ DBusMessage *reply;
+ DBusHandlerResult result = DBUS_HANDLER_RESULT_HANDLED;
+
+ if (!g_strcmp0(member, "GetAll"))
+ reply = impl_prop_GetAll (message, path, pathstr);
+ else if (!g_strcmp0 (member, "Get"))
+ reply = impl_prop_GetSet (message, path, pathstr, TRUE);
+ else if (!g_strcmp0 (member, "Set"))
+ reply = impl_prop_GetSet (message, path, pathstr, FALSE);
+ else
+ result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+ if (reply)
+ {
+ dbus_connection_send (bus, reply, NULL);
+ dbus_message_unref (reply);
+ }
+
+ return result;
+}
+
+/*---------------------------------------------------------------------------*/
+
+static const char *introspection_header =
+"<?xml version=\"1.0\"?>\n";
+
+static const char *introspection_node_element =
+"<node name=\"%s\">\n";
+
+static const char *introspection_footer =
+"</node>";
+
+static void
+append_interface (GString *str,
+ const gchar *interface,
+ const gchar *directory)
+{
+ gchar *filename;
+ gchar *contents;
+ gsize len;
+
+ GError *err = NULL;
+
+ filename = g_build_filename (directory, interface, NULL);
+
+ if (g_file_get_contents (filename, &contents, &len, &err))
+ {
+ g_string_append_len (str, contents, len);
+ }
+ else
+ {
+ g_warning ("AT-SPI: Cannot find introspection XML file %s - %s",
+ filename, err->message);
+ g_error_free (err);
+ }
+
+ g_string_append (str, "\n");
+ g_free (filename);
+ g_free (contents);
+}
+
+static DBusHandlerResult
+handle_introspection (DBusConnection *bus,
+ DBusMessage *message,
+ DRoutePath *path,
+ const gchar *iface,
+ const gchar *member,
+ const gchar *pathstr)
+{
+ GString *output;
+ gchar *final;
+ gint i;
+
+ DBusMessage *reply;
+
+ _DROUTE_DEBUG ("DRoute (handle introspection): %s\n", pathstr);
+
+ if (g_strcmp0 (member, "Introspect"))
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+ output = g_string_new(introspection_header);
+
+ g_string_append_printf(output, introspection_node_element, pathstr);
+
+ for (i=0; i < path->interfaces->len; i++)
+ {
+ gchar *interface = (gchar *) g_ptr_array_index (path->interfaces, i);
+ append_interface(output, interface, path->cnx->introspect_dir);
+ }
+
+ g_string_append(output, introspection_footer);
+ final = g_string_free(output, FALSE);
+
+ reply = dbus_message_new_method_return (message);
+ if (!reply)
+ oom ();
+ dbus_message_append_args(reply, DBUS_TYPE_STRING, &final,
+ DBUS_TYPE_INVALID);
+ dbus_connection_send (bus, reply, NULL);
+
+ dbus_message_unref (reply);
+ g_free(final);
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+/*---------------------------------------------------------------------------*/
+
+static DBusHandlerResult
+handle_other (DBusConnection *bus,
+ DBusMessage *message,
+ DRoutePath *path,
+ const gchar *iface,
+ const gchar *member,
+ const gchar *pathstr)
+{
+ gint result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+ StrPair pair;
+ DRouteFunction func;
+ DBusMessage *reply = NULL;
+
+ pair.one = iface;
+ pair.two = member;
+
+ _DROUTE_DEBUG ("DRoute (handle other): %s|%s on %s\n", member, iface, pathstr);
+
+ func = (DRouteFunction) g_hash_table_lookup (path->methods, &pair);
+ if (func != NULL)
+ {
+ void *datum = path_get_datum (path, pathstr);
+
+ reply = (func) (bus, message, datum);
+
+ if (!reply)
+ {
+ /* All D-Bus method calls must have a reply.
+ * If one is not provided presume that the call has a void
+ * return and no error has occured.
+ */
+ reply = dbus_message_new_method_return (message);
+ }
+ dbus_connection_send (bus, reply, NULL);
+ dbus_message_unref (reply);
+ result = DBUS_HANDLER_RESULT_HANDLED;
+ }
+
+ _DROUTE_DEBUG ("DRoute (handle other) (reply): type %d\n",
+ dbus_message_get_type(reply));
+ return result;
+}
+
+/*---------------------------------------------------------------------------*/
+
+static DBusHandlerResult
+handle_message (DBusConnection *bus, DBusMessage *message, void *user_data)
+{
+ DRoutePath *path = (DRoutePath *) user_data;
+ const gchar *iface = dbus_message_get_interface (message);
+ const gchar *member = dbus_message_get_member (message);
+ const gint type = dbus_message_get_type (message);
+ const gchar *pathstr = dbus_message_get_path (message);
+
+ /* Check for basic reasons not to handle */
+ if (type != DBUS_MESSAGE_TYPE_METHOD_CALL ||
+ member == NULL ||
+ iface == NULL)
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+ if (!strcmp (iface, "org.freedesktop.DBus.Properties"))
+ return handle_properties (bus, message, path, iface, member, pathstr);
+
+ if (!strcmp (iface, "org.freedesktop.DBus.Introspectable"))
+ return handle_introspection (bus, message, path, iface, member, pathstr);
+
+ return handle_other (bus, message, path, iface, member, pathstr);
+}
+
+/*---------------------------------------------------------------------------*/
+
+DBusMessage *
+droute_not_yet_handled_error (DBusMessage *message)
+{
+ DBusMessage *reply;
+ gchar *errmsg;
+
+ errmsg= g_strdup_printf (
+ "Method \"%s\" with signature \"%s\" on interface \"%s\" doesn't exist\n",
+ dbus_message_get_member (message),
+ dbus_message_get_signature (message),
+ dbus_message_get_interface (message));
+ reply = dbus_message_new_error (message,
+ DBUS_ERROR_UNKNOWN_METHOD,
+ errmsg);
+ g_free (errmsg);
+ return reply;
+}
+
+DBusMessage *
+droute_out_of_memory_error (DBusMessage *message)
+{
+ DBusMessage *reply;
+ gchar *errmsg;
+
+ errmsg= g_strdup_printf (
+ "Method \"%s\" with signature \"%s\" on interface \"%s\" could not be processed due to lack of memory\n",
+ dbus_message_get_member (message),
+ dbus_message_get_signature (message),
+ dbus_message_get_interface (message));
+ reply = dbus_message_new_error (message,
+ DBUS_ERROR_NO_MEMORY,
+ errmsg);
+ g_free (errmsg);
+ return reply;
+}
+
+DBusMessage *
+droute_invalid_arguments_error (DBusMessage *message)
+{
+ DBusMessage *reply;
+ gchar *errmsg;
+
+ errmsg= g_strdup_printf (
+ "Method \"%s\" with signature \"%s\" on interface \"%s\" was supplied with invalid arguments\n",
+ dbus_message_get_member (message),
+ dbus_message_get_signature (message),
+ dbus_message_get_interface (message));
+ reply = dbus_message_new_error (message,
+ DBUS_ERROR_INVALID_ARGS,
+ errmsg);
+ g_free (errmsg);
+ return reply;
+}
+
+/*END------------------------------------------------------------------------*/
diff --git a/droute/droute.h b/droute/droute.h
new file mode 100644
index 0000000..a892c62
--- /dev/null
+++ b/droute/droute.h
@@ -0,0 +1,95 @@
+/*
+ * AT-SPI - Assistive Technology Service Provider Interface
+ * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
+ *
+ * Copyright 2008 Novell, Inc.
+ * Copyright 2008 Codethink Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#ifndef _DROUTE_H
+#define _DROUTE_H
+
+#include <dbus/dbus.h>
+#include <glib.h>
+
+#include <droute/droute-variant.h>
+
+
+typedef DBusMessage *(*DRouteFunction) (DBusConnection *, DBusMessage *, void *);
+typedef dbus_bool_t (*DRoutePropertyFunction) (DBusMessageIter *, void *);
+
+typedef void *(*DRouteGetDatumFunction) (const char *, void *);
+
+typedef struct _DRouteMethod DRouteMethod;
+struct _DRouteMethod
+{
+ DRouteFunction func;
+ const char *name;
+};
+
+typedef struct _DRouteProperty DRouteProperty;
+struct _DRouteProperty
+{
+ DRoutePropertyFunction get;
+ DRoutePropertyFunction set;
+ const char *name;
+};
+
+/*---------------------------------------------------------------------------*/
+
+typedef struct _DRouteContext DRouteContext;
+
+typedef struct _DRoutePath DRoutePath;
+
+/*---------------------------------------------------------------------------*/
+
+DRouteContext *
+droute_new (DBusConnection *bus,
+ const char *introspect_dir);
+void
+droute_free (DRouteContext *cnx);
+
+DRoutePath *
+droute_add_one (DRouteContext *cnx,
+ const char *path,
+ const void *data);
+
+DRoutePath *
+droute_add_many (DRouteContext *cnx,
+ const char *path,
+ const void *data,
+ const DRouteGetDatumFunction get_datum);
+
+void
+droute_path_add_interface (DRoutePath *path,
+ const char *name,
+ const DRouteMethod *methods,
+ const DRouteProperty *properties);
+
+DBusMessage *
+droute_not_yet_handled_error (DBusMessage *message);
+
+DBusMessage *
+droute_invalid_arguments_error (DBusMessage *message);
+
+DBusMessage *
+droute_out_of_memory_error (DBusMessage *message);
+
+DBusConnection *
+droute_get_bus (DRouteContext *cnx);
+
+#endif /* _DROUTE_H */
diff --git a/droute/test.interface.One b/droute/test.interface.One
new file mode 100644
index 0000000..a8e2206
--- /dev/null
+++ b/droute/test.interface.One
@@ -0,0 +1,15 @@
+<interface name="test.interface.One">
+ <method name="null"/>
+ <method name="getInt">
+ <arg direction="out" type="o"/>
+ </method>
+ <method name="setInt">
+ <arg direction="in" type="o"/>
+ </method>
+ <method name="getString">
+ <arg direction="out" type="s"/>
+ </method>
+ <method name="setString">
+ <arg direction="in" type="s"/>
+ </method>
+</interface>
diff --git a/droute/test.interface.Two b/droute/test.interface.Two
new file mode 100644
index 0000000..ca661ec
--- /dev/null
+++ b/droute/test.interface.Two
@@ -0,0 +1,15 @@
+<interface name="test.interface.Two">
+ <method name="null"/>
+ <method name="getInt">
+ <arg direction="out" type="o"/>
+ </method>
+ <method name="setInt">
+ <arg direction="in" type="o"/>
+ </method>
+ <method name="getString">
+ <arg direction="out" type="s"/>
+ </method>
+ <method name="setString">
+ <arg direction="in" type="s"/>
+ </method>
+</interface>