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

source code of gtk/subprojects/glib/glib/gvariant-serialiser.c