gvariant-serialiser: Factor out functions for dealing with framing offsets

This introduces no functional changes.

Helps: #2121
This commit is contained in:
William Manley 2020-06-25 17:08:21 +01:00 committed by Philip Withnall
parent 1deacdd4e8
commit 446e69f5ed

View File

@ -635,30 +635,62 @@ gvs_calculate_total_size (gsize body_size,
return body_size + 8 * offsets;
}
static gsize
gvs_variable_sized_array_n_children (GVariantSerialised value)
struct Offsets
{
gsize data_size;
guchar *array;
gsize length;
guint offset_size;
gboolean is_normal;
};
static gsize
gvs_offsets_get_offset_n (struct Offsets *offsets,
gsize n)
{
return gvs_read_unaligned_le (
offsets->array + (offsets->offset_size * n), offsets->offset_size);
}
static struct Offsets
gvs_variable_sized_array_get_frame_offsets (GVariantSerialised value)
{
struct Offsets out = { 0, };
gsize offsets_array_size;
gsize offset_size;
gsize last_end;
if (value.size == 0)
return 0;
{
out.is_normal = TRUE;
return out;
}
offset_size = gvs_get_offset_size (value.size);
last_end = gvs_read_unaligned_le (value.data + value.size -
offset_size, offset_size);
out.offset_size = gvs_get_offset_size (value.size);
last_end = gvs_read_unaligned_le (value.data + value.size - out.offset_size,
out.offset_size);
if (last_end > value.size)
return 0;
return out; /* offsets not normal */
offsets_array_size = value.size - last_end;
if (offsets_array_size % offset_size)
return 0;
if (offsets_array_size % out.offset_size)
return out; /* offsets not normal */
return offsets_array_size / offset_size;
out.data_size = last_end;
out.array = value.data + last_end;
out.length = offsets_array_size / out.offset_size;
out.is_normal = TRUE;
return out;
}
static gsize
gvs_variable_sized_array_n_children (GVariantSerialised value)
{
return gvs_variable_sized_array_get_frame_offsets (value).length;
}
static GVariantSerialised
@ -666,8 +698,9 @@ gvs_variable_sized_array_get_child (GVariantSerialised value,
gsize index_)
{
GVariantSerialised child = { 0, };
gsize offset_size;
gsize last_end;
struct Offsets offsets = gvs_variable_sized_array_get_frame_offsets (value);
gsize start;
gsize end;
@ -675,18 +708,11 @@ gvs_variable_sized_array_get_child (GVariantSerialised value,
g_variant_type_info_ref (child.type_info);
child.depth = value.depth + 1;
offset_size = gvs_get_offset_size (value.size);
last_end = gvs_read_unaligned_le (value.data + value.size -
offset_size, offset_size);
if (index_ > 0)
{
guint alignment;
start = gvs_read_unaligned_le (value.data + last_end +
(offset_size * (index_ - 1)),
offset_size);
start = gvs_offsets_get_offset_n (&offsets, index_ - 1);
g_variant_type_info_query (child.type_info, &alignment, NULL);
start += (-start) & alignment;
@ -694,11 +720,9 @@ gvs_variable_sized_array_get_child (GVariantSerialised value,
else
start = 0;
end = gvs_read_unaligned_le (value.data + last_end +
(offset_size * index_),
offset_size);
end = gvs_offsets_get_offset_n (&offsets, index_);
if (start < end && end <= value.size && end <= last_end)
if (start < end && end <= value.size && end <= offsets.data_size)
{
child.data = value.data + start;
child.size = end - start;
@ -770,34 +794,16 @@ static gboolean
gvs_variable_sized_array_is_normal (GVariantSerialised value)
{
GVariantSerialised child = { 0, };
gsize offsets_array_size;
guchar *offsets_array;
guint offset_size;
guint alignment;
gsize last_end;
gsize length;
gsize offset;
gsize i;
if (value.size == 0)
return TRUE;
struct Offsets offsets = gvs_variable_sized_array_get_frame_offsets (value);
offset_size = gvs_get_offset_size (value.size);
last_end = gvs_read_unaligned_le (value.data + value.size -
offset_size, offset_size);
if (last_end > value.size)
if (!offsets.is_normal)
return FALSE;
offsets_array_size = value.size - last_end;
if (offsets_array_size % offset_size)
return FALSE;
offsets_array = value.data + value.size - offsets_array_size;
length = offsets_array_size / offset_size;
if (length == 0)
if (value.size != 0 && offsets.length == 0)
return FALSE;
child.type_info = g_variant_type_info_element (value.type_info);
@ -805,14 +811,14 @@ gvs_variable_sized_array_is_normal (GVariantSerialised value)
child.depth = value.depth + 1;
offset = 0;
for (i = 0; i < length; i++)
for (i = 0; i < offsets.length; i++)
{
gsize this_end;
this_end = gvs_read_unaligned_le (offsets_array + offset_size * i,
offset_size);
this_end = gvs_read_unaligned_le (offsets.array + offsets.offset_size * i,
offsets.offset_size);
if (this_end < offset || this_end > last_end)
if (this_end < offset || this_end > offsets.data_size)
return FALSE;
while (offset & alignment)
@ -834,7 +840,7 @@ gvs_variable_sized_array_is_normal (GVariantSerialised value)
offset = this_end;
}
g_assert (offset == last_end);
g_assert (offset == offsets.data_size);
return TRUE;
}