From 13e15733f38a40c6ef6a1baede91cce81c86ebaa Mon Sep 17 00:00:00 2001 From: Ryan Lortie Date: Fri, 28 Nov 2014 17:57:30 -0500 Subject: [PATCH] GVariant: support serialising to GVariantVectors Add code for serialising GVariant to GVariantVectors. Export that internally via the glib-private machanism so that we can use it from GDBus. --- glib/glib-private.c | 4 +- glib/glib-private.h | 7 ++ glib/gvariant-core.c | 56 +++++++++++++ glib/gvariant-serialiser.c | 192 +++++++++++++++++++++++++++++++++++++++++++++ glib/gvariant-serialiser.h | 11 +++ 5 files changed, 269 insertions(+), 1 deletion(-) diff --git a/glib/glib-private.c b/glib/glib-private.c index bbf879f..3c1dac6 100644 --- a/glib/glib-private.c +++ b/glib/glib-private.c @@ -44,7 +44,9 @@ glib__private__ (void) g_main_context_new_with_next_id, g_dir_open_with_errno, - g_dir_new_from_dirp + g_dir_new_from_dirp, + + g_variant_to_vectors }; return &table; diff --git a/glib/glib-private.h b/glib/glib-private.h index 0a28008..40509b6 100644 --- a/glib/glib-private.h +++ b/glib/glib-private.h @@ -20,6 +20,7 @@ #include #include "gwakeup.h" +#include "gvariant-vectors.h" #if defined(__GNUC__) # define _g_alignof(type) (__alignof__ (type)) @@ -30,6 +31,8 @@ GMainContext * g_get_worker_context (void); gboolean g_check_setuid (void); GMainContext * g_main_context_new_with_next_id (guint next_id); +void g_variant_to_vectors (GVariant *value, + GVariantVectors *vectors); #ifdef G_OS_WIN32 gchar *_glib_get_dll_directory (void); @@ -61,6 +64,10 @@ typedef struct { guint flags); GDir * (* g_dir_new_from_dirp) (gpointer dirp); + void (* g_variant_to_vectors) (GVariant *value, + GVariantVectors *vectors); + + /* Add other private functions here, initialize them in glib-private.c */ } GLibPrivateVTable; diff --git a/glib/gvariant-core.c b/glib/gvariant-core.c index 4ab4238..45b876b 100644 --- a/glib/gvariant-core.c +++ b/glib/gvariant-core.c @@ -19,6 +19,7 @@ #include "config.h" #include +#include "glib-private.h" #include #include @@ -424,6 +425,61 @@ g_variant_ensure_serialised (GVariant *value) } } +/* Now we have the code to recursively serialise a GVariant into a + * GVariantVectors structure. + * + * We want to do this in cases where the GVariant contains large chunks + * of serialised data in order to avoid having to copy this data. + * + * This generally works the same as normal serialising (co-recursion + * with the serialiser) but instead of using a callback we just hard-code + * the callback with the name g_variant_callback_write_to_vectors(). + * + * This is a private API that will be used by GDBus. + */ +gsize +g_variant_callback_write_to_vectors (GVariantVectors *vectors, + gpointer data, + GVariantTypeInfo **type_info) +{ + GVariant *value = data; + + if (g_variant_lock_in_tree_form (value)) + { + g_variant_serialiser_write_to_vectors (vectors, value->type_info, value->size, + (gpointer *) value->contents.tree.children, + value->contents.tree.n_children); + + g_variant_unlock (value); + } + else + g_variant_vectors_append_gbytes (vectors, value->contents.serialised.bytes, + value->contents.serialised.data, value->size); + + if (type_info) + *type_info = value->type_info; + + return value->size; +} + +/* < private > + * g_variant_serialise_to_vectors: + * @value: a #GVariant + * @vectors: (out): the result + * + * Serialises @value into @vectors. + * + * The caller must free @vectors. + */ +void +g_variant_to_vectors (GVariant *value, + GVariantVectors *vectors) +{ + g_variant_vectors_init (vectors); + + g_variant_callback_write_to_vectors (vectors, value, NULL); +} + /* < private > * g_variant_alloc: * @type: the type of the new instance diff --git a/glib/gvariant-serialiser.c b/glib/gvariant-serialiser.c index 5df7fc3..c25a7be 100644 --- a/glib/gvariant-serialiser.c +++ b/glib/gvariant-serialiser.c @@ -292,6 +292,19 @@ gvs_fixed_sized_maybe_serialise (GVariantSerialised value, } } +static gsize +gvs_fixed_sized_maybe_write_to_vectors (GVariantVectors *vectors, + GVariantTypeInfo *type_info, + gsize size, + const gpointer *children, + gsize n_children) +{ + if (!n_children) + return 0; + + return g_variant_callback_write_to_vectors (vectors, children[0], NULL); +} + static gboolean gvs_fixed_sized_maybe_is_normal (GVariantSerialised value) { @@ -384,6 +397,20 @@ gvs_variable_sized_maybe_serialise (GVariantSerialised value, } } +static void +gvs_variable_sized_maybe_write_to_vectors (GVariantVectors *vectors, + GVariantTypeInfo *type_info, + gsize size, + const gpointer *children, + gsize n_children) +{ + if (n_children) + { + g_variant_callback_write_to_vectors (vectors, children[0], NULL); + g_variant_vectors_append_copy (vectors, "", 1); + } +} + static gboolean gvs_variable_sized_maybe_is_normal (GVariantSerialised value) { @@ -482,6 +509,19 @@ gvs_fixed_sized_array_serialise (GVariantSerialised value, } } +static void +gvs_fixed_sized_array_write_to_vectors (GVariantVectors *vectors, + GVariantTypeInfo *type_info, + gsize size, + const gpointer *children, + gsize n_children) +{ + gsize i; + + for (i = 0; i < n_children; i++) + g_variant_callback_write_to_vectors (vectors, children[i], NULL); +} + static gboolean gvs_fixed_sized_array_is_normal (GVariantSerialised value) { @@ -747,6 +787,38 @@ gvs_variable_sized_array_serialise (GVariantSerialised value, } } +static void +gvs_variable_sized_array_write_to_vectors (GVariantVectors *vectors, + GVariantTypeInfo *type_info, + gsize size, + const gpointer *children, + gsize n_children) +{ + guint offset_key; + guint alignment; + gsize offset; + gsize i; + + if (n_children == 0) + return; + + offset_key = g_variant_vectors_reserve_offsets (vectors, n_children, gvs_get_offset_size (size)); + g_variant_type_info_query (type_info, &alignment, NULL); + offset = 0; + + for (i = 0; i < n_children; i++) + { + if ((-offset) & alignment) + offset += g_variant_vectors_append_pad (vectors, (-offset) & alignment); + + offset += g_variant_callback_write_to_vectors (vectors, children[i], NULL); + + g_variant_vectors_write_to_offsets (vectors, i, offset, offset_key); + } + + g_variant_vectors_commit_offsets (vectors, offset_key); +} + static gboolean gvs_variable_sized_array_is_normal (GVariantSerialised value) { @@ -1014,6 +1086,95 @@ gvs_tuple_serialise (GVariantSerialised value, value.data[offset++] = '\0'; } + +static void +gvs_tuple_write_to_vectors (GVariantVectors *vectors, + GVariantTypeInfo *type_info, + gsize size, + const gpointer *children, + gsize n_children) +{ + const GVariantMemberInfo *member_info = NULL; + gsize fixed_size; + gsize offset; + gsize i; + + if (n_children == 0) + { + g_variant_vectors_append_copy (vectors, "", 1); + return; + } + + g_variant_type_info_query (type_info, NULL, &fixed_size); + offset = 0; + + if (!fixed_size) + { + gsize n_offsets; + + member_info = g_variant_type_info_member_info (type_info, n_children - 1); + n_offsets = member_info->i + 1; + + if (n_offsets) + { + gsize offset_key = 0; + + offset_key = g_variant_vectors_reserve_offsets (vectors, n_offsets, gvs_get_offset_size (size)); + + for (i = 0; i < n_children; i++) + { + guint alignment; + + member_info = g_variant_type_info_member_info (type_info, i); + g_variant_type_info_query (member_info->type_info, &alignment, NULL); + + if ((-offset) & alignment) + offset += g_variant_vectors_append_pad (vectors, (-offset) & alignment); + + offset += g_variant_callback_write_to_vectors (vectors, children[i], NULL); + + if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_OFFSET) + g_variant_vectors_write_to_offsets (vectors, --n_offsets, offset, offset_key); + } + + g_variant_vectors_commit_offsets (vectors, offset_key); + } + else + { + for (i = 0; i < n_children; i++) + { + guint alignment; + + member_info = g_variant_type_info_member_info (type_info, i); + g_variant_type_info_query (member_info->type_info, &alignment, NULL); + + if ((-offset) & alignment) + offset += g_variant_vectors_append_pad (vectors, (-offset) & alignment); + + offset += g_variant_callback_write_to_vectors (vectors, children[i], NULL); + } + } + } + else + { + for (i = 0; i < n_children; i++) + { + guint alignment; + + member_info = g_variant_type_info_member_info (type_info, i); + g_variant_type_info_query (member_info->type_info, &alignment, NULL); + + if ((-offset) & alignment) + offset += g_variant_vectors_append_pad (vectors, (-offset) & alignment); + + offset += g_variant_callback_write_to_vectors (vectors, children[i], NULL); + } + + g_assert (fixed_size - offset < 8); + g_variant_vectors_append_pad (vectors, fixed_size - offset); + } +} + static gboolean gvs_tuple_is_normal (GVariantSerialised value) { @@ -1226,6 +1387,23 @@ gvs_variant_serialise (GVariantSerialised value, memcpy (value.data + child.size + 1, type_string, strlen (type_string)); } +static void +gvs_variant_write_to_vectors (GVariantVectors *vectors, + GVariantTypeInfo *type_info, + gsize size, + const gpointer *children, + gsize n_children) +{ + GVariantTypeInfo *child_type_info; + const gchar *type_string; + + g_variant_callback_write_to_vectors (vectors, children[0], &child_type_info); + type_string = g_variant_type_info_get_type_string (child_type_info); + + g_variant_vectors_append_copy (vectors, "", 1); + g_variant_vectors_append_copy (vectors, type_string, strlen (type_string)); +} + static inline gboolean gvs_variant_is_normal (GVariantSerialised value) { @@ -1435,7 +1613,21 @@ g_variant_serialiser_needed_size (GVariantTypeInfo *type_info, return gvs_/**/,/**/_needed_size (type_info, gvs_filler, children, n_children); + ) + g_assert_not_reached (); +} + +void +g_variant_serialiser_write_to_vectors (GVariantVectors *vectors, + GVariantTypeInfo *type_info, + gsize size, + const gpointer *children, + gsize n_children) +{ + DISPATCH_CASES (type_info, + gvs_/**/,/**/_write_to_vectors (vectors, type_info, size, children, n_children); + return; ) g_assert_not_reached (); } diff --git a/glib/gvariant-serialiser.h b/glib/gvariant-serialiser.h index 2be3299..a558da0 100644 --- a/glib/gvariant-serialiser.h +++ b/glib/gvariant-serialiser.h @@ -22,6 +22,7 @@ #define __G_VARIANT_SERIALISER_H__ #include "gvarianttypeinfo.h" +#include "gvariant-vectors.h" typedef struct { @@ -70,4 +71,14 @@ GLIB_AVAILABLE_IN_ALL gboolean g_variant_serialiser_is_signature (gconstpointer data, gsize size); + +gsize g_variant_callback_write_to_vectors (GVariantVectors *vectors, + gpointer data, + GVariantTypeInfo **type_info); +void g_variant_serialiser_write_to_vectors (GVariantVectors *items, + GVariantTypeInfo *type_info, + gsize size, + const gpointer *children, + gsize n_children); + #endif /* __G_VARIANT_SERIALISER_H__ */ -- 2.7.4