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