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