mirror of
https://gitlab.freedesktop.org/dbus/dbus.git
synced 2026-05-01 09:07:58 +02:00
* dbus/dbus-message.c (dbus_message_iter_get_fixed_array): Patch from Rob Taylor <rob.taylor@collabora.co.uk> to correct a bogus assertion that the next element to read from the iter is fixed in size. This is not the case when you are at the end of the iter, because the next element type is INVALID. * dbus/dbus-string.c (_dbus_string_init_const_len): Correct a a bogus assert which means that you may not initialise a 0-length string unless you provide a non-NULL pointer. This prevented you from marshalling messages containing zero-length arrays in some cases. * glib/dbus-gvalue.c (demarshal_collection_array): Another patch from Rob to correct bogus asserts when trying to demarshal an array and get_fixed_array got you 0 elements. Append nothing to the GArray in this case. * test/glib/test-dbus-glib.c: Add a test case for round-tripping an empty array via the glib bindings. Without all of the above patches, this new test fails.
1851 lines
48 KiB
C
1851 lines
48 KiB
C
/* -*- mode: C; c-file-style: "gnu" -*- */
|
|
/* dbus-gvalue.c GValue to-from DBusMessageIter
|
|
*
|
|
* Copyright (C) 2004 Ximian, Inc.
|
|
* Copyright (C) 2005 Red Hat, Inc.
|
|
*
|
|
* 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 <string.h>
|
|
#include <glib.h>
|
|
#include <glib/gi18n.h>
|
|
#include "dbus/dbus-signature.h"
|
|
|
|
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;
|
|
|
|
static GQuark
|
|
dbus_g_type_metadata_data_quark ()
|
|
{
|
|
static GQuark quark;
|
|
if (!quark)
|
|
quark = g_quark_from_static_string ("DBusGTypeMetaData");
|
|
|
|
return quark;
|
|
}
|
|
|
|
static void
|
|
set_type_metadata (GType type, const DBusGTypeMarshalData *data)
|
|
{
|
|
g_type_set_qdata (type, dbus_g_type_metadata_data_quark (), (gpointer) data);
|
|
}
|
|
|
|
static void
|
|
register_basic (int typecode, const DBusGTypeMarshalData *typedata)
|
|
{
|
|
set_type_metadata (_dbus_gtype_from_basic_typecode (typecode), typedata);
|
|
}
|
|
|
|
void
|
|
_dbus_g_value_types_init (void)
|
|
{
|
|
static gboolean types_initialized;
|
|
|
|
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
|
|
*/
|
|
GType
|
|
dbus_g_object_path_get_g_type (void)
|
|
{
|
|
static GType type_id = 0;
|
|
|
|
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++)
|
|
{
|
|
g_string_append (sig, _dbus_gtype_to_signature (
|
|
dbus_g_type_get_struct_member_type (gtype, i)));
|
|
}
|
|
g_string_append (sig, DBUS_STRUCT_END_CHAR_AS_STRING);
|
|
ret = g_string_free (sig, FALSE);
|
|
}
|
|
else
|
|
{
|
|
typedata = g_type_get_qdata (gtype, dbus_g_type_metadata_data_quark ());
|
|
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;
|
|
|
|
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;
|
|
|
|
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 (!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
|
|
* Unit test for general glib stuff
|
|
* @returns #TRUE on success.
|
|
*/
|
|
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 */
|