GVariant vector deserialiser WIP
authorRyan Lortie <desrt@desrt.ca>
Wed, 3 Dec 2014 07:14:19 +0000 (02:14 -0500)
committerMaciej Wereski <m.wereski@partner.samsung.com>
Fri, 10 Jul 2015 09:47:43 +0000 (11:47 +0200)
glib/glib-private.c
glib/glib-private.h
glib/gvariant-core.c
glib/gvariant-serialiser.c
glib/gvariant-serialiser.h
glib/gvariant-vectors.h

index 3c1dac6..5c23c0c 100644 (file)
@@ -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;
index 40509b6..29fa2f2 100644 (file)
@@ -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 */
index 32b1a88..62aabaa 100644 (file)
@@ -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 -- */
 
 /**
index c25a7be..1c0a9fe 100644 (file)
@@ -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,
index a558da0..2cd983a 100644 (file)
@@ -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);
index b1f0519..73d1f2f 100644 (file)
@@ -19,7 +19,7 @@ typedef struct
 {
   GBytes *gbytes;
   union {
-    gconstpointer pointer;
+    const guchar *pointer;
     gsize         offset;
   } data;
   gsize    size;