X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=glib%2Fgvariant-serialiser.c;h=d5cbd3ce5627639bc6634d51d14edac6198341fa;hb=2e5bd8cf47f9e1559ccc44823a2f321b8ff8c1ea;hp=5daf43aa518975114047d179a1109533e4a48b0c;hpb=1b033919845cef366842373da9f1cfb56f522d01;p=platform%2Fupstream%2Fglib.git diff --git a/glib/gvariant-serialiser.c b/glib/gvariant-serialiser.c index 5daf43a..d5cbd3c 100644 --- a/glib/gvariant-serialiser.c +++ b/glib/gvariant-serialiser.c @@ -13,9 +13,7 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * License along with this library; if not, see . * * Author: Ryan Lortie */ @@ -89,7 +87,7 @@ /* < private > * GVariantSerialised: * @type_info: the #GVariantTypeInfo of this value - * @data: the serialised data of this value, or %NULL + * @data: (allow-none): the serialised data of this value, or %NULL * @size: the size of this value * * A structure representing a GVariant in serialised form. This @@ -261,6 +259,28 @@ gvs_fixed_sized_maybe_get_child (GVariantSerialised value, return value; } +static gboolean +gvs_fixed_sized_maybe_unpack_all (GVariantTypeInfo *type_info, + const guchar *end, + gsize end_size, + gsize total_size, + GArray *results) +{ + if (total_size) + { + GVariantUnpacked unpacked; + + unpacked.type_info = g_variant_type_info_element (type_info); + g_variant_type_info_ref (unpacked.type_info); + unpacked.skip = 0; + unpacked.size = total_size; + + g_array_append_val (results, unpacked); + } + + return TRUE; +} + static gsize gvs_fixed_sized_maybe_needed_size (GVariantTypeInfo *type_info, GVariantSerialisedFiller gvs_filler, @@ -294,6 +314,19 @@ gvs_fixed_sized_maybe_serialise (GVariantSerialised value, } } +static gsize +gvs_fixed_sized_maybe_write_to_vectors (GVariantVectors *vectors, + GVariantTypeInfo *type_info, + gsize size, + const gpointer *children, + gsize n_children) +{ + if (!n_children) + return 0; + + return g_variant_callback_write_to_vectors (vectors, children[0], NULL); +} + static gboolean gvs_fixed_sized_maybe_is_normal (GVariantSerialised value) { @@ -352,6 +385,28 @@ gvs_variable_sized_maybe_get_child (GVariantSerialised value, return value; } +static gboolean +gvs_variable_sized_maybe_unpack_all (GVariantTypeInfo *type_info, + const guchar *end, + gsize end_size, + gsize total_size, + GArray *results) +{ + if (total_size) + { + GVariantUnpacked unpacked; + + unpacked.type_info = g_variant_type_info_element (type_info); + g_variant_type_info_ref (unpacked.type_info); + unpacked.skip = 0; + unpacked.size = total_size - 1; + + g_array_append_val (results, unpacked); + } + + return TRUE; +} + static gsize gvs_variable_sized_maybe_needed_size (GVariantTypeInfo *type_info, GVariantSerialisedFiller gvs_filler, @@ -386,6 +441,20 @@ gvs_variable_sized_maybe_serialise (GVariantSerialised value, } } +static void +gvs_variable_sized_maybe_write_to_vectors (GVariantVectors *vectors, + GVariantTypeInfo *type_info, + gsize size, + const gpointer *children, + gsize n_children) +{ + if (n_children) + { + g_variant_callback_write_to_vectors (vectors, children[0], NULL); + g_variant_vectors_append_copy (vectors, "", 1); + } +} + static gboolean gvs_variable_sized_maybe_is_normal (GVariantSerialised value) { @@ -451,6 +520,39 @@ gvs_fixed_sized_array_get_child (GVariantSerialised value, return child; } +static gboolean +gvs_fixed_sized_array_unpack_all (GVariantTypeInfo *type_info, + const guchar *end, + gsize end_size, + gsize total_size, + GArray *results) +{ + GVariantTypeInfo *element; + gsize element_fixed_size; + gsize i, n; + + element = g_variant_type_info_element (type_info); + g_variant_type_info_query (element, NULL, &element_fixed_size); + + if (total_size % element_fixed_size) + return FALSE; + + n = total_size / element_fixed_size; + + for (i = 0; i < n; i++) + { + GVariantUnpacked unpacked; + + unpacked.type_info = g_variant_type_info_ref (element); + unpacked.skip = 0; + unpacked.size = element_fixed_size; + + g_array_append_val (results, unpacked); + } + + return TRUE; +} + static gsize gvs_fixed_sized_array_needed_size (GVariantTypeInfo *type_info, GVariantSerialisedFiller gvs_filler, @@ -484,6 +586,19 @@ gvs_fixed_sized_array_serialise (GVariantSerialised value, } } +static void +gvs_fixed_sized_array_write_to_vectors (GVariantVectors *vectors, + GVariantTypeInfo *type_info, + gsize size, + const gpointer *children, + gsize n_children) +{ + gsize i; + + for (i = 0; i < n_children; i++) + g_variant_callback_write_to_vectors (vectors, children[i], NULL); +} + static gboolean gvs_fixed_sized_array_is_normal (GVariantSerialised value) { @@ -552,9 +667,10 @@ gvs_fixed_sized_array_is_normal (GVariantSerialised value) * normal form and that is the one that the serialiser must produce. */ +/* bytes may be NULL if (size == 0). */ static inline gsize -gvs_read_unaligned_le (guchar *bytes, - guint size) +gvs_read_unaligned_le (const guchar *bytes, + guint size) { union { @@ -563,7 +679,8 @@ gvs_read_unaligned_le (guchar *bytes, } tmpvalue; tmpvalue.integer = 0; - memcpy (&tmpvalue.bytes, bytes, size); + if (bytes != NULL) + memcpy (&tmpvalue.bytes, bytes, size); return GSIZE_FROM_LE (tmpvalue.integer); } @@ -688,6 +805,80 @@ gvs_variable_sized_array_get_child (GVariantSerialised value, return child; } +static gboolean +gvs_variable_sized_array_unpack_all (GVariantTypeInfo *type_info, + const guchar *end, + gsize end_size, + gsize total_size, + GArray *results) +{ + GVariantTypeInfo *element; + guint element_alignment; + const guchar *offsets; + gsize offset_size; + gsize offsets_array_size; + gsize prev_end; + gsize last_end; + gsize i, n; + + if (total_size == 0) + return TRUE; + + element = g_variant_type_info_element (type_info); + g_variant_type_info_query (element, &element_alignment, NULL); + + offset_size = gvs_get_offset_size (total_size); + + if (offset_size > end_size) + return FALSE; + + last_end = gvs_read_unaligned_le (end - offset_size, offset_size); + + if (last_end > total_size) + return 0; + + offsets_array_size = total_size - last_end; + + if (offsets_array_size > end_size) + return FALSE; + + offsets = end - offsets_array_size; + + if (offsets_array_size % offset_size) + return FALSE; + + n = offsets_array_size / offset_size; + + if (n == 0) + return FALSE; + + prev_end = 0; + + for (i = 0; i < n; i++) + { + GVariantUnpacked unpacked; + gsize start; + gsize end; + + start = prev_end + ((-prev_end) & element_alignment); + end = gvs_read_unaligned_le (offsets, offset_size); + offsets += offset_size; + + if (start < prev_end || end < start) + return FALSE; + + unpacked.type_info = g_variant_type_info_ref (element); + unpacked.skip = start - prev_end; + unpacked.size = end - start; + + g_array_append_val (results, unpacked); + + prev_end = end; + } + + return TRUE; +} + static gsize gvs_variable_sized_array_needed_size (GVariantTypeInfo *type_info, GVariantSerialisedFiller gvs_filler, @@ -747,6 +938,38 @@ gvs_variable_sized_array_serialise (GVariantSerialised value, } } +static void +gvs_variable_sized_array_write_to_vectors (GVariantVectors *vectors, + GVariantTypeInfo *type_info, + gsize size, + const gpointer *children, + gsize n_children) +{ + guint offset_key; + guint alignment; + gsize offset; + gsize i; + + if (n_children == 0) + return; + + offset_key = g_variant_vectors_reserve_offsets (vectors, n_children, gvs_get_offset_size (size)); + g_variant_type_info_query (type_info, &alignment, NULL); + offset = 0; + + for (i = 0; i < n_children; i++) + { + if ((-offset) & alignment) + offset += g_variant_vectors_append_pad (vectors, (-offset) & alignment); + + offset += g_variant_callback_write_to_vectors (vectors, children[i], NULL); + + g_variant_vectors_write_to_offsets (vectors, i, offset, offset_key); + } + + g_variant_vectors_commit_offsets (vectors, offset_key); +} + static gboolean gvs_variable_sized_array_is_normal (GVariantSerialised value) { @@ -918,7 +1141,7 @@ gvs_tuple_get_child (GVariantSerialised value, child.size = fixed_size; } - else /* G_VARIANT_MEMEBER_ENDING_OFFSET */ + else /* G_VARIANT_MEMBER_ENDING_OFFSET */ end = gvs_read_unaligned_le (value.data + value.size - offset_size * (member_info->i + 2), offset_size); @@ -932,6 +1155,86 @@ gvs_tuple_get_child (GVariantSerialised value, return child; } +static gboolean +gvs_tuple_unpack_all (GVariantTypeInfo *type_info, + const guchar *end_pointer, + gsize end_size, + gsize total_size, + GArray *results) +{ + gsize offset_size; + gsize prev_end; + gsize i, n; + + n = g_variant_type_info_n_members (type_info); + + /* An empty tuple (n = 0) is always encoded as a single byte, which + * means that we should not be attempting to unpack it from multiple + * vectors. + */ + if (n == 0) + return FALSE; + + offset_size = gvs_get_offset_size (total_size); + + prev_end = 0; + + for (i = 0; i < n; i++) + { + const GVariantMemberInfo *member_info; + GVariantUnpacked unpacked; + gsize fixed_size; + guint alignment; + gsize start; + gsize end; + + member_info = g_variant_type_info_member_info (type_info, i); + g_variant_type_info_query (member_info->type_info, &alignment, &fixed_size); + + start = prev_end + ((-prev_end) & alignment); + + switch (member_info->ending_type) + { + case G_VARIANT_MEMBER_ENDING_FIXED: + end = start + fixed_size; + break; + + case G_VARIANT_MEMBER_ENDING_LAST: + end = total_size; + break; + + case G_VARIANT_MEMBER_ENDING_OFFSET: + if (end_size < offset_size) + return FALSE; + + end_pointer -= offset_size; + total_size -= offset_size; + end_size -= offset_size; + + end = gvs_read_unaligned_le (end_pointer, offset_size); + break; + + default: + g_assert_not_reached (); + } + + if (start < prev_end || end < start) + return FALSE; + + unpacked.type_info = g_variant_type_info_ref (member_info->type_info); + unpacked.skip = start - prev_end; + unpacked.size = end - start; + + g_array_append_val (results, unpacked); + + prev_end = end; + } + + g_assert (prev_end == total_size); + + return TRUE; +} + static gsize gvs_tuple_needed_size (GVariantTypeInfo *type_info, GVariantSerialisedFiller gvs_filler, @@ -1014,6 +1317,95 @@ gvs_tuple_serialise (GVariantSerialised value, value.data[offset++] = '\0'; } + +static void +gvs_tuple_write_to_vectors (GVariantVectors *vectors, + GVariantTypeInfo *type_info, + gsize size, + const gpointer *children, + gsize n_children) +{ + const GVariantMemberInfo *member_info = NULL; + gsize fixed_size; + gsize offset; + gsize i; + + if (n_children == 0) + { + g_variant_vectors_append_copy (vectors, "", 1); + return; + } + + g_variant_type_info_query (type_info, NULL, &fixed_size); + offset = 0; + + if (!fixed_size) + { + gsize n_offsets; + + member_info = g_variant_type_info_member_info (type_info, n_children - 1); + n_offsets = member_info->i + 1; + + if (n_offsets) + { + gsize offset_key = 0; + + offset_key = g_variant_vectors_reserve_offsets (vectors, n_offsets, gvs_get_offset_size (size)); + + for (i = 0; i < n_children; i++) + { + guint alignment; + + member_info = g_variant_type_info_member_info (type_info, i); + g_variant_type_info_query (member_info->type_info, &alignment, NULL); + + if ((-offset) & alignment) + offset += g_variant_vectors_append_pad (vectors, (-offset) & alignment); + + offset += g_variant_callback_write_to_vectors (vectors, children[i], NULL); + + if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_OFFSET) + g_variant_vectors_write_to_offsets (vectors, --n_offsets, offset, offset_key); + } + + g_variant_vectors_commit_offsets (vectors, offset_key); + } + else + { + for (i = 0; i < n_children; i++) + { + guint alignment; + + member_info = g_variant_type_info_member_info (type_info, i); + g_variant_type_info_query (member_info->type_info, &alignment, NULL); + + if ((-offset) & alignment) + offset += g_variant_vectors_append_pad (vectors, (-offset) & alignment); + + offset += g_variant_callback_write_to_vectors (vectors, children[i], NULL); + } + } + } + else + { + for (i = 0; i < n_children; i++) + { + guint alignment; + + member_info = g_variant_type_info_member_info (type_info, i); + g_variant_type_info_query (member_info->type_info, &alignment, NULL); + + if ((-offset) & alignment) + offset += g_variant_vectors_append_pad (vectors, (-offset) & alignment); + + offset += g_variant_callback_write_to_vectors (vectors, children[i], NULL); + } + + g_assert (fixed_size - offset < 8); + g_variant_vectors_append_pad (vectors, fixed_size - offset); + } +} + static gboolean gvs_tuple_is_normal (GVariantSerialised value) { @@ -1023,6 +1415,10 @@ gvs_tuple_is_normal (GVariantSerialised value) gsize offset; gsize i; + /* as per the comment in gvs_tuple_get_child() */ + if G_UNLIKELY (value.data == NULL && value.size != 0) + return FALSE; + offset_size = gvs_get_offset_size (value.size); length = g_variant_type_info_n_members (value.type_info); offset_ptr = value.size; @@ -1190,6 +1586,74 @@ gvs_variant_get_child (GVariantSerialised value, return child; } +static GVariantTypeInfo * +gvs_variant_find_type (const guchar *end_pointer, + gsize end_size, + gsize total_size, + gsize *child_size) +{ + gsize i; + + for (i = 1; i <= end_size; i++) + if (end_pointer[-i] == '\0') + { + const gchar *type_string = (gchar *) end_pointer - i + 1; + const gchar *limit = (gchar *) end_pointer; + const gchar *end; + + /* We may have a type string of length 'i'. Check for validity. */ + if (g_variant_type_string_scan (type_string, limit, &end) && end == limit) + { + const GVariantType *type = (GVariantType *) type_string; + + if (g_variant_type_is_definite (type)) + { + GVariantTypeInfo *type_info; + gsize fixed_size; + + type_info = g_variant_type_info_get (type); + + g_variant_type_info_query (type_info, NULL, &fixed_size); + + if (!fixed_size || fixed_size == total_size - i) + { + *child_size = total_size - i; + + return type_info; + } + + g_variant_type_info_unref (type_info); + } + } + + /* No sense in trying other lengths if we already failed */ + break; + } + + return NULL; +} + +static gboolean +gvs_variant_unpack_all (GVariantTypeInfo *type_info, + const guchar *end_pointer, + gsize end_size, + gsize total_size, + GArray *results) +{ + GVariantUnpacked unpacked; + + if ((unpacked.type_info = gvs_variant_find_type (end_pointer, end_size, total_size, &unpacked.size))) + { + unpacked.skip = 0; + + g_array_append_val (results, unpacked); + + return TRUE; + } + + return FALSE; +} + static inline gsize gvs_variant_needed_size (GVariantTypeInfo *type_info, GVariantSerialisedFiller gvs_filler, @@ -1222,6 +1686,23 @@ gvs_variant_serialise (GVariantSerialised value, memcpy (value.data + child.size + 1, type_string, strlen (type_string)); } +static void +gvs_variant_write_to_vectors (GVariantVectors *vectors, + GVariantTypeInfo *type_info, + gsize size, + const gpointer *children, + gsize n_children) +{ + GVariantTypeInfo *child_type_info; + const gchar *type_string; + + g_variant_callback_write_to_vectors (vectors, children[0], &child_type_info); + type_string = g_variant_type_info_get_type_string (child_type_info); + + g_variant_vectors_append_copy (vectors, "", 1); + g_variant_vectors_append_copy (vectors, type_string, strlen (type_string)); +} + static inline gboolean gvs_variant_is_normal (GVariantSerialised value) { @@ -1300,11 +1781,12 @@ gvs_variant_is_normal (GVariantSerialised value) /* < private > * g_variant_serialised_n_children: * @serialised: a #GVariantSerialised - * @returns: the number of children * * For serialised data that represents a container value (maybes, * tuples, arrays, variants), determine how many child items are inside * that container. + * + * Returns: the number of children */ gsize g_variant_serialised_n_children (GVariantSerialised serialised) @@ -1323,7 +1805,6 @@ g_variant_serialised_n_children (GVariantSerialised serialised) * g_variant_serialised_get_child: * @serialised: a #GVariantSerialised * @index_: the index of the child to fetch - * @returns: a #GVariantSerialised for the child * * Extracts a child from a serialised data representing a container * value. @@ -1338,6 +1819,8 @@ g_variant_serialised_n_children (GVariantSerialised serialised) * item of a variable-sized type is being returned. * * .data is never non-%NULL if size is 0. + * + * Returns: a #GVariantSerialised for the child */ GVariantSerialised g_variant_serialised_get_child (GVariantSerialised serialised, @@ -1429,7 +1912,35 @@ g_variant_serialiser_needed_size (GVariantTypeInfo *type_info, return gvs_/**/,/**/_needed_size (type_info, gvs_filler, children, n_children); + ) + g_assert_not_reached (); +} +gboolean +g_variant_serialiser_unpack_all (GVariantTypeInfo *type_info, + const guchar *end, + gsize end_size, + gsize total_size, + GArray *results) +{ + DISPATCH_CASES (type_info, + return gvs_/**/,/**/_unpack_all (type_info, end, end_size, total_size, results); + ) + + /* We are here because type_info is not a container type */ + return FALSE; +} + +void +g_variant_serialiser_write_to_vectors (GVariantVectors *vectors, + GVariantTypeInfo *type_info, + gsize size, + const gpointer *children, + gsize n_children) +{ + DISPATCH_CASES (type_info, + gvs_/**/,/**/_write_to_vectors (vectors, type_info, size, children, n_children); + return; ) g_assert_not_reached (); } @@ -1591,11 +2102,20 @@ gboolean g_variant_serialiser_is_string (gconstpointer data, gsize size) { + const gchar *expected_end; const gchar *end; + if (size == 0) + return FALSE; + + expected_end = ((gchar *) data) + size - 1; + + if (*expected_end != '\0') + return FALSE; + g_utf8_validate (data, size, &end); - return data == end - (size - 1); + return end == expected_end; } /* < private >