[glib] GDBus: Fix serialization of empty arrays
- From: David Zeuthen <davidz src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib] GDBus: Fix serialization of empty arrays
- Date: Fri, 14 May 2010 16:56:53 +0000 (UTC)
commit bb6530eb34a16cbf34ce130c21071a25666a704b
Author: David Zeuthen <davidz redhat com>
Date: Fri May 14 12:49:51 2010 -0400
GDBus: Fix serialization of empty arrays
It turns out that we didn't observe padding (neither when reading nor
writing) for empty arrays which (apparently) is needed according to
the D-Bus spec and reference implementation. A simple test case to
provoke this behavior is as follows (notice the lack of 4 bytes worth
of padding at position 0x0064):
Error calling dbus_message_demarshal() on this blob: org.freedesktop.DBus.Error.InvalidArgs: Message is corrupted (Alignment padding not null)
0000: 6c 01 00 01 2e 00 00 00 41 00 00 00 37 00 00 00 l.......A...7...
0010: 08 01 67 00 08 73 61 7b 73 76 7d 61 73 00 00 00 ..g..sa{sv}as...
0020: 01 01 6f 00 08 00 00 00 2f 66 6f 6f 2f 62 61 72 ..o...../foo/bar
0030: 00 00 00 00 00 00 00 00 03 01 73 00 06 00 00 00 ..........s.....
0040: 4d 65 6d 62 65 72 00 00 11 00 00 00 30 31 32 33 Member......0123
0050: 34 35 36 37 38 39 30 31 32 33 34 35 36 00 00 00 4567890123456...
0060: 00 00 00 00 0e 00 00 00 09 00 00 00 53 6f 6d 65 ............Some
0070: 74 68 69 6e 67 00 thing.
The blob was generated from the following GVariant value:
('01234567890123456', @a{sv} {}, ['Something'])
If the blob was encoded using DBusMessageIter, the payload would have been:
0000: 6c 01 00 01 32 00 00 00 41 00 00 00 36 00 00 00 l...2...A...6...
0010: 01 01 6f 00 08 00 00 00 2f 66 6f 6f 2f 62 61 72 ..o...../foo/bar
0020: 00 00 00 00 00 00 00 00 03 01 73 00 06 00 00 00 ..........s.....
0030: 4d 65 6d 62 65 72 00 00 08 01 67 00 08 73 61 7b Member....g..sa{
0040: 73 76 7d 61 73 00 00 00 11 00 00 00 30 31 32 33 sv}as.......0123
0050: 34 35 36 37 38 39 30 31 32 33 34 35 36 00 00 00 4567890123456...
0060: 00 00 00 00 00 00 00 00 0e 00 00 00 09 00 00 00 ................
0070: 53 6f 6d 65 74 68 69 6e 67 00 Something.
** ERROR:gdbus-serialization.c:547:check_serialization: code should not be reached
Aborted
and this is now in the libdbus-1-using serialization test case.
Signed-off-by: David Zeuthen <davidz redhat com>
gio/gdbusmessage.c | 680 ++++++++++++++++++++++++---------------
gio/tests/gdbus-serialization.c | 12 +
2 files changed, 439 insertions(+), 253 deletions(-)
---
diff --git a/gio/gdbusmessage.c b/gio/gdbusmessage.c
index 0f1e0d2..4d98e3e 100644
--- a/gio/gdbusmessage.c
+++ b/gio/gdbusmessage.c
@@ -682,6 +682,8 @@ ensure_input_padding (GMemoryInputStream *mis,
offset = g_seekable_tell (G_SEEKABLE (mis));
wanted_offset = ((offset + padding_size - 1) / padding_size) * padding_size;
+ /*g_debug ("ensure_input_padding(%d) pushed offset 0x%04x to 0x%04x", (gint) padding_size, (gint) offset, (gint) wanted_offset);*/
+
return g_seekable_seek (G_SEEKABLE (mis), wanted_offset, G_SEEK_SET, NULL, error);
}
@@ -751,164 +753,206 @@ read_string (GMemoryInputStream *mis,
return NULL;
}
+/* if just_align==TRUE, don't read a value, just align the input stream wrt padding */
static GVariant *
parse_value_from_blob (GMemoryInputStream *mis,
GDataInputStream *dis,
const GVariantType *type,
+ gboolean just_align,
GError **error)
{
GVariant *ret;
GError *local_error;
+ /*g_debug ("Reading type %s from offset 0x%04x", g_variant_type_dup_string (type), (gint) g_seekable_tell (G_SEEKABLE (mis)));*/
+
+ ret = NULL;
+
local_error = NULL;
if (g_variant_type_equal (type, G_VARIANT_TYPE_BOOLEAN))
{
- gboolean v;
if (!ensure_input_padding (mis, 4, &local_error))
goto fail;
- v = g_data_input_stream_read_uint32 (dis, NULL, &local_error);
- if (local_error != NULL)
- goto fail;
- ret = g_variant_new_boolean (v);
+ if (!just_align)
+ {
+ gboolean v;
+ v = g_data_input_stream_read_uint32 (dis, NULL, &local_error);
+ if (local_error != NULL)
+ goto fail;
+ ret = g_variant_new_boolean (v);
+ }
}
else if (g_variant_type_equal (type, G_VARIANT_TYPE_BYTE))
{
- guchar v;
- v = g_data_input_stream_read_byte (dis, NULL, &local_error);
- if (local_error != NULL)
- goto fail;
- ret = g_variant_new_byte (v);
+ if (!just_align)
+ {
+ guchar v;
+ v = g_data_input_stream_read_byte (dis, NULL, &local_error);
+ if (local_error != NULL)
+ goto fail;
+ ret = g_variant_new_byte (v);
+ }
}
else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT16))
{
- gint16 v;
if (!ensure_input_padding (mis, 2, &local_error))
goto fail;
- v = g_data_input_stream_read_int16 (dis, NULL, &local_error);
- if (local_error != NULL)
- goto fail;
- ret = g_variant_new_int16 (v);
+ if (!just_align)
+ {
+ gint16 v;
+ v = g_data_input_stream_read_int16 (dis, NULL, &local_error);
+ if (local_error != NULL)
+ goto fail;
+ ret = g_variant_new_int16 (v);
+ }
}
else if (g_variant_type_equal (type, G_VARIANT_TYPE_UINT16))
{
- guint16 v;
if (!ensure_input_padding (mis, 2, &local_error))
goto fail;
- v = g_data_input_stream_read_uint16 (dis, NULL, &local_error);
- if (local_error != NULL)
- goto fail;
- ret = g_variant_new_uint16 (v);
+ if (!just_align)
+ {
+ guint16 v;
+ v = g_data_input_stream_read_uint16 (dis, NULL, &local_error);
+ if (local_error != NULL)
+ goto fail;
+ ret = g_variant_new_uint16 (v);
+ }
}
else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT32))
{
- gint32 v;
if (!ensure_input_padding (mis, 4, &local_error))
goto fail;
- v = g_data_input_stream_read_int32 (dis, NULL, &local_error);
- if (local_error != NULL)
- goto fail;
- ret = g_variant_new_int32 (v);
+ if (!just_align)
+ {
+ gint32 v;
+ v = g_data_input_stream_read_int32 (dis, NULL, &local_error);
+ if (local_error != NULL)
+ goto fail;
+ ret = g_variant_new_int32 (v);
+ }
}
else if (g_variant_type_equal (type, G_VARIANT_TYPE_UINT32))
{
- guint32 v;
if (!ensure_input_padding (mis, 4, &local_error))
goto fail;
- v = g_data_input_stream_read_uint32 (dis, NULL, &local_error);
- if (local_error != NULL)
- goto fail;
- ret = g_variant_new_uint32 (v);
+ if (!just_align)
+ {
+ guint32 v;
+ v = g_data_input_stream_read_uint32 (dis, NULL, &local_error);
+ if (local_error != NULL)
+ goto fail;
+ ret = g_variant_new_uint32 (v);
+ }
}
else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT64))
{
- gint64 v;
if (!ensure_input_padding (mis, 8, &local_error))
goto fail;
- v = g_data_input_stream_read_int64 (dis, NULL, &local_error);
- if (local_error != NULL)
- goto fail;
- ret = g_variant_new_int64 (v);
+ if (!just_align)
+ {
+ gint64 v;
+ v = g_data_input_stream_read_int64 (dis, NULL, &local_error);
+ if (local_error != NULL)
+ goto fail;
+ ret = g_variant_new_int64 (v);
+ }
}
else if (g_variant_type_equal (type, G_VARIANT_TYPE_UINT64))
{
- guint64 v;
if (!ensure_input_padding (mis, 8, &local_error))
goto fail;
- v = g_data_input_stream_read_uint64 (dis, NULL, &local_error);
- if (local_error != NULL)
- goto fail;
- ret = g_variant_new_uint64 (v);
+ if (!just_align)
+ {
+ guint64 v;
+ v = g_data_input_stream_read_uint64 (dis, NULL, &local_error);
+ if (local_error != NULL)
+ goto fail;
+ ret = g_variant_new_uint64 (v);
+ }
}
else if (g_variant_type_equal (type, G_VARIANT_TYPE_DOUBLE))
{
- guint64 v;
- gdouble *encoded;
if (!ensure_input_padding (mis, 8, &local_error))
goto fail;
- v = g_data_input_stream_read_uint64 (dis, NULL, &local_error);
- if (local_error != NULL)
- goto fail;
- /* TODO: hmm */
- encoded = (gdouble *) &v;
- ret = g_variant_new_double (*encoded);
+ if (!just_align)
+ {
+ guint64 v;
+ gdouble *encoded;
+ v = g_data_input_stream_read_uint64 (dis, NULL, &local_error);
+ if (local_error != NULL)
+ goto fail;
+ /* TODO: hmm */
+ encoded = (gdouble *) &v;
+ ret = g_variant_new_double (*encoded);
+ }
}
else if (g_variant_type_equal (type, G_VARIANT_TYPE_STRING))
{
- guint32 len;
- gchar *v;
if (!ensure_input_padding (mis, 4, &local_error))
goto fail;
- len = g_data_input_stream_read_uint32 (dis, NULL, &local_error);
- if (local_error != NULL)
- goto fail;
- v = read_string (mis, dis, (gsize) len, &local_error);
- if (v == NULL)
- goto fail;
- ret = g_variant_new_string (v);
+ if (!just_align)
+ {
+ guint32 len;
+ gchar *v;
+ len = g_data_input_stream_read_uint32 (dis, NULL, &local_error);
+ if (local_error != NULL)
+ goto fail;
+ v = read_string (mis, dis, (gsize) len, &local_error);
+ if (v == NULL)
+ goto fail;
+ ret = g_variant_new_string (v);
+ }
}
else if (g_variant_type_equal (type, G_VARIANT_TYPE_OBJECT_PATH))
{
- guint32 len;
- gchar *v;
if (!ensure_input_padding (mis, 4, &local_error))
goto fail;
- len = g_data_input_stream_read_uint32 (dis, NULL, &local_error);
- if (local_error != NULL)
- goto fail;
- v = read_string (mis, dis, (gsize) len, &local_error);
- if (v == NULL)
- goto fail;
- if (!g_variant_is_object_path (v))
+ if (!just_align)
{
- g_set_error (&local_error,
- G_IO_ERROR,
- G_IO_ERROR_INVALID_ARGUMENT,
- _("Parsed value `%s' is not a valid D-Bus object path"),
- v);
- goto fail;
+ guint32 len;
+ gchar *v;
+ len = g_data_input_stream_read_uint32 (dis, NULL, &local_error);
+ if (local_error != NULL)
+ goto fail;
+ v = read_string (mis, dis, (gsize) len, &local_error);
+ if (v == NULL)
+ goto fail;
+ if (!g_variant_is_object_path (v))
+ {
+ g_set_error (&local_error,
+ G_IO_ERROR,
+ G_IO_ERROR_INVALID_ARGUMENT,
+ _("Parsed value `%s' is not a valid D-Bus object path"),
+ v);
+ goto fail;
+ }
+ ret = g_variant_new_object_path (v);
}
- ret = g_variant_new_object_path (v);
}
else if (g_variant_type_equal (type, G_VARIANT_TYPE_SIGNATURE))
{
- guchar len;
- gchar *v;
- len = g_data_input_stream_read_byte (dis, NULL, &local_error);
- if (local_error != NULL)
- goto fail;
- v = read_string (mis, dis, (gsize) len, &local_error);
- if (v == NULL)
- goto fail;
- if (!g_variant_is_signature (v))
+ if (!just_align)
{
- g_set_error (&local_error,
- G_IO_ERROR,
- G_IO_ERROR_INVALID_ARGUMENT,
- _("Parsed value `%s' is not a valid D-Bus signature"),
+ guchar len;
+ gchar *v;
+ len = g_data_input_stream_read_byte (dis, NULL, &local_error);
+ if (local_error != NULL)
+ goto fail;
+ v = read_string (mis, dis, (gsize) len, &local_error);
+ if (v == NULL)
+ goto fail;
+ if (!g_variant_is_signature (v))
+ {
+ g_set_error (&local_error,
+ G_IO_ERROR,
+ G_IO_ERROR_INVALID_ARGUMENT,
+ _("Parsed value `%s' is not a valid D-Bus signature"),
v);
- goto fail;
+ goto fail;
+ }
+ ret = g_variant_new_signature (v);
}
- ret = g_variant_new_signature (v);
}
else if (g_variant_type_is_array (type))
{
@@ -935,24 +979,47 @@ parse_value_from_blob (GMemoryInputStream *mis,
builder = g_variant_builder_new (type);
element_type = g_variant_type_element (type);
- /* TODO: optimize array of primitive types */
-
- offset = g_seekable_tell (G_SEEKABLE (mis));
- target = offset + array_len;
- while (offset < target)
+ if (array_len == 0)
{
GVariant *item;
- item = parse_value_from_blob (mis, dis, element_type, &local_error);
- if (item == NULL)
+ item = parse_value_from_blob (mis,
+ dis,
+ element_type,
+ TRUE,
+ &local_error);
+ g_assert (item == NULL);
+ }
+ else
+ {
+ /* TODO: optimize array of primitive types */
+ offset = g_seekable_tell (G_SEEKABLE (mis));
+ target = offset + array_len;
+ while (offset < target)
{
- g_variant_builder_unref (builder);
- goto fail;
+ GVariant *item;
+ item = parse_value_from_blob (mis,
+ dis,
+ element_type,
+ FALSE,
+ &local_error);
+ if (item == NULL)
+ {
+ g_variant_builder_unref (builder);
+ goto fail;
+ }
+ g_variant_builder_add_value (builder, item);
+ offset = g_seekable_tell (G_SEEKABLE (mis));
}
- g_variant_builder_add_value (builder, item);
- offset = g_seekable_tell (G_SEEKABLE (mis));
}
- ret = g_variant_builder_end (builder);
+ if (!just_align)
+ {
+ ret = g_variant_builder_end (builder);
+ }
+ else
+ {
+ g_variant_builder_unref (builder);
+ }
}
else if (g_variant_type_is_dict_entry (type))
{
@@ -964,73 +1031,98 @@ parse_value_from_blob (GMemoryInputStream *mis,
if (!ensure_input_padding (mis, 8, &local_error))
goto fail;
- key_type = g_variant_type_key (type);
- key = parse_value_from_blob (mis, dis, key_type, &local_error);
- if (key == NULL)
- goto fail;
-
- value_type = g_variant_type_value (type);
- value = parse_value_from_blob (mis, dis, value_type, &local_error);
- if (value == NULL)
+ if (!just_align)
{
- g_variant_unref (key);
- goto fail;
+ key_type = g_variant_type_key (type);
+ key = parse_value_from_blob (mis,
+ dis,
+ key_type,
+ FALSE,
+ &local_error);
+ if (key == NULL)
+ goto fail;
+
+ value_type = g_variant_type_value (type);
+ value = parse_value_from_blob (mis,
+ dis,
+ value_type,
+ FALSE,
+ &local_error);
+ if (value == NULL)
+ {
+ g_variant_unref (key);
+ goto fail;
+ }
+ ret = g_variant_new_dict_entry (key, value);
}
- ret = g_variant_new_dict_entry (key, value);
}
else if (g_variant_type_is_tuple (type))
{
- const GVariantType *element_type;
- GVariantBuilder *builder;
-
if (!ensure_input_padding (mis, 8, &local_error))
goto fail;
- builder = g_variant_builder_new (type);
- element_type = g_variant_type_first (type);
- while (element_type != NULL)
+ if (!just_align)
{
- GVariant *item;
- item = parse_value_from_blob (mis, dis, element_type, &local_error);
- if (item == NULL)
+ const GVariantType *element_type;
+ GVariantBuilder *builder;
+
+ builder = g_variant_builder_new (type);
+ element_type = g_variant_type_first (type);
+ while (element_type != NULL)
{
- g_variant_builder_unref (builder);
- goto fail;
- }
- g_variant_builder_add_value (builder, item);
+ GVariant *item;
+ item = parse_value_from_blob (mis,
+ dis,
+ element_type,
+ FALSE,
+ &local_error);
+ if (item == NULL)
+ {
+ g_variant_builder_unref (builder);
+ goto fail;
+ }
+ g_variant_builder_add_value (builder, item);
- element_type = g_variant_type_next (element_type);
+ element_type = g_variant_type_next (element_type);
+ }
+ ret = g_variant_builder_end (builder);
}
- ret = g_variant_builder_end (builder);
}
else if (g_variant_type_is_variant (type))
{
- guchar siglen;
- gchar *sig;
- GVariantType *variant_type;
- GVariant *value;
-
- siglen = g_data_input_stream_read_byte (dis, NULL, &local_error);
- if (local_error != NULL)
- goto fail;
- sig = read_string (mis, dis, (gsize) siglen, &local_error);
- if (sig == NULL)
- goto fail;
- if (!g_variant_is_signature (sig))
+ if (!just_align)
{
- g_set_error (&local_error,
- G_IO_ERROR,
- G_IO_ERROR_INVALID_ARGUMENT,
- _("Parsed value `%s' for variant is not a valid D-Bus signature"),
- sig);
- goto fail;
+ guchar siglen;
+ gchar *sig;
+ GVariantType *variant_type;
+ GVariant *value;
+
+ siglen = g_data_input_stream_read_byte (dis, NULL, &local_error);
+ if (local_error != NULL)
+ goto fail;
+ sig = read_string (mis, dis, (gsize) siglen, &local_error);
+ if (sig == NULL)
+ goto fail;
+ if (!g_variant_is_signature (sig))
+ {
+ g_set_error (&local_error,
+ G_IO_ERROR,
+ G_IO_ERROR_INVALID_ARGUMENT,
+ _("Parsed value `%s' for variant is not a valid D-Bus signature"),
+ sig);
+ goto fail;
+ }
+ variant_type = g_variant_type_new (sig);
+ value = parse_value_from_blob (mis,
+ dis,
+ variant_type,
+ FALSE,
+ &local_error);
+ g_variant_type_free (variant_type);
+ if (value == NULL)
+ goto fail;
+ ret = g_variant_new_variant (value);
}
- variant_type = g_variant_type_new (sig);
- value = parse_value_from_blob (mis, dis, variant_type, &local_error);
- g_variant_type_free (variant_type);
- if (value == NULL)
- goto fail;
- ret = g_variant_new_variant (value);
}
else
{
@@ -1045,7 +1137,7 @@ parse_value_from_blob (GMemoryInputStream *mis,
goto fail;
}
- g_assert (ret != NULL);
+ g_assert ((just_align && ret == NULL) || (!just_align && ret != NULL));
return ret;
fail:
@@ -1204,6 +1296,7 @@ g_dbus_message_new_from_blob (guchar *blob,
headers = parse_value_from_blob (mis,
dis,
G_VARIANT_TYPE ("a{yv}"),
+ FALSE,
error);
if (headers == NULL)
goto out;
@@ -1260,6 +1353,7 @@ g_dbus_message_new_from_blob (guchar *blob,
message->priv->body = parse_value_from_blob (mis,
dis,
variant_type,
+ FALSE,
error);
if (message->priv->body == NULL)
{
@@ -1325,105 +1419,141 @@ ensure_output_padding (GMemoryOutputStream *mos,
return padding_needed;
}
+/* note that value can be NULL for e.g. empty arrays - type is never NULL */
static gboolean
append_value_to_blob (GVariant *value,
+ const GVariantType *type,
GMemoryOutputStream *mos,
GDataOutputStream *dos,
gsize *out_padding_added,
GError **error)
{
- const GVariantType *type;
gsize padding_added;
padding_added = 0;
- type = g_variant_get_type (value);
if (g_variant_type_equal (type, G_VARIANT_TYPE_BOOLEAN))
{
- gboolean v = g_variant_get_boolean (value);
padding_added = ensure_output_padding (mos, dos, 4);
- g_data_output_stream_put_uint32 (dos, v, NULL, NULL);
+ if (value != NULL)
+ {
+ gboolean v = g_variant_get_boolean (value);
+ g_data_output_stream_put_uint32 (dos, v, NULL, NULL);
+ }
}
else if (g_variant_type_equal (type, G_VARIANT_TYPE_BYTE))
{
- guint8 v = g_variant_get_byte (value);
- g_data_output_stream_put_byte (dos, v, NULL, NULL);
+ if (value != NULL)
+ {
+ guint8 v = g_variant_get_byte (value);
+ g_data_output_stream_put_byte (dos, v, NULL, NULL);
+ }
}
else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT16))
{
- gint16 v = g_variant_get_int16 (value);
padding_added = ensure_output_padding (mos, dos, 2);
- g_data_output_stream_put_int16 (dos, v, NULL, NULL);
+ if (value != NULL)
+ {
+ gint16 v = g_variant_get_int16 (value);
+ g_data_output_stream_put_int16 (dos, v, NULL, NULL);
+ }
}
else if (g_variant_type_equal (type, G_VARIANT_TYPE_UINT16))
{
- guint16 v = g_variant_get_uint16 (value);
padding_added = ensure_output_padding (mos, dos, 2);
- g_data_output_stream_put_uint16 (dos, v, NULL, NULL);
+ if (value != NULL)
+ {
+ guint16 v = g_variant_get_uint16 (value);
+ g_data_output_stream_put_uint16 (dos, v, NULL, NULL);
+ }
}
else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT32))
{
- gint32 v = g_variant_get_int32 (value);
padding_added = ensure_output_padding (mos, dos, 4);
- g_data_output_stream_put_int32 (dos, v, NULL, NULL);
+ if (value != NULL)
+ {
+ gint32 v = g_variant_get_int32 (value);
+ g_data_output_stream_put_int32 (dos, v, NULL, NULL);
+ }
}
else if (g_variant_type_equal (type, G_VARIANT_TYPE_UINT32))
{
- guint32 v = g_variant_get_uint32 (value);
padding_added = ensure_output_padding (mos, dos, 4);
- g_data_output_stream_put_uint32 (dos, v, NULL, NULL);
+ if (value != NULL)
+ {
+ guint32 v = g_variant_get_uint32 (value);
+ g_data_output_stream_put_uint32 (dos, v, NULL, NULL);
+ }
}
else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT64))
{
- gint64 v = g_variant_get_int64 (value);
padding_added = ensure_output_padding (mos, dos, 8);
- g_data_output_stream_put_int64 (dos, v, NULL, NULL);
+ if (value != NULL)
+ {
+ gint64 v = g_variant_get_int64 (value);
+ g_data_output_stream_put_int64 (dos, v, NULL, NULL);
+ }
}
else if (g_variant_type_equal (type, G_VARIANT_TYPE_UINT64))
{
- guint64 v = g_variant_get_uint64 (value);
padding_added = ensure_output_padding (mos, dos, 8);
- g_data_output_stream_put_uint64 (dos, v, NULL, NULL);
+ if (value != NULL)
+ {
+ guint64 v = g_variant_get_uint64 (value);
+ g_data_output_stream_put_uint64 (dos, v, NULL, NULL);
+ }
}
else if (g_variant_type_equal (type, G_VARIANT_TYPE_DOUBLE))
{
- guint64 *encoded;
- gdouble v = g_variant_get_double (value);
padding_added = ensure_output_padding (mos, dos, 8);
- /* TODO: hmm */
- encoded = (guint64 *) &v;
- g_data_output_stream_put_uint64 (dos, *encoded, NULL, NULL);
+ if (value != NULL)
+ {
+ guint64 *encoded;
+ gdouble v = g_variant_get_double (value);
+ /* TODO: hmm */
+ encoded = (guint64 *) &v;
+ g_data_output_stream_put_uint64 (dos, *encoded, NULL, NULL);
+ }
}
else if (g_variant_type_equal (type, G_VARIANT_TYPE_STRING))
{
- const gchar *v = g_variant_get_string (value, NULL);
- gsize len;
padding_added = ensure_output_padding (mos, dos, 4);
- len = strlen (v);
- g_data_output_stream_put_uint32 (dos, len, NULL, NULL);
- g_data_output_stream_put_string (dos, v, NULL, NULL);
- g_data_output_stream_put_byte (dos, '\0', NULL, NULL);
+ if (value != NULL)
+ {
+ const gchar *v = g_variant_get_string (value, NULL);
+ gsize len;
+ len = strlen (v);
+ g_data_output_stream_put_uint32 (dos, len, NULL, NULL);
+ g_data_output_stream_put_string (dos, v, NULL, NULL);
+ g_data_output_stream_put_byte (dos, '\0', NULL, NULL);
+ }
}
else if (g_variant_type_equal (type, G_VARIANT_TYPE_OBJECT_PATH))
{
- /* TODO: validate object path */
- const gchar *v = g_variant_get_string (value, NULL);
- gsize len;
padding_added = ensure_output_padding (mos, dos, 4);
- len = strlen (v);
- g_data_output_stream_put_uint32 (dos, len, NULL, NULL);
- g_data_output_stream_put_string (dos, v, NULL, NULL);
- g_data_output_stream_put_byte (dos, '\0', NULL, NULL);
+ if (value != NULL)
+ {
+ /* TODO: validate object path */
+ const gchar *v = g_variant_get_string (value, NULL);
+ gsize len;
+ len = strlen (v);
+ g_data_output_stream_put_uint32 (dos, len, NULL, NULL);
+ g_data_output_stream_put_string (dos, v, NULL, NULL);
+ g_data_output_stream_put_byte (dos, '\0', NULL, NULL);
+ }
}
else if (g_variant_type_equal (type, G_VARIANT_TYPE_SIGNATURE))
{
- /* TODO: validate signature (including max len being 255) */
- const gchar *v = g_variant_get_string (value, NULL);
- gsize len;
- len = strlen (v);
- g_data_output_stream_put_byte (dos, len, NULL, NULL);
- g_data_output_stream_put_string (dos, v, NULL, NULL);
- g_data_output_stream_put_byte (dos, '\0', NULL, NULL);
+ if (value != NULL)
+ {
+ /* TODO: validate signature (including max len being 255) */
+ const gchar *v = g_variant_get_string (value, NULL);
+ gsize len;
+ len = strlen (v);
+ g_data_output_stream_put_byte (dos, len, NULL, NULL);
+ g_data_output_stream_put_string (dos, v, NULL, NULL);
+ g_data_output_stream_put_byte (dos, '\0', NULL, NULL);
+ }
}
else if (g_variant_type_is_array (type))
{
@@ -1433,86 +1563,121 @@ append_value_to_blob (GVariant *value,
goffset array_payload_begin_offset;
goffset cur_offset;
gsize array_len;
- guint n;
padding_added = ensure_output_padding (mos, dos, 4);
-
- /* array length - will be filled in later */
- array_len_offset = g_memory_output_stream_get_data_size (mos);
- g_data_output_stream_put_uint32 (dos, 0xF00DFACE, NULL, NULL);
-
- /* From the D-Bus spec:
- *
- * "A UINT32 giving the length of the array data in bytes,
- * followed by alignment padding to the alignment boundary of
- * the array element type, followed by each array element. The
- * array length is from the end of the alignment padding to
- * the end of the last element, i.e. it does not include the
- * padding after the length, or any padding after the last
- * element."
- *
- * Thus, we need to count how much padding the first element
- * contributes and subtract that from the array length.
- */
- array_payload_begin_offset = g_memory_output_stream_get_data_size (mos);
-
- g_variant_iter_init (&iter, value);
- n = 0;
- while ((item = g_variant_iter_next_value (&iter)))
+ if (value != NULL)
{
- gsize padding_added_for_item;
- if (!append_value_to_blob (item, mos, dos, &padding_added_for_item, error))
- goto fail;
- if (n == 0)
+ /* array length - will be filled in later */
+ array_len_offset = g_memory_output_stream_get_data_size (mos);
+ g_data_output_stream_put_uint32 (dos, 0xF00DFACE, NULL, NULL);
+
+ /* From the D-Bus spec:
+ *
+ * "A UINT32 giving the length of the array data in bytes,
+ * followed by alignment padding to the alignment boundary of
+ * the array element type, followed by each array element. The
+ * array length is from the end of the alignment padding to
+ * the end of the last element, i.e. it does not include the
+ * padding after the length, or any padding after the last
+ * element."
+ *
+ * Thus, we need to count how much padding the first element
+ * contributes and subtract that from the array length.
+ */
+ array_payload_begin_offset = g_memory_output_stream_get_data_size (mos);
+
+ if (g_variant_n_children (value) == 0)
{
+ gsize padding_added_for_item;
+ if (!append_value_to_blob (NULL,
+ g_variant_type_element (type),
+ mos,
+ dos,
+ &padding_added_for_item,
+ error))
+ goto fail;
array_payload_begin_offset += padding_added_for_item;
}
- n++;
- }
+ else
+ {
+ guint n;
+ n = 0;
+ g_variant_iter_init (&iter, value);
+ while ((item = g_variant_iter_next_value (&iter)))
+ {
+ gsize padding_added_for_item;
+ if (!append_value_to_blob (item,
+ g_variant_get_type (item),
+ mos,
+ dos,
+ &padding_added_for_item,
+ error))
+ goto fail;
+ if (n == 0)
+ {
+ array_payload_begin_offset += padding_added_for_item;
+ }
+ n++;
+ }
+ }
- cur_offset = g_memory_output_stream_get_data_size (mos);
+ cur_offset = g_memory_output_stream_get_data_size (mos);
- array_len = cur_offset - array_payload_begin_offset;
+ array_len = cur_offset - array_payload_begin_offset;
- if (!g_seekable_seek (G_SEEKABLE (mos), array_len_offset, G_SEEK_SET, NULL, error))
- goto fail;
+ if (!g_seekable_seek (G_SEEKABLE (mos), array_len_offset, G_SEEK_SET, NULL, error))
+ goto fail;
- g_data_output_stream_put_uint32 (dos, array_len, NULL, NULL);
+ g_data_output_stream_put_uint32 (dos, array_len, NULL, NULL);
- if (!g_seekable_seek (G_SEEKABLE (mos), cur_offset, G_SEEK_SET, NULL, error))
- goto fail;
+ if (!g_seekable_seek (G_SEEKABLE (mos), cur_offset, G_SEEK_SET, NULL, error))
+ goto fail;
+ }
}
else if (g_variant_type_is_dict_entry (type) || g_variant_type_is_tuple (type))
{
- GVariant *item;
- GVariantIter iter;
-
padding_added = ensure_output_padding (mos, dos, 8);
-
- g_variant_iter_init (&iter, value);
-
- while ((item = g_variant_iter_next_value (&iter)))
+ if (value != NULL)
{
- if (!append_value_to_blob (item, mos, dos, NULL, error))
- goto fail;
+ GVariant *item;
+ GVariantIter iter;
+ g_variant_iter_init (&iter, value);
+ while ((item = g_variant_iter_next_value (&iter)))
+ {
+ if (!append_value_to_blob (item,
+ g_variant_get_type (item),
+ mos,
+ dos,
+ NULL,
+ error))
+ goto fail;
+ }
}
}
else if (g_variant_type_is_variant (type))
{
- GVariant *child;
- const gchar *signature;
- child = g_variant_get_child_value (value, 0);
- signature = g_variant_get_type_string (child);
- /* TODO: validate signature (including max len being 255) */
- g_data_output_stream_put_byte (dos, strlen (signature), NULL, NULL);
- g_data_output_stream_put_string (dos, signature, NULL, NULL);
- g_data_output_stream_put_byte (dos, '\0', NULL, NULL);
- if (!append_value_to_blob (child, mos, dos, NULL, error))
+ if (value != NULL)
{
+ GVariant *child;
+ const gchar *signature;
+ child = g_variant_get_child_value (value, 0);
+ signature = g_variant_get_type_string (child);
+ /* TODO: validate signature (including max len being 255) */
+ g_data_output_stream_put_byte (dos, strlen (signature), NULL, NULL);
+ g_data_output_stream_put_string (dos, signature, NULL, NULL);
+ g_data_output_stream_put_byte (dos, '\0', NULL, NULL);
+ if (!append_value_to_blob (child,
+ g_variant_get_type (child),
+ mos,
+ dos,
+ NULL,
+ error))
+ {
+ g_variant_unref (child);
+ goto fail;
+ }
g_variant_unref (child);
- goto fail;
}
- g_variant_unref (child);
}
else
{
@@ -1557,7 +1722,12 @@ append_body_to_blob (GVariant *value,
g_variant_iter_init (&iter, value);
while ((item = g_variant_iter_next_value (&iter)))
{
- if (!append_value_to_blob (item, mos, dos, NULL, error))
+ if (!append_value_to_blob (item,
+ g_variant_get_type (item),
+ mos,
+ dos,
+ NULL,
+ error))
goto fail;
}
return TRUE;
@@ -1660,7 +1830,11 @@ g_dbus_message_to_blob (GDBusMessage *message,
}
header_fields = g_variant_new ("a{yv}", builder);
- if (!append_value_to_blob (header_fields, mos, dos, NULL, error))
+ if (!append_value_to_blob (header_fields,
+ g_variant_get_type (header_fields),
+ mos, dos,
+ NULL,
+ error))
{
g_variant_unref (header_fields);
goto out;
diff --git a/gio/tests/gdbus-serialization.c b/gio/tests/gdbus-serialization.c
index 90e380f..3a49f07 100644
--- a/gio/tests/gdbus-serialization.c
+++ b/gio/tests/gdbus-serialization.c
@@ -618,6 +618,7 @@ message_serialize_complex (void)
GVariant *value;
error = NULL;
+
value = g_variant_parse (G_VARIANT_TYPE ("(aia{ss})"),
"([1, 2, 3], {'one': 'white', 'two': 'black'})",
NULL, NULL, &error);
@@ -635,6 +636,17 @@ message_serialize_complex (void)
" dict_entry:\n"
" string: `two'\n"
" string: `black'\n");
+
+ value = g_variant_parse (G_VARIANT_TYPE ("(sa{sv}as)"),
+ "('01234567890123456', {}, ['Something'])",
+ NULL, NULL, &error);
+ g_assert_no_error (error);
+ g_assert (value != NULL);
+ check_serialization (value,
+ "value 0: string: `01234567890123456'\n"
+ "value 1: array:\n"
+ "value 2: array:\n"
+ " string: `Something'\n");
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]