GVariant: support serialising to GVariantVectors
[platform/upstream/glib.git] / glib / gvariant-serialiser.c
1 /*
2  * Copyright © 2007, 2008 Ryan Lortie
3  * Copyright © 2010 Codethink Limited
4  *
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.
9  *
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.
14  *
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/>.
17  *
18  * Author: Ryan Lortie <desrt@desrt.ca>
19  */
20
21 /* Prologue {{{1 */
22 #include "config.h"
23
24 #include "gvariant-serialiser.h"
25
26 #include <glib/gtestutils.h>
27 #include <glib/gstrfuncs.h>
28 #include <glib/gtypes.h>
29
30 #include <string.h>
31
32
33 /* GVariantSerialiser
34  *
35  * After this prologue section, this file has roughly 2 parts.
36  *
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.
41  *
42  * Each section documents the format of that particular type of
43  * container and implements 5 functions for dealing with it:
44  *
45  *  n_children:
46  *    - determines (according to serialised data) how many child values
47  *      are inside a particular container value.
48  *
49  *  get_child:
50  *    - gets the type of and the serialised data corresponding to a
51  *      given child value within the container value.
52  *
53  *  needed_size:
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.
57  *
58  *  serialise:
59  *    - write the serialised data for a container of this type,
60  *      containing the given children, to a buffer.
61  *
62  *  is_normal:
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
68  *      the normal form.
69  *
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.
73  *
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.
78  *
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).
85  */
86
87 /* < private >
88  * GVariantSerialised:
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
92  *
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.
97  *
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.
101  *
102  * @type_info must be non-%NULL.
103  *
104  * @data must be properly aligned for the type described by @type_info.
105  *
106  * If @type_info describes a fixed-sized type then @size must always be
107  * equal to the fixed size of that type.
108  *
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.
116  */
117
118 /* < private >
119  * g_variant_serialised_check:
120  * @serialised: a #GVariantSerialised struct
121  *
122  * Checks @serialised for validity according to the invariants described
123  * above.
124  */
125 static void
126 g_variant_serialised_check (GVariantSerialised serialised)
127 {
128   gsize fixed_size;
129   guint alignment;
130
131   g_assert (serialised.type_info != NULL);
132   g_variant_type_info_query (serialised.type_info, &alignment, &fixed_size);
133
134   if (fixed_size)
135     g_assert_cmpint (serialised.size, ==, fixed_size);
136   else
137     g_assert (serialised.size == 0 || serialised.data != NULL);
138
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
145    * care about 3 bits.
146    */
147   alignment &= sizeof (struct {
148                          char a;
149                          union {
150                            guint64 x;
151                            void *y;
152                            gdouble z;
153                          } b;
154                        }
155                       ) - 9;
156
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.
160    *
161    * Check if this is a small allocation and return without enforcing
162    * the alignment assertion if this is the case.
163    */
164   if (serialised.size <= alignment)
165     return;
166
167   g_assert_cmpint (alignment & (gsize) serialised.data, ==, 0);
168 }
169
170 /* < private >
171  * GVariantSerialisedFiller:
172  * @serialised: a #GVariantSerialised instance to fill
173  * @data: data from the children array
174  *
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.
178  *
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.
184  *
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
189  * of the child.
190  *
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.
195  *
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
199  * @data.
200  *
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.
205  */
206
207 /* PART 1: Container types {{{1
208  *
209  * This section contains the serialiser implementation functions for
210  * each container type.
211  */
212
213 /* Maybe {{{2
214  *
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".
221  */
222
223 /* Fixed-sized Maybe {{{3
224  *
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.
232  *
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".
236  */
237
238 static gsize
239 gvs_fixed_sized_maybe_n_children (GVariantSerialised value)
240 {
241   gsize element_fixed_size;
242
243   g_variant_type_info_query_element (value.type_info, NULL,
244                                      &element_fixed_size);
245
246   return (element_fixed_size == value.size) ? 1 : 0;
247 }
248
249 static GVariantSerialised
250 gvs_fixed_sized_maybe_get_child (GVariantSerialised value,
251                                  gsize              index_)
252 {
253   /* the child has the same bounds as the
254    * container, so just update the type.
255    */
256   value.type_info = g_variant_type_info_element (value.type_info);
257   g_variant_type_info_ref (value.type_info);
258
259   return value;
260 }
261
262 static gsize
263 gvs_fixed_sized_maybe_needed_size (GVariantTypeInfo         *type_info,
264                                    GVariantSerialisedFiller  gvs_filler,
265                                    const gpointer           *children,
266                                    gsize                     n_children)
267 {
268   if (n_children)
269     {
270       gsize element_fixed_size;
271
272       g_variant_type_info_query_element (type_info, NULL,
273                                          &element_fixed_size);
274
275       return element_fixed_size;
276     }
277   else
278     return 0;
279 }
280
281 static void
282 gvs_fixed_sized_maybe_serialise (GVariantSerialised        value,
283                                  GVariantSerialisedFiller  gvs_filler,
284                                  const gpointer           *children,
285                                  gsize                     n_children)
286 {
287   if (n_children)
288     {
289       GVariantSerialised child = { NULL, value.data, value.size };
290
291       gvs_filler (&child, children[0]);
292     }
293 }
294
295 static gsize
296 gvs_fixed_sized_maybe_write_to_vectors (GVariantVectors  *vectors,
297                                         GVariantTypeInfo *type_info,
298                                         gsize             size,
299                                         const gpointer   *children,
300                                         gsize             n_children)
301 {
302   if (!n_children)
303     return 0;
304
305   return g_variant_callback_write_to_vectors (vectors, children[0], NULL);
306 }
307
308 static gboolean
309 gvs_fixed_sized_maybe_is_normal (GVariantSerialised value)
310 {
311   if (value.size > 0)
312     {
313       gsize element_fixed_size;
314
315       g_variant_type_info_query_element (value.type_info,
316                                          NULL, &element_fixed_size);
317
318       if (value.size != element_fixed_size)
319         return FALSE;
320
321       /* proper element size: "Just".  recurse to the child. */
322       value.type_info = g_variant_type_info_element (value.type_info);
323
324       return g_variant_serialised_is_normal (value);
325     }
326
327   /* size of 0: "Nothing" */
328   return TRUE;
329 }
330
331 /* Variable-sized Maybe
332  *
333  * The size of a maybe value with a variable-sized element type is
334  * either 0 or strictly greater than 0.  The case where the size of the
335  * maybe value is zero corresponds to the "Nothing" case and the case
336  * where the size of the maybe value is greater than zero corresponds to
337  * the "Just" case; in that case, the serialised data of the child value
338  * forms the first part of the serialised data of the maybe value and is
339  * followed by a single zero byte.  This zero byte is always appended,
340  * regardless of any zero bytes that may already be at the end of the
341  * serialised ata of the child value.
342  */
343
344 static gsize
345 gvs_variable_sized_maybe_n_children (GVariantSerialised value)
346 {
347   return (value.size > 0) ? 1 : 0;
348 }
349
350 static GVariantSerialised
351 gvs_variable_sized_maybe_get_child (GVariantSerialised value,
352                                     gsize              index_)
353 {
354   /* remove the padding byte and update the type. */
355   value.type_info = g_variant_type_info_element (value.type_info);
356   g_variant_type_info_ref (value.type_info);
357   value.size--;
358
359   /* if it's zero-sized then it may as well be NULL */
360   if (value.size == 0)
361     value.data = NULL;
362
363   return value;
364 }
365
366 static gsize
367 gvs_variable_sized_maybe_needed_size (GVariantTypeInfo         *type_info,
368                                       GVariantSerialisedFiller  gvs_filler,
369                                       const gpointer           *children,
370                                       gsize                     n_children)
371 {
372   if (n_children)
373     {
374       GVariantSerialised child = { 0, };
375
376       gvs_filler (&child, children[0]);
377
378       return child.size + 1;
379     }
380   else
381     return 0;
382 }
383
384 static void
385 gvs_variable_sized_maybe_serialise (GVariantSerialised        value,
386                                     GVariantSerialisedFiller  gvs_filler,
387                                     const gpointer           *children,
388                                     gsize                     n_children)
389 {
390   if (n_children)
391     {
392       GVariantSerialised child = { NULL, value.data, value.size - 1 };
393
394       /* write the data for the child.  */
395       gvs_filler (&child, children[0]);
396       value.data[child.size] = '\0';
397     }
398 }
399
400 static void
401 gvs_variable_sized_maybe_write_to_vectors (GVariantVectors  *vectors,
402                                            GVariantTypeInfo *type_info,
403                                            gsize             size,
404                                            const gpointer   *children,
405                                            gsize             n_children)
406 {
407   if (n_children)
408     {
409       g_variant_callback_write_to_vectors (vectors, children[0], NULL);
410       g_variant_vectors_append_copy (vectors, "", 1);
411     }
412 }
413
414 static gboolean
415 gvs_variable_sized_maybe_is_normal (GVariantSerialised value)
416 {
417   if (value.size == 0)
418     return TRUE;
419
420   if (value.data[value.size - 1] != '\0')
421     return FALSE;
422
423   value.type_info = g_variant_type_info_element (value.type_info);
424   value.size--;
425
426   return g_variant_serialised_is_normal (value);
427 }
428
429 /* Arrays {{{2
430  *
431  * Just as with maybe types, array types are handled depending on if the
432  * element type of the array type is a fixed-sized or variable-sized
433  * type.  Similar to maybe types, for convenience, an array value with a
434  * fixed-sized element type is called a "fixed-sized array" and an array
435  * value with a variable-sized element type is called a "variable sized
436  * array".
437  */
438
439 /* Fixed-sized Array {{{3
440  *
441  * For fixed sized arrays, the serialised data is simply a concatenation
442  * of the serialised data of each element, in order.  Since fixed-sized
443  * values always have a fixed size that is a multiple of their alignment
444  * requirement no extra padding is required.
445  *
446  * In the event that a fixed-sized array is presented with a size that
447  * is not an integer multiple of the element size then the value of the
448  * array must be taken as being empty.
449  */
450
451 static gsize
452 gvs_fixed_sized_array_n_children (GVariantSerialised value)
453 {
454   gsize element_fixed_size;
455
456   g_variant_type_info_query_element (value.type_info, NULL,
457                                      &element_fixed_size);
458
459   if (value.size % element_fixed_size == 0)
460     return value.size / element_fixed_size;
461
462   return 0;
463 }
464
465 static GVariantSerialised
466 gvs_fixed_sized_array_get_child (GVariantSerialised value,
467                                  gsize              index_)
468 {
469   GVariantSerialised child = { 0, };
470
471   child.type_info = g_variant_type_info_element (value.type_info);
472   g_variant_type_info_query (child.type_info, NULL, &child.size);
473   child.data = value.data + (child.size * index_);
474   g_variant_type_info_ref (child.type_info);
475
476   return child;
477 }
478
479 static gsize
480 gvs_fixed_sized_array_needed_size (GVariantTypeInfo         *type_info,
481                                    GVariantSerialisedFiller  gvs_filler,
482                                    const gpointer           *children,
483                                    gsize                     n_children)
484 {
485   gsize element_fixed_size;
486
487   g_variant_type_info_query_element (type_info, NULL, &element_fixed_size);
488
489   return element_fixed_size * n_children;
490 }
491
492 static void
493 gvs_fixed_sized_array_serialise (GVariantSerialised        value,
494                                  GVariantSerialisedFiller  gvs_filler,
495                                  const gpointer           *children,
496                                  gsize                     n_children)
497 {
498   GVariantSerialised child = { 0, };
499   gsize i;
500
501   child.type_info = g_variant_type_info_element (value.type_info);
502   g_variant_type_info_query (child.type_info, NULL, &child.size);
503   child.data = value.data;
504
505   for (i = 0; i < n_children; i++)
506     {
507       gvs_filler (&child, children[i]);
508       child.data += child.size;
509     }
510 }
511
512 static void
513 gvs_fixed_sized_array_write_to_vectors (GVariantVectors  *vectors,
514                                         GVariantTypeInfo *type_info,
515                                         gsize             size,
516                                         const gpointer   *children,
517                                         gsize             n_children)
518 {
519   gsize i;
520
521   for (i = 0; i < n_children; i++)
522     g_variant_callback_write_to_vectors (vectors, children[i], NULL);
523 }
524
525 static gboolean
526 gvs_fixed_sized_array_is_normal (GVariantSerialised value)
527 {
528   GVariantSerialised child = { 0, };
529
530   child.type_info = g_variant_type_info_element (value.type_info);
531   g_variant_type_info_query (child.type_info, NULL, &child.size);
532
533   if (value.size % child.size != 0)
534     return FALSE;
535
536   for (child.data = value.data;
537        child.data < value.data + value.size;
538        child.data += child.size)
539     {
540       if (!g_variant_serialised_is_normal (child))
541         return FALSE;
542     }
543
544   return TRUE;
545 }
546
547 /* Variable-sized Array {{{3
548  *
549  * Variable sized arrays, containing variable-sized elements, must be
550  * able to determine the boundaries between the elements.  The items
551  * cannot simply be concatenated.  Additionally, we are faced with the
552  * fact that non-fixed-sized values do not necessarily have a size that
553  * is a multiple of their alignment requirement, so we may need to
554  * insert zero-filled padding.
555  *
556  * While it is possible to find the start of an item by starting from
557  * the end of the item before it and padding for alignment, it is not
558  * generally possible to do the reverse operation.  For this reason, we
559  * record the end point of each element in the array.
560  *
561  * GVariant works in terms of "offsets".  An offset is a pointer to a
562  * boundary between two bytes.  In 4 bytes of serialised data, there
563  * would be 5 possible offsets: one at the start ('0'), one between each
564  * pair of adjacent bytes ('1', '2', '3') and one at the end ('4').
565  *
566  * The numeric value of an offset is an unsigned integer given relative
567  * to the start of the serialised data of the array.  Offsets are always
568  * stored in little endian byte order and are always only as big as they
569  * need to be.  For example, in 255 bytes of serialised data, there are
570  * 256 offsets.  All possibilities can be stored in an 8 bit unsigned
571  * integer.  In 256 bytes of serialised data, however, there are 257
572  * possible offsets so 16 bit integers must be used.  The size of an
573  * offset is always a power of 2.
574  *
575  * The offsets are stored at the end of the serialised data of the
576  * array.  They are simply concatenated on without any particular
577  * alignment.  The size of the offsets is included in the size of the
578  * serialised data for purposes of determining the size of the offsets.
579  * This presents a possibly ambiguity; in certain cases, a particular
580  * value of array could have two different serialised forms.
581  *
582  * Imagine an array containing a single string of 253 bytes in length
583  * (so, 254 bytes including the nul terminator).  Now the offset must be
584  * written.  If an 8 bit offset is written, it will bring the size of
585  * the array's serialised data to 255 -- which means that the use of an
586  * 8 bit offset was valid.  If a 16 bit offset is used then the total
587  * size of the array will be 256 -- which means that the use of a 16 bit
588  * offset was valid.  Although both of these will be accepted by the
589  * deserialiser, only the smaller of the two is considered to be in
590  * normal form and that is the one that the serialiser must produce.
591  */
592
593 /* bytes may be NULL if (size == 0). */
594 static inline gsize
595 gvs_read_unaligned_le (guchar *bytes,
596                        guint   size)
597 {
598   union
599   {
600     guchar bytes[GLIB_SIZEOF_SIZE_T];
601     gsize integer;
602   } tmpvalue;
603
604   tmpvalue.integer = 0;
605   if (bytes != NULL)
606     memcpy (&tmpvalue.bytes, bytes, size);
607
608   return GSIZE_FROM_LE (tmpvalue.integer);
609 }
610
611 static inline void
612 gvs_write_unaligned_le (guchar *bytes,
613                         gsize   value,
614                         guint   size)
615 {
616   union
617   {
618     guchar bytes[GLIB_SIZEOF_SIZE_T];
619     gsize integer;
620   } tmpvalue;
621
622   tmpvalue.integer = GSIZE_TO_LE (value);
623   memcpy (bytes, &tmpvalue.bytes, size);
624 }
625
626 static guint
627 gvs_get_offset_size (gsize size)
628 {
629   if (size > G_MAXUINT32)
630     return 8;
631
632   else if (size > G_MAXUINT16)
633     return 4;
634
635   else if (size > G_MAXUINT8)
636     return 2;
637
638   else if (size > 0)
639     return 1;
640
641   return 0;
642 }
643
644 static gsize
645 gvs_calculate_total_size (gsize body_size,
646                           gsize offsets)
647 {
648   if (body_size + 1 * offsets <= G_MAXUINT8)
649     return body_size + 1 * offsets;
650
651   if (body_size + 2 * offsets <= G_MAXUINT16)
652     return body_size + 2 * offsets;
653
654   if (body_size + 4 * offsets <= G_MAXUINT32)
655     return body_size + 4 * offsets;
656
657   return body_size + 8 * offsets;
658 }
659
660 static gsize
661 gvs_variable_sized_array_n_children (GVariantSerialised value)
662 {
663   gsize offsets_array_size;
664   gsize offset_size;
665   gsize last_end;
666
667   if (value.size == 0)
668     return 0;
669
670   offset_size = gvs_get_offset_size (value.size);
671
672   last_end = gvs_read_unaligned_le (value.data + value.size -
673                                     offset_size, offset_size);
674
675   if (last_end > value.size)
676     return 0;
677
678   offsets_array_size = value.size - last_end;
679
680   if (offsets_array_size % offset_size)
681     return 0;
682
683   return offsets_array_size / offset_size;
684 }
685
686 static GVariantSerialised
687 gvs_variable_sized_array_get_child (GVariantSerialised value,
688                                     gsize              index_)
689 {
690   GVariantSerialised child = { 0, };
691   gsize offset_size;
692   gsize last_end;
693   gsize start;
694   gsize end;
695
696   child.type_info = g_variant_type_info_element (value.type_info);
697   g_variant_type_info_ref (child.type_info);
698
699   offset_size = gvs_get_offset_size (value.size);
700
701   last_end = gvs_read_unaligned_le (value.data + value.size -
702                                     offset_size, offset_size);
703
704   if (index_ > 0)
705     {
706       guint alignment;
707
708       start = gvs_read_unaligned_le (value.data + last_end +
709                                      (offset_size * (index_ - 1)),
710                                      offset_size);
711
712       g_variant_type_info_query (child.type_info, &alignment, NULL);
713       start += (-start) & alignment;
714     }
715   else
716     start = 0;
717
718   end = gvs_read_unaligned_le (value.data + last_end +
719                                (offset_size * index_),
720                                offset_size);
721
722   if (start < end && end <= value.size)
723     {
724       child.data = value.data + start;
725       child.size = end - start;
726     }
727
728   return child;
729 }
730
731 static gsize
732 gvs_variable_sized_array_needed_size (GVariantTypeInfo         *type_info,
733                                       GVariantSerialisedFiller  gvs_filler,
734                                       const gpointer           *children,
735                                       gsize                     n_children)
736 {
737   guint alignment;
738   gsize offset;
739   gsize i;
740
741   g_variant_type_info_query (type_info, &alignment, NULL);
742   offset = 0;
743
744   for (i = 0; i < n_children; i++)
745     {
746       GVariantSerialised child = { 0, };
747
748       offset += (-offset) & alignment;
749       gvs_filler (&child, children[i]);
750       offset += child.size;
751     }
752
753   return gvs_calculate_total_size (offset, n_children);
754 }
755
756 static void
757 gvs_variable_sized_array_serialise (GVariantSerialised        value,
758                                     GVariantSerialisedFiller  gvs_filler,
759                                     const gpointer           *children,
760                                     gsize                     n_children)
761 {
762   guchar *offset_ptr;
763   gsize offset_size;
764   guint alignment;
765   gsize offset;
766   gsize i;
767
768   g_variant_type_info_query (value.type_info, &alignment, NULL);
769   offset_size = gvs_get_offset_size (value.size);
770   offset = 0;
771
772   offset_ptr = value.data + value.size - offset_size * n_children;
773
774   for (i = 0; i < n_children; i++)
775     {
776       GVariantSerialised child = { 0, };
777
778       while (offset & alignment)
779         value.data[offset++] = '\0';
780
781       child.data = value.data + offset;
782       gvs_filler (&child, children[i]);
783       offset += child.size;
784
785       gvs_write_unaligned_le (offset_ptr, offset, offset_size);
786       offset_ptr += offset_size;
787     }
788 }
789
790 static void
791 gvs_variable_sized_array_write_to_vectors (GVariantVectors  *vectors,
792                                            GVariantTypeInfo *type_info,
793                                            gsize             size,
794                                            const gpointer   *children,
795                                            gsize             n_children)
796 {
797   guint offset_key;
798   guint alignment;
799   gsize offset;
800   gsize i;
801
802   if (n_children == 0)
803     return;
804
805   offset_key = g_variant_vectors_reserve_offsets (vectors, n_children, gvs_get_offset_size (size));
806   g_variant_type_info_query (type_info, &alignment, NULL);
807   offset = 0;
808
809   for (i = 0; i < n_children; i++)
810     {
811       if ((-offset) & alignment)
812         offset += g_variant_vectors_append_pad (vectors, (-offset) & alignment);
813
814       offset += g_variant_callback_write_to_vectors (vectors, children[i], NULL);
815
816       g_variant_vectors_write_to_offsets (vectors, i, offset, offset_key);
817     }
818
819   g_variant_vectors_commit_offsets (vectors, offset_key);
820 }
821
822 static gboolean
823 gvs_variable_sized_array_is_normal (GVariantSerialised value)
824 {
825   GVariantSerialised child = { 0, };
826   gsize offsets_array_size;
827   guchar *offsets_array;
828   guint offset_size;
829   guint alignment;
830   gsize last_end;
831   gsize length;
832   gsize offset;
833   gsize i;
834
835   if (value.size == 0)
836     return TRUE;
837
838   offset_size = gvs_get_offset_size (value.size);
839   last_end = gvs_read_unaligned_le (value.data + value.size -
840                                     offset_size, offset_size);
841
842   if (last_end > value.size)
843     return FALSE;
844
845   offsets_array_size = value.size - last_end;
846
847   if (offsets_array_size % offset_size)
848     return FALSE;
849
850   offsets_array = value.data + value.size - offsets_array_size;
851   length = offsets_array_size / offset_size;
852
853   if (length == 0)
854     return FALSE;
855
856   child.type_info = g_variant_type_info_element (value.type_info);
857   g_variant_type_info_query (child.type_info, &alignment, NULL);
858   offset = 0;
859
860   for (i = 0; i < length; i++)
861     {
862       gsize this_end;
863
864       this_end = gvs_read_unaligned_le (offsets_array + offset_size * i,
865                                         offset_size);
866
867       if (this_end < offset || this_end > last_end)
868         return FALSE;
869
870       while (offset & alignment)
871         {
872           if (!(offset < this_end && value.data[offset] == '\0'))
873             return FALSE;
874           offset++;
875         }
876
877       child.data = value.data + offset;
878       child.size = this_end - offset;
879
880       if (child.size == 0)
881         child.data = NULL;
882
883       if (!g_variant_serialised_is_normal (child))
884         return FALSE;
885
886       offset = this_end;
887     }
888
889   g_assert (offset == last_end);
890
891   return TRUE;
892 }
893
894 /* Tuples {{{2
895  *
896  * Since tuples can contain a mix of variable- and fixed-sized items,
897  * they are, in terms of serialisation, a hybrid of variable-sized and
898  * fixed-sized arrays.
899  *
900  * Offsets are only stored for variable-sized items.  Also, since the
901  * number of items in a tuple is known from its type, we are able to
902  * know exactly how many offsets to expect in the serialised data (and
903  * therefore how much space is taken up by the offset array).  This
904  * means that we know where the end of the serialised data for the last
905  * item is -- we can just subtract the size of the offset array from the
906  * total size of the tuple.  For this reason, the last item in the tuple
907  * doesn't need an offset stored.
908  *
909  * Tuple offsets are stored in reverse.  This design choice allows
910  * iterator-based deserialisers to be more efficient.
911  *
912  * Most of the "heavy lifting" here is handled by the GVariantTypeInfo
913  * for the tuple.  See the notes in gvarianttypeinfo.h.
914  */
915
916 static gsize
917 gvs_tuple_n_children (GVariantSerialised value)
918 {
919   return g_variant_type_info_n_members (value.type_info);
920 }
921
922 static GVariantSerialised
923 gvs_tuple_get_child (GVariantSerialised value,
924                      gsize              index_)
925 {
926   const GVariantMemberInfo *member_info;
927   GVariantSerialised child = { 0, };
928   gsize offset_size;
929   gsize start, end;
930
931   member_info = g_variant_type_info_member_info (value.type_info, index_);
932   child.type_info = g_variant_type_info_ref (member_info->type_info);
933   offset_size = gvs_get_offset_size (value.size);
934
935   /* tuples are the only (potentially) fixed-sized containers, so the
936    * only ones that have to deal with the possibility of having %NULL
937    * data with a non-zero %size if errors occurred elsewhere.
938    */
939   if G_UNLIKELY (value.data == NULL && value.size != 0)
940     {
941       g_variant_type_info_query (child.type_info, NULL, &child.size);
942
943       /* this can only happen in fixed-sized tuples,
944        * so the child must also be fixed sized.
945        */
946       g_assert (child.size != 0);
947       child.data = NULL;
948
949       return child;
950     }
951
952   if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_OFFSET)
953     {
954       if (offset_size * (member_info->i + 2) > value.size)
955         return child;
956     }
957   else
958     {
959       if (offset_size * (member_info->i + 1) > value.size)
960         {
961           /* if the child is fixed size, return its size.
962            * if child is not fixed-sized, return size = 0.
963            */
964           g_variant_type_info_query (child.type_info, NULL, &child.size);
965
966           return child;
967         }
968     }
969
970   if (member_info->i + 1)
971     start = gvs_read_unaligned_le (value.data + value.size -
972                                    offset_size * (member_info->i + 1),
973                                    offset_size);
974   else
975     start = 0;
976
977   start += member_info->a;
978   start &= member_info->b;
979   start |= member_info->c;
980
981   if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_LAST)
982     end = value.size - offset_size * (member_info->i + 1);
983
984   else if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_FIXED)
985     {
986       gsize fixed_size;
987
988       g_variant_type_info_query (child.type_info, NULL, &fixed_size);
989       end = start + fixed_size;
990       child.size = fixed_size;
991     }
992
993   else /* G_VARIANT_MEMBER_ENDING_OFFSET */
994     end = gvs_read_unaligned_le (value.data + value.size -
995                                  offset_size * (member_info->i + 2),
996                                  offset_size);
997
998   if (start < end && end <= value.size)
999     {
1000       child.data = value.data + start;
1001       child.size = end - start;
1002     }
1003
1004   return child;
1005 }
1006
1007 static gsize
1008 gvs_tuple_needed_size (GVariantTypeInfo         *type_info,
1009                        GVariantSerialisedFiller  gvs_filler,
1010                        const gpointer           *children,
1011                        gsize                     n_children)
1012 {
1013   const GVariantMemberInfo *member_info = NULL;
1014   gsize fixed_size;
1015   gsize offset;
1016   gsize i;
1017
1018   g_variant_type_info_query (type_info, NULL, &fixed_size);
1019
1020   if (fixed_size)
1021     return fixed_size;
1022
1023   offset = 0;
1024
1025   for (i = 0; i < n_children; i++)
1026     {
1027       guint alignment;
1028
1029       member_info = g_variant_type_info_member_info (type_info, i);
1030       g_variant_type_info_query (member_info->type_info,
1031                                  &alignment, &fixed_size);
1032       offset += (-offset) & alignment;
1033
1034       if (fixed_size)
1035         offset += fixed_size;
1036       else
1037         {
1038           GVariantSerialised child = { 0, };
1039
1040           gvs_filler (&child, children[i]);
1041           offset += child.size;
1042         }
1043     }
1044
1045   return gvs_calculate_total_size (offset, member_info->i + 1);
1046 }
1047
1048 static void
1049 gvs_tuple_serialise (GVariantSerialised        value,
1050                      GVariantSerialisedFiller  gvs_filler,
1051                      const gpointer           *children,
1052                      gsize                     n_children)
1053 {
1054   gsize offset_size;
1055   gsize offset;
1056   gsize i;
1057
1058   offset_size = gvs_get_offset_size (value.size);
1059   offset = 0;
1060
1061   for (i = 0; i < n_children; i++)
1062     {
1063       const GVariantMemberInfo *member_info;
1064       GVariantSerialised child = { 0, };
1065       guint alignment;
1066
1067       member_info = g_variant_type_info_member_info (value.type_info, i);
1068       g_variant_type_info_query (member_info->type_info, &alignment, NULL);
1069
1070       while (offset & alignment)
1071         value.data[offset++] = '\0';
1072
1073       child.data = value.data + offset;
1074       gvs_filler (&child, children[i]);
1075       offset += child.size;
1076
1077       if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_OFFSET)
1078         {
1079           value.size -= offset_size;
1080           gvs_write_unaligned_le (value.data + value.size,
1081                                   offset, offset_size);
1082         }
1083     }
1084
1085   while (offset < value.size)
1086     value.data[offset++] = '\0';
1087 }
1088
1089
1090 static void
1091 gvs_tuple_write_to_vectors (GVariantVectors  *vectors,
1092                             GVariantTypeInfo *type_info,
1093                             gsize             size,
1094                             const gpointer   *children,
1095                             gsize             n_children)
1096 {
1097   const GVariantMemberInfo *member_info = NULL;
1098   gsize fixed_size;
1099   gsize offset;
1100   gsize i;
1101
1102   if (n_children == 0)
1103     {
1104       g_variant_vectors_append_copy (vectors, "", 1);
1105       return;
1106     }
1107
1108   g_variant_type_info_query (type_info, NULL, &fixed_size);
1109   offset = 0;
1110
1111   if (!fixed_size)
1112     {
1113       gsize n_offsets;
1114
1115       member_info = g_variant_type_info_member_info (type_info, n_children - 1);
1116       n_offsets = member_info->i + 1;
1117
1118       if (n_offsets)
1119         {
1120           gsize offset_key = 0;
1121
1122           offset_key = g_variant_vectors_reserve_offsets (vectors, n_offsets, gvs_get_offset_size (size));
1123
1124           for (i = 0; i < n_children; i++)
1125             {
1126               guint alignment;
1127
1128               member_info = g_variant_type_info_member_info (type_info, i);
1129               g_variant_type_info_query (member_info->type_info, &alignment, NULL);
1130
1131               if ((-offset) & alignment)
1132                 offset += g_variant_vectors_append_pad (vectors, (-offset) & alignment);
1133
1134               offset += g_variant_callback_write_to_vectors (vectors, children[i], NULL);
1135
1136               if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_OFFSET)
1137                 g_variant_vectors_write_to_offsets (vectors, --n_offsets, offset, offset_key);
1138             }
1139
1140           g_variant_vectors_commit_offsets (vectors, offset_key);
1141         }
1142       else
1143         {
1144           for (i = 0; i < n_children; i++)
1145             {
1146               guint alignment;
1147
1148               member_info = g_variant_type_info_member_info (type_info, i);
1149               g_variant_type_info_query (member_info->type_info, &alignment, NULL);
1150
1151               if ((-offset) & alignment)
1152                 offset += g_variant_vectors_append_pad (vectors, (-offset) & alignment);
1153
1154               offset += g_variant_callback_write_to_vectors (vectors, children[i], NULL);
1155             }
1156         }
1157     }
1158   else
1159     {
1160       for (i = 0; i < n_children; i++)
1161         {
1162           guint alignment;
1163
1164           member_info = g_variant_type_info_member_info (type_info, i);
1165           g_variant_type_info_query (member_info->type_info, &alignment, NULL);
1166
1167           if ((-offset) & alignment)
1168             offset += g_variant_vectors_append_pad (vectors, (-offset) & alignment);
1169
1170           offset += g_variant_callback_write_to_vectors (vectors, children[i], NULL);
1171         }
1172
1173       g_assert (fixed_size - offset < 8);
1174       g_variant_vectors_append_pad (vectors, fixed_size - offset);
1175     }
1176 }
1177
1178 static gboolean
1179 gvs_tuple_is_normal (GVariantSerialised value)
1180 {
1181   guint offset_size;
1182   gsize offset_ptr;
1183   gsize length;
1184   gsize offset;
1185   gsize i;
1186
1187   /* as per the comment in gvs_tuple_get_child() */
1188   if G_UNLIKELY (value.data == NULL && value.size != 0)
1189     return FALSE;
1190
1191   offset_size = gvs_get_offset_size (value.size);
1192   length = g_variant_type_info_n_members (value.type_info);
1193   offset_ptr = value.size;
1194   offset = 0;
1195
1196   for (i = 0; i < length; i++)
1197     {
1198       const GVariantMemberInfo *member_info;
1199       GVariantSerialised child;
1200       gsize fixed_size;
1201       guint alignment;
1202       gsize end;
1203
1204       member_info = g_variant_type_info_member_info (value.type_info, i);
1205       child.type_info = member_info->type_info;
1206
1207       g_variant_type_info_query (child.type_info, &alignment, &fixed_size);
1208
1209       while (offset & alignment)
1210         {
1211           if (offset > value.size || value.data[offset] != '\0')
1212             return FALSE;
1213           offset++;
1214         }
1215
1216       child.data = value.data + offset;
1217
1218       switch (member_info->ending_type)
1219         {
1220         case G_VARIANT_MEMBER_ENDING_FIXED:
1221           end = offset + fixed_size;
1222           break;
1223
1224         case G_VARIANT_MEMBER_ENDING_LAST:
1225           end = offset_ptr;
1226           break;
1227
1228         case G_VARIANT_MEMBER_ENDING_OFFSET:
1229           offset_ptr -= offset_size;
1230
1231           if (offset_ptr < offset)
1232             return FALSE;
1233
1234           end = gvs_read_unaligned_le (value.data + offset_ptr, offset_size);
1235           break;
1236
1237         default:
1238           g_assert_not_reached ();
1239         }
1240
1241       if (end < offset || end > offset_ptr)
1242         return FALSE;
1243
1244       child.size = end - offset;
1245
1246       if (child.size == 0)
1247         child.data = NULL;
1248
1249       if (!g_variant_serialised_is_normal (child))
1250         return FALSE;
1251
1252       offset = end;
1253     }
1254
1255   {
1256     gsize fixed_size;
1257     guint alignment;
1258
1259     g_variant_type_info_query (value.type_info, &alignment, &fixed_size);
1260
1261     if (fixed_size)
1262       {
1263         g_assert (fixed_size == value.size);
1264         g_assert (offset_ptr == value.size);
1265
1266         if (i == 0)
1267           {
1268             if (value.data[offset++] != '\0')
1269               return FALSE;
1270           }
1271         else
1272           {
1273             while (offset & alignment)
1274               if (value.data[offset++] != '\0')
1275                 return FALSE;
1276           }
1277
1278         g_assert (offset == value.size);
1279       }
1280   }
1281
1282   return offset_ptr == offset;
1283 }
1284
1285 /* Variants {{{2
1286  *
1287  * Variants are stored by storing the serialised data of the child,
1288  * followed by a '\0' character, followed by the type string of the
1289  * child.
1290  *
1291  * In the case that a value is presented that contains no '\0'
1292  * character, or doesn't have a single well-formed definite type string
1293  * following that character, the variant must be taken as containing the
1294  * unit tuple: ().
1295  */
1296
1297 static inline gsize
1298 gvs_variant_n_children (GVariantSerialised value)
1299 {
1300   return 1;
1301 }
1302
1303 static inline GVariantSerialised
1304 gvs_variant_get_child (GVariantSerialised value,
1305                        gsize              index_)
1306 {
1307   GVariantSerialised child = { 0, };
1308
1309   /* NOTE: not O(1) and impossible for it to be... */
1310   if (value.size)
1311     {
1312       /* find '\0' character */
1313       for (child.size = value.size - 1; child.size; child.size--)
1314         if (value.data[child.size] == '\0')
1315           break;
1316
1317       /* ensure we didn't just hit the start of the string */
1318       if (value.data[child.size] == '\0')
1319         {
1320           const gchar *type_string = (gchar *) &value.data[child.size + 1];
1321           const gchar *limit = (gchar *) &value.data[value.size];
1322           const gchar *end;
1323
1324           if (g_variant_type_string_scan (type_string, limit, &end) &&
1325               end == limit)
1326             {
1327               const GVariantType *type = (GVariantType *) type_string;
1328
1329               if (g_variant_type_is_definite (type))
1330                 {
1331                   gsize fixed_size;
1332
1333                   child.type_info = g_variant_type_info_get (type);
1334
1335                   if (child.size != 0)
1336                     /* only set to non-%NULL if size > 0 */
1337                     child.data = value.data;
1338
1339                   g_variant_type_info_query (child.type_info,
1340                                              NULL, &fixed_size);
1341
1342                   if (!fixed_size || fixed_size == child.size)
1343                     return child;
1344
1345                   g_variant_type_info_unref (child.type_info);
1346                 }
1347             }
1348         }
1349     }
1350
1351   child.type_info = g_variant_type_info_get (G_VARIANT_TYPE_UNIT);
1352   child.data = NULL;
1353   child.size = 1;
1354
1355   return child;
1356 }
1357
1358 static inline gsize
1359 gvs_variant_needed_size (GVariantTypeInfo         *type_info,
1360                          GVariantSerialisedFiller  gvs_filler,
1361                          const gpointer           *children,
1362                          gsize                     n_children)
1363 {
1364   GVariantSerialised child = { 0, };
1365   const gchar *type_string;
1366
1367   gvs_filler (&child, children[0]);
1368   type_string = g_variant_type_info_get_type_string (child.type_info);
1369
1370   return child.size + 1 + strlen (type_string);
1371 }
1372
1373 static inline void
1374 gvs_variant_serialise (GVariantSerialised        value,
1375                        GVariantSerialisedFiller  gvs_filler,
1376                        const gpointer           *children,
1377                        gsize                     n_children)
1378 {
1379   GVariantSerialised child = { 0, };
1380   const gchar *type_string;
1381
1382   child.data = value.data;
1383
1384   gvs_filler (&child, children[0]);
1385   type_string = g_variant_type_info_get_type_string (child.type_info);
1386   value.data[child.size] = '\0';
1387   memcpy (value.data + child.size + 1, type_string, strlen (type_string));
1388 }
1389
1390 static void
1391 gvs_variant_write_to_vectors (GVariantVectors  *vectors,
1392                               GVariantTypeInfo *type_info,
1393                               gsize             size,
1394                               const gpointer   *children,
1395                               gsize             n_children)
1396 {
1397   GVariantTypeInfo *child_type_info;
1398   const gchar *type_string;
1399
1400   g_variant_callback_write_to_vectors (vectors, children[0], &child_type_info);
1401   type_string = g_variant_type_info_get_type_string (child_type_info);
1402
1403   g_variant_vectors_append_copy (vectors, "", 1);
1404   g_variant_vectors_append_copy (vectors, type_string, strlen (type_string));
1405 }
1406
1407 static inline gboolean
1408 gvs_variant_is_normal (GVariantSerialised value)
1409 {
1410   GVariantSerialised child;
1411   gboolean normal;
1412
1413   child = gvs_variant_get_child (value, 0);
1414
1415   normal = (child.data != NULL || child.size == 0) &&
1416            g_variant_serialised_is_normal (child);
1417
1418   g_variant_type_info_unref (child.type_info);
1419
1420   return normal;
1421 }
1422
1423
1424
1425 /* PART 2: Serialiser API {{{1
1426  *
1427  * This is the implementation of the API of the serialiser as advertised
1428  * in gvariant-serialiser.h.
1429  */
1430
1431 /* Dispatch Utilities {{{2
1432  *
1433  * These macros allow a given function (for example,
1434  * g_variant_serialiser_serialise) to be dispatched to the appropriate
1435  * type-specific function above (fixed/variable-sized maybe,
1436  * fixed/variable-sized array, tuple or variant).
1437  */
1438 #define DISPATCH_FIXED(type_info, before, after) \
1439   {                                                     \
1440     gsize fixed_size;                                   \
1441                                                         \
1442     g_variant_type_info_query_element (type_info, NULL, \
1443                                        &fixed_size);    \
1444                                                         \
1445     if (fixed_size)                                     \
1446       {                                                 \
1447         before ## fixed_sized ## after                  \
1448       }                                                 \
1449     else                                                \
1450       {                                                 \
1451         before ## variable_sized ## after               \
1452       }                                                 \
1453   }
1454
1455 #define DISPATCH_CASES(type_info, before, after) \
1456   switch (g_variant_type_info_get_type_char (type_info))        \
1457     {                                                           \
1458       case G_VARIANT_TYPE_INFO_CHAR_MAYBE:                      \
1459         DISPATCH_FIXED (type_info, before, _maybe ## after)     \
1460                                                                 \
1461       case G_VARIANT_TYPE_INFO_CHAR_ARRAY:                      \
1462         DISPATCH_FIXED (type_info, before, _array ## after)     \
1463                                                                 \
1464       case G_VARIANT_TYPE_INFO_CHAR_DICT_ENTRY:                 \
1465       case G_VARIANT_TYPE_INFO_CHAR_TUPLE:                      \
1466         {                                                       \
1467           before ## tuple ## after                              \
1468         }                                                       \
1469                                                                 \
1470       case G_VARIANT_TYPE_INFO_CHAR_VARIANT:                    \
1471         {                                                       \
1472           before ## variant ## after                            \
1473         }                                                       \
1474     }
1475
1476 /* Serialiser entry points {{{2
1477  *
1478  * These are the functions that are called in order for the serialiser
1479  * to do its thing.
1480  */
1481
1482 /* < private >
1483  * g_variant_serialised_n_children:
1484  * @serialised: a #GVariantSerialised
1485  *
1486  * For serialised data that represents a container value (maybes,
1487  * tuples, arrays, variants), determine how many child items are inside
1488  * that container.
1489  *
1490  * Returns: the number of children
1491  */
1492 gsize
1493 g_variant_serialised_n_children (GVariantSerialised serialised)
1494 {
1495   g_variant_serialised_check (serialised);
1496
1497   DISPATCH_CASES (serialised.type_info,
1498
1499                   return gvs_/**/,/**/_n_children (serialised);
1500
1501                  )
1502   g_assert_not_reached ();
1503 }
1504
1505 /* < private >
1506  * g_variant_serialised_get_child:
1507  * @serialised: a #GVariantSerialised
1508  * @index_: the index of the child to fetch
1509  *
1510  * Extracts a child from a serialised data representing a container
1511  * value.
1512  *
1513  * It is an error to call this function with an index out of bounds.
1514  *
1515  * If the result .data == %NULL and .size > 0 then there has been an
1516  * error extracting the requested fixed-sized value.  This number of
1517  * zero bytes needs to be allocated instead.
1518  *
1519  * In the case that .data == %NULL and .size == 0 then a zero-sized
1520  * item of a variable-sized type is being returned.
1521  *
1522  * .data is never non-%NULL if size is 0.
1523  *
1524  * Returns: a #GVariantSerialised for the child
1525  */
1526 GVariantSerialised
1527 g_variant_serialised_get_child (GVariantSerialised serialised,
1528                                 gsize              index_)
1529 {
1530   GVariantSerialised child;
1531
1532   g_variant_serialised_check (serialised);
1533
1534   if G_LIKELY (index_ < g_variant_serialised_n_children (serialised))
1535     {
1536       DISPATCH_CASES (serialised.type_info,
1537
1538                       child = gvs_/**/,/**/_get_child (serialised, index_);
1539                       g_assert (child.size || child.data == NULL);
1540                       g_variant_serialised_check (child);
1541                       return child;
1542
1543                      )
1544       g_assert_not_reached ();
1545     }
1546
1547   g_error ("Attempt to access item %"G_GSIZE_FORMAT
1548            " in a container with only %"G_GSIZE_FORMAT" items",
1549            index_, g_variant_serialised_n_children (serialised));
1550 }
1551
1552 /* < private >
1553  * g_variant_serialiser_serialise:
1554  * @serialised: a #GVariantSerialised, properly set up
1555  * @gvs_filler: the filler function
1556  * @children: an array of child items
1557  * @n_children: the size of @children
1558  *
1559  * Writes data in serialised form.
1560  *
1561  * The type_info field of @serialised must be filled in to type info for
1562  * the type that we are serialising.
1563  *
1564  * The size field of @serialised must be filled in with the value
1565  * returned by a previous call to g_variant_serialiser_needed_size().
1566  *
1567  * The data field of @serialised must be a pointer to a properly-aligned
1568  * memory region large enough to serialise into (ie: at least as big as
1569  * the size field).
1570  *
1571  * This function is only resonsible for serialising the top-level
1572  * container.  @gvs_filler is called on each child of the container in
1573  * order for all of the data of that child to be filled in.
1574  */
1575 void
1576 g_variant_serialiser_serialise (GVariantSerialised        serialised,
1577                                 GVariantSerialisedFiller  gvs_filler,
1578                                 const gpointer           *children,
1579                                 gsize                     n_children)
1580 {
1581   g_variant_serialised_check (serialised);
1582
1583   DISPATCH_CASES (serialised.type_info,
1584
1585                   gvs_/**/,/**/_serialise (serialised, gvs_filler,
1586                                            children, n_children);
1587                   return;
1588
1589                  )
1590   g_assert_not_reached ();
1591 }
1592
1593 /* < private >
1594  * g_variant_serialiser_needed_size:
1595  * @type_info: the type to serialise for
1596  * @gvs_filler: the filler function
1597  * @children: an array of child items
1598  * @n_children: the size of @children
1599  *
1600  * Determines how much memory would be needed to serialise this value.
1601  *
1602  * This function is only resonsible for performing calculations for the
1603  * top-level container.  @gvs_filler is called on each child of the
1604  * container in order to determine its size.
1605  */
1606 gsize
1607 g_variant_serialiser_needed_size (GVariantTypeInfo         *type_info,
1608                                   GVariantSerialisedFiller  gvs_filler,
1609                                   const gpointer           *children,
1610                                   gsize                     n_children)
1611 {
1612   DISPATCH_CASES (type_info,
1613
1614                   return gvs_/**/,/**/_needed_size (type_info, gvs_filler,
1615                                                     children, n_children);
1616                  )
1617   g_assert_not_reached ();
1618 }
1619
1620
1621 void
1622 g_variant_serialiser_write_to_vectors (GVariantVectors  *vectors,
1623                                        GVariantTypeInfo *type_info,
1624                                        gsize             size,
1625                                        const gpointer   *children,
1626                                        gsize             n_children)
1627 {
1628   DISPATCH_CASES (type_info,
1629                   gvs_/**/,/**/_write_to_vectors (vectors, type_info, size, children, n_children);
1630                   return;
1631                  )
1632   g_assert_not_reached ();
1633 }
1634
1635 /* Byteswapping {{{2 */
1636
1637 /* < private >
1638  * g_variant_serialised_byteswap:
1639  * @value: a #GVariantSerialised
1640  *
1641  * Byte-swap serialised data.  The result of this function is only
1642  * well-defined if the data is in normal form.
1643  */
1644 void
1645 g_variant_serialised_byteswap (GVariantSerialised serialised)
1646 {
1647   gsize fixed_size;
1648   guint alignment;
1649
1650   g_variant_serialised_check (serialised);
1651
1652   if (!serialised.data)
1653     return;
1654
1655   /* the types we potentially need to byteswap are
1656    * exactly those with alignment requirements.
1657    */
1658   g_variant_type_info_query (serialised.type_info, &alignment, &fixed_size);
1659   if (!alignment)
1660     return;
1661
1662   /* if fixed size and alignment are equal then we are down
1663    * to the base integer type and we should swap it.  the
1664    * only exception to this is if we have a tuple with a
1665    * single item, and then swapping it will be OK anyway.
1666    */
1667   if (alignment + 1 == fixed_size)
1668     {
1669       switch (fixed_size)
1670       {
1671         case 2:
1672           {
1673             guint16 *ptr = (guint16 *) serialised.data;
1674
1675             g_assert_cmpint (serialised.size, ==, 2);
1676             *ptr = GUINT16_SWAP_LE_BE (*ptr);
1677           }
1678           return;
1679
1680         case 4:
1681           {
1682             guint32 *ptr = (guint32 *) serialised.data;
1683
1684             g_assert_cmpint (serialised.size, ==, 4);
1685             *ptr = GUINT32_SWAP_LE_BE (*ptr);
1686           }
1687           return;
1688
1689         case 8:
1690           {
1691             guint64 *ptr = (guint64 *) serialised.data;
1692
1693             g_assert_cmpint (serialised.size, ==, 8);
1694             *ptr = GUINT64_SWAP_LE_BE (*ptr);
1695           }
1696           return;
1697
1698         default:
1699           g_assert_not_reached ();
1700       }
1701     }
1702
1703   /* else, we have a container that potentially contains
1704    * some children that need to be byteswapped.
1705    */
1706   else
1707     {
1708       gsize children, i;
1709
1710       children = g_variant_serialised_n_children (serialised);
1711       for (i = 0; i < children; i++)
1712         {
1713           GVariantSerialised child;
1714
1715           child = g_variant_serialised_get_child (serialised, i);
1716           g_variant_serialised_byteswap (child);
1717           g_variant_type_info_unref (child.type_info);
1718         }
1719     }
1720 }
1721
1722 /* Normal form checking {{{2 */
1723
1724 /* < private >
1725  * g_variant_serialised_is_normal:
1726  * @serialised: a #GVariantSerialised
1727  *
1728  * Determines, recursively if @serialised is in normal form.  There is
1729  * precisely one normal form of serialised data for each possible value.
1730  *
1731  * It is possible that multiple byte sequences form the serialised data
1732  * for a given value if, for example, the padding bytes are filled in
1733  * with something other than zeros, but only one form is the normal
1734  * form.
1735  */
1736 gboolean
1737 g_variant_serialised_is_normal (GVariantSerialised serialised)
1738 {
1739   DISPATCH_CASES (serialised.type_info,
1740
1741                   return gvs_/**/,/**/_is_normal (serialised);
1742
1743                  )
1744
1745   if (serialised.data == NULL)
1746     return FALSE;
1747
1748   /* some hard-coded terminal cases */
1749   switch (g_variant_type_info_get_type_char (serialised.type_info))
1750     {
1751     case 'b': /* boolean */
1752       return serialised.data[0] < 2;
1753
1754     case 's': /* string */
1755       return g_variant_serialiser_is_string (serialised.data,
1756                                              serialised.size);
1757
1758     case 'o':
1759       return g_variant_serialiser_is_object_path (serialised.data,
1760                                                   serialised.size);
1761
1762     case 'g':
1763       return g_variant_serialiser_is_signature (serialised.data,
1764                                                 serialised.size);
1765
1766     default:
1767       /* all of the other types are fixed-sized numerical types for
1768        * which all possible values are valid (including various NaN
1769        * representations for floating point values).
1770        */
1771       return TRUE;
1772     }
1773 }
1774
1775 /* Validity-checking functions {{{2
1776  *
1777  * Checks if strings, object paths and signature strings are valid.
1778  */
1779
1780 /* < private >
1781  * g_variant_serialiser_is_string:
1782  * @data: a possible string
1783  * @size: the size of @data
1784  *
1785  * Ensures that @data is a valid string with a nul terminator at the end
1786  * and no nul bytes embedded.
1787  */
1788 gboolean
1789 g_variant_serialiser_is_string (gconstpointer data,
1790                                 gsize         size)
1791 {
1792   const gchar *expected_end;
1793   const gchar *end;
1794
1795   if (size == 0)
1796     return FALSE;
1797
1798   expected_end = ((gchar *) data) + size - 1;
1799
1800   if (*expected_end != '\0')
1801     return FALSE;
1802
1803   g_utf8_validate (data, size, &end);
1804
1805   return end == expected_end;
1806 }
1807
1808 /* < private >
1809  * g_variant_serialiser_is_object_path:
1810  * @data: a possible D-Bus object path
1811  * @size: the size of @data
1812  *
1813  * Performs the checks for being a valid string.
1814  *
1815  * Also, ensures that @data is a valid DBus object path, as per the D-Bus
1816  * specification.
1817  */
1818 gboolean
1819 g_variant_serialiser_is_object_path (gconstpointer data,
1820                                      gsize         size)
1821 {
1822   const gchar *string = data;
1823   gsize i;
1824
1825   if (!g_variant_serialiser_is_string (data, size))
1826     return FALSE;
1827
1828   /* The path must begin with an ASCII '/' (integer 47) character */
1829   if (string[0] != '/')
1830     return FALSE;
1831
1832   for (i = 1; string[i]; i++)
1833     /* Each element must only contain the ASCII characters
1834      * "[A-Z][a-z][0-9]_"
1835      */
1836     if (g_ascii_isalnum (string[i]) || string[i] == '_')
1837       ;
1838
1839     /* must consist of elements separated by slash characters. */
1840     else if (string[i] == '/')
1841       {
1842         /* No element may be the empty string. */
1843         /* Multiple '/' characters cannot occur in sequence. */
1844         if (string[i - 1] == '/')
1845           return FALSE;
1846       }
1847
1848     else
1849       return FALSE;
1850
1851   /* A trailing '/' character is not allowed unless the path is the
1852    * root path (a single '/' character).
1853    */
1854   if (i > 1 && string[i - 1] == '/')
1855     return FALSE;
1856
1857   return TRUE;
1858 }
1859
1860 /* < private >
1861  * g_variant_serialiser_is_signature:
1862  * @data: a possible D-Bus signature
1863  * @size: the size of @data
1864  *
1865  * Performs the checks for being a valid string.
1866  *
1867  * Also, ensures that @data is a valid D-Bus type signature, as per the
1868  * D-Bus specification.
1869  */
1870 gboolean
1871 g_variant_serialiser_is_signature (gconstpointer data,
1872                                    gsize         size)
1873 {
1874   const gchar *string = data;
1875   gsize first_invalid;
1876
1877   if (!g_variant_serialiser_is_string (data, size))
1878     return FALSE;
1879
1880   /* make sure no non-definite characters appear */
1881   first_invalid = strspn (string, "ybnqiuxthdvasog(){}");
1882   if (string[first_invalid])
1883     return FALSE;
1884
1885   /* make sure each type string is well-formed */
1886   while (*string)
1887     if (!g_variant_type_string_scan (string, NULL, &string))
1888       return FALSE;
1889
1890   return TRUE;
1891 }
1892
1893 /* Epilogue {{{1 */
1894 /* vim:set foldmethod=marker: */