[dconf] Support maybe types in dconf



commit e103f710c6ac5b9db21a88bd904b104bda1bf911
Author: Ryan Lortie <desrt desrt ca>
Date:   Fri Jul 22 10:33:03 2011 +0200

    Support maybe types in dconf
    
    Work around the fact that we can't send maybe types over D-Bus by
    sending a blob of serialised GVariant data instead.
    
    Abuse the fact that we're using an array to denote 'maybe' at the level
    of the dconf protocol and fill that array with 2 items (which would not
    otherwise be possible) to indicate this special case.

 engine/dconf-engine.c |   45 ++++++++++++++++++++++++++++++++++++++++++++-
 service/service.c     |   37 +++++++++++++++++++++++++++++++++----
 2 files changed, 77 insertions(+), 5 deletions(-)
---
diff --git a/engine/dconf-engine.c b/engine/dconf-engine.c
index 087d780..88f7e83 100644
--- a/engine/dconf-engine.c
+++ b/engine/dconf-engine.c
@@ -565,6 +565,28 @@ dconf_engine_is_writable (DConfEngine *engine,
   return writable;
 }
 
+/* be conservative and fast:  false negatives are OK */
+static gboolean
+is_dbusable (GVariant *value)
+{
+  const gchar *type;
+
+  type = g_variant_get_type_string (value);
+
+  /* maybe definitely won't work.
+   * variant?  too lazy to check inside...
+   */
+  if (strchr (type, 'v') || strchr (type, 'm'))
+    return FALSE;
+
+  /* XXX: we could also check for '{}' not inside an array...
+   * but i'm not sure we want to support that anyway.
+   */
+
+  /* this will avoid any too-deeply-nested limits */
+  return strlen (type) < 32;
+}
+
 static GVariant *
 fake_maybe (GVariant *value)
 {
@@ -573,7 +595,28 @@ fake_maybe (GVariant *value)
   g_variant_builder_init (&builder, G_VARIANT_TYPE ("av"));
 
   if (value != NULL)
-    g_variant_builder_add (&builder, "v", value);
+    {
+      if (is_dbusable (value))
+        g_variant_builder_add (&builder, "v", value);
+
+      else
+        {
+          GVariant *variant;
+          GVariant *ay;
+
+          variant = g_variant_new_variant (value);
+          ay = g_variant_new_from_data (G_VARIANT_TYPE_BYTESTRING,
+                                        g_variant_get_data (variant),
+                                        g_variant_get_size (variant),
+                                        TRUE,
+                                        (GDestroyNotify) g_variant_unref,
+                                        variant);
+          g_variant_builder_add (&builder, "v", ay);
+
+          g_variant_builder_add (&builder, "v",
+                                 g_variant_new_string ("serialised GVariant"));
+        }
+    }
 
   return g_variant_builder_end (&builder);
 }
diff --git a/service/service.c b/service/service.c
index 54418d1..99051ec 100644
--- a/service/service.c
+++ b/service/service.c
@@ -97,13 +97,42 @@ static void
 unwrap_maybe (GVariant **ptr)
 {
   GVariant *array, *child;
+  gsize n_children;
 
   array = *ptr;
+  n_children = g_variant_n_children (array);
 
-  if (g_variant_n_children (array))
-    child = g_variant_get_child_value (array, 0);
-  else
-    child = NULL;
+  switch (n_children)
+    {
+    case 0:
+      child = NULL;
+      break;
+    case 1: default:
+      child = g_variant_get_child_value (array, 0);
+      break;
+    case 2:
+      {
+        GVariant *untrusted;
+        GVariant *ay;
+
+        g_variant_get_child (array, 0, "v", &ay);
+        if (!g_variant_is_of_type (ay, G_VARIANT_TYPE_BYTESTRING))
+          {
+            g_variant_unref (ay);
+            child = NULL;
+            break;
+          }
+
+        untrusted = g_variant_new_from_data (G_VARIANT_TYPE_VARIANT,
+                                             g_variant_get_data (ay),
+                                             g_variant_get_size (ay),
+                                             FALSE,
+                                             (GDestroyNotify) g_variant_unref, ay);
+        g_variant_ref_sink (untrusted);
+        child = g_variant_get_normal_form (untrusted);
+        g_variant_unref (untrusted);
+      }
+    }
 
   g_variant_unref (array);
   *ptr = child;



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]