X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=glib%2Fgvariant-serialiser.c;h=c25a7bea77d3020faeeb4d30120a4a7357f15a1d;hb=13e15733f38a40c6ef6a1baede91cce81c86ebaa;hp=f92d49bf3f9842a93a5941a5c91a22ecb500c034;hpb=e04c9c699c1ca181419d3d325aade70cf3e14763;p=platform%2Fupstream%2Fglib.git diff --git a/glib/gvariant-serialiser.c b/glib/gvariant-serialiser.c index f92d49b..c25a7be 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 */ @@ -31,7 +29,6 @@ #include -#include "galias.h" /* GVariantSerialiser * @@ -84,13 +81,13 @@ * values is permitted (eg: 0 to 255 is a valid byte). Special checks * need to be performed for booleans (only 0 or 1 allowed), strings * (properly nul-terminated) and object paths and signature strings - * (meeting the DBus specification requirements). + * (meeting the D-Bus specification requirements). */ /* < 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 @@ -139,6 +136,34 @@ g_variant_serialised_check (GVariantSerialised serialised) else g_assert (serialised.size == 0 || serialised.data != NULL); + /* Depending on the native alignment requirements of the machine, the + * compiler will insert either 3 or 7 padding bytes after the char. + * This will result in the sizeof() the struct being 12 or 16. + * Subtract 9 to get 3 or 7 which is a nice bitmask to apply to get + * the alignment bits that we "care about" being zero: in the + * 4-aligned case, we care about 2 bits, and in the 8-aligned case, we + * care about 3 bits. + */ + alignment &= sizeof (struct { + char a; + union { + guint64 x; + void *y; + gdouble z; + } b; + } + ) - 9; + + /* Some OSes (FreeBSD is a known example) have a malloc() that returns + * unaligned memory if you request small sizes. 'malloc (1);', for + * example, has been seen to return pointers aligned to 6 mod 16. + * + * Check if this is a small allocation and return without enforcing + * the alignment assertion if this is the case. + */ + if (serialised.size <= alignment) + return; + g_assert_cmpint (alignment & (gsize) serialised.data, ==, 0); } @@ -267,6 +292,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) { @@ -333,7 +371,7 @@ gvs_variable_sized_maybe_needed_size (GVariantTypeInfo *type_info, { if (n_children) { - GVariantSerialised child = { }; + GVariantSerialised child = { 0, }; gvs_filler (&child, children[0]); @@ -359,6 +397,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) { @@ -414,7 +466,7 @@ static GVariantSerialised gvs_fixed_sized_array_get_child (GVariantSerialised value, gsize index_) { - GVariantSerialised child = { }; + GVariantSerialised child = { 0, }; child.type_info = g_variant_type_info_element (value.type_info); g_variant_type_info_query (child.type_info, NULL, &child.size); @@ -443,7 +495,7 @@ gvs_fixed_sized_array_serialise (GVariantSerialised value, const gpointer *children, gsize n_children) { - GVariantSerialised child = { }; + GVariantSerialised child = { 0, }; gsize i; child.type_info = g_variant_type_info_element (value.type_info); @@ -457,10 +509,23 @@ 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) { - GVariantSerialised child = { }; + GVariantSerialised child = { 0, }; child.type_info = g_variant_type_info_element (value.type_info); g_variant_type_info_query (child.type_info, NULL, &child.size); @@ -484,7 +549,7 @@ gvs_fixed_sized_array_is_normal (GVariantSerialised value) * Variable sized arrays, containing variable-sized elements, must be * able to determine the boundaries between the elements. The items * cannot simply be concatenated. Additionally, we are faced with the - * fact that non-fixed-sized values do not neccessarily have a size that + * fact that non-fixed-sized values do not necessarily have a size that * is a multiple of their alignment requirement, so we may need to * insert zero-filled padding. * @@ -525,6 +590,7 @@ 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) @@ -536,7 +602,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); } @@ -620,7 +687,7 @@ static GVariantSerialised gvs_variable_sized_array_get_child (GVariantSerialised value, gsize index_) { - GVariantSerialised child = { }; + GVariantSerialised child = { 0, }; gsize offset_size; gsize last_end; gsize start; @@ -676,7 +743,7 @@ gvs_variable_sized_array_needed_size (GVariantTypeInfo *type_info, for (i = 0; i < n_children; i++) { - GVariantSerialised child = { }; + GVariantSerialised child = { 0, }; offset += (-offset) & alignment; gvs_filler (&child, children[i]); @@ -706,7 +773,7 @@ gvs_variable_sized_array_serialise (GVariantSerialised value, for (i = 0; i < n_children; i++) { - GVariantSerialised child = { }; + GVariantSerialised child = { 0, }; while (offset & alignment) value.data[offset++] = '\0'; @@ -720,10 +787,42 @@ 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) { - GVariantSerialised child = { }; + GVariantSerialised child = { 0, }; gsize offsets_array_size; guchar *offsets_array; guint offset_size; @@ -825,7 +924,7 @@ gvs_tuple_get_child (GVariantSerialised value, gsize index_) { const GVariantMemberInfo *member_info; - GVariantSerialised child = { }; + GVariantSerialised child = { 0, }; gsize offset_size; gsize start, end; @@ -835,7 +934,7 @@ gvs_tuple_get_child (GVariantSerialised value, /* tuples are the only (potentially) fixed-sized containers, so the * only ones that have to deal with the possibility of having %NULL - * data with a non-zero %size if errors occured elsewhere. + * data with a non-zero %size if errors occurred elsewhere. */ if G_UNLIKELY (value.data == NULL && value.size != 0) { @@ -891,7 +990,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); @@ -936,7 +1035,7 @@ gvs_tuple_needed_size (GVariantTypeInfo *type_info, offset += fixed_size; else { - GVariantSerialised child = { }; + GVariantSerialised child = { 0, }; gvs_filler (&child, children[i]); offset += child.size; @@ -962,7 +1061,7 @@ gvs_tuple_serialise (GVariantSerialised value, for (i = 0; i < n_children; i++) { const GVariantMemberInfo *member_info; - GVariantSerialised child = { }; + GVariantSerialised child = { 0, }; guint alignment; member_info = g_variant_type_info_member_info (value.type_info, i); @@ -987,6 +1086,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) { @@ -996,6 +1184,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; @@ -1041,6 +1233,9 @@ gvs_tuple_is_normal (GVariantSerialised value) end = gvs_read_unaligned_le (value.data + offset_ptr, offset_size); break; + + default: + g_assert_not_reached (); } if (end < offset || end > offset_ptr) @@ -1109,12 +1304,11 @@ static inline GVariantSerialised gvs_variant_get_child (GVariantSerialised value, gsize index_) { - GVariantSerialised child = { }; + GVariantSerialised child = { 0, }; /* NOTE: not O(1) and impossible for it to be... */ if (value.size) { - /* find '\0' character */ for (child.size = value.size - 1; child.size; child.size--) if (value.data[child.size] == '\0') @@ -1167,7 +1361,7 @@ gvs_variant_needed_size (GVariantTypeInfo *type_info, const gpointer *children, gsize n_children) { - GVariantSerialised child = { }; + GVariantSerialised child = { 0, }; const gchar *type_string; gvs_filler (&child, children[0]); @@ -1182,7 +1376,7 @@ gvs_variant_serialise (GVariantSerialised value, const gpointer *children, gsize n_children) { - GVariantSerialised child = { }; + GVariantSerialised child = { 0, }; const gchar *type_string; child.data = value.data; @@ -1193,6 +1387,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) { @@ -1271,11 +1482,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) @@ -1294,7 +1506,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. @@ -1309,6 +1520,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, @@ -1400,7 +1613,21 @@ g_variant_serialiser_needed_size (GVariantTypeInfo *type_info, return gvs_/**/,/**/_needed_size (type_info, gvs_filler, children, n_children); + ) + g_assert_not_reached (); +} + +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 (); } @@ -1515,6 +1742,9 @@ g_variant_serialised_is_normal (GVariantSerialised serialised) ) + if (serialised.data == NULL) + return FALSE; + /* some hard-coded terminal cases */ switch (g_variant_type_info_get_type_char (serialised.type_info)) { @@ -1559,25 +1789,30 @@ gboolean g_variant_serialiser_is_string (gconstpointer data, gsize size) { - const gchar *string = data; + const gchar *expected_end; + const gchar *end; if (size == 0) return FALSE; - if (string[size - 1] != '\0') + expected_end = ((gchar *) data) + size - 1; + + if (*expected_end != '\0') return FALSE; - return strlen (string) == size - 1; + g_utf8_validate (data, size, &end); + + return end == expected_end; } /* < private > * g_variant_serialiser_is_object_path: - * @data: a possible DBus object path + * @data: a possible D-Bus object path * @size: the size of @data * * Performs the checks for being a valid string. * - * Also, ensures that @data is a valid DBus object path, as per the DBus + * Also, ensures that @data is a valid DBus object path, as per the D-Bus * specification. */ gboolean @@ -1624,13 +1859,13 @@ g_variant_serialiser_is_object_path (gconstpointer data, /* < private > * g_variant_serialiser_is_signature: - * @data: a possible DBus signature + * @data: a possible D-Bus signature * @size: the size of @data * * Performs the checks for being a valid string. * - * Also, ensures that @data is a valid DBus type signature, as per the - * DBus specification. + * Also, ensures that @data is a valid D-Bus type signature, as per the + * D-Bus specification. */ gboolean g_variant_serialiser_is_signature (gconstpointer data, @@ -1655,4 +1890,5 @@ g_variant_serialiser_is_signature (gconstpointer data, return TRUE; } +/* Epilogue {{{1 */ /* vim:set foldmethod=marker: */