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