os/ossrv/ofdbus/dbus-glib/dbus/dbus-gvalue-utils.c
changeset 0 bde4ae8d615e
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/os/ossrv/ofdbus/dbus-glib/dbus/dbus-gvalue-utils.c	Fri Jun 15 03:10:57 2012 +0200
     1.3 @@ -0,0 +1,1446 @@
     1.4 +/* -*- mode: C; c-file-style: "gnu" -*- */
     1.5 +/* dbus-gvalue-utils.c: Non-DBus-specific functions related to GType/GValue 
     1.6 + *
     1.7 + * Copyright (C) 2005 Red Hat, Inc.
     1.8 + * Portion Copyright © 2008 Nokia Corporation and/or its subsidiary(-ies). All rights reserved.
     1.9 + * Licensed under the Academic Free License version 2.1
    1.10 + * 
    1.11 + * This program is free software; you can redistribute it and/or modify
    1.12 + * it under the terms of the GNU General Public License as published by
    1.13 + * the Free Software Foundation; either version 2 of the License, or
    1.14 + * (at your option) any later version.
    1.15 + *
    1.16 + * This program is distributed in the hope that it will be useful,
    1.17 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    1.18 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    1.19 + * GNU General Public License for more details.
    1.20 + * 
    1.21 + * You should have received a copy of the GNU General Public License
    1.22 + * along with this program; if not, write to the Free Software
    1.23 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    1.24 + *
    1.25 + */
    1.26 +
    1.27 +#ifndef __SYMBIAN32__
    1.28 +#include <config.h>
    1.29 +#else
    1.30 +#include "config.h"
    1.31 +#endif //__SYMBIAN32__
    1.32 +#include "dbus/dbus-glib.h"
    1.33 +#include "dbus-gvalue-utils.h"
    1.34 +#include "dbus-gtest.h"
    1.35 +#include <glib.h>
    1.36 +#include <string.h>
    1.37 +#include <gobject/gvaluecollector.h>
    1.38 +
    1.39 +
    1.40 +static guint
    1.41 +fixed_type_get_size (GType type)
    1.42 +{
    1.43 +  switch (type)
    1.44 +    {
    1.45 +    case G_TYPE_CHAR:
    1.46 +    case G_TYPE_UCHAR:
    1.47 +      return sizeof (gchar);
    1.48 +    case G_TYPE_BOOLEAN:
    1.49 +      return sizeof (gboolean);
    1.50 +    case G_TYPE_LONG:
    1.51 +    case G_TYPE_ULONG:
    1.52 +      return sizeof (glong);
    1.53 +    case G_TYPE_INT:
    1.54 +    case G_TYPE_UINT:
    1.55 +      return sizeof (gint);
    1.56 +    case G_TYPE_INT64:
    1.57 +    case G_TYPE_UINT64:
    1.58 +      return sizeof (gint64);
    1.59 +    case G_TYPE_FLOAT:
    1.60 +      return sizeof (gfloat);
    1.61 +    case G_TYPE_DOUBLE:
    1.62 +      return sizeof (gdouble);
    1.63 +    default:
    1.64 +      return 0;
    1.65 +    }
    1.66 +}
    1.67 +
    1.68 +gboolean
    1.69 +_dbus_g_type_is_fixed (GType type)
    1.70 +{
    1.71 +  return fixed_type_get_size (type) > 0;
    1.72 +}
    1.73 +
    1.74 +guint
    1.75 +_dbus_g_type_fixed_get_size (GType type)
    1.76 +{
    1.77 +  g_assert (_dbus_g_type_is_fixed (type));
    1.78 +  return fixed_type_get_size (type);
    1.79 +}
    1.80 +
    1.81 +gboolean
    1.82 +_dbus_gvalue_store (GValue          *value,
    1.83 +		   gpointer        storage)
    1.84 +{
    1.85 +  /* FIXME - can we use the GValue lcopy_value method
    1.86 +   * to do this in a cleaner way?
    1.87 +   */
    1.88 +  switch (g_type_fundamental (G_VALUE_TYPE (value)))
    1.89 +    {
    1.90 +    case G_TYPE_CHAR:
    1.91 +      *((gchar *) storage) = g_value_get_char (value);
    1.92 +      return TRUE;
    1.93 +    case G_TYPE_UCHAR:
    1.94 +      *((guchar *) storage) = g_value_get_uchar (value);
    1.95 +      return TRUE;
    1.96 +    case G_TYPE_BOOLEAN:
    1.97 +      *((gboolean *) storage) = g_value_get_boolean (value);
    1.98 +      return TRUE;
    1.99 +    case G_TYPE_LONG:
   1.100 +      *((glong *) storage) = g_value_get_long (value);
   1.101 +      return TRUE;
   1.102 +    case G_TYPE_ULONG:
   1.103 +      *((gulong *) storage) = g_value_get_ulong (value);
   1.104 +      return TRUE;
   1.105 +    case G_TYPE_INT:
   1.106 +      *((gint *) storage) = g_value_get_int (value);
   1.107 +      return TRUE;
   1.108 +    case G_TYPE_UINT:
   1.109 +      *((guint *) storage) = g_value_get_uint (value);
   1.110 +      return TRUE;
   1.111 +    case G_TYPE_INT64:
   1.112 +      *((gint64 *) storage) = g_value_get_int64 (value);
   1.113 +      return TRUE;
   1.114 +    case G_TYPE_UINT64:
   1.115 +      *((guint64 *) storage) = g_value_get_uint64 (value);
   1.116 +      return TRUE;
   1.117 +    case G_TYPE_DOUBLE:
   1.118 +      *((gdouble *) storage) = g_value_get_double (value);
   1.119 +      return TRUE;
   1.120 +    case G_TYPE_STRING:
   1.121 +      *((gchar **) storage) = (char*) g_value_get_string (value);
   1.122 +      return TRUE;
   1.123 +    case G_TYPE_OBJECT:
   1.124 +      *((gpointer *) storage) = g_value_get_object (value);
   1.125 +      return TRUE;
   1.126 +    case G_TYPE_BOXED:
   1.127 +      *((gpointer *) storage) = g_value_get_boxed (value);
   1.128 +      return TRUE;
   1.129 +    default:
   1.130 +      return FALSE;
   1.131 +    }
   1.132 +}
   1.133 +
   1.134 +gboolean
   1.135 +_dbus_gvalue_set_from_pointer (GValue          *value,
   1.136 +			      gconstpointer    storage)
   1.137 +{
   1.138 +  /* FIXME - is there a better way to do this? */
   1.139 +  switch (g_type_fundamental (G_VALUE_TYPE (value)))
   1.140 +    {
   1.141 +    case G_TYPE_CHAR:
   1.142 +      g_value_set_char (value, *((gchar *) storage));
   1.143 +      return TRUE;
   1.144 +    case G_TYPE_UCHAR:
   1.145 +      g_value_set_uchar (value, *((guchar *) storage));
   1.146 +      return TRUE;
   1.147 +    case G_TYPE_BOOLEAN:
   1.148 +      g_value_set_boolean (value, *((gboolean *) storage));
   1.149 +      return TRUE;
   1.150 +    case G_TYPE_LONG:
   1.151 +      g_value_set_long (value, *((glong *) storage));
   1.152 +      return TRUE;
   1.153 +    case G_TYPE_ULONG:
   1.154 +      g_value_set_ulong (value, *((gulong *) storage));
   1.155 +      return TRUE;
   1.156 +    case G_TYPE_INT:
   1.157 +      g_value_set_int (value, *((gint *) storage));
   1.158 +      return TRUE;
   1.159 +    case G_TYPE_UINT:
   1.160 +      g_value_set_uint (value, *((guint *) storage));
   1.161 +      return TRUE;
   1.162 +    case G_TYPE_INT64:
   1.163 +      g_value_set_int64 (value, *((gint64 *) storage));
   1.164 +      return TRUE;
   1.165 +    case G_TYPE_UINT64:
   1.166 +      g_value_set_uint64 (value, *((guint64 *) storage));
   1.167 +      return TRUE;
   1.168 +    case G_TYPE_DOUBLE:
   1.169 +      g_value_set_double (value, *((gdouble *) storage));
   1.170 +      return TRUE;
   1.171 +    case G_TYPE_STRING:
   1.172 +      g_value_set_string (value, *((gchar **) storage));
   1.173 +      return TRUE;
   1.174 +    case G_TYPE_OBJECT:
   1.175 +      g_value_set_object (value, *((gpointer *) storage));
   1.176 +      return TRUE;
   1.177 +    case G_TYPE_BOXED:
   1.178 +      g_value_set_boxed (value, *((gpointer *) storage));
   1.179 +      return TRUE;
   1.180 +    default:
   1.181 +      return FALSE;
   1.182 +    }
   1.183 +}
   1.184 +
   1.185 +gboolean
   1.186 +_dbus_gvalue_take (GValue          *value,
   1.187 +		  GTypeCValue     *cvalue)
   1.188 +{
   1.189 +  GType g_type;
   1.190 +  GTypeValueTable *value_table;
   1.191 +  char *error_msg;
   1.192 +
   1.193 +  g_type = G_VALUE_TYPE (value);
   1.194 +  value_table = g_type_value_table_peek (g_type);
   1.195 +
   1.196 +  error_msg = value_table->collect_value (value, 1, cvalue, G_VALUE_NOCOPY_CONTENTS);
   1.197 +  if (error_msg)
   1.198 +    {
   1.199 +      g_warning ("%s: %s", G_STRLOC, error_msg);
   1.200 +      g_free (error_msg);
   1.201 +      return FALSE;
   1.202 +    }
   1.203 +  /* Clear the NOCOPY_CONTENTS flag; we want to take ownership
   1.204 +   * of the value.
   1.205 +   */
   1.206 +  value->data[1].v_uint &= ~(G_VALUE_NOCOPY_CONTENTS);
   1.207 +  return TRUE;
   1.208 +}
   1.209 +
   1.210 +gboolean
   1.211 +_dbus_gtype_can_signal_error (GType gtype)
   1.212 +{
   1.213 +  switch (gtype)
   1.214 +    {
   1.215 +    case G_TYPE_BOOLEAN:
   1.216 +    case G_TYPE_INT:
   1.217 +    case G_TYPE_UINT:
   1.218 +    case G_TYPE_STRING:
   1.219 +    case G_TYPE_BOXED:
   1.220 +    case G_TYPE_OBJECT:
   1.221 +      return TRUE;
   1.222 +    default:
   1.223 +      return FALSE;
   1.224 +    }
   1.225 +}
   1.226 +
   1.227 +gboolean
   1.228 +_dbus_gvalue_signals_error (const GValue *value)
   1.229 +{
   1.230 +  /* Hardcoded rules for return value semantics for certain
   1.231 +   * types.  Perhaps in the future we'd want an annotation
   1.232 +   * specifying which return values are errors, but in
   1.233 +   * reality people will probably just use boolean and
   1.234 +   * boxed, and there the semantics are pretty standard.
   1.235 +   */
   1.236 +  switch (G_TYPE_FUNDAMENTAL (G_VALUE_TYPE (value)))
   1.237 +    {
   1.238 +    case G_TYPE_BOOLEAN:
   1.239 +      return (g_value_get_boolean (value) == FALSE);
   1.240 +      break;
   1.241 +    case G_TYPE_INT:
   1.242 +      return (g_value_get_int (value) < 0);
   1.243 +      break;
   1.244 +    case G_TYPE_UINT:
   1.245 +      return (g_value_get_uint (value) == 0);
   1.246 +      break;
   1.247 +    case G_TYPE_STRING:
   1.248 +      return (g_value_get_string (value) == NULL);
   1.249 +      break;
   1.250 +    case G_TYPE_BOXED:
   1.251 +      return (g_value_get_boxed (value) == NULL);
   1.252 +      break;
   1.253 +    case G_TYPE_OBJECT:
   1.254 +      return (g_value_get_object (value) == NULL);
   1.255 +      break;
   1.256 +    default:
   1.257 +      g_assert_not_reached ();
   1.258 +    }
   1.259 +}
   1.260 +
   1.261 +
   1.262 +static gboolean
   1.263 +hash_func_from_gtype (GType gtype, GHashFunc *func)
   1.264 +{
   1.265 +  switch (gtype)
   1.266 +    {
   1.267 +    case G_TYPE_CHAR:
   1.268 +    case G_TYPE_UCHAR:
   1.269 +    case G_TYPE_BOOLEAN:
   1.270 +    case G_TYPE_INT:
   1.271 +    case G_TYPE_UINT:
   1.272 +      *func = NULL;
   1.273 +      return TRUE;
   1.274 +    case G_TYPE_STRING:
   1.275 +      *func = g_str_hash;
   1.276 +      return TRUE;
   1.277 +    default:
   1.278 +      return FALSE;
   1.279 +    }
   1.280 +}
   1.281 +
   1.282 +static void
   1.283 +unset_and_free_g_value (gpointer val)
   1.284 +{
   1.285 +  GValue *value = val;
   1.286 +
   1.287 +  g_value_unset (value);
   1.288 +  g_free (value);
   1.289 +}
   1.290 +
   1.291 +static gboolean
   1.292 +hash_free_from_gtype (GType gtype, GDestroyNotify *func)
   1.293 +{
   1.294 +  switch (gtype)
   1.295 +    {
   1.296 +    case G_TYPE_CHAR:
   1.297 +    case G_TYPE_UCHAR:
   1.298 +    case G_TYPE_BOOLEAN:
   1.299 +    case G_TYPE_INT:
   1.300 +    case G_TYPE_UINT:
   1.301 +      *func = NULL;
   1.302 +      return TRUE;
   1.303 +    case G_TYPE_DOUBLE:
   1.304 +    case G_TYPE_STRING:
   1.305 +      *func = g_free;
   1.306 +      return TRUE;
   1.307 +    default:
   1.308 +      if (gtype == G_TYPE_VALUE)
   1.309 +	{
   1.310 +	  *func = unset_and_free_g_value;
   1.311 +	  return TRUE;
   1.312 +	}
   1.313 +      else if (gtype == G_TYPE_VALUE_ARRAY)
   1.314 +        {
   1.315 +          *func = (GDestroyNotify) g_value_array_free;
   1.316 +          return TRUE;
   1.317 +        }
   1.318 +      else if (dbus_g_type_is_collection (gtype))
   1.319 +        {
   1.320 +          const DBusGTypeSpecializedCollectionVtable* vtable;
   1.321 +          vtable = dbus_g_type_collection_peek_vtable (gtype);
   1.322 +          if (vtable->base_vtable.simple_free_func)
   1.323 +            {
   1.324 +              *func = vtable->base_vtable.simple_free_func;
   1.325 +              return TRUE;
   1.326 +            }
   1.327 +        }
   1.328 +      else if (dbus_g_type_is_map (gtype))
   1.329 +        {
   1.330 +          const DBusGTypeSpecializedMapVtable* vtable;
   1.331 +          vtable = dbus_g_type_map_peek_vtable (gtype);
   1.332 +          if (vtable->base_vtable.simple_free_func)
   1.333 +            {
   1.334 +              *func = vtable->base_vtable.simple_free_func;
   1.335 +              return TRUE;
   1.336 +            }
   1.337 +        }
   1.338 +      else if (dbus_g_type_is_struct (gtype))
   1.339 +        {
   1.340 +          const DBusGTypeSpecializedStructVtable *vtable;
   1.341 +          vtable = dbus_g_type_struct_peek_vtable (gtype);
   1.342 +          if (vtable->base_vtable.simple_free_func)
   1.343 +            {
   1.344 +              *func = vtable->base_vtable.simple_free_func;
   1.345 +              return TRUE;
   1.346 +            }
   1.347 +        }
   1.348 +      return FALSE;
   1.349 +    }
   1.350 +}
   1.351 +
   1.352 +gboolean
   1.353 +_dbus_gtype_is_valid_hash_key (GType type)
   1.354 +{
   1.355 +  GHashFunc func;
   1.356 +  return hash_func_from_gtype (type, &func);
   1.357 +}
   1.358 +
   1.359 +gboolean
   1.360 +_dbus_gtype_is_valid_hash_value (GType type)
   1.361 +{
   1.362 +  GDestroyNotify func;
   1.363 +  return hash_free_from_gtype (type, &func);
   1.364 +}
   1.365 +
   1.366 +GHashFunc
   1.367 +_dbus_g_hash_func_from_gtype (GType gtype)
   1.368 +{
   1.369 +  GHashFunc func;
   1.370 +  gboolean ret;
   1.371 +  ret = hash_func_from_gtype (gtype, &func);
   1.372 +  g_assert (ret != FALSE);
   1.373 +  return func;
   1.374 +}
   1.375 +
   1.376 +GEqualFunc
   1.377 +_dbus_g_hash_equal_from_gtype (GType gtype)
   1.378 +{
   1.379 +  g_assert (_dbus_gtype_is_valid_hash_key (gtype));
   1.380 +
   1.381 +  switch (gtype)
   1.382 +    {
   1.383 +    case G_TYPE_CHAR:
   1.384 +    case G_TYPE_UCHAR:
   1.385 +    case G_TYPE_BOOLEAN:
   1.386 +    case G_TYPE_INT:
   1.387 +    case G_TYPE_UINT:
   1.388 +      return NULL;
   1.389 +    case G_TYPE_STRING:
   1.390 +      return g_str_equal;
   1.391 +    default:
   1.392 +      g_assert_not_reached ();
   1.393 +      return NULL;
   1.394 +    }
   1.395 +}
   1.396 +
   1.397 +GDestroyNotify
   1.398 +_dbus_g_hash_free_from_gtype (GType gtype)
   1.399 +{
   1.400 +  GDestroyNotify func;
   1.401 +  gboolean ret;
   1.402 +  ret = hash_free_from_gtype (gtype, &func);
   1.403 +  g_assert (ret != FALSE);
   1.404 +  return func;
   1.405 +}
   1.406 +
   1.407 +static void gvalue_take_ptrarray_value (GValue *value, gpointer instance);
   1.408 +
   1.409 +static void
   1.410 +gvalue_take_hash_value (GValue *value, gpointer instance)
   1.411 +{
   1.412 +  switch (g_type_fundamental (G_VALUE_TYPE (value)))
   1.413 +    {
   1.414 +    case G_TYPE_CHAR:
   1.415 +      g_value_set_char (value, (gchar) GPOINTER_TO_INT (instance));
   1.416 +      break;
   1.417 +    case G_TYPE_UCHAR:
   1.418 +      g_value_set_uchar (value, (guchar) GPOINTER_TO_UINT (instance));
   1.419 +      break;
   1.420 +    case G_TYPE_BOOLEAN:
   1.421 +      g_value_set_boolean (value, (gboolean) GPOINTER_TO_UINT (instance));
   1.422 +      break;
   1.423 +    case G_TYPE_INT:
   1.424 +      g_value_set_int (value, GPOINTER_TO_INT (instance));
   1.425 +      break;
   1.426 +    case G_TYPE_UINT:
   1.427 +      g_value_set_uint (value, GPOINTER_TO_UINT (instance));
   1.428 +      break;
   1.429 +    case G_TYPE_DOUBLE:
   1.430 +      g_value_set_double (value, *(gdouble *) instance);
   1.431 +      break;
   1.432 +    default:
   1.433 +      gvalue_take_ptrarray_value (value, instance);
   1.434 +      break;
   1.435 +    }
   1.436 +}
   1.437 +
   1.438 +static gpointer ptrarray_value_from_gvalue (const GValue *value);
   1.439 +
   1.440 +static gpointer
   1.441 +hash_value_from_gvalue (GValue *value)
   1.442 +{
   1.443 +  switch (g_type_fundamental (G_VALUE_TYPE (value)))
   1.444 +    {
   1.445 +    case G_TYPE_CHAR:
   1.446 +      return GINT_TO_POINTER ((int) g_value_get_char (value));
   1.447 +      break;
   1.448 +    case G_TYPE_UCHAR:
   1.449 +      return GUINT_TO_POINTER ((guint) g_value_get_uchar (value));
   1.450 +      break;
   1.451 +    case G_TYPE_BOOLEAN:
   1.452 +      return GUINT_TO_POINTER ((guint) g_value_get_boolean (value));
   1.453 +      break;
   1.454 +    case G_TYPE_INT:
   1.455 +      return GINT_TO_POINTER (g_value_get_int (value));
   1.456 +      break;
   1.457 +    case G_TYPE_UINT:
   1.458 +      return GUINT_TO_POINTER (g_value_get_uint (value));
   1.459 +      break;
   1.460 +    case G_TYPE_DOUBLE:
   1.461 +      {
   1.462 +        gdouble *p = (gdouble *) g_malloc0 (sizeof (gdouble));
   1.463 +        *p = g_value_get_double (value);
   1.464 +        return (gpointer) p;
   1.465 +      }
   1.466 +      break;
   1.467 +    default:
   1.468 +      return ptrarray_value_from_gvalue (value);
   1.469 +      break;
   1.470 +    }
   1.471 +}
   1.472 +
   1.473 +struct DBusGHashTableValueForeachData
   1.474 +{
   1.475 +  DBusGTypeSpecializedMapIterator func;
   1.476 +  GType key_type;
   1.477 +  GType value_type;
   1.478 +  gpointer data;
   1.479 +};
   1.480 +
   1.481 +static void
   1.482 +hashtable_foreach_with_values (gpointer key, gpointer value, gpointer user_data)
   1.483 +{
   1.484 +  GValue key_val = {0, };
   1.485 +  GValue value_val = {0, };
   1.486 +  struct DBusGHashTableValueForeachData *data = user_data;
   1.487 +  
   1.488 +  g_value_init (&key_val, data->key_type);
   1.489 +  g_value_init (&value_val, data->value_type);
   1.490 +  gvalue_take_hash_value (&key_val, key);
   1.491 +  gvalue_take_hash_value (&value_val, value);
   1.492 +
   1.493 +  data->func (&key_val, &value_val, data->data);
   1.494 +}
   1.495 +
   1.496 +
   1.497 +static void
   1.498 +hashtable_iterator (GType                           hash_type,
   1.499 +		    gpointer                        instance,
   1.500 +		    DBusGTypeSpecializedMapIterator iterator,
   1.501 +		    gpointer                        user_data)
   1.502 +{
   1.503 +  struct DBusGHashTableValueForeachData data;
   1.504 +  GType key_gtype;
   1.505 +  GType value_gtype;
   1.506 +
   1.507 +  key_gtype = dbus_g_type_get_map_key_specialization (hash_type);
   1.508 +  value_gtype = dbus_g_type_get_map_value_specialization (hash_type);
   1.509 +
   1.510 +  data.func = iterator;
   1.511 +  data.key_type = key_gtype;
   1.512 +  data.value_type = value_gtype;
   1.513 +  data.data = user_data;
   1.514 +
   1.515 +  g_hash_table_foreach (instance, hashtable_foreach_with_values, &data);
   1.516 +}
   1.517 +
   1.518 +void
   1.519 +_dbus_g_hash_table_insert_steal_values (GHashTable *table,
   1.520 +				       GValue     *key_val,
   1.521 +				       GValue     *value_val)
   1.522 +{
   1.523 +  gpointer key, val;
   1.524 +  
   1.525 +  key = hash_value_from_gvalue (key_val);
   1.526 +  val = hash_value_from_gvalue (value_val);
   1.527 +
   1.528 +  g_hash_table_insert (table, key, val);
   1.529 +}
   1.530 +
   1.531 +static void
   1.532 +hashtable_append (DBusGTypeSpecializedAppendContext *ctx,
   1.533 +		  GValue                            *key,
   1.534 +		  GValue                            *val)
   1.535 +{
   1.536 +  GHashTable *table;
   1.537 +
   1.538 +  table = g_value_get_boxed (ctx->val);
   1.539 +  _dbus_g_hash_table_insert_steal_values (table, key, val);
   1.540 +}
   1.541 +
   1.542 +static gpointer
   1.543 +hashtable_constructor (GType type)
   1.544 +{
   1.545 +  GHashTable *ret;
   1.546 +  GType key_gtype;
   1.547 +  GType value_gtype;
   1.548 +
   1.549 +  key_gtype = dbus_g_type_get_map_key_specialization (type);
   1.550 +  value_gtype = dbus_g_type_get_map_value_specialization (type);
   1.551 +
   1.552 +  ret = g_hash_table_new_full (_dbus_g_hash_func_from_gtype (key_gtype),
   1.553 +			       _dbus_g_hash_equal_from_gtype (key_gtype),
   1.554 +			       _dbus_g_hash_free_from_gtype (key_gtype),
   1.555 +			       _dbus_g_hash_free_from_gtype (value_gtype));
   1.556 +  return ret;
   1.557 +}
   1.558 +
   1.559 +static void
   1.560 +hashtable_insert_values (GHashTable       *table,
   1.561 +			 const GValue     *key_val,
   1.562 +			 const GValue     *value_val)
   1.563 +{
   1.564 +  GValue key_copy = {0, };
   1.565 +  GValue value_copy = {0, };
   1.566 +
   1.567 +  g_value_init (&key_copy, G_VALUE_TYPE (key_val));
   1.568 +  g_value_copy (key_val, &key_copy);
   1.569 +  g_value_init (&value_copy, G_VALUE_TYPE (value_val));
   1.570 +  g_value_copy (value_val, &value_copy);
   1.571 +  
   1.572 +  _dbus_g_hash_table_insert_steal_values (table, &key_copy, &value_copy);
   1.573 +}
   1.574 +
   1.575 +static void
   1.576 +hashtable_foreach_copy (const GValue *key, const GValue *val, gpointer data)
   1.577 +{
   1.578 +  hashtable_insert_values ((GHashTable *) data, key, val);
   1.579 +}
   1.580 +
   1.581 +static gpointer
   1.582 +hashtable_copy (GType type, gpointer src)
   1.583 +{
   1.584 +  GHashTable *ghash;
   1.585 +  GHashTable *ret;
   1.586 +  GValue hashval = {0,};
   1.587 +
   1.588 +  ghash = src;
   1.589 +
   1.590 +  ret = hashtable_constructor (type);
   1.591 +
   1.592 +  g_value_init (&hashval, type);
   1.593 +  g_value_set_static_boxed (&hashval, ghash); 
   1.594 +  dbus_g_type_map_value_iterate (&hashval, hashtable_foreach_copy, ret);
   1.595 +  return ret;
   1.596 +}
   1.597 +
   1.598 +static void
   1.599 +hashtable_simple_free (gpointer val)
   1.600 +{
   1.601 +  g_hash_table_destroy (val);
   1.602 +}
   1.603 +
   1.604 +static gpointer
   1.605 +valuearray_constructor (GType type)
   1.606 +{
   1.607 +  GValueArray *ret;
   1.608 +  guint size = dbus_g_type_get_struct_size (type);
   1.609 +  guint i;
   1.610 +  ret = g_value_array_new (size);
   1.611 +  for (i=0; i < size; i++)
   1.612 +    {
   1.613 +      GValue val = {0,};
   1.614 +      g_value_init (&val, dbus_g_type_get_struct_member_type (type, i));
   1.615 +      g_value_array_append(ret, &val);
   1.616 +    }
   1.617 +  return (gpointer)ret;
   1.618 +}
   1.619 +
   1.620 +static gpointer
   1.621 +valuearray_copy (GType type, gpointer src)
   1.622 +{
   1.623 +  return g_value_array_copy ((GValueArray*) src);
   1.624 +}
   1.625 +
   1.626 +static void
   1.627 +valuearray_simple_free (gpointer val)
   1.628 +{
   1.629 +  g_value_array_free (val);
   1.630 +}
   1.631 +
   1.632 +static gboolean
   1.633 +valuearray_get_member (GType type, gpointer instance,
   1.634 +                       guint member, GValue *ret)
   1.635 +{
   1.636 +  GValueArray *va = (GValueArray*) instance;
   1.637 +  const GValue *val;
   1.638 +  if (member < dbus_g_type_get_struct_size (type))
   1.639 +    {
   1.640 +      val = g_value_array_get_nth (va, member);
   1.641 +      g_value_copy (val, ret);
   1.642 +      return TRUE;
   1.643 +    }
   1.644 +  else
   1.645 +    return FALSE;
   1.646 +}
   1.647 +
   1.648 +static gboolean
   1.649 +valuearray_set_member (GType type, gpointer instance,
   1.650 +                       guint member, const GValue *member_type)
   1.651 +{
   1.652 +  GValueArray *va = (GValueArray*) instance;
   1.653 +  GValue *vp;
   1.654 +  if (member < dbus_g_type_get_struct_size (type))
   1.655 +    {
   1.656 +      vp = g_value_array_get_nth (va, member);
   1.657 +      g_value_copy (member_type, vp);
   1.658 +      return TRUE;
   1.659 +    }
   1.660 +  else
   1.661 +    return FALSE;
   1.662 +}
   1.663 +
   1.664 +
   1.665 +static gpointer
   1.666 +array_constructor (GType type)
   1.667 +{
   1.668 +  GArray *array;
   1.669 +  guint elt_size;
   1.670 +  GType elt_type;
   1.671 +  gboolean zero_terminated;
   1.672 +  gboolean clear;
   1.673 +
   1.674 +  elt_type = dbus_g_type_get_collection_specialization (type);
   1.675 +  g_assert (elt_type != G_TYPE_INVALID);
   1.676 +
   1.677 +  elt_size = _dbus_g_type_fixed_get_size (elt_type);
   1.678 +
   1.679 +  /* These are "safe" defaults */ 
   1.680 +  zero_terminated = TRUE; /* ((struct _DBusGRealArray*) garray)->zero_terminated; */
   1.681 +  clear = TRUE; /* ((struct _DBusGRealArray*) garray)->clear; */
   1.682 +
   1.683 +  array = g_array_new (zero_terminated, clear, elt_size);
   1.684 +  return array;
   1.685 +}
   1.686 +
   1.687 +static gpointer
   1.688 +array_copy (GType type, gpointer src)
   1.689 +{
   1.690 +  GArray *garray;
   1.691 +  GArray *new;
   1.692 +
   1.693 +  garray = src;
   1.694 +
   1.695 +  new = array_constructor (type);
   1.696 +  g_array_append_vals (new, garray->data, garray->len);
   1.697 +
   1.698 +  return new;
   1.699 +}
   1.700 +
   1.701 +static void
   1.702 +array_simple_free (gpointer val)
   1.703 +{
   1.704 +  GArray *array;
   1.705 +  array = val;
   1.706 +  g_array_free (array, TRUE);
   1.707 +}
   1.708 +
   1.709 +static gboolean
   1.710 +array_fixed_accessor (GType type, gpointer instance, gpointer *values, guint *len)
   1.711 +{
   1.712 +  GType elt_type;
   1.713 +  GArray *array = instance;
   1.714 +
   1.715 +  elt_type = dbus_g_type_get_collection_specialization (type);
   1.716 +  if (!_dbus_g_type_is_fixed (elt_type))
   1.717 +    return FALSE;
   1.718 +
   1.719 +  *values = array->data;
   1.720 +  *len = array->len;
   1.721 +  return TRUE;
   1.722 +}
   1.723 +
   1.724 +static gpointer
   1.725 +ptrarray_constructor (GType type)
   1.726 +{
   1.727 +  /* Later we should determine a destructor, need g_ptr_array_destroy */
   1.728 +  return g_ptr_array_new ();
   1.729 +}
   1.730 +
   1.731 +static void
   1.732 +gvalue_take_ptrarray_value (GValue *value, gpointer instance)
   1.733 +{
   1.734 +  switch (g_type_fundamental (G_VALUE_TYPE (value)))
   1.735 +    {
   1.736 +    case G_TYPE_STRING:
   1.737 +      g_value_take_string (value, instance);
   1.738 +      break;
   1.739 +    case G_TYPE_BOXED:
   1.740 +      g_value_take_boxed (value, instance);
   1.741 +      break;
   1.742 +    case G_TYPE_OBJECT:
   1.743 +      g_value_take_object (value, instance);
   1.744 +      break;
   1.745 +    default:
   1.746 +      g_assert_not_reached ();
   1.747 +      break;
   1.748 +    }
   1.749 +}
   1.750 +
   1.751 +static gpointer
   1.752 +ptrarray_value_from_gvalue (const GValue *value)
   1.753 +{
   1.754 +  GValue tmp = {0, };
   1.755 +
   1.756 +  /* if the NOCOPY flag is set, then value was created via set_static and hence
   1.757 +   * is not owned by us. in order to preserve the "take" semantics that the API
   1.758 +   * has in general (which avoids copying in the common case), we must copy any
   1.759 +   * static values so that we can indiscriminately free the entire collection
   1.760 +   * later. */
   1.761 +  if (value->data[1].v_uint & G_VALUE_NOCOPY_CONTENTS)
   1.762 +    {
   1.763 +      g_value_init (&tmp, G_VALUE_TYPE (value));
   1.764 +      g_value_copy (value, &tmp);
   1.765 +      value = &tmp;
   1.766 +    }
   1.767 +
   1.768 +  switch (g_type_fundamental (G_VALUE_TYPE (value)))
   1.769 +    {
   1.770 +    case G_TYPE_STRING:
   1.771 +      return (gpointer) g_value_get_string (value);
   1.772 +      break;
   1.773 +    case G_TYPE_BOXED:
   1.774 +      return g_value_get_boxed (value);
   1.775 +      break;
   1.776 +    case G_TYPE_OBJECT:
   1.777 +      return g_value_get_object (value);
   1.778 +      break;
   1.779 +    default:
   1.780 +      g_assert_not_reached ();
   1.781 +      return NULL;
   1.782 +    }
   1.783 +}
   1.784 +
   1.785 +static void
   1.786 +ptrarray_iterator (GType                                   ptrarray_type,
   1.787 +		   gpointer                                instance,
   1.788 +		   DBusGTypeSpecializedCollectionIterator  iterator,
   1.789 +		   gpointer                                user_data)
   1.790 +{
   1.791 +  GPtrArray *ptrarray;
   1.792 +  GType elt_gtype;
   1.793 +  guint i;
   1.794 +
   1.795 +  ptrarray = instance;
   1.796 +
   1.797 +  elt_gtype = dbus_g_type_get_collection_specialization (ptrarray_type);
   1.798 +
   1.799 +  for (i = 0; i < ptrarray->len; i++)
   1.800 +    {
   1.801 +      GValue val = {0, };
   1.802 +      g_value_init (&val, elt_gtype);
   1.803 +      gvalue_take_ptrarray_value (&val, g_ptr_array_index (ptrarray, i));
   1.804 +      iterator (&val, user_data);
   1.805 +    }
   1.806 +}
   1.807 +
   1.808 +static void
   1.809 +ptrarray_copy_elt (const GValue *val, gpointer user_data)
   1.810 +{
   1.811 +  GPtrArray *dest = user_data;
   1.812 +  GValue val_copy = {0, };
   1.813 +
   1.814 +  g_value_init (&val_copy, G_VALUE_TYPE (val));
   1.815 +  g_value_copy (val, &val_copy);
   1.816 +
   1.817 +  g_ptr_array_add (dest, ptrarray_value_from_gvalue (&val_copy));
   1.818 +}
   1.819 +
   1.820 +static gpointer
   1.821 +ptrarray_copy (GType type, gpointer src)
   1.822 +{
   1.823 +  GPtrArray *new;
   1.824 +  GValue array_val = {0, };
   1.825 +
   1.826 +  g_value_init (&array_val, type);
   1.827 +  g_value_set_static_boxed (&array_val, src);
   1.828 +
   1.829 +  new = ptrarray_constructor (type);
   1.830 +  dbus_g_type_collection_value_iterate (&array_val, ptrarray_copy_elt, new);
   1.831 +
   1.832 +  return new;
   1.833 +}
   1.834 +
   1.835 +static void
   1.836 +ptrarray_append (DBusGTypeSpecializedAppendContext *ctx, GValue *value)
   1.837 +{
   1.838 +  GPtrArray *array;
   1.839 +
   1.840 +  array = g_value_get_boxed (ctx->val);
   1.841 +
   1.842 +  g_ptr_array_add (array, ptrarray_value_from_gvalue (value));
   1.843 +}
   1.844 +
   1.845 +static void
   1.846 +ptrarray_free (GType type, gpointer val)
   1.847 +{
   1.848 +  GPtrArray *array;
   1.849 +  GValue elt_val = {0, };
   1.850 +  GType elt_gtype;
   1.851 +  unsigned int i;
   1.852 +
   1.853 +  array = val;
   1.854 +
   1.855 +  elt_gtype = dbus_g_type_get_collection_specialization (type);
   1.856 +
   1.857 +  for (i = 0; i < array->len; i++)
   1.858 +    {
   1.859 +      g_value_init (&elt_val, elt_gtype);
   1.860 +      gvalue_take_ptrarray_value (&elt_val, g_ptr_array_index (array, i));
   1.861 +      g_value_unset (&elt_val);
   1.862 +    }
   1.863 +
   1.864 +  g_ptr_array_free (array, TRUE);
   1.865 +}
   1.866 +
   1.867 +static gpointer
   1.868 +slist_constructor (GType type)
   1.869 +{
   1.870 +  return NULL;
   1.871 +}
   1.872 +
   1.873 +static void
   1.874 +slist_iterator (GType                                   list_type,
   1.875 +		gpointer                                instance,
   1.876 +		DBusGTypeSpecializedCollectionIterator  iterator,
   1.877 +		gpointer                                user_data)
   1.878 +{
   1.879 +  GSList *slist;
   1.880 +  GType elt_gtype;
   1.881 +
   1.882 +  slist = instance;
   1.883 +
   1.884 +  elt_gtype = dbus_g_type_get_collection_specialization (list_type);
   1.885 +
   1.886 +  for (slist = instance; slist != NULL; slist = slist->next)
   1.887 +    {
   1.888 +      GValue val = {0, };
   1.889 +      g_value_init (&val, elt_gtype);
   1.890 +      gvalue_take_ptrarray_value (&val, slist->data);
   1.891 +      iterator (&val, user_data);
   1.892 +    }
   1.893 +}
   1.894 +
   1.895 +static void
   1.896 +slist_copy_elt (const GValue *val, gpointer user_data)
   1.897 +{
   1.898 +  GSList **dest = user_data;
   1.899 +  GValue val_copy = {0, };
   1.900 +
   1.901 +  g_value_init (&val_copy, G_VALUE_TYPE (val));
   1.902 +  g_value_copy (val, &val_copy);
   1.903 +
   1.904 +  *dest = g_slist_append (*dest, ptrarray_value_from_gvalue (&val_copy));
   1.905 +}
   1.906 +
   1.907 +static gpointer
   1.908 +slist_copy (GType type, gpointer src)
   1.909 +{
   1.910 +  GSList *new;
   1.911 +  GValue slist_val = {0, };
   1.912 +
   1.913 +  g_value_init (&slist_val, type);
   1.914 +  g_value_set_static_boxed (&slist_val, src);
   1.915 +
   1.916 +  new = slist_constructor (type);
   1.917 +  dbus_g_type_collection_value_iterate (&slist_val, slist_copy_elt, &new);
   1.918 +
   1.919 +  return new;
   1.920 +}
   1.921 +
   1.922 +static void
   1.923 +slist_append (DBusGTypeSpecializedAppendContext *ctx, GValue *value)
   1.924 +{
   1.925 +  GSList *list;
   1.926 +
   1.927 +  list = g_value_get_boxed (ctx->val);
   1.928 +  list = g_slist_prepend (list, ptrarray_value_from_gvalue (value));
   1.929 +  g_value_set_static_boxed (ctx->val, list);
   1.930 +}
   1.931 +
   1.932 +static void
   1.933 +slist_end_append (DBusGTypeSpecializedAppendContext *ctx)
   1.934 +{
   1.935 +  GSList *list;
   1.936 +
   1.937 +  /* if you append multiple times to the slist, this will reverse the existing
   1.938 +   * elements... we need an init_append function */
   1.939 +  list = g_value_get_boxed (ctx->val);
   1.940 +  list = g_slist_reverse (list);
   1.941 +
   1.942 +  g_value_take_boxed (ctx->val, list);
   1.943 +}
   1.944 +
   1.945 +static void
   1.946 +slist_free (GType type, gpointer val)
   1.947 +{
   1.948 +  GSList *list;
   1.949 +  GType elt_gtype;
   1.950 +  list = val;
   1.951 +
   1.952 +  elt_gtype = dbus_g_type_get_collection_specialization (type);
   1.953 +
   1.954 +  while (list != NULL)
   1.955 +    {
   1.956 +      GValue elt_val = {0, };
   1.957 +      g_value_init (&elt_val, elt_gtype);
   1.958 +      gvalue_take_ptrarray_value (&elt_val, list->data);
   1.959 +      g_value_unset (&elt_val);
   1.960 +      list = g_slist_next(list);
   1.961 +    }
   1.962 +  list=val;
   1.963 +  g_slist_free (list);
   1.964 +}
   1.965 +
   1.966 +void
   1.967 +_dbus_g_type_specialized_builtins_init (void)
   1.968 +{
   1.969 +  /* types with a simple_free function can be freed at run-time without
   1.970 +   * the destroy function needing to know the type, so they can be
   1.971 +   * stored in hash tables */
   1.972 +
   1.973 +  static const DBusGTypeSpecializedCollectionVtable array_vtable = {
   1.974 +    {
   1.975 +      array_constructor,
   1.976 +      NULL,
   1.977 +      array_copy,
   1.978 +      array_simple_free,
   1.979 +      NULL,
   1.980 +      NULL,
   1.981 +    },
   1.982 +    array_fixed_accessor,
   1.983 +    NULL,
   1.984 +    NULL,
   1.985 +    NULL
   1.986 +  };
   1.987 +
   1.988 +
   1.989 +  static const DBusGTypeSpecializedCollectionVtable ptrarray_vtable = {
   1.990 +    {
   1.991 +      ptrarray_constructor,
   1.992 +      ptrarray_free,
   1.993 +      ptrarray_copy,
   1.994 +      NULL,
   1.995 +      NULL,
   1.996 +      NULL,
   1.997 +    },
   1.998 +    NULL,
   1.999 +    ptrarray_iterator,
  1.1000 +    ptrarray_append,
  1.1001 +    NULL,
  1.1002 +  };
  1.1003 +
  1.1004 +
  1.1005 +  static const DBusGTypeSpecializedCollectionVtable slist_vtable = {
  1.1006 +    {
  1.1007 +      slist_constructor,
  1.1008 +      slist_free,
  1.1009 +      slist_copy,
  1.1010 +      NULL,
  1.1011 +      NULL,
  1.1012 +      NULL,
  1.1013 +    },
  1.1014 +    NULL,
  1.1015 +    slist_iterator,
  1.1016 +    slist_append,
  1.1017 +    slist_end_append,
  1.1018 +  };
  1.1019 +
  1.1020 +  static const DBusGTypeSpecializedMapVtable hashtable_vtable = {
  1.1021 +    {
  1.1022 +      hashtable_constructor,
  1.1023 +      NULL,
  1.1024 +      hashtable_copy,
  1.1025 +      hashtable_simple_free,
  1.1026 +      NULL,
  1.1027 +      NULL
  1.1028 +    },
  1.1029 +    hashtable_iterator,
  1.1030 +    hashtable_append
  1.1031 +  };
  1.1032 +
  1.1033 +  static const DBusGTypeSpecializedStructVtable valuearray_vtable = {
  1.1034 +    {
  1.1035 +      valuearray_constructor,
  1.1036 +      NULL,
  1.1037 +      valuearray_copy,
  1.1038 +      valuearray_simple_free,
  1.1039 +      NULL,
  1.1040 +      NULL
  1.1041 +    },
  1.1042 +    valuearray_get_member,
  1.1043 +    valuearray_set_member
  1.1044 +  };
  1.1045 +
  1.1046 +  dbus_g_type_register_collection ("GSList", &slist_vtable, 0);
  1.1047 +  dbus_g_type_register_collection ("GArray", &array_vtable, 0);
  1.1048 +  dbus_g_type_register_collection ("GPtrArray", &ptrarray_vtable, 0);
  1.1049 +  dbus_g_type_register_map ("GHashTable", &hashtable_vtable, 0);
  1.1050 +  dbus_g_type_register_struct ("GValueArray", &valuearray_vtable, 0);
  1.1051 +}
  1.1052 +
  1.1053 +#ifdef DBUS_BUILD_TESTS
  1.1054 +
  1.1055 +typedef struct
  1.1056 +{
  1.1057 +  gboolean seen_foo;
  1.1058 +  gboolean seen_baz;
  1.1059 +} TestSpecializedHashData;
  1.1060 +
  1.1061 +static void
  1.1062 +test_specialized_hash (const GValue *key, const GValue *val, gpointer user_data)
  1.1063 +{
  1.1064 +  TestSpecializedHashData *data = user_data;
  1.1065 +
  1.1066 +  g_assert (G_VALUE_HOLDS_STRING (key));
  1.1067 +  g_assert (G_VALUE_HOLDS_STRING (val));
  1.1068 +
  1.1069 +  if (!strcmp (g_value_get_string (key), "foo"))
  1.1070 +    {
  1.1071 +      data->seen_foo = TRUE;
  1.1072 +      g_assert (!strcmp (g_value_get_string (val), "bar"));
  1.1073 +    }
  1.1074 +  else if (!strcmp (g_value_get_string (key), "baz"))
  1.1075 +    {
  1.1076 +      data->seen_baz = TRUE;
  1.1077 +      g_assert (!strcmp (g_value_get_string (val), "moo"));
  1.1078 +    }
  1.1079 +  else
  1.1080 +    {
  1.1081 +      g_assert_not_reached ();
  1.1082 +    }
  1.1083 +}
  1.1084 +
  1.1085 +static void
  1.1086 +test_specialized_hash_2 (const GValue *key, const GValue *val, gpointer user_data)
  1.1087 +{
  1.1088 +  TestSpecializedHashData *data = user_data;
  1.1089 +  const GValue *realval;
  1.1090 +
  1.1091 +  g_assert (G_VALUE_HOLDS_STRING (key));
  1.1092 +  g_assert (G_VALUE_TYPE (val) == G_TYPE_VALUE);
  1.1093 +
  1.1094 +  realval = g_value_get_boxed (val);
  1.1095 +
  1.1096 +  if (!strcmp (g_value_get_string (key), "foo"))
  1.1097 +    {
  1.1098 +      data->seen_foo = TRUE;
  1.1099 +      g_assert (G_VALUE_HOLDS_UINT (realval));
  1.1100 +      g_assert (g_value_get_uint (realval) == 20);
  1.1101 +    }
  1.1102 +  else if (!strcmp (g_value_get_string (key), "baz"))
  1.1103 +    {
  1.1104 +      data->seen_baz = TRUE;
  1.1105 +      g_assert (G_VALUE_HOLDS_STRING (realval));
  1.1106 +      g_assert (!strcmp ("bar", g_value_get_string (realval)));
  1.1107 +    }
  1.1108 +  else
  1.1109 +    {
  1.1110 +      g_assert_not_reached ();
  1.1111 +    }
  1.1112 +}
  1.1113 +
  1.1114 + 	#ifdef __SYMBIAN32__
  1.1115 +	EXPORT_C
  1.1116 +	#endif
  1.1117 +gboolean
  1.1118 +_dbus_gvalue_utils_test (const char *datadir)
  1.1119 +{
  1.1120 +  GType type;
  1.1121 +
  1.1122 +  dbus_g_type_specialized_init ();
  1.1123 + _dbus_g_type_specialized_builtins_init ();
  1.1124 +
  1.1125 +  type = dbus_g_type_get_collection ("GArray", G_TYPE_UINT);
  1.1126 +  g_assert (dbus_g_type_is_collection (type));
  1.1127 +  g_assert (dbus_g_type_get_collection_specialization (type) == G_TYPE_UINT);
  1.1128 +  {
  1.1129 +    GArray *instance;
  1.1130 +
  1.1131 +    instance = dbus_g_type_specialized_construct (type);
  1.1132 +
  1.1133 +    g_assert (instance->len == 0);
  1.1134 +
  1.1135 +    g_array_free (instance, TRUE);
  1.1136 +  }
  1.1137 +
  1.1138 +  type = dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_STRING);
  1.1139 +  g_assert (dbus_g_type_is_map (type));
  1.1140 +  g_assert (dbus_g_type_get_map_key_specialization (type) == G_TYPE_STRING);
  1.1141 +  g_assert (dbus_g_type_get_map_value_specialization (type) == G_TYPE_STRING);
  1.1142 +  {
  1.1143 +    GHashTable *instance;
  1.1144 +    GValue val = { 0, };
  1.1145 +    TestSpecializedHashData hashdata;
  1.1146 +
  1.1147 +    instance = dbus_g_type_specialized_construct (type);
  1.1148 +
  1.1149 +    g_assert (g_hash_table_size (instance) == 0);
  1.1150 +    g_hash_table_insert (instance, g_strdup ("foo"), g_strdup ("bar"));
  1.1151 +    g_hash_table_insert (instance, g_strdup ("baz"), g_strdup ("moo"));
  1.1152 +    g_assert (g_hash_table_size (instance) == 2);
  1.1153 +
  1.1154 +    g_value_init (&val, type);
  1.1155 +    g_value_set_boxed_take_ownership (&val, instance);
  1.1156 +    hashdata.seen_foo = FALSE;
  1.1157 +    hashdata.seen_baz = FALSE;
  1.1158 +    dbus_g_type_map_value_iterate (&val,
  1.1159 +				   test_specialized_hash, 
  1.1160 +				   &hashdata);
  1.1161 +    
  1.1162 +    g_assert (hashdata.seen_foo);
  1.1163 +    g_assert (hashdata.seen_baz);
  1.1164 +
  1.1165 +    g_value_unset (&val);
  1.1166 +  }
  1.1167 +
  1.1168 +  type = dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_VALUE);
  1.1169 +  g_assert (dbus_g_type_is_map (type));
  1.1170 +  g_assert (dbus_g_type_get_map_key_specialization (type) == G_TYPE_STRING);
  1.1171 +  g_assert (dbus_g_type_get_map_value_specialization (type) == G_TYPE_VALUE);
  1.1172 +  {
  1.1173 +    GHashTable *instance;
  1.1174 +    GValue val = { 0, };
  1.1175 +    TestSpecializedHashData hashdata;
  1.1176 +    DBusGTypeSpecializedAppendContext ctx;
  1.1177 +    GValue *eltval;
  1.1178 +
  1.1179 +    instance = dbus_g_type_specialized_construct (type);
  1.1180 +    g_value_init (&val, type);
  1.1181 +    g_value_set_boxed_take_ownership (&val, instance);
  1.1182 +
  1.1183 +    dbus_g_type_specialized_init_append (&val, &ctx);
  1.1184 +
  1.1185 +    {
  1.1186 +      GValue keyval = { 0, };
  1.1187 +      GValue valval = { 0, };
  1.1188 +      g_value_init (&keyval, G_TYPE_STRING);
  1.1189 +      g_value_set_string (&keyval, "foo"); 
  1.1190 +
  1.1191 +      g_value_init (&valval, G_TYPE_VALUE);
  1.1192 +      eltval = g_new0 (GValue, 1);
  1.1193 +      g_value_init (eltval, G_TYPE_UINT);
  1.1194 +      g_value_set_uint (eltval, 20);
  1.1195 +      g_value_set_boxed_take_ownership (&valval, eltval);
  1.1196 +      dbus_g_type_specialized_map_append (&ctx, &keyval, &valval);
  1.1197 +    }
  1.1198 +
  1.1199 +    {
  1.1200 +      GValue keyval = { 0, };
  1.1201 +      GValue valval = { 0, };
  1.1202 +      g_value_init (&keyval, G_TYPE_STRING);
  1.1203 +      g_value_set_string (&keyval, "baz"); 
  1.1204 +      g_value_init (&valval, G_TYPE_VALUE);
  1.1205 +      eltval = g_new0 (GValue, 1);
  1.1206 +      g_value_init (eltval, G_TYPE_STRING);
  1.1207 +      g_value_set_string (eltval, "bar");
  1.1208 +      g_value_set_boxed_take_ownership (&valval, eltval);
  1.1209 +      dbus_g_type_specialized_map_append (&ctx, &keyval, &valval);
  1.1210 +    }
  1.1211 +
  1.1212 +    hashdata.seen_foo = FALSE;
  1.1213 +    hashdata.seen_baz = FALSE;
  1.1214 +    dbus_g_type_map_value_iterate (&val,
  1.1215 +				   test_specialized_hash_2, 
  1.1216 +				   &hashdata);
  1.1217 +    
  1.1218 +    g_assert (hashdata.seen_foo);
  1.1219 +    g_assert (hashdata.seen_baz);
  1.1220 +
  1.1221 +    g_value_unset (&val);
  1.1222 +  }
  1.1223 +
  1.1224 +  type = dbus_g_type_get_collection ("GSList", G_TYPE_OBJECT);
  1.1225 +  g_assert (dbus_g_type_is_collection (type));
  1.1226 +  g_assert (dbus_g_type_get_collection_specialization (type) == G_TYPE_OBJECT);
  1.1227 +  {
  1.1228 +    GSList *instance, *tmp, *copy;
  1.1229 +    GValue val = {0, };
  1.1230 +    GValue copyval = {0, };
  1.1231 +    DBusGTypeSpecializedAppendContext ctx;
  1.1232 +    GObject *objects[3];
  1.1233 +    int i;
  1.1234 +
  1.1235 +    instance = dbus_g_type_specialized_construct (type);
  1.1236 +    g_assert (instance == NULL);
  1.1237 +
  1.1238 +    g_value_init (&val, type);
  1.1239 +    g_value_take_boxed (&val, instance);
  1.1240 +
  1.1241 +    dbus_g_type_specialized_init_append (&val, &ctx);
  1.1242 +
  1.1243 +    for (i = 0; i < 3; i++)
  1.1244 +      {
  1.1245 +        GValue eltval = { 0, };
  1.1246 +        GObject *obj = g_object_new (G_TYPE_OBJECT, NULL);
  1.1247 +
  1.1248 +        g_assert (obj != NULL);
  1.1249 +        objects[i] = obj;
  1.1250 +        g_object_add_weak_pointer (obj, (gpointer) (objects + i));
  1.1251 +
  1.1252 +        g_value_init (&eltval, G_TYPE_OBJECT);
  1.1253 +        g_value_take_object (&eltval, obj);
  1.1254 +        dbus_g_type_specialized_collection_append (&ctx, &eltval);
  1.1255 +      }
  1.1256 +
  1.1257 +    dbus_g_type_specialized_collection_end_append (&ctx);
  1.1258 +
  1.1259 +    instance = g_value_get_boxed (&val);
  1.1260 +    g_assert (g_slist_length (instance) == 3);
  1.1261 +
  1.1262 +    for (tmp = instance; tmp; tmp = tmp->next)
  1.1263 +      {
  1.1264 +        GObject *obj = tmp->data;
  1.1265 +        g_assert (G_IS_OBJECT (obj));
  1.1266 +        g_assert (obj->ref_count == 1);
  1.1267 +      }
  1.1268 +
  1.1269 +    g_value_init (&copyval, type);
  1.1270 +    g_value_copy (&val, &copyval);
  1.1271 +
  1.1272 +    copy = g_value_get_boxed (&copyval);
  1.1273 +    g_assert (g_slist_length (copy) == 3);
  1.1274 +
  1.1275 +    for (tmp = copy; tmp; tmp = tmp->next)
  1.1276 +      {
  1.1277 +        GObject *obj = tmp->data;
  1.1278 +        g_assert (G_IS_OBJECT (obj));
  1.1279 +        g_assert (obj->ref_count == 2);
  1.1280 +      }
  1.1281 +
  1.1282 +    g_value_unset (&copyval);
  1.1283 +
  1.1284 +    for (i = 0; i < 3; i++)
  1.1285 +      {
  1.1286 +        g_assert (objects[i] != NULL);
  1.1287 +      }
  1.1288 +
  1.1289 +    for (tmp = instance; tmp; tmp = tmp->next)
  1.1290 +      {
  1.1291 +        GObject *obj = tmp->data;
  1.1292 +        g_assert (G_IS_OBJECT (obj));
  1.1293 +        g_assert (obj->ref_count == 1);
  1.1294 +      }
  1.1295 +
  1.1296 +    g_value_unset (&val);
  1.1297 +
  1.1298 +    for (i = 0; i < 3; i++)
  1.1299 +      {
  1.1300 +        g_assert (objects[i] == NULL);
  1.1301 +      }
  1.1302 +  }
  1.1303 +
  1.1304 +  type = dbus_g_type_get_collection ("GPtrArray", G_TYPE_STRING);
  1.1305 +  g_assert (dbus_g_type_is_collection (type));
  1.1306 +  g_assert (dbus_g_type_get_collection_specialization (type) == G_TYPE_STRING);
  1.1307 +  {
  1.1308 +    GPtrArray *instance;
  1.1309 +    DBusGTypeSpecializedAppendContext ctx;
  1.1310 +    GValue val = {0, };
  1.1311 +    GValue eltval = {0, };
  1.1312 +
  1.1313 +    instance = dbus_g_type_specialized_construct (type);
  1.1314 +
  1.1315 +    g_assert (instance->len == 0);
  1.1316 +
  1.1317 +    g_value_init (&val, type);
  1.1318 +    g_value_set_boxed_take_ownership (&val, instance);
  1.1319 +
  1.1320 +    dbus_g_type_specialized_init_append (&val, &ctx);
  1.1321 +
  1.1322 +    g_value_init (&eltval, G_TYPE_STRING);
  1.1323 +    g_value_set_static_string (&eltval, "foo");
  1.1324 +    dbus_g_type_specialized_collection_append (&ctx, &eltval);
  1.1325 +
  1.1326 +    g_value_reset (&eltval);
  1.1327 +    g_value_set_static_string (&eltval, "bar");
  1.1328 +    dbus_g_type_specialized_collection_append (&ctx, &eltval);
  1.1329 +
  1.1330 +    g_value_reset (&eltval);
  1.1331 +    g_value_set_static_string (&eltval, "baz");
  1.1332 +    dbus_g_type_specialized_collection_append (&ctx, &eltval);
  1.1333 +
  1.1334 +    dbus_g_type_specialized_collection_end_append (&ctx);
  1.1335 +
  1.1336 +    g_assert (instance->len == 3);
  1.1337 +
  1.1338 +    g_assert (!strcmp ("foo", g_ptr_array_index (instance, 0)));
  1.1339 +    g_assert (!strcmp ("bar", g_ptr_array_index (instance, 1)));
  1.1340 +    g_assert (!strcmp ("baz", g_ptr_array_index (instance, 2)));
  1.1341 +
  1.1342 +    g_value_unset (&val);
  1.1343 +  }
  1.1344 +
  1.1345 +  type = dbus_g_type_get_struct ("GValueArray", G_TYPE_STRING, G_TYPE_UINT, DBUS_TYPE_G_OBJECT_PATH, G_TYPE_INVALID);
  1.1346 +  g_assert (dbus_g_type_is_struct (type));
  1.1347 +  g_assert (dbus_g_type_get_struct_size (type) == 3);
  1.1348 +  g_assert (dbus_g_type_get_struct_member_type (type, 0) == G_TYPE_STRING);
  1.1349 +  g_assert (dbus_g_type_get_struct_member_type (type, 1) == G_TYPE_UINT);
  1.1350 +  g_assert (dbus_g_type_get_struct_member_type (type, 2) == DBUS_TYPE_G_OBJECT_PATH);
  1.1351 +  {
  1.1352 +    GValueArray *instance;
  1.1353 +    GValue val = {0, };
  1.1354 +    GValue memval = {0, };
  1.1355 +
  1.1356 +    instance = dbus_g_type_specialized_construct (type);
  1.1357 +
  1.1358 +    g_assert (instance->n_values == 3);
  1.1359 +
  1.1360 +    g_value_init (&val, type);
  1.1361 +    g_value_set_boxed_take_ownership (&val, instance);
  1.1362 +
  1.1363 +    g_value_init (&memval, G_TYPE_STRING);
  1.1364 +    g_value_set_static_string (&memval, "foo");
  1.1365 +    dbus_g_type_struct_set_member (&val, 0, &memval);
  1.1366 +    g_value_unset (&memval);
  1.1367 +
  1.1368 +    g_value_init (&memval, G_TYPE_UINT);
  1.1369 +    g_value_set_uint (&memval, 42);
  1.1370 +    dbus_g_type_struct_set_member (&val, 1, &memval);
  1.1371 +    g_value_unset (&memval);
  1.1372 +
  1.1373 +    g_value_init (&memval, DBUS_TYPE_G_OBJECT_PATH);
  1.1374 +    g_value_set_static_boxed (&memval, "/bar/moo/foo/baz");
  1.1375 +    dbus_g_type_struct_set_member (&val, 2, &memval);
  1.1376 +    g_value_unset (&memval);
  1.1377 +
  1.1378 +    g_assert (instance->n_values == 3);
  1.1379 +
  1.1380 +    g_value_init (&memval, G_TYPE_STRING);
  1.1381 +    dbus_g_type_struct_get_member (&val, 0, &memval);
  1.1382 +    g_assert (0 == strcmp (g_value_get_string (&memval), "foo"));
  1.1383 +    g_value_unset (&memval);
  1.1384 +
  1.1385 +    g_value_init (&memval, G_TYPE_UINT);
  1.1386 +    dbus_g_type_struct_get_member (&val, 1, &memval);
  1.1387 +    g_assert (g_value_get_uint (&memval) == 42);
  1.1388 +    g_value_unset (&memval);
  1.1389 +
  1.1390 +    g_value_init (&memval, DBUS_TYPE_G_OBJECT_PATH);
  1.1391 +    dbus_g_type_struct_get_member (&val, 2, &memval);
  1.1392 +    g_assert (0 == strcmp ((gchar*) g_value_get_boxed (&memval),
  1.1393 +                           "/bar/moo/foo/baz"));
  1.1394 +    g_value_unset (&memval);
  1.1395 +
  1.1396 +    g_value_unset (&val);
  1.1397 +  }
  1.1398 +
  1.1399 +  type = dbus_g_type_get_struct ("GValueArray", G_TYPE_STRING, G_TYPE_UINT, DBUS_TYPE_G_OBJECT_PATH, G_TYPE_INVALID);
  1.1400 +  g_assert (dbus_g_type_is_struct (type));
  1.1401 +  g_assert (dbus_g_type_get_struct_size (type) == 3);
  1.1402 +  g_assert (dbus_g_type_get_struct_member_type (type, 0) == G_TYPE_STRING);
  1.1403 +  g_assert (dbus_g_type_get_struct_member_type (type, 1) == G_TYPE_UINT);
  1.1404 +  g_assert (dbus_g_type_get_struct_member_type (type, 2) == DBUS_TYPE_G_OBJECT_PATH);
  1.1405 +  {
  1.1406 +    GValueArray *instance;
  1.1407 +    GValue val = {0, };
  1.1408 +
  1.1409 +    instance = dbus_g_type_specialized_construct (type);
  1.1410 +
  1.1411 +    g_assert (instance->n_values == 3);
  1.1412 +
  1.1413 +    g_value_init (&val, type);
  1.1414 +    g_value_set_boxed_take_ownership (&val, instance);
  1.1415 +
  1.1416 +    dbus_g_type_struct_set (&val,
  1.1417 +                            0,"foo",
  1.1418 +                            1, 42,
  1.1419 +                            2, "/bar/moo/foo/baz",
  1.1420 +                            G_MAXUINT);
  1.1421 +
  1.1422 +    g_assert (instance->n_values == 3);
  1.1423 +
  1.1424 +    {
  1.1425 +      gchar *string;
  1.1426 +      guint intval;
  1.1427 +      gchar *path;
  1.1428 +
  1.1429 +      dbus_g_type_struct_get (&val,
  1.1430 +                              0, &string,
  1.1431 +                              1, &intval,
  1.1432 +                              2, &path,
  1.1433 +                              G_MAXUINT);
  1.1434 +
  1.1435 +      g_assert (0 == strcmp (string, "foo"));
  1.1436 +      g_assert (intval == 42);
  1.1437 +      g_assert (0 == strcmp (path, "/bar/moo/foo/baz"));
  1.1438 +    }
  1.1439 +
  1.1440 +    g_value_unset (&val);
  1.1441 +  }
  1.1442 +
  1.1443 +
  1.1444 +  return TRUE;
  1.1445 +}
  1.1446 +
  1.1447 +
  1.1448 +
  1.1449 +#endif /* DBUS_BUILD_TESTS */