1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-gvalue-utils.c: Non-DBus-specific functions related to GType/GValue
3 *
4 * Copyright (C) 2005 Red Hat, Inc.
5 *
6 * SPDX-License-Identifier: AFL-2.1 OR GPL-2.0-or-later
7 *
8 * Licensed under the Academic Free License version 2.1
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 *
24 */
25
26 #include <config.h>
27 #include "dbus/dbus-glib.h"
28 #include "dbus-gtype-specialized-priv.h"
29 #include "dbus-gvalue-utils.h"
30 #include "dbus-gtest.h"
31 #include <glib.h>
32 #include <string.h>
33 #include <gobject/gvaluecollector.h>
34
35
36 static guint
fixed_type_get_size(GType type)37 fixed_type_get_size (GType type)
38 {
39 switch (type)
40 {
41 case G_TYPE_CHAR:
42 case G_TYPE_UCHAR:
43 return sizeof (gchar);
44 case G_TYPE_BOOLEAN:
45 return sizeof (gboolean);
46 case G_TYPE_LONG:
47 case G_TYPE_ULONG:
48 return sizeof (glong);
49 case G_TYPE_INT:
50 case G_TYPE_UINT:
51 return sizeof (gint);
52 case G_TYPE_INT64:
53 case G_TYPE_UINT64:
54 return sizeof (gint64);
55 case G_TYPE_FLOAT:
56 return sizeof (gfloat);
57 case G_TYPE_DOUBLE:
58 return sizeof (gdouble);
59 default:
60 return 0;
61 }
62 }
63
64 gboolean
_dbus_g_type_is_fixed(GType type)65 _dbus_g_type_is_fixed (GType type)
66 {
67 return fixed_type_get_size (type) > 0;
68 }
69
70 guint
_dbus_g_type_fixed_get_size(GType type)71 _dbus_g_type_fixed_get_size (GType type)
72 {
73 g_assert (_dbus_g_type_is_fixed (type));
74 return fixed_type_get_size (type);
75 }
76
77 gboolean
_dbus_gvalue_store(GValue * value,gpointer storage)78 _dbus_gvalue_store (GValue *value,
79 gpointer storage)
80 {
81 /* FIXME - can we use the GValue lcopy_value method
82 * to do this in a cleaner way?
83 */
84 switch (g_type_fundamental (G_VALUE_TYPE (value)))
85 {
86 case G_TYPE_CHAR:
87 *((gchar *) storage) = g_value_get_char (value);
88 return TRUE;
89 case G_TYPE_UCHAR:
90 *((guchar *) storage) = g_value_get_uchar (value);
91 return TRUE;
92 case G_TYPE_BOOLEAN:
93 *((gboolean *) storage) = g_value_get_boolean (value);
94 return TRUE;
95 case G_TYPE_LONG:
96 *((glong *) storage) = g_value_get_long (value);
97 return TRUE;
98 case G_TYPE_ULONG:
99 *((gulong *) storage) = g_value_get_ulong (value);
100 return TRUE;
101 case G_TYPE_INT:
102 *((gint *) storage) = g_value_get_int (value);
103 return TRUE;
104 case G_TYPE_UINT:
105 *((guint *) storage) = g_value_get_uint (value);
106 return TRUE;
107 case G_TYPE_INT64:
108 *((gint64 *) storage) = g_value_get_int64 (value);
109 return TRUE;
110 case G_TYPE_UINT64:
111 *((guint64 *) storage) = g_value_get_uint64 (value);
112 return TRUE;
113 case G_TYPE_DOUBLE:
114 *((gdouble *) storage) = g_value_get_double (value);
115 return TRUE;
116 case G_TYPE_STRING:
117 *((gchar **) storage) = (char*) g_value_get_string (value);
118 return TRUE;
119 case G_TYPE_OBJECT:
120 *((gpointer *) storage) = g_value_get_object (value);
121 return TRUE;
122 case G_TYPE_BOXED:
123 *((gpointer *) storage) = g_value_get_boxed (value);
124 return TRUE;
125 default:
126 return FALSE;
127 }
128 }
129
130 gboolean
_dbus_gvalue_set_from_pointer(GValue * value,gconstpointer storage)131 _dbus_gvalue_set_from_pointer (GValue *value,
132 gconstpointer storage)
133 {
134 /* FIXME - is there a better way to do this? */
135 switch (g_type_fundamental (G_VALUE_TYPE (value)))
136 {
137 case G_TYPE_CHAR:
138 g_value_set_char (value, *((gchar *) storage));
139 return TRUE;
140 case G_TYPE_UCHAR:
141 g_value_set_uchar (value, *((guchar *) storage));
142 return TRUE;
143 case G_TYPE_BOOLEAN:
144 g_value_set_boolean (value, *((gboolean *) storage));
145 return TRUE;
146 case G_TYPE_LONG:
147 g_value_set_long (value, *((glong *) storage));
148 return TRUE;
149 case G_TYPE_ULONG:
150 g_value_set_ulong (value, *((gulong *) storage));
151 return TRUE;
152 case G_TYPE_INT:
153 g_value_set_int (value, *((gint *) storage));
154 return TRUE;
155 case G_TYPE_UINT:
156 g_value_set_uint (value, *((guint *) storage));
157 return TRUE;
158 case G_TYPE_INT64:
159 g_value_set_int64 (value, *((gint64 *) storage));
160 return TRUE;
161 case G_TYPE_UINT64:
162 g_value_set_uint64 (value, *((guint64 *) storage));
163 return TRUE;
164 case G_TYPE_DOUBLE:
165 g_value_set_double (value, *((gdouble *) storage));
166 return TRUE;
167 case G_TYPE_STRING:
168 g_value_set_string (value, *((gchar **) storage));
169 return TRUE;
170 case G_TYPE_OBJECT:
171 g_value_set_object (value, *((gpointer *) storage));
172 return TRUE;
173 case G_TYPE_BOXED:
174 g_value_set_boxed (value, *((gpointer *) storage));
175 return TRUE;
176 default:
177 return FALSE;
178 }
179 }
180
181 gboolean
_dbus_gvalue_take(GValue * value,GTypeCValue * cvalue)182 _dbus_gvalue_take (GValue *value,
183 GTypeCValue *cvalue)
184 {
185 GType g_type;
186 GTypeValueTable *value_table;
187 char *error_msg;
188
189 g_type = G_VALUE_TYPE (value);
190 value_table = g_type_value_table_peek (g_type);
191
192 error_msg = value_table->collect_value (value, 1, cvalue, G_VALUE_NOCOPY_CONTENTS);
193 if (error_msg)
194 {
195 g_warning ("%s: %s", G_STRLOC, error_msg);
196 g_free (error_msg);
197 return FALSE;
198 }
199 /* Clear the NOCOPY_CONTENTS flag; we want to take ownership
200 * of the value.
201 */
202 value->data[1].v_uint &= ~(G_VALUE_NOCOPY_CONTENTS);
203 return TRUE;
204 }
205
206 gboolean
_dbus_gtype_can_signal_error(GType gtype)207 _dbus_gtype_can_signal_error (GType gtype)
208 {
209 switch (gtype)
210 {
211 case G_TYPE_BOOLEAN:
212 case G_TYPE_INT:
213 case G_TYPE_UINT:
214 case G_TYPE_STRING:
215 case G_TYPE_BOXED:
216 case G_TYPE_OBJECT:
217 return TRUE;
218 default:
219 return FALSE;
220 }
221 }
222
223 gboolean
_dbus_gvalue_signals_error(const GValue * value)224 _dbus_gvalue_signals_error (const GValue *value)
225 {
226 /* Hardcoded rules for return value semantics for certain
227 * types. Perhaps in the future we'd want an annotation
228 * specifying which return values are errors, but in
229 * reality people will probably just use boolean and
230 * boxed, and there the semantics are pretty standard.
231 */
232 switch (G_TYPE_FUNDAMENTAL (G_VALUE_TYPE (value)))
233 {
234 case G_TYPE_BOOLEAN:
235 return (g_value_get_boolean (value) == FALSE);
236 break;
237 case G_TYPE_INT:
238 return (g_value_get_int (value) < 0);
239 break;
240 case G_TYPE_UINT:
241 return (g_value_get_uint (value) == 0);
242 break;
243 case G_TYPE_STRING:
244 return (g_value_get_string (value) == NULL);
245 break;
246 case G_TYPE_BOXED:
247 return (g_value_get_boxed (value) == NULL);
248 break;
249 case G_TYPE_OBJECT:
250 return (g_value_get_object (value) == NULL);
251 break;
252 default:
253 g_assert_not_reached ();
254 return FALSE;
255 }
256 }
257
258
259 static gboolean
hash_func_from_gtype(GType gtype,GHashFunc * func)260 hash_func_from_gtype (GType gtype, GHashFunc *func)
261 {
262 switch (gtype)
263 {
264 case G_TYPE_CHAR:
265 case G_TYPE_UCHAR:
266 case G_TYPE_BOOLEAN:
267 case G_TYPE_INT:
268 case G_TYPE_UINT:
269 *func = NULL;
270 return TRUE;
271 case G_TYPE_STRING:
272 *func = g_str_hash;
273 return TRUE;
274 default:
275 if (gtype == DBUS_TYPE_G_OBJECT_PATH)
276 {
277 *func = g_str_hash;
278 return TRUE;
279 }
280 else if (gtype == DBUS_TYPE_G_SIGNATURE)
281 {
282 *func = g_str_hash;
283 return TRUE;
284 }
285 return FALSE;
286 }
287 }
288
289 static void
unset_and_free_g_value(gpointer val)290 unset_and_free_g_value (gpointer val)
291 {
292 GValue *value = val;
293
294 g_value_unset (value);
295 g_free (value);
296 }
297
298 static gboolean
299 gtype_can_simple_free (GType type);
300
301 static gboolean
hash_simple_free_from_gtype(GType gtype,GDestroyNotify * func)302 hash_simple_free_from_gtype (GType gtype, GDestroyNotify *func)
303 {
304 switch (gtype)
305 {
306 case G_TYPE_CHAR:
307 case G_TYPE_UCHAR:
308 case G_TYPE_BOOLEAN:
309 case G_TYPE_INT:
310 case G_TYPE_UINT:
311 *func = NULL;
312 return TRUE;
313 case G_TYPE_DOUBLE:
314 case G_TYPE_STRING:
315 *func = g_free;
316 return TRUE;
317 default:
318 if (gtype == G_TYPE_VALUE)
319 {
320 *func = unset_and_free_g_value;
321 return TRUE;
322 }
323 else if (gtype == G_TYPE_VALUE_ARRAY)
324 {
325 *func = (GDestroyNotify) g_value_array_free;
326 return TRUE;
327 }
328 else if (gtype == G_TYPE_STRV)
329 {
330 *func = (GDestroyNotify) g_strfreev;
331 return TRUE;
332 }
333 else if (gtype == DBUS_TYPE_G_OBJECT_PATH)
334 {
335 *func = g_free;
336 return TRUE;
337 }
338 else if (gtype == DBUS_TYPE_G_SIGNATURE)
339 {
340 *func = g_free;
341 return TRUE;
342 }
343 else if (dbus_g_type_is_collection (gtype))
344 {
345 const DBusGTypeSpecializedCollectionVtable* vtable;
346 vtable = dbus_g_type_collection_peek_vtable (gtype);
347 if (vtable->base_vtable.simple_free_func)
348 {
349 *func = vtable->base_vtable.simple_free_func;
350 return TRUE;
351 }
352 }
353 else if (dbus_g_type_is_map (gtype))
354 {
355 const DBusGTypeSpecializedMapVtable* vtable;
356 GType key_gtype, value_gtype;
357
358 key_gtype = dbus_g_type_get_map_key_specialization (gtype);
359 value_gtype = dbus_g_type_get_map_value_specialization (gtype);
360
361 /* if either the key or the value don't have "simple" (without a
362 * GType) free functions, then the hashtable's contents must be freed
363 * with hashtable_free, so the hashtable itself can't have a simple
364 * free function. */
365 if (!gtype_can_simple_free (key_gtype) ||
366 !gtype_can_simple_free (value_gtype))
367 return FALSE;
368
369 vtable = dbus_g_type_map_peek_vtable (gtype);
370 if (vtable->base_vtable.simple_free_func)
371 {
372 *func = vtable->base_vtable.simple_free_func;
373 return TRUE;
374 }
375 }
376 else if (dbus_g_type_is_struct (gtype))
377 {
378 const DBusGTypeSpecializedStructVtable *vtable;
379 vtable = dbus_g_type_struct_peek_vtable (gtype);
380 if (vtable->base_vtable.simple_free_func)
381 {
382 *func = vtable->base_vtable.simple_free_func;
383 return TRUE;
384 }
385 }
386 return FALSE;
387 }
388 }
389
390 static gboolean
gtype_can_simple_free(GType type)391 gtype_can_simple_free (GType type)
392 {
393 GDestroyNotify func;
394 return hash_simple_free_from_gtype (type, &func);
395 }
396
397 gboolean
_dbus_gtype_is_valid_hash_key(GType type)398 _dbus_gtype_is_valid_hash_key (GType type)
399 {
400 GHashFunc func;
401 return hash_func_from_gtype (type, &func);
402 }
403
404 gboolean
_dbus_gtype_is_valid_hash_value(GType gtype)405 _dbus_gtype_is_valid_hash_value (GType gtype)
406 {
407 /* anything we can take into a GValue using gvalue_take_hash_value is fine */
408 switch (g_type_fundamental (gtype))
409 {
410 case G_TYPE_CHAR:
411 case G_TYPE_UCHAR:
412 case G_TYPE_BOOLEAN:
413 case G_TYPE_INT:
414 case G_TYPE_UINT:
415 case G_TYPE_DOUBLE:
416 case G_TYPE_STRING:
417 case G_TYPE_BOXED:
418 case G_TYPE_OBJECT:
419 return TRUE;
420 }
421
422 return FALSE;
423 }
424
425 GHashFunc
_dbus_g_hash_func_from_gtype(GType gtype)426 _dbus_g_hash_func_from_gtype (GType gtype)
427 {
428 GHashFunc func;
429 gboolean ret;
430 ret = hash_func_from_gtype (gtype, &func);
431 g_assert (ret != FALSE);
432 return func;
433 }
434
435 GEqualFunc
_dbus_g_hash_equal_from_gtype(GType gtype)436 _dbus_g_hash_equal_from_gtype (GType gtype)
437 {
438 g_assert (_dbus_gtype_is_valid_hash_key (gtype));
439
440 switch (gtype)
441 {
442 case G_TYPE_CHAR:
443 case G_TYPE_UCHAR:
444 case G_TYPE_BOOLEAN:
445 case G_TYPE_INT:
446 case G_TYPE_UINT:
447 return NULL;
448 case G_TYPE_STRING:
449 return g_str_equal;
450 default:
451 if (gtype == DBUS_TYPE_G_OBJECT_PATH)
452 return g_str_equal;
453 else if (gtype == DBUS_TYPE_G_SIGNATURE)
454 return g_str_equal;
455 g_assert_not_reached ();
456 return NULL;
457 }
458 }
459
460 static void
hash_fake_simple_free_func(gpointer val)461 hash_fake_simple_free_func (gpointer val)
462 {
463 /* Havoc would be proud... :P */
464 g_critical ("If you see this message then the author of this application or "
465 "one of its libraries has tried to remove or replace the value %p in a "
466 "hash table which was constructed by the D-Bus Glib bindings.\n\n"
467
468 "However, it was not possible for the bindings to provide a destroy "
469 "function to g_hash_table_new_full which is able to free this value, as "
470 "its GType must be known in order to free it. This means the memory "
471 "allocated to store the value has most likely just been leaked.\n\n"
472
473 "To avoid this error, the GHashTable (or keys/values \"stolen\" from "
474 "it) should be freed by using g_boxed_free as follows:\n"
475 " g_boxed_free (dbus_g_type_get_map (\"GHashTable\", key_gtype, "
476 "value_gtype), hash_table);\n", val);
477 }
478
479 GDestroyNotify
_dbus_g_hash_free_from_gtype(GType gtype)480 _dbus_g_hash_free_from_gtype (GType gtype)
481 {
482 GDestroyNotify func;
483 gboolean ret;
484
485 ret = hash_simple_free_from_gtype (gtype, &func);
486
487 /* if the value doesn't have a simple free function, we cannot define a
488 * meaningful free function here. instead, this hash table must be freed
489 * using g_boxed_free so that the hash_free function gets invoked. if the
490 * user does not do so, we provide a fake free function to provide a warning
491 * in this case. */
492 if (ret == FALSE)
493 {
494 g_assert (_dbus_gtype_is_valid_hash_value (gtype));
495
496 func = hash_fake_simple_free_func;
497 }
498
499 return func;
500 }
501
502 static void gvalue_take_ptrarray_value (GValue *value, gpointer instance);
503
504 static void
gvalue_take_hash_value(GValue * value,gpointer instance)505 gvalue_take_hash_value (GValue *value, gpointer instance)
506 {
507 switch (g_type_fundamental (G_VALUE_TYPE (value)))
508 {
509 case G_TYPE_CHAR:
510 g_value_set_char (value, (gchar) GPOINTER_TO_INT (instance));
511 break;
512 case G_TYPE_UCHAR:
513 g_value_set_uchar (value, (guchar) GPOINTER_TO_UINT (instance));
514 break;
515 case G_TYPE_BOOLEAN:
516 g_value_set_boolean (value, (gboolean) GPOINTER_TO_UINT (instance));
517 break;
518 case G_TYPE_INT:
519 g_value_set_int (value, GPOINTER_TO_INT (instance));
520 break;
521 case G_TYPE_UINT:
522 g_value_set_uint (value, GPOINTER_TO_UINT (instance));
523 break;
524 case G_TYPE_DOUBLE:
525 g_value_set_double (value, *(gdouble *) instance);
526 break;
527 default:
528 gvalue_take_ptrarray_value (value, instance);
529 break;
530 }
531 }
532
533 static gpointer ptrarray_value_from_gvalue (const GValue *value);
534
535 static gpointer
hash_value_from_gvalue(GValue * value)536 hash_value_from_gvalue (GValue *value)
537 {
538 switch (g_type_fundamental (G_VALUE_TYPE (value)))
539 {
540 case G_TYPE_CHAR:
541 return GINT_TO_POINTER ((int) g_value_get_char (value));
542 break;
543 case G_TYPE_UCHAR:
544 return GUINT_TO_POINTER ((guint) g_value_get_uchar (value));
545 break;
546 case G_TYPE_BOOLEAN:
547 return GUINT_TO_POINTER ((guint) g_value_get_boolean (value));
548 break;
549 case G_TYPE_INT:
550 return GINT_TO_POINTER (g_value_get_int (value));
551 break;
552 case G_TYPE_UINT:
553 return GUINT_TO_POINTER (g_value_get_uint (value));
554 break;
555 case G_TYPE_DOUBLE:
556 {
557 gdouble *p = (gdouble *) g_malloc0 (sizeof (gdouble));
558 *p = g_value_get_double (value);
559 return (gpointer) p;
560 }
561 break;
562 default:
563 return ptrarray_value_from_gvalue (value);
564 break;
565 }
566 }
567
568 struct DBusGHashTableValueForeachData
569 {
570 DBusGTypeSpecializedMapIterator func;
571 GType key_type;
572 GType value_type;
573 gpointer data;
574 };
575
576 static void
hashtable_foreach_with_values(gpointer key,gpointer value,gpointer user_data)577 hashtable_foreach_with_values (gpointer key, gpointer value, gpointer user_data)
578 {
579 GValue key_val = {0, };
580 GValue value_val = {0, };
581 struct DBusGHashTableValueForeachData *data = user_data;
582
583 g_value_init (&key_val, data->key_type);
584 g_value_init (&value_val, data->value_type);
585 gvalue_take_hash_value (&key_val, key);
586 gvalue_take_hash_value (&value_val, value);
587
588 data->func (&key_val, &value_val, data->data);
589 }
590
591
592 static void
hashtable_iterator(GType hash_type,gpointer instance,DBusGTypeSpecializedMapIterator iterator,gpointer user_data)593 hashtable_iterator (GType hash_type,
594 gpointer instance,
595 DBusGTypeSpecializedMapIterator iterator,
596 gpointer user_data)
597 {
598 struct DBusGHashTableValueForeachData data;
599 GType key_gtype;
600 GType value_gtype;
601
602 key_gtype = dbus_g_type_get_map_key_specialization (hash_type);
603 value_gtype = dbus_g_type_get_map_value_specialization (hash_type);
604
605 data.func = iterator;
606 data.key_type = key_gtype;
607 data.value_type = value_gtype;
608 data.data = user_data;
609
610 g_hash_table_foreach (instance, hashtable_foreach_with_values, &data);
611 }
612
613 void
_dbus_g_hash_table_insert_steal_values(GHashTable * table,GValue * key_val,GValue * value_val)614 _dbus_g_hash_table_insert_steal_values (GHashTable *table,
615 GValue *key_val,
616 GValue *value_val)
617 {
618 gpointer key, val;
619
620 key = hash_value_from_gvalue (key_val);
621 val = hash_value_from_gvalue (value_val);
622
623 g_hash_table_insert (table, key, val);
624 }
625
626 static void
hashtable_append(DBusGTypeSpecializedAppendContext * ctx,GValue * key,GValue * val)627 hashtable_append (DBusGTypeSpecializedAppendContext *ctx,
628 GValue *key,
629 GValue *val)
630 {
631 GHashTable *table;
632
633 table = g_value_get_boxed (ctx->val);
634 _dbus_g_hash_table_insert_steal_values (table, key, val);
635 }
636
637 static gpointer
hashtable_constructor(GType type)638 hashtable_constructor (GType type)
639 {
640 GHashTable *ret;
641 GType key_gtype;
642 GType value_gtype;
643
644 key_gtype = dbus_g_type_get_map_key_specialization (type);
645 value_gtype = dbus_g_type_get_map_value_specialization (type);
646
647 ret = g_hash_table_new_full (_dbus_g_hash_func_from_gtype (key_gtype),
648 _dbus_g_hash_equal_from_gtype (key_gtype),
649 _dbus_g_hash_free_from_gtype (key_gtype),
650 _dbus_g_hash_free_from_gtype (value_gtype));
651 return ret;
652 }
653
654 static void
hashtable_insert_values(GHashTable * table,const GValue * key_val,const GValue * value_val)655 hashtable_insert_values (GHashTable *table,
656 const GValue *key_val,
657 const GValue *value_val)
658 {
659 GValue key_copy = {0, };
660 GValue value_copy = {0, };
661
662 g_value_init (&key_copy, G_VALUE_TYPE (key_val));
663 g_value_copy (key_val, &key_copy);
664 g_value_init (&value_copy, G_VALUE_TYPE (value_val));
665 g_value_copy (value_val, &value_copy);
666
667 _dbus_g_hash_table_insert_steal_values (table, &key_copy, &value_copy);
668 }
669
670 static void
hashtable_foreach_copy(const GValue * key,const GValue * val,gpointer data)671 hashtable_foreach_copy (const GValue *key, const GValue *val, gpointer data)
672 {
673 hashtable_insert_values ((GHashTable *) data, key, val);
674 }
675
676 static gpointer
hashtable_copy(GType type,gpointer src)677 hashtable_copy (GType type, gpointer src)
678 {
679 GHashTable *ghash;
680 GHashTable *ret;
681 GValue hashval = {0,};
682
683 ghash = src;
684
685 ret = hashtable_constructor (type);
686
687 g_value_init (&hashval, type);
688 g_value_set_static_boxed (&hashval, ghash);
689 dbus_g_type_map_value_iterate (&hashval, hashtable_foreach_copy, ret);
690 return ret;
691 }
692
693 /* we leave this here for backwards compatibility - any hash tables nested
694 * inside hash tables will use this as their free function if users were
695 * already relying on it, but dbus-glib itself will never use it directly as
696 * hashtable_free is also defined. */
697 static void
hashtable_simple_free(gpointer val)698 hashtable_simple_free (gpointer val)
699 {
700 g_hash_table_unref (val);
701 }
702
703 struct DBusGHashTableFreeData
704 {
705 GType key_gtype;
706 GType value_gtype;
707 };
708
709 static gboolean
hashtable_free_foreach_steal(gpointer key,gpointer value,gpointer user_data)710 hashtable_free_foreach_steal (gpointer key,
711 gpointer value,
712 gpointer user_data)
713 {
714 struct DBusGHashTableFreeData *data = user_data;
715 GValue val = { 0, };
716
717 g_value_init (&val, data->key_gtype);
718 gvalue_take_hash_value (&val, key);
719 g_value_unset (&val);
720
721 g_value_init (&val, data->value_gtype);
722 gvalue_take_hash_value (&val, value);
723 g_value_unset (&val);
724
725 return TRUE;
726 }
727
728 static void
hashtable_free(GType type,gpointer val)729 hashtable_free (GType type,
730 gpointer val)
731 {
732 struct DBusGHashTableFreeData data = { 0, };
733 GHashTable *hash = val;
734
735 data.key_gtype = dbus_g_type_get_map_key_specialization (type);
736 data.value_gtype = dbus_g_type_get_map_value_specialization (type);
737
738 /* wheee, fun. two cases here. either:
739 *
740 * a) the keys and value types both have simple (ie, no * GType parameter is
741 * needed to know how to free them) free functions, in which case they were
742 * set as the hash free functions when the hash table was constructed. in
743 * this case, it's sufficient for us to unref the hash table as before. we
744 * have to keep doing this in order to maintain compatibility with the ABI
745 * which was around before hash tables could contain types which don't have
746 * simple free functions (such as GPtrArrays of other stuff). for these
747 * tables, users were able to ref the hash tables and add/remove values, and
748 * rely on meaningful free functions.
749 *
750 * b) for any other key or value types where /do/ need to know the GType in
751 * order to free it, this function is the only "right" way to free the hash
752 * table. both the key and value free functions were set to print a big nasty
753 * warning, and we free the contents of the hashtable with foreach_steal.
754 */
755 if (gtype_can_simple_free (data.key_gtype) &&
756 gtype_can_simple_free (data.value_gtype))
757 {
758 g_hash_table_unref (hash);
759 }
760 else
761 {
762 g_hash_table_foreach_steal (hash, hashtable_free_foreach_steal, &data);
763 g_hash_table_unref (hash);
764 }
765 }
766
767 static gpointer
valuearray_constructor(GType type)768 valuearray_constructor (GType type)
769 {
770 GValueArray *ret;
771 guint size = dbus_g_type_get_struct_size (type);
772 guint i;
773 ret = g_value_array_new (size);
774 for (i=0; i < size; i++)
775 {
776 GValue val = {0,};
777 g_value_init (&val, dbus_g_type_get_struct_member_type (type, i));
778 g_value_array_append(ret, &val);
779 }
780 return (gpointer)ret;
781 }
782
783 static gpointer
valuearray_copy(GType type,gpointer src)784 valuearray_copy (GType type, gpointer src)
785 {
786 return g_value_array_copy ((GValueArray*) src);
787 }
788
789 static void
valuearray_simple_free(gpointer val)790 valuearray_simple_free (gpointer val)
791 {
792 g_value_array_free (val);
793 }
794
795 static gboolean
valuearray_get_member(GType type,gpointer instance,guint member,GValue * ret)796 valuearray_get_member (GType type, gpointer instance,
797 guint member, GValue *ret)
798 {
799 GValueArray *va = (GValueArray*) instance;
800 const GValue *val;
801 if (member < dbus_g_type_get_struct_size (type))
802 {
803 val = g_value_array_get_nth (va, member);
804 g_value_copy (val, ret);
805 return TRUE;
806 }
807 else
808 return FALSE;
809 }
810
811 static gboolean
valuearray_set_member(GType type,gpointer instance,guint member,const GValue * member_type)812 valuearray_set_member (GType type, gpointer instance,
813 guint member, const GValue *member_type)
814 {
815 GValueArray *va = (GValueArray*) instance;
816 GValue *vp;
817 if (member < dbus_g_type_get_struct_size (type))
818 {
819 vp = g_value_array_get_nth (va, member);
820 g_value_copy (member_type, vp);
821 return TRUE;
822 }
823 else
824 return FALSE;
825 }
826
827
828 static gpointer
array_constructor(GType type)829 array_constructor (GType type)
830 {
831 GArray *array;
832 guint elt_size;
833 GType elt_type;
834 gboolean zero_terminated;
835 gboolean clear;
836
837 elt_type = dbus_g_type_get_collection_specialization (type);
838 g_assert (elt_type != G_TYPE_INVALID);
839
840 elt_size = _dbus_g_type_fixed_get_size (elt_type);
841
842 /* These are "safe" defaults */
843 zero_terminated = TRUE; /* ((struct _DBusGRealArray*) garray)->zero_terminated; */
844 clear = TRUE; /* ((struct _DBusGRealArray*) garray)->clear; */
845
846 array = g_array_new (zero_terminated, clear, elt_size);
847 return array;
848 }
849
850 static void
array_iterator(GType garray_type,gpointer instance,DBusGTypeSpecializedCollectionIterator iterator,gpointer user_data)851 array_iterator (GType garray_type,
852 gpointer instance,
853 DBusGTypeSpecializedCollectionIterator iterator,
854 gpointer user_data)
855 {
856 GArray *array;
857 GType elt_gtype;
858 guint i;
859
860 array = instance;
861
862 elt_gtype = dbus_g_type_get_collection_specialization (garray_type);
863
864 for (i = 0; i < array->len; i++)
865 {
866 GValue val = {0, };
867 g_value_init (&val, elt_gtype);
868
869 switch (elt_gtype)
870 {
871 case G_TYPE_BOOLEAN:
872 g_value_set_boolean (&val, !!g_array_index (array, gboolean, i));
873 break;
874
875 case G_TYPE_FLOAT:
876 g_value_set_float (&val, g_array_index (array, gfloat, i));
877 break;
878
879 case G_TYPE_DOUBLE:
880 g_value_set_double (&val, g_array_index (array, gdouble, i));
881 break;
882
883 case G_TYPE_CHAR:
884 g_value_set_char (&val, g_array_index (array, gchar, i));
885 break;
886
887 case G_TYPE_UCHAR:
888 g_value_set_uchar (&val, g_array_index (array, guchar, i));
889 break;
890
891 case G_TYPE_INT:
892 g_value_set_int (&val, g_array_index (array, gint, i));
893 break;
894
895 case G_TYPE_UINT:
896 g_value_set_uint (&val, g_array_index (array, guint, i));
897 break;
898
899 case G_TYPE_LONG:
900 g_value_set_long (&val, g_array_index (array, glong, i));
901 break;
902
903 case G_TYPE_ULONG:
904 g_value_set_ulong (&val, g_array_index (array, gulong, i));
905 break;
906
907 case G_TYPE_INT64:
908 g_value_set_int64 (&val, g_array_index (array, gint64, i));
909 break;
910
911 case G_TYPE_UINT64:
912 g_value_set_uint64 (&val, g_array_index (array, guint64, i));
913 break;
914
915 default:
916 g_assert_not_reached ();
917 }
918
919 iterator (&val, user_data);
920 }
921 }
922
923 static void
array_append(DBusGTypeSpecializedAppendContext * ctx,GValue * value)924 array_append (DBusGTypeSpecializedAppendContext *ctx,
925 GValue *value)
926 {
927 GArray *array = g_value_get_boxed (ctx->val);
928 GType elt_gtype;
929 union {
930 guint64 u64;
931 gint64 i64;
932 gulong ul;
933 glong l;
934 guint u;
935 gint i;
936 guchar uc;
937 gchar c;
938 gboolean b;
939 gfloat f;
940 gdouble d;
941 } tmp;
942
943 elt_gtype = dbus_g_type_get_collection_specialization (
944 G_VALUE_TYPE (ctx->val));
945
946 switch (elt_gtype)
947 {
948 case G_TYPE_BOOLEAN:
949 tmp.b = g_value_get_boolean (value);
950 g_array_append_val (array, tmp.b);
951 break;
952
953 case G_TYPE_FLOAT:
954 tmp.f = g_value_get_float (value);
955 g_array_append_val (array, tmp.f);
956 break;
957
958 case G_TYPE_DOUBLE:
959 tmp.d = g_value_get_double (value);
960 g_array_append_val (array, tmp.d);
961 break;
962
963 case G_TYPE_CHAR:
964 tmp.c = g_value_get_char (value);
965 g_array_append_val (array, tmp.c);
966 break;
967
968 case G_TYPE_UCHAR:
969 tmp.uc = g_value_get_uchar (value);
970 g_array_append_val (array, tmp.uc);
971 break;
972
973 case G_TYPE_INT:
974 tmp.i = g_value_get_int (value);
975 g_array_append_val (array, tmp.i);
976 break;
977
978 case G_TYPE_UINT:
979 tmp.u = g_value_get_uint (value);
980 g_array_append_val (array, tmp.u);
981 break;
982
983 case G_TYPE_LONG:
984 tmp.l = g_value_get_long (value);
985 g_array_append_val (array, tmp.l);
986 break;
987
988 case G_TYPE_ULONG:
989 tmp.ul = g_value_get_ulong (value);
990 g_array_append_val (array, tmp.ul);
991 break;
992
993 case G_TYPE_INT64:
994 tmp.i64 = g_value_get_int64 (value);
995 g_array_append_val (array, tmp.i64);
996 break;
997
998 case G_TYPE_UINT64:
999 tmp.u64 = g_value_get_uint64 (value);
1000 g_array_append_val (array, tmp.u64);
1001 break;
1002
1003 default:
1004 g_assert_not_reached ();
1005 }
1006 }
1007
1008 static gpointer
array_copy(GType type,gpointer src)1009 array_copy (GType type, gpointer src)
1010 {
1011 GArray *garray;
1012 GArray *new;
1013
1014 garray = src;
1015
1016 new = array_constructor (type);
1017 g_array_append_vals (new, garray->data, garray->len);
1018
1019 return new;
1020 }
1021
1022 static void
array_simple_free(gpointer val)1023 array_simple_free (gpointer val)
1024 {
1025 GArray *array;
1026 array = val;
1027 g_array_free (array, TRUE);
1028 }
1029
1030 static gboolean
array_fixed_accessor(GType type,gpointer instance,gpointer * values,guint * len)1031 array_fixed_accessor (GType type, gpointer instance, gpointer *values, guint *len)
1032 {
1033 GType elt_type;
1034 GArray *array = instance;
1035
1036 elt_type = dbus_g_type_get_collection_specialization (type);
1037 if (!_dbus_g_type_is_fixed (elt_type))
1038 return FALSE;
1039
1040 *values = array->data;
1041 *len = array->len;
1042 return TRUE;
1043 }
1044
1045 static gpointer
ptrarray_constructor(GType type)1046 ptrarray_constructor (GType type)
1047 {
1048 /* Later we should determine a destructor, need g_ptr_array_destroy */
1049 return g_ptr_array_new ();
1050 }
1051
1052 static void
gvalue_take_ptrarray_value(GValue * value,gpointer instance)1053 gvalue_take_ptrarray_value (GValue *value, gpointer instance)
1054 {
1055 switch (g_type_fundamental (G_VALUE_TYPE (value)))
1056 {
1057 case G_TYPE_STRING:
1058 g_value_take_string (value, instance);
1059 break;
1060 case G_TYPE_BOXED:
1061 g_value_take_boxed (value, instance);
1062 break;
1063 case G_TYPE_OBJECT:
1064 g_value_take_object (value, instance);
1065 break;
1066 default:
1067 g_assert_not_reached ();
1068 break;
1069 }
1070 }
1071
1072 static gpointer
ptrarray_value_from_gvalue(const GValue * value)1073 ptrarray_value_from_gvalue (const GValue *value)
1074 {
1075 GValue tmp = {0, };
1076
1077 /* if the NOCOPY flag is set, then value was created via set_static and hence
1078 * is not owned by us. in order to preserve the "take" semantics that the API
1079 * has in general (which avoids copying in the common case), we must copy any
1080 * static values so that we can indiscriminately free the entire collection
1081 * later. */
1082 if (value->data[1].v_uint & G_VALUE_NOCOPY_CONTENTS)
1083 {
1084 g_value_init (&tmp, G_VALUE_TYPE (value));
1085 g_value_copy (value, &tmp);
1086 value = &tmp;
1087 }
1088
1089 switch (g_type_fundamental (G_VALUE_TYPE (value)))
1090 {
1091 case G_TYPE_STRING:
1092 return (gpointer) g_value_get_string (value);
1093 break;
1094 case G_TYPE_BOXED:
1095 return g_value_get_boxed (value);
1096 break;
1097 case G_TYPE_OBJECT:
1098 return g_value_get_object (value);
1099 break;
1100 default:
1101 g_assert_not_reached ();
1102 return NULL;
1103 }
1104 }
1105
1106 static void
ptrarray_iterator(GType ptrarray_type,gpointer instance,DBusGTypeSpecializedCollectionIterator iterator,gpointer user_data)1107 ptrarray_iterator (GType ptrarray_type,
1108 gpointer instance,
1109 DBusGTypeSpecializedCollectionIterator iterator,
1110 gpointer user_data)
1111 {
1112 GPtrArray *ptrarray;
1113 GType elt_gtype;
1114 guint i;
1115
1116 ptrarray = instance;
1117
1118 elt_gtype = dbus_g_type_get_collection_specialization (ptrarray_type);
1119
1120 for (i = 0; i < ptrarray->len; i++)
1121 {
1122 GValue val = {0, };
1123 g_value_init (&val, elt_gtype);
1124 gvalue_take_ptrarray_value (&val, g_ptr_array_index (ptrarray, i));
1125 iterator (&val, user_data);
1126 }
1127 }
1128
1129 static void
ptrarray_copy_elt(const GValue * val,gpointer user_data)1130 ptrarray_copy_elt (const GValue *val, gpointer user_data)
1131 {
1132 GPtrArray *dest = user_data;
1133 GValue val_copy = {0, };
1134
1135 g_value_init (&val_copy, G_VALUE_TYPE (val));
1136 g_value_copy (val, &val_copy);
1137
1138 g_ptr_array_add (dest, ptrarray_value_from_gvalue (&val_copy));
1139 }
1140
1141 static gpointer
ptrarray_copy(GType type,gpointer src)1142 ptrarray_copy (GType type, gpointer src)
1143 {
1144 GPtrArray *new;
1145 GValue array_val = {0, };
1146
1147 g_value_init (&array_val, type);
1148 g_value_set_static_boxed (&array_val, src);
1149
1150 new = ptrarray_constructor (type);
1151 dbus_g_type_collection_value_iterate (&array_val, ptrarray_copy_elt, new);
1152
1153 return new;
1154 }
1155
1156 static void
ptrarray_append(DBusGTypeSpecializedAppendContext * ctx,GValue * value)1157 ptrarray_append (DBusGTypeSpecializedAppendContext *ctx, GValue *value)
1158 {
1159 GPtrArray *array;
1160
1161 array = g_value_get_boxed (ctx->val);
1162
1163 g_ptr_array_add (array, ptrarray_value_from_gvalue (value));
1164 }
1165
1166 static void
ptrarray_free(GType type,gpointer val)1167 ptrarray_free (GType type, gpointer val)
1168 {
1169 GPtrArray *array;
1170 GValue elt_val = {0, };
1171 GType elt_gtype;
1172 unsigned int i;
1173
1174 array = val;
1175
1176 elt_gtype = dbus_g_type_get_collection_specialization (type);
1177
1178 for (i = 0; i < array->len; i++)
1179 {
1180 g_value_init (&elt_val, elt_gtype);
1181 gvalue_take_ptrarray_value (&elt_val, g_ptr_array_index (array, i));
1182 g_value_unset (&elt_val);
1183 }
1184
1185 g_ptr_array_free (array, TRUE);
1186 }
1187
1188 static gpointer
slist_constructor(GType type)1189 slist_constructor (GType type)
1190 {
1191 return NULL;
1192 }
1193
1194 static void
slist_iterator(GType list_type,gpointer instance,DBusGTypeSpecializedCollectionIterator iterator,gpointer user_data)1195 slist_iterator (GType list_type,
1196 gpointer instance,
1197 DBusGTypeSpecializedCollectionIterator iterator,
1198 gpointer user_data)
1199 {
1200 GSList *slist;
1201 GType elt_gtype;
1202
1203 slist = instance;
1204
1205 elt_gtype = dbus_g_type_get_collection_specialization (list_type);
1206
1207 for (slist = instance; slist != NULL; slist = slist->next)
1208 {
1209 GValue val = {0, };
1210 g_value_init (&val, elt_gtype);
1211 gvalue_take_ptrarray_value (&val, slist->data);
1212 iterator (&val, user_data);
1213 }
1214 }
1215
1216 static void
slist_copy_elt(const GValue * val,gpointer user_data)1217 slist_copy_elt (const GValue *val, gpointer user_data)
1218 {
1219 GSList **dest = user_data;
1220 GValue val_copy = {0, };
1221
1222 g_value_init (&val_copy, G_VALUE_TYPE (val));
1223 g_value_copy (val, &val_copy);
1224
1225 *dest = g_slist_append (*dest, ptrarray_value_from_gvalue (&val_copy));
1226 }
1227
1228 static gpointer
slist_copy(GType type,gpointer src)1229 slist_copy (GType type, gpointer src)
1230 {
1231 GSList *new;
1232 GValue slist_val = {0, };
1233
1234 g_value_init (&slist_val, type);
1235 g_value_set_static_boxed (&slist_val, src);
1236
1237 new = slist_constructor (type);
1238 dbus_g_type_collection_value_iterate (&slist_val, slist_copy_elt, &new);
1239
1240 return new;
1241 }
1242
1243 static void
slist_append(DBusGTypeSpecializedAppendContext * ctx,GValue * value)1244 slist_append (DBusGTypeSpecializedAppendContext *ctx, GValue *value)
1245 {
1246 GSList *list;
1247
1248 list = g_value_get_boxed (ctx->val);
1249 list = g_slist_prepend (list, ptrarray_value_from_gvalue (value));
1250 g_value_set_static_boxed (ctx->val, list);
1251 }
1252
1253 static void
slist_end_append(DBusGTypeSpecializedAppendContext * ctx)1254 slist_end_append (DBusGTypeSpecializedAppendContext *ctx)
1255 {
1256 GSList *list;
1257
1258 /* if you append multiple times to the slist, this will reverse the existing
1259 * elements... we need an init_append function */
1260 list = g_value_get_boxed (ctx->val);
1261 list = g_slist_reverse (list);
1262
1263 g_value_take_boxed (ctx->val, list);
1264 }
1265
1266 static void
slist_free(GType type,gpointer val)1267 slist_free (GType type, gpointer val)
1268 {
1269 GSList *list;
1270 GType elt_gtype;
1271 list = val;
1272
1273 elt_gtype = dbus_g_type_get_collection_specialization (type);
1274
1275 while (list != NULL)
1276 {
1277 GValue elt_val = {0, };
1278 g_value_init (&elt_val, elt_gtype);
1279 gvalue_take_ptrarray_value (&elt_val, list->data);
1280 g_value_unset (&elt_val);
1281 list = g_slist_next(list);
1282 }
1283 list=val;
1284 g_slist_free (list);
1285 }
1286
1287 void
_dbus_g_type_specialized_builtins_init(void)1288 _dbus_g_type_specialized_builtins_init (void)
1289 {
1290 /* types with a simple_free function can be freed at run-time without
1291 * the destroy function needing to know the type, so they can be
1292 * stored in hash tables */
1293
1294 static const DBusGTypeSpecializedCollectionVtable array_vtable = {
1295 {
1296 array_constructor,
1297 NULL,
1298 array_copy,
1299 array_simple_free,
1300 NULL,
1301 NULL,
1302 },
1303 array_fixed_accessor,
1304 array_iterator,
1305 array_append,
1306 NULL
1307 };
1308
1309
1310 static const DBusGTypeSpecializedCollectionVtable ptrarray_vtable = {
1311 {
1312 ptrarray_constructor,
1313 ptrarray_free,
1314 ptrarray_copy,
1315 NULL,
1316 NULL,
1317 NULL,
1318 },
1319 NULL,
1320 ptrarray_iterator,
1321 ptrarray_append,
1322 NULL,
1323 };
1324
1325
1326 static const DBusGTypeSpecializedCollectionVtable slist_vtable = {
1327 {
1328 slist_constructor,
1329 slist_free,
1330 slist_copy,
1331 NULL,
1332 NULL,
1333 NULL,
1334 },
1335 NULL,
1336 slist_iterator,
1337 slist_append,
1338 slist_end_append,
1339 };
1340
1341 static const DBusGTypeSpecializedMapVtable hashtable_vtable = {
1342 {
1343 hashtable_constructor,
1344 hashtable_free,
1345 hashtable_copy,
1346 hashtable_simple_free,
1347 NULL,
1348 NULL
1349 },
1350 hashtable_iterator,
1351 hashtable_append
1352 };
1353
1354 static const DBusGTypeSpecializedStructVtable valuearray_vtable = {
1355 {
1356 valuearray_constructor,
1357 NULL,
1358 valuearray_copy,
1359 valuearray_simple_free,
1360 NULL,
1361 NULL
1362 },
1363 valuearray_get_member,
1364 valuearray_set_member
1365 };
1366
1367 _dbus_g_type_register_collection ("GSList", &slist_vtable, 0);
1368 _dbus_g_type_register_collection ("GArray", &array_vtable, 0);
1369 _dbus_g_type_register_collection ("GPtrArray", &ptrarray_vtable, 0);
1370 _dbus_g_type_register_map ("GHashTable", &hashtable_vtable, 0);
1371 _dbus_g_type_register_struct ("GValueArray", &valuearray_vtable, 0);
1372 }
1373