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 &gt;= 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