From beb9cd2eb219e04f9872c6a4dd743d5d1c36b4b1 Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Mon, 13 Jun 2005 03:01:30 +0000 Subject: 2005-06-12 Colin Walters Async signals and various bugfixes and testing by Ross Burton . * glib/dbus-gvalue.h: (struct DBusBasicGValue): Delete. (dbus_gvalue_genmarshal_name_from_type) (dbus_gvalue_ctype_from_type): Moved to dbus-binding-tool-glib.c. (dbus_gtype_to_dbus_type): Renamed to dbus_gtype_from_signature. (dbus_g_value_types_init, dbus_gtype_from_signature) (dbus_gtype_from_signature_iter, dbus_gtype_to_signature) (dbus_gtypes_from_arg_signature): New function prototypes. (dbus_gvalue_demarshal): Take context and error arguments. (dbus_gvalue_demarshal_variant): New function. (dbus_gvalue_demarshal_message): New function. (dbus_gvalue_store): Delete. * glib/dbus-gvalue.c: File has been almost entirely rewritten; now we special-case more types such as DBUS_TYPE_SIGNATURE, handle arrays and hash tables correctly, etc. Full support for recursive values is not yet complete. * glib/dbus-gproxy.c (dbus_g_proxy_class_init): Change last argument of signal to G_TYPE_POINTER since we now pass a structure. (lookup_g_marshaller): Delete in favor of _dbus_gobject_lookup_marshaller. (marshal_dbus_message_to_g_marshaller): Use _dbus_gobject_lookup_marshaller and dbus_gvalue_demarshal_message to handle remote signal callbacks. (dbus_g_proxy_new_from_proxy): New function; creates a new DBusGProxy by copying an existing one. (dbus_g_proxy_get_interface, dbus_g_proxy_set_interface) (dbus_g_proxy_get_path): New functions. (dbus_g_proxy_marshal_args_to_message): New function; factored out of existing code. (DBUS_G_VALUE_ARRAY_COLLECT_ALL): Collect all arguments from a varargs array. (dbus_g_proxy_begin_call_internal): New function. (dbus_g_proxy_end_call_internal): New function. (dbus_g_proxy_begin_call): Take GTypes instead of DBus types as arguments; simply invoke dbus_g_proxy_begin_call_internal after collecting args into value array. (dbus_g_proxy_end_call): Take GTypes instead of DBus types; invoke dbus_g_proxy_end_call_internal. (dbus_g_proxy_invoke): Simply invoke begin_call_interanl and end_call_internal. (dbus_g_proxy_call_no_reply): Take GTypes instead of DBus types. (array_free_all): New function. (dbus_g_proxy_add_signal): Take GTypes. * glib/dbus-gobject.h: (_dbus_glib_marshal_dbus_message_to_gvalue_array): Delete. (_dbus_gobject_get_path, _dbus_gobject_lookup_marshaller): Prototype. * glib/dbus-gobject.c: Add a global marshal_table hash which stores mappings from type signatures to marshallers. Change lots of invocations of dbus_gtype_to_dbus_type to dbus_gtype_to_signature. (_dbus_glib_marshal_dbus_message_to_gvalue_array): Delete. (introspect_signals): Fix test for query.return_type. (set_object_property): Update invocation of dbus_gvalue_demarshal. (invoke_object_method): Many changes. Handle asynchronous invocations. Convert arguments with dbus_gvalue_demarshal_message. Handle errors. Use DBusSignatureIter instead of strlen on args. Handle all arguments generically. Special-case variants. (dbus_g_method_return, dbus_g_method_return_error): New function. (DBusGSignalClosure): New structure, closes over signal information. (dbus_g_signal_closure_new): New function. (dbus_g_signal_closure_finalize): New function. (signal_emitter_marshaller): New function; is special marshaller which emits signals on bus. (export_signals): New function; introspects object signals and connects to them. (dbus_g_object_type_install_info): Take GType instead of GObjectClass. (dbus_g_connection_register_g_object): Invoke export_signals. (dbus_g_connection_lookup_g_object): New function. (DBusGFuncSignature) New structure; used for mapping type signatures to marshallers. (funcsig_hash): New function; hashes DBusGFuncSignature. (funcsig_equal): New function; compares DBusGFuncSignature. (_dbus_gobject_lookup_marshaller): New function. (dbus_g_object_register_marshaller): New function; used to register a marshaller at runtime for a particular signature. * glib/dbus-gmain.c (_dbus_gmain_test): Add various tests. * glib/dbus-binding-tool-glib.h: Add DBUS_GLIB_ANNOTATION_ASYNC which notes a server method implementation should be asynchronous. * glib/dbus-binding-tool-glib.c (dbus_binding_tool_output_glib_server): Call dbus_g_value_types_init. (write_formal_parameters): Use dbus_gtype_from_signature. Handle variants specially. (dbus_g_type_get_lookup_function): Turn GType into an invocation of a lookup function. (write_args_for_direction): Use dbus_g_type_get_lookup_function. (write_untyped_out_args): New method; write output arguments. (write_formal_declarations_for_direction): Function for writing prototypes. (write_formal_parameters_for_direction): Function for writing implementations. (write_typed_args_for_direction): Function for writing arguments prefixed with GTypes. (write_async_method_client): Write out async version of method. * glib/dbus-binding-tool-glib.c: Include dbus-gvalue-utils.h. (dbus_g_type_get_marshal_name): Move mapping from GType to marshal name into here. (dbus_g_type_get_c_name): Move into here. (compute_marshaller): Convert signature to type with dbus_gtype_from_signature, use dbus_g_type_get_marshal_name. (compute_marshaller_name): Ditto. (compute_marshaller): Handle async signal annotations. (gather_marshallers): Return if we don't have a known prefix. (generate_glue): Collect introspection blob here, and write all of the blob at the end. This allows an object with multiple interfaces to work. Mark async methods in introspection blob. * glib/Makefile.am (libdbus_glib_1_la_SOURCES): Add dbus-gtype-specialized.c, dbus-gtype-specialized.h, dbus-gvalue-utils.h, dbus-gvalue-utils.c. * dbus/dbus-glib.h: Don't include dbus-protocol.h; this avoids people accidentally using DBUS_TYPE_* which should not be necessary anymore. Do include dbus-gtype-specialized.h, which are utilities for GLib container types. Add various #defines for types such as DBUS_TYPE_G_BOOLEAN_ARRAY. (DBusGValueIterator, DBusGValue): Define, not fully used yet. (dbus_g_value_get_g_type): Type for recursive value. (dbus_g_value_open, dbus_g_value_iterator_get_value) (dbus_g_value_iterator_get_values, dbus_g_value_iterator_recurse) (dbus_g_value_free): Prototypes. (dbus_g_object_register_marshaller, dbus_g_proxy_new_from_proxy): Prototype. (dbus_g_proxy_set_interface): Prototype. (dbus_g_proxy_begin_call, dbus_g_proxy_end_call) (dbus_g_proxy_call_no_reply): Take GLib types instead of DBus types. (dbus_g_proxy_get_path, dbus_g_proxy_get_interface): Accessors. (DBusGAsyncData, DBusGMethodInvocation): Structures for doing async invocations. (dbus_g_method_return, dbus_g_method_return_error): Prototypes. * doc/dbus-tutorial.xml: Update GLib section. * tools/dbus-viewer.c (load_child_nodes): Update for new invocation type of dbus_g_proxy_end_call. (load_from_service_thread_func): Ditto. * tools/print-introspect.c (main): Ditto. * tools/dbus-names-model.c (have_names_notify) (names_model_reload, names_model_set_connection) Use GTypes. * python/Makefile.am (INCLUDES): Define DBUS_COMPILATION, needed since Python bindings use GLib bindings. * test/glib/Makefile.am (INCLUDES): Define DBUS_COMPILATION. Add --prefix argument. * tools/Makefile.am: Define DBUS_COMPILATION. Remove unneeded --ignore-unsupported arg. * test/glib/test-service-glib.c: * test/glib/test-service-glib.xml: * test/glib/test-dbus-glib.c: Add many more tests. --- glib/dbus-gvalue.c | 1508 +++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 1319 insertions(+), 189 deletions(-) (limited to 'glib/dbus-gvalue.c') diff --git a/glib/dbus-gvalue.c b/glib/dbus-gvalue.c index eae5a458..8506330d 100644 --- a/glib/dbus-gvalue.c +++ b/glib/dbus-gvalue.c @@ -22,202 +22,680 @@ * */ -#include +#include "dbus-gvalue.h" +#include "dbus-gobject.h" +#include "dbus-gvalue-utils.h" +#include "dbus/dbus-glib.h" +#include +#include +#include #include "dbus/dbus-signature.h" -/* This is slightly evil, we don't use g_value_set_foo() functions */ +static gboolean demarshal_static_variant (DBusGValueMarshalCtx *context, + DBusMessageIter *iter, + GValue *value, + GError **error); +static gpointer dbus_g_value_copy (gpointer value); + + +struct DBusGValue +{ + enum { + DBUS_G_VALUE_TYPE_TOPLEVEL, + DBUS_G_VALUE_TYPE_ITERATOR + } type; + union { + struct { + DBusGConnection *connection; + DBusGProxy *proxy; + DBusMessage *message; + char *signature; + } toplevel; + struct { + DBusGValue *toplevel; + DBusMessageIter iterator; + } recurse; + } value; +}; + +static gboolean marshal_basic (DBusMessageIter *iter, + GValue *value); +static gboolean demarshal_basic (DBusGValueMarshalCtx *context, + DBusMessageIter *iter, + GValue *value, + GError **error); +static gboolean marshal_strv (DBusMessageIter *iter, + GValue *value); +static gboolean demarshal_strv (DBusGValueMarshalCtx *context, + DBusMessageIter *iter, + GValue *value, + GError **error); +static gboolean marshal_variant (DBusMessageIter *iter, + GValue *value); +static gboolean demarshal_variant (DBusGValueMarshalCtx *context, + DBusMessageIter *iter, + GValue *value, + GError **error); +static gboolean marshal_garray_basic (DBusMessageIter *iter, + GValue *value); +static gboolean demarshal_garray_basic (DBusGValueMarshalCtx *context, + DBusMessageIter *iter, + GValue *value, + GError **error); +static gboolean marshal_proxy (DBusMessageIter *iter, + GValue *value); +static gboolean demarshal_proxy (DBusGValueMarshalCtx *context, + DBusMessageIter *iter, + GValue *value, + GError **error); +static gboolean marshal_object (DBusMessageIter *iter, + GValue *value); +static gboolean demarshal_object (DBusGValueMarshalCtx *context, + DBusMessageIter *iter, + GValue *value, + GError **error); +static gboolean marshal_proxy_array (DBusMessageIter *iter, + GValue *value); +static gboolean demarshal_proxy_array (DBusGValueMarshalCtx *context, + DBusMessageIter *iter, + GValue *value, + GError **error); +static gboolean marshal_map (DBusMessageIter *iter, + GValue *value); +static gboolean demarshal_ghashtable (DBusGValueMarshalCtx *context, + DBusMessageIter *iter, + GValue *value, + GError **error); + +typedef gboolean (*DBusGValueMarshalFunc) (DBusMessageIter *iter, + GValue *value); +typedef gboolean (*DBusGValueDemarshalFunc) (DBusGValueMarshalCtx *context, + DBusMessageIter *iter, + GValue *value, + GError **error); + +typedef struct { + DBusGValueMarshalFunc marshaller; + DBusGValueDemarshalFunc demarshaller; +} DBusGTypeMarshalVtable; + +typedef struct { + const char *sig; + const DBusGTypeMarshalVtable *vtable; +} DBusGTypeMarshalData; + +static GQuark +dbus_g_type_metadata_data_quark () +{ + static GQuark quark; + if (!quark) + quark = g_quark_from_static_string ("DBusGTypeMetaData"); + + return quark; +} + +static void +set_type_metadata (GType type, const DBusGTypeMarshalData *data) +{ + g_type_set_qdata (type, dbus_g_type_metadata_data_quark (), (gpointer) data); +} + #define MAP_BASIC(d_t, g_t) \ case DBUS_TYPE_##d_t: \ return G_TYPE_##g_t; - static GType -dbus_dbus_type_to_gtype (int type) +typecode_to_gtype (int type) { switch (type) { MAP_BASIC (BOOLEAN, BOOLEAN); MAP_BASIC (BYTE, UCHAR); + MAP_BASIC (INT16, INT); MAP_BASIC (INT32, INT); + MAP_BASIC (UINT16, UINT); MAP_BASIC (UINT32, UINT); MAP_BASIC (INT64, INT64); MAP_BASIC (UINT64, UINT64); MAP_BASIC (DOUBLE, DOUBLE); - case DBUS_TYPE_INT16: - return G_TYPE_INT; - case DBUS_TYPE_UINT16: - return G_TYPE_UINT; - case DBUS_TYPE_STRING: - case DBUS_TYPE_OBJECT_PATH: - case DBUS_TYPE_SIGNATURE: - return G_TYPE_STRING; - case DBUS_TYPE_STRUCT: - case DBUS_TYPE_ARRAY: - case DBUS_TYPE_VARIANT: + MAP_BASIC (STRING, STRING); default: return G_TYPE_INVALID; } } - #undef MAP_BASIC -gboolean -dbus_gvalue_init (int type, - GValue *value) +static gboolean +dbus_typecode_maps_to_basic (int typecode) +{ + return typecode_to_gtype (typecode) != G_TYPE_INVALID; +} + +static gboolean +basic_typecode_to_gtype (int typecode) +{ + g_assert (dbus_type_is_basic (typecode)); + g_assert (dbus_typecode_maps_to_basic (typecode)); + return typecode_to_gtype (typecode); +} + +static void +register_basic (int typecode, const DBusGTypeMarshalData *typedata) { + set_type_metadata (basic_typecode_to_gtype (typecode), typedata); +} + +static void +register_array (int typecode, const DBusGTypeMarshalData *typedata) +{ + GType elt_gtype; GType gtype; - gtype = dbus_dbus_type_to_gtype (type); - if (gtype == G_TYPE_INVALID) - return FALSE; - g_value_init (value, gtype); - return TRUE; + elt_gtype = basic_typecode_to_gtype (typecode); + gtype = dbus_g_type_get_collection ("GArray", elt_gtype); + set_type_metadata (gtype, typedata); +} + +static void +register_dict (int key_type, int value_type, const DBusGTypeMarshalData *typedata) +{ + GType key_gtype; + GType value_gtype; + GType gtype; + + key_gtype = basic_typecode_to_gtype (key_type); + value_gtype = basic_typecode_to_gtype (value_type); + gtype = dbus_g_type_get_map ("GHashTable", key_gtype, value_gtype); + set_type_metadata (gtype, typedata); +} + +void +dbus_g_value_types_init (void) +{ + static gboolean types_initialized; + + + if (types_initialized) + return; + + g_assert (sizeof (DBusGValueIterator) >= sizeof (DBusMessageIter)); + + dbus_g_type_specialized_init (); + dbus_g_type_specialized_builtins_init (); + + static const DBusGTypeMarshalVtable basic_vtable = { + marshal_basic, + demarshal_basic + }; + static const DBusGTypeMarshalVtable garray_basic_vtable = { + marshal_garray_basic, + demarshal_garray_basic + }; + static const DBusGTypeMarshalVtable ghashtable_vtable = { + marshal_map, + demarshal_ghashtable + }; + + /* Register basic types */ + { + static const DBusGTypeMarshalData typedata = { + DBUS_TYPE_BOOLEAN_AS_STRING, + &basic_vtable, + }; + register_basic (DBUS_TYPE_BOOLEAN, &typedata); + } + { + static const DBusGTypeMarshalData typedata = { + DBUS_TYPE_BYTE_AS_STRING, + &basic_vtable, + }; + register_basic (DBUS_TYPE_BYTE, &typedata); + } + { + static const DBusGTypeMarshalData typedata = { + DBUS_TYPE_INT16_AS_STRING, + &basic_vtable, + }; + register_basic (DBUS_TYPE_INT16, &typedata); + } + { + static const DBusGTypeMarshalData typedata = { + DBUS_TYPE_UINT16_AS_STRING, + &basic_vtable, + }; + register_basic (DBUS_TYPE_UINT16, &typedata); + } + { + static const DBusGTypeMarshalData typedata = { + DBUS_TYPE_UINT32_AS_STRING, + &basic_vtable, + }; + register_basic (DBUS_TYPE_UINT32, &typedata); + } + { + static const DBusGTypeMarshalData typedata = { + DBUS_TYPE_INT32_AS_STRING, + &basic_vtable, + }; + register_basic (DBUS_TYPE_INT32, &typedata); + } + { + static const DBusGTypeMarshalData typedata = { + DBUS_TYPE_UINT64_AS_STRING, + &basic_vtable, + }; + register_basic (DBUS_TYPE_UINT64, &typedata); + } + { + static const DBusGTypeMarshalData typedata = { + DBUS_TYPE_INT64_AS_STRING, + &basic_vtable, + }; + register_basic (DBUS_TYPE_INT64, &typedata); + } + { + static const DBusGTypeMarshalData typedata = { + DBUS_TYPE_DOUBLE_AS_STRING, + &basic_vtable, + }; + register_basic (DBUS_TYPE_DOUBLE, &typedata); + } + { + static const DBusGTypeMarshalData typedata = { + DBUS_TYPE_STRING_AS_STRING, + &basic_vtable, + }; + register_basic (DBUS_TYPE_STRING, &typedata); + } + + /* Register complex types with builtin GType mappings */ + { + static const DBusGTypeMarshalVtable vtable = { + marshal_variant, + demarshal_variant + }; + static const DBusGTypeMarshalData typedata = { + DBUS_TYPE_VARIANT_AS_STRING, + &vtable + }; + set_type_metadata (G_TYPE_VALUE, &typedata); + }; + { + static const DBusGTypeMarshalVtable vtable = { + marshal_strv, + demarshal_strv + }; + static const DBusGTypeMarshalData typedata = { + DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_STRING_AS_STRING, + &vtable + }; + set_type_metadata (G_TYPE_STRV, &typedata); + }; + + { + static const DBusGTypeMarshalData typedata = { + DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_BOOLEAN_AS_STRING, + &garray_basic_vtable + }; + register_array (DBUS_TYPE_BOOLEAN, &typedata); + } + { + static const DBusGTypeMarshalData typedata = { + DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_BYTE_AS_STRING, + &garray_basic_vtable + }; + register_array (DBUS_TYPE_BYTE, &typedata); + } + { + static const DBusGTypeMarshalData typedata = { + DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_UINT32_AS_STRING, + &garray_basic_vtable + }; + register_array (DBUS_TYPE_UINT32, &typedata); + } + { + static const DBusGTypeMarshalData typedata = { + DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_INT32_AS_STRING, + &garray_basic_vtable + }; + register_array (DBUS_TYPE_INT32, &typedata); + } + { + static const DBusGTypeMarshalData typedata = { + DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_UINT64_AS_STRING, + &garray_basic_vtable + }; + register_array (DBUS_TYPE_UINT64, &typedata); + } + { + static const DBusGTypeMarshalData typedata = { + DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_INT64_AS_STRING, + &garray_basic_vtable + }; + register_array (DBUS_TYPE_INT64, &typedata); + } + { + static const DBusGTypeMarshalData typedata = { + DBUS_TYPE_ARRAY_AS_STRING DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_STRING_AS_STRING DBUS_DICT_ENTRY_END_CHAR_AS_STRING, + &ghashtable_vtable, + }; + register_dict (DBUS_TYPE_STRING, DBUS_TYPE_STRING, &typedata); + } + + { + static const DBusGTypeMarshalVtable vtable = { + marshal_proxy, + demarshal_proxy + }; + static const DBusGTypeMarshalData typedata = { + DBUS_TYPE_OBJECT_PATH_AS_STRING, + &vtable + }; + set_type_metadata (DBUS_TYPE_G_PROXY, &typedata); + } + + { + static const DBusGTypeMarshalVtable vtable = { + marshal_object, + demarshal_object + }; + static const DBusGTypeMarshalData typedata = { + DBUS_TYPE_OBJECT_PATH_AS_STRING, + &vtable + }; + set_type_metadata (G_TYPE_OBJECT, &typedata); + } + + { + static const DBusGTypeMarshalVtable vtable = { + marshal_proxy_array, + demarshal_proxy_array + }; + static const DBusGTypeMarshalData typedata = { + DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING, + &vtable + }; + set_type_metadata (DBUS_TYPE_G_PROXY_ARRAY, &typedata); + } + + types_initialized = TRUE; } -/* FIXME - broken for containers +/** + * Get the GLib type ID for a DBusGValue boxed type. + * + * @returns GLib type */ -static int -base_type_from_signature (const char *signature) +GType +dbus_g_value_get_g_type (void) { - DBusSignatureIter iter; + static GType type_id = 0; - dbus_signature_iter_init (&iter, signature); + if (!type_id) + type_id = g_boxed_type_register_static ("DBusGValue", + dbus_g_value_copy, + (GBoxedFreeFunc) dbus_g_value_free); + return type_id; +} + +void +dbus_g_value_open (DBusGValue *value, + DBusGValueIterator *iter) +{ + DBusGValue *real; + + g_return_if_fail (value->type == DBUS_G_VALUE_TYPE_TOPLEVEL); + + real = (DBusGValue*) iter; + real->type = DBUS_G_VALUE_TYPE_ITERATOR; + real->value.recurse.toplevel = value; - return dbus_signature_iter_get_current_type (&iter); + dbus_message_iter_init (value->value.toplevel.message, + &(real->value.recurse.iterator)); + value->value.recurse.toplevel = value; } -const char * -dbus_gvalue_genmarshal_name_from_type (const char *signature) +gboolean +dbus_g_value_iterator_get_values (DBusGValueIterator *iter, + GError **error, + GValue *first_val, + ...) { - int type; + GValue *value; + va_list args; + DBusGValue *iterval; - type = base_type_from_signature (signature); - switch (type) + va_start (args, first_val); + + iterval = (DBusGValue *) iter; + + value = first_val; + do { - case DBUS_TYPE_BOOLEAN: - return "BOOLEAN"; - case DBUS_TYPE_BYTE: - return "UCHAR"; - case DBUS_TYPE_INT32: - return "INT"; - case DBUS_TYPE_UINT32: - return "UINT"; - case DBUS_TYPE_INT64: - return "INT64"; - case DBUS_TYPE_UINT64: - return "UINT64"; - case DBUS_TYPE_DOUBLE: - return "DOUBLE"; - case DBUS_TYPE_INT16: - return "INT"; - break; - case DBUS_TYPE_UINT16: - return "UINT"; - case DBUS_TYPE_STRING: - case DBUS_TYPE_OBJECT_PATH: - case DBUS_TYPE_SIGNATURE: - return "STRING"; - - case DBUS_TYPE_STRUCT: - case DBUS_TYPE_ARRAY: - case DBUS_TYPE_VARIANT: - return NULL; - } + DBusGValueMarshalCtx context; + + context.gconnection = (iterval->value.recurse.toplevel)->value.toplevel.connection; + context.proxy = (iterval->value.recurse.toplevel)->value.toplevel.proxy; + if (!dbus_gvalue_demarshal (&context, + &(iterval->value.recurse.iterator), + value, + error)) + return FALSE; + } while ((value = va_arg (args, GValue *)) != NULL); + + return TRUE; +} + +static char * +dbus_g_value_get_signature (DBusGValue *value) +{ + return value->value.toplevel.signature; +} + +static gpointer +dbus_g_value_copy (gpointer value) +{ + /* FIXME */ return NULL; } -const char * -dbus_gvalue_ctype_from_type (const char *signature, gboolean in) +void +dbus_g_value_free (DBusGValue *value) +{ + if (value->type == DBUS_G_VALUE_TYPE_TOPLEVEL) + { + dbus_message_unref (value->value.toplevel.message); + g_free (value->value.toplevel.signature); + } +} + +static GType +signature_iter_to_g_type_dict (const DBusSignatureIter *subiter, gboolean is_client) { - int type; + DBusSignatureIter iter; + GType key_gtype; + GType value_gtype; - type = base_type_from_signature (signature); + g_assert (dbus_signature_iter_get_current_type (subiter) == DBUS_TYPE_DICT_ENTRY); - switch (type) + dbus_signature_iter_recurse (subiter, &iter); + + key_gtype = dbus_gtype_from_signature_iter (&iter, is_client); + if (key_gtype == G_TYPE_INVALID) + return G_TYPE_INVALID; + + dbus_signature_iter_next (&iter); + value_gtype = dbus_gtype_from_signature_iter (&iter, is_client); + if (value_gtype == G_TYPE_INVALID) + return G_TYPE_INVALID; + + if (!dbus_gtype_is_valid_hash_key (key_gtype) + || !dbus_gtype_is_valid_hash_value (value_gtype)) + /* Later we need to return DBUS_TYPE_G_VALUE */ + return G_TYPE_INVALID; + + return dbus_g_type_get_map ("GHashTable", key_gtype, value_gtype); +} + +static GType +signature_iter_to_g_type_array (DBusSignatureIter *iter, gboolean is_client) +{ + GType elt_gtype; + DBusGTypeMarshalData *typedata; + + elt_gtype = dbus_gtype_from_signature_iter (iter, is_client); + if (elt_gtype == G_TYPE_INVALID) + return G_TYPE_INVALID; + + typedata = g_type_get_qdata (elt_gtype, dbus_g_type_metadata_data_quark ()); + if (typedata == NULL) + return G_TYPE_INVALID; + + if (elt_gtype == G_TYPE_OBJECT) + return DBUS_TYPE_G_OBJECT_ARRAY; + if (elt_gtype == G_TYPE_STRING) + return G_TYPE_STRV; + if (dbus_g_type_is_fixed (elt_gtype)) + return dbus_g_type_get_collection ("GArray", elt_gtype); + + /* Later we need to return DBUS_TYPE_G_VALUE */ + return G_TYPE_INVALID; +} + +static gboolean +signature_iter_to_g_type_struct (DBusSignatureIter *origiter, gboolean is_client) +{ + /* FIXME allow structures */ + return G_TYPE_INVALID; +#if 0 + DBusSignatureIter iter; + int current_type; + + iter = *origiter; + + while ((current_type = dbus_signature_iter_get_current_type (&iter)) != DBUS_TYPE_INVALID) { + subtype = dbus_gtype_from_signature_iter (&iter, is_client); + if (subtype == G_TYPE_INVALID) + return G_TYPE_INVALID; + } + return DBUS_TYPE_G_VALUE (); +#endif +} + +GType +dbus_gtype_from_signature_iter (DBusSignatureIter *iter, gboolean is_client) +{ + int current_type; + + current_type = dbus_signature_iter_get_current_type (iter); + /* TODO: handle type 0? */ + if (dbus_typecode_maps_to_basic (current_type)) + return basic_typecode_to_gtype (current_type); + else if (current_type == DBUS_TYPE_OBJECT_PATH) + return is_client ? DBUS_TYPE_G_PROXY : G_TYPE_OBJECT; + else { - case DBUS_TYPE_BOOLEAN: - return "gboolean"; - case DBUS_TYPE_BYTE: - return "guchar"; - case DBUS_TYPE_INT32: - return "gint32"; - case DBUS_TYPE_UINT32: - return "guint32"; - case DBUS_TYPE_INT64: - return "gint64"; - case DBUS_TYPE_UINT64: - return "guint64"; - case DBUS_TYPE_DOUBLE: - return "gdouble"; - case DBUS_TYPE_INT16: - return "gint"; - break; - case DBUS_TYPE_UINT16: - return "guint"; - case DBUS_TYPE_STRING: - case DBUS_TYPE_OBJECT_PATH: - case DBUS_TYPE_SIGNATURE: - /* FIXME - kind of a hack */ - if (in) - return "const char *"; + DBusSignatureIter subiter; + + g_assert (dbus_type_is_container (current_type)); + dbus_signature_iter_recurse (iter, &subiter); + + if (current_type == DBUS_TYPE_ARRAY) + { + int elt_type = dbus_signature_iter_get_current_type (&subiter); + if (elt_type == DBUS_TYPE_DICT_ENTRY) + return signature_iter_to_g_type_dict (&subiter, is_client); + else + return signature_iter_to_g_type_array (&subiter, is_client); + } + else if (current_type == DBUS_TYPE_STRUCT) + return signature_iter_to_g_type_struct (&subiter, is_client); + else if (current_type == DBUS_TYPE_VARIANT) + return g_value_get_type (); + else if (current_type == DBUS_TYPE_DICT_ENTRY) + return G_TYPE_INVALID; else - return "char *"; - case DBUS_TYPE_STRUCT: - case DBUS_TYPE_ARRAY: - case DBUS_TYPE_VARIANT: - return NULL; + { + g_assert_not_reached (); + return G_TYPE_INVALID; + } } - return NULL; } -const char * -dbus_gtype_to_dbus_type (GType type) +GType +dbus_gtype_from_signature (const char *signature, gboolean is_client) { - switch (type) + DBusSignatureIter iter; + + dbus_signature_iter_init (&iter, signature); + + return dbus_gtype_from_signature_iter (&iter, is_client); +} + +static char * +dbus_gvalue_to_signature (GValue *value) +{ + const char *ret; + + ret = dbus_gtype_to_signature (G_VALUE_TYPE (value)); + if (ret) + return g_strdup (ret); + else { - case G_TYPE_CHAR: - case G_TYPE_UCHAR: - return DBUS_TYPE_BYTE_AS_STRING; + DBusGValue *val; - case G_TYPE_BOOLEAN: - return DBUS_TYPE_BOOLEAN_AS_STRING; + g_assert (G_VALUE_TYPE (value) == DBUS_TYPE_G_VALUE); - /* long gets cut to 32 bits so the remote API is consistent - * on all architectures - */ + val = g_value_get_boxed (value); - case G_TYPE_LONG: - case G_TYPE_INT: - return DBUS_TYPE_INT32_AS_STRING; - case G_TYPE_ULONG: - case G_TYPE_UINT: - return DBUS_TYPE_UINT32_AS_STRING; + return dbus_g_value_get_signature (val); + } +} - case G_TYPE_INT64: - return DBUS_TYPE_INT64_AS_STRING; +const char * +dbus_gtype_to_signature (GType gtype) +{ + DBusGTypeMarshalData *typedata; - case G_TYPE_UINT64: - return DBUS_TYPE_UINT64_AS_STRING; - - case G_TYPE_FLOAT: - case G_TYPE_DOUBLE: - return DBUS_TYPE_DOUBLE_AS_STRING; + typedata = g_type_get_qdata (gtype, dbus_g_type_metadata_data_quark ()); + if (typedata == NULL) + return NULL; + return typedata->sig; +} - case G_TYPE_STRING: - return DBUS_TYPE_STRING_AS_STRING; +GArray * +dbus_gtypes_from_arg_signature (const char *argsig, gboolean is_client) +{ + GArray *ret; + int current_type; + DBusSignatureIter sigiter; - default: - return NULL; + ret = g_array_new (FALSE, FALSE, sizeof (GType)); + + dbus_signature_iter_init (&sigiter, argsig); + while ((current_type = dbus_signature_iter_get_current_type (&sigiter)) != DBUS_TYPE_INVALID) + { + GType curtype; + + curtype = dbus_gtype_from_signature_iter (&sigiter, is_client); + g_array_append_val (ret, curtype); + dbus_signature_iter_next (&sigiter); } + return ret; } -gboolean -dbus_gvalue_demarshal (DBusMessageIter *iter, GValue *value) -{ - g_assert (sizeof (dbus_bool_t) == sizeof (value->data[0].v_int)); - dbus_gvalue_init (dbus_message_iter_get_arg_type (iter), value); +static gboolean +demarshal_basic (DBusGValueMarshalCtx *context, + DBusMessageIter *iter, + GValue *value, + GError **error) +{ + int current_type; - switch (dbus_message_iter_get_arg_type (iter)) + current_type = dbus_message_iter_get_arg_type (iter); + g_assert (dbus_type_is_basic (current_type)); + + switch (current_type) { case DBUS_TYPE_BOOLEAN: { @@ -283,24 +761,407 @@ dbus_gvalue_demarshal (DBusMessageIter *iter, GValue *value) return TRUE; } 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); + g_value_set_string (value, s); return TRUE; } - case DBUS_TYPE_STRUCT: - case DBUS_TYPE_ARRAY: - case DBUS_TYPE_VARIANT: default: + g_assert_not_reached (); + return FALSE; + } +} + +static gboolean +demarshal_static_variant (DBusGValueMarshalCtx *context, + DBusMessageIter *iter, + GValue *value, + GError **error) +{ + char *sig; + int current_type; + DBusMessageIter subiter; + GType variant_type; + + current_type = dbus_message_iter_get_arg_type (iter); + dbus_message_iter_recurse (iter, &subiter); + sig = dbus_message_iter_get_signature (&subiter); + + variant_type = dbus_gtype_from_signature (sig, context->proxy != NULL); + if (variant_type != G_TYPE_INVALID) + { + g_value_init (value, variant_type); + + if (!dbus_gvalue_demarshal (context, &subiter, value, error)) + { + dbus_free (sig); + return FALSE; + } + } + dbus_free (sig); + return TRUE; +} + +static gboolean +demarshal_variant (DBusGValueMarshalCtx *context, + DBusMessageIter *iter, + GValue *value, + GError **error) + +{ + GValue *variant_val; + variant_val = g_new0 (GValue, 1); + + if (!demarshal_static_variant (context, iter, variant_val, error)) + return FALSE; + + g_value_set_boxed_take_ownership (value, variant_val); + return TRUE; +} + +static gboolean +demarshal_proxy (DBusGValueMarshalCtx *context, + DBusMessageIter *iter, + GValue *value, + GError **error) +{ + const char *name; + DBusGProxy *new_proxy; + const char *objpath; + int current_type; + + current_type = dbus_message_iter_get_arg_type (iter); + g_assert (current_type == DBUS_TYPE_OBJECT_PATH); + + g_assert (context->proxy != NULL); + + name = dbus_g_proxy_get_bus_name (context->proxy); + + dbus_message_iter_get_basic (iter, &objpath); + + new_proxy = dbus_g_proxy_new_from_proxy (context->proxy, NULL, objpath); + g_value_set_object_take_ownership (value, new_proxy); + + return TRUE; +} + +static gboolean +demarshal_object (DBusGValueMarshalCtx *context, + DBusMessageIter *iter, + GValue *value, + GError **error) +{ + const char *objpath; + int current_type; + GObject *obj; + + current_type = dbus_message_iter_get_arg_type (iter); + g_assert (current_type == DBUS_TYPE_OBJECT_PATH); + g_assert (context->proxy == NULL); + + dbus_message_iter_get_basic (iter, &objpath); + + obj = dbus_g_connection_lookup_g_object (context->gconnection, objpath); + if (obj == NULL) + { + g_set_error (error, + DBUS_GERROR, + DBUS_GERROR_INVALID_ARGS, + _("Unregistered object at path '%s'"), + objpath); return FALSE; } + g_value_set_object (value, obj); + + return TRUE; } - + +static gboolean +demarshal_strv (DBusGValueMarshalCtx *context, + DBusMessageIter *iter, + GValue *value, + GError **error) +{ + DBusMessageIter subiter; + int current_type; + char **ret; + int len; + int i; + + dbus_message_iter_recurse (iter, &subiter); + + len = dbus_message_iter_get_array_len (&subiter); + g_assert (len >= 0); + ret = g_malloc (sizeof (char *) * (len + 1)); + + i = 0; + while ((current_type = dbus_message_iter_get_arg_type (&subiter)) != DBUS_TYPE_INVALID) + { + g_assert (i < len); + g_assert (current_type == DBUS_TYPE_STRING); + + dbus_message_iter_get_basic (&subiter, &(ret[i])); + ret[i] = g_strdup (ret[i]); + + dbus_message_iter_next (&subiter); + i++; + } + ret[i] = NULL; + g_value_set_boxed_take_ownership (value, ret); + + return TRUE; +} + +static gboolean +demarshal_garray_basic (DBusGValueMarshalCtx *context, + DBusMessageIter *iter, + GValue *value, + GError **error) +{ + DBusMessageIter subiter; + GArray *ret; + GType elt_gtype; + int elt_size; + void *msgarray; + int msgarray_len; + + dbus_message_iter_recurse (iter, &subiter); + + elt_gtype = dbus_g_type_get_collection_specialization (G_VALUE_TYPE (value)); + g_assert (elt_gtype != G_TYPE_INVALID); + g_assert (dbus_g_type_is_fixed (elt_gtype)); + + elt_size = dbus_g_type_fixed_get_size (elt_gtype); + + ret = g_array_new (FALSE, TRUE, elt_size); + + msgarray = NULL; + dbus_message_iter_get_fixed_array (&subiter, + &msgarray, + &msgarray_len); + g_assert (msgarray != NULL); + g_assert (msgarray_len >= 0); + g_array_append_vals (ret, msgarray, (guint) msgarray_len); + + g_value_set_boxed_take_ownership (value, ret); + + return TRUE; +} + +static gboolean +demarshal_proxy_array (DBusGValueMarshalCtx *context, + DBusMessageIter *iter, + GValue *value, + GError **error) +{ + DBusMessageIter subiter; + GPtrArray *ret; + guint len; + guint i; + int current_type; + + g_assert (dbus_message_iter_get_arg_type (iter) == DBUS_TYPE_ARRAY); + + dbus_message_iter_recurse (iter, &subiter); + + len = dbus_message_iter_get_array_len (&subiter); + g_assert (len >= 0); + ret = g_ptr_array_sized_new (len); + + i = 0; + while ((current_type = dbus_message_iter_get_arg_type (&subiter)) != DBUS_TYPE_INVALID) + { + GValue subval = {0, }; + g_assert (i < len); + + if (!demarshal_proxy (context, &subiter, &subval, error)) + { + for (i = 0; i < ret->len; i++) + g_object_unref (g_ptr_array_index (ret, i)); + g_ptr_array_free (ret, TRUE); + return FALSE; + } + + g_ptr_array_index (ret, i) = g_value_get_boxed (&subval); + /* Don't unset value, now owned by ret */ + + i++; + } + g_value_set_boxed_take_ownership (value, ret); + + return TRUE; +} + +static gboolean +demarshal_ghashtable (DBusGValueMarshalCtx *context, + DBusMessageIter *iter, + GValue *value, + GError **error) +{ + GType gtype; + DBusMessageIter subiter; + int current_type; + GHashTable *ret; + GType key_gtype; + GType value_gtype; + + current_type = dbus_message_iter_get_arg_type (iter); + g_assert (current_type == DBUS_TYPE_ARRAY); + + gtype = G_VALUE_TYPE (value); + + dbus_message_iter_recurse (iter, &subiter); + + g_assert (dbus_message_iter_get_arg_type (&subiter) == DBUS_TYPE_DICT_ENTRY); + + key_gtype = dbus_g_type_get_map_key_specialization (gtype); + g_assert (dbus_gtype_is_valid_hash_key (key_gtype)); + value_gtype = dbus_g_type_get_map_value_specialization (gtype); + g_assert (dbus_gtype_is_valid_hash_value (value_gtype)); + + ret = g_hash_table_new_full (dbus_g_hash_func_from_gtype (key_gtype), + dbus_g_hash_equal_from_gtype (key_gtype), + dbus_g_hash_free_from_gtype (key_gtype), + dbus_g_hash_free_from_gtype (value_gtype)); + + while ((current_type = dbus_message_iter_get_arg_type (&subiter)) != DBUS_TYPE_INVALID) + { + DBusMessageIter entry_iter; + GValue key_value = {0,}; + GValue value_value = {0,}; + + current_type = dbus_message_iter_get_arg_type (&subiter); + g_assert (current_type == DBUS_TYPE_DICT_ENTRY); + + dbus_message_iter_recurse (&subiter, &entry_iter); + + g_value_init (&key_value, key_gtype); + if (!dbus_gvalue_demarshal (context, + &entry_iter, + &key_value, + error)) + return FALSE; + + dbus_message_iter_next (&entry_iter); + + g_value_init (&value_value, value_gtype); + if (!dbus_gvalue_demarshal (context, + &entry_iter, + &value_value, + error)) + return FALSE; + + dbus_g_hash_table_insert_steal_values (ret, + &key_value, + &value_value); + /* Ownership of values passes to hash table, don't unset */ + + dbus_message_iter_next (&subiter); + } + g_value_set_boxed_take_ownership (value, ret); + + return TRUE; +} + +static gboolean +demarshal_recurse (DBusGValueMarshalCtx *context, + DBusMessageIter *iter, + GValue *value, + GError **error) +{ + return FALSE; +} + +gboolean +dbus_gvalue_demarshal (DBusGValueMarshalCtx *context, + DBusMessageIter *iter, + GValue *value, + GError **error) +{ + GType gtype; + DBusGTypeMarshalData *typedata; + + gtype = G_VALUE_TYPE (value); + + typedata = g_type_get_qdata (gtype, dbus_g_type_metadata_data_quark ()); + g_return_val_if_fail (typedata != NULL || g_type_is_a (gtype, DBUS_TYPE_G_VALUE), FALSE); + + if (typedata == NULL) + { + if (g_type_is_a (gtype, DBUS_TYPE_G_VALUE)) + return demarshal_recurse (context, iter, value, error); + g_assert_not_reached (); + } + g_assert (typedata->vtable); + return typedata->vtable->demarshaller (context, iter, value, error); +} + gboolean -dbus_gvalue_marshal (DBusMessageIter *iter, GValue *value) +dbus_gvalue_demarshal_variant (DBusGValueMarshalCtx *context, + DBusMessageIter *iter, + GValue *value, + GError **error) +{ + return demarshal_static_variant (context, iter, value, error); +} + +GValueArray * +dbus_gvalue_demarshal_message (DBusGValueMarshalCtx *context, + DBusMessage *message, + guint n_types, + const GType *types, + GError **error) +{ + GValueArray *ret; + DBusMessageIter iter; + int current_type; + guint index; + + ret = g_value_array_new (6); /* 6 is a typical maximum for arguments */ + + dbus_message_iter_init (message, &iter); + index = 0; + while ((current_type = dbus_message_iter_get_arg_type (&iter)) != DBUS_TYPE_INVALID) + { + GValue *value; + GType gtype; + + if (index >= n_types) + { + g_set_error (error, DBUS_GERROR, + DBUS_GERROR_INVALID_ARGS, + _("Too many arguments in message")); + goto lose; + } + + g_value_array_append (ret, NULL); + value = g_value_array_get_nth (ret, index); + + gtype = types[index]; + g_value_init (value, gtype); + + if (!dbus_gvalue_demarshal (context, &iter, value, error)) + goto lose; + dbus_message_iter_next (&iter); + index++; + } + if (index < n_types) + { + g_set_error (error, DBUS_GERROR, + DBUS_GERROR_INVALID_ARGS, + _("Too few arguments in message")); + goto lose; + } + + return ret; + lose: + g_value_array_free (ret); + return NULL; +} + +static gboolean +marshal_basic (DBusMessageIter *iter, GValue *value) { GType value_type; @@ -353,9 +1214,6 @@ dbus_gvalue_marshal (DBusMessageIter *iter, GValue *value) goto nomem; } return TRUE; - /* long gets cut to 32 bits so the remote API is consistent - * on all architectures - */ case G_TYPE_LONG: { dbus_int32_t v = g_value_get_long (value); @@ -424,9 +1282,10 @@ dbus_gvalue_marshal (DBusMessageIter *iter, GValue *value) return TRUE; default: - /* FIXME: we need to define custom boxed types for arrays - etc. so we can map them transparently / pleasantly */ - return FALSE; + { + g_assert_not_reached (); + return FALSE; + } } nomem: @@ -434,49 +1293,320 @@ dbus_gvalue_marshal (DBusMessageIter *iter, GValue *value) return FALSE; } -/* FIXME is there a better way to do this? */ +static gboolean +marshal_strv (DBusMessageIter *iter, + GValue *value) +{ + DBusMessageIter subiter; + char **array; + char **elt; + gboolean ret; + + g_assert (G_VALUE_TYPE (value) == g_strv_get_type ()); + + array = g_value_get_boxed (value); + + if (!dbus_message_iter_open_container (iter, + DBUS_TYPE_ARRAY, + "s", + &subiter)) + goto out; + + for (elt = array; *elt; elt++) + { + if (!dbus_message_iter_append_basic (&subiter, + DBUS_TYPE_STRING, + elt)) + goto out; + } + + if (!dbus_message_iter_close_container (iter, &subiter)) + goto out; + ret = TRUE; + out: + return ret; +} + +static gboolean +marshal_garray_basic (DBusMessageIter *iter, + GValue *value) +{ + GType elt_gtype; + DBusMessageIter subiter; + GArray *array; + guint elt_size; + const char *subsignature_str; + gboolean ret; + + elt_gtype = dbus_g_type_get_collection_specialization (G_VALUE_TYPE (value)); + /* FIXME - this means we can't send an array of DBusGValue right now... */ + subsignature_str = dbus_gtype_to_signature (elt_gtype); + g_assert (subsignature_str != NULL); + + elt_size = dbus_g_type_fixed_get_size (elt_gtype); + + array = g_value_get_boxed (value); + + if (!dbus_message_iter_open_container (iter, + DBUS_TYPE_ARRAY, + subsignature_str, + &subiter)) + goto out; + + /* TODO - This assumes that basic values are the same size + * is this always true? If it is we can probably avoid + * a lot of the overhead in _marshal_basic_instance... + */ + if (!dbus_message_iter_append_fixed_array (&subiter, + subsignature_str[0], + &(array->data), + array->len)) + goto out; + + if (!dbus_message_iter_close_container (iter, &subiter)) + goto out; + ret = TRUE; + out: + return ret; +} + +static gboolean +marshal_proxy (DBusMessageIter *iter, + GValue *value) +{ + const char *path; + DBusGProxy *proxy; + + g_assert (G_VALUE_TYPE (value) == dbus_g_proxy_get_type ()); + + proxy = g_value_get_object (value); + path = dbus_g_proxy_get_path (proxy); + + if (!dbus_message_iter_append_basic (iter, + DBUS_TYPE_OBJECT_PATH, + &path)) + return FALSE; + return TRUE; +} + +static gboolean +marshal_object (DBusMessageIter *iter, + GValue *value) +{ + const char *path; + GObject *obj; + + obj = g_value_get_object (value); + path = _dbus_gobject_get_path (obj); + + if (path == NULL) + /* FIXME should throw error */ + return FALSE; + + if (!dbus_message_iter_append_basic (iter, + DBUS_TYPE_OBJECT_PATH, + &path)) + return FALSE; + return TRUE; +} + +static gboolean +marshal_proxy_array (DBusMessageIter *iter, + GValue *value) +{ + DBusMessageIter subiter; + GPtrArray *array; + const char *subsignature_str; + gboolean ret; + guint i; + + subsignature_str = dbus_gtype_to_signature (DBUS_TYPE_G_PROXY); + g_assert (subsignature_str != NULL); + + array = g_value_get_boxed (value); + + if (!dbus_message_iter_open_container (iter, + DBUS_TYPE_ARRAY, + subsignature_str, + &subiter)) + goto out; + + for (i = 0; i < array->len; i++) + { + GValue val = {0, }; + + g_value_init (&val, DBUS_TYPE_G_PROXY); + g_value_set_static_boxed (&val, g_ptr_array_index (array, i)); + + marshal_proxy (&subiter, &val); + + g_value_unset (&val); + } + + if (!dbus_message_iter_close_container (iter, &subiter)) + goto out; + ret = TRUE; + out: + return ret; +} + +struct DBusGLibHashMarshalData +{ + const char *entry_sig; + DBusMessageIter *iter; + gboolean err; +}; + +static void +marshal_map_entry (const GValue *key, + const GValue *value, + gpointer data) +{ + struct DBusGLibHashMarshalData *hashdata = data; + DBusMessageIter subiter; + + if (hashdata->err) + return; + + if (!dbus_message_iter_open_container (hashdata->iter, + DBUS_TYPE_DICT_ENTRY, + NULL, + &subiter)) + goto lose; + + if (!dbus_gvalue_marshal (&subiter, (GValue*) key)) + goto lose; + + if (!dbus_gvalue_marshal (&subiter, (GValue*) value)) + goto lose; + + if (!dbus_message_iter_close_container (hashdata->iter, &subiter)) + goto lose; + + return; + lose: + hashdata->err = TRUE; +} + +static gboolean +marshal_map (DBusMessageIter *iter, + GValue *value) +{ + GType gtype; + DBusMessageIter arr_iter; + gboolean ret; + struct DBusGLibHashMarshalData hashdata; + GType key_type; + GType value_type; + const char *key_sig; + const char *value_sig; + char *entry_sig; + char *array_sig; + + gtype = G_VALUE_TYPE (value); + + ret = FALSE; + + key_type = dbus_g_type_get_map_key_specialization (gtype); + g_assert (dbus_gtype_is_valid_hash_key (key_type)); + value_type = dbus_g_type_get_map_value_specialization (gtype); + g_assert (dbus_gtype_is_valid_hash_value (value_type)); + + key_sig = dbus_gtype_to_signature (key_type); + value_sig = dbus_gtype_to_signature (value_type); + entry_sig = g_strdup_printf ("%s%s", key_sig, value_sig); + array_sig = g_strdup_printf ("%c%s%c", + DBUS_DICT_ENTRY_BEGIN_CHAR, + entry_sig, + DBUS_DICT_ENTRY_END_CHAR); + if (!dbus_message_iter_open_container (iter, + DBUS_TYPE_ARRAY, + array_sig, + &arr_iter)) + goto lose; + + hashdata.iter = &arr_iter; + hashdata.err = FALSE; + hashdata.entry_sig = entry_sig; + + dbus_g_type_map_value_iterate (value, + marshal_map_entry, + &hashdata); + + if (!dbus_message_iter_close_container (iter, &arr_iter)) + goto lose; + + out: + g_free (entry_sig); + g_free (array_sig); + return !hashdata.err; + lose: + hashdata.err = TRUE; + goto out; +} + +static gboolean +marshal_variant (DBusMessageIter *iter, + GValue *value) +{ + GType value_gtype; + DBusMessageIter subiter; + char *variant_sig; + GValue *real_value; + gboolean ret; + + real_value = g_value_get_boxed (value); + value_gtype = G_VALUE_TYPE (real_value); + + variant_sig = dbus_gvalue_to_signature (real_value); + if (variant_sig == NULL) + { + g_warning ("Unsupported value type \"%s\"", + g_type_name (value_gtype)); + return FALSE; + } + + if (!dbus_message_iter_open_container (iter, + DBUS_TYPE_VARIANT, + variant_sig, + &subiter)) + goto out; + + if (!marshal_basic (&subiter, real_value)) + goto out; + + if (!dbus_message_iter_close_container (iter, &subiter)) + goto out; + + ret = TRUE; + out: + g_free (variant_sig); + return ret; +} + +static gboolean +marshal_recurse (DBusMessageIter *iter, + GValue *value) +{ + return FALSE; +} + gboolean -dbus_gvalue_store (GValue *value, - gpointer storage) +dbus_gvalue_marshal (DBusMessageIter *iter, + GValue *value) { - switch (G_VALUE_TYPE (value)) + GType gtype; + DBusGTypeMarshalData *typedata; + + gtype = G_VALUE_TYPE (value); + + typedata = g_type_get_qdata (gtype, dbus_g_type_metadata_data_quark ()); + if (typedata == NULL) { - 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: + if (g_type_is_a (gtype, DBUS_TYPE_G_VALUE)) + return marshal_recurse (iter, value); return FALSE; } + g_assert (typedata->vtable); + return typedata->vtable->marshaller (iter, value); } -- cgit