[glib/gv-load: 3/3] GVariant: add loading, byteswapping, normal-form



commit 27e1e3d219211c15970721e35a0fdcd75fe18f66
Author: Ryan Lortie <desrt desrt ca>
Date:   Sun Mar 14 14:01:24 2010 -0400

    GVariant: add loading, byteswapping, normal-form

 glib/glib.symbols    |    5 ++
 glib/gvariant-core.c |   61 +++++++++++++++-
 glib/gvariant.c      |  193 ++++++++++++++++++++++++++++++++++++++++++++++++++
 glib/gvariant.h      |   10 +++
 4 files changed, 265 insertions(+), 4 deletions(-)
---
diff --git a/glib/glib.symbols b/glib/glib.symbols
index 9d0c2a1..e7c36a9 100644
--- a/glib/glib.symbols
+++ b/glib/glib.symbols
@@ -1705,6 +1705,7 @@ g_variant_get_child_value
 g_variant_get_size
 g_variant_get_data
 g_variant_store
+g_variant_is_normal_form
 #endif
 
 #if IN_FILE(__G_VARIANT_C__)
@@ -1788,6 +1789,10 @@ g_variant_builder_add
 g_variant_get_child
 g_variant_iter_next
 g_variant_iter_loop
+
+g_variant_create_from_data
+g_variant_get_normal_form
+g_variant_byteswap
 #endif
 #endif
 
diff --git a/glib/gvariant-core.c b/glib/gvariant-core.c
index 51e1fac..183fa09 100644
--- a/glib/gvariant-core.c
+++ b/glib/gvariant-core.c
@@ -709,10 +709,9 @@ g_variant_get_size (GVariant *value)
  * @returns: the serialised form of @value, or %NULL
  *
  * Returns a pointer to the serialised form of a #GVariant instance.
- * The returned data is in machine native byte order but may not be in
- * fully-normalised form if read from an untrusted source.  The returned
- * data must not be freed; it remains valid for as long as @value
- * exists.
+ * The returned data may not be in fully-normalised form if read from an
+ * untrusted source.  The returned data must not be freed; it remains
+ * valid for as long as @value exists.
  *
  * If @value is a fixed-sized value that was deserialised from a
  * corrupted serialised container then %NULL may be returned.  In this
@@ -875,5 +874,59 @@ g_variant_store (GVariant *value,
   g_variant_unlock (value);
 }
 
+/**
+ * g_variant_is_normal_form:
+ * @value: a #GVariant instance
+ * @returns: %TRUE if @value is in normal form
+ *
+ * Checks if @value is in normal form.
+ *
+ * The main reason to do this is to detect if a given chunk of
+ * serialised data is in normal form: load the data into a #GVariant
+ * using g_variant_create_from_data() and then use this function to
+ * check.
+ *
+ * If @value is found to be in normal form then it will be marked as
+ * being trusted.  If the value was already marked as being trusted then
+ * this function will immediately return %TRUE.
+ *
+ * Since: 2.24
+ **/
+gboolean
+g_variant_is_normal_form (GVariant *value)
+{
+  if (value->state & STATE_TRUSTED)
+    return TRUE;
+
+  g_variant_lock (value);
+
+  if (value->state & STATE_SERIALISED)
+    {
+      GVariantSerialised serialised = {
+        value->type_info,
+        (gpointer) value->contents.serialised.data,
+        value->size
+      };
+
+      if (g_variant_serialised_is_normal (serialised))
+        value->state |= STATE_TRUSTED;
+    }
+  else
+    {
+      gboolean normal = TRUE;
+      gsize i;
+
+      for (i = 0; i < value->contents.tree.n_children; i++)
+        normal &= g_variant_is_normal_form (value->contents.tree.children[i]);
+
+      if (normal)
+        value->state |= STATE_TRUSTED;
+    }
+
+  g_variant_unlock (value);
+
+  return (value->state & STATE_TRUSTED) != 0;
+}
+
 #define __G_VARIANT_CORE_C__
 #include "galiasdef.c"
diff --git a/glib/gvariant.c b/glib/gvariant.c
index 1cacb63..c815fec 100644
--- a/glib/gvariant.c
+++ b/glib/gvariant.c
@@ -3912,6 +3912,199 @@ g_variant_iter_loop (GVariantIter *iter,
   return value != NULL;
 }
 
+/* Serialised data {{{1 */
+static GVariant *
+g_variant_deep_copy (GVariant *value)
+{
+  switch (g_variant_classify (value))
+    {
+    case G_VARIANT_CLASS_MAYBE:
+    case G_VARIANT_CLASS_ARRAY:
+    case G_VARIANT_CLASS_TUPLE:
+    case G_VARIANT_CLASS_DICT_ENTRY:
+    case G_VARIANT_CLASS_VARIANT:
+      {
+        GVariantBuilder builder;
+        GVariantIter iter;
+        GVariant *child;
+
+        g_variant_builder_init (&builder, g_variant_get_type (value));
+        g_variant_iter_init (&iter, value);
+
+        while ((child = g_variant_iter_next_value (&iter)))
+          {
+            g_variant_builder_add_value (&builder, g_variant_deep_copy (child));
+            g_variant_unref (child);
+          }
+
+        return g_variant_builder_end (&builder);
+      }
+
+    case G_VARIANT_CLASS_BOOLEAN:
+      return g_variant_new_boolean (g_variant_get_boolean (value));
+
+    case G_VARIANT_CLASS_BYTE:
+      return g_variant_new_byte (g_variant_get_byte (value));
+
+    case G_VARIANT_CLASS_INT16:
+      return g_variant_new_int16 (g_variant_get_int16 (value));
+
+    case G_VARIANT_CLASS_UINT16:
+      return g_variant_new_uint16 (g_variant_get_uint16 (value));
+
+    case G_VARIANT_CLASS_INT32:
+      return g_variant_new_int32 (g_variant_get_int32 (value));
+
+    case G_VARIANT_CLASS_UINT32:
+      return g_variant_new_uint32 (g_variant_get_uint32 (value));
+
+    case G_VARIANT_CLASS_INT64:
+      return g_variant_new_int64 (g_variant_get_int64 (value));
+
+    case G_VARIANT_CLASS_UINT64:
+      return g_variant_new_uint64 (g_variant_get_uint64 (value));
+
+    case G_VARIANT_CLASS_HANDLE:
+      return g_variant_new_handle (g_variant_get_handle (value));
+
+    case G_VARIANT_CLASS_DOUBLE:
+      return g_variant_new_double (g_variant_get_double (value));
+
+    case G_VARIANT_CLASS_STRING:
+      return g_variant_new_string (g_variant_get_string (value, NULL));
+
+    case G_VARIANT_CLASS_OBJECT_PATH:
+      return g_variant_new_object_path (g_variant_get_string (value, NULL));
+
+    case G_VARIANT_CLASS_SIGNATURE:
+      return g_variant_new_signature (g_variant_get_string (value, NULL));
+    }
+
+  g_assert_not_reached ();
+}
+
+/**
+ * g_variant_get_normal_form:
+ * @value: a #GVariant
+ * @returns: a trusted #GVariant
+ *
+ * Gets a #GVariant instance that has the same value as @value and is
+ * trusted to be in normal form.
+ *
+ * If @value is already trusted to be in normal form then a new
+ * reference to @value is returned.
+ *
+ * If @value is not already trusted, then it is scanned to check if it
+ * is in normal form.  If it is found to be in normal form then it is
+ * marked as trusted and a new reference to it is returned.
+ *
+ * If @value is found not to be in normal form then a new trusted
+ * #GVariant is created with the same value as @value.
+ *
+ * It makes sense to call this function if you've received #GVariant
+ * data from untrusted sources and you want to ensure your serialised
+ * output is definitely in normal form.
+ **/
+GVariant *
+g_variant_get_normal_form (GVariant *value)
+{
+  GVariant *trusted;
+
+  if (g_variant_is_normal_form (value))
+    return g_variant_ref (value);
+
+  trusted = g_variant_deep_copy (value);
+  g_assert (g_variant_is_trusted (trusted));
+
+  return g_variant_ref_sink (trusted);
+}
+
+/**
+ * g_variant_byteswap:
+ * @value: a #GVariant
+ * @returns: the byteswapped form of @value
+ *
+ * Performs a byteswapping operation on the contents of @value.  The
+ * result is that all multi-byte numeric data contained in @value is
+ * byteswapped.  That includes 16, 32, and 64bit signed and unsigned
+ * integers as well as file handles and double precision floating point
+ * values.
+ *
+ * This function is an identity mapping on any value that does not
+ * contain multi-byte numeric data.  That include strings, booleans,
+ * bytes and containers containing only these things (recursively).
+ *
+ * The returned value is always in normal form and is marked as trusted.
+ **/
+GVariant *
+g_variant_byteswap (GVariant *value)
+{
+  GVariantSerialised serialised;
+  GVariant *trusted;
+  GBuffer *buffer;
+  GVariant *new;
+
+  trusted = g_variant_get_normal_form (value);
+  serialised.type_info = g_variant_get_type_info (value);
+  serialised.size = g_variant_get_size (trusted);
+  serialised.data = g_malloc (serialised.size);
+  g_variant_store (value, serialised.data);
+
+  buffer = g_buffer_new_take_data (serialised.data, serialised.size);
+  new = g_variant_new_from_buffer (g_variant_get_type (value), buffer, TRUE);
+  g_buffer_unref (buffer);
+
+  return g_variant_ref_sink (new);
+}
+
+/**
+ * g_variant_create_from_data:
+ * @type: a #GVariantType
+ * @data: the serialised data
+ * @size: the size of @data
+ * @trusted: %TRUE if @data is definitely in normal form
+ * @notify: function to call when @data is no longer needed
+ * @user_data: data for @notify
+ *
+ * Creates a new #GVariant instance from serialised data.
+ *
+ * @type is the type of #GVariant instance that will be constructed.
+ * The interpretation of @data depends on knowing the type.
+ *
+ * @data is not modified by this function and must remain valid with an
+ * unchanging value until such a time as @notify is called with
+ * @user_data.  If the contents of @data change before that time then
+ * the result is undefined.
+ *
+ * If @data is trusted to be serialised data in normal form then
+ * @trusted should be %TRUE.  This applies to serialised data created
+ * within this process or read from a trusted location on the disk (such
+ * as a file installed in /usr/lib alongside your application).  You
+ * should set trusted to %FALSE if @data is read from the network, a
+ * file in the user's home directory, etc.
+ *
+ * @notify will be called with @user_data when @data is no longer
+ * needed.  The exact time of this call is unspecified and might even be
+ * before this function returns.
+ **/
+GVariant *
+g_variant_create_from_data (const GVariantType *type,
+                            gconstpointer       data,
+                            gsize               size,
+                            gboolean            trusted,
+                            GDestroyNotify      notify,
+                            gpointer            user_data)
+{
+  GVariant *value;
+  GBuffer *buffer;
+
+  buffer = g_buffer_new_from_pointer (data, size, notify, user_data);
+  value = g_variant_new_from_buffer (type, buffer, trusted);
+  g_buffer_unref (buffer);
+
+  return g_variant_ref_sink (value);
+}
+
 /* Epilogue {{{1 */
 #define __G_VARIANT_C__
 #include "galiasdef.c"
diff --git a/glib/gvariant.h b/glib/gvariant.h
index abf8102..4d6f9c9 100644
--- a/glib/gvariant.h
+++ b/glib/gvariant.h
@@ -139,6 +139,16 @@ guint                           g_variant_hash                          (gconstp
 gboolean                        g_variant_equal                         (gconstpointer         one,
                                                                          gconstpointer         two);
 
+GVariant *                      g_variant_get_normal_form               (GVariant             *variant);
+gboolean                        g_variant_is_normal_form                (GVariant             *variant);
+GVariant *                      g_variant_byteswap                      (GVariant             *variant);
+GVariant *                      g_variant_create_from_data              (const GVariantType   *type,
+                                                                         gconstpointer         data,
+                                                                         gsize                 size,
+                                                                         gboolean              trusted,
+                                                                         GDestroyNotify        notify,
+                                                                         gpointer              user_data);
+
 typedef struct _GVariantIter GVariantIter;
 struct _GVariantIter {
   /*< private >*/



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