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