[glib/glib-2-26] GSettings: Big Endian fixes



commit fe225e7e7c7424fbfbdeb63c41db63c21f8f7751
Author: Ryan Lortie <desrt desrt ca>
Date:   Fri Nov 12 10:57:05 2010 -0500

    GSettings: Big Endian fixes
    
    Backport a bunch of fixes from master, squashed together into this one
    commit.

 gio/glib-compile-schemas.c |    6 +++
 gio/gsettings.c            |   15 +++++++++
 gio/gsettingsschema.c      |   14 +-------
 gio/gvdb/gvdb-reader.c     |   73 ++++++++++++++++++++++++++++++++++++++++---
 gio/gvdb/gvdb-reader.h     |    6 +++
 gio/strinfo.c              |    4 +-
 gio/tests/gsettings.c      |   14 +++++---
 glib/gvariant.c            |   40 ++++++++++++++++--------
 8 files changed, 133 insertions(+), 39 deletions(-)
---
diff --git a/gio/glib-compile-schemas.c b/gio/glib-compile-schemas.c
index 22681d0..f75ae08 100644
--- a/gio/glib-compile-schemas.c
+++ b/gio/glib-compile-schemas.c
@@ -623,12 +623,18 @@ key_state_serialise (KeyState *state)
           if (state->strinfo->len)
             {
               GVariant *array;
+              guint32 *words;
               gpointer data;
               gsize size;
+              gint i;
 
               data = state->strinfo->str;
               size = state->strinfo->len;
 
+              words = data;
+              for (i = 0; i < size / sizeof (guint32); i++)
+                words[i] = GUINT32_TO_LE (words[i]);
+
               array = g_variant_new_from_data (G_VARIANT_TYPE ("au"),
                                                data, size, TRUE,
                                                g_free, data);
diff --git a/gio/gsettings.c b/gio/gsettings.c
index 2365fa9..94d1f3a 100644
--- a/gio/gsettings.c
+++ b/gio/gsettings.c
@@ -813,6 +813,18 @@ typedef struct
   GVariant *default_value;
 } GSettingsKeyInfo;
 
+static inline void
+endian_fixup (GVariant **value)
+{
+#if G_BYTE_ORDER == G_BIG_ENDIAN
+  GVariant *tmp;
+
+  tmp = g_variant_byteswap (*value);
+  g_variant_unref (*value);
+  *value = tmp;
+#endif
+}
+
 static void
 g_settings_get_key_info (GSettingsKeyInfo *info,
                          GSettings        *settings,
@@ -827,6 +839,7 @@ g_settings_get_key_info (GSettingsKeyInfo *info,
   iter = g_settings_schema_get_value (settings->priv->schema, key);
 
   info->default_value = g_variant_iter_next_value (iter);
+  endian_fixup (&info->default_value);
   info->type = g_variant_get_type (info->default_value);
   info->settings = g_object_ref (settings);
   info->key = g_intern_string (key);
@@ -859,6 +872,8 @@ g_settings_get_key_info (GSettingsKeyInfo *info,
 
         case 'r':
           g_variant_get (data, "(**)", &info->minimum, &info->maximum);
+          endian_fixup (&info->minimum);
+          endian_fixup (&info->maximum);
           break;
 
         default:
diff --git a/gio/gsettingsschema.c b/gio/gsettingsschema.c
index 6d8d77a..45572a3 100644
--- a/gio/gsettingsschema.c
+++ b/gio/gsettingsschema.c
@@ -181,7 +181,7 @@ g_settings_schema_get_string (GSettingsSchema *schema,
   const gchar *result = NULL;
   GVariant *value;
 
-  if ((value = gvdb_table_get_value (schema->priv->table, key)))
+  if ((value = gvdb_table_get_raw_value (schema->priv->table, key)))
     {
       result = g_variant_get_string (value, NULL);
       g_variant_unref (value);
@@ -231,21 +231,11 @@ g_settings_schema_get_value (GSettingsSchema *schema,
   GVariantIter *iter;
   GVariant *value;
 
-  value = gvdb_table_get_value (schema->priv->table, key);
+  value = gvdb_table_get_raw_value (schema->priv->table, key);
 
   if G_UNLIKELY (value == NULL)
     g_error ("schema does not contain a key named '%s'", key);
 
-#if G_BYTE_ORDER == G_BIG_ENDIAN
-  {
-    GVariant *tmp;
-
-    tmp = g_variant_byteswap (value);
-    g_variant_unref (value);
-    value = tmp;
-  }
-#endif
-
   iter = g_variant_iter_new (value);
   g_variant_unref (value);
 
diff --git a/gio/gvdb/gvdb-reader.c b/gio/gvdb/gvdb-reader.c
index 1cd3206..d25e537 100644
--- a/gio/gvdb/gvdb-reader.c
+++ b/gio/gvdb/gvdb-reader.c
@@ -34,11 +34,11 @@ struct _GvdbTable {
   gboolean byteswapped;
   gboolean trusted;
 
-  const guint32 *bloom_words;
+  const guint32_le *bloom_words;
   guint32 n_bloom_words;
   guint bloom_shift;
 
-  const guint32 *hash_buckets;
+  const guint32_le *hash_buckets;
   guint32 n_buckets;
 
   struct gvdb_hash_item *hash_items;
@@ -206,7 +206,7 @@ gvdb_table_bloom_filter (GvdbTable *file,
   mask = 1 << (hash_value & 31);
   mask |= 1 << ((hash_value >> file->bloom_shift) & 31);
 
-  return (file->bloom_words[word] & mask) == mask;
+  return (guint32_from_le (file->bloom_words[word]) & mask) == mask;
 }
 
 static gboolean
@@ -262,10 +262,10 @@ gvdb_table_lookup (GvdbTable   *file,
     return NULL;
 
   bucket = hash_value % file->n_buckets;
-  itemno = file->hash_buckets[bucket];
+  itemno = guint32_from_le (file->hash_buckets[bucket]);
 
   if (bucket == file->n_buckets - 1 ||
-      (lastno = file->hash_buckets[bucket + 1]) > file->n_hash_items)
+      (lastno = guint32_from_le(file->hash_buckets[bucket + 1])) > file->n_hash_items)
     lastno = file->n_hash_items;
 
   while G_LIKELY (itemno < lastno)
@@ -438,11 +438,46 @@ gvdb_table_get_value (GvdbTable    *file,
                       const gchar  *key)
 {
   const struct gvdb_hash_item *item;
+  GVariant *value;
 
   if ((item = gvdb_table_lookup (file, key, 'v')) == NULL)
     return NULL;
 
-  return gvdb_table_value_from_item (file, item);
+  value = gvdb_table_value_from_item (file, item);
+
+  if (value && file->byteswapped)
+    {
+      GVariant *tmp;
+
+      tmp = g_variant_byteswap (value);
+      g_variant_unref (value);
+      value = tmp;
+    }
+
+  return value;
+}
+
+/**
+ * gvdb_table_get_raw_value:
+ * @table: a #GvdbTable
+ * @key: a string
+ * @returns: a #GVariant, or %NULL
+ *
+ * Looks up a value named @key in @file.
+ *
+ * This call is equivalent to gvdb_table_get_value() except that it
+ * never byteswaps the value.
+ **/
+GVariant *
+gvdb_table_get_raw_value (GvdbTable   *table,
+                          const gchar *key)
+{
+  const struct gvdb_hash_item *item;
+
+  if ((item = gvdb_table_lookup (table, key, 'v')) == NULL)
+    return NULL;
+
+  return gvdb_table_value_from_item (table, item);
 }
 
 /**
@@ -522,6 +557,23 @@ gvdb_table_unref (GvdbTable *file)
     }
 }
 
+/**
+ * gvdb_table_is_valid:
+ * @table: a #GvdbTable
+ * @returns: %TRUE if @table is still valid
+ *
+ * Checks if the table is still valid.
+ *
+ * An on-disk GVDB can be marked as invalid.  This happens when the file
+ * has been replaced.  The appropriate action is typically to reopen the
+ * file.
+ **/
+gboolean
+gvdb_table_is_valid (GvdbTable *table)
+{
+  return !!*table->data;
+}
+
 void
 gvdb_table_walk (GvdbTable         *table,
                  const gchar       *key,
@@ -579,6 +631,15 @@ gvdb_table_walk (GvdbTable         *table,
 
                   if (value != NULL)
                     {
+                      if (table->byteswapped)
+                        {
+                          GVariant *tmp;
+
+                          tmp = g_variant_byteswap (value);
+                          g_variant_unref (value);
+                          value = tmp;
+                        }
+
                       value_func (name, name_len, value, user_data);
                       g_variant_unref (value);
                     }
diff --git a/gio/gvdb/gvdb-reader.h b/gio/gvdb/gvdb-reader.h
index a29c16e..9f302c0 100644
--- a/gio/gvdb/gvdb-reader.h
+++ b/gio/gvdb/gvdb-reader.h
@@ -42,6 +42,9 @@ G_GNUC_INTERNAL
 GvdbTable *             gvdb_table_get_table                            (GvdbTable    *table,
                                                                          const gchar  *key);
 G_GNUC_INTERNAL
+GVariant *              gvdb_table_get_raw_value                        (GvdbTable    *table,
+                                                                         const gchar  *key);
+G_GNUC_INTERNAL
 GVariant *              gvdb_table_get_value                            (GvdbTable    *table,
                                                                          const gchar  *key);
 
@@ -49,6 +52,9 @@ G_GNUC_INTERNAL
 gboolean                gvdb_table_has_value                            (GvdbTable    *table,
                                                                          const gchar  *key);
 
+G_GNUC_INTERNAL
+gboolean                gvdb_table_is_valid                             (GvdbTable    *table);
+
 typedef void          (*GvdbWalkValueFunc)                              (const gchar       *name,
                                                                          gsize              name_len,
                                                                          GVariant          *value,
diff --git a/gio/strinfo.c b/gio/strinfo.c
index 84e4acf..6836b59 100644
--- a/gio/strinfo.c
+++ b/gio/strinfo.c
@@ -193,7 +193,7 @@ strinfo_find_integer (const guint32 *strinfo,
   guint i;
 
   for (i = 0; i < length; i++)
-    if (strinfo[i] == value)
+    if (strinfo[i] == GUINT32_TO_LE (value))
       {
         const guchar *charinfo = (const guchar *) &strinfo[i];
 
@@ -226,7 +226,7 @@ strinfo_enum_from_string (const guint32 *strinfo,
   if (index < 0)
     return FALSE;
 
-  *result = strinfo[index];
+  *result = GUINT32_FROM_LE (strinfo[index]);
   return TRUE;
 }
 
diff --git a/gio/tests/gsettings.c b/gio/tests/gsettings.c
index fdadf96..271617a 100644
--- a/gio/tests/gsettings.c
+++ b/gio/tests/gsettings.c
@@ -942,6 +942,8 @@ test_simple_binding (void)
   gint i;
   gint16 n;
   guint16 q;
+  gint n2;
+  guint q2;
   gint64 i64;
   guint64 u64;
   gdouble d;
@@ -991,9 +993,9 @@ test_simple_binding (void)
   g_assert_cmpint (n, ==, 1234);
 
   g_settings_set (settings, "int16", "n", 4321);
-  n = 1111;
-  g_object_get (obj, "int16", &n, NULL);
-  g_assert_cmpint (n, ==, 4321);
+  n2 = 1111;
+  g_object_get (obj, "int16", &n2, NULL);
+  g_assert_cmpint (n2, ==, 4321);
 
   g_settings_bind (settings, "uint16", obj, "uint16", G_SETTINGS_BIND_DEFAULT);
 
@@ -1003,9 +1005,9 @@ test_simple_binding (void)
   g_assert_cmpuint (q, ==, G_MAXUINT16);
 
   g_settings_set (settings, "uint16", "q", (guint16) G_MAXINT16);
-  q = 1111;
-  g_object_get (obj, "uint16", &q, NULL);
-  g_assert_cmpuint (q, ==, (guint16) G_MAXINT16);
+  q2 = 1111;
+  g_object_get (obj, "uint16", &q2, NULL);
+  g_assert_cmpuint (q2, ==, (guint16) G_MAXINT16);
 
   g_settings_bind (settings, "int", obj, "int", G_SETTINGS_BIND_DEFAULT);
 
diff --git a/glib/gvariant.c b/glib/gvariant.c
index f9eb851..e333597 100644
--- a/glib/gvariant.c
+++ b/glib/gvariant.c
@@ -4566,23 +4566,37 @@ g_variant_get_normal_form (GVariant *value)
 GVariant *
 g_variant_byteswap (GVariant *value)
 {
-  GVariantSerialised serialised;
-  GVariant *trusted;
-  GBuffer *buffer;
+  GVariantTypeInfo *type_info;
+  guint alignment;
   GVariant *new;
 
-  trusted = g_variant_get_normal_form (value);
-  serialised.type_info = g_variant_get_type_info (trusted);
-  serialised.size = g_variant_get_size (trusted);
-  serialised.data = g_malloc (serialised.size);
-  g_variant_store (trusted, serialised.data);
-  g_variant_unref (trusted);
+  type_info = g_variant_get_type_info (value);
 
-  g_variant_serialised_byteswap (serialised);
+  g_variant_type_info_query (type_info, &alignment, NULL);
 
-  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);
+  if (alignment)
+    /* (potentially) contains multi-byte numeric data */
+    {
+      GVariantSerialised serialised;
+      GVariant *trusted;
+      GBuffer *buffer;
+
+      trusted = g_variant_get_normal_form (value);
+      serialised.type_info = g_variant_get_type_info (trusted);
+      serialised.size = g_variant_get_size (trusted);
+      serialised.data = g_malloc (serialised.size);
+      g_variant_store (trusted, serialised.data);
+      g_variant_unref (trusted);
+
+      g_variant_serialised_byteswap (serialised);
+
+      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);
+    }
+  else
+    /* contains no multi-byte data */
+    new = value;
 
   return g_variant_ref_sink (new);
 }



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