From 4a48fff0c7c0377d68d1e24cc113e275057b4800 Mon Sep 17 00:00:00 2001 From: Robert McQueen Date: Mon, 13 Feb 2006 22:30:11 +0000 Subject: 2006-02-13 Robert McQueen * glib/dbus-binding-tool-glib.c, glib/dbus-gmain.c, glib/dbus-gsignature.c, glib/dbus-gtype-specialized.c, glib/dbus-gtype-specialized.h, glib/dbus-gvalue-utils.c, glib/dbus-gvalue-utils.h, glib/dbus-gvalue.c: Patch from Rob Taylor to add a big missing piece of the glib bindings jigsaw puzzle. This modifies the existing specialised types to have N type parameters (rather than the current 1 or 2 for arrays and dictionaries respectively). You can then use this to get a glib type to represent any arbitrary D-Bus struct type using dbus_g_type_get_struct. The only implementation of these types is with GValueArrays as before, but it's now possible to store these in arrays, emit them in signals, etc. --- glib/dbus-binding-tool-glib.c | 26 ++++ glib/dbus-gmain.c | 4 +- glib/dbus-gsignature.c | 25 +++- glib/dbus-gtype-specialized.c | 296 ++++++++++++++++++++++++++++++++++++++---- glib/dbus-gtype-specialized.h | 43 ++++++ glib/dbus-gvalue-utils.c | 184 ++++++++++++++++++++++++++ glib/dbus-gvalue-utils.h | 2 +- glib/dbus-gvalue.c | 148 ++++++++++++++++++++- 8 files changed, 695 insertions(+), 33 deletions(-) (limited to 'glib') diff --git a/glib/dbus-binding-tool-glib.c b/glib/dbus-binding-tool-glib.c index 21e02744..1386e3f1 100644 --- a/glib/dbus-binding-tool-glib.c +++ b/glib/dbus-binding-tool-glib.c @@ -98,6 +98,10 @@ static const char * dbus_g_type_get_c_name (GType gtype) { GType subtype; + if (dbus_g_type_is_struct (gtype)) + { + return "GValueArray"; + } if (dbus_g_type_is_collection (gtype)) { subtype = dbus_g_type_get_collection_specialization(gtype); @@ -1050,6 +1054,28 @@ dbus_g_type_get_lookup_function (GType gtype) g_free (value_lookup); return type_lookup; } + else if (dbus_g_type_is_struct (gtype)) + { + GType value_gtype; + GString *string; + char *value_lookup = NULL; + guint size, i; + + string = g_string_new ("dbus_g_type_get_struct (\"GValueArray\""); + + size = dbus_g_type_get_struct_size (gtype); + for (i=0; i < size; i++) + { + value_gtype = dbus_g_type_get_struct_member_type(gtype, i); + value_lookup = dbus_g_type_get_lookup_function (value_gtype); + g_assert (value_lookup); + g_string_append_printf (string, ", %s", value_lookup); + g_free (value_lookup); + } + g_string_append (string, ", G_TYPE_INVALID)"); + return g_string_free (string, FALSE); + } + MAP_KNOWN(G_TYPE_VALUE); MAP_KNOWN(G_TYPE_STRV); MAP_KNOWN(G_TYPE_VALUE_ARRAY); diff --git a/glib/dbus-gmain.c b/glib/dbus-gmain.c index 993bcf37..267f0bfa 100644 --- a/glib/dbus-gmain.c +++ b/glib/dbus-gmain.c @@ -754,14 +754,14 @@ _dbus_gmain_test (const char *test_data_dir) rectype = dbus_g_type_get_collection ("GArray", G_TYPE_UINT); g_assert (rectype != G_TYPE_INVALID); - g_assert (!strcmp (g_type_name (rectype), "GArray+guint")); + g_assert (!strcmp (g_type_name (rectype), "GArray_guint_")); type = _dbus_gtype_from_signature ("au", TRUE); g_assert (type == rectype); rectype = dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_STRING); g_assert (rectype != G_TYPE_INVALID); - g_assert (!strcmp (g_type_name (rectype), "GHashTable+gchararray+gchararray")); + g_assert (!strcmp (g_type_name (rectype), "GHashTable_gchararray+gchararray_")); type = _dbus_gtype_from_signature ("a{ss}", TRUE); g_assert (type == rectype); diff --git a/glib/dbus-gsignature.c b/glib/dbus-gsignature.c index a0370b0e..5df959db 100644 --- a/glib/dbus-gsignature.c +++ b/glib/dbus-gsignature.c @@ -117,6 +117,25 @@ signature_iter_to_g_type_array (DBusSignatureIter *iter, gboolean is_client) return G_TYPE_INVALID; } +static GType +signature_iter_to_g_type_struct (DBusSignatureIter *iter, gboolean is_client) +{ + GArray *types; + GType ret; + types = g_array_new (FALSE, FALSE, sizeof (GType)); + do + { + GType curtype; + curtype = _dbus_gtype_from_signature_iter (iter, is_client); + g_array_append_val (types, curtype); + } + while (dbus_signature_iter_next (iter)); + + ret = dbus_g_type_get_structv ("GValueArray", types->len, (GType*) types->data); + g_array_free (types, TRUE); + return ret; +} + GType _dbus_gtype_from_signature_iter (DBusSignatureIter *iter, gboolean is_client) { @@ -136,8 +155,6 @@ _dbus_gtype_from_signature_iter (DBusSignatureIter *iter, gboolean is_client) if (current_type == DBUS_TYPE_VARIANT) return G_TYPE_VALUE; - if (current_type == DBUS_TYPE_STRUCT) - return G_TYPE_VALUE_ARRAY; dbus_signature_iter_recurse (iter, &subiter); @@ -149,6 +166,10 @@ _dbus_gtype_from_signature_iter (DBusSignatureIter *iter, gboolean 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 { g_assert_not_reached (); diff --git a/glib/dbus-gtype-specialized.c b/glib/dbus-gtype-specialized.c index ad93a8c5..338e49d0 100644 --- a/glib/dbus-gtype-specialized.c +++ b/glib/dbus-gtype-specialized.c @@ -28,7 +28,8 @@ typedef enum { DBUS_G_SPECTYPE_COLLECTION, - DBUS_G_SPECTYPE_MAP + DBUS_G_SPECTYPE_MAP, + DBUS_G_SPECTYPE_STRUCT } DBusGTypeSpecializedType; typedef struct { @@ -37,7 +38,8 @@ typedef struct { } DBusGTypeSpecializedContainer; typedef struct { - GType types[6]; + guint num_types; + GType *types; const DBusGTypeSpecializedContainer *klass; } DBusGTypeSpecializedData; @@ -71,6 +73,7 @@ lookup_specialization_data (GType type) return g_type_get_qdata (type, specialized_type_data_quark ()); } + /* Copied from gboxed.c */ static void proxy_value_init (GValue *value) @@ -151,7 +154,9 @@ proxy_collect_value (GValue *value, value->data[1].v_uint = G_VALUE_NOCOPY_CONTENTS; } else - value->data[0].v_pointer = data->klass->vtable->copy_func (type, collect_values[0].v_pointer); + { + value->data[0].v_pointer = data->klass->vtable->copy_func (type, collect_values[0].v_pointer); + } } return NULL; @@ -188,18 +193,21 @@ proxy_lcopy_value (const GValue *value, } static char * -build_specialization_name (const char *prefix, GType first_type, GType second_type) +build_specialization_name (const char *prefix, guint num_types, GType *types) { GString *fullname; + guint i; fullname = g_string_new (prefix); - g_string_append_c (fullname, '+'); - g_string_append (fullname, g_type_name (first_type)); - if (second_type != G_TYPE_INVALID) + + g_string_append_c (fullname, '_'); + for (i=0; i < num_types; i++) { - g_string_append_c (fullname, '+'); - g_string_append (fullname, g_type_name (second_type)); + if (i!=0) + g_string_append_c (fullname, '+'); + g_string_append (fullname, g_type_name (types[i])); } + g_string_append_c (fullname, '_'); return g_string_free (fullname, FALSE); } @@ -235,6 +243,16 @@ dbus_g_type_register_map (const char *name, register_container (name, DBUS_G_SPECTYPE_MAP, (const DBusGTypeSpecializedVtable*) vtable); } +void +dbus_g_type_register_struct (const char *name, + const DBusGTypeSpecializedStructVtable *vtable, + guint flags) +{ + g_return_if_fail (specialized_types_is_initialized ()); + register_container (name, DBUS_G_SPECTYPE_STRUCT, (const DBusGTypeSpecializedVtable*) vtable); +} + + const DBusGTypeSpecializedMapVtable* dbus_g_type_map_peek_vtable (GType map_type) { DBusGTypeSpecializedData *data; @@ -257,12 +275,22 @@ const DBusGTypeSpecializedCollectionVtable* dbus_g_type_collection_peek_vtable ( return (DBusGTypeSpecializedCollectionVtable *)(data->klass->vtable); } +const DBusGTypeSpecializedStructVtable* dbus_g_type_struct_peek_vtable (GType struct_type) +{ + DBusGTypeSpecializedData *data; + g_return_val_if_fail (dbus_g_type_is_struct (struct_type), NULL); + + data = lookup_specialization_data (struct_type); + g_assert (data != NULL); + + return (DBusGTypeSpecializedStructVtable *)(data->klass->vtable); +} static GType register_specialized_instance (const DBusGTypeSpecializedContainer *klass, char *name, - GType first_type, - GType second_type) + guint num_types, + GType *types) { GType ret; @@ -297,8 +325,8 @@ register_specialized_instance (const DBusGTypeSpecializedContainer *klass, { DBusGTypeSpecializedData *data; data = g_new0 (DBusGTypeSpecializedData, 1); - data->types[0] = first_type; - data->types[1] = second_type; + data->num_types = num_types; + data->types = g_memdup (types, sizeof (GType) * num_types); data->klass = klass; g_type_set_qdata (ret, specialized_type_data_quark (), data); } @@ -308,8 +336,8 @@ register_specialized_instance (const DBusGTypeSpecializedContainer *klass, static GType lookup_or_register_specialized (const char *container, - GType first_type, - GType second_type) + guint num_types, + GType *types) { GType ret; char *name; @@ -320,14 +348,14 @@ lookup_or_register_specialized (const char *container, klass = g_hash_table_lookup (specialized_containers, container); g_return_val_if_fail (klass != NULL, G_TYPE_INVALID); - name = build_specialization_name (container, first_type, second_type); + name = build_specialization_name (container, num_types, types); ret = g_type_from_name (name); if (ret == G_TYPE_INVALID) { /* Take ownership of name */ ret = register_specialized_instance (klass, name, - first_type, - second_type); + num_types, + types); } else g_free (name); @@ -338,7 +366,7 @@ GType dbus_g_type_get_collection (const char *container, GType specialization) { - return lookup_or_register_specialized (container, specialization, G_TYPE_INVALID); + return lookup_or_register_specialized (container, 1, &specialization); } GType @@ -346,9 +374,42 @@ dbus_g_type_get_map (const char *container, GType key_specialization, GType value_specialization) { - return lookup_or_register_specialized (container, key_specialization, value_specialization); + GType types[2] = {key_specialization, value_specialization}; + return lookup_or_register_specialized (container, 2, types); +} + +GType +dbus_g_type_get_structv (const char *container, + guint num_items, + GType *types) +{ + return lookup_or_register_specialized (container, num_items, types); } +GType +dbus_g_type_get_struct (const char *container, + GType first_type, + ...) +{ + GArray *types; + GType curtype; + va_list args; + va_start (args, first_type); + + types = g_array_new (FALSE, FALSE, sizeof (GType)); + curtype = first_type; + while (curtype != G_TYPE_INVALID) + { + g_array_append_val (types, curtype); + curtype = va_arg (args, GType); + } + va_end (args); + return lookup_or_register_specialized (container, types->len, (GType*)types->data); + +} + + + gboolean dbus_g_type_is_collection (GType gtype) { @@ -369,13 +430,27 @@ dbus_g_type_is_map (GType gtype) return data->klass->type == DBUS_G_SPECTYPE_MAP; } +gboolean +dbus_g_type_is_struct (GType gtype) +{ + DBusGTypeSpecializedData *data; + data = lookup_specialization_data (gtype); + if (data == NULL) + return FALSE; + return data->klass->type == DBUS_G_SPECTYPE_STRUCT; +} + + static GType get_specialization_index (GType gtype, guint i) { DBusGTypeSpecializedData *data; data = lookup_specialization_data (gtype); - return data->types[i]; + if (i < data->num_types) + return data->types[i]; + else + return G_TYPE_INVALID; } GType @@ -399,6 +474,25 @@ dbus_g_type_get_map_value_specialization (GType gtype) return get_specialization_index (gtype, 1); } +GType +dbus_g_type_get_struct_member_type (GType gtype, guint index) +{ + g_return_val_if_fail (dbus_g_type_is_struct (gtype), G_TYPE_INVALID); + return get_specialization_index (gtype, index); +} + +guint +dbus_g_type_get_struct_size (GType gtype) +{ + DBusGTypeSpecializedData *data; + g_return_val_if_fail (dbus_g_type_is_struct (gtype), G_TYPE_INVALID); + + data = lookup_specialization_data (gtype); + return data->num_types; +} + + + gpointer dbus_g_type_specialized_construct (GType type) { @@ -469,7 +563,8 @@ dbus_g_type_specialized_init_append (GValue *value, DBusGTypeSpecializedAppendCo gtype = G_VALUE_TYPE (value); specdata = lookup_specialization_data (gtype); g_return_if_fail (specdata != NULL); - + g_return_if_fail (specdata->num_types != 0); + realctx->val = value; realctx->specialization_type = specdata->types[0]; realctx->specdata = specdata; @@ -519,3 +614,160 @@ dbus_g_type_map_value_iterate (const GValue *value, g_value_get_boxed (value), iterator, user_data); } + +gboolean +dbus_g_type_struct_get_member (const GValue *value, + guint index, + GValue *dest) +{ + DBusGTypeSpecializedData *data; + GType gtype; + + g_return_val_if_fail (specialized_types_is_initialized (), FALSE); + g_return_val_if_fail (G_VALUE_HOLDS_BOXED (value), FALSE); + + gtype = G_VALUE_TYPE (value); + data = lookup_specialization_data (gtype); + g_return_val_if_fail (data != NULL, FALSE); + + return ((DBusGTypeSpecializedStructVtable *) (data->klass->vtable))->get_member(gtype, + g_value_get_boxed (value), + index, dest); +} + +gboolean +dbus_g_type_struct_set_member (GValue *value, + guint index, + const GValue *src) +{ + DBusGTypeSpecializedData *data; + GType gtype; + + g_return_val_if_fail (specialized_types_is_initialized (), FALSE); + g_return_val_if_fail (G_VALUE_HOLDS_BOXED (value), FALSE); + + gtype = G_VALUE_TYPE (value); + data = lookup_specialization_data (gtype); + g_return_val_if_fail (data != NULL, FALSE); + + return ((DBusGTypeSpecializedStructVtable *) (data->klass->vtable))->set_member(gtype, + g_value_get_boxed (value), + index, src); +} + +/** + * dbus_g_type_struct_get: + * @value: a GValue containing a DBusGTypeStruct type + * @member: struct member to get + * @...: location in which to return the value of this member, + * followed optionally by more member/return locations pairs, followed by + * by G_MAXUINT + * + * Collects the selected values of this struct into the return locations + * provided. + * + * Returns: FALSE on failure + */ + +gboolean +dbus_g_type_struct_get (const GValue *value, + guint first_member, + ...) +{ + va_list var_args; + GType type; + guint size,i; + gchar *error; + GValue val = {0,}; + + g_return_val_if_fail (dbus_g_type_is_struct (G_VALUE_TYPE (value)), FALSE); + + va_start (var_args, first_member); + size = dbus_g_type_get_struct_size (G_VALUE_TYPE (value)); + i = first_member; + while (i != G_MAXUINT) + { + if (i >= size) + goto error; + + type = dbus_g_type_get_struct_member_type (G_VALUE_TYPE (value),i); + + g_value_init (&val, type); + dbus_g_type_struct_get_member (value, i, &val); + + G_VALUE_LCOPY (&val, var_args, 0, &error); + if (error) + { + g_warning ("%s, %s", G_STRFUNC, error); + g_free (error); + g_value_unset (&val); + goto error; + } + g_value_unset (&val); + i = va_arg (var_args, guint); + } + va_end (var_args); + return TRUE; +error: + va_end (var_args); + return FALSE; +} + +/** + * dbus_g_type_struct_set: + * @value: a GValue containing a DBusGTypeStruct type + * @member: struct member to set + * @...: value for the first member, followed optionally by + * more member/value pairs, followed by G_MAXUINT + * + * Sets the selected members of the struct in @value. + * + * Returns: FALSE on failure + */ + +gboolean +dbus_g_type_struct_set (GValue *value, + guint first_member, + ...) +{ + va_list var_args; + GType type; + guint size,i; + gchar *error; + GValue val = {0,}; + + g_return_val_if_fail (dbus_g_type_is_struct (G_VALUE_TYPE (value)), FALSE); + + va_start (var_args, first_member); + size = dbus_g_type_get_struct_size (G_VALUE_TYPE (value)); + i = first_member; + while (i != G_MAXUINT) + { + if (i >= size) + goto error; + + type = dbus_g_type_get_struct_member_type (G_VALUE_TYPE (value),i); + + g_value_init (&val, type); + + G_VALUE_COLLECT (&val, var_args, 0, &error); + if (error) + { + g_warning ("%s, %s", G_STRFUNC, error); + g_free (error); + g_value_unset (&val); + goto error; + } + + dbus_g_type_struct_set_member (value, i, &val); + + g_value_unset (&val); + i = va_arg (var_args, guint); + } + va_end (var_args); + return TRUE; +error: + va_end (var_args); + return FALSE; +} + diff --git a/glib/dbus-gtype-specialized.h b/glib/dbus-gtype-specialized.h index 505c95bc..1d260092 100644 --- a/glib/dbus-gtype-specialized.h +++ b/glib/dbus-gtype-specialized.h @@ -34,11 +34,21 @@ GType dbus_g_type_get_collection (const char *contain GType dbus_g_type_get_map (const char *container, GType key_specialization, GType value_specialization); +GType dbus_g_type_get_structv (const char *container, + guint num_items, + GType *types); +GType dbus_g_type_get_struct (const char *container, + GType first_type, + ...); gboolean dbus_g_type_is_collection (GType gtype); gboolean dbus_g_type_is_map (GType gtype); +gboolean dbus_g_type_is_struct (GType gtype); GType dbus_g_type_get_collection_specialization (GType gtype); GType dbus_g_type_get_map_key_specialization (GType gtype); GType dbus_g_type_get_map_value_specialization (GType gtype); +GType dbus_g_type_get_struct_member_type (GType gtype, + guint index); +guint dbus_g_type_get_struct_size (GType gtype); typedef void (*DBusGTypeSpecializedCollectionIterator) (const GValue *val, gpointer user_data); @@ -81,6 +91,21 @@ void dbus_g_type_map_value_iterate (const GValue DBusGTypeSpecializedMapIterator iterator, gpointer user_data); +gboolean dbus_g_type_struct_get_member (const GValue *value, + guint index, + GValue *dest); +gboolean dbus_g_type_struct_set_member (GValue *value, + guint index, + const GValue *src); + +gboolean dbus_g_type_struct_get (const GValue *value, + guint member, + ...); + +gboolean dbus_g_type_struct_set (GValue *value, + guint member, + ...); + typedef gpointer (*DBusGTypeSpecializedConstructor) (GType type); typedef void (*DBusGTypeSpecializedFreeFunc) (GType type, gpointer val); typedef gpointer (*DBusGTypeSpecializedCopyFunc) (GType type, gpointer src); @@ -116,6 +141,15 @@ typedef struct { DBusGTypeSpecializedMapAppendFunc append_func; } DBusGTypeSpecializedMapVtable; +typedef gboolean (*DBusGTypeSpecializedStructGetMember) (GType type, gpointer instance, guint member, GValue *ret_value); +typedef gboolean (*DBusGTypeSpecializedStructSetMember) (GType type, gpointer instance, guint member, const GValue *new_value); + +typedef struct { + DBusGTypeSpecializedVtable base_vtable; + DBusGTypeSpecializedStructGetMember get_member; + DBusGTypeSpecializedStructSetMember set_member; +} DBusGTypeSpecializedStructVtable; + void dbus_g_type_specialized_init (void); void dbus_g_type_register_collection (const char *name, @@ -128,6 +162,15 @@ void dbus_g_type_register_map (const char const DBusGTypeSpecializedMapVtable* dbus_g_type_map_peek_vtable (GType map_type); const DBusGTypeSpecializedCollectionVtable* dbus_g_type_collection_peek_vtable (GType collection_type); +void dbus_g_type_register_struct (const char *name, + const DBusGTypeSpecializedStructVtable *vtable, + guint flags); + +const DBusGTypeSpecializedMapVtable* dbus_g_type_map_peek_vtable (GType map_type); +const DBusGTypeSpecializedCollectionVtable* dbus_g_type_collection_peek_vtable (GType collection_type); + +const DBusGTypeSpecializedStructVtable* dbus_g_type_struct_peek_vtable (GType struct_type); + G_END_DECLS #endif diff --git a/glib/dbus-gvalue-utils.c b/glib/dbus-gvalue-utils.c index 04c0c3e8..f64a921f 100644 --- a/glib/dbus-gvalue-utils.c +++ b/glib/dbus-gvalue-utils.c @@ -334,6 +334,16 @@ hash_free_from_gtype (GType gtype, GDestroyNotify *func) return TRUE; } } + else if (dbus_g_type_is_struct (gtype)) + { + const DBusGTypeSpecializedStructVtable *vtable; + vtable = dbus_g_type_struct_peek_vtable (gtype); + if (vtable->base_vtable.simple_free_func) + { + *func = vtable->base_vtable.simple_free_func; + return TRUE; + } + } return FALSE; } } @@ -611,6 +621,67 @@ hashtable_simple_free (gpointer val) g_hash_table_destroy (val); } +static gpointer +valuearray_constructor (GType type) +{ + GValueArray *ret; + guint size = dbus_g_type_get_struct_size (type); + guint i; + ret = g_value_array_new (size); + for (i=0; i < size; i++) + { + GValue val = {0,}; + g_value_init (&val, dbus_g_type_get_struct_member_type (type, i)); + g_value_array_append(ret, &val); + } + return (gpointer)ret; +} + +static gpointer +valuearray_copy (GType type, gpointer src) +{ + return g_value_array_copy ((GValueArray*) src); +} + +static void +valuearray_simple_free (gpointer val) +{ + g_value_array_free (val); +} + +static gboolean +valuearray_get_member (GType type, gpointer instance, + guint member, GValue *ret) +{ + GValueArray *va = (GValueArray*) instance; + const GValue *val; + if (member < dbus_g_type_get_struct_size (type)) + { + val = g_value_array_get_nth (va, member); + g_value_copy (val, ret); + return TRUE; + } + else + return FALSE; +} + +static gboolean +valuearray_set_member (GType type, gpointer instance, + guint member, const GValue *member_type) +{ + GValueArray *va = (GValueArray*) instance; + GValue *vp; + if (member < dbus_g_type_get_struct_size (type)) + { + vp = g_value_array_get_nth (va, member); + g_value_copy (member_type, vp); + return TRUE; + } + else + return FALSE; +} + + static gpointer array_constructor (GType type) { @@ -945,10 +1016,24 @@ _dbus_g_type_specialized_builtins_init (void) hashtable_append }; + static const DBusGTypeSpecializedStructVtable valuearray_vtable = { + { + valuearray_constructor, + NULL, + valuearray_copy, + valuearray_simple_free, + NULL, + NULL + }, + valuearray_get_member, + valuearray_set_member + }; + dbus_g_type_register_collection ("GSList", &slist_vtable, 0); dbus_g_type_register_collection ("GArray", &array_vtable, 0); dbus_g_type_register_collection ("GPtrArray", &ptrarray_vtable, 0); dbus_g_type_register_map ("GHashTable", &hashtable_vtable, 0); + dbus_g_type_register_struct ("GValueArray", &valuearray_vtable, 0); } #ifdef DBUS_BUILD_TESTS @@ -1160,6 +1245,105 @@ _dbus_gvalue_utils_test (const char *datadir) g_value_unset (&val); } + type = dbus_g_type_get_struct ("GValueArray", G_TYPE_STRING, G_TYPE_UINT, DBUS_TYPE_G_OBJECT_PATH, G_TYPE_INVALID); + g_assert (dbus_g_type_is_struct (type)); + g_assert (dbus_g_type_get_struct_size (type) == 3); + g_assert (dbus_g_type_get_struct_member_type (type, 0) == G_TYPE_STRING); + g_assert (dbus_g_type_get_struct_member_type (type, 1) == G_TYPE_UINT); + g_assert (dbus_g_type_get_struct_member_type (type, 2) == DBUS_TYPE_G_OBJECT_PATH); + { + GValueArray *instance; + GValue val = {0, }; + GValue memval = {0, }; + + instance = dbus_g_type_specialized_construct (type); + + g_assert (instance->n_values == 3); + + g_value_init (&val, type); + g_value_set_boxed_take_ownership (&val, instance); + + g_value_init (&memval, G_TYPE_STRING); + g_value_set_static_string (&memval, "foo"); + dbus_g_type_struct_set_member (&val, 0, &memval); + g_value_unset (&memval); + + g_value_init (&memval, G_TYPE_UINT); + g_value_set_uint (&memval, 42); + dbus_g_type_struct_set_member (&val, 1, &memval); + g_value_unset (&memval); + + g_value_init (&memval, DBUS_TYPE_G_OBJECT_PATH); + g_value_set_static_boxed (&memval, "/bar/moo/foo/baz"); + dbus_g_type_struct_set_member (&val, 2, &memval); + g_value_unset (&memval); + + g_assert (instance->n_values == 3); + + g_value_init (&memval, G_TYPE_STRING); + dbus_g_type_struct_get_member (&val, 0, &memval); + g_assert (0 == strcmp (g_value_get_string (&memval), "foo")); + g_value_unset (&memval); + + g_value_init (&memval, G_TYPE_UINT); + dbus_g_type_struct_get_member (&val, 1, &memval); + g_assert (g_value_get_uint (&memval) == 42); + g_value_unset (&memval); + + g_value_init (&memval, DBUS_TYPE_G_OBJECT_PATH); + dbus_g_type_struct_get_member (&val, 2, &memval); + g_assert (0 == strcmp ((gchar*) g_value_get_boxed (&memval), + "/bar/moo/foo/baz")); + g_value_unset (&memval); + + g_value_unset (&val); + } + + type = dbus_g_type_get_struct ("GValueArray", G_TYPE_STRING, G_TYPE_UINT, DBUS_TYPE_G_OBJECT_PATH, G_TYPE_INVALID); + g_assert (dbus_g_type_is_struct (type)); + g_assert (dbus_g_type_get_struct_size (type) == 3); + g_assert (dbus_g_type_get_struct_member_type (type, 0) == G_TYPE_STRING); + g_assert (dbus_g_type_get_struct_member_type (type, 1) == G_TYPE_UINT); + g_assert (dbus_g_type_get_struct_member_type (type, 2) == DBUS_TYPE_G_OBJECT_PATH); + { + GValueArray *instance; + GValue val = {0, }; + + instance = dbus_g_type_specialized_construct (type); + + g_assert (instance->n_values == 3); + + g_value_init (&val, type); + g_value_set_boxed_take_ownership (&val, instance); + + dbus_g_type_struct_set (&val, + 0,"foo", + 1, 42, + 2, "/bar/moo/foo/baz", + G_MAXUINT); + + g_assert (instance->n_values == 3); + + { + gchar *string; + guint intval; + gchar *path; + + dbus_g_type_struct_get (&val, + 0, &string, + 1, &intval, + 2, &path, + G_MAXUINT); + + g_assert (0 == strcmp (string, "foo")); + g_assert (intval == 42); + g_assert (0 == strcmp (path, "/bar/moo/foo/baz")); + } + + g_value_unset (&val); + } + + return TRUE; } diff --git a/glib/dbus-gvalue-utils.h b/glib/dbus-gvalue-utils.h index 139f4a31..cba3b61a 100644 --- a/glib/dbus-gvalue-utils.h +++ b/glib/dbus-gvalue-utils.h @@ -29,7 +29,7 @@ G_BEGIN_DECLS -void _dbus_g_type_specialized_builtins_init (void); +void _dbus_g_type_specialized_builtins_init (void); gboolean _dbus_g_type_is_fixed (GType gtype); guint _dbus_g_type_fixed_get_size (GType gtype); diff --git a/glib/dbus-gvalue.c b/glib/dbus-gvalue.c index e332e71a..3e8cf1e7 100644 --- a/glib/dbus-gvalue.c +++ b/glib/dbus-gvalue.c @@ -107,6 +107,13 @@ static gboolean demarshal_collection_array (DBusGValueMarshalCtx *cont DBusMessageIter *iter, GValue *value, GError **error); +static gboolean marshal_struct (DBusMessageIter *iter, + const GValue *value); +static gboolean demarshal_struct (DBusGValueMarshalCtx *context, + DBusMessageIter *iter, + GValue *value, + GError **error); + typedef gboolean (*DBusGValueMarshalFunc) (DBusMessageIter *iter, const GValue *value); @@ -346,6 +353,7 @@ dbus_g_object_path_get_g_type (void) return type_id; } + char * _dbus_gtype_to_signature (GType gtype) { @@ -377,6 +385,21 @@ _dbus_gtype_to_signature (GType gtype) g_free (key_subsig); g_free (val_subsig); } + else if (dbus_g_type_is_struct (gtype)) + { + guint i, size; + GString *sig; + size = dbus_g_type_get_struct_size (gtype); + sig = g_string_sized_new (size+2); /*some sensible starting size*/ + g_string_assign (sig, DBUS_STRUCT_BEGIN_CHAR_AS_STRING); + for (i=0; i < size; i++) + { + g_string_append (sig, _dbus_gtype_to_signature ( + dbus_g_type_get_struct_member_type (gtype, i))); + } + g_string_append (sig, DBUS_STRUCT_END_CHAR_AS_STRING); + ret = g_string_free (sig, FALSE); + } else { typedata = g_type_get_qdata (gtype, dbus_g_type_metadata_data_quark ()); @@ -384,7 +407,6 @@ _dbus_gtype_to_signature (GType gtype) return NULL; ret = g_strdup (typedata->sig); } - return ret; } @@ -851,6 +873,76 @@ demarshal_map (DBusGValueMarshalCtx *context, return TRUE; } +static gboolean +demarshal_struct (DBusGValueMarshalCtx *context, + DBusMessageIter *iter, + GValue *value, + GError **error) +{ + int current_type; + DBusMessageIter subiter; + guint i, size; + GValue val = {0,}; + GType elt_type; + + current_type = dbus_message_iter_get_arg_type (iter); + if (current_type != DBUS_TYPE_STRUCT) + { + g_set_error (error, + DBUS_GERROR, + DBUS_GERROR_INVALID_ARGS, + _("Expected D-BUS struct, got type code \'%c\'"), (guchar) current_type); + return FALSE; + } + + dbus_message_iter_recurse (iter, &subiter); + + g_value_set_boxed_take_ownership (value, + dbus_g_type_specialized_construct (G_VALUE_TYPE (value))); + + size = dbus_g_type_get_struct_size (G_VALUE_TYPE (value)); + + for (i=0; i < size; i++) + { + + elt_type = dbus_g_type_get_struct_member_type (G_VALUE_TYPE(value), i); + if (elt_type == G_TYPE_INVALID) + { + g_value_unset (value); + g_set_error (error, + DBUS_GERROR, + DBUS_GERROR_INVALID_ARGS, + _("Couldn't demarshal argument, " + "struct type %s has no member %d"), + g_type_name (G_VALUE_TYPE(value)), i); + return FALSE; + } + + g_value_init (&val, elt_type); + + if (!_dbus_gvalue_demarshal (context, &subiter, &val, error)) + { + g_value_unset (&val); + g_value_unset (value); + return FALSE; + } + if (!dbus_g_type_struct_set_member (value, i, &val)) + { + g_value_unset (&val); + g_value_unset (value); + return FALSE; + } + + dbus_message_iter_next (&subiter); + g_value_unset (&val); + } + + g_assert (dbus_message_iter_get_arg_type (&subiter) == DBUS_TYPE_INVALID); + + return TRUE; +} + + static DBusGValueDemarshalFunc get_type_demarshaller (GType type) { @@ -865,6 +957,8 @@ get_type_demarshaller (GType type) return demarshal_collection; if (dbus_g_type_is_map (type)) return demarshal_map; + if (dbus_g_type_is_struct (type)) + return demarshal_struct; g_warning ("No demarshaller registered for type \"%s\"", g_type_name (type)); return NULL; @@ -1452,6 +1546,48 @@ marshal_map (DBusMessageIter *iter, goto out; } +static gboolean +marshal_struct (DBusMessageIter *iter, + const GValue *value) +{ + GType gtype; + DBusMessageIter subiter; + gboolean ret; + guint size, i; + GValue val = {0,}; + + gtype = G_VALUE_TYPE (value); + + ret = FALSE; + + size = dbus_g_type_get_struct_size (gtype); + + if (!dbus_message_iter_open_container (iter, + DBUS_TYPE_STRUCT, + NULL, + &subiter)) + goto oom; + + for (i = 0; i < size; i++) + { + g_value_init (&val, dbus_g_type_get_struct_member_type + (G_VALUE_TYPE(value), i)); + if (!dbus_g_type_struct_get_member (value, i, &val)) + return FALSE; + if (!_dbus_gvalue_marshal (&subiter, &val)) + return FALSE; + g_value_unset(&val); + } + + if (!dbus_message_iter_close_container (iter, &subiter)) + goto oom; + + return TRUE; + oom: + g_error ("out of memory"); + return FALSE; +} + static gboolean marshal_variant (DBusMessageIter *iter, const GValue *value) @@ -1504,6 +1640,8 @@ get_type_marshaller (GType type) return marshal_collection; if (dbus_g_type_is_map (type)) return marshal_map; + if (dbus_g_type_is_struct (type)) + return marshal_struct; g_warning ("No marshaller registered for type \"%s\"", g_type_name (type)); return NULL; @@ -1697,17 +1835,15 @@ _dbus_gvalue_test (const char *test_data_dir) assert_bidirectional_mapping (G_TYPE_UCHAR, DBUS_TYPE_BYTE_AS_STRING); assert_bidirectional_mapping (G_TYPE_UINT, DBUS_TYPE_UINT32_AS_STRING); - assert_signature_maps_to (DBUS_STRUCT_BEGIN_CHAR_AS_STRING DBUS_TYPE_STRING_AS_STRING DBUS_STRUCT_END_CHAR_AS_STRING, G_TYPE_VALUE_ARRAY); - assert_signature_maps_to (DBUS_STRUCT_BEGIN_CHAR_AS_STRING DBUS_STRUCT_END_CHAR_AS_STRING, G_TYPE_VALUE_ARRAY); - assert_signature_maps_to (DBUS_STRUCT_BEGIN_CHAR_AS_STRING DBUS_TYPE_UINT32_AS_STRING DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_STRING_AS_STRING DBUS_STRUCT_END_CHAR_AS_STRING, G_TYPE_VALUE_ARRAY); - assert_bidirectional_mapping (dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_VALUE), - DBUS_TYPE_ARRAY_AS_STRING DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING DBUS_DICT_ENTRY_END_CHAR_AS_STRING); + DBUS_TYPE_ARRAY_AS_STRING DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING DBUS_DICT_ENTRY_END_CHAR_AS_STRING); assert_bidirectional_mapping (dbus_g_type_get_collection ("GPtrArray", DBUS_TYPE_G_OBJECT_PATH), DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING); assert_bidirectional_mapping (dbus_g_type_get_collection ("GArray", G_TYPE_INT), DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_INT32_AS_STRING); + assert_bidirectional_mapping (dbus_g_type_get_struct ("GValueArray", G_TYPE_INT, G_TYPE_STRING, DBUS_TYPE_G_OBJECT_PATH, G_TYPE_INVALID), + DBUS_STRUCT_BEGIN_CHAR_AS_STRING DBUS_TYPE_INT32_AS_STRING DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING DBUS_STRUCT_END_CHAR_AS_STRING ); return TRUE; } -- cgit