mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-01-11 15:06:14 +01:00
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>
This commit is contained in:
parent
285a124608
commit
bb6530eb34
@ -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)
|
||||
{
|
||||
g_variant_builder_unref (builder);
|
||||
goto fail;
|
||||
}
|
||||
g_variant_builder_add_value (builder, item);
|
||||
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)
|
||||
{
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
g_variant_builder_unref (builder);
|
||||
goto fail;
|
||||
}
|
||||
g_variant_builder_add_value (builder, item);
|
||||
const GVariantType *element_type;
|
||||
GVariantBuilder *builder;
|
||||
|
||||
element_type = g_variant_type_next (element_type);
|
||||
builder = g_variant_builder_new (type);
|
||||
element_type = g_variant_type_first (type);
|
||||
while (element_type != NULL)
|
||||
{
|
||||
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);
|
||||
}
|
||||
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);
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
cur_offset = g_memory_output_stream_get_data_size (mos);
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
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;
|
||||
|
@ -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");
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user