diff -r 000000000000 -r e4d67989cc36 ofdbus/dbus-glib/dbus/dbus-gvalue.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ofdbus/dbus-glib/dbus/dbus-gvalue.c Tue Feb 02 02:01:42 2010 +0200 @@ -0,0 +1,1908 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* dbus-gvalue.c GValue to-from DBusMessageIter + * + * Copyright (C) 2004 Ximian, Inc. + * Copyright (C) 2005 Red Hat, Inc. + * Portion Copyright © 2008 Nokia Corporation and/or its subsidiary(-ies). All rights reserved. + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "config.h" +#include "dbus-gtest.h" +#include "dbus-gvalue.h" +#include "dbus-gsignature.h" +#include "dbus-gobject.h" +#include "dbus-gvalue-utils.h" +#include "dbus/dbus-glib.h" +#include +#include +#ifndef __SYMBIAN32__ +#include +#include +#define _(x) dgettext (GETTEXT_PACKAGE, x) +#define N_(x) x +#else + +#define _(x) x +#define N_(x) x +#endif + + +#include "dbus/dbus-signature.h" +#ifdef __SYMBIAN32__ +#include "libdbus_glib_wsd_solution.h" +#endif + +static gboolean demarshal_static_variant (DBusGValueMarshalCtx *context, + DBusMessageIter *iter, + GValue *value, + GError **error); + + +static gboolean marshal_basic (DBusMessageIter *iter, + const GValue *value); +static gboolean demarshal_basic (DBusGValueMarshalCtx *context, + DBusMessageIter *iter, + GValue *value, + GError **error); +static gboolean marshal_strv (DBusMessageIter *iter, + const GValue *value); +static gboolean demarshal_strv (DBusGValueMarshalCtx *context, + DBusMessageIter *iter, + GValue *value, + GError **error); +static gboolean marshal_valuearray (DBusMessageIter *iter, + const GValue *value); +static gboolean demarshal_valuearray (DBusGValueMarshalCtx *context, + DBusMessageIter *iter, + GValue *value, + GError **error); +static gboolean marshal_variant (DBusMessageIter *iter, + const GValue *value); +static gboolean demarshal_variant (DBusGValueMarshalCtx *context, + DBusMessageIter *iter, + GValue *value, + GError **error); +static gboolean marshal_proxy (DBusMessageIter *iter, + const GValue *value); +static gboolean demarshal_proxy (DBusGValueMarshalCtx *context, + DBusMessageIter *iter, + GValue *value, + GError **error); +static gboolean marshal_object_path (DBusMessageIter *iter, + const GValue *value); +static gboolean demarshal_object_path (DBusGValueMarshalCtx *context, + DBusMessageIter *iter, + GValue *value, + GError **error); +static gboolean marshal_object (DBusMessageIter *iter, + const GValue *value); +static gboolean demarshal_object (DBusGValueMarshalCtx *context, + DBusMessageIter *iter, + GValue *value, + GError **error); +static gboolean marshal_map (DBusMessageIter *iter, + const GValue *value); +static gboolean demarshal_map (DBusGValueMarshalCtx *context, + DBusMessageIter *iter, + GValue *value, + GError **error); + +static gboolean marshal_collection (DBusMessageIter *iter, + const GValue *value); +static gboolean marshal_collection_ptrarray (DBusMessageIter *iter, + const GValue *value); +static gboolean marshal_collection_array (DBusMessageIter *iter, + const GValue *value); +static gboolean demarshal_collection (DBusGValueMarshalCtx *context, + DBusMessageIter *iter, + GValue *value, + GError **error); +static gboolean demarshal_collection_ptrarray (DBusGValueMarshalCtx *context, + DBusMessageIter *iter, + GValue *value, + GError **error); +static gboolean demarshal_collection_array (DBusGValueMarshalCtx *context, + 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); +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; + + +#if EMULATOR +GET_STATIC_VAR_FROM_TLS(quark,dbus_gvalue,GQuark ) +#define quark (*GET_DBUS_WSD_VAR_NAME(quark,dbus_gvalue,s)()) +#endif + +static GQuark +dbus_g_type_metadata_data_quark () +{ +#ifndef EMULATOR + static GQuark quark; +#endif + 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); +} + +static void +register_basic (int typecode, const DBusGTypeMarshalData *typedata) +{ + set_type_metadata (_dbus_gtype_from_basic_typecode (typecode), typedata); +} + +#if EMULATOR +GET_STATIC_VAR_FROM_TLS(types_initialized,dbus_gvalue,gboolean ) +#define types_initialized (*GET_DBUS_WSD_VAR_NAME(types_initialized,dbus_gvalue,s)()) + +#endif + +void +_dbus_g_value_types_init (void) +{ + +#ifndef EMULATOR + static gboolean types_initialized; +#endif + + static const DBusGTypeMarshalVtable basic_vtable = { + marshal_basic, + demarshal_basic + }; + + if (types_initialized) + return; + + dbus_g_type_specialized_init (); + _dbus_g_type_specialized_builtins_init (); + + /* 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); + } + /* fundamental GTypes that don't map 1:1 with D-BUS types */ + { + static const DBusGTypeMarshalData typedata = { + DBUS_TYPE_BYTE_AS_STRING, + &basic_vtable, + }; + set_type_metadata (G_TYPE_CHAR, &typedata); + } + { + static const DBusGTypeMarshalData typedata = { + DBUS_TYPE_INT32_AS_STRING, + &basic_vtable, + }; + set_type_metadata (G_TYPE_LONG, &typedata); + } + { + static const DBusGTypeMarshalData typedata = { + DBUS_TYPE_UINT32_AS_STRING, + &basic_vtable, + }; + set_type_metadata (G_TYPE_ULONG, &typedata); + } + { + static const DBusGTypeMarshalData typedata = { + DBUS_TYPE_DOUBLE_AS_STRING, + &basic_vtable, + }; + set_type_metadata (G_TYPE_FLOAT, &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); + }; + + + /* Register some types specific to the D-BUS GLib bindings */ + { + 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_path, + demarshal_object_path + }; + static const DBusGTypeMarshalData typedata = { + DBUS_TYPE_OBJECT_PATH_AS_STRING, + &vtable + }; + set_type_metadata (DBUS_TYPE_G_OBJECT_PATH, &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); + } + + types_initialized = TRUE; +} + +/** + * Get the GLib type ID for a DBusGObjectPath boxed type. + * + * Returns: GLib type + */ + #if EMULATOR +GET_STATIC_VAR_FROM_TLS(type_id,dbus_gvalue,GType ) +#define type_id (*GET_DBUS_WSD_VAR_NAME(type_id,dbus_gvalue,s)()) +#endif + + #ifdef __SYMBIAN32__ + EXPORT_C + #endif +GType +dbus_g_object_path_get_g_type (void) +{ + #ifndef EMULATOR + static GType type_id = 0; +#endif + + + + if (!type_id) + type_id = g_boxed_type_register_static ("DBusGObjectPath", + (GBoxedCopyFunc) g_strdup, + (GBoxedFreeFunc) g_free); + return type_id; +} + + +char * +_dbus_gtype_to_signature (GType gtype) +{ + char *ret; + DBusGTypeMarshalData *typedata; + + if (dbus_g_type_is_collection (gtype)) + { + GType elt_gtype; + char *subsig; + + elt_gtype = dbus_g_type_get_collection_specialization (gtype); + subsig = _dbus_gtype_to_signature (elt_gtype); + ret = g_strconcat (DBUS_TYPE_ARRAY_AS_STRING, subsig, NULL); + g_free (subsig); + } + else if (dbus_g_type_is_map (gtype)) + { + GType key_gtype; + GType val_gtype; + char *key_subsig; + char *val_subsig; + + key_gtype = dbus_g_type_get_map_key_specialization (gtype); + val_gtype = dbus_g_type_get_map_value_specialization (gtype); + key_subsig = _dbus_gtype_to_signature (key_gtype); + val_subsig = _dbus_gtype_to_signature (val_gtype); + ret = g_strconcat (DBUS_TYPE_ARRAY_AS_STRING DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING, key_subsig, val_subsig, DBUS_DICT_ENTRY_END_CHAR_AS_STRING, NULL); + 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++) + { + gchar *subsig; + subsig = _dbus_gtype_to_signature ( + dbus_g_type_get_struct_member_type (gtype, i)); + g_string_append (sig, subsig); + g_free (subsig); + } + 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 ()); + if (typedata == NULL) + return NULL; + ret = g_strdup (typedata->sig); + } + return ret; +} + +char * +_dbus_gvalue_to_signature (const GValue *val) +{ + GType gtype; + + gtype = G_VALUE_TYPE (val); + if (g_type_is_a (gtype, G_TYPE_VALUE_ARRAY)) + { + GString *str; + guint i; + GValueArray *array; + + array = g_value_get_boxed (val); + + str = g_string_new (DBUS_STRUCT_BEGIN_CHAR_AS_STRING); + for (i = 0; i < array->n_values; i++) + { + char *sig; + sig = _dbus_gvalue_to_signature (g_value_array_get_nth (array, i)); + g_string_append (str, sig); + g_free (sig); + } + g_string_append (str, DBUS_STRUCT_END_CHAR_AS_STRING); + + return g_string_free (str, FALSE); + } + else + return _dbus_gtype_to_signature (gtype); +} + +static gboolean +demarshal_basic (DBusGValueMarshalCtx *context, + DBusMessageIter *iter, + GValue *value, + GError **error) +{ + int current_type; + + current_type = dbus_message_iter_get_arg_type (iter); + g_assert (dbus_type_is_basic (current_type)); + + switch (current_type) + { + case DBUS_TYPE_BOOLEAN: + { + dbus_bool_t bool; + dbus_message_iter_get_basic (iter, &bool); + g_value_set_boolean (value, bool); + return TRUE; + } + case DBUS_TYPE_BYTE: + { + unsigned char byte; + dbus_message_iter_get_basic (iter, &byte); + g_value_set_uchar (value, byte); + return TRUE; + } + case DBUS_TYPE_INT32: + { + dbus_int32_t intval; + dbus_message_iter_get_basic (iter, &intval); + g_value_set_int (value, intval); + return TRUE; + } + case DBUS_TYPE_UINT32: + { + dbus_uint32_t intval; + dbus_message_iter_get_basic (iter, &intval); + g_value_set_uint (value, intval); + return TRUE; + } + case DBUS_TYPE_INT64: + { + dbus_int64_t intval; + dbus_message_iter_get_basic (iter, &intval); + g_value_set_int64 (value, intval); + return TRUE; + } + case DBUS_TYPE_UINT64: + { + dbus_uint64_t intval; + dbus_message_iter_get_basic (iter, &intval); + g_value_set_uint64 (value, intval); + return TRUE; + } + case DBUS_TYPE_DOUBLE: + { + double dval; + dbus_message_iter_get_basic (iter, &dval); + g_value_set_double (value, dval); + return TRUE; + } + case DBUS_TYPE_INT16: + { + dbus_int16_t v; + dbus_message_iter_get_basic (iter, &v); + g_value_set_int (value, v); + return TRUE; + } + case DBUS_TYPE_UINT16: + { + dbus_uint16_t v; + dbus_message_iter_get_basic (iter, &v); + g_value_set_uint (value, v); + return TRUE; + } + case DBUS_TYPE_STRING: + { + const char *s; + dbus_message_iter_get_basic (iter, &s); + g_value_set_string (value, s); + return TRUE; + } + 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) +{ + DBusGProxy *new_proxy; + const char *objpath; + int current_type; + + current_type = dbus_message_iter_get_arg_type (iter); + if (current_type != DBUS_TYPE_OBJECT_PATH) + { + g_set_error (error, + DBUS_GERROR, + DBUS_GERROR_INVALID_ARGS, + _("Expected D-BUS object path, got type code \'%c\'"), (guchar) current_type); + return FALSE; + } + + g_assert (context->proxy != NULL); + + 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_path (DBusGValueMarshalCtx *context, + DBusMessageIter *iter, + GValue *value, + GError **error) +{ + const char *objpath; + int current_type; + + current_type = dbus_message_iter_get_arg_type (iter); + if (current_type != DBUS_TYPE_OBJECT_PATH) + { + g_set_error (error, + DBUS_GERROR, + DBUS_GERROR_INVALID_ARGS, + _("Expected D-BUS object path, got type code \'%c\'"), (guchar) current_type); + return FALSE; + } + + dbus_message_iter_get_basic (iter, &objpath); + + g_value_set_boxed_take_ownership (value, g_strdup (objpath)); + + 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); + if (current_type != DBUS_TYPE_OBJECT_PATH) + { + g_set_error (error, + DBUS_GERROR, + DBUS_GERROR_INVALID_ARGS, + _("Expected D-BUS object path, got type code \'%c\'"), (guchar) current_type); + return FALSE; + } + 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; + + current_type = dbus_message_iter_get_arg_type (iter); + if (current_type != DBUS_TYPE_ARRAY) + { + g_set_error (error, + DBUS_GERROR, + DBUS_GERROR_INVALID_ARGS, + _("Expected D-BUS array, got type code \'%c\'"), (guchar) current_type); + return FALSE; + } + + dbus_message_iter_recurse (iter, &subiter); + + current_type = dbus_message_iter_get_arg_type (&subiter); + if (current_type != DBUS_TYPE_INVALID + && current_type != DBUS_TYPE_STRING) + { + g_set_error (error, + DBUS_GERROR, + DBUS_GERROR_INVALID_ARGS, + _("Expected D-BUS string, got type code \'%c\'"), (guchar) current_type); + return FALSE; + } + + 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_valuearray (DBusGValueMarshalCtx *context, + DBusMessageIter *iter, + GValue *value, + GError **error) +{ + int current_type; + GValueArray *ret; + DBusMessageIter subiter; + + 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); + + ret = g_value_array_new (12); + + while ((current_type = dbus_message_iter_get_arg_type (&subiter)) != DBUS_TYPE_INVALID) + { + GValue *val; + GType elt_type; + char *current_sig; + + g_value_array_append (ret, NULL); + val = g_value_array_get_nth (ret, ret->n_values - 1); + + current_sig = dbus_message_iter_get_signature (&subiter); + elt_type = _dbus_gtype_from_signature (current_sig, TRUE); + + dbus_free (current_sig); + if (elt_type == G_TYPE_INVALID) + { + g_value_array_free (ret); + g_set_error (error, + DBUS_GERROR, + DBUS_GERROR_INVALID_ARGS, + _("Couldn't demarshal argument with signature \"%s\""), current_sig); + return FALSE; + } + + g_value_init (val, elt_type); + + if (!_dbus_gvalue_demarshal (context, &subiter, val, error)) + { + g_value_array_free (ret); + return FALSE; + } + + dbus_message_iter_next (&subiter); + } + + g_value_set_boxed_take_ownership (value, ret); + + return TRUE; +} + +static gboolean +demarshal_map (DBusGValueMarshalCtx *context, + DBusMessageIter *iter, + GValue *value, + GError **error) +{ + GType gtype; + DBusMessageIter subiter; + int current_type; + gpointer ret; + GType key_gtype; + GType value_gtype; + DBusGTypeSpecializedAppendContext appendctx; + + current_type = dbus_message_iter_get_arg_type (iter); + if (current_type != DBUS_TYPE_ARRAY) + { + g_set_error (error, + DBUS_GERROR, + DBUS_GERROR_INVALID_ARGS, + _("Expected D-BUS array, got type code \'%c\'"), (guchar) current_type); + return FALSE; + } + + gtype = G_VALUE_TYPE (value); + + dbus_message_iter_recurse (iter, &subiter); + + current_type = dbus_message_iter_get_arg_type (&subiter); + if (current_type != DBUS_TYPE_INVALID + && current_type != DBUS_TYPE_DICT_ENTRY) + { + g_set_error (error, + DBUS_GERROR, + DBUS_GERROR_INVALID_ARGS, + _("Expected D-BUS dict entry, got type code \'%c\'"), (guchar) current_type); + return FALSE; + } + + key_gtype = dbus_g_type_get_map_key_specialization (gtype); + value_gtype = dbus_g_type_get_map_value_specialization (gtype); + + ret = dbus_g_type_specialized_construct (gtype); + g_value_set_boxed_take_ownership (value, ret); + + dbus_g_type_specialized_init_append (value, &appendctx); + + 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_type_specialized_map_append (&appendctx, &key_value, &value_value); + /* Ownership of values passes to map, don't unset */ + + dbus_message_iter_next (&subiter); + } + + 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) +{ + DBusGTypeMarshalData *typedata; + + typedata = g_type_get_qdata (type, dbus_g_type_metadata_data_quark ()); + if (typedata == NULL) + { + if (g_type_is_a (type, G_TYPE_VALUE_ARRAY)) + return demarshal_valuearray; + if (dbus_g_type_is_collection (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; + } + g_assert (typedata->vtable); + return typedata->vtable->demarshaller; +} + +static gboolean +demarshal_collection (DBusGValueMarshalCtx *context, + DBusMessageIter *iter, + GValue *value, + GError **error) +{ + GType coltype; + GType subtype; + + coltype = G_VALUE_TYPE (value); + subtype = dbus_g_type_get_collection_specialization (coltype); + + if (_dbus_g_type_is_fixed (subtype)) + return demarshal_collection_array (context, iter, value, error); + else + return demarshal_collection_ptrarray (context, iter, value, error); +} + +static gboolean +demarshal_collection_ptrarray (DBusGValueMarshalCtx *context, + DBusMessageIter *iter, + GValue *value, + GError **error) +{ + GType coltype; + GType subtype; + gpointer instance; + DBusGTypeSpecializedAppendContext ctx; + DBusGValueDemarshalFunc demarshaller; + DBusMessageIter subiter; + int current_type; + + current_type = dbus_message_iter_get_arg_type (iter); + + if (current_type != DBUS_TYPE_ARRAY) + { + g_set_error (error, + DBUS_GERROR, + DBUS_GERROR_INVALID_ARGS, + _("Expected D-BUS array, got type code \'%c\'"), (guchar) current_type); + return FALSE; + } + + dbus_message_iter_recurse (iter, &subiter); + + coltype = G_VALUE_TYPE (value); + subtype = dbus_g_type_get_collection_specialization (coltype); + + demarshaller = get_type_demarshaller (subtype); + + if (!demarshaller) + { + g_set_error (error, + DBUS_GERROR, + DBUS_GERROR_INVALID_ARGS, + _("No demarshaller registered for type \"%s\" of collection \"%s\""), + g_type_name (coltype), + g_type_name (subtype)); + return FALSE; + } + + instance = dbus_g_type_specialized_construct (coltype); + g_value_set_boxed_take_ownership (value, instance); + + dbus_g_type_specialized_init_append (value, &ctx); + + while ((current_type = dbus_message_iter_get_arg_type (&subiter)) != DBUS_TYPE_INVALID) + { + GValue eltval = {0, }; + + g_value_init (&eltval, subtype); + + if (!demarshaller (context, &subiter, &eltval, error)) + { + dbus_g_type_specialized_collection_end_append (&ctx); + g_value_unset (value); + return FALSE; + } + dbus_g_type_specialized_collection_append (&ctx, &eltval); + + dbus_message_iter_next (&subiter); + } + dbus_g_type_specialized_collection_end_append (&ctx); + + return TRUE; +} + +static gboolean +demarshal_collection_array (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 || msgarray_len == 0); + + if (msgarray_len) + g_array_append_vals (ret, msgarray, (guint) msgarray_len); + + g_value_set_boxed_take_ownership (value, ret); + + return TRUE; +} + +gboolean +_dbus_gvalue_demarshal (DBusGValueMarshalCtx *context, + DBusMessageIter *iter, + GValue *value, + GError **error) +{ + GType gtype; + DBusGValueDemarshalFunc demarshaller; + + gtype = G_VALUE_TYPE (value); + + demarshaller = get_type_demarshaller (gtype); + + if (demarshaller == NULL) + { + g_set_error (error, + DBUS_GERROR, + DBUS_GERROR_INVALID_ARGS, + _("No demarshaller registered for type \"%s\""), + g_type_name (gtype)); + return FALSE; + } + + return demarshaller (context, iter, value, error); +} + +gboolean +_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, const GValue *value) +{ + GType value_type; + + value_type = G_VALUE_TYPE (value); + + switch (value_type) + { + case G_TYPE_CHAR: + { + char b = g_value_get_char (value); + if (!dbus_message_iter_append_basic (iter, + DBUS_TYPE_BYTE, + &b)) + goto nomem; + } + return TRUE; + case G_TYPE_UCHAR: + { + unsigned char b = g_value_get_uchar (value); + if (!dbus_message_iter_append_basic (iter, + DBUS_TYPE_BYTE, + &b)) + goto nomem; + } + return TRUE; + case G_TYPE_BOOLEAN: + { + dbus_bool_t b = g_value_get_boolean (value); + if (!dbus_message_iter_append_basic (iter, + DBUS_TYPE_BOOLEAN, + &b)) + goto nomem; + } + return TRUE; + case G_TYPE_INT: + { + dbus_int32_t v = g_value_get_int (value); + if (!dbus_message_iter_append_basic (iter, + DBUS_TYPE_INT32, + &v)) + goto nomem; + } + return TRUE; + case G_TYPE_UINT: + { + dbus_uint32_t v = g_value_get_uint (value); + if (!dbus_message_iter_append_basic (iter, + DBUS_TYPE_UINT32, + &v)) + goto nomem; + } + return TRUE; + case G_TYPE_LONG: + { + dbus_int32_t v = g_value_get_long (value); + if (!dbus_message_iter_append_basic (iter, + DBUS_TYPE_INT32, + &v)) + goto nomem; + } + return TRUE; + case G_TYPE_ULONG: + { + dbus_uint32_t v = g_value_get_ulong (value); + if (!dbus_message_iter_append_basic (iter, + DBUS_TYPE_UINT32, + &v)) + goto nomem; + } + return TRUE; + case G_TYPE_INT64: + { + gint64 v = g_value_get_int64 (value); + if (!dbus_message_iter_append_basic (iter, + DBUS_TYPE_INT64, + &v)) + goto nomem; + } + return TRUE; + case G_TYPE_UINT64: + { + guint64 v = g_value_get_uint64 (value); + if (!dbus_message_iter_append_basic (iter, + DBUS_TYPE_UINT64, + &v)) + goto nomem; + } + return TRUE; + case G_TYPE_FLOAT: + { + double v = g_value_get_float (value); + + if (!dbus_message_iter_append_basic (iter, + DBUS_TYPE_DOUBLE, + &v)) + goto nomem; + } + return TRUE; + case G_TYPE_DOUBLE: + { + double v = g_value_get_double (value); + + if (!dbus_message_iter_append_basic (iter, + DBUS_TYPE_DOUBLE, + &v)) + goto nomem; + } + return TRUE; + case G_TYPE_STRING: + /* FIXME, the GValue string may not be valid UTF-8 */ + { + const char *v = g_value_get_string (value); + if (!v) + v = ""; + if (!dbus_message_iter_append_basic (iter, + DBUS_TYPE_STRING, + &v)) + goto nomem; + } + return TRUE; + + default: + { + g_assert_not_reached (); + return FALSE; + } + } + + nomem: + g_error ("no memory"); + return FALSE; +} + +static gboolean +marshal_strv (DBusMessageIter *iter, + const GValue *value) +{ + DBusMessageIter subiter; + char **array; + char **elt; + gboolean ret = FALSE; + + 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; + + if (array) + { + 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_valuearray (DBusMessageIter *iter, + const GValue *value) +{ + GValueArray *array; + guint i; + DBusMessageIter subiter; + + g_assert (G_VALUE_TYPE (value) == G_TYPE_VALUE_ARRAY); + + array = g_value_get_boxed (value); + + if (!dbus_message_iter_open_container (iter, + DBUS_TYPE_STRUCT, + NULL, + &subiter)) + goto oom; + + if (array) + { + for (i = 0; i < array->n_values; i++) + { + if (!_dbus_gvalue_marshal (&subiter, g_value_array_get_nth (array, i))) + return FALSE; + } + } + + if (!dbus_message_iter_close_container (iter, &subiter)) + goto oom; + + return TRUE; + oom: + g_error ("out of memory"); + return FALSE; +} + +static gboolean +marshal_proxy (DBusMessageIter *iter, + const 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_path (DBusMessageIter *iter, + const GValue *value) +{ + const char *path; + + g_assert (G_VALUE_TYPE (value) == DBUS_TYPE_G_OBJECT_PATH); + + path = (const char*) g_value_get_boxed (value); + + if (!dbus_message_iter_append_basic (iter, + DBUS_TYPE_OBJECT_PATH, + &path)) + return FALSE; + return TRUE; +} + +static gboolean +marshal_object (DBusMessageIter *iter, + const 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; +} + +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, key)) + goto lose; + + if (!_dbus_gvalue_marshal (&subiter, 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, + const GValue *value) +{ + GType gtype; + DBusMessageIter arr_iter; + gboolean ret; + struct DBusGLibHashMarshalData hashdata; + char *key_sig; + char *value_sig; + GType key_type; + GType value_type; + 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); + if (!key_sig) + { + g_warning ("Cannot marshal type \"%s\" in map\n", g_type_name (key_type)); + return FALSE; + } + value_sig = _dbus_gtype_to_signature (value_type); + if (!value_sig) + { + g_free (key_sig); + g_warning ("Cannot marshal type \"%s\" in map\n", g_type_name (value_type)); + return FALSE; + } + entry_sig = g_strdup_printf ("%s%s", key_sig, value_sig); + g_free (key_sig); + g_free (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_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) +{ + GType value_gtype; + DBusMessageIter subiter; + char *variant_sig; + GValue *real_value; + gboolean ret = FALSE; + + 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 ("Cannot marshal type \"%s\" in variant", g_type_name (value_gtype)); + return FALSE; + } + + if (!dbus_message_iter_open_container (iter, + DBUS_TYPE_VARIANT, + variant_sig, + &subiter)) + goto out; + + if (!_dbus_gvalue_marshal (&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 DBusGValueMarshalFunc +get_type_marshaller (GType type) +{ + DBusGTypeMarshalData *typedata; + + typedata = g_type_get_qdata (type, dbus_g_type_metadata_data_quark ()); + if (typedata == NULL) + { + if (g_type_is_a (type, G_TYPE_VALUE_ARRAY)) + return marshal_valuearray; + if (dbus_g_type_is_collection (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; + } + g_assert (typedata->vtable); + return typedata->vtable->marshaller; +} + +typedef struct +{ + DBusMessageIter *iter; + DBusGValueMarshalFunc marshaller; + gboolean err; +} DBusGValueCollectionMarshalData; + +static void +collection_marshal_iterator (const GValue *eltval, + gpointer user_data) +{ + DBusGValueCollectionMarshalData *data = user_data; + + if (data->err) + return; + + if (!data->marshaller (data->iter, eltval)) + data->err = TRUE; +} + +static gboolean +marshal_collection (DBusMessageIter *iter, + const GValue *value) +{ + GType coltype; + GType subtype; + + coltype = G_VALUE_TYPE (value); + subtype = dbus_g_type_get_collection_specialization (coltype); + + if (_dbus_g_type_is_fixed (subtype)) + return marshal_collection_array (iter, value); + else + return marshal_collection_ptrarray (iter, value); +} + +static gboolean +marshal_collection_ptrarray (DBusMessageIter *iter, + const GValue *value) +{ + GType coltype; + GType elt_gtype; + DBusGValueCollectionMarshalData data; + DBusMessageIter subiter; + char *elt_sig; + + coltype = G_VALUE_TYPE (value); + elt_gtype = dbus_g_type_get_collection_specialization (coltype); + data.marshaller = get_type_marshaller (elt_gtype); + if (!data.marshaller) + return FALSE; + + elt_sig = _dbus_gtype_to_signature (elt_gtype); + if (!elt_sig) + { + g_warning ("Cannot marshal type \"%s\" in collection\n", g_type_name (elt_gtype)); + return FALSE; + } + + if (!dbus_message_iter_open_container (iter, + DBUS_TYPE_ARRAY, + elt_sig, + &subiter)) + goto oom; + g_free (elt_sig); + + data.iter = &subiter; + data.err = FALSE; + + dbus_g_type_collection_value_iterate (value, + collection_marshal_iterator, + &data); + + if (!dbus_message_iter_close_container (iter, &subiter)) + goto oom; + + return !data.err; + oom: + g_error ("out of memory"); + return FALSE; +} + + +static gboolean +marshal_collection_array (DBusMessageIter *iter, + const GValue *value) +{ + GType elt_gtype; + DBusMessageIter subiter; + GArray *array; + guint elt_size; + char *subsignature_str; + + elt_gtype = dbus_g_type_get_collection_specialization (G_VALUE_TYPE (value)); + g_assert (_dbus_g_type_is_fixed (elt_gtype)); + subsignature_str = _dbus_gtype_to_signature (elt_gtype); + if (!subsignature_str) + { + g_warning ("Cannot marshal type \"%s\" in collection\n", g_type_name (elt_gtype)); + return FALSE; + } + + 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 oom; + + /* 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 (!array || !dbus_message_iter_append_fixed_array (&subiter, + subsignature_str[0], + &(array->data), + array->len)) + goto oom; + + if (!dbus_message_iter_close_container (iter, &subiter)) + goto oom; + g_free (subsignature_str); + return TRUE; + oom: + g_error ("out of memory"); + return FALSE; +} + +gboolean +_dbus_gvalue_marshal (DBusMessageIter *iter, + const GValue *value) +{ + GType gtype; + DBusGValueMarshalFunc marshaller; + + gtype = G_VALUE_TYPE (value); + + marshaller = get_type_marshaller (gtype); + if (marshaller == NULL) + return FALSE; + return marshaller (iter, value); +} + +#ifdef DBUS_BUILD_TESTS + +static void +assert_type_maps_to (GType gtype, const char *expected_sig) +{ + char *sig; + sig = _dbus_gtype_to_signature (gtype); + g_assert (sig != NULL); + g_assert (!strcmp (expected_sig, sig)); + g_free (sig); +} + +static void +assert_signature_maps_to (const char *sig, GType expected_gtype) +{ + g_assert (_dbus_gtype_from_signature (sig, TRUE) == expected_gtype); +} + +static void +assert_bidirectional_mapping (GType gtype, const char *expected_sig) +{ + assert_type_maps_to (gtype, expected_sig); + assert_signature_maps_to (expected_sig, gtype); +} + +/** + * @ingroup DBusGLibInternals + * @test_data_dir: + * + * Unit test for general glib stuff + * Returns: #TRUE on success. + */ + #ifdef __SYMBIAN32__ + EXPORT_C + #endif +gboolean +_dbus_gvalue_test (const char *test_data_dir) +{ + _dbus_g_value_types_init (); + + assert_bidirectional_mapping (G_TYPE_STRING, DBUS_TYPE_STRING_AS_STRING); + assert_bidirectional_mapping (G_TYPE_UCHAR, DBUS_TYPE_BYTE_AS_STRING); + assert_bidirectional_mapping (G_TYPE_UINT, DBUS_TYPE_UINT32_AS_STRING); + + 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); + 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; +} + +#endif /* DBUS_BUILD_TESTS */