00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include <config.h>
00025 #include "dbus/dbus-glib.h"
00026 #include "dbus-gvalue-utils.h"
00027 #include "dbus-gtest.h"
00028 #include <glib.h>
00029 #include <string.h>
00030 #include <gobject/gvaluecollector.h>
00031
00032
00033 static guint
00034 fixed_type_get_size (GType type)
00035 {
00036 switch (type)
00037 {
00038 case G_TYPE_CHAR:
00039 case G_TYPE_UCHAR:
00040 return sizeof (gchar);
00041 case G_TYPE_BOOLEAN:
00042 return sizeof (gboolean);
00043 case G_TYPE_LONG:
00044 case G_TYPE_ULONG:
00045 return sizeof (glong);
00046 case G_TYPE_INT:
00047 case G_TYPE_UINT:
00048 return sizeof (gint);
00049 case G_TYPE_INT64:
00050 case G_TYPE_UINT64:
00051 return sizeof (gint64);
00052 case G_TYPE_FLOAT:
00053 return sizeof (gfloat);
00054 case G_TYPE_DOUBLE:
00055 return sizeof (gdouble);
00056 default:
00057 return 0;
00058 }
00059 }
00060
00061 gboolean
00062 _dbus_g_type_is_fixed (GType type)
00063 {
00064 return fixed_type_get_size (type) > 0;
00065 }
00066
00067 guint
00068 _dbus_g_type_fixed_get_size (GType type)
00069 {
00070 g_assert (_dbus_g_type_is_fixed (type));
00071 return fixed_type_get_size (type);
00072 }
00073
00074 gboolean
00075 _dbus_gvalue_store (GValue *value,
00076 gpointer storage)
00077 {
00078
00079
00080
00081 switch (g_type_fundamental (G_VALUE_TYPE (value)))
00082 {
00083 case G_TYPE_CHAR:
00084 *((gchar *) storage) = g_value_get_char (value);
00085 return TRUE;
00086 case G_TYPE_UCHAR:
00087 *((guchar *) storage) = g_value_get_uchar (value);
00088 return TRUE;
00089 case G_TYPE_BOOLEAN:
00090 *((gboolean *) storage) = g_value_get_boolean (value);
00091 return TRUE;
00092 case G_TYPE_LONG:
00093 *((glong *) storage) = g_value_get_long (value);
00094 return TRUE;
00095 case G_TYPE_ULONG:
00096 *((gulong *) storage) = g_value_get_ulong (value);
00097 return TRUE;
00098 case G_TYPE_INT:
00099 *((gint *) storage) = g_value_get_int (value);
00100 return TRUE;
00101 case G_TYPE_UINT:
00102 *((guint *) storage) = g_value_get_uint (value);
00103 return TRUE;
00104 case G_TYPE_INT64:
00105 *((gint64 *) storage) = g_value_get_int64 (value);
00106 return TRUE;
00107 case G_TYPE_UINT64:
00108 *((guint64 *) storage) = g_value_get_uint64 (value);
00109 return TRUE;
00110 case G_TYPE_DOUBLE:
00111 *((gdouble *) storage) = g_value_get_double (value);
00112 return TRUE;
00113 case G_TYPE_STRING:
00114 *((gchar **) storage) = (char*) g_value_get_string (value);
00115 return TRUE;
00116 case G_TYPE_OBJECT:
00117 *((gpointer *) storage) = g_value_get_object (value);
00118 return TRUE;
00119 case G_TYPE_BOXED:
00120 *((gpointer *) storage) = g_value_get_boxed (value);
00121 return TRUE;
00122 default:
00123 return FALSE;
00124 }
00125 }
00126
00127 gboolean
00128 _dbus_gvalue_set_from_pointer (GValue *value,
00129 gconstpointer storage)
00130 {
00131
00132 switch (g_type_fundamental (G_VALUE_TYPE (value)))
00133 {
00134 case G_TYPE_CHAR:
00135 g_value_set_char (value, *((gchar *) storage));
00136 return TRUE;
00137 case G_TYPE_UCHAR:
00138 g_value_set_uchar (value, *((guchar *) storage));
00139 return TRUE;
00140 case G_TYPE_BOOLEAN:
00141 g_value_set_boolean (value, *((gboolean *) storage));
00142 return TRUE;
00143 case G_TYPE_LONG:
00144 g_value_set_long (value, *((glong *) storage));
00145 return TRUE;
00146 case G_TYPE_ULONG:
00147 g_value_set_ulong (value, *((gulong *) storage));
00148 return TRUE;
00149 case G_TYPE_INT:
00150 g_value_set_int (value, *((gint *) storage));
00151 return TRUE;
00152 case G_TYPE_UINT:
00153 g_value_set_uint (value, *((guint *) storage));
00154 return TRUE;
00155 case G_TYPE_INT64:
00156 g_value_set_int64 (value, *((gint64 *) storage));
00157 return TRUE;
00158 case G_TYPE_UINT64:
00159 g_value_set_uint64 (value, *((guint64 *) storage));
00160 return TRUE;
00161 case G_TYPE_DOUBLE:
00162 g_value_set_double (value, *((gdouble *) storage));
00163 return TRUE;
00164 case G_TYPE_STRING:
00165 g_value_set_string (value, *((gchar **) storage));
00166 return TRUE;
00167 case G_TYPE_OBJECT:
00168 g_value_set_object (value, *((gpointer *) storage));
00169 return TRUE;
00170 case G_TYPE_BOXED:
00171 g_value_set_boxed (value, *((gpointer *) storage));
00172 return TRUE;
00173 default:
00174 return FALSE;
00175 }
00176 }
00177
00178 gboolean
00179 _dbus_gvalue_take (GValue *value,
00180 GTypeCValue *cvalue)
00181 {
00182 GType g_type;
00183 GTypeValueTable *value_table;
00184 char *error_msg;
00185
00186 g_type = G_VALUE_TYPE (value);
00187 value_table = g_type_value_table_peek (g_type);
00188
00189 error_msg = value_table->collect_value (value, 1, cvalue, G_VALUE_NOCOPY_CONTENTS);
00190 if (error_msg)
00191 {
00192 g_warning ("%s: %s", G_STRLOC, error_msg);
00193 g_free (error_msg);
00194 return FALSE;
00195 }
00196
00197
00198
00199 value->data[1].v_uint &= ~(G_VALUE_NOCOPY_CONTENTS);
00200 return TRUE;
00201 }
00202
00203 gboolean
00204 _dbus_gtype_can_signal_error (GType gtype)
00205 {
00206 switch (gtype)
00207 {
00208 case G_TYPE_BOOLEAN:
00209 case G_TYPE_INT:
00210 case G_TYPE_UINT:
00211 case G_TYPE_STRING:
00212 case G_TYPE_BOXED:
00213 case G_TYPE_OBJECT:
00214 return TRUE;
00215 default:
00216 return FALSE;
00217 }
00218 }
00219
00220 gboolean
00221 _dbus_gvalue_signals_error (const GValue *value)
00222 {
00223
00224
00225
00226
00227
00228
00229 switch (G_TYPE_FUNDAMENTAL (G_VALUE_TYPE (value)))
00230 {
00231 case G_TYPE_BOOLEAN:
00232 return (g_value_get_boolean (value) == FALSE);
00233 break;
00234 case G_TYPE_INT:
00235 return (g_value_get_int (value) < 0);
00236 break;
00237 case G_TYPE_UINT:
00238 return (g_value_get_uint (value) == 0);
00239 break;
00240 case G_TYPE_STRING:
00241 return (g_value_get_string (value) == NULL);
00242 break;
00243 case G_TYPE_BOXED:
00244 return (g_value_get_boxed (value) == NULL);
00245 break;
00246 case G_TYPE_OBJECT:
00247 return (g_value_get_object (value) == NULL);
00248 break;
00249 default:
00250 g_assert_not_reached ();
00251 }
00252 }
00253
00254
00255 static gboolean
00256 hash_func_from_gtype (GType gtype, GHashFunc *func)
00257 {
00258 switch (gtype)
00259 {
00260 case G_TYPE_CHAR:
00261 case G_TYPE_UCHAR:
00262 case G_TYPE_BOOLEAN:
00263 case G_TYPE_INT:
00264 case G_TYPE_UINT:
00265 *func = NULL;
00266 return TRUE;
00267 case G_TYPE_STRING:
00268 *func = g_str_hash;
00269 return TRUE;
00270 default:
00271 return FALSE;
00272 }
00273 }
00274
00275 static void
00276 unset_and_free_g_value (gpointer val)
00277 {
00278 GValue *value = val;
00279
00280 g_value_unset (value);
00281 g_free (value);
00282 }
00283
00284 static gboolean
00285 hash_free_from_gtype (GType gtype, GDestroyNotify *func)
00286 {
00287 switch (gtype)
00288 {
00289 case G_TYPE_CHAR:
00290 case G_TYPE_UCHAR:
00291 case G_TYPE_BOOLEAN:
00292 case G_TYPE_INT:
00293 case G_TYPE_UINT:
00294 *func = NULL;
00295 return TRUE;
00296 case G_TYPE_DOUBLE:
00297 case G_TYPE_STRING:
00298 *func = g_free;
00299 return TRUE;
00300 default:
00301 if (gtype == G_TYPE_VALUE)
00302 {
00303 *func = unset_and_free_g_value;
00304 return TRUE;
00305 }
00306 else if (gtype == G_TYPE_VALUE_ARRAY)
00307 {
00308 *func = (GDestroyNotify) g_value_array_free;
00309 return TRUE;
00310 }
00311 else if (dbus_g_type_is_collection (gtype))
00312 {
00313 const DBusGTypeSpecializedCollectionVtable* vtable;
00314 vtable = dbus_g_type_collection_peek_vtable (gtype);
00315 if (vtable->base_vtable.simple_free_func)
00316 {
00317 *func = vtable->base_vtable.simple_free_func;
00318 return TRUE;
00319 }
00320 }
00321 else if (dbus_g_type_is_map (gtype))
00322 {
00323 const DBusGTypeSpecializedMapVtable* vtable;
00324 vtable = dbus_g_type_map_peek_vtable (gtype);
00325 if (vtable->base_vtable.simple_free_func)
00326 {
00327 *func = vtable->base_vtable.simple_free_func;
00328 return TRUE;
00329 }
00330 }
00331 else if (dbus_g_type_is_struct (gtype))
00332 {
00333 const DBusGTypeSpecializedStructVtable *vtable;
00334 vtable = dbus_g_type_struct_peek_vtable (gtype);
00335 if (vtable->base_vtable.simple_free_func)
00336 {
00337 *func = vtable->base_vtable.simple_free_func;
00338 return TRUE;
00339 }
00340 }
00341 return FALSE;
00342 }
00343 }
00344
00345 gboolean
00346 _dbus_gtype_is_valid_hash_key (GType type)
00347 {
00348 GHashFunc func;
00349 return hash_func_from_gtype (type, &func);
00350 }
00351
00352 gboolean
00353 _dbus_gtype_is_valid_hash_value (GType type)
00354 {
00355 GDestroyNotify func;
00356 return hash_free_from_gtype (type, &func);
00357 }
00358
00359 GHashFunc
00360 _dbus_g_hash_func_from_gtype (GType gtype)
00361 {
00362 GHashFunc func;
00363 gboolean ret;
00364 ret = hash_func_from_gtype (gtype, &func);
00365 g_assert (ret != FALSE);
00366 return func;
00367 }
00368
00369 GEqualFunc
00370 _dbus_g_hash_equal_from_gtype (GType gtype)
00371 {
00372 g_assert (_dbus_gtype_is_valid_hash_key (gtype));
00373
00374 switch (gtype)
00375 {
00376 case G_TYPE_CHAR:
00377 case G_TYPE_UCHAR:
00378 case G_TYPE_BOOLEAN:
00379 case G_TYPE_INT:
00380 case G_TYPE_UINT:
00381 return NULL;
00382 case G_TYPE_STRING:
00383 return g_str_equal;
00384 default:
00385 g_assert_not_reached ();
00386 return NULL;
00387 }
00388 }
00389
00390 GDestroyNotify
00391 _dbus_g_hash_free_from_gtype (GType gtype)
00392 {
00393 GDestroyNotify func;
00394 gboolean ret;
00395 ret = hash_free_from_gtype (gtype, &func);
00396 g_assert (ret != FALSE);
00397 return func;
00398 }
00399
00400 static void gvalue_take_ptrarray_value (GValue *value, gpointer instance);
00401
00402 static void
00403 gvalue_take_hash_value (GValue *value, gpointer instance)
00404 {
00405 switch (g_type_fundamental (G_VALUE_TYPE (value)))
00406 {
00407 case G_TYPE_CHAR:
00408 g_value_set_char (value, (gchar) GPOINTER_TO_INT (instance));
00409 break;
00410 case G_TYPE_UCHAR:
00411 g_value_set_uchar (value, (guchar) GPOINTER_TO_UINT (instance));
00412 break;
00413 case G_TYPE_BOOLEAN:
00414 g_value_set_boolean (value, (gboolean) GPOINTER_TO_UINT (instance));
00415 break;
00416 case G_TYPE_INT:
00417 g_value_set_int (value, GPOINTER_TO_INT (instance));
00418 break;
00419 case G_TYPE_UINT:
00420 g_value_set_uint (value, GPOINTER_TO_UINT (instance));
00421 break;
00422 case G_TYPE_DOUBLE:
00423 g_value_set_double (value, *(gdouble *) instance);
00424 break;
00425 default:
00426 gvalue_take_ptrarray_value (value, instance);
00427 break;
00428 }
00429 }
00430
00431 static gpointer ptrarray_value_from_gvalue (const GValue *value);
00432
00433 static gpointer
00434 hash_value_from_gvalue (GValue *value)
00435 {
00436 switch (g_type_fundamental (G_VALUE_TYPE (value)))
00437 {
00438 case G_TYPE_CHAR:
00439 return GINT_TO_POINTER ((int) g_value_get_char (value));
00440 break;
00441 case G_TYPE_UCHAR:
00442 return GUINT_TO_POINTER ((guint) g_value_get_uchar (value));
00443 break;
00444 case G_TYPE_BOOLEAN:
00445 return GUINT_TO_POINTER ((guint) g_value_get_boolean (value));
00446 break;
00447 case G_TYPE_INT:
00448 return GINT_TO_POINTER (g_value_get_int (value));
00449 break;
00450 case G_TYPE_UINT:
00451 return GUINT_TO_POINTER (g_value_get_uint (value));
00452 break;
00453 case G_TYPE_DOUBLE:
00454 {
00455 gdouble *p = (gdouble *) g_malloc0 (sizeof (gdouble));
00456 *p = g_value_get_double (value);
00457 return (gpointer) p;
00458 }
00459 break;
00460 default:
00461 return ptrarray_value_from_gvalue (value);
00462 break;
00463 }
00464 }
00465
00466 struct DBusGHashTableValueForeachData
00467 {
00468 DBusGTypeSpecializedMapIterator func;
00469 GType key_type;
00470 GType value_type;
00471 gpointer data;
00472 };
00473
00474 static void
00475 hashtable_foreach_with_values (gpointer key, gpointer value, gpointer user_data)
00476 {
00477 GValue key_val = {0, };
00478 GValue value_val = {0, };
00479 struct DBusGHashTableValueForeachData *data = user_data;
00480
00481 g_value_init (&key_val, data->key_type);
00482 g_value_init (&value_val, data->value_type);
00483 gvalue_take_hash_value (&key_val, key);
00484 gvalue_take_hash_value (&value_val, value);
00485
00486 data->func (&key_val, &value_val, data->data);
00487 }
00488
00489
00490 static void
00491 hashtable_iterator (GType hash_type,
00492 gpointer instance,
00493 DBusGTypeSpecializedMapIterator iterator,
00494 gpointer user_data)
00495 {
00496 struct DBusGHashTableValueForeachData data;
00497 GType key_gtype;
00498 GType value_gtype;
00499
00500 key_gtype = dbus_g_type_get_map_key_specialization (hash_type);
00501 value_gtype = dbus_g_type_get_map_value_specialization (hash_type);
00502
00503 data.func = iterator;
00504 data.key_type = key_gtype;
00505 data.value_type = value_gtype;
00506 data.data = user_data;
00507
00508 g_hash_table_foreach (instance, hashtable_foreach_with_values, &data);
00509 }
00510
00511 void
00512 _dbus_g_hash_table_insert_steal_values (GHashTable *table,
00513 GValue *key_val,
00514 GValue *value_val)
00515 {
00516 gpointer key, val;
00517
00518 key = hash_value_from_gvalue (key_val);
00519 val = hash_value_from_gvalue (value_val);
00520
00521 g_hash_table_insert (table, key, val);
00522 }
00523
00524 static void
00525 hashtable_append (DBusGTypeSpecializedAppendContext *ctx,
00526 GValue *key,
00527 GValue *val)
00528 {
00529 GHashTable *table;
00530
00531 table = g_value_get_boxed (ctx->val);
00532 _dbus_g_hash_table_insert_steal_values (table, key, val);
00533 }
00534
00535 static gpointer
00536 hashtable_constructor (GType type)
00537 {
00538 GHashTable *ret;
00539 GType key_gtype;
00540 GType value_gtype;
00541
00542 key_gtype = dbus_g_type_get_map_key_specialization (type);
00543 value_gtype = dbus_g_type_get_map_value_specialization (type);
00544
00545 ret = g_hash_table_new_full (_dbus_g_hash_func_from_gtype (key_gtype),
00546 _dbus_g_hash_equal_from_gtype (key_gtype),
00547 _dbus_g_hash_free_from_gtype (key_gtype),
00548 _dbus_g_hash_free_from_gtype (value_gtype));
00549 return ret;
00550 }
00551
00552 static void
00553 hashtable_insert_values (GHashTable *table,
00554 const GValue *key_val,
00555 const GValue *value_val)
00556 {
00557 GValue key_copy = {0, };
00558 GValue value_copy = {0, };
00559
00560 g_value_init (&key_copy, G_VALUE_TYPE (key_val));
00561 g_value_copy (key_val, &key_copy);
00562 g_value_init (&value_copy, G_VALUE_TYPE (value_val));
00563 g_value_copy (value_val, &value_copy);
00564
00565 _dbus_g_hash_table_insert_steal_values (table, &key_copy, &value_copy);
00566 }
00567
00568 static void
00569 hashtable_foreach_copy (const GValue *key, const GValue *val, gpointer data)
00570 {
00571 hashtable_insert_values ((GHashTable *) data, key, val);
00572 }
00573
00574 static gpointer
00575 hashtable_copy (GType type, gpointer src)
00576 {
00577 GHashTable *ghash;
00578 GHashTable *ret;
00579 GValue hashval = {0,};
00580
00581 ghash = src;
00582
00583 ret = hashtable_constructor (type);
00584
00585 g_value_init (&hashval, type);
00586 g_value_set_static_boxed (&hashval, ghash);
00587 dbus_g_type_map_value_iterate (&hashval, hashtable_foreach_copy, ret);
00588 return ret;
00589 }
00590
00591 static void
00592 hashtable_simple_free (gpointer val)
00593 {
00594 g_hash_table_destroy (val);
00595 }
00596
00597 static gpointer
00598 valuearray_constructor (GType type)
00599 {
00600 GValueArray *ret;
00601 guint size = dbus_g_type_get_struct_size (type);
00602 guint i;
00603 ret = g_value_array_new (size);
00604 for (i=0; i < size; i++)
00605 {
00606 GValue val = {0,};
00607 g_value_init (&val, dbus_g_type_get_struct_member_type (type, i));
00608 g_value_array_append(ret, &val);
00609 }
00610 return (gpointer)ret;
00611 }
00612
00613 static gpointer
00614 valuearray_copy (GType type, gpointer src)
00615 {
00616 return g_value_array_copy ((GValueArray*) src);
00617 }
00618
00619 static void
00620 valuearray_simple_free (gpointer val)
00621 {
00622 g_value_array_free (val);
00623 }
00624
00625 static gboolean
00626 valuearray_get_member (GType type, gpointer instance,
00627 guint member, GValue *ret)
00628 {
00629 GValueArray *va = (GValueArray*) instance;
00630 const GValue *val;
00631 if (member < dbus_g_type_get_struct_size (type))
00632 {
00633 val = g_value_array_get_nth (va, member);
00634 g_value_copy (val, ret);
00635 return TRUE;
00636 }
00637 else
00638 return FALSE;
00639 }
00640
00641 static gboolean
00642 valuearray_set_member (GType type, gpointer instance,
00643 guint member, const GValue *member_type)
00644 {
00645 GValueArray *va = (GValueArray*) instance;
00646 GValue *vp;
00647 if (member < dbus_g_type_get_struct_size (type))
00648 {
00649 vp = g_value_array_get_nth (va, member);
00650 g_value_copy (member_type, vp);
00651 return TRUE;
00652 }
00653 else
00654 return FALSE;
00655 }
00656
00657
00658 static gpointer
00659 array_constructor (GType type)
00660 {
00661 GArray *array;
00662 guint elt_size;
00663 GType elt_type;
00664 gboolean zero_terminated;
00665 gboolean clear;
00666
00667 elt_type = dbus_g_type_get_collection_specialization (type);
00668 g_assert (elt_type != G_TYPE_INVALID);
00669
00670 elt_size = _dbus_g_type_fixed_get_size (elt_type);
00671
00672
00673 zero_terminated = TRUE;
00674 clear = TRUE;
00675
00676 array = g_array_new (zero_terminated, clear, elt_size);
00677 return array;
00678 }
00679
00680 static gpointer
00681 array_copy (GType type, gpointer src)
00682 {
00683 GArray *garray;
00684 GArray *new;
00685
00686 garray = src;
00687
00688 new = array_constructor (type);
00689 g_array_append_vals (new, garray->data, garray->len);
00690
00691 return new;
00692 }
00693
00694 static void
00695 array_simple_free (gpointer val)
00696 {
00697 GArray *array;
00698 array = val;
00699 g_array_free (array, TRUE);
00700 }
00701
00702 static gboolean
00703 array_fixed_accessor (GType type, gpointer instance, gpointer *values, guint *len)
00704 {
00705 GType elt_type;
00706 GArray *array = instance;
00707
00708 elt_type = dbus_g_type_get_collection_specialization (type);
00709 if (!_dbus_g_type_is_fixed (elt_type))
00710 return FALSE;
00711
00712 *values = array->data;
00713 *len = array->len;
00714 return TRUE;
00715 }
00716
00717 static gpointer
00718 ptrarray_constructor (GType type)
00719 {
00720
00721 return g_ptr_array_new ();
00722 }
00723
00724 static void
00725 gvalue_take_ptrarray_value (GValue *value, gpointer instance)
00726 {
00727 switch (g_type_fundamental (G_VALUE_TYPE (value)))
00728 {
00729 case G_TYPE_STRING:
00730 g_value_take_string (value, instance);
00731 break;
00732 case G_TYPE_BOXED:
00733 g_value_take_boxed (value, instance);
00734 break;
00735 case G_TYPE_OBJECT:
00736 g_value_take_object (value, instance);
00737 break;
00738 default:
00739 g_assert_not_reached ();
00740 break;
00741 }
00742 }
00743
00744 static gpointer
00745 ptrarray_value_from_gvalue (const GValue *value)
00746 {
00747 GValue tmp = {0, };
00748
00749
00750
00751
00752
00753
00754 if (value->data[1].v_uint & G_VALUE_NOCOPY_CONTENTS)
00755 {
00756 g_value_init (&tmp, G_VALUE_TYPE (value));
00757 g_value_copy (value, &tmp);
00758 value = &tmp;
00759 }
00760
00761 switch (g_type_fundamental (G_VALUE_TYPE (value)))
00762 {
00763 case G_TYPE_STRING:
00764 return (gpointer) g_value_get_string (value);
00765 break;
00766 case G_TYPE_BOXED:
00767 return g_value_get_boxed (value);
00768 break;
00769 case G_TYPE_OBJECT:
00770 return g_value_get_object (value);
00771 break;
00772 default:
00773 g_assert_not_reached ();
00774 return NULL;
00775 }
00776 }
00777
00778 static void
00779 ptrarray_iterator (GType ptrarray_type,
00780 gpointer instance,
00781 DBusGTypeSpecializedCollectionIterator iterator,
00782 gpointer user_data)
00783 {
00784 GPtrArray *ptrarray;
00785 GType elt_gtype;
00786 guint i;
00787
00788 ptrarray = instance;
00789
00790 elt_gtype = dbus_g_type_get_collection_specialization (ptrarray_type);
00791
00792 for (i = 0; i < ptrarray->len; i++)
00793 {
00794 GValue val = {0, };
00795 g_value_init (&val, elt_gtype);
00796 gvalue_take_ptrarray_value (&val, g_ptr_array_index (ptrarray, i));
00797 iterator (&val, user_data);
00798 }
00799 }
00800
00801 static void
00802 ptrarray_copy_elt (const GValue *val, gpointer user_data)
00803 {
00804 GPtrArray *dest = user_data;
00805 GValue val_copy = {0, };
00806
00807 g_value_init (&val_copy, G_VALUE_TYPE (val));
00808 g_value_copy (val, &val_copy);
00809
00810 g_ptr_array_add (dest, ptrarray_value_from_gvalue (&val_copy));
00811 }
00812
00813 static gpointer
00814 ptrarray_copy (GType type, gpointer src)
00815 {
00816 GPtrArray *new;
00817 GValue array_val = {0, };
00818
00819 g_value_init (&array_val, type);
00820 g_value_set_static_boxed (&array_val, src);
00821
00822 new = ptrarray_constructor (type);
00823 dbus_g_type_collection_value_iterate (&array_val, ptrarray_copy_elt, new);
00824
00825 return new;
00826 }
00827
00828 static void
00829 ptrarray_append (DBusGTypeSpecializedAppendContext *ctx, GValue *value)
00830 {
00831 GPtrArray *array;
00832
00833 array = g_value_get_boxed (ctx->val);
00834
00835 g_ptr_array_add (array, ptrarray_value_from_gvalue (value));
00836 }
00837
00838 static void
00839 ptrarray_free (GType type, gpointer val)
00840 {
00841 GPtrArray *array;
00842 GValue elt_val = {0, };
00843 GType elt_gtype;
00844 unsigned int i;
00845
00846 array = val;
00847
00848 elt_gtype = dbus_g_type_get_collection_specialization (type);
00849
00850 for (i = 0; i < array->len; i++)
00851 {
00852 g_value_init (&elt_val, elt_gtype);
00853 gvalue_take_ptrarray_value (&elt_val, g_ptr_array_index (array, i));
00854 g_value_unset (&elt_val);
00855 }
00856
00857 g_ptr_array_free (array, TRUE);
00858 }
00859
00860 static gpointer
00861 slist_constructor (GType type)
00862 {
00863 return NULL;
00864 }
00865
00866 static void
00867 slist_iterator (GType list_type,
00868 gpointer instance,
00869 DBusGTypeSpecializedCollectionIterator iterator,
00870 gpointer user_data)
00871 {
00872 GSList *slist;
00873 GType elt_gtype;
00874
00875 slist = instance;
00876
00877 elt_gtype = dbus_g_type_get_collection_specialization (list_type);
00878
00879 for (slist = instance; slist != NULL; slist = slist->next)
00880 {
00881 GValue val = {0, };
00882 g_value_init (&val, elt_gtype);
00883 gvalue_take_ptrarray_value (&val, slist->data);
00884 iterator (&val, user_data);
00885 }
00886 }
00887
00888 static void
00889 slist_copy_elt (const GValue *val, gpointer user_data)
00890 {
00891 GSList **dest = user_data;
00892 GValue val_copy = {0, };
00893
00894 g_value_init (&val_copy, G_VALUE_TYPE (val));
00895 g_value_copy (val, &val_copy);
00896
00897 *dest = g_slist_append (*dest, ptrarray_value_from_gvalue (&val_copy));
00898 }
00899
00900 static gpointer
00901 slist_copy (GType type, gpointer src)
00902 {
00903 GSList *new;
00904 GValue slist_val = {0, };
00905
00906 g_value_init (&slist_val, type);
00907 g_value_set_static_boxed (&slist_val, src);
00908
00909 new = slist_constructor (type);
00910 dbus_g_type_collection_value_iterate (&slist_val, slist_copy_elt, &new);
00911
00912 return new;
00913 }
00914
00915 static void
00916 slist_append (DBusGTypeSpecializedAppendContext *ctx, GValue *value)
00917 {
00918 GSList *list;
00919
00920 list = g_value_get_boxed (ctx->val);
00921 list = g_slist_prepend (list, ptrarray_value_from_gvalue (value));
00922 g_value_set_static_boxed (ctx->val, list);
00923 }
00924
00925 static void
00926 slist_end_append (DBusGTypeSpecializedAppendContext *ctx)
00927 {
00928 GSList *list;
00929
00930
00931
00932 list = g_value_get_boxed (ctx->val);
00933 list = g_slist_reverse (list);
00934
00935 g_value_take_boxed (ctx->val, list);
00936 }
00937
00938 static void
00939 slist_free (GType type, gpointer val)
00940 {
00941 GSList *list;
00942 GType elt_gtype;
00943 list = val;
00944
00945 elt_gtype = dbus_g_type_get_collection_specialization (type);
00946
00947 while (list != NULL)
00948 {
00949 GValue elt_val = {0, };
00950 g_value_init (&elt_val, elt_gtype);
00951 gvalue_take_ptrarray_value (&elt_val, list->data);
00952 g_value_unset (&elt_val);
00953 list = g_slist_next(list);
00954 }
00955 list=val;
00956 g_slist_free (list);
00957 }
00958
00959 void
00960 _dbus_g_type_specialized_builtins_init (void)
00961 {
00962
00963
00964
00965
00966 static const DBusGTypeSpecializedCollectionVtable array_vtable = {
00967 {
00968 array_constructor,
00969 NULL,
00970 array_copy,
00971 array_simple_free,
00972 NULL,
00973 NULL,
00974 },
00975 array_fixed_accessor,
00976 NULL,
00977 NULL,
00978 NULL
00979 };
00980
00981
00982 static const DBusGTypeSpecializedCollectionVtable ptrarray_vtable = {
00983 {
00984 ptrarray_constructor,
00985 ptrarray_free,
00986 ptrarray_copy,
00987 NULL,
00988 NULL,
00989 NULL,
00990 },
00991 NULL,
00992 ptrarray_iterator,
00993 ptrarray_append,
00994 NULL,
00995 };
00996
00997
00998 static const DBusGTypeSpecializedCollectionVtable slist_vtable = {
00999 {
01000 slist_constructor,
01001 slist_free,
01002 slist_copy,
01003 NULL,
01004 NULL,
01005 NULL,
01006 },
01007 NULL,
01008 slist_iterator,
01009 slist_append,
01010 slist_end_append,
01011 };
01012
01013 static const DBusGTypeSpecializedMapVtable hashtable_vtable = {
01014 {
01015 hashtable_constructor,
01016 NULL,
01017 hashtable_copy,
01018 hashtable_simple_free,
01019 NULL,
01020 NULL
01021 },
01022 hashtable_iterator,
01023 hashtable_append
01024 };
01025
01026 static const DBusGTypeSpecializedStructVtable valuearray_vtable = {
01027 {
01028 valuearray_constructor,
01029 NULL,
01030 valuearray_copy,
01031 valuearray_simple_free,
01032 NULL,
01033 NULL
01034 },
01035 valuearray_get_member,
01036 valuearray_set_member
01037 };
01038
01039 dbus_g_type_register_collection ("GSList", &slist_vtable, 0);
01040 dbus_g_type_register_collection ("GArray", &array_vtable, 0);
01041 dbus_g_type_register_collection ("GPtrArray", &ptrarray_vtable, 0);
01042 dbus_g_type_register_map ("GHashTable", &hashtable_vtable, 0);
01043 dbus_g_type_register_struct ("GValueArray", &valuearray_vtable, 0);
01044 }
01045
01046 #ifdef DBUS_BUILD_TESTS
01047
01048 typedef struct
01049 {
01050 gboolean seen_foo;
01051 gboolean seen_baz;
01052 } TestSpecializedHashData;
01053
01054 static void
01055 test_specialized_hash (const GValue *key, const GValue *val, gpointer user_data)
01056 {
01057 TestSpecializedHashData *data = user_data;
01058
01059 g_assert (G_VALUE_HOLDS_STRING (key));
01060 g_assert (G_VALUE_HOLDS_STRING (val));
01061
01062 if (!strcmp (g_value_get_string (key), "foo"))
01063 {
01064 data->seen_foo = TRUE;
01065 g_assert (!strcmp (g_value_get_string (val), "bar"));
01066 }
01067 else if (!strcmp (g_value_get_string (key), "baz"))
01068 {
01069 data->seen_baz = TRUE;
01070 g_assert (!strcmp (g_value_get_string (val), "moo"));
01071 }
01072 else
01073 {
01074 g_assert_not_reached ();
01075 }
01076 }
01077
01078 static void
01079 test_specialized_hash_2 (const GValue *key, const GValue *val, gpointer user_data)
01080 {
01081 TestSpecializedHashData *data = user_data;
01082 const GValue *realval;
01083
01084 g_assert (G_VALUE_HOLDS_STRING (key));
01085 g_assert (G_VALUE_TYPE (val) == G_TYPE_VALUE);
01086
01087 realval = g_value_get_boxed (val);
01088
01089 if (!strcmp (g_value_get_string (key), "foo"))
01090 {
01091 data->seen_foo = TRUE;
01092 g_assert (G_VALUE_HOLDS_UINT (realval));
01093 g_assert (g_value_get_uint (realval) == 20);
01094 }
01095 else if (!strcmp (g_value_get_string (key), "baz"))
01096 {
01097 data->seen_baz = TRUE;
01098 g_assert (G_VALUE_HOLDS_STRING (realval));
01099 g_assert (!strcmp ("bar", g_value_get_string (realval)));
01100 }
01101 else
01102 {
01103 g_assert_not_reached ();
01104 }
01105 }
01106
01107 gboolean
01108 _dbus_gvalue_utils_test (const char *datadir)
01109 {
01110 GType type;
01111
01112 dbus_g_type_specialized_init ();
01113 _dbus_g_type_specialized_builtins_init ();
01114
01115 type = dbus_g_type_get_collection ("GArray", G_TYPE_UINT);
01116 g_assert (dbus_g_type_is_collection (type));
01117 g_assert (dbus_g_type_get_collection_specialization (type) == G_TYPE_UINT);
01118 {
01119 GArray *instance;
01120
01121 instance = dbus_g_type_specialized_construct (type);
01122
01123 g_assert (instance->len == 0);
01124
01125 g_array_free (instance, TRUE);
01126 }
01127
01128 type = dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_STRING);
01129 g_assert (dbus_g_type_is_map (type));
01130 g_assert (dbus_g_type_get_map_key_specialization (type) == G_TYPE_STRING);
01131 g_assert (dbus_g_type_get_map_value_specialization (type) == G_TYPE_STRING);
01132 {
01133 GHashTable *instance;
01134 GValue val = { 0, };
01135 TestSpecializedHashData hashdata;
01136
01137 instance = dbus_g_type_specialized_construct (type);
01138
01139 g_assert (g_hash_table_size (instance) == 0);
01140 g_hash_table_insert (instance, g_strdup ("foo"), g_strdup ("bar"));
01141 g_hash_table_insert (instance, g_strdup ("baz"), g_strdup ("moo"));
01142 g_assert (g_hash_table_size (instance) == 2);
01143
01144 g_value_init (&val, type);
01145 g_value_set_boxed_take_ownership (&val, instance);
01146 hashdata.seen_foo = FALSE;
01147 hashdata.seen_baz = FALSE;
01148 dbus_g_type_map_value_iterate (&val,
01149 test_specialized_hash,
01150 &hashdata);
01151
01152 g_assert (hashdata.seen_foo);
01153 g_assert (hashdata.seen_baz);
01154
01155 g_value_unset (&val);
01156 }
01157
01158 type = dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_VALUE);
01159 g_assert (dbus_g_type_is_map (type));
01160 g_assert (dbus_g_type_get_map_key_specialization (type) == G_TYPE_STRING);
01161 g_assert (dbus_g_type_get_map_value_specialization (type) == G_TYPE_VALUE);
01162 {
01163 GHashTable *instance;
01164 GValue val = { 0, };
01165 TestSpecializedHashData hashdata;
01166 DBusGTypeSpecializedAppendContext ctx;
01167 GValue *eltval;
01168
01169 instance = dbus_g_type_specialized_construct (type);
01170 g_value_init (&val, type);
01171 g_value_set_boxed_take_ownership (&val, instance);
01172
01173 dbus_g_type_specialized_init_append (&val, &ctx);
01174
01175 {
01176 GValue keyval = { 0, };
01177 GValue valval = { 0, };
01178 g_value_init (&keyval, G_TYPE_STRING);
01179 g_value_set_string (&keyval, "foo");
01180
01181 g_value_init (&valval, G_TYPE_VALUE);
01182 eltval = g_new0 (GValue, 1);
01183 g_value_init (eltval, G_TYPE_UINT);
01184 g_value_set_uint (eltval, 20);
01185 g_value_set_boxed_take_ownership (&valval, eltval);
01186 dbus_g_type_specialized_map_append (&ctx, &keyval, &valval);
01187 }
01188
01189 {
01190 GValue keyval = { 0, };
01191 GValue valval = { 0, };
01192 g_value_init (&keyval, G_TYPE_STRING);
01193 g_value_set_string (&keyval, "baz");
01194 g_value_init (&valval, G_TYPE_VALUE);
01195 eltval = g_new0 (GValue, 1);
01196 g_value_init (eltval, G_TYPE_STRING);
01197 g_value_set_string (eltval, "bar");
01198 g_value_set_boxed_take_ownership (&valval, eltval);
01199 dbus_g_type_specialized_map_append (&ctx, &keyval, &valval);
01200 }
01201
01202 hashdata.seen_foo = FALSE;
01203 hashdata.seen_baz = FALSE;
01204 dbus_g_type_map_value_iterate (&val,
01205 test_specialized_hash_2,
01206 &hashdata);
01207
01208 g_assert (hashdata.seen_foo);
01209 g_assert (hashdata.seen_baz);
01210
01211 g_value_unset (&val);
01212 }
01213
01214 type = dbus_g_type_get_collection ("GSList", G_TYPE_OBJECT);
01215 g_assert (dbus_g_type_is_collection (type));
01216 g_assert (dbus_g_type_get_collection_specialization (type) == G_TYPE_OBJECT);
01217 {
01218 GSList *instance, *tmp, *copy;
01219 GValue val = {0, };
01220 GValue copyval = {0, };
01221 DBusGTypeSpecializedAppendContext ctx;
01222 GObject *objects[3];
01223 int i;
01224
01225 instance = dbus_g_type_specialized_construct (type);
01226 g_assert (instance == NULL);
01227
01228 g_value_init (&val, type);
01229 g_value_take_boxed (&val, instance);
01230
01231 dbus_g_type_specialized_init_append (&val, &ctx);
01232
01233 for (i = 0; i < 3; i++)
01234 {
01235 GValue eltval = { 0, };
01236 GObject *obj = g_object_new (G_TYPE_OBJECT, NULL);
01237
01238 g_assert (obj != NULL);
01239 objects[i] = obj;
01240 g_object_add_weak_pointer (obj, (gpointer) (objects + i));
01241
01242 g_value_init (&eltval, G_TYPE_OBJECT);
01243 g_value_take_object (&eltval, obj);
01244 dbus_g_type_specialized_collection_append (&ctx, &eltval);
01245 }
01246
01247 dbus_g_type_specialized_collection_end_append (&ctx);
01248
01249 instance = g_value_get_boxed (&val);
01250 g_assert (g_slist_length (instance) == 3);
01251
01252 for (tmp = instance; tmp; tmp = tmp->next)
01253 {
01254 GObject *obj = tmp->data;
01255 g_assert (G_IS_OBJECT (obj));
01256 g_assert (obj->ref_count == 1);
01257 }
01258
01259 g_value_init (©val, type);
01260 g_value_copy (&val, ©val);
01261
01262 copy = g_value_get_boxed (©val);
01263 g_assert (g_slist_length (copy) == 3);
01264
01265 for (tmp = copy; tmp; tmp = tmp->next)
01266 {
01267 GObject *obj = tmp->data;
01268 g_assert (G_IS_OBJECT (obj));
01269 g_assert (obj->ref_count == 2);
01270 }
01271
01272 g_value_unset (©val);
01273
01274 for (i = 0; i < 3; i++)
01275 {
01276 g_assert (objects[i] != NULL);
01277 }
01278
01279 for (tmp = instance; tmp; tmp = tmp->next)
01280 {
01281 GObject *obj = tmp->data;
01282 g_assert (G_IS_OBJECT (obj));
01283 g_assert (obj->ref_count == 1);
01284 }
01285
01286 g_value_unset (&val);
01287
01288 for (i = 0; i < 3; i++)
01289 {
01290 g_assert (objects[i] == NULL);
01291 }
01292 }
01293
01294 type = dbus_g_type_get_collection ("GPtrArray", G_TYPE_STRING);
01295 g_assert (dbus_g_type_is_collection (type));
01296 g_assert (dbus_g_type_get_collection_specialization (type) == G_TYPE_STRING);
01297 {
01298 GPtrArray *instance;
01299 DBusGTypeSpecializedAppendContext ctx;
01300 GValue val = {0, };
01301 GValue eltval = {0, };
01302
01303 instance = dbus_g_type_specialized_construct (type);
01304
01305 g_assert (instance->len == 0);
01306
01307 g_value_init (&val, type);
01308 g_value_set_boxed_take_ownership (&val, instance);
01309
01310 dbus_g_type_specialized_init_append (&val, &ctx);
01311
01312 g_value_init (&eltval, G_TYPE_STRING);
01313 g_value_set_static_string (&eltval, "foo");
01314 dbus_g_type_specialized_collection_append (&ctx, &eltval);
01315
01316 g_value_reset (&eltval);
01317 g_value_set_static_string (&eltval, "bar");
01318 dbus_g_type_specialized_collection_append (&ctx, &eltval);
01319
01320 g_value_reset (&eltval);
01321 g_value_set_static_string (&eltval, "baz");
01322 dbus_g_type_specialized_collection_append (&ctx, &eltval);
01323
01324 dbus_g_type_specialized_collection_end_append (&ctx);
01325
01326 g_assert (instance->len == 3);
01327
01328 g_assert (!strcmp ("foo", g_ptr_array_index (instance, 0)));
01329 g_assert (!strcmp ("bar", g_ptr_array_index (instance, 1)));
01330 g_assert (!strcmp ("baz", g_ptr_array_index (instance, 2)));
01331
01332 g_value_unset (&val);
01333 }
01334
01335 type = dbus_g_type_get_struct ("GValueArray", G_TYPE_STRING, G_TYPE_UINT, DBUS_TYPE_G_OBJECT_PATH, G_TYPE_INVALID);
01336 g_assert (dbus_g_type_is_struct (type));
01337 g_assert (dbus_g_type_get_struct_size (type) == 3);
01338 g_assert (dbus_g_type_get_struct_member_type (type, 0) == G_TYPE_STRING);
01339 g_assert (dbus_g_type_get_struct_member_type (type, 1) == G_TYPE_UINT);
01340 g_assert (dbus_g_type_get_struct_member_type (type, 2) == DBUS_TYPE_G_OBJECT_PATH);
01341 {
01342 GValueArray *instance;
01343 GValue val = {0, };
01344 GValue memval = {0, };
01345
01346 instance = dbus_g_type_specialized_construct (type);
01347
01348 g_assert (instance->n_values == 3);
01349
01350 g_value_init (&val, type);
01351 g_value_set_boxed_take_ownership (&val, instance);
01352
01353 g_value_init (&memval, G_TYPE_STRING);
01354 g_value_set_static_string (&memval, "foo");
01355 dbus_g_type_struct_set_member (&val, 0, &memval);
01356 g_value_unset (&memval);
01357
01358 g_value_init (&memval, G_TYPE_UINT);
01359 g_value_set_uint (&memval, 42);
01360 dbus_g_type_struct_set_member (&val, 1, &memval);
01361 g_value_unset (&memval);
01362
01363 g_value_init (&memval, DBUS_TYPE_G_OBJECT_PATH);
01364 g_value_set_static_boxed (&memval, "/bar/moo/foo/baz");
01365 dbus_g_type_struct_set_member (&val, 2, &memval);
01366 g_value_unset (&memval);
01367
01368 g_assert (instance->n_values == 3);
01369
01370 g_value_init (&memval, G_TYPE_STRING);
01371 dbus_g_type_struct_get_member (&val, 0, &memval);
01372 g_assert (0 == strcmp (g_value_get_string (&memval), "foo"));
01373 g_value_unset (&memval);
01374
01375 g_value_init (&memval, G_TYPE_UINT);
01376 dbus_g_type_struct_get_member (&val, 1, &memval);
01377 g_assert (g_value_get_uint (&memval) == 42);
01378 g_value_unset (&memval);
01379
01380 g_value_init (&memval, DBUS_TYPE_G_OBJECT_PATH);
01381 dbus_g_type_struct_get_member (&val, 2, &memval);
01382 g_assert (0 == strcmp ((gchar*) g_value_get_boxed (&memval),
01383 "/bar/moo/foo/baz"));
01384 g_value_unset (&memval);
01385
01386 g_value_unset (&val);
01387 }
01388
01389 type = dbus_g_type_get_struct ("GValueArray", G_TYPE_STRING, G_TYPE_UINT, DBUS_TYPE_G_OBJECT_PATH, G_TYPE_INVALID);
01390 g_assert (dbus_g_type_is_struct (type));
01391 g_assert (dbus_g_type_get_struct_size (type) == 3);
01392 g_assert (dbus_g_type_get_struct_member_type (type, 0) == G_TYPE_STRING);
01393 g_assert (dbus_g_type_get_struct_member_type (type, 1) == G_TYPE_UINT);
01394 g_assert (dbus_g_type_get_struct_member_type (type, 2) == DBUS_TYPE_G_OBJECT_PATH);
01395 {
01396 GValueArray *instance;
01397 GValue val = {0, };
01398
01399 instance = dbus_g_type_specialized_construct (type);
01400
01401 g_assert (instance->n_values == 3);
01402
01403 g_value_init (&val, type);
01404 g_value_set_boxed_take_ownership (&val, instance);
01405
01406 dbus_g_type_struct_set (&val,
01407 0,"foo",
01408 1, 42,
01409 2, "/bar/moo/foo/baz",
01410 G_MAXUINT);
01411
01412 g_assert (instance->n_values == 3);
01413
01414 {
01415 gchar *string;
01416 guint intval;
01417 gchar *path;
01418
01419 dbus_g_type_struct_get (&val,
01420 0, &string,
01421 1, &intval,
01422 2, &path,
01423 G_MAXUINT);
01424
01425 g_assert (0 == strcmp (string, "foo"));
01426 g_assert (intval == 42);
01427 g_assert (0 == strcmp (path, "/bar/moo/foo/baz"));
01428 }
01429
01430 g_value_unset (&val);
01431 }
01432
01433
01434 return TRUE;
01435 }
01436
01437
01438
01439 #endif