Coverage Report

Created: 2025-10-10 07:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/glib/glib/gvariant-serialiser.c
Line
Count
Source
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
 */
133
gboolean
134
g_variant_serialised_check (GVariantSerialised serialised)
135
0
{
136
0
  gsize fixed_size;
137
0
  guint alignment;
138
139
0
  if (serialised.type_info == NULL)
140
0
    return FALSE;
141
0
  g_variant_type_info_query (serialised.type_info, &alignment, &fixed_size);
142
143
0
  if (fixed_size != 0 && serialised.size != fixed_size)
144
0
    return FALSE;
145
0
  else if (fixed_size == 0 &&
146
0
           !(serialised.size == 0 || serialised.data != NULL))
147
0
    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
0
  alignment &= sizeof (struct {
158
0
                         char a;
159
0
                         union {
160
0
                           guint64 x;
161
0
                           void *y;
162
0
                           gdouble z;
163
0
                         } b;
164
0
                       }
165
0
                      ) - 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
0
  return (serialised.size <= alignment ||
175
0
          (alignment & (gsize) serialised.data) == 0);
176
0
}
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
246
static gsize
247
gvs_fixed_sized_maybe_n_children (GVariantSerialised value)
248
0
{
249
0
  gsize element_fixed_size;
250
251
0
  g_variant_type_info_query_element (value.type_info, NULL,
252
0
                                     &element_fixed_size);
253
254
0
  return (element_fixed_size == value.size) ? 1 : 0;
255
0
}
256
257
static GVariantSerialised
258
gvs_fixed_sized_maybe_get_child (GVariantSerialised value,
259
                                 gsize              index_)
260
0
{
261
  /* the child has the same bounds as the
262
   * container, so just update the type.
263
   */
264
0
  value.type_info = g_variant_type_info_element (value.type_info);
265
0
  g_variant_type_info_ref (value.type_info);
266
0
  value.depth++;
267
268
0
  return value;
269
0
}
270
271
static gsize
272
gvs_fixed_sized_maybe_needed_size (GVariantTypeInfo         *type_info,
273
                                   GVariantSerialisedFiller  gvs_filler,
274
                                   const gpointer           *children,
275
                                   gsize                     n_children)
276
0
{
277
0
  if (n_children)
278
0
    {
279
0
      gsize element_fixed_size;
280
281
0
      g_variant_type_info_query_element (type_info, NULL,
282
0
                                         &element_fixed_size);
283
284
0
      return element_fixed_size;
285
0
    }
286
0
  else
287
0
    return 0;
288
0
}
289
290
static void
291
gvs_fixed_sized_maybe_serialise (GVariantSerialised        value,
292
                                 GVariantSerialisedFiller  gvs_filler,
293
                                 const gpointer           *children,
294
                                 gsize                     n_children)
295
0
{
296
0
  if (n_children)
297
0
    {
298
0
      GVariantSerialised child = { NULL, value.data, value.size, value.depth + 1 };
299
300
0
      gvs_filler (&child, children[0]);
301
0
    }
302
0
}
303
304
static gboolean
305
gvs_fixed_sized_maybe_is_normal (GVariantSerialised value)
306
0
{
307
0
  if (value.size > 0)
308
0
    {
309
0
      gsize element_fixed_size;
310
311
0
      g_variant_type_info_query_element (value.type_info,
312
0
                                         NULL, &element_fixed_size);
313
314
0
      if (value.size != element_fixed_size)
315
0
        return FALSE;
316
317
      /* proper element size: "Just".  recurse to the child. */
318
0
      value.type_info = g_variant_type_info_element (value.type_info);
319
0
      value.depth++;
320
321
0
      return g_variant_serialised_is_normal (value);
322
0
    }
323
324
  /* size of 0: "Nothing" */
325
0
  return TRUE;
326
0
}
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
341
static gsize
342
gvs_variable_sized_maybe_n_children (GVariantSerialised value)
343
0
{
344
0
  return (value.size > 0) ? 1 : 0;
345
0
}
346
347
static GVariantSerialised
348
gvs_variable_sized_maybe_get_child (GVariantSerialised value,
349
                                    gsize              index_)
350
0
{
351
  /* remove the padding byte and update the type. */
352
0
  value.type_info = g_variant_type_info_element (value.type_info);
353
0
  g_variant_type_info_ref (value.type_info);
354
0
  value.size--;
355
356
  /* if it's zero-sized then it may as well be NULL */
357
0
  if (value.size == 0)
358
0
    value.data = NULL;
359
360
0
  value.depth++;
361
362
0
  return value;
363
0
}
364
365
static gsize
366
gvs_variable_sized_maybe_needed_size (GVariantTypeInfo         *type_info,
367
                                      GVariantSerialisedFiller  gvs_filler,
368
                                      const gpointer           *children,
369
                                      gsize                     n_children)
370
0
{
371
0
  if (n_children)
372
0
    {
373
0
      GVariantSerialised child = { 0, };
374
375
0
      gvs_filler (&child, children[0]);
376
377
0
      return child.size + 1;
378
0
    }
379
0
  else
380
0
    return 0;
381
0
}
382
383
static void
384
gvs_variable_sized_maybe_serialise (GVariantSerialised        value,
385
                                    GVariantSerialisedFiller  gvs_filler,
386
                                    const gpointer           *children,
387
                                    gsize                     n_children)
388
0
{
389
0
  if (n_children)
390
0
    {
391
0
      GVariantSerialised child = { NULL, value.data, value.size - 1, value.depth + 1 };
392
393
      /* write the data for the child.  */
394
0
      gvs_filler (&child, children[0]);
395
0
      value.data[child.size] = '\0';
396
0
    }
397
0
}
398
399
static gboolean
400
gvs_variable_sized_maybe_is_normal (GVariantSerialised value)
401
0
{
402
0
  if (value.size == 0)
403
0
    return TRUE;
404
405
0
  if (value.data[value.size - 1] != '\0')
406
0
    return FALSE;
407
408
0
  value.type_info = g_variant_type_info_element (value.type_info);
409
0
  value.size--;
410
0
  value.depth++;
411
412
0
  return g_variant_serialised_is_normal (value);
413
0
}
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
437
static gsize
438
gvs_fixed_sized_array_n_children (GVariantSerialised value)
439
0
{
440
0
  gsize element_fixed_size;
441
442
0
  g_variant_type_info_query_element (value.type_info, NULL,
443
0
                                     &element_fixed_size);
444
445
0
  if (value.size % element_fixed_size == 0)
446
0
    return value.size / element_fixed_size;
447
448
0
  return 0;
449
0
}
450
451
static GVariantSerialised
452
gvs_fixed_sized_array_get_child (GVariantSerialised value,
453
                                 gsize              index_)
454
0
{
455
0
  GVariantSerialised child = { 0, };
456
457
0
  child.type_info = g_variant_type_info_element (value.type_info);
458
0
  g_variant_type_info_query (child.type_info, NULL, &child.size);
459
0
  child.data = value.data + (child.size * index_);
460
0
  g_variant_type_info_ref (child.type_info);
461
0
  child.depth = value.depth + 1;
462
463
0
  return child;
464
0
}
465
466
static gsize
467
gvs_fixed_sized_array_needed_size (GVariantTypeInfo         *type_info,
468
                                   GVariantSerialisedFiller  gvs_filler,
469
                                   const gpointer           *children,
470
                                   gsize                     n_children)
471
0
{
472
0
  gsize element_fixed_size;
473
474
0
  g_variant_type_info_query_element (type_info, NULL, &element_fixed_size);
475
476
0
  return element_fixed_size * n_children;
477
0
}
478
479
static void
480
gvs_fixed_sized_array_serialise (GVariantSerialised        value,
481
                                 GVariantSerialisedFiller  gvs_filler,
482
                                 const gpointer           *children,
483
                                 gsize                     n_children)
484
0
{
485
0
  GVariantSerialised child = { 0, };
486
0
  gsize i;
487
488
0
  child.type_info = g_variant_type_info_element (value.type_info);
489
0
  g_variant_type_info_query (child.type_info, NULL, &child.size);
490
0
  child.data = value.data;
491
0
  child.depth = value.depth + 1;
492
493
0
  for (i = 0; i < n_children; i++)
494
0
    {
495
0
      gvs_filler (&child, children[i]);
496
0
      child.data += child.size;
497
0
    }
498
0
}
499
500
static gboolean
501
gvs_fixed_sized_array_is_normal (GVariantSerialised value)
502
0
{
503
0
  GVariantSerialised child = { 0, };
504
505
0
  child.type_info = g_variant_type_info_element (value.type_info);
506
0
  g_variant_type_info_query (child.type_info, NULL, &child.size);
507
0
  child.depth = value.depth + 1;
508
509
0
  if (value.size % child.size != 0)
510
0
    return FALSE;
511
512
0
  for (child.data = value.data;
513
0
       child.data < value.data + value.size;
514
0
       child.data += child.size)
515
0
    {
516
0
      if (!g_variant_serialised_is_normal (child))
517
0
        return FALSE;
518
0
    }
519
520
0
  return TRUE;
521
0
}
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). */
570
static inline gsize
571
gvs_read_unaligned_le (guchar *bytes,
572
                       guint   size)
573
0
{
574
0
  union
575
0
  {
576
0
    guchar bytes[GLIB_SIZEOF_SIZE_T];
577
0
    gsize integer;
578
0
  } tmpvalue;
579
580
0
  tmpvalue.integer = 0;
581
0
  if (bytes != NULL)
582
0
    memcpy (&tmpvalue.bytes, bytes, size);
583
584
0
  return GSIZE_FROM_LE (tmpvalue.integer);
585
0
}
586
587
static inline void
588
gvs_write_unaligned_le (guchar *bytes,
589
                        gsize   value,
590
                        guint   size)
591
0
{
592
0
  union
593
0
  {
594
0
    guchar bytes[GLIB_SIZEOF_SIZE_T];
595
0
    gsize integer;
596
0
  } tmpvalue;
597
598
0
  tmpvalue.integer = GSIZE_TO_LE (value);
599
0
  memcpy (bytes, &tmpvalue.bytes, size);
600
0
}
601
602
static guint
603
gvs_get_offset_size (gsize size)
604
0
{
605
0
  if (size > G_MAXUINT32)
606
0
    return 8;
607
608
0
  else if (size > G_MAXUINT16)
609
0
    return 4;
610
611
0
  else if (size > G_MAXUINT8)
612
0
    return 2;
613
614
0
  else if (size > 0)
615
0
    return 1;
616
617
0
  return 0;
618
0
}
619
620
static gsize
621
gvs_calculate_total_size (gsize body_size,
622
                          gsize offsets)
623
0
{
624
0
  if (body_size + 1 * offsets <= G_MAXUINT8)
625
0
    return body_size + 1 * offsets;
626
627
0
  if (body_size + 2 * offsets <= G_MAXUINT16)
628
0
    return body_size + 2 * offsets;
629
630
0
  if (body_size + 4 * offsets <= G_MAXUINT32)
631
0
    return body_size + 4 * offsets;
632
633
0
  return body_size + 8 * offsets;
634
0
}
635
636
static gsize
637
gvs_variable_sized_array_n_children (GVariantSerialised value)
638
0
{
639
0
  gsize offsets_array_size;
640
0
  gsize offset_size;
641
0
  gsize last_end;
642
643
0
  if (value.size == 0)
644
0
    return 0;
645
646
0
  offset_size = gvs_get_offset_size (value.size);
647
648
0
  last_end = gvs_read_unaligned_le (value.data + value.size -
649
0
                                    offset_size, offset_size);
650
651
0
  if (last_end > value.size)
652
0
    return 0;
653
654
0
  offsets_array_size = value.size - last_end;
655
656
0
  if (offsets_array_size % offset_size)
657
0
    return 0;
658
659
0
  return offsets_array_size / offset_size;
660
0
}
661
662
static GVariantSerialised
663
gvs_variable_sized_array_get_child (GVariantSerialised value,
664
                                    gsize              index_)
665
0
{
666
0
  GVariantSerialised child = { 0, };
667
0
  gsize offset_size;
668
0
  gsize last_end;
669
0
  gsize start;
670
0
  gsize end;
671
672
0
  child.type_info = g_variant_type_info_element (value.type_info);
673
0
  g_variant_type_info_ref (child.type_info);
674
0
  child.depth = value.depth + 1;
675
676
0
  offset_size = gvs_get_offset_size (value.size);
677
678
0
  last_end = gvs_read_unaligned_le (value.data + value.size -
679
0
                                    offset_size, offset_size);
680
681
0
  if (index_ > 0)
682
0
    {
683
0
      guint alignment;
684
685
0
      start = gvs_read_unaligned_le (value.data + last_end +
686
0
                                     (offset_size * (index_ - 1)),
687
0
                                     offset_size);
688
689
0
      g_variant_type_info_query (child.type_info, &alignment, NULL);
690
0
      start += (-start) & alignment;
691
0
    }
692
0
  else
693
0
    start = 0;
694
695
0
  end = gvs_read_unaligned_le (value.data + last_end +
696
0
                               (offset_size * index_),
697
0
                               offset_size);
698
699
0
  if (start < end && end <= value.size && end <= last_end)
700
0
    {
701
0
      child.data = value.data + start;
702
0
      child.size = end - start;
703
0
    }
704
705
0
  return child;
706
0
}
707
708
static gsize
709
gvs_variable_sized_array_needed_size (GVariantTypeInfo         *type_info,
710
                                      GVariantSerialisedFiller  gvs_filler,
711
                                      const gpointer           *children,
712
                                      gsize                     n_children)
713
0
{
714
0
  guint alignment;
715
0
  gsize offset;
716
0
  gsize i;
717
718
0
  g_variant_type_info_query (type_info, &alignment, NULL);
719
0
  offset = 0;
720
721
0
  for (i = 0; i < n_children; i++)
722
0
    {
723
0
      GVariantSerialised child = { 0, };
724
725
0
      offset += (-offset) & alignment;
726
0
      gvs_filler (&child, children[i]);
727
0
      offset += child.size;
728
0
    }
729
730
0
  return gvs_calculate_total_size (offset, n_children);
731
0
}
732
733
static void
734
gvs_variable_sized_array_serialise (GVariantSerialised        value,
735
                                    GVariantSerialisedFiller  gvs_filler,
736
                                    const gpointer           *children,
737
                                    gsize                     n_children)
738
0
{
739
0
  guchar *offset_ptr;
740
0
  gsize offset_size;
741
0
  guint alignment;
742
0
  gsize offset;
743
0
  gsize i;
744
745
0
  g_variant_type_info_query (value.type_info, &alignment, NULL);
746
0
  offset_size = gvs_get_offset_size (value.size);
747
0
  offset = 0;
748
749
0
  offset_ptr = value.data + value.size - offset_size * n_children;
750
751
0
  for (i = 0; i < n_children; i++)
752
0
    {
753
0
      GVariantSerialised child = { 0, };
754
755
0
      while (offset & alignment)
756
0
        value.data[offset++] = '\0';
757
758
0
      child.data = value.data + offset;
759
0
      gvs_filler (&child, children[i]);
760
0
      offset += child.size;
761
762
0
      gvs_write_unaligned_le (offset_ptr, offset, offset_size);
763
0
      offset_ptr += offset_size;
764
0
    }
765
0
}
766
767
static gboolean
768
gvs_variable_sized_array_is_normal (GVariantSerialised value)
769
0
{
770
0
  GVariantSerialised child = { 0, };
771
0
  gsize offsets_array_size;
772
0
  guchar *offsets_array;
773
0
  guint offset_size;
774
0
  guint alignment;
775
0
  gsize last_end;
776
0
  gsize length;
777
0
  gsize offset;
778
0
  gsize i;
779
780
0
  if (value.size == 0)
781
0
    return TRUE;
782
783
0
  offset_size = gvs_get_offset_size (value.size);
784
0
  last_end = gvs_read_unaligned_le (value.data + value.size -
785
0
                                    offset_size, offset_size);
786
787
0
  if (last_end > value.size)
788
0
    return FALSE;
789
790
0
  offsets_array_size = value.size - last_end;
791
792
0
  if (offsets_array_size % offset_size)
793
0
    return FALSE;
794
795
0
  offsets_array = value.data + value.size - offsets_array_size;
796
0
  length = offsets_array_size / offset_size;
797
798
0
  if (length == 0)
799
0
    return FALSE;
800
801
0
  child.type_info = g_variant_type_info_element (value.type_info);
802
0
  g_variant_type_info_query (child.type_info, &alignment, NULL);
803
0
  child.depth = value.depth + 1;
804
0
  offset = 0;
805
806
0
  for (i = 0; i < length; i++)
807
0
    {
808
0
      gsize this_end;
809
810
0
      this_end = gvs_read_unaligned_le (offsets_array + offset_size * i,
811
0
                                        offset_size);
812
813
0
      if (this_end < offset || this_end > last_end)
814
0
        return FALSE;
815
816
0
      while (offset & alignment)
817
0
        {
818
0
          if (!(offset < this_end && value.data[offset] == '\0'))
819
0
            return FALSE;
820
0
          offset++;
821
0
        }
822
823
0
      child.data = value.data + offset;
824
0
      child.size = this_end - offset;
825
826
0
      if (child.size == 0)
827
0
        child.data = NULL;
828
829
0
      if (!g_variant_serialised_is_normal (child))
830
0
        return FALSE;
831
832
0
      offset = this_end;
833
0
    }
834
835
0
  g_assert (offset == last_end);
836
837
0
  return TRUE;
838
0
}
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
862
static gsize
863
gvs_tuple_n_children (GVariantSerialised value)
864
0
{
865
0
  return g_variant_type_info_n_members (value.type_info);
866
0
}
867
868
static GVariantSerialised
869
gvs_tuple_get_child (GVariantSerialised value,
870
                     gsize              index_)
871
0
{
872
0
  const GVariantMemberInfo *member_info;
873
0
  GVariantSerialised child = { 0, };
874
0
  gsize offset_size;
875
0
  gsize start, end, last_end;
876
877
0
  member_info = g_variant_type_info_member_info (value.type_info, index_);
878
0
  child.type_info = g_variant_type_info_ref (member_info->type_info);
879
0
  child.depth = value.depth + 1;
880
0
  offset_size = gvs_get_offset_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
0
  if G_UNLIKELY (value.data == NULL && value.size != 0)
887
0
    {
888
0
      g_variant_type_info_query (child.type_info, NULL, &child.size);
889
890
      /* this can only happen in fixed-sized tuples,
891
       * so the child must also be fixed sized.
892
       */
893
0
      g_assert (child.size != 0);
894
0
      child.data = NULL;
895
896
0
      return child;
897
0
    }
898
899
0
  if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_OFFSET)
900
0
    {
901
0
      if (offset_size * (member_info->i + 2) > value.size)
902
0
        return child;
903
0
    }
904
0
  else
905
0
    {
906
0
      if (offset_size * (member_info->i + 1) > value.size)
907
0
        {
908
          /* if the child is fixed size, return its size.
909
           * if child is not fixed-sized, return size = 0.
910
           */
911
0
          g_variant_type_info_query (child.type_info, NULL, &child.size);
912
913
0
          return child;
914
0
        }
915
0
    }
916
917
0
  if (member_info->i + 1)
918
0
    start = gvs_read_unaligned_le (value.data + value.size -
919
0
                                   offset_size * (member_info->i + 1),
920
0
                                   offset_size);
921
0
  else
922
0
    start = 0;
923
924
0
  start += member_info->a;
925
0
  start &= member_info->b;
926
0
  start |= member_info->c;
927
928
0
  if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_LAST)
929
0
    end = value.size - offset_size * (member_info->i + 1);
930
931
0
  else if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_FIXED)
932
0
    {
933
0
      gsize fixed_size;
934
935
0
      g_variant_type_info_query (child.type_info, NULL, &fixed_size);
936
0
      end = start + fixed_size;
937
0
      child.size = fixed_size;
938
0
    }
939
940
0
  else /* G_VARIANT_MEMBER_ENDING_OFFSET */
941
0
    end = gvs_read_unaligned_le (value.data + value.size -
942
0
                                 offset_size * (member_info->i + 2),
943
0
                                 offset_size);
944
945
  /* The child should not extend into the offset table. */
946
0
  if (index_ != g_variant_type_info_n_members (value.type_info) - 1)
947
0
    {
948
0
      GVariantSerialised last_child;
949
0
      last_child = gvs_tuple_get_child (value,
950
0
                                        g_variant_type_info_n_members (value.type_info) - 1);
951
0
      last_end = last_child.data + last_child.size - value.data;
952
0
      g_variant_type_info_unref (last_child.type_info);
953
0
    }
954
0
  else
955
0
    last_end = end;
956
957
0
  if (start < end && end <= value.size && end <= last_end)
958
0
    {
959
0
      child.data = value.data + start;
960
0
      child.size = end - start;
961
0
    }
962
963
0
  return child;
964
0
}
965
966
static gsize
967
gvs_tuple_needed_size (GVariantTypeInfo         *type_info,
968
                       GVariantSerialisedFiller  gvs_filler,
969
                       const gpointer           *children,
970
                       gsize                     n_children)
971
0
{
972
0
  const GVariantMemberInfo *member_info = NULL;
973
0
  gsize fixed_size;
974
0
  gsize offset;
975
0
  gsize i;
976
977
0
  g_variant_type_info_query (type_info, NULL, &fixed_size);
978
979
0
  if (fixed_size)
980
0
    return fixed_size;
981
982
0
  offset = 0;
983
984
0
  for (i = 0; i < n_children; i++)
985
0
    {
986
0
      guint alignment;
987
988
0
      member_info = g_variant_type_info_member_info (type_info, i);
989
0
      g_variant_type_info_query (member_info->type_info,
990
0
                                 &alignment, &fixed_size);
991
0
      offset += (-offset) & alignment;
992
993
0
      if (fixed_size)
994
0
        offset += fixed_size;
995
0
      else
996
0
        {
997
0
          GVariantSerialised child = { 0, };
998
999
0
          gvs_filler (&child, children[i]);
1000
0
          offset += child.size;
1001
0
        }
1002
0
    }
1003
1004
0
  return gvs_calculate_total_size (offset, member_info->i + 1);
1005
0
}
1006
1007
static void
1008
gvs_tuple_serialise (GVariantSerialised        value,
1009
                     GVariantSerialisedFiller  gvs_filler,
1010
                     const gpointer           *children,
1011
                     gsize                     n_children)
1012
0
{
1013
0
  gsize offset_size;
1014
0
  gsize offset;
1015
0
  gsize i;
1016
1017
0
  offset_size = gvs_get_offset_size (value.size);
1018
0
  offset = 0;
1019
1020
0
  for (i = 0; i < n_children; i++)
1021
0
    {
1022
0
      const GVariantMemberInfo *member_info;
1023
0
      GVariantSerialised child = { 0, };
1024
0
      guint alignment;
1025
1026
0
      member_info = g_variant_type_info_member_info (value.type_info, i);
1027
0
      g_variant_type_info_query (member_info->type_info, &alignment, NULL);
1028
1029
0
      while (offset & alignment)
1030
0
        value.data[offset++] = '\0';
1031
1032
0
      child.data = value.data + offset;
1033
0
      gvs_filler (&child, children[i]);
1034
0
      offset += child.size;
1035
1036
0
      if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_OFFSET)
1037
0
        {
1038
0
          value.size -= offset_size;
1039
0
          gvs_write_unaligned_le (value.data + value.size,
1040
0
                                  offset, offset_size);
1041
0
        }
1042
0
    }
1043
1044
0
  while (offset < value.size)
1045
0
    value.data[offset++] = '\0';
1046
0
}
1047
1048
static gboolean
1049
gvs_tuple_is_normal (GVariantSerialised value)
1050
0
{
1051
0
  guint offset_size;
1052
0
  gsize offset_ptr;
1053
0
  gsize length;
1054
0
  gsize offset;
1055
0
  gsize i;
1056
1057
  /* as per the comment in gvs_tuple_get_child() */
1058
0
  if G_UNLIKELY (value.data == NULL && value.size != 0)
1059
0
    return FALSE;
1060
1061
0
  offset_size = gvs_get_offset_size (value.size);
1062
0
  length = g_variant_type_info_n_members (value.type_info);
1063
0
  offset_ptr = value.size;
1064
0
  offset = 0;
1065
1066
0
  for (i = 0; i < length; i++)
1067
0
    {
1068
0
      const GVariantMemberInfo *member_info;
1069
0
      GVariantSerialised child;
1070
0
      gsize fixed_size;
1071
0
      guint alignment;
1072
0
      gsize end;
1073
1074
0
      member_info = g_variant_type_info_member_info (value.type_info, i);
1075
0
      child.type_info = member_info->type_info;
1076
0
      child.depth = value.depth + 1;
1077
1078
0
      g_variant_type_info_query (child.type_info, &alignment, &fixed_size);
1079
1080
0
      while (offset & alignment)
1081
0
        {
1082
0
          if (offset > value.size || value.data[offset] != '\0')
1083
0
            return FALSE;
1084
0
          offset++;
1085
0
        }
1086
1087
0
      child.data = value.data + offset;
1088
1089
0
      switch (member_info->ending_type)
1090
0
        {
1091
0
        case G_VARIANT_MEMBER_ENDING_FIXED:
1092
0
          end = offset + fixed_size;
1093
0
          break;
1094
1095
0
        case G_VARIANT_MEMBER_ENDING_LAST:
1096
0
          end = offset_ptr;
1097
0
          break;
1098
1099
0
        case G_VARIANT_MEMBER_ENDING_OFFSET:
1100
0
          if (offset_ptr < offset_size)
1101
0
            return FALSE;
1102
1103
0
          offset_ptr -= offset_size;
1104
1105
0
          if (offset_ptr < offset)
1106
0
            return FALSE;
1107
1108
0
          end = gvs_read_unaligned_le (value.data + offset_ptr, offset_size);
1109
0
          break;
1110
1111
0
        default:
1112
0
          g_assert_not_reached ();
1113
0
        }
1114
1115
0
      if (end < offset || end > offset_ptr)
1116
0
        return FALSE;
1117
1118
0
      child.size = end - offset;
1119
1120
0
      if (child.size == 0)
1121
0
        child.data = NULL;
1122
1123
0
      if (!g_variant_serialised_is_normal (child))
1124
0
        return FALSE;
1125
1126
0
      offset = end;
1127
0
    }
1128
1129
0
  {
1130
0
    gsize fixed_size;
1131
0
    guint alignment;
1132
1133
0
    g_variant_type_info_query (value.type_info, &alignment, &fixed_size);
1134
1135
0
    if (fixed_size)
1136
0
      {
1137
0
        g_assert (fixed_size == value.size);
1138
0
        g_assert (offset_ptr == value.size);
1139
1140
0
        if (i == 0)
1141
0
          {
1142
0
            if (value.data[offset++] != '\0')
1143
0
              return FALSE;
1144
0
          }
1145
0
        else
1146
0
          {
1147
0
            while (offset & alignment)
1148
0
              if (value.data[offset++] != '\0')
1149
0
                return FALSE;
1150
0
          }
1151
1152
0
        g_assert (offset == value.size);
1153
0
      }
1154
0
  }
1155
1156
0
  return offset_ptr == offset;
1157
0
}
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
1171
static inline gsize
1172
gvs_variant_n_children (GVariantSerialised value)
1173
0
{
1174
0
  return 1;
1175
0
}
1176
1177
static inline GVariantSerialised
1178
gvs_variant_get_child (GVariantSerialised value,
1179
                       gsize              index_)
1180
0
{
1181
0
  GVariantSerialised child = { 0, };
1182
1183
  /* NOTE: not O(1) and impossible for it to be... */
1184
0
  if (value.size)
1185
0
    {
1186
      /* find '\0' character */
1187
0
      for (child.size = value.size - 1; child.size; child.size--)
1188
0
        if (value.data[child.size] == '\0')
1189
0
          break;
1190
1191
      /* ensure we didn't just hit the start of the string */
1192
0
      if (value.data[child.size] == '\0')
1193
0
        {
1194
0
          const gchar *type_string = (gchar *) &value.data[child.size + 1];
1195
0
          const gchar *limit = (gchar *) &value.data[value.size];
1196
0
          const gchar *end;
1197
1198
0
          if (g_variant_type_string_scan (type_string, limit, &end) &&
1199
0
              end == limit)
1200
0
            {
1201
0
              const GVariantType *type = (GVariantType *) type_string;
1202
1203
0
              if (g_variant_type_is_definite (type))
1204
0
                {
1205
0
                  gsize fixed_size;
1206
0
                  gsize child_type_depth;
1207
1208
0
                  child.type_info = g_variant_type_info_get (type);
1209
0
                  child.depth = value.depth + 1;
1210
1211
0
                  if (child.size != 0)
1212
                    /* only set to non-%NULL if size > 0 */
1213
0
                    child.data = value.data;
1214
1215
0
                  g_variant_type_info_query (child.type_info,
1216
0
                                             NULL, &fixed_size);
1217
0
                  child_type_depth = g_variant_type_info_query_depth (child.type_info);
1218
1219
0
                  if ((!fixed_size || fixed_size == child.size) &&
1220
0
                      value.depth < G_VARIANT_MAX_RECURSION_DEPTH - child_type_depth)
1221
0
                    return child;
1222
1223
0
                  g_variant_type_info_unref (child.type_info);
1224
0
                }
1225
0
            }
1226
0
        }
1227
0
    }
1228
1229
0
  child.type_info = g_variant_type_info_get (G_VARIANT_TYPE_UNIT);
1230
0
  child.data = NULL;
1231
0
  child.size = 1;
1232
0
  child.depth = value.depth + 1;
1233
1234
0
  return child;
1235
0
}
1236
1237
static inline gsize
1238
gvs_variant_needed_size (GVariantTypeInfo         *type_info,
1239
                         GVariantSerialisedFiller  gvs_filler,
1240
                         const gpointer           *children,
1241
                         gsize                     n_children)
1242
0
{
1243
0
  GVariantSerialised child = { 0, };
1244
0
  const gchar *type_string;
1245
1246
0
  gvs_filler (&child, children[0]);
1247
0
  type_string = g_variant_type_info_get_type_string (child.type_info);
1248
1249
0
  return child.size + 1 + strlen (type_string);
1250
0
}
1251
1252
static inline void
1253
gvs_variant_serialise (GVariantSerialised        value,
1254
                       GVariantSerialisedFiller  gvs_filler,
1255
                       const gpointer           *children,
1256
                       gsize                     n_children)
1257
0
{
1258
0
  GVariantSerialised child = { 0, };
1259
0
  const gchar *type_string;
1260
1261
0
  child.data = value.data;
1262
1263
0
  gvs_filler (&child, children[0]);
1264
0
  type_string = g_variant_type_info_get_type_string (child.type_info);
1265
0
  value.data[child.size] = '\0';
1266
0
  memcpy (value.data + child.size + 1, type_string, strlen (type_string));
1267
0
}
1268
1269
static inline gboolean
1270
gvs_variant_is_normal (GVariantSerialised value)
1271
0
{
1272
0
  GVariantSerialised child;
1273
0
  gboolean normal;
1274
0
  gsize child_type_depth;
1275
1276
0
  child = gvs_variant_get_child (value, 0);
1277
0
  child_type_depth = g_variant_type_info_query_depth (child.type_info);
1278
1279
0
  normal = (value.depth < G_VARIANT_MAX_RECURSION_DEPTH - child_type_depth) &&
1280
0
           (child.data != NULL || child.size == 0) &&
1281
0
           g_variant_serialised_is_normal (child);
1282
1283
0
  g_variant_type_info_unref (child.type_info);
1284
1285
0
  return normal;
1286
0
}
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
0
  {                                                     \
1305
0
    gsize fixed_size;                                   \
1306
0
                                                        \
1307
0
    g_variant_type_info_query_element (type_info, NULL, \
1308
0
                                       &fixed_size);    \
1309
0
                                                        \
1310
0
    if (fixed_size)                                     \
1311
0
      {                                                 \
1312
0
        before ## fixed_sized ## after                  \
1313
0
      }                                                 \
1314
0
    else                                                \
1315
0
      {                                                 \
1316
0
        before ## variable_sized ## after               \
1317
0
      }                                                 \
1318
0
  }
1319
1320
#define DISPATCH_CASES(type_info, before, after) \
1321
0
  switch (g_variant_type_info_get_type_char (type_info))        \
1322
0
    {                                                           \
1323
0
      case G_VARIANT_TYPE_INFO_CHAR_MAYBE:                      \
1324
0
        DISPATCH_FIXED (type_info, before, _maybe ## after)     \
1325
0
                                                                \
1326
0
      case G_VARIANT_TYPE_INFO_CHAR_ARRAY:                      \
1327
0
        DISPATCH_FIXED (type_info, before, _array ## after)     \
1328
0
                                                                \
1329
0
      case G_VARIANT_TYPE_INFO_CHAR_DICT_ENTRY:                 \
1330
0
      case G_VARIANT_TYPE_INFO_CHAR_TUPLE:                      \
1331
0
        {                                                       \
1332
0
          before ## tuple ## after                              \
1333
0
        }                                                       \
1334
0
                                                                \
1335
0
      case G_VARIANT_TYPE_INFO_CHAR_VARIANT:                    \
1336
0
        {                                                       \
1337
0
          before ## variant ## after                            \
1338
0
        }                                                       \
1339
0
    }
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
 */
1357
gsize
1358
g_variant_serialised_n_children (GVariantSerialised serialised)
1359
0
{
1360
0
  g_assert (g_variant_serialised_check (serialised));
1361
1362
0
  DISPATCH_CASES (serialised.type_info,
1363
1364
0
                  return gvs_/**/,/**/_n_children (serialised);
1365
1366
0
                 )
1367
0
  g_assert_not_reached ();
1368
0
}
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
 */
1391
GVariantSerialised
1392
g_variant_serialised_get_child (GVariantSerialised serialised,
1393
                                gsize              index_)
1394
0
{
1395
0
  GVariantSerialised child;
1396
1397
0
  g_assert (g_variant_serialised_check (serialised));
1398
1399
0
  if G_LIKELY (index_ < g_variant_serialised_n_children (serialised))
1400
0
    {
1401
0
      DISPATCH_CASES (serialised.type_info,
1402
1403
0
                      child = gvs_/**/,/**/_get_child (serialised, index_);
1404
0
                      g_assert (child.size || child.data == NULL);
1405
0
                      g_assert (g_variant_serialised_check (child));
1406
0
                      return child;
1407
1408
0
                     )
1409
0
      g_assert_not_reached ();
1410
0
    }
1411
1412
0
  g_error ("Attempt to access item %"G_GSIZE_FORMAT
1413
0
           " in a container with only %"G_GSIZE_FORMAT" items",
1414
0
           index_, g_variant_serialised_n_children (serialised));
1415
0
}
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
 */
1440
void
1441
g_variant_serialiser_serialise (GVariantSerialised        serialised,
1442
                                GVariantSerialisedFiller  gvs_filler,
1443
                                const gpointer           *children,
1444
                                gsize                     n_children)
1445
0
{
1446
0
  g_assert (g_variant_serialised_check (serialised));
1447
1448
0
  DISPATCH_CASES (serialised.type_info,
1449
1450
0
                  gvs_/**/,/**/_serialise (serialised, gvs_filler,
1451
0
                                           children, n_children);
1452
0
                  return;
1453
1454
0
                 )
1455
0
  g_assert_not_reached ();
1456
0
}
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
 */
1471
gsize
1472
g_variant_serialiser_needed_size (GVariantTypeInfo         *type_info,
1473
                                  GVariantSerialisedFiller  gvs_filler,
1474
                                  const gpointer           *children,
1475
                                  gsize                     n_children)
1476
0
{
1477
0
  DISPATCH_CASES (type_info,
1478
1479
0
                  return gvs_/**/,/**/_needed_size (type_info, gvs_filler,
1480
0
                                                    children, n_children);
1481
1482
0
                 )
1483
0
  g_assert_not_reached ();
1484
0
}
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
 */
1495
void
1496
g_variant_serialised_byteswap (GVariantSerialised serialised)
1497
0
{
1498
0
  gsize fixed_size;
1499
0
  guint alignment;
1500
1501
0
  g_assert (g_variant_serialised_check (serialised));
1502
1503
0
  if (!serialised.data)
1504
0
    return;
1505
1506
  /* the types we potentially need to byteswap are
1507
   * exactly those with alignment requirements.
1508
   */
1509
0
  g_variant_type_info_query (serialised.type_info, &alignment, &fixed_size);
1510
0
  if (!alignment)
1511
0
    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
0
  if (alignment + 1 == fixed_size)
1519
0
    {
1520
0
      switch (fixed_size)
1521
0
      {
1522
0
        case 2:
1523
0
          {
1524
0
            guint16 *ptr = (guint16 *) serialised.data;
1525
1526
0
            g_assert_cmpint (serialised.size, ==, 2);
1527
0
            *ptr = GUINT16_SWAP_LE_BE (*ptr);
1528
0
          }
1529
0
          return;
1530
1531
0
        case 4:
1532
0
          {
1533
0
            guint32 *ptr = (guint32 *) serialised.data;
1534
1535
0
            g_assert_cmpint (serialised.size, ==, 4);
1536
0
            *ptr = GUINT32_SWAP_LE_BE (*ptr);
1537
0
          }
1538
0
          return;
1539
1540
0
        case 8:
1541
0
          {
1542
0
            guint64 *ptr = (guint64 *) serialised.data;
1543
1544
0
            g_assert_cmpint (serialised.size, ==, 8);
1545
0
            *ptr = GUINT64_SWAP_LE_BE (*ptr);
1546
0
          }
1547
0
          return;
1548
1549
0
        default:
1550
0
          g_assert_not_reached ();
1551
0
      }
1552
0
    }
1553
1554
  /* else, we have a container that potentially contains
1555
   * some children that need to be byteswapped.
1556
   */
1557
0
  else
1558
0
    {
1559
0
      gsize children, i;
1560
1561
0
      children = g_variant_serialised_n_children (serialised);
1562
0
      for (i = 0; i < children; i++)
1563
0
        {
1564
0
          GVariantSerialised child;
1565
1566
0
          child = g_variant_serialised_get_child (serialised, i);
1567
0
          g_variant_serialised_byteswap (child);
1568
0
          g_variant_type_info_unref (child.type_info);
1569
0
        }
1570
0
    }
1571
0
}
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
 */
1587
gboolean
1588
g_variant_serialised_is_normal (GVariantSerialised serialised)
1589
0
{
1590
0
  DISPATCH_CASES (serialised.type_info,
1591
1592
0
                  return gvs_/**/,/**/_is_normal (serialised);
1593
1594
0
                 )
1595
1596
0
  if (serialised.data == NULL)
1597
0
    return FALSE;
1598
0
  if (serialised.depth >= G_VARIANT_MAX_RECURSION_DEPTH)
1599
0
    return FALSE;
1600
1601
  /* some hard-coded terminal cases */
1602
0
  switch (g_variant_type_info_get_type_char (serialised.type_info))
1603
0
    {
1604
0
    case 'b': /* boolean */
1605
0
      return serialised.data[0] < 2;
1606
1607
0
    case 's': /* string */
1608
0
      return g_variant_serialiser_is_string (serialised.data,
1609
0
                                             serialised.size);
1610
1611
0
    case 'o':
1612
0
      return g_variant_serialiser_is_object_path (serialised.data,
1613
0
                                                  serialised.size);
1614
1615
0
    case 'g':
1616
0
      return g_variant_serialiser_is_signature (serialised.data,
1617
0
                                                serialised.size);
1618
1619
0
    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
0
      return TRUE;
1625
0
    }
1626
0
}
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
 */
1641
gboolean
1642
g_variant_serialiser_is_string (gconstpointer data,
1643
                                gsize         size)
1644
0
{
1645
0
  const gchar *expected_end;
1646
0
  const gchar *end;
1647
1648
  /* Strings must end with a nul terminator. */
1649
0
  if (size == 0)
1650
0
    return FALSE;
1651
1652
0
  expected_end = ((gchar *) data) + size - 1;
1653
1654
0
  if (*expected_end != '\0')
1655
0
    return FALSE;
1656
1657
0
  g_utf8_validate_len (data, size, &end);
1658
1659
0
  return end == expected_end;
1660
0
}
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
 */
1672
gboolean
1673
g_variant_serialiser_is_object_path (gconstpointer data,
1674
                                     gsize         size)
1675
0
{
1676
0
  const gchar *string = data;
1677
0
  gsize i;
1678
1679
0
  if (!g_variant_serialiser_is_string (data, size))
1680
0
    return FALSE;
1681
1682
  /* The path must begin with an ASCII '/' (integer 47) character */
1683
0
  if (string[0] != '/')
1684
0
    return FALSE;
1685
1686
0
  for (i = 1; string[i]; i++)
1687
    /* Each element must only contain the ASCII characters
1688
     * "[A-Z][a-z][0-9]_"
1689
     */
1690
0
    if (g_ascii_isalnum (string[i]) || string[i] == '_')
1691
0
      ;
1692
1693
    /* must consist of elements separated by slash characters. */
1694
0
    else if (string[i] == '/')
1695
0
      {
1696
        /* No element may be the empty string. */
1697
        /* Multiple '/' characters cannot occur in sequence. */
1698
0
        if (string[i - 1] == '/')
1699
0
          return FALSE;
1700
0
      }
1701
1702
0
    else
1703
0
      return FALSE;
1704
1705
  /* A trailing '/' character is not allowed unless the path is the
1706
   * root path (a single '/' character).
1707
   */
1708
0
  if (i > 1 && string[i - 1] == '/')
1709
0
    return FALSE;
1710
1711
0
  return TRUE;
1712
0
}
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
 */
1726
gboolean
1727
g_variant_serialiser_is_signature (gconstpointer data,
1728
                                   gsize         size)
1729
0
{
1730
0
  const gchar *string = data;
1731
0
  gsize first_invalid;
1732
1733
0
  if (!g_variant_serialiser_is_string (data, size))
1734
0
    return FALSE;
1735
1736
  /* make sure no non-definite characters appear */
1737
0
  first_invalid = strspn (string, "ybnqiuxthdvasog(){}");
1738
0
  if (string[first_invalid])
1739
0
    return FALSE;
1740
1741
  /* make sure each type string is well-formed */
1742
0
  while (*string)
1743
0
    if (!g_variant_type_string_scan (string, NULL, &string))
1744
0
      return FALSE;
1745
1746
0
  return TRUE;
1747
0
}
1748
1749
/* Epilogue {{{1 */
1750
/* vim:set foldmethod=marker: */