2 * Copyright © 2007, 2008 Ryan Lortie
3 * Copyright © 2010 Codethink Limited
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 * Author: Ryan Lortie <desrt@desrt.ca>
24 #include "gvariant-serialiser.h"
26 #include <glib/gtestutils.h>
27 #include <glib/gstrfuncs.h>
28 #include <glib/gtypes.h>
35 * After this prologue section, this file has roughly 2 parts.
37 * The first part is split up into sections according to various
38 * container types. Maybe, Array, Tuple, Variant. The Maybe and Array
39 * sections are subdivided for element types being fixed or
40 * variable-sized types.
42 * Each section documents the format of that particular type of
43 * container and implements 5 functions for dealing with it:
46 * - determines (according to serialised data) how many child values
47 * are inside a particular container value.
50 * - gets the type of and the serialised data corresponding to a
51 * given child value within the container value.
54 * - determines how much space would be required to serialise a
55 * container of this type, containing the given children so that
56 * buffers can be preallocated before serialising.
59 * - write the serialised data for a container of this type,
60 * containing the given children, to a buffer.
63 * - check the given data to ensure that it is in normal form. For a
64 * given set of child values, there is exactly one normal form for
65 * the serialised data of a container. Other forms are possible
66 * while maintaining the same children (for example, by inserting
67 * something other than zero bytes as padding) but only one form is
70 * The second part contains the main entry point for each of the above 5
71 * functions and logic to dispatch it to the handler for the appropriate
72 * container type code.
74 * The second part also contains a routine to byteswap serialised
75 * values. This code makes use of the n_children() and get_child()
76 * functions above to do its work so no extra support is needed on a
77 * per-container-type basis.
79 * There is also additional code for checking for normal form. All
80 * numeric types are always in normal form since the full range of
81 * values is permitted (eg: 0 to 255 is a valid byte). Special checks
82 * need to be performed for booleans (only 0 or 1 allowed), strings
83 * (properly nul-terminated) and object paths and signature strings
84 * (meeting the D-Bus specification requirements).
89 * @type_info: the #GVariantTypeInfo of this value
90 * @data: (allow-none): the serialised data of this value, or %NULL
91 * @size: the size of this value
93 * A structure representing a GVariant in serialised form. This
94 * structure is used with #GVariantSerialisedFiller functions and as the
95 * primary interface to the serialiser. See #GVariantSerialisedFiller
96 * for a description of its use there.
98 * When used with the serialiser API functions, the following invariants
99 * apply to all #GVariantTypeSerialised structures passed to and
100 * returned from the serialiser.
102 * @type_info must be non-%NULL.
104 * @data must be properly aligned for the type described by @type_info.
106 * If @type_info describes a fixed-sized type then @size must always be
107 * equal to the fixed size of that type.
109 * For fixed-sized types (and only fixed-sized types), @data may be
110 * %NULL even if @size is non-zero. This happens when a framing error
111 * occurs while attempting to extract a fixed-sized value out of a
112 * variable-sized container. There is no data to return for the
113 * fixed-sized type, yet @size must be non-zero. The effect of this
114 * combination should be as if @data were a pointer to an
115 * appropriately-sized zero-filled region.
119 * g_variant_serialised_check:
120 * @serialised: a #GVariantSerialised struct
122 * Checks @serialised for validity according to the invariants described
126 g_variant_serialised_check (GVariantSerialised serialised)
131 g_assert (serialised.type_info != NULL);
132 g_variant_type_info_query (serialised.type_info, &alignment, &fixed_size);
135 g_assert_cmpint (serialised.size, ==, fixed_size);
137 g_assert (serialised.size == 0 || serialised.data != NULL);
139 /* Depending on the native alignment requirements of the machine, the
140 * compiler will insert either 3 or 7 padding bytes after the char.
141 * This will result in the sizeof() the struct being 12 or 16.
142 * Subtract 9 to get 3 or 7 which is a nice bitmask to apply to get
143 * the alignment bits that we "care about" being zero: in the
144 * 4-aligned case, we care about 2 bits, and in the 8-aligned case, we
147 alignment &= sizeof (struct {
157 /* Some OSes (FreeBSD is a known example) have a malloc() that returns
158 * unaligned memory if you request small sizes. 'malloc (1);', for
159 * example, has been seen to return pointers aligned to 6 mod 16.
161 * Check if this is a small allocation and return without enforcing
162 * the alignment assertion if this is the case.
164 if (serialised.size <= alignment)
167 g_assert_cmpint (alignment & (gsize) serialised.data, ==, 0);
171 * GVariantSerialisedFiller:
172 * @serialised: a #GVariantSerialised instance to fill
173 * @data: data from the children array
175 * This function is called back from g_variant_serialiser_needed_size()
176 * and g_variant_serialiser_serialise(). It fills in missing details
177 * from a partially-complete #GVariantSerialised.
179 * The @data parameter passed back to the function is one of the items
180 * that was passed to the serialiser in the @children array. It
181 * represents a single child item of the container that is being
182 * serialised. The information filled in to @serialised is the
183 * information for this child.
185 * If the @type_info field of @serialised is %NULL then the callback
186 * function must set it to the type information corresponding to the
187 * type of the child. No reference should be added. If it is non-%NULL
188 * then the callback should assert that it is equal to the actual type
191 * If the @size field is zero then the callback must fill it in with the
192 * required amount of space to store the serialised form of the child.
193 * If it is non-zero then the callback should assert that it is equal to
194 * the needed size of the child.
196 * If @data is non-%NULL then it points to a space that is properly
197 * aligned for and large enough to store the serialised data of the
198 * child. The callback must store the serialised form of the child at
201 * If the child value is another container then the callback will likely
202 * recurse back into the serialiser by calling
203 * g_variant_serialiser_needed_size() to determine @size and
204 * g_variant_serialiser_serialise() to write to @data.
207 /* PART 1: Container types {{{1
209 * This section contains the serialiser implementation functions for
210 * each container type.
215 * Maybe types are handled depending on if the element type of the maybe
216 * type is a fixed-sized or variable-sized type. Although all maybe
217 * types themselves are variable-sized types, herein, a maybe value with
218 * a fixed-sized element type is called a "fixed-sized maybe" for
219 * convenience and a maybe value with a variable-sized element type is
220 * called a "variable-sized maybe".
223 /* Fixed-sized Maybe {{{3
225 * The size of a maybe value with a fixed-sized element type is either 0
226 * or equal to the fixed size of its element type. The case where the
227 * size of the maybe value is zero corresponds to the "Nothing" case and
228 * the case where the size of the maybe value is equal to the fixed size
229 * of the element type corresponds to the "Just" case; in that case, the
230 * serialised data of the child value forms the entire serialised data
231 * of the maybe value.
233 * In the event that a fixed-sized maybe value is presented with a size
234 * that is not equal to the fixed size of the element type then the
235 * value must be taken to be "Nothing".
239 gvs_fixed_sized_maybe_n_children (GVariantSerialised value)
241 gsize element_fixed_size;
243 g_variant_type_info_query_element (value.type_info, NULL,
244 &element_fixed_size);
246 return (element_fixed_size == value.size) ? 1 : 0;
249 static GVariantSerialised
250 gvs_fixed_sized_maybe_get_child (GVariantSerialised value,
253 /* the child has the same bounds as the
254 * container, so just update the type.
256 value.type_info = g_variant_type_info_element (value.type_info);
257 g_variant_type_info_ref (value.type_info);
263 gvs_fixed_sized_maybe_unpack_all (GVariantTypeInfo *type_info,
264 const guchar *end_pointer,
267 GArray *unpacked_children)
271 GVariantUnpacked unpacked;
273 unpacked.type_info = g_variant_type_info_ref (g_variant_type_info_element (type_info));
275 unpacked.size = total_size;
277 g_array_append_val (unpacked_children, unpacked);
284 gvs_fixed_sized_maybe_needed_size (GVariantTypeInfo *type_info,
285 GVariantSerialisedFiller gvs_filler,
286 const gpointer *children,
291 gsize element_fixed_size;
293 g_variant_type_info_query_element (type_info, NULL,
294 &element_fixed_size);
296 return element_fixed_size;
303 gvs_fixed_sized_maybe_serialise (GVariantSerialised value,
304 GVariantSerialisedFiller gvs_filler,
305 const gpointer *children,
310 GVariantSerialised child = { NULL, value.data, value.size };
312 gvs_filler (&child, children[0]);
317 gvs_fixed_sized_maybe_write_to_vectors (GVariantVectors *vectors,
318 GVariantTypeInfo *type_info,
320 const gpointer *children,
326 return g_variant_callback_write_to_vectors (vectors, children[0], NULL);
330 gvs_fixed_sized_maybe_is_normal (GVariantSerialised value)
334 gsize element_fixed_size;
336 g_variant_type_info_query_element (value.type_info,
337 NULL, &element_fixed_size);
339 if (value.size != element_fixed_size)
342 /* proper element size: "Just". recurse to the child. */
343 value.type_info = g_variant_type_info_element (value.type_info);
345 return g_variant_serialised_is_normal (value);
348 /* size of 0: "Nothing" */
352 /* Variable-sized Maybe
354 * The size of a maybe value with a variable-sized element type is
355 * either 0 or strictly greater than 0. The case where the size of the
356 * maybe value is zero corresponds to the "Nothing" case and the case
357 * where the size of the maybe value is greater than zero corresponds to
358 * the "Just" case; in that case, the serialised data of the child value
359 * forms the first part of the serialised data of the maybe value and is
360 * followed by a single zero byte. This zero byte is always appended,
361 * regardless of any zero bytes that may already be at the end of the
362 * serialised ata of the child value.
366 gvs_variable_sized_maybe_n_children (GVariantSerialised value)
368 return (value.size > 0) ? 1 : 0;
371 static GVariantSerialised
372 gvs_variable_sized_maybe_get_child (GVariantSerialised value,
375 /* remove the padding byte and update the type. */
376 value.type_info = g_variant_type_info_element (value.type_info);
377 g_variant_type_info_ref (value.type_info);
380 /* if it's zero-sized then it may as well be NULL */
388 gvs_variable_sized_maybe_unpack_all (GVariantTypeInfo *type_info,
389 const guchar *end_pointer,
392 GArray *unpacked_children)
396 GVariantUnpacked unpacked;
398 unpacked.type_info = g_variant_type_info_ref (g_variant_type_info_element (type_info));
400 unpacked.size = total_size - 1;
402 g_array_append_val (unpacked_children, unpacked);
409 gvs_variable_sized_maybe_needed_size (GVariantTypeInfo *type_info,
410 GVariantSerialisedFiller gvs_filler,
411 const gpointer *children,
416 GVariantSerialised child = { 0, };
418 gvs_filler (&child, children[0]);
420 return child.size + 1;
427 gvs_variable_sized_maybe_serialise (GVariantSerialised value,
428 GVariantSerialisedFiller gvs_filler,
429 const gpointer *children,
434 GVariantSerialised child = { NULL, value.data, value.size - 1 };
436 /* write the data for the child. */
437 gvs_filler (&child, children[0]);
438 value.data[child.size] = '\0';
443 gvs_variable_sized_maybe_write_to_vectors (GVariantVectors *vectors,
444 GVariantTypeInfo *type_info,
446 const gpointer *children,
451 g_variant_callback_write_to_vectors (vectors, children[0], NULL);
452 g_variant_vectors_append_copy (vectors, "", 1);
457 gvs_variable_sized_maybe_is_normal (GVariantSerialised value)
462 if (value.data[value.size - 1] != '\0')
465 value.type_info = g_variant_type_info_element (value.type_info);
468 return g_variant_serialised_is_normal (value);
473 * Just as with maybe types, array types are handled depending on if the
474 * element type of the array type is a fixed-sized or variable-sized
475 * type. Similar to maybe types, for convenience, an array value with a
476 * fixed-sized element type is called a "fixed-sized array" and an array
477 * value with a variable-sized element type is called a "variable sized
481 /* Fixed-sized Array {{{3
483 * For fixed sized arrays, the serialised data is simply a concatenation
484 * of the serialised data of each element, in order. Since fixed-sized
485 * values always have a fixed size that is a multiple of their alignment
486 * requirement no extra padding is required.
488 * In the event that a fixed-sized array is presented with a size that
489 * is not an integer multiple of the element size then the value of the
490 * array must be taken as being empty.
494 gvs_fixed_sized_array_n_children (GVariantSerialised value)
496 gsize element_fixed_size;
498 g_variant_type_info_query_element (value.type_info, NULL,
499 &element_fixed_size);
501 if (value.size % element_fixed_size == 0)
502 return value.size / element_fixed_size;
507 static GVariantSerialised
508 gvs_fixed_sized_array_get_child (GVariantSerialised value,
511 GVariantSerialised child = { 0, };
513 child.type_info = g_variant_type_info_element (value.type_info);
514 g_variant_type_info_query (child.type_info, NULL, &child.size);
515 child.data = value.data + (child.size * index_);
516 g_variant_type_info_ref (child.type_info);
522 gvs_fixed_sized_array_unpack_all (GVariantTypeInfo *type_info,
523 const guchar *end_pointer,
526 GArray *unpacked_children)
528 GVariantTypeInfo *element;
529 gsize element_fixed_size;
532 element = g_variant_type_info_element (type_info);
533 g_variant_type_info_query (element, NULL, &element_fixed_size);
535 if (total_size % element_fixed_size)
538 n = total_size / element_fixed_size;
540 for (i = 0; i < n; i++)
542 GVariantUnpacked unpacked;
544 unpacked.type_info = g_variant_type_info_ref (element);
546 unpacked.size = element_fixed_size;
548 g_array_append_val (unpacked_children, unpacked);
555 gvs_fixed_sized_array_needed_size (GVariantTypeInfo *type_info,
556 GVariantSerialisedFiller gvs_filler,
557 const gpointer *children,
560 gsize element_fixed_size;
562 g_variant_type_info_query_element (type_info, NULL, &element_fixed_size);
564 return element_fixed_size * n_children;
568 gvs_fixed_sized_array_serialise (GVariantSerialised value,
569 GVariantSerialisedFiller gvs_filler,
570 const gpointer *children,
573 GVariantSerialised child = { 0, };
576 child.type_info = g_variant_type_info_element (value.type_info);
577 g_variant_type_info_query (child.type_info, NULL, &child.size);
578 child.data = value.data;
580 for (i = 0; i < n_children; i++)
582 gvs_filler (&child, children[i]);
583 child.data += child.size;
588 gvs_fixed_sized_array_write_to_vectors (GVariantVectors *vectors,
589 GVariantTypeInfo *type_info,
591 const gpointer *children,
596 for (i = 0; i < n_children; i++)
597 g_variant_callback_write_to_vectors (vectors, children[i], NULL);
601 gvs_fixed_sized_array_is_normal (GVariantSerialised value)
603 GVariantSerialised child = { 0, };
605 child.type_info = g_variant_type_info_element (value.type_info);
606 g_variant_type_info_query (child.type_info, NULL, &child.size);
608 if (value.size % child.size != 0)
611 for (child.data = value.data;
612 child.data < value.data + value.size;
613 child.data += child.size)
615 if (!g_variant_serialised_is_normal (child))
622 /* Variable-sized Array {{{3
624 * Variable sized arrays, containing variable-sized elements, must be
625 * able to determine the boundaries between the elements. The items
626 * cannot simply be concatenated. Additionally, we are faced with the
627 * fact that non-fixed-sized values do not necessarily have a size that
628 * is a multiple of their alignment requirement, so we may need to
629 * insert zero-filled padding.
631 * While it is possible to find the start of an item by starting from
632 * the end of the item before it and padding for alignment, it is not
633 * generally possible to do the reverse operation. For this reason, we
634 * record the end point of each element in the array.
636 * GVariant works in terms of "offsets". An offset is a pointer to a
637 * boundary between two bytes. In 4 bytes of serialised data, there
638 * would be 5 possible offsets: one at the start ('0'), one between each
639 * pair of adjacent bytes ('1', '2', '3') and one at the end ('4').
641 * The numeric value of an offset is an unsigned integer given relative
642 * to the start of the serialised data of the array. Offsets are always
643 * stored in little endian byte order and are always only as big as they
644 * need to be. For example, in 255 bytes of serialised data, there are
645 * 256 offsets. All possibilities can be stored in an 8 bit unsigned
646 * integer. In 256 bytes of serialised data, however, there are 257
647 * possible offsets so 16 bit integers must be used. The size of an
648 * offset is always a power of 2.
650 * The offsets are stored at the end of the serialised data of the
651 * array. They are simply concatenated on without any particular
652 * alignment. The size of the offsets is included in the size of the
653 * serialised data for purposes of determining the size of the offsets.
654 * This presents a possibly ambiguity; in certain cases, a particular
655 * value of array could have two different serialised forms.
657 * Imagine an array containing a single string of 253 bytes in length
658 * (so, 254 bytes including the nul terminator). Now the offset must be
659 * written. If an 8 bit offset is written, it will bring the size of
660 * the array's serialised data to 255 -- which means that the use of an
661 * 8 bit offset was valid. If a 16 bit offset is used then the total
662 * size of the array will be 256 -- which means that the use of a 16 bit
663 * offset was valid. Although both of these will be accepted by the
664 * deserialiser, only the smaller of the two is considered to be in
665 * normal form and that is the one that the serialiser must produce.
668 /* bytes may be NULL if (size == 0). */
670 gvs_read_unaligned_le (const guchar *bytes,
675 guchar bytes[GLIB_SIZEOF_SIZE_T];
679 tmpvalue.integer = 0;
681 memcpy (&tmpvalue.bytes, bytes, size);
683 return GSIZE_FROM_LE (tmpvalue.integer);
687 gvs_write_unaligned_le (guchar *bytes,
693 guchar bytes[GLIB_SIZEOF_SIZE_T];
697 tmpvalue.integer = GSIZE_TO_LE (value);
698 memcpy (bytes, &tmpvalue.bytes, size);
702 gvs_get_offset_size (gsize size)
704 if (size > G_MAXUINT32)
707 else if (size > G_MAXUINT16)
710 else if (size > G_MAXUINT8)
720 gvs_calculate_total_size (gsize body_size,
723 if (body_size + 1 * offsets <= G_MAXUINT8)
724 return body_size + 1 * offsets;
726 if (body_size + 2 * offsets <= G_MAXUINT16)
727 return body_size + 2 * offsets;
729 if (body_size + 4 * offsets <= G_MAXUINT32)
730 return body_size + 4 * offsets;
732 return body_size + 8 * offsets;
736 gvs_variable_sized_array_n_children (GVariantSerialised value)
738 gsize offsets_array_size;
745 offset_size = gvs_get_offset_size (value.size);
747 last_end = gvs_read_unaligned_le (value.data + value.size -
748 offset_size, offset_size);
750 if (last_end > value.size)
753 offsets_array_size = value.size - last_end;
755 if (offsets_array_size % offset_size)
758 return offsets_array_size / offset_size;
761 static GVariantSerialised
762 gvs_variable_sized_array_get_child (GVariantSerialised value,
765 GVariantSerialised child = { 0, };
771 child.type_info = g_variant_type_info_element (value.type_info);
772 g_variant_type_info_ref (child.type_info);
774 offset_size = gvs_get_offset_size (value.size);
776 last_end = gvs_read_unaligned_le (value.data + value.size -
777 offset_size, offset_size);
783 start = gvs_read_unaligned_le (value.data + last_end +
784 (offset_size * (index_ - 1)),
787 g_variant_type_info_query (child.type_info, &alignment, NULL);
788 start += (-start) & alignment;
793 end = gvs_read_unaligned_le (value.data + last_end +
794 (offset_size * index_),
797 if (start < end && end <= value.size)
799 child.data = value.data + start;
800 child.size = end - start;
807 gvs_variable_sized_array_unpack_all (GVariantTypeInfo *type_info,
808 const guchar *end_pointer,
811 GArray *unpacked_children)
813 GVariantTypeInfo *element;
814 guint element_alignment;
815 const guchar *offsets;
817 gsize offsets_array_size;
825 element = g_variant_type_info_element (type_info);
826 g_variant_type_info_query (element, &element_alignment, NULL);
828 offset_size = gvs_get_offset_size (total_size);
830 if (offset_size > end_size)
833 last_end = gvs_read_unaligned_le (end_pointer - offset_size, offset_size);
835 if (last_end > total_size)
838 offsets_array_size = total_size - last_end;
840 if (offsets_array_size > end_size)
843 offsets = end_pointer - offsets_array_size;
845 if (offsets_array_size % offset_size)
848 n = offsets_array_size / offset_size;
855 for (i = 0; i < n; i++)
857 GVariantUnpacked unpacked;
861 start = prev_end + ((-prev_end) & element_alignment);
862 end = gvs_read_unaligned_le (offsets, offset_size);
863 offsets += offset_size;
865 if (start < prev_end || end < start || end > last_end)
868 unpacked.type_info = g_variant_type_info_ref (element);
869 unpacked.skip = start - prev_end;
870 unpacked.size = end - start;
872 g_array_append_val (unpacked_children, unpacked);
881 gvs_variable_sized_array_needed_size (GVariantTypeInfo *type_info,
882 GVariantSerialisedFiller gvs_filler,
883 const gpointer *children,
890 g_variant_type_info_query (type_info, &alignment, NULL);
893 for (i = 0; i < n_children; i++)
895 GVariantSerialised child = { 0, };
897 offset += (-offset) & alignment;
898 gvs_filler (&child, children[i]);
899 offset += child.size;
902 return gvs_calculate_total_size (offset, n_children);
906 gvs_variable_sized_array_serialise (GVariantSerialised value,
907 GVariantSerialisedFiller gvs_filler,
908 const gpointer *children,
917 g_variant_type_info_query (value.type_info, &alignment, NULL);
918 offset_size = gvs_get_offset_size (value.size);
921 offset_ptr = value.data + value.size - offset_size * n_children;
923 for (i = 0; i < n_children; i++)
925 GVariantSerialised child = { 0, };
927 while (offset & alignment)
928 value.data[offset++] = '\0';
930 child.data = value.data + offset;
931 gvs_filler (&child, children[i]);
932 offset += child.size;
934 gvs_write_unaligned_le (offset_ptr, offset, offset_size);
935 offset_ptr += offset_size;
940 gvs_variable_sized_array_write_to_vectors (GVariantVectors *vectors,
941 GVariantTypeInfo *type_info,
943 const gpointer *children,
954 offset_key = g_variant_vectors_reserve_offsets (vectors, n_children, gvs_get_offset_size (size));
955 g_variant_type_info_query (type_info, &alignment, NULL);
958 for (i = 0; i < n_children; i++)
960 if ((-offset) & alignment)
961 offset += g_variant_vectors_append_pad (vectors, (-offset) & alignment);
963 offset += g_variant_callback_write_to_vectors (vectors, children[i], NULL);
965 g_variant_vectors_write_to_offsets (vectors, i, offset, offset_key);
968 g_variant_vectors_commit_offsets (vectors, offset_key);
972 gvs_variable_sized_array_is_normal (GVariantSerialised value)
974 GVariantSerialised child = { 0, };
975 gsize offsets_array_size;
976 guchar *offsets_array;
987 offset_size = gvs_get_offset_size (value.size);
988 last_end = gvs_read_unaligned_le (value.data + value.size -
989 offset_size, offset_size);
991 if (last_end > value.size)
994 offsets_array_size = value.size - last_end;
996 if (offsets_array_size % offset_size)
999 offsets_array = value.data + value.size - offsets_array_size;
1000 length = offsets_array_size / offset_size;
1005 child.type_info = g_variant_type_info_element (value.type_info);
1006 g_variant_type_info_query (child.type_info, &alignment, NULL);
1009 for (i = 0; i < length; i++)
1013 this_end = gvs_read_unaligned_le (offsets_array + offset_size * i,
1016 if (this_end < offset || this_end > last_end)
1019 while (offset & alignment)
1021 if (!(offset < this_end && value.data[offset] == '\0'))
1026 child.data = value.data + offset;
1027 child.size = this_end - offset;
1029 if (child.size == 0)
1032 if (!g_variant_serialised_is_normal (child))
1038 g_assert (offset == last_end);
1045 * Since tuples can contain a mix of variable- and fixed-sized items,
1046 * they are, in terms of serialisation, a hybrid of variable-sized and
1047 * fixed-sized arrays.
1049 * Offsets are only stored for variable-sized items. Also, since the
1050 * number of items in a tuple is known from its type, we are able to
1051 * know exactly how many offsets to expect in the serialised data (and
1052 * therefore how much space is taken up by the offset array). This
1053 * means that we know where the end of the serialised data for the last
1054 * item is -- we can just subtract the size of the offset array from the
1055 * total size of the tuple. For this reason, the last item in the tuple
1056 * doesn't need an offset stored.
1058 * Tuple offsets are stored in reverse. This design choice allows
1059 * iterator-based deserialisers to be more efficient.
1061 * Most of the "heavy lifting" here is handled by the GVariantTypeInfo
1062 * for the tuple. See the notes in gvarianttypeinfo.h.
1066 gvs_tuple_n_children (GVariantSerialised value)
1068 return g_variant_type_info_n_members (value.type_info);
1071 static GVariantSerialised
1072 gvs_tuple_get_child (GVariantSerialised value,
1075 const GVariantMemberInfo *member_info;
1076 GVariantSerialised child = { 0, };
1080 member_info = g_variant_type_info_member_info (value.type_info, index_);
1081 child.type_info = g_variant_type_info_ref (member_info->type_info);
1082 offset_size = gvs_get_offset_size (value.size);
1084 /* tuples are the only (potentially) fixed-sized containers, so the
1085 * only ones that have to deal with the possibility of having %NULL
1086 * data with a non-zero %size if errors occurred elsewhere.
1088 if G_UNLIKELY (value.data == NULL && value.size != 0)
1090 g_variant_type_info_query (child.type_info, NULL, &child.size);
1092 /* this can only happen in fixed-sized tuples,
1093 * so the child must also be fixed sized.
1095 g_assert (child.size != 0);
1101 if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_OFFSET)
1103 if (offset_size * (member_info->i + 2) > value.size)
1108 if (offset_size * (member_info->i + 1) > value.size)
1110 /* if the child is fixed size, return its size.
1111 * if child is not fixed-sized, return size = 0.
1113 g_variant_type_info_query (child.type_info, NULL, &child.size);
1119 if (member_info->i + 1)
1120 start = gvs_read_unaligned_le (value.data + value.size -
1121 offset_size * (member_info->i + 1),
1126 start += member_info->a;
1127 start &= member_info->b;
1128 start |= member_info->c;
1130 if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_LAST)
1131 end = value.size - offset_size * (member_info->i + 1);
1133 else if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_FIXED)
1137 g_variant_type_info_query (child.type_info, NULL, &fixed_size);
1138 end = start + fixed_size;
1139 child.size = fixed_size;
1142 else /* G_VARIANT_MEMBER_ENDING_OFFSET */
1143 end = gvs_read_unaligned_le (value.data + value.size -
1144 offset_size * (member_info->i + 2),
1147 if (start < end && end <= value.size)
1149 child.data = value.data + start;
1150 child.size = end - start;
1157 gvs_tuple_unpack_all (GVariantTypeInfo *type_info,
1158 const guchar *end_pointer,
1161 GArray *unpacked_children)
1167 n = g_variant_type_info_n_members (type_info);
1169 /* An empty tuple (n = 0) is always encoded as a single byte, which
1170 * means that we should not be attempting to unpack it from multiple
1176 offset_size = gvs_get_offset_size (total_size);
1180 for (i = 0; i < n; i++)
1182 const GVariantMemberInfo *member_info;
1183 GVariantUnpacked unpacked;
1189 member_info = g_variant_type_info_member_info (type_info, i);
1190 g_variant_type_info_query (member_info->type_info, &alignment, &fixed_size);
1192 start = prev_end + ((-prev_end) & alignment);
1194 switch (member_info->ending_type)
1196 case G_VARIANT_MEMBER_ENDING_FIXED:
1197 end = start + fixed_size;
1200 case G_VARIANT_MEMBER_ENDING_LAST:
1204 case G_VARIANT_MEMBER_ENDING_OFFSET:
1205 if (end_size < offset_size)
1208 end_pointer -= offset_size;
1209 total_size -= offset_size;
1210 end_size -= offset_size;
1212 end = gvs_read_unaligned_le (end_pointer, offset_size);
1216 g_assert_not_reached ();
1219 if (start < prev_end || end < start || end > total_size)
1222 unpacked.type_info = g_variant_type_info_ref (member_info->type_info);
1223 unpacked.skip = start - prev_end;
1224 unpacked.size = end - start;
1226 g_array_append_val (unpacked_children, unpacked);
1231 g_assert (prev_end == total_size);
1237 gvs_tuple_needed_size (GVariantTypeInfo *type_info,
1238 GVariantSerialisedFiller gvs_filler,
1239 const gpointer *children,
1242 const GVariantMemberInfo *member_info = NULL;
1247 g_variant_type_info_query (type_info, NULL, &fixed_size);
1254 for (i = 0; i < n_children; i++)
1258 member_info = g_variant_type_info_member_info (type_info, i);
1259 g_variant_type_info_query (member_info->type_info,
1260 &alignment, &fixed_size);
1261 offset += (-offset) & alignment;
1264 offset += fixed_size;
1267 GVariantSerialised child = { 0, };
1269 gvs_filler (&child, children[i]);
1270 offset += child.size;
1274 return gvs_calculate_total_size (offset, member_info->i + 1);
1278 gvs_tuple_serialise (GVariantSerialised value,
1279 GVariantSerialisedFiller gvs_filler,
1280 const gpointer *children,
1287 offset_size = gvs_get_offset_size (value.size);
1290 for (i = 0; i < n_children; i++)
1292 const GVariantMemberInfo *member_info;
1293 GVariantSerialised child = { 0, };
1296 member_info = g_variant_type_info_member_info (value.type_info, i);
1297 g_variant_type_info_query (member_info->type_info, &alignment, NULL);
1299 while (offset & alignment)
1300 value.data[offset++] = '\0';
1302 child.data = value.data + offset;
1303 gvs_filler (&child, children[i]);
1304 offset += child.size;
1306 if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_OFFSET)
1308 value.size -= offset_size;
1309 gvs_write_unaligned_le (value.data + value.size,
1310 offset, offset_size);
1314 while (offset < value.size)
1315 value.data[offset++] = '\0';
1320 gvs_tuple_write_to_vectors (GVariantVectors *vectors,
1321 GVariantTypeInfo *type_info,
1323 const gpointer *children,
1326 const GVariantMemberInfo *member_info = NULL;
1331 if (n_children == 0)
1333 g_variant_vectors_append_copy (vectors, "", 1);
1337 g_variant_type_info_query (type_info, NULL, &fixed_size);
1344 member_info = g_variant_type_info_member_info (type_info, n_children - 1);
1345 n_offsets = member_info->i + 1;
1349 gsize offset_key = 0;
1351 offset_key = g_variant_vectors_reserve_offsets (vectors, n_offsets, gvs_get_offset_size (size));
1353 for (i = 0; i < n_children; i++)
1357 member_info = g_variant_type_info_member_info (type_info, i);
1358 g_variant_type_info_query (member_info->type_info, &alignment, NULL);
1360 if ((-offset) & alignment)
1361 offset += g_variant_vectors_append_pad (vectors, (-offset) & alignment);
1363 offset += g_variant_callback_write_to_vectors (vectors, children[i], NULL);
1365 if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_OFFSET)
1366 g_variant_vectors_write_to_offsets (vectors, --n_offsets, offset, offset_key);
1369 g_variant_vectors_commit_offsets (vectors, offset_key);
1373 for (i = 0; i < n_children; i++)
1377 member_info = g_variant_type_info_member_info (type_info, i);
1378 g_variant_type_info_query (member_info->type_info, &alignment, NULL);
1380 if ((-offset) & alignment)
1381 offset += g_variant_vectors_append_pad (vectors, (-offset) & alignment);
1383 offset += g_variant_callback_write_to_vectors (vectors, children[i], NULL);
1389 for (i = 0; i < n_children; i++)
1393 member_info = g_variant_type_info_member_info (type_info, i);
1394 g_variant_type_info_query (member_info->type_info, &alignment, NULL);
1396 if ((-offset) & alignment)
1397 offset += g_variant_vectors_append_pad (vectors, (-offset) & alignment);
1399 offset += g_variant_callback_write_to_vectors (vectors, children[i], NULL);
1402 g_assert (fixed_size - offset < 8);
1403 g_variant_vectors_append_pad (vectors, fixed_size - offset);
1408 gvs_tuple_is_normal (GVariantSerialised value)
1416 /* as per the comment in gvs_tuple_get_child() */
1417 if G_UNLIKELY (value.data == NULL && value.size != 0)
1420 offset_size = gvs_get_offset_size (value.size);
1421 length = g_variant_type_info_n_members (value.type_info);
1422 offset_ptr = value.size;
1425 for (i = 0; i < length; i++)
1427 const GVariantMemberInfo *member_info;
1428 GVariantSerialised child;
1433 member_info = g_variant_type_info_member_info (value.type_info, i);
1434 child.type_info = member_info->type_info;
1436 g_variant_type_info_query (child.type_info, &alignment, &fixed_size);
1438 while (offset & alignment)
1440 if (offset > value.size || value.data[offset] != '\0')
1445 child.data = value.data + offset;
1447 switch (member_info->ending_type)
1449 case G_VARIANT_MEMBER_ENDING_FIXED:
1450 end = offset + fixed_size;
1453 case G_VARIANT_MEMBER_ENDING_LAST:
1457 case G_VARIANT_MEMBER_ENDING_OFFSET:
1458 offset_ptr -= offset_size;
1460 if (offset_ptr < offset)
1463 end = gvs_read_unaligned_le (value.data + offset_ptr, offset_size);
1467 g_assert_not_reached ();
1470 if (end < offset || end > offset_ptr)
1473 child.size = end - offset;
1475 if (child.size == 0)
1478 if (!g_variant_serialised_is_normal (child))
1488 g_variant_type_info_query (value.type_info, &alignment, &fixed_size);
1492 g_assert (fixed_size == value.size);
1493 g_assert (offset_ptr == value.size);
1497 if (value.data[offset++] != '\0')
1502 while (offset & alignment)
1503 if (value.data[offset++] != '\0')
1507 g_assert (offset == value.size);
1511 return offset_ptr == offset;
1516 * Variants are stored by storing the serialised data of the child,
1517 * followed by a '\0' character, followed by the type string of the
1520 * In the case that a value is presented that contains no '\0'
1521 * character, or doesn't have a single well-formed definite type string
1522 * following that character, the variant must be taken as containing the
1527 gvs_variant_n_children (GVariantSerialised value)
1532 static GVariantTypeInfo *
1533 gvs_variant_find_type (const guchar *end_pointer,
1540 for (i = 1; i <= end_size; i++)
1541 if (end_pointer[-i] == '\0')
1543 const gchar *type_string = (gchar *) end_pointer - i + 1;
1544 const gchar *limit = (gchar *) end_pointer;
1547 /* We may have a type string of length 'i'. Check for validity. */
1548 if (g_variant_type_string_scan (type_string, limit, &end) && end == limit)
1550 const GVariantType *type = (GVariantType *) type_string;
1552 if (g_variant_type_is_definite (type))
1554 GVariantTypeInfo *type_info;
1557 type_info = g_variant_type_info_get (type);
1559 g_variant_type_info_query (type_info, NULL, &fixed_size);
1561 if (!fixed_size || fixed_size == total_size - i)
1563 *child_size = total_size - i;
1568 g_variant_type_info_unref (type_info);
1572 /* No sense in trying other lengths if we already failed */
1579 static inline GVariantSerialised
1580 gvs_variant_get_child (GVariantSerialised value,
1583 GVariantSerialised child = { 0, };
1585 if ((child.type_info = gvs_variant_find_type (value.data + value.size, value.size, value.size, &child.size)))
1587 if (child.size != 0)
1588 child.data = value.data;
1592 child.type_info = g_variant_type_info_get (G_VARIANT_TYPE_UNIT);
1600 gvs_variant_unpack_all (GVariantTypeInfo *type_info,
1601 const guchar *end_pointer,
1604 GArray *unpacked_children)
1606 GVariantUnpacked unpacked;
1608 if ((unpacked.type_info = gvs_variant_find_type (end_pointer, end_size, total_size, &unpacked.size)))
1612 g_array_append_val (unpacked_children, unpacked);
1621 gvs_variant_needed_size (GVariantTypeInfo *type_info,
1622 GVariantSerialisedFiller gvs_filler,
1623 const gpointer *children,
1626 GVariantSerialised child = { 0, };
1627 const gchar *type_string;
1629 gvs_filler (&child, children[0]);
1630 type_string = g_variant_type_info_get_type_string (child.type_info);
1632 return child.size + 1 + strlen (type_string);
1636 gvs_variant_serialise (GVariantSerialised value,
1637 GVariantSerialisedFiller gvs_filler,
1638 const gpointer *children,
1641 GVariantSerialised child = { 0, };
1642 const gchar *type_string;
1644 child.data = value.data;
1646 gvs_filler (&child, children[0]);
1647 type_string = g_variant_type_info_get_type_string (child.type_info);
1648 value.data[child.size] = '\0';
1649 memcpy (value.data + child.size + 1, type_string, strlen (type_string));
1653 gvs_variant_write_to_vectors (GVariantVectors *vectors,
1654 GVariantTypeInfo *type_info,
1656 const gpointer *children,
1659 GVariantTypeInfo *child_type_info;
1660 const gchar *type_string;
1662 g_variant_callback_write_to_vectors (vectors, children[0], &child_type_info);
1663 type_string = g_variant_type_info_get_type_string (child_type_info);
1665 g_variant_vectors_append_copy (vectors, "", 1);
1666 g_variant_vectors_append_copy (vectors, type_string, strlen (type_string));
1669 static inline gboolean
1670 gvs_variant_is_normal (GVariantSerialised value)
1672 GVariantSerialised child;
1675 child = gvs_variant_get_child (value, 0);
1677 normal = (child.data != NULL || child.size == 0) &&
1678 g_variant_serialised_is_normal (child);
1680 g_variant_type_info_unref (child.type_info);
1687 /* PART 2: Serialiser API {{{1
1689 * This is the implementation of the API of the serialiser as advertised
1690 * in gvariant-serialiser.h.
1693 /* Dispatch Utilities {{{2
1695 * These macros allow a given function (for example,
1696 * g_variant_serialiser_serialise) to be dispatched to the appropriate
1697 * type-specific function above (fixed/variable-sized maybe,
1698 * fixed/variable-sized array, tuple or variant).
1700 #define DISPATCH_FIXED(type_info, before, after) \
1704 g_variant_type_info_query_element (type_info, NULL, \
1709 before ## fixed_sized ## after \
1713 before ## variable_sized ## after \
1717 #define DISPATCH_CASES(type_info, before, after) \
1718 switch (g_variant_type_info_get_type_char (type_info)) \
1720 case G_VARIANT_TYPE_INFO_CHAR_MAYBE: \
1721 DISPATCH_FIXED (type_info, before, _maybe ## after) \
1723 case G_VARIANT_TYPE_INFO_CHAR_ARRAY: \
1724 DISPATCH_FIXED (type_info, before, _array ## after) \
1726 case G_VARIANT_TYPE_INFO_CHAR_DICT_ENTRY: \
1727 case G_VARIANT_TYPE_INFO_CHAR_TUPLE: \
1729 before ## tuple ## after \
1732 case G_VARIANT_TYPE_INFO_CHAR_VARIANT: \
1734 before ## variant ## after \
1738 /* Serialiser entry points {{{2
1740 * These are the functions that are called in order for the serialiser
1745 * g_variant_serialised_n_children:
1746 * @serialised: a #GVariantSerialised
1748 * For serialised data that represents a container value (maybes,
1749 * tuples, arrays, variants), determine how many child items are inside
1752 * Returns: the number of children
1755 g_variant_serialised_n_children (GVariantSerialised serialised)
1757 g_variant_serialised_check (serialised);
1759 DISPATCH_CASES (serialised.type_info,
1761 return gvs_/**/,/**/_n_children (serialised);
1764 g_assert_not_reached ();
1768 * g_variant_serialised_get_child:
1769 * @serialised: a #GVariantSerialised
1770 * @index_: the index of the child to fetch
1772 * Extracts a child from a serialised data representing a container
1775 * It is an error to call this function with an index out of bounds.
1777 * If the result .data == %NULL and .size > 0 then there has been an
1778 * error extracting the requested fixed-sized value. This number of
1779 * zero bytes needs to be allocated instead.
1781 * In the case that .data == %NULL and .size == 0 then a zero-sized
1782 * item of a variable-sized type is being returned.
1784 * .data is never non-%NULL if size is 0.
1786 * Returns: a #GVariantSerialised for the child
1789 g_variant_serialised_get_child (GVariantSerialised serialised,
1792 GVariantSerialised child;
1794 g_variant_serialised_check (serialised);
1796 if G_LIKELY (index_ < g_variant_serialised_n_children (serialised))
1798 DISPATCH_CASES (serialised.type_info,
1800 child = gvs_/**/,/**/_get_child (serialised, index_);
1801 g_assert (child.size || child.data == NULL);
1802 g_variant_serialised_check (child);
1806 g_assert_not_reached ();
1809 g_error ("Attempt to access item %"G_GSIZE_FORMAT
1810 " in a container with only %"G_GSIZE_FORMAT" items",
1811 index_, g_variant_serialised_n_children (serialised));
1815 * g_variant_serialiser_serialise:
1816 * @serialised: a #GVariantSerialised, properly set up
1817 * @gvs_filler: the filler function
1818 * @children: an array of child items
1819 * @n_children: the size of @children
1821 * Writes data in serialised form.
1823 * The type_info field of @serialised must be filled in to type info for
1824 * the type that we are serialising.
1826 * The size field of @serialised must be filled in with the value
1827 * returned by a previous call to g_variant_serialiser_needed_size().
1829 * The data field of @serialised must be a pointer to a properly-aligned
1830 * memory region large enough to serialise into (ie: at least as big as
1833 * This function is only resonsible for serialising the top-level
1834 * container. @gvs_filler is called on each child of the container in
1835 * order for all of the data of that child to be filled in.
1838 g_variant_serialiser_serialise (GVariantSerialised serialised,
1839 GVariantSerialisedFiller gvs_filler,
1840 const gpointer *children,
1843 g_variant_serialised_check (serialised);
1845 DISPATCH_CASES (serialised.type_info,
1847 gvs_/**/,/**/_serialise (serialised, gvs_filler,
1848 children, n_children);
1852 g_assert_not_reached ();
1856 * g_variant_serialiser_needed_size:
1857 * @type_info: the type to serialise for
1858 * @gvs_filler: the filler function
1859 * @children: an array of child items
1860 * @n_children: the size of @children
1862 * Determines how much memory would be needed to serialise this value.
1864 * This function is only resonsible for performing calculations for the
1865 * top-level container. @gvs_filler is called on each child of the
1866 * container in order to determine its size.
1869 g_variant_serialiser_needed_size (GVariantTypeInfo *type_info,
1870 GVariantSerialisedFiller gvs_filler,
1871 const gpointer *children,
1874 DISPATCH_CASES (type_info,
1876 return gvs_/**/,/**/_needed_size (type_info, gvs_filler,
1877 children, n_children);
1879 g_assert_not_reached ();
1883 g_variant_serialiser_unpack_all (GVariantTypeInfo *type_info,
1884 const guchar *end_pointer,
1887 GArray *unpacked_children)
1889 DISPATCH_CASES (type_info,
1890 return gvs_/**/,/**/_unpack_all (type_info, end_pointer, end_size, total_size, unpacked_children);
1893 /* We are here because type_info is not a container type */
1898 g_variant_serialiser_write_to_vectors (GVariantVectors *vectors,
1899 GVariantTypeInfo *type_info,
1901 const gpointer *children,
1904 DISPATCH_CASES (type_info,
1905 gvs_/**/,/**/_write_to_vectors (vectors, type_info, size, children, n_children);
1908 g_assert_not_reached ();
1911 /* Byteswapping {{{2 */
1914 * g_variant_serialised_byteswap:
1915 * @value: a #GVariantSerialised
1917 * Byte-swap serialised data. The result of this function is only
1918 * well-defined if the data is in normal form.
1921 g_variant_serialised_byteswap (GVariantSerialised serialised)
1926 g_variant_serialised_check (serialised);
1928 if (!serialised.data)
1931 /* the types we potentially need to byteswap are
1932 * exactly those with alignment requirements.
1934 g_variant_type_info_query (serialised.type_info, &alignment, &fixed_size);
1938 /* if fixed size and alignment are equal then we are down
1939 * to the base integer type and we should swap it. the
1940 * only exception to this is if we have a tuple with a
1941 * single item, and then swapping it will be OK anyway.
1943 if (alignment + 1 == fixed_size)
1949 guint16 *ptr = (guint16 *) serialised.data;
1951 g_assert_cmpint (serialised.size, ==, 2);
1952 *ptr = GUINT16_SWAP_LE_BE (*ptr);
1958 guint32 *ptr = (guint32 *) serialised.data;
1960 g_assert_cmpint (serialised.size, ==, 4);
1961 *ptr = GUINT32_SWAP_LE_BE (*ptr);
1967 guint64 *ptr = (guint64 *) serialised.data;
1969 g_assert_cmpint (serialised.size, ==, 8);
1970 *ptr = GUINT64_SWAP_LE_BE (*ptr);
1975 g_assert_not_reached ();
1979 /* else, we have a container that potentially contains
1980 * some children that need to be byteswapped.
1986 children = g_variant_serialised_n_children (serialised);
1987 for (i = 0; i < children; i++)
1989 GVariantSerialised child;
1991 child = g_variant_serialised_get_child (serialised, i);
1992 g_variant_serialised_byteswap (child);
1993 g_variant_type_info_unref (child.type_info);
1998 /* Normal form checking {{{2 */
2001 * g_variant_serialised_is_normal:
2002 * @serialised: a #GVariantSerialised
2004 * Determines, recursively if @serialised is in normal form. There is
2005 * precisely one normal form of serialised data for each possible value.
2007 * It is possible that multiple byte sequences form the serialised data
2008 * for a given value if, for example, the padding bytes are filled in
2009 * with something other than zeros, but only one form is the normal
2013 g_variant_serialised_is_normal (GVariantSerialised serialised)
2015 DISPATCH_CASES (serialised.type_info,
2017 return gvs_/**/,/**/_is_normal (serialised);
2021 if (serialised.data == NULL)
2024 /* some hard-coded terminal cases */
2025 switch (g_variant_type_info_get_type_char (serialised.type_info))
2027 case 'b': /* boolean */
2028 return serialised.data[0] < 2;
2030 case 's': /* string */
2031 return g_variant_serialiser_is_string (serialised.data,
2035 return g_variant_serialiser_is_object_path (serialised.data,
2039 return g_variant_serialiser_is_signature (serialised.data,
2043 /* all of the other types are fixed-sized numerical types for
2044 * which all possible values are valid (including various NaN
2045 * representations for floating point values).
2051 /* Validity-checking functions {{{2
2053 * Checks if strings, object paths and signature strings are valid.
2057 * g_variant_serialiser_is_string:
2058 * @data: a possible string
2059 * @size: the size of @data
2061 * Ensures that @data is a valid string with a nul terminator at the end
2062 * and no nul bytes embedded.
2065 g_variant_serialiser_is_string (gconstpointer data,
2068 const gchar *expected_end;
2074 expected_end = ((gchar *) data) + size - 1;
2076 if (*expected_end != '\0')
2079 g_utf8_validate (data, size, &end);
2081 return end == expected_end;
2085 * g_variant_serialiser_is_object_path:
2086 * @data: a possible D-Bus object path
2087 * @size: the size of @data
2089 * Performs the checks for being a valid string.
2091 * Also, ensures that @data is a valid DBus object path, as per the D-Bus
2095 g_variant_serialiser_is_object_path (gconstpointer data,
2098 const gchar *string = data;
2101 if (!g_variant_serialiser_is_string (data, size))
2104 /* The path must begin with an ASCII '/' (integer 47) character */
2105 if (string[0] != '/')
2108 for (i = 1; string[i]; i++)
2109 /* Each element must only contain the ASCII characters
2110 * "[A-Z][a-z][0-9]_"
2112 if (g_ascii_isalnum (string[i]) || string[i] == '_')
2115 /* must consist of elements separated by slash characters. */
2116 else if (string[i] == '/')
2118 /* No element may be the empty string. */
2119 /* Multiple '/' characters cannot occur in sequence. */
2120 if (string[i - 1] == '/')
2127 /* A trailing '/' character is not allowed unless the path is the
2128 * root path (a single '/' character).
2130 if (i > 1 && string[i - 1] == '/')
2137 * g_variant_serialiser_is_signature:
2138 * @data: a possible D-Bus signature
2139 * @size: the size of @data
2141 * Performs the checks for being a valid string.
2143 * Also, ensures that @data is a valid D-Bus type signature, as per the
2144 * D-Bus specification.
2147 g_variant_serialiser_is_signature (gconstpointer data,
2150 const gchar *string = data;
2151 gsize first_invalid;
2153 if (!g_variant_serialiser_is_string (data, size))
2156 /* make sure no non-definite characters appear */
2157 first_invalid = strspn (string, "ybnqiuxthdvasog(){}");
2158 if (string[first_invalid])
2161 /* make sure each type string is well-formed */
2163 if (!g_variant_type_string_scan (string, NULL, &string))
2170 /* vim:set foldmethod=marker: */