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