GVariant: support serialising to GVariantVectors
[platform/upstream/glib.git] / gio / gdbusintrospection.c
1 /* GDBus - GLib D-Bus Library
2  *
3  * Copyright (C) 2008-2010 Red Hat, Inc.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General
16  * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
17  *
18  * Author: David Zeuthen <davidz@redhat.com>
19  */
20
21 #include "config.h"
22
23 #include <stdlib.h>
24 #include <string.h>
25
26 #include "gdbusintrospection.h"
27
28 #include "glibintl.h"
29
30 /**
31  * SECTION:gdbusintrospection
32  * @title: D-Bus Introspection Data
33  * @short_description: Node and interface description data structures
34  * @include: gio/gio.h
35  *
36  * Various data structures and convenience routines to parse and
37  * generate D-Bus introspection XML. Introspection information is
38  * used when registering objects with g_dbus_connection_register_object().
39  *
40  * The format of D-Bus introspection XML is specified in the
41  * [D-Bus specification](http://dbus.freedesktop.org/doc/dbus-specification.html#introspection-format)
42  */
43
44 /* ---------------------------------------------------------------------------------------------------- */
45
46 #define _MY_DEFINE_BOXED_TYPE(TypeName, type_name) \
47   G_DEFINE_BOXED_TYPE (TypeName, type_name, type_name##_ref, type_name##_unref)
48
49 _MY_DEFINE_BOXED_TYPE (GDBusNodeInfo,       g_dbus_node_info);
50 _MY_DEFINE_BOXED_TYPE (GDBusInterfaceInfo,  g_dbus_interface_info);
51 _MY_DEFINE_BOXED_TYPE (GDBusMethodInfo,     g_dbus_method_info);
52 _MY_DEFINE_BOXED_TYPE (GDBusSignalInfo,     g_dbus_signal_info);
53 _MY_DEFINE_BOXED_TYPE (GDBusPropertyInfo,   g_dbus_property_info);
54 _MY_DEFINE_BOXED_TYPE (GDBusArgInfo,        g_dbus_arg_info);
55 _MY_DEFINE_BOXED_TYPE (GDBusAnnotationInfo, g_dbus_annotation_info);
56
57 /* ---------------------------------------------------------------------------------------------------- */
58
59 typedef struct
60 {
61   /* stuff we are currently collecting */
62   GPtrArray *args;
63   GPtrArray *out_args;
64   GPtrArray *methods;
65   GPtrArray *signals;
66   GPtrArray *properties;
67   GPtrArray *interfaces;
68   GPtrArray *nodes;
69   GPtrArray *annotations;
70
71   /* A list of GPtrArray's containing annotations */
72   GSList *annotations_stack;
73
74   /* A list of GPtrArray's containing interfaces */
75   GSList *interfaces_stack;
76
77   /* A list of GPtrArray's containing nodes */
78   GSList *nodes_stack;
79
80   /* Whether the direction was "in" for last parsed arg */
81   gboolean last_arg_was_in;
82
83   /* Number of args currently being collected; used for assigning
84    * names to args without a "name" attribute
85    */
86   guint num_args;
87
88 } ParseData;
89
90 /* ---------------------------------------------------------------------------------------------------- */
91
92 /**
93  * g_dbus_node_info_ref:
94  * @info: A #GDBusNodeInfo
95  *
96  * If @info is statically allocated does nothing. Otherwise increases
97  * the reference count.
98  *
99  * Returns: The same @info.
100  *
101  * Since: 2.26
102  */
103 GDBusNodeInfo *
104 g_dbus_node_info_ref (GDBusNodeInfo *info)
105 {
106   if (info->ref_count == -1)
107     return info;
108   g_atomic_int_inc (&info->ref_count);
109   return info;
110 }
111
112 /**
113  * g_dbus_interface_info_ref:
114  * @info: A #GDBusInterfaceInfo
115  *
116  * If @info is statically allocated does nothing. Otherwise increases
117  * the reference count.
118  *
119  * Returns: The same @info.
120  *
121  * Since: 2.26
122  */
123 GDBusInterfaceInfo *
124 g_dbus_interface_info_ref (GDBusInterfaceInfo *info)
125 {
126   if (info->ref_count == -1)
127     return info;
128   g_atomic_int_inc (&info->ref_count);
129   return info;
130 }
131
132 /**
133  * g_dbus_method_info_ref:
134  * @info: A #GDBusMethodInfo
135  *
136  * If @info is statically allocated does nothing. Otherwise increases
137  * the reference count.
138  *
139  * Returns: The same @info.
140  *
141  * Since: 2.26
142  */
143 GDBusMethodInfo *
144 g_dbus_method_info_ref (GDBusMethodInfo *info)
145 {
146   if (info->ref_count == -1)
147     return info;
148   g_atomic_int_inc (&info->ref_count);
149   return info;
150 }
151
152 /**
153  * g_dbus_signal_info_ref:
154  * @info: A #GDBusSignalInfo
155  *
156  * If @info is statically allocated does nothing. Otherwise increases
157  * the reference count.
158  *
159  * Returns: The same @info.
160  *
161  * Since: 2.26
162  */
163 GDBusSignalInfo *
164 g_dbus_signal_info_ref (GDBusSignalInfo *info)
165 {
166   if (info->ref_count == -1)
167     return info;
168   g_atomic_int_inc (&info->ref_count);
169   return info;
170 }
171
172 /**
173  * g_dbus_property_info_ref:
174  * @info: A #GDBusPropertyInfo
175  *
176  * If @info is statically allocated does nothing. Otherwise increases
177  * the reference count.
178  *
179  * Returns: The same @info.
180  *
181  * Since: 2.26
182  */
183 GDBusPropertyInfo *
184 g_dbus_property_info_ref (GDBusPropertyInfo *info)
185 {
186   if (info->ref_count == -1)
187     return info;
188   g_atomic_int_inc (&info->ref_count);
189   return info;
190 }
191
192 /**
193  * g_dbus_arg_info_ref:
194  * @info: A #GDBusArgInfo
195  *
196  * If @info is statically allocated does nothing. Otherwise increases
197  * the reference count.
198  *
199  * Returns: The same @info.
200  *
201  * Since: 2.26
202  */
203 GDBusArgInfo *
204 g_dbus_arg_info_ref (GDBusArgInfo *info)
205 {
206   if (info->ref_count == -1)
207     return info;
208   g_atomic_int_inc (&info->ref_count);
209   return info;
210 }
211
212 /**
213  * g_dbus_annotation_info_ref:
214  * @info: A #GDBusNodeInfo
215  *
216  * If @info is statically allocated does nothing. Otherwise increases
217  * the reference count.
218  *
219  * Returns: The same @info.
220  *
221  * Since: 2.26
222  */
223 GDBusAnnotationInfo *
224 g_dbus_annotation_info_ref (GDBusAnnotationInfo *info)
225 {
226   if (info->ref_count == -1)
227     return info;
228   g_atomic_int_inc (&info->ref_count);
229   return info;
230 }
231
232 /* ---------------------------------------------------------------------------------------------------- */
233
234 static void
235 free_null_terminated_array (gpointer array, GDestroyNotify unref_func)
236 {
237   guint n;
238   gpointer *p = array;
239   if (p == NULL)
240     return;
241   for (n = 0; p[n] != NULL; n++)
242     unref_func (p[n]);
243   g_free (p);
244 }
245
246 /**
247  * g_dbus_annotation_info_unref:
248  * @info: A #GDBusAnnotationInfo.
249  *
250  * If @info is statically allocated, does nothing. Otherwise decreases
251  * the reference count of @info. When its reference count drops to 0,
252  * the memory used is freed.
253  *
254  * Since: 2.26
255  */
256 void
257 g_dbus_annotation_info_unref (GDBusAnnotationInfo *info)
258 {
259   if (info->ref_count == -1)
260     return;
261   if (g_atomic_int_dec_and_test (&info->ref_count))
262     {
263       g_free (info->key);
264       g_free (info->value);
265       free_null_terminated_array (info->annotations, (GDestroyNotify) g_dbus_annotation_info_unref);
266       g_free (info);
267     }
268 }
269
270 /**
271  * g_dbus_arg_info_unref:
272  * @info: A #GDBusArgInfo.
273  *
274  * If @info is statically allocated, does nothing. Otherwise decreases
275  * the reference count of @info. When its reference count drops to 0,
276  * the memory used is freed.
277  *
278  * Since: 2.26
279  */
280 void
281 g_dbus_arg_info_unref (GDBusArgInfo *info)
282 {
283   if (info->ref_count == -1)
284     return;
285   if (g_atomic_int_dec_and_test (&info->ref_count))
286     {
287       g_free (info->name);
288       g_free (info->signature);
289       free_null_terminated_array (info->annotations, (GDestroyNotify) g_dbus_annotation_info_unref);
290       g_free (info);
291     }
292 }
293
294 /**
295  * g_dbus_method_info_unref:
296  * @info: A #GDBusMethodInfo.
297  *
298  * If @info is statically allocated, does nothing. Otherwise decreases
299  * the reference count of @info. When its reference count drops to 0,
300  * the memory used is freed.
301  *
302  * Since: 2.26
303  */
304 void
305 g_dbus_method_info_unref (GDBusMethodInfo *info)
306 {
307   if (info->ref_count == -1)
308     return;
309   if (g_atomic_int_dec_and_test (&info->ref_count))
310     {
311       g_free (info->name);
312       free_null_terminated_array (info->in_args, (GDestroyNotify) g_dbus_arg_info_unref);
313       free_null_terminated_array (info->out_args, (GDestroyNotify) g_dbus_arg_info_unref);
314       free_null_terminated_array (info->annotations, (GDestroyNotify) g_dbus_annotation_info_unref);
315       g_free (info);
316     }
317 }
318
319 /**
320  * g_dbus_signal_info_unref:
321  * @info: A #GDBusSignalInfo.
322  *
323  * If @info is statically allocated, does nothing. Otherwise decreases
324  * the reference count of @info. When its reference count drops to 0,
325  * the memory used is freed.
326  *
327  * Since: 2.26
328  */
329 void
330 g_dbus_signal_info_unref (GDBusSignalInfo *info)
331 {
332   if (info->ref_count == -1)
333     return;
334   if (g_atomic_int_dec_and_test (&info->ref_count))
335     {
336       g_free (info->name);
337       free_null_terminated_array (info->args, (GDestroyNotify) g_dbus_arg_info_unref);
338       free_null_terminated_array (info->annotations, (GDestroyNotify) g_dbus_annotation_info_unref);
339       g_free (info);
340     }
341 }
342
343 /**
344  * g_dbus_property_info_unref:
345  * @info: A #GDBusPropertyInfo.
346  *
347  * If @info is statically allocated, does nothing. Otherwise decreases
348  * the reference count of @info. When its reference count drops to 0,
349  * the memory used is freed.
350  *
351  * Since: 2.26
352  */
353 void
354 g_dbus_property_info_unref (GDBusPropertyInfo *info)
355 {
356   if (info->ref_count == -1)
357     return;
358   if (g_atomic_int_dec_and_test (&info->ref_count))
359     {
360       g_free (info->name);
361       g_free (info->signature);
362       free_null_terminated_array (info->annotations, (GDestroyNotify) g_dbus_annotation_info_unref);
363       g_free (info);
364     }
365 }
366
367 /**
368  * g_dbus_interface_info_unref:
369  * @info: A #GDBusInterfaceInfo.
370  *
371  * If @info is statically allocated, does nothing. Otherwise decreases
372  * the reference count of @info. When its reference count drops to 0,
373  * the memory used is freed.
374  *
375  * Since: 2.26
376  */
377 void
378 g_dbus_interface_info_unref (GDBusInterfaceInfo *info)
379 {
380   if (info->ref_count == -1)
381     return;
382   if (g_atomic_int_dec_and_test (&info->ref_count))
383     {
384       g_free (info->name);
385       free_null_terminated_array (info->methods, (GDestroyNotify) g_dbus_method_info_unref);
386       free_null_terminated_array (info->signals, (GDestroyNotify) g_dbus_signal_info_unref);
387       free_null_terminated_array (info->properties, (GDestroyNotify) g_dbus_property_info_unref);
388       free_null_terminated_array (info->annotations, (GDestroyNotify) g_dbus_annotation_info_unref);
389       g_free (info);
390     }
391 }
392
393 /**
394  * g_dbus_node_info_unref:
395  * @info: A #GDBusNodeInfo.
396  *
397  * If @info is statically allocated, does nothing. Otherwise decreases
398  * the reference count of @info. When its reference count drops to 0,
399  * the memory used is freed.
400  *
401  * Since: 2.26
402  */
403 void
404 g_dbus_node_info_unref (GDBusNodeInfo *info)
405 {
406   if (info->ref_count == -1)
407     return;
408   if (g_atomic_int_dec_and_test (&info->ref_count))
409     {
410       g_free (info->path);
411       free_null_terminated_array (info->interfaces, (GDestroyNotify) g_dbus_interface_info_unref);
412       free_null_terminated_array (info->nodes, (GDestroyNotify) g_dbus_node_info_unref);
413       free_null_terminated_array (info->annotations, (GDestroyNotify) g_dbus_annotation_info_unref);
414       g_free (info);
415     }
416 }
417
418 /* ---------------------------------------------------------------------------------------------------- */
419
420 static void
421 g_dbus_annotation_info_set (ParseData            *data,
422                             GDBusAnnotationInfo  *info,
423                             const gchar          *key,
424                             const gchar          *value,
425                             GDBusAnnotationInfo **embedded_annotations)
426 {
427   info->ref_count = 1;
428
429   if (key != NULL)
430     info->key = g_strdup (key);
431
432   if (value != NULL)
433     info->value = g_strdup (value);
434
435   if (embedded_annotations != NULL)
436     info->annotations = embedded_annotations;
437 }
438
439 static void
440 g_dbus_arg_info_set (ParseData            *data,
441                      GDBusArgInfo         *info,
442                      const gchar          *name,
443                      const gchar          *signature,
444                      GDBusAnnotationInfo **annotations)
445 {
446   info->ref_count = 1;
447
448   /* name may be NULL - TODO: compute name? */
449   if (name != NULL)
450     info->name = g_strdup (name);
451
452   if (signature != NULL)
453     info->signature = g_strdup (signature);
454
455   if (annotations != NULL)
456     info->annotations = annotations;
457 }
458
459 static void
460 g_dbus_method_info_set (ParseData            *data,
461                         GDBusMethodInfo      *info,
462                         const gchar          *name,
463                         GDBusArgInfo        **in_args,
464                         GDBusArgInfo        **out_args,
465                         GDBusAnnotationInfo **annotations)
466 {
467   info->ref_count = 1;
468
469   if (name != NULL)
470     info->name = g_strdup (name);
471
472   if (in_args != NULL)
473     info->in_args = in_args;
474
475   if (out_args != NULL)
476     info->out_args = out_args;
477
478   if (annotations != NULL)
479     info->annotations = annotations;
480 }
481
482 static void
483 g_dbus_signal_info_set (ParseData            *data,
484                         GDBusSignalInfo      *info,
485                         const gchar          *name,
486                         GDBusArgInfo        **args,
487                         GDBusAnnotationInfo **annotations)
488 {
489   info->ref_count = 1;
490
491   if (name != NULL)
492     info->name = g_strdup (name);
493
494   if (args != NULL)
495     info->args = args;
496
497   if (annotations != NULL)
498     info->annotations = annotations;
499 }
500
501 static void
502 g_dbus_property_info_set (ParseData               *data,
503                           GDBusPropertyInfo       *info,
504                           const gchar             *name,
505                           const gchar             *signature,
506                           GDBusPropertyInfoFlags   flags,
507                           GDBusAnnotationInfo    **annotations)
508 {
509   info->ref_count = 1;
510
511   if (name != NULL)
512     info->name = g_strdup (name);
513
514   if (flags != G_DBUS_PROPERTY_INFO_FLAGS_NONE)
515     info->flags = flags;
516
517   if (signature != NULL)
518     info->signature = g_strdup (signature);
519
520   if (annotations != NULL)
521     info->annotations = annotations;
522 }
523
524 static void
525 g_dbus_interface_info_set (ParseData            *data,
526                            GDBusInterfaceInfo   *info,
527                            const gchar          *name,
528                            GDBusMethodInfo     **methods,
529                            GDBusSignalInfo     **signals,
530                            GDBusPropertyInfo   **properties,
531                            GDBusAnnotationInfo **annotations)
532 {
533   info->ref_count = 1;
534
535   if (name != NULL)
536     info->name = g_strdup (name);
537
538   if (methods != NULL)
539     info->methods = methods;
540
541   if (signals != NULL)
542     info->signals = signals;
543
544   if (properties != NULL)
545     info->properties = properties;
546
547   if (annotations != NULL)
548     info->annotations = annotations;
549 }
550
551 static void
552 g_dbus_node_info_set (ParseData            *data,
553                       GDBusNodeInfo        *info,
554                       const gchar          *path,
555                       GDBusInterfaceInfo  **interfaces,
556                       GDBusNodeInfo       **nodes,
557                       GDBusAnnotationInfo **annotations)
558 {
559   info->ref_count = 1;
560
561   if (path != NULL)
562     {
563       info->path = g_strdup (path);
564       /* TODO: relative / absolute path snafu */
565     }
566
567   if (interfaces != NULL)
568     info->interfaces = interfaces;
569
570   if (nodes != NULL)
571     info->nodes = nodes;
572
573   if (annotations != NULL)
574     info->annotations = annotations;
575 }
576
577 /* ---------------------------------------------------------------------------------------------------- */
578
579 static void
580 g_dbus_annotation_info_generate_xml (GDBusAnnotationInfo *info,
581                                      guint                indent,
582                                      GString             *string_builder)
583 {
584   gchar *tmp;
585   guint n;
586
587   tmp = g_markup_printf_escaped ("%*s<annotation name=\"%s\" value=\"%s\"",
588                                  indent, "",
589                                  info->key,
590                                  info->value);
591   g_string_append (string_builder, tmp);
592   g_free (tmp);
593
594   if (info->annotations == NULL)
595     {
596       g_string_append (string_builder, "/>\n");
597     }
598   else
599     {
600       g_string_append (string_builder, ">\n");
601
602       for (n = 0; info->annotations != NULL && info->annotations[n] != NULL; n++)
603         g_dbus_annotation_info_generate_xml (info->annotations[n],
604                                              indent + 2,
605                                              string_builder);
606
607       g_string_append_printf (string_builder, "%*s</annotation>\n",
608                               indent, "");
609     }
610
611 }
612
613 static void
614 g_dbus_arg_info_generate_xml (GDBusArgInfo *info,
615                               guint         indent,
616                               const gchar  *extra_attributes,
617                               GString      *string_builder)
618 {
619   guint n;
620
621   g_string_append_printf (string_builder, "%*s<arg type=\"%s\"",
622                           indent, "",
623                           info->signature);
624
625   if (info->name != NULL)
626     g_string_append_printf (string_builder, " name=\"%s\"", info->name);
627
628   if (extra_attributes != NULL)
629     g_string_append_printf (string_builder, " %s", extra_attributes);
630
631   if (info->annotations == NULL)
632     {
633       g_string_append (string_builder, "/>\n");
634     }
635   else
636     {
637       g_string_append (string_builder, ">\n");
638
639       for (n = 0; info->annotations != NULL && info->annotations[n] != NULL; n++)
640         g_dbus_annotation_info_generate_xml (info->annotations[n],
641                                              indent + 2,
642                                              string_builder);
643
644       g_string_append_printf (string_builder, "%*s</arg>\n", indent, "");
645     }
646
647 }
648
649 static void
650 g_dbus_method_info_generate_xml (GDBusMethodInfo *info,
651                                  guint            indent,
652                                  GString         *string_builder)
653 {
654   guint n;
655
656   g_string_append_printf (string_builder, "%*s<method name=\"%s\"",
657                           indent, "",
658                           info->name);
659
660   if (info->annotations == NULL && info->in_args == NULL && info->out_args == NULL)
661     {
662       g_string_append (string_builder, "/>\n");
663     }
664   else
665     {
666       g_string_append (string_builder, ">\n");
667
668       for (n = 0; info->annotations != NULL && info->annotations[n] != NULL; n++)
669         g_dbus_annotation_info_generate_xml (info->annotations[n],
670                                              indent + 2,
671                                              string_builder);
672
673       for (n = 0; info->in_args != NULL && info->in_args[n] != NULL; n++)
674         g_dbus_arg_info_generate_xml (info->in_args[n],
675                                       indent + 2,
676                                       "direction=\"in\"",
677                                       string_builder);
678
679       for (n = 0; info->out_args != NULL && info->out_args[n] != NULL; n++)
680         g_dbus_arg_info_generate_xml (info->out_args[n],
681                                       indent + 2,
682                                       "direction=\"out\"",
683                                       string_builder);
684
685       g_string_append_printf (string_builder, "%*s</method>\n", indent, "");
686     }
687 }
688
689 static void
690 g_dbus_signal_info_generate_xml (GDBusSignalInfo *info,
691                                  guint            indent,
692                                  GString         *string_builder)
693 {
694   guint n;
695
696   g_string_append_printf (string_builder, "%*s<signal name=\"%s\"",
697                           indent, "",
698                           info->name);
699
700   if (info->annotations == NULL && info->args == NULL)
701     {
702       g_string_append (string_builder, "/>\n");
703     }
704   else
705     {
706       g_string_append (string_builder, ">\n");
707
708       for (n = 0; info->annotations != NULL && info->annotations[n] != NULL; n++)
709         g_dbus_annotation_info_generate_xml (info->annotations[n],
710                                              indent + 2,
711                                              string_builder);
712
713       for (n = 0; info->args != NULL && info->args[n] != NULL; n++)
714         g_dbus_arg_info_generate_xml (info->args[n],
715                                       indent + 2,
716                                       NULL,
717                                       string_builder);
718
719       g_string_append_printf (string_builder, "%*s</signal>\n", indent, "");
720     }
721 }
722
723 static void
724 g_dbus_property_info_generate_xml (GDBusPropertyInfo *info,
725                                    guint              indent,
726                                    GString           *string_builder)
727 {
728   guint n;
729   const gchar *access_string;
730
731   if ((info->flags & G_DBUS_PROPERTY_INFO_FLAGS_READABLE) &&
732       (info->flags & G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE))
733     {
734       access_string = "readwrite";
735     }
736   else if (info->flags & G_DBUS_PROPERTY_INFO_FLAGS_READABLE)
737     {
738       access_string = "read";
739     }
740   else if (info->flags & G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE)
741     {
742       access_string = "write";
743     }
744   else
745     {
746       g_assert_not_reached ();
747     }
748
749   g_string_append_printf (string_builder, "%*s<property type=\"%s\" name=\"%s\" access=\"%s\"",
750                           indent, "",
751                           info->signature,
752                           info->name,
753                           access_string);
754
755   if (info->annotations == NULL)
756     {
757       g_string_append (string_builder, "/>\n");
758     }
759   else
760     {
761       g_string_append (string_builder, ">\n");
762
763       for (n = 0; info->annotations != NULL && info->annotations[n] != NULL; n++)
764         g_dbus_annotation_info_generate_xml (info->annotations[n],
765                                                indent + 2,
766                                                string_builder);
767
768       g_string_append_printf (string_builder, "%*s</property>\n", indent, "");
769     }
770
771 }
772
773 /**
774  * g_dbus_interface_info_generate_xml:
775  * @info: A #GDBusNodeInfo
776  * @indent: Indentation level.
777  * @string_builder: (out): A #GString to to append XML data to.
778  *
779  * Appends an XML representation of @info (and its children) to @string_builder.
780  *
781  * This function is typically used for generating introspection XML
782  * documents at run-time for handling the
783  * `org.freedesktop.DBus.Introspectable.Introspect`
784  * method.
785  *
786  * Since: 2.26
787  */
788 void
789 g_dbus_interface_info_generate_xml (GDBusInterfaceInfo *info,
790                                     guint               indent,
791                                     GString            *string_builder)
792 {
793   guint n;
794
795   g_string_append_printf (string_builder, "%*s<interface name=\"%s\">\n",
796                           indent, "",
797                           info->name);
798
799   for (n = 0; info->annotations != NULL && info->annotations[n] != NULL; n++)
800     g_dbus_annotation_info_generate_xml (info->annotations[n],
801                                          indent + 2,
802                                          string_builder);
803
804   for (n = 0; info->methods != NULL && info->methods[n] != NULL; n++)
805     g_dbus_method_info_generate_xml (info->methods[n],
806                                      indent + 2,
807                                      string_builder);
808
809   for (n = 0; info->signals != NULL && info->signals[n] != NULL; n++)
810     g_dbus_signal_info_generate_xml (info->signals[n],
811                                      indent + 2,
812                                      string_builder);
813
814   for (n = 0; info->properties != NULL && info->properties[n] != NULL; n++)
815     g_dbus_property_info_generate_xml (info->properties[n],
816                                        indent + 2,
817                                        string_builder);
818
819   g_string_append_printf (string_builder, "%*s</interface>\n", indent, "");
820 }
821
822 /**
823  * g_dbus_node_info_generate_xml:
824  * @info: A #GDBusNodeInfo.
825  * @indent: Indentation level.
826  * @string_builder: (out): A #GString to to append XML data to.
827  *
828  * Appends an XML representation of @info (and its children) to @string_builder.
829  *
830  * This function is typically used for generating introspection XML documents at run-time for
831  * handling the `org.freedesktop.DBus.Introspectable.Introspect`  method.
832  *
833  * Since: 2.26
834  */
835 void
836 g_dbus_node_info_generate_xml (GDBusNodeInfo *info,
837                                guint          indent,
838                                GString       *string_builder)
839 {
840   guint n;
841
842   g_string_append_printf (string_builder, "%*s<node", indent, "");
843   if (info->path != NULL)
844     g_string_append_printf (string_builder, " name=\"%s\"", info->path);
845
846   if (info->interfaces == NULL && info->nodes == NULL && info->annotations == NULL)
847     {
848       g_string_append (string_builder, "/>\n");
849     }
850   else
851     {
852       g_string_append (string_builder, ">\n");
853
854       for (n = 0; info->annotations != NULL && info->annotations[n] != NULL; n++)
855         g_dbus_annotation_info_generate_xml (info->annotations[n],
856                                              indent + 2,
857                                              string_builder);
858
859       for (n = 0; info->interfaces != NULL && info->interfaces[n] != NULL; n++)
860         g_dbus_interface_info_generate_xml (info->interfaces[n],
861                                             indent + 2,
862                                             string_builder);
863
864       for (n = 0; info->nodes != NULL && info->nodes[n] != NULL; n++)
865         g_dbus_node_info_generate_xml (info->nodes[n],
866                                        indent + 2,
867                                        string_builder);
868
869       g_string_append_printf (string_builder, "%*s</node>\n", indent, "");
870     }
871 }
872
873 /* ---------------------------------------------------------------------------------------------------- */
874
875 static GDBusAnnotationInfo **
876 parse_data_steal_annotations (ParseData *data,
877                               guint     *out_num_elements)
878 {
879   GDBusAnnotationInfo **ret;
880   if (out_num_elements != NULL)
881     *out_num_elements = data->annotations->len;
882   if (data->annotations == NULL)
883     ret = NULL;
884   else
885     {
886       g_ptr_array_add (data->annotations, NULL);
887       ret = (GDBusAnnotationInfo **) g_ptr_array_free (data->annotations, FALSE);
888     }
889   data->annotations = g_ptr_array_new ();
890   return ret;
891 }
892
893 static GDBusArgInfo **
894 parse_data_steal_args (ParseData *data,
895                        guint     *out_num_elements)
896 {
897   GDBusArgInfo **ret;
898   if (out_num_elements != NULL)
899     *out_num_elements = data->args->len;
900   if (data->args == NULL)
901     ret = NULL;
902   else
903     {
904       g_ptr_array_add (data->args, NULL);
905       ret = (GDBusArgInfo **) g_ptr_array_free (data->args, FALSE);
906     }
907   data->args = g_ptr_array_new ();
908   return ret;
909 }
910
911 static GDBusArgInfo **
912 parse_data_steal_out_args (ParseData *data,
913                            guint     *out_num_elements)
914 {
915   GDBusArgInfo **ret;
916   if (out_num_elements != NULL)
917     *out_num_elements = data->out_args->len;
918   if (data->out_args == NULL)
919     ret = NULL;
920   else
921     {
922       g_ptr_array_add (data->out_args, NULL);
923       ret = (GDBusArgInfo **) g_ptr_array_free (data->out_args, FALSE);
924     }
925   data->out_args = g_ptr_array_new ();
926   return ret;
927 }
928
929 static GDBusMethodInfo **
930 parse_data_steal_methods (ParseData *data,
931                           guint     *out_num_elements)
932 {
933   GDBusMethodInfo **ret;
934   if (out_num_elements != NULL)
935     *out_num_elements = data->methods->len;
936   if (data->methods == NULL)
937     ret = NULL;
938   else
939     {
940       g_ptr_array_add (data->methods, NULL);
941       ret = (GDBusMethodInfo **) g_ptr_array_free (data->methods, FALSE);
942     }
943   data->methods = g_ptr_array_new ();
944   return ret;
945 }
946
947 static GDBusSignalInfo **
948 parse_data_steal_signals (ParseData *data,
949                           guint     *out_num_elements)
950 {
951   GDBusSignalInfo **ret;
952   if (out_num_elements != NULL)
953     *out_num_elements = data->signals->len;
954   if (data->signals == NULL)
955     ret = NULL;
956   else
957     {
958       g_ptr_array_add (data->signals, NULL);
959       ret = (GDBusSignalInfo **) g_ptr_array_free (data->signals, FALSE);
960     }
961   data->signals = g_ptr_array_new ();
962   return ret;
963 }
964
965 static GDBusPropertyInfo **
966 parse_data_steal_properties (ParseData *data,
967                              guint     *out_num_elements)
968 {
969   GDBusPropertyInfo **ret;
970   if (out_num_elements != NULL)
971     *out_num_elements = data->properties->len;
972   if (data->properties == NULL)
973     ret = NULL;
974   else
975     {
976       g_ptr_array_add (data->properties, NULL);
977       ret = (GDBusPropertyInfo **) g_ptr_array_free (data->properties, FALSE);
978     }
979   data->properties = g_ptr_array_new ();
980   return ret;
981 }
982
983 static GDBusInterfaceInfo **
984 parse_data_steal_interfaces (ParseData *data,
985                              guint     *out_num_elements)
986 {
987   GDBusInterfaceInfo **ret;
988   if (out_num_elements != NULL)
989     *out_num_elements = data->interfaces->len;
990   if (data->interfaces == NULL)
991     ret = NULL;
992   else
993     {
994       g_ptr_array_add (data->interfaces, NULL);
995       ret = (GDBusInterfaceInfo **) g_ptr_array_free (data->interfaces, FALSE);
996     }
997   data->interfaces = g_ptr_array_new ();
998   return ret;
999 }
1000
1001 static GDBusNodeInfo **
1002 parse_data_steal_nodes (ParseData *data,
1003                         guint     *out_num_elements)
1004 {
1005   GDBusNodeInfo **ret;
1006   if (out_num_elements != NULL)
1007     *out_num_elements = data->nodes->len;
1008   if (data->nodes == NULL)
1009     ret = NULL;
1010   else
1011     {
1012       g_ptr_array_add (data->nodes, NULL);
1013       ret = (GDBusNodeInfo **) g_ptr_array_free (data->nodes, FALSE);
1014     }
1015   data->nodes = g_ptr_array_new ();
1016   return ret;
1017 }
1018
1019 /* ---------------------------------------------------------------------------------------------------- */
1020
1021 static void
1022 parse_data_free_annotations (ParseData *data)
1023 {
1024   if (data->annotations == NULL)
1025     return;
1026   g_ptr_array_foreach (data->annotations, (GFunc) g_dbus_annotation_info_unref, NULL);
1027   g_ptr_array_free (data->annotations, TRUE);
1028   data->annotations = NULL;
1029 }
1030
1031 static void
1032 parse_data_free_args (ParseData *data)
1033 {
1034   if (data->args == NULL)
1035     return;
1036   g_ptr_array_foreach (data->args, (GFunc) g_dbus_arg_info_unref, NULL);
1037   g_ptr_array_free (data->args, TRUE);
1038   data->args = NULL;
1039 }
1040
1041 static void
1042 parse_data_free_out_args (ParseData *data)
1043 {
1044   if (data->out_args == NULL)
1045     return;
1046   g_ptr_array_foreach (data->out_args, (GFunc) g_dbus_arg_info_unref, NULL);
1047   g_ptr_array_free (data->out_args, TRUE);
1048   data->out_args = NULL;
1049 }
1050
1051 static void
1052 parse_data_free_methods (ParseData *data)
1053 {
1054   if (data->methods == NULL)
1055     return;
1056   g_ptr_array_foreach (data->methods, (GFunc) g_dbus_method_info_unref, NULL);
1057   g_ptr_array_free (data->methods, TRUE);
1058   data->methods = NULL;
1059 }
1060
1061 static void
1062 parse_data_free_signals (ParseData *data)
1063 {
1064   if (data->signals == NULL)
1065     return;
1066   g_ptr_array_foreach (data->signals, (GFunc) g_dbus_signal_info_unref, NULL);
1067   g_ptr_array_free (data->signals, TRUE);
1068   data->signals = NULL;
1069 }
1070
1071 static void
1072 parse_data_free_properties (ParseData *data)
1073 {
1074   if (data->properties == NULL)
1075     return;
1076   g_ptr_array_foreach (data->properties, (GFunc) g_dbus_property_info_unref, NULL);
1077   g_ptr_array_free (data->properties, TRUE);
1078   data->properties = NULL;
1079 }
1080
1081 static void
1082 parse_data_free_interfaces (ParseData *data)
1083 {
1084   if (data->interfaces == NULL)
1085     return;
1086   g_ptr_array_foreach (data->interfaces, (GFunc) g_dbus_interface_info_unref, NULL);
1087   g_ptr_array_free (data->interfaces, TRUE);
1088   data->interfaces = NULL;
1089 }
1090
1091 static void
1092 parse_data_free_nodes (ParseData *data)
1093 {
1094   if (data->nodes == NULL)
1095     return;
1096   g_ptr_array_foreach (data->nodes, (GFunc) g_dbus_node_info_unref, NULL);
1097   g_ptr_array_free (data->nodes, TRUE);
1098   data->nodes = NULL;
1099 }
1100
1101 /* ---------------------------------------------------------------------------------------------------- */
1102
1103 static GDBusAnnotationInfo *
1104 parse_data_get_annotation (ParseData *data,
1105                            gboolean   create_new)
1106 {
1107   if (create_new)
1108     g_ptr_array_add (data->annotations, g_new0 (GDBusAnnotationInfo, 1));
1109   return data->annotations->pdata[data->annotations->len - 1];
1110 }
1111
1112 static GDBusArgInfo *
1113 parse_data_get_arg (ParseData *data,
1114                     gboolean   create_new)
1115 {
1116   if (create_new)
1117     g_ptr_array_add (data->args, g_new0 (GDBusArgInfo, 1));
1118   return data->args->pdata[data->args->len - 1];
1119 }
1120
1121 static GDBusArgInfo *
1122 parse_data_get_out_arg (ParseData *data,
1123                         gboolean   create_new)
1124 {
1125   if (create_new)
1126     g_ptr_array_add (data->out_args, g_new0 (GDBusArgInfo, 1));
1127   return data->out_args->pdata[data->out_args->len - 1];
1128 }
1129
1130 static GDBusMethodInfo *
1131 parse_data_get_method (ParseData *data,
1132                        gboolean   create_new)
1133 {
1134   if (create_new)
1135     g_ptr_array_add (data->methods, g_new0 (GDBusMethodInfo, 1));
1136   return data->methods->pdata[data->methods->len - 1];
1137 }
1138
1139 static GDBusSignalInfo *
1140 parse_data_get_signal (ParseData *data,
1141                        gboolean   create_new)
1142 {
1143   if (create_new)
1144     g_ptr_array_add (data->signals, g_new0 (GDBusSignalInfo, 1));
1145   return data->signals->pdata[data->signals->len - 1];
1146 }
1147
1148 static GDBusPropertyInfo *
1149 parse_data_get_property (ParseData *data,
1150                          gboolean   create_new)
1151 {
1152   if (create_new)
1153     g_ptr_array_add (data->properties, g_new0 (GDBusPropertyInfo, 1));
1154   return data->properties->pdata[data->properties->len - 1];
1155 }
1156
1157 static GDBusInterfaceInfo *
1158 parse_data_get_interface (ParseData *data,
1159                           gboolean   create_new)
1160 {
1161   if (create_new)
1162     g_ptr_array_add (data->interfaces, g_new0 (GDBusInterfaceInfo, 1));
1163   return data->interfaces->pdata[data->interfaces->len - 1];
1164 }
1165
1166 static GDBusNodeInfo *
1167 parse_data_get_node (ParseData *data,
1168                      gboolean   create_new)
1169 {
1170   if (create_new)
1171     g_ptr_array_add (data->nodes, g_new0 (GDBusNodeInfo, 1));
1172   return data->nodes->pdata[data->nodes->len - 1];
1173 }
1174
1175 /* ---------------------------------------------------------------------------------------------------- */
1176
1177 static ParseData *
1178 parse_data_new (void)
1179 {
1180   ParseData *data;
1181
1182   data = g_new0 (ParseData, 1);
1183
1184   /* initialize arrays */
1185   parse_data_steal_annotations (data, NULL);
1186   parse_data_steal_args (data, NULL);
1187   parse_data_steal_out_args (data, NULL);
1188   parse_data_steal_methods (data, NULL);
1189   parse_data_steal_signals (data, NULL);
1190   parse_data_steal_properties (data, NULL);
1191   parse_data_steal_interfaces (data, NULL);
1192   parse_data_steal_nodes (data, NULL);
1193
1194   return data;
1195 }
1196
1197 static void
1198 parse_data_free (ParseData *data)
1199 {
1200   GSList *l;
1201
1202   /* free stack of annotation arrays */
1203   for (l = data->annotations_stack; l != NULL; l = l->next)
1204     {
1205       GPtrArray *annotations = l->data;
1206       g_ptr_array_foreach (annotations, (GFunc) g_dbus_annotation_info_unref, NULL);
1207       g_ptr_array_free (annotations, TRUE);
1208     }
1209   g_slist_free (data->annotations_stack);
1210
1211   /* free stack of interface arrays */
1212   for (l = data->interfaces_stack; l != NULL; l = l->next)
1213     {
1214       GPtrArray *interfaces = l->data;
1215       g_ptr_array_foreach (interfaces, (GFunc) g_dbus_interface_info_unref, NULL);
1216       g_ptr_array_free (interfaces, TRUE);
1217     }
1218   g_slist_free (data->interfaces_stack);
1219
1220   /* free stack of node arrays */
1221   for (l = data->nodes_stack; l != NULL; l = l->next)
1222     {
1223       GPtrArray *nodes = l->data;
1224       g_ptr_array_foreach (nodes, (GFunc) g_dbus_node_info_unref, NULL);
1225       g_ptr_array_free (nodes, TRUE);
1226     }
1227   g_slist_free (data->nodes_stack);
1228
1229   /* free arrays (data->annotations, data->interfaces and data->nodes have been freed above) */
1230   parse_data_free_args (data);
1231   parse_data_free_out_args (data);
1232   parse_data_free_methods (data);
1233   parse_data_free_signals (data);
1234   parse_data_free_properties (data);
1235   parse_data_free_interfaces (data);
1236   parse_data_free_annotations (data);
1237   parse_data_free_nodes (data);
1238
1239   g_free (data);
1240 }
1241
1242 /* ---------------------------------------------------------------------------------------------------- */
1243
1244 static void
1245 parser_start_element (GMarkupParseContext  *context,
1246                       const gchar          *element_name,
1247                       const gchar         **attribute_names,
1248                       const gchar         **attribute_values,
1249                       gpointer              user_data,
1250                       GError              **error)
1251 {
1252   ParseData *data = user_data;
1253   GSList *stack;
1254   const gchar *name;
1255   const gchar *type;
1256   const gchar *access;
1257   const gchar *direction;
1258   const gchar *value;
1259
1260   name = NULL;
1261   type = NULL;
1262   access = NULL;
1263   direction = NULL;
1264   value = NULL;
1265
1266   stack = (GSList *) g_markup_parse_context_get_element_stack (context);
1267
1268   /* ---------------------------------------------------------------------------------------------------- */
1269   if (strcmp (element_name, "node") == 0)
1270     {
1271       if (!(g_slist_length (stack) >= 1 || strcmp (stack->next->data, "node") != 0))
1272         {
1273           g_set_error_literal (error,
1274                                G_MARKUP_ERROR,
1275                                G_MARKUP_ERROR_INVALID_CONTENT,
1276                                "<node> elements can only be top-level or embedded in other <node> elements");
1277           goto out;
1278         }
1279
1280       if (!g_markup_collect_attributes (element_name,
1281                                         attribute_names,
1282                                         attribute_values,
1283                                         error,
1284                                         G_MARKUP_COLLECT_STRING | G_MARKUP_COLLECT_OPTIONAL, "name", &name,
1285                                         /* some hand-written introspection XML documents use this */
1286                                         G_MARKUP_COLLECT_STRING | G_MARKUP_COLLECT_OPTIONAL, "xmlns:doc", NULL,
1287                                         G_MARKUP_COLLECT_INVALID))
1288         goto out;
1289
1290       g_dbus_node_info_set (data,
1291                             parse_data_get_node (data, TRUE),
1292                             name,
1293                             NULL,
1294                             NULL,
1295                             NULL);
1296
1297       /* push the currently retrieved interfaces and nodes on the stack and prepare new arrays */
1298       data->interfaces_stack = g_slist_prepend (data->interfaces_stack, data->interfaces);
1299       data->interfaces = NULL;
1300       parse_data_steal_interfaces (data, NULL);
1301
1302       data->nodes_stack = g_slist_prepend (data->nodes_stack, data->nodes);
1303       data->nodes = NULL;
1304       parse_data_steal_nodes (data, NULL);
1305
1306     }
1307   /* ---------------------------------------------------------------------------------------------------- */
1308   else if (strcmp (element_name, "interface") == 0)
1309     {
1310       if (g_slist_length (stack) < 2 || strcmp (stack->next->data, "node") != 0)
1311         {
1312           g_set_error_literal (error,
1313                                G_MARKUP_ERROR,
1314                                G_MARKUP_ERROR_INVALID_CONTENT,
1315                                "<interface> elements can only be embedded in <node> elements");
1316           goto out;
1317         }
1318
1319       if (!g_markup_collect_attributes (element_name,
1320                                         attribute_names,
1321                                         attribute_values,
1322                                         error,
1323                                         G_MARKUP_COLLECT_STRING, "name", &name,
1324                                         /* seen in the wild */
1325                                         G_MARKUP_COLLECT_STRING | G_MARKUP_COLLECT_OPTIONAL, "version", NULL,
1326                                         G_MARKUP_COLLECT_INVALID))
1327         goto out;
1328
1329       g_dbus_interface_info_set (data,
1330                                  parse_data_get_interface (data, TRUE),
1331                                  name,
1332                                  NULL,
1333                                  NULL,
1334                                  NULL,
1335                                  NULL);
1336
1337     }
1338   /* ---------------------------------------------------------------------------------------------------- */
1339   else if (strcmp (element_name, "method") == 0)
1340     {
1341       if (g_slist_length (stack) < 2 || strcmp (stack->next->data, "interface") != 0)
1342         {
1343           g_set_error_literal (error,
1344                                G_MARKUP_ERROR,
1345                                G_MARKUP_ERROR_INVALID_CONTENT,
1346                                "<method> elements can only be embedded in <interface> elements");
1347           goto out;
1348         }
1349
1350       if (!g_markup_collect_attributes (element_name,
1351                                         attribute_names,
1352                                         attribute_values,
1353                                         error,
1354                                         G_MARKUP_COLLECT_STRING, "name", &name,
1355                                         /* seen in the wild */
1356                                         G_MARKUP_COLLECT_STRING | G_MARKUP_COLLECT_OPTIONAL, "version", NULL,
1357                                         G_MARKUP_COLLECT_INVALID))
1358         goto out;
1359
1360       g_dbus_method_info_set (data,
1361                               parse_data_get_method (data, TRUE),
1362                               name,
1363                               NULL,
1364                               NULL,
1365                               NULL);
1366
1367       data->num_args = 0;
1368
1369     }
1370   /* ---------------------------------------------------------------------------------------------------- */
1371   else if (strcmp (element_name, "signal") == 0)
1372     {
1373       if (g_slist_length (stack) < 2 || strcmp (stack->next->data, "interface") != 0)
1374         {
1375           g_set_error_literal (error,
1376                                G_MARKUP_ERROR,
1377                                G_MARKUP_ERROR_INVALID_CONTENT,
1378                                "<signal> elements can only be embedded in <interface> elements");
1379           goto out;
1380         }
1381
1382       if (!g_markup_collect_attributes (element_name,
1383                                         attribute_names,
1384                                         attribute_values,
1385                                         error,
1386                                         G_MARKUP_COLLECT_STRING, "name", &name,
1387                                         G_MARKUP_COLLECT_INVALID))
1388         goto out;
1389
1390       g_dbus_signal_info_set (data,
1391                               parse_data_get_signal (data, TRUE),
1392                               name,
1393                               NULL,
1394                               NULL);
1395
1396       data->num_args = 0;
1397
1398     }
1399   /* ---------------------------------------------------------------------------------------------------- */
1400   else if (strcmp (element_name, "property") == 0)
1401     {
1402       GDBusPropertyInfoFlags flags;
1403
1404       if (g_slist_length (stack) < 2 || strcmp (stack->next->data, "interface") != 0)
1405         {
1406           g_set_error_literal (error,
1407                                G_MARKUP_ERROR,
1408                                G_MARKUP_ERROR_INVALID_CONTENT,
1409                                "<property> elements can only be embedded in <interface> elements");
1410           goto out;
1411         }
1412
1413       if (!g_markup_collect_attributes (element_name,
1414                                         attribute_names,
1415                                         attribute_values,
1416                                         error,
1417                                         G_MARKUP_COLLECT_STRING, "name", &name,
1418                                         G_MARKUP_COLLECT_STRING, "type", &type,
1419                                         G_MARKUP_COLLECT_STRING, "access", &access,
1420                                         G_MARKUP_COLLECT_INVALID))
1421         goto out;
1422
1423       if (strcmp (access, "read") == 0)
1424         flags = G_DBUS_PROPERTY_INFO_FLAGS_READABLE;
1425       else if (strcmp (access, "write") == 0)
1426         flags = G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE;
1427       else if (strcmp (access, "readwrite") == 0)
1428         flags = G_DBUS_PROPERTY_INFO_FLAGS_READABLE | G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE;
1429       else
1430         {
1431           g_set_error (error,
1432                        G_MARKUP_ERROR,
1433                        G_MARKUP_ERROR_INVALID_CONTENT,
1434                        "Unknown value '%s' of access attribute for element <property>",
1435                        access);
1436           goto out;
1437         }
1438
1439       g_dbus_property_info_set (data,
1440                                 parse_data_get_property (data, TRUE),
1441                                 name,
1442                                 type,
1443                                 flags,
1444                                 NULL);
1445
1446     }
1447   /* ---------------------------------------------------------------------------------------------------- */
1448   else if (strcmp (element_name, "arg") == 0)
1449     {
1450       gboolean is_in;
1451       gchar *name_to_use;
1452
1453       if (g_slist_length (stack) < 2 ||
1454           (strcmp (stack->next->data, "method") != 0 &&
1455            strcmp (stack->next->data, "signal") != 0))
1456         {
1457           g_set_error_literal (error,
1458                                G_MARKUP_ERROR,
1459                                G_MARKUP_ERROR_INVALID_CONTENT,
1460                                "<arg> elements can only be embedded in <method> or <signal> elements");
1461           goto out;
1462         }
1463
1464       if (!g_markup_collect_attributes (element_name,
1465                                         attribute_names,
1466                                         attribute_values,
1467                                         error,
1468                                         G_MARKUP_COLLECT_STRING | G_MARKUP_COLLECT_OPTIONAL, "name", &name,
1469                                         G_MARKUP_COLLECT_STRING | G_MARKUP_COLLECT_OPTIONAL, "direction", &direction,
1470                                         G_MARKUP_COLLECT_STRING, "type", &type,
1471                                         G_MARKUP_COLLECT_INVALID))
1472         goto out;
1473
1474       if (strcmp (stack->next->data, "method") == 0)
1475         is_in = TRUE;
1476       else
1477         is_in = FALSE;
1478       if (direction != NULL)
1479         {
1480           if (strcmp (direction, "in") == 0)
1481             is_in = TRUE;
1482           else if (strcmp (direction, "out") == 0)
1483             is_in = FALSE;
1484           else
1485             {
1486               g_set_error (error,
1487                            G_MARKUP_ERROR,
1488                            G_MARKUP_ERROR_INVALID_CONTENT,
1489                            "Unknown value '%s' of direction attribute",
1490                            direction);
1491               goto out;
1492             }
1493         }
1494
1495       if (is_in && strcmp (stack->next->data, "signal") == 0)
1496         {
1497           g_set_error_literal (error,
1498                                G_MARKUP_ERROR,
1499                                G_MARKUP_ERROR_INVALID_CONTENT,
1500                                "Only direction 'out' is allowed for <arg> elements embedded in <signal>");
1501           goto out;
1502         }
1503
1504       if (name == NULL)
1505         name_to_use = g_strdup_printf ("arg_%d", data->num_args);
1506       else
1507         name_to_use = g_strdup (name);
1508       data->num_args++;
1509
1510       if (is_in)
1511         {
1512           g_dbus_arg_info_set (data,
1513                                parse_data_get_arg (data, TRUE),
1514                                name_to_use,
1515                                type,
1516                                NULL);
1517           data->last_arg_was_in = TRUE;
1518         }
1519       else
1520         {
1521           g_dbus_arg_info_set (data,
1522                                parse_data_get_out_arg (data, TRUE),
1523                                name_to_use,
1524                                type,
1525                                NULL);
1526           data->last_arg_was_in = FALSE;
1527
1528         }
1529
1530       g_free (name_to_use);
1531     }
1532   /* ---------------------------------------------------------------------------------------------------- */
1533   else if (strcmp (element_name, "annotation") == 0)
1534     {
1535       if (g_slist_length (stack) < 2 ||
1536           (strcmp (stack->next->data, "node") != 0 &&
1537            strcmp (stack->next->data, "interface") != 0 &&
1538            strcmp (stack->next->data, "signal") != 0 &&
1539            strcmp (stack->next->data, "method") != 0 &&
1540            strcmp (stack->next->data, "property") != 0 &&
1541            strcmp (stack->next->data, "arg") != 0 &&
1542            strcmp (stack->next->data, "annotation") != 0))
1543         {
1544           g_set_error_literal (error,
1545                                G_MARKUP_ERROR,
1546                                G_MARKUP_ERROR_INVALID_CONTENT,
1547                                "<annotation> elements can only be embedded in <node>, <interface>, <signal>, <method>, <property>, <arg> or <annotation> elements");
1548           goto out;
1549         }
1550
1551       if (!g_markup_collect_attributes (element_name,
1552                                         attribute_names,
1553                                         attribute_values,
1554                                         error,
1555                                         G_MARKUP_COLLECT_STRING, "name", &name,
1556                                         G_MARKUP_COLLECT_STRING, "value", &value,
1557                                         G_MARKUP_COLLECT_INVALID))
1558         goto out;
1559
1560       g_dbus_annotation_info_set (data,
1561                                   parse_data_get_annotation (data, TRUE),
1562                                   name,
1563                                   value,
1564                                   NULL);
1565     }
1566   /* ---------------------------------------------------------------------------------------------------- */
1567   else
1568     {
1569       /* don't bail on unknown elements; just ignore them */
1570     }
1571   /* ---------------------------------------------------------------------------------------------------- */
1572
1573   /* push the currently retrieved annotations on the stack and prepare a new one */
1574   data->annotations_stack = g_slist_prepend (data->annotations_stack, data->annotations);
1575   data->annotations = NULL;
1576   parse_data_steal_annotations (data, NULL);
1577
1578  out:
1579   ;
1580 }
1581
1582 /* ---------------------------------------------------------------------------------------------------- */
1583
1584 static GDBusAnnotationInfo **
1585 steal_annotations (ParseData *data)
1586 {
1587   return parse_data_steal_annotations (data, NULL);
1588 }
1589
1590
1591 static void
1592 parser_end_element (GMarkupParseContext  *context,
1593                     const gchar          *element_name,
1594                     gpointer              user_data,
1595                     GError              **error)
1596 {
1597   ParseData *data = user_data;
1598   gboolean have_popped_annotations;
1599
1600   have_popped_annotations = FALSE;
1601
1602   if (strcmp (element_name, "node") == 0)
1603     {
1604       guint num_nodes;
1605       guint num_interfaces;
1606       GDBusNodeInfo **nodes;
1607       GDBusInterfaceInfo **interfaces;
1608
1609       nodes = parse_data_steal_nodes (data, &num_nodes);
1610       interfaces = parse_data_steal_interfaces (data, &num_interfaces);
1611
1612       /* destroy the nodes, interfaces for scope we're exiting and and pop the nodes, interfaces from the
1613        * scope we're reentering
1614        */
1615       parse_data_free_interfaces (data);
1616       data->interfaces = (GPtrArray *) data->interfaces_stack->data;
1617       data->interfaces_stack = g_slist_remove (data->interfaces_stack, data->interfaces_stack->data);
1618
1619       parse_data_free_nodes (data);
1620       data->nodes = (GPtrArray *) data->nodes_stack->data;
1621       data->nodes_stack = g_slist_remove (data->nodes_stack, data->nodes_stack->data);
1622
1623       g_dbus_node_info_set (data,
1624                             parse_data_get_node (data, FALSE),
1625                             NULL,
1626                             interfaces,
1627                             nodes,
1628                             steal_annotations (data));
1629
1630     }
1631   else if (strcmp (element_name, "interface") == 0)
1632     {
1633       guint num_methods;
1634       guint num_signals;
1635       guint num_properties;
1636       GDBusMethodInfo **methods;
1637       GDBusSignalInfo **signals;
1638       GDBusPropertyInfo **properties;
1639
1640       methods    = parse_data_steal_methods    (data, &num_methods);
1641       signals    = parse_data_steal_signals    (data, &num_signals);
1642       properties = parse_data_steal_properties (data, &num_properties);
1643
1644       g_dbus_interface_info_set (data,
1645                                  parse_data_get_interface (data, FALSE),
1646                                  NULL,
1647                                  methods,
1648                                  signals,
1649                                  properties,
1650                                  steal_annotations (data));
1651
1652     }
1653   else if (strcmp (element_name, "method") == 0)
1654     {
1655       guint in_num_args;
1656       guint out_num_args;
1657       GDBusArgInfo **in_args;
1658       GDBusArgInfo **out_args;
1659
1660       in_args  = parse_data_steal_args     (data, &in_num_args);
1661       out_args = parse_data_steal_out_args (data, &out_num_args);
1662
1663       g_dbus_method_info_set (data,
1664                               parse_data_get_method (data, FALSE),
1665                               NULL,
1666                               in_args,
1667                               out_args,
1668                               steal_annotations (data));
1669     }
1670   else if (strcmp (element_name, "signal") == 0)
1671     {
1672       guint num_args;
1673       GDBusArgInfo **args;
1674
1675       args = parse_data_steal_out_args (data, &num_args);
1676
1677       g_dbus_signal_info_set (data,
1678                               parse_data_get_signal (data, FALSE),
1679                               NULL,
1680                               args,
1681                               steal_annotations (data));
1682     }
1683   else if (strcmp (element_name, "property") == 0)
1684     {
1685       g_dbus_property_info_set (data,
1686                                 parse_data_get_property (data, FALSE),
1687                                 NULL,
1688                                 NULL,
1689                                 G_DBUS_PROPERTY_INFO_FLAGS_NONE,
1690                                 steal_annotations (data));
1691     }
1692   else if (strcmp (element_name, "arg") == 0)
1693     {
1694       g_dbus_arg_info_set (data,
1695                            data->last_arg_was_in ? parse_data_get_arg (data, FALSE) : parse_data_get_out_arg (data, FALSE),
1696                            NULL,
1697                            NULL,
1698                            steal_annotations (data));
1699     }
1700   else if (strcmp (element_name, "annotation") == 0)
1701     {
1702       GDBusAnnotationInfo **embedded_annotations;
1703
1704       embedded_annotations = steal_annotations (data);
1705
1706       /* destroy the annotations for scope we're exiting and and pop the annotations from the scope we're reentering */
1707       parse_data_free_annotations (data);
1708       data->annotations = (GPtrArray *) data->annotations_stack->data;
1709       data->annotations_stack = g_slist_remove (data->annotations_stack, data->annotations_stack->data);
1710
1711       have_popped_annotations = TRUE;
1712
1713       g_dbus_annotation_info_set (data,
1714                                   parse_data_get_annotation (data, FALSE),
1715                                   NULL,
1716                                   NULL,
1717                                   embedded_annotations);
1718     }
1719   else
1720     {
1721       /* don't bail on unknown elements; just ignore them */
1722     }
1723
1724   if (!have_popped_annotations)
1725     {
1726       /* destroy the annotations for scope we're exiting and and pop the annotations from the scope we're reentering */
1727       parse_data_free_annotations (data);
1728       data->annotations = (GPtrArray *) data->annotations_stack->data;
1729       data->annotations_stack = g_slist_remove (data->annotations_stack, data->annotations_stack->data);
1730     }
1731 }
1732
1733 /* ---------------------------------------------------------------------------------------------------- */
1734
1735 static void
1736 parser_error (GMarkupParseContext *context,
1737               GError              *error,
1738               gpointer             user_data)
1739 {
1740   gint line_number;
1741   gint char_number;
1742
1743   g_markup_parse_context_get_position (context, &line_number, &char_number);
1744
1745   g_prefix_error (&error, "%d:%d: ",
1746                   line_number,
1747                   char_number);
1748 }
1749
1750 /* ---------------------------------------------------------------------------------------------------- */
1751
1752 /**
1753  * g_dbus_node_info_new_for_xml:
1754  * @xml_data: Valid D-Bus introspection XML.
1755  * @error: Return location for error.
1756  *
1757  * Parses @xml_data and returns a #GDBusNodeInfo representing the data.
1758  *
1759  * The introspection XML must contain exactly one top-level
1760  * <node> element.
1761  *
1762  * Note that this routine is using a
1763  * [GMarkup][glib-Simple-XML-Subset-Parser.description]-based
1764  * parser that only accepts a subset of valid XML documents.
1765  *
1766  * Returns: A #GDBusNodeInfo structure or %NULL if @error is set. Free
1767  * with g_dbus_node_info_unref().
1768  *
1769  * Since: 2.26
1770  */
1771 GDBusNodeInfo *
1772 g_dbus_node_info_new_for_xml (const gchar  *xml_data,
1773                               GError      **error)
1774 {
1775   GDBusNodeInfo *ret;
1776   GMarkupParseContext *context;
1777   GMarkupParser *parser;
1778   guint num_nodes;
1779   ParseData *data;
1780   GDBusNodeInfo **ughret;
1781
1782   ret = NULL;
1783   parser = NULL;
1784   context = NULL;
1785
1786   parser = g_new0 (GMarkupParser, 1);
1787   parser->start_element = parser_start_element;
1788   parser->end_element   = parser_end_element;
1789   parser->error         = parser_error;
1790
1791   data = parse_data_new ();
1792   context = g_markup_parse_context_new (parser,
1793                                         G_MARKUP_IGNORE_QUALIFIED,
1794                                         data,
1795                                         (GDestroyNotify) parse_data_free);
1796
1797   if (!g_markup_parse_context_parse (context,
1798                                      xml_data,
1799                                      strlen (xml_data),
1800                                      error))
1801     goto out;
1802
1803   if (!g_markup_parse_context_end_parse (context, error))
1804     goto out;
1805
1806   ughret = parse_data_steal_nodes (data, &num_nodes);
1807
1808   if (num_nodes != 1)
1809     {
1810       guint n;
1811
1812       g_set_error (error,
1813                    G_MARKUP_ERROR,
1814                    G_MARKUP_ERROR_INVALID_CONTENT,
1815                    "Expected a single node in introspection XML, found %d",
1816                    num_nodes);
1817
1818       /* clean up */
1819       for (n = 0; n < num_nodes; n++)
1820         {
1821           g_dbus_node_info_unref (ughret[n]);
1822           ughret[n] = NULL;
1823         }
1824     }
1825
1826   ret = ughret[0];
1827   g_free (ughret);
1828
1829  out:
1830   g_free (parser);
1831   if (context != NULL)
1832     g_markup_parse_context_free (context);
1833
1834   return ret;
1835 }
1836
1837 /* ---------------------------------------------------------------------------------------------------- */
1838
1839 /**
1840  * g_dbus_annotation_info_lookup:
1841  * @annotations: (array zero-terminated=1) (allow-none): A %NULL-terminated array of annotations or %NULL.
1842  * @name: The name of the annotation to look up.
1843  *
1844  * Looks up the value of an annotation.
1845  *
1846  * The cost of this function is O(n) in number of annotations.
1847  *
1848  * Returns: The value or %NULL if not found. Do not free, it is owned by @annotations.
1849  *
1850  * Since: 2.26
1851  */
1852 const gchar *
1853 g_dbus_annotation_info_lookup (GDBusAnnotationInfo **annotations,
1854                                const gchar          *name)
1855 {
1856   guint n;
1857   const gchar *ret;
1858
1859   ret = NULL;
1860   for (n = 0; annotations != NULL && annotations[n] != NULL; n++)
1861     {
1862       if (g_strcmp0 (annotations[n]->key, name) == 0)
1863         {
1864           ret = annotations[n]->value;
1865           goto out;
1866         }
1867     }
1868
1869  out:
1870   return ret;
1871 }
1872
1873 /* ---------------------------------------------------------------------------------------------------- */
1874
1875 G_LOCK_DEFINE_STATIC (info_cache_lock);
1876
1877 typedef struct
1878 {
1879   gint use_count;
1880
1881   /* gchar* -> GDBusMethodInfo* */
1882   GHashTable *method_name_to_data;
1883
1884   /* gchar* -> GDBusMethodInfo* */
1885   GHashTable *signal_name_to_data;
1886
1887   /* gchar* -> GDBusMethodInfo* */
1888   GHashTable *property_name_to_data;
1889 } InfoCacheEntry;
1890
1891 static void
1892 info_cache_free (InfoCacheEntry *cache)
1893 {
1894   g_assert (cache->use_count == 0);
1895   g_hash_table_unref (cache->method_name_to_data);
1896   g_hash_table_unref (cache->signal_name_to_data);
1897   g_hash_table_unref (cache->property_name_to_data);
1898   g_slice_free (InfoCacheEntry, cache);
1899 }
1900
1901 /* maps from GDBusInterfaceInfo* to InfoCacheEntry* */
1902 static GHashTable *info_cache = NULL;
1903
1904 /* ---------------------------------------------------------------------------------------------------- */
1905
1906 /**
1907  * g_dbus_interface_info_lookup_method:
1908  * @info: A #GDBusInterfaceInfo.
1909  * @name: A D-Bus method name (typically in CamelCase)
1910  *
1911  * Looks up information about a method.
1912  *
1913  * The cost of this function is O(n) in number of methods unless
1914  * g_dbus_interface_info_cache_build() has been used on @info.
1915  *
1916  * Returns: (transfer none): A #GDBusMethodInfo or %NULL if not found. Do not free, it is owned by @info.
1917  *
1918  * Since: 2.26
1919  */
1920 GDBusMethodInfo *
1921 g_dbus_interface_info_lookup_method (GDBusInterfaceInfo *info,
1922                                      const gchar        *name)
1923 {
1924   guint n;
1925   GDBusMethodInfo *result;
1926
1927   G_LOCK (info_cache_lock);
1928   if (G_LIKELY (info_cache != NULL))
1929     {
1930       InfoCacheEntry *cache;
1931       cache = g_hash_table_lookup (info_cache, info);
1932       if (G_LIKELY (cache != NULL))
1933         {
1934           result = g_hash_table_lookup (cache->method_name_to_data, name);
1935           G_UNLOCK (info_cache_lock);
1936           goto out;
1937         }
1938     }
1939   G_UNLOCK (info_cache_lock);
1940
1941   for (n = 0; info->methods != NULL && info->methods[n] != NULL; n++)
1942     {
1943       GDBusMethodInfo *i = info->methods[n];
1944
1945       if (g_strcmp0 (i->name, name) == 0)
1946         {
1947           result = i;
1948           goto out;
1949         }
1950     }
1951
1952   result = NULL;
1953
1954  out:
1955   return result;
1956 }
1957
1958 /* ---------------------------------------------------------------------------------------------------- */
1959
1960 /**
1961  * g_dbus_interface_info_lookup_signal:
1962  * @info: A #GDBusInterfaceInfo.
1963  * @name: A D-Bus signal name (typically in CamelCase)
1964  *
1965  * Looks up information about a signal.
1966  *
1967  * The cost of this function is O(n) in number of signals unless
1968  * g_dbus_interface_info_cache_build() has been used on @info.
1969  *
1970  * Returns: (transfer none): A #GDBusSignalInfo or %NULL if not found. Do not free, it is owned by @info.
1971  *
1972  * Since: 2.26
1973  */
1974 GDBusSignalInfo *
1975 g_dbus_interface_info_lookup_signal (GDBusInterfaceInfo *info,
1976                                      const gchar        *name)
1977 {
1978   guint n;
1979   GDBusSignalInfo *result;
1980
1981   G_LOCK (info_cache_lock);
1982   if (G_LIKELY (info_cache != NULL))
1983     {
1984       InfoCacheEntry *cache;
1985       cache = g_hash_table_lookup (info_cache, info);
1986       if (G_LIKELY (cache != NULL))
1987         {
1988           result = g_hash_table_lookup (cache->signal_name_to_data, name);
1989           G_UNLOCK (info_cache_lock);
1990           goto out;
1991         }
1992     }
1993   G_UNLOCK (info_cache_lock);
1994
1995   for (n = 0; info->signals != NULL && info->signals[n] != NULL; n++)
1996     {
1997       GDBusSignalInfo *i = info->signals[n];
1998
1999       if (g_strcmp0 (i->name, name) == 0)
2000         {
2001           result = i;
2002           goto out;
2003         }
2004     }
2005
2006   result = NULL;
2007
2008  out:
2009   return result;
2010 }
2011
2012 /* ---------------------------------------------------------------------------------------------------- */
2013
2014 /**
2015  * g_dbus_interface_info_lookup_property:
2016  * @info: A #GDBusInterfaceInfo.
2017  * @name: A D-Bus property name (typically in CamelCase).
2018  *
2019  * Looks up information about a property.
2020  *
2021  * The cost of this function is O(n) in number of properties unless
2022  * g_dbus_interface_info_cache_build() has been used on @info.
2023  *
2024  * Returns: (transfer none): A #GDBusPropertyInfo or %NULL if not found. Do not free, it is owned by @info.
2025  *
2026  * Since: 2.26
2027  */
2028 GDBusPropertyInfo *
2029 g_dbus_interface_info_lookup_property (GDBusInterfaceInfo *info,
2030                                        const gchar        *name)
2031 {
2032   guint n;
2033   GDBusPropertyInfo *result;
2034
2035   G_LOCK (info_cache_lock);
2036   if (G_LIKELY (info_cache != NULL))
2037     {
2038       InfoCacheEntry *cache;
2039       cache = g_hash_table_lookup (info_cache, info);
2040       if (G_LIKELY (cache != NULL))
2041         {
2042           result = g_hash_table_lookup (cache->property_name_to_data, name);
2043           G_UNLOCK (info_cache_lock);
2044           goto out;
2045         }
2046     }
2047   G_UNLOCK (info_cache_lock);
2048
2049   for (n = 0; info->properties != NULL && info->properties[n] != NULL; n++)
2050     {
2051       GDBusPropertyInfo *i = info->properties[n];
2052
2053       if (g_strcmp0 (i->name, name) == 0)
2054         {
2055           result = i;
2056           goto out;
2057         }
2058     }
2059
2060   result = NULL;
2061
2062  out:
2063   return result;
2064 }
2065
2066 /* ---------------------------------------------------------------------------------------------------- */
2067
2068 /**
2069  * g_dbus_interface_info_cache_build:
2070  * @info: A #GDBusInterfaceInfo.
2071  *
2072  * Builds a lookup-cache to speed up
2073  * g_dbus_interface_info_lookup_method(),
2074  * g_dbus_interface_info_lookup_signal() and
2075  * g_dbus_interface_info_lookup_property().
2076  *
2077  * If this has already been called with @info, the existing cache is
2078  * used and its use count is increased.
2079  *
2080  * Note that @info cannot be modified until
2081  * g_dbus_interface_info_cache_release() is called.
2082  *
2083  * Since: 2.30
2084  */
2085 void
2086 g_dbus_interface_info_cache_build (GDBusInterfaceInfo *info)
2087 {
2088   InfoCacheEntry *cache;
2089   guint n;
2090
2091   G_LOCK (info_cache_lock);
2092   if (info_cache == NULL)
2093     info_cache = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) info_cache_free);
2094   cache = g_hash_table_lookup (info_cache, info);
2095   if (cache != NULL)
2096     {
2097       cache->use_count += 1;
2098       goto out;
2099     }
2100   cache = g_slice_new0 (InfoCacheEntry);
2101   cache->use_count = 1;
2102   cache->method_name_to_data = g_hash_table_new (g_str_hash, g_str_equal);
2103   cache->signal_name_to_data = g_hash_table_new (g_str_hash, g_str_equal);
2104   cache->property_name_to_data = g_hash_table_new (g_str_hash, g_str_equal);
2105   for (n = 0; info->methods != NULL && info->methods[n] != NULL; n++)
2106     g_hash_table_insert (cache->method_name_to_data, info->methods[n]->name, info->methods[n]);
2107   for (n = 0; info->signals != NULL && info->signals[n] != NULL; n++)
2108     g_hash_table_insert (cache->signal_name_to_data, info->signals[n]->name, info->signals[n]);
2109   for (n = 0; info->properties != NULL && info->properties[n] != NULL; n++)
2110     g_hash_table_insert (cache->property_name_to_data, info->properties[n]->name, info->properties[n]);
2111   g_hash_table_insert (info_cache, info, cache);
2112  out:
2113   G_UNLOCK (info_cache_lock);
2114 }
2115
2116 /**
2117  * g_dbus_interface_info_cache_release:
2118  * @info: A GDBusInterfaceInfo
2119  *
2120  * Decrements the usage count for the cache for @info built by
2121  * g_dbus_interface_info_cache_build() (if any) and frees the
2122  * resources used by the cache if the usage count drops to zero.
2123  *
2124  * Since: 2.30
2125  */
2126 void
2127 g_dbus_interface_info_cache_release (GDBusInterfaceInfo *info)
2128 {
2129   InfoCacheEntry *cache;
2130
2131   G_LOCK (info_cache_lock);
2132   if (G_UNLIKELY (info_cache == NULL))
2133     {
2134       g_warning ("%s called for interface %s but there is no cache", info->name, G_STRFUNC);
2135       goto out;
2136     }
2137
2138   cache = g_hash_table_lookup (info_cache, info);
2139   if (G_UNLIKELY (cache == NULL))
2140     {
2141       g_warning ("%s called for interface %s but there is no cache entry", info->name, G_STRFUNC);
2142       goto out;
2143     }
2144   cache->use_count -= 1;
2145   if (cache->use_count == 0)
2146     {
2147       g_hash_table_remove (info_cache, info);
2148       /* could nuke info_cache itself if empty */
2149     }
2150  out:
2151   G_UNLOCK (info_cache_lock);
2152 }
2153
2154
2155 /* ---------------------------------------------------------------------------------------------------- */
2156
2157 /**
2158  * g_dbus_node_info_lookup_interface:
2159  * @info: A #GDBusNodeInfo.
2160  * @name: A D-Bus interface name.
2161  *
2162  * Looks up information about an interface.
2163  *
2164  * The cost of this function is O(n) in number of interfaces.
2165  *
2166  * Returns: (transfer none): A #GDBusInterfaceInfo or %NULL if not found. Do not free, it is owned by @info.
2167  *
2168  * Since: 2.26
2169  */
2170 GDBusInterfaceInfo *
2171 g_dbus_node_info_lookup_interface (GDBusNodeInfo *info,
2172                                    const gchar   *name)
2173 {
2174   guint n;
2175   GDBusInterfaceInfo *result;
2176
2177   for (n = 0; info->interfaces != NULL && info->interfaces[n] != NULL; n++)
2178     {
2179       GDBusInterfaceInfo *i = info->interfaces[n];
2180
2181       if (g_strcmp0 (i->name, name) == 0)
2182         {
2183           result = i;
2184           goto out;
2185         }
2186     }
2187
2188   result = NULL;
2189
2190  out:
2191   return result;
2192 }