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