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