[glib/wip/gvariant-kdbus] finish up vector deserialiser



commit e1903e40d8fe7f38c624cbd25ba8d0e215fc2741
Author: Ryan Lortie <desrt desrt ca>
Date:   Wed Dec 3 20:35:18 2014 -0500

    finish up vector deserialiser
    
    seems to have stopped crashing now...

 glib/gvariant-core.c       |   46 +++++++++++++--
 glib/gvariant-serialiser.c |  142 +++++++++++++++++++++++++++++++++++++++++--
 glib/tests/gvariant.c      |   19 ++++++-
 3 files changed, 194 insertions(+), 13 deletions(-)
---
diff --git a/glib/gvariant-core.c b/glib/gvariant-core.c
index 62aabaa..ea0a94e 100644
--- a/glib/gvariant-core.c
+++ b/glib/gvariant-core.c
@@ -675,6 +675,19 @@ g_variant_vector_deserialise (GVariantTypeInfo *type_info,
 {
   g_assert (size > 0);
 
+#if 0
+  gsize tally = 0;
+  gint i;
+
+  g_print ("enter as %s (size %d)\n", g_variant_type_info_get_type_string (type_info), (guint) size);
+  for (i = 0; first_vector + i <= last_vector; i++)
+    {
+      g_print ("  %p %d\n", first_vector[i].data.pointer, (guint) first_vector[i].size);
+      tally += first_vector[i].size;
+    }
+  g_assert_cmpint (size, ==, tally);
+#endif
+
   if (first_vector < last_vector)
     {
       GVariantVector *vector = first_vector;
@@ -691,6 +704,16 @@ g_variant_vector_deserialise (GVariantTypeInfo *type_info,
         {
           /* We are supposed to consume type_info */
           g_variant_type_info_unref (type_info);
+
+          for (i = offset; i < children->len; i++)
+            {
+              GVariantUnpacked *unpacked = &g_array_index (children, GVariantUnpacked, i);
+
+              g_variant_type_info_unref (unpacked->type_info);
+            }
+
+          g_array_set_size (children, offset);
+
           return FALSE;
         }
 
@@ -701,7 +724,8 @@ g_variant_vector_deserialise (GVariantTypeInfo *type_info,
         {
           GVariantUnpacked *unpacked;
           GVariantVector *fv;
-          gsize saved_size;
+          const guchar *resume_at;
+          gsize resume_at_size;
 
           unpacked = &g_array_index (children, GVariantUnpacked, offset + i);
 
@@ -717,6 +741,9 @@ g_variant_vector_deserialise (GVariantTypeInfo *type_info,
               unpacked->skip -= vector->size;
               vector++;
             }
+          g_assert (vector >= first_vector);
+          g_assert (vector <= last_vector);
+
           fv = vector;
           fv->data.pointer += unpacked->skip;
           fv->size -= unpacked->skip;
@@ -736,14 +763,21 @@ g_variant_vector_deserialise (GVariantTypeInfo *type_info,
            * it is the end of our child.
            */
           size = unpacked->size;
+          //g_print ("need to seek %d bytes\n", (guint) size);
           while (unpacked->size > vector->size)
             {
+              //g_print ("  skipping %d\n", (guint) vector->size);
               unpacked->size -= vector->size;
               vector++;
             }
 
+          g_assert (vector >= first_vector);
+          g_assert (vector <= last_vector);
+
           /* temporarily replace the size field */
-          saved_size = vector->size;
+          //g_print ("--adj last size from %d to %d\n", (guint) vector->size, (guint) unpacked->size);
+          resume_at = vector->data.pointer + unpacked->size;
+          resume_at_size = vector->size - unpacked->size;
           vector->size = unpacked->size;
 
           new[i] = g_variant_vector_deserialise (unpacked->type_info, fv, vector, size, trusted, children);
@@ -761,7 +795,7 @@ g_variant_vector_deserialise (GVariantTypeInfo *type_info,
 
               /* 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);
+                g_variant_type_info_unref (g_array_index (children, GVariantUnpacked, offset + j).type_info);
 
               /* Rewind this */
               g_array_set_size (children, offset);
@@ -773,8 +807,10 @@ g_variant_vector_deserialise (GVariantTypeInfo *type_info,
             }
 
           /* Repair the last vector and move past our data */
-          vector->data.pointer += unpacked->size;
-          vector->size -= saved_size - unpacked->size;
+          //g_print ("chug %d\n", (guint) unpacked->size);
+          vector->data.pointer = resume_at;
+          vector->size = resume_at_size;
+          //g_print ("now have %d left\n", (guint) vector->size);
         }
 
       /* Rewind */
diff --git a/glib/gvariant-serialiser.c b/glib/gvariant-serialiser.c
index 7880c5a..d5cbd3c 100644
--- a/glib/gvariant-serialiser.c
+++ b/glib/gvariant-serialiser.c
@@ -864,14 +864,16 @@ gvs_variable_sized_array_unpack_all (GVariantTypeInfo *type_info,
       end = gvs_read_unaligned_le (offsets, offset_size);
       offsets += offset_size;
 
-      if (start < prev_end || end < start) { g_assert_not_reached ();
-        return FALSE; /* XXX free the array and type infos */ }
+      if (start < prev_end || end < start)
+       return FALSE;
 
       unpacked.type_info = g_variant_type_info_ref (element);
       unpacked.skip = start - prev_end;
       unpacked.size = end - start;
 
       g_array_append_val (results, unpacked);
+
+      prev_end = end;
     }
 
   return TRUE;
@@ -1155,13 +1157,82 @@ gvs_tuple_get_child (GVariantSerialised value,
 
 static gboolean
 gvs_tuple_unpack_all (GVariantTypeInfo *type_info,
-                      const guchar     *end,
+                      const guchar     *end_pointer,
                       gsize             end_size,
                       gsize             total_size,
                       GArray           *results)
 {
-  g_assert_not_reached (); /* FIXME */
-  return FALSE;
+  gsize offset_size;
+  gsize prev_end;
+  gsize i, n;
+
+  n = g_variant_type_info_n_members (type_info);
+
+  /* An empty tuple (n = 0) is always encoded as a single byte, which
+   * means that we should not be attempting to unpack it from multiple
+   * vectors.
+   */
+  if (n == 0)
+    return FALSE;
+
+  offset_size = gvs_get_offset_size (total_size);
+
+  prev_end = 0;
+
+  for (i = 0; i < n; i++)
+    {
+      const GVariantMemberInfo *member_info;
+      GVariantUnpacked unpacked;
+      gsize fixed_size;
+      guint alignment;
+      gsize start;
+      gsize end;
+
+      member_info = g_variant_type_info_member_info (type_info, i);
+      g_variant_type_info_query (member_info->type_info, &alignment, &fixed_size);
+
+      start = prev_end + ((-prev_end) & alignment);
+
+      switch (member_info->ending_type)
+        {
+        case G_VARIANT_MEMBER_ENDING_FIXED:
+          end = start + fixed_size;
+          break;
+
+        case G_VARIANT_MEMBER_ENDING_LAST:
+          end = total_size;
+          break;
+
+        case G_VARIANT_MEMBER_ENDING_OFFSET:
+          if (end_size < offset_size)
+            return FALSE;
+
+          end_pointer -= offset_size;
+          total_size -= offset_size;
+          end_size -= offset_size;
+
+          end = gvs_read_unaligned_le (end_pointer, offset_size);
+          break;
+
+        default:
+          g_assert_not_reached ();
+        }
+
+      if (start < prev_end || end < start)
+        return FALSE;
+
+      unpacked.type_info = g_variant_type_info_ref (member_info->type_info);
+      unpacked.skip = start - prev_end;
+      unpacked.size = end - start;
+
+      g_array_append_val (results, unpacked);
+
+      prev_end = end;
+    }
+
+  g_assert (prev_end == total_size);
+
+  return TRUE;
 }
 
 static gsize
@@ -1515,14 +1586,71 @@ gvs_variant_get_child (GVariantSerialised value,
   return child;
 }
 
+static GVariantTypeInfo *
+gvs_variant_find_type (const guchar *end_pointer,
+                       gsize         end_size,
+                       gsize         total_size,
+                       gsize        *child_size)
+{
+  gsize i;
+
+  for (i = 1; i <= end_size; i++)
+    if (end_pointer[-i] == '\0')
+      {
+        const gchar *type_string = (gchar *) end_pointer - i + 1;
+        const gchar *limit = (gchar *) end_pointer;
+        const gchar *end;
+
+        /* We may have a type string of length 'i'.  Check for validity. */
+        if (g_variant_type_string_scan (type_string, limit, &end) && end == limit)
+          {
+            const GVariantType *type = (GVariantType *) type_string;
+
+            if (g_variant_type_is_definite (type))
+              {
+                GVariantTypeInfo *type_info;
+                gsize fixed_size;
+
+                type_info = g_variant_type_info_get (type);
+
+                g_variant_type_info_query (type_info, NULL, &fixed_size);
+
+                if (!fixed_size || fixed_size == total_size - i)
+                  {
+                    *child_size = total_size - i;
+
+                    return type_info;
+                  }
+
+                g_variant_type_info_unref (type_info);
+              }
+          }
+
+        /* No sense in trying other lengths if we already failed */
+        break;
+      }
+
+  return NULL;
+}
+
 static gboolean
 gvs_variant_unpack_all (GVariantTypeInfo *type_info,
-                        const guchar     *end,
+                        const guchar     *end_pointer,
                         gsize             end_size,
                         gsize             total_size,
                         GArray           *results)
 {
-  g_assert_not_reached (); /* FIXME */
+  GVariantUnpacked unpacked;
+
+  if ((unpacked.type_info = gvs_variant_find_type (end_pointer, end_size, total_size, &unpacked.size)))
+    {
+      unpacked.skip = 0;
+
+      g_array_append_val (results, unpacked);
+
+      return TRUE;
+    }
+
   return FALSE;
 }
 
diff --git a/glib/tests/gvariant.c b/glib/tests/gvariant.c
index d42bdfb..3d38b4f 100644
--- a/glib/tests/gvariant.c
+++ b/glib/tests/gvariant.c
@@ -4643,9 +4643,26 @@ test_vector_serialiser (void)
 
   for (i = 0; i < 100; i++)
     {
-      value = create_random_gvariant (4);
+      guint j;
+
+      value = create_random_gvariant (2);
+      //g_print (">>> %s\n", g_variant_print (value, TRUE));
 
       GLIB_PRIVATE_CALL(g_variant_to_vectors) (value, &vectors);
+      for (j = 0; j < vectors.vectors->len; j++)
+        {
+          GVariantVector *v = &g_array_index (vectors.vectors, GVariantVector, j);
+
+          if (!v->gbytes)
+            {
+              v->gbytes = g_bytes_new (NULL, 0);
+              v->data.pointer = v->data.offset + vectors.extra_bytes->data;
+            }
+
+          //g_print ("  V %p %p %d\n", v, v->data.pointer, (guint) v->size);
+        }
+      GLIB_PRIVATE_CALL(g_variant_from_vectors) (g_variant_get_type (value), (GVariantVector *) 
vectors.vectors->data, vectors.vectors->len, g_variant_get_size (value), TRUE);
+      continue;
       flattened = flatten_vectors (&vectors);
       g_byte_array_free (vectors.extra_bytes, TRUE);
       g_byte_array_free (vectors.offsets, TRUE);


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