1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-gtype-specialized.c: Non-DBus-specific functions for specialized GTypes
3 *
4 * Copyright (C) 2005 Red Hat, Inc.
5 * Copyright (C) 2007 Codethink Ltd.
6 *
7 * SPDX-License-Identifier: AFL-2.1 OR GPL-2.0-or-later
8 *
9 * Licensed under the Academic Free License version 2.1
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24 *
25 */
26
27 #include <config.h>
28
29 #include "dbus-glib.h"
30 #include "dbus-gtype-specialized-priv.h"
31 #include "dbus-gvalue-utils.h"
32 #include <glib.h>
33 #include <string.h>
34 #include <gobject/gvaluecollector.h>
35
36 /**
37 * SECTION:dbus-gtype-specialized
38 * @title: Specializable GType System
39 * @short_description: Specialized GTypes
40 * @stability: Unstable
41 *
42 * Specialized gtypes are basically a way to allow the definition of
43 * recursive #GTypes. It allows the definition of 'containers' which is
44 * basically a user defined structure capable of holding other data, and a
45 * set of functions defining how to access that structure. Containers come in
46 * 3 flavors: collections, maps and structs.
47 *
48 * A collection is a container that holds an ordered set of items, all
49 * of which must be the same type. (This is an <emphasis>array</emphasis>
50 * in standard D-Bus terminology.) dbus-glib specialized collections can be
51 * #GArray (for numeric elements), #GPtrArray (for string, object or
52 * boxed elements), #GSList (for boxed elements, not recommended), or a
53 * user-defined type.
54 *
55 * A map is a container that holds a set of key/value pairs.
56 * The keys have one type, and the values another; the type of the keys
57 * must be a numeric or string-like type. (This is a <emphasis>dict</emphasis>
58 * (dictionary) or <emphasis>array of dict entry</emphasis> in standard D-Bus
59 * terminology.) dbus-glib specialized maps can be #GHashTable or a
60 * user-defined type.
61 *
62 * A struct is a container that holds a fixed number of members, each member
63 * having a predefined type. (This is a <emphasis>struct</emphasis> in
64 * standard D-Bus terminology.) It is analogous to the C @struct keyword, but
65 * dbus-glib does not generally represent D-Bus structs in C structs.
66 * dbus-glib specialized structs can be #GValueArray or a user-defined type.
67 *
68 * A specialization is a GType detailing a particular container with
69 * particular types (a type specialization).
70 *
71 * Functions are provided for constructing and manipulating specializations.
72 *
73 * This documentation needs splitting into two pages, one for defining new
74 * containers and using existing containers. I expect most users to only do
75 * the latter. I also need to add some examples.
76 *
77 * Deprecated: New code should use GDBus instead. The closest equivalent
78 * is #GVariant, which is much better-designed.
79 */
80
81 /**
82 * DBUS_TYPE_G_BOOLEAN_ARRAY:
83 *
84 * Expands to a function call returning the #GType of a #GArray of #gboolean
85 * (corresponding to the D-Bus signature "ab").
86 *
87 * Deprecated: New code should use GDBus instead. The closest equivalent
88 * is `G_VARIANT_TYPE ("ab")`.
89 */
90
91 /**
92 * DBUS_TYPE_G_INT_ARRAY:
93 *
94 * Expands to a function call returning the #GType of a #GArray of #gint
95 * (corresponding to the D-Bus signature "ai").
96 *
97 * Deprecated: New code should use GDBus instead. The closest equivalent
98 * is `G_VARIANT_TYPE ("ai")`.
99 */
100
101 /**
102 * DBUS_TYPE_G_UINT_ARRAY:
103 *
104 * Expands to a function call returning the #GType of a #GArray of #guint
105 * (corresponding to the D-Bus signature "au").
106 *
107 * Deprecated: New code should use GDBus instead. The closest equivalent
108 * is `G_VARIANT_TYPE ("au")`.
109 */
110
111 /**
112 * DBUS_TYPE_G_INT64_ARRAY:
113 *
114 * Expands to a function call returning the #GType of a #GArray of #gint64
115 * (corresponding to the D-Bus signature "ax").
116 *
117 * Deprecated: New code should use GDBus instead. The closest equivalent
118 * is `G_VARIANT_TYPE ("ax")`.
119 */
120
121 /**
122 * DBUS_TYPE_G_UINT64_ARRAY:
123 *
124 * Expands to a function call returning the #GType of a #GArray of #guint64
125 * (corresponding to the D-Bus signature "at").
126 *
127 * Deprecated: New code should use GDBus instead. The closest equivalent
128 * is `G_VARIANT_TYPE ("at")`.
129 */
130
131 /**
132 * DBUS_TYPE_G_UCHAR_ARRAY:
133 *
134 * Expands to a function call returning the #GType of a #GArray of #guchar
135 * (corresponding to the D-Bus signature "ay").
136 *
137 * Note that this is not the same thing as a #GByteArray! dbus-glib does not
138 * know about the #GByteArray type.
139 *
140 * Deprecated: New code should use GDBus instead. The closest equivalent
141 * is %G_VARIANT_TYPE_BYTESTRING.
142 */
143
144 /**
145 * DBUS_TYPE_G_OBJECT_ARRAY:
146 *
147 * Expands to a function call returning the #GType of a #GPtrArray of #GObject.
148 *
149 * Use this type with caution: it can sometimes be used as a representation
150 * of arrays whose D-Bus signature is "ao" (transferred as an array of object
151 * paths), but the conventional type for such arrays is
152 * <literal>(dbus_g_type_get_collection ("GPtrArray",
153 * DBUS_TYPE_G_OBJECT_PATH))</literal>.
154 *
155 * Deprecated: New code should use GDBus instead. The closest equivalent
156 * is %G_VARIANT_TYPE_OBJECT_PATH_ARRAY.
157 */
158
159 /**
160 * DBUS_TYPE_G_STRING_STRING_HASHTABLE:
161 *
162 * Expands to a function call returning the #GType of a #GHashTable where the
163 * keys are strings and the values are also strings (corresponding to the
164 * D-Bus signature "a{ss}").
165 *
166 * Deprecated: New code should use GDBus instead. The closest equivalent
167 * is `G_VARIANT_TYPE ("a{ss}")`.
168 */
169
170 /**
171 * DBusGTypeSpecializedVtable:
172 * @constructor: returns a new, blank instance of the @type
173 * @free_func: if not %NULL, frees the @type instance @val
174 * @copy_func: returns a "deep copy" of the @type instance @val
175 * @simple_free_func: if not %NULL, frees its argument
176 *
177 * A table of methods used to implement specialized container behaviour on
178 * user-defined collections, maps and structs. Exactly one of @free_func and
179 * @simple_free_func must be implemented; the other must be %NULL.
180 * @constructor and @copy_func must always be implemented.
181 *
182 * There are additional members, which are reserved for future expansion and
183 * must be %NULL.
184 *
185 * Deprecated: New code should use GDBus instead.
186 */
187
188 /**
189 * DBusGTypeSpecializedConstructor:
190 * @type: a specialized boxed type
191 *
192 * <!-- -->
193 *
194 * Returns: a new instance of @type
195 *
196 * Deprecated: New code should use GDBus instead.
197 */
198
199 /**
200 * DBusGTypeSpecializedFreeFunc:
201 * @type: a specialized boxed type
202 * @val: an instance of @type
203 *
204 * Frees @val according to @type. This is analogous to #GBoxedFreeFunc, but
205 * can use information from @type (for instance to free the contents of a
206 * container before freeing the actual container).
207 *
208 * Deprecated: New code should use GDBus instead.
209 */
210
211 /**
212 * DBusGTypeSpecializedCopyFunc:
213 * @type: a specialized boxed type
214 * @src: an instance of @type
215 *
216 * Copies @src according to @type. This is analogous to #GBoxedCopyFunc, but
217 * can use information from @type (for instance to copy each element of a
218 * collection).
219 *
220 * Returns: a deep copy of @src
221 *
222 * Deprecated: New code should use GDBus instead.
223 */
224
225 /**
226 * DBusGTypeSpecializedCollectionFixedAccessorFunc:
227 * @type: a specialized collection boxed type
228 * @instance: an instance of @type
229 * @values: used to return a pointer to the contents of @instance
230 * @len: used to return the number of elements in @instance
231 *
232 * Implements dbus_g_type_collection_get_fixed() for a #GValue with type
233 * @type, containing @instance.
234 *
235 * Returns: %TRUE on success
236 *
237 * Deprecated: New code should use GDBus instead.
238 */
239
240 /**
241 * DBusGTypeSpecializedCollectionIterator:
242 * @value: an element of the collection
243 * @user_data: the data supplied when calling
244 * dbus_g_type_collection_value_iterate()
245 *
246 * A library-user-supplied function, called for each element in the
247 * collection when dbus_g_type_collection_value_iterate() is called.
248 *
249 * Deprecated: New code should use GDBus instead.
250 */
251
252 /**
253 * DBusGTypeSpecializedCollectionIteratorFunc:
254 * @type: a specialized collection boxed type
255 * @instance: an instance of @type
256 * @iterator: the function to call for each element
257 * @user_data: data to pass to @iterator
258 *
259 * Implements dbus_g_type_collection_value_iterate() for a #GValue with
260 * type @type, containing @instance.
261 *
262 * Deprecated: New code should use GDBus instead.
263 */
264
265 /**
266 * DBusGTypeSpecializedCollectionAppendFunc:
267 * @ctx: an appending context returned by dbus_g_type_specialized_init_append()
268 * @val: a value to copy into the collection
269 *
270 * Implements dbus_g_type_specialized_collection_append().
271 *
272 * This function should use the @val and @specialization_type members of @ctx.
273 *
274 * Deprecated: New code should use GDBus instead.
275 */
276
277 /**
278 * DBusGTypeSpecializedCollectionEndAppendFunc:
279 * @ctx: an appending context returned by dbus_g_type_specialized_init_append()
280 *
281 * Implements dbus_g_type_specialized_collection_end_append().
282 *
283 * This function should use the @val and @specialization_type members of @ctx.
284 *
285 * Deprecated: New code should use GDBus instead.
286 */
287
288 /**
289 * DBusGTypeSpecializedCollectionVtable:
290 * @base_vtable: base methods shared between collections and other types
291 * @fixed_accessor: if not %NULL, provides access to the contents of this
292 * collection, as documented for dbus_g_type_collection_get_fixed()
293 * @iterator: iterates through the members of @instance
294 * @append_func: appends a new member to @instance
295 * @end_append_func: if not %NULL, called after each group of calls to
296 * the @append_func
297 *
298 * A table of methods used to implement specialized collection behaviour
299 * on user-defined types. At least @iterator and @append_func must be
300 * implemented.
301 *
302 * Deprecated: New code should use GDBus instead.
303 */
304
305 /**
306 * DBusGTypeSpecializedMapIterator:
307 * @key_val: a key from the map
308 * @value_val: a value from the map
309 * @user_data: the data supplied when calling
310 * dbus_g_type_map_value_iterate()
311 *
312 * A library-user-supplied function, called for each key/value pair in the
313 * collection when dbus_g_type_map_value_iterate() is called.
314 *
315 * Deprecated: New code should use GDBus instead.
316 */
317
318 /**
319 * DBusGTypeSpecializedMapIteratorFunc:
320 * @type: a specialized map boxed type
321 * @instance: an instance of @type
322 * @iterator: the function to call for each key/value pair
323 * @user_data: data to pass to @iterator
324 *
325 * Implements dbus_g_type_map_value_iterate() for a #GValue with
326 * type @type, containing @instance.
327 *
328 * Deprecated: New code should use GDBus instead.
329 */
330
331 /**
332 * DBusGTypeSpecializedMapAppendFunc:
333 * @ctx: an appending context returned by dbus_g_type_specialized_init_append()
334 * @key: a key to add to the collection
335 * @val: a value to add to the collection
336 *
337 * Implements dbus_g_type_specialized_map_append().
338 *
339 * This function should use the @val and @specialization_type members of @ctx,
340 * and replace any existing value with key equal to @key.
341 *
342 * Deprecated: New code should use GDBus instead.
343 */
344
345 /**
346 * DBusGTypeSpecializedMapVtable:
347 * @base_vtable: base methods shared between maps and other types
348 * @iterator: iterates through the members of @instance
349 * @append_func: adds a new key/value pair to @instance
350 *
351 * A table of methods used to implement specialized collection behaviour
352 * on user-defined types. Both methods must be implemented.
353 *
354 * Deprecated: New code should use GDBus instead.
355 */
356
357 /**
358 * DBusGTypeSpecializedStructGetMember:
359 * @type: a specialized struct boxed type
360 * @instance: an instance of @type
361 * @member: the index of the member, starting from 0
362 * @ret_value: an initialized #GValue of the appropriate type for the given
363 * member of @type
364 *
365 * Implements dbus_g_type_struct_get_member() for a #GValue with type @type,
366 * containing @instance.
367 *
368 * Returns: %TRUE on success
369 *
370 * Deprecated: New code should use GDBus instead.
371 */
372
373 /**
374 * DBusGTypeSpecializedStructSetMember:
375 * @type: a specialized struct boxed type
376 * @instance: an instance of @type
377 * @member: the index of the member, starting from 0
378 * @new_value: an initialized #GValue of the appropriate type for the given
379 * member of @type
380 *
381 * Implements dbus_g_type_struct_set_member() for a #GValue with type @type,
382 * containing @instance.
383 *
384 * Returns: %TRUE on success
385 *
386 * Deprecated: New code should use GDBus instead.
387 */
388
389 /**
390 * DBusGTypeSpecializedStructVtable:
391 * @base_vtable: base methods shared between maps and other types
392 * @get_member: returns a member by its index
393 * @set_member: sets a member by its index
394 *
395 * A table of methods used to implement specialized collection behaviour
396 * on user-defined types. Both methods must be implemented.
397 *
398 * Deprecated: New code should use GDBus instead.
399 */
400
401 typedef enum {
402 DBUS_G_SPECTYPE_COLLECTION,
403 DBUS_G_SPECTYPE_MAP,
404 DBUS_G_SPECTYPE_STRUCT
405 } DBusGTypeSpecializedType;
406
407 typedef struct {
408 DBusGTypeSpecializedType type;
409 const DBusGTypeSpecializedVtable *vtable;
410 } DBusGTypeSpecializedContainer;
411
412 typedef struct {
413 guint num_types;
414 GType *types;
415 const DBusGTypeSpecializedContainer *klass;
416 } DBusGTypeSpecializedData;
417
418 static GHashTable /* char * -> data* */ *specialized_containers;
419
420 static GQuark
specialized_type_data_quark()421 specialized_type_data_quark ()
422 {
423 static GQuark quark;
424 if (!quark)
425 quark = g_quark_from_static_string ("DBusGTypeSpecializedData");
426
427 return quark;
428 }
429
430 static gpointer
specialized_init(gpointer arg G_GNUC_UNUSED)431 specialized_init (gpointer arg G_GNUC_UNUSED)
432 {
433 g_assert (specialized_containers == NULL);
434
435 specialized_containers = g_hash_table_new_full (g_str_hash, g_str_equal,
436 g_free, NULL);
437
438 _dbus_g_type_specialized_builtins_init ();
439 return NULL;
440 }
441
442 /**
443 * dbus_g_type_specialized_init:
444 *
445 * Initialize dbus-glib specialized #GType<!-- -->s.
446 *
447 * In older versions of dbus-glib, it was necessary to do this before
448 * instantiating or registering any specialized type. It is now done
449 * automatically whenever necessary.
450 *
451 * Deprecated: New code should use GDBus instead.
452 */
453 void
dbus_g_type_specialized_init(void)454 dbus_g_type_specialized_init (void)
455 {
456 static GOnce once = G_ONCE_INIT;
457
458 g_once (&once, specialized_init, NULL);
459 }
460
461 static DBusGTypeSpecializedData *
lookup_specialization_data(GType type)462 lookup_specialization_data (GType type)
463 {
464 return g_type_get_qdata (type, specialized_type_data_quark ());
465 }
466
467
468 /* Copied from gboxed.c */
469 static void
proxy_value_init(GValue * value)470 proxy_value_init (GValue *value)
471 {
472 value->data[0].v_pointer = NULL;
473 }
474
475 /* Adapted from gboxed.c */
476 static void
proxy_value_free(GValue * value)477 proxy_value_free (GValue *value)
478 {
479 if (value->data[0].v_pointer && !(value->data[1].v_uint & G_VALUE_NOCOPY_CONTENTS))
480 {
481 DBusGTypeSpecializedData *data;
482 GType type;
483
484 type = G_VALUE_TYPE (value);
485 data = lookup_specialization_data (type);
486 g_assert (data != NULL);
487
488 if (data->klass->vtable->free_func)
489 {
490 data->klass->vtable->free_func (type, value->data[0].v_pointer);
491 }
492 else
493 {
494 g_assert (data->klass->vtable->simple_free_func != NULL);
495 data->klass->vtable->simple_free_func (value->data[0].v_pointer);
496 }
497 }
498 }
499
500 /* Adapted from gboxed.c */
501 static void
proxy_value_copy(const GValue * src_value,GValue * dest_value)502 proxy_value_copy (const GValue *src_value,
503 GValue *dest_value)
504 {
505 if (src_value->data[0].v_pointer)
506 {
507 DBusGTypeSpecializedData *data;
508 GType type;
509 type = G_VALUE_TYPE (src_value);
510 data = lookup_specialization_data (type);
511 g_assert (data != NULL);
512 dest_value->data[0].v_pointer = data->klass->vtable->copy_func (type, src_value->data[0].v_pointer);
513 }
514 else
515 dest_value->data[0].v_pointer = src_value->data[0].v_pointer;
516 }
517
518 /* Copied from gboxed.c */
519 static gpointer
proxy_value_peek_pointer(const GValue * value)520 proxy_value_peek_pointer (const GValue *value)
521 {
522 return value->data[0].v_pointer;
523 }
524
525 /* Adapted from gboxed.c */
526 static gchar*
proxy_collect_value(GValue * value,guint n_collect_values,GTypeCValue * collect_values,guint collect_flags)527 proxy_collect_value (GValue *value,
528 guint n_collect_values,
529 GTypeCValue *collect_values,
530 guint collect_flags)
531 {
532 DBusGTypeSpecializedData *data;
533 GType type;
534
535 type = G_VALUE_TYPE (value);
536 data = lookup_specialization_data (type);
537
538 if (!collect_values[0].v_pointer)
539 value->data[0].v_pointer = NULL;
540 else
541 {
542 if (collect_flags & G_VALUE_NOCOPY_CONTENTS)
543 {
544 value->data[0].v_pointer = collect_values[0].v_pointer;
545 value->data[1].v_uint = G_VALUE_NOCOPY_CONTENTS;
546 }
547 else
548 {
549 value->data[0].v_pointer = data->klass->vtable->copy_func (type, collect_values[0].v_pointer);
550 }
551 }
552
553 return NULL;
554 }
555
556 /* Adapted from gboxed.c */
557 static gchar*
proxy_lcopy_value(const GValue * value,guint n_collect_values,GTypeCValue * collect_values,guint collect_flags)558 proxy_lcopy_value (const GValue *value,
559 guint n_collect_values,
560 GTypeCValue *collect_values,
561 guint collect_flags)
562 {
563 gpointer *boxed_p = collect_values[0].v_pointer;
564
565 if (!boxed_p)
566 return g_strdup_printf ("value location for `%s' passed as NULL", G_VALUE_TYPE_NAME (value));
567
568 if (!value->data[0].v_pointer)
569 *boxed_p = NULL;
570 else if (collect_flags & G_VALUE_NOCOPY_CONTENTS)
571 *boxed_p = value->data[0].v_pointer;
572 else
573 {
574 DBusGTypeSpecializedData *data;
575 GType type;
576
577 type = G_VALUE_TYPE (value);
578 data = lookup_specialization_data (type);
579
580 *boxed_p = data->klass->vtable->copy_func (type, value->data[0].v_pointer);
581 }
582
583 return NULL;
584 }
585
586 static char *
build_specialization_name(const char * prefix,guint num_types,const GType * types)587 build_specialization_name (const char *prefix, guint num_types, const GType *types)
588 {
589 GString *fullname;
590 guint i;
591
592 fullname = g_string_new (prefix);
593
594 g_string_append_c (fullname, '_');
595 for (i=0; i < num_types; i++)
596 {
597 if (i!=0)
598 g_string_append_c (fullname, '+');
599 g_string_append (fullname, g_type_name (types[i]));
600 }
601 g_string_append_c (fullname, '_');
602 return g_string_free (fullname, FALSE);
603 }
604
605 static void
register_container(const char * name,DBusGTypeSpecializedType type,const DBusGTypeSpecializedVtable * vtable)606 register_container (const char *name,
607 DBusGTypeSpecializedType type,
608 const DBusGTypeSpecializedVtable *vtable)
609 {
610 DBusGTypeSpecializedContainer *klass;
611
612 g_warn_if_fail (vtable->constructor != NULL);
613 /* must have either free_func or simple_free_func */
614 g_warn_if_fail (vtable->free_func != NULL ||
615 vtable->simple_free_func != NULL);
616 g_warn_if_fail (vtable->copy_func != NULL);
617
618 klass = g_new0 (DBusGTypeSpecializedContainer, 1);
619 klass->type = type;
620 klass->vtable = vtable;
621
622 g_hash_table_insert (specialized_containers, g_strdup (name), klass);
623 }
624
625 /**
626 * dbus_g_type_register_collection:
627 * @name: The name of a new collection container
628 * @vtable: the vtable defining the new container
629 * @flags: As yet unused.
630 *
631 * Defines a new collection container.
632 *
633 * Deprecated: New code should use GDBus instead.
634 */
635 void
dbus_g_type_register_collection(const char * name,const DBusGTypeSpecializedCollectionVtable * vtable,guint flags)636 dbus_g_type_register_collection (const char *name,
637 const DBusGTypeSpecializedCollectionVtable *vtable,
638 guint flags)
639 {
640 dbus_g_type_specialized_init();
641
642 _dbus_g_type_register_collection (name, vtable, flags);
643 }
644
645 void
_dbus_g_type_register_collection(const char * name,const DBusGTypeSpecializedCollectionVtable * vtable,guint flags)646 _dbus_g_type_register_collection (const char *name,
647 const DBusGTypeSpecializedCollectionVtable *vtable,
648 guint flags)
649 {
650 /* fixed_accessor is optional */
651 g_warn_if_fail (vtable->iterator != NULL);
652 g_warn_if_fail (vtable->append_func != NULL);
653 /* end_append_func is optional */
654
655 register_container (name, DBUS_G_SPECTYPE_COLLECTION, (const DBusGTypeSpecializedVtable*) vtable);
656 }
657
658 /**
659 * dbus_g_type_register_map:
660 * @name: The name of a new map container
661 * @vtable: the vtable defining the new container
662 * @flags: As yet unused.
663 *
664 * Defines a new map container.
665 *
666 * Deprecated: New code should use GDBus instead.
667 */
668 void
dbus_g_type_register_map(const char * name,const DBusGTypeSpecializedMapVtable * vtable,guint flags)669 dbus_g_type_register_map (const char *name,
670 const DBusGTypeSpecializedMapVtable *vtable,
671 guint flags)
672 {
673 dbus_g_type_specialized_init();
674
675 _dbus_g_type_register_map (name, vtable, flags);
676 }
677
678 void
_dbus_g_type_register_map(const char * name,const DBusGTypeSpecializedMapVtable * vtable,guint flags)679 _dbus_g_type_register_map (const char *name,
680 const DBusGTypeSpecializedMapVtable *vtable,
681 guint flags)
682 {
683 g_warn_if_fail (vtable->iterator != NULL);
684 g_warn_if_fail (vtable->append_func != NULL);
685
686 register_container (name, DBUS_G_SPECTYPE_MAP, (const DBusGTypeSpecializedVtable*) vtable);
687 }
688
689 /**
690 * dbus_g_type_register_struct:
691 * @name: The name of a new struct container
692 * @vtable: the vtable defining the new container
693 * @flags: As yet unused.
694 *
695 * Defines a new struct container.
696 *
697 * Deprecated: New code should use GDBus instead.
698 */
699 void
dbus_g_type_register_struct(const char * name,const DBusGTypeSpecializedStructVtable * vtable,guint flags)700 dbus_g_type_register_struct (const char *name,
701 const DBusGTypeSpecializedStructVtable *vtable,
702 guint flags)
703 {
704 dbus_g_type_specialized_init();
705
706 _dbus_g_type_register_struct (name, vtable, flags);
707 }
708
709 void
_dbus_g_type_register_struct(const char * name,const DBusGTypeSpecializedStructVtable * vtable,guint flags)710 _dbus_g_type_register_struct (const char *name,
711 const DBusGTypeSpecializedStructVtable *vtable,
712 guint flags)
713 {
714 g_warn_if_fail (vtable->get_member != NULL);
715 g_warn_if_fail (vtable->set_member != NULL);
716
717 register_container (name, DBUS_G_SPECTYPE_STRUCT, (const DBusGTypeSpecializedVtable*) vtable);
718 }
719
720 /**
721 * dbus_g_type_map_peek_vtable:
722 * @map_type: a gtype of a map specialization
723 *
724 * Peek the vtable for a given map specialization
725 *
726 * Returns: the vtable
727 *
728 * Deprecated: New code should use GDBus instead.
729 */
dbus_g_type_map_peek_vtable(GType map_type)730 const DBusGTypeSpecializedMapVtable* dbus_g_type_map_peek_vtable (GType map_type)
731 {
732 DBusGTypeSpecializedData *data;
733 g_return_val_if_fail (dbus_g_type_is_map(map_type), NULL);
734
735 data = lookup_specialization_data (map_type);
736 g_assert (data != NULL);
737
738 return (DBusGTypeSpecializedMapVtable *)(data->klass->vtable);
739 }
740
741 /**
742 * dbus_g_type_collection_peek_vtable:
743 * @collection_type: a gtype of a collection specialization
744 *
745 * Peek the vtable for a given collection specialization
746 *
747 * Returns: the vtable
748 *
749 * Deprecated: New code should use GDBus instead.
750 */
dbus_g_type_collection_peek_vtable(GType collection_type)751 const DBusGTypeSpecializedCollectionVtable* dbus_g_type_collection_peek_vtable (GType collection_type)
752 {
753 DBusGTypeSpecializedData *data;
754 g_return_val_if_fail (dbus_g_type_is_collection(collection_type), NULL);
755
756 data = lookup_specialization_data (collection_type);
757 g_assert (data != NULL);
758
759 return (DBusGTypeSpecializedCollectionVtable *)(data->klass->vtable);
760 }
761
762 /**
763 * dbus_g_type_struct_peek_vtable:
764 * @struct_type: a gtype of a struct specialization
765 *
766 * Peek the vtable for a given struct specialization
767 *
768 * Returns: the vtable
769 *
770 * Deprecated: New code should use GDBus instead.
771 */
dbus_g_type_struct_peek_vtable(GType struct_type)772 const DBusGTypeSpecializedStructVtable* dbus_g_type_struct_peek_vtable (GType struct_type)
773 {
774 DBusGTypeSpecializedData *data;
775 g_return_val_if_fail (dbus_g_type_is_struct (struct_type), NULL);
776
777 data = lookup_specialization_data (struct_type);
778 g_assert (data != NULL);
779
780 return (DBusGTypeSpecializedStructVtable *)(data->klass->vtable);
781 }
782
783 static GType
register_specialized_instance(const DBusGTypeSpecializedContainer * klass,const char * name,guint num_types,const GType * types)784 register_specialized_instance (const DBusGTypeSpecializedContainer *klass,
785 const char *name,
786 guint num_types,
787 const GType *types)
788 {
789 GType ret;
790
791 static const GTypeValueTable vtable =
792 {
793 proxy_value_init,
794 proxy_value_free,
795 proxy_value_copy,
796 proxy_value_peek_pointer,
797 "p",
798 proxy_collect_value,
799 "p",
800 proxy_lcopy_value,
801 };
802 static const GTypeInfo derived_info =
803 {
804 0, /* class_size */
805 NULL, /* base_init */
806 NULL, /* base_finalize */
807 NULL, /* class_init */
808 NULL, /* class_finalize */
809 NULL, /* class_data */
810 0, /* instance_size */
811 0, /* n_preallocs */
812 NULL, /* instance_init */
813 &vtable, /* value_table */
814 };
815
816 ret = g_type_register_static (G_TYPE_BOXED, name, &derived_info, 0);
817 /* install proxy functions upon successfull registration */
818 if (ret != G_TYPE_INVALID)
819 {
820 DBusGTypeSpecializedData *data;
821 data = g_new0 (DBusGTypeSpecializedData, 1);
822 data->num_types = num_types;
823 data->types = g_memdup (types, sizeof (GType) * num_types);
824 data->klass = klass;
825 g_type_set_qdata (ret, specialized_type_data_quark (), data);
826 }
827
828 return ret;
829 }
830
831 static GType
lookup_or_register_specialized(const char * container,guint num_types,const GType * types)832 lookup_or_register_specialized (const char *container,
833 guint num_types,
834 const GType *types)
835 {
836 GType ret;
837 char *name;
838 const DBusGTypeSpecializedContainer *klass;
839
840 dbus_g_type_specialized_init();
841
842 klass = g_hash_table_lookup (specialized_containers, container);
843 g_return_val_if_fail (klass != NULL, G_TYPE_INVALID);
844
845 name = build_specialization_name (container, num_types, types);
846 ret = g_type_from_name (name);
847 if (ret == G_TYPE_INVALID)
848 {
849 /* Take ownership of name */
850 ret = register_specialized_instance (klass, name,
851 num_types,
852 types);
853 }
854 g_free (name);
855 return ret;
856 }
857
858
859 /**
860 * dbus_g_type_get_collection:
861 * @container: a string specifying a registered collection type
862 * @specialization: #GType of collection elements
863 *
864 * Gets a #GType for a particular collection instance,
865 * creating the type if not already created.
866 *
867 * Returns: the #GType of that instance
868 *
869 * Deprecated: New code should use GDBus instead.
870 */
871 GType
dbus_g_type_get_collection(const char * container,GType specialization)872 dbus_g_type_get_collection (const char *container,
873 GType specialization)
874 {
875 return lookup_or_register_specialized (container, 1, &specialization);
876 }
877
878 /**
879 * dbus_g_type_get_map:
880 * @container: a string specifying a registered map type
881 * @key_specialization: #GType of keys
882 * @value_specialization: #GType of values
883 *
884 * Gets a #GType for a particular map instance,
885 * creating the type if not already created.
886 *
887 * Returns: the #GType of that instance
888 *
889 * Deprecated: New code should use GDBus instead.
890 */
891 GType
dbus_g_type_get_map(const char * container,GType key_specialization,GType value_specialization)892 dbus_g_type_get_map (const char *container,
893 GType key_specialization,
894 GType value_specialization)
895 {
896 GType types[2];
897 types[0] = key_specialization;
898 types[1] = value_specialization;
899 return lookup_or_register_specialized (container, 2, types);
900 }
901
902 /**
903 * dbus_g_type_get_structv:
904 * @container: a string specifying a registered struct type
905 * @num_members: number of members in the struct
906 * @types: an array specufying a GType for each struct element
907 *
908 * Gets a #GType for a particular struct instance,
909 * creating the type if not already created.
910 *
911 * Returns: the #GType of that instance
912 *
913 * Deprecated: New code should use GDBus instead.
914 */
915 GType
dbus_g_type_get_structv(const char * container,guint num_members,GType * types)916 dbus_g_type_get_structv (const char *container,
917 guint num_members,
918 GType *types)
919 {
920 return lookup_or_register_specialized (container, num_members, types);
921 }
922
923 /**
924 * dbus_g_type_get_struct:
925 * @container: a string specifying a registered struct type
926 * @first_type: #GType for the struct's first member
927 * @...: more GTypes for the struct's members, terminated by G_TYPE_INVALID
928 *
929 * Varags method to get a #GType for a particular struct instance,
930 * creating the type if not already created.
931 *
932 * Returns: the #GType of that instance
933 *
934 * Deprecated: New code should use GDBus instead.
935 */
936 GType
dbus_g_type_get_struct(const char * container,GType first_type,...)937 dbus_g_type_get_struct (const char *container,
938 GType first_type,
939 ...)
940 {
941 GArray *types;
942 GType curtype, ret;
943 va_list args;
944 va_start (args, first_type);
945
946 types = g_array_new (FALSE, FALSE, sizeof (GType));
947 curtype = first_type;
948 while (curtype != G_TYPE_INVALID)
949 {
950 g_array_append_val (types, curtype);
951 curtype = va_arg (args, GType);
952 }
953 va_end (args);
954
955 ret = lookup_or_register_specialized (container, types->len,
956 (GType *) types->data);
957
958 g_array_free (types, TRUE);
959
960 return ret;
961 }
962
963
964 /**
965 * dbus_g_type_is_collection:
966 * @gtype: a GType to test
967 *
968 * Tests if a given GType is a collection.
969 *
970 * Returns: true if the given GType is a collection
971 *
972 * Deprecated: New code should use GDBus instead.
973 */
974 gboolean
dbus_g_type_is_collection(GType gtype)975 dbus_g_type_is_collection (GType gtype)
976 {
977 DBusGTypeSpecializedData *data;
978 data = lookup_specialization_data (gtype);
979 if (data == NULL)
980 return FALSE;
981 return data->klass->type == DBUS_G_SPECTYPE_COLLECTION;
982 }
983
984 /**
985 * dbus_g_type_is_map:
986 * @gtype: a GType to test
987 *
988 * Tests if a given GType is a map,
989 * i.e. it was created with dbus_g_type_get_map().
990 *
991 * Returns: true if the given GType is a map
992 *
993 * Deprecated: New code should use GDBus instead.
994 */
995 gboolean
dbus_g_type_is_map(GType gtype)996 dbus_g_type_is_map (GType gtype)
997 {
998 DBusGTypeSpecializedData *data;
999 data = lookup_specialization_data (gtype);
1000 if (data == NULL)
1001 return FALSE;
1002 return data->klass->type == DBUS_G_SPECTYPE_MAP;
1003 }
1004
1005 /**
1006 * dbus_g_type_is_struct:
1007 * @gtype: a GType to test
1008 *
1009 * Tests if a given GType is a struct,
1010 * i.e. it was created with dbus_g_type_get_struct()
1011 *
1012 * Returns: true if the given GType is a struct
1013 *
1014 * Deprecated: New code should use GDBus instead.
1015 */
1016 gboolean
dbus_g_type_is_struct(GType gtype)1017 dbus_g_type_is_struct (GType gtype)
1018 {
1019 DBusGTypeSpecializedData *data;
1020 data = lookup_specialization_data (gtype);
1021 if (data == NULL)
1022 return FALSE;
1023 return data->klass->type == DBUS_G_SPECTYPE_STRUCT;
1024 }
1025
1026
1027 static GType
get_specialization_index(GType gtype,guint i)1028 get_specialization_index (GType gtype, guint i)
1029 {
1030 DBusGTypeSpecializedData *data;
1031
1032 data = lookup_specialization_data (gtype);
1033 if (i < data->num_types)
1034 return data->types[i];
1035 else
1036 return G_TYPE_INVALID;
1037 }
1038
1039 /**
1040 * dbus_g_type_get_collection_specialization:
1041 * @gtype: a collection #GType, as created by dbus_g_type_get_collection()
1042 *
1043 * Return the type of each element in collections of type @gtype.
1044 * It is an error to call this function on a non-collection type.
1045 *
1046 * Returns: the element type for a given collection GType.
1047 *
1048 * Deprecated: New code should use GDBus instead.
1049 */
1050 GType
dbus_g_type_get_collection_specialization(GType gtype)1051 dbus_g_type_get_collection_specialization (GType gtype)
1052 {
1053 g_return_val_if_fail (dbus_g_type_is_collection (gtype), G_TYPE_INVALID);
1054 return get_specialization_index (gtype, 0);
1055 }
1056
1057 /**
1058 * dbus_g_type_get_map_key_specialization:
1059 * @gtype: a map #GType, as created by dbus_g_type_get_map()
1060 *
1061 * Return the type of the keys in maps of type @gtype.
1062 * It is an error to call this function on a non-map type.
1063 *
1064 * Returns: the key type for a given map #GType.
1065 *
1066 * Deprecated: New code should use GDBus instead.
1067 */
1068 GType
dbus_g_type_get_map_key_specialization(GType gtype)1069 dbus_g_type_get_map_key_specialization (GType gtype)
1070 {
1071 g_return_val_if_fail (dbus_g_type_is_map (gtype), G_TYPE_INVALID);
1072 return get_specialization_index (gtype, 0);
1073 }
1074
1075 /**
1076 * dbus_g_type_get_map_value_specialization:
1077 * @gtype: a map GType, as created by dbus_g_type_get_map().
1078 *
1079 * Return the type of the values in maps of type @gtype.
1080 * It is an error to call this function on a non-map type.
1081 *
1082 * Returns: the value type for a given map GType.
1083 *
1084 * Deprecated: New code should use GDBus instead.
1085 */
1086 GType
dbus_g_type_get_map_value_specialization(GType gtype)1087 dbus_g_type_get_map_value_specialization (GType gtype)
1088 {
1089 g_return_val_if_fail (dbus_g_type_is_map (gtype), G_TYPE_INVALID);
1090 return get_specialization_index (gtype, 1);
1091 }
1092
1093 /**
1094 * dbus_g_type_get_struct_member_type
1095 * @gtype: a struct GType, as created with dbus_g_type_get_struct()
1096 * @member: the index of a struct member
1097 *
1098 * Get the type of a member of a specialized struct.
1099 * It is an error to call this function on a non-struct type.
1100 *
1101 * Returns: the type for a given member of a struct #GType,
1102 * or %G_TYPE_INVALID if @member >= dbus_g_type_get_struct_size()
1103 *
1104 * Deprecated: New code should use GDBus instead.
1105 */
1106 GType
dbus_g_type_get_struct_member_type(GType gtype,guint member)1107 dbus_g_type_get_struct_member_type (GType gtype, guint member)
1108 {
1109 g_return_val_if_fail (dbus_g_type_is_struct (gtype), G_TYPE_INVALID);
1110 return get_specialization_index (gtype, member);
1111 }
1112
1113 /**
1114 * dbus_g_type_get_struct_size
1115 * @gtype: a struct GType, as created with dbus_g_type_get_struct().
1116 *
1117 * Get the number of members in a specialized struct.
1118 * It is an error to call this function on a non-struct type.
1119 *
1120 * Returns: the number of members in a given struct #GType.
1121 *
1122 * Deprecated: New code should use GDBus instead.
1123 */
1124 guint
dbus_g_type_get_struct_size(GType gtype)1125 dbus_g_type_get_struct_size (GType gtype)
1126 {
1127 DBusGTypeSpecializedData *data;
1128 g_return_val_if_fail (dbus_g_type_is_struct (gtype), G_TYPE_INVALID);
1129
1130 data = lookup_specialization_data (gtype);
1131 return data->num_types;
1132 }
1133
1134 /**
1135 * dbus_g_type_specialized_construct:
1136 * @gtype: a specialized #GType, as created by dbus_g_type_get_collection(),
1137 * dbus_g_type_get_map() or dbus_g_type_get_struct()
1138 *
1139 * Create an instance of a given specialized type.
1140 * The structure created and returned will depend on the container type of the
1141 * GType. E.g. If the given type was created by
1142 * dbus_g_type_get_collection("GArray", G_TYPE_INT),
1143 * then this will return a GArray with element_size of sizeof(int)
1144 *
1145 * Returns: a pointer to a newly constructed instance of the given type.
1146 *
1147 * Deprecated: New code should use GDBus instead.
1148 */
1149 gpointer
dbus_g_type_specialized_construct(GType gtype)1150 dbus_g_type_specialized_construct (GType gtype)
1151 {
1152 DBusGTypeSpecializedData *data;
1153
1154 dbus_g_type_specialized_init();
1155
1156 data = lookup_specialization_data (gtype);
1157 g_return_val_if_fail (data != NULL, FALSE);
1158
1159 return data->klass->vtable->constructor (gtype);
1160 }
1161
1162 /**
1163 * dbus_g_type_collection_get_fixed:
1164 * @value: a GValue containing a boxed specialized collection
1165 * that has a @fixed_accessor in its vtable
1166 * @data_ret: used to return a pointer to the fixed data, which must not be
1167 * modified (for instance, for a #GArray of #gint, this would point
1168 * to an array of #gint)
1169 * @len_ret: used to return the length (counting collection elements, not
1170 * bytes: in a #GArray containing one #gint, this would be 1)
1171 *
1172 * Calling this function is likely to be a bad idea. Consider using
1173 * dbus_g_type_collection_value_iterate() instead.
1174 *
1175 * On success, @data_ret is a pointer to the underlying data in a collection
1176 * of fixed-length fundamental types. Knowledge of the underlying data model
1177 * of the collection is needed in order to use @data_ret correctly.
1178 *
1179 * It is an error to call this function on a specialized type that is not a
1180 * collection, or on a collection that does not have a @fixed_accessor in its
1181 * #DBusGTypeSpecializedCollectionVtable.
1182 *
1183 * Specialized #GArray<!---->s are the only types provided by dbus-glib that
1184 * can be used with this function; user-defined types might also work.
1185 *
1186 * Returns: %TRUE on success
1187 *
1188 * Deprecated: New code should use GDBus instead.
1189 */
1190 gboolean
dbus_g_type_collection_get_fixed(GValue * value,gpointer * data_ret,guint * len_ret)1191 dbus_g_type_collection_get_fixed (GValue *value,
1192 gpointer *data_ret,
1193 guint *len_ret)
1194 {
1195 DBusGTypeSpecializedData *data;
1196 DBusGTypeSpecializedCollectionVtable *vtable;
1197 GType gtype;
1198
1199 dbus_g_type_specialized_init();
1200
1201 g_return_val_if_fail (G_VALUE_HOLDS_BOXED (value), FALSE);
1202
1203 gtype = G_VALUE_TYPE (value);
1204 g_return_val_if_fail (dbus_g_type_is_collection (gtype), FALSE);
1205
1206 data = lookup_specialization_data (gtype);
1207 /* dbus_g_type_is_collection() already checked this */
1208 g_assert (data != NULL);
1209
1210 vtable = (DBusGTypeSpecializedCollectionVtable *) (data->klass->vtable);
1211 g_return_val_if_fail (vtable->fixed_accessor != NULL, FALSE);
1212
1213 return vtable->fixed_accessor (gtype, g_value_get_boxed (value),
1214 data_ret, len_ret);
1215 }
1216
1217 /**
1218 * dbus_g_type_collection_value_iterate:
1219 * @value: a #GValue holding a collection type.
1220 * @iterator: a function to call for each element
1221 * @user_data: user data to pass to the @iterator
1222 *
1223 * Calls the given function for each element of the collection.
1224 * The function is passed a #GValue containing the element and the given
1225 * @user_data parameter. The collection may not be modified while iterating over
1226 * it.
1227 *
1228 * Deprecated: New code should use GDBus instead.
1229 */
1230 void
dbus_g_type_collection_value_iterate(const GValue * value,DBusGTypeSpecializedCollectionIterator iterator,gpointer user_data)1231 dbus_g_type_collection_value_iterate (const GValue *value,
1232 DBusGTypeSpecializedCollectionIterator iterator,
1233 gpointer user_data)
1234 {
1235 DBusGTypeSpecializedData *data;
1236 GType gtype;
1237
1238 dbus_g_type_specialized_init();
1239
1240 g_return_if_fail (G_VALUE_HOLDS_BOXED (value));
1241
1242 gtype = G_VALUE_TYPE (value);
1243 g_return_if_fail (dbus_g_type_is_collection (gtype));
1244
1245 data = lookup_specialization_data (gtype);
1246 /* dbus_g_type_is_collection() already checked this */
1247 g_assert (data != NULL);
1248
1249 ((DBusGTypeSpecializedCollectionVtable *) data->klass->vtable)->iterator (gtype,
1250 g_value_get_boxed (value),
1251 iterator, user_data);
1252 }
1253
1254 /**
1255 * DBusGTypeSpecializedAppendContext:
1256 * @val: the #GValue containing the array to which you're appending
1257 * @specialization_type: the #GType of the array's elements
1258 *
1259 * A context for appending. There are more fields, which are private.
1260 *
1261 * Deprecated: New code should use GDBus instead.
1262 */
1263
1264 typedef struct {
1265 GValue *val;
1266 GType specialization_type;
1267 DBusGTypeSpecializedData *specdata;
1268 guint c;
1269 gpointer d;
1270 } DBusGTypeSpecializedAppendContextReal;
1271
1272 G_STATIC_ASSERT (sizeof (DBusGTypeSpecializedAppendContextReal) ==
1273 sizeof (DBusGTypeSpecializedAppendContext));
1274
1275 /**
1276 * dbus_g_type_specialized_init_append:
1277 * @value: a #GValue containing an instance of specialized type
1278 * @ctx: a #DBusGTypeSpecializedAppendContext in which to return a new appending context.
1279 *
1280 * Create a new context for adding elements to a collection or key/value pairs
1281 * to a map. You generally don't need or want to use this..
1282 *
1283 * Deprecated: New code should use GDBus instead.
1284 */
1285 void
dbus_g_type_specialized_init_append(GValue * value,DBusGTypeSpecializedAppendContext * ctx)1286 dbus_g_type_specialized_init_append (GValue *value, DBusGTypeSpecializedAppendContext *ctx)
1287 {
1288 DBusGTypeSpecializedAppendContextReal *realctx = (DBusGTypeSpecializedAppendContextReal *) ctx;
1289 GType gtype;
1290 DBusGTypeSpecializedData *specdata;
1291
1292 dbus_g_type_specialized_init();
1293
1294 g_return_if_fail (G_VALUE_HOLDS_BOXED (value));
1295 gtype = G_VALUE_TYPE (value);
1296 specdata = lookup_specialization_data (gtype);
1297 g_return_if_fail (specdata != NULL);
1298 g_return_if_fail (specdata->num_types != 0);
1299
1300 realctx->val = value;
1301 realctx->specialization_type = specdata->types[0];
1302 realctx->specdata = specdata;
1303 }
1304
1305 /**
1306 * dbus_g_type_specialized_collection_append:
1307 * @ctx: a context created by dbus_g_type_specialized_init_append()
1308 * for a #GValue containing a collection
1309 * @elt: a #GValue containing an element to append to the collection
1310 *
1311 * Appends a given element to the end of a collection.
1312 *
1313 * Deprecated: New code should use GDBus instead.
1314 */
1315 void
dbus_g_type_specialized_collection_append(DBusGTypeSpecializedAppendContext * ctx,GValue * elt)1316 dbus_g_type_specialized_collection_append (DBusGTypeSpecializedAppendContext *ctx,
1317 GValue *elt)
1318 {
1319 DBusGTypeSpecializedAppendContextReal *realctx = (DBusGTypeSpecializedAppendContextReal *) ctx;
1320
1321 g_return_if_fail (dbus_g_type_is_collection (G_VALUE_TYPE (ctx->val)));
1322
1323 ((DBusGTypeSpecializedCollectionVtable *) realctx->specdata->klass->vtable)->append_func (ctx, elt);
1324 }
1325
1326 /**
1327 * dbus_g_type_specialized_collection_end_append:
1328 * @ctx: a context created by dbus_g_type_specialized_init_append()
1329 * for a #GValue containing a collection
1330 *
1331 * Finish appending elements to a given collection
1332 *
1333 * Deprecated: New code should use GDBus instead.
1334 */
1335 void
dbus_g_type_specialized_collection_end_append(DBusGTypeSpecializedAppendContext * ctx)1336 dbus_g_type_specialized_collection_end_append (DBusGTypeSpecializedAppendContext *ctx)
1337 {
1338 DBusGTypeSpecializedAppendContextReal *realctx = (DBusGTypeSpecializedAppendContextReal *) ctx;
1339
1340 g_return_if_fail (dbus_g_type_is_collection (G_VALUE_TYPE (ctx->val)));
1341
1342 if (((DBusGTypeSpecializedCollectionVtable *) realctx->specdata->klass->vtable)->end_append_func != NULL)
1343 ((DBusGTypeSpecializedCollectionVtable *) realctx->specdata->klass->vtable)->end_append_func (ctx);
1344 }
1345
1346 /**
1347 * dbus_g_type_specialized_map_append:
1348 * @ctx: a context created by dbus_g_type_specialized_init_append()
1349 * for a #GValue containing a map
1350 * @key: a GValue containing a key, whose contents will be stolen by @ctx
1351 * @val: a GValue containing a value, whose contents will be stolen by @ctx
1352 *
1353 * Inserts the given key/value pair into the map instance.
1354 *
1355 * Deprecated: New code should use GDBus instead.
1356 */
1357 void
dbus_g_type_specialized_map_append(DBusGTypeSpecializedAppendContext * ctx,GValue * key,GValue * val)1358 dbus_g_type_specialized_map_append (DBusGTypeSpecializedAppendContext *ctx,
1359 GValue *key,
1360 GValue *val)
1361 {
1362 DBusGTypeSpecializedAppendContextReal *realctx = (DBusGTypeSpecializedAppendContextReal *) ctx;
1363
1364 g_return_if_fail (dbus_g_type_is_map (G_VALUE_TYPE (ctx->val)));
1365
1366 ((DBusGTypeSpecializedMapVtable *) realctx->specdata->klass->vtable)->append_func (ctx, key, val);
1367 }
1368
1369
1370 /**
1371 * dbus_g_type_map_value_iterate:
1372 * @value: a #GValue holding a specialized map
1373 * @iterator: a function to call for each element
1374 * @user_data: user data to pass to the @iterator
1375 *
1376 * Calls the given function for each key/value pair of the map.
1377 * The function is passed two GValues containing the key/value pair and the given
1378 * @user_data parameter. The map may not be modified while iterating over
1379 * it.
1380 *
1381 * Deprecated: New code should use GDBus instead.
1382 */
1383 void
dbus_g_type_map_value_iterate(const GValue * value,DBusGTypeSpecializedMapIterator iterator,gpointer user_data)1384 dbus_g_type_map_value_iterate (const GValue *value,
1385 DBusGTypeSpecializedMapIterator iterator,
1386 gpointer user_data)
1387 {
1388 DBusGTypeSpecializedData *data;
1389 GType gtype;
1390
1391 dbus_g_type_specialized_init();
1392
1393 g_return_if_fail (G_VALUE_HOLDS_BOXED (value));
1394
1395 gtype = G_VALUE_TYPE (value);
1396 g_return_if_fail (dbus_g_type_is_map (gtype));
1397
1398 data = lookup_specialization_data (gtype);
1399 /* already checked by dbus_g_type_is_map() */
1400 g_assert (data != NULL);
1401
1402 ((DBusGTypeSpecializedMapVtable *) data->klass->vtable)->iterator (gtype,
1403 g_value_get_boxed (value),
1404 iterator, user_data);
1405 }
1406
1407 /**
1408 * dbus_g_type_struct_get_member:
1409 * @value: a #GValue containing a struct instance
1410 * @member: the index of a given member
1411 * @dest: an initialised #GValue in which to return the struct member
1412 *
1413 * Fetches a given member of a given struct instance. @dest must be initialised
1414 * was the correct type for that member, e.g. as returned by
1415 * @dbus_g_type_get_struct_member_type
1416 *
1417 * Returns: %TRUE if successful
1418 *
1419 * Deprecated: New code should use GDBus instead.
1420 */
1421 gboolean
dbus_g_type_struct_get_member(const GValue * value,guint member,GValue * dest)1422 dbus_g_type_struct_get_member (const GValue *value,
1423 guint member,
1424 GValue *dest)
1425 {
1426 DBusGTypeSpecializedData *data;
1427 GType gtype;
1428
1429 dbus_g_type_specialized_init();
1430
1431 g_return_val_if_fail (G_VALUE_HOLDS_BOXED (value), FALSE);
1432
1433 gtype = G_VALUE_TYPE (value);
1434 g_return_val_if_fail (dbus_g_type_is_struct (gtype), FALSE);
1435
1436 data = lookup_specialization_data (gtype);
1437 /* already checked by dbus_g_type_is_struct() */
1438 g_assert (data != NULL);
1439
1440 return ((DBusGTypeSpecializedStructVtable *) (data->klass->vtable))->get_member(gtype,
1441 g_value_get_boxed (value),
1442 member, dest);
1443 }
1444
1445 /**
1446 * dbus_g_type_struct_set_member:
1447 * @value: a #GValue containing a struct instance
1448 * @member: the index of a given member
1449 * @src: an #GValue containing the new value for that struct member
1450 *
1451 * Sets a given member of a struct to a new value. The type of @src must match
1452 * the existing type of @member member of the struct.
1453 *
1454 * Returns: %TRUE if successful
1455 *
1456 * Deprecated: New code should use GDBus instead.
1457 */
1458 gboolean
dbus_g_type_struct_set_member(GValue * value,guint member,const GValue * src)1459 dbus_g_type_struct_set_member (GValue *value,
1460 guint member,
1461 const GValue *src)
1462 {
1463 DBusGTypeSpecializedData *data;
1464 GType gtype;
1465
1466 dbus_g_type_specialized_init();
1467
1468 g_return_val_if_fail (G_VALUE_HOLDS_BOXED (value), FALSE);
1469
1470 gtype = G_VALUE_TYPE (value);
1471 g_return_val_if_fail (dbus_g_type_is_struct (gtype), FALSE);
1472
1473 data = lookup_specialization_data (gtype);
1474 /* already checked by dbus_g_type_is_struct() */
1475 g_assert (data != NULL);
1476
1477 return ((DBusGTypeSpecializedStructVtable *) (data->klass->vtable))->set_member(gtype,
1478 g_value_get_boxed (value),
1479 member, src);
1480 }
1481
1482 /**
1483 * dbus_g_type_struct_get:
1484 * @value: a #GValue containing a struct instance
1485 * @member: struct member to get
1486 * @...: location in which to return the value of this member,
1487 * followed optionally by more member/return locations pairs, followed
1488 * by %G_MAXUINT
1489 *
1490 * Collects the selected values of this struct into the return locations
1491 * provided.
1492 *
1493 * Returns: %FALSE on failure
1494 *
1495 * Deprecated: New code should use GDBus instead.
1496 */
1497
1498 gboolean
dbus_g_type_struct_get(const GValue * value,guint first_member,...)1499 dbus_g_type_struct_get (const GValue *value,
1500 guint first_member,
1501 ...)
1502 {
1503 va_list var_args;
1504 GType type;
1505 guint size,i;
1506 gchar *error;
1507 GValue val = {0,};
1508
1509 g_return_val_if_fail (dbus_g_type_is_struct (G_VALUE_TYPE (value)), FALSE);
1510
1511 va_start (var_args, first_member);
1512 size = dbus_g_type_get_struct_size (G_VALUE_TYPE (value));
1513 i = first_member;
1514 while (i != G_MAXUINT)
1515 {
1516 if (i >= size)
1517 goto error;
1518
1519 type = dbus_g_type_get_struct_member_type (G_VALUE_TYPE (value),i);
1520
1521 g_value_init (&val, type);
1522 dbus_g_type_struct_get_member (value, i, &val);
1523
1524 G_VALUE_LCOPY (&val, var_args, 0, &error);
1525 if (error)
1526 {
1527 g_warning ("%s, %s", G_STRFUNC, error);
1528 g_free (error);
1529 g_value_unset (&val);
1530 goto error;
1531 }
1532 g_value_unset (&val);
1533 i = va_arg (var_args, guint);
1534 }
1535 va_end (var_args);
1536 return TRUE;
1537 error:
1538 va_end (var_args);
1539 return FALSE;
1540 }
1541
1542 /**
1543 * dbus_g_type_struct_set:
1544 * @value: a #GValue containing a struct instance
1545 * @member: struct member to set
1546 * @...: value for the first member, followed optionally by
1547 * more member/value pairs, followed by %G_MAXUINT
1548 *
1549 * Sets the selected members of the struct in @value.
1550 *
1551 * Returns: %FALSE on failure
1552 *
1553 * Deprecated: New code should use GDBus instead.
1554 */
1555
1556 gboolean
dbus_g_type_struct_set(GValue * value,guint first_member,...)1557 dbus_g_type_struct_set (GValue *value,
1558 guint first_member,
1559 ...)
1560 {
1561 va_list var_args;
1562 GType type;
1563 guint size,i;
1564 gchar *error;
1565 GValue val = {0,};
1566
1567 g_return_val_if_fail (dbus_g_type_is_struct (G_VALUE_TYPE (value)), FALSE);
1568
1569 va_start (var_args, first_member);
1570 size = dbus_g_type_get_struct_size (G_VALUE_TYPE (value));
1571 i = first_member;
1572 while (i != G_MAXUINT)
1573 {
1574 if (i >= size)
1575 goto error;
1576
1577 type = dbus_g_type_get_struct_member_type (G_VALUE_TYPE (value),i);
1578
1579 g_value_init (&val, type);
1580
1581 G_VALUE_COLLECT (&val, var_args, 0, &error);
1582 if (error)
1583 {
1584 g_warning ("%s, %s", G_STRFUNC, error);
1585 g_free (error);
1586 g_value_unset (&val);
1587 goto error;
1588 }
1589
1590 dbus_g_type_struct_set_member (value, i, &val);
1591
1592 g_value_unset (&val);
1593 i = va_arg (var_args, guint);
1594 }
1595 va_end (var_args);
1596 return TRUE;
1597 error:
1598 va_end (var_args);
1599 return FALSE;
1600 }
1601
1602 static void
_collection_iterator(const GValue * value,gpointer user_data)1603 _collection_iterator (const GValue *value,
1604 gpointer user_data)
1605 {
1606 GPtrArray *children = user_data;
1607
1608 g_ptr_array_add (children, dbus_g_value_build_g_variant (value));
1609 }
1610
1611 static void
_map_iterator(const GValue * kvalue,const GValue * vvalue,gpointer user_data)1612 _map_iterator (const GValue *kvalue,
1613 const GValue *vvalue,
1614 gpointer user_data)
1615 {
1616 GPtrArray *children = user_data;
1617
1618 g_ptr_array_add (children,
1619 g_variant_new_dict_entry (
1620 dbus_g_value_build_g_variant (kvalue),
1621 dbus_g_value_build_g_variant (vvalue)));
1622 }
1623
1624 static GVariantType *
dbus_g_value_type_build_g_variant_type(GType type)1625 dbus_g_value_type_build_g_variant_type (GType type)
1626 {
1627 if (dbus_g_type_is_collection (type))
1628 {
1629 GType element_type = dbus_g_type_get_collection_specialization (type);
1630 GVariantType *element_sig = dbus_g_value_type_build_g_variant_type (
1631 element_type);
1632 GVariantType *ret = g_variant_type_new_array (element_sig);
1633
1634 g_variant_type_free (element_sig);
1635 return ret;
1636 }
1637 else if (dbus_g_type_is_map (type))
1638 {
1639 GType key_type = dbus_g_type_get_map_key_specialization (type);
1640 GType value_type = dbus_g_type_get_map_value_specialization (type);
1641 GVariantType *key_sig = dbus_g_value_type_build_g_variant_type (
1642 key_type);
1643 GVariantType *value_sig = dbus_g_value_type_build_g_variant_type (
1644 value_type);
1645 GVariantType *entry_sig = g_variant_type_new_dict_entry (key_sig,
1646 value_sig);
1647 GVariantType *ret = g_variant_type_new_array (entry_sig);
1648
1649 g_variant_type_free (key_sig);
1650 g_variant_type_free (value_sig);
1651 g_variant_type_free (entry_sig);
1652 return ret;
1653 }
1654 else if (dbus_g_type_is_struct (type))
1655 {
1656 guint size = dbus_g_type_get_struct_size (type);
1657 guint i;
1658 GVariantType **sigs = g_new0 (GVariantType *, size);
1659 GVariantType *ret;
1660
1661 for (i = 0; i < size; i++)
1662 {
1663 GType t = dbus_g_type_get_struct_member_type (type, i);
1664
1665 sigs[i] = dbus_g_value_type_build_g_variant_type (t);
1666 }
1667
1668 ret = g_variant_type_new_tuple ((const GVariantType * const *) sigs,
1669 size);
1670
1671 for (i = 0; i < size; i++)
1672 g_variant_type_free (sigs[i]);
1673
1674 g_free (sigs);
1675 return ret;
1676 }
1677 else if (type == G_TYPE_BOOLEAN)
1678 return g_variant_type_copy (G_VARIANT_TYPE_BOOLEAN);
1679 else if (type == G_TYPE_UCHAR)
1680 return g_variant_type_copy (G_VARIANT_TYPE_BYTE);
1681 else if (type == G_TYPE_INT)
1682 return g_variant_type_copy (G_VARIANT_TYPE_INT32);
1683 else if (type == G_TYPE_UINT)
1684 return g_variant_type_copy (G_VARIANT_TYPE_UINT32);
1685 else if (type == G_TYPE_INT64)
1686 return g_variant_type_copy (G_VARIANT_TYPE_INT64);
1687 else if (type == G_TYPE_UINT64)
1688 return g_variant_type_copy (G_VARIANT_TYPE_UINT64);
1689 else if (type == G_TYPE_DOUBLE)
1690 return g_variant_type_copy (G_VARIANT_TYPE_DOUBLE);
1691 else if (type == G_TYPE_STRING)
1692 return g_variant_type_copy (G_VARIANT_TYPE_STRING);
1693 else if (type == G_TYPE_STRV)
1694 return g_variant_type_copy (G_VARIANT_TYPE_STRING_ARRAY);
1695 else if (type == DBUS_TYPE_G_OBJECT_PATH)
1696 return g_variant_type_copy (G_VARIANT_TYPE_OBJECT_PATH);
1697 else if (type == DBUS_TYPE_G_SIGNATURE)
1698 return g_variant_type_copy (G_VARIANT_TYPE_SIGNATURE);
1699 else if (type == G_TYPE_VALUE)
1700 return g_variant_type_copy (G_VARIANT_TYPE_VARIANT);
1701 else
1702 g_error ("%s: Unknown type: %s", G_STRFUNC, g_type_name (type));
1703 }
1704
1705 /**
1706 * dbus_g_value_build_g_variant:
1707 * @value: a simple or specialized #GValue to convert to a #GVariant
1708 *
1709 * Recurses @value and converts its contents to a #GVariant.
1710 *
1711 * The value must either be a simple value (integer, string, boolean,
1712 * object path etc.) or a specialized container registered with
1713 * dbus_g_type_get_collection(), dbus_g_type_get_map() or
1714 * dbus_g_type_get_struct(). Providing any other type is a programming error
1715 * (including as a child type).
1716 *
1717 * Returns: a new #GVariant containing @value with a floating reference
1718 *
1719 * Deprecated: New code should use GDBus instead.
1720 */
1721 GVariant *
dbus_g_value_build_g_variant(const GValue * value)1722 dbus_g_value_build_g_variant (const GValue *value)
1723 {
1724 GType type;
1725
1726 g_return_val_if_fail (G_IS_VALUE (value), NULL);
1727
1728 type = G_VALUE_TYPE (value);
1729
1730 if (dbus_g_type_is_collection (type))
1731 {
1732 GVariant *variant;
1733 GPtrArray *children;
1734 GVariantType *signature = NULL;
1735
1736 children = g_ptr_array_new ();
1737 dbus_g_type_collection_value_iterate (value, _collection_iterator,
1738 children);
1739
1740 if (children->len == 0)
1741 {
1742 /* we can't cheat by saying "the type of the children? that!" */
1743 GType element_type = dbus_g_type_get_collection_specialization (
1744 type);
1745
1746 signature = dbus_g_value_type_build_g_variant_type (element_type);
1747 }
1748
1749 variant = g_variant_new_array (signature, (GVariant **) children->pdata,
1750 children->len);
1751 g_ptr_array_free (children, TRUE);
1752 g_variant_type_free (signature);
1753
1754 return variant;
1755 }
1756 else if (dbus_g_type_is_map (type))
1757 {
1758 GVariant *variant;
1759 GPtrArray *children;
1760 GVariantType *signature = NULL;
1761
1762 children = g_ptr_array_new ();
1763 dbus_g_type_map_value_iterate (value, _map_iterator, children);
1764
1765 if (children->len == 0)
1766 {
1767 /* we can't cheat by saying "the type of the children? that!" */
1768 GType key_type = dbus_g_type_get_map_key_specialization (
1769 type);
1770 GType value_type = dbus_g_type_get_map_value_specialization (
1771 type);
1772 GVariantType *k = dbus_g_value_type_build_g_variant_type (key_type);
1773 GVariantType *v = dbus_g_value_type_build_g_variant_type (
1774 value_type);
1775
1776 signature = g_variant_type_new_dict_entry (k, v);
1777 g_variant_type_free (k);
1778 g_variant_type_free (v);
1779 }
1780
1781 variant = g_variant_new_array (signature, (GVariant **) children->pdata,
1782 children->len);
1783 g_ptr_array_free (children, TRUE);
1784 g_variant_type_free (signature);
1785
1786 return variant;
1787 }
1788 else if (dbus_g_type_is_struct (type))
1789 {
1790 GVariant *variant, **children;
1791 guint size, i;
1792
1793 size = dbus_g_type_get_struct_size (type);
1794 children = g_new0 (GVariant *, size);
1795
1796 for (i = 0; i < size; i++)
1797 {
1798 GValue cvalue = { 0, };
1799
1800 g_value_init (&cvalue, dbus_g_type_get_struct_member_type (type, i));
1801 dbus_g_type_struct_get_member (value, i, &cvalue);
1802
1803 children[i] = dbus_g_value_build_g_variant (&cvalue);
1804 g_value_unset (&cvalue);
1805 }
1806
1807 variant = g_variant_new_tuple (children, size);
1808 g_free (children);
1809
1810 return variant;
1811 }
1812 else if (type == G_TYPE_BOOLEAN)
1813 return g_variant_new_boolean (g_value_get_boolean (value));
1814 else if (type == G_TYPE_UCHAR)
1815 return g_variant_new_byte (g_value_get_uchar (value));
1816 else if (type == G_TYPE_INT)
1817 return g_variant_new_int32 (g_value_get_int (value));
1818 else if (type == G_TYPE_UINT)
1819 return g_variant_new_uint32 (g_value_get_uint (value));
1820 else if (type == G_TYPE_INT64)
1821 return g_variant_new_int64 (g_value_get_int64 (value));
1822 else if (type == G_TYPE_UINT64)
1823 return g_variant_new_uint64 (g_value_get_uint64 (value));
1824 else if (type == G_TYPE_DOUBLE)
1825 return g_variant_new_double (g_value_get_double (value));
1826 else if (type == G_TYPE_STRING)
1827 {
1828 const gchar *str = g_value_get_string (value);
1829 return g_variant_new_string ((str != NULL) ? str : "");
1830 }
1831 else if (type == G_TYPE_STRV)
1832 {
1833 const gchar * const *strv = g_value_get_boxed (value);
1834 return g_variant_new_strv (strv, (strv != NULL) ? -1 : 0);
1835 }
1836 else if (type == DBUS_TYPE_G_OBJECT_PATH)
1837 return g_variant_new_object_path (g_value_get_boxed (value));
1838 else if (type == DBUS_TYPE_G_SIGNATURE)
1839 return g_variant_new_signature (g_value_get_boxed (value));
1840 else if (type == G_TYPE_VALUE)
1841 return g_variant_new_variant (
1842 dbus_g_value_build_g_variant (g_value_get_boxed (value)));
1843 else
1844 {
1845 g_error ("%s: Unknown type: %s", G_STRFUNC, g_type_name (type));
1846 }
1847 }
1848