mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-04-03 22:33:08 +02: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
|
static gboolean
|
||||||
validate_headers (GDBusMessage *message,
|
validate_headers (GDBusMessage *message,
|
||||||
GError **error)
|
GError **error)
|
||||||
@ -1378,6 +1399,35 @@ read_string (GMemoryBuffer *mbuf,
|
|||||||
return str;
|
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 */
|
/* if just_align==TRUE, don't read a value, just align the input stream wrt padding */
|
||||||
|
|
||||||
/* returns a non-floating GVariant! */
|
/* returns a non-floating GVariant! */
|
||||||
@ -1588,10 +1638,8 @@ parse_value_from_blob (GMemoryBuffer *buf,
|
|||||||
if (!just_align)
|
if (!just_align)
|
||||||
{
|
{
|
||||||
guint32 array_len;
|
guint32 array_len;
|
||||||
goffset offset;
|
|
||||||
goffset target;
|
|
||||||
const GVariantType *element_type;
|
const GVariantType *element_type;
|
||||||
GVariantBuilder builder;
|
guint fixed_size;
|
||||||
|
|
||||||
array_len = g_memory_buffer_read_uint32 (buf);
|
array_len = g_memory_buffer_read_uint32 (buf);
|
||||||
|
|
||||||
@ -1614,44 +1662,82 @@ parse_value_from_blob (GMemoryBuffer *buf,
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_variant_builder_init (&builder, type);
|
|
||||||
element_type = g_variant_type_element (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;
|
gconstpointer array_data;
|
||||||
item = parse_value_from_blob (buf,
|
|
||||||
element_type,
|
if (array_len % fixed_size != 0)
|
||||||
TRUE,
|
{
|
||||||
indent + 2,
|
g_set_error (&local_error,
|
||||||
NULL);
|
G_IO_ERROR,
|
||||||
g_assert (item == NULL);
|
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
|
else
|
||||||
{
|
{
|
||||||
/* TODO: optimize array of primitive types */
|
GVariantBuilder builder;
|
||||||
offset = buf->pos;
|
goffset offset;
|
||||||
target = offset + array_len;
|
goffset target;
|
||||||
while (offset < target)
|
|
||||||
|
g_variant_builder_init (&builder, type);
|
||||||
|
|
||||||
|
if (array_len == 0)
|
||||||
{
|
{
|
||||||
GVariant *item;
|
GVariant *item;
|
||||||
item = parse_value_from_blob (buf,
|
item = parse_value_from_blob (buf,
|
||||||
element_type,
|
element_type,
|
||||||
FALSE,
|
TRUE,
|
||||||
indent + 2,
|
indent + 2,
|
||||||
&local_error);
|
NULL);
|
||||||
if (item == NULL)
|
g_assert (item == NULL);
|
||||||
{
|
}
|
||||||
g_variant_builder_clear (&builder);
|
else
|
||||||
goto fail;
|
{
|
||||||
}
|
offset = buf->pos;
|
||||||
g_variant_builder_add_value (&builder, item);
|
target = offset + array_len;
|
||||||
g_variant_unref (item);
|
while (offset < target)
|
||||||
offset = buf->pos;
|
{
|
||||||
|
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;
|
break;
|
||||||
|
|
||||||
@ -1812,12 +1898,9 @@ parse_value_from_blob (GMemoryBuffer *buf,
|
|||||||
is_leaf = is_leaf; /* To avoid -Wunused-but-set-variable */
|
is_leaf = is_leaf; /* To avoid -Wunused-but-set-variable */
|
||||||
#endif /* DEBUG_SERIALIZER */
|
#endif /* DEBUG_SERIALIZER */
|
||||||
|
|
||||||
/* sink the reference */
|
/* sink the reference, if floating */
|
||||||
if (ret != NULL)
|
if (ret != NULL)
|
||||||
{
|
g_variant_take_ref (ret);
|
||||||
g_assert (g_variant_is_floating (ret));
|
|
||||||
g_variant_ref_sink (ret);
|
|
||||||
}
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user