From 74b1b35402f6b9bbc09999a6224dfc04bc48b2a9 Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Wed, 9 Mar 2005 17:09:11 +0000 Subject: 2005-03-09 Colin Walters * glib/dbus-gproxy.c (dbus_g_proxy_invoke): New method; calls to this are generated for client-side wrappers. Invokes a D-BUS method and returns reply values. * glib/dbus-binding-tool-glib.c (write_args_sig_for_direction): New function; writes signature string for argument direction. (write_args_for_direction): Change to pass input values directly instead of via address, and fix indentation. (generate_client_glue): Change to invoke dbus_g_proxy_invoke. Also make generated wrappers inlineable. * dbus/dbus-message.c (dbus_message_iter_get_fixed_array): Add note about using dbus_type_is_fixed. * dbus/dbus-marshal-basic.c (_dbus_type_is_fixed): Moved to dbus/dbus-signature.c as dbus_type_is_fixed. All callers updated. * dbus/dbus-signature.c (dbus_type_is_fixed): Moved here from dbus/dbus-marshal-basic.c:_dbus_type_is_fixed. * dbus/dbus-signature.h: Prototype. * glib/dbus-binding-tool-glib.c (compute_marshaller_name): Fix error printf code. * test/glib/test-dbus-glib.c (main): Be sure to clear error as appropriate instead of just freeing it. (main): Free returned strings using g_free. * test/glib/Makefile.am (test-service-glib-glue.h) (test-service-glib-bindings.h): Add dependency on dbus-binding-tool. * glib/dbus-gvalue.c (MAP_BASIC): Refactored from MAP_BASIC_INIT; simply maps a simple D-BUS type to GType. (dbus_dbus_type_to_gtype): Function which maps D-BUS type to GType. (dbus_gvalue_init): Just invoke dbus_dbus_type_to_gtype and initialize the value with it. (dbus_gvalue_binding_type_from_type): Unused, delete. (dbus_gvalue_demarshal): Switch to hardcoding demarshalling for various types instead of unmarshalling to value data directly. Remove can_convert boolean. (dbus_gvalue_marshal): Remove duplicate initialization; switch to returning directly instead of using can_convert boolean. (dbus_gvalue_store): New function; not related to D-BUS per-se. Stores a GValue in a pointer to a value of its corresponding C type. * glib/dbus-gvalue.h: Remove dbus_gvalue_binding_type_from_type, add dbus_gvalue_store. --- ChangeLog | 55 ++++++++ dbus/dbus-glib.h | 7 + dbus/dbus-marshal-basic.c | 34 +---- dbus/dbus-marshal-byteswap.c | 3 +- dbus/dbus-marshal-recursive-util.c | 4 +- dbus/dbus-marshal-recursive.c | 8 +- dbus/dbus-message.c | 11 +- dbus/dbus-signature.c | 30 +++++ dbus/dbus-signature.h | 1 + glib/dbus-binding-tool-glib.c | 73 ++++++----- glib/dbus-gproxy.c | 205 ++++++++++++++++++++++++++++++ glib/dbus-gvalue.c | 254 +++++++++++++++++++++---------------- glib/dbus-gvalue.h | 4 +- test/glib/Makefile.am | 4 +- test/glib/test-dbus-glib.c | 6 +- 15 files changed, 509 insertions(+), 190 deletions(-) diff --git a/ChangeLog b/ChangeLog index 844b73ca..c57228a1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,58 @@ +2005-03-09 Colin Walters + + * glib/dbus-gproxy.c (dbus_g_proxy_invoke): New method; calls + to this are generated for client-side wrappers. Invokes a + D-BUS method and returns reply values. + + * glib/dbus-binding-tool-glib.c (write_args_sig_for_direction): New + function; writes signature string for argument direction. + (write_args_for_direction): Change to pass input values directly + instead of via address, and fix indentation. + (generate_client_glue): Change to invoke dbus_g_proxy_invoke. Also + make generated wrappers inlineable. + + * dbus/dbus-message.c (dbus_message_iter_get_fixed_array): Add + note about using dbus_type_is_fixed. + + * dbus/dbus-marshal-basic.c (_dbus_type_is_fixed): Moved to + dbus/dbus-signature.c as dbus_type_is_fixed. + + All callers updated. + + * dbus/dbus-signature.c (dbus_type_is_fixed): Moved here + from dbus/dbus-marshal-basic.c:_dbus_type_is_fixed. + + * dbus/dbus-signature.h: Prototype. + + * glib/dbus-binding-tool-glib.c (compute_marshaller_name): Fix + error printf code. + + * test/glib/test-dbus-glib.c (main): Be sure to clear error as + appropriate instead of just freeing it. + (main): Free returned strings using g_free. + + * test/glib/Makefile.am (test-service-glib-glue.h) + (test-service-glib-bindings.h): Add dependency on dbus-binding-tool. + + * glib/dbus-gvalue.c (MAP_BASIC): Refactored from MAP_BASIC_INIT; + simply maps a simple D-BUS type to GType. + (dbus_dbus_type_to_gtype): Function which maps D-BUS type to + GType. + (dbus_gvalue_init): Just invoke dbus_dbus_type_to_gtype and + initialize the value with it. + (dbus_gvalue_binding_type_from_type): Unused, delete. + (dbus_gvalue_demarshal): Switch to hardcoding demarshalling for + various types instead of unmarshalling to value data directly. + Remove can_convert boolean. + (dbus_gvalue_marshal): Remove duplicate initialization; switch to + returning directly instead of using can_convert boolean. + (dbus_gvalue_store): New function; not related to D-BUS per-se. + Stores a GValue in a pointer to a value of its corresponding C + type. + + * glib/dbus-gvalue.h: Remove dbus_gvalue_binding_type_from_type, + add dbus_gvalue_store. + 2005-03-08 Joe Shaw Fix a bunch of lifecycle and memory management problems diff --git a/dbus/dbus-glib.h b/dbus/dbus-glib.h index a9aad540..e1b4a704 100644 --- a/dbus/dbus-glib.h +++ b/dbus/dbus-glib.h @@ -174,6 +174,13 @@ void dbus_g_proxy_call_no_reply (DBusGProxy *proxy, const char* dbus_g_proxy_get_bus_name (DBusGProxy *proxy); +gboolean dbus_g_proxy_invoke (DBusGProxy *proxy, + const char *method, + const char *insig, + const char *outsig, + GError **error, + ...); + #undef DBUS_INSIDE_DBUS_GLIB_H G_END_DECLS diff --git a/dbus/dbus-marshal-basic.c b/dbus/dbus-marshal-basic.c index fde58d51..ea0648ae 100644 --- a/dbus/dbus-marshal-basic.c +++ b/dbus/dbus-marshal-basic.c @@ -620,7 +620,7 @@ _dbus_marshal_read_fixed_multi (const DBusString *str, int array_len; int alignment; - _dbus_assert (_dbus_type_is_fixed (element_type)); + _dbus_assert (dbus_type_is_fixed (element_type)); _dbus_assert (dbus_type_is_basic (element_type)); #if 0 @@ -1054,7 +1054,7 @@ marshal_fixed_multi (DBusString *str, /** * Marshals a block of values of fixed-length type all at once, as an - * optimization. _dbus_type_is_fixed() returns #TRUE for fixed-length + * optimization. dbus_type_is_fixed() returns #TRUE for fixed-length * types, which are the basic types minus the string-like types. * * The value argument should be the adddress of an @@ -1080,7 +1080,7 @@ _dbus_marshal_write_fixed_multi (DBusString *str, { const void* vp = *(const DBusBasicValue**)value; - _dbus_assert (_dbus_type_is_fixed (element_type)); + _dbus_assert (dbus_type_is_fixed (element_type)); _dbus_assert (n_elements >= 0); #if 0 @@ -1298,34 +1298,6 @@ _dbus_type_is_valid (int typecode) } } -/** - * Tells you whether values of this type can change length if you set - * them to some other value. For this purpose, you assume that the - * first byte of the old and new value would be in the same location, - * so alignment padding is not a factor. - * - * @returns #FALSE if the type can occupy different lengths - */ -dbus_bool_t -_dbus_type_is_fixed (int typecode) -{ - switch (typecode) - { - case DBUS_TYPE_BYTE: - case DBUS_TYPE_BOOLEAN: - case DBUS_TYPE_INT16: - case DBUS_TYPE_UINT16: - case DBUS_TYPE_INT32: - case DBUS_TYPE_UINT32: - case DBUS_TYPE_INT64: - case DBUS_TYPE_UINT64: - case DBUS_TYPE_DOUBLE: - return TRUE; - default: - return FALSE; - } -} - /** * Returns a string describing the given type. * diff --git a/dbus/dbus-marshal-byteswap.c b/dbus/dbus-marshal-byteswap.c index c8ec8942..7571e2fc 100644 --- a/dbus/dbus-marshal-byteswap.c +++ b/dbus/dbus-marshal-byteswap.c @@ -23,6 +23,7 @@ #include "dbus-marshal-byteswap.h" #include "dbus-marshal-basic.h" +#include "dbus-signature.h" /** * @addtogroup DBusMarshal @@ -103,7 +104,7 @@ byteswap_body_helper (DBusTypeReader *reader, p = _DBUS_ALIGN_ADDRESS (p, alignment); - if (_dbus_type_is_fixed (elem_type)) + if (dbus_type_is_fixed (elem_type)) { if (alignment > 1) _dbus_swap_array (p, array_len / alignment, alignment); diff --git a/dbus/dbus-marshal-recursive-util.c b/dbus/dbus-marshal-recursive-util.c index e1b00e58..0d06bc2f 100644 --- a/dbus/dbus-marshal-recursive-util.c +++ b/dbus/dbus-marshal-recursive-util.c @@ -3074,7 +3074,7 @@ array_write_value (TestTypeNode *node, goto oom; if (arrays_write_fixed_in_blocks && - _dbus_type_is_fixed (element_type) && + dbus_type_is_fixed (element_type) && child->klass->write_multi) { if (!node_write_multi (child, block, &sub, seed, n_copies)) @@ -3138,7 +3138,7 @@ array_read_or_set_value (TestTypeNode *node, _dbus_type_reader_recurse (reader, &sub); if (realign_root == NULL && arrays_write_fixed_in_blocks && - _dbus_type_is_fixed (_dbus_type_reader_get_element_type (reader)) && + dbus_type_is_fixed (_dbus_type_reader_get_element_type (reader)) && child->klass->read_multi) { if (!node_read_multi (child, &sub, seed, n_copies)) diff --git a/dbus/dbus-marshal-recursive.c b/dbus/dbus-marshal-recursive.c index 432e6f0b..6fcbd623 100644 --- a/dbus/dbus-marshal-recursive.c +++ b/dbus/dbus-marshal-recursive.c @@ -1018,7 +1018,7 @@ _dbus_type_reader_read_fixed_multi (const DBusTypeReader *reader, reader->type_pos); _dbus_assert (element_type != DBUS_TYPE_INVALID); /* why we don't use get_current_type() */ - _dbus_assert (_dbus_type_is_fixed (element_type)); + _dbus_assert (dbus_type_is_fixed (element_type)); alignment = _dbus_type_get_alignment (element_type); @@ -1464,7 +1464,7 @@ _dbus_type_reader_set_basic (DBusTypeReader *reader, _dbus_assert (dbus_type_is_basic (current_type)); - if (_dbus_type_is_fixed (current_type)) + if (dbus_type_is_fixed (current_type)) { reader_set_basic_fixed_length (reader, current_type, value); return TRUE; @@ -2404,7 +2404,7 @@ _dbus_type_writer_write_basic (DBusTypeWriter *writer, /** * Writes a block of fixed-length basic values, i.e. those that are - * both _dbus_type_is_fixed() and _dbus_type_is_basic(). The block + * both dbus_type_is_fixed() and _dbus_type_is_basic(). The block * must be written inside an array. * * The value parameter should be the address of said array of values, @@ -2423,7 +2423,7 @@ _dbus_type_writer_write_fixed_multi (DBusTypeWriter *writer, int n_elements) { _dbus_assert (writer->container_type == DBUS_TYPE_ARRAY); - _dbus_assert (_dbus_type_is_fixed (element_type)); + _dbus_assert (dbus_type_is_fixed (element_type)); _dbus_assert (writer->type_pos_is_expectation); _dbus_assert (n_elements >= 0); diff --git a/dbus/dbus-message.c b/dbus/dbus-message.c index 672a72b4..b090fab0 100644 --- a/dbus/dbus-message.c +++ b/dbus/dbus-message.c @@ -1270,7 +1270,7 @@ dbus_message_append_args_valist (DBusMessage *message, &array)) goto failed; - if (_dbus_type_is_fixed (element_type)) + if (dbus_type_is_fixed (element_type)) { const DBusBasicValue **value; int n_elements; @@ -1676,6 +1676,9 @@ dbus_message_iter_get_basic (DBusMessageIter *iter, * such as integers, bool, double. The block read will be from the * current position in the array until the end of the array. * + * This function should only be used if #dbus_type_is_fixed returns + * #TRUE for the element type. + * * The value argument should be the address of a location to store the * returned array. So for int32 it should be a "const dbus_int32_t**" * The returned value is by reference and should not be freed. @@ -1693,7 +1696,7 @@ dbus_message_iter_get_fixed_array (DBusMessageIter *iter, _dbus_return_if_fail (_dbus_message_iter_check (real)); _dbus_return_if_fail (value != NULL); - _dbus_return_if_fail (_dbus_type_is_fixed (_dbus_type_reader_get_element_type (&real->u.reader))); + _dbus_return_if_fail (dbus_type_is_fixed (_dbus_type_reader_get_element_type (&real->u.reader))); _dbus_type_reader_read_fixed_multi (&real->u.reader, value, n_elements); @@ -1778,7 +1781,7 @@ _dbus_message_iter_get_args_valist (DBusMessageIter *iter, goto out; } - if (_dbus_type_is_fixed (spec_element_type)) + if (dbus_type_is_fixed (spec_element_type)) { ptr = va_arg (var_args, const DBusBasicValue**); n_elements_p = va_arg (var_args, int*); @@ -2138,7 +2141,7 @@ dbus_message_iter_append_fixed_array (DBusMessageIter *iter, _dbus_return_val_if_fail (_dbus_message_iter_append_check (real), FALSE); _dbus_return_val_if_fail (real->iter_type == DBUS_MESSAGE_ITER_TYPE_WRITER, FALSE); - _dbus_return_val_if_fail (_dbus_type_is_fixed (element_type), FALSE); + _dbus_return_val_if_fail (dbus_type_is_fixed (element_type), FALSE); _dbus_return_val_if_fail (real->u.writer.container_type == DBUS_TYPE_ARRAY, FALSE); _dbus_return_val_if_fail (value != NULL, FALSE); _dbus_return_val_if_fail (n_elements >= 0, FALSE); diff --git a/dbus/dbus-signature.c b/dbus/dbus-signature.c index 698c21ed..7cbae7c2 100644 --- a/dbus/dbus-signature.c +++ b/dbus/dbus-signature.c @@ -262,6 +262,36 @@ dbus_type_is_basic (int typecode) return !(typecode == DBUS_TYPE_INVALID || TYPE_IS_CONTAINER (typecode)); } +/** + * Tells you whether values of this type can change length if you set + * them to some other value. For this purpose, you assume that the + * first byte of the old and new value would be in the same location, + * so alignment padding is not a factor. + * + * This function is useful to determine whether #dbus_message_iter_get_fixed_array + * may be used. + * + * @returns #FALSE if the type can occupy different lengths + */ +dbus_bool_t +dbus_type_is_fixed (int typecode) +{ + switch (typecode) + { + case DBUS_TYPE_BYTE: + case DBUS_TYPE_BOOLEAN: + case DBUS_TYPE_INT16: + case DBUS_TYPE_UINT16: + case DBUS_TYPE_INT32: + case DBUS_TYPE_UINT32: + case DBUS_TYPE_INT64: + case DBUS_TYPE_UINT64: + case DBUS_TYPE_DOUBLE: + return TRUE; + default: + return FALSE; + } +} #ifdef DBUS_BUILD_TESTS diff --git a/dbus/dbus-signature.h b/dbus/dbus-signature.h index 3c50795e..fd64ed11 100644 --- a/dbus/dbus-signature.h +++ b/dbus/dbus-signature.h @@ -65,6 +65,7 @@ dbus_bool_t dbus_signature_validate_single (const char *signatur dbus_bool_t dbus_type_is_basic (int typecode); dbus_bool_t dbus_type_is_container (int typecode); +dbus_bool_t dbus_type_is_fixed (int typecode); DBUS_END_DECLS diff --git a/glib/dbus-binding-tool-glib.c b/glib/dbus-binding-tool-glib.c index 641f07da..5bd413e1 100644 --- a/glib/dbus-binding-tool-glib.c +++ b/glib/dbus-binding-tool-glib.c @@ -140,7 +140,7 @@ compute_marshaller_name (MethodInfo *method, GError **error) g_set_error (error, DBUS_BINDING_TOOL_ERROR, DBUS_BINDING_TOOL_ERROR_UNSUPPORTED_CONVERSION, - _("Unsupported conversion from D-BUS type %d to glib-genmarshal type"), + _("Unsupported conversion from D-BUS type %s to glib-genmarshal type"), type); g_string_free (ret, TRUE); return NULL; @@ -647,42 +647,54 @@ write_formal_parameters (InterfaceInfo *iface, MethodInfo *method, GIOChannel *c } static gboolean -write_args_for_direction (InterfaceInfo *iface, MethodInfo *method, GIOChannel *channel, int direction, GError **error) +write_args_sig_for_direction (InterfaceInfo *iface, MethodInfo *method, GIOChannel *channel, int direction, GError **error) { GSList *args; + WRITE_OR_LOSE ("\""); + for (args = method_info_get_args (method); args; args = args->next) { ArgInfo *arg; - const char *type_str; arg = args->data; if (direction != arg_info_get_direction (arg)) continue; - type_str = dbus_gvalue_binding_type_from_type (arg_info_get_type (arg)); - if (!type_str) - { - g_set_error (error, - DBUS_BINDING_TOOL_ERROR, - DBUS_BINDING_TOOL_ERROR_UNSUPPORTED_CONVERSION, - _("Unsupported conversion from D-BUS type %s"), - arg_info_get_type (arg)); - return FALSE; - } + if (!write_printf_to_iochannel ("%s", channel, error, arg_info_get_type (arg))) + goto io_lose; + } + + WRITE_OR_LOSE ("\", "); + + return TRUE; + io_lose: + return FALSE; +} + +static gboolean +write_args_for_direction (InterfaceInfo *iface, MethodInfo *method, GIOChannel *channel, int direction, GError **error) +{ + GSList *args; + + for (args = method_info_get_args (method); args; args = args->next) + { + ArgInfo *arg; + + arg = args->data; + + if (direction != arg_info_get_direction (arg)) + continue; - switch (direction) { case ARG_IN: - if (!write_printf_to_iochannel (" %s, &IN_%s,\n", channel, error, - type_str, arg_info_get_name (arg))) + if (!write_printf_to_iochannel ("IN_%s, ", channel, error, arg_info_get_name (arg))) goto io_lose; break; case ARG_OUT: - if (!write_printf_to_iochannel (" %s, OUT_%s,\n", channel, error, - type_str, arg_info_get_name (arg))) + if (!write_printf_to_iochannel ("OUT_%s, ", channel, error, arg_info_get_name (arg))) goto io_lose; break; case ARG_INVALID: @@ -746,7 +758,7 @@ generate_client_glue (BaseInfo *base, DBusBindingToolCData *data, GError **error method_name = compute_client_method_name (interface, method); - WRITE_OR_LOSE ("static gboolean\n"); + WRITE_OR_LOSE ("static\n#ifdef G_HAVE_INLINE\ninline\n#endif\ngboolean\n"); if (!write_printf_to_iochannel ("%s (DBusGProxy *proxy", channel, error, method_name)) goto io_lose; @@ -758,29 +770,26 @@ generate_client_glue (BaseInfo *base, DBusBindingToolCData *data, GError **error WRITE_OR_LOSE (", GError **error)\n\n"); WRITE_OR_LOSE ("{\n"); - WRITE_OR_LOSE (" gboolean ret;\n\n"); - WRITE_OR_LOSE (" DBusGPendingCall *call;\n\n"); - if (!write_printf_to_iochannel (" call = dbus_g_proxy_begin_call (proxy, \"%s\",\n", - channel, error, + if (!write_printf_to_iochannel (" return dbus_g_proxy_invoke (proxy, \"%s\", ", channel, error, method_info_get_name (method))) goto io_lose; - if (!write_args_for_direction (interface, method, channel, ARG_IN, error)) + if (!write_args_sig_for_direction (interface, method, channel, ARG_IN, error)) goto io_lose; - WRITE_OR_LOSE (" DBUS_TYPE_INVALID);\n"); - WRITE_OR_LOSE (" ret = dbus_g_proxy_end_call (proxy, call, error,\n"); - - if (!write_args_for_direction (interface, method, channel, ARG_OUT, error)) + if (!write_args_sig_for_direction (interface, method, channel, ARG_OUT, error)) goto io_lose; - WRITE_OR_LOSE (" DBUS_TYPE_INVALID);\n"); + WRITE_OR_LOSE ("error, "); - WRITE_OR_LOSE (" dbus_g_pending_call_unref (call);\n"); - WRITE_OR_LOSE (" return ret;\n"); + if (!write_args_for_direction (interface, method, channel, ARG_IN, error)) + goto io_lose; + + if (!write_args_for_direction (interface, method, channel, ARG_OUT, error)) + goto io_lose; - WRITE_OR_LOSE ("}\n\n"); + WRITE_OR_LOSE ("NULL);\n}\n\n"); } } return TRUE; diff --git a/glib/dbus-gproxy.c b/glib/dbus-gproxy.c index 65f14e12..b5e977a4 100644 --- a/glib/dbus-gproxy.c +++ b/glib/dbus-gproxy.c @@ -22,11 +22,14 @@ */ #include #include +#include #include "dbus-gutils.h" #include "dbus-gmarshal.h" #include "dbus-gvalue.h" #include "dbus-gobject.h" #include +#include +#include /** * @addtogroup DBusGLibInternals @@ -1396,6 +1399,208 @@ dbus_g_proxy_end_call (DBusGProxy *proxy, return FALSE; } +/** + * Function for invoking a method and receiving reply values. + * Normally this is not used directly - calls to it are generated + * from client-side wrappers (see dbus-binding-tool). + * + * This function takes two type signatures, one for method arguments, + * and one for return values. The remaining arguments after the + * error parameter should be values of the input arguments, + * followed by pointer values to storage for return values. + * + * @param proxy a proxy for a remote interface + * @param method method to invoke + * @param insig signature of input values + * @param outsig signature of output values + * @param error return location for an error + * @returns #FALSE if an error is set, TRUE otherwise + */ +gboolean +dbus_g_proxy_invoke (DBusGProxy *proxy, + const char *method, + const char *insig, + const char *outsig, + GError **error, + ...) +{ + DBusPendingCall *pending; + DBusMessage *message; + DBusMessage *reply; + va_list args; + va_list args_unwind; + int n_retvals_processed; + DBusMessageIter msgiter; + DBusSignatureIter sigiter; + int expected_type; + gboolean ret; + DBusError derror; + + g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), FALSE); + g_return_val_if_fail (!DBUS_G_PROXY_DESTROYED (proxy), FALSE); + + va_start (args, error); + /* Keep around a copy of output arguments so we + * can free on error. */ + G_VA_COPY (args_unwind, args); + + ret = FALSE; + pending = NULL; + reply = NULL; + n_retvals_processed = 0; + message = dbus_message_new_method_call (proxy->name, + proxy->path, + proxy->interface, + method); + if (message == NULL) + goto oom; + + dbus_signature_iter_init (&sigiter, insig); + dbus_message_iter_init_append (message, &msgiter); + while ((expected_type = dbus_signature_iter_get_current_type (&sigiter)) != DBUS_TYPE_INVALID) + { + GValue gvalue = {0, }; + char *collect_err; + + if (!dbus_gvalue_init (expected_type, &gvalue)) + { + g_set_error (error, DBUS_GERROR, + DBUS_GERROR_INVALID_ARGS, + _("Unsupported type '%c'"), expected_type); + goto out; + } + + G_VALUE_COLLECT (&gvalue, args, G_VALUE_NOCOPY_CONTENTS, &collect_err); + + if (collect_err) + { + g_set_error (error, DBUS_GERROR, + DBUS_GERROR_INVALID_ARGS, + collect_err); + goto out; + } + + /* Anything we can init must be marshallable */ + if (!dbus_gvalue_marshal (&msgiter, &gvalue)) + g_assert_not_reached (); + g_value_unset (&gvalue); + + dbus_signature_iter_next (&sigiter); + } + + if (!dbus_connection_send_with_reply (proxy->manager->connection, + message, + &pending, + -1)) + goto oom; + + dbus_pending_call_block (pending); + reply = dbus_pending_call_steal_reply (pending); + + g_assert (reply != NULL); + + dbus_error_init (&derror); + + switch (dbus_message_get_type (reply)) + { + case DBUS_MESSAGE_TYPE_METHOD_RETURN: + + dbus_signature_iter_init (&sigiter, outsig); + dbus_message_iter_init (reply, &msgiter); + while ((expected_type = dbus_signature_iter_get_current_type (&sigiter)) != DBUS_TYPE_INVALID) + { + int arg_type; + gpointer *value_ret; + GValue gvalue = { 0, }; + + value_ret = va_arg (args, gpointer *); + + arg_type = dbus_message_iter_get_arg_type (&msgiter); + if (expected_type != arg_type) + { + if (arg_type == DBUS_TYPE_INVALID) + g_set_error (error, DBUS_GERROR, + DBUS_GERROR_INVALID_ARGS, + _("Too few arguments in reply")); + else + g_set_error (error, DBUS_GERROR, + DBUS_GERROR_INVALID_ARGS, + _("Reply argument was \"%c\", expected \"%c\""), + arg_type, expected_type); + goto out; + } + + if (!dbus_gvalue_demarshal (&msgiter, &gvalue)) + { + g_set_error (error, + DBUS_GERROR, + DBUS_GERROR_INVALID_ARGS, + _("Couldn't convert argument type \"%c\""), expected_type); + goto out; + } + /* Anything that can be demarshaled must be storable */ + if (!dbus_gvalue_store (&gvalue, value_ret)) + g_assert_not_reached (); + g_value_unset (&gvalue); + + n_retvals_processed++; + dbus_signature_iter_next (&sigiter); + dbus_message_iter_next (&msgiter); + } + if (dbus_message_iter_get_arg_type (&msgiter) != DBUS_TYPE_INVALID) + { + g_set_error (error, DBUS_GERROR, + DBUS_GERROR_INVALID_ARGS, + _("Too many arguments")); + goto out; + } + break; + case DBUS_MESSAGE_TYPE_ERROR: + dbus_set_error_from_message (&derror, reply); + dbus_set_g_error (error, &derror); + dbus_error_free (&derror); + goto out; + break; + default: + dbus_set_error (&derror, DBUS_ERROR_FAILED, + "Reply was neither a method return nor an exception"); + dbus_set_g_error (error, &derror); + dbus_error_free (&derror); + goto out; + break; + } + + ret = TRUE; + out: + va_end (args); + + if (ret == FALSE) + { + int i; + for (i = 0; i < n_retvals_processed; i++) + { + gpointer retval; + + retval = va_arg (args_unwind, gpointer); + + g_free (retval); + } + } + va_end (args_unwind); + + if (pending) + dbus_pending_call_unref (pending); + if (message) + dbus_message_unref (message); + if (reply) + dbus_message_unref (reply); + return ret; + oom: + g_error ("Out of memory"); + ret = FALSE; + goto out; +} + /** * Sends a method call message as with dbus_g_proxy_begin_call(), but * does not ask for a reply or allow you to receive one. diff --git a/glib/dbus-gvalue.c b/glib/dbus-gvalue.c index bcda9259..eae5a458 100644 --- a/glib/dbus-gvalue.c +++ b/glib/dbus-gvalue.c @@ -26,50 +26,51 @@ #include "dbus/dbus-signature.h" /* This is slightly evil, we don't use g_value_set_foo() functions */ -#define MAP_BASIC_INIT(d_t, g_t) \ - case DBUS_TYPE_##d_t: \ - g_value_init (value, G_TYPE_##g_t); \ - break +#define MAP_BASIC(d_t, g_t) \ + case DBUS_TYPE_##d_t: \ + return G_TYPE_##g_t; -gboolean -dbus_gvalue_init (int type, - GValue *value) +static GType +dbus_dbus_type_to_gtype (int type) { - gboolean can_convert; - - can_convert = TRUE; - switch (type) { - MAP_BASIC_INIT (BOOLEAN, BOOLEAN); - MAP_BASIC_INIT (BYTE, UCHAR); - MAP_BASIC_INIT (INT32, INT); - MAP_BASIC_INIT (UINT32, UINT); - MAP_BASIC_INIT (INT64, INT64); - MAP_BASIC_INIT (UINT64, UINT64); - MAP_BASIC_INIT (DOUBLE, DOUBLE); - + MAP_BASIC (BOOLEAN, BOOLEAN); + MAP_BASIC (BYTE, UCHAR); + MAP_BASIC (INT32, INT); + MAP_BASIC (UINT32, UINT); + MAP_BASIC (INT64, INT64); + MAP_BASIC (UINT64, UINT64); + MAP_BASIC (DOUBLE, DOUBLE); case DBUS_TYPE_INT16: - g_value_init (value, G_TYPE_INT); - break; + return G_TYPE_INT; case DBUS_TYPE_UINT16: - g_value_init (value, G_TYPE_UINT); - break; - + return G_TYPE_UINT; case DBUS_TYPE_STRING: case DBUS_TYPE_OBJECT_PATH: case DBUS_TYPE_SIGNATURE: - g_value_init (value, G_TYPE_STRING); - break; - + return G_TYPE_STRING; case DBUS_TYPE_STRUCT: case DBUS_TYPE_ARRAY: case DBUS_TYPE_VARIANT: default: - can_convert = FALSE; + return G_TYPE_INVALID; } -#undef MAP_BASIC_INIT - return can_convert; +} + +#undef MAP_BASIC + +gboolean +dbus_gvalue_init (int type, + GValue *value) +{ + GType gtype; + + gtype = dbus_dbus_type_to_gtype (type); + if (gtype == G_TYPE_INVALID) + return FALSE; + g_value_init (value, gtype); + return TRUE; } /* FIXME - broken for containers @@ -124,43 +125,6 @@ dbus_gvalue_genmarshal_name_from_type (const char *signature) return NULL; } -const char * -dbus_gvalue_binding_type_from_type (const char *signature) -{ - int type; - - type = base_type_from_signature (signature); - -#define STRINGIFY(x) \ - case x: \ - return (#x) - - switch (type) - { - STRINGIFY(DBUS_TYPE_BOOLEAN); - STRINGIFY(DBUS_TYPE_BYTE); - STRINGIFY(DBUS_TYPE_INT32); - STRINGIFY(DBUS_TYPE_UINT32); - STRINGIFY(DBUS_TYPE_INT64); - STRINGIFY(DBUS_TYPE_UINT64); - STRINGIFY(DBUS_TYPE_DOUBLE); - case DBUS_TYPE_INT16: - return "DBUS_TYPE_INT32"; - case DBUS_TYPE_UINT16: - return "DBUS_TYPE_UINT32"; - STRINGIFY(DBUS_TYPE_STRING); - STRINGIFY(DBUS_TYPE_OBJECT_PATH); - STRINGIFY(DBUS_TYPE_SIGNATURE); - - case DBUS_TYPE_STRUCT: - case DBUS_TYPE_ARRAY: - case DBUS_TYPE_VARIANT: - return NULL; - } -#undef STRINGIFY - return NULL; -} - const char * dbus_gvalue_ctype_from_type (const char *signature, gboolean in) { @@ -249,69 +213,96 @@ dbus_gtype_to_dbus_type (GType type) gboolean dbus_gvalue_demarshal (DBusMessageIter *iter, GValue *value) { - gboolean can_convert = TRUE; - g_assert (sizeof (dbus_bool_t) == sizeof (value->data[0].v_int)); dbus_gvalue_init (dbus_message_iter_get_arg_type (iter), value); -/* This is slightly evil, we don't use g_value_set_foo() functions */ -#define MAP_BASIC(d_t, g_t) \ - case DBUS_TYPE_##d_t: \ - dbus_message_iter_get_basic (iter, &value->data[0]); \ - break - switch (dbus_message_iter_get_arg_type (iter)) { - MAP_BASIC (BOOLEAN, BOOLEAN); - MAP_BASIC (BYTE, UCHAR); - MAP_BASIC (INT32, INT); - MAP_BASIC (UINT32, UINT); - MAP_BASIC (INT64, INT64); - MAP_BASIC (UINT64, UINT64); - MAP_BASIC (DOUBLE, DOUBLE); - + case DBUS_TYPE_BOOLEAN: + { + dbus_bool_t bool; + dbus_message_iter_get_basic (iter, &bool); + g_value_set_boolean (value, bool); + return TRUE; + } + case DBUS_TYPE_BYTE: + { + unsigned char byte; + dbus_message_iter_get_basic (iter, &byte); + g_value_set_uchar (value, byte); + return TRUE; + } + case DBUS_TYPE_INT32: + { + dbus_int32_t intval; + dbus_message_iter_get_basic (iter, &intval); + g_value_set_int (value, intval); + return TRUE; + } + case DBUS_TYPE_UINT32: + { + dbus_uint32_t intval; + dbus_message_iter_get_basic (iter, &intval); + g_value_set_uint (value, intval); + return TRUE; + } + case DBUS_TYPE_INT64: + { + dbus_int64_t intval; + dbus_message_iter_get_basic (iter, &intval); + g_value_set_int64 (value, intval); + return TRUE; + } + case DBUS_TYPE_UINT64: + { + dbus_uint64_t intval; + dbus_message_iter_get_basic (iter, &intval); + g_value_set_uint64 (value, intval); + return TRUE; + } + case DBUS_TYPE_DOUBLE: + { + double dval; + dbus_message_iter_get_basic (iter, &dval); + g_value_set_double (value, dval); + return TRUE; + } case DBUS_TYPE_INT16: { dbus_int16_t v; dbus_message_iter_get_basic (iter, &v); g_value_set_int (value, v); + return TRUE; } - break; case DBUS_TYPE_UINT16: { dbus_uint16_t v; dbus_message_iter_get_basic (iter, &v); g_value_set_uint (value, v); + return TRUE; } - break; - case DBUS_TYPE_STRING: case DBUS_TYPE_OBJECT_PATH: case DBUS_TYPE_SIGNATURE: { const char *s; - dbus_message_iter_get_basic (iter, &s); g_value_set_string (value, s); + return TRUE; } - break; - case DBUS_TYPE_STRUCT: case DBUS_TYPE_ARRAY: case DBUS_TYPE_VARIANT: default: - can_convert = FALSE; + return FALSE; } -#undef MAP_BASIC - return can_convert; } gboolean dbus_gvalue_marshal (DBusMessageIter *iter, GValue *value) { - gboolean can_convert = TRUE; - GType value_type = G_VALUE_TYPE (value); + GType value_type; value_type = G_VALUE_TYPE (value); @@ -325,7 +316,7 @@ dbus_gvalue_marshal (DBusMessageIter *iter, GValue *value) &b)) goto nomem; } - break; + return TRUE; case G_TYPE_UCHAR: { unsigned char b = g_value_get_uchar (value); @@ -334,7 +325,7 @@ dbus_gvalue_marshal (DBusMessageIter *iter, GValue *value) &b)) goto nomem; } - break; + return TRUE; case G_TYPE_BOOLEAN: { dbus_bool_t b = g_value_get_boolean (value); @@ -343,7 +334,7 @@ dbus_gvalue_marshal (DBusMessageIter *iter, GValue *value) &b)) goto nomem; } - break; + return TRUE; case G_TYPE_INT: { dbus_int32_t v = g_value_get_int (value); @@ -352,7 +343,7 @@ dbus_gvalue_marshal (DBusMessageIter *iter, GValue *value) &v)) goto nomem; } - break; + return TRUE; case G_TYPE_UINT: { dbus_uint32_t v = g_value_get_uint (value); @@ -361,7 +352,7 @@ dbus_gvalue_marshal (DBusMessageIter *iter, GValue *value) &v)) goto nomem; } - break; + return TRUE; /* long gets cut to 32 bits so the remote API is consistent * on all architectures */ @@ -373,7 +364,7 @@ dbus_gvalue_marshal (DBusMessageIter *iter, GValue *value) &v)) goto nomem; } - break; + return TRUE; case G_TYPE_ULONG: { dbus_uint32_t v = g_value_get_ulong (value); @@ -382,7 +373,7 @@ dbus_gvalue_marshal (DBusMessageIter *iter, GValue *value) &v)) goto nomem; } - break; + return TRUE; case G_TYPE_INT64: { gint64 v = g_value_get_int64 (value); @@ -391,7 +382,7 @@ dbus_gvalue_marshal (DBusMessageIter *iter, GValue *value) &v)) goto nomem; } - break; + return TRUE; case G_TYPE_UINT64: { guint64 v = g_value_get_uint64 (value); @@ -400,7 +391,7 @@ dbus_gvalue_marshal (DBusMessageIter *iter, GValue *value) &v)) goto nomem; } - break; + return TRUE; case G_TYPE_FLOAT: { double v = g_value_get_float (value); @@ -410,7 +401,7 @@ dbus_gvalue_marshal (DBusMessageIter *iter, GValue *value) &v)) goto nomem; } - break; + return TRUE; case G_TYPE_DOUBLE: { double v = g_value_get_double (value); @@ -420,7 +411,7 @@ dbus_gvalue_marshal (DBusMessageIter *iter, GValue *value) &v)) goto nomem; } - break; + return TRUE; case G_TYPE_STRING: /* FIXME, the GValue string may not be valid UTF-8 */ { @@ -430,19 +421,62 @@ dbus_gvalue_marshal (DBusMessageIter *iter, GValue *value) &v)) goto nomem; } - break; + return TRUE; default: /* FIXME: we need to define custom boxed types for arrays etc. so we can map them transparently / pleasantly */ - can_convert = FALSE; - break; + return FALSE; } - return can_convert; - nomem: g_error ("no memory"); return FALSE; } +/* FIXME is there a better way to do this? */ +gboolean +dbus_gvalue_store (GValue *value, + gpointer storage) +{ + switch (G_VALUE_TYPE (value)) + { + case G_TYPE_CHAR: + *((gchar *) storage) = g_value_get_char (value); + return TRUE; + case G_TYPE_UCHAR: + *((guchar *) storage) = g_value_get_uchar (value); + return TRUE; + case G_TYPE_BOOLEAN: + *((gboolean *) storage) = g_value_get_boolean (value); + return TRUE; + case G_TYPE_LONG: + *((glong *) storage) = g_value_get_long (value); + return TRUE; + case G_TYPE_ULONG: + *((gulong *) storage) = g_value_get_ulong (value); + return TRUE; + case G_TYPE_INT: + *((gint *) storage) = g_value_get_int (value); + return TRUE; + case G_TYPE_UINT: + *((guint *) storage) = g_value_get_uint (value); + return TRUE; + case G_TYPE_INT64: + *((gint64 *) storage) = g_value_get_int64 (value); + return TRUE; + case G_TYPE_UINT64: + *((guint64 *) storage) = g_value_get_uint64 (value); + return TRUE; + case G_TYPE_FLOAT: + case G_TYPE_DOUBLE: + *((gdouble *) storage) = g_value_get_double (value); + return TRUE; + case G_TYPE_STRING: + /* FIXME - should optimize by not duping string twice */ + *((gchar **) storage) = g_value_dup_string (value); + return TRUE; + default: + return FALSE; + } +} diff --git a/glib/dbus-gvalue.h b/glib/dbus-gvalue.h index dc1cf323..4caa6880 100644 --- a/glib/dbus-gvalue.h +++ b/glib/dbus-gvalue.h @@ -24,8 +24,6 @@ const char * dbus_gvalue_genmarshal_name_from_type (const char *type); const char * dbus_gvalue_ctype_from_type (const char *type, gboolean in); -const char * dbus_gvalue_binding_type_from_type (const char *type); - const char * dbus_gtype_to_dbus_type (GType type); gboolean dbus_gvalue_init (int type, @@ -36,6 +34,8 @@ gboolean dbus_gvalue_demarshal (DBusMessageIter *iter, gboolean dbus_gvalue_marshal (DBusMessageIter *iter, GValue *value); +gboolean dbus_gvalue_store (GValue *value, + gpointer storage); G_END_DECLS diff --git a/test/glib/Makefile.am b/test/glib/Makefile.am index 58f4d778..b0b8361a 100644 --- a/test/glib/Makefile.am +++ b/test/glib/Makefile.am @@ -44,10 +44,10 @@ test_service_glib_SOURCES= \ BUILT_SOURCES = test-service-glib-glue.h test-service-glib-bindings.h -test-service-glib-glue.h: test-service-glib.xml +test-service-glib-glue.h: test-service-glib.xml $(top_builddir)/glib/dbus-binding-tool $(top_builddir)/glib/dbus-binding-tool --mode=glib-server --output=test-service-glib-glue.h test-service-glib.xml -test-service-glib-bindings.h: test-service-glib.xml +test-service-glib-bindings.h: test-service-glib.xml $(top_builddir)/glib/dbus-binding-tool $(top_builddir)/glib/dbus-binding-tool --mode=glib-client --output=test-service-glib-bindings.h test-service-glib.xml CLEANFILES = test-service-glib-glue.h test-service-glib-bindings.h diff --git a/test/glib/test-dbus-glib.c b/test/glib/test-dbus-glib.c index 0c2078e5..b0dc9efc 100644 --- a/test/glib/test-dbus-glib.c +++ b/test/glib/test-dbus-glib.c @@ -267,7 +267,7 @@ main (int argc, char **argv) lose ("ThrowError call unexpectedly succeeded!"); g_print ("ThrowError failed (as expected) returned error: %s\n", error->message); - g_error_free (error); + g_clear_error (&error); v_STRING = "foobar"; call = dbus_g_proxy_begin_call (proxy, "Uppercase", @@ -313,12 +313,13 @@ main (int argc, char **argv) lose ("(wrapped) ThrowError call unexpectedly succeeded!"); g_print ("(wrapped) ThrowError failed (as expected) returned error: %s\n", error->message); - g_error_free (error); + g_clear_error (&error); if (!org_freedesktop_DBus_Tests_MyObject_uppercase (proxy, "foobar", &v_STRING_2, &error)) lose_gerror ("Failed to complete (wrapped) Uppercase call", error); if (strcmp ("FOOBAR", v_STRING_2) != 0) lose ("(wrapped) Uppercase call returned unexpected string %s", v_STRING_2); + g_free (v_STRING_2); if (!org_freedesktop_DBus_Tests_MyObject_many_args (proxy, 26, "bazwhee", G_PI, &v_DOUBLE_2, &v_STRING_2, &error)) @@ -330,6 +331,7 @@ main (int argc, char **argv) if (strcmp ("BAZWHEE", v_STRING_2) != 0) lose ("(wrapped) ManyArgs call returned unexpected string %s", v_STRING_2); + g_free (v_STRING_2); g_object_unref (G_OBJECT (proxy)); -- cgit