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 : 4 : _MY_DEFINE_BOXED_TYPE (GDBusNodeInfo, g_dbus_node_info)
38 : 251 : _MY_DEFINE_BOXED_TYPE (GDBusInterfaceInfo, g_dbus_interface_info)
39 : 4 : _MY_DEFINE_BOXED_TYPE (GDBusMethodInfo, g_dbus_method_info)
40 : 4 : _MY_DEFINE_BOXED_TYPE (GDBusSignalInfo, g_dbus_signal_info)
41 : 4 : _MY_DEFINE_BOXED_TYPE (GDBusPropertyInfo, g_dbus_property_info)
42 : 4 : _MY_DEFINE_BOXED_TYPE (GDBusArgInfo, g_dbus_arg_info)
43 : 4 : _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 : 200581 : g_dbus_interface_info_ref (GDBusInterfaceInfo *info)
115 : : {
116 : 200581 : if (g_atomic_int_get (&info->ref_count) == -1)
117 : 417 : return info;
118 : 200164 : g_atomic_int_inc (&info->ref_count);
119 : 200164 : 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 : 938 : g_dbus_method_info_ref (GDBusMethodInfo *info)
135 : : {
136 : 938 : if (g_atomic_int_get (&info->ref_count) == -1)
137 : 473 : return info;
138 : 465 : g_atomic_int_inc (&info->ref_count);
139 : 465 : 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 : 5195 : free_null_terminated_array (gpointer array, GDestroyNotify unref_func)
226 : : {
227 : : guint n;
228 : 5195 : gpointer *p = array;
229 : 5195 : if (p == NULL)
230 : 0 : return;
231 : 8234 : for (n = 0; p[n] != NULL; n++)
232 : 3039 : unref_func (p[n]);
233 : 5195 : 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 : 126 : g_dbus_annotation_info_unref (GDBusAnnotationInfo *info)
248 : : {
249 : 126 : if (g_atomic_int_get (&info->ref_count) == -1)
250 : 0 : return;
251 : 126 : if (g_atomic_int_dec_and_test (&info->ref_count))
252 : : {
253 : 126 : g_free (info->key);
254 : 126 : g_free (info->value);
255 : 126 : free_null_terminated_array (info->annotations, (GDestroyNotify) g_dbus_annotation_info_unref);
256 : 126 : 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 : 1503 : g_dbus_arg_info_unref (GDBusArgInfo *info)
272 : : {
273 : 1503 : if (g_atomic_int_get (&info->ref_count) == -1)
274 : 0 : return;
275 : 1503 : if (g_atomic_int_dec_and_test (&info->ref_count))
276 : : {
277 : 1503 : g_free (info->name);
278 : 1503 : g_free (info->signature);
279 : 1503 : free_null_terminated_array (info->annotations, (GDestroyNotify) g_dbus_annotation_info_unref);
280 : 1503 : 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 : 1430 : g_dbus_method_info_unref (GDBusMethodInfo *info)
296 : : {
297 : 1430 : if (g_atomic_int_get (&info->ref_count) == -1)
298 : 473 : return;
299 : 957 : if (g_atomic_int_dec_and_test (&info->ref_count))
300 : : {
301 : 493 : g_free (info->name);
302 : 493 : free_null_terminated_array (info->in_args, (GDestroyNotify) g_dbus_arg_info_unref);
303 : 493 : free_null_terminated_array (info->out_args, (GDestroyNotify) g_dbus_arg_info_unref);
304 : 493 : free_null_terminated_array (info->annotations, (GDestroyNotify) g_dbus_annotation_info_unref);
305 : 493 : 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 : 122 : g_dbus_signal_info_unref (GDBusSignalInfo *info)
321 : : {
322 : 122 : if (g_atomic_int_get (&info->ref_count) == -1)
323 : 0 : return;
324 : 122 : if (g_atomic_int_dec_and_test (&info->ref_count))
325 : : {
326 : 122 : g_free (info->name);
327 : 122 : free_null_terminated_array (info->args, (GDestroyNotify) g_dbus_arg_info_unref);
328 : 122 : free_null_terminated_array (info->annotations, (GDestroyNotify) g_dbus_annotation_info_unref);
329 : 122 : 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 : 512 : g_dbus_property_info_unref (GDBusPropertyInfo *info)
345 : : {
346 : 512 : if (g_atomic_int_get (&info->ref_count) == -1)
347 : 12 : return;
348 : 500 : if (g_atomic_int_dec_and_test (&info->ref_count))
349 : : {
350 : 500 : g_free (info->name);
351 : 500 : g_free (info->signature);
352 : 500 : free_null_terminated_array (info->annotations, (GDestroyNotify) g_dbus_annotation_info_unref);
353 : 500 : 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 : 201048 : g_dbus_interface_info_unref (GDBusInterfaceInfo *info)
369 : : {
370 : 201048 : if (g_atomic_int_get (&info->ref_count) == -1)
371 : 669 : return;
372 : 200379 : if (g_atomic_int_dec_and_test (&info->ref_count))
373 : : {
374 : 221 : g_free (info->name);
375 : 221 : free_null_terminated_array (info->methods, (GDestroyNotify) g_dbus_method_info_unref);
376 : 221 : free_null_terminated_array (info->signals, (GDestroyNotify) g_dbus_signal_info_unref);
377 : 221 : free_null_terminated_array (info->properties, (GDestroyNotify) g_dbus_property_info_unref);
378 : 221 : free_null_terminated_array (info->annotations, (GDestroyNotify) g_dbus_annotation_info_unref);
379 : 221 : 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 : 153 : g_dbus_node_info_unref (GDBusNodeInfo *info)
395 : : {
396 : 153 : if (g_atomic_int_get (&info->ref_count) == -1)
397 : 0 : return;
398 : 153 : if (g_atomic_int_dec_and_test (&info->ref_count))
399 : : {
400 : 153 : g_free (info->path);
401 : 153 : free_null_terminated_array (info->interfaces, (GDestroyNotify) g_dbus_interface_info_unref);
402 : 153 : free_null_terminated_array (info->nodes, (GDestroyNotify) g_dbus_node_info_unref);
403 : 153 : free_null_terminated_array (info->annotations, (GDestroyNotify) g_dbus_annotation_info_unref);
404 : 153 : g_free (info);
405 : : }
406 : : }
407 : :
408 : : /* ---------------------------------------------------------------------------------------------------- */
409 : :
410 : : static void
411 : 252 : g_dbus_annotation_info_set (ParseData *data,
412 : : GDBusAnnotationInfo *info,
413 : : const gchar *key,
414 : : const gchar *value,
415 : : GDBusAnnotationInfo **embedded_annotations)
416 : : {
417 : 252 : info->ref_count = 1;
418 : :
419 : 252 : if (key != NULL)
420 : 126 : info->key = g_strdup (key);
421 : :
422 : 252 : if (value != NULL)
423 : 126 : info->value = g_strdup (value);
424 : :
425 : 252 : if (embedded_annotations != NULL)
426 : 126 : info->annotations = embedded_annotations;
427 : 252 : }
428 : :
429 : : static void
430 : 5362 : g_dbus_arg_info_set (ParseData *data,
431 : : GDBusArgInfo *info,
432 : : const gchar *name,
433 : : const gchar *signature,
434 : : GDBusAnnotationInfo **annotations)
435 : : {
436 : 5362 : info->ref_count = 1;
437 : :
438 : : /* name may be NULL - TODO: compute name? */
439 : 5362 : if (name != NULL)
440 : 2681 : info->name = g_strdup (name);
441 : :
442 : 5362 : if (signature != NULL)
443 : 2681 : info->signature = g_strdup (signature);
444 : :
445 : 5362 : if (annotations != NULL)
446 : 2681 : info->annotations = annotations;
447 : 5362 : }
448 : :
449 : : static void
450 : 1416 : 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 : 1416 : info->ref_count = 1;
458 : :
459 : 1416 : if (name != NULL)
460 : 708 : info->name = g_strdup (name);
461 : :
462 : 1416 : if (in_args != NULL)
463 : 708 : info->in_args = in_args;
464 : :
465 : 1416 : if (out_args != NULL)
466 : 708 : info->out_args = out_args;
467 : :
468 : 1416 : if (annotations != NULL)
469 : 708 : info->annotations = annotations;
470 : 1416 : }
471 : :
472 : : static void
473 : 294 : g_dbus_signal_info_set (ParseData *data,
474 : : GDBusSignalInfo *info,
475 : : const gchar *name,
476 : : GDBusArgInfo **args,
477 : : GDBusAnnotationInfo **annotations)
478 : : {
479 : 294 : info->ref_count = 1;
480 : :
481 : 294 : if (name != NULL)
482 : 147 : info->name = g_strdup (name);
483 : :
484 : 294 : if (args != NULL)
485 : 147 : info->args = args;
486 : :
487 : 294 : if (annotations != NULL)
488 : 147 : info->annotations = annotations;
489 : 294 : }
490 : :
491 : : static void
492 : 1398 : 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 : 1398 : info->ref_count = 1;
500 : :
501 : 1398 : if (name != NULL)
502 : 699 : info->name = g_strdup (name);
503 : :
504 : 1398 : if (flags != G_DBUS_PROPERTY_INFO_FLAGS_NONE)
505 : 699 : info->flags = flags;
506 : :
507 : 1398 : if (signature != NULL)
508 : 699 : info->signature = g_strdup (signature);
509 : :
510 : 1398 : if (annotations != NULL)
511 : 699 : info->annotations = annotations;
512 : 1398 : }
513 : :
514 : : static void
515 : 506 : 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 : 506 : info->ref_count = 1;
524 : :
525 : 506 : if (name != NULL)
526 : 253 : info->name = g_strdup (name);
527 : :
528 : 506 : if (methods != NULL)
529 : 253 : info->methods = methods;
530 : :
531 : 506 : if (signals != NULL)
532 : 253 : info->signals = signals;
533 : :
534 : 506 : if (properties != NULL)
535 : 253 : info->properties = properties;
536 : :
537 : 506 : if (annotations != NULL)
538 : 253 : info->annotations = annotations;
539 : 506 : }
540 : :
541 : : static void
542 : 318 : 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 : 318 : info->ref_count = 1;
550 : :
551 : 318 : if (path != NULL)
552 : : {
553 : 48 : info->path = g_strdup (path);
554 : : /* TODO: relative / absolute path snafu */
555 : : }
556 : :
557 : 318 : if (interfaces != NULL)
558 : 159 : info->interfaces = interfaces;
559 : :
560 : 318 : if (nodes != NULL)
561 : 159 : info->nodes = nodes;
562 : :
563 : 318 : if (annotations != NULL)
564 : 159 : info->annotations = annotations;
565 : 318 : }
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 : 9657 : parse_data_steal_annotations (ParseData *data,
867 : : guint *out_num_elements)
868 : : {
869 : : GDBusAnnotationInfo **ret;
870 : 9657 : if (out_num_elements != NULL)
871 : 0 : *out_num_elements = data->annotations->len;
872 : 9657 : if (data->annotations == NULL)
873 : 4884 : ret = NULL;
874 : : else
875 : : {
876 : 4773 : g_ptr_array_add (data->annotations, NULL);
877 : 4773 : ret = (GDBusAnnotationInfo **) g_ptr_array_free (data->annotations, FALSE);
878 : : }
879 : 9657 : data->annotations = g_ptr_array_new ();
880 : 9657 : return ret;
881 : : }
882 : :
883 : : static GDBusArgInfo **
884 : 819 : parse_data_steal_args (ParseData *data,
885 : : guint *out_num_elements)
886 : : {
887 : : GDBusArgInfo **ret;
888 : 819 : if (out_num_elements != NULL)
889 : 708 : *out_num_elements = data->args->len;
890 : 819 : if (data->args == NULL)
891 : 111 : ret = NULL;
892 : : else
893 : : {
894 : 708 : g_ptr_array_add (data->args, NULL);
895 : 708 : ret = (GDBusArgInfo **) g_ptr_array_free (data->args, FALSE);
896 : : }
897 : 819 : data->args = g_ptr_array_new ();
898 : 819 : return ret;
899 : : }
900 : :
901 : : static GDBusArgInfo **
902 : 966 : parse_data_steal_out_args (ParseData *data,
903 : : guint *out_num_elements)
904 : : {
905 : : GDBusArgInfo **ret;
906 : 966 : if (out_num_elements != NULL)
907 : 855 : *out_num_elements = data->out_args->len;
908 : 966 : if (data->out_args == NULL)
909 : 111 : ret = NULL;
910 : : else
911 : : {
912 : 855 : g_ptr_array_add (data->out_args, NULL);
913 : 855 : ret = (GDBusArgInfo **) g_ptr_array_free (data->out_args, FALSE);
914 : : }
915 : 966 : data->out_args = g_ptr_array_new ();
916 : 966 : return ret;
917 : : }
918 : :
919 : : static GDBusMethodInfo **
920 : 364 : parse_data_steal_methods (ParseData *data,
921 : : guint *out_num_elements)
922 : : {
923 : : GDBusMethodInfo **ret;
924 : 364 : if (out_num_elements != NULL)
925 : 253 : *out_num_elements = data->methods->len;
926 : 364 : if (data->methods == NULL)
927 : 111 : ret = NULL;
928 : : else
929 : : {
930 : 253 : g_ptr_array_add (data->methods, NULL);
931 : 253 : ret = (GDBusMethodInfo **) g_ptr_array_free (data->methods, FALSE);
932 : : }
933 : 364 : data->methods = g_ptr_array_new ();
934 : 364 : return ret;
935 : : }
936 : :
937 : : static GDBusSignalInfo **
938 : 364 : parse_data_steal_signals (ParseData *data,
939 : : guint *out_num_elements)
940 : : {
941 : : GDBusSignalInfo **ret;
942 : 364 : if (out_num_elements != NULL)
943 : 253 : *out_num_elements = data->signals->len;
944 : 364 : if (data->signals == NULL)
945 : 111 : ret = NULL;
946 : : else
947 : : {
948 : 253 : g_ptr_array_add (data->signals, NULL);
949 : 253 : ret = (GDBusSignalInfo **) g_ptr_array_free (data->signals, FALSE);
950 : : }
951 : 364 : data->signals = g_ptr_array_new ();
952 : 364 : return ret;
953 : : }
954 : :
955 : : static GDBusPropertyInfo **
956 : 364 : parse_data_steal_properties (ParseData *data,
957 : : guint *out_num_elements)
958 : : {
959 : : GDBusPropertyInfo **ret;
960 : 364 : if (out_num_elements != NULL)
961 : 253 : *out_num_elements = data->properties->len;
962 : 364 : if (data->properties == NULL)
963 : 111 : ret = NULL;
964 : : else
965 : : {
966 : 253 : g_ptr_array_add (data->properties, NULL);
967 : 253 : ret = (GDBusPropertyInfo **) g_ptr_array_free (data->properties, FALSE);
968 : : }
969 : 364 : data->properties = g_ptr_array_new ();
970 : 364 : return ret;
971 : : }
972 : :
973 : : static GDBusInterfaceInfo **
974 : 429 : parse_data_steal_interfaces (ParseData *data,
975 : : guint *out_num_elements)
976 : : {
977 : : GDBusInterfaceInfo **ret;
978 : 429 : if (out_num_elements != NULL)
979 : 159 : *out_num_elements = data->interfaces->len;
980 : 429 : if (data->interfaces == NULL)
981 : 270 : ret = NULL;
982 : : else
983 : : {
984 : 159 : g_ptr_array_add (data->interfaces, NULL);
985 : 159 : ret = (GDBusInterfaceInfo **) g_ptr_array_free (data->interfaces, FALSE);
986 : : }
987 : 429 : data->interfaces = g_ptr_array_new ();
988 : 429 : return ret;
989 : : }
990 : :
991 : : static GDBusNodeInfo **
992 : 540 : parse_data_steal_nodes (ParseData *data,
993 : : guint *out_num_elements)
994 : : {
995 : : GDBusNodeInfo **ret;
996 : 540 : if (out_num_elements != NULL)
997 : 270 : *out_num_elements = data->nodes->len;
998 : 540 : if (data->nodes == NULL)
999 : 270 : ret = NULL;
1000 : : else
1001 : : {
1002 : 270 : g_ptr_array_add (data->nodes, NULL);
1003 : 270 : ret = (GDBusNodeInfo **) g_ptr_array_free (data->nodes, FALSE);
1004 : : }
1005 : 540 : data->nodes = g_ptr_array_new ();
1006 : 540 : return ret;
1007 : : }
1008 : :
1009 : : /* ---------------------------------------------------------------------------------------------------- */
1010 : :
1011 : : static void
1012 : 4884 : parse_data_free_annotations (ParseData *data)
1013 : : {
1014 : 4884 : if (data->annotations == NULL)
1015 : 0 : return;
1016 : 4884 : g_ptr_array_foreach (data->annotations, (GFunc) g_dbus_annotation_info_unref, NULL);
1017 : 4884 : g_ptr_array_free (data->annotations, TRUE);
1018 : 4884 : data->annotations = NULL;
1019 : : }
1020 : :
1021 : : static void
1022 : 111 : parse_data_free_args (ParseData *data)
1023 : : {
1024 : 111 : if (data->args == NULL)
1025 : 0 : return;
1026 : 111 : g_ptr_array_foreach (data->args, (GFunc) g_dbus_arg_info_unref, NULL);
1027 : 111 : g_ptr_array_free (data->args, TRUE);
1028 : 111 : data->args = NULL;
1029 : : }
1030 : :
1031 : : static void
1032 : 111 : parse_data_free_out_args (ParseData *data)
1033 : : {
1034 : 111 : if (data->out_args == NULL)
1035 : 0 : return;
1036 : 111 : g_ptr_array_foreach (data->out_args, (GFunc) g_dbus_arg_info_unref, NULL);
1037 : 111 : g_ptr_array_free (data->out_args, TRUE);
1038 : 111 : data->out_args = NULL;
1039 : : }
1040 : :
1041 : : static void
1042 : 111 : parse_data_free_methods (ParseData *data)
1043 : : {
1044 : 111 : if (data->methods == NULL)
1045 : 0 : return;
1046 : 111 : g_ptr_array_foreach (data->methods, (GFunc) g_dbus_method_info_unref, NULL);
1047 : 111 : g_ptr_array_free (data->methods, TRUE);
1048 : 111 : data->methods = NULL;
1049 : : }
1050 : :
1051 : : static void
1052 : 111 : parse_data_free_signals (ParseData *data)
1053 : : {
1054 : 111 : if (data->signals == NULL)
1055 : 0 : return;
1056 : 111 : g_ptr_array_foreach (data->signals, (GFunc) g_dbus_signal_info_unref, NULL);
1057 : 111 : g_ptr_array_free (data->signals, TRUE);
1058 : 111 : data->signals = NULL;
1059 : : }
1060 : :
1061 : : static void
1062 : 111 : parse_data_free_properties (ParseData *data)
1063 : : {
1064 : 111 : if (data->properties == NULL)
1065 : 0 : return;
1066 : 111 : g_ptr_array_foreach (data->properties, (GFunc) g_dbus_property_info_unref, NULL);
1067 : 111 : g_ptr_array_free (data->properties, TRUE);
1068 : 111 : data->properties = NULL;
1069 : : }
1070 : :
1071 : : static void
1072 : 270 : parse_data_free_interfaces (ParseData *data)
1073 : : {
1074 : 270 : if (data->interfaces == NULL)
1075 : 0 : return;
1076 : 270 : g_ptr_array_foreach (data->interfaces, (GFunc) g_dbus_interface_info_unref, NULL);
1077 : 270 : g_ptr_array_free (data->interfaces, TRUE);
1078 : 270 : data->interfaces = NULL;
1079 : : }
1080 : :
1081 : : static void
1082 : 270 : parse_data_free_nodes (ParseData *data)
1083 : : {
1084 : 270 : if (data->nodes == NULL)
1085 : 0 : return;
1086 : 270 : g_ptr_array_foreach (data->nodes, (GFunc) g_dbus_node_info_unref, NULL);
1087 : 270 : g_ptr_array_free (data->nodes, TRUE);
1088 : 270 : data->nodes = NULL;
1089 : : }
1090 : :
1091 : : /* ---------------------------------------------------------------------------------------------------- */
1092 : :
1093 : : static GDBusAnnotationInfo *
1094 : 252 : parse_data_get_annotation (ParseData *data,
1095 : : gboolean create_new)
1096 : : {
1097 : 252 : if (create_new)
1098 : 126 : g_ptr_array_add (data->annotations, g_new0 (GDBusAnnotationInfo, 1));
1099 : 252 : return data->annotations->pdata[data->annotations->len - 1];
1100 : : }
1101 : :
1102 : : static GDBusArgInfo *
1103 : 2648 : parse_data_get_arg (ParseData *data,
1104 : : gboolean create_new)
1105 : : {
1106 : 2648 : if (create_new)
1107 : 1324 : g_ptr_array_add (data->args, g_new0 (GDBusArgInfo, 1));
1108 : 2648 : return data->args->pdata[data->args->len - 1];
1109 : : }
1110 : :
1111 : : static GDBusArgInfo *
1112 : 2714 : parse_data_get_out_arg (ParseData *data,
1113 : : gboolean create_new)
1114 : : {
1115 : 2714 : if (create_new)
1116 : 1357 : g_ptr_array_add (data->out_args, g_new0 (GDBusArgInfo, 1));
1117 : 2714 : return data->out_args->pdata[data->out_args->len - 1];
1118 : : }
1119 : :
1120 : : static GDBusMethodInfo *
1121 : 1416 : parse_data_get_method (ParseData *data,
1122 : : gboolean create_new)
1123 : : {
1124 : 1416 : if (create_new)
1125 : 708 : g_ptr_array_add (data->methods, g_new0 (GDBusMethodInfo, 1));
1126 : 1416 : return data->methods->pdata[data->methods->len - 1];
1127 : : }
1128 : :
1129 : : static GDBusSignalInfo *
1130 : 294 : parse_data_get_signal (ParseData *data,
1131 : : gboolean create_new)
1132 : : {
1133 : 294 : if (create_new)
1134 : 147 : g_ptr_array_add (data->signals, g_new0 (GDBusSignalInfo, 1));
1135 : 294 : return data->signals->pdata[data->signals->len - 1];
1136 : : }
1137 : :
1138 : : static GDBusPropertyInfo *
1139 : 1398 : parse_data_get_property (ParseData *data,
1140 : : gboolean create_new)
1141 : : {
1142 : 1398 : if (create_new)
1143 : 699 : g_ptr_array_add (data->properties, g_new0 (GDBusPropertyInfo, 1));
1144 : 1398 : return data->properties->pdata[data->properties->len - 1];
1145 : : }
1146 : :
1147 : : static GDBusInterfaceInfo *
1148 : 506 : parse_data_get_interface (ParseData *data,
1149 : : gboolean create_new)
1150 : : {
1151 : 506 : if (create_new)
1152 : 253 : g_ptr_array_add (data->interfaces, g_new0 (GDBusInterfaceInfo, 1));
1153 : 506 : return data->interfaces->pdata[data->interfaces->len - 1];
1154 : : }
1155 : :
1156 : : static GDBusNodeInfo *
1157 : 318 : parse_data_get_node (ParseData *data,
1158 : : gboolean create_new)
1159 : : {
1160 : 318 : if (create_new)
1161 : 159 : g_ptr_array_add (data->nodes, g_new0 (GDBusNodeInfo, 1));
1162 : 318 : return data->nodes->pdata[data->nodes->len - 1];
1163 : : }
1164 : :
1165 : : /* ---------------------------------------------------------------------------------------------------- */
1166 : :
1167 : : static ParseData *
1168 : 111 : parse_data_new (void)
1169 : : {
1170 : : ParseData *data;
1171 : :
1172 : 111 : data = g_new0 (ParseData, 1);
1173 : :
1174 : : /* initialize arrays */
1175 : 111 : parse_data_steal_annotations (data, NULL);
1176 : 111 : parse_data_steal_args (data, NULL);
1177 : 111 : parse_data_steal_out_args (data, NULL);
1178 : 111 : parse_data_steal_methods (data, NULL);
1179 : 111 : parse_data_steal_signals (data, NULL);
1180 : 111 : parse_data_steal_properties (data, NULL);
1181 : 111 : parse_data_steal_interfaces (data, NULL);
1182 : 111 : parse_data_steal_nodes (data, NULL);
1183 : :
1184 : 111 : return data;
1185 : : }
1186 : :
1187 : : static void
1188 : 111 : parse_data_free (ParseData *data)
1189 : : {
1190 : : GSList *l;
1191 : :
1192 : : /* free stack of annotation arrays */
1193 : 111 : for (l = data->annotations_stack; l != NULL; l = l->next)
1194 : : {
1195 : 0 : GPtrArray *annotations = l->data;
1196 : 0 : g_ptr_array_foreach (annotations, (GFunc) g_dbus_annotation_info_unref, NULL);
1197 : 0 : g_ptr_array_free (annotations, TRUE);
1198 : : }
1199 : 111 : g_slist_free (data->annotations_stack);
1200 : :
1201 : : /* free stack of interface arrays */
1202 : 111 : for (l = data->interfaces_stack; l != NULL; l = l->next)
1203 : : {
1204 : 0 : GPtrArray *interfaces = l->data;
1205 : 0 : g_ptr_array_foreach (interfaces, (GFunc) g_dbus_interface_info_unref, NULL);
1206 : 0 : g_ptr_array_free (interfaces, TRUE);
1207 : : }
1208 : 111 : g_slist_free (data->interfaces_stack);
1209 : :
1210 : : /* free stack of node arrays */
1211 : 111 : for (l = data->nodes_stack; l != NULL; l = l->next)
1212 : : {
1213 : 0 : GPtrArray *nodes = l->data;
1214 : 0 : g_ptr_array_foreach (nodes, (GFunc) g_dbus_node_info_unref, NULL);
1215 : 0 : g_ptr_array_free (nodes, TRUE);
1216 : : }
1217 : 111 : g_slist_free (data->nodes_stack);
1218 : :
1219 : : /* free arrays (data->annotations, data->interfaces and data->nodes have been freed above) */
1220 : 111 : parse_data_free_args (data);
1221 : 111 : parse_data_free_out_args (data);
1222 : 111 : parse_data_free_methods (data);
1223 : 111 : parse_data_free_signals (data);
1224 : 111 : parse_data_free_properties (data);
1225 : 111 : parse_data_free_interfaces (data);
1226 : 111 : parse_data_free_annotations (data);
1227 : 111 : parse_data_free_nodes (data);
1228 : :
1229 : 111 : g_free (data);
1230 : 111 : }
1231 : :
1232 : : /* ---------------------------------------------------------------------------------------------------- */
1233 : :
1234 : : static void
1235 : 4773 : 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 : 4773 : 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 : 4773 : name = NULL;
1251 : 4773 : type = NULL;
1252 : 4773 : access = NULL;
1253 : 4773 : direction = NULL;
1254 : 4773 : value = NULL;
1255 : :
1256 : 4773 : stack = (GSList *) g_markup_parse_context_get_element_stack (context);
1257 : :
1258 : : /* ---------------------------------------------------------------------------------------------------- */
1259 : 4773 : if (strcmp (element_name, "node") == 0)
1260 : : {
1261 : 159 : if (!(g_slist_length (stack) >= 1 || strcmp (stack->next->data, "node") != 0))
1262 : : {
1263 : 0 : 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 : 0 : goto out;
1268 : : }
1269 : :
1270 : 159 : 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 : 0 : goto out;
1279 : :
1280 : 159 : 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 : 159 : data->interfaces_stack = g_slist_prepend (data->interfaces_stack, data->interfaces);
1289 : 159 : data->interfaces = NULL;
1290 : 159 : parse_data_steal_interfaces (data, NULL);
1291 : :
1292 : 159 : data->nodes_stack = g_slist_prepend (data->nodes_stack, data->nodes);
1293 : 159 : data->nodes = NULL;
1294 : 159 : parse_data_steal_nodes (data, NULL);
1295 : :
1296 : : }
1297 : : /* ---------------------------------------------------------------------------------------------------- */
1298 : 4614 : else if (strcmp (element_name, "interface") == 0)
1299 : : {
1300 : 253 : if (g_slist_length (stack) < 2 || strcmp (stack->next->data, "node") != 0)
1301 : : {
1302 : 0 : 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 : 0 : goto out;
1307 : : }
1308 : :
1309 : 253 : 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 : 0 : goto out;
1318 : :
1319 : 253 : 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 : 4361 : else if (strcmp (element_name, "method") == 0)
1330 : : {
1331 : 708 : if (g_slist_length (stack) < 2 || strcmp (stack->next->data, "interface") != 0)
1332 : : {
1333 : 0 : 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 : 0 : goto out;
1338 : : }
1339 : :
1340 : 708 : 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 : 0 : goto out;
1349 : :
1350 : 708 : g_dbus_method_info_set (data,
1351 : : parse_data_get_method (data, TRUE),
1352 : : name,
1353 : : NULL,
1354 : : NULL,
1355 : : NULL);
1356 : :
1357 : 708 : data->num_args = 0;
1358 : :
1359 : : }
1360 : : /* ---------------------------------------------------------------------------------------------------- */
1361 : 3653 : else if (strcmp (element_name, "signal") == 0)
1362 : : {
1363 : 147 : if (g_slist_length (stack) < 2 || strcmp (stack->next->data, "interface") != 0)
1364 : : {
1365 : 0 : 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 : 0 : goto out;
1370 : : }
1371 : :
1372 : 147 : 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 : 0 : goto out;
1379 : :
1380 : 147 : g_dbus_signal_info_set (data,
1381 : : parse_data_get_signal (data, TRUE),
1382 : : name,
1383 : : NULL,
1384 : : NULL);
1385 : :
1386 : 147 : data->num_args = 0;
1387 : :
1388 : : }
1389 : : /* ---------------------------------------------------------------------------------------------------- */
1390 : 3506 : else if (strcmp (element_name, "property") == 0)
1391 : : {
1392 : : GDBusPropertyInfoFlags flags;
1393 : :
1394 : 699 : if (g_slist_length (stack) < 2 || strcmp (stack->next->data, "interface") != 0)
1395 : : {
1396 : 0 : 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 : 0 : goto out;
1401 : : }
1402 : :
1403 : 699 : 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 : 0 : goto out;
1412 : :
1413 : 699 : if (strcmp (access, "read") == 0)
1414 : 46 : flags = G_DBUS_PROPERTY_INFO_FLAGS_READABLE;
1415 : 653 : else if (strcmp (access, "write") == 0)
1416 : 24 : flags = G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE;
1417 : 629 : else if (strcmp (access, "readwrite") == 0)
1418 : 629 : flags = G_DBUS_PROPERTY_INFO_FLAGS_READABLE | G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE;
1419 : : else
1420 : : {
1421 : 0 : 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 : 0 : goto out;
1427 : : }
1428 : :
1429 : 699 : 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 : 2807 : else if (strcmp (element_name, "arg") == 0)
1439 : : {
1440 : : gboolean is_in;
1441 : : gchar *name_to_use;
1442 : :
1443 : 2681 : if (g_slist_length (stack) < 2 ||
1444 : 2681 : (strcmp (stack->next->data, "method") != 0 &&
1445 : 325 : strcmp (stack->next->data, "signal") != 0))
1446 : : {
1447 : 0 : 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 : 0 : goto out;
1452 : : }
1453 : :
1454 : 2681 : 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 : 0 : goto out;
1463 : :
1464 : 2681 : if (strcmp (stack->next->data, "method") == 0)
1465 : 2356 : is_in = TRUE;
1466 : : else
1467 : 325 : is_in = FALSE;
1468 : 2681 : if (direction != NULL)
1469 : : {
1470 : 2356 : if (strcmp (direction, "in") == 0)
1471 : 1323 : is_in = TRUE;
1472 : 1033 : else if (strcmp (direction, "out") == 0)
1473 : 1033 : is_in = FALSE;
1474 : : else
1475 : : {
1476 : 0 : g_set_error (error,
1477 : : G_MARKUP_ERROR,
1478 : : G_MARKUP_ERROR_INVALID_CONTENT,
1479 : : "Unknown value '%s' of direction attribute",
1480 : : direction);
1481 : 0 : goto out;
1482 : : }
1483 : : }
1484 : :
1485 : 2681 : if (is_in && strcmp (stack->next->data, "signal") == 0)
1486 : : {
1487 : 0 : 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 : 0 : goto out;
1492 : : }
1493 : :
1494 : 2681 : if (name == NULL)
1495 : 461 : name_to_use = g_strdup_printf ("arg_%d", data->num_args);
1496 : : else
1497 : 4440 : name_to_use = g_strdup (name);
1498 : 2681 : data->num_args++;
1499 : :
1500 : 2681 : if (is_in)
1501 : : {
1502 : 1324 : g_dbus_arg_info_set (data,
1503 : : parse_data_get_arg (data, TRUE),
1504 : : name_to_use,
1505 : : type,
1506 : : NULL);
1507 : 1324 : data->last_arg_was_in = TRUE;
1508 : : }
1509 : : else
1510 : : {
1511 : 1357 : g_dbus_arg_info_set (data,
1512 : : parse_data_get_out_arg (data, TRUE),
1513 : : name_to_use,
1514 : : type,
1515 : : NULL);
1516 : 1357 : data->last_arg_was_in = FALSE;
1517 : :
1518 : : }
1519 : :
1520 : 2681 : g_free (name_to_use);
1521 : : }
1522 : : /* ---------------------------------------------------------------------------------------------------- */
1523 : 126 : else if (strcmp (element_name, "annotation") == 0)
1524 : : {
1525 : 126 : if (g_slist_length (stack) < 2 ||
1526 : 126 : (strcmp (stack->next->data, "node") != 0 &&
1527 : 126 : strcmp (stack->next->data, "interface") != 0 &&
1528 : 112 : strcmp (stack->next->data, "signal") != 0 &&
1529 : 100 : strcmp (stack->next->data, "method") != 0 &&
1530 : 74 : strcmp (stack->next->data, "property") != 0 &&
1531 : 36 : strcmp (stack->next->data, "arg") != 0 &&
1532 : 0 : strcmp (stack->next->data, "annotation") != 0))
1533 : : {
1534 : 0 : 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 : 0 : goto out;
1539 : : }
1540 : :
1541 : 126 : 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 : 0 : goto out;
1549 : :
1550 : 126 : 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 : 4773 : data->annotations_stack = g_slist_prepend (data->annotations_stack, data->annotations);
1565 : 4773 : data->annotations = NULL;
1566 : 4773 : parse_data_steal_annotations (data, NULL);
1567 : :
1568 : 4773 : out:
1569 : : ;
1570 : 4773 : }
1571 : :
1572 : : /* ---------------------------------------------------------------------------------------------------- */
1573 : :
1574 : : static GDBusAnnotationInfo **
1575 : 4773 : steal_annotations (ParseData *data)
1576 : : {
1577 : 4773 : return parse_data_steal_annotations (data, NULL);
1578 : : }
1579 : :
1580 : :
1581 : : static void
1582 : 4773 : parser_end_element (GMarkupParseContext *context,
1583 : : const gchar *element_name,
1584 : : gpointer user_data,
1585 : : GError **error)
1586 : : {
1587 : 4773 : ParseData *data = user_data;
1588 : : gboolean have_popped_annotations;
1589 : :
1590 : 4773 : have_popped_annotations = FALSE;
1591 : :
1592 : 4773 : if (strcmp (element_name, "node") == 0)
1593 : : {
1594 : : guint num_nodes;
1595 : : guint num_interfaces;
1596 : : GDBusNodeInfo **nodes;
1597 : : GDBusInterfaceInfo **interfaces;
1598 : :
1599 : 159 : nodes = parse_data_steal_nodes (data, &num_nodes);
1600 : 159 : 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 : 159 : parse_data_free_interfaces (data);
1606 : 159 : data->interfaces = (GPtrArray *) data->interfaces_stack->data;
1607 : 159 : data->interfaces_stack = g_slist_remove (data->interfaces_stack, data->interfaces_stack->data);
1608 : :
1609 : 159 : parse_data_free_nodes (data);
1610 : 159 : data->nodes = (GPtrArray *) data->nodes_stack->data;
1611 : 159 : data->nodes_stack = g_slist_remove (data->nodes_stack, data->nodes_stack->data);
1612 : :
1613 : 159 : 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 : 4614 : 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 : 253 : methods = parse_data_steal_methods (data, &num_methods);
1631 : 253 : signals = parse_data_steal_signals (data, &num_signals);
1632 : 253 : properties = parse_data_steal_properties (data, &num_properties);
1633 : :
1634 : 253 : 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 : 4361 : 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 : 708 : in_args = parse_data_steal_args (data, &in_num_args);
1651 : 708 : out_args = parse_data_steal_out_args (data, &out_num_args);
1652 : :
1653 : 708 : 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 : 3653 : else if (strcmp (element_name, "signal") == 0)
1661 : : {
1662 : : guint num_args;
1663 : : GDBusArgInfo **args;
1664 : :
1665 : 147 : args = parse_data_steal_out_args (data, &num_args);
1666 : :
1667 : 147 : g_dbus_signal_info_set (data,
1668 : : parse_data_get_signal (data, FALSE),
1669 : : NULL,
1670 : : args,
1671 : : steal_annotations (data));
1672 : : }
1673 : 3506 : else if (strcmp (element_name, "property") == 0)
1674 : : {
1675 : 699 : 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 : 2807 : else if (strcmp (element_name, "arg") == 0)
1683 : : {
1684 : 5362 : g_dbus_arg_info_set (data,
1685 : 2681 : 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 : 126 : else if (strcmp (element_name, "annotation") == 0)
1691 : : {
1692 : : GDBusAnnotationInfo **embedded_annotations;
1693 : :
1694 : 126 : 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 : 126 : parse_data_free_annotations (data);
1698 : 126 : data->annotations = (GPtrArray *) data->annotations_stack->data;
1699 : 126 : data->annotations_stack = g_slist_remove (data->annotations_stack, data->annotations_stack->data);
1700 : :
1701 : 126 : have_popped_annotations = TRUE;
1702 : :
1703 : 126 : 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 : 4773 : 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 : 4647 : parse_data_free_annotations (data);
1718 : 4647 : data->annotations = (GPtrArray *) data->annotations_stack->data;
1719 : 4647 : data->annotations_stack = g_slist_remove (data->annotations_stack, data->annotations_stack->data);
1720 : : }
1721 : 4773 : }
1722 : :
1723 : : /* ---------------------------------------------------------------------------------------------------- */
1724 : :
1725 : : static void
1726 : 0 : parser_error (GMarkupParseContext *context,
1727 : : GError *error,
1728 : : gpointer user_data)
1729 : : {
1730 : : gint line_number;
1731 : : gint char_number;
1732 : :
1733 : 0 : g_markup_parse_context_get_position (context, &line_number, &char_number);
1734 : :
1735 : 0 : g_prefix_error (&error, "%d:%d: ",
1736 : : line_number,
1737 : : char_number);
1738 : 0 : }
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 : 111 : 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 : 111 : ret = NULL;
1773 : 111 : parser = NULL;
1774 : 111 : context = NULL;
1775 : :
1776 : 111 : parser = g_new0 (GMarkupParser, 1);
1777 : 111 : parser->start_element = parser_start_element;
1778 : 111 : parser->end_element = parser_end_element;
1779 : 111 : parser->error = parser_error;
1780 : :
1781 : 111 : data = parse_data_new ();
1782 : 111 : context = g_markup_parse_context_new (parser,
1783 : : G_MARKUP_IGNORE_QUALIFIED,
1784 : : data,
1785 : : (GDestroyNotify) parse_data_free);
1786 : :
1787 : 111 : if (!g_markup_parse_context_parse (context,
1788 : : xml_data,
1789 : 111 : strlen (xml_data),
1790 : : error))
1791 : 0 : goto out;
1792 : :
1793 : 111 : if (!g_markup_parse_context_end_parse (context, error))
1794 : 0 : goto out;
1795 : :
1796 : 111 : ughret = parse_data_steal_nodes (data, &num_nodes);
1797 : :
1798 : 111 : if (num_nodes != 1)
1799 : : {
1800 : : guint n;
1801 : :
1802 : 0 : 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 : 0 : for (n = 0; n < num_nodes; n++)
1810 : : {
1811 : 0 : g_dbus_node_info_unref (ughret[n]);
1812 : 0 : ughret[n] = NULL;
1813 : : }
1814 : : }
1815 : :
1816 : 111 : ret = ughret[0];
1817 : 111 : g_free (ughret);
1818 : :
1819 : 111 : out:
1820 : 111 : g_free (parser);
1821 : 111 : if (context != NULL)
1822 : 111 : g_markup_parse_context_free (context);
1823 : :
1824 : 111 : 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 : 25 : g_dbus_annotation_info_lookup (GDBusAnnotationInfo **annotations,
1844 : : const gchar *name)
1845 : : {
1846 : : guint n;
1847 : : const gchar *ret;
1848 : :
1849 : 25 : ret = NULL;
1850 : 28 : for (n = 0; annotations != NULL && annotations[n] != NULL; n++)
1851 : : {
1852 : 28 : if (g_strcmp0 (annotations[n]->key, name) == 0)
1853 : : {
1854 : 25 : ret = annotations[n]->value;
1855 : 25 : goto out;
1856 : : }
1857 : : }
1858 : :
1859 : 0 : out:
1860 : 25 : 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 : 1960 : info_cache_free (InfoCacheEntry *cache)
1883 : : {
1884 : 1960 : g_assert (cache->use_count == 0);
1885 : 1960 : g_hash_table_unref (cache->method_name_to_data);
1886 : 1960 : g_hash_table_unref (cache->signal_name_to_data);
1887 : 1960 : g_hash_table_unref (cache->property_name_to_data);
1888 : 1960 : g_slice_free (InfoCacheEntry, cache);
1889 : 1960 : }
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 : 1030 : g_dbus_interface_info_lookup_method (GDBusInterfaceInfo *info,
1912 : : const gchar *name)
1913 : : {
1914 : : guint n;
1915 : : GDBusMethodInfo *result;
1916 : :
1917 : 1030 : G_LOCK (info_cache_lock);
1918 : 1030 : if (G_LIKELY (info_cache != NULL))
1919 : : {
1920 : : InfoCacheEntry *cache;
1921 : 1020 : cache = g_hash_table_lookup (info_cache, info);
1922 : 1020 : if (G_LIKELY (cache != NULL))
1923 : : {
1924 : 796 : result = g_hash_table_lookup (cache->method_name_to_data, name);
1925 : 796 : G_UNLOCK (info_cache_lock);
1926 : 796 : goto out;
1927 : : }
1928 : : }
1929 : 234 : G_UNLOCK (info_cache_lock);
1930 : :
1931 : 238 : for (n = 0; info->methods != NULL && info->methods[n] != NULL; n++)
1932 : : {
1933 : 237 : GDBusMethodInfo *i = info->methods[n];
1934 : :
1935 : 237 : if (g_strcmp0 (i->name, name) == 0)
1936 : : {
1937 : 233 : result = i;
1938 : 233 : goto out;
1939 : : }
1940 : : }
1941 : :
1942 : 1 : result = NULL;
1943 : :
1944 : 1030 : out:
1945 : 1030 : 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 : 27 : g_dbus_interface_info_lookup_signal (GDBusInterfaceInfo *info,
1966 : : const gchar *name)
1967 : : {
1968 : : guint n;
1969 : : GDBusSignalInfo *result;
1970 : :
1971 : 27 : G_LOCK (info_cache_lock);
1972 : 27 : if (G_LIKELY (info_cache != NULL))
1973 : : {
1974 : : InfoCacheEntry *cache;
1975 : 21 : cache = g_hash_table_lookup (info_cache, info);
1976 : 21 : if (G_LIKELY (cache != NULL))
1977 : : {
1978 : 21 : result = g_hash_table_lookup (cache->signal_name_to_data, name);
1979 : 21 : G_UNLOCK (info_cache_lock);
1980 : 21 : goto out;
1981 : : }
1982 : : }
1983 : 6 : G_UNLOCK (info_cache_lock);
1984 : :
1985 : 6 : for (n = 0; info->signals != NULL && info->signals[n] != NULL; n++)
1986 : : {
1987 : 6 : GDBusSignalInfo *i = info->signals[n];
1988 : :
1989 : 6 : if (g_strcmp0 (i->name, name) == 0)
1990 : : {
1991 : 6 : result = i;
1992 : 6 : goto out;
1993 : : }
1994 : : }
1995 : :
1996 : 0 : result = NULL;
1997 : :
1998 : 27 : out:
1999 : 27 : 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 : 1791 : g_dbus_interface_info_lookup_property (GDBusInterfaceInfo *info,
2020 : : const gchar *name)
2021 : : {
2022 : : guint n;
2023 : : GDBusPropertyInfo *result;
2024 : :
2025 : 1791 : G_LOCK (info_cache_lock);
2026 : 1791 : if (G_LIKELY (info_cache != NULL))
2027 : : {
2028 : : InfoCacheEntry *cache;
2029 : 1787 : cache = g_hash_table_lookup (info_cache, info);
2030 : 1787 : if (G_LIKELY (cache != NULL))
2031 : : {
2032 : 1787 : result = g_hash_table_lookup (cache->property_name_to_data, name);
2033 : 1787 : G_UNLOCK (info_cache_lock);
2034 : 1787 : goto out;
2035 : : }
2036 : : }
2037 : 4 : G_UNLOCK (info_cache_lock);
2038 : :
2039 : 40 : for (n = 0; info->properties != NULL && info->properties[n] != NULL; n++)
2040 : : {
2041 : 40 : GDBusPropertyInfo *i = info->properties[n];
2042 : :
2043 : 40 : if (g_strcmp0 (i->name, name) == 0)
2044 : : {
2045 : 4 : result = i;
2046 : 4 : goto out;
2047 : : }
2048 : : }
2049 : :
2050 : 0 : result = NULL;
2051 : :
2052 : 1791 : out:
2053 : 1791 : 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 : 200558 : g_dbus_interface_info_cache_build (GDBusInterfaceInfo *info)
2077 : : {
2078 : : InfoCacheEntry *cache;
2079 : : guint n;
2080 : :
2081 : 200558 : G_LOCK (info_cache_lock);
2082 : 200558 : if (info_cache == NULL)
2083 : 27 : info_cache = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) info_cache_free);
2084 : 200558 : cache = g_hash_table_lookup (info_cache, info);
2085 : 200558 : if (cache != NULL)
2086 : : {
2087 : 198589 : cache->use_count += 1;
2088 : 198589 : goto out;
2089 : : }
2090 : 1969 : cache = g_slice_new0 (InfoCacheEntry);
2091 : 1969 : cache->use_count = 1;
2092 : 1969 : cache->method_name_to_data = g_hash_table_new (g_str_hash, g_str_equal);
2093 : 1969 : cache->signal_name_to_data = g_hash_table_new (g_str_hash, g_str_equal);
2094 : 1969 : cache->property_name_to_data = g_hash_table_new (g_str_hash, g_str_equal);
2095 : 6973 : for (n = 0; info->methods != NULL && info->methods[n] != NULL; n++)
2096 : 5004 : g_hash_table_insert (cache->method_name_to_data, info->methods[n]->name, info->methods[n]);
2097 : 3847 : for (n = 0; info->signals != NULL && info->signals[n] != NULL; n++)
2098 : 1878 : g_hash_table_insert (cache->signal_name_to_data, info->signals[n]->name, info->signals[n]);
2099 : 3169 : for (n = 0; info->properties != NULL && info->properties[n] != NULL; n++)
2100 : 1200 : g_hash_table_insert (cache->property_name_to_data, info->properties[n]->name, info->properties[n]);
2101 : 1969 : g_hash_table_insert (info_cache, info, cache);
2102 : 200558 : out:
2103 : 200558 : G_UNLOCK (info_cache_lock);
2104 : 200558 : }
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 : 200549 : g_dbus_interface_info_cache_release (GDBusInterfaceInfo *info)
2118 : : {
2119 : : InfoCacheEntry *cache;
2120 : :
2121 : 200549 : G_LOCK (info_cache_lock);
2122 : 200549 : if (G_UNLIKELY (info_cache == NULL))
2123 : : {
2124 : 0 : g_warning ("%s called for interface %s but there is no cache", info->name, G_STRFUNC);
2125 : 0 : goto out;
2126 : : }
2127 : :
2128 : 200549 : cache = g_hash_table_lookup (info_cache, info);
2129 : 200549 : if (G_UNLIKELY (cache == NULL))
2130 : : {
2131 : 0 : g_warning ("%s called for interface %s but there is no cache entry", info->name, G_STRFUNC);
2132 : 0 : goto out;
2133 : : }
2134 : 200549 : cache->use_count -= 1;
2135 : 200549 : if (cache->use_count == 0)
2136 : : {
2137 : 1960 : g_hash_table_remove (info_cache, info);
2138 : : /* could nuke info_cache itself if empty */
2139 : : }
2140 : 198589 : out:
2141 : 200549 : G_UNLOCK (info_cache_lock);
2142 : 200549 : }
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 : 36 : g_dbus_node_info_lookup_interface (GDBusNodeInfo *info,
2162 : : const gchar *name)
2163 : : {
2164 : : guint n;
2165 : : GDBusInterfaceInfo *result;
2166 : :
2167 : 70 : for (n = 0; info->interfaces != NULL && info->interfaces[n] != NULL; n++)
2168 : : {
2169 : 69 : GDBusInterfaceInfo *i = info->interfaces[n];
2170 : :
2171 : 69 : if (g_strcmp0 (i->name, name) == 0)
2172 : : {
2173 : 35 : result = i;
2174 : 35 : goto out;
2175 : : }
2176 : : }
2177 : :
2178 : 1 : result = NULL;
2179 : :
2180 : 36 : out:
2181 : 36 : return result;
2182 : : }
|