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