From 28d2e961940e5b242e008f23bf9b2d68ab555cfa Mon Sep 17 00:00:00 2001 From: Mike Gorse Date: Mon, 23 Jun 2008 18:50:15 -0400 Subject: [PATCH] Added dbind --- dbind/Makefile.am | 24 +++ dbind/dbind-any.c | 452 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ dbind/dbind-any.h | 18 +++ dbind/dbind.c | 215 ++++++++++++++++++++++++++ dbind/dbind.h | 39 +++++ dbind/dbtest.c | 403 ++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 1151 insertions(+) create mode 100644 dbind/Makefile.am create mode 100644 dbind/dbind-any.c create mode 100644 dbind/dbind-any.h create mode 100644 dbind/dbind.c create mode 100644 dbind/dbind.h create mode 100644 dbind/dbtest.c diff --git a/dbind/Makefile.am b/dbind/Makefile.am new file mode 100644 index 0000000..97365b8 --- /dev/null +++ b/dbind/Makefile.am @@ -0,0 +1,24 @@ +lib_LTLIBRARIES = libdbind.la + +INCLUDES = \ + -DG_LOG_DOMAIN=\"dbind\" \ + -I$(top_srcdir) \ + $(WARN_CFLAGS) \ + $(DBUS_CFLAGS) \ + $(GLIB_CFLAGS) + +libdbindinclude_HEADERS = \ + dbind-any.h \ + dbind.h +libdbindincludedir=$(includedir)/dbind-0.1 + +libdbind_la_SOURCES = \ + dbind.c \ + dbind-any.c +libdbind_la_LIBADD = $(DBUS_LIBS) $(GLIB_LIBS) + +TESTS = dbtest + +check_PROGRAMS = dbtest +dbtest_SOURCES = dbtest.c +dbtest_LDFLAGS = libdbind.la \ No newline at end of file diff --git a/dbind/dbind-any.c b/dbind/dbind-any.c new file mode 100644 index 0000000..1f784e5 --- /dev/null +++ b/dbind/dbind-any.c @@ -0,0 +1,452 @@ +/* type driven marshalling */ +#include "config.h" +#include "dbind-config.h" +#define DBUS_API_SUBJECT_TO_CHANGE +#include +#include +#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))) + +unsigned int dbind_find_c_alignment_r (char **type); +unsigned int dbind_find_c_alignment (char *type); + +static void +warn_braces () +{ + fprintf (stderr, "Error: dbus flags structures & dicts with braces rather than " + " an explicit type member of 'struct'\n"); +} + +/* gather immediate allocation information for this type */ +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; + } +} + +size_t dbind_gather_alloc_info (char *type) +{ + return dbind_gather_alloc_info_r (&type); +} + +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; + } +} + +unsigned int +dbind_find_c_alignment (char *type) +{ + return dbind_find_c_alignment_r (&type); +} + +#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 + +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_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); +} + +static void +dbind_any_free_r (char **type, void **data) +{ + size_t len; + +#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, *child_type_string; + + (*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; + } +} + +/* 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); +} diff --git a/dbind/dbind-any.h b/dbind/dbind-any.h new file mode 100644 index 0000000..ce6482e --- /dev/null +++ b/dbind/dbind-any.h @@ -0,0 +1,18 @@ +#ifndef _DBIND_ANY_H_ +#define _DBIND_ANY_H_ + +#include + +size_t dbind_gather_alloc_info (char *type); +void dbind_any_marshal (DBusMessageIter *iter, + char **type, + void **val); +void dbind_any_demarshal (DBusMessageIter *iter, + char **type, + void **val); +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..4da315b --- /dev/null +++ b/dbind/dbind.c @@ -0,0 +1,215 @@ +#include "config.h" +#include +#define DBUS_API_SUBJECT_TO_CHANGE +#include +#include +#include +#include + +/* + * FIXME: compare types - to ensure they match & + * do dynamic padding of structures etc. + */ + +struct _DBindContext { + DBusConnection *cnx; +}; + +DBindContext * +dbind_create_context (DBusBusType type, DBusError *opt_error) +{ + DBindContext *ctx = NULL; + DBusConnection *cnx; + DBusError *err, real_err; + + if (opt_error) + err = opt_error; + else { + dbus_error_init (&real_err); + err = &real_err; + } + + cnx = dbus_bus_get (DBUS_BUS_SESSION, err); + if (!cnx) + goto out; + + ctx = g_new0 (DBindContext, 1); + ctx->cnx = cnx; + +out: + if (err == &real_err) + dbus_error_free (err); + + return ctx; +} + +void +dbind_context_free (DBindContext *ctx) +{ + if (!ctx) + return; + dbus_connection_unref (ctx->cnx); + g_free (ctx); +} + +dbus_bool_t +dbind_context_method_call (DBindContext *ctx, + const char *bus_name, + const char *path, + const char *interface, + const char *method, + DBusError *opt_error, + const char *arg_types, + ...) +{ + dbus_bool_t success; + va_list args; + + va_start (args, arg_types); + + success = dbind_connection_method_call_va + (ctx->cnx, bus_name, path, interface, method, opt_error, arg_types, args); + + va_end (args); + + return success; +} + +dbus_bool_t +dbind_connection_method_call (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; + va_list args; + + va_start (args, arg_types); + + success = dbind_connection_method_call_va + (cnx, bus_name, path, interface, method, opt_error, arg_types, args); + + va_end (args); + + return success; +} + +dbus_bool_t +dbind_connection_method_call_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; + 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_method_call (bus_name, path, interface, method); + if (!msg) + goto out; + dbus_message_set_auto_start (msg, TRUE); + + /* marshal */ + p = (char *)arg_types; + { + DBusMessageIter iter; + + dbus_message_iter_init_append (msg, &iter); + /* 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_STRUCT_BEGIN_CHAR: + case DBUS_TYPE_DICT_ENTRY: + 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); + } + } + + reply = dbus_connection_send_with_reply_and_block (cnx, msg, -1, err); + if (!reply) + goto out; + + /* demarshal */ + if (p[0] == '=' && p[1] == '>') + { + DBusMessageIter iter; + p += 2; + dbus_message_iter_init (reply, &iter); + for (;*p != '\0';) { + void *arg = va_arg (args, void *); + dbind_any_demarshal (&iter, &p, &arg); + } + } + + 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; +} + diff --git a/dbind/dbind.h b/dbind/dbind.h new file mode 100644 index 0000000..4e66359 --- /dev/null +++ b/dbind/dbind.h @@ -0,0 +1,39 @@ +#ifndef _DBIND_H_ +#define _DBIND_H_ + + +#define DBUS_API_SUBJECT_TO_CHANGE +#include + +typedef struct _DBindContext DBindContext; + +DBindContext *dbind_create_context (DBusBusType type, DBusError *opt_error); +void dbind_context_free (DBindContext *ctx); +dbus_bool_t dbind_context_method_call (DBindContext *ctx, + const char *bus_name, + const char *path, + const char *interface, + const char *method, + DBusError *opt_error, + const char *arg_types, + ...); + +/* dbus connection variants */ +dbus_bool_t dbind_connection_method_call (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_connection_method_call_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); + +#endif /* _DBIND_H_ */ diff --git a/dbind/dbtest.c b/dbind/dbtest.c new file mode 100644 index 0000000..9a3ae86 --- /dev/null +++ b/dbind/dbtest.c @@ -0,0 +1,403 @@ +#include +#include +#include +#define DBUS_API_SUBJECT_TO_CHANGE +#include +#include + +/* 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 (DBindContext *ctx) +{ + GArray *spaces; + DBusError error; + int i; + typedef struct { + char *name; + char *id; + char *url; + } TeamSpace; + + dbus_error_init (&error); + if (!dbind_context_method_call (ctx, 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); +} + +extern dbind_find_c_alignment (char *type); + +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) +{ + DBindContext *ctx; + + ctx = dbind_create_context (DBUS_BUS_SESSION, NULL); + if (!ctx) + return 1; + + test_helpers (); + test_marshalling (); + test_teamspaces (ctx); + + dbind_context_free (ctx); + + return 0; +} -- 2.7.4