diff options
author | Ryan Lortie <desrt@desrt.ca> | 2011-07-22 10:33:03 +0200 |
---|---|---|
committer | Ryan Lortie <desrt@desrt.ca> | 2011-07-22 10:35:10 +0200 |
commit | e103f710c6ac5b9db21a88bd904b104bda1bf911 (patch) | |
tree | 6c7ac2457d3d06d65b2e91f3e323894ca9b5c5fc | |
parent | 5a8b222f297546105350e734bb79bd8373bdd1a2 (diff) | |
download | dconf-e103f710c6ac5b9db21a88bd904b104bda1bf911.tar.gz |
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.
-rw-r--r-- | engine/dconf-engine.c | 45 | ||||
-rw-r--r-- | 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; |