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