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