Fix this cost -> the cost typos
[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_attributes (element_name,
1280                                         attribute_names,
1281                                         attribute_values,
1282                                         error,
1283                                         G_MARKUP_COLLECT_STRING | G_MARKUP_COLLECT_OPTIONAL, "name", &name,
1284                                         /* some hand-written introspection XML documents use this */
1285                                         G_MARKUP_COLLECT_STRING | G_MARKUP_COLLECT_OPTIONAL, "xmlns:doc", NULL,
1286                                         G_MARKUP_COLLECT_INVALID))
1287         goto out;
1288
1289       g_dbus_node_info_set (data,
1290                             parse_data_get_node (data, TRUE),
1291                             name,
1292                             NULL,
1293                             NULL,
1294                             NULL);
1295
1296       /* push the currently retrieved interfaces and nodes on the stack and prepare new arrays */
1297       data->interfaces_stack = g_slist_prepend (data->interfaces_stack, data->interfaces);
1298       data->interfaces = NULL;
1299       parse_data_steal_interfaces (data, NULL);
1300
1301       data->nodes_stack = g_slist_prepend (data->nodes_stack, data->nodes);
1302       data->nodes = NULL;
1303       parse_data_steal_nodes (data, NULL);
1304
1305     }
1306   /* ---------------------------------------------------------------------------------------------------- */
1307   else if (strcmp (element_name, "interface") == 0)
1308     {
1309       if (g_slist_length (stack) < 2 || strcmp (stack->next->data, "node") != 0)
1310         {
1311           g_set_error_literal (error,
1312                                G_MARKUP_ERROR,
1313                                G_MARKUP_ERROR_INVALID_CONTENT,
1314                                "<interface> elements can only be embedded in <node> elements");
1315           goto out;
1316         }
1317
1318       if (!g_markup_collect_attributes (element_name,
1319                                         attribute_names,
1320                                         attribute_values,
1321                                         error,
1322                                         G_MARKUP_COLLECT_STRING, "name", &name,
1323                                         /* seen in the wild */
1324                                         G_MARKUP_COLLECT_STRING | G_MARKUP_COLLECT_OPTIONAL, "version", NULL,
1325                                         G_MARKUP_COLLECT_INVALID))
1326         goto out;
1327
1328       g_dbus_interface_info_set (data,
1329                                  parse_data_get_interface (data, TRUE),
1330                                  name,
1331                                  NULL,
1332                                  NULL,
1333                                  NULL,
1334                                  NULL);
1335
1336     }
1337   /* ---------------------------------------------------------------------------------------------------- */
1338   else if (strcmp (element_name, "method") == 0)
1339     {
1340       if (g_slist_length (stack) < 2 || strcmp (stack->next->data, "interface") != 0)
1341         {
1342           g_set_error_literal (error,
1343                                G_MARKUP_ERROR,
1344                                G_MARKUP_ERROR_INVALID_CONTENT,
1345                                "<method> elements can only be embedded in <interface> elements");
1346           goto out;
1347         }
1348
1349       if (!g_markup_collect_attributes (element_name,
1350                                         attribute_names,
1351                                         attribute_values,
1352                                         error,
1353                                         G_MARKUP_COLLECT_STRING, "name", &name,
1354                                         /* seen in the wild */
1355                                         G_MARKUP_COLLECT_STRING | G_MARKUP_COLLECT_OPTIONAL, "version", NULL,
1356                                         G_MARKUP_COLLECT_INVALID))
1357         goto out;
1358
1359       g_dbus_method_info_set (data,
1360                               parse_data_get_method (data, TRUE),
1361                               name,
1362                               NULL,
1363                               NULL,
1364                               NULL);
1365
1366       data->num_args = 0;
1367
1368     }
1369   /* ---------------------------------------------------------------------------------------------------- */
1370   else if (strcmp (element_name, "signal") == 0)
1371     {
1372       if (g_slist_length (stack) < 2 || strcmp (stack->next->data, "interface") != 0)
1373         {
1374           g_set_error_literal (error,
1375                                G_MARKUP_ERROR,
1376                                G_MARKUP_ERROR_INVALID_CONTENT,
1377                                "<signal> elements can only be embedded in <interface> elements");
1378           goto out;
1379         }
1380
1381       if (!g_markup_collect_attributes (element_name,
1382                                         attribute_names,
1383                                         attribute_values,
1384                                         error,
1385                                         G_MARKUP_COLLECT_STRING, "name", &name,
1386                                         G_MARKUP_COLLECT_INVALID))
1387         goto out;
1388
1389       g_dbus_signal_info_set (data,
1390                               parse_data_get_signal (data, TRUE),
1391                               name,
1392                               NULL,
1393                               NULL);
1394
1395       data->num_args = 0;
1396
1397     }
1398   /* ---------------------------------------------------------------------------------------------------- */
1399   else if (strcmp (element_name, "property") == 0)
1400     {
1401       GDBusPropertyInfoFlags flags;
1402
1403       if (g_slist_length (stack) < 2 || strcmp (stack->next->data, "interface") != 0)
1404         {
1405           g_set_error_literal (error,
1406                                G_MARKUP_ERROR,
1407                                G_MARKUP_ERROR_INVALID_CONTENT,
1408                                "<property> elements can only be embedded in <interface> elements");
1409           goto out;
1410         }
1411
1412       if (!g_markup_collect_attributes (element_name,
1413                                         attribute_names,
1414                                         attribute_values,
1415                                         error,
1416                                         G_MARKUP_COLLECT_STRING, "name", &name,
1417                                         G_MARKUP_COLLECT_STRING, "type", &type,
1418                                         G_MARKUP_COLLECT_STRING, "access", &access,
1419                                         G_MARKUP_COLLECT_INVALID))
1420         goto out;
1421
1422       if (strcmp (access, "read") == 0)
1423         flags = G_DBUS_PROPERTY_INFO_FLAGS_READABLE;
1424       else if (strcmp (access, "write") == 0)
1425         flags = G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE;
1426       else if (strcmp (access, "readwrite") == 0)
1427         flags = G_DBUS_PROPERTY_INFO_FLAGS_READABLE | G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE;
1428       else
1429         {
1430           g_set_error (error,
1431                        G_MARKUP_ERROR,
1432                        G_MARKUP_ERROR_INVALID_CONTENT,
1433                        "Unknown value '%s' of access attribute for element <property>",
1434                        access);
1435           goto out;
1436         }
1437
1438       g_dbus_property_info_set (data,
1439                                 parse_data_get_property (data, TRUE),
1440                                 name,
1441                                 type,
1442                                 flags,
1443                                 NULL);
1444
1445     }
1446   /* ---------------------------------------------------------------------------------------------------- */
1447   else if (strcmp (element_name, "arg") == 0)
1448     {
1449       gboolean is_in;
1450       gchar *name_to_use;
1451
1452       if (g_slist_length (stack) < 2 ||
1453           (strcmp (stack->next->data, "method") != 0 &&
1454            strcmp (stack->next->data, "signal") != 0))
1455         {
1456           g_set_error_literal (error,
1457                                G_MARKUP_ERROR,
1458                                G_MARKUP_ERROR_INVALID_CONTENT,
1459                                "<arg> elements can only be embedded in <method> or <signal> elements");
1460           goto out;
1461         }
1462
1463       if (!g_markup_collect_attributes (element_name,
1464                                         attribute_names,
1465                                         attribute_values,
1466                                         error,
1467                                         G_MARKUP_COLLECT_STRING | G_MARKUP_COLLECT_OPTIONAL, "name", &name,
1468                                         G_MARKUP_COLLECT_STRING | G_MARKUP_COLLECT_OPTIONAL, "direction", &direction,
1469                                         G_MARKUP_COLLECT_STRING, "type", &type,
1470                                         G_MARKUP_COLLECT_INVALID))
1471         goto out;
1472
1473       if (strcmp (stack->next->data, "method") == 0)
1474         is_in = TRUE;
1475       else
1476         is_in = FALSE;
1477       if (direction != NULL)
1478         {
1479           if (strcmp (direction, "in") == 0)
1480             is_in = TRUE;
1481           else if (strcmp (direction, "out") == 0)
1482             is_in = FALSE;
1483           else
1484             {
1485               g_set_error (error,
1486                            G_MARKUP_ERROR,
1487                            G_MARKUP_ERROR_INVALID_CONTENT,
1488                            "Unknown value '%s' of direction attribute",
1489                            direction);
1490               goto out;
1491             }
1492         }
1493
1494       if (is_in && strcmp (stack->next->data, "signal") == 0)
1495         {
1496           g_set_error_literal (error,
1497                                G_MARKUP_ERROR,
1498                                G_MARKUP_ERROR_INVALID_CONTENT,
1499                                "Only direction 'out' is allowed for <arg> elements embedded in <signal>");
1500           goto out;
1501         }
1502
1503       if (name == NULL)
1504         name_to_use = g_strdup_printf ("arg_%d", data->num_args);
1505       else
1506         name_to_use = g_strdup (name);
1507       data->num_args++;
1508
1509       if (is_in)
1510         {
1511           g_dbus_arg_info_set (data,
1512                                parse_data_get_arg (data, TRUE),
1513                                name_to_use,
1514                                type,
1515                                NULL);
1516           data->last_arg_was_in = TRUE;
1517         }
1518       else
1519         {
1520           g_dbus_arg_info_set (data,
1521                                parse_data_get_out_arg (data, TRUE),
1522                                name_to_use,
1523                                type,
1524                                NULL);
1525           data->last_arg_was_in = FALSE;
1526
1527         }
1528
1529       g_free (name_to_use);
1530     }
1531   /* ---------------------------------------------------------------------------------------------------- */
1532   else if (strcmp (element_name, "annotation") == 0)
1533     {
1534       if (g_slist_length (stack) < 2 ||
1535           (strcmp (stack->next->data, "node") != 0 &&
1536            strcmp (stack->next->data, "interface") != 0 &&
1537            strcmp (stack->next->data, "signal") != 0 &&
1538            strcmp (stack->next->data, "method") != 0 &&
1539            strcmp (stack->next->data, "property") != 0 &&
1540            strcmp (stack->next->data, "arg") != 0 &&
1541            strcmp (stack->next->data, "annotation") != 0))
1542         {
1543           g_set_error_literal (error,
1544                                G_MARKUP_ERROR,
1545                                G_MARKUP_ERROR_INVALID_CONTENT,
1546                                "<annotation> elements can only be embedded in <node>, <interface>, <signal>, <method>, <property>, <arg> or <annotation> elements");
1547           goto out;
1548         }
1549
1550       if (!g_markup_collect_attributes (element_name,
1551                                         attribute_names,
1552                                         attribute_values,
1553                                         error,
1554                                         G_MARKUP_COLLECT_STRING, "name", &name,
1555                                         G_MARKUP_COLLECT_STRING, "value", &value,
1556                                         G_MARKUP_COLLECT_INVALID))
1557         goto out;
1558
1559       g_dbus_annotation_info_set (data,
1560                                   parse_data_get_annotation (data, TRUE),
1561                                   name,
1562                                   value,
1563                                   NULL);
1564     }
1565   /* ---------------------------------------------------------------------------------------------------- */
1566   else
1567     {
1568       /* don't bail on unknown elements; just ignore them */
1569     }
1570   /* ---------------------------------------------------------------------------------------------------- */
1571
1572   /* push the currently retrieved annotations on the stack and prepare a new one */
1573   data->annotations_stack = g_slist_prepend (data->annotations_stack, data->annotations);
1574   data->annotations = NULL;
1575   parse_data_steal_annotations (data, NULL);
1576
1577  out:
1578   ;
1579 }
1580
1581 /* ---------------------------------------------------------------------------------------------------- */
1582
1583 static GDBusAnnotationInfo **
1584 steal_annotations (ParseData *data)
1585 {
1586   return parse_data_steal_annotations (data, NULL);
1587 }
1588
1589
1590 static void
1591 parser_end_element (GMarkupParseContext  *context,
1592                     const gchar          *element_name,
1593                     gpointer              user_data,
1594                     GError              **error)
1595 {
1596   ParseData *data = user_data;
1597   gboolean have_popped_annotations;
1598
1599   have_popped_annotations = FALSE;
1600
1601   if (strcmp (element_name, "node") == 0)
1602     {
1603       guint num_nodes;
1604       guint num_interfaces;
1605       GDBusNodeInfo **nodes;
1606       GDBusInterfaceInfo **interfaces;
1607
1608       nodes = parse_data_steal_nodes (data, &num_nodes);
1609       interfaces = parse_data_steal_interfaces (data, &num_interfaces);
1610
1611       /* destroy the nodes, interfaces for scope we're exiting and and pop the nodes, interfaces from the
1612        * scope we're reentering
1613        */
1614       parse_data_free_interfaces (data);
1615       data->interfaces = (GPtrArray *) data->interfaces_stack->data;
1616       data->interfaces_stack = g_slist_remove (data->interfaces_stack, data->interfaces_stack->data);
1617
1618       parse_data_free_nodes (data);
1619       data->nodes = (GPtrArray *) data->nodes_stack->data;
1620       data->nodes_stack = g_slist_remove (data->nodes_stack, data->nodes_stack->data);
1621
1622       g_dbus_node_info_set (data,
1623                             parse_data_get_node (data, FALSE),
1624                             NULL,
1625                             interfaces,
1626                             nodes,
1627                             steal_annotations (data));
1628
1629     }
1630   else if (strcmp (element_name, "interface") == 0)
1631     {
1632       guint num_methods;
1633       guint num_signals;
1634       guint num_properties;
1635       GDBusMethodInfo **methods;
1636       GDBusSignalInfo **signals;
1637       GDBusPropertyInfo **properties;
1638
1639       methods    = parse_data_steal_methods    (data, &num_methods);
1640       signals    = parse_data_steal_signals    (data, &num_signals);
1641       properties = parse_data_steal_properties (data, &num_properties);
1642
1643       g_dbus_interface_info_set (data,
1644                                  parse_data_get_interface (data, FALSE),
1645                                  NULL,
1646                                  methods,
1647                                  signals,
1648                                  properties,
1649                                  steal_annotations (data));
1650
1651     }
1652   else if (strcmp (element_name, "method") == 0)
1653     {
1654       guint in_num_args;
1655       guint out_num_args;
1656       GDBusArgInfo **in_args;
1657       GDBusArgInfo **out_args;
1658
1659       in_args  = parse_data_steal_args     (data, &in_num_args);
1660       out_args = parse_data_steal_out_args (data, &out_num_args);
1661
1662       g_dbus_method_info_set (data,
1663                               parse_data_get_method (data, FALSE),
1664                               NULL,
1665                               in_args,
1666                               out_args,
1667                               steal_annotations (data));
1668     }
1669   else if (strcmp (element_name, "signal") == 0)
1670     {
1671       guint num_args;
1672       GDBusArgInfo **args;
1673
1674       args = parse_data_steal_out_args (data, &num_args);
1675
1676       g_dbus_signal_info_set (data,
1677                               parse_data_get_signal (data, FALSE),
1678                               NULL,
1679                               args,
1680                               steal_annotations (data));
1681     }
1682   else if (strcmp (element_name, "property") == 0)
1683     {
1684       g_dbus_property_info_set (data,
1685                                 parse_data_get_property (data, FALSE),
1686                                 NULL,
1687                                 NULL,
1688                                 G_DBUS_PROPERTY_INFO_FLAGS_NONE,
1689                                 steal_annotations (data));
1690     }
1691   else if (strcmp (element_name, "arg") == 0)
1692     {
1693       g_dbus_arg_info_set (data,
1694                            data->last_arg_was_in ? parse_data_get_arg (data, FALSE) : parse_data_get_out_arg (data, FALSE),
1695                            NULL,
1696                            NULL,
1697                            steal_annotations (data));
1698     }
1699   else if (strcmp (element_name, "annotation") == 0)
1700     {
1701       GDBusAnnotationInfo **embedded_annotations;
1702
1703       embedded_annotations = steal_annotations (data);
1704
1705       /* destroy the annotations for scope we're exiting and and pop the annotations from the scope we're reentering */
1706       parse_data_free_annotations (data);
1707       data->annotations = (GPtrArray *) data->annotations_stack->data;
1708       data->annotations_stack = g_slist_remove (data->annotations_stack, data->annotations_stack->data);
1709
1710       have_popped_annotations = TRUE;
1711
1712       g_dbus_annotation_info_set (data,
1713                                   parse_data_get_annotation (data, FALSE),
1714                                   NULL,
1715                                   NULL,
1716                                   embedded_annotations);
1717     }
1718   else
1719     {
1720       /* don't bail on unknown elements; just ignore them */
1721     }
1722
1723   if (!have_popped_annotations)
1724     {
1725       /* destroy the annotations for scope we're exiting and and pop the annotations from the scope we're reentering */
1726       parse_data_free_annotations (data);
1727       data->annotations = (GPtrArray *) data->annotations_stack->data;
1728       data->annotations_stack = g_slist_remove (data->annotations_stack, data->annotations_stack->data);
1729     }
1730 }
1731
1732 /* ---------------------------------------------------------------------------------------------------- */
1733
1734 static void
1735 parser_error (GMarkupParseContext *context,
1736               GError              *error,
1737               gpointer             user_data)
1738 {
1739   gint line_number;
1740   gint char_number;
1741
1742   g_markup_parse_context_get_position (context, &line_number, &char_number);
1743
1744   g_prefix_error (&error, "%d:%d: ",
1745                   line_number,
1746                   char_number);
1747 }
1748
1749 /* ---------------------------------------------------------------------------------------------------- */
1750
1751 /**
1752  * g_dbus_node_info_new_for_xml:
1753  * @xml_data: Valid D-Bus introspection XML.
1754  * @error: Return location for error.
1755  *
1756  * Parses @xml_data and returns a #GDBusNodeInfo representing the data.
1757  *
1758  * The introspection XML must contain exactly one top-level
1759  * <tag class="starttag">node</tag> element.
1760  *
1761  * Note that this routine is using a
1762  * <link linkend="glib-Simple-XML-Subset-Parser.description">GMarkup</link>-based
1763  * parser that only accepts a subset of valid XML documents.
1764  *
1765  * Returns: A #GDBusNodeInfo structure or %NULL if @error is set. Free
1766  * with g_dbus_node_info_unref().
1767  *
1768  * Since: 2.26
1769  */
1770 GDBusNodeInfo *
1771 g_dbus_node_info_new_for_xml (const gchar  *xml_data,
1772                               GError      **error)
1773 {
1774   GDBusNodeInfo *ret;
1775   GMarkupParseContext *context;
1776   GMarkupParser *parser;
1777   guint num_nodes;
1778   ParseData *data;
1779   GDBusNodeInfo **ughret;
1780
1781   ret = NULL;
1782   parser = NULL;
1783   context = NULL;
1784
1785   parser = g_new0 (GMarkupParser, 1);
1786   parser->start_element = parser_start_element;
1787   parser->end_element   = parser_end_element;
1788   parser->error         = parser_error;
1789
1790   data = parse_data_new ();
1791   context = g_markup_parse_context_new (parser,
1792                                         0,
1793                                         data,
1794                                         (GDestroyNotify) parse_data_free);
1795
1796   if (!g_markup_parse_context_parse (context,
1797                                      xml_data,
1798                                      strlen (xml_data),
1799                                      error))
1800     goto out;
1801
1802   if (!g_markup_parse_context_end_parse (context, error))
1803     goto out;
1804
1805   ughret = parse_data_steal_nodes (data, &num_nodes);
1806
1807   if (num_nodes != 1)
1808     {
1809       guint n;
1810
1811       g_set_error (error,
1812                    G_MARKUP_ERROR,
1813                    G_MARKUP_ERROR_INVALID_CONTENT,
1814                    "Expected a single node in introspection XML, found %d",
1815                    num_nodes);
1816
1817       /* clean up */
1818       for (n = 0; n < num_nodes; n++)
1819         {
1820           g_dbus_node_info_unref (ughret[n]);
1821           ughret[n] = NULL;
1822         }
1823     }
1824
1825   ret = ughret[0];
1826   g_free (ughret);
1827
1828  out:
1829   if (parser != NULL)
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 }