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