summaryrefslogtreecommitdiffstats
path: root/glib/dbus-gvalue.c
diff options
context:
space:
mode:
authorColin Walters <walters@verbum.org>2005-06-13 03:01:30 +0000
committerColin Walters <walters@verbum.org>2005-06-13 03:01:30 +0000
commitbeb9cd2eb219e04f9872c6a4dd743d5d1c36b4b1 (patch)
tree392eb655fe68d80363169bf170c9a123430a4058 /glib/dbus-gvalue.c
parent982de71850996f01c244429809ba23f715353ea3 (diff)
2005-06-12 Colin Walters <walters@verbum.org>
Async signals and various bugfixes and testing by Ross Burton <ross@burtonini.com>. * 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.
Diffstat (limited to 'glib/dbus-gvalue.c')
-rw-r--r--glib/dbus-gvalue.c1508
1 files changed, 1319 insertions, 189 deletions
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 <dbus-gvalue.h>
+#include "dbus-gvalue.h"
+#include "dbus-gobject.h"
+#include "dbus-gvalue-utils.h"
+#include "dbus/dbus-glib.h"
+#include <string.h>
+#include <glib.h>
+#include <glib/gi18n.h>
#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);
}