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