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