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