Branch data Line data Source code
1 : : /*
2 : : * Copyright © 2007, 2008 Ryan Lortie
3 : : * Copyright © 2010 Codethink Limited
4 : : * Copyright © 2020 William Manley
5 : : *
6 : : * SPDX-License-Identifier: LGPL-2.1-or-later
7 : : *
8 : : * This library is free software; you can redistribute it and/or
9 : : * modify it under the terms of the GNU Lesser General Public
10 : : * License as published by the Free Software Foundation; either
11 : : * version 2.1 of the License, or (at your option) any later version.
12 : : *
13 : : * This library is distributed in the hope that it will be useful,
14 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 : : * Lesser General Public License for more details.
17 : : *
18 : : * You should have received a copy of the GNU Lesser General Public
19 : : * License along with this library; if not, see <http://www.gnu.org/licenses/>.
20 : : *
21 : : * Author: Ryan Lortie <desrt@desrt.ca>
22 : : */
23 : :
24 : : /* Prologue {{{1 */
25 : : #include "config.h"
26 : :
27 : : #include "gvariant-serialiser.h"
28 : :
29 : : #include <glib/gvariant-internal.h>
30 : : #include <glib/gtestutils.h>
31 : : #include <glib/gstrfuncs.h>
32 : : #include <glib/gtypes.h>
33 : :
34 : : #include <string.h>
35 : :
36 : :
37 : : /* GVariantSerialiser
38 : : *
39 : : * After this prologue section, this file has roughly 2 parts.
40 : : *
41 : : * The first part is split up into sections according to various
42 : : * container types. Maybe, Array, Tuple, Variant. The Maybe and Array
43 : : * sections are subdivided for element types being fixed or
44 : : * variable-sized types.
45 : : *
46 : : * Each section documents the format of that particular type of
47 : : * container and implements 5 functions for dealing with it:
48 : : *
49 : : * n_children:
50 : : * - determines (according to serialized data) how many child values
51 : : * are inside a particular container value.
52 : : *
53 : : * get_child:
54 : : * - gets the type of and the serialized data corresponding to a
55 : : * given child value within the container value.
56 : : *
57 : : * needed_size:
58 : : * - determines how much space would be required to serialize a
59 : : * container of this type, containing the given children so that
60 : : * buffers can be preallocated before serializing.
61 : : *
62 : : * serialise:
63 : : * - write the serialized data for a container of this type,
64 : : * containing the given children, to a buffer.
65 : : *
66 : : * is_normal:
67 : : * - check the given data to ensure that it is in normal form. For a
68 : : * given set of child values, there is exactly one normal form for
69 : : * the serialized data of a container. Other forms are possible
70 : : * while maintaining the same children (for example, by inserting
71 : : * something other than zero bytes as padding) but only one form is
72 : : * the normal form.
73 : : *
74 : : * The second part contains the main entry point for each of the above 5
75 : : * functions and logic to dispatch it to the handler for the appropriate
76 : : * container type code.
77 : : *
78 : : * The second part also contains a routine to byteswap serialized
79 : : * values. This code makes use of the n_children() and get_child()
80 : : * functions above to do its work so no extra support is needed on a
81 : : * per-container-type basis.
82 : : *
83 : : * There is also additional code for checking for normal form. All
84 : : * numeric types are always in normal form since the full range of
85 : : * values is permitted (eg: 0 to 255 is a valid byte). Special checks
86 : : * need to be performed for booleans (only 0 or 1 allowed), strings
87 : : * (properly nul-terminated) and object paths and signature strings
88 : : * (meeting the D-Bus specification requirements). Depth checks need to be
89 : : * performed for nested types (arrays, tuples, and variants), to avoid massive
90 : : * recursion which could exhaust our stack when handling untrusted input.
91 : : */
92 : :
93 : : /* < private >
94 : : * GVariantSerialised:
95 : : * @type_info: the #GVariantTypeInfo of this value
96 : : * @data: (nullable): the serialized data of this value, or %NULL
97 : : * @size: the size of this value
98 : : *
99 : : * A structure representing a GVariant in serialized form. This
100 : : * structure is used with #GVariantSerialisedFiller functions and as the
101 : : * primary interface to the serializer. See #GVariantSerialisedFiller
102 : : * for a description of its use there.
103 : : *
104 : : * When used with the serializer API functions, the following invariants
105 : : * apply to all #GVariantTypeSerialised structures passed to and
106 : : * returned from the serializer.
107 : : *
108 : : * @type_info must be non-%NULL.
109 : : *
110 : : * @data must be properly aligned for the type described by @type_info.
111 : : *
112 : : * If @type_info describes a fixed-sized type then @size must always be
113 : : * equal to the fixed size of that type.
114 : : *
115 : : * For fixed-sized types (and only fixed-sized types), @data may be
116 : : * %NULL even if @size is non-zero. This happens when a framing error
117 : : * occurs while attempting to extract a fixed-sized value out of a
118 : : * variable-sized container. There is no data to return for the
119 : : * fixed-sized type, yet @size must be non-zero. The effect of this
120 : : * combination should be as if @data were a pointer to an
121 : : * appropriately-sized zero-filled region.
122 : : *
123 : : * @depth has no restrictions; the depth of a top-level serialized #GVariant is
124 : : * zero, and it increases for each level of nested child.
125 : : *
126 : : * @checked_offsets_up_to is always ≥ @ordered_offsets_up_to
127 : : */
128 : :
129 : : /* < private >
130 : : * g_variant_serialised_check:
131 : : * @serialised: a #GVariantSerialised struct
132 : : *
133 : : * Checks @serialised for validity according to the invariants described
134 : : * above.
135 : : *
136 : : * Returns: %TRUE if @serialised is valid; %FALSE otherwise
137 : : */
138 : : gboolean
139 : 93399494 : g_variant_serialised_check (GVariantSerialised serialised)
140 : : {
141 : : gsize fixed_size;
142 : : guint alignment;
143 : :
144 : 93399494 : if (serialised.type_info == NULL)
145 : 0 : return FALSE;
146 : 93399494 : g_variant_type_info_query (serialised.type_info, &alignment, &fixed_size);
147 : :
148 : 93399494 : if (fixed_size != 0 && serialised.size != fixed_size)
149 : 136 : return FALSE;
150 : 116489232 : else if (fixed_size == 0 &&
151 : 83003390 : !(serialised.size == 0 || serialised.data != NULL))
152 : 0 : return FALSE;
153 : :
154 : 93399358 : if (serialised.ordered_offsets_up_to > serialised.checked_offsets_up_to)
155 : 0 : return FALSE;
156 : :
157 : : /* Depending on the native alignment requirements of the machine, the
158 : : * compiler will insert either 3 or 7 padding bytes after the char.
159 : : * This will result in the sizeof() the struct being 12 or 16.
160 : : * Subtract 9 to get 3 or 7 which is a nice bitmask to apply to get
161 : : * the alignment bits that we "care about" being zero: in the
162 : : * 4-aligned case, we care about 2 bits, and in the 8-aligned case, we
163 : : * care about 3 bits.
164 : : */
165 : 93399358 : alignment &= sizeof (struct {
166 : : char a;
167 : : union {
168 : : guint64 x;
169 : : void *y;
170 : : gdouble z;
171 : : } b;
172 : : }
173 : : ) - 9;
174 : :
175 : : /* Some OSes (FreeBSD is a known example) have a malloc() that returns
176 : : * unaligned memory if you request small sizes. 'malloc (1);', for
177 : : * example, has been seen to return pointers aligned to 6 mod 16.
178 : : *
179 : : * Check if this is a small allocation and return without enforcing
180 : : * the alignment assertion if this is the case.
181 : : */
182 : 129138794 : return (serialised.size <= alignment ||
183 : 67691026 : (alignment & (gsize) serialised.data) == 0);
184 : 35223008 : }
185 : :
186 : : /* < private >
187 : : * GVariantSerialisedFiller:
188 : : * @serialised: a #GVariantSerialised instance to fill
189 : : * @data: data from the children array
190 : : *
191 : : * This function is called back from g_variant_serialiser_needed_size()
192 : : * and g_variant_serialiser_serialise(). It fills in missing details
193 : : * from a partially-complete #GVariantSerialised.
194 : : *
195 : : * The @data parameter passed back to the function is one of the items
196 : : * that was passed to the serializer in the @children array. It
197 : : * represents a single child item of the container that is being
198 : : * serialized. The information filled in to @serialised is the
199 : : * information for this child.
200 : : *
201 : : * If the @type_info field of @serialised is %NULL then the callback
202 : : * function must set it to the type information corresponding to the
203 : : * type of the child. No reference should be added. If it is non-%NULL
204 : : * then the callback should assert that it is equal to the actual type
205 : : * of the child.
206 : : *
207 : : * If the @size field is zero then the callback must fill it in with the
208 : : * required amount of space to store the serialized form of the child.
209 : : * If it is non-zero then the callback should assert that it is equal to
210 : : * the needed size of the child.
211 : : *
212 : : * If @data is non-%NULL then it points to a space that is properly
213 : : * aligned for and large enough to store the serialized data of the
214 : : * child. The callback must store the serialized form of the child at
215 : : * @data.
216 : : *
217 : : * If the child value is another container then the callback will likely
218 : : * recurse back into the serializer by calling
219 : : * g_variant_serialiser_needed_size() to determine @size and
220 : : * g_variant_serialiser_serialise() to write to @data.
221 : : */
222 : :
223 : : /* PART 1: Container types {{{1
224 : : *
225 : : * This section contains the serializer implementation functions for
226 : : * each container type.
227 : : */
228 : :
229 : : /* Maybe {{{2
230 : : *
231 : : * Maybe types are handled depending on if the element type of the maybe
232 : : * type is a fixed-sized or variable-sized type. Although all maybe
233 : : * types themselves are variable-sized types, herein, a maybe value with
234 : : * a fixed-sized element type is called a "fixed-sized maybe" for
235 : : * convenience and a maybe value with a variable-sized element type is
236 : : * called a "variable-sized maybe".
237 : : */
238 : :
239 : : /* Fixed-sized Maybe {{{3
240 : : *
241 : : * The size of a maybe value with a fixed-sized element type is either 0
242 : : * or equal to the fixed size of its element type. The case where the
243 : : * size of the maybe value is zero corresponds to the "Nothing" case and
244 : : * the case where the size of the maybe value is equal to the fixed size
245 : : * of the element type corresponds to the "Just" case; in that case, the
246 : : * serialized data of the child value forms the entire serialized data
247 : : * of the maybe value.
248 : : *
249 : : * In the event that a fixed-sized maybe value is presented with a size
250 : : * that is not equal to the fixed size of the element type then the
251 : : * value must be taken to be "Nothing".
252 : : */
253 : :
254 : : static gsize
255 : 140091 : gvs_fixed_sized_maybe_n_children (GVariantSerialised value)
256 : : {
257 : : gsize element_fixed_size;
258 : :
259 : 140091 : g_variant_type_info_query_element (value.type_info, NULL,
260 : : &element_fixed_size);
261 : :
262 : 140091 : return (element_fixed_size == value.size) ? 1 : 0;
263 : : }
264 : :
265 : : static GVariantSerialised
266 : 41451 : gvs_fixed_sized_maybe_get_child (GVariantSerialised value,
267 : : gsize index_)
268 : : {
269 : : /* the child has the same bounds as the
270 : : * container, so just update the type.
271 : : */
272 : 41451 : value.type_info = g_variant_type_info_element (value.type_info);
273 : 41451 : g_variant_type_info_ref (value.type_info);
274 : 41451 : value.depth++;
275 : 41451 : value.ordered_offsets_up_to = 0;
276 : 41451 : value.checked_offsets_up_to = 0;
277 : :
278 : 41451 : return value;
279 : : }
280 : :
281 : : static gsize
282 : 166829 : gvs_fixed_sized_maybe_needed_size (GVariantTypeInfo *type_info,
283 : : GVariantSerialisedFiller gvs_filler,
284 : : const gpointer *children,
285 : : gsize n_children)
286 : : {
287 : 166829 : if (n_children)
288 : : {
289 : : gsize element_fixed_size;
290 : :
291 : 82666 : g_variant_type_info_query_element (type_info, NULL,
292 : : &element_fixed_size);
293 : :
294 : 82666 : return element_fixed_size;
295 : : }
296 : : else
297 : 84163 : return 0;
298 : 57449 : }
299 : :
300 : : static void
301 : 60691 : gvs_fixed_sized_maybe_serialise (GVariantSerialised value,
302 : : GVariantSerialisedFiller gvs_filler,
303 : : const gpointer *children,
304 : : gsize n_children)
305 : : {
306 : 60691 : if (n_children)
307 : : {
308 : 31993 : GVariantSerialised child = { NULL, value.data, value.size, value.depth + 1, 0, 0 };
309 : :
310 : 31993 : gvs_filler (&child, children[0]);
311 : 11639 : }
312 : 60691 : }
313 : :
314 : : static gboolean
315 : 41147 : gvs_fixed_sized_maybe_is_normal (GVariantSerialised value)
316 : : {
317 : 41147 : if (value.size > 0)
318 : : {
319 : : gsize element_fixed_size;
320 : :
321 : 20516 : g_variant_type_info_query_element (value.type_info,
322 : : NULL, &element_fixed_size);
323 : :
324 : 20516 : if (value.size != element_fixed_size)
325 : 36 : return FALSE;
326 : :
327 : : /* proper element size: "Just". recurse to the child. */
328 : 20480 : value.type_info = g_variant_type_info_element (value.type_info);
329 : 20480 : value.depth++;
330 : 20480 : value.ordered_offsets_up_to = 0;
331 : 20480 : value.checked_offsets_up_to = 0;
332 : :
333 : 20480 : return g_variant_serialised_is_normal (value);
334 : : }
335 : :
336 : : /* size of 0: "Nothing" */
337 : 20631 : return TRUE;
338 : 17784 : }
339 : :
340 : : /* Variable-sized Maybe
341 : : *
342 : : * The size of a maybe value with a variable-sized element type is
343 : : * either 0 or strictly greater than 0. The case where the size of the
344 : : * maybe value is zero corresponds to the "Nothing" case and the case
345 : : * where the size of the maybe value is greater than zero corresponds to
346 : : * the "Just" case; in that case, the serialized data of the child value
347 : : * forms the first part of the serialized data of the maybe value and is
348 : : * followed by a single zero byte. This zero byte is always appended,
349 : : * regardless of any zero bytes that may already be at the end of the
350 : : * serialized ata of the child value.
351 : : */
352 : :
353 : : static gsize
354 : 64845 : gvs_variable_sized_maybe_n_children (GVariantSerialised value)
355 : : {
356 : 64845 : return (value.size > 0) ? 1 : 0;
357 : : }
358 : :
359 : : static GVariantSerialised
360 : 20579 : gvs_variable_sized_maybe_get_child (GVariantSerialised value,
361 : : gsize index_)
362 : : {
363 : : /* remove the padding byte and update the type. */
364 : 20579 : value.type_info = g_variant_type_info_element (value.type_info);
365 : 20579 : g_variant_type_info_ref (value.type_info);
366 : 20579 : value.size--;
367 : :
368 : : /* if it's zero-sized then it may as well be NULL */
369 : 20579 : if (value.size == 0)
370 : 368 : value.data = NULL;
371 : :
372 : 20579 : value.depth++;
373 : 20579 : value.ordered_offsets_up_to = 0;
374 : 20579 : value.checked_offsets_up_to = 0;
375 : :
376 : 20579 : return value;
377 : : }
378 : :
379 : : static gsize
380 : 86810 : gvs_variable_sized_maybe_needed_size (GVariantTypeInfo *type_info,
381 : : GVariantSerialisedFiller gvs_filler,
382 : : const gpointer *children,
383 : : gsize n_children)
384 : : {
385 : 86810 : if (n_children)
386 : : {
387 : 43459 : GVariantSerialised child = { 0, };
388 : :
389 : 43459 : gvs_filler (&child, children[0]);
390 : :
391 : 43459 : return child.size + 1;
392 : : }
393 : : else
394 : 43351 : return 0;
395 : 76256 : }
396 : :
397 : : static void
398 : 33969 : gvs_variable_sized_maybe_serialise (GVariantSerialised value,
399 : : GVariantSerialisedFiller gvs_filler,
400 : : const gpointer *children,
401 : : gsize n_children)
402 : : {
403 : 33969 : if (n_children)
404 : : {
405 : 19078 : GVariantSerialised child = { NULL, value.data, value.size - 1, value.depth + 1, 0, 0 };
406 : :
407 : : /* write the data for the child. */
408 : 19078 : gvs_filler (&child, children[0]);
409 : 19078 : value.data[child.size] = '\0';
410 : 14925 : }
411 : 33969 : }
412 : :
413 : : static gboolean
414 : 15385 : gvs_variable_sized_maybe_is_normal (GVariantSerialised value)
415 : : {
416 : 15385 : if (value.size == 0)
417 : 7566 : return TRUE;
418 : :
419 : 7819 : if (value.data[value.size - 1] != '\0')
420 : 34 : return FALSE;
421 : :
422 : 7785 : value.type_info = g_variant_type_info_element (value.type_info);
423 : 7785 : value.size--;
424 : 7785 : value.depth++;
425 : 7785 : value.ordered_offsets_up_to = 0;
426 : 7785 : value.checked_offsets_up_to = 0;
427 : :
428 : 7785 : return g_variant_serialised_is_normal (value);
429 : 12595 : }
430 : :
431 : : /* Arrays {{{2
432 : : *
433 : : * Just as with maybe types, array types are handled depending on if the
434 : : * element type of the array type is a fixed-sized or variable-sized
435 : : * type. Similar to maybe types, for convenience, an array value with a
436 : : * fixed-sized element type is called a "fixed-sized array" and an array
437 : : * value with a variable-sized element type is called a "variable sized
438 : : * array".
439 : : */
440 : :
441 : : /* Fixed-sized Array {{{3
442 : : *
443 : : * For fixed sized arrays, the serialized data is simply a concatenation
444 : : * of the serialized data of each element, in order. Since fixed-sized
445 : : * values always have a fixed size that is a multiple of their alignment
446 : : * requirement no extra padding is required.
447 : : *
448 : : * In the event that a fixed-sized array is presented with a size that
449 : : * is not an integer multiple of the element size then the value of the
450 : : * array must be taken as being empty.
451 : : */
452 : :
453 : : static gsize
454 : 7919814 : gvs_fixed_sized_array_n_children (GVariantSerialised value)
455 : : {
456 : : gsize element_fixed_size;
457 : :
458 : 7919814 : g_variant_type_info_query_element (value.type_info, NULL,
459 : : &element_fixed_size);
460 : :
461 : 7919814 : if (value.size % element_fixed_size == 0)
462 : 7919763 : return value.size / element_fixed_size;
463 : :
464 : 51 : return 0;
465 : 7181990 : }
466 : :
467 : : static GVariantSerialised
468 : 7771978 : gvs_fixed_sized_array_get_child (GVariantSerialised value,
469 : : gsize index_)
470 : : {
471 : 7771978 : GVariantSerialised child = { 0, };
472 : :
473 : 7771978 : child.type_info = g_variant_type_info_element (value.type_info);
474 : 7771978 : g_variant_type_info_query (child.type_info, NULL, &child.size);
475 : 7771978 : child.data = value.data + (child.size * index_);
476 : 7771978 : g_variant_type_info_ref (child.type_info);
477 : 7771978 : child.depth = value.depth + 1;
478 : :
479 : 7771978 : return child;
480 : : }
481 : :
482 : : static gsize
483 : 190684 : gvs_fixed_sized_array_needed_size (GVariantTypeInfo *type_info,
484 : : GVariantSerialisedFiller gvs_filler,
485 : : const gpointer *children,
486 : : gsize n_children)
487 : : {
488 : : gsize element_fixed_size;
489 : :
490 : 190684 : g_variant_type_info_query_element (type_info, NULL, &element_fixed_size);
491 : :
492 : 190684 : return element_fixed_size * n_children;
493 : : }
494 : :
495 : : static void
496 : 78219 : gvs_fixed_sized_array_serialise (GVariantSerialised value,
497 : : GVariantSerialisedFiller gvs_filler,
498 : : const gpointer *children,
499 : : gsize n_children)
500 : : {
501 : 78219 : GVariantSerialised child = { 0, };
502 : : gsize i;
503 : :
504 : 78219 : child.type_info = g_variant_type_info_element (value.type_info);
505 : 78219 : g_variant_type_info_query (child.type_info, NULL, &child.size);
506 : 78219 : child.data = value.data;
507 : 78219 : child.depth = value.depth + 1;
508 : :
509 : 4941623 : for (i = 0; i < n_children; i++)
510 : : {
511 : 4863404 : gvs_filler (&child, children[i]);
512 : 4863404 : child.data += child.size;
513 : 4246420 : }
514 : 78219 : }
515 : :
516 : : static gboolean
517 : 35918 : gvs_fixed_sized_array_is_normal (GVariantSerialised value)
518 : : {
519 : 35918 : GVariantSerialised child = { 0, };
520 : : gsize offset;
521 : :
522 : 35918 : child.type_info = g_variant_type_info_element (value.type_info);
523 : 35918 : g_variant_type_info_query (child.type_info, NULL, &child.size);
524 : 35918 : child.depth = value.depth + 1;
525 : :
526 : 35918 : if (value.size % child.size != 0)
527 : 32 : return FALSE;
528 : :
529 : 2270246 : for (offset = 0; offset < value.size; offset += child.size)
530 : : {
531 : 2234404 : child.data = value.data + offset;
532 : 2234404 : if (!g_variant_serialised_is_normal (child))
533 : 44 : return FALSE;
534 : 1739003 : }
535 : :
536 : 35842 : return TRUE;
537 : 27822 : }
538 : :
539 : : /* Variable-sized Array {{{3
540 : : *
541 : : * Variable sized arrays, containing variable-sized elements, must be
542 : : * able to determine the boundaries between the elements. The items
543 : : * cannot simply be concatenated. Additionally, we are faced with the
544 : : * fact that non-fixed-sized values do not necessarily have a size that
545 : : * is a multiple of their alignment requirement, so we may need to
546 : : * insert zero-filled padding.
547 : : *
548 : : * While it is possible to find the start of an item by starting from
549 : : * the end of the item before it and padding for alignment, it is not
550 : : * generally possible to do the reverse operation. For this reason, we
551 : : * record the end point of each element in the array.
552 : : *
553 : : * GVariant works in terms of "offsets". An offset is a pointer to a
554 : : * boundary between two bytes. In 4 bytes of serialized data, there
555 : : * would be 5 possible offsets: one at the start ('0'), one between each
556 : : * pair of adjacent bytes ('1', '2', '3') and one at the end ('4').
557 : : *
558 : : * The numeric value of an offset is an unsigned integer given relative
559 : : * to the start of the serialized data of the array. Offsets are always
560 : : * stored in little endian byte order and are always only as big as they
561 : : * need to be. For example, in 255 bytes of serialized data, there are
562 : : * 256 offsets. All possibilities can be stored in an 8 bit unsigned
563 : : * integer. In 256 bytes of serialized data, however, there are 257
564 : : * possible offsets so 16 bit integers must be used. The size of an
565 : : * offset is always a power of 2.
566 : : *
567 : : * The offsets are stored at the end of the serialized data of the
568 : : * array. They are simply concatenated on without any particular
569 : : * alignment. The size of the offsets is included in the size of the
570 : : * serialized data for purposes of determining the size of the offsets.
571 : : * This presents a possibly ambiguity; in certain cases, a particular
572 : : * value of array could have two different serialized forms.
573 : : *
574 : : * Imagine an array containing a single string of 253 bytes in length
575 : : * (so, 254 bytes including the nul terminator). Now the offset must be
576 : : * written. If an 8 bit offset is written, it will bring the size of
577 : : * the array's serialized data to 255 -- which means that the use of an
578 : : * 8 bit offset was valid. If a 16 bit offset is used then the total
579 : : * size of the array will be 256 -- which means that the use of a 16 bit
580 : : * offset was valid. Although both of these will be accepted by the
581 : : * deserializer, only the smaller of the two is considered to be in
582 : : * normal form and that is the one that the serializer must produce.
583 : : */
584 : :
585 : : /* bytes may be NULL if (size == 0). */
586 : : static inline gsize
587 : 49642387 : gvs_read_unaligned_le (guchar *bytes,
588 : : guint size)
589 : : {
590 : : union
591 : : {
592 : : guchar bytes[GLIB_SIZEOF_SIZE_T];
593 : : gsize integer;
594 : : } tmpvalue;
595 : :
596 : 49642387 : tmpvalue.integer = 0;
597 : 49642387 : if (bytes != NULL)
598 : 49642387 : memcpy (&tmpvalue.bytes, bytes, size);
599 : :
600 : 49642387 : return GSIZE_FROM_LE (tmpvalue.integer);
601 : : }
602 : :
603 : : static inline void
604 : 2087780 : gvs_write_unaligned_le (guchar *bytes,
605 : : gsize value,
606 : : guint size)
607 : : {
608 : : union
609 : : {
610 : : guchar bytes[GLIB_SIZEOF_SIZE_T];
611 : : gsize integer;
612 : : } tmpvalue;
613 : :
614 : 2087780 : tmpvalue.integer = GSIZE_TO_LE (value);
615 : 2087780 : memcpy (bytes, &tmpvalue.bytes, size);
616 : 2087780 : }
617 : :
618 : : static guint
619 : 38537653 : gvs_get_offset_size (gsize size)
620 : : {
621 : 38537653 : if (size > G_MAXUINT32)
622 : 0 : return 8;
623 : :
624 : 38537653 : else if (size > G_MAXUINT16)
625 : 32346072 : return 4;
626 : :
627 : 6191581 : else if (size > G_MAXUINT8)
628 : 5168562 : return 2;
629 : :
630 : 1023019 : else if (size > 0)
631 : 777013 : return 1;
632 : :
633 : 246006 : return 0;
634 : 7010162 : }
635 : :
636 : : static gsize
637 : 37275807 : gvs_calculate_total_size (gsize body_size,
638 : : gsize offsets)
639 : : {
640 : 37275807 : if (body_size + 1 * offsets <= G_MAXUINT8)
641 : 280366 : return body_size + 1 * offsets;
642 : :
643 : 36995441 : if (body_size + 2 * offsets <= G_MAXUINT16)
644 : 4649753 : return body_size + 2 * offsets;
645 : :
646 : 32345688 : if (body_size + 4 * offsets <= G_MAXUINT32)
647 : 32345688 : return body_size + 4 * offsets;
648 : :
649 : 0 : return body_size + 8 * offsets;
650 : 6293528 : }
651 : :
652 : : struct Offsets
653 : : {
654 : : gsize data_size;
655 : :
656 : : guchar *array;
657 : : gsize length;
658 : : guint offset_size;
659 : :
660 : : gboolean is_normal;
661 : : };
662 : :
663 : : static gsize
664 : 3900120 : gvs_offsets_get_offset_n (struct Offsets *offsets,
665 : : gsize n)
666 : : {
667 : 5962902 : return gvs_read_unaligned_le (
668 : 3900120 : offsets->array + (offsets->offset_size * n), offsets->offset_size);
669 : : }
670 : :
671 : : static struct Offsets
672 : 44937713 : gvs_variable_sized_array_get_frame_offsets (GVariantSerialised value)
673 : : {
674 : 44937713 : struct Offsets out = { 0, };
675 : : gsize offsets_array_size;
676 : : gsize last_end;
677 : :
678 : 44937713 : if (value.size == 0)
679 : : {
680 : 8099567 : out.is_normal = TRUE;
681 : 8099567 : return out;
682 : : }
683 : :
684 : 36838146 : out.offset_size = gvs_get_offset_size (value.size);
685 : 42850656 : last_end = gvs_read_unaligned_le (value.data + value.size - out.offset_size,
686 : 6012510 : out.offset_size);
687 : :
688 : 36838146 : if (last_end > value.size)
689 : 87 : return out; /* offsets not normal */
690 : :
691 : 36838059 : offsets_array_size = value.size - last_end;
692 : :
693 : 36838059 : if (offsets_array_size % out.offset_size)
694 : 98 : return out; /* offsets not normal */
695 : :
696 : 36837961 : out.data_size = last_end;
697 : 36837961 : out.array = value.data + last_end;
698 : 36837961 : out.length = offsets_array_size / out.offset_size;
699 : :
700 : 36837961 : if (out.length > 0 && gvs_calculate_total_size (last_end, out.length) != value.size)
701 : 1217 : return out; /* offset size not minimal */
702 : :
703 : 36836744 : out.is_normal = TRUE;
704 : :
705 : 36836744 : return out;
706 : 6999094 : }
707 : :
708 : : static gsize
709 : 26525161 : gvs_variable_sized_array_n_children (GVariantSerialised value)
710 : : {
711 : 26525161 : return gvs_variable_sized_array_get_frame_offsets (value).length;
712 : : }
713 : :
714 : : /* Find the index of the first out-of-order element in @data, assuming that
715 : : * @data is an array of elements of given @type, starting at index @start and
716 : : * containing a further @len-@start elements. */
717 : : #define DEFINE_FIND_UNORDERED(type, le_to_native) \
718 : : static gsize \
719 : : find_unordered_##type (const guint8 *data, gsize start, gsize len) \
720 : : { \
721 : : gsize off; \
722 : : type current_le, previous_le, current, previous; \
723 : : \
724 : : memcpy (&previous_le, data + start * sizeof (current), sizeof (current)); \
725 : : previous = le_to_native (previous_le); \
726 : : for (off = (start + 1) * sizeof (current); off < len * sizeof (current); off += sizeof (current)) \
727 : : { \
728 : : memcpy (¤t_le, data + off, sizeof (current)); \
729 : : current = le_to_native (current_le); \
730 : : if (current < previous) \
731 : : break; \
732 : : previous = current; \
733 : : } \
734 : : return off / sizeof (current) - 1; \
735 : : }
736 : :
737 : : #define NO_CONVERSION(x) (x)
738 : 807763 : DEFINE_FIND_UNORDERED (guint8, NO_CONVERSION);
739 : 49175682 : DEFINE_FIND_UNORDERED (guint16, GUINT16_FROM_LE);
740 : 18602763 : DEFINE_FIND_UNORDERED (guint32, GUINT32_FROM_LE);
741 : 0 : DEFINE_FIND_UNORDERED (guint64, GUINT64_FROM_LE);
742 : :
743 : : static GVariantSerialised
744 : 18394230 : gvs_variable_sized_array_get_child (GVariantSerialised value,
745 : : gsize index_)
746 : : {
747 : 18394230 : GVariantSerialised child = { 0, };
748 : :
749 : 18394230 : struct Offsets offsets = gvs_variable_sized_array_get_frame_offsets (value);
750 : :
751 : : gsize start;
752 : : gsize end;
753 : :
754 : 18394230 : child.type_info = g_variant_type_info_element (value.type_info);
755 : 18394230 : g_variant_type_info_ref (child.type_info);
756 : 18394230 : child.depth = value.depth + 1;
757 : :
758 : : /* If the requested @index_ is beyond the set of indices whose framing offsets
759 : : * have been checked, check the remaining offsets to see whether they’re
760 : : * normal (in order, no overlapping array elements).
761 : : *
762 : : * Don’t bother checking if the highest known-good offset is lower than the
763 : : * highest checked offset, as that means there’s an invalid element at that
764 : : * index, so there’s no need to check further. */
765 : 18394230 : if (offsets.array != NULL &&
766 : 18394230 : index_ > value.checked_offsets_up_to &&
767 : 17585385 : value.ordered_offsets_up_to == value.checked_offsets_up_to)
768 : : {
769 : 17585385 : switch (offsets.offset_size)
770 : : {
771 : 12627 : case 1:
772 : : {
773 : 35032 : value.ordered_offsets_up_to = find_unordered_guint8 (
774 : 22405 : offsets.array, value.checked_offsets_up_to, index_ + 1);
775 : 22405 : break;
776 : : }
777 : 554444 : case 2:
778 : : {
779 : 1956740 : value.ordered_offsets_up_to = find_unordered_guint16 (
780 : 1402296 : offsets.array, value.checked_offsets_up_to, index_ + 1);
781 : 1402296 : break;
782 : : }
783 : 14199751 : case 4:
784 : : {
785 : 30360435 : value.ordered_offsets_up_to = find_unordered_guint32 (
786 : 16160684 : offsets.array, value.checked_offsets_up_to, index_ + 1);
787 : 16160684 : break;
788 : : }
789 : 0 : case 8:
790 : : {
791 : 0 : value.ordered_offsets_up_to = find_unordered_guint64 (
792 : 0 : offsets.array, value.checked_offsets_up_to, index_ + 1);
793 : 0 : break;
794 : : }
795 : 0 : default:
796 : : /* gvs_get_offset_size() only returns maximum 8 */
797 : : g_assert_not_reached ();
798 : 0 : }
799 : :
800 : 17585385 : value.checked_offsets_up_to = index_;
801 : 2818563 : }
802 : :
803 : 18394230 : if (index_ > value.ordered_offsets_up_to)
804 : : {
805 : : /* Offsets are invalid somewhere, so return an empty child. */
806 : 16427762 : return child;
807 : : }
808 : :
809 : 1966468 : if (index_ > 0)
810 : : {
811 : : guint alignment;
812 : :
813 : 1933652 : start = gvs_offsets_get_offset_n (&offsets, index_ - 1);
814 : :
815 : 1933652 : g_variant_type_info_query (child.type_info, &alignment, NULL);
816 : 1933652 : start += (-start) & alignment;
817 : 911333 : }
818 : : else
819 : 32816 : start = 0;
820 : :
821 : 1966468 : end = gvs_offsets_get_offset_n (&offsets, index_);
822 : :
823 : 1966468 : if (start < end && end <= value.size && end <= offsets.data_size)
824 : : {
825 : 1921135 : child.data = value.data + start;
826 : 1921135 : child.size = end - start;
827 : 903714 : }
828 : :
829 : 1966468 : return child;
830 : 2993001 : }
831 : :
832 : : static gsize
833 : 82520 : gvs_variable_sized_array_needed_size (GVariantTypeInfo *type_info,
834 : : GVariantSerialisedFiller gvs_filler,
835 : : const gpointer *children,
836 : : gsize n_children)
837 : : {
838 : : guint alignment;
839 : : gsize offset;
840 : : gsize i;
841 : :
842 : 82520 : g_variant_type_info_query (type_info, &alignment, NULL);
843 : 82520 : offset = 0;
844 : :
845 : 5191595 : for (i = 0; i < n_children; i++)
846 : : {
847 : 5109075 : GVariantSerialised child = { 0, };
848 : :
849 : 5109075 : offset += (-offset) & alignment;
850 : 5109075 : gvs_filler (&child, children[i]);
851 : 5109075 : offset += child.size;
852 : 2285587 : }
853 : :
854 : 82520 : return gvs_calculate_total_size (offset, n_children);
855 : : }
856 : :
857 : : static void
858 : 31768 : gvs_variable_sized_array_serialise (GVariantSerialised value,
859 : : GVariantSerialisedFiller gvs_filler,
860 : : const gpointer *children,
861 : : gsize n_children)
862 : : {
863 : : guchar *offset_ptr;
864 : : gsize offset_size;
865 : : guint alignment;
866 : : gsize offset;
867 : : gsize i;
868 : :
869 : : /* Nothing to write, and @value.data may be NULL. */
870 : 31768 : if (n_children == 0)
871 : 538 : return;
872 : :
873 : 31230 : g_variant_type_info_query (value.type_info, &alignment, NULL);
874 : 31230 : offset_size = gvs_get_offset_size (value.size);
875 : 31230 : offset = 0;
876 : :
877 : 31230 : offset_ptr = value.data + value.size - offset_size * n_children;
878 : :
879 : 1907473 : for (i = 0; i < n_children; i++)
880 : : {
881 : 1876243 : GVariantSerialised child = { 0, };
882 : :
883 : 2299307 : while (offset & alignment)
884 : 423064 : value.data[offset++] = '\0';
885 : :
886 : 1876243 : child.data = value.data + offset;
887 : 1876243 : gvs_filler (&child, children[i]);
888 : 1876243 : offset += child.size;
889 : :
890 : 1876243 : gvs_write_unaligned_le (offset_ptr, offset, offset_size);
891 : 1876243 : offset_ptr += offset_size;
892 : 869262 : }
893 : 13802 : }
894 : :
895 : : static gboolean
896 : 18322 : gvs_variable_sized_array_is_normal (GVariantSerialised value)
897 : : {
898 : 18322 : GVariantSerialised child = { 0, };
899 : : guint alignment;
900 : : gsize offset;
901 : : gsize i;
902 : :
903 : 18322 : struct Offsets offsets = gvs_variable_sized_array_get_frame_offsets (value);
904 : :
905 : 18322 : if (!offsets.is_normal)
906 : 80 : return FALSE;
907 : :
908 : 18242 : if (value.size != 0 && offsets.length == 0)
909 : 0 : return FALSE;
910 : :
911 : 18242 : g_assert (value.size != 0 || offsets.length == 0);
912 : :
913 : 18242 : child.type_info = g_variant_type_info_element (value.type_info);
914 : 18242 : g_variant_type_info_query (child.type_info, &alignment, NULL);
915 : 18242 : child.depth = value.depth + 1;
916 : 18242 : offset = 0;
917 : :
918 : 1135022 : for (i = 0; i < offsets.length; i++)
919 : : {
920 : : gsize this_end;
921 : :
922 : 1852551 : this_end = gvs_read_unaligned_le (offsets.array + offsets.offset_size * i,
923 : 735436 : offsets.offset_size);
924 : :
925 : 1117115 : if (this_end < offset || this_end > offsets.data_size)
926 : 87 : return FALSE;
927 : :
928 : 1383363 : while (offset & alignment)
929 : : {
930 : 266353 : if (!(offset < this_end && value.data[offset] == '\0'))
931 : 18 : return FALSE;
932 : 266335 : offset++;
933 : : }
934 : :
935 : 1117010 : child.data = value.data + offset;
936 : 1117010 : child.size = this_end - offset;
937 : :
938 : 1117010 : if (child.size == 0)
939 : 25578 : child.data = NULL;
940 : :
941 : 1117010 : if (!g_variant_serialised_is_normal (child))
942 : 230 : return FALSE;
943 : :
944 : 1116780 : offset = this_end;
945 : 735255 : }
946 : :
947 : 17907 : g_assert (offset == offsets.data_size);
948 : :
949 : : /* All offsets have now been checked. */
950 : 17907 : value.ordered_offsets_up_to = G_MAXSIZE;
951 : 17907 : value.checked_offsets_up_to = G_MAXSIZE;
952 : :
953 : 17907 : return TRUE;
954 : 11912 : }
955 : :
956 : : /* Tuples {{{2
957 : : *
958 : : * Since tuples can contain a mix of variable- and fixed-sized items,
959 : : * they are, in terms of serialization, a hybrid of variable-sized and
960 : : * fixed-sized arrays.
961 : : *
962 : : * Offsets are only stored for variable-sized items. Also, since the
963 : : * number of items in a tuple is known from its type, we are able to
964 : : * know exactly how many offsets to expect in the serialized data (and
965 : : * therefore how much space is taken up by the offset array). This
966 : : * means that we know where the end of the serialized data for the last
967 : : * item is -- we can just subtract the size of the offset array from the
968 : : * total size of the tuple. For this reason, the last item in the tuple
969 : : * doesn't need an offset stored.
970 : : *
971 : : * Tuple offsets are stored in reverse. This design choice allows
972 : : * iterator-based deserializers to be more efficient.
973 : : *
974 : : * Most of the "heavy lifting" here is handled by the GVariantTypeInfo
975 : : * for the tuple. See the notes in gvarianttypeinfo.h.
976 : : */
977 : :
978 : : /* Read the offset stored at byte @position of @value. A zero @offset_size
979 : : * means there is no offset table at all; @value.data may then be NULL, so no
980 : : * pointer into it is formed. */
981 : : static gsize
982 : 8202224 : gvs_tuple_read_offset (GVariantSerialised value,
983 : : gsize position,
984 : : gsize offset_size)
985 : : {
986 : 8202224 : if (offset_size == 0)
987 : 415218 : return 0;
988 : :
989 : 7787006 : return gvs_read_unaligned_le (value.data + position, offset_size);
990 : 5719892 : }
991 : :
992 : : /* Note: This doesn’t guarantee that @out_member_end >= @out_member_start; that
993 : : * condition may not hold true for invalid serialised variants. The caller is
994 : : * responsible for checking the returned values and handling invalid ones
995 : : * appropriately. */
996 : : static void
997 : 10082102 : gvs_tuple_get_member_bounds (GVariantSerialised value,
998 : : gsize index_,
999 : : gsize offset_size,
1000 : : gsize *out_member_start,
1001 : : gsize *out_member_end)
1002 : : {
1003 : : const GVariantMemberInfo *member_info;
1004 : : gsize member_start, member_end;
1005 : :
1006 : 10082102 : member_info = g_variant_type_info_member_info (value.type_info, index_);
1007 : :
1008 : 10082102 : if (member_info->i + 1 &&
1009 : 5933653 : offset_size * (member_info->i + 1) <= value.size)
1010 : 5933631 : member_start = gvs_tuple_read_offset (value,
1011 : 5933631 : value.size - offset_size * (member_info->i + 1),
1012 : 4208601 : offset_size);
1013 : : else
1014 : 4148471 : member_start = 0;
1015 : :
1016 : 10082102 : member_start += member_info->a;
1017 : 10082102 : member_start &= member_info->b;
1018 : 10082102 : member_start |= member_info->c;
1019 : :
1020 : 10082102 : if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_LAST &&
1021 : 641620 : offset_size * (member_info->i + 1) <= value.size)
1022 : 641598 : member_end = value.size - offset_size * (member_info->i + 1);
1023 : :
1024 : 9440504 : else if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_FIXED)
1025 : : {
1026 : : gsize fixed_size;
1027 : :
1028 : 7338091 : g_variant_type_info_query (member_info->type_info, NULL, &fixed_size);
1029 : 7338091 : member_end = member_start + fixed_size;
1030 : 5404104 : }
1031 : :
1032 : 2102413 : else if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_OFFSET &&
1033 : 2102391 : offset_size * (member_info->i + 2) <= value.size)
1034 : 2102381 : member_end = gvs_tuple_read_offset (value,
1035 : 2102381 : value.size - offset_size * (member_info->i + 2),
1036 : 1387838 : offset_size);
1037 : :
1038 : : else /* invalid */
1039 : 32 : member_end = G_MAXSIZE;
1040 : :
1041 : 10082102 : if (out_member_start != NULL)
1042 : 8800757 : *out_member_start = member_start;
1043 : 10082102 : if (out_member_end != NULL)
1044 : 10082102 : *out_member_end = member_end;
1045 : 10082102 : }
1046 : :
1047 : : static gsize
1048 : 1657781 : gvs_tuple_n_children (GVariantSerialised value)
1049 : : {
1050 : 1657781 : return g_variant_type_info_n_members (value.type_info);
1051 : : }
1052 : :
1053 : : static GVariantSerialised
1054 : 1411824 : gvs_tuple_get_child (GVariantSerialised value,
1055 : : gsize index_)
1056 : : {
1057 : : const GVariantMemberInfo *member_info;
1058 : 1411824 : GVariantSerialised child = { 0, };
1059 : : gsize offset_size;
1060 : : gsize start, end, last_end;
1061 : :
1062 : 1411824 : member_info = g_variant_type_info_member_info (value.type_info, index_);
1063 : 1411824 : child.type_info = g_variant_type_info_ref (member_info->type_info);
1064 : 1411824 : child.depth = value.depth + 1;
1065 : 1411824 : offset_size = gvs_get_offset_size (value.size);
1066 : :
1067 : : /* Ensure the size is set for fixed-sized children, or
1068 : : * g_variant_serialised_check() will fail, even if we return
1069 : : * (child.data == NULL) to indicate an error. */
1070 : 1411824 : if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_FIXED)
1071 : 977819 : g_variant_type_info_query (child.type_info, NULL, &child.size);
1072 : :
1073 : : /* tuples are the only (potentially) fixed-sized containers, so the
1074 : : * only ones that have to deal with the possibility of having %NULL
1075 : : * data with a non-zero %size if errors occurred elsewhere.
1076 : : */
1077 : 1411824 : if G_UNLIKELY (value.data == NULL && value.size != 0)
1078 : : {
1079 : : /* this can only happen in fixed-sized tuples,
1080 : : * so the child must also be fixed sized.
1081 : : */
1082 : 27038 : g_assert (child.size != 0);
1083 : 27038 : child.data = NULL;
1084 : :
1085 : 27038 : return child;
1086 : : }
1087 : :
1088 : : /* If the requested @index_ is beyond the set of indices whose framing offsets
1089 : : * have been checked, check the remaining offsets to see whether they’re
1090 : : * normal (in order, no overlapping tuple elements).
1091 : : *
1092 : : * Unlike the checks in gvs_variable_sized_array_get_child(), we have to check
1093 : : * all the tuple *elements* here, not just all the framing offsets, since
1094 : : * tuples contain a mix of elements which use framing offsets and ones which
1095 : : * don’t. None of them are allowed to overlap. */
1096 : 1384786 : if (index_ > value.checked_offsets_up_to &&
1097 : 1019976 : value.ordered_offsets_up_to == value.checked_offsets_up_to)
1098 : : {
1099 : 1019976 : gsize i, prev_i_end = 0;
1100 : :
1101 : 1019976 : if (value.checked_offsets_up_to > 0)
1102 : 0 : gvs_tuple_get_member_bounds (value, value.checked_offsets_up_to - 1, offset_size, NULL, &prev_i_end);
1103 : :
1104 : 8340724 : for (i = value.checked_offsets_up_to; i <= index_; i++)
1105 : : {
1106 : : gsize i_start, i_end;
1107 : :
1108 : 7519412 : gvs_tuple_get_member_bounds (value, i, offset_size, &i_start, &i_end);
1109 : :
1110 : 7519412 : if (i_start > i_end || i_start < prev_i_end || i_end > value.size)
1111 : 9843 : break;
1112 : :
1113 : 7320748 : prev_i_end = i_end;
1114 : 5435883 : }
1115 : :
1116 : 1019976 : value.ordered_offsets_up_to = i - 1;
1117 : 1019976 : value.checked_offsets_up_to = index_;
1118 : 640274 : }
1119 : :
1120 : 1384786 : if (index_ > value.ordered_offsets_up_to)
1121 : : {
1122 : : /* Offsets are invalid somewhere, so return an empty child. */
1123 : 103417 : return child;
1124 : : }
1125 : :
1126 : 1281369 : if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_OFFSET)
1127 : : {
1128 : 282050 : if (offset_size * (member_info->i + 2) > value.size)
1129 : 16 : return child;
1130 : 164719 : }
1131 : : else
1132 : : {
1133 : 999319 : if (offset_size * (member_info->i + 1) > value.size)
1134 : 8 : return child;
1135 : : }
1136 : :
1137 : : /* The child should not extend into the offset table. */
1138 : 1281345 : gvs_tuple_get_member_bounds (value, index_, offset_size, &start, &end);
1139 : 1281345 : gvs_tuple_get_member_bounds (value, g_variant_type_info_n_members (value.type_info) - 1, offset_size, NULL, &last_end);
1140 : :
1141 : 1281345 : if (start < end && end <= value.size && end <= last_end)
1142 : : {
1143 : 1132455 : child.data = value.data + start;
1144 : 1132455 : child.size = end - start;
1145 : 806551 : }
1146 : :
1147 : 1281345 : return child;
1148 : 826560 : }
1149 : :
1150 : : static gsize
1151 : 250220 : gvs_tuple_needed_size (GVariantTypeInfo *type_info,
1152 : : GVariantSerialisedFiller gvs_filler,
1153 : : const gpointer *children,
1154 : : gsize n_children)
1155 : : {
1156 : 250220 : const GVariantMemberInfo *member_info = NULL;
1157 : : gsize fixed_size;
1158 : : gsize offset;
1159 : : gsize i;
1160 : :
1161 : 250220 : g_variant_type_info_query (type_info, NULL, &fixed_size);
1162 : :
1163 : 250220 : if (fixed_size)
1164 : 8879 : return fixed_size;
1165 : :
1166 : 241341 : offset = 0;
1167 : :
1168 : : /* We must go through at least one iteration below. If the tuple had no
1169 : : * children, it would have a fixed size. */
1170 : 241341 : g_assert (n_children > 0);
1171 : :
1172 : 2533523 : for (i = 0; i < n_children; i++)
1173 : : {
1174 : : guint alignment;
1175 : :
1176 : 2292182 : member_info = g_variant_type_info_member_info (type_info, i);
1177 : 2292182 : g_variant_type_info_query (member_info->type_info,
1178 : : &alignment, &fixed_size);
1179 : 2292182 : offset += (-offset) & alignment;
1180 : :
1181 : 2292182 : if (fixed_size)
1182 : 1630278 : offset += fixed_size;
1183 : : else
1184 : : {
1185 : 661904 : GVariantSerialised child = { 0, };
1186 : :
1187 : 661904 : gvs_filler (&child, children[i]);
1188 : 661904 : offset += child.size;
1189 : : }
1190 : 1725169 : }
1191 : :
1192 : 241341 : return gvs_calculate_total_size (offset, member_info->i + 1);
1193 : 176075 : }
1194 : :
1195 : : static void
1196 : 141437 : gvs_tuple_serialise (GVariantSerialised value,
1197 : : GVariantSerialisedFiller gvs_filler,
1198 : : const gpointer *children,
1199 : : gsize n_children)
1200 : : {
1201 : : gsize offset_size;
1202 : : gsize offset;
1203 : : gsize i;
1204 : :
1205 : : /* A tuple whose members all serialise to nothing takes up no space at all,
1206 : : * and @value.data may then be NULL. There is nothing to write in that case,
1207 : : * and no pointer into @value.data may be formed. */
1208 : 141437 : if (value.size == 0)
1209 : 12 : return;
1210 : :
1211 : 141425 : offset_size = gvs_get_offset_size (value.size);
1212 : 141425 : offset = 0;
1213 : :
1214 : 1173249 : for (i = 0; i < n_children; i++)
1215 : : {
1216 : : const GVariantMemberInfo *member_info;
1217 : 1031824 : GVariantSerialised child = { 0, };
1218 : : guint alignment;
1219 : :
1220 : 1031824 : member_info = g_variant_type_info_member_info (value.type_info, i);
1221 : 1031824 : g_variant_type_info_query (member_info->type_info, &alignment, NULL);
1222 : :
1223 : 1816660 : while (offset & alignment)
1224 : 784836 : value.data[offset++] = '\0';
1225 : :
1226 : 1031824 : child.data = value.data + offset;
1227 : 1031824 : gvs_filler (&child, children[i]);
1228 : 1031824 : offset += child.size;
1229 : :
1230 : 1031824 : if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_OFFSET)
1231 : : {
1232 : 211537 : value.size -= offset_size;
1233 : 357004 : gvs_write_unaligned_le (value.data + value.size,
1234 : 145467 : offset, offset_size);
1235 : 145467 : }
1236 : 756981 : }
1237 : :
1238 : 225783 : while (offset < value.size)
1239 : 84358 : value.data[offset++] = '\0';
1240 : 84088 : }
1241 : :
1242 : : static gboolean
1243 : 115053 : gvs_tuple_is_normal (GVariantSerialised value)
1244 : : {
1245 : : guint offset_size;
1246 : : gsize offset_ptr;
1247 : : gsize length;
1248 : : gsize offset;
1249 : : gsize i;
1250 : : gsize offset_table_size;
1251 : :
1252 : : /* as per the comment in gvs_tuple_get_child() */
1253 : 115053 : if G_UNLIKELY (value.data == NULL && value.size != 0)
1254 : 25 : return FALSE;
1255 : :
1256 : 115028 : offset_size = gvs_get_offset_size (value.size);
1257 : 115028 : length = g_variant_type_info_n_members (value.type_info);
1258 : 115028 : offset_ptr = value.size;
1259 : 115028 : offset = 0;
1260 : :
1261 : 995505 : for (i = 0; i < length; i++)
1262 : : {
1263 : : const GVariantMemberInfo *member_info;
1264 : 881439 : GVariantSerialised child = { 0, };
1265 : : gsize fixed_size;
1266 : : guint alignment;
1267 : : gsize end;
1268 : :
1269 : 881439 : member_info = g_variant_type_info_member_info (value.type_info, i);
1270 : 881439 : child.type_info = member_info->type_info;
1271 : 881439 : child.depth = value.depth + 1;
1272 : :
1273 : 881439 : g_variant_type_info_query (child.type_info, &alignment, &fixed_size);
1274 : :
1275 : 1532551 : while (offset & alignment)
1276 : : {
1277 : 651231 : if (offset >= value.size || value.data[offset] != '\0')
1278 : 556 : return FALSE;
1279 : 651112 : offset++;
1280 : : }
1281 : :
1282 : 881320 : child.data = value.data != NULL ? value.data + offset : NULL;
1283 : :
1284 : 881320 : switch (member_info->ending_type)
1285 : : {
1286 : 165726 : case G_VARIANT_MEMBER_ENDING_FIXED:
1287 : 683979 : end = offset + fixed_size;
1288 : 683979 : break;
1289 : :
1290 : 8595 : case G_VARIANT_MEMBER_ENDING_LAST:
1291 : 31117 : end = offset_ptr;
1292 : 31117 : break;
1293 : :
1294 : 42765 : case G_VARIANT_MEMBER_ENDING_OFFSET:
1295 : 166224 : if (offset_ptr < offset_size)
1296 : 4 : return FALSE;
1297 : :
1298 : 166220 : offset_ptr -= offset_size;
1299 : :
1300 : 166220 : if (offset_ptr < offset)
1301 : 8 : return FALSE;
1302 : :
1303 : 166212 : end = gvs_tuple_read_offset (value, offset_ptr, offset_size);
1304 : 166212 : break;
1305 : :
1306 : 0 : default:
1307 : : g_assert_not_reached ();
1308 : 0 : }
1309 : :
1310 : 881308 : if (end < offset || end > offset_ptr)
1311 : 106 : return FALSE;
1312 : :
1313 : 881202 : child.size = end - offset;
1314 : :
1315 : 881202 : if (child.size == 0)
1316 : 3014 : child.data = NULL;
1317 : :
1318 : 881202 : if (!g_variant_serialised_is_normal (child))
1319 : 725 : return FALSE;
1320 : :
1321 : 880477 : offset = end;
1322 : 663828 : }
1323 : :
1324 : : /* All element bounds have been checked above. */
1325 : 114066 : value.ordered_offsets_up_to = G_MAXSIZE;
1326 : 114066 : value.checked_offsets_up_to = G_MAXSIZE;
1327 : :
1328 : : {
1329 : : gsize fixed_size;
1330 : : guint alignment;
1331 : :
1332 : 114066 : g_variant_type_info_query (value.type_info, &alignment, &fixed_size);
1333 : :
1334 : 114066 : if (fixed_size)
1335 : : {
1336 : 44439 : g_assert (fixed_size == value.size);
1337 : 44439 : g_assert (offset_ptr == value.size);
1338 : :
1339 : 44439 : if (i == 0)
1340 : : {
1341 : 701 : if (value.data[offset++] != '\0')
1342 : 29 : return FALSE;
1343 : 387 : }
1344 : : else
1345 : : {
1346 : 118571 : while (offset & alignment)
1347 : 74853 : if (value.data[offset++] != '\0')
1348 : 20 : return FALSE;
1349 : : }
1350 : :
1351 : 44404 : g_assert (offset == value.size);
1352 : 21732 : }
1353 : : }
1354 : :
1355 : : /* @offset_ptr has been counting backwards from the end of the variant, to
1356 : : * find the beginning of the offset table. @offset has been counting forwards
1357 : : * from the beginning of the variant to find the end of the data. They should
1358 : : * have met in the middle. */
1359 : 114031 : if (offset_ptr != offset)
1360 : 0 : return FALSE;
1361 : :
1362 : 114031 : offset_table_size = value.size - offset_ptr;
1363 : 114031 : if (value.size > 0 &&
1364 : 113985 : gvs_calculate_total_size (offset, offset_table_size / offset_size) != value.size)
1365 : 4 : return FALSE; /* offset size not minimal */
1366 : :
1367 : 114027 : return TRUE;
1368 : 73338 : }
1369 : :
1370 : : /* Variants {{{2
1371 : : *
1372 : : * Variants are stored by storing the serialized data of the child,
1373 : : * followed by a '\0' character, followed by the type string of the
1374 : : * child.
1375 : : *
1376 : : * In the case that a value is presented that contains no '\0'
1377 : : * character, or doesn't have a single well-formed definite type string
1378 : : * following that character, the variant must be taken as containing the
1379 : : * unit tuple: ().
1380 : : */
1381 : :
1382 : : static inline gsize
1383 : 196486 : gvs_variant_n_children (GVariantSerialised value)
1384 : : {
1385 : 196486 : return 1;
1386 : : }
1387 : :
1388 : : static inline GVariantSerialised
1389 : 195096 : gvs_variant_get_child (GVariantSerialised value,
1390 : : gsize index_)
1391 : : {
1392 : 195096 : GVariantSerialised child = { 0, };
1393 : :
1394 : : /* NOTE: not O(1) and impossible for it to be... */
1395 : 195096 : if (value.size)
1396 : : {
1397 : : /* find '\0' character */
1398 : 307137 : for (child.size = value.size - 1; child.size; child.size--)
1399 : 305759 : if (value.data[child.size] == '\0')
1400 : 109321 : break;
1401 : :
1402 : : /* ensure we didn't just hit the start of the string */
1403 : 110699 : if (value.data[child.size] == '\0')
1404 : : {
1405 : 110603 : const gchar *type_string = (gchar *) &value.data[child.size + 1];
1406 : 110603 : const gchar *limit = (gchar *) &value.data[value.size];
1407 : : const gchar *end;
1408 : :
1409 : 110603 : if (g_variant_type_string_scan (type_string, limit, &end) &&
1410 : 110056 : end == limit)
1411 : : {
1412 : 110021 : const GVariantType *type = (GVariantType *) type_string;
1413 : :
1414 : 110021 : if (g_variant_type_is_definite (type))
1415 : : {
1416 : : gsize fixed_size;
1417 : : gsize child_type_depth;
1418 : :
1419 : 110021 : child.type_info = g_variant_type_info_get (type);
1420 : 110021 : child.depth = value.depth + 1;
1421 : :
1422 : 110021 : if (child.size != 0)
1423 : : /* only set to non-%NULL if size > 0 */
1424 : 108775 : child.data = value.data;
1425 : :
1426 : 110021 : g_variant_type_info_query (child.type_info,
1427 : : NULL, &fixed_size);
1428 : 110021 : child_type_depth = g_variant_type_info_query_depth (child.type_info);
1429 : :
1430 : 110021 : if ((!fixed_size || fixed_size == child.size) &&
1431 : 110021 : value.depth < G_VARIANT_MAX_RECURSION_DEPTH - child_type_depth)
1432 : 110012 : return child;
1433 : :
1434 : 9 : g_variant_type_info_unref (child.type_info);
1435 : 7 : }
1436 : 7 : }
1437 : 310 : }
1438 : 341 : }
1439 : :
1440 : 85084 : child.type_info = g_variant_type_info_get (G_VARIANT_TYPE_UNIT);
1441 : 85084 : child.data = NULL;
1442 : 85084 : child.size = 1;
1443 : 85084 : child.depth = value.depth + 1;
1444 : :
1445 : 85084 : return child;
1446 : 57928 : }
1447 : :
1448 : : static inline gsize
1449 : 166373 : gvs_variant_needed_size (GVariantTypeInfo *type_info,
1450 : : GVariantSerialisedFiller gvs_filler,
1451 : : const gpointer *children,
1452 : : gsize n_children)
1453 : : {
1454 : 166373 : GVariantSerialised child = { 0, };
1455 : : const gchar *type_string;
1456 : :
1457 : 166373 : gvs_filler (&child, children[0]);
1458 : 166373 : type_string = g_variant_type_info_get_type_string (child.type_info);
1459 : :
1460 : 166373 : return child.size + 1 + strlen (type_string);
1461 : : }
1462 : :
1463 : : static inline void
1464 : 62495 : gvs_variant_serialise (GVariantSerialised value,
1465 : : GVariantSerialisedFiller gvs_filler,
1466 : : const gpointer *children,
1467 : : gsize n_children)
1468 : : {
1469 : 62495 : GVariantSerialised child = { 0, };
1470 : : const gchar *type_string;
1471 : :
1472 : 62495 : child.data = value.data;
1473 : :
1474 : 62495 : gvs_filler (&child, children[0]);
1475 : 62495 : type_string = g_variant_type_info_get_type_string (child.type_info);
1476 : 62495 : value.data[child.size] = '\0';
1477 : 62495 : memcpy (value.data + child.size + 1, type_string, strlen (type_string));
1478 : 62495 : }
1479 : :
1480 : : static inline gboolean
1481 : 31224 : gvs_variant_is_normal (GVariantSerialised value)
1482 : : {
1483 : : GVariantSerialised child;
1484 : : gboolean normal;
1485 : : gsize child_type_depth;
1486 : :
1487 : 31224 : child = gvs_variant_get_child (value, 0);
1488 : 31224 : child_type_depth = g_variant_type_info_query_depth (child.type_info);
1489 : :
1490 : 84714 : normal = (value.depth < G_VARIANT_MAX_RECURSION_DEPTH - child_type_depth) &&
1491 : 53325 : (child.data != NULL || child.size == 0) &&
1492 : 30897 : g_variant_serialised_is_normal (child);
1493 : :
1494 : 31224 : g_variant_type_info_unref (child.type_info);
1495 : :
1496 : 31224 : return normal;
1497 : : }
1498 : :
1499 : :
1500 : :
1501 : : /* PART 2: Serializer API {{{1
1502 : : *
1503 : : * This is the implementation of the API of the serializer as advertised
1504 : : * in gvariant-serialiser.h.
1505 : : */
1506 : :
1507 : : /* Dispatch Utilities {{{2
1508 : : *
1509 : : * These macros allow a given function (for example,
1510 : : * g_variant_serialiser_serialise) to be dispatched to the appropriate
1511 : : * type-specific function above (fixed/variable-sized maybe,
1512 : : * fixed/variable-sized array, tuple or variant).
1513 : : */
1514 : : #define DISPATCH_FIXED(type_info, before, after) \
1515 : : { \
1516 : : gsize fixed_size; \
1517 : : \
1518 : : g_variant_type_info_query_element (type_info, NULL, \
1519 : : &fixed_size); \
1520 : : \
1521 : : if (fixed_size) \
1522 : : { \
1523 : : before ## fixed_sized ## after \
1524 : : } \
1525 : : else \
1526 : : { \
1527 : : before ## variable_sized ## after \
1528 : : } \
1529 : : }
1530 : :
1531 : : #define DISPATCH_CASES(type_info, before, after) \
1532 : : switch (g_variant_type_info_get_type_char (type_info)) \
1533 : : { \
1534 : : case G_VARIANT_TYPE_INFO_CHAR_MAYBE: \
1535 : : DISPATCH_FIXED (type_info, before, _maybe ## after) \
1536 : : \
1537 : : case G_VARIANT_TYPE_INFO_CHAR_ARRAY: \
1538 : : DISPATCH_FIXED (type_info, before, _array ## after) \
1539 : : \
1540 : : case G_VARIANT_TYPE_INFO_CHAR_DICT_ENTRY: \
1541 : : case G_VARIANT_TYPE_INFO_CHAR_TUPLE: \
1542 : : { \
1543 : : before ## tuple ## after \
1544 : : } \
1545 : : \
1546 : : case G_VARIANT_TYPE_INFO_CHAR_VARIANT: \
1547 : : { \
1548 : : before ## variant ## after \
1549 : : } \
1550 : : }
1551 : :
1552 : : /* Serializer entry points {{{2
1553 : : *
1554 : : * These are the functions that are called in order for the serializer
1555 : : * to do its thing.
1556 : : */
1557 : :
1558 : : /* < private >
1559 : : * g_variant_serialised_n_children:
1560 : : * @serialised: a #GVariantSerialised
1561 : : *
1562 : : * For serialized data that represents a container value (maybes,
1563 : : * tuples, arrays, variants), determine how many child items are inside
1564 : : * that container.
1565 : : *
1566 : : * Returns: the number of children
1567 : : */
1568 : : gsize
1569 : 36504178 : g_variant_serialised_n_children (GVariantSerialised serialised)
1570 : : {
1571 : 36504178 : g_assert (g_variant_serialised_check (serialised));
1572 : :
1573 : 36504178 : DISPATCH_CASES (serialised.type_info,
1574 : :
1575 : 12284394 : return gvs_/**/,/**/_n_children (serialised);
1576 : :
1577 : : )
1578 : : g_assert_not_reached ();
1579 : 12284394 : }
1580 : :
1581 : : /* < private >
1582 : : * g_variant_serialised_get_child:
1583 : : * @serialised: a #GVariantSerialised
1584 : : * @index_: the index of the child to fetch
1585 : : *
1586 : : * Extracts a child from a serialized data representing a container
1587 : : * value.
1588 : : *
1589 : : * It is an error to call this function with an index out of bounds.
1590 : : *
1591 : : * If the result .data == %NULL and .size > 0 then there has been an
1592 : : * error extracting the requested fixed-sized value. This number of
1593 : : * zero bytes needs to be allocated instead.
1594 : : *
1595 : : * In the case that .data == %NULL and .size == 0 then a zero-sized
1596 : : * item of a variable-sized type is being returned.
1597 : : *
1598 : : * .data is never non-%NULL if size is 0.
1599 : : *
1600 : : * Returns: a #GVariantSerialised for the child
1601 : : */
1602 : : GVariantSerialised
1603 : 27803934 : g_variant_serialised_get_child (GVariantSerialised serialised,
1604 : : gsize index_)
1605 : : {
1606 : : GVariantSerialised child;
1607 : :
1608 : 27803934 : g_assert (g_variant_serialised_check (serialised));
1609 : :
1610 : 27803934 : if G_LIKELY (index_ < g_variant_serialised_n_children (serialised))
1611 : : {
1612 : 27803934 : DISPATCH_CASES (serialised.type_info,
1613 : :
1614 : 10971228 : child = gvs_/**/,/**/_get_child (serialised, index_);
1615 : 10971228 : g_assert (child.size || child.data == NULL);
1616 : 10971228 : g_assert (g_variant_serialised_check (child));
1617 : 10971228 : return child;
1618 : :
1619 : : )
1620 : : g_assert_not_reached ();
1621 : 0 : }
1622 : :
1623 : 0 : g_error ("Attempt to access item %"G_GSIZE_FORMAT
1624 : : " in a container with only %"G_GSIZE_FORMAT" items",
1625 : 0 : index_, g_variant_serialised_n_children (serialised));
1626 : 10971228 : }
1627 : :
1628 : : /* < private >
1629 : : * g_variant_serialiser_serialise:
1630 : : * @serialised: a #GVariantSerialised, properly set up
1631 : : * @gvs_filler: the filler function
1632 : : * @children: an array of child items
1633 : : * @n_children: the size of @children
1634 : : *
1635 : : * Writes data in serialized form.
1636 : : *
1637 : : * The type_info field of @serialised must be filled in to type info for
1638 : : * the type that we are serializing.
1639 : : *
1640 : : * The size field of @serialised must be filled in with the value
1641 : : * returned by a previous call to g_variant_serialiser_needed_size().
1642 : : *
1643 : : * The data field of @serialised must be a pointer to a properly-aligned
1644 : : * memory region large enough to serialize into (ie: at least as big as
1645 : : * the size field).
1646 : : *
1647 : : * This function is only responsible for serializing the top-level
1648 : : * container. @gvs_filler is called on each child of the container in
1649 : : * order for all of the data of that child to be filled in.
1650 : : */
1651 : : void
1652 : 408579 : g_variant_serialiser_serialise (GVariantSerialised serialised,
1653 : : GVariantSerialisedFiller gvs_filler,
1654 : : const gpointer *children,
1655 : : gsize n_children)
1656 : : {
1657 : 408579 : g_assert (g_variant_serialised_check (serialised));
1658 : :
1659 : 408579 : DISPATCH_CASES (serialised.type_info,
1660 : :
1661 : 226710 : gvs_/**/,/**/_serialise (serialised, gvs_filler,
1662 : 226710 : children, n_children);
1663 : 226710 : return;
1664 : :
1665 : : )
1666 : : g_assert_not_reached ();
1667 : 226710 : }
1668 : :
1669 : : /* < private >
1670 : : * g_variant_serialiser_needed_size:
1671 : : * @type_info: the type to serialize for
1672 : : * @gvs_filler: the filler function
1673 : : * @children: an array of child items
1674 : : * @n_children: the size of @children
1675 : : *
1676 : : * Determines how much memory would be needed to serialize this value.
1677 : : *
1678 : : * This function is only responsible for performing calculations for the
1679 : : * top-level container. @gvs_filler is called on each child of the
1680 : : * container in order to determine its size.
1681 : : */
1682 : : gsize
1683 : 943436 : g_variant_serialiser_needed_size (GVariantTypeInfo *type_info,
1684 : : GVariantSerialisedFiller gvs_filler,
1685 : : const gpointer *children,
1686 : : gsize n_children)
1687 : : {
1688 : 943436 : DISPATCH_CASES (type_info,
1689 : :
1690 : 1074990 : return gvs_/**/,/**/_needed_size (type_info, gvs_filler,
1691 : 537495 : children, n_children);
1692 : :
1693 : : )
1694 : : g_assert_not_reached ();
1695 : 537495 : }
1696 : :
1697 : : /* Byteswapping {{{2 */
1698 : :
1699 : : /* < private >
1700 : : * g_variant_serialised_byteswap:
1701 : : * @value: a #GVariantSerialised
1702 : : *
1703 : : * Byte-swap serialized data. The result of this function is only
1704 : : * well-defined if the data is in normal form.
1705 : : */
1706 : : void
1707 : 812116 : g_variant_serialised_byteswap (GVariantSerialised serialised)
1708 : : {
1709 : : gsize fixed_size;
1710 : : guint alignment;
1711 : :
1712 : 812116 : g_assert (g_variant_serialised_check (serialised));
1713 : :
1714 : 812116 : if (!serialised.data)
1715 : 56043 : return;
1716 : :
1717 : : /* the types we potentially need to byteswap are
1718 : : * exactly those with alignment requirements.
1719 : : */
1720 : 808072 : g_variant_type_info_query (serialised.type_info, &alignment, &fixed_size);
1721 : 808072 : if (!alignment)
1722 : 24865 : return;
1723 : :
1724 : : /* if fixed size and alignment are equal then we are down
1725 : : * to the base integer type and we should swap it. the
1726 : : * only exception to this is if we have a tuple with a
1727 : : * single item, and then swapping it will be OK anyway.
1728 : : */
1729 : 783207 : if (alignment + 1 == fixed_size)
1730 : : {
1731 : 748868 : switch (fixed_size)
1732 : : {
1733 : 11026 : case 2:
1734 : : {
1735 : 392267 : guint16 *ptr = (guint16 *) serialised.data;
1736 : :
1737 : 392267 : g_assert_cmpint (serialised.size, ==, 2);
1738 : 392267 : *ptr = GUINT16_SWAP_LE_BE (*ptr);
1739 : : }
1740 : 392267 : return;
1741 : :
1742 : 11292 : case 4:
1743 : : {
1744 : 31210 : guint32 *ptr = (guint32 *) serialised.data;
1745 : :
1746 : 31210 : g_assert_cmpint (serialised.size, ==, 4);
1747 : 31210 : *ptr = GUINT32_SWAP_LE_BE (*ptr);
1748 : : }
1749 : 31210 : return;
1750 : :
1751 : 21854 : case 8:
1752 : : {
1753 : 325391 : guint64 *ptr = (guint64 *) serialised.data;
1754 : :
1755 : 325391 : g_assert_cmpint (serialised.size, ==, 8);
1756 : 325391 : *ptr = GUINT64_SWAP_LE_BE (*ptr);
1757 : : }
1758 : 325391 : return;
1759 : :
1760 : 0 : default:
1761 : : g_assert_not_reached ();
1762 : 0 : }
1763 : 0 : }
1764 : :
1765 : : /* else, we have a container that potentially contains
1766 : : * some children that need to be byteswapped.
1767 : : */
1768 : : else
1769 : : {
1770 : : gsize children, i;
1771 : :
1772 : 34339 : children = g_variant_serialised_n_children (serialised);
1773 : 846143 : for (i = 0; i < children; i++)
1774 : : {
1775 : : GVariantSerialised child;
1776 : :
1777 : 811804 : child = g_variant_serialised_get_child (serialised, i);
1778 : 811804 : g_variant_serialised_byteswap (child);
1779 : 811804 : g_variant_type_info_unref (child.type_info);
1780 : 738458 : }
1781 : : }
1782 : 738607 : }
1783 : :
1784 : : /* Normal form checking {{{2 */
1785 : :
1786 : : /* < private >
1787 : : * g_variant_serialised_is_normal:
1788 : : * @serialised: a #GVariantSerialised
1789 : : *
1790 : : * Determines, recursively if @serialised is in normal form. There is
1791 : : * precisely one normal form of serialized data for each possible value.
1792 : : *
1793 : : * It is possible that multiple byte sequences form the serialized data
1794 : : * for a given value if, for example, the padding bytes are filled in
1795 : : * with something other than zeros, but only one form is the normal
1796 : : * form.
1797 : : */
1798 : : gboolean
1799 : 4296694 : g_variant_serialised_is_normal (GVariantSerialised serialised)
1800 : : {
1801 : 4296694 : if (serialised.depth >= G_VARIANT_MAX_RECURSION_DEPTH)
1802 : 0 : return FALSE;
1803 : :
1804 : 4296694 : DISPATCH_CASES (serialised.type_info,
1805 : :
1806 : 152409 : return gvs_/**/,/**/_is_normal (serialised);
1807 : :
1808 : : )
1809 : :
1810 : 4039645 : if (serialised.data == NULL)
1811 : 157 : return FALSE;
1812 : :
1813 : : /* some hard-coded terminal cases */
1814 : 4039488 : switch (g_variant_type_info_get_type_char (serialised.type_info))
1815 : : {
1816 : 52451 : case 'b': /* boolean */
1817 : 155992 : return serialised.data[0] < 2;
1818 : :
1819 : 299718 : case 's': /* string */
1820 : 455496 : return g_variant_serialiser_is_string (serialised.data,
1821 : 77889 : serialised.size);
1822 : :
1823 : 33569 : case 'o':
1824 : 1271321 : return g_variant_serialiser_is_object_path (serialised.data,
1825 : 618876 : serialised.size);
1826 : :
1827 : 27226 : case 'g':
1828 : 158464 : return g_variant_serialiser_is_signature (serialised.data,
1829 : 65619 : serialised.size);
1830 : :
1831 : 613949 : default:
1832 : : /* all of the other types are fixed-sized numerical types for
1833 : : * which all possible values are valid (including various NaN
1834 : : * representations for floating point values).
1835 : : */
1836 : 2760599 : return TRUE;
1837 : : }
1838 : 3165055 : }
1839 : :
1840 : : /* Validity-checking functions {{{2
1841 : : *
1842 : : * Checks if strings, object paths and signature strings are valid.
1843 : : */
1844 : :
1845 : : /* < private >
1846 : : * g_variant_serialiser_is_string:
1847 : : * @data: a possible string
1848 : : * @size: the size of @data
1849 : : *
1850 : : * Ensures that @data is a valid string with a nul terminator at the end
1851 : : * and no nul bytes embedded.
1852 : : */
1853 : : gboolean
1854 : 2148124 : g_variant_serialiser_is_string (gconstpointer data,
1855 : : gsize size)
1856 : : {
1857 : : const gchar *expected_end;
1858 : : const gchar *end;
1859 : :
1860 : : /* Strings must end with a nul terminator. */
1861 : 2148124 : if (size == 0)
1862 : 73958 : return FALSE;
1863 : :
1864 : 2074166 : expected_end = ((gchar *) data) + size - 1;
1865 : :
1866 : 2074166 : if (*expected_end != '\0')
1867 : 79 : return FALSE;
1868 : :
1869 : 2074087 : g_utf8_validate_len (data, size, &end);
1870 : :
1871 : 2074087 : return end == expected_end;
1872 : 833918 : }
1873 : :
1874 : : /* < private >
1875 : : * g_variant_serialiser_is_object_path:
1876 : : * @data: a possible D-Bus object path
1877 : : * @size: the size of @data
1878 : : *
1879 : : * Performs the checks for being a valid string.
1880 : : *
1881 : : * Also, ensures that @data is a valid D-Bus object path, as per the D-Bus
1882 : : * specification.
1883 : : */
1884 : : gboolean
1885 : 1053863 : g_variant_serialiser_is_object_path (gconstpointer data,
1886 : : gsize size)
1887 : : {
1888 : 1053863 : const gchar *string = data;
1889 : : gsize i;
1890 : :
1891 : 1053863 : if (!g_variant_serialiser_is_string (data, size))
1892 : 15888 : return FALSE;
1893 : :
1894 : : /* The path must begin with an ASCII '/' (integer 47) character */
1895 : 1037975 : if (string[0] != '/')
1896 : 35 : return FALSE;
1897 : :
1898 : 79954759 : for (i = 1; string[i]; i++)
1899 : : /* Each element must only contain the ASCII characters
1900 : : * "[A-Z][a-z][0-9]_"
1901 : : */
1902 : 78917354 : if (g_ascii_isalnum (string[i]) || string[i] == '_')
1903 : : ;
1904 : :
1905 : : /* must consist of elements separated by slash characters. */
1906 : 197451 : else if (string[i] == '/')
1907 : : {
1908 : : /* No element may be the empty string. */
1909 : : /* Multiple '/' characters cannot occur in sequence. */
1910 : 197431 : if (string[i - 1] == '/')
1911 : 4 : return FALSE;
1912 : 511 : }
1913 : :
1914 : : else
1915 : 20 : return FALSE;
1916 : :
1917 : : /* A trailing '/' character is not allowed unless the path is the
1918 : : * root path (a single '/' character).
1919 : : */
1920 : 1037916 : if (i > 1 && string[i - 1] == '/')
1921 : 2 : return FALSE;
1922 : :
1923 : 1037914 : return TRUE;
1924 : 661549 : }
1925 : :
1926 : : /* < private >
1927 : : * g_variant_serialiser_is_signature:
1928 : : * @data: a possible D-Bus signature
1929 : : * @size: the size of @data
1930 : : *
1931 : : * Performs the checks for being a valid string.
1932 : : *
1933 : : * Also, ensures that @data is a valid D-Bus type signature, as per the
1934 : : * D-Bus specification. Note that this means the empty string is valid, as the
1935 : : * D-Bus specification defines a signature as “zero or more single complete
1936 : : * types”.
1937 : : */
1938 : : gboolean
1939 : 419682 : g_variant_serialiser_is_signature (gconstpointer data,
1940 : : gsize size)
1941 : : {
1942 : 419682 : const gchar *string = data;
1943 : : gsize first_invalid;
1944 : :
1945 : 419682 : if (!g_variant_serialiser_is_string (data, size))
1946 : 44800 : return FALSE;
1947 : :
1948 : : /* make sure no non-definite characters appear */
1949 : 374882 : first_invalid = strspn (string, "ybnqiuxthdvasog(){}");
1950 : 374882 : if (string[first_invalid])
1951 : 45 : return FALSE;
1952 : :
1953 : : /* make sure each type string is well-formed */
1954 : 12768136 : while (*string)
1955 : 12393307 : if (!g_variant_type_string_scan (string, NULL, &string))
1956 : 8 : return FALSE;
1957 : :
1958 : 374829 : return TRUE;
1959 : 85420 : }
1960 : :
1961 : : /* Epilogue {{{1 */
1962 : : /* vim:set foldmethod=marker: */
|