mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-03-28 10:30:03 +01:00
GDBusMessage: fast-path decoding of fixed arrays
Instead of creating a separate GVariant for each of the 'y's in an 'ay', use g_variant_new_fixed_array(). https://bugzilla.gnome.org/show_bug.cgi?id=732754
This commit is contained in:
parent
958da1e9dc
commit
5463c8cedb
@ -1205,6 +1205,27 @@ g_dbus_message_set_unix_fd_list (GDBusMessage *message,
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static guint
|
||||
get_type_fixed_size (const GVariantType *type)
|
||||
{
|
||||
/* NB: we do not treat 'b' as fixed-size here because GVariant and
|
||||
* D-Bus disagree about the size.
|
||||
*/
|
||||
switch (*g_variant_type_peek_string (type))
|
||||
{
|
||||
case 'y':
|
||||
return 1;
|
||||
case 'n': case 'q':
|
||||
return 2;
|
||||
case 'i': case 'u': case 'h':
|
||||
return 4;
|
||||
case 'x': case 't': case 'd':
|
||||
return 8;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
validate_headers (GDBusMessage *message,
|
||||
GError **error)
|
||||
@ -1378,6 +1399,35 @@ read_string (GMemoryBuffer *mbuf,
|
||||
return str;
|
||||
}
|
||||
|
||||
static gconstpointer
|
||||
read_bytes (GMemoryBuffer *mbuf,
|
||||
gsize len,
|
||||
GError **error)
|
||||
{
|
||||
gconstpointer result;
|
||||
|
||||
if (mbuf->pos + len > mbuf->valid_len || mbuf->pos + len < mbuf->pos)
|
||||
{
|
||||
mbuf->pos = mbuf->valid_len;
|
||||
/* G_GSIZE_FORMAT doesn't work with gettext, so we use %lu */
|
||||
g_set_error (error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_INVALID_ARGUMENT,
|
||||
g_dngettext (GETTEXT_PACKAGE,
|
||||
"Wanted to read %lu byte but only got %lu",
|
||||
"Wanted to read %lu bytes but only got %lu",
|
||||
(gulong)len),
|
||||
(gulong)len,
|
||||
(gulong)(mbuf->valid_len - mbuf->pos));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
result = mbuf->data + mbuf->pos;
|
||||
mbuf->pos += len;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* if just_align==TRUE, don't read a value, just align the input stream wrt padding */
|
||||
|
||||
/* returns a non-floating GVariant! */
|
||||
@ -1588,10 +1638,8 @@ parse_value_from_blob (GMemoryBuffer *buf,
|
||||
if (!just_align)
|
||||
{
|
||||
guint32 array_len;
|
||||
goffset offset;
|
||||
goffset target;
|
||||
const GVariantType *element_type;
|
||||
GVariantBuilder builder;
|
||||
guint fixed_size;
|
||||
|
||||
array_len = g_memory_buffer_read_uint32 (buf);
|
||||
|
||||
@ -1614,44 +1662,82 @@ parse_value_from_blob (GMemoryBuffer *buf,
|
||||
goto fail;
|
||||
}
|
||||
|
||||
g_variant_builder_init (&builder, type);
|
||||
element_type = g_variant_type_element (type);
|
||||
fixed_size = get_type_fixed_size (element_type);
|
||||
|
||||
if (array_len == 0)
|
||||
/* Fast-path the cases like 'ay', etc. */
|
||||
if (fixed_size != 0)
|
||||
{
|
||||
GVariant *item;
|
||||
item = parse_value_from_blob (buf,
|
||||
element_type,
|
||||
TRUE,
|
||||
indent + 2,
|
||||
NULL);
|
||||
g_assert (item == NULL);
|
||||
gconstpointer array_data;
|
||||
|
||||
if (array_len % fixed_size != 0)
|
||||
{
|
||||
g_set_error (&local_error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_INVALID_ARGUMENT,
|
||||
_("Encountered array of type 'a%c', expected to have a length a multiple "
|
||||
"of %u bytes, but found to be %u bytes in length"),
|
||||
g_variant_type_peek_string (element_type)[0], fixed_size, array_len);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ensure_input_padding (buf, fixed_size);
|
||||
array_data = read_bytes (buf, array_len, &local_error);
|
||||
if (array_data == NULL)
|
||||
goto fail;
|
||||
|
||||
ret = g_variant_new_fixed_array (element_type, array_data, array_len / fixed_size, fixed_size);
|
||||
|
||||
if (g_memory_buffer_is_byteswapped (buf))
|
||||
{
|
||||
GVariant *tmp = g_variant_ref_sink (ret);
|
||||
ret = g_variant_byteswap (tmp);
|
||||
g_variant_unref (tmp);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* TODO: optimize array of primitive types */
|
||||
offset = buf->pos;
|
||||
target = offset + array_len;
|
||||
while (offset < target)
|
||||
GVariantBuilder builder;
|
||||
goffset offset;
|
||||
goffset target;
|
||||
|
||||
g_variant_builder_init (&builder, type);
|
||||
|
||||
if (array_len == 0)
|
||||
{
|
||||
GVariant *item;
|
||||
item = parse_value_from_blob (buf,
|
||||
element_type,
|
||||
FALSE,
|
||||
TRUE,
|
||||
indent + 2,
|
||||
&local_error);
|
||||
if (item == NULL)
|
||||
{
|
||||
g_variant_builder_clear (&builder);
|
||||
goto fail;
|
||||
}
|
||||
g_variant_builder_add_value (&builder, item);
|
||||
g_variant_unref (item);
|
||||
offset = buf->pos;
|
||||
NULL);
|
||||
g_assert (item == NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
offset = buf->pos;
|
||||
target = offset + array_len;
|
||||
while (offset < target)
|
||||
{
|
||||
GVariant *item;
|
||||
item = parse_value_from_blob (buf,
|
||||
element_type,
|
||||
FALSE,
|
||||
indent + 2,
|
||||
&local_error);
|
||||
if (item == NULL)
|
||||
{
|
||||
g_variant_builder_clear (&builder);
|
||||
goto fail;
|
||||
}
|
||||
g_variant_builder_add_value (&builder, item);
|
||||
g_variant_unref (item);
|
||||
offset = buf->pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ret = g_variant_builder_end (&builder);
|
||||
ret = g_variant_builder_end (&builder);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@ -1812,12 +1898,9 @@ parse_value_from_blob (GMemoryBuffer *buf,
|
||||
is_leaf = is_leaf; /* To avoid -Wunused-but-set-variable */
|
||||
#endif /* DEBUG_SERIALIZER */
|
||||
|
||||
/* sink the reference */
|
||||
/* sink the reference, if floating */
|
||||
if (ret != NULL)
|
||||
{
|
||||
g_assert (g_variant_is_floating (ret));
|
||||
g_variant_ref_sink (ret);
|
||||
}
|
||||
g_variant_take_ref (ret);
|
||||
return ret;
|
||||
|
||||
fail:
|
||||
|
Loading…
x
Reference in New Issue
Block a user