Coverage Report

Created: 2025-07-01 07:09

/src/glib/gio/gdbusutils.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
 * This library is free software; you can redistribute it and/or
6
 * modify it under the terms of the GNU Lesser General Public
7
 * License as published by the Free Software Foundation; either
8
 * version 2.1 of the License, or (at your option) any later version.
9
 *
10
 * This library is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13
 * Lesser General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU Lesser General
16
 * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
17
 *
18
 * Author: David Zeuthen <davidz@redhat.com>
19
 */
20
21
#include "config.h"
22
23
#include <stdlib.h>
24
#include <string.h>
25
26
#include "gdbusutils.h"
27
28
#include "glibintl.h"
29
30
/**
31
 * SECTION:gdbusutils
32
 * @title: D-Bus Utilities
33
 * @short_description: Various utilities related to D-Bus
34
 * @include: gio/gio.h
35
 *
36
 * Various utility routines related to D-Bus.
37
 */
38
39
static gboolean
40
is_valid_bus_name_character (gint c,
41
                             gboolean allow_hyphen)
42
0
{
43
0
  return
44
0
    (c >= '0' && c <= '9') ||
45
0
    (c >= 'A' && c <= 'Z') ||
46
0
    (c >= 'a' && c <= 'z') ||
47
0
    (c == '_') ||
48
0
    (allow_hyphen && c == '-');
49
0
}
50
51
static gboolean
52
is_valid_initial_bus_name_character (gint c,
53
                                     gboolean allow_initial_digit,
54
                                     gboolean allow_hyphen)
55
0
{
56
0
  if (allow_initial_digit)
57
0
    return is_valid_bus_name_character (c, allow_hyphen);
58
0
  else
59
0
    return
60
0
      (c >= 'A' && c <= 'Z') ||
61
0
      (c >= 'a' && c <= 'z') ||
62
0
      (c == '_') ||
63
0
      (allow_hyphen && c == '-');
64
0
}
65
66
static gboolean
67
is_valid_name (const gchar *start,
68
               guint len,
69
               gboolean allow_initial_digit,
70
               gboolean allow_hyphen)
71
0
{
72
0
  gboolean ret;
73
0
  const gchar *s;
74
0
  const gchar *end;
75
0
  gboolean has_dot;
76
77
0
  ret = FALSE;
78
79
0
  if (len == 0)
80
0
    goto out;
81
82
0
  s = start;
83
0
  end = s + len;
84
0
  has_dot = FALSE;
85
0
  while (s != end)
86
0
    {
87
0
      if (*s == '.')
88
0
        {
89
0
          s += 1;
90
0
          if (G_UNLIKELY (!is_valid_initial_bus_name_character (*s, allow_initial_digit, allow_hyphen)))
91
0
            goto out;
92
0
          has_dot = TRUE;
93
0
        }
94
0
      else if (G_UNLIKELY (!is_valid_bus_name_character (*s, allow_hyphen)))
95
0
        {
96
0
          goto out;
97
0
        }
98
0
      s += 1;
99
0
    }
100
101
0
  if (G_UNLIKELY (!has_dot))
102
0
    goto out;
103
104
0
  ret = TRUE;
105
106
0
 out:
107
0
  return ret;
108
0
}
109
110
/**
111
 * g_dbus_is_name:
112
 * @string: The string to check.
113
 *
114
 * Checks if @string is a valid D-Bus bus name (either unique or well-known).
115
 *
116
 * Returns: %TRUE if valid, %FALSE otherwise.
117
 *
118
 * Since: 2.26
119
 */
120
gboolean
121
g_dbus_is_name (const gchar *string)
122
0
{
123
0
  guint len;
124
0
  gboolean ret;
125
0
  const gchar *s;
126
127
0
  g_return_val_if_fail (string != NULL, FALSE);
128
129
0
  ret = FALSE;
130
131
0
  len = strlen (string);
132
0
  if (G_UNLIKELY (len == 0 || len > 255))
133
0
    goto out;
134
135
0
  s = string;
136
0
  if (*s == ':')
137
0
    {
138
      /* handle unique name */
139
0
      if (!is_valid_name (s + 1, len - 1, TRUE, TRUE))
140
0
        goto out;
141
0
      ret = TRUE;
142
0
      goto out;
143
0
    }
144
0
  else if (G_UNLIKELY (*s == '.'))
145
0
    {
146
      /* can't start with a . */
147
0
      goto out;
148
0
    }
149
0
  else if (G_UNLIKELY (!is_valid_initial_bus_name_character (*s, FALSE, TRUE)))
150
0
    goto out;
151
152
0
  ret = is_valid_name (s + 1, len - 1, FALSE, TRUE);
153
154
0
 out:
155
0
  return ret;
156
0
}
157
158
/**
159
 * g_dbus_is_unique_name:
160
 * @string: The string to check.
161
 *
162
 * Checks if @string is a valid D-Bus unique bus name.
163
 *
164
 * Returns: %TRUE if valid, %FALSE otherwise.
165
 *
166
 * Since: 2.26
167
 */
168
gboolean
169
g_dbus_is_unique_name (const gchar *string)
170
0
{
171
0
  gboolean ret;
172
0
  guint len;
173
174
0
  g_return_val_if_fail (string != NULL, FALSE);
175
176
0
  ret = FALSE;
177
178
0
  len = strlen (string);
179
0
  if (G_UNLIKELY (len == 0 || len > 255))
180
0
    goto out;
181
182
0
  if (G_UNLIKELY (*string != ':'))
183
0
    goto out;
184
185
0
  if (G_UNLIKELY (!is_valid_name (string + 1, len - 1, TRUE, TRUE)))
186
0
    goto out;
187
188
0
  ret = TRUE;
189
190
0
 out:
191
0
  return ret;
192
0
}
193
194
/**
195
 * g_dbus_is_member_name:
196
 * @string: The string to check.
197
 *
198
 * Checks if @string is a valid D-Bus member (e.g. signal or method) name.
199
 *
200
 * Returns: %TRUE if valid, %FALSE otherwise.
201
 *
202
 * Since: 2.26
203
 */
204
gboolean
205
g_dbus_is_member_name (const gchar *string)
206
0
{
207
0
  gboolean ret;
208
0
  guint n;
209
210
0
  ret = FALSE;
211
0
  if (G_UNLIKELY (string == NULL))
212
0
    goto out;
213
214
0
  if (G_UNLIKELY (!is_valid_initial_bus_name_character (string[0], FALSE, FALSE)))
215
0
    goto out;
216
217
0
  for (n = 1; string[n] != '\0'; n++)
218
0
    {
219
0
      if (G_UNLIKELY (!is_valid_bus_name_character (string[n], FALSE)))
220
0
        {
221
0
          goto out;
222
0
        }
223
0
    }
224
225
0
  ret = TRUE;
226
227
0
 out:
228
0
  return ret;
229
0
}
230
231
/**
232
 * g_dbus_is_interface_name:
233
 * @string: The string to check.
234
 *
235
 * Checks if @string is a valid D-Bus interface name.
236
 *
237
 * Returns: %TRUE if valid, %FALSE otherwise.
238
 *
239
 * Since: 2.26
240
 */
241
gboolean
242
g_dbus_is_interface_name (const gchar *string)
243
0
{
244
0
  guint len;
245
0
  gboolean ret;
246
0
  const gchar *s;
247
248
0
  g_return_val_if_fail (string != NULL, FALSE);
249
250
0
  ret = FALSE;
251
252
0
  len = strlen (string);
253
0
  if (G_UNLIKELY (len == 0 || len > 255))
254
0
    goto out;
255
256
0
  s = string;
257
0
  if (G_UNLIKELY (*s == '.'))
258
0
    {
259
      /* can't start with a . */
260
0
      goto out;
261
0
    }
262
0
  else if (G_UNLIKELY (!is_valid_initial_bus_name_character (*s, FALSE, FALSE)))
263
0
    goto out;
264
265
0
  ret = is_valid_name (s + 1, len - 1, FALSE, FALSE);
266
267
0
 out:
268
0
  return ret;
269
0
}
270
271
/* ---------------------------------------------------------------------------------------------------- */
272
273
/* TODO: maybe move to glib? if so, it should conform to http://en.wikipedia.org/wiki/Guid and/or
274
 *       http://tools.ietf.org/html/rfc4122 - specifically it should have hyphens then.
275
 */
276
277
/**
278
 * g_dbus_generate_guid:
279
 *
280
 * Generate a D-Bus GUID that can be used with
281
 * e.g. g_dbus_connection_new().
282
 *
283
 * See the D-Bus specification regarding what strings are valid D-Bus
284
 * GUID (for example, D-Bus GUIDs are not RFC-4122 compliant).
285
 *
286
 * Returns: A valid D-Bus GUID. Free with g_free().
287
 *
288
 * Since: 2.26
289
 */
290
gchar *
291
g_dbus_generate_guid (void)
292
0
{
293
0
  GString *s;
294
0
  guint32 r1;
295
0
  guint32 r2;
296
0
  guint32 r3;
297
0
  gint64 now_us;
298
299
0
  s = g_string_new (NULL);
300
301
0
  r1 = g_random_int ();
302
0
  r2 = g_random_int ();
303
0
  r3 = g_random_int ();
304
0
  now_us = g_get_real_time ();
305
306
0
  g_string_append_printf (s, "%08x", r1);
307
0
  g_string_append_printf (s, "%08x", r2);
308
0
  g_string_append_printf (s, "%08x", r3);
309
0
  g_string_append_printf (s, "%08x", (guint32) (now_us / G_USEC_PER_SEC));
310
311
0
  return g_string_free (s, FALSE);
312
0
}
313
314
/**
315
 * g_dbus_is_guid:
316
 * @string: The string to check.
317
 *
318
 * Checks if @string is a D-Bus GUID.
319
 *
320
 * See the D-Bus specification regarding what strings are valid D-Bus
321
 * GUID (for example, D-Bus GUIDs are not RFC-4122 compliant).
322
 *
323
 * Returns: %TRUE if @string is a guid, %FALSE otherwise.
324
 *
325
 * Since: 2.26
326
 */
327
gboolean
328
g_dbus_is_guid (const gchar *string)
329
0
{
330
0
  gboolean ret;
331
0
  guint n;
332
333
0
  g_return_val_if_fail (string != NULL, FALSE);
334
335
0
  ret = FALSE;
336
337
0
  for (n = 0; n < 32; n++)
338
0
    {
339
0
      if (!g_ascii_isxdigit (string[n]))
340
0
        goto out;
341
0
    }
342
0
  if (string[32] != '\0')
343
0
    goto out;
344
345
0
  ret = TRUE;
346
347
0
 out:
348
0
  return ret;
349
0
}
350
351
/* ---------------------------------------------------------------------------------------------------- */
352
353
/**
354
 * g_dbus_gvariant_to_gvalue:
355
 * @value: A #GVariant.
356
 * @out_gvalue: (out): Return location pointing to a zero-filled (uninitialized) #GValue.
357
 *
358
 * Converts a #GVariant to a #GValue. If @value is floating, it is consumed.
359
 *
360
 * The rules specified in the g_dbus_gvalue_to_gvariant() function are
361
 * used - this function is essentially its reverse form. So, a #GVariant
362
 * containing any basic or string array type will be converted to a #GValue
363
 * containing a basic value or string array. Any other #GVariant (handle,
364
 * variant, tuple, dict entry) will be converted to a #GValue containing that
365
 * #GVariant.
366
 *
367
 * The conversion never fails - a valid #GValue is always returned in
368
 * @out_gvalue.
369
 *
370
 * Since: 2.30
371
 */
372
void
373
g_dbus_gvariant_to_gvalue (GVariant  *value,
374
                           GValue    *out_gvalue)
375
0
{
376
0
  const GVariantType *type;
377
0
  gchar **array;
378
379
0
  g_return_if_fail (value != NULL);
380
0
  g_return_if_fail (out_gvalue != NULL);
381
382
0
  memset (out_gvalue, '\0', sizeof (GValue));
383
384
0
  switch (g_variant_classify (value))
385
0
    {
386
0
    case G_VARIANT_CLASS_BOOLEAN:
387
0
      g_value_init (out_gvalue, G_TYPE_BOOLEAN);
388
0
      g_value_set_boolean (out_gvalue, g_variant_get_boolean (value));
389
0
      break;
390
391
0
    case G_VARIANT_CLASS_BYTE:
392
0
      g_value_init (out_gvalue, G_TYPE_UCHAR);
393
0
      g_value_set_uchar (out_gvalue, g_variant_get_byte (value));
394
0
      break;
395
396
0
    case G_VARIANT_CLASS_INT16:
397
0
      g_value_init (out_gvalue, G_TYPE_INT);
398
0
      g_value_set_int (out_gvalue, g_variant_get_int16 (value));
399
0
      break;
400
401
0
    case G_VARIANT_CLASS_UINT16:
402
0
      g_value_init (out_gvalue, G_TYPE_UINT);
403
0
      g_value_set_uint (out_gvalue, g_variant_get_uint16 (value));
404
0
      break;
405
406
0
    case G_VARIANT_CLASS_INT32:
407
0
      g_value_init (out_gvalue, G_TYPE_INT);
408
0
      g_value_set_int (out_gvalue, g_variant_get_int32 (value));
409
0
      break;
410
411
0
    case G_VARIANT_CLASS_UINT32:
412
0
      g_value_init (out_gvalue, G_TYPE_UINT);
413
0
      g_value_set_uint (out_gvalue, g_variant_get_uint32 (value));
414
0
      break;
415
416
0
    case G_VARIANT_CLASS_INT64:
417
0
      g_value_init (out_gvalue, G_TYPE_INT64);
418
0
      g_value_set_int64 (out_gvalue, g_variant_get_int64 (value));
419
0
      break;
420
421
0
    case G_VARIANT_CLASS_UINT64:
422
0
      g_value_init (out_gvalue, G_TYPE_UINT64);
423
0
      g_value_set_uint64 (out_gvalue, g_variant_get_uint64 (value));
424
0
      break;
425
426
0
    case G_VARIANT_CLASS_DOUBLE:
427
0
      g_value_init (out_gvalue, G_TYPE_DOUBLE);
428
0
      g_value_set_double (out_gvalue, g_variant_get_double (value));
429
0
      break;
430
431
0
    case G_VARIANT_CLASS_STRING:
432
0
      g_value_init (out_gvalue, G_TYPE_STRING);
433
0
      g_value_set_string (out_gvalue, g_variant_get_string (value, NULL));
434
0
      break;
435
436
0
    case G_VARIANT_CLASS_OBJECT_PATH:
437
0
      g_value_init (out_gvalue, G_TYPE_STRING);
438
0
      g_value_set_string (out_gvalue, g_variant_get_string (value, NULL));
439
0
      break;
440
441
0
    case G_VARIANT_CLASS_SIGNATURE:
442
0
      g_value_init (out_gvalue, G_TYPE_STRING);
443
0
      g_value_set_string (out_gvalue, g_variant_get_string (value, NULL));
444
0
      break;
445
446
0
    case G_VARIANT_CLASS_ARRAY:
447
0
      type = g_variant_get_type (value);
448
0
      switch (g_variant_type_peek_string (type)[1])
449
0
        {
450
0
        case G_VARIANT_CLASS_BYTE:
451
0
          g_value_init (out_gvalue, G_TYPE_STRING);
452
0
          g_value_set_string (out_gvalue, g_variant_get_bytestring (value));
453
0
          break;
454
455
0
        case G_VARIANT_CLASS_STRING:
456
0
          g_value_init (out_gvalue, G_TYPE_STRV);
457
0
          array = g_variant_dup_strv (value, NULL);
458
0
          g_value_take_boxed (out_gvalue, array);
459
0
          break;
460
461
0
        case G_VARIANT_CLASS_OBJECT_PATH:
462
0
          g_value_init (out_gvalue, G_TYPE_STRV);
463
0
          array = g_variant_dup_objv (value, NULL);
464
0
          g_value_take_boxed (out_gvalue, array);
465
0
          break;
466
467
0
        case G_VARIANT_CLASS_ARRAY:
468
0
          switch (g_variant_type_peek_string (type)[2])
469
0
            {
470
0
            case G_VARIANT_CLASS_BYTE:
471
0
              g_value_init (out_gvalue, G_TYPE_STRV);
472
0
              array = g_variant_dup_bytestring_array (value, NULL);
473
0
              g_value_take_boxed (out_gvalue, array);
474
0
              break;
475
476
0
            default:
477
0
              g_value_init (out_gvalue, G_TYPE_VARIANT);
478
0
              g_value_set_variant (out_gvalue, value);
479
0
              break;
480
0
            }
481
0
          break;
482
483
0
        default:
484
0
          g_value_init (out_gvalue, G_TYPE_VARIANT);
485
0
          g_value_set_variant (out_gvalue, value);
486
0
          break;
487
0
        }
488
0
      break;
489
490
0
    case G_VARIANT_CLASS_HANDLE:
491
0
    case G_VARIANT_CLASS_VARIANT:
492
0
    case G_VARIANT_CLASS_MAYBE:
493
0
    case G_VARIANT_CLASS_TUPLE:
494
0
    case G_VARIANT_CLASS_DICT_ENTRY:
495
0
      g_value_init (out_gvalue, G_TYPE_VARIANT);
496
0
      g_value_set_variant (out_gvalue, value);
497
0
      break;
498
0
    }
499
0
}
500
501
502
/**
503
 * g_dbus_gvalue_to_gvariant:
504
 * @gvalue: A #GValue to convert to a #GVariant
505
 * @type: A #GVariantType
506
 *
507
 * Converts a #GValue to a #GVariant of the type indicated by the @type
508
 * parameter.
509
 *
510
 * The conversion is using the following rules:
511
 *
512
 * - #G_TYPE_STRING: 's', 'o', 'g' or 'ay'
513
 * - #G_TYPE_STRV: 'as', 'ao' or 'aay'
514
 * - #G_TYPE_BOOLEAN: 'b'
515
 * - #G_TYPE_UCHAR: 'y'
516
 * - #G_TYPE_INT: 'i', 'n'
517
 * - #G_TYPE_UINT: 'u', 'q'
518
 * - #G_TYPE_INT64 'x'
519
 * - #G_TYPE_UINT64: 't'
520
 * - #G_TYPE_DOUBLE: 'd'
521
 * - #G_TYPE_VARIANT: Any #GVariantType
522
 *
523
 * This can fail if e.g. @gvalue is of type #G_TYPE_STRING and @type
524
 * is ['i'][G-VARIANT-TYPE-INT32:CAPS]. It will also fail for any #GType
525
 * (including e.g. #G_TYPE_OBJECT and #G_TYPE_BOXED derived-types) not
526
 * in the table above.
527
 *
528
 * Note that if @gvalue is of type #G_TYPE_VARIANT and its value is
529
 * %NULL, the empty #GVariant instance (never %NULL) for @type is
530
 * returned (e.g. 0 for scalar types, the empty string for string types,
531
 * '/' for object path types, the empty array for any array type and so on).
532
 *
533
 * See the g_dbus_gvariant_to_gvalue() function for how to convert a
534
 * #GVariant to a #GValue.
535
 *
536
 * Returns: (transfer full): A #GVariant (never floating) of
537
 *     #GVariantType @type holding the data from @gvalue or an empty #GVariant
538
 *     in case of failure. Free with g_variant_unref().
539
 *
540
 * Since: 2.30
541
 */
542
GVariant *
543
g_dbus_gvalue_to_gvariant (const GValue       *gvalue,
544
                           const GVariantType *type)
545
0
{
546
0
  GVariant *ret;
547
0
  const gchar *s;
548
0
  const gchar * const *as;
549
0
  const gchar *empty_strv[1] = {NULL};
550
551
0
  g_return_val_if_fail (gvalue != NULL, NULL);
552
0
  g_return_val_if_fail (type != NULL, NULL);
553
554
0
  ret = NULL;
555
556
  /* @type can easily be e.g. "s" with the GValue holding a GVariant - for example this
557
   * can happen when using the org.gtk.GDBus.C.ForceGVariant annotation with the
558
   * gdbus-codegen(1) tool.
559
   */
560
0
  if (G_VALUE_TYPE (gvalue) == G_TYPE_VARIANT)
561
0
    {
562
0
      ret = g_value_dup_variant (gvalue);
563
0
    }
564
0
  else
565
0
    {
566
0
      switch (g_variant_type_peek_string (type)[0])
567
0
        {
568
0
        case G_VARIANT_CLASS_BOOLEAN:
569
0
          ret = g_variant_ref_sink (g_variant_new_boolean (g_value_get_boolean (gvalue)));
570
0
          break;
571
572
0
        case G_VARIANT_CLASS_BYTE:
573
0
          ret = g_variant_ref_sink (g_variant_new_byte (g_value_get_uchar (gvalue)));
574
0
          break;
575
576
0
        case G_VARIANT_CLASS_INT16:
577
0
          ret = g_variant_ref_sink (g_variant_new_int16 (g_value_get_int (gvalue)));
578
0
          break;
579
580
0
        case G_VARIANT_CLASS_UINT16:
581
0
          ret = g_variant_ref_sink (g_variant_new_uint16 (g_value_get_uint (gvalue)));
582
0
          break;
583
584
0
        case G_VARIANT_CLASS_INT32:
585
0
          ret = g_variant_ref_sink (g_variant_new_int32 (g_value_get_int (gvalue)));
586
0
          break;
587
588
0
        case G_VARIANT_CLASS_UINT32:
589
0
          ret = g_variant_ref_sink (g_variant_new_uint32 (g_value_get_uint (gvalue)));
590
0
          break;
591
592
0
        case G_VARIANT_CLASS_INT64:
593
0
          ret = g_variant_ref_sink (g_variant_new_int64 (g_value_get_int64 (gvalue)));
594
0
          break;
595
596
0
        case G_VARIANT_CLASS_UINT64:
597
0
          ret = g_variant_ref_sink (g_variant_new_uint64 (g_value_get_uint64 (gvalue)));
598
0
          break;
599
600
0
        case G_VARIANT_CLASS_DOUBLE:
601
0
          ret = g_variant_ref_sink (g_variant_new_double (g_value_get_double (gvalue)));
602
0
          break;
603
604
0
        case G_VARIANT_CLASS_STRING:
605
0
          s = g_value_get_string (gvalue);
606
0
          if (s == NULL)
607
0
            s = "";
608
0
          ret = g_variant_ref_sink (g_variant_new_string (s));
609
0
          break;
610
611
0
        case G_VARIANT_CLASS_OBJECT_PATH:
612
0
          s = g_value_get_string (gvalue);
613
0
          if (s == NULL)
614
0
            s = "/";
615
0
          ret = g_variant_ref_sink (g_variant_new_object_path (s));
616
0
          break;
617
618
0
        case G_VARIANT_CLASS_SIGNATURE:
619
0
          s = g_value_get_string (gvalue);
620
0
          if (s == NULL)
621
0
            s = "";
622
0
          ret = g_variant_ref_sink (g_variant_new_signature (s));
623
0
          break;
624
625
0
        case G_VARIANT_CLASS_ARRAY:
626
0
          switch (g_variant_type_peek_string (type)[1])
627
0
            {
628
0
            case G_VARIANT_CLASS_BYTE:
629
0
              s = g_value_get_string (gvalue);
630
0
              if (s == NULL)
631
0
                s = "";
632
0
              ret = g_variant_ref_sink (g_variant_new_bytestring (s));
633
0
              break;
634
635
0
            case G_VARIANT_CLASS_STRING:
636
0
              as = g_value_get_boxed (gvalue);
637
0
              if (as == NULL)
638
0
                as = empty_strv;
639
0
              ret = g_variant_ref_sink (g_variant_new_strv (as, -1));
640
0
              break;
641
642
0
            case G_VARIANT_CLASS_OBJECT_PATH:
643
0
              as = g_value_get_boxed (gvalue);
644
0
              if (as == NULL)
645
0
                as = empty_strv;
646
0
              ret = g_variant_ref_sink (g_variant_new_objv (as, -1));
647
0
              break;
648
649
0
            case G_VARIANT_CLASS_ARRAY:
650
0
              switch (g_variant_type_peek_string (type)[2])
651
0
                {
652
0
                case G_VARIANT_CLASS_BYTE:
653
0
                  as = g_value_get_boxed (gvalue);
654
0
                  if (as == NULL)
655
0
                    as = empty_strv;
656
0
                  ret = g_variant_ref_sink (g_variant_new_bytestring_array (as, -1));
657
0
                  break;
658
659
0
                default:
660
0
                  ret = g_value_dup_variant (gvalue);
661
0
                  break;
662
0
                }
663
0
              break;
664
665
0
            default:
666
0
              ret = g_value_dup_variant (gvalue);
667
0
              break;
668
0
            }
669
0
          break;
670
671
0
        case G_VARIANT_CLASS_HANDLE:
672
0
        case G_VARIANT_CLASS_VARIANT:
673
0
        case G_VARIANT_CLASS_MAYBE:
674
0
        case G_VARIANT_CLASS_TUPLE:
675
0
        case G_VARIANT_CLASS_DICT_ENTRY:
676
0
          ret = g_value_dup_variant (gvalue);
677
0
          break;
678
0
        }
679
0
    }
680
681
  /* Could be that the GValue is holding a NULL GVariant - in that case,
682
   * we return an "empty" GVariant instead of a NULL GVariant
683
   */
684
0
  if (ret == NULL)
685
0
    {
686
0
      GVariant *untrusted_empty;
687
0
      untrusted_empty = g_variant_new_from_data (type, NULL, 0, FALSE, NULL, NULL);
688
0
      ret = g_variant_take_ref (g_variant_get_normal_form (untrusted_empty));
689
0
      g_variant_unref (untrusted_empty);
690
0
    }
691
692
0
  g_assert (!g_variant_is_floating (ret));
693
694
0
  return ret;
695
0
}
696
697
/**
698
 * g_dbus_escape_object_path_bytestring:
699
 * @bytes: (array zero-terminated=1) (element-type guint8): the string of bytes to escape
700
 *
701
 * Escapes @bytes for use in a D-Bus object path component.
702
 * @bytes is an array of zero or more nonzero bytes in an
703
 * unspecified encoding, followed by a single zero byte.
704
 *
705
 * The escaping method consists of replacing all non-alphanumeric
706
 * characters (see g_ascii_isalnum()) with their hexadecimal value
707
 * preceded by an underscore (`_`). For example:
708
 * `foo.bar.baz` will become `foo_2ebar_2ebaz`.
709
 *
710
 * This method is appropriate to use when the input is nearly
711
 * a valid object path component but is not when your input
712
 * is far from being a valid object path component.
713
 * Other escaping algorithms are also valid to use with
714
 * D-Bus object paths.
715
 *
716
 * This can be reversed with g_dbus_unescape_object_path().
717
 *
718
 * Returns: an escaped version of @bytes. Free with g_free().
719
 *
720
 * Since: 2.68
721
 *
722
 */
723
gchar *
724
g_dbus_escape_object_path_bytestring (const guint8 *bytes)
725
0
{
726
0
  GString *escaped;
727
0
  const guint8 *p;
728
729
0
  g_return_val_if_fail (bytes != NULL, NULL);
730
731
0
  if (*bytes == '\0')
732
0
    return g_strdup ("_");
733
734
0
  escaped = g_string_new (NULL);
735
0
  for (p = bytes; *p; p++)
736
0
    {
737
0
      if (g_ascii_isalnum (*p))
738
0
        g_string_append_c (escaped, *p);
739
0
      else
740
0
        g_string_append_printf (escaped, "_%02x", *p);
741
0
    }
742
743
0
  return g_string_free (escaped, FALSE);
744
0
}
745
746
/**
747
 * g_dbus_escape_object_path:
748
 * @s: the string to escape
749
 *
750
 * This is a language binding friendly version of g_dbus_escape_object_path_bytestring().
751
 *
752
 * Returns: an escaped version of @s. Free with g_free().
753
 *
754
 * Since: 2.68
755
 */
756
gchar *
757
g_dbus_escape_object_path (const gchar *s)
758
0
{
759
0
  return (gchar *) g_dbus_escape_object_path_bytestring ((const guint8 *) s);
760
0
}
761
762
/**
763
 * g_dbus_unescape_object_path:
764
 * @s: the string to unescape
765
 *
766
 * Unescapes an string that was previously escaped with
767
 * g_dbus_escape_object_path(). If the string is in a format that could
768
 * not have been returned by g_dbus_escape_object_path(), this function
769
 * returns %NULL.
770
 *
771
 * Encoding alphanumeric characters which do not need to be
772
 * encoded is not allowed (e.g `_63` is not valid, the string
773
 * should contain `c` instead).
774
 *
775
 * Returns: (array zero-terminated=1) (element-type guint8) (nullable): an
776
 *   unescaped version of @s, or %NULL if @s is not a string returned
777
 *   from g_dbus_escape_object_path(). Free with g_free().
778
 *
779
 * Since: 2.68
780
 */
781
guint8 *
782
g_dbus_unescape_object_path (const gchar *s)
783
0
{
784
0
  GString *unescaped;
785
0
  const gchar *p;
786
787
0
  g_return_val_if_fail (s != NULL, NULL);
788
789
0
  if (g_str_equal (s, "_"))
790
0
    return (guint8 *) g_strdup ("");
791
792
0
  unescaped = g_string_new (NULL);
793
0
  for (p = s; *p; p++)
794
0
    {
795
0
      gint hi, lo;
796
797
0
      if (g_ascii_isalnum (*p))
798
0
        {
799
0
          g_string_append_c (unescaped, *p);
800
0
        }
801
0
      else if (*p == '_' &&
802
0
               ((hi = g_ascii_xdigit_value (p[1])) >= 0) &&
803
0
               ((lo = g_ascii_xdigit_value (p[2])) >= 0) &&
804
0
               (hi || lo) &&                      /* \0 is not allowed */
805
0
               !g_ascii_isalnum ((hi << 4) | lo)) /* alnums must not be encoded */
806
0
        {
807
0
          g_string_append_c (unescaped, (hi << 4) | lo);
808
0
          p += 2;
809
0
        }
810
0
      else
811
0
        {
812
          /* the string was not encoded correctly */
813
0
          g_string_free (unescaped, TRUE);
814
0
          return NULL;
815
0
        }
816
0
    }
817
818
0
  return (guint8 *) g_string_free (unescaped, FALSE);
819
0
}