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 : 19188922 : g_variant_serialised_check (GVariantSerialised serialised)
140 : : {
141 : : gsize fixed_size;
142 : : guint alignment;
143 : :
144 : 19188922 : if (serialised.type_info == NULL)
145 : 0 : return FALSE;
146 : 19188922 : g_variant_type_info_query (serialised.type_info, &alignment, &fixed_size);
147 : :
148 : 19188922 : if (fixed_size != 0 && serialised.size != fixed_size)
149 : 81 : return FALSE;
150 : 19188841 : else if (fixed_size == 0 &&
151 : 14853737 : !(serialised.size == 0 || serialised.data != NULL))
152 : 0 : return FALSE;
153 : :
154 : 19188841 : 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 : 19188841 : 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 : 35970506 : return (serialised.size <= alignment ||
183 : 16781665 : (alignment & (gsize) serialised.data) == 0);
184 : : }
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 : 55229 : gvs_fixed_sized_maybe_n_children (GVariantSerialised value)
256 : : {
257 : : gsize element_fixed_size;
258 : :
259 : 55229 : g_variant_type_info_query_element (value.type_info, NULL,
260 : : &element_fixed_size);
261 : :
262 : 55229 : return (element_fixed_size == value.size) ? 1 : 0;
263 : : }
264 : :
265 : : static GVariantSerialised
266 : 12923 : 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 : 12923 : value.type_info = g_variant_type_info_element (value.type_info);
273 : 12923 : g_variant_type_info_ref (value.type_info);
274 : 12923 : value.depth++;
275 : 12923 : value.ordered_offsets_up_to = 0;
276 : 12923 : value.checked_offsets_up_to = 0;
277 : :
278 : 12923 : return value;
279 : : }
280 : :
281 : : static gsize
282 : 56818 : gvs_fixed_sized_maybe_needed_size (GVariantTypeInfo *type_info,
283 : : GVariantSerialisedFiller gvs_filler,
284 : : const gpointer *children,
285 : : gsize n_children)
286 : : {
287 : 56818 : if (n_children)
288 : : {
289 : : gsize element_fixed_size;
290 : :
291 : 28121 : g_variant_type_info_query_element (type_info, NULL,
292 : : &element_fixed_size);
293 : :
294 : 28121 : return element_fixed_size;
295 : : }
296 : : else
297 : 28697 : return 0;
298 : : }
299 : :
300 : : static void
301 : 21677 : gvs_fixed_sized_maybe_serialise (GVariantSerialised value,
302 : : GVariantSerialisedFiller gvs_filler,
303 : : const gpointer *children,
304 : : gsize n_children)
305 : : {
306 : 21677 : if (n_children)
307 : : {
308 : 11695 : GVariantSerialised child = { NULL, value.data, value.size, value.depth + 1, 0, 0 };
309 : :
310 : 11695 : gvs_filler (&child, children[0]);
311 : : }
312 : 21677 : }
313 : :
314 : : static gboolean
315 : 17657 : gvs_fixed_sized_maybe_is_normal (GVariantSerialised value)
316 : : {
317 : 17657 : if (value.size > 0)
318 : : {
319 : : gsize element_fixed_size;
320 : :
321 : 8712 : g_variant_type_info_query_element (value.type_info,
322 : : NULL, &element_fixed_size);
323 : :
324 : 8712 : if (value.size != element_fixed_size)
325 : 16 : return FALSE;
326 : :
327 : : /* proper element size: "Just". recurse to the child. */
328 : 8696 : value.type_info = g_variant_type_info_element (value.type_info);
329 : 8696 : value.depth++;
330 : 8696 : value.ordered_offsets_up_to = 0;
331 : 8696 : value.checked_offsets_up_to = 0;
332 : :
333 : 8696 : return g_variant_serialised_is_normal (value);
334 : : }
335 : :
336 : : /* size of 0: "Nothing" */
337 : 8945 : return TRUE;
338 : : }
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 : 19067 : gvs_variable_sized_maybe_n_children (GVariantSerialised value)
355 : : {
356 : 19067 : return (value.size > 0) ? 1 : 0;
357 : : }
358 : :
359 : : static GVariantSerialised
360 : 7298 : gvs_variable_sized_maybe_get_child (GVariantSerialised value,
361 : : gsize index_)
362 : : {
363 : : /* remove the padding byte and update the type. */
364 : 7298 : value.type_info = g_variant_type_info_element (value.type_info);
365 : 7298 : g_variant_type_info_ref (value.type_info);
366 : 7298 : value.size--;
367 : :
368 : : /* if it's zero-sized then it may as well be NULL */
369 : 7298 : if (value.size == 0)
370 : 78 : value.data = NULL;
371 : :
372 : 7298 : value.depth++;
373 : 7298 : value.ordered_offsets_up_to = 0;
374 : 7298 : value.checked_offsets_up_to = 0;
375 : :
376 : 7298 : return value;
377 : : }
378 : :
379 : : static gsize
380 : 27854 : gvs_variable_sized_maybe_needed_size (GVariantTypeInfo *type_info,
381 : : GVariantSerialisedFiller gvs_filler,
382 : : const gpointer *children,
383 : : gsize n_children)
384 : : {
385 : 27854 : if (n_children)
386 : : {
387 : 13911 : GVariantSerialised child = { 0, };
388 : :
389 : 13911 : gvs_filler (&child, children[0]);
390 : :
391 : 13911 : return child.size + 1;
392 : : }
393 : : else
394 : 13943 : return 0;
395 : : }
396 : :
397 : : static void
398 : 11452 : gvs_variable_sized_maybe_serialise (GVariantSerialised value,
399 : : GVariantSerialisedFiller gvs_filler,
400 : : const gpointer *children,
401 : : gsize n_children)
402 : : {
403 : 11452 : if (n_children)
404 : : {
405 : 6736 : GVariantSerialised child = { NULL, value.data, value.size - 1, value.depth + 1, 0, 0 };
406 : :
407 : : /* write the data for the child. */
408 : 6736 : gvs_filler (&child, children[0]);
409 : 6736 : value.data[child.size] = '\0';
410 : : }
411 : 11452 : }
412 : :
413 : : static gboolean
414 : 9092 : gvs_variable_sized_maybe_is_normal (GVariantSerialised value)
415 : : {
416 : 9092 : if (value.size == 0)
417 : 4511 : return TRUE;
418 : :
419 : 4581 : if (value.data[value.size - 1] != '\0')
420 : 15 : return FALSE;
421 : :
422 : 4566 : value.type_info = g_variant_type_info_element (value.type_info);
423 : 4566 : value.size--;
424 : 4566 : value.depth++;
425 : 4566 : value.ordered_offsets_up_to = 0;
426 : 4566 : value.checked_offsets_up_to = 0;
427 : :
428 : 4566 : return g_variant_serialised_is_normal (value);
429 : : }
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 : 3260541 : gvs_fixed_sized_array_n_children (GVariantSerialised value)
455 : : {
456 : : gsize element_fixed_size;
457 : :
458 : 3260541 : g_variant_type_info_query_element (value.type_info, NULL,
459 : : &element_fixed_size);
460 : :
461 : 3260541 : if (value.size % element_fixed_size == 0)
462 : 3260527 : return value.size / element_fixed_size;
463 : :
464 : 14 : return 0;
465 : : }
466 : :
467 : : static GVariantSerialised
468 : 3208893 : gvs_fixed_sized_array_get_child (GVariantSerialised value,
469 : : gsize index_)
470 : : {
471 : 3208893 : GVariantSerialised child = { 0, };
472 : :
473 : 3208893 : child.type_info = g_variant_type_info_element (value.type_info);
474 : 3208893 : g_variant_type_info_query (child.type_info, NULL, &child.size);
475 : 3208893 : child.data = value.data + (child.size * index_);
476 : 3208893 : g_variant_type_info_ref (child.type_info);
477 : 3208893 : child.depth = value.depth + 1;
478 : :
479 : 3208893 : return child;
480 : : }
481 : :
482 : : static gsize
483 : 129015 : 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 : 129015 : g_variant_type_info_query_element (type_info, NULL, &element_fixed_size);
491 : :
492 : 129015 : return element_fixed_size * n_children;
493 : : }
494 : :
495 : : static void
496 : 45252 : gvs_fixed_sized_array_serialise (GVariantSerialised value,
497 : : GVariantSerialisedFiller gvs_filler,
498 : : const gpointer *children,
499 : : gsize n_children)
500 : : {
501 : 45252 : GVariantSerialised child = { 0, };
502 : : gsize i;
503 : :
504 : 45252 : child.type_info = g_variant_type_info_element (value.type_info);
505 : 45252 : g_variant_type_info_query (child.type_info, NULL, &child.size);
506 : 45252 : child.data = value.data;
507 : 45252 : child.depth = value.depth + 1;
508 : :
509 : 2851463 : for (i = 0; i < n_children; i++)
510 : : {
511 : 2806211 : gvs_filler (&child, children[i]);
512 : 2806211 : child.data += child.size;
513 : : }
514 : 45252 : }
515 : :
516 : : static gboolean
517 : 24382 : gvs_fixed_sized_array_is_normal (GVariantSerialised value)
518 : : {
519 : 24382 : GVariantSerialised child = { 0, };
520 : :
521 : 24382 : child.type_info = g_variant_type_info_element (value.type_info);
522 : 24382 : g_variant_type_info_query (child.type_info, NULL, &child.size);
523 : 24382 : child.depth = value.depth + 1;
524 : :
525 : 24382 : if (value.size % child.size != 0)
526 : 13 : return FALSE;
527 : :
528 : 24369 : for (child.data = value.data;
529 : 1562495 : child.data < value.data + value.size;
530 : 1538126 : child.data += child.size)
531 : : {
532 : 1538144 : if (!g_variant_serialised_is_normal (child))
533 : 18 : return FALSE;
534 : : }
535 : :
536 : 24351 : return TRUE;
537 : : }
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 : 9918465 : 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 : 9918465 : tmpvalue.integer = 0;
597 : 9918465 : if (bytes != NULL)
598 : 9142485 : memcpy (&tmpvalue.bytes, bytes, size);
599 : :
600 : 9918465 : return GSIZE_FROM_LE (tmpvalue.integer);
601 : : }
602 : :
603 : : static inline void
604 : 995105 : 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 : 995105 : tmpvalue.integer = GSIZE_TO_LE (value);
615 : 995105 : memcpy (bytes, &tmpvalue.bytes, size);
616 : 995105 : }
617 : :
618 : : static guint
619 : 4537194 : gvs_get_offset_size (gsize size)
620 : : {
621 : 4537194 : if (size > G_MAXUINT32)
622 : 0 : return 8;
623 : :
624 : 4537194 : else if (size > G_MAXUINT16)
625 : 1494760 : return 4;
626 : :
627 : 3042434 : else if (size > G_MAXUINT8)
628 : 2308150 : return 2;
629 : :
630 : 734284 : else if (size > 0)
631 : 359221 : return 1;
632 : :
633 : 375063 : return 0;
634 : : }
635 : :
636 : : static gsize
637 : 3726068 : gvs_calculate_total_size (gsize body_size,
638 : : gsize offsets)
639 : : {
640 : 3726068 : if (body_size + 1 * offsets <= G_MAXUINT8)
641 : 114332 : return body_size + 1 * offsets;
642 : :
643 : 3611736 : if (body_size + 2 * offsets <= G_MAXUINT16)
644 : 2117415 : return body_size + 2 * offsets;
645 : :
646 : 1494321 : if (body_size + 4 * offsets <= G_MAXUINT32)
647 : 1494321 : return body_size + 4 * offsets;
648 : :
649 : 0 : return body_size + 8 * offsets;
650 : : }
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 : 1922296 : gvs_offsets_get_offset_n (struct Offsets *offsets,
665 : : gsize n)
666 : : {
667 : 3844592 : return gvs_read_unaligned_le (
668 : 1922296 : offsets->array + (offsets->offset_size * n), offsets->offset_size);
669 : : }
670 : :
671 : : static struct Offsets
672 : 3924104 : gvs_variable_sized_array_get_frame_offsets (GVariantSerialised value)
673 : : {
674 : 3924104 : struct Offsets out = { 0, };
675 : : gsize offsets_array_size;
676 : : gsize last_end;
677 : :
678 : 3924104 : if (value.size == 0)
679 : : {
680 : 366400 : out.is_normal = TRUE;
681 : 366400 : return out;
682 : : }
683 : :
684 : 3557704 : out.offset_size = gvs_get_offset_size (value.size);
685 : 3557704 : last_end = gvs_read_unaligned_le (value.data + value.size - out.offset_size,
686 : : out.offset_size);
687 : :
688 : 3557704 : if (last_end > value.size)
689 : 46 : return out; /* offsets not normal */
690 : :
691 : 3557658 : offsets_array_size = value.size - last_end;
692 : :
693 : 3557658 : if (offsets_array_size % out.offset_size)
694 : 47 : return out; /* offsets not normal */
695 : :
696 : 3557611 : out.data_size = last_end;
697 : 3557611 : out.array = value.data + last_end;
698 : 3557611 : out.length = offsets_array_size / out.offset_size;
699 : :
700 : 3557611 : if (out.length > 0 && gvs_calculate_total_size (last_end, out.length) != value.size)
701 : 1251 : return out; /* offset size not minimal */
702 : :
703 : 3556360 : out.is_normal = TRUE;
704 : :
705 : 3556360 : return out;
706 : : }
707 : :
708 : : static gsize
709 : 2146966 : gvs_variable_sized_array_n_children (GVariantSerialised value)
710 : : {
711 : 2146966 : 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 : 453441 : DEFINE_FIND_UNORDERED (guint8, NO_CONVERSION);
739 : 32962680 : DEFINE_FIND_UNORDERED (guint16, GUINT16_FROM_LE);
740 : 1577492 : DEFINE_FIND_UNORDERED (guint32, GUINT32_FROM_LE);
741 : 0 : DEFINE_FIND_UNORDERED (guint64, GUINT64_FROM_LE);
742 : :
743 : : static GVariantSerialised
744 : 1764781 : gvs_variable_sized_array_get_child (GVariantSerialised value,
745 : : gsize index_)
746 : : {
747 : 1764781 : GVariantSerialised child = { 0, };
748 : :
749 : 1764781 : struct Offsets offsets = gvs_variable_sized_array_get_frame_offsets (value);
750 : :
751 : : gsize start;
752 : : gsize end;
753 : :
754 : 1764781 : child.type_info = g_variant_type_info_element (value.type_info);
755 : 1764781 : g_variant_type_info_ref (child.type_info);
756 : 1764781 : 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 : 1764781 : if (offsets.array != NULL &&
766 : 1764781 : index_ > value.checked_offsets_up_to &&
767 : 1572848 : value.ordered_offsets_up_to == value.checked_offsets_up_to)
768 : : {
769 : 1572848 : switch (offsets.offset_size)
770 : : {
771 : 14631 : case 1:
772 : : {
773 : 29262 : value.ordered_offsets_up_to = find_unordered_guint8 (
774 : 14631 : offsets.array, value.checked_offsets_up_to, index_ + 1);
775 : 14631 : break;
776 : : }
777 : 814018 : case 2:
778 : : {
779 : 1628036 : value.ordered_offsets_up_to = find_unordered_guint16 (
780 : 814018 : offsets.array, value.checked_offsets_up_to, index_ + 1);
781 : 814018 : break;
782 : : }
783 : 744199 : case 4:
784 : : {
785 : 1488398 : value.ordered_offsets_up_to = find_unordered_guint32 (
786 : 744199 : offsets.array, value.checked_offsets_up_to, index_ + 1);
787 : 744199 : 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 : : }
799 : :
800 : 1572848 : value.checked_offsets_up_to = index_;
801 : : }
802 : :
803 : 1764781 : if (index_ > value.ordered_offsets_up_to)
804 : : {
805 : : /* Offsets are invalid somewhere, so return an empty child. */
806 : 794929 : return child;
807 : : }
808 : :
809 : 969852 : if (index_ > 0)
810 : : {
811 : : guint alignment;
812 : :
813 : 952444 : start = gvs_offsets_get_offset_n (&offsets, index_ - 1);
814 : :
815 : 952444 : g_variant_type_info_query (child.type_info, &alignment, NULL);
816 : 952444 : start += (-start) & alignment;
817 : : }
818 : : else
819 : 17408 : start = 0;
820 : :
821 : 969852 : end = gvs_offsets_get_offset_n (&offsets, index_);
822 : :
823 : 969852 : if (start < end && end <= value.size && end <= offsets.data_size)
824 : : {
825 : 956465 : child.data = value.data + start;
826 : 956465 : child.size = end - start;
827 : : }
828 : :
829 : 969852 : return child;
830 : : }
831 : :
832 : : static gsize
833 : 39912 : 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 : 39912 : g_variant_type_info_query (type_info, &alignment, NULL);
843 : 39912 : offset = 0;
844 : :
845 : 2412925 : for (i = 0; i < n_children; i++)
846 : : {
847 : 2373013 : GVariantSerialised child = { 0, };
848 : :
849 : 2373013 : offset += (-offset) & alignment;
850 : 2373013 : gvs_filler (&child, children[i]);
851 : 2373013 : offset += child.size;
852 : : }
853 : :
854 : 39912 : return gvs_calculate_total_size (offset, n_children);
855 : : }
856 : :
857 : : static void
858 : 16573 : 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 : 16573 : g_variant_type_info_query (value.type_info, &alignment, NULL);
870 : 16573 : offset_size = gvs_get_offset_size (value.size);
871 : 16573 : offset = 0;
872 : :
873 : 16573 : offset_ptr = value.data + value.size - offset_size * n_children;
874 : :
875 : 914141 : for (i = 0; i < n_children; i++)
876 : : {
877 : 897568 : GVariantSerialised child = { 0, };
878 : :
879 : 1249102 : while (offset & alignment)
880 : 351534 : value.data[offset++] = '\0';
881 : :
882 : 897568 : child.data = value.data + offset;
883 : 897568 : gvs_filler (&child, children[i]);
884 : 897568 : offset += child.size;
885 : :
886 : 897568 : gvs_write_unaligned_le (offset_ptr, offset, offset_size);
887 : 897568 : offset_ptr += offset_size;
888 : : }
889 : 16573 : }
890 : :
891 : : static gboolean
892 : 12357 : gvs_variable_sized_array_is_normal (GVariantSerialised value)
893 : : {
894 : 12357 : GVariantSerialised child = { 0, };
895 : : guint alignment;
896 : : gsize offset;
897 : : gsize i;
898 : :
899 : 12357 : struct Offsets offsets = gvs_variable_sized_array_get_frame_offsets (value);
900 : :
901 : 12357 : if (!offsets.is_normal)
902 : 42 : return FALSE;
903 : :
904 : 12315 : if (value.size != 0 && offsets.length == 0)
905 : 0 : return FALSE;
906 : :
907 : 12315 : g_assert (value.size != 0 || offsets.length == 0);
908 : :
909 : 12315 : child.type_info = g_variant_type_info_element (value.type_info);
910 : 12315 : g_variant_type_info_query (child.type_info, &alignment, NULL);
911 : 12315 : child.depth = value.depth + 1;
912 : 12315 : offset = 0;
913 : :
914 : 768366 : for (i = 0; i < offsets.length; i++)
915 : : {
916 : : gsize this_end;
917 : :
918 : 756209 : this_end = gvs_read_unaligned_le (offsets.array + offsets.offset_size * i,
919 : : offsets.offset_size);
920 : :
921 : 756209 : if (this_end < offset || this_end > offsets.data_size)
922 : 54 : return FALSE;
923 : :
924 : 934199 : while (offset & alignment)
925 : : {
926 : 178050 : if (!(offset < this_end && value.data[offset] == '\0'))
927 : 6 : return FALSE;
928 : 178044 : offset++;
929 : : }
930 : :
931 : 756149 : child.data = value.data + offset;
932 : 756149 : child.size = this_end - offset;
933 : :
934 : 756149 : if (child.size == 0)
935 : 11804 : child.data = NULL;
936 : :
937 : 756149 : if (!g_variant_serialised_is_normal (child))
938 : 98 : return FALSE;
939 : :
940 : 756051 : offset = this_end;
941 : : }
942 : :
943 : 12157 : g_assert (offset == offsets.data_size);
944 : :
945 : : /* All offsets have now been checked. */
946 : 12157 : value.ordered_offsets_up_to = G_MAXSIZE;
947 : 12157 : value.checked_offsets_up_to = G_MAXSIZE;
948 : :
949 : 12157 : return TRUE;
950 : : }
951 : :
952 : : /* Tuples {{{2
953 : : *
954 : : * Since tuples can contain a mix of variable- and fixed-sized items,
955 : : * they are, in terms of serialization, a hybrid of variable-sized and
956 : : * fixed-sized arrays.
957 : : *
958 : : * Offsets are only stored for variable-sized items. Also, since the
959 : : * number of items in a tuple is known from its type, we are able to
960 : : * know exactly how many offsets to expect in the serialized data (and
961 : : * therefore how much space is taken up by the offset array). This
962 : : * means that we know where the end of the serialized data for the last
963 : : * item is -- we can just subtract the size of the offset array from the
964 : : * total size of the tuple. For this reason, the last item in the tuple
965 : : * doesn't need an offset stored.
966 : : *
967 : : * Tuple offsets are stored in reverse. This design choice allows
968 : : * iterator-based deserializers to be more efficient.
969 : : *
970 : : * Most of the "heavy lifting" here is handled by the GVariantTypeInfo
971 : : * for the tuple. See the notes in gvarianttypeinfo.h.
972 : : */
973 : :
974 : : /* Note: This doesn’t guarantee that @out_member_end >= @out_member_start; that
975 : : * condition may not hold true for invalid serialised variants. The caller is
976 : : * responsible for checking the returned values and handling invalid ones
977 : : * appropriately. */
978 : : static void
979 : 4441145 : gvs_tuple_get_member_bounds (GVariantSerialised value,
980 : : gsize index_,
981 : : gsize offset_size,
982 : : gsize *out_member_start,
983 : : gsize *out_member_end)
984 : : {
985 : : const GVariantMemberInfo *member_info;
986 : : gsize member_start, member_end;
987 : :
988 : 4441145 : member_info = g_variant_type_info_member_info (value.type_info, index_);
989 : :
990 : 4441145 : if (member_info->i + 1 &&
991 : 2707722 : offset_size * (member_info->i + 1) <= value.size)
992 : 2707699 : member_start = gvs_read_unaligned_le (value.data + value.size -
993 : 2707699 : offset_size * (member_info->i + 1),
994 : : offset_size);
995 : : else
996 : 1733446 : member_start = 0;
997 : :
998 : 4441145 : member_start += member_info->a;
999 : 4441145 : member_start &= member_info->b;
1000 : 4441145 : member_start |= member_info->c;
1001 : :
1002 : 4441145 : if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_LAST &&
1003 : 483988 : offset_size * (member_info->i + 1) <= value.size)
1004 : 483965 : member_end = value.size - offset_size * (member_info->i + 1);
1005 : :
1006 : 3957180 : else if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_FIXED)
1007 : : {
1008 : : gsize fixed_size;
1009 : :
1010 : 3042166 : g_variant_type_info_query (member_info->type_info, NULL, &fixed_size);
1011 : 3042166 : member_end = member_start + fixed_size;
1012 : : }
1013 : :
1014 : 915014 : else if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_OFFSET &&
1015 : 914991 : offset_size * (member_info->i + 2) <= value.size)
1016 : 914986 : member_end = gvs_read_unaligned_le (value.data + value.size -
1017 : 914986 : offset_size * (member_info->i + 2),
1018 : : offset_size);
1019 : :
1020 : : else /* invalid */
1021 : 28 : member_end = G_MAXSIZE;
1022 : :
1023 : 4441145 : if (out_member_start != NULL)
1024 : 3660610 : *out_member_start = member_start;
1025 : 4441145 : if (out_member_end != NULL)
1026 : 4441145 : *out_member_end = member_end;
1027 : 4441145 : }
1028 : :
1029 : : static gsize
1030 : 967321 : gvs_tuple_n_children (GVariantSerialised value)
1031 : : {
1032 : 967321 : return g_variant_type_info_n_members (value.type_info);
1033 : : }
1034 : :
1035 : : static GVariantSerialised
1036 : 868137 : gvs_tuple_get_child (GVariantSerialised value,
1037 : : gsize index_)
1038 : : {
1039 : : const GVariantMemberInfo *member_info;
1040 : 868137 : GVariantSerialised child = { 0, };
1041 : : gsize offset_size;
1042 : : gsize start, end, last_end;
1043 : :
1044 : 868137 : member_info = g_variant_type_info_member_info (value.type_info, index_);
1045 : 868137 : child.type_info = g_variant_type_info_ref (member_info->type_info);
1046 : 868137 : child.depth = value.depth + 1;
1047 : 868137 : offset_size = gvs_get_offset_size (value.size);
1048 : :
1049 : : /* Ensure the size is set for fixed-sized children, or
1050 : : * g_variant_serialised_check() will fail, even if we return
1051 : : * (child.data == NULL) to indicate an error. */
1052 : 868137 : if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_FIXED)
1053 : 548632 : g_variant_type_info_query (child.type_info, NULL, &child.size);
1054 : :
1055 : : /* tuples are the only (potentially) fixed-sized containers, so the
1056 : : * only ones that have to deal with the possibility of having %NULL
1057 : : * data with a non-zero %size if errors occurred elsewhere.
1058 : : */
1059 : 868137 : if G_UNLIKELY (value.data == NULL && value.size != 0)
1060 : : {
1061 : : /* this can only happen in fixed-sized tuples,
1062 : : * so the child must also be fixed sized.
1063 : : */
1064 : 23296 : g_assert (child.size != 0);
1065 : 23296 : child.data = NULL;
1066 : :
1067 : 23296 : return child;
1068 : : }
1069 : :
1070 : : /* If the requested @index_ is beyond the set of indices whose framing offsets
1071 : : * have been checked, check the remaining offsets to see whether they’re
1072 : : * normal (in order, no overlapping tuple elements).
1073 : : *
1074 : : * Unlike the checks in gvs_variable_sized_array_get_child(), we have to check
1075 : : * all the tuple *elements* here, not just all the framing offsets, since
1076 : : * tuples contain a mix of elements which use framing offsets and ones which
1077 : : * don’t. None of them are allowed to overlap. */
1078 : 844841 : if (index_ > value.checked_offsets_up_to &&
1079 : 613327 : value.ordered_offsets_up_to == value.checked_offsets_up_to)
1080 : : {
1081 : 613327 : gsize i, prev_i_end = 0;
1082 : :
1083 : 613327 : if (value.checked_offsets_up_to > 0)
1084 : 0 : gvs_tuple_get_member_bounds (value, value.checked_offsets_up_to - 1, offset_size, NULL, &prev_i_end);
1085 : :
1086 : 3176615 : for (i = value.checked_offsets_up_to; i <= index_; i++)
1087 : : {
1088 : : gsize i_start, i_end;
1089 : :
1090 : 2880075 : gvs_tuple_get_member_bounds (value, i, offset_size, &i_start, &i_end);
1091 : :
1092 : 2880075 : if (i_start > i_end || i_start < prev_i_end || i_end > value.size)
1093 : : break;
1094 : :
1095 : 2563288 : prev_i_end = i_end;
1096 : : }
1097 : :
1098 : 613327 : value.ordered_offsets_up_to = i - 1;
1099 : 613327 : value.checked_offsets_up_to = index_;
1100 : : }
1101 : :
1102 : 844841 : if (index_ > value.ordered_offsets_up_to)
1103 : : {
1104 : : /* Offsets are invalid somewhere, so return an empty child. */
1105 : 64278 : return child;
1106 : : }
1107 : :
1108 : 780563 : if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_OFFSET)
1109 : : {
1110 : 215776 : if (offset_size * (member_info->i + 2) > value.size)
1111 : 16 : return child;
1112 : : }
1113 : : else
1114 : : {
1115 : 564787 : if (offset_size * (member_info->i + 1) > value.size)
1116 : 12 : return child;
1117 : : }
1118 : :
1119 : : /* The child should not extend into the offset table. */
1120 : 780535 : gvs_tuple_get_member_bounds (value, index_, offset_size, &start, &end);
1121 : 780535 : gvs_tuple_get_member_bounds (value, g_variant_type_info_n_members (value.type_info) - 1, offset_size, NULL, &last_end);
1122 : :
1123 : 780535 : if (start < end && end <= value.size && end <= last_end)
1124 : : {
1125 : 466392 : child.data = value.data + start;
1126 : 466392 : child.size = end - start;
1127 : : }
1128 : :
1129 : 780535 : return child;
1130 : : }
1131 : :
1132 : : static gsize
1133 : 102372 : gvs_tuple_needed_size (GVariantTypeInfo *type_info,
1134 : : GVariantSerialisedFiller gvs_filler,
1135 : : const gpointer *children,
1136 : : gsize n_children)
1137 : : {
1138 : 102372 : const GVariantMemberInfo *member_info = NULL;
1139 : : gsize fixed_size;
1140 : : gsize offset;
1141 : : gsize i;
1142 : :
1143 : 102372 : g_variant_type_info_query (type_info, NULL, &fixed_size);
1144 : :
1145 : 102372 : if (fixed_size)
1146 : 6089 : return fixed_size;
1147 : :
1148 : 96283 : offset = 0;
1149 : :
1150 : : /* We must go through at least one iteration below. If the tuple had no
1151 : : * children, it would have a fixed size. */
1152 : 96283 : g_assert (n_children > 0);
1153 : :
1154 : 1012032 : for (i = 0; i < n_children; i++)
1155 : : {
1156 : : guint alignment;
1157 : :
1158 : 915749 : member_info = g_variant_type_info_member_info (type_info, i);
1159 : 915749 : g_variant_type_info_query (member_info->type_info,
1160 : : &alignment, &fixed_size);
1161 : 915749 : offset += (-offset) & alignment;
1162 : :
1163 : 915749 : if (fixed_size)
1164 : 676980 : offset += fixed_size;
1165 : : else
1166 : : {
1167 : 238769 : GVariantSerialised child = { 0, };
1168 : :
1169 : 238769 : gvs_filler (&child, children[i]);
1170 : 238769 : offset += child.size;
1171 : : }
1172 : : }
1173 : :
1174 : 96283 : return gvs_calculate_total_size (offset, member_info->i + 1);
1175 : : }
1176 : :
1177 : : static void
1178 : 62028 : gvs_tuple_serialise (GVariantSerialised value,
1179 : : GVariantSerialisedFiller gvs_filler,
1180 : : const gpointer *children,
1181 : : gsize n_children)
1182 : : {
1183 : : gsize offset_size;
1184 : : gsize offset;
1185 : : gsize i;
1186 : :
1187 : 62028 : offset_size = gvs_get_offset_size (value.size);
1188 : 62028 : offset = 0;
1189 : :
1190 : 446624 : for (i = 0; i < n_children; i++)
1191 : : {
1192 : : const GVariantMemberInfo *member_info;
1193 : 384596 : GVariantSerialised child = { 0, };
1194 : : guint alignment;
1195 : :
1196 : 384596 : member_info = g_variant_type_info_member_info (value.type_info, i);
1197 : 384596 : g_variant_type_info_query (member_info->type_info, &alignment, NULL);
1198 : :
1199 : 655795 : while (offset & alignment)
1200 : 271199 : value.data[offset++] = '\0';
1201 : :
1202 : 384596 : child.data = value.data + offset;
1203 : 384596 : gvs_filler (&child, children[i]);
1204 : 384596 : offset += child.size;
1205 : :
1206 : 384596 : if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_OFFSET)
1207 : : {
1208 : 97537 : value.size -= offset_size;
1209 : 97537 : gvs_write_unaligned_le (value.data + value.size,
1210 : : offset, offset_size);
1211 : : }
1212 : : }
1213 : :
1214 : 80074 : while (offset < value.size)
1215 : 18046 : value.data[offset++] = '\0';
1216 : 62028 : }
1217 : :
1218 : : static gboolean
1219 : 32774 : gvs_tuple_is_normal (GVariantSerialised value)
1220 : : {
1221 : : guint offset_size;
1222 : : gsize offset_ptr;
1223 : : gsize length;
1224 : : gsize offset;
1225 : : gsize i;
1226 : : gsize offset_table_size;
1227 : :
1228 : : /* as per the comment in gvs_tuple_get_child() */
1229 : 32774 : if G_UNLIKELY (value.data == NULL && value.size != 0)
1230 : 22 : return FALSE;
1231 : :
1232 : 32752 : offset_size = gvs_get_offset_size (value.size);
1233 : 32752 : length = g_variant_type_info_n_members (value.type_info);
1234 : 32752 : offset_ptr = value.size;
1235 : 32752 : offset = 0;
1236 : :
1237 : 331659 : for (i = 0; i < length; i++)
1238 : : {
1239 : : const GVariantMemberInfo *member_info;
1240 : 299362 : GVariantSerialised child = { 0, };
1241 : : gsize fixed_size;
1242 : : guint alignment;
1243 : : gsize end;
1244 : :
1245 : 299362 : member_info = g_variant_type_info_member_info (value.type_info, i);
1246 : 299362 : child.type_info = member_info->type_info;
1247 : 299362 : child.depth = value.depth + 1;
1248 : :
1249 : 299362 : g_variant_type_info_query (child.type_info, &alignment, &fixed_size);
1250 : :
1251 : 523426 : while (offset & alignment)
1252 : : {
1253 : 224104 : if (offset > value.size || value.data[offset] != '\0')
1254 : 455 : return FALSE;
1255 : 224064 : offset++;
1256 : : }
1257 : :
1258 : 299322 : child.data = value.data + offset;
1259 : :
1260 : 299322 : switch (member_info->ending_type)
1261 : : {
1262 : 233779 : case G_VARIANT_MEMBER_ENDING_FIXED:
1263 : 233779 : end = offset + fixed_size;
1264 : 233779 : break;
1265 : :
1266 : 5966 : case G_VARIANT_MEMBER_ENDING_LAST:
1267 : 5966 : end = offset_ptr;
1268 : 5966 : break;
1269 : :
1270 : 59577 : case G_VARIANT_MEMBER_ENDING_OFFSET:
1271 : 59577 : if (offset_ptr < offset_size)
1272 : 2 : return FALSE;
1273 : :
1274 : 59575 : offset_ptr -= offset_size;
1275 : :
1276 : 59575 : if (offset_ptr < offset)
1277 : 4 : return FALSE;
1278 : :
1279 : 59571 : end = gvs_read_unaligned_le (value.data + offset_ptr, offset_size);
1280 : 59571 : break;
1281 : :
1282 : 0 : default:
1283 : : g_assert_not_reached ();
1284 : : }
1285 : :
1286 : 299316 : if (end < offset || end > offset_ptr)
1287 : 63 : return FALSE;
1288 : :
1289 : 299253 : child.size = end - offset;
1290 : :
1291 : 299253 : if (child.size == 0)
1292 : 2018 : child.data = NULL;
1293 : :
1294 : 299253 : if (!g_variant_serialised_is_normal (child))
1295 : 346 : return FALSE;
1296 : :
1297 : 298907 : offset = end;
1298 : : }
1299 : :
1300 : : /* All element bounds have been checked above. */
1301 : 32297 : value.ordered_offsets_up_to = G_MAXSIZE;
1302 : 32297 : value.checked_offsets_up_to = G_MAXSIZE;
1303 : :
1304 : : {
1305 : : gsize fixed_size;
1306 : : guint alignment;
1307 : :
1308 : 32297 : g_variant_type_info_query (value.type_info, &alignment, &fixed_size);
1309 : :
1310 : 32297 : if (fixed_size)
1311 : : {
1312 : 9209 : g_assert (fixed_size == value.size);
1313 : 9209 : g_assert (offset_ptr == value.size);
1314 : :
1315 : 9209 : if (i == 0)
1316 : : {
1317 : 268 : if (value.data[offset++] != '\0')
1318 : 24 : return FALSE;
1319 : : }
1320 : : else
1321 : : {
1322 : 21591 : while (offset & alignment)
1323 : 12666 : if (value.data[offset++] != '\0')
1324 : 16 : return FALSE;
1325 : : }
1326 : :
1327 : 9185 : g_assert (offset == value.size);
1328 : : }
1329 : : }
1330 : :
1331 : : /* @offset_ptr has been counting backwards from the end of the variant, to
1332 : : * find the beginning of the offset table. @offset has been counting forwards
1333 : : * from the beginning of the variant to find the end of the data. They should
1334 : : * have met in the middle. */
1335 : 32273 : if (offset_ptr != offset)
1336 : 0 : return FALSE;
1337 : :
1338 : 32273 : offset_table_size = value.size - offset_ptr;
1339 : 32273 : if (value.size > 0 &&
1340 : 32262 : gvs_calculate_total_size (offset, offset_table_size / offset_size) != value.size)
1341 : 2 : return FALSE; /* offset size not minimal */
1342 : :
1343 : 32271 : return TRUE;
1344 : : }
1345 : :
1346 : : /* Variants {{{2
1347 : : *
1348 : : * Variants are stored by storing the serialized data of the child,
1349 : : * followed by a '\0' character, followed by the type string of the
1350 : : * child.
1351 : : *
1352 : : * In the case that a value is presented that contains no '\0'
1353 : : * character, or doesn't have a single well-formed definite type string
1354 : : * following that character, the variant must be taken as containing the
1355 : : * unit tuple: ().
1356 : : */
1357 : :
1358 : : static inline gsize
1359 : 146155 : gvs_variant_n_children (GVariantSerialised value)
1360 : : {
1361 : 146155 : return 1;
1362 : : }
1363 : :
1364 : : static inline GVariantSerialised
1365 : 145774 : gvs_variant_get_child (GVariantSerialised value,
1366 : : gsize index_)
1367 : : {
1368 : 145774 : GVariantSerialised child = { 0, };
1369 : :
1370 : : /* NOTE: not O(1) and impossible for it to be... */
1371 : 145774 : if (value.size)
1372 : : {
1373 : : /* find '\0' character */
1374 : 288656 : for (child.size = value.size - 1; child.size; child.size--)
1375 : 288167 : if (value.data[child.size] == '\0')
1376 : 125970 : break;
1377 : :
1378 : : /* ensure we didn't just hit the start of the string */
1379 : 126459 : if (value.data[child.size] == '\0')
1380 : : {
1381 : 126402 : const gchar *type_string = (gchar *) &value.data[child.size + 1];
1382 : 126402 : const gchar *limit = (gchar *) &value.data[value.size];
1383 : : const gchar *end;
1384 : :
1385 : 126402 : if (g_variant_type_string_scan (type_string, limit, &end) &&
1386 : 126141 : end == limit)
1387 : : {
1388 : 126122 : const GVariantType *type = (GVariantType *) type_string;
1389 : :
1390 : 126122 : if (g_variant_type_is_definite (type))
1391 : : {
1392 : : gsize fixed_size;
1393 : : gsize child_type_depth;
1394 : :
1395 : 126120 : child.type_info = g_variant_type_info_get (type);
1396 : 126120 : child.depth = value.depth + 1;
1397 : :
1398 : 126120 : if (child.size != 0)
1399 : : /* only set to non-%NULL if size > 0 */
1400 : 125718 : child.data = value.data;
1401 : :
1402 : 126120 : g_variant_type_info_query (child.type_info,
1403 : : NULL, &fixed_size);
1404 : 126120 : child_type_depth = g_variant_type_info_query_depth (child.type_info);
1405 : :
1406 : 126120 : if ((!fixed_size || fixed_size == child.size) &&
1407 : 126120 : value.depth < G_VARIANT_MAX_RECURSION_DEPTH - child_type_depth)
1408 : 126118 : return child;
1409 : :
1410 : 2 : g_variant_type_info_unref (child.type_info);
1411 : : }
1412 : : }
1413 : : }
1414 : : }
1415 : :
1416 : 19656 : child.type_info = g_variant_type_info_get (G_VARIANT_TYPE_UNIT);
1417 : 19656 : child.data = NULL;
1418 : 19656 : child.size = 1;
1419 : 19656 : child.depth = value.depth + 1;
1420 : :
1421 : 19656 : return child;
1422 : : }
1423 : :
1424 : : static inline gsize
1425 : 209574 : gvs_variant_needed_size (GVariantTypeInfo *type_info,
1426 : : GVariantSerialisedFiller gvs_filler,
1427 : : const gpointer *children,
1428 : : gsize n_children)
1429 : : {
1430 : 209574 : GVariantSerialised child = { 0, };
1431 : : const gchar *type_string;
1432 : :
1433 : 209574 : gvs_filler (&child, children[0]);
1434 : 209574 : type_string = g_variant_type_info_get_type_string (child.type_info);
1435 : :
1436 : 209574 : return child.size + 1 + strlen (type_string);
1437 : : }
1438 : :
1439 : : static inline void
1440 : 73293 : gvs_variant_serialise (GVariantSerialised value,
1441 : : GVariantSerialisedFiller gvs_filler,
1442 : : const gpointer *children,
1443 : : gsize n_children)
1444 : : {
1445 : 73293 : GVariantSerialised child = { 0, };
1446 : : const gchar *type_string;
1447 : :
1448 : 73293 : child.data = value.data;
1449 : :
1450 : 73293 : gvs_filler (&child, children[0]);
1451 : 73293 : type_string = g_variant_type_info_get_type_string (child.type_info);
1452 : 73293 : value.data[child.size] = '\0';
1453 : 73293 : memcpy (value.data + child.size + 1, type_string, strlen (type_string));
1454 : 73293 : }
1455 : :
1456 : : static inline gboolean
1457 : 33731 : gvs_variant_is_normal (GVariantSerialised value)
1458 : : {
1459 : : GVariantSerialised child;
1460 : : gboolean normal;
1461 : : gsize child_type_depth;
1462 : :
1463 : 33731 : child = gvs_variant_get_child (value, 0);
1464 : 33731 : child_type_depth = g_variant_type_info_query_depth (child.type_info);
1465 : :
1466 : 101193 : normal = (value.depth < G_VARIANT_MAX_RECURSION_DEPTH - child_type_depth) &&
1467 : 67303 : (child.data != NULL || child.size == 0) &&
1468 : 33572 : g_variant_serialised_is_normal (child);
1469 : :
1470 : 33731 : g_variant_type_info_unref (child.type_info);
1471 : :
1472 : 33731 : return normal;
1473 : : }
1474 : :
1475 : :
1476 : :
1477 : : /* PART 2: Serializer API {{{1
1478 : : *
1479 : : * This is the implementation of the API of the serializer as advertised
1480 : : * in gvariant-serialiser.h.
1481 : : */
1482 : :
1483 : : /* Dispatch Utilities {{{2
1484 : : *
1485 : : * These macros allow a given function (for example,
1486 : : * g_variant_serialiser_serialise) to be dispatched to the appropriate
1487 : : * type-specific function above (fixed/variable-sized maybe,
1488 : : * fixed/variable-sized array, tuple or variant).
1489 : : */
1490 : : #define DISPATCH_FIXED(type_info, before, after) \
1491 : : { \
1492 : : gsize fixed_size; \
1493 : : \
1494 : : g_variant_type_info_query_element (type_info, NULL, \
1495 : : &fixed_size); \
1496 : : \
1497 : : if (fixed_size) \
1498 : : { \
1499 : : before ## fixed_sized ## after \
1500 : : } \
1501 : : else \
1502 : : { \
1503 : : before ## variable_sized ## after \
1504 : : } \
1505 : : }
1506 : :
1507 : : #define DISPATCH_CASES(type_info, before, after) \
1508 : : switch (g_variant_type_info_get_type_char (type_info)) \
1509 : : { \
1510 : : case G_VARIANT_TYPE_INFO_CHAR_MAYBE: \
1511 : : DISPATCH_FIXED (type_info, before, _maybe ## after) \
1512 : : \
1513 : : case G_VARIANT_TYPE_INFO_CHAR_ARRAY: \
1514 : : DISPATCH_FIXED (type_info, before, _array ## after) \
1515 : : \
1516 : : case G_VARIANT_TYPE_INFO_CHAR_DICT_ENTRY: \
1517 : : case G_VARIANT_TYPE_INFO_CHAR_TUPLE: \
1518 : : { \
1519 : : before ## tuple ## after \
1520 : : } \
1521 : : \
1522 : : case G_VARIANT_TYPE_INFO_CHAR_VARIANT: \
1523 : : { \
1524 : : before ## variant ## after \
1525 : : } \
1526 : : }
1527 : :
1528 : : /* Serializer entry points {{{2
1529 : : *
1530 : : * These are the functions that are called in order for the serializer
1531 : : * to do its thing.
1532 : : */
1533 : :
1534 : : /* < private >
1535 : : * g_variant_serialised_n_children:
1536 : : * @serialised: a #GVariantSerialised
1537 : : *
1538 : : * For serialized data that represents a container value (maybes,
1539 : : * tuples, arrays, variants), determine how many child items are inside
1540 : : * that container.
1541 : : *
1542 : : * Returns: the number of children
1543 : : */
1544 : : gsize
1545 : 6595279 : g_variant_serialised_n_children (GVariantSerialised serialised)
1546 : : {
1547 : 6595279 : g_assert (g_variant_serialised_check (serialised));
1548 : :
1549 : 6595279 : DISPATCH_CASES (serialised.type_info,
1550 : :
1551 : : return gvs_/**/,/**/_n_children (serialised);
1552 : :
1553 : : )
1554 : : g_assert_not_reached ();
1555 : : }
1556 : :
1557 : : /* < private >
1558 : : * g_variant_serialised_get_child:
1559 : : * @serialised: a #GVariantSerialised
1560 : : * @index_: the index of the child to fetch
1561 : : *
1562 : : * Extracts a child from a serialized data representing a container
1563 : : * value.
1564 : : *
1565 : : * It is an error to call this function with an index out of bounds.
1566 : : *
1567 : : * If the result .data == %NULL and .size > 0 then there has been an
1568 : : * error extracting the requested fixed-sized value. This number of
1569 : : * zero bytes needs to be allocated instead.
1570 : : *
1571 : : * In the case that .data == %NULL and .size == 0 then a zero-sized
1572 : : * item of a variable-sized type is being returned.
1573 : : *
1574 : : * .data is never non-%NULL if size is 0.
1575 : : *
1576 : : * Returns: a #GVariantSerialised for the child
1577 : : */
1578 : : GVariantSerialised
1579 : 5974075 : g_variant_serialised_get_child (GVariantSerialised serialised,
1580 : : gsize index_)
1581 : : {
1582 : : GVariantSerialised child;
1583 : :
1584 : 5974075 : g_assert (g_variant_serialised_check (serialised));
1585 : :
1586 : 5974075 : if G_LIKELY (index_ < g_variant_serialised_n_children (serialised))
1587 : : {
1588 : 5974075 : DISPATCH_CASES (serialised.type_info,
1589 : :
1590 : : child = gvs_/**/,/**/_get_child (serialised, index_);
1591 : : g_assert (child.size || child.data == NULL);
1592 : : g_assert (g_variant_serialised_check (child));
1593 : : return child;
1594 : :
1595 : : )
1596 : : g_assert_not_reached ();
1597 : : }
1598 : :
1599 : 0 : g_error ("Attempt to access item %"G_GSIZE_FORMAT
1600 : : " in a container with only %"G_GSIZE_FORMAT" items",
1601 : : index_, g_variant_serialised_n_children (serialised));
1602 : : }
1603 : :
1604 : : /* < private >
1605 : : * g_variant_serialiser_serialise:
1606 : : * @serialised: a #GVariantSerialised, properly set up
1607 : : * @gvs_filler: the filler function
1608 : : * @children: an array of child items
1609 : : * @n_children: the size of @children
1610 : : *
1611 : : * Writes data in serialized form.
1612 : : *
1613 : : * The type_info field of @serialised must be filled in to type info for
1614 : : * the type that we are serializing.
1615 : : *
1616 : : * The size field of @serialised must be filled in with the value
1617 : : * returned by a previous call to g_variant_serialiser_needed_size().
1618 : : *
1619 : : * The data field of @serialised must be a pointer to a properly-aligned
1620 : : * memory region large enough to serialize into (ie: at least as big as
1621 : : * the size field).
1622 : : *
1623 : : * This function is only responsible for serializing the top-level
1624 : : * container. @gvs_filler is called on each child of the container in
1625 : : * order for all of the data of that child to be filled in.
1626 : : */
1627 : : void
1628 : 230275 : g_variant_serialiser_serialise (GVariantSerialised serialised,
1629 : : GVariantSerialisedFiller gvs_filler,
1630 : : const gpointer *children,
1631 : : gsize n_children)
1632 : : {
1633 : 230275 : g_assert (g_variant_serialised_check (serialised));
1634 : :
1635 : 230275 : DISPATCH_CASES (serialised.type_info,
1636 : :
1637 : : gvs_/**/,/**/_serialise (serialised, gvs_filler,
1638 : : children, n_children);
1639 : : return;
1640 : :
1641 : : )
1642 : : g_assert_not_reached ();
1643 : : }
1644 : :
1645 : : /* < private >
1646 : : * g_variant_serialiser_needed_size:
1647 : : * @type_info: the type to serialize for
1648 : : * @gvs_filler: the filler function
1649 : : * @children: an array of child items
1650 : : * @n_children: the size of @children
1651 : : *
1652 : : * Determines how much memory would be needed to serialize this value.
1653 : : *
1654 : : * This function is only responsible for performing calculations for the
1655 : : * top-level container. @gvs_filler is called on each child of the
1656 : : * container in order to determine its size.
1657 : : */
1658 : : gsize
1659 : 565545 : g_variant_serialiser_needed_size (GVariantTypeInfo *type_info,
1660 : : GVariantSerialisedFiller gvs_filler,
1661 : : const gpointer *children,
1662 : : gsize n_children)
1663 : : {
1664 : 565545 : DISPATCH_CASES (type_info,
1665 : :
1666 : : return gvs_/**/,/**/_needed_size (type_info, gvs_filler,
1667 : : children, n_children);
1668 : :
1669 : : )
1670 : : g_assert_not_reached ();
1671 : : }
1672 : :
1673 : : /* Byteswapping {{{2 */
1674 : :
1675 : : /* < private >
1676 : : * g_variant_serialised_byteswap:
1677 : : * @value: a #GVariantSerialised
1678 : : *
1679 : : * Byte-swap serialized data. The result of this function is only
1680 : : * well-defined if the data is in normal form.
1681 : : */
1682 : : void
1683 : 345862 : g_variant_serialised_byteswap (GVariantSerialised serialised)
1684 : : {
1685 : : gsize fixed_size;
1686 : : guint alignment;
1687 : :
1688 : 345862 : g_assert (g_variant_serialised_check (serialised));
1689 : :
1690 : 345862 : if (!serialised.data)
1691 : 320274 : return;
1692 : :
1693 : : /* the types we potentially need to byteswap are
1694 : : * exactly those with alignment requirements.
1695 : : */
1696 : 345387 : g_variant_type_info_query (serialised.type_info, &alignment, &fixed_size);
1697 : 345387 : if (!alignment)
1698 : 10682 : return;
1699 : :
1700 : : /* if fixed size and alignment are equal then we are down
1701 : : * to the base integer type and we should swap it. the
1702 : : * only exception to this is if we have a tuple with a
1703 : : * single item, and then swapping it will be OK anyway.
1704 : : */
1705 : 334705 : if (alignment + 1 == fixed_size)
1706 : : {
1707 : 309117 : switch (fixed_size)
1708 : : {
1709 : 13193 : case 2:
1710 : : {
1711 : 13193 : guint16 *ptr = (guint16 *) serialised.data;
1712 : :
1713 : 13193 : g_assert_cmpint (serialised.size, ==, 2);
1714 : 13193 : *ptr = GUINT16_SWAP_LE_BE (*ptr);
1715 : : }
1716 : 13193 : return;
1717 : :
1718 : 286617 : case 4:
1719 : : {
1720 : 286617 : guint32 *ptr = (guint32 *) serialised.data;
1721 : :
1722 : 286617 : g_assert_cmpint (serialised.size, ==, 4);
1723 : 286617 : *ptr = GUINT32_SWAP_LE_BE (*ptr);
1724 : : }
1725 : 286617 : return;
1726 : :
1727 : 9307 : case 8:
1728 : : {
1729 : 9307 : guint64 *ptr = (guint64 *) serialised.data;
1730 : :
1731 : 9307 : g_assert_cmpint (serialised.size, ==, 8);
1732 : 9307 : *ptr = GUINT64_SWAP_LE_BE (*ptr);
1733 : : }
1734 : 9307 : return;
1735 : :
1736 : 0 : default:
1737 : : g_assert_not_reached ();
1738 : : }
1739 : : }
1740 : :
1741 : : /* else, we have a container that potentially contains
1742 : : * some children that need to be byteswapped.
1743 : : */
1744 : : else
1745 : : {
1746 : : gsize children, i;
1747 : :
1748 : 25588 : children = g_variant_serialised_n_children (serialised);
1749 : 371284 : for (i = 0; i < children; i++)
1750 : : {
1751 : : GVariantSerialised child;
1752 : :
1753 : 345696 : child = g_variant_serialised_get_child (serialised, i);
1754 : 345696 : g_variant_serialised_byteswap (child);
1755 : 345696 : g_variant_type_info_unref (child.type_info);
1756 : : }
1757 : : }
1758 : : }
1759 : :
1760 : : /* Normal form checking {{{2 */
1761 : :
1762 : : /* < private >
1763 : : * g_variant_serialised_is_normal:
1764 : : * @serialised: a #GVariantSerialised
1765 : : *
1766 : : * Determines, recursively if @serialised is in normal form. There is
1767 : : * precisely one normal form of serialized data for each possible value.
1768 : : *
1769 : : * It is possible that multiple byte sequences form the serialized data
1770 : : * for a given value if, for example, the padding bytes are filled in
1771 : : * with something other than zeros, but only one form is the normal
1772 : : * form.
1773 : : */
1774 : : gboolean
1775 : 2642874 : g_variant_serialised_is_normal (GVariantSerialised serialised)
1776 : : {
1777 : 2642874 : if (serialised.depth >= G_VARIANT_MAX_RECURSION_DEPTH)
1778 : 0 : return FALSE;
1779 : :
1780 : 2642874 : DISPATCH_CASES (serialised.type_info,
1781 : :
1782 : : return gvs_/**/,/**/_is_normal (serialised);
1783 : :
1784 : : )
1785 : :
1786 : 2512881 : if (serialised.data == NULL)
1787 : 82 : return FALSE;
1788 : :
1789 : : /* some hard-coded terminal cases */
1790 : 2512799 : switch (g_variant_type_info_get_type_char (serialised.type_info))
1791 : : {
1792 : 48951 : case 'b': /* boolean */
1793 : 48951 : return serialised.data[0] < 2;
1794 : :
1795 : 160244 : case 's': /* string */
1796 : 160244 : return g_variant_serialiser_is_string (serialised.data,
1797 : : serialised.size);
1798 : :
1799 : 47669 : case 'o':
1800 : 47669 : return g_variant_serialiser_is_object_path (serialised.data,
1801 : : serialised.size);
1802 : :
1803 : 507824 : case 'g':
1804 : 507824 : return g_variant_serialiser_is_signature (serialised.data,
1805 : : serialised.size);
1806 : :
1807 : 1748111 : default:
1808 : : /* all of the other types are fixed-sized numerical types for
1809 : : * which all possible values are valid (including various NaN
1810 : : * representations for floating point values).
1811 : : */
1812 : 1748111 : return TRUE;
1813 : : }
1814 : : }
1815 : :
1816 : : /* Validity-checking functions {{{2
1817 : : *
1818 : : * Checks if strings, object paths and signature strings are valid.
1819 : : */
1820 : :
1821 : : /* < private >
1822 : : * g_variant_serialiser_is_string:
1823 : : * @data: a possible string
1824 : : * @size: the size of @data
1825 : : *
1826 : : * Ensures that @data is a valid string with a nul terminator at the end
1827 : : * and no nul bytes embedded.
1828 : : */
1829 : : gboolean
1830 : 1503662 : g_variant_serialiser_is_string (gconstpointer data,
1831 : : gsize size)
1832 : : {
1833 : : const gchar *expected_end;
1834 : : const gchar *end;
1835 : :
1836 : : /* Strings must end with a nul terminator. */
1837 : 1503662 : if (size == 0)
1838 : 100214 : return FALSE;
1839 : :
1840 : 1403448 : expected_end = ((gchar *) data) + size - 1;
1841 : :
1842 : 1403448 : if (*expected_end != '\0')
1843 : 40 : return FALSE;
1844 : :
1845 : 1403408 : g_utf8_validate_len (data, size, &end);
1846 : :
1847 : 1403408 : return end == expected_end;
1848 : : }
1849 : :
1850 : : /* < private >
1851 : : * g_variant_serialiser_is_object_path:
1852 : : * @data: a possible D-Bus object path
1853 : : * @size: the size of @data
1854 : : *
1855 : : * Performs the checks for being a valid string.
1856 : : *
1857 : : * Also, ensures that @data is a valid D-Bus object path, as per the D-Bus
1858 : : * specification.
1859 : : */
1860 : : gboolean
1861 : 488771 : g_variant_serialiser_is_object_path (gconstpointer data,
1862 : : gsize size)
1863 : : {
1864 : 488771 : const gchar *string = data;
1865 : : gsize i;
1866 : :
1867 : 488771 : if (!g_variant_serialiser_is_string (data, size))
1868 : 62747 : return FALSE;
1869 : :
1870 : : /* The path must begin with an ASCII '/' (integer 47) character */
1871 : 426024 : if (string[0] != '/')
1872 : 18 : return FALSE;
1873 : :
1874 : 16220873 : for (i = 1; string[i]; i++)
1875 : : /* Each element must only contain the ASCII characters
1876 : : * "[A-Z][a-z][0-9]_"
1877 : : */
1878 : 15794878 : if (g_ascii_isalnum (string[i]) || string[i] == '_')
1879 : : ;
1880 : :
1881 : : /* must consist of elements separated by slash characters. */
1882 : 203738 : else if (string[i] == '/')
1883 : : {
1884 : : /* No element may be the empty string. */
1885 : : /* Multiple '/' characters cannot occur in sequence. */
1886 : 203729 : if (string[i - 1] == '/')
1887 : 2 : return FALSE;
1888 : : }
1889 : :
1890 : : else
1891 : 9 : return FALSE;
1892 : :
1893 : : /* A trailing '/' character is not allowed unless the path is the
1894 : : * root path (a single '/' character).
1895 : : */
1896 : 425995 : if (i > 1 && string[i - 1] == '/')
1897 : 1 : return FALSE;
1898 : :
1899 : 425994 : return TRUE;
1900 : : }
1901 : :
1902 : : /* < private >
1903 : : * g_variant_serialiser_is_signature:
1904 : : * @data: a possible D-Bus signature
1905 : : * @size: the size of @data
1906 : : *
1907 : : * Performs the checks for being a valid string.
1908 : : *
1909 : : * Also, ensures that @data is a valid D-Bus type signature, as per the
1910 : : * D-Bus specification. Note that this means the empty string is valid, as the
1911 : : * D-Bus specification defines a signature as “zero or more single complete
1912 : : * types”.
1913 : : */
1914 : : gboolean
1915 : 810729 : g_variant_serialiser_is_signature (gconstpointer data,
1916 : : gsize size)
1917 : : {
1918 : 810729 : const gchar *string = data;
1919 : : gsize first_invalid;
1920 : :
1921 : 810729 : if (!g_variant_serialiser_is_string (data, size))
1922 : 7307 : return FALSE;
1923 : :
1924 : : /* make sure no non-definite characters appear */
1925 : 803422 : first_invalid = strspn (string, "ybnqiuxthdvasog(){}");
1926 : 803422 : if (string[first_invalid])
1927 : 28 : return FALSE;
1928 : :
1929 : : /* make sure each type string is well-formed */
1930 : 56576006 : while (*string)
1931 : 55772616 : if (!g_variant_type_string_scan (string, NULL, &string))
1932 : 4 : return FALSE;
1933 : :
1934 : 803390 : return TRUE;
1935 : : }
1936 : :
1937 : : /* Epilogue {{{1 */
1938 : : /* vim:set foldmethod=marker: */
|