diff options
Diffstat (limited to 'glib/dbus-gvalue.c')
| -rw-r--r-- | glib/dbus-gvalue.c | 1508 | 
1 files changed, 1319 insertions, 189 deletions
diff --git a/glib/dbus-gvalue.c b/glib/dbus-gvalue.c index eae5a458..8506330d 100644 --- a/glib/dbus-gvalue.c +++ b/glib/dbus-gvalue.c @@ -22,202 +22,680 @@   *   */ -#include <dbus-gvalue.h> +#include "dbus-gvalue.h" +#include "dbus-gobject.h" +#include "dbus-gvalue-utils.h" +#include "dbus/dbus-glib.h" +#include <string.h> +#include <glib.h> +#include <glib/gi18n.h>  #include "dbus/dbus-signature.h" -/* This is slightly evil, we don't use g_value_set_foo() functions */ +static gboolean demarshal_static_variant (DBusGValueMarshalCtx    *context, +					  DBusMessageIter         *iter, +					  GValue                  *value, +					  GError                 **error); +static gpointer dbus_g_value_copy (gpointer value); + + +struct DBusGValue +{ +  enum { +    DBUS_G_VALUE_TYPE_TOPLEVEL, +    DBUS_G_VALUE_TYPE_ITERATOR +  } type; +  union { +    struct { +      DBusGConnection        *connection; +      DBusGProxy             *proxy; +      DBusMessage            *message; +      char                   *signature; +    } toplevel; +    struct { +      DBusGValue             *toplevel; +      DBusMessageIter         iterator; +    } recurse; +  } value; +}; + +static gboolean marshal_basic                   (DBusMessageIter           *iter, +						 GValue                    *value); +static gboolean demarshal_basic                 (DBusGValueMarshalCtx      *context, +						 DBusMessageIter           *iter, +						 GValue                    *value, +						 GError                   **error); +static gboolean marshal_strv                    (DBusMessageIter           *iter, +						 GValue                    *value); +static gboolean demarshal_strv                  (DBusGValueMarshalCtx      *context, +						 DBusMessageIter           *iter, +						 GValue                    *value, +						 GError                   **error); +static gboolean marshal_variant                 (DBusMessageIter           *iter, +						 GValue                    *value); +static gboolean demarshal_variant               (DBusGValueMarshalCtx      *context, +						 DBusMessageIter           *iter, +						 GValue                    *value, +						 GError                   **error); +static gboolean marshal_garray_basic            (DBusMessageIter           *iter, +						 GValue                    *value); +static gboolean demarshal_garray_basic          (DBusGValueMarshalCtx      *context, +						 DBusMessageIter           *iter, +						 GValue                    *value, +						 GError                   **error); +static gboolean marshal_proxy                   (DBusMessageIter           *iter, +						 GValue                    *value); +static gboolean demarshal_proxy                 (DBusGValueMarshalCtx      *context, +						 DBusMessageIter           *iter, +						 GValue                    *value, +						 GError                   **error); +static gboolean marshal_object                  (DBusMessageIter           *iter, +						 GValue                    *value); +static gboolean demarshal_object                (DBusGValueMarshalCtx      *context, +						 DBusMessageIter           *iter, +						 GValue                    *value, +						 GError                   **error); +static gboolean marshal_proxy_array             (DBusMessageIter           *iter, +						 GValue                    *value); +static gboolean demarshal_proxy_array           (DBusGValueMarshalCtx      *context, +						 DBusMessageIter           *iter, +						 GValue                    *value, +						 GError                   **error); +static gboolean marshal_map                     (DBusMessageIter           *iter, +						 GValue                    *value); +static gboolean demarshal_ghashtable            (DBusGValueMarshalCtx      *context, +						 DBusMessageIter           *iter, +						 GValue                    *value, +						 GError                   **error); + +typedef gboolean (*DBusGValueMarshalFunc)       (DBusMessageIter           *iter, +						 GValue                    *value); +typedef gboolean (*DBusGValueDemarshalFunc)     (DBusGValueMarshalCtx      *context, +						 DBusMessageIter           *iter, +						 GValue                    *value, +						 GError                   **error); + +typedef struct { +  DBusGValueMarshalFunc       marshaller; +  DBusGValueDemarshalFunc     demarshaller; +} DBusGTypeMarshalVtable; + +typedef struct { +  const char                       *sig; +  const DBusGTypeMarshalVtable     *vtable; +} DBusGTypeMarshalData; + +static GQuark +dbus_g_type_metadata_data_quark () +{ +  static GQuark quark; +  if (!quark) +    quark = g_quark_from_static_string ("DBusGTypeMetaData"); +   +  return quark; +} + +static void +set_type_metadata (GType type, const DBusGTypeMarshalData *data) +{ +  g_type_set_qdata (type, dbus_g_type_metadata_data_quark (), (gpointer) data); +} +  #define MAP_BASIC(d_t, g_t)                     \      case DBUS_TYPE_##d_t:                       \        return G_TYPE_##g_t; -  static GType -dbus_dbus_type_to_gtype (int type) +typecode_to_gtype (int type)  {    switch (type)      {        MAP_BASIC (BOOLEAN, BOOLEAN);        MAP_BASIC (BYTE,    UCHAR); +      MAP_BASIC (INT16,   INT);        MAP_BASIC (INT32,   INT); +      MAP_BASIC (UINT16,  UINT);        MAP_BASIC (UINT32,  UINT);        MAP_BASIC (INT64,   INT64);        MAP_BASIC (UINT64,  UINT64);        MAP_BASIC (DOUBLE,  DOUBLE); -    case DBUS_TYPE_INT16: -      return G_TYPE_INT; -    case DBUS_TYPE_UINT16: -      return G_TYPE_UINT; -    case DBUS_TYPE_STRING: -    case DBUS_TYPE_OBJECT_PATH: -    case DBUS_TYPE_SIGNATURE: -      return G_TYPE_STRING; -    case DBUS_TYPE_STRUCT: -    case DBUS_TYPE_ARRAY: -    case DBUS_TYPE_VARIANT: +      MAP_BASIC (STRING,  STRING);      default:        return G_TYPE_INVALID;      }  } -  #undef MAP_BASIC -gboolean -dbus_gvalue_init (int     type, -		  GValue *value) +static gboolean +dbus_typecode_maps_to_basic (int typecode) +{ +  return typecode_to_gtype (typecode) != G_TYPE_INVALID; +} + +static gboolean +basic_typecode_to_gtype (int typecode) +{ +  g_assert (dbus_type_is_basic (typecode)); +  g_assert (dbus_typecode_maps_to_basic (typecode)); +  return typecode_to_gtype (typecode); +} + +static void +register_basic (int typecode, const DBusGTypeMarshalData *typedata)  { +  set_type_metadata (basic_typecode_to_gtype (typecode), typedata); +} + +static void +register_array (int typecode, const DBusGTypeMarshalData *typedata) +{ +  GType elt_gtype;    GType gtype; -  gtype = dbus_dbus_type_to_gtype (type); -  if (gtype == G_TYPE_INVALID) -    return FALSE; -  g_value_init (value, gtype); -  return TRUE; +  elt_gtype = basic_typecode_to_gtype (typecode);  +  gtype = dbus_g_type_get_collection ("GArray", elt_gtype); +  set_type_metadata (gtype, typedata);  +} + +static void +register_dict (int key_type, int value_type, const DBusGTypeMarshalData *typedata) +{ +  GType key_gtype; +  GType value_gtype; +  GType gtype; + +  key_gtype = basic_typecode_to_gtype (key_type);  +  value_gtype = basic_typecode_to_gtype (value_type);  +  gtype = dbus_g_type_get_map ("GHashTable", key_gtype, value_gtype); +  set_type_metadata (gtype, typedata);  +} + +void +dbus_g_value_types_init (void) +{ +  static gboolean types_initialized; + + +  if (types_initialized) +    return; + +  g_assert (sizeof (DBusGValueIterator) >= sizeof (DBusMessageIter)); + +  dbus_g_type_specialized_init (); +  dbus_g_type_specialized_builtins_init (); +   +  static const DBusGTypeMarshalVtable basic_vtable = { +    marshal_basic, +    demarshal_basic +  }; +  static const DBusGTypeMarshalVtable garray_basic_vtable = { +    marshal_garray_basic, +    demarshal_garray_basic +  }; +  static const DBusGTypeMarshalVtable ghashtable_vtable = { +    marshal_map, +    demarshal_ghashtable +  }; + +  /* Register basic types */ +  { +    static const DBusGTypeMarshalData typedata = { +      DBUS_TYPE_BOOLEAN_AS_STRING, +      &basic_vtable, +    }; +    register_basic (DBUS_TYPE_BOOLEAN, &typedata); +  } +  { +    static const DBusGTypeMarshalData typedata = { +      DBUS_TYPE_BYTE_AS_STRING, +      &basic_vtable, +    }; +    register_basic (DBUS_TYPE_BYTE, &typedata); +  } +  { +    static const DBusGTypeMarshalData typedata = { +      DBUS_TYPE_INT16_AS_STRING, +      &basic_vtable, +    }; +    register_basic (DBUS_TYPE_INT16, &typedata); +  } +  { +    static const DBusGTypeMarshalData typedata = { +      DBUS_TYPE_UINT16_AS_STRING, +      &basic_vtable, +    }; +    register_basic (DBUS_TYPE_UINT16, &typedata); +  } +  { +    static const DBusGTypeMarshalData typedata = { +      DBUS_TYPE_UINT32_AS_STRING, +      &basic_vtable, +    }; +    register_basic (DBUS_TYPE_UINT32, &typedata); +  } +  { +    static const DBusGTypeMarshalData typedata = { +      DBUS_TYPE_INT32_AS_STRING, +      &basic_vtable, +    }; +    register_basic (DBUS_TYPE_INT32, &typedata); +  } +  { +    static const DBusGTypeMarshalData typedata = { +      DBUS_TYPE_UINT64_AS_STRING, +      &basic_vtable, +    }; +    register_basic (DBUS_TYPE_UINT64, &typedata); +  } +  { +    static const DBusGTypeMarshalData typedata = { +      DBUS_TYPE_INT64_AS_STRING, +      &basic_vtable, +    }; +    register_basic (DBUS_TYPE_INT64, &typedata); +  } +  { +    static const DBusGTypeMarshalData typedata = { +      DBUS_TYPE_DOUBLE_AS_STRING, +      &basic_vtable, +    }; +    register_basic (DBUS_TYPE_DOUBLE, &typedata); +  } +  { +    static const DBusGTypeMarshalData typedata = { +      DBUS_TYPE_STRING_AS_STRING, +      &basic_vtable, +    }; +    register_basic (DBUS_TYPE_STRING, &typedata); +  } +   +  /* Register complex types with builtin GType mappings */ +  { +    static const DBusGTypeMarshalVtable vtable = { +      marshal_variant, +      demarshal_variant +    }; +    static const DBusGTypeMarshalData typedata = { +      DBUS_TYPE_VARIANT_AS_STRING, +      &vtable +    }; +    set_type_metadata (G_TYPE_VALUE, &typedata); +  }; +  { +    static const DBusGTypeMarshalVtable vtable = { +      marshal_strv, +      demarshal_strv +    }; +    static const DBusGTypeMarshalData typedata = { +      DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_STRING_AS_STRING, +      &vtable +    }; +    set_type_metadata (G_TYPE_STRV, &typedata); +  }; + +  {  +    static const DBusGTypeMarshalData typedata = { +      DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_BOOLEAN_AS_STRING, +      &garray_basic_vtable +    }; +    register_array (DBUS_TYPE_BOOLEAN, &typedata); +  } +  {  +    static const DBusGTypeMarshalData typedata = { +      DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_BYTE_AS_STRING, +      &garray_basic_vtable +    }; +    register_array (DBUS_TYPE_BYTE, &typedata); +  } +  {  +    static const DBusGTypeMarshalData typedata = { +      DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_UINT32_AS_STRING, +      &garray_basic_vtable +    }; +    register_array (DBUS_TYPE_UINT32, &typedata); +  } +  {  +    static const DBusGTypeMarshalData typedata = { +      DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_INT32_AS_STRING, +      &garray_basic_vtable +    }; +    register_array (DBUS_TYPE_INT32, &typedata); +  } +  {  +    static const DBusGTypeMarshalData typedata = { +      DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_UINT64_AS_STRING, +      &garray_basic_vtable +    }; +    register_array (DBUS_TYPE_UINT64, &typedata); +  } +  {  +    static const DBusGTypeMarshalData typedata = { +      DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_INT64_AS_STRING, +      &garray_basic_vtable +    }; +    register_array (DBUS_TYPE_INT64, &typedata); +  } +  {  +    static const DBusGTypeMarshalData typedata = { +      DBUS_TYPE_ARRAY_AS_STRING DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_STRING_AS_STRING DBUS_DICT_ENTRY_END_CHAR_AS_STRING, +      &ghashtable_vtable, +    }; +    register_dict (DBUS_TYPE_STRING, DBUS_TYPE_STRING, &typedata); +  } + +  { +    static const DBusGTypeMarshalVtable vtable = { +      marshal_proxy, +      demarshal_proxy +    }; +    static const DBusGTypeMarshalData typedata = { +      DBUS_TYPE_OBJECT_PATH_AS_STRING, +      &vtable +    }; +    set_type_metadata (DBUS_TYPE_G_PROXY, &typedata); +  } + +  { +    static const DBusGTypeMarshalVtable vtable = { +      marshal_object, +      demarshal_object +    }; +    static const DBusGTypeMarshalData typedata = { +      DBUS_TYPE_OBJECT_PATH_AS_STRING, +      &vtable +    }; +    set_type_metadata (G_TYPE_OBJECT, &typedata); +  } + +  { +    static const DBusGTypeMarshalVtable vtable = { +      marshal_proxy_array, +      demarshal_proxy_array +    }; +    static const DBusGTypeMarshalData typedata = { +      DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING, +      &vtable +    }; +    set_type_metadata (DBUS_TYPE_G_PROXY_ARRAY, &typedata); +  } + +  types_initialized = TRUE;  } -/* FIXME - broken for containers +/** + * Get the GLib type ID for a DBusGValue boxed type. + * + * @returns GLib type   */ -static int -base_type_from_signature  (const char *signature) +GType +dbus_g_value_get_g_type (void)  { -  DBusSignatureIter iter; +  static GType type_id = 0; -  dbus_signature_iter_init (&iter, signature); +  if (!type_id) +    type_id = g_boxed_type_register_static ("DBusGValue", +					    dbus_g_value_copy, +					    (GBoxedFreeFunc) dbus_g_value_free); +  return type_id; +} + +void +dbus_g_value_open (DBusGValue          *value, +		   DBusGValueIterator  *iter) +{ +  DBusGValue *real; + +  g_return_if_fail (value->type == DBUS_G_VALUE_TYPE_TOPLEVEL); + +  real = (DBusGValue*) iter; +  real->type = DBUS_G_VALUE_TYPE_ITERATOR; +  real->value.recurse.toplevel = value; -  return dbus_signature_iter_get_current_type (&iter); +  dbus_message_iter_init (value->value.toplevel.message, +			  &(real->value.recurse.iterator)); +  value->value.recurse.toplevel = value;  } -const char * -dbus_gvalue_genmarshal_name_from_type (const char *signature) +gboolean +dbus_g_value_iterator_get_values (DBusGValueIterator *iter, +				  GError            **error, +				  GValue             *first_val, +				  ...)  { -  int type; +  GValue *value; +  va_list args; +  DBusGValue *iterval; -  type = base_type_from_signature (signature); -  switch (type) +  va_start (args, first_val); + +  iterval = (DBusGValue *) iter; + +  value = first_val; +  do      { -    case DBUS_TYPE_BOOLEAN: -      return "BOOLEAN"; -    case DBUS_TYPE_BYTE: -      return "UCHAR"; -    case DBUS_TYPE_INT32: -      return "INT"; -    case DBUS_TYPE_UINT32: -      return "UINT"; -    case DBUS_TYPE_INT64: -      return "INT64"; -    case DBUS_TYPE_UINT64: -      return "UINT64"; -    case DBUS_TYPE_DOUBLE: -      return "DOUBLE"; -    case DBUS_TYPE_INT16: -      return "INT"; -      break; -    case DBUS_TYPE_UINT16: -      return "UINT"; -    case DBUS_TYPE_STRING: -    case DBUS_TYPE_OBJECT_PATH: -    case DBUS_TYPE_SIGNATURE: -      return "STRING"; -       -    case DBUS_TYPE_STRUCT: -    case DBUS_TYPE_ARRAY: -    case DBUS_TYPE_VARIANT: -      return NULL; -    } +      DBusGValueMarshalCtx context; + +      context.gconnection = (iterval->value.recurse.toplevel)->value.toplevel.connection; +      context.proxy = (iterval->value.recurse.toplevel)->value.toplevel.proxy; +      if (!dbus_gvalue_demarshal (&context, +				  &(iterval->value.recurse.iterator), +				  value, +				  error)) +	return FALSE; +    } while ((value = va_arg (args, GValue *)) != NULL); +   +  return TRUE; +} + +static char * +dbus_g_value_get_signature (DBusGValue *value) +{ +  return value->value.toplevel.signature; +} + +static gpointer +dbus_g_value_copy (gpointer value) +{ +  /* FIXME */    return NULL;  } -const char * -dbus_gvalue_ctype_from_type (const char *signature, gboolean in) +void +dbus_g_value_free (DBusGValue *value) +{ +  if (value->type == DBUS_G_VALUE_TYPE_TOPLEVEL) +    { +      dbus_message_unref (value->value.toplevel.message); +      g_free (value->value.toplevel.signature); +    } +} + +static GType +signature_iter_to_g_type_dict (const DBusSignatureIter *subiter, gboolean is_client)  { -  int type; +  DBusSignatureIter iter; +  GType key_gtype; +  GType value_gtype; -  type = base_type_from_signature (signature); +  g_assert (dbus_signature_iter_get_current_type (subiter) == DBUS_TYPE_DICT_ENTRY); -  switch (type) +  dbus_signature_iter_recurse (subiter, &iter); + +  key_gtype = dbus_gtype_from_signature_iter (&iter, is_client);  +  if (key_gtype == G_TYPE_INVALID) +    return G_TYPE_INVALID; + +  dbus_signature_iter_next (&iter); +  value_gtype = dbus_gtype_from_signature_iter (&iter, is_client); +  if (value_gtype == G_TYPE_INVALID) +    return G_TYPE_INVALID; + +  if (!dbus_gtype_is_valid_hash_key (key_gtype) +      || !dbus_gtype_is_valid_hash_value (value_gtype)) +    /* Later we need to return DBUS_TYPE_G_VALUE */ +    return G_TYPE_INVALID;  + +  return dbus_g_type_get_map ("GHashTable", key_gtype, value_gtype); +} + +static GType +signature_iter_to_g_type_array (DBusSignatureIter *iter, gboolean is_client) +{ +  GType elt_gtype; +  DBusGTypeMarshalData *typedata; + +  elt_gtype = dbus_gtype_from_signature_iter (iter, is_client); +  if (elt_gtype == G_TYPE_INVALID) +    return G_TYPE_INVALID; + +  typedata = g_type_get_qdata (elt_gtype, dbus_g_type_metadata_data_quark ()); +  if (typedata == NULL) +    return G_TYPE_INVALID; +   +  if (elt_gtype == G_TYPE_OBJECT) +    return DBUS_TYPE_G_OBJECT_ARRAY; +  if (elt_gtype == G_TYPE_STRING) +    return G_TYPE_STRV; +  if (dbus_g_type_is_fixed (elt_gtype)) +    return dbus_g_type_get_collection ("GArray", elt_gtype); + +  /* Later we need to return DBUS_TYPE_G_VALUE */ +  return G_TYPE_INVALID;  +} + +static gboolean +signature_iter_to_g_type_struct (DBusSignatureIter *origiter, gboolean is_client) +{ +  /* FIXME allow structures */ +  return G_TYPE_INVALID; +#if 0 +  DBusSignatureIter iter; +  int current_type; + +  iter = *origiter; + +  while ((current_type = dbus_signature_iter_get_current_type (&iter)) != DBUS_TYPE_INVALID) { +    subtype = dbus_gtype_from_signature_iter (&iter, is_client); +    if (subtype == G_TYPE_INVALID) +      return G_TYPE_INVALID; +  } +  return DBUS_TYPE_G_VALUE (); +#endif +} + +GType +dbus_gtype_from_signature_iter (DBusSignatureIter *iter, gboolean is_client) +{ +  int current_type; + +  current_type = dbus_signature_iter_get_current_type (iter); +  /* TODO: handle type 0? */ +  if (dbus_typecode_maps_to_basic (current_type)) +    return basic_typecode_to_gtype (current_type); +  else if (current_type == DBUS_TYPE_OBJECT_PATH) +    return is_client ? DBUS_TYPE_G_PROXY : G_TYPE_OBJECT; +  else      { -    case DBUS_TYPE_BOOLEAN: -      return "gboolean"; -    case DBUS_TYPE_BYTE: -      return "guchar"; -    case DBUS_TYPE_INT32: -      return "gint32"; -    case DBUS_TYPE_UINT32: -      return "guint32"; -    case DBUS_TYPE_INT64: -      return "gint64"; -    case DBUS_TYPE_UINT64: -      return "guint64"; -    case DBUS_TYPE_DOUBLE: -      return "gdouble"; -    case DBUS_TYPE_INT16: -      return "gint"; -      break; -    case DBUS_TYPE_UINT16: -      return "guint"; -    case DBUS_TYPE_STRING: -    case DBUS_TYPE_OBJECT_PATH: -    case DBUS_TYPE_SIGNATURE: -      /* FIXME - kind of a hack */ -      if (in) -	return "const char *"; +      DBusSignatureIter subiter; + +      g_assert (dbus_type_is_container (current_type)); +      dbus_signature_iter_recurse (iter, &subiter); + +      if (current_type == DBUS_TYPE_ARRAY) +	{ +	  int elt_type = dbus_signature_iter_get_current_type (&subiter); +	  if (elt_type == DBUS_TYPE_DICT_ENTRY) +	    return signature_iter_to_g_type_dict (&subiter, is_client); +	  else  +	    return signature_iter_to_g_type_array (&subiter, is_client); +	} +      else if (current_type == DBUS_TYPE_STRUCT) +	return signature_iter_to_g_type_struct (&subiter, is_client); +      else if (current_type == DBUS_TYPE_VARIANT) +	return g_value_get_type (); +      else if (current_type == DBUS_TYPE_DICT_ENTRY) +	return G_TYPE_INVALID;        else -	return "char *"; -    case DBUS_TYPE_STRUCT: -    case DBUS_TYPE_ARRAY: -    case DBUS_TYPE_VARIANT: -      return NULL; +	{ +	  g_assert_not_reached (); +	  return G_TYPE_INVALID; +	}      } -  return NULL;  } -const char * -dbus_gtype_to_dbus_type (GType type) +GType +dbus_gtype_from_signature (const char *signature, gboolean is_client)  { -  switch (type) +  DBusSignatureIter iter; + +  dbus_signature_iter_init (&iter, signature); + +  return dbus_gtype_from_signature_iter (&iter, is_client); +} + +static char * +dbus_gvalue_to_signature (GValue *value) +{ +  const char *ret; + +  ret = dbus_gtype_to_signature (G_VALUE_TYPE (value)); +  if (ret) +    return g_strdup (ret); +  else      { -    case G_TYPE_CHAR: -    case G_TYPE_UCHAR: -      return DBUS_TYPE_BYTE_AS_STRING; +      DBusGValue *val; -    case G_TYPE_BOOLEAN: -      return DBUS_TYPE_BOOLEAN_AS_STRING; +      g_assert (G_VALUE_TYPE (value) == DBUS_TYPE_G_VALUE); -      /* long gets cut to 32 bits so the remote API is consistent -       * on all architectures -       */ +      val = g_value_get_boxed (value); -    case G_TYPE_LONG: -    case G_TYPE_INT: -      return DBUS_TYPE_INT32_AS_STRING; -    case G_TYPE_ULONG: -    case G_TYPE_UINT: -      return DBUS_TYPE_UINT32_AS_STRING; +      return dbus_g_value_get_signature (val); +    } +} -    case G_TYPE_INT64: -      return DBUS_TYPE_INT64_AS_STRING; +const char * +dbus_gtype_to_signature (GType gtype) +{ +  DBusGTypeMarshalData *typedata; -    case G_TYPE_UINT64: -      return DBUS_TYPE_UINT64_AS_STRING; -       -    case G_TYPE_FLOAT: -    case G_TYPE_DOUBLE: -      return DBUS_TYPE_DOUBLE_AS_STRING; +  typedata = g_type_get_qdata (gtype, dbus_g_type_metadata_data_quark ()); +  if (typedata == NULL) +    return NULL; +  return typedata->sig; +} -    case G_TYPE_STRING: -      return DBUS_TYPE_STRING_AS_STRING; +GArray * +dbus_gtypes_from_arg_signature (const char *argsig, gboolean is_client) +{ +  GArray *ret; +  int current_type; +  DBusSignatureIter sigiter; -    default: -      return NULL; +  ret = g_array_new (FALSE, FALSE, sizeof (GType)); + +  dbus_signature_iter_init (&sigiter, argsig); +  while ((current_type = dbus_signature_iter_get_current_type (&sigiter)) != DBUS_TYPE_INVALID) +    { +      GType curtype; + +      curtype = dbus_gtype_from_signature_iter (&sigiter, is_client); +      g_array_append_val (ret, curtype); +      dbus_signature_iter_next (&sigiter);      } +  return ret;  } -gboolean -dbus_gvalue_demarshal (DBusMessageIter *iter, GValue *value) -{ -  g_assert (sizeof (dbus_bool_t) == sizeof (value->data[0].v_int)); -  dbus_gvalue_init (dbus_message_iter_get_arg_type (iter), value); +static gboolean +demarshal_basic (DBusGValueMarshalCtx      *context, +		 DBusMessageIter           *iter, +		 GValue                    *value, +		 GError                   **error) +{ +  int current_type; -  switch (dbus_message_iter_get_arg_type (iter)) +  current_type = dbus_message_iter_get_arg_type (iter); +  g_assert (dbus_type_is_basic (current_type)); + +  switch (current_type)      {      case DBUS_TYPE_BOOLEAN:        { @@ -283,24 +761,407 @@ dbus_gvalue_demarshal (DBusMessageIter *iter, GValue *value)  	return TRUE;        }      case DBUS_TYPE_STRING: -    case DBUS_TYPE_OBJECT_PATH: -    case DBUS_TYPE_SIGNATURE:        {          const char *s;          dbus_message_iter_get_basic (iter, &s); -        g_value_set_string (value, s); +	g_value_set_string (value, s);  	return TRUE;        } -    case DBUS_TYPE_STRUCT: -    case DBUS_TYPE_ARRAY: -    case DBUS_TYPE_VARIANT:      default: +      g_assert_not_reached (); +      return FALSE; +    } +} + +static gboolean +demarshal_static_variant (DBusGValueMarshalCtx    *context, +			  DBusMessageIter         *iter, +			  GValue                  *value, +			  GError                 **error) +{ +  char *sig; +  int current_type; +  DBusMessageIter subiter; +  GType variant_type; + +  current_type = dbus_message_iter_get_arg_type (iter); +  dbus_message_iter_recurse (iter, &subiter); +  sig = dbus_message_iter_get_signature (&subiter); + +  variant_type = dbus_gtype_from_signature (sig, context->proxy != NULL); +  if (variant_type != G_TYPE_INVALID) +    { +      g_value_init (value, variant_type); + +      if (!dbus_gvalue_demarshal (context, &subiter, value, error)) +	{ +	  dbus_free (sig); +	  return FALSE; +	} +    } +  dbus_free (sig); +  return TRUE; +} + +static gboolean +demarshal_variant (DBusGValueMarshalCtx    *context, +		   DBusMessageIter         *iter, +		   GValue                  *value, +		   GError                 **error) + +{ +  GValue *variant_val; +  variant_val = g_new0 (GValue, 1); + +  if (!demarshal_static_variant (context, iter, variant_val, error)) +    return FALSE; +   +  g_value_set_boxed_take_ownership (value, variant_val); +  return TRUE; +} + +static gboolean +demarshal_proxy (DBusGValueMarshalCtx    *context, +		 DBusMessageIter         *iter, +		 GValue                  *value, +		 GError                 **error) +{ +  const char *name; +  DBusGProxy *new_proxy; +  const char *objpath; +  int current_type; + +  current_type = dbus_message_iter_get_arg_type (iter); +  g_assert (current_type == DBUS_TYPE_OBJECT_PATH); + +  g_assert (context->proxy != NULL); +   +  name = dbus_g_proxy_get_bus_name (context->proxy); +       +  dbus_message_iter_get_basic (iter, &objpath); + +  new_proxy = dbus_g_proxy_new_from_proxy (context->proxy, NULL, objpath); +  g_value_set_object_take_ownership (value, new_proxy); + +  return TRUE; +} + +static gboolean +demarshal_object (DBusGValueMarshalCtx    *context, +		  DBusMessageIter         *iter, +		  GValue                  *value, +		  GError                 **error) +{ +  const char *objpath; +  int current_type; +  GObject *obj; + +  current_type = dbus_message_iter_get_arg_type (iter); +  g_assert (current_type == DBUS_TYPE_OBJECT_PATH); +  g_assert (context->proxy == NULL); + +  dbus_message_iter_get_basic (iter, &objpath); + +  obj = dbus_g_connection_lookup_g_object (context->gconnection, objpath); +  if (obj == NULL) +    { +      g_set_error (error, +		   DBUS_GERROR, +		   DBUS_GERROR_INVALID_ARGS, +		   _("Unregistered object at path '%s'"), +		   objpath);        return FALSE;      } +  g_value_set_object (value, obj); + +  return TRUE;  } -     + +static gboolean +demarshal_strv (DBusGValueMarshalCtx    *context, +		DBusMessageIter         *iter, +		GValue                  *value, +		GError                 **error) +{ +  DBusMessageIter subiter; +  int current_type; +  char **ret; +  int len; +  int i; + +  dbus_message_iter_recurse (iter, &subiter); + +  len = dbus_message_iter_get_array_len (&subiter); +  g_assert (len >= 0); +  ret = g_malloc (sizeof (char *) * (len + 1)); +   +  i = 0; +  while ((current_type = dbus_message_iter_get_arg_type (&subiter)) != DBUS_TYPE_INVALID) +    { +      g_assert (i < len); +      g_assert (current_type == DBUS_TYPE_STRING); +       +      dbus_message_iter_get_basic (&subiter, &(ret[i])); +      ret[i] = g_strdup (ret[i]); + +      dbus_message_iter_next (&subiter); +      i++; +    } +  ret[i] = NULL;  +  g_value_set_boxed_take_ownership (value, ret); +   +  return TRUE; +} + +static gboolean +demarshal_garray_basic (DBusGValueMarshalCtx    *context, +			DBusMessageIter         *iter, +			GValue                  *value, +			GError                 **error) +{ +  DBusMessageIter subiter; +  GArray *ret; +  GType elt_gtype; +  int elt_size; +  void *msgarray; +  int msgarray_len; + +  dbus_message_iter_recurse (iter, &subiter); + +  elt_gtype = dbus_g_type_get_collection_specialization (G_VALUE_TYPE (value)); +  g_assert (elt_gtype != G_TYPE_INVALID); +  g_assert (dbus_g_type_is_fixed (elt_gtype)); + +  elt_size = dbus_g_type_fixed_get_size (elt_gtype); +   +  ret = g_array_new (FALSE, TRUE, elt_size); + +  msgarray = NULL; +  dbus_message_iter_get_fixed_array (&subiter, +				     &msgarray, +				     &msgarray_len); +  g_assert (msgarray != NULL); +  g_assert (msgarray_len >= 0); +  g_array_append_vals (ret, msgarray, (guint) msgarray_len); + +  g_value_set_boxed_take_ownership (value, ret); +   +  return TRUE; +} + +static gboolean +demarshal_proxy_array (DBusGValueMarshalCtx    *context, +		       DBusMessageIter         *iter, +		       GValue                  *value, +		       GError                 **error) +{ +  DBusMessageIter subiter; +  GPtrArray *ret; +  guint len; +  guint i; +  int current_type; + +  g_assert (dbus_message_iter_get_arg_type (iter) == DBUS_TYPE_ARRAY); + +  dbus_message_iter_recurse (iter, &subiter); + +  len = dbus_message_iter_get_array_len (&subiter); +  g_assert (len >= 0); +  ret = g_ptr_array_sized_new (len); +   +  i = 0; +  while ((current_type = dbus_message_iter_get_arg_type (&subiter)) != DBUS_TYPE_INVALID) +    { +      GValue subval = {0, }; +      g_assert (i < len); + +      if (!demarshal_proxy (context, &subiter, &subval, error)) +	{ +	  for (i = 0; i < ret->len; i++) +	    g_object_unref (g_ptr_array_index (ret, i)); +	  g_ptr_array_free (ret, TRUE); +	  return FALSE; +	} + +      g_ptr_array_index (ret, i) = g_value_get_boxed (&subval); +      /* Don't unset value, now owned by ret */ + +      i++; +    } +  g_value_set_boxed_take_ownership (value, ret); +   +  return TRUE; +} + +static gboolean +demarshal_ghashtable (DBusGValueMarshalCtx    *context, +		      DBusMessageIter         *iter, +		      GValue                  *value, +		      GError                 **error) +{ +  GType gtype; +  DBusMessageIter subiter; +  int current_type; +  GHashTable *ret; +  GType key_gtype; +  GType value_gtype; + +  current_type = dbus_message_iter_get_arg_type (iter); +  g_assert (current_type == DBUS_TYPE_ARRAY); + +  gtype = G_VALUE_TYPE (value); + +  dbus_message_iter_recurse (iter, &subiter); + +  g_assert (dbus_message_iter_get_arg_type (&subiter) == DBUS_TYPE_DICT_ENTRY); + +  key_gtype = dbus_g_type_get_map_key_specialization (gtype); +  g_assert (dbus_gtype_is_valid_hash_key (key_gtype)); +  value_gtype = dbus_g_type_get_map_value_specialization (gtype); +  g_assert (dbus_gtype_is_valid_hash_value (value_gtype)); + +  ret = g_hash_table_new_full (dbus_g_hash_func_from_gtype (key_gtype), +			       dbus_g_hash_equal_from_gtype (key_gtype), +			       dbus_g_hash_free_from_gtype (key_gtype), +			       dbus_g_hash_free_from_gtype (value_gtype)); + +  while ((current_type = dbus_message_iter_get_arg_type (&subiter)) != DBUS_TYPE_INVALID) +    { +      DBusMessageIter entry_iter; +      GValue key_value = {0,}; +      GValue value_value = {0,}; + +      current_type = dbus_message_iter_get_arg_type (&subiter); +      g_assert (current_type == DBUS_TYPE_DICT_ENTRY); + +      dbus_message_iter_recurse (&subiter, &entry_iter); + +      g_value_init (&key_value, key_gtype); +      if (!dbus_gvalue_demarshal (context, +				  &entry_iter, +				  &key_value, +				  error)) +	return FALSE; + +      dbus_message_iter_next (&entry_iter); + +      g_value_init (&value_value, value_gtype); +      if (!dbus_gvalue_demarshal (context, +				  &entry_iter, +				  &value_value, +				  error)) +	return FALSE; + +      dbus_g_hash_table_insert_steal_values (ret, +					     &key_value, +					     &value_value); +      /* Ownership of values passes to hash table, don't unset */ + +      dbus_message_iter_next (&subiter); +    } +  g_value_set_boxed_take_ownership (value, ret); +   +  return TRUE; +} + +static gboolean +demarshal_recurse (DBusGValueMarshalCtx    *context, +		   DBusMessageIter         *iter, +		   GValue                  *value, +		   GError                 **error) +{ +  return FALSE; +} + +gboolean +dbus_gvalue_demarshal (DBusGValueMarshalCtx    *context, +		       DBusMessageIter         *iter, +		       GValue                  *value, +		       GError                 **error) +{ +  GType gtype; +  DBusGTypeMarshalData *typedata; + +  gtype = G_VALUE_TYPE (value); + +  typedata = g_type_get_qdata (gtype, dbus_g_type_metadata_data_quark ()); +  g_return_val_if_fail (typedata != NULL || g_type_is_a (gtype, DBUS_TYPE_G_VALUE), FALSE); + +  if (typedata == NULL) +    { +      if (g_type_is_a (gtype, DBUS_TYPE_G_VALUE)) +	return demarshal_recurse (context, iter, value, error); +      g_assert_not_reached (); +    } +  g_assert (typedata->vtable); +  return typedata->vtable->demarshaller (context, iter, value, error); +} +  gboolean -dbus_gvalue_marshal (DBusMessageIter *iter, GValue *value) +dbus_gvalue_demarshal_variant (DBusGValueMarshalCtx    *context, +			       DBusMessageIter         *iter, +			       GValue                  *value, +			       GError                 **error) +{ +  return demarshal_static_variant (context, iter, value, error); +} + +GValueArray * +dbus_gvalue_demarshal_message  (DBusGValueMarshalCtx    *context, +				DBusMessage             *message, +				guint                    n_types, +				const GType             *types, +				GError                 **error) +{ +  GValueArray *ret; +  DBusMessageIter iter; +  int current_type; +  guint index; +   +  ret = g_value_array_new (6);  /* 6 is a typical maximum for arguments */ + +  dbus_message_iter_init (message, &iter); +  index = 0; +  while ((current_type = dbus_message_iter_get_arg_type (&iter)) != DBUS_TYPE_INVALID) +    { +      GValue *value; +      GType gtype; + +      if (index >= n_types) +	{ +	  g_set_error (error, DBUS_GERROR, +		       DBUS_GERROR_INVALID_ARGS, +		       _("Too many arguments in message")); +	  goto lose; +	} +       +      g_value_array_append (ret, NULL); +      value = g_value_array_get_nth (ret, index); + +      gtype = types[index];  +      g_value_init (value, gtype); + +      if (!dbus_gvalue_demarshal (context, &iter, value, error)) +	goto lose; +      dbus_message_iter_next (&iter); +      index++; +    } +  if (index < n_types) +    { +      g_set_error (error, DBUS_GERROR, +		   DBUS_GERROR_INVALID_ARGS, +		   _("Too few arguments in message")); +      goto lose; +    } + +  return ret; + lose: +  g_value_array_free (ret); +  return NULL; +} + +static gboolean +marshal_basic (DBusMessageIter *iter, GValue *value)  {    GType value_type; @@ -353,9 +1214,6 @@ dbus_gvalue_marshal (DBusMessageIter *iter, GValue *value)            goto nomem;        }        return TRUE; -      /* long gets cut to 32 bits so the remote API is consistent -       * on all architectures -       */      case G_TYPE_LONG:        {          dbus_int32_t v = g_value_get_long (value); @@ -424,9 +1282,10 @@ dbus_gvalue_marshal (DBusMessageIter *iter, GValue *value)        return TRUE;      default: -      /* FIXME: we need to define custom boxed types for arrays -	 etc. so we can map them transparently / pleasantly */ -      return FALSE; +      { +	g_assert_not_reached (); +	return FALSE; +      }      }   nomem: @@ -434,49 +1293,320 @@ dbus_gvalue_marshal (DBusMessageIter *iter, GValue *value)    return FALSE;  } -/* FIXME is there a better way to do this? */ +static gboolean +marshal_strv (DBusMessageIter   *iter, +	      GValue             *value) +{ +  DBusMessageIter subiter; +  char **array; +  char **elt; +  gboolean ret; + +  g_assert (G_VALUE_TYPE (value) == g_strv_get_type ()); + +  array = g_value_get_boxed (value); + +  if (!dbus_message_iter_open_container (iter, +					 DBUS_TYPE_ARRAY, +					 "s", +					 &subiter)) +    goto out; + +  for (elt = array; *elt; elt++) +    { +      if (!dbus_message_iter_append_basic (&subiter, +					   DBUS_TYPE_STRING, +					   elt)) +	goto out; +    } + +  if (!dbus_message_iter_close_container (iter, &subiter)) +    goto out; +  ret = TRUE; + out: +  return ret; +} + +static gboolean +marshal_garray_basic (DBusMessageIter   *iter, +		      GValue            *value) +{ +  GType elt_gtype; +  DBusMessageIter subiter; +  GArray *array; +  guint elt_size; +  const char *subsignature_str; +  gboolean ret; + +  elt_gtype = dbus_g_type_get_collection_specialization (G_VALUE_TYPE (value)); +  /* FIXME - this means we can't send an array of DBusGValue right now... */ +  subsignature_str = dbus_gtype_to_signature (elt_gtype); +  g_assert (subsignature_str != NULL); +   +  elt_size = dbus_g_type_fixed_get_size (elt_gtype); + +  array = g_value_get_boxed (value); + +  if (!dbus_message_iter_open_container (iter, +					 DBUS_TYPE_ARRAY, +					 subsignature_str, +					 &subiter)) +    goto out; + +  /* TODO - This assumes that basic values are the same size +   * is this always true?  If it is we can probably avoid +   * a lot of the overhead in _marshal_basic_instance... +   */ +  if (!dbus_message_iter_append_fixed_array (&subiter, +					     subsignature_str[0], +					     &(array->data), +					     array->len)) +    goto out; + +  if (!dbus_message_iter_close_container (iter, &subiter)) +    goto out; +  ret = TRUE; + out: +  return ret; +} + +static gboolean +marshal_proxy (DBusMessageIter         *iter, +	       GValue                  *value) +{ +  const char *path; +  DBusGProxy *proxy; + +  g_assert (G_VALUE_TYPE (value) == dbus_g_proxy_get_type ()); + +  proxy = g_value_get_object (value); +  path = dbus_g_proxy_get_path (proxy); +   +  if (!dbus_message_iter_append_basic (iter, +				       DBUS_TYPE_OBJECT_PATH, +				       &path)) +    return FALSE; +  return TRUE; +} + +static gboolean +marshal_object (DBusMessageIter         *iter, +		GValue                  *value) +{ +  const char *path; +  GObject *obj; + +  obj = g_value_get_object (value); +  path = _dbus_gobject_get_path (obj); + +  if (path == NULL) +    /* FIXME should throw error */ +    return FALSE; +   +  if (!dbus_message_iter_append_basic (iter, +				       DBUS_TYPE_OBJECT_PATH, +				       &path)) +    return FALSE; +  return TRUE; +} + +static gboolean +marshal_proxy_array (DBusMessageIter   *iter, +		     GValue            *value) +{ +  DBusMessageIter subiter; +  GPtrArray *array; +  const char *subsignature_str; +  gboolean ret; +  guint i; + +  subsignature_str = dbus_gtype_to_signature (DBUS_TYPE_G_PROXY); +  g_assert (subsignature_str != NULL); + +  array = g_value_get_boxed (value); + +  if (!dbus_message_iter_open_container (iter, +					 DBUS_TYPE_ARRAY, +					 subsignature_str, +					 &subiter)) +    goto out; + +  for (i = 0; i < array->len; i++) +    { +      GValue val = {0, }; + +      g_value_init (&val, DBUS_TYPE_G_PROXY); +      g_value_set_static_boxed (&val, g_ptr_array_index (array, i)); + +      marshal_proxy (&subiter, &val); + +      g_value_unset (&val); +    } + +  if (!dbus_message_iter_close_container (iter, &subiter)) +    goto out; +  ret = TRUE; + out: +  return ret; +} + +struct DBusGLibHashMarshalData +{ +  const char *entry_sig; +  DBusMessageIter *iter; +  gboolean err; +}; + +static void +marshal_map_entry (const GValue *key, +		   const GValue *value, +		   gpointer data) +{ +  struct DBusGLibHashMarshalData *hashdata = data; +  DBusMessageIter subiter; + +  if (hashdata->err) +    return; + +  if (!dbus_message_iter_open_container (hashdata->iter, +					 DBUS_TYPE_DICT_ENTRY, +					 NULL, +					 &subiter)) +    goto lose; + +  if (!dbus_gvalue_marshal (&subiter, (GValue*) key)) +    goto lose; + +  if (!dbus_gvalue_marshal (&subiter, (GValue*) value)) +    goto lose; + +  if (!dbus_message_iter_close_container (hashdata->iter, &subiter)) +    goto lose; +   +  return; + lose: +  hashdata->err = TRUE; +} + +static gboolean +marshal_map (DBusMessageIter   *iter, +	     GValue            *value) +{ +  GType gtype; +  DBusMessageIter arr_iter; +  gboolean ret; +  struct DBusGLibHashMarshalData hashdata; +  GType key_type; +  GType value_type; +  const char *key_sig; +  const char *value_sig; +  char *entry_sig; +  char *array_sig; + +  gtype = G_VALUE_TYPE (value); + +  ret = FALSE; + +  key_type = dbus_g_type_get_map_key_specialization (gtype); +  g_assert (dbus_gtype_is_valid_hash_key (key_type)); +  value_type = dbus_g_type_get_map_value_specialization (gtype); +  g_assert (dbus_gtype_is_valid_hash_value (value_type)); + +  key_sig = dbus_gtype_to_signature (key_type); +  value_sig = dbus_gtype_to_signature (value_type); +  entry_sig = g_strdup_printf ("%s%s", key_sig, value_sig); +  array_sig = g_strdup_printf ("%c%s%c", +			       DBUS_DICT_ENTRY_BEGIN_CHAR, +			       entry_sig, +			       DBUS_DICT_ENTRY_END_CHAR); +  if (!dbus_message_iter_open_container (iter, +					 DBUS_TYPE_ARRAY, +					 array_sig, +					 &arr_iter)) +    goto lose; + +  hashdata.iter = &arr_iter; +  hashdata.err = FALSE; +  hashdata.entry_sig = entry_sig; + +  dbus_g_type_map_value_iterate (value, +				 marshal_map_entry, +				 &hashdata); + +  if (!dbus_message_iter_close_container (iter, &arr_iter)) +    goto lose; + + out: +  g_free (entry_sig); +  g_free (array_sig); +  return !hashdata.err; + lose: +  hashdata.err = TRUE; +  goto out; +} + +static gboolean +marshal_variant (DBusMessageIter          *iter, +		 GValue                   *value) +{ +  GType value_gtype; +  DBusMessageIter subiter; +  char *variant_sig; +  GValue *real_value; +  gboolean ret; + +  real_value = g_value_get_boxed (value); +  value_gtype = G_VALUE_TYPE (real_value); + +  variant_sig = dbus_gvalue_to_signature (real_value); +  if (variant_sig == NULL) +    { +      g_warning ("Unsupported value type \"%s\"", +		 g_type_name (value_gtype)); +      return FALSE; +    } + +  if (!dbus_message_iter_open_container (iter, +					 DBUS_TYPE_VARIANT, +					 variant_sig, +					 &subiter)) +    goto out; + +  if (!marshal_basic (&subiter, real_value)) +    goto out; + +  if (!dbus_message_iter_close_container (iter, &subiter)) +    goto out; + +  ret = TRUE; + out: +  g_free (variant_sig); +  return ret; +} + +static gboolean +marshal_recurse (DBusMessageIter         *iter, +		 GValue                  *value) +{ +  return FALSE; +} +  gboolean -dbus_gvalue_store (GValue          *value, -		   gpointer        storage) +dbus_gvalue_marshal (DBusMessageIter         *iter, +		     GValue                  *value)  { -  switch (G_VALUE_TYPE (value)) +  GType gtype; +  DBusGTypeMarshalData *typedata; + +  gtype = G_VALUE_TYPE (value); + +  typedata = g_type_get_qdata (gtype, dbus_g_type_metadata_data_quark ()); +  if (typedata == NULL)      { -    case G_TYPE_CHAR: -      *((gchar *) storage) = g_value_get_char (value); -      return TRUE; -    case G_TYPE_UCHAR: -      *((guchar *) storage) = g_value_get_uchar (value); -      return TRUE; -    case G_TYPE_BOOLEAN: -      *((gboolean *) storage) = g_value_get_boolean (value); -      return TRUE; -    case G_TYPE_LONG: -      *((glong *) storage) = g_value_get_long (value); -      return TRUE; -    case G_TYPE_ULONG: -      *((gulong *) storage) = g_value_get_ulong (value); -      return TRUE; -    case G_TYPE_INT: -      *((gint *) storage) = g_value_get_int (value); -      return TRUE; -    case G_TYPE_UINT: -      *((guint *) storage) = g_value_get_uint (value); -      return TRUE; -    case G_TYPE_INT64: -      *((gint64 *) storage) = g_value_get_int64 (value); -      return TRUE; -    case G_TYPE_UINT64: -      *((guint64 *) storage) = g_value_get_uint64 (value); -      return TRUE; -    case G_TYPE_FLOAT: -    case G_TYPE_DOUBLE: -      *((gdouble *) storage) = g_value_get_double (value); -      return TRUE; -    case G_TYPE_STRING: -      /* FIXME - should optimize by not duping string twice */ -      *((gchar **) storage) = g_value_dup_string (value); -      return TRUE; -    default: +      if (g_type_is_a (gtype, DBUS_TYPE_G_VALUE)) +	return marshal_recurse (iter, value);        return FALSE;      } +  g_assert (typedata->vtable); +  return typedata->vtable->marshaller (iter, value);  }  | 
