diff options
author | Ryan Lortie <desrt@desrt.ca> | 2014-12-03 02:14:19 -0500 |
---|---|---|
committer | Ryan Lortie <desrt@desrt.ca> | 2014-12-03 02:14:19 -0500 |
commit | 3468ab849b4ee04f1494d5dead6045a7984f4886 (patch) | |
tree | a04d2a5ca6b00658d49d8b8c2b8354a732e01faf | |
parent | a169f1d1a855b7119178ce372b5bacb314aa3f37 (diff) | |
download | glib-3468ab849b4ee04f1494d5dead6045a7984f4886.tar.gz |
GVariant vector deserialiser WIP
-rw-r--r-- | glib/glib-private.c | 3 | ||||
-rw-r--r-- | glib/glib-private.h | 10 | ||||
-rw-r--r-- | glib/gvariant-core.c | 151 | ||||
-rw-r--r-- | glib/gvariant-serialiser.c | 9 | ||||
-rw-r--r-- | glib/gvariant-serialiser.h | 13 | ||||
-rw-r--r-- | glib/gvariant-vectors.h | 2 |
6 files changed, 186 insertions, 2 deletions
diff --git a/glib/glib-private.c b/glib/glib-private.c index 3c1dac636..5c23c0c97 100644 --- a/glib/glib-private.c +++ b/glib/glib-private.c @@ -46,7 +46,8 @@ glib__private__ (void) g_dir_open_with_errno, g_dir_new_from_dirp, - g_variant_to_vectors + g_variant_to_vectors, + g_variant_from_vectors }; return &table; diff --git a/glib/glib-private.h b/glib/glib-private.h index 40509b68f..29fa2f267 100644 --- a/glib/glib-private.h +++ b/glib/glib-private.h @@ -33,6 +33,11 @@ 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); +GVariant * g_variant_from_vectors (const GVariantType *type, + GVariantVector *vectors, + gsize n_vectors, + gsize size, + gboolean trusted); #ifdef G_OS_WIN32 gchar *_glib_get_dll_directory (void); @@ -66,6 +71,11 @@ typedef struct { void (* g_variant_to_vectors) (GVariant *value, GVariantVectors *vectors); + GVariant * (* g_variant_from_vectors) (const GVariantType *type, + GVariantVector *vectors, + gsize n_vectors, + gsize size, + gboolean trusted); /* Add other private functions here, initialize them in glib-private.c */ diff --git a/glib/gvariant-core.c b/glib/gvariant-core.c index 32b1a886a..62aabaaca 100644 --- a/glib/gvariant-core.c +++ b/glib/gvariant-core.c @@ -665,6 +665,157 @@ g_variant_get_serialised (GVariant *value, return value->contents.serialised.data; } +static GVariant * +g_variant_vector_deserialise (GVariantTypeInfo *type_info, + GVariantVector *first_vector, + GVariantVector *last_vector, + gsize size, + gboolean trusted, + GArray *children) +{ + g_assert (size > 0); + + if (first_vector < last_vector) + { + GVariantVector *vector = first_vector; + gconstpointer end; + GVariant **new; + guint offset; + guint i, n; + + end = last_vector->data.pointer + last_vector->size; + + offset = children->len; + + if (!g_variant_serialiser_unpack_all (type_info, end, last_vector->size, size, children)) + { + /* We are supposed to consume type_info */ + g_variant_type_info_unref (type_info); + return FALSE; + } + + n = children->len - offset; + new = g_new (GVariant *, n); + + for (i = 0; i < n; i++) + { + GVariantUnpacked *unpacked; + GVariantVector *fv; + gsize saved_size; + + unpacked = &g_array_index (children, GVariantUnpacked, offset + i); + + /* Skip the alignment. + * + * We can destroy vectors because we won't be going back. + * + * We do a >= compare because we want to go to the next vector + * if it is the start of our child. + */ + while (unpacked->skip >= vector->size) + { + unpacked->skip -= vector->size; + vector++; + } + fv = vector; + fv->data.pointer += unpacked->skip; + fv->size -= unpacked->skip; + + if (unpacked->size == 0) + { + new[i] = g_variant_new_serialised (type_info, g_bytes_new (NULL, 0), NULL, 0, trusted); + continue; + } + + /* Now skip to the end, according to 'size'. + * + * We cannot destroy everything here because we will probably + * end up reusing the last one. + * + * We do a > compare because we want to stay on this vector if + * it is the end of our child. + */ + size = unpacked->size; + while (unpacked->size > vector->size) + { + unpacked->size -= vector->size; + vector++; + } + + /* temporarily replace the size field */ + saved_size = vector->size; + vector->size = unpacked->size; + + new[i] = g_variant_vector_deserialise (unpacked->type_info, fv, vector, size, trusted, children); + + if (new[i] == NULL) + { + gint j; + + /* Free the new children array and any children in it up + * to this point. + */ + for (j = 0; j < i; j++) + g_variant_unref (new[j]); + g_free (new); + + /* Consume the type_info for the remaining children */ + for (j = i + 1; j < n; j++) + g_variant_type_info_unref (g_array_index (children, GVariantUnpacked, offset + i).type_info); + + /* Rewind this */ + g_array_set_size (children, offset); + + /* We have to free this */ + g_variant_type_info_unref (type_info); + + return NULL; + } + + /* Repair the last vector and move past our data */ + vector->data.pointer += unpacked->size; + vector->size -= saved_size - unpacked->size; + } + + /* Rewind */ + g_array_set_size (children, offset); + + /* Create the tree-form GVariant in the usual way */ + return g_variant_new_from_children (type_info, new, n, trusted); + } + else + { + g_assert (first_vector == last_vector); + g_assert (size == first_vector->size); + + return g_variant_new_serialised (type_info, g_bytes_ref (first_vector->gbytes), + first_vector->data.pointer, size, trusted); + } +} + +GVariant * +g_variant_from_vectors (const GVariantType *type, + GVariantVector *vectors, + gsize n_vectors, + gsize size, + gboolean trusted) +{ + GVariant *result; + GArray *tmp; + + g_return_val_if_fail (vectors != NULL || n_vectors == 0, NULL); + + if (size == 0) + return g_variant_new_serialised (g_variant_type_info_get (type), g_bytes_new (NULL, 0), NULL, 0, trusted); + + tmp = g_array_new (FALSE, FALSE, sizeof (GVariantUnpacked)); + result = g_variant_vector_deserialise (g_variant_type_info_get (type), + vectors, vectors + n_vectors - 1, size, trusted, tmp); + g_array_free (tmp, TRUE); + + return result; +} + /* -- public -- */ /** diff --git a/glib/gvariant-serialiser.c b/glib/gvariant-serialiser.c index c25a7bea7..1c0a9fe77 100644 --- a/glib/gvariant-serialiser.c +++ b/glib/gvariant-serialiser.c @@ -1617,6 +1617,15 @@ g_variant_serialiser_needed_size (GVariantTypeInfo *type_info, g_assert_not_reached (); } +gboolean +g_variant_serialiser_unpack_all (GVariantTypeInfo *type_info, + gconstpointer end, + gsize end_size, + gsize total_size, + GArray *results) +{ + return FALSE; +} void g_variant_serialiser_write_to_vectors (GVariantVectors *vectors, diff --git a/glib/gvariant-serialiser.h b/glib/gvariant-serialiser.h index a558da020..2cd983a3b 100644 --- a/glib/gvariant-serialiser.h +++ b/glib/gvariant-serialiser.h @@ -31,6 +31,13 @@ typedef struct gsize size; } GVariantSerialised; +typedef struct +{ + GVariantTypeInfo *type_info; + gsize skip; + gsize size; +} GVariantUnpacked; + /* deserialisation */ GLIB_AVAILABLE_IN_ALL gsize g_variant_serialised_n_children (GVariantSerialised container); @@ -38,6 +45,12 @@ GLIB_AVAILABLE_IN_ALL GVariantSerialised g_variant_serialised_get_child (GVariantSerialised container, gsize index); +gboolean g_variant_serialiser_unpack_all (GVariantTypeInfo *type_info, + gconstpointer end_pointer, + gsize end_size, + gsize total_size, + GArray *results_array); + /* serialisation */ typedef void (*GVariantSerialisedFiller) (GVariantSerialised *serialised, gpointer data); diff --git a/glib/gvariant-vectors.h b/glib/gvariant-vectors.h index b1f0519f9..73d1f2ffe 100644 --- a/glib/gvariant-vectors.h +++ b/glib/gvariant-vectors.h @@ -19,7 +19,7 @@ typedef struct { GBytes *gbytes; union { - gconstpointer pointer; + const guchar *pointer; gsize offset; } data; gsize size; |