g_dbus_address_escape_value: add
authorSimon McVittie <simon.mcvittie@collabora.co.uk>
Wed, 13 Feb 2013 20:42:58 +0000 (20:42 +0000)
committerSimon McVittie <simon.mcvittie@collabora.co.uk>
Wed, 13 Feb 2013 20:42:58 +0000 (20:42 +0000)
This is a GLib reimplementation of dbus_address_escape_value().
It's useful if you want to construct a D-Bus address from pieces:
for instance, if you have a listening Unix socket whose path is known,
and you want to connect a D-Bus peer to it.

Bug: https://bugzilla.gnome.org/show_bug.cgi?id=693673
Reviewed-by: Colin Walters <walters@verbum.org>
[amended to add Since: 2.36 as per review]
Signed-off-by: Simon McVittie <simon.mcvittie@collabora.co.uk>
gio/gdbusaddress.c
gio/gdbusaddress.h
gio/tests/gdbus-addresses.c

index 8c1d31c..cc9703c 100644 (file)
@@ -1586,3 +1586,50 @@ g_dbus_address_get_for_bus_sync (GBusType       bus_type,
 
   return ret;
 }
+
+/**
+ * g_dbus_address_escape_value:
+ * @string: an unescaped string to be included in a D-Bus address
+ *  as the value in a key-value pair
+ *
+ * Escape @string so it can appear in a D-Bus address as the value
+ * part of a key-value pair.
+ *
+ * For instance, if @string is <code>/run/bus-for-:0</code>,
+ * this function would return <code>/run/bus-for-%3A0</code>,
+ * which could be used in a D-Bus address like
+ * <code>unix:nonce-tcp:host=127.0.0.1,port=42,noncefile=/run/bus-for-%3A0</code>.
+ *
+ * Returns: (transfer full): a copy of @string with all
+ *  non-optionally-escaped bytes escaped
+ *
+ * Since: 2.36
+ */
+gchar *
+g_dbus_address_escape_value (const gchar *string)
+{
+  GString *s;
+  gsize i;
+
+  g_return_val_if_fail (string != NULL, NULL);
+
+  /* There will often not be anything needing escaping at all. */
+  s = g_string_sized_new (strlen (string));
+
+  /* D-Bus address escaping is mostly the same as URI escaping... */
+  g_string_append_uri_escaped (s, string, "\\/", FALSE);
+
+  /* ... but '~' is an unreserved character in URIs, but a
+   * non-optionally-escaped character in D-Bus addresses. */
+  for (i = 0; i < s->len; i++)
+    {
+      if (G_UNLIKELY (s->str[i] == '~'))
+        {
+          s->str[i] = '%';
+          g_string_insert (s, i + 1, "7E");
+          i += 2;
+        }
+    }
+
+  return g_string_free (s, FALSE);
+}
index 55896b8..08773aa 100644 (file)
@@ -31,6 +31,9 @@
 
 G_BEGIN_DECLS
 
+GLIB_AVAILABLE_IN_2_36
+gchar *g_dbus_address_escape_value (const gchar *string);
+
 GLIB_AVAILABLE_IN_ALL
 gboolean g_dbus_is_address (const gchar *string);
 GLIB_AVAILABLE_IN_ALL
index 72388c5..c5a237d 100644 (file)
@@ -102,6 +102,29 @@ test_mixed_address (void)
   g_assert (!g_dbus_is_supported_address ("tcp:host=localhost,port=42;tcp:family=bla", NULL));
 }
 
+static const struct { const char *before; const char *after; } escaping[] = {
+      { "foo", "foo" },
+      { "/.\\-_", "/.\\-_" },
+      { "<=>", "%3C%3D%3E" },
+      { "/foo~1", "/foo%7E1" },
+      { "\xe2\x98\xad\xff", "%E2%98%AD%FF" },
+      { NULL, NULL }
+};
+
+static void
+test_escape_address (void)
+{
+  gsize i;
+
+  for (i = 0; escaping[i].before != NULL; i++)
+    {
+      gchar *s = g_dbus_address_escape_value (escaping[i].before);
+
+      g_assert_cmpstr (s, ==, escaping[i].after);
+      g_free (s);
+    }
+}
+
 int
 main (int   argc,
       char *argv[])
@@ -116,6 +139,7 @@ main (int   argc,
   g_test_add_func ("/gdbus/tcp-address", test_tcp_address);
   g_test_add_func ("/gdbus/autolaunch-address", test_autolaunch_address);
   g_test_add_func ("/gdbus/mixed-address", test_mixed_address);
+  g_test_add_func ("/gdbus/escape-address", test_escape_address);
 
   return g_test_run();
 }