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