Coverage Report

Created: 2025-07-11 06:48

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