GDBus: Fix obvious crasher when looking up annotations
[platform/upstream/glib.git] / gio / gdbusintrospection.c
1 /* GDBus - GLib D-Bus Library
2  *
3  * Copyright (C) 2008-2010 Red Hat, Inc.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General
16  * Public License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
18  * Boston, MA 02111-1307, USA.
19  *
20  * Author: David Zeuthen <davidz@redhat.com>
21  */
22
23 #include "config.h"
24
25 #include <stdlib.h>
26 #include <string.h>
27
28 #include "gdbusintrospection.h"
29
30 #include "glibintl.h"
31 #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_annotation_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  * @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 @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  *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 (info->path != NULL)
902     g_string_append_printf (string_builder, " name=\"%s\"", info->path);
903
904   if (info->interfaces == NULL && info->nodes == NULL && 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; info->annotations != NULL && info->annotations[n] != NULL; n++)
913         g_dbus_annotation_info_generate_xml (info->annotations[n],
914                                              indent + 2,
915                                              string_builder);
916
917       for (n = 0; info->interfaces != NULL && info->interfaces[n] != NULL; n++)
918         g_dbus_interface_info_generate_xml (info->interfaces[n],
919                                             indent + 2,
920                                             string_builder);
921
922       for (n = 0; info->nodes != NULL && info->nodes[n] != NULL; n++)
923         g_dbus_node_info_generate_xml (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,
935                               guint     *out_num_elements)
936 {
937   GDBusAnnotationInfo **ret;
938   if (out_num_elements != NULL)
939     *out_num_elements = data->annotations->len;
940   if (data->annotations == NULL)
941     ret = NULL;
942   else
943     {
944       g_ptr_array_add (data->annotations, NULL);
945       ret = (GDBusAnnotationInfo **) g_ptr_array_free (data->annotations, FALSE);
946     }
947   data->annotations = g_ptr_array_new ();
948   return ret;
949 }
950
951 static GDBusArgInfo **
952 parse_data_steal_args (ParseData *data,
953                        guint     *out_num_elements)
954 {
955   GDBusArgInfo **ret;
956   if (out_num_elements != NULL)
957     *out_num_elements = data->args->len;
958   if (data->args == NULL)
959     ret = NULL;
960   else
961     {
962       g_ptr_array_add (data->args, NULL);
963       ret = (GDBusArgInfo **) g_ptr_array_free (data->args, FALSE);
964     }
965   data->args = g_ptr_array_new ();
966   return ret;
967 }
968
969 static GDBusArgInfo **
970 parse_data_steal_out_args (ParseData *data,
971                            guint     *out_num_elements)
972 {
973   GDBusArgInfo **ret;
974   if (out_num_elements != NULL)
975     *out_num_elements = data->out_args->len;
976   if (data->out_args == NULL)
977     ret = NULL;
978   else
979     {
980       g_ptr_array_add (data->out_args, NULL);
981       ret = (GDBusArgInfo **) g_ptr_array_free (data->out_args, FALSE);
982     }
983   data->out_args = g_ptr_array_new ();
984   return ret;
985 }
986
987 static GDBusMethodInfo **
988 parse_data_steal_methods (ParseData *data,
989                           guint     *out_num_elements)
990 {
991   GDBusMethodInfo **ret;
992   if (out_num_elements != NULL)
993     *out_num_elements = data->methods->len;
994   if (data->methods == NULL)
995     ret = NULL;
996   else
997     {
998       g_ptr_array_add (data->methods, NULL);
999       ret = (GDBusMethodInfo **) g_ptr_array_free (data->methods, FALSE);
1000     }
1001   data->methods = g_ptr_array_new ();
1002   return ret;
1003 }
1004
1005 static GDBusSignalInfo **
1006 parse_data_steal_signals (ParseData *data,
1007                           guint     *out_num_elements)
1008 {
1009   GDBusSignalInfo **ret;
1010   if (out_num_elements != NULL)
1011     *out_num_elements = data->signals->len;
1012   if (data->signals == NULL)
1013     ret = NULL;
1014   else
1015     {
1016       g_ptr_array_add (data->signals, NULL);
1017       ret = (GDBusSignalInfo **) g_ptr_array_free (data->signals, FALSE);
1018     }
1019   data->signals = g_ptr_array_new ();
1020   return ret;
1021 }
1022
1023 static GDBusPropertyInfo **
1024 parse_data_steal_properties (ParseData *data,
1025                              guint     *out_num_elements)
1026 {
1027   GDBusPropertyInfo **ret;
1028   if (out_num_elements != NULL)
1029     *out_num_elements = data->properties->len;
1030   if (data->properties == NULL)
1031     ret = NULL;
1032   else
1033     {
1034       g_ptr_array_add (data->properties, NULL);
1035       ret = (GDBusPropertyInfo **) g_ptr_array_free (data->properties, FALSE);
1036     }
1037   data->properties = g_ptr_array_new ();
1038   return ret;
1039 }
1040
1041 static GDBusInterfaceInfo **
1042 parse_data_steal_interfaces (ParseData *data,
1043                              guint     *out_num_elements)
1044 {
1045   GDBusInterfaceInfo **ret;
1046   if (out_num_elements != NULL)
1047     *out_num_elements = data->interfaces->len;
1048   if (data->interfaces == NULL)
1049     ret = NULL;
1050   else
1051     {
1052       g_ptr_array_add (data->interfaces, NULL);
1053       ret = (GDBusInterfaceInfo **) g_ptr_array_free (data->interfaces, FALSE);
1054     }
1055   data->interfaces = g_ptr_array_new ();
1056   return ret;
1057 }
1058
1059 static GDBusNodeInfo **
1060 parse_data_steal_nodes (ParseData *data,
1061                         guint     *out_num_elements)
1062 {
1063   GDBusNodeInfo **ret;
1064   if (out_num_elements != NULL)
1065     *out_num_elements = data->nodes->len;
1066   if (data->nodes == NULL)
1067     ret = NULL;
1068   else
1069     {
1070       g_ptr_array_add (data->nodes, NULL);
1071       ret = (GDBusNodeInfo **) g_ptr_array_free (data->nodes, FALSE);
1072     }
1073   data->nodes = g_ptr_array_new ();
1074   return ret;
1075 }
1076
1077 /* ---------------------------------------------------------------------------------------------------- */
1078
1079 static void
1080 parse_data_free_annotations (ParseData *data)
1081 {
1082   if (data->annotations == NULL)
1083     return;
1084   g_ptr_array_foreach (data->annotations, (GFunc) g_dbus_annotation_info_unref, NULL);
1085   g_ptr_array_free (data->annotations, TRUE);
1086   data->annotations = NULL;
1087 }
1088
1089 static void
1090 parse_data_free_args (ParseData *data)
1091 {
1092   if (data->args == NULL)
1093     return;
1094   g_ptr_array_foreach (data->args, (GFunc) g_dbus_arg_info_unref, NULL);
1095   g_ptr_array_free (data->args, TRUE);
1096   data->args = NULL;
1097 }
1098
1099 static void
1100 parse_data_free_out_args (ParseData *data)
1101 {
1102   if (data->out_args == NULL)
1103     return;
1104   g_ptr_array_foreach (data->out_args, (GFunc) g_dbus_arg_info_unref, NULL);
1105   g_ptr_array_free (data->out_args, TRUE);
1106   data->out_args = NULL;
1107 }
1108
1109 static void
1110 parse_data_free_methods (ParseData *data)
1111 {
1112   if (data->methods == NULL)
1113     return;
1114   g_ptr_array_foreach (data->methods, (GFunc) g_dbus_method_info_unref, NULL);
1115   g_ptr_array_free (data->methods, TRUE);
1116   data->methods = NULL;
1117 }
1118
1119 static void
1120 parse_data_free_signals (ParseData *data)
1121 {
1122   if (data->signals == NULL)
1123     return;
1124   g_ptr_array_foreach (data->signals, (GFunc) g_dbus_signal_info_unref, NULL);
1125   g_ptr_array_free (data->signals, TRUE);
1126   data->signals = NULL;
1127 }
1128
1129 static void
1130 parse_data_free_properties (ParseData *data)
1131 {
1132   if (data->properties == NULL)
1133     return;
1134   g_ptr_array_foreach (data->properties, (GFunc) g_dbus_property_info_unref, NULL);
1135   g_ptr_array_free (data->properties, TRUE);
1136   data->properties = NULL;
1137 }
1138
1139 static void
1140 parse_data_free_interfaces (ParseData *data)
1141 {
1142   if (data->interfaces == NULL)
1143     return;
1144   g_ptr_array_foreach (data->interfaces, (GFunc) g_dbus_interface_info_unref, NULL);
1145   g_ptr_array_free (data->interfaces, TRUE);
1146   data->interfaces = NULL;
1147 }
1148
1149 static void
1150 parse_data_free_nodes (ParseData *data)
1151 {
1152   if (data->nodes == NULL)
1153     return;
1154   g_ptr_array_foreach (data->nodes, (GFunc) g_dbus_node_info_unref, NULL);
1155   g_ptr_array_free (data->nodes, TRUE);
1156   data->nodes = NULL;
1157 }
1158
1159 /* ---------------------------------------------------------------------------------------------------- */
1160
1161 static GDBusAnnotationInfo *
1162 parse_data_get_annotation (ParseData *data,
1163                            gboolean   create_new)
1164 {
1165   if (create_new)
1166     g_ptr_array_add (data->annotations, g_new0 (GDBusAnnotationInfo, 1));
1167   return data->annotations->pdata[data->annotations->len - 1];
1168 }
1169
1170 static GDBusArgInfo *
1171 parse_data_get_arg (ParseData *data,
1172                     gboolean   create_new)
1173 {
1174   if (create_new)
1175     g_ptr_array_add (data->args, g_new0 (GDBusArgInfo, 1));
1176   return data->args->pdata[data->args->len - 1];
1177 }
1178
1179 static GDBusArgInfo *
1180 parse_data_get_out_arg (ParseData *data,
1181                         gboolean   create_new)
1182 {
1183   if (create_new)
1184     g_ptr_array_add (data->out_args, g_new0 (GDBusArgInfo, 1));
1185   return data->out_args->pdata[data->out_args->len - 1];
1186 }
1187
1188 static GDBusMethodInfo *
1189 parse_data_get_method (ParseData *data,
1190                        gboolean   create_new)
1191 {
1192   if (create_new)
1193     g_ptr_array_add (data->methods, g_new0 (GDBusMethodInfo, 1));
1194   return data->methods->pdata[data->methods->len - 1];
1195 }
1196
1197 static GDBusSignalInfo *
1198 parse_data_get_signal (ParseData *data,
1199                        gboolean   create_new)
1200 {
1201   if (create_new)
1202     g_ptr_array_add (data->signals, g_new0 (GDBusSignalInfo, 1));
1203   return data->signals->pdata[data->signals->len - 1];
1204 }
1205
1206 static GDBusPropertyInfo *
1207 parse_data_get_property (ParseData *data,
1208                          gboolean   create_new)
1209 {
1210   if (create_new)
1211     g_ptr_array_add (data->properties, g_new0 (GDBusPropertyInfo, 1));
1212   return data->properties->pdata[data->properties->len - 1];
1213 }
1214
1215 static GDBusInterfaceInfo *
1216 parse_data_get_interface (ParseData *data,
1217                           gboolean   create_new)
1218 {
1219   if (create_new)
1220     g_ptr_array_add (data->interfaces, g_new0 (GDBusInterfaceInfo, 1));
1221   return data->interfaces->pdata[data->interfaces->len - 1];
1222 }
1223
1224 static GDBusNodeInfo *
1225 parse_data_get_node (ParseData *data,
1226                      gboolean   create_new)
1227 {
1228   if (create_new)
1229     g_ptr_array_add (data->nodes, g_new0 (GDBusNodeInfo, 1));
1230   return data->nodes->pdata[data->nodes->len - 1];
1231 }
1232
1233 /* ---------------------------------------------------------------------------------------------------- */
1234
1235 static ParseData *
1236 parse_data_new (void)
1237 {
1238   ParseData *data;
1239
1240   data = g_new0 (ParseData, 1);
1241
1242   /* initialize arrays */
1243   parse_data_steal_annotations (data, NULL);
1244   parse_data_steal_args (data, NULL);
1245   parse_data_steal_out_args (data, NULL);
1246   parse_data_steal_methods (data, NULL);
1247   parse_data_steal_signals (data, NULL);
1248   parse_data_steal_properties (data, NULL);
1249   parse_data_steal_interfaces (data, NULL);
1250   parse_data_steal_nodes (data, NULL);
1251
1252   return data;
1253 }
1254
1255 static void
1256 parse_data_free (ParseData *data)
1257 {
1258   GSList *l;
1259
1260   /* free stack of annotation arrays */
1261   for (l = data->annotations_stack; l != NULL; l = l->next)
1262     {
1263       GPtrArray *annotations = l->data;
1264       g_ptr_array_foreach (annotations, (GFunc) g_dbus_annotation_info_unref, NULL);
1265       g_ptr_array_free (annotations, TRUE);
1266     }
1267   g_slist_free (data->annotations_stack);
1268
1269   /* free stack of interface arrays */
1270   for (l = data->interfaces_stack; l != NULL; l = l->next)
1271     {
1272       GPtrArray *interfaces = l->data;
1273       g_ptr_array_foreach (interfaces, (GFunc) g_dbus_interface_info_unref, NULL);
1274       g_ptr_array_free (interfaces, TRUE);
1275     }
1276   g_slist_free (data->interfaces_stack);
1277
1278   /* free stack of node arrays */
1279   for (l = data->nodes_stack; l != NULL; l = l->next)
1280     {
1281       GPtrArray *nodes = l->data;
1282       g_ptr_array_foreach (nodes, (GFunc) g_dbus_node_info_unref, NULL);
1283       g_ptr_array_free (nodes, TRUE);
1284     }
1285   g_slist_free (data->nodes_stack);
1286
1287   /* free arrays (data->annotations, data->interfaces and data->nodes have been freed above) */
1288   parse_data_free_args (data);
1289   parse_data_free_out_args (data);
1290   parse_data_free_methods (data);
1291   parse_data_free_signals (data);
1292   parse_data_free_properties (data);
1293
1294   g_free (data);
1295 }
1296
1297 /* ---------------------------------------------------------------------------------------------------- */
1298
1299 static void
1300 parser_start_element (GMarkupParseContext  *context,
1301                       const gchar          *element_name,
1302                       const gchar         **attribute_names,
1303                       const gchar         **attribute_values,
1304                       gpointer              user_data,
1305                       GError              **error)
1306 {
1307   ParseData *data = user_data;
1308   GSList *stack;
1309   const gchar *name;
1310   const gchar *type;
1311   const gchar *access;
1312   const gchar *direction;
1313   const gchar *value;
1314
1315   name = NULL;
1316   type = NULL;
1317   access = NULL;
1318   direction = NULL;
1319   value = NULL;
1320
1321   stack = (GSList *) g_markup_parse_context_get_element_stack (context);
1322
1323   /* ---------------------------------------------------------------------------------------------------- */
1324   if (strcmp (element_name, "node") == 0)
1325     {
1326       if (!(g_slist_length (stack) >= 1 || strcmp (stack->next->data, "node") != 0))
1327         {
1328           g_set_error_literal (error,
1329                                G_MARKUP_ERROR,
1330                                G_MARKUP_ERROR_INVALID_CONTENT,
1331                                "<node> elements can only be top-level or embedded in other <node> elements");
1332           goto out;
1333         }
1334
1335       if (!g_markup_collect_attributes (element_name,
1336                                         attribute_names,
1337                                         attribute_values,
1338                                         error,
1339                                         G_MARKUP_COLLECT_STRING | G_MARKUP_COLLECT_OPTIONAL, "name", &name,
1340                                         /* some hand-written introspection XML documents use this */
1341                                         G_MARKUP_COLLECT_STRING | G_MARKUP_COLLECT_OPTIONAL, "xmlns:doc", NULL,
1342                                         G_MARKUP_COLLECT_INVALID))
1343         goto out;
1344
1345       g_dbus_node_info_set (data,
1346                             parse_data_get_node (data, TRUE),
1347                             name,
1348                             0, NULL,
1349                             0, NULL,
1350                             NULL);
1351
1352       /* push the currently retrieved interfaces and nodes on the stack and prepare new arrays */
1353       data->interfaces_stack = g_slist_prepend (data->interfaces_stack, data->interfaces);
1354       data->interfaces = NULL;
1355       parse_data_steal_interfaces (data, NULL);
1356
1357       data->nodes_stack = g_slist_prepend (data->nodes_stack, data->nodes);
1358       data->nodes = NULL;
1359       parse_data_steal_nodes (data, NULL);
1360
1361     }
1362   /* ---------------------------------------------------------------------------------------------------- */
1363   else if (strcmp (element_name, "interface") == 0)
1364     {
1365       if (g_slist_length (stack) < 2 || strcmp (stack->next->data, "node") != 0)
1366         {
1367           g_set_error_literal (error,
1368                                G_MARKUP_ERROR,
1369                                G_MARKUP_ERROR_INVALID_CONTENT,
1370                                "<interface> elements can only be embedded in <node> elements");
1371           goto out;
1372         }
1373
1374       if (!g_markup_collect_attributes (element_name,
1375                                         attribute_names,
1376                                         attribute_values,
1377                                         error,
1378                                         G_MARKUP_COLLECT_STRING, "name", &name,
1379                                         G_MARKUP_COLLECT_INVALID))
1380         goto out;
1381
1382       g_dbus_interface_info_set (data,
1383                                  parse_data_get_interface (data, TRUE),
1384                                  name,
1385                                  0, NULL,
1386                                  0, NULL,
1387                                  0, NULL,
1388                                  NULL);
1389
1390     }
1391   /* ---------------------------------------------------------------------------------------------------- */
1392   else if (strcmp (element_name, "method") == 0)
1393     {
1394       if (g_slist_length (stack) < 2 || strcmp (stack->next->data, "interface") != 0)
1395         {
1396           g_set_error_literal (error,
1397                                G_MARKUP_ERROR,
1398                                G_MARKUP_ERROR_INVALID_CONTENT,
1399                                "<method> elements can only be embedded in <interface> elements");
1400           goto out;
1401         }
1402
1403       if (!g_markup_collect_attributes (element_name,
1404                                         attribute_names,
1405                                         attribute_values,
1406                                         error,
1407                                         G_MARKUP_COLLECT_STRING, "name", &name,
1408                                         G_MARKUP_COLLECT_INVALID))
1409         goto out;
1410
1411       g_dbus_method_info_set (data,
1412                               parse_data_get_method (data, TRUE),
1413                               name,
1414                               0, NULL,
1415                               0, NULL,
1416                               NULL);
1417
1418       data->num_args = 0;
1419
1420     }
1421   /* ---------------------------------------------------------------------------------------------------- */
1422   else if (strcmp (element_name, "signal") == 0)
1423     {
1424       if (g_slist_length (stack) < 2 || strcmp (stack->next->data, "interface") != 0)
1425         {
1426           g_set_error_literal (error,
1427                                G_MARKUP_ERROR,
1428                                G_MARKUP_ERROR_INVALID_CONTENT,
1429                                "<signal> elements can only be embedded in <interface> elements");
1430           goto out;
1431         }
1432
1433       if (!g_markup_collect_attributes (element_name,
1434                                         attribute_names,
1435                                         attribute_values,
1436                                         error,
1437                                         G_MARKUP_COLLECT_STRING, "name", &name,
1438                                         G_MARKUP_COLLECT_INVALID))
1439         goto out;
1440
1441       g_dbus_signal_info_set (data,
1442                               parse_data_get_signal (data, TRUE),
1443                               name,
1444                               0, NULL,
1445                               NULL);
1446
1447       data->num_args = 0;
1448
1449     }
1450   /* ---------------------------------------------------------------------------------------------------- */
1451   else if (strcmp (element_name, "property") == 0)
1452     {
1453       GDBusPropertyInfoFlags flags;
1454
1455       if (g_slist_length (stack) < 2 || strcmp (stack->next->data, "interface") != 0)
1456         {
1457           g_set_error_literal (error,
1458                                G_MARKUP_ERROR,
1459                                G_MARKUP_ERROR_INVALID_CONTENT,
1460                                "<property> elements can only be embedded in <interface> elements");
1461           goto out;
1462         }
1463
1464       if (!g_markup_collect_attributes (element_name,
1465                                         attribute_names,
1466                                         attribute_values,
1467                                         error,
1468                                         G_MARKUP_COLLECT_STRING, "name", &name,
1469                                         G_MARKUP_COLLECT_STRING, "type", &type,
1470                                         G_MARKUP_COLLECT_STRING, "access", &access,
1471                                         G_MARKUP_COLLECT_INVALID))
1472         goto out;
1473
1474       if (strcmp (access, "read") == 0)
1475         flags = G_DBUS_PROPERTY_INFO_FLAGS_READABLE;
1476       else if (strcmp (access, "write") == 0)
1477         flags = G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE;
1478       else if (strcmp (access, "readwrite") == 0)
1479         flags = G_DBUS_PROPERTY_INFO_FLAGS_READABLE | G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE;
1480       else
1481         {
1482           g_set_error (error,
1483                        G_MARKUP_ERROR,
1484                        G_MARKUP_ERROR_INVALID_CONTENT,
1485                        "Unknown value '%s' of access attribute for element <property>",
1486                        access);
1487           goto out;
1488         }
1489
1490       g_dbus_property_info_set (data,
1491                                 parse_data_get_property (data, TRUE),
1492                                 name,
1493                                 type,
1494                                 flags,
1495                                 NULL);
1496
1497     }
1498   /* ---------------------------------------------------------------------------------------------------- */
1499   else if (strcmp (element_name, "arg") == 0)
1500     {
1501       gboolean is_in;
1502       gchar *name_to_use;
1503
1504       if (g_slist_length (stack) < 2 ||
1505           (strcmp (stack->next->data, "method") != 0 &&
1506            strcmp (stack->next->data, "signal") != 0))
1507         {
1508           g_set_error_literal (error,
1509                                G_MARKUP_ERROR,
1510                                G_MARKUP_ERROR_INVALID_CONTENT,
1511                                "<arg> elements can only be embedded in <method> or <signal> elements");
1512           goto out;
1513         }
1514
1515       if (!g_markup_collect_attributes (element_name,
1516                                         attribute_names,
1517                                         attribute_values,
1518                                         error,
1519                                         G_MARKUP_COLLECT_STRING | G_MARKUP_COLLECT_OPTIONAL, "name", &name,
1520                                         G_MARKUP_COLLECT_STRING | G_MARKUP_COLLECT_OPTIONAL, "direction", &direction,
1521                                         G_MARKUP_COLLECT_STRING, "type", &type,
1522                                         G_MARKUP_COLLECT_INVALID))
1523         goto out;
1524
1525       is_in = FALSE;
1526       if (direction != NULL)
1527         {
1528           if (strcmp (direction, "in") == 0)
1529             is_in = TRUE;
1530           else if (strcmp (direction, "out") == 0)
1531             is_in = FALSE;
1532           else
1533             {
1534               g_set_error (error,
1535                            G_MARKUP_ERROR,
1536                            G_MARKUP_ERROR_INVALID_CONTENT,
1537                            "Unknown value '%s' of direction attribute",
1538                            direction);
1539               goto out;
1540             }
1541         }
1542
1543       if (is_in && strcmp (stack->next->data, "signal") == 0)
1544         {
1545           g_set_error_literal (error,
1546                                G_MARKUP_ERROR,
1547                                G_MARKUP_ERROR_INVALID_CONTENT,
1548                                "Only direction 'out' is allowed for <arg> elements embedded in <signal>");
1549           goto out;
1550         }
1551
1552       if (name == NULL)
1553         name_to_use = g_strdup_printf ("arg_%d", data->num_args);
1554       else
1555         name_to_use = g_strdup (name);
1556       data->num_args++;
1557
1558       if (is_in)
1559         {
1560           g_dbus_arg_info_set (data,
1561                                parse_data_get_arg (data, TRUE),
1562                                name_to_use,
1563                                type,
1564                                NULL);
1565           data->last_arg_was_in = TRUE;
1566         }
1567       else
1568         {
1569           g_dbus_arg_info_set (data,
1570                                parse_data_get_out_arg (data, TRUE),
1571                                name_to_use,
1572                                type,
1573                                NULL);
1574           data->last_arg_was_in = FALSE;
1575
1576         }
1577
1578       g_free (name_to_use);
1579     }
1580   /* ---------------------------------------------------------------------------------------------------- */
1581   else if (strcmp (element_name, "annotation") == 0)
1582     {
1583       if (g_slist_length (stack) < 2 ||
1584           (strcmp (stack->next->data, "node") != 0 &&
1585            strcmp (stack->next->data, "interface") != 0 &&
1586            strcmp (stack->next->data, "signal") != 0 &&
1587            strcmp (stack->next->data, "method") != 0 &&
1588            strcmp (stack->next->data, "property") != 0 &&
1589            strcmp (stack->next->data, "arg") != 0 &&
1590            strcmp (stack->next->data, "annotation") != 0))
1591         {
1592           g_set_error_literal (error,
1593                                G_MARKUP_ERROR,
1594                                G_MARKUP_ERROR_INVALID_CONTENT,
1595                                "<annotation> elements can only be embedded in <node>, <interface>, <signal>, <method>, <property>, <arg> or <annotation> elements");
1596           goto out;
1597         }
1598
1599       if (!g_markup_collect_attributes (element_name,
1600                                         attribute_names,
1601                                         attribute_values,
1602                                         error,
1603                                         G_MARKUP_COLLECT_STRING, "name", &name,
1604                                         G_MARKUP_COLLECT_STRING, "value", &value,
1605                                         G_MARKUP_COLLECT_INVALID))
1606         goto out;
1607
1608       g_dbus_annotation_info_set (data,
1609                                   parse_data_get_annotation (data, TRUE),
1610                                   name,
1611                                   value,
1612                                   NULL);
1613     }
1614   /* ---------------------------------------------------------------------------------------------------- */
1615   else
1616     {
1617       /* don't bail on unknown elements; just ignore them */
1618     }
1619   /* ---------------------------------------------------------------------------------------------------- */
1620
1621   /* push the currently retrieved annotations on the stack and prepare a new one */
1622   data->annotations_stack = g_slist_prepend (data->annotations_stack, data->annotations);
1623   data->annotations = NULL;
1624   parse_data_steal_annotations (data, NULL);
1625
1626  out:
1627   ;
1628 }
1629
1630 /* ---------------------------------------------------------------------------------------------------- */
1631
1632 static GDBusAnnotationInfo **
1633 steal_annotations (ParseData *data)
1634 {
1635   return parse_data_steal_annotations (data, NULL);
1636 }
1637
1638
1639 static void
1640 parser_end_element (GMarkupParseContext  *context,
1641                     const gchar          *element_name,
1642                     gpointer              user_data,
1643                     GError              **error)
1644 {
1645   ParseData *data = user_data;
1646   gboolean have_popped_annotations;
1647
1648   have_popped_annotations = FALSE;
1649
1650   if (strcmp (element_name, "node") == 0)
1651     {
1652       guint num_nodes;
1653       guint num_interfaces;
1654       GDBusNodeInfo **nodes;
1655       GDBusInterfaceInfo **interfaces;
1656
1657       nodes = parse_data_steal_nodes (data, &num_nodes);
1658       interfaces = parse_data_steal_interfaces (data, &num_interfaces);
1659
1660       /* destroy the nodes, interfaces for scope we're exiting and and pop the nodes, interfaces from the
1661        * scope we're reentering
1662        */
1663       parse_data_free_interfaces (data);
1664       data->interfaces = (GPtrArray *) data->interfaces_stack->data;
1665       data->interfaces_stack = g_slist_remove (data->interfaces_stack, data->interfaces_stack->data);
1666
1667       parse_data_free_nodes (data);
1668       data->nodes = (GPtrArray *) data->nodes_stack->data;
1669       data->nodes_stack = g_slist_remove (data->nodes_stack, data->nodes_stack->data);
1670
1671       g_dbus_node_info_set (data,
1672                             parse_data_get_node (data, FALSE),
1673                             NULL,
1674                             num_interfaces,
1675                             interfaces,
1676                             num_nodes,
1677                             nodes,
1678                             steal_annotations (data));
1679
1680     }
1681   else if (strcmp (element_name, "interface") == 0)
1682     {
1683       guint num_methods;
1684       guint num_signals;
1685       guint num_properties;
1686       GDBusMethodInfo **methods;
1687       GDBusSignalInfo **signals;
1688       GDBusPropertyInfo **properties;
1689
1690       methods    = parse_data_steal_methods    (data, &num_methods);
1691       signals    = parse_data_steal_signals    (data, &num_signals);
1692       properties = parse_data_steal_properties (data, &num_properties);
1693
1694       g_dbus_interface_info_set (data,
1695                                  parse_data_get_interface (data, FALSE),
1696                                  NULL,
1697                                  num_methods,
1698                                  methods,
1699                                  num_signals,
1700                                  signals,
1701                                  num_properties,
1702                                  properties,
1703                                  steal_annotations (data));
1704
1705     }
1706   else if (strcmp (element_name, "method") == 0)
1707     {
1708       guint in_num_args;
1709       guint out_num_args;
1710       GDBusArgInfo **in_args;
1711       GDBusArgInfo **out_args;
1712
1713       in_args  = parse_data_steal_args     (data, &in_num_args);
1714       out_args = parse_data_steal_out_args (data, &out_num_args);
1715
1716       g_dbus_method_info_set (data,
1717                               parse_data_get_method (data, FALSE),
1718                               NULL,
1719                               in_num_args,
1720                               in_args,
1721                               out_num_args,
1722                               out_args,
1723                               steal_annotations (data));
1724     }
1725   else if (strcmp (element_name, "signal") == 0)
1726     {
1727       guint num_args;
1728       GDBusArgInfo **args;
1729
1730       args = parse_data_steal_out_args (data, &num_args);
1731
1732       g_dbus_signal_info_set (data,
1733                               parse_data_get_signal (data, FALSE),
1734                               NULL,
1735                               num_args,
1736                               args,
1737                               steal_annotations (data));
1738     }
1739   else if (strcmp (element_name, "property") == 0)
1740     {
1741       g_dbus_property_info_set (data,
1742                                 parse_data_get_property (data, FALSE),
1743                                 NULL,
1744                                 NULL,
1745                                 G_DBUS_PROPERTY_INFO_FLAGS_NONE,
1746                                 steal_annotations (data));
1747     }
1748   else if (strcmp (element_name, "arg") == 0)
1749     {
1750       g_dbus_arg_info_set (data,
1751                            data->last_arg_was_in ? parse_data_get_arg (data, FALSE) : parse_data_get_out_arg (data, FALSE),
1752                            NULL,
1753                            NULL,
1754                            steal_annotations (data));
1755     }
1756   else if (strcmp (element_name, "annotation") == 0)
1757     {
1758       GDBusAnnotationInfo **embedded_annotations;
1759
1760       embedded_annotations = steal_annotations (data);
1761
1762       /* destroy the annotations for scope we're exiting and and pop the annotations from the scope we're reentering */
1763       parse_data_free_annotations (data);
1764       data->annotations = (GPtrArray *) data->annotations_stack->data;
1765       data->annotations_stack = g_slist_remove (data->annotations_stack, data->annotations_stack->data);
1766
1767       have_popped_annotations = TRUE;
1768
1769       g_dbus_annotation_info_set (data,
1770                                   parse_data_get_annotation (data, FALSE),
1771                                   NULL,
1772                                   NULL,
1773                                   embedded_annotations);
1774     }
1775   else
1776     {
1777       /* don't bail on unknown elements; just ignore them */
1778     }
1779
1780   if (!have_popped_annotations)
1781     {
1782       /* destroy the annotations for scope we're exiting and and pop the annotations from the scope we're reentering */
1783       parse_data_free_annotations (data);
1784       data->annotations = (GPtrArray *) data->annotations_stack->data;
1785       data->annotations_stack = g_slist_remove (data->annotations_stack, data->annotations_stack->data);
1786     }
1787 }
1788
1789 /* ---------------------------------------------------------------------------------------------------- */
1790
1791 static void
1792 parser_error (GMarkupParseContext *context,
1793               GError              *error,
1794               gpointer             user_data)
1795 {
1796   gint line_number;
1797   gint char_number;
1798
1799   g_markup_parse_context_get_position (context, &line_number, &char_number);
1800
1801   g_prefix_error (&error, "%d:%d: ",
1802                   line_number,
1803                   char_number);
1804 }
1805
1806 /* ---------------------------------------------------------------------------------------------------- */
1807
1808 /**
1809  * g_dbus_node_info_new_for_xml:
1810  * @xml_data: Valid D-Bus introspection XML.
1811  * @error: Return location for error.
1812  *
1813  * Parses @xml_data and returns a #GDBusNodeInfo representing the data.
1814  *
1815  * Returns: A #GDBusNodeInfo structure or %NULL if @error is set. Free
1816  * with g_dbus_node_info_unref().
1817  *
1818  * Since: 2.26
1819  */
1820 GDBusNodeInfo *
1821 g_dbus_node_info_new_for_xml (const gchar  *xml_data,
1822                               GError      **error)
1823 {
1824   GDBusNodeInfo *ret;
1825   GMarkupParseContext *context;
1826   GMarkupParser *parser;
1827   guint num_nodes;
1828   ParseData *data;
1829
1830   ret = NULL;
1831   parser = NULL;
1832   context = NULL;
1833
1834   parser = g_new0 (GMarkupParser, 1);
1835   parser->start_element = parser_start_element;
1836   parser->end_element   = parser_end_element;
1837   parser->error         = parser_error;
1838
1839   data = parse_data_new ();
1840   context = g_markup_parse_context_new (parser,
1841                                         0,
1842                                         data,
1843                                         (GDestroyNotify) parse_data_free);
1844
1845   if (!g_markup_parse_context_parse (context,
1846                                      xml_data,
1847                                      strlen (xml_data),
1848                                      error))
1849     goto out;
1850
1851   GDBusNodeInfo **ughret;
1852   ughret = parse_data_steal_nodes (data, &num_nodes);
1853
1854   if (num_nodes != 1)
1855     {
1856       guint n;
1857
1858       g_set_error (error,
1859                    G_MARKUP_ERROR,
1860                    G_MARKUP_ERROR_INVALID_CONTENT,
1861                    "Expected a single node in introspection XML, found %d",
1862                    num_nodes);
1863
1864       /* clean up */
1865       for (n = 0; n < num_nodes; n++)
1866         {
1867           for (n = 0; n < num_nodes; n++)
1868             g_dbus_node_info_unref (&(ret[n]));
1869         }
1870       g_free (ret);
1871       ret = NULL;
1872     }
1873
1874   ret = ughret[0];
1875   g_free (ughret);
1876
1877  out:
1878   if (parser != NULL)
1879     g_free (parser);
1880   if (context != NULL)
1881     g_markup_parse_context_free (context);
1882
1883   return ret;
1884 }
1885
1886 /* ---------------------------------------------------------------------------------------------------- */
1887
1888 /**
1889  * g_dbus_annotation_info_lookup:
1890  * @annotations: A %NULL-terminated array of annotations or %NULL.
1891  * @name: The name of the annotation to look up.
1892  *
1893  * Looks up the value of an annotation.
1894  *
1895  * This cost of this function is O(n) in number of annotations.
1896  *
1897  * Returns: The value or %NULL if not found. Do not free, it is owned by @annotations.
1898  *
1899  * Since: 2.26
1900  */
1901 const gchar *
1902 g_dbus_annotation_info_lookup (const GDBusAnnotationInfo **annotations,
1903                                const gchar                *name)
1904 {
1905   guint n;
1906   const gchar *ret;
1907
1908   ret = NULL;
1909   for (n = 0; annotations != NULL && annotations[n] != NULL; n++)
1910     {
1911       if (g_strcmp0 (annotations[n]->key, name) == 0)
1912         {
1913           ret = annotations[n]->value;
1914           goto out;
1915         }
1916     }
1917
1918  out:
1919   return ret;
1920 }
1921
1922 /* ---------------------------------------------------------------------------------------------------- */
1923
1924 /**
1925  * g_dbus_interface_info_lookup_method:
1926  * @info: A #GDBusInterfaceInfo.
1927  * @name: A D-Bus method name (typically in CamelCase)
1928  *
1929  * Looks up information about a method.
1930  *
1931  * This cost of this function is O(n) in number of methods.
1932  *
1933  * Returns: A #GDBusMethodInfo or %NULL if not found. Do not free, it is owned by @info.
1934  *
1935  * Since: 2.26
1936  */
1937 const GDBusMethodInfo *
1938 g_dbus_interface_info_lookup_method (const GDBusInterfaceInfo *info,
1939                                      const gchar              *name)
1940 {
1941   guint n;
1942   const GDBusMethodInfo *result;
1943
1944   for (n = 0; info->methods != NULL && info->methods[n] != NULL; n++)
1945     {
1946       const GDBusMethodInfo *i = info->methods[n];
1947
1948       if (g_strcmp0 (i->name, name) == 0)
1949         {
1950           result = i;
1951           goto out;
1952         }
1953     }
1954
1955   result = NULL;
1956
1957  out:
1958   return result;
1959 }
1960
1961 /* ---------------------------------------------------------------------------------------------------- */
1962
1963 /**
1964  * g_dbus_interface_info_lookup_signal:
1965  * @info: A #GDBusInterfaceInfo.
1966  * @name: A D-Bus signal name (typically in CamelCase)
1967  *
1968  * Looks up information about a signal.
1969  *
1970  * This cost of this function is O(n) in number of signals.
1971  *
1972  * Returns: A #GDBusSignalInfo or %NULL if not found. Do not free, it is owned by @info.
1973  *
1974  * Since: 2.26
1975  */
1976 const GDBusSignalInfo *
1977 g_dbus_interface_info_lookup_signal (const GDBusInterfaceInfo *info,
1978                                      const gchar              *name)
1979 {
1980   guint n;
1981   const GDBusSignalInfo *result;
1982
1983   for (n = 0; info->signals != NULL && info->signals[n] != NULL; n++)
1984     {
1985       const GDBusSignalInfo *i = info->signals[n];
1986
1987       if (g_strcmp0 (i->name, name) == 0)
1988         {
1989           result = i;
1990           goto out;
1991         }
1992     }
1993
1994   result = NULL;
1995
1996  out:
1997   return result;
1998 }
1999
2000 /* ---------------------------------------------------------------------------------------------------- */
2001
2002 /**
2003  * g_dbus_interface_info_lookup_property:
2004  * @info: A #GDBusInterfaceInfo.
2005  * @name: A D-Bus property name (typically in CamelCase).
2006  *
2007  * Looks up information about a property.
2008  *
2009  * This cost of this function is O(n) in number of properties.
2010  *
2011  * Returns: A #GDBusPropertyInfo or %NULL if not found. Do not free, it is owned by @info.
2012  *
2013  * Since: 2.26
2014  */
2015 const GDBusPropertyInfo *
2016 g_dbus_interface_info_lookup_property (const GDBusInterfaceInfo *info,
2017                                        const gchar              *name)
2018 {
2019   guint n;
2020   const GDBusPropertyInfo *result;
2021
2022   for (n = 0; info->properties != NULL && info->properties[n] != NULL; n++)
2023     {
2024       const GDBusPropertyInfo *i = info->properties[n];
2025
2026       if (g_strcmp0 (i->name, name) == 0)
2027         {
2028           result = i;
2029           goto out;
2030         }
2031     }
2032
2033   result = NULL;
2034
2035  out:
2036   return result;
2037 }
2038
2039 /* ---------------------------------------------------------------------------------------------------- */
2040
2041 /**
2042  * g_dbus_node_info_lookup_interface:
2043  * @info: A #GDBusNodeInfo.
2044  * @name: A D-Bus interface name.
2045  *
2046  * Looks up information about an interface.
2047  *
2048  * This cost of this function is O(n) in number of interfaces.
2049  *
2050  * Returns: A #GDBusInterfaceInfo or %NULL if not found. Do not free, it is owned by @info.
2051  *
2052  * Since: 2.26
2053  */
2054 const GDBusInterfaceInfo *
2055 g_dbus_node_info_lookup_interface (const GDBusNodeInfo *info,
2056                                    const gchar         *name)
2057 {
2058   guint n;
2059   const GDBusInterfaceInfo *result;
2060
2061   for (n = 0; info->interfaces != NULL && info->interfaces[n] != NULL; n++)
2062     {
2063       const GDBusInterfaceInfo *i = info->interfaces[n];
2064
2065       if (g_strcmp0 (i->name, name) == 0)
2066         {
2067           result = i;
2068           goto out;
2069         }
2070     }
2071
2072   result = NULL;
2073
2074  out:
2075   return result;
2076 }
2077
2078 #define __G_DBUS_INTROSPECTION_C__
2079 #include "gioaliasdef.c"