Merge lp:~attente/glib/gicon-upstream into lp:ubuntu/saucy/glib2.0
- gicon-upstream
- Merge into saucy
Proposed by
William Hua
Status: | Merged |
---|---|
Merge reported by: | Sebastien Bacher |
Merged at revision: | not available |
Proposed branch: | lp:~attente/glib/gicon-upstream |
Merge into: | lp:ubuntu/saucy/glib2.0 |
Diff against target: |
27569 lines (+26956/-46) 51 files modified
.pc/applied-patches (+3/-0) .pc/g-variant-get-data-as-bytes.patch/glib/gvariant-core.c (+1104/-0) .pc/g-variant-get-data-as-bytes.patch/glib/tests/gvariant.c (+4339/-0) .pc/g-variant-new-take-string.patch/docs/reference/glib/glib-sections.txt (+3227/-0) .pc/g-variant-new-take-string.patch/glib/gvariant.c (+5328/-0) .pc/g-variant-new-take-string.patch/glib/gvariant.h (+395/-0) .pc/gicon-serialization-support.patch/docs/reference/gio/gio-docs.xml (+306/-0) .pc/gicon-serialization-support.patch/docs/reference/gio/gio-sections.txt (+4024/-0) .pc/gicon-serialization-support.patch/gio/Makefile.am (+786/-0) .pc/gicon-serialization-support.patch/gio/gemblem.c (+359/-0) .pc/gicon-serialization-support.patch/gio/gemblemedicon.c (+423/-0) .pc/gicon-serialization-support.patch/gio/gfileicon.c (+340/-0) .pc/gicon-serialization-support.patch/gio/gicon.c (+449/-0) .pc/gicon-serialization-support.patch/gio/gicon.h (+96/-0) .pc/gicon-serialization-support.patch/gio/gio.h (+164/-0) .pc/gicon-serialization-support.patch/gio/giotypes.h (+473/-0) .pc/gicon-serialization-support.patch/gio/gmenu.c (+1336/-0) .pc/gicon-serialization-support.patch/gio/gmenu.h (+177/-0) .pc/gicon-serialization-support.patch/gio/gmenumodel.h (+276/-0) .pc/gicon-serialization-support.patch/gio/gthemedicon.c (+522/-0) .pc/gicon-serialization-support.patch/gio/gvfs.h (+133/-0) .pc/gicon-serialization-support.patch/gio/tests/g-icon.c (+382/-0) debian/changelog (+11/-0) debian/libglib2.0-0.symbols (+7/-0) debian/patches/g-variant-get-data-as-bytes.patch (+58/-0) debian/patches/g-variant-new-take-string.patch (+66/-0) debian/patches/gicon-serialization-support.patch (+1205/-0) debian/patches/series (+3/-0) docs/reference/gio/gio-docs.xml (+1/-0) docs/reference/gio/gio-sections.txt (+19/-1) docs/reference/glib/glib-sections.txt (+1/-0) gio/Makefile.am (+2/-0) gio/gbytesicon.c (+264/-0) gio/gbytesicon.h (+54/-0) gio/gemblem.c (+21/-0) gio/gemblemedicon.c (+49/-0) gio/gfileicon.c (+9/-0) gio/gicon.c (+277/-39) gio/gicon.h (+7/-0) gio/gio.h (+1/-0) gio/giotypes.h (+1/-0) gio/gmenu.c (+41/-0) gio/gmenu.h (+4/-0) gio/gmenumodel.h (+15/-0) gio/gthemedicon.c (+9/-0) gio/gvfs.h (+2/-1) gio/tests/g-icon.c (+121/-1) glib/gvariant-core.c (+14/-1) glib/gvariant.c (+36/-0) glib/gvariant.h (+2/-0) glib/tests/gvariant.c (+14/-3) |
To merge this branch: | bzr merge lp:~attente/glib/gicon-upstream |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Ubuntu branches | Pending | ||
Review via email: mp+162430@code.launchpad.net |
Commit message
* debian/
- Add upstream's g_variant_
* debian/
- Add upstream's GVariant bytes serialization bug fix.
* debian/
- Add upstream's improved GIcon serialization support.
Description of the change
Patch GLib with upstream bug fixes to GVariant and changes to GIcon interface.
To post a comment you must log in.
Revision history for this message
Sebastien Bacher (seb128) wrote : | # |
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file '.pc/applied-patches' |
2 | --- .pc/applied-patches 2013-04-10 11:43:24 +0000 |
3 | +++ .pc/applied-patches 2013-05-03 17:57:29 +0000 |
4 | @@ -13,3 +13,6 @@ |
5 | 17_check_abis_mips_symbols.patch |
6 | 61_glib-compile-binaries-path.patch |
7 | 90_gio-modules-multiarch-compat.patch |
8 | +g-variant-new-take-string.patch |
9 | +g-variant-get-data-as-bytes.patch |
10 | +gicon-serialization-support.patch |
11 | |
12 | === added directory '.pc/g-variant-get-data-as-bytes.patch' |
13 | === added directory '.pc/g-variant-get-data-as-bytes.patch/glib' |
14 | === added file '.pc/g-variant-get-data-as-bytes.patch/glib/gvariant-core.c' |
15 | --- .pc/g-variant-get-data-as-bytes.patch/glib/gvariant-core.c 1970-01-01 00:00:00 +0000 |
16 | +++ .pc/g-variant-get-data-as-bytes.patch/glib/gvariant-core.c 2013-05-03 17:57:29 +0000 |
17 | @@ -0,0 +1,1104 @@ |
18 | +/* |
19 | + * Copyright © 2007, 2008 Ryan Lortie |
20 | + * Copyright © 2010 Codethink Limited |
21 | + * |
22 | + * This library is free software; you can redistribute it and/or |
23 | + * modify it under the terms of the GNU Lesser General Public |
24 | + * License as published by the Free Software Foundation; either |
25 | + * version 2 of the License, or (at your option) any later version. |
26 | + * |
27 | + * This library is distributed in the hope that it will be useful, |
28 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
29 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
30 | + * Lesser General Public License for more details. |
31 | + * |
32 | + * You should have received a copy of the GNU Lesser General Public |
33 | + * License along with this library; if not, write to the |
34 | + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
35 | + * Boston, MA 02111-1307, USA. |
36 | + */ |
37 | + |
38 | +#include "config.h" |
39 | + |
40 | +#include <glib/gvariant-core.h> |
41 | + |
42 | +#include <glib/gvariant-serialiser.h> |
43 | +#include <glib/gtestutils.h> |
44 | +#include <glib/gbitlock.h> |
45 | +#include <glib/gatomic.h> |
46 | +#include <glib/gbytes.h> |
47 | +#include <glib/gslice.h> |
48 | +#include <glib/gmem.h> |
49 | +#include <string.h> |
50 | + |
51 | + |
52 | +/* |
53 | + * This file includes the structure definition for GVariant and a small |
54 | + * set of functions that are allowed to access the structure directly. |
55 | + * |
56 | + * This minimises the amount of code that can possibly touch a GVariant |
57 | + * structure directly to a few simple fundamental operations. These few |
58 | + * operations are written to be completely threadsafe with respect to |
59 | + * all possible outside access. This means that we only need to be |
60 | + * concerned about thread safety issues in this one small file. |
61 | + * |
62 | + * Most GVariant API functions are in gvariant.c. |
63 | + */ |
64 | + |
65 | +/** |
66 | + * GVariant: |
67 | + * |
68 | + * #GVariant is an opaque data structure and can only be accessed |
69 | + * using the following functions. |
70 | + * |
71 | + * Since: 2.24 |
72 | + **/ |
73 | +struct _GVariant |
74 | +/* see below for field member documentation */ |
75 | +{ |
76 | + GVariantTypeInfo *type_info; |
77 | + gsize size; |
78 | + |
79 | + union |
80 | + { |
81 | + struct |
82 | + { |
83 | + GBytes *bytes; |
84 | + gconstpointer data; |
85 | + } serialised; |
86 | + |
87 | + struct |
88 | + { |
89 | + GVariant **children; |
90 | + gsize n_children; |
91 | + } tree; |
92 | + } contents; |
93 | + |
94 | + gint state; |
95 | + gint ref_count; |
96 | +}; |
97 | + |
98 | +/* struct GVariant: |
99 | + * |
100 | + * There are two primary forms of GVariant instances: "serialised form" |
101 | + * and "tree form". |
102 | + * |
103 | + * "serialised form": A serialised GVariant instance stores its value in |
104 | + * the GVariant serialisation format. All |
105 | + * basic-typed instances (ie: non-containers) are in |
106 | + * serialised format, as are some containers. |
107 | + * |
108 | + * "tree form": Some containers are in "tree form". In this case, |
109 | + * instead of containing the serialised data for the |
110 | + * container, the instance contains an array of pointers to |
111 | + * the child values of the container (thus forming a tree). |
112 | + * |
113 | + * It is possible for an instance to transition from tree form to |
114 | + * serialised form. This happens, implicitly, if the serialised data is |
115 | + * requested (eg: via g_variant_get_data()). Serialised form instances |
116 | + * never transition into tree form. |
117 | + * |
118 | + * |
119 | + * The fields of the structure are documented here: |
120 | + * |
121 | + * type_info: this is a reference to a GVariantTypeInfo describing the |
122 | + * type of the instance. When the instance is freed, this |
123 | + * reference must be released with g_variant_type_info_unref(). |
124 | + * |
125 | + * The type_info field never changes during the life of the |
126 | + * instance, so it can be accessed without a lock. |
127 | + * |
128 | + * size: this is the size of the serialised form for the instance, if it |
129 | + * is known. If the instance is in serialised form then it is, by |
130 | + * definition, known. If the instance is in tree form then it may |
131 | + * be unknown (in which case it is -1). It is possible for the |
132 | + * size to be known when in tree form if, for example, the user |
133 | + * has called g_variant_get_size() without calling |
134 | + * g_variant_get_data(). Additionally, even when the user calls |
135 | + * g_variant_get_data() the size of the data must first be |
136 | + * determined so that a large enough buffer can be allocated for |
137 | + * the data. |
138 | + * |
139 | + * Once the size is known, it can never become unknown again. |
140 | + * g_variant_ensure_size() is used to ensure that the size is in |
141 | + * the known state -- it calculates the size if needed. After |
142 | + * that, the size field can be accessed without a lock. |
143 | + * |
144 | + * contents: a union containing either the information associated with |
145 | + * holding a value in serialised form or holding a value in |
146 | + * tree form. |
147 | + * |
148 | + * .serialised: Only valid when the instance is in serialised form. |
149 | + * |
150 | + * Since an instance can never transition away from |
151 | + * serialised form, once these fields are set, they will |
152 | + * never be changed. It is therefore valid to access |
153 | + * them without holding a lock. |
154 | + * |
155 | + * .bytes: the #GBytes that contains the memory pointed to by |
156 | + * .data, or %NULL if .data is %NULL. In the event that |
157 | + * the instance was deserialised from another instance, |
158 | + * then the bytes will be shared by both of them. When |
159 | + * the instance is freed, this reference must be released |
160 | + * with g_bytes_unref(). |
161 | + * |
162 | + * .data: the serialised data (of size 'size') of the instance. |
163 | + * This pointer should not be freed or modified in any way. |
164 | + * #GBytes is responsible for memory management. |
165 | + * |
166 | + * This pointer may be %NULL in two cases: |
167 | + * |
168 | + * - if the serialised size of the instance is 0 |
169 | + * |
170 | + * - if the instance is of a fixed-sized type and was |
171 | + * deserialised out of a corrupted container such that |
172 | + * the container contains too few bytes to point to the |
173 | + * entire proper fixed-size of this instance. In this |
174 | + * case, 'size' will still be equal to the proper fixed |
175 | + * size, but this pointer will be %NULL. This is exactly |
176 | + * the reason that g_variant_get_data() sometimes returns |
177 | + * %NULL. For all other calls, the effect should be as |
178 | + * if .data pointed to the appropriate number of nul |
179 | + * bytes. |
180 | + * |
181 | + * .tree: Only valid when the instance is in tree form. |
182 | + * |
183 | + * Note that accesses from other threads could result in |
184 | + * conversion of the instance from tree form to serialised form |
185 | + * at any time. For this reason, the instance lock must always |
186 | + * be held while performing any operations on 'contents.tree'. |
187 | + * |
188 | + * .children: the array of the child instances of this instance. |
189 | + * When the instance is freed (or converted to serialised |
190 | + * form) then each child must have g_variant_unref() |
191 | + * called on it and the array must be freed using |
192 | + * g_free(). |
193 | + * |
194 | + * .n_children: the number of items in the .children array. |
195 | + * |
196 | + * state: a bitfield describing the state of the instance. It is a |
197 | + * bitwise-or of the following STATE_* constants: |
198 | + * |
199 | + * STATE_LOCKED: the instance lock is held. This is the bit used by |
200 | + * g_bit_lock(). |
201 | + * |
202 | + * STATE_SERIALISED: the instance is in serialised form. If this |
203 | + * flag is not set then the instance is in tree |
204 | + * form. |
205 | + * |
206 | + * STATE_TRUSTED: for serialised form instances, this means that the |
207 | + * serialised data is known to be in normal form (ie: |
208 | + * not corrupted). |
209 | + * |
210 | + * For tree form instances, this means that all of the |
211 | + * child instances in the contents.tree.children array |
212 | + * are trusted. This means that if the container is |
213 | + * serialised then the resulting data will be in |
214 | + * normal form. |
215 | + * |
216 | + * If this flag is unset it does not imply that the |
217 | + * data is corrupted. It merely means that we're not |
218 | + * sure that it's valid. See g_variant_is_trusted(). |
219 | + * |
220 | + * STATE_FLOATING: if this flag is set then the object has a floating |
221 | + * reference. See g_variant_ref_sink(). |
222 | + * |
223 | + * ref_count: the reference count of the instance |
224 | + */ |
225 | +#define STATE_LOCKED 1 |
226 | +#define STATE_SERIALISED 2 |
227 | +#define STATE_TRUSTED 4 |
228 | +#define STATE_FLOATING 8 |
229 | + |
230 | +/* -- private -- */ |
231 | +/* < private > |
232 | + * g_variant_lock: |
233 | + * @value: a #GVariant |
234 | + * |
235 | + * Locks @value for performing sensitive operations. |
236 | + */ |
237 | +static void |
238 | +g_variant_lock (GVariant *value) |
239 | +{ |
240 | + g_bit_lock (&value->state, 0); |
241 | +} |
242 | + |
243 | +/* < private > |
244 | + * g_variant_unlock: |
245 | + * @value: a #GVariant |
246 | + * |
247 | + * Unlocks @value after performing sensitive operations. |
248 | + */ |
249 | +static void |
250 | +g_variant_unlock (GVariant *value) |
251 | +{ |
252 | + g_bit_unlock (&value->state, 0); |
253 | +} |
254 | + |
255 | +/* < private > |
256 | + * g_variant_release_children: |
257 | + * @value: a #GVariant |
258 | + * |
259 | + * Releases the reference held on each child in the 'children' array of |
260 | + * @value and frees the array itself. @value must be in tree form. |
261 | + * |
262 | + * This is done when freeing a tree-form instance or converting it to |
263 | + * serialised form. |
264 | + * |
265 | + * The current thread must hold the lock on @value. |
266 | + */ |
267 | +static void |
268 | +g_variant_release_children (GVariant *value) |
269 | +{ |
270 | + gsize i; |
271 | + |
272 | + g_assert (value->state & STATE_LOCKED); |
273 | + g_assert (~value->state & STATE_SERIALISED); |
274 | + |
275 | + for (i = 0; i < value->contents.tree.n_children; i++) |
276 | + g_variant_unref (value->contents.tree.children[i]); |
277 | + |
278 | + g_free (value->contents.tree.children); |
279 | +} |
280 | + |
281 | +/* This begins the main body of the recursive serialiser. |
282 | + * |
283 | + * There are 3 functions here that work as a team with the serialiser to |
284 | + * get things done. g_variant_store() has a trivial role, but as a |
285 | + * public API function, it has its definition elsewhere. |
286 | + * |
287 | + * Note that "serialisation" of an instance does not mean that the |
288 | + * instance is converted to serialised form -- it means that the |
289 | + * serialised form of an instance is written to an external buffer. |
290 | + * g_variant_ensure_serialised() (which is not part of this set of |
291 | + * functions) is the function that is responsible for converting an |
292 | + * instance to serialised form. |
293 | + * |
294 | + * We are only concerned here with container types since non-container |
295 | + * instances are always in serialised form. For these instances, |
296 | + * storing their serialised form merely involves a memcpy(). |
297 | + * |
298 | + * Serialisation is a two-step process. First, the size of the |
299 | + * serialised data must be calculated so that an appropriately-sized |
300 | + * buffer can be allocated. Second, the data is written into the |
301 | + * buffer. |
302 | + * |
303 | + * Determining the size: |
304 | + * The process of determining the size is triggered by a call to |
305 | + * g_variant_ensure_size() on a container. This invokes the |
306 | + * serialiser code to determine the size. The serialiser is passed |
307 | + * g_variant_fill_gvs() as a callback. |
308 | + * |
309 | + * g_variant_fill_gvs() is called by the serialiser on each child of |
310 | + * the container which, in turn, calls g_variant_ensure_size() on |
311 | + * itself and fills in the result of its own size calculation. |
312 | + * |
313 | + * The serialiser uses the size information from the children to |
314 | + * calculate the size needed for the entire container. |
315 | + * |
316 | + * Writing the data: |
317 | + * After the buffer has been allocated, g_variant_serialise() is |
318 | + * called on the container. This invokes the serialiser code to write |
319 | + * the bytes to the container. The serialiser is, again, passed |
320 | + * g_variant_fill_gvs() as a callback. |
321 | + * |
322 | + * This time, when g_variant_fill_gvs() is called for each child, the |
323 | + * child is given a pointer to a sub-region of the allocated buffer |
324 | + * where it should write its data. This is done by calling |
325 | + * g_variant_store(). In the event that the instance is in serialised |
326 | + * form this means a memcpy() of the serialised data into the |
327 | + * allocated buffer. In the event that the instance is in tree form |
328 | + * this means a recursive call back into g_variant_serialise(). |
329 | + * |
330 | + * |
331 | + * The forward declaration here allows corecursion via callback: |
332 | + */ |
333 | +static void g_variant_fill_gvs (GVariantSerialised *, gpointer); |
334 | + |
335 | +/* < private > |
336 | + * g_variant_ensure_size: |
337 | + * @value: a #GVariant |
338 | + * |
339 | + * Ensures that the ->size field of @value is filled in properly. This |
340 | + * must be done as a precursor to any serialisation of the value in |
341 | + * order to know how large of a buffer is needed to store the data. |
342 | + * |
343 | + * The current thread must hold the lock on @value. |
344 | + */ |
345 | +static void |
346 | +g_variant_ensure_size (GVariant *value) |
347 | +{ |
348 | + g_assert (value->state & STATE_LOCKED); |
349 | + |
350 | + if (value->size == (gssize) -1) |
351 | + { |
352 | + gpointer *children; |
353 | + gsize n_children; |
354 | + |
355 | + children = (gpointer *) value->contents.tree.children; |
356 | + n_children = value->contents.tree.n_children; |
357 | + value->size = g_variant_serialiser_needed_size (value->type_info, |
358 | + g_variant_fill_gvs, |
359 | + children, n_children); |
360 | + } |
361 | +} |
362 | + |
363 | +/* < private > |
364 | + * g_variant_serialise: |
365 | + * @value: a #GVariant |
366 | + * @data: an appropriately-sized buffer |
367 | + * |
368 | + * Serialises @value into @data. @value must be in tree form. |
369 | + * |
370 | + * No change is made to @value. |
371 | + * |
372 | + * The current thread must hold the lock on @value. |
373 | + */ |
374 | +static void |
375 | +g_variant_serialise (GVariant *value, |
376 | + gpointer data) |
377 | +{ |
378 | + GVariantSerialised serialised = { 0, }; |
379 | + gpointer *children; |
380 | + gsize n_children; |
381 | + |
382 | + g_assert (~value->state & STATE_SERIALISED); |
383 | + g_assert (value->state & STATE_LOCKED); |
384 | + |
385 | + serialised.type_info = value->type_info; |
386 | + serialised.size = value->size; |
387 | + serialised.data = data; |
388 | + |
389 | + children = (gpointer *) value->contents.tree.children; |
390 | + n_children = value->contents.tree.n_children; |
391 | + |
392 | + g_variant_serialiser_serialise (serialised, g_variant_fill_gvs, |
393 | + children, n_children); |
394 | +} |
395 | + |
396 | +/* < private > |
397 | + * g_variant_fill_gvs: |
398 | + * @serialised: a pointer to a #GVariantSerialised |
399 | + * @data: a #GVariant instance |
400 | + * |
401 | + * This is the callback that is passed by a tree-form container instance |
402 | + * to the serialiser. This callback gets called on each child of the |
403 | + * container. Each child is responsible for performing the following |
404 | + * actions: |
405 | + * |
406 | + * - reporting its type |
407 | + * |
408 | + * - reporting its serialised size (requires knowing the size first) |
409 | + * |
410 | + * - possibly storing its serialised form into the provided buffer |
411 | + */ |
412 | +static void |
413 | +g_variant_fill_gvs (GVariantSerialised *serialised, |
414 | + gpointer data) |
415 | +{ |
416 | + GVariant *value = data; |
417 | + |
418 | + g_variant_lock (value); |
419 | + g_variant_ensure_size (value); |
420 | + g_variant_unlock (value); |
421 | + |
422 | + if (serialised->type_info == NULL) |
423 | + serialised->type_info = value->type_info; |
424 | + g_assert (serialised->type_info == value->type_info); |
425 | + |
426 | + if (serialised->size == 0) |
427 | + serialised->size = value->size; |
428 | + g_assert (serialised->size == value->size); |
429 | + |
430 | + if (serialised->data) |
431 | + /* g_variant_store() is a public API, so it |
432 | + * it will reacquire the lock if it needs to. |
433 | + */ |
434 | + g_variant_store (value, serialised->data); |
435 | +} |
436 | + |
437 | +/* this ends the main body of the recursive serialiser */ |
438 | + |
439 | +/* < private > |
440 | + * g_variant_ensure_serialised: |
441 | + * @value: a #GVariant |
442 | + * |
443 | + * Ensures that @value is in serialised form. |
444 | + * |
445 | + * If @value is in tree form then this function ensures that the |
446 | + * serialised size is known and then allocates a buffer of that size and |
447 | + * serialises the instance into the buffer. The 'children' array is |
448 | + * then released and the instance is set to serialised form based on the |
449 | + * contents of the buffer. |
450 | + * |
451 | + * The current thread must hold the lock on @value. |
452 | + */ |
453 | +static void |
454 | +g_variant_ensure_serialised (GVariant *value) |
455 | +{ |
456 | + g_assert (value->state & STATE_LOCKED); |
457 | + |
458 | + if (~value->state & STATE_SERIALISED) |
459 | + { |
460 | + GBytes *bytes; |
461 | + gpointer data; |
462 | + |
463 | + g_variant_ensure_size (value); |
464 | + data = g_malloc (value->size); |
465 | + g_variant_serialise (value, data); |
466 | + |
467 | + g_variant_release_children (value); |
468 | + |
469 | + bytes = g_bytes_new_take (data, value->size); |
470 | + value->contents.serialised.data = g_bytes_get_data (bytes, NULL); |
471 | + value->contents.serialised.bytes = bytes; |
472 | + value->state |= STATE_SERIALISED; |
473 | + } |
474 | +} |
475 | + |
476 | +/* < private > |
477 | + * g_variant_alloc: |
478 | + * @type: the type of the new instance |
479 | + * @serialised: if the instance will be in serialised form |
480 | + * @trusted: if the instance will be trusted |
481 | + * |
482 | + * Allocates a #GVariant instance and does some common work (such as |
483 | + * looking up and filling in the type info), setting the state field, |
484 | + * and setting the ref_count to 1. |
485 | + * |
486 | + * Returns: a new #GVariant with a floating reference |
487 | + */ |
488 | +static GVariant * |
489 | +g_variant_alloc (const GVariantType *type, |
490 | + gboolean serialised, |
491 | + gboolean trusted) |
492 | +{ |
493 | + GVariant *value; |
494 | + |
495 | + value = g_slice_new (GVariant); |
496 | + value->type_info = g_variant_type_info_get (type); |
497 | + value->state = (serialised ? STATE_SERIALISED : 0) | |
498 | + (trusted ? STATE_TRUSTED : 0) | |
499 | + STATE_FLOATING; |
500 | + value->size = (gssize) -1; |
501 | + value->ref_count = 1; |
502 | + |
503 | + return value; |
504 | +} |
505 | + |
506 | +/** |
507 | + * g_variant_new_from_bytes: |
508 | + * @type: a #GVariantType |
509 | + * @bytes: a #GBytes |
510 | + * @trusted: if the contents of @bytes are trusted |
511 | + * |
512 | + * Constructs a new serialised-mode #GVariant instance. This is the |
513 | + * inner interface for creation of new serialised values that gets |
514 | + * called from various functions in gvariant.c. |
515 | + * |
516 | + * A reference is taken on @bytes. |
517 | + * |
518 | + * Returns: a new #GVariant with a floating reference |
519 | + * |
520 | + * Since: 2.36 |
521 | + */ |
522 | +GVariant * |
523 | +g_variant_new_from_bytes (const GVariantType *type, |
524 | + GBytes *bytes, |
525 | + gboolean trusted) |
526 | +{ |
527 | + GVariant *value; |
528 | + guint alignment; |
529 | + gsize size; |
530 | + |
531 | + value = g_variant_alloc (type, TRUE, trusted); |
532 | + |
533 | + value->contents.serialised.bytes = g_bytes_ref (bytes); |
534 | + |
535 | + g_variant_type_info_query (value->type_info, |
536 | + &alignment, &size); |
537 | + |
538 | + if (size && g_bytes_get_size (bytes) != size) |
539 | + { |
540 | + /* Creating a fixed-sized GVariant with a bytes of the wrong |
541 | + * size. |
542 | + * |
543 | + * We should do the equivalent of pulling a fixed-sized child out |
544 | + * of a brozen container (ie: data is NULL size is equal to the correct |
545 | + * fixed size). |
546 | + */ |
547 | + value->contents.serialised.data = NULL; |
548 | + value->size = size; |
549 | + } |
550 | + else |
551 | + { |
552 | + value->contents.serialised.data = g_bytes_get_data (bytes, &value->size); |
553 | + } |
554 | + |
555 | + return value; |
556 | +} |
557 | + |
558 | +/* -- internal -- */ |
559 | + |
560 | +/* < internal > |
561 | + * g_variant_new_from_children: |
562 | + * @type: a #GVariantType |
563 | + * @children: an array of #GVariant pointers. Consumed. |
564 | + * @n_children: the length of @children |
565 | + * @trusted: %TRUE if every child in @children in trusted |
566 | + * |
567 | + * Constructs a new tree-mode #GVariant instance. This is the inner |
568 | + * interface for creation of new serialised values that gets called from |
569 | + * various functions in gvariant.c. |
570 | + * |
571 | + * @children is consumed by this function. g_free() will be called on |
572 | + * it some time later. |
573 | + * |
574 | + * Returns: a new #GVariant with a floating reference |
575 | + */ |
576 | +GVariant * |
577 | +g_variant_new_from_children (const GVariantType *type, |
578 | + GVariant **children, |
579 | + gsize n_children, |
580 | + gboolean trusted) |
581 | +{ |
582 | + GVariant *value; |
583 | + |
584 | + value = g_variant_alloc (type, FALSE, trusted); |
585 | + value->contents.tree.children = children; |
586 | + value->contents.tree.n_children = n_children; |
587 | + |
588 | + return value; |
589 | +} |
590 | + |
591 | +/* < internal > |
592 | + * g_variant_get_type_info: |
593 | + * @value: a #GVariant |
594 | + * |
595 | + * Returns the #GVariantTypeInfo corresponding to the type of @value. A |
596 | + * reference is not added, so the return value is only good for the |
597 | + * duration of the life of @value. |
598 | + * |
599 | + * Returns: the #GVariantTypeInfo for @value |
600 | + */ |
601 | +GVariantTypeInfo * |
602 | +g_variant_get_type_info (GVariant *value) |
603 | +{ |
604 | + return value->type_info; |
605 | +} |
606 | + |
607 | +/* < internal > |
608 | + * g_variant_is_trusted: |
609 | + * @value: a #GVariant |
610 | + * |
611 | + * Determines if @value is trusted by #GVariant to contain only |
612 | + * fully-valid data. All values constructed solely via #GVariant APIs |
613 | + * are trusted, but values containing data read in from other sources |
614 | + * are usually not trusted. |
615 | + * |
616 | + * The main advantage of trusted data is that certain checks can be |
617 | + * skipped. For example, we don't need to check that a string is |
618 | + * properly nul-terminated or that an object path is actually a |
619 | + * properly-formatted object path. |
620 | + * |
621 | + * Returns: if @value is trusted |
622 | + */ |
623 | +gboolean |
624 | +g_variant_is_trusted (GVariant *value) |
625 | +{ |
626 | + return (value->state & STATE_TRUSTED) != 0; |
627 | +} |
628 | + |
629 | +/* -- public -- */ |
630 | + |
631 | +/** |
632 | + * g_variant_unref: |
633 | + * @value: a #GVariant |
634 | + * |
635 | + * Decreases the reference count of @value. When its reference count |
636 | + * drops to 0, the memory used by the variant is freed. |
637 | + * |
638 | + * Since: 2.24 |
639 | + **/ |
640 | +void |
641 | +g_variant_unref (GVariant *value) |
642 | +{ |
643 | + g_return_if_fail (value != NULL); |
644 | + g_return_if_fail (value->ref_count > 0); |
645 | + |
646 | + if (g_atomic_int_dec_and_test (&value->ref_count)) |
647 | + { |
648 | + if G_UNLIKELY (value->state & STATE_LOCKED) |
649 | + g_critical ("attempting to free a locked GVariant instance. " |
650 | + "This should never happen."); |
651 | + |
652 | + value->state |= STATE_LOCKED; |
653 | + |
654 | + g_variant_type_info_unref (value->type_info); |
655 | + |
656 | + if (value->state & STATE_SERIALISED) |
657 | + g_bytes_unref (value->contents.serialised.bytes); |
658 | + else |
659 | + g_variant_release_children (value); |
660 | + |
661 | + memset (value, 0, sizeof (GVariant)); |
662 | + g_slice_free (GVariant, value); |
663 | + } |
664 | +} |
665 | + |
666 | +/** |
667 | + * g_variant_ref: |
668 | + * @value: a #GVariant |
669 | + * |
670 | + * Increases the reference count of @value. |
671 | + * |
672 | + * Returns: the same @value |
673 | + * |
674 | + * Since: 2.24 |
675 | + **/ |
676 | +GVariant * |
677 | +g_variant_ref (GVariant *value) |
678 | +{ |
679 | + g_return_val_if_fail (value != NULL, NULL); |
680 | + g_return_val_if_fail (value->ref_count > 0, NULL); |
681 | + |
682 | + g_atomic_int_inc (&value->ref_count); |
683 | + |
684 | + return value; |
685 | +} |
686 | + |
687 | +/** |
688 | + * g_variant_ref_sink: |
689 | + * @value: a #GVariant |
690 | + * |
691 | + * #GVariant uses a floating reference count system. All functions with |
692 | + * names starting with <literal>g_variant_new_</literal> return floating |
693 | + * references. |
694 | + * |
695 | + * Calling g_variant_ref_sink() on a #GVariant with a floating reference |
696 | + * will convert the floating reference into a full reference. Calling |
697 | + * g_variant_ref_sink() on a non-floating #GVariant results in an |
698 | + * additional normal reference being added. |
699 | + * |
700 | + * In other words, if the @value is floating, then this call "assumes |
701 | + * ownership" of the floating reference, converting it to a normal |
702 | + * reference. If the @value is not floating, then this call adds a |
703 | + * new normal reference increasing the reference count by one. |
704 | + * |
705 | + * All calls that result in a #GVariant instance being inserted into a |
706 | + * container will call g_variant_ref_sink() on the instance. This means |
707 | + * that if the value was just created (and has only its floating |
708 | + * reference) then the container will assume sole ownership of the value |
709 | + * at that point and the caller will not need to unreference it. This |
710 | + * makes certain common styles of programming much easier while still |
711 | + * maintaining normal refcounting semantics in situations where values |
712 | + * are not floating. |
713 | + * |
714 | + * Returns: the same @value |
715 | + * |
716 | + * Since: 2.24 |
717 | + **/ |
718 | +GVariant * |
719 | +g_variant_ref_sink (GVariant *value) |
720 | +{ |
721 | + g_return_val_if_fail (value != NULL, NULL); |
722 | + g_return_val_if_fail (value->ref_count > 0, NULL); |
723 | + |
724 | + g_variant_lock (value); |
725 | + |
726 | + if (~value->state & STATE_FLOATING) |
727 | + g_variant_ref (value); |
728 | + else |
729 | + value->state &= ~STATE_FLOATING; |
730 | + |
731 | + g_variant_unlock (value); |
732 | + |
733 | + return value; |
734 | +} |
735 | + |
736 | +/** |
737 | + * g_variant_take_ref: |
738 | + * @value: a #GVariant |
739 | + * |
740 | + * If @value is floating, sink it. Otherwise, do nothing. |
741 | + * |
742 | + * Typically you want to use g_variant_ref_sink() in order to |
743 | + * automatically do the correct thing with respect to floating or |
744 | + * non-floating references, but there is one specific scenario where |
745 | + * this function is helpful. |
746 | + * |
747 | + * The situation where this function is helpful is when creating an API |
748 | + * that allows the user to provide a callback function that returns a |
749 | + * #GVariant. We certainly want to allow the user the flexibility to |
750 | + * return a non-floating reference from this callback (for the case |
751 | + * where the value that is being returned already exists). |
752 | + * |
753 | + * At the same time, the style of the #GVariant API makes it likely that |
754 | + * for newly-created #GVariant instances, the user can be saved some |
755 | + * typing if they are allowed to return a #GVariant with a floating |
756 | + * reference. |
757 | + * |
758 | + * Using this function on the return value of the user's callback allows |
759 | + * the user to do whichever is more convenient for them. The caller |
760 | + * will alway receives exactly one full reference to the value: either |
761 | + * the one that was returned in the first place, or a floating reference |
762 | + * that has been converted to a full reference. |
763 | + * |
764 | + * This function has an odd interaction when combined with |
765 | + * g_variant_ref_sink() running at the same time in another thread on |
766 | + * the same #GVariant instance. If g_variant_ref_sink() runs first then |
767 | + * the result will be that the floating reference is converted to a hard |
768 | + * reference. If g_variant_take_ref() runs first then the result will |
769 | + * be that the floating reference is converted to a hard reference and |
770 | + * an additional reference on top of that one is added. It is best to |
771 | + * avoid this situation. |
772 | + * |
773 | + * Returns: the same @value |
774 | + **/ |
775 | +GVariant * |
776 | +g_variant_take_ref (GVariant *value) |
777 | +{ |
778 | + g_return_val_if_fail (value != NULL, NULL); |
779 | + g_return_val_if_fail (value->ref_count > 0, NULL); |
780 | + |
781 | + g_atomic_int_and (&value->state, ~STATE_FLOATING); |
782 | + |
783 | + return value; |
784 | +} |
785 | + |
786 | +/** |
787 | + * g_variant_is_floating: |
788 | + * @value: a #GVariant |
789 | + * |
790 | + * Checks whether @value has a floating reference count. |
791 | + * |
792 | + * This function should only ever be used to assert that a given variant |
793 | + * is or is not floating, or for debug purposes. To acquire a reference |
794 | + * to a variant that might be floating, always use g_variant_ref_sink() |
795 | + * or g_variant_take_ref(). |
796 | + * |
797 | + * See g_variant_ref_sink() for more information about floating reference |
798 | + * counts. |
799 | + * |
800 | + * Returns: whether @value is floating |
801 | + * |
802 | + * Since: 2.26 |
803 | + **/ |
804 | +gboolean |
805 | +g_variant_is_floating (GVariant *value) |
806 | +{ |
807 | + g_return_val_if_fail (value != NULL, FALSE); |
808 | + |
809 | + return (value->state & STATE_FLOATING) != 0; |
810 | +} |
811 | + |
812 | +/** |
813 | + * g_variant_get_size: |
814 | + * @value: a #GVariant instance |
815 | + * |
816 | + * Determines the number of bytes that would be required to store @value |
817 | + * with g_variant_store(). |
818 | + * |
819 | + * If @value has a fixed-sized type then this function always returned |
820 | + * that fixed size. |
821 | + * |
822 | + * In the case that @value is already in serialised form or the size has |
823 | + * already been calculated (ie: this function has been called before) |
824 | + * then this function is O(1). Otherwise, the size is calculated, an |
825 | + * operation which is approximately O(n) in the number of values |
826 | + * involved. |
827 | + * |
828 | + * Returns: the serialised size of @value |
829 | + * |
830 | + * Since: 2.24 |
831 | + **/ |
832 | +gsize |
833 | +g_variant_get_size (GVariant *value) |
834 | +{ |
835 | + g_variant_lock (value); |
836 | + g_variant_ensure_size (value); |
837 | + g_variant_unlock (value); |
838 | + |
839 | + return value->size; |
840 | +} |
841 | + |
842 | +/** |
843 | + * g_variant_get_data: |
844 | + * @value: a #GVariant instance |
845 | + * |
846 | + * Returns a pointer to the serialised form of a #GVariant instance. |
847 | + * The returned data may not be in fully-normalised form if read from an |
848 | + * untrusted source. The returned data must not be freed; it remains |
849 | + * valid for as long as @value exists. |
850 | + * |
851 | + * If @value is a fixed-sized value that was deserialised from a |
852 | + * corrupted serialised container then %NULL may be returned. In this |
853 | + * case, the proper thing to do is typically to use the appropriate |
854 | + * number of nul bytes in place of @value. If @value is not fixed-sized |
855 | + * then %NULL is never returned. |
856 | + * |
857 | + * In the case that @value is already in serialised form, this function |
858 | + * is O(1). If the value is not already in serialised form, |
859 | + * serialisation occurs implicitly and is approximately O(n) in the size |
860 | + * of the result. |
861 | + * |
862 | + * To deserialise the data returned by this function, in addition to the |
863 | + * serialised data, you must know the type of the #GVariant, and (if the |
864 | + * machine might be different) the endianness of the machine that stored |
865 | + * it. As a result, file formats or network messages that incorporate |
866 | + * serialised #GVariant<!---->s must include this information either |
867 | + * implicitly (for instance "the file always contains a |
868 | + * %G_VARIANT_TYPE_VARIANT and it is always in little-endian order") or |
869 | + * explicitly (by storing the type and/or endianness in addition to the |
870 | + * serialised data). |
871 | + * |
872 | + * Returns: (transfer none): the serialised form of @value, or %NULL |
873 | + * |
874 | + * Since: 2.24 |
875 | + **/ |
876 | +gconstpointer |
877 | +g_variant_get_data (GVariant *value) |
878 | +{ |
879 | + g_variant_lock (value); |
880 | + g_variant_ensure_serialised (value); |
881 | + g_variant_unlock (value); |
882 | + |
883 | + return value->contents.serialised.data; |
884 | +} |
885 | + |
886 | +/** |
887 | + * g_variant_get_data_as_bytes: |
888 | + * @value: a #GVariant |
889 | + * |
890 | + * Returns a pointer to the serialised form of a #GVariant instance. |
891 | + * The semantics of this function are exactly the same as |
892 | + * g_variant_get_data(), except that the returned #GBytes holds |
893 | + * a reference to the variant data. |
894 | + * |
895 | + * Returns: (transfer full): A new #GBytes representing the variant data |
896 | + * |
897 | + * Since: 2.36 |
898 | + */ |
899 | +GBytes * |
900 | +g_variant_get_data_as_bytes (GVariant *value) |
901 | +{ |
902 | + g_variant_lock (value); |
903 | + g_variant_ensure_serialised (value); |
904 | + g_variant_unlock (value); |
905 | + |
906 | + return g_bytes_ref (value->contents.serialised.bytes); |
907 | +} |
908 | + |
909 | + |
910 | +/** |
911 | + * g_variant_n_children: |
912 | + * @value: a container #GVariant |
913 | + * |
914 | + * Determines the number of children in a container #GVariant instance. |
915 | + * This includes variants, maybes, arrays, tuples and dictionary |
916 | + * entries. It is an error to call this function on any other type of |
917 | + * #GVariant. |
918 | + * |
919 | + * For variants, the return value is always 1. For values with maybe |
920 | + * types, it is always zero or one. For arrays, it is the length of the |
921 | + * array. For tuples it is the number of tuple items (which depends |
922 | + * only on the type). For dictionary entries, it is always 2 |
923 | + * |
924 | + * This function is O(1). |
925 | + * |
926 | + * Returns: the number of children in the container |
927 | + * |
928 | + * Since: 2.24 |
929 | + **/ |
930 | +gsize |
931 | +g_variant_n_children (GVariant *value) |
932 | +{ |
933 | + gsize n_children; |
934 | + |
935 | + g_variant_lock (value); |
936 | + |
937 | + if (value->state & STATE_SERIALISED) |
938 | + { |
939 | + GVariantSerialised serialised = { |
940 | + value->type_info, |
941 | + (gpointer) value->contents.serialised.data, |
942 | + value->size |
943 | + }; |
944 | + |
945 | + n_children = g_variant_serialised_n_children (serialised); |
946 | + } |
947 | + else |
948 | + n_children = value->contents.tree.n_children; |
949 | + |
950 | + g_variant_unlock (value); |
951 | + |
952 | + return n_children; |
953 | +} |
954 | + |
955 | +/** |
956 | + * g_variant_get_child_value: |
957 | + * @value: a container #GVariant |
958 | + * @index_: the index of the child to fetch |
959 | + * |
960 | + * Reads a child item out of a container #GVariant instance. This |
961 | + * includes variants, maybes, arrays, tuples and dictionary |
962 | + * entries. It is an error to call this function on any other type of |
963 | + * #GVariant. |
964 | + * |
965 | + * It is an error if @index_ is greater than the number of child items |
966 | + * in the container. See g_variant_n_children(). |
967 | + * |
968 | + * The returned value is never floating. You should free it with |
969 | + * g_variant_unref() when you're done with it. |
970 | + * |
971 | + * This function is O(1). |
972 | + * |
973 | + * Returns: (transfer full): the child at the specified index |
974 | + * |
975 | + * Since: 2.24 |
976 | + **/ |
977 | +GVariant * |
978 | +g_variant_get_child_value (GVariant *value, |
979 | + gsize index_) |
980 | +{ |
981 | + g_return_val_if_fail (index_ < g_variant_n_children (value), NULL); |
982 | + |
983 | + if (~g_atomic_int_get (&value->state) & STATE_SERIALISED) |
984 | + { |
985 | + g_variant_lock (value); |
986 | + |
987 | + if (~value->state & STATE_SERIALISED) |
988 | + { |
989 | + GVariant *child; |
990 | + |
991 | + child = g_variant_ref (value->contents.tree.children[index_]); |
992 | + g_variant_unlock (value); |
993 | + |
994 | + return child; |
995 | + } |
996 | + |
997 | + g_variant_unlock (value); |
998 | + } |
999 | + |
1000 | + { |
1001 | + GVariantSerialised serialised = { |
1002 | + value->type_info, |
1003 | + (gpointer) value->contents.serialised.data, |
1004 | + value->size |
1005 | + }; |
1006 | + GVariantSerialised s_child; |
1007 | + GVariant *child; |
1008 | + |
1009 | + /* get the serialiser to extract the serialised data for the child |
1010 | + * from the serialised data for the container |
1011 | + */ |
1012 | + s_child = g_variant_serialised_get_child (serialised, index_); |
1013 | + |
1014 | + /* create a new serialised instance out of it */ |
1015 | + child = g_slice_new (GVariant); |
1016 | + child->type_info = s_child.type_info; |
1017 | + child->state = (value->state & STATE_TRUSTED) | |
1018 | + STATE_SERIALISED; |
1019 | + child->size = s_child.size; |
1020 | + child->ref_count = 1; |
1021 | + child->contents.serialised.bytes = |
1022 | + g_bytes_ref (value->contents.serialised.bytes); |
1023 | + child->contents.serialised.data = s_child.data; |
1024 | + |
1025 | + return child; |
1026 | + } |
1027 | +} |
1028 | + |
1029 | +/** |
1030 | + * g_variant_store: |
1031 | + * @value: the #GVariant to store |
1032 | + * @data: the location to store the serialised data at |
1033 | + * |
1034 | + * Stores the serialised form of @value at @data. @data should be |
1035 | + * large enough. See g_variant_get_size(). |
1036 | + * |
1037 | + * The stored data is in machine native byte order but may not be in |
1038 | + * fully-normalised form if read from an untrusted source. See |
1039 | + * g_variant_get_normal_form() for a solution. |
1040 | + * |
1041 | + * As with g_variant_get_data(), to be able to deserialise the |
1042 | + * serialised variant successfully, its type and (if the destination |
1043 | + * machine might be different) its endianness must also be available. |
1044 | + * |
1045 | + * This function is approximately O(n) in the size of @data. |
1046 | + * |
1047 | + * Since: 2.24 |
1048 | + **/ |
1049 | +void |
1050 | +g_variant_store (GVariant *value, |
1051 | + gpointer data) |
1052 | +{ |
1053 | + g_variant_lock (value); |
1054 | + |
1055 | + if (value->state & STATE_SERIALISED) |
1056 | + { |
1057 | + if (value->contents.serialised.data != NULL) |
1058 | + memcpy (data, value->contents.serialised.data, value->size); |
1059 | + else |
1060 | + memset (data, 0, value->size); |
1061 | + } |
1062 | + else |
1063 | + g_variant_serialise (value, data); |
1064 | + |
1065 | + g_variant_unlock (value); |
1066 | +} |
1067 | + |
1068 | +/** |
1069 | + * g_variant_is_normal_form: |
1070 | + * @value: a #GVariant instance |
1071 | + * |
1072 | + * Checks if @value is in normal form. |
1073 | + * |
1074 | + * The main reason to do this is to detect if a given chunk of |
1075 | + * serialised data is in normal form: load the data into a #GVariant |
1076 | + * using g_variant_new_from_data() and then use this function to |
1077 | + * check. |
1078 | + * |
1079 | + * If @value is found to be in normal form then it will be marked as |
1080 | + * being trusted. If the value was already marked as being trusted then |
1081 | + * this function will immediately return %TRUE. |
1082 | + * |
1083 | + * Returns: %TRUE if @value is in normal form |
1084 | + * |
1085 | + * Since: 2.24 |
1086 | + **/ |
1087 | +gboolean |
1088 | +g_variant_is_normal_form (GVariant *value) |
1089 | +{ |
1090 | + if (value->state & STATE_TRUSTED) |
1091 | + return TRUE; |
1092 | + |
1093 | + g_variant_lock (value); |
1094 | + |
1095 | + if (value->state & STATE_SERIALISED) |
1096 | + { |
1097 | + GVariantSerialised serialised = { |
1098 | + value->type_info, |
1099 | + (gpointer) value->contents.serialised.data, |
1100 | + value->size |
1101 | + }; |
1102 | + |
1103 | + if (g_variant_serialised_is_normal (serialised)) |
1104 | + value->state |= STATE_TRUSTED; |
1105 | + } |
1106 | + else |
1107 | + { |
1108 | + gboolean normal = TRUE; |
1109 | + gsize i; |
1110 | + |
1111 | + for (i = 0; i < value->contents.tree.n_children; i++) |
1112 | + normal &= g_variant_is_normal_form (value->contents.tree.children[i]); |
1113 | + |
1114 | + if (normal) |
1115 | + value->state |= STATE_TRUSTED; |
1116 | + } |
1117 | + |
1118 | + g_variant_unlock (value); |
1119 | + |
1120 | + return (value->state & STATE_TRUSTED) != 0; |
1121 | +} |
1122 | |
1123 | === added directory '.pc/g-variant-get-data-as-bytes.patch/glib/tests' |
1124 | === added file '.pc/g-variant-get-data-as-bytes.patch/glib/tests/gvariant.c' |
1125 | --- .pc/g-variant-get-data-as-bytes.patch/glib/tests/gvariant.c 1970-01-01 00:00:00 +0000 |
1126 | +++ .pc/g-variant-get-data-as-bytes.patch/glib/tests/gvariant.c 2013-05-03 17:57:29 +0000 |
1127 | @@ -0,0 +1,4339 @@ |
1128 | +/* |
1129 | + * Copyright © 2010 Codethink Limited |
1130 | + * |
1131 | + * This library is free software; you can redistribute it and/or |
1132 | + * modify it under the terms of the GNU Lesser General Public |
1133 | + * License as published by the Free Software Foundation; either |
1134 | + * version 2 of the licence, or (at your option) any later version. |
1135 | + * |
1136 | + * See the included COPYING file for more information. |
1137 | + * |
1138 | + * Author: Ryan Lortie <desrt@desrt.ca> |
1139 | + */ |
1140 | + |
1141 | +#include "config.h" |
1142 | + |
1143 | +#include <glib/gvariant-internal.h> |
1144 | +#include <string.h> |
1145 | +#include <stdlib.h> |
1146 | +#include <glib.h> |
1147 | + |
1148 | +#define BASIC "bynqiuxthdsog?" |
1149 | +#define N_BASIC (G_N_ELEMENTS (BASIC) - 1) |
1150 | + |
1151 | +#define INVALIDS "cefjklpwz&@^$" |
1152 | +#define N_INVALIDS (G_N_ELEMENTS (INVALIDS) - 1) |
1153 | + |
1154 | +/* see comment in gvariant-serialiser.c about this madness. |
1155 | + * |
1156 | + * we use this to get testing of non-strictly-aligned GVariant instances |
1157 | + * on machines that can tolerate it. it is necessary to support this |
1158 | + * because some systems have malloc() that returns non-8-aligned |
1159 | + * pointers. it is necessary to have special support in the tests |
1160 | + * because on most machines malloc() is 8-aligned. |
1161 | + */ |
1162 | +#define ALIGN_BITS (sizeof (struct { char a; union { \ |
1163 | + guint64 x; void *y; gdouble z; } b; }) - 9) |
1164 | + |
1165 | +static gboolean |
1166 | +randomly (gdouble prob) |
1167 | +{ |
1168 | + return g_test_rand_double_range (0, 1) < prob; |
1169 | +} |
1170 | + |
1171 | +/* corecursion */ |
1172 | +static GVariantType * |
1173 | +append_tuple_type_string (GString *, GString *, gboolean, gint); |
1174 | + |
1175 | +/* append a random GVariantType to a GString |
1176 | + * append a description of the type to another GString |
1177 | + * return what the type is |
1178 | + */ |
1179 | +static GVariantType * |
1180 | +append_type_string (GString *string, |
1181 | + GString *description, |
1182 | + gboolean definite, |
1183 | + gint depth) |
1184 | +{ |
1185 | + if (!depth-- || randomly (0.3)) |
1186 | + { |
1187 | + gchar b = BASIC[g_test_rand_int_range (0, N_BASIC - definite)]; |
1188 | + g_string_append_c (string, b); |
1189 | + g_string_append_c (description, b); |
1190 | + |
1191 | + switch (b) |
1192 | + { |
1193 | + case 'b': |
1194 | + return g_variant_type_copy (G_VARIANT_TYPE_BOOLEAN); |
1195 | + case 'y': |
1196 | + return g_variant_type_copy (G_VARIANT_TYPE_BYTE); |
1197 | + case 'n': |
1198 | + return g_variant_type_copy (G_VARIANT_TYPE_INT16); |
1199 | + case 'q': |
1200 | + return g_variant_type_copy (G_VARIANT_TYPE_UINT16); |
1201 | + case 'i': |
1202 | + return g_variant_type_copy (G_VARIANT_TYPE_INT32); |
1203 | + case 'u': |
1204 | + return g_variant_type_copy (G_VARIANT_TYPE_UINT32); |
1205 | + case 'x': |
1206 | + return g_variant_type_copy (G_VARIANT_TYPE_INT64); |
1207 | + case 't': |
1208 | + return g_variant_type_copy (G_VARIANT_TYPE_UINT64); |
1209 | + case 'h': |
1210 | + return g_variant_type_copy (G_VARIANT_TYPE_HANDLE); |
1211 | + case 'd': |
1212 | + return g_variant_type_copy (G_VARIANT_TYPE_DOUBLE); |
1213 | + case 's': |
1214 | + return g_variant_type_copy (G_VARIANT_TYPE_STRING); |
1215 | + case 'o': |
1216 | + return g_variant_type_copy (G_VARIANT_TYPE_OBJECT_PATH); |
1217 | + case 'g': |
1218 | + return g_variant_type_copy (G_VARIANT_TYPE_SIGNATURE); |
1219 | + case '?': |
1220 | + return g_variant_type_copy (G_VARIANT_TYPE_BASIC); |
1221 | + default: |
1222 | + g_assert_not_reached (); |
1223 | + } |
1224 | + } |
1225 | + else |
1226 | + { |
1227 | + GVariantType *result; |
1228 | + |
1229 | + switch (g_test_rand_int_range (0, definite ? 5 : 7)) |
1230 | + { |
1231 | + case 0: |
1232 | + { |
1233 | + GVariantType *element; |
1234 | + |
1235 | + g_string_append_c (string, 'a'); |
1236 | + g_string_append (description, "a of "); |
1237 | + element = append_type_string (string, description, |
1238 | + definite, depth); |
1239 | + result = g_variant_type_new_array (element); |
1240 | + g_variant_type_free (element); |
1241 | + } |
1242 | + |
1243 | + g_assert (g_variant_type_is_array (result)); |
1244 | + break; |
1245 | + |
1246 | + case 1: |
1247 | + { |
1248 | + GVariantType *element; |
1249 | + |
1250 | + g_string_append_c (string, 'm'); |
1251 | + g_string_append (description, "m of "); |
1252 | + element = append_type_string (string, description, |
1253 | + definite, depth); |
1254 | + result = g_variant_type_new_maybe (element); |
1255 | + g_variant_type_free (element); |
1256 | + } |
1257 | + |
1258 | + g_assert (g_variant_type_is_maybe (result)); |
1259 | + break; |
1260 | + |
1261 | + case 2: |
1262 | + result = append_tuple_type_string (string, description, |
1263 | + definite, depth); |
1264 | + |
1265 | + g_assert (g_variant_type_is_tuple (result)); |
1266 | + break; |
1267 | + |
1268 | + case 3: |
1269 | + { |
1270 | + GVariantType *key, *value; |
1271 | + |
1272 | + g_string_append_c (string, '{'); |
1273 | + g_string_append (description, "e of ["); |
1274 | + key = append_type_string (string, description, definite, 0); |
1275 | + g_string_append (description, ", "); |
1276 | + value = append_type_string (string, description, definite, depth); |
1277 | + g_string_append_c (description, ']'); |
1278 | + g_string_append_c (string, '}'); |
1279 | + result = g_variant_type_new_dict_entry (key, value); |
1280 | + g_variant_type_free (key); |
1281 | + g_variant_type_free (value); |
1282 | + } |
1283 | + |
1284 | + g_assert (g_variant_type_is_dict_entry (result)); |
1285 | + break; |
1286 | + |
1287 | + case 4: |
1288 | + g_string_append_c (string, 'v'); |
1289 | + g_string_append_c (description, 'V'); |
1290 | + result = g_variant_type_copy (G_VARIANT_TYPE_VARIANT); |
1291 | + g_assert (g_variant_type_equal (result, G_VARIANT_TYPE_VARIANT)); |
1292 | + break; |
1293 | + |
1294 | + case 5: |
1295 | + g_string_append_c (string, '*'); |
1296 | + g_string_append_c (description, 'S'); |
1297 | + result = g_variant_type_copy (G_VARIANT_TYPE_ANY); |
1298 | + g_assert (g_variant_type_equal (result, G_VARIANT_TYPE_ANY)); |
1299 | + break; |
1300 | + |
1301 | + case 6: |
1302 | + g_string_append_c (string, 'r'); |
1303 | + g_string_append_c (description, 'R'); |
1304 | + result = g_variant_type_copy (G_VARIANT_TYPE_TUPLE); |
1305 | + g_assert (g_variant_type_is_tuple (result)); |
1306 | + break; |
1307 | + |
1308 | + default: |
1309 | + g_assert_not_reached (); |
1310 | + } |
1311 | + |
1312 | + return result; |
1313 | + } |
1314 | +} |
1315 | + |
1316 | +static GVariantType * |
1317 | +append_tuple_type_string (GString *string, |
1318 | + GString *description, |
1319 | + gboolean definite, |
1320 | + gint depth) |
1321 | +{ |
1322 | + GVariantType *result, *other_result; |
1323 | + GVariantType **types; |
1324 | + gint size; |
1325 | + gint i; |
1326 | + |
1327 | + g_string_append_c (string, '('); |
1328 | + g_string_append (description, "t of ["); |
1329 | + |
1330 | + size = g_test_rand_int_range (0, 20); |
1331 | + types = g_new (GVariantType *, size + 1); |
1332 | + |
1333 | + for (i = 0; i < size; i++) |
1334 | + { |
1335 | + types[i] = append_type_string (string, description, definite, depth); |
1336 | + |
1337 | + if (i < size - 1) |
1338 | + g_string_append (description, ", "); |
1339 | + } |
1340 | + |
1341 | + types[i] = NULL; |
1342 | + |
1343 | + g_string_append_c (description, ']'); |
1344 | + g_string_append_c (string, ')'); |
1345 | + |
1346 | + result = g_variant_type_new_tuple ((gpointer) types, size); |
1347 | + other_result = g_variant_type_new_tuple ((gpointer) types, -1); |
1348 | + g_assert (g_variant_type_equal (result, other_result)); |
1349 | + g_variant_type_free (other_result); |
1350 | + for (i = 0; i < size; i++) |
1351 | + g_variant_type_free (types[i]); |
1352 | + g_free (types); |
1353 | + |
1354 | + return result; |
1355 | +} |
1356 | + |
1357 | +/* given a valid type string, make it invalid */ |
1358 | +static gchar * |
1359 | +invalid_mutation (const gchar *type_string) |
1360 | +{ |
1361 | + gboolean have_parens, have_braces; |
1362 | + |
1363 | + /* it's valid, so '(' implies ')' and same for '{' and '}' */ |
1364 | + have_parens = strchr (type_string, '(') != NULL; |
1365 | + have_braces = strchr (type_string, '{') != NULL; |
1366 | + |
1367 | + if (have_parens && have_braces && randomly (0.3)) |
1368 | + { |
1369 | + /* swap a paren and a brace */ |
1370 | + gchar *pp, *bp; |
1371 | + gint np, nb; |
1372 | + gchar p, b; |
1373 | + gchar *new; |
1374 | + |
1375 | + new = g_strdup (type_string); |
1376 | + |
1377 | + if (randomly (0.5)) |
1378 | + p = '(', b = '{'; |
1379 | + else |
1380 | + p = ')', b = '}'; |
1381 | + |
1382 | + np = nb = 0; |
1383 | + pp = bp = new - 1; |
1384 | + |
1385 | + /* count number of parens/braces */ |
1386 | + while ((pp = strchr (pp + 1, p))) np++; |
1387 | + while ((bp = strchr (bp + 1, b))) nb++; |
1388 | + |
1389 | + /* randomly pick one of each */ |
1390 | + np = g_test_rand_int_range (0, np) + 1; |
1391 | + nb = g_test_rand_int_range (0, nb) + 1; |
1392 | + |
1393 | + /* find it */ |
1394 | + pp = bp = new - 1; |
1395 | + while (np--) pp = strchr (pp + 1, p); |
1396 | + while (nb--) bp = strchr (bp + 1, b); |
1397 | + |
1398 | + /* swap */ |
1399 | + g_assert (*bp == b && *pp == p); |
1400 | + *bp = p; |
1401 | + *pp = b; |
1402 | + |
1403 | + return new; |
1404 | + } |
1405 | + |
1406 | + if ((have_parens || have_braces) && randomly (0.3)) |
1407 | + { |
1408 | + /* drop a paren/brace */ |
1409 | + gchar *new; |
1410 | + gchar *pp; |
1411 | + gint np; |
1412 | + gchar p; |
1413 | + |
1414 | + if (have_parens) |
1415 | + if (randomly (0.5)) p = '('; else p = ')'; |
1416 | + else |
1417 | + if (randomly (0.5)) p = '{'; else p = '}'; |
1418 | + |
1419 | + new = g_strdup (type_string); |
1420 | + |
1421 | + np = 0; |
1422 | + pp = new - 1; |
1423 | + while ((pp = strchr (pp + 1, p))) np++; |
1424 | + np = g_test_rand_int_range (0, np) + 1; |
1425 | + pp = new - 1; |
1426 | + while (np--) pp = strchr (pp + 1, p); |
1427 | + g_assert (*pp == p); |
1428 | + |
1429 | + while (*pp) |
1430 | + { |
1431 | + *pp = *(pp + 1); |
1432 | + pp++; |
1433 | + } |
1434 | + |
1435 | + return new; |
1436 | + } |
1437 | + |
1438 | + /* else, perform a random mutation at a random point */ |
1439 | + { |
1440 | + gint length, n; |
1441 | + gchar *new; |
1442 | + gchar p; |
1443 | + |
1444 | + if (randomly (0.3)) |
1445 | + { |
1446 | + /* insert a paren/brace */ |
1447 | + if (randomly (0.5)) |
1448 | + if (randomly (0.5)) p = '('; else p = ')'; |
1449 | + else |
1450 | + if (randomly (0.5)) p = '{'; else p = '}'; |
1451 | + } |
1452 | + else if (randomly (0.5)) |
1453 | + { |
1454 | + /* insert junk */ |
1455 | + p = INVALIDS[g_test_rand_int_range (0, N_INVALIDS)]; |
1456 | + } |
1457 | + else |
1458 | + { |
1459 | + /* truncate */ |
1460 | + p = '\0'; |
1461 | + } |
1462 | + |
1463 | + |
1464 | + length = strlen (type_string); |
1465 | + new = g_malloc (length + 2); |
1466 | + n = g_test_rand_int_range (0, length); |
1467 | + memcpy (new, type_string, n); |
1468 | + new[n] = p; |
1469 | + memcpy (new + n + 1, type_string + n, length - n); |
1470 | + new[length + 1] = '\0'; |
1471 | + |
1472 | + return new; |
1473 | + } |
1474 | +} |
1475 | + |
1476 | +/* describe a type using the same language as is generated |
1477 | + * while generating the type with append_type_string |
1478 | + */ |
1479 | +static gchar * |
1480 | +describe_type (const GVariantType *type) |
1481 | +{ |
1482 | + gchar *result; |
1483 | + |
1484 | + if (g_variant_type_is_container (type)) |
1485 | + { |
1486 | + g_assert (!g_variant_type_is_basic (type)); |
1487 | + |
1488 | + if (g_variant_type_is_array (type)) |
1489 | + { |
1490 | + gchar *subtype = describe_type (g_variant_type_element (type)); |
1491 | + result = g_strdup_printf ("a of %s", subtype); |
1492 | + g_free (subtype); |
1493 | + } |
1494 | + else if (g_variant_type_is_maybe (type)) |
1495 | + { |
1496 | + gchar *subtype = describe_type (g_variant_type_element (type)); |
1497 | + result = g_strdup_printf ("m of %s", subtype); |
1498 | + g_free (subtype); |
1499 | + } |
1500 | + else if (g_variant_type_is_tuple (type)) |
1501 | + { |
1502 | + if (!g_variant_type_equal (type, G_VARIANT_TYPE_TUPLE)) |
1503 | + { |
1504 | + const GVariantType *sub; |
1505 | + GString *string; |
1506 | + gint length; |
1507 | + gint i; |
1508 | + |
1509 | + string = g_string_new ("t of ["); |
1510 | + |
1511 | + length = g_variant_type_n_items (type); |
1512 | + sub = g_variant_type_first (type); |
1513 | + for (i = 0; i < length; i++) |
1514 | + { |
1515 | + gchar *subtype = describe_type (sub); |
1516 | + g_string_append (string, subtype); |
1517 | + g_free (subtype); |
1518 | + |
1519 | + if ((sub = g_variant_type_next (sub))) |
1520 | + g_string_append (string, ", "); |
1521 | + } |
1522 | + g_assert (sub == NULL); |
1523 | + g_string_append_c (string, ']'); |
1524 | + |
1525 | + result = g_string_free (string, FALSE); |
1526 | + } |
1527 | + else |
1528 | + result = g_strdup ("R"); |
1529 | + } |
1530 | + else if (g_variant_type_is_dict_entry (type)) |
1531 | + { |
1532 | + gchar *key, *value, *key2, *value2; |
1533 | + |
1534 | + key = describe_type (g_variant_type_key (type)); |
1535 | + value = describe_type (g_variant_type_value (type)); |
1536 | + key2 = describe_type (g_variant_type_first (type)); |
1537 | + value2 = describe_type ( |
1538 | + g_variant_type_next (g_variant_type_first (type))); |
1539 | + g_assert (g_variant_type_next (g_variant_type_next ( |
1540 | + g_variant_type_first (type))) == NULL); |
1541 | + g_assert_cmpstr (key, ==, key2); |
1542 | + g_assert_cmpstr (value, ==, value2); |
1543 | + result = g_strjoin ("", "e of [", key, ", ", value, "]", NULL); |
1544 | + g_free (key2); |
1545 | + g_free (value2); |
1546 | + g_free (key); |
1547 | + g_free (value); |
1548 | + } |
1549 | + else if (g_variant_type_equal (type, G_VARIANT_TYPE_VARIANT)) |
1550 | + { |
1551 | + result = g_strdup ("V"); |
1552 | + } |
1553 | + else |
1554 | + g_assert_not_reached (); |
1555 | + } |
1556 | + else |
1557 | + { |
1558 | + if (g_variant_type_is_definite (type)) |
1559 | + { |
1560 | + g_assert (g_variant_type_is_basic (type)); |
1561 | + |
1562 | + if (g_variant_type_equal (type, G_VARIANT_TYPE_BOOLEAN)) |
1563 | + result = g_strdup ("b"); |
1564 | + else if (g_variant_type_equal (type, G_VARIANT_TYPE_BYTE)) |
1565 | + result = g_strdup ("y"); |
1566 | + else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT16)) |
1567 | + result = g_strdup ("n"); |
1568 | + else if (g_variant_type_equal (type, G_VARIANT_TYPE_UINT16)) |
1569 | + result = g_strdup ("q"); |
1570 | + else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT32)) |
1571 | + result = g_strdup ("i"); |
1572 | + else if (g_variant_type_equal (type, G_VARIANT_TYPE_UINT32)) |
1573 | + result = g_strdup ("u"); |
1574 | + else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT64)) |
1575 | + result = g_strdup ("x"); |
1576 | + else if (g_variant_type_equal (type, G_VARIANT_TYPE_UINT64)) |
1577 | + result = g_strdup ("t"); |
1578 | + else if (g_variant_type_equal (type, G_VARIANT_TYPE_HANDLE)) |
1579 | + result = g_strdup ("h"); |
1580 | + else if (g_variant_type_equal (type, G_VARIANT_TYPE_DOUBLE)) |
1581 | + result = g_strdup ("d"); |
1582 | + else if (g_variant_type_equal (type, G_VARIANT_TYPE_STRING)) |
1583 | + result = g_strdup ("s"); |
1584 | + else if (g_variant_type_equal (type, G_VARIANT_TYPE_OBJECT_PATH)) |
1585 | + result = g_strdup ("o"); |
1586 | + else if (g_variant_type_equal (type, G_VARIANT_TYPE_SIGNATURE)) |
1587 | + result = g_strdup ("g"); |
1588 | + else |
1589 | + g_assert_not_reached (); |
1590 | + } |
1591 | + else |
1592 | + { |
1593 | + if (g_variant_type_equal (type, G_VARIANT_TYPE_ANY)) |
1594 | + { |
1595 | + result = g_strdup ("S"); |
1596 | + } |
1597 | + else if (g_variant_type_equal (type, G_VARIANT_TYPE_BASIC)) |
1598 | + { |
1599 | + result = g_strdup ("?"); |
1600 | + } |
1601 | + else |
1602 | + g_assert_not_reached (); |
1603 | + } |
1604 | + } |
1605 | + |
1606 | + return result; |
1607 | +} |
1608 | + |
1609 | +/* given a type string, replace one of the indefinite type characters in |
1610 | + * it with a matching type (possibly the same type). |
1611 | + */ |
1612 | +static gchar * |
1613 | +generate_subtype (const gchar *type_string) |
1614 | +{ |
1615 | + GVariantType *replacement; |
1616 | + GString *result, *junk; |
1617 | + gint length, n = 0, l; |
1618 | + |
1619 | + result = g_string_new (NULL); |
1620 | + junk = g_string_new (NULL); |
1621 | + |
1622 | + /* count the number of indefinite type characters */ |
1623 | + for (length = 0; type_string[length]; length++) |
1624 | + n += type_string[length] == 'r' || |
1625 | + type_string[length] == '?' || |
1626 | + type_string[length] == '*'; |
1627 | + /* length now is strlen (type_string) */ |
1628 | + |
1629 | + /* pick one at random to replace */ |
1630 | + n = g_test_rand_int_range (0, n) + 1; |
1631 | + |
1632 | + /* find it */ |
1633 | + l = -1; |
1634 | + while (n--) l += strcspn (type_string + l + 1, "r?*") + 1; |
1635 | + g_assert (type_string[l] == 'r' || |
1636 | + type_string[l] == '?' || |
1637 | + type_string[l] == '*'); |
1638 | + |
1639 | + /* store up to that point in a GString */ |
1640 | + g_string_append_len (result, type_string, l); |
1641 | + |
1642 | + /* then store the replacement in the GString */ |
1643 | + if (type_string[l] == 'r') |
1644 | + replacement = append_tuple_type_string (result, junk, FALSE, 3); |
1645 | + |
1646 | + else if (type_string[l] == '?') |
1647 | + replacement = append_type_string (result, junk, FALSE, 0); |
1648 | + |
1649 | + else if (type_string[l] == '*') |
1650 | + replacement = append_type_string (result, junk, FALSE, 3); |
1651 | + |
1652 | + else |
1653 | + g_assert_not_reached (); |
1654 | + |
1655 | + /* ensure the replacement has the proper type */ |
1656 | + g_assert (g_variant_type_is_subtype_of (replacement, |
1657 | + (gpointer) &type_string[l])); |
1658 | + |
1659 | + /* store the rest from the original type string */ |
1660 | + g_string_append (result, type_string + l + 1); |
1661 | + |
1662 | + g_variant_type_free (replacement); |
1663 | + g_string_free (junk, TRUE); |
1664 | + |
1665 | + return g_string_free (result, FALSE); |
1666 | +} |
1667 | + |
1668 | +struct typestack |
1669 | +{ |
1670 | + const GVariantType *type; |
1671 | + struct typestack *parent; |
1672 | +}; |
1673 | + |
1674 | +/* given an indefinite type string, replace one of the indefinite |
1675 | + * characters in it with a matching type and ensure that the result is a |
1676 | + * subtype of the original. repeat. |
1677 | + */ |
1678 | +static void |
1679 | +subtype_check (const gchar *type_string, |
1680 | + struct typestack *parent_ts) |
1681 | +{ |
1682 | + struct typestack ts, *node; |
1683 | + gchar *subtype; |
1684 | + gint depth = 0; |
1685 | + |
1686 | + subtype = generate_subtype (type_string); |
1687 | + |
1688 | + ts.type = G_VARIANT_TYPE (subtype); |
1689 | + ts.parent = parent_ts; |
1690 | + |
1691 | + for (node = &ts; node; node = node->parent) |
1692 | + { |
1693 | + /* this type should be a subtype of each parent type */ |
1694 | + g_assert (g_variant_type_is_subtype_of (ts.type, node->type)); |
1695 | + |
1696 | + /* it should only be a supertype when it is exactly equal */ |
1697 | + g_assert (g_variant_type_is_subtype_of (node->type, ts.type) == |
1698 | + g_variant_type_equal (ts.type, node->type)); |
1699 | + |
1700 | + depth++; |
1701 | + } |
1702 | + |
1703 | + if (!g_variant_type_is_definite (ts.type) && depth < 5) |
1704 | + { |
1705 | + /* the type is still indefinite and we haven't repeated too many |
1706 | + * times. go once more. |
1707 | + */ |
1708 | + |
1709 | + subtype_check (subtype, &ts); |
1710 | + } |
1711 | + |
1712 | + g_free (subtype); |
1713 | +} |
1714 | + |
1715 | +static void |
1716 | +test_gvarianttype (void) |
1717 | +{ |
1718 | + gint i; |
1719 | + |
1720 | + for (i = 0; i < 2000; i++) |
1721 | + { |
1722 | + GString *type_string, *description; |
1723 | + GVariantType *type, *other_type; |
1724 | + const GVariantType *ctype; |
1725 | + gchar *invalid; |
1726 | + gchar *desc; |
1727 | + |
1728 | + type_string = g_string_new (NULL); |
1729 | + description = g_string_new (NULL); |
1730 | + |
1731 | + /* generate a random type, its type string and a description |
1732 | + * |
1733 | + * exercises type constructor functions and g_variant_type_copy() |
1734 | + */ |
1735 | + type = append_type_string (type_string, description, FALSE, 6); |
1736 | + |
1737 | + /* convert the type string to a type and ensure that it is equal |
1738 | + * to the one produced with the type constructor routines |
1739 | + */ |
1740 | + ctype = G_VARIANT_TYPE (type_string->str); |
1741 | + g_assert (g_variant_type_equal (ctype, type)); |
1742 | + g_assert (g_variant_type_hash (ctype) == g_variant_type_hash (type)); |
1743 | + g_assert (g_variant_type_is_subtype_of (ctype, type)); |
1744 | + g_assert (g_variant_type_is_subtype_of (type, ctype)); |
1745 | + |
1746 | + /* check if the type is indefinite */ |
1747 | + if (!g_variant_type_is_definite (type)) |
1748 | + { |
1749 | + struct typestack ts = { type, NULL }; |
1750 | + |
1751 | + /* if it is indefinite, then replace one of the indefinite |
1752 | + * characters with a matching type and ensure that the result |
1753 | + * is a subtype of the original type. repeat. |
1754 | + */ |
1755 | + subtype_check (type_string->str, &ts); |
1756 | + } |
1757 | + else |
1758 | + /* ensure that no indefinite characters appear */ |
1759 | + g_assert (strcspn (type_string->str, "r?*") == type_string->len); |
1760 | + |
1761 | + |
1762 | + /* describe the type. |
1763 | + * |
1764 | + * exercises the type iterator interface |
1765 | + */ |
1766 | + desc = describe_type (type); |
1767 | + |
1768 | + /* make sure the description matches */ |
1769 | + g_assert_cmpstr (desc, ==, description->str); |
1770 | + g_free (desc); |
1771 | + |
1772 | + /* make an invalid mutation to the type and make sure the type |
1773 | + * validation routines catch it */ |
1774 | + invalid = invalid_mutation (type_string->str); |
1775 | + g_assert (g_variant_type_string_is_valid (type_string->str)); |
1776 | + g_assert (!g_variant_type_string_is_valid (invalid)); |
1777 | + g_free (invalid); |
1778 | + |
1779 | + /* concatenate another type to the type string and ensure that |
1780 | + * the result is recognised as being invalid |
1781 | + */ |
1782 | + other_type = append_type_string (type_string, description, FALSE, 2); |
1783 | + |
1784 | + g_string_free (description, TRUE); |
1785 | + g_string_free (type_string, TRUE); |
1786 | + g_variant_type_free (other_type); |
1787 | + g_variant_type_free (type); |
1788 | + } |
1789 | +} |
1790 | + |
1791 | +#define ALIGNED(x, y) (((x + (y - 1)) / y) * y) |
1792 | + |
1793 | +/* do our own calculation of the fixed_size and alignment of a type |
1794 | + * using a simple algorithm to make sure the "fancy" one in the |
1795 | + * implementation is correct. |
1796 | + */ |
1797 | +static void |
1798 | +calculate_type_info (const GVariantType *type, |
1799 | + gsize *fixed_size, |
1800 | + guint *alignment) |
1801 | +{ |
1802 | + if (g_variant_type_is_array (type) || |
1803 | + g_variant_type_is_maybe (type)) |
1804 | + { |
1805 | + calculate_type_info (g_variant_type_element (type), NULL, alignment); |
1806 | + |
1807 | + if (fixed_size) |
1808 | + *fixed_size = 0; |
1809 | + } |
1810 | + else if (g_variant_type_is_tuple (type) || |
1811 | + g_variant_type_is_dict_entry (type)) |
1812 | + { |
1813 | + if (g_variant_type_n_items (type)) |
1814 | + { |
1815 | + const GVariantType *sub; |
1816 | + gboolean variable; |
1817 | + gsize size; |
1818 | + guint al; |
1819 | + |
1820 | + variable = FALSE; |
1821 | + size = 0; |
1822 | + al = 0; |
1823 | + |
1824 | + sub = g_variant_type_first (type); |
1825 | + do |
1826 | + { |
1827 | + gsize this_fs; |
1828 | + guint this_al; |
1829 | + |
1830 | + calculate_type_info (sub, &this_fs, &this_al); |
1831 | + |
1832 | + al = MAX (al, this_al); |
1833 | + |
1834 | + if (!this_fs) |
1835 | + { |
1836 | + variable = TRUE; |
1837 | + size = 0; |
1838 | + } |
1839 | + |
1840 | + if (!variable) |
1841 | + { |
1842 | + size = ALIGNED (size, this_al); |
1843 | + size += this_fs; |
1844 | + } |
1845 | + } |
1846 | + while ((sub = g_variant_type_next (sub))); |
1847 | + |
1848 | + size = ALIGNED (size, al); |
1849 | + |
1850 | + if (alignment) |
1851 | + *alignment = al; |
1852 | + |
1853 | + if (fixed_size) |
1854 | + *fixed_size = size; |
1855 | + } |
1856 | + else |
1857 | + { |
1858 | + if (fixed_size) |
1859 | + *fixed_size = 1; |
1860 | + |
1861 | + if (alignment) |
1862 | + *alignment = 1; |
1863 | + } |
1864 | + } |
1865 | + else |
1866 | + { |
1867 | + gint fs, al; |
1868 | + |
1869 | + if (g_variant_type_equal (type, G_VARIANT_TYPE_BOOLEAN) || |
1870 | + g_variant_type_equal (type, G_VARIANT_TYPE_BYTE)) |
1871 | + { |
1872 | + al = fs = 1; |
1873 | + } |
1874 | + |
1875 | + else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT16) || |
1876 | + g_variant_type_equal (type, G_VARIANT_TYPE_UINT16)) |
1877 | + { |
1878 | + al = fs = 2; |
1879 | + } |
1880 | + |
1881 | + else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT32) || |
1882 | + g_variant_type_equal (type, G_VARIANT_TYPE_UINT32) || |
1883 | + g_variant_type_equal (type, G_VARIANT_TYPE_HANDLE)) |
1884 | + { |
1885 | + al = fs = 4; |
1886 | + } |
1887 | + |
1888 | + else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT64) || |
1889 | + g_variant_type_equal (type, G_VARIANT_TYPE_UINT64) || |
1890 | + g_variant_type_equal (type, G_VARIANT_TYPE_DOUBLE)) |
1891 | + { |
1892 | + al = fs = 8; |
1893 | + } |
1894 | + else if (g_variant_type_equal (type, G_VARIANT_TYPE_STRING) || |
1895 | + g_variant_type_equal (type, G_VARIANT_TYPE_OBJECT_PATH) || |
1896 | + g_variant_type_equal (type, G_VARIANT_TYPE_SIGNATURE)) |
1897 | + { |
1898 | + al = 1; |
1899 | + fs = 0; |
1900 | + } |
1901 | + else if (g_variant_type_equal (type, G_VARIANT_TYPE_VARIANT)) |
1902 | + { |
1903 | + al = 8; |
1904 | + fs = 0; |
1905 | + } |
1906 | + else |
1907 | + g_assert_not_reached (); |
1908 | + |
1909 | + if (fixed_size) |
1910 | + *fixed_size = fs; |
1911 | + |
1912 | + if (alignment) |
1913 | + *alignment = al; |
1914 | + } |
1915 | +} |
1916 | + |
1917 | +/* same as the describe_type() function above, but iterates over |
1918 | + * typeinfo instead of types. |
1919 | + */ |
1920 | +static gchar * |
1921 | +describe_info (GVariantTypeInfo *info) |
1922 | +{ |
1923 | + gchar *result; |
1924 | + |
1925 | + switch (g_variant_type_info_get_type_char (info)) |
1926 | + { |
1927 | + case G_VARIANT_TYPE_INFO_CHAR_MAYBE: |
1928 | + { |
1929 | + gchar *element; |
1930 | + |
1931 | + element = describe_info (g_variant_type_info_element (info)); |
1932 | + result = g_strdup_printf ("m of %s", element); |
1933 | + g_free (element); |
1934 | + } |
1935 | + break; |
1936 | + |
1937 | + case G_VARIANT_TYPE_INFO_CHAR_ARRAY: |
1938 | + { |
1939 | + gchar *element; |
1940 | + |
1941 | + element = describe_info (g_variant_type_info_element (info)); |
1942 | + result = g_strdup_printf ("a of %s", element); |
1943 | + g_free (element); |
1944 | + } |
1945 | + break; |
1946 | + |
1947 | + case G_VARIANT_TYPE_INFO_CHAR_TUPLE: |
1948 | + { |
1949 | + const gchar *sep = ""; |
1950 | + GString *string; |
1951 | + gint length; |
1952 | + gint i; |
1953 | + |
1954 | + string = g_string_new ("t of ["); |
1955 | + length = g_variant_type_info_n_members (info); |
1956 | + |
1957 | + for (i = 0; i < length; i++) |
1958 | + { |
1959 | + const GVariantMemberInfo *minfo; |
1960 | + gchar *subtype; |
1961 | + |
1962 | + g_string_append (string, sep); |
1963 | + sep = ", "; |
1964 | + |
1965 | + minfo = g_variant_type_info_member_info (info, i); |
1966 | + subtype = describe_info (minfo->type_info); |
1967 | + g_string_append (string, subtype); |
1968 | + g_free (subtype); |
1969 | + } |
1970 | + |
1971 | + g_string_append_c (string, ']'); |
1972 | + |
1973 | + result = g_string_free (string, FALSE); |
1974 | + } |
1975 | + break; |
1976 | + |
1977 | + case G_VARIANT_TYPE_INFO_CHAR_DICT_ENTRY: |
1978 | + { |
1979 | + const GVariantMemberInfo *keyinfo, *valueinfo; |
1980 | + gchar *key, *value; |
1981 | + |
1982 | + g_assert_cmpint (g_variant_type_info_n_members (info), ==, 2); |
1983 | + keyinfo = g_variant_type_info_member_info (info, 0); |
1984 | + valueinfo = g_variant_type_info_member_info (info, 1); |
1985 | + key = describe_info (keyinfo->type_info); |
1986 | + value = describe_info (valueinfo->type_info); |
1987 | + result = g_strjoin ("", "e of [", key, ", ", value, "]", NULL); |
1988 | + g_free (key); |
1989 | + g_free (value); |
1990 | + } |
1991 | + break; |
1992 | + |
1993 | + case G_VARIANT_TYPE_INFO_CHAR_VARIANT: |
1994 | + result = g_strdup ("V"); |
1995 | + break; |
1996 | + |
1997 | + default: |
1998 | + result = g_strdup (g_variant_type_info_get_type_string (info)); |
1999 | + g_assert_cmpint (strlen (result), ==, 1); |
2000 | + break; |
2001 | + } |
2002 | + |
2003 | + return result; |
2004 | +} |
2005 | + |
2006 | +/* check that the O(1) method of calculating offsets meshes with the |
2007 | + * results of simple iteration. |
2008 | + */ |
2009 | +static void |
2010 | +check_offsets (GVariantTypeInfo *info, |
2011 | + const GVariantType *type) |
2012 | +{ |
2013 | + gint flavour; |
2014 | + gint length; |
2015 | + |
2016 | + length = g_variant_type_info_n_members (info); |
2017 | + g_assert_cmpint (length, ==, g_variant_type_n_items (type)); |
2018 | + |
2019 | + /* the 'flavour' is the low order bits of the ending point of |
2020 | + * variable-size items in the tuple. this lets us test that the type |
2021 | + * info is correct for various starting alignments. |
2022 | + */ |
2023 | + for (flavour = 0; flavour < 8; flavour++) |
2024 | + { |
2025 | + const GVariantType *subtype; |
2026 | + gsize last_offset_index; |
2027 | + gsize last_offset; |
2028 | + gsize position; |
2029 | + gint i; |
2030 | + |
2031 | + subtype = g_variant_type_first (type); |
2032 | + last_offset_index = -1; |
2033 | + last_offset = 0; |
2034 | + position = 0; |
2035 | + |
2036 | + /* go through the tuple, keeping track of our position */ |
2037 | + for (i = 0; i < length; i++) |
2038 | + { |
2039 | + gsize fixed_size; |
2040 | + guint alignment; |
2041 | + |
2042 | + calculate_type_info (subtype, &fixed_size, &alignment); |
2043 | + |
2044 | + position = ALIGNED (position, alignment); |
2045 | + |
2046 | + /* compare our current aligned position (ie: the start of this |
2047 | + * item) to the start offset that would be calculated if we |
2048 | + * used the type info |
2049 | + */ |
2050 | + { |
2051 | + const GVariantMemberInfo *member; |
2052 | + gsize start; |
2053 | + |
2054 | + member = g_variant_type_info_member_info (info, i); |
2055 | + g_assert_cmpint (member->i, ==, last_offset_index); |
2056 | + |
2057 | + /* do the calculation using the typeinfo */ |
2058 | + start = last_offset; |
2059 | + start += member->a; |
2060 | + start &= member->b; |
2061 | + start |= member->c; |
2062 | + |
2063 | + /* did we reach the same spot? */ |
2064 | + g_assert_cmpint (start, ==, position); |
2065 | + } |
2066 | + |
2067 | + if (fixed_size) |
2068 | + { |
2069 | + /* fixed size. add that size. */ |
2070 | + position += fixed_size; |
2071 | + } |
2072 | + else |
2073 | + { |
2074 | + /* variable size. do the flavouring. */ |
2075 | + while ((position & 0x7) != flavour) |
2076 | + position++; |
2077 | + |
2078 | + /* and store the offset, just like it would be in the |
2079 | + * serialised data. |
2080 | + */ |
2081 | + last_offset = position; |
2082 | + last_offset_index++; |
2083 | + } |
2084 | + |
2085 | + /* next type */ |
2086 | + subtype = g_variant_type_next (subtype); |
2087 | + } |
2088 | + |
2089 | + /* make sure we used up exactly all the types */ |
2090 | + g_assert (subtype == NULL); |
2091 | + } |
2092 | +} |
2093 | + |
2094 | +static void |
2095 | +test_gvarianttypeinfo (void) |
2096 | +{ |
2097 | + gint i; |
2098 | + |
2099 | + for (i = 0; i < 2000; i++) |
2100 | + { |
2101 | + GString *type_string, *description; |
2102 | + gsize fixed_size1, fixed_size2; |
2103 | + guint alignment1, alignment2; |
2104 | + GVariantTypeInfo *info; |
2105 | + GVariantType *type; |
2106 | + gchar *desc; |
2107 | + |
2108 | + type_string = g_string_new (NULL); |
2109 | + description = g_string_new (NULL); |
2110 | + |
2111 | + /* random type */ |
2112 | + type = append_type_string (type_string, description, TRUE, 6); |
2113 | + |
2114 | + /* create a typeinfo for it */ |
2115 | + info = g_variant_type_info_get (type); |
2116 | + |
2117 | + /* make sure the typeinfo has the right type string */ |
2118 | + g_assert_cmpstr (g_variant_type_info_get_type_string (info), ==, |
2119 | + type_string->str); |
2120 | + |
2121 | + /* calculate the alignment and fixed size, compare to the |
2122 | + * typeinfo's calculations |
2123 | + */ |
2124 | + calculate_type_info (type, &fixed_size1, &alignment1); |
2125 | + g_variant_type_info_query (info, &alignment2, &fixed_size2); |
2126 | + g_assert_cmpint (fixed_size1, ==, fixed_size2); |
2127 | + g_assert_cmpint (alignment1, ==, alignment2 + 1); |
2128 | + |
2129 | + /* test the iteration functions over typeinfo structures by |
2130 | + * "describing" the typeinfo and verifying equality. |
2131 | + */ |
2132 | + desc = describe_info (info); |
2133 | + g_assert_cmpstr (desc, ==, description->str); |
2134 | + |
2135 | + /* do extra checks for containers */ |
2136 | + if (g_variant_type_is_array (type) || |
2137 | + g_variant_type_is_maybe (type)) |
2138 | + { |
2139 | + const GVariantType *element; |
2140 | + gsize efs1, efs2; |
2141 | + guint ea1, ea2; |
2142 | + |
2143 | + element = g_variant_type_element (type); |
2144 | + calculate_type_info (element, &efs1, &ea1); |
2145 | + g_variant_type_info_query_element (info, &ea2, &efs2); |
2146 | + g_assert_cmpint (efs1, ==, efs2); |
2147 | + g_assert_cmpint (ea1, ==, ea2 + 1); |
2148 | + |
2149 | + g_assert_cmpint (ea1, ==, alignment1); |
2150 | + g_assert_cmpint (0, ==, fixed_size1); |
2151 | + } |
2152 | + else if (g_variant_type_is_tuple (type) || |
2153 | + g_variant_type_is_dict_entry (type)) |
2154 | + { |
2155 | + /* make sure the "magic constants" are working */ |
2156 | + check_offsets (info, type); |
2157 | + } |
2158 | + |
2159 | + g_string_free (type_string, TRUE); |
2160 | + g_string_free (description, TRUE); |
2161 | + g_variant_type_info_unref (info); |
2162 | + g_variant_type_free (type); |
2163 | + g_free (desc); |
2164 | + } |
2165 | + |
2166 | + g_variant_type_info_assert_no_infos (); |
2167 | +} |
2168 | + |
2169 | +#define MAX_FIXED_MULTIPLIER 256 |
2170 | +#define MAX_INSTANCE_SIZE 1024 |
2171 | +#define MAX_ARRAY_CHILDREN 128 |
2172 | +#define MAX_TUPLE_CHILDREN 128 |
2173 | + |
2174 | +/* this function generates a random type such that all characteristics |
2175 | + * that are "interesting" to the serialiser are tested. |
2176 | + * |
2177 | + * this basically means: |
2178 | + * - test different alignments |
2179 | + * - test variable sized items and fixed sized items |
2180 | + * - test different fixed sizes |
2181 | + */ |
2182 | +static gchar * |
2183 | +random_type_string (void) |
2184 | +{ |
2185 | + const guchar base_types[] = "ynix"; |
2186 | + guchar base_type; |
2187 | + |
2188 | + base_type = base_types[g_test_rand_int_range (0, 4)]; |
2189 | + |
2190 | + if (g_test_rand_bit ()) |
2191 | + /* construct a fixed-sized type */ |
2192 | + { |
2193 | + char type_string[MAX_FIXED_MULTIPLIER]; |
2194 | + guint multiplier; |
2195 | + guint i = 0; |
2196 | + |
2197 | + multiplier = g_test_rand_int_range (1, sizeof type_string - 1); |
2198 | + |
2199 | + type_string[i++] = '('; |
2200 | + while (multiplier--) |
2201 | + type_string[i++] = base_type; |
2202 | + type_string[i++] = ')'; |
2203 | + |
2204 | + return g_strndup (type_string, i); |
2205 | + } |
2206 | + else |
2207 | + /* construct a variable-sized type */ |
2208 | + { |
2209 | + char type_string[2] = { 'a', base_type }; |
2210 | + |
2211 | + return g_strndup (type_string, 2); |
2212 | + } |
2213 | +} |
2214 | + |
2215 | +typedef struct |
2216 | +{ |
2217 | + GVariantTypeInfo *type_info; |
2218 | + guint alignment; |
2219 | + gsize size; |
2220 | + gboolean is_fixed_sized; |
2221 | + |
2222 | + guint32 seed; |
2223 | + |
2224 | +#define INSTANCE_MAGIC 1287582829 |
2225 | + guint magic; |
2226 | +} RandomInstance; |
2227 | + |
2228 | +static RandomInstance * |
2229 | +random_instance (GVariantTypeInfo *type_info) |
2230 | +{ |
2231 | + RandomInstance *instance; |
2232 | + |
2233 | + instance = g_slice_new (RandomInstance); |
2234 | + |
2235 | + if (type_info == NULL) |
2236 | + { |
2237 | + gchar *str = random_type_string (); |
2238 | + instance->type_info = g_variant_type_info_get (G_VARIANT_TYPE (str)); |
2239 | + g_free (str); |
2240 | + } |
2241 | + else |
2242 | + instance->type_info = g_variant_type_info_ref (type_info); |
2243 | + |
2244 | + instance->seed = g_test_rand_int (); |
2245 | + |
2246 | + g_variant_type_info_query (instance->type_info, |
2247 | + &instance->alignment, |
2248 | + &instance->size); |
2249 | + |
2250 | + instance->is_fixed_sized = instance->size != 0; |
2251 | + |
2252 | + if (!instance->is_fixed_sized) |
2253 | + instance->size = g_test_rand_int_range (0, MAX_INSTANCE_SIZE); |
2254 | + |
2255 | + instance->magic = INSTANCE_MAGIC; |
2256 | + |
2257 | + return instance; |
2258 | +} |
2259 | + |
2260 | +static void |
2261 | +random_instance_free (RandomInstance *instance) |
2262 | +{ |
2263 | + g_variant_type_info_unref (instance->type_info); |
2264 | + g_slice_free (RandomInstance, instance); |
2265 | +} |
2266 | + |
2267 | +static void |
2268 | +append_instance_size (RandomInstance *instance, |
2269 | + gsize *offset) |
2270 | +{ |
2271 | + *offset += (-*offset) & instance->alignment; |
2272 | + *offset += instance->size; |
2273 | +} |
2274 | + |
2275 | +static void |
2276 | +random_instance_write (RandomInstance *instance, |
2277 | + guchar *buffer) |
2278 | +{ |
2279 | + GRand *rand; |
2280 | + gint i; |
2281 | + |
2282 | + g_assert_cmpint ((gsize) buffer & ALIGN_BITS & instance->alignment, ==, 0); |
2283 | + |
2284 | + rand = g_rand_new_with_seed (instance->seed); |
2285 | + for (i = 0; i < instance->size; i++) |
2286 | + buffer[i] = g_rand_int (rand); |
2287 | + g_rand_free (rand); |
2288 | +} |
2289 | + |
2290 | +static void |
2291 | +append_instance_data (RandomInstance *instance, |
2292 | + guchar **buffer) |
2293 | +{ |
2294 | + while (((gsize) *buffer) & instance->alignment) |
2295 | + *(*buffer)++ = '\0'; |
2296 | + |
2297 | + random_instance_write (instance, *buffer); |
2298 | + *buffer += instance->size; |
2299 | +} |
2300 | + |
2301 | +static gboolean |
2302 | +random_instance_assert (RandomInstance *instance, |
2303 | + guchar *buffer, |
2304 | + gsize size) |
2305 | +{ |
2306 | + GRand *rand; |
2307 | + gint i; |
2308 | + |
2309 | + g_assert_cmpint ((gsize) buffer & ALIGN_BITS & instance->alignment, ==, 0); |
2310 | + g_assert_cmpint (size, ==, instance->size); |
2311 | + |
2312 | + rand = g_rand_new_with_seed (instance->seed); |
2313 | + for (i = 0; i < instance->size; i++) |
2314 | + { |
2315 | + guchar byte = g_rand_int (rand); |
2316 | + |
2317 | + g_assert (buffer[i] == byte); |
2318 | + } |
2319 | + g_rand_free (rand); |
2320 | + |
2321 | + return i == instance->size; |
2322 | +} |
2323 | + |
2324 | +static gboolean |
2325 | +random_instance_check (RandomInstance *instance, |
2326 | + guchar *buffer, |
2327 | + gsize size) |
2328 | +{ |
2329 | + GRand *rand; |
2330 | + gint i; |
2331 | + |
2332 | + g_assert_cmpint ((gsize) buffer & ALIGN_BITS & instance->alignment, ==, 0); |
2333 | + |
2334 | + if (size != instance->size) |
2335 | + return FALSE; |
2336 | + |
2337 | + rand = g_rand_new_with_seed (instance->seed); |
2338 | + for (i = 0; i < instance->size; i++) |
2339 | + if (buffer[i] != (guchar) g_rand_int (rand)) |
2340 | + break; |
2341 | + g_rand_free (rand); |
2342 | + |
2343 | + return i == instance->size; |
2344 | +} |
2345 | + |
2346 | +static void |
2347 | +random_instance_filler (GVariantSerialised *serialised, |
2348 | + gpointer data) |
2349 | +{ |
2350 | + RandomInstance *instance = data; |
2351 | + |
2352 | + g_assert (instance->magic == INSTANCE_MAGIC); |
2353 | + |
2354 | + if (serialised->type_info == NULL) |
2355 | + serialised->type_info = instance->type_info; |
2356 | + |
2357 | + if (serialised->size == 0) |
2358 | + serialised->size = instance->size; |
2359 | + |
2360 | + g_assert (serialised->type_info == instance->type_info); |
2361 | + g_assert (serialised->size == instance->size); |
2362 | + |
2363 | + if (serialised->data) |
2364 | + random_instance_write (instance, serialised->data); |
2365 | +} |
2366 | + |
2367 | +static gsize |
2368 | +calculate_offset_size (gsize body_size, |
2369 | + gsize n_offsets) |
2370 | +{ |
2371 | + if (body_size == 0) |
2372 | + return 0; |
2373 | + |
2374 | + if (body_size + n_offsets <= G_MAXUINT8) |
2375 | + return 1; |
2376 | + |
2377 | + if (body_size + 2 * n_offsets <= G_MAXUINT16) |
2378 | + return 2; |
2379 | + |
2380 | + if (body_size + 4 * n_offsets <= G_MAXUINT32) |
2381 | + return 4; |
2382 | + |
2383 | + /* the test case won't generate anything bigger */ |
2384 | + g_assert_not_reached (); |
2385 | +} |
2386 | + |
2387 | +static gpointer |
2388 | +flavoured_malloc (gsize size, gsize flavour) |
2389 | +{ |
2390 | + g_assert (flavour < 8); |
2391 | + |
2392 | + if (size == 0) |
2393 | + return NULL; |
2394 | + |
2395 | + return ((gchar *) g_malloc (size + flavour)) + flavour; |
2396 | +} |
2397 | + |
2398 | +static void |
2399 | +flavoured_free (gpointer data, |
2400 | + gsize flavour) |
2401 | +{ |
2402 | + if (!data) |
2403 | + return; |
2404 | + g_free (((gchar *) data) - flavour); |
2405 | +} |
2406 | + |
2407 | +static gpointer |
2408 | +align_malloc (gsize size) |
2409 | +{ |
2410 | + gpointer mem; |
2411 | + |
2412 | +#ifdef HAVE_POSIX_MEMALIGN |
2413 | + if (posix_memalign (&mem, 8, size)) |
2414 | + g_error ("posix_memalign failed"); |
2415 | +#else |
2416 | + /* NOTE: there may be platforms that lack posix_memalign() and also |
2417 | + * have malloc() that returns non-8-aligned. if so, we need to try |
2418 | + * harder here. |
2419 | + */ |
2420 | + mem = malloc (size); |
2421 | +#endif |
2422 | + |
2423 | + return mem; |
2424 | +} |
2425 | + |
2426 | +static void |
2427 | +align_free (gpointer mem) |
2428 | +{ |
2429 | + free (mem); |
2430 | +} |
2431 | + |
2432 | +static void |
2433 | +append_offset (guchar **offset_ptr, |
2434 | + gsize offset, |
2435 | + guint offset_size) |
2436 | +{ |
2437 | + union |
2438 | + { |
2439 | + guchar bytes[sizeof (gsize)]; |
2440 | + gsize integer; |
2441 | + } tmpvalue; |
2442 | + |
2443 | + tmpvalue.integer = GSIZE_TO_LE (offset); |
2444 | + memcpy (*offset_ptr, tmpvalue.bytes, offset_size); |
2445 | + *offset_ptr += offset_size; |
2446 | +} |
2447 | + |
2448 | +static void |
2449 | +prepend_offset (guchar **offset_ptr, |
2450 | + gsize offset, |
2451 | + guint offset_size) |
2452 | +{ |
2453 | + union |
2454 | + { |
2455 | + guchar bytes[sizeof (gsize)]; |
2456 | + gsize integer; |
2457 | + } tmpvalue; |
2458 | + |
2459 | + *offset_ptr -= offset_size; |
2460 | + tmpvalue.integer = GSIZE_TO_LE (offset); |
2461 | + memcpy (*offset_ptr, tmpvalue.bytes, offset_size); |
2462 | +} |
2463 | + |
2464 | +static void |
2465 | +test_maybe (void) |
2466 | +{ |
2467 | + GVariantTypeInfo *type_info; |
2468 | + RandomInstance *instance; |
2469 | + gsize needed_size; |
2470 | + guchar *data; |
2471 | + |
2472 | + instance = random_instance (NULL); |
2473 | + |
2474 | + { |
2475 | + const gchar *element; |
2476 | + gchar *tmp; |
2477 | + |
2478 | + element = g_variant_type_info_get_type_string (instance->type_info); |
2479 | + tmp = g_strdup_printf ("m%s", element); |
2480 | + type_info = g_variant_type_info_get (G_VARIANT_TYPE (tmp)); |
2481 | + g_free (tmp); |
2482 | + } |
2483 | + |
2484 | + needed_size = g_variant_serialiser_needed_size (type_info, |
2485 | + random_instance_filler, |
2486 | + NULL, 0); |
2487 | + g_assert_cmpint (needed_size, ==, 0); |
2488 | + |
2489 | + needed_size = g_variant_serialiser_needed_size (type_info, |
2490 | + random_instance_filler, |
2491 | + (gpointer *) &instance, 1); |
2492 | + |
2493 | + if (instance->is_fixed_sized) |
2494 | + g_assert_cmpint (needed_size, ==, instance->size); |
2495 | + else |
2496 | + g_assert_cmpint (needed_size, ==, instance->size + 1); |
2497 | + |
2498 | + { |
2499 | + guchar *ptr; |
2500 | + |
2501 | + ptr = data = align_malloc (needed_size); |
2502 | + append_instance_data (instance, &ptr); |
2503 | + |
2504 | + if (!instance->is_fixed_sized) |
2505 | + *ptr++ = '\0'; |
2506 | + |
2507 | + g_assert_cmpint (ptr - data, ==, needed_size); |
2508 | + } |
2509 | + |
2510 | + { |
2511 | + guint alignment; |
2512 | + guint flavour; |
2513 | + |
2514 | + alignment = (instance->alignment & ALIGN_BITS) + 1; |
2515 | + |
2516 | + for (flavour = 0; flavour < 8; flavour += alignment) |
2517 | + { |
2518 | + GVariantSerialised serialised; |
2519 | + GVariantSerialised child; |
2520 | + |
2521 | + serialised.type_info = type_info; |
2522 | + serialised.data = flavoured_malloc (needed_size, flavour); |
2523 | + serialised.size = needed_size; |
2524 | + |
2525 | + g_variant_serialiser_serialise (serialised, |
2526 | + random_instance_filler, |
2527 | + (gpointer *) &instance, 1); |
2528 | + child = g_variant_serialised_get_child (serialised, 0); |
2529 | + g_assert (child.type_info == instance->type_info); |
2530 | + random_instance_assert (instance, child.data, child.size); |
2531 | + g_variant_type_info_unref (child.type_info); |
2532 | + flavoured_free (serialised.data, flavour); |
2533 | + } |
2534 | + } |
2535 | + |
2536 | + g_variant_type_info_unref (type_info); |
2537 | + random_instance_free (instance); |
2538 | + align_free (data); |
2539 | +} |
2540 | + |
2541 | +static void |
2542 | +test_maybes (void) |
2543 | +{ |
2544 | + guint i; |
2545 | + |
2546 | + for (i = 0; i < 1000; i++) |
2547 | + test_maybe (); |
2548 | + |
2549 | + g_variant_type_info_assert_no_infos (); |
2550 | +} |
2551 | + |
2552 | +static void |
2553 | +test_array (void) |
2554 | +{ |
2555 | + GVariantTypeInfo *element_info; |
2556 | + GVariantTypeInfo *array_info; |
2557 | + RandomInstance **instances; |
2558 | + gsize needed_size; |
2559 | + gsize offset_size; |
2560 | + guint n_children; |
2561 | + guchar *data; |
2562 | + |
2563 | + { |
2564 | + gchar *element_type, *array_type; |
2565 | + |
2566 | + element_type = random_type_string (); |
2567 | + array_type = g_strdup_printf ("a%s", element_type); |
2568 | + |
2569 | + element_info = g_variant_type_info_get (G_VARIANT_TYPE (element_type)); |
2570 | + array_info = g_variant_type_info_get (G_VARIANT_TYPE (array_type)); |
2571 | + g_assert (g_variant_type_info_element (array_info) == element_info); |
2572 | + |
2573 | + g_free (element_type); |
2574 | + g_free (array_type); |
2575 | + } |
2576 | + |
2577 | + { |
2578 | + guint i; |
2579 | + |
2580 | + n_children = g_test_rand_int_range (0, MAX_ARRAY_CHILDREN); |
2581 | + instances = g_new (RandomInstance *, n_children); |
2582 | + for (i = 0; i < n_children; i++) |
2583 | + instances[i] = random_instance (element_info); |
2584 | + } |
2585 | + |
2586 | + needed_size = g_variant_serialiser_needed_size (array_info, |
2587 | + random_instance_filler, |
2588 | + (gpointer *) instances, |
2589 | + n_children); |
2590 | + |
2591 | + { |
2592 | + gsize element_fixed_size; |
2593 | + gsize body_size = 0; |
2594 | + guint i; |
2595 | + |
2596 | + for (i = 0; i < n_children; i++) |
2597 | + append_instance_size (instances[i], &body_size); |
2598 | + |
2599 | + g_variant_type_info_query (element_info, NULL, &element_fixed_size); |
2600 | + |
2601 | + if (!element_fixed_size) |
2602 | + { |
2603 | + offset_size = calculate_offset_size (body_size, n_children); |
2604 | + |
2605 | + if (offset_size == 0) |
2606 | + offset_size = 1; |
2607 | + } |
2608 | + else |
2609 | + offset_size = 0; |
2610 | + |
2611 | + g_assert_cmpint (needed_size, ==, body_size + n_children * offset_size); |
2612 | + } |
2613 | + |
2614 | + { |
2615 | + guchar *offset_ptr, *body_ptr; |
2616 | + guint i; |
2617 | + |
2618 | + body_ptr = data = align_malloc (needed_size); |
2619 | + offset_ptr = body_ptr + needed_size - offset_size * n_children; |
2620 | + |
2621 | + for (i = 0; i < n_children; i++) |
2622 | + { |
2623 | + append_instance_data (instances[i], &body_ptr); |
2624 | + append_offset (&offset_ptr, body_ptr - data, offset_size); |
2625 | + } |
2626 | + |
2627 | + g_assert (body_ptr == data + needed_size - offset_size * n_children); |
2628 | + g_assert (offset_ptr == data + needed_size); |
2629 | + } |
2630 | + |
2631 | + { |
2632 | + guint alignment; |
2633 | + gsize flavour; |
2634 | + guint i; |
2635 | + |
2636 | + g_variant_type_info_query (array_info, &alignment, NULL); |
2637 | + alignment = (alignment & ALIGN_BITS) + 1; |
2638 | + |
2639 | + for (flavour = 0; flavour < 8; flavour += alignment) |
2640 | + { |
2641 | + GVariantSerialised serialised; |
2642 | + |
2643 | + serialised.type_info = array_info; |
2644 | + serialised.data = flavoured_malloc (needed_size, flavour); |
2645 | + serialised.size = needed_size; |
2646 | + |
2647 | + g_variant_serialiser_serialise (serialised, random_instance_filler, |
2648 | + (gpointer *) instances, n_children); |
2649 | + |
2650 | + g_assert (memcmp (serialised.data, data, serialised.size) == 0); |
2651 | + g_assert (g_variant_serialised_n_children (serialised) == n_children); |
2652 | + |
2653 | + for (i = 0; i < n_children; i++) |
2654 | + { |
2655 | + GVariantSerialised child; |
2656 | + |
2657 | + child = g_variant_serialised_get_child (serialised, i); |
2658 | + g_assert (child.type_info == instances[i]->type_info); |
2659 | + random_instance_assert (instances[i], child.data, child.size); |
2660 | + g_variant_type_info_unref (child.type_info); |
2661 | + } |
2662 | + |
2663 | + flavoured_free (serialised.data, flavour); |
2664 | + } |
2665 | + } |
2666 | + |
2667 | + { |
2668 | + guint i; |
2669 | + |
2670 | + for (i = 0; i < n_children; i++) |
2671 | + random_instance_free (instances[i]); |
2672 | + g_free (instances); |
2673 | + } |
2674 | + |
2675 | + g_variant_type_info_unref (element_info); |
2676 | + g_variant_type_info_unref (array_info); |
2677 | + align_free (data); |
2678 | +} |
2679 | + |
2680 | +static void |
2681 | +test_arrays (void) |
2682 | +{ |
2683 | + guint i; |
2684 | + |
2685 | + for (i = 0; i < 100; i++) |
2686 | + test_array (); |
2687 | + |
2688 | + g_variant_type_info_assert_no_infos (); |
2689 | +} |
2690 | + |
2691 | +static void |
2692 | +test_tuple (void) |
2693 | +{ |
2694 | + GVariantTypeInfo *type_info; |
2695 | + RandomInstance **instances; |
2696 | + gboolean fixed_size; |
2697 | + gsize needed_size; |
2698 | + gsize offset_size; |
2699 | + guint n_children; |
2700 | + guint alignment; |
2701 | + guchar *data; |
2702 | + |
2703 | + n_children = g_test_rand_int_range (0, MAX_TUPLE_CHILDREN); |
2704 | + instances = g_new (RandomInstance *, n_children); |
2705 | + |
2706 | + { |
2707 | + GString *type_string; |
2708 | + guint i; |
2709 | + |
2710 | + fixed_size = TRUE; |
2711 | + alignment = 0; |
2712 | + |
2713 | + type_string = g_string_new ("("); |
2714 | + for (i = 0; i < n_children; i++) |
2715 | + { |
2716 | + const gchar *str; |
2717 | + |
2718 | + instances[i] = random_instance (NULL); |
2719 | + |
2720 | + alignment |= instances[i]->alignment; |
2721 | + if (!instances[i]->is_fixed_sized) |
2722 | + fixed_size = FALSE; |
2723 | + |
2724 | + str = g_variant_type_info_get_type_string (instances[i]->type_info); |
2725 | + g_string_append (type_string, str); |
2726 | + } |
2727 | + g_string_append_c (type_string, ')'); |
2728 | + |
2729 | + type_info = g_variant_type_info_get (G_VARIANT_TYPE (type_string->str)); |
2730 | + g_string_free (type_string, TRUE); |
2731 | + } |
2732 | + |
2733 | + needed_size = g_variant_serialiser_needed_size (type_info, |
2734 | + random_instance_filler, |
2735 | + (gpointer *) instances, |
2736 | + n_children); |
2737 | + { |
2738 | + gsize body_size = 0; |
2739 | + gsize offsets = 0; |
2740 | + guint i; |
2741 | + |
2742 | + for (i = 0; i < n_children; i++) |
2743 | + { |
2744 | + append_instance_size (instances[i], &body_size); |
2745 | + |
2746 | + if (i != n_children - 1 && !instances[i]->is_fixed_sized) |
2747 | + offsets++; |
2748 | + } |
2749 | + |
2750 | + if (fixed_size) |
2751 | + { |
2752 | + body_size += (-body_size) & alignment; |
2753 | + |
2754 | + g_assert ((body_size == 0) == (n_children == 0)); |
2755 | + if (n_children == 0) |
2756 | + body_size = 1; |
2757 | + } |
2758 | + |
2759 | + offset_size = calculate_offset_size (body_size, offsets); |
2760 | + g_assert_cmpint (needed_size, ==, body_size + offsets * offset_size); |
2761 | + } |
2762 | + |
2763 | + { |
2764 | + guchar *body_ptr; |
2765 | + guchar *ofs_ptr; |
2766 | + guint i; |
2767 | + |
2768 | + body_ptr = data = align_malloc (needed_size); |
2769 | + ofs_ptr = body_ptr + needed_size; |
2770 | + |
2771 | + for (i = 0; i < n_children; i++) |
2772 | + { |
2773 | + append_instance_data (instances[i], &body_ptr); |
2774 | + |
2775 | + if (i != n_children - 1 && !instances[i]->is_fixed_sized) |
2776 | + prepend_offset (&ofs_ptr, body_ptr - data, offset_size); |
2777 | + } |
2778 | + |
2779 | + if (fixed_size) |
2780 | + { |
2781 | + while (((gsize) body_ptr) & alignment) |
2782 | + *body_ptr++ = '\0'; |
2783 | + |
2784 | + g_assert ((body_ptr == data) == (n_children == 0)); |
2785 | + if (n_children == 0) |
2786 | + *body_ptr++ = '\0'; |
2787 | + |
2788 | + } |
2789 | + |
2790 | + |
2791 | + g_assert (body_ptr == ofs_ptr); |
2792 | + } |
2793 | + |
2794 | + { |
2795 | + gsize flavour; |
2796 | + guint i; |
2797 | + |
2798 | + alignment = (alignment & ALIGN_BITS) + 1; |
2799 | + |
2800 | + for (flavour = 0; flavour < 8; flavour += alignment) |
2801 | + { |
2802 | + GVariantSerialised serialised; |
2803 | + |
2804 | + serialised.type_info = type_info; |
2805 | + serialised.data = flavoured_malloc (needed_size, flavour); |
2806 | + serialised.size = needed_size; |
2807 | + |
2808 | + g_variant_serialiser_serialise (serialised, random_instance_filler, |
2809 | + (gpointer *) instances, n_children); |
2810 | + |
2811 | + g_assert (memcmp (serialised.data, data, serialised.size) == 0); |
2812 | + g_assert (g_variant_serialised_n_children (serialised) == n_children); |
2813 | + |
2814 | + for (i = 0; i < n_children; i++) |
2815 | + { |
2816 | + GVariantSerialised child; |
2817 | + |
2818 | + child = g_variant_serialised_get_child (serialised, i); |
2819 | + g_assert (child.type_info == instances[i]->type_info); |
2820 | + random_instance_assert (instances[i], child.data, child.size); |
2821 | + g_variant_type_info_unref (child.type_info); |
2822 | + } |
2823 | + |
2824 | + flavoured_free (serialised.data, flavour); |
2825 | + } |
2826 | + } |
2827 | + |
2828 | + { |
2829 | + guint i; |
2830 | + |
2831 | + for (i = 0; i < n_children; i++) |
2832 | + random_instance_free (instances[i]); |
2833 | + g_free (instances); |
2834 | + } |
2835 | + |
2836 | + g_variant_type_info_unref (type_info); |
2837 | + align_free (data); |
2838 | +} |
2839 | + |
2840 | +static void |
2841 | +test_tuples (void) |
2842 | +{ |
2843 | + guint i; |
2844 | + |
2845 | + for (i = 0; i < 100; i++) |
2846 | + test_tuple (); |
2847 | + |
2848 | + g_variant_type_info_assert_no_infos (); |
2849 | +} |
2850 | + |
2851 | +static void |
2852 | +test_variant (void) |
2853 | +{ |
2854 | + GVariantTypeInfo *type_info; |
2855 | + RandomInstance *instance; |
2856 | + const gchar *type_string; |
2857 | + gsize needed_size; |
2858 | + guchar *data; |
2859 | + gsize len; |
2860 | + |
2861 | + type_info = g_variant_type_info_get (G_VARIANT_TYPE_VARIANT); |
2862 | + instance = random_instance (NULL); |
2863 | + |
2864 | + type_string = g_variant_type_info_get_type_string (instance->type_info); |
2865 | + len = strlen (type_string); |
2866 | + |
2867 | + needed_size = g_variant_serialiser_needed_size (type_info, |
2868 | + random_instance_filler, |
2869 | + (gpointer *) &instance, 1); |
2870 | + |
2871 | + g_assert_cmpint (needed_size, ==, instance->size + 1 + len); |
2872 | + |
2873 | + { |
2874 | + guchar *ptr; |
2875 | + |
2876 | + ptr = data = align_malloc (needed_size); |
2877 | + append_instance_data (instance, &ptr); |
2878 | + *ptr++ = '\0'; |
2879 | + memcpy (ptr, type_string, len); |
2880 | + ptr += len; |
2881 | + |
2882 | + g_assert (data + needed_size == ptr); |
2883 | + } |
2884 | + |
2885 | + { |
2886 | + gsize alignment; |
2887 | + gsize flavour; |
2888 | + |
2889 | + /* variants are always 8-aligned */ |
2890 | + alignment = ALIGN_BITS + 1; |
2891 | + |
2892 | + for (flavour = 0; flavour < 8; flavour += alignment) |
2893 | + { |
2894 | + GVariantSerialised serialised; |
2895 | + GVariantSerialised child; |
2896 | + |
2897 | + serialised.type_info = type_info; |
2898 | + serialised.data = flavoured_malloc (needed_size, flavour); |
2899 | + serialised.size = needed_size; |
2900 | + |
2901 | + g_variant_serialiser_serialise (serialised, random_instance_filler, |
2902 | + (gpointer *) &instance, 1); |
2903 | + |
2904 | + g_assert (memcmp (serialised.data, data, serialised.size) == 0); |
2905 | + g_assert (g_variant_serialised_n_children (serialised) == 1); |
2906 | + |
2907 | + child = g_variant_serialised_get_child (serialised, 0); |
2908 | + g_assert (child.type_info == instance->type_info); |
2909 | + random_instance_check (instance, child.data, child.size); |
2910 | + |
2911 | + g_variant_type_info_unref (child.type_info); |
2912 | + flavoured_free (serialised.data, flavour); |
2913 | + } |
2914 | + } |
2915 | + |
2916 | + g_variant_type_info_unref (type_info); |
2917 | + random_instance_free (instance); |
2918 | + align_free (data); |
2919 | +} |
2920 | + |
2921 | +static void |
2922 | +test_variants (void) |
2923 | +{ |
2924 | + guint i; |
2925 | + |
2926 | + for (i = 0; i < 100; i++) |
2927 | + test_variant (); |
2928 | + |
2929 | + g_variant_type_info_assert_no_infos (); |
2930 | +} |
2931 | + |
2932 | +static void |
2933 | +test_strings (void) |
2934 | +{ |
2935 | + struct { |
2936 | + guint flags; |
2937 | + guint size; |
2938 | + gconstpointer data; |
2939 | + } test_cases[] = { |
2940 | +#define is_nval 0 |
2941 | +#define is_string 1 |
2942 | +#define is_objpath is_string | 2 |
2943 | +#define is_sig is_string | 4 |
2944 | + { is_sig, 1, "" }, |
2945 | + { is_nval, 0, NULL }, |
2946 | + { is_nval, 13, "hello\xffworld!" }, |
2947 | + { is_string, 13, "hello world!" }, |
2948 | + { is_nval, 13, "hello world\0" }, |
2949 | + { is_nval, 13, "hello\0world!" }, |
2950 | + { is_nval, 12, "hello world!" }, |
2951 | + { is_nval, 13, "hello world!\xff" }, |
2952 | + |
2953 | + { is_objpath, 2, "/" }, |
2954 | + { is_objpath, 3, "/a" }, |
2955 | + { is_string, 3, "//" }, |
2956 | + { is_objpath, 11, "/some/path" }, |
2957 | + { is_string, 12, "/some/path/" }, |
2958 | + { is_nval, 11, "/some\0path" }, |
2959 | + { is_string, 11, "/some\\path" }, |
2960 | + { is_string, 12, "/some//path" }, |
2961 | + { is_string, 12, "/some-/path" }, |
2962 | + |
2963 | + { is_sig, 2, "i" }, |
2964 | + { is_sig, 2, "s" }, |
2965 | + { is_sig, 5, "(si)" }, |
2966 | + { is_string, 4, "(si" }, |
2967 | + { is_string, 2, "*" }, |
2968 | + { is_sig, 3, "ai" }, |
2969 | + { is_string, 3, "mi" }, |
2970 | + { is_string, 2, "r" }, |
2971 | + { is_sig, 15, "(yyy{sv}ssiai)" }, |
2972 | + { is_string, 16, "(yyy{yv}ssiai))" }, |
2973 | + { is_string, 15, "(yyy{vv}ssiai)" }, |
2974 | + { is_string, 15, "(yyy{sv)ssiai}" } |
2975 | + }; |
2976 | + guint i; |
2977 | + |
2978 | + for (i = 0; i < G_N_ELEMENTS (test_cases); i++) |
2979 | + { |
2980 | + guint flags; |
2981 | + |
2982 | + flags = g_variant_serialiser_is_string (test_cases[i].data, |
2983 | + test_cases[i].size) |
2984 | + ? 1 : 0; |
2985 | + |
2986 | + flags |= g_variant_serialiser_is_object_path (test_cases[i].data, |
2987 | + test_cases[i].size) |
2988 | + ? 2 : 0; |
2989 | + |
2990 | + flags |= g_variant_serialiser_is_signature (test_cases[i].data, |
2991 | + test_cases[i].size) |
2992 | + ? 4 : 0; |
2993 | + |
2994 | + g_assert (flags == test_cases[i].flags); |
2995 | + } |
2996 | +} |
2997 | + |
2998 | +typedef struct _TreeInstance TreeInstance; |
2999 | +struct _TreeInstance |
3000 | +{ |
3001 | + GVariantTypeInfo *info; |
3002 | + |
3003 | + TreeInstance **children; |
3004 | + gsize n_children; |
3005 | + |
3006 | + union { |
3007 | + guint64 integer; |
3008 | + gdouble floating; |
3009 | + gchar string[32]; |
3010 | + } data; |
3011 | + gsize data_size; |
3012 | +}; |
3013 | + |
3014 | +static GVariantType * |
3015 | +make_random_definite_type (int depth) |
3016 | +{ |
3017 | + GString *description; |
3018 | + GString *type_string; |
3019 | + GVariantType *type; |
3020 | + |
3021 | + description = g_string_new (NULL); |
3022 | + type_string = g_string_new (NULL); |
3023 | + type = append_type_string (type_string, description, TRUE, depth); |
3024 | + g_string_free (description, TRUE); |
3025 | + g_string_free (type_string, TRUE); |
3026 | + |
3027 | + return type; |
3028 | +} |
3029 | + |
3030 | +static void |
3031 | +make_random_string (gchar *string, |
3032 | + gsize size, |
3033 | + const GVariantType *type) |
3034 | +{ |
3035 | + gint i; |
3036 | + |
3037 | + /* create strings that are valid signature strings */ |
3038 | +#define good_chars "bynqiuxthdsog" |
3039 | + |
3040 | + for (i = 0; i < size - 1; i++) |
3041 | + string[i] = good_chars[g_test_rand_int_range (0, strlen (good_chars))]; |
3042 | + string[i] = '\0'; |
3043 | + |
3044 | + /* in case we need an object path, prefix a '/' */ |
3045 | + if (*g_variant_type_peek_string (type) == 'o') |
3046 | + string[0] = '/'; |
3047 | + |
3048 | +#undef good_chars |
3049 | +} |
3050 | + |
3051 | +static TreeInstance * |
3052 | +tree_instance_new (const GVariantType *type, |
3053 | + int depth) |
3054 | +{ |
3055 | + const GVariantType *child_type = NULL; |
3056 | + GVariantType *mytype = NULL; |
3057 | + TreeInstance *instance; |
3058 | + gboolean is_tuple_type; |
3059 | + |
3060 | + if (type == NULL) |
3061 | + type = mytype = make_random_definite_type (depth); |
3062 | + |
3063 | + instance = g_slice_new (TreeInstance); |
3064 | + instance->info = g_variant_type_info_get (type); |
3065 | + instance->children = NULL; |
3066 | + instance->n_children = 0; |
3067 | + instance->data_size = 0; |
3068 | + |
3069 | + is_tuple_type = FALSE; |
3070 | + |
3071 | + switch (*g_variant_type_peek_string (type)) |
3072 | + { |
3073 | + case G_VARIANT_TYPE_INFO_CHAR_MAYBE: |
3074 | + instance->n_children = g_test_rand_int_range (0, 2); |
3075 | + child_type = g_variant_type_element (type); |
3076 | + break; |
3077 | + |
3078 | + case G_VARIANT_TYPE_INFO_CHAR_ARRAY: |
3079 | + instance->n_children = g_test_rand_int_range (0, MAX_ARRAY_CHILDREN); |
3080 | + child_type = g_variant_type_element (type); |
3081 | + break; |
3082 | + |
3083 | + case G_VARIANT_TYPE_INFO_CHAR_DICT_ENTRY: |
3084 | + case G_VARIANT_TYPE_INFO_CHAR_TUPLE: |
3085 | + instance->n_children = g_variant_type_n_items (type); |
3086 | + child_type = g_variant_type_first (type); |
3087 | + is_tuple_type = TRUE; |
3088 | + break; |
3089 | + |
3090 | + case G_VARIANT_TYPE_INFO_CHAR_VARIANT: |
3091 | + instance->n_children = 1; |
3092 | + child_type = NULL; |
3093 | + break; |
3094 | + |
3095 | + case 'b': |
3096 | + instance->data.integer = g_test_rand_int_range (0, 2); |
3097 | + instance->data_size = 1; |
3098 | + break; |
3099 | + |
3100 | + case 'y': |
3101 | + instance->data.integer = g_test_rand_int (); |
3102 | + instance->data_size = 1; |
3103 | + break; |
3104 | + |
3105 | + case 'n': case 'q': |
3106 | + instance->data.integer = g_test_rand_int (); |
3107 | + instance->data_size = 2; |
3108 | + break; |
3109 | + |
3110 | + case 'i': case 'u': case 'h': |
3111 | + instance->data.integer = g_test_rand_int (); |
3112 | + instance->data_size = 4; |
3113 | + break; |
3114 | + |
3115 | + case 'x': case 't': |
3116 | + instance->data.integer = g_test_rand_int (); |
3117 | + instance->data.integer <<= 32; |
3118 | + instance->data.integer |= (guint32) g_test_rand_int (); |
3119 | + instance->data_size = 8; |
3120 | + break; |
3121 | + |
3122 | + case 'd': |
3123 | + instance->data.floating = g_test_rand_double (); |
3124 | + instance->data_size = 8; |
3125 | + break; |
3126 | + |
3127 | + case 's': case 'o': case 'g': |
3128 | + instance->data_size = g_test_rand_int_range (10, 20); |
3129 | + make_random_string (instance->data.string, instance->data_size, type); |
3130 | + break; |
3131 | + } |
3132 | + |
3133 | + if (instance->data_size == 0) |
3134 | + /* no data -> it is a container */ |
3135 | + { |
3136 | + guint i; |
3137 | + |
3138 | + instance->children = g_new (TreeInstance *, instance->n_children); |
3139 | + |
3140 | + for (i = 0; i < instance->n_children; i++) |
3141 | + { |
3142 | + instance->children[i] = tree_instance_new (child_type, depth - 1); |
3143 | + |
3144 | + if (is_tuple_type) |
3145 | + child_type = g_variant_type_next (child_type); |
3146 | + } |
3147 | + |
3148 | + g_assert (!is_tuple_type || child_type == NULL); |
3149 | + } |
3150 | + |
3151 | + g_variant_type_free (mytype); |
3152 | + |
3153 | + return instance; |
3154 | +} |
3155 | + |
3156 | +static void |
3157 | +tree_instance_free (TreeInstance *instance) |
3158 | +{ |
3159 | + gint i; |
3160 | + |
3161 | + g_variant_type_info_unref (instance->info); |
3162 | + for (i = 0; i < instance->n_children; i++) |
3163 | + tree_instance_free (instance->children[i]); |
3164 | + g_free (instance->children); |
3165 | + g_slice_free (TreeInstance, instance); |
3166 | +} |
3167 | + |
3168 | +static gboolean i_am_writing_byteswapped; |
3169 | + |
3170 | +static void |
3171 | +tree_filler (GVariantSerialised *serialised, |
3172 | + gpointer data) |
3173 | +{ |
3174 | + TreeInstance *instance = data; |
3175 | + |
3176 | + if (serialised->type_info == NULL) |
3177 | + serialised->type_info = instance->info; |
3178 | + |
3179 | + if (instance->data_size == 0) |
3180 | + /* is a container */ |
3181 | + { |
3182 | + if (serialised->size == 0) |
3183 | + serialised->size = |
3184 | + g_variant_serialiser_needed_size (instance->info, tree_filler, |
3185 | + (gpointer *) instance->children, |
3186 | + instance->n_children); |
3187 | + |
3188 | + if (serialised->data) |
3189 | + g_variant_serialiser_serialise (*serialised, tree_filler, |
3190 | + (gpointer *) instance->children, |
3191 | + instance->n_children); |
3192 | + } |
3193 | + else |
3194 | + /* it is a leaf */ |
3195 | + { |
3196 | + if (serialised->size == 0) |
3197 | + serialised->size = instance->data_size; |
3198 | + |
3199 | + if (serialised->data) |
3200 | + { |
3201 | + switch (instance->data_size) |
3202 | + { |
3203 | + case 1: |
3204 | + *serialised->data = instance->data.integer; |
3205 | + break; |
3206 | + |
3207 | + case 2: |
3208 | + { |
3209 | + guint16 value = instance->data.integer; |
3210 | + |
3211 | + if (i_am_writing_byteswapped) |
3212 | + value = GUINT16_SWAP_LE_BE (value); |
3213 | + |
3214 | + *(guint16 *) serialised->data = value; |
3215 | + } |
3216 | + break; |
3217 | + |
3218 | + case 4: |
3219 | + { |
3220 | + guint32 value = instance->data.integer; |
3221 | + |
3222 | + if (i_am_writing_byteswapped) |
3223 | + value = GUINT32_SWAP_LE_BE (value); |
3224 | + |
3225 | + *(guint32 *) serialised->data = value; |
3226 | + } |
3227 | + break; |
3228 | + |
3229 | + case 8: |
3230 | + { |
3231 | + guint64 value = instance->data.integer; |
3232 | + |
3233 | + if (i_am_writing_byteswapped) |
3234 | + value = GUINT64_SWAP_LE_BE (value); |
3235 | + |
3236 | + *(guint64 *) serialised->data = value; |
3237 | + } |
3238 | + break; |
3239 | + |
3240 | + default: |
3241 | + memcpy (serialised->data, |
3242 | + instance->data.string, |
3243 | + instance->data_size); |
3244 | + break; |
3245 | + } |
3246 | + } |
3247 | + } |
3248 | +} |
3249 | + |
3250 | +static gboolean |
3251 | +check_tree (TreeInstance *instance, |
3252 | + GVariantSerialised serialised) |
3253 | +{ |
3254 | + if (instance->info != serialised.type_info) |
3255 | + return FALSE; |
3256 | + |
3257 | + if (instance->data_size == 0) |
3258 | + /* is a container */ |
3259 | + { |
3260 | + gint i; |
3261 | + |
3262 | + if (g_variant_serialised_n_children (serialised) != |
3263 | + instance->n_children) |
3264 | + return FALSE; |
3265 | + |
3266 | + for (i = 0; i < instance->n_children; i++) |
3267 | + { |
3268 | + GVariantSerialised child; |
3269 | + gpointer data = NULL; |
3270 | + gboolean ok; |
3271 | + |
3272 | + child = g_variant_serialised_get_child (serialised, i); |
3273 | + if (child.size && child.data == NULL) |
3274 | + child.data = data = g_malloc0 (child.size); |
3275 | + ok = check_tree (instance->children[i], child); |
3276 | + g_variant_type_info_unref (child.type_info); |
3277 | + g_free (data); |
3278 | + |
3279 | + if (!ok) |
3280 | + return FALSE; |
3281 | + } |
3282 | + |
3283 | + return TRUE; |
3284 | + } |
3285 | + else |
3286 | + /* it is a leaf */ |
3287 | + { |
3288 | + switch (instance->data_size) |
3289 | + { |
3290 | + case 1: |
3291 | + g_assert (serialised.size == 1); |
3292 | + return *(guint8 *) serialised.data == |
3293 | + (guint8) instance->data.integer; |
3294 | + |
3295 | + case 2: |
3296 | + g_assert (serialised.size == 2); |
3297 | + return *(guint16 *) serialised.data == |
3298 | + (guint16) instance->data.integer; |
3299 | + |
3300 | + case 4: |
3301 | + g_assert (serialised.size == 4); |
3302 | + return *(guint32 *) serialised.data == |
3303 | + (guint32) instance->data.integer; |
3304 | + |
3305 | + case 8: |
3306 | + g_assert (serialised.size == 8); |
3307 | + return *(guint64 *) serialised.data == |
3308 | + (guint64) instance->data.integer; |
3309 | + |
3310 | + default: |
3311 | + if (serialised.size != instance->data_size) |
3312 | + return FALSE; |
3313 | + |
3314 | + return memcmp (serialised.data, |
3315 | + instance->data.string, |
3316 | + instance->data_size) == 0; |
3317 | + } |
3318 | + } |
3319 | +} |
3320 | + |
3321 | +static void |
3322 | +serialise_tree (TreeInstance *tree, |
3323 | + GVariantSerialised *serialised) |
3324 | +{ |
3325 | + GVariantSerialised empty = { }; |
3326 | + |
3327 | + *serialised = empty; |
3328 | + tree_filler (serialised, tree); |
3329 | + serialised->data = g_malloc (serialised->size); |
3330 | + tree_filler (serialised, tree); |
3331 | +} |
3332 | + |
3333 | +static void |
3334 | +test_byteswap (void) |
3335 | +{ |
3336 | + GVariantSerialised one, two; |
3337 | + TreeInstance *tree; |
3338 | + |
3339 | + tree = tree_instance_new (NULL, 3); |
3340 | + serialise_tree (tree, &one); |
3341 | + |
3342 | + i_am_writing_byteswapped = TRUE; |
3343 | + serialise_tree (tree, &two); |
3344 | + i_am_writing_byteswapped = FALSE; |
3345 | + |
3346 | + g_variant_serialised_byteswap (two); |
3347 | + |
3348 | + g_assert_cmpint (one.size, ==, two.size); |
3349 | + g_assert (memcmp (one.data, two.data, one.size) == 0); |
3350 | + |
3351 | + tree_instance_free (tree); |
3352 | + g_free (one.data); |
3353 | + g_free (two.data); |
3354 | +} |
3355 | + |
3356 | +static void |
3357 | +test_byteswaps (void) |
3358 | +{ |
3359 | + int i; |
3360 | + |
3361 | + for (i = 0; i < 200; i++) |
3362 | + test_byteswap (); |
3363 | + |
3364 | + g_variant_type_info_assert_no_infos (); |
3365 | +} |
3366 | + |
3367 | +static void |
3368 | +test_fuzz (gdouble *fuzziness) |
3369 | +{ |
3370 | + GVariantSerialised serialised; |
3371 | + TreeInstance *tree; |
3372 | + |
3373 | + /* make an instance */ |
3374 | + tree = tree_instance_new (NULL, 3); |
3375 | + |
3376 | + /* serialise it */ |
3377 | + serialise_tree (tree, &serialised); |
3378 | + |
3379 | + g_assert (g_variant_serialised_is_normal (serialised)); |
3380 | + g_assert (check_tree (tree, serialised)); |
3381 | + |
3382 | + if (serialised.size) |
3383 | + { |
3384 | + gboolean fuzzed = FALSE; |
3385 | + gboolean a, b; |
3386 | + |
3387 | + while (!fuzzed) |
3388 | + { |
3389 | + gint i; |
3390 | + |
3391 | + for (i = 0; i < serialised.size; i++) |
3392 | + if (randomly (*fuzziness)) |
3393 | + { |
3394 | + serialised.data[i] += g_test_rand_int_range (1, 256); |
3395 | + fuzzed = TRUE; |
3396 | + } |
3397 | + } |
3398 | + |
3399 | + /* at least one byte in the serialised data has changed. |
3400 | + * |
3401 | + * this means that at least one of the following is true: |
3402 | + * |
3403 | + * - the serialised data now represents a different value: |
3404 | + * check_tree() will return FALSE |
3405 | + * |
3406 | + * - the serialised data is in non-normal form: |
3407 | + * g_variant_serialiser_is_normal() will return FALSE |
3408 | + * |
3409 | + * we always do both checks to increase exposure of the serialiser |
3410 | + * to corrupt data. |
3411 | + */ |
3412 | + a = g_variant_serialised_is_normal (serialised); |
3413 | + b = check_tree (tree, serialised); |
3414 | + |
3415 | + g_assert (!a || !b); |
3416 | + } |
3417 | + |
3418 | + tree_instance_free (tree); |
3419 | + g_free (serialised.data); |
3420 | +} |
3421 | + |
3422 | + |
3423 | +static void |
3424 | +test_fuzzes (gpointer data) |
3425 | +{ |
3426 | + gdouble fuzziness; |
3427 | + int i; |
3428 | + |
3429 | + fuzziness = GPOINTER_TO_INT (data) / 100.; |
3430 | + |
3431 | + for (i = 0; i < 200; i++) |
3432 | + test_fuzz (&fuzziness); |
3433 | + |
3434 | + g_variant_type_info_assert_no_infos (); |
3435 | +} |
3436 | + |
3437 | +static GVariant * |
3438 | +tree_instance_get_gvariant (TreeInstance *tree) |
3439 | +{ |
3440 | + const GVariantType *type; |
3441 | + GVariant *result; |
3442 | + |
3443 | + type = (GVariantType *) g_variant_type_info_get_type_string (tree->info); |
3444 | + |
3445 | + switch (g_variant_type_info_get_type_char (tree->info)) |
3446 | + { |
3447 | + case G_VARIANT_TYPE_INFO_CHAR_MAYBE: |
3448 | + { |
3449 | + const GVariantType *child_type; |
3450 | + GVariant *child; |
3451 | + |
3452 | + if (tree->n_children) |
3453 | + child = tree_instance_get_gvariant (tree->children[0]); |
3454 | + else |
3455 | + child = NULL; |
3456 | + |
3457 | + child_type = g_variant_type_element (type); |
3458 | + |
3459 | + if (child != NULL && randomly (0.5)) |
3460 | + child_type = NULL; |
3461 | + |
3462 | + result = g_variant_new_maybe (child_type, child); |
3463 | + } |
3464 | + break; |
3465 | + |
3466 | + case G_VARIANT_TYPE_INFO_CHAR_ARRAY: |
3467 | + { |
3468 | + const GVariantType *child_type; |
3469 | + GVariant **children; |
3470 | + gint i; |
3471 | + |
3472 | + children = g_new (GVariant *, tree->n_children); |
3473 | + for (i = 0; i < tree->n_children; i++) |
3474 | + children[i] = tree_instance_get_gvariant (tree->children[i]); |
3475 | + |
3476 | + child_type = g_variant_type_element (type); |
3477 | + |
3478 | + if (i > 0 && randomly (0.5)) |
3479 | + child_type = NULL; |
3480 | + |
3481 | + result = g_variant_new_array (child_type, children, tree->n_children); |
3482 | + g_free (children); |
3483 | + } |
3484 | + break; |
3485 | + |
3486 | + case G_VARIANT_TYPE_INFO_CHAR_TUPLE: |
3487 | + { |
3488 | + GVariant **children; |
3489 | + gint i; |
3490 | + |
3491 | + children = g_new (GVariant *, tree->n_children); |
3492 | + for (i = 0; i < tree->n_children; i++) |
3493 | + children[i] = tree_instance_get_gvariant (tree->children[i]); |
3494 | + |
3495 | + result = g_variant_new_tuple (children, tree->n_children); |
3496 | + g_free (children); |
3497 | + } |
3498 | + break; |
3499 | + |
3500 | + case G_VARIANT_TYPE_INFO_CHAR_DICT_ENTRY: |
3501 | + { |
3502 | + GVariant *key, *val; |
3503 | + |
3504 | + g_assert (tree->n_children == 2); |
3505 | + |
3506 | + key = tree_instance_get_gvariant (tree->children[0]); |
3507 | + val = tree_instance_get_gvariant (tree->children[1]); |
3508 | + |
3509 | + result = g_variant_new_dict_entry (key, val); |
3510 | + } |
3511 | + break; |
3512 | + |
3513 | + case G_VARIANT_TYPE_INFO_CHAR_VARIANT: |
3514 | + { |
3515 | + GVariant *value; |
3516 | + |
3517 | + g_assert (tree->n_children == 1); |
3518 | + |
3519 | + value = tree_instance_get_gvariant (tree->children[0]); |
3520 | + result = g_variant_new_variant (value); |
3521 | + } |
3522 | + break; |
3523 | + |
3524 | + case 'b': |
3525 | + result = g_variant_new_boolean (tree->data.integer > 0); |
3526 | + break; |
3527 | + |
3528 | + case 'y': |
3529 | + result = g_variant_new_byte (tree->data.integer); |
3530 | + break; |
3531 | + |
3532 | + case 'n': |
3533 | + result = g_variant_new_int16 (tree->data.integer); |
3534 | + break; |
3535 | + |
3536 | + case 'q': |
3537 | + result = g_variant_new_uint16 (tree->data.integer); |
3538 | + break; |
3539 | + |
3540 | + case 'i': |
3541 | + result = g_variant_new_int32 (tree->data.integer); |
3542 | + break; |
3543 | + |
3544 | + case 'u': |
3545 | + result = g_variant_new_uint32 (tree->data.integer); |
3546 | + break; |
3547 | + |
3548 | + case 'x': |
3549 | + result = g_variant_new_int64 (tree->data.integer); |
3550 | + break; |
3551 | + |
3552 | + case 't': |
3553 | + result = g_variant_new_uint64 (tree->data.integer); |
3554 | + break; |
3555 | + |
3556 | + case 'h': |
3557 | + result = g_variant_new_handle (tree->data.integer); |
3558 | + break; |
3559 | + |
3560 | + case 'd': |
3561 | + result = g_variant_new_double (tree->data.floating); |
3562 | + break; |
3563 | + |
3564 | + case 's': |
3565 | + result = g_variant_new_string (tree->data.string); |
3566 | + break; |
3567 | + |
3568 | + case 'o': |
3569 | + result = g_variant_new_object_path (tree->data.string); |
3570 | + break; |
3571 | + |
3572 | + case 'g': |
3573 | + result = g_variant_new_signature (tree->data.string); |
3574 | + break; |
3575 | + |
3576 | + default: |
3577 | + g_assert_not_reached (); |
3578 | + } |
3579 | + |
3580 | + return result; |
3581 | +} |
3582 | + |
3583 | +static gboolean |
3584 | +tree_instance_check_gvariant (TreeInstance *tree, |
3585 | + GVariant *value) |
3586 | +{ |
3587 | + const GVariantType *type; |
3588 | + |
3589 | + type = (GVariantType *) g_variant_type_info_get_type_string (tree->info); |
3590 | + g_assert (g_variant_is_of_type (value, type)); |
3591 | + |
3592 | + switch (g_variant_type_info_get_type_char (tree->info)) |
3593 | + { |
3594 | + case G_VARIANT_TYPE_INFO_CHAR_MAYBE: |
3595 | + { |
3596 | + GVariant *child; |
3597 | + gboolean equal; |
3598 | + |
3599 | + child = g_variant_get_maybe (value); |
3600 | + |
3601 | + if (child != NULL && tree->n_children == 1) |
3602 | + equal = tree_instance_check_gvariant (tree->children[0], child); |
3603 | + else if (child == NULL && tree->n_children == 0) |
3604 | + equal = TRUE; |
3605 | + else |
3606 | + equal = FALSE; |
3607 | + |
3608 | + if (child != NULL) |
3609 | + g_variant_unref (child); |
3610 | + |
3611 | + return equal; |
3612 | + } |
3613 | + break; |
3614 | + |
3615 | + case G_VARIANT_TYPE_INFO_CHAR_ARRAY: |
3616 | + case G_VARIANT_TYPE_INFO_CHAR_TUPLE: |
3617 | + case G_VARIANT_TYPE_INFO_CHAR_DICT_ENTRY: |
3618 | + { |
3619 | + gsize i; |
3620 | + |
3621 | + if (g_variant_n_children (value) != tree->n_children) |
3622 | + return FALSE; |
3623 | + |
3624 | + for (i = 0; i < tree->n_children; i++) |
3625 | + { |
3626 | + GVariant *child; |
3627 | + gboolean equal; |
3628 | + |
3629 | + child = g_variant_get_child_value (value, i); |
3630 | + equal = tree_instance_check_gvariant (tree->children[i], child); |
3631 | + g_variant_unref (child); |
3632 | + |
3633 | + if (!equal) |
3634 | + return FALSE; |
3635 | + } |
3636 | + |
3637 | + return TRUE; |
3638 | + } |
3639 | + break; |
3640 | + |
3641 | + case G_VARIANT_TYPE_INFO_CHAR_VARIANT: |
3642 | + { |
3643 | + const gchar *str1, *str2; |
3644 | + GVariant *child; |
3645 | + gboolean equal; |
3646 | + |
3647 | + child = g_variant_get_variant (value); |
3648 | + str1 = g_variant_get_type_string (child); |
3649 | + str2 = g_variant_type_info_get_type_string (tree->children[0]->info); |
3650 | + /* GVariant only keeps one copy of type strings around */ |
3651 | + equal = str1 == str2 && |
3652 | + tree_instance_check_gvariant (tree->children[0], child); |
3653 | + |
3654 | + g_variant_unref (child); |
3655 | + |
3656 | + return equal; |
3657 | + } |
3658 | + break; |
3659 | + |
3660 | + case 'b': |
3661 | + return g_variant_get_boolean (value) == tree->data.integer; |
3662 | + |
3663 | + case 'y': |
3664 | + return g_variant_get_byte (value) == (guchar) tree->data.integer; |
3665 | + |
3666 | + case 'n': |
3667 | + return g_variant_get_int16 (value) == (gint16) tree->data.integer; |
3668 | + |
3669 | + case 'q': |
3670 | + return g_variant_get_uint16 (value) == (guint16) tree->data.integer; |
3671 | + |
3672 | + case 'i': |
3673 | + return g_variant_get_int32 (value) == (gint32) tree->data.integer; |
3674 | + |
3675 | + case 'u': |
3676 | + return g_variant_get_uint32 (value) == (guint32) tree->data.integer; |
3677 | + |
3678 | + case 'x': |
3679 | + return g_variant_get_int64 (value) == (gint64) tree->data.integer; |
3680 | + |
3681 | + case 't': |
3682 | + return g_variant_get_uint64 (value) == (guint64) tree->data.integer; |
3683 | + |
3684 | + case 'h': |
3685 | + return g_variant_get_handle (value) == (gint32) tree->data.integer; |
3686 | + |
3687 | + case 'd': |
3688 | + { |
3689 | + gdouble floating = g_variant_get_double (value); |
3690 | + |
3691 | + return memcmp (&floating, &tree->data.floating, sizeof floating) == 0; |
3692 | + } |
3693 | + |
3694 | + case 's': |
3695 | + case 'o': |
3696 | + case 'g': |
3697 | + return strcmp (g_variant_get_string (value, NULL), |
3698 | + tree->data.string) == 0; |
3699 | + |
3700 | + default: |
3701 | + g_assert_not_reached (); |
3702 | + } |
3703 | +} |
3704 | + |
3705 | +static void |
3706 | +tree_instance_build_gvariant (TreeInstance *tree, |
3707 | + GVariantBuilder *builder, |
3708 | + gboolean guess_ok) |
3709 | +{ |
3710 | + const GVariantType *type; |
3711 | + |
3712 | + type = (GVariantType *) g_variant_type_info_get_type_string (tree->info); |
3713 | + |
3714 | + if (g_variant_type_is_container (type)) |
3715 | + { |
3716 | + gsize i; |
3717 | + |
3718 | + /* force GVariantBuilder to guess the type half the time */ |
3719 | + if (guess_ok && randomly (0.5)) |
3720 | + { |
3721 | + if (g_variant_type_is_array (type) && tree->n_children) |
3722 | + type = G_VARIANT_TYPE_ARRAY; |
3723 | + |
3724 | + if (g_variant_type_is_maybe (type) && tree->n_children) |
3725 | + type = G_VARIANT_TYPE_MAYBE; |
3726 | + |
3727 | + if (g_variant_type_is_tuple (type)) |
3728 | + type = G_VARIANT_TYPE_TUPLE; |
3729 | + |
3730 | + if (g_variant_type_is_dict_entry (type)) |
3731 | + type = G_VARIANT_TYPE_DICT_ENTRY; |
3732 | + } |
3733 | + else |
3734 | + guess_ok = FALSE; |
3735 | + |
3736 | + g_variant_builder_open (builder, type); |
3737 | + |
3738 | + for (i = 0; i < tree->n_children; i++) |
3739 | + tree_instance_build_gvariant (tree->children[i], builder, guess_ok); |
3740 | + |
3741 | + g_variant_builder_close (builder); |
3742 | + } |
3743 | + else |
3744 | + g_variant_builder_add_value (builder, tree_instance_get_gvariant (tree)); |
3745 | +} |
3746 | + |
3747 | + |
3748 | +static gboolean |
3749 | +tree_instance_check_iter (TreeInstance *tree, |
3750 | + GVariantIter *iter) |
3751 | +{ |
3752 | + GVariant *value; |
3753 | + |
3754 | + value = g_variant_iter_next_value (iter); |
3755 | + |
3756 | + if (g_variant_is_container (value)) |
3757 | + { |
3758 | + gsize i; |
3759 | + |
3760 | + iter = g_variant_iter_new (value); |
3761 | + g_variant_unref (value); |
3762 | + |
3763 | + if (g_variant_iter_n_children (iter) != tree->n_children) |
3764 | + { |
3765 | + g_variant_iter_free (iter); |
3766 | + return FALSE; |
3767 | + } |
3768 | + |
3769 | + for (i = 0; i < tree->n_children; i++) |
3770 | + if (!tree_instance_check_iter (tree->children[i], iter)) |
3771 | + { |
3772 | + g_variant_iter_free (iter); |
3773 | + return FALSE; |
3774 | + } |
3775 | + |
3776 | + g_assert (g_variant_iter_next_value (iter) == NULL); |
3777 | + g_variant_iter_free (iter); |
3778 | + |
3779 | + return TRUE; |
3780 | + } |
3781 | + |
3782 | + else |
3783 | + { |
3784 | + gboolean equal; |
3785 | + |
3786 | + equal = tree_instance_check_gvariant (tree, value); |
3787 | + g_variant_unref (value); |
3788 | + |
3789 | + return equal; |
3790 | + } |
3791 | +} |
3792 | + |
3793 | +static void |
3794 | +test_container (void) |
3795 | +{ |
3796 | + TreeInstance *tree; |
3797 | + GVariant *value; |
3798 | + gchar *s1, *s2; |
3799 | + |
3800 | + tree = tree_instance_new (NULL, 3); |
3801 | + value = g_variant_ref_sink (tree_instance_get_gvariant (tree)); |
3802 | + |
3803 | + s1 = g_variant_print (value, TRUE); |
3804 | + g_assert (tree_instance_check_gvariant (tree, value)); |
3805 | + |
3806 | + g_variant_get_data (value); |
3807 | + |
3808 | + s2 = g_variant_print (value, TRUE); |
3809 | + g_assert (tree_instance_check_gvariant (tree, value)); |
3810 | + |
3811 | + g_assert_cmpstr (s1, ==, s2); |
3812 | + |
3813 | + if (g_variant_is_container (value)) |
3814 | + { |
3815 | + GVariantBuilder builder; |
3816 | + GVariantIter iter; |
3817 | + GVariant *built; |
3818 | + GVariant *val; |
3819 | + gchar *s3; |
3820 | + |
3821 | + g_variant_builder_init (&builder, G_VARIANT_TYPE_VARIANT); |
3822 | + tree_instance_build_gvariant (tree, &builder, TRUE); |
3823 | + built = g_variant_builder_end (&builder); |
3824 | + g_variant_ref_sink (built); |
3825 | + g_variant_get_data (built); |
3826 | + val = g_variant_get_variant (built); |
3827 | + |
3828 | + s3 = g_variant_print (val, TRUE); |
3829 | + g_assert_cmpstr (s1, ==, s3); |
3830 | + |
3831 | + g_variant_iter_init (&iter, built); |
3832 | + g_assert (tree_instance_check_iter (tree, &iter)); |
3833 | + g_assert (g_variant_iter_next_value (&iter) == NULL); |
3834 | + |
3835 | + g_variant_unref (built); |
3836 | + g_variant_unref (val); |
3837 | + g_free (s3); |
3838 | + } |
3839 | + |
3840 | + tree_instance_free (tree); |
3841 | + g_variant_unref (value); |
3842 | + g_free (s2); |
3843 | + g_free (s1); |
3844 | +} |
3845 | + |
3846 | +static void |
3847 | +test_utf8 (void) |
3848 | +{ |
3849 | + const gchar invalid[] = "hello\xffworld"; |
3850 | + GVariant *value; |
3851 | + |
3852 | + /* ensure that the test data is not valid utf8... */ |
3853 | + g_assert (!g_utf8_validate (invalid, -1, NULL)); |
3854 | + |
3855 | + /* load the data untrusted */ |
3856 | + value = g_variant_new_from_data (G_VARIANT_TYPE_STRING, |
3857 | + invalid, sizeof invalid, |
3858 | + FALSE, NULL, NULL); |
3859 | + |
3860 | + /* ensure that the problem is caught and we get valid UTF-8 */ |
3861 | + g_assert (g_utf8_validate (g_variant_get_string (value, NULL), -1, NULL)); |
3862 | + g_variant_unref (value); |
3863 | + |
3864 | + |
3865 | + /* now load it trusted */ |
3866 | + value = g_variant_new_from_data (G_VARIANT_TYPE_STRING, |
3867 | + invalid, sizeof invalid, |
3868 | + TRUE, NULL, NULL); |
3869 | + |
3870 | + /* ensure we get the invalid data (ie: make sure that time wasn't |
3871 | + * wasted on validating data that was marked as trusted) |
3872 | + */ |
3873 | + g_assert (g_variant_get_string (value, NULL) == invalid); |
3874 | + g_variant_unref (value); |
3875 | +} |
3876 | + |
3877 | +static void |
3878 | +test_containers (void) |
3879 | +{ |
3880 | + gint i; |
3881 | + |
3882 | + for (i = 0; i < 100; i++) |
3883 | + { |
3884 | + test_container (); |
3885 | + } |
3886 | + |
3887 | + g_variant_type_info_assert_no_infos (); |
3888 | +} |
3889 | + |
3890 | +static void |
3891 | +test_format_strings (void) |
3892 | +{ |
3893 | + GVariantType *type; |
3894 | + const gchar *end; |
3895 | + |
3896 | + g_assert (g_variant_format_string_scan ("i", NULL, &end) && *end == '\0'); |
3897 | + g_assert (g_variant_format_string_scan ("@i", NULL, &end) && *end == '\0'); |
3898 | + g_assert (g_variant_format_string_scan ("@ii", NULL, &end) && *end == 'i'); |
3899 | + g_assert (g_variant_format_string_scan ("^a&s", NULL, &end) && *end == '\0'); |
3900 | + g_assert (g_variant_format_string_scan ("(^as)", NULL, &end) && |
3901 | + *end == '\0'); |
3902 | + g_assert (!g_variant_format_string_scan ("(^s)", NULL, &end)); |
3903 | + g_assert (!g_variant_format_string_scan ("(^a)", NULL, &end)); |
3904 | + g_assert (!g_variant_format_string_scan ("(z)", NULL, &end)); |
3905 | + g_assert (!g_variant_format_string_scan ("az", NULL, &end)); |
3906 | + g_assert (!g_variant_format_string_scan ("{**}", NULL, &end)); |
3907 | + g_assert (!g_variant_format_string_scan ("{@**}", NULL, &end)); |
3908 | + g_assert (g_variant_format_string_scan ("{@y*}", NULL, &end) && |
3909 | + *end == '\0'); |
3910 | + g_assert (g_variant_format_string_scan ("{yv}", NULL, &end) && |
3911 | + *end == '\0'); |
3912 | + g_assert (!g_variant_format_string_scan ("{&?v}", NULL, &end)); |
3913 | + g_assert (g_variant_format_string_scan ("{@?v}", NULL, &end) && |
3914 | + *end == '\0'); |
3915 | + g_assert (!g_variant_format_string_scan ("{&@sv}", NULL, &end)); |
3916 | + g_assert (!g_variant_format_string_scan ("{@&sv}", NULL, &end)); |
3917 | + g_assert (g_variant_format_string_scan ("{&sv}", NULL, &end) && |
3918 | + *end == '\0'); |
3919 | + g_assert (!g_variant_format_string_scan ("{vv}", NULL, &end)); |
3920 | + g_assert (!g_variant_format_string_scan ("{y}", NULL, &end)); |
3921 | + g_assert (!g_variant_format_string_scan ("{yyy}", NULL, &end)); |
3922 | + g_assert (!g_variant_format_string_scan ("{ya}", NULL, &end)); |
3923 | + g_assert (g_variant_format_string_scan ("&s", NULL, &end) && *end == '\0'); |
3924 | + g_assert (!g_variant_format_string_scan ("&as", NULL, &end)); |
3925 | + g_assert (!g_variant_format_string_scan ("@z", NULL, &end)); |
3926 | + g_assert (!g_variant_format_string_scan ("az", NULL, &end)); |
3927 | + g_assert (!g_variant_format_string_scan ("a&s", NULL, &end)); |
3928 | + |
3929 | + type = g_variant_format_string_scan_type ("mm(@xy^a&s*?@?)", NULL, &end); |
3930 | + g_assert (type && *end == '\0'); |
3931 | + g_assert (g_variant_type_equal (type, G_VARIANT_TYPE ("mm(xyas*?\?)"))); |
3932 | + g_variant_type_free (type); |
3933 | + |
3934 | + type = g_variant_format_string_scan_type ("mm(@xy^a&*?@?)", NULL, NULL); |
3935 | + g_assert (type == NULL); |
3936 | +} |
3937 | + |
3938 | +static void |
3939 | +exit_on_abort (int signal) |
3940 | +{ |
3941 | + exit (signal); |
3942 | +} |
3943 | + |
3944 | +static gboolean |
3945 | +do_failed_test (const gchar *pattern) |
3946 | +{ |
3947 | + if (g_test_trap_fork (1000000, G_TEST_TRAP_SILENCE_STDERR)) |
3948 | + { |
3949 | + signal (SIGABRT, exit_on_abort); |
3950 | + return TRUE; |
3951 | + } |
3952 | + |
3953 | + g_test_trap_assert_failed (); |
3954 | + g_test_trap_assert_stderr (pattern); |
3955 | + |
3956 | + return FALSE; |
3957 | +} |
3958 | + |
3959 | +static void |
3960 | +test_invalid_varargs (void) |
3961 | +{ |
3962 | + GVariant *value; |
3963 | + const gchar *end; |
3964 | + |
3965 | + if (!g_test_undefined ()) |
3966 | + return; |
3967 | + |
3968 | + g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, |
3969 | + "*GVariant format string*"); |
3970 | + g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, |
3971 | + "*valid_format_string*"); |
3972 | + value = g_variant_new ("z"); |
3973 | + g_test_assert_expected_messages (); |
3974 | + g_assert (value == NULL); |
3975 | + |
3976 | + g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, |
3977 | + "*valid GVariant format string as a prefix*"); |
3978 | + g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, |
3979 | + "*valid_format_string*"); |
3980 | + value = g_variant_new_va ("z", &end, NULL); |
3981 | + g_test_assert_expected_messages (); |
3982 | + g_assert (value == NULL); |
3983 | + |
3984 | + value = g_variant_new ("y", 'a'); |
3985 | + g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, |
3986 | + "*type of `q' but * has a type of `y'*"); |
3987 | + g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, |
3988 | + "*valid_format_string*"); |
3989 | + g_variant_get (value, "q"); |
3990 | + g_test_assert_expected_messages (); |
3991 | + g_variant_unref (value); |
3992 | +} |
3993 | + |
3994 | +static void |
3995 | +check_and_free (GVariant *value, |
3996 | + const gchar *str) |
3997 | +{ |
3998 | + gchar *valstr = g_variant_print (value, FALSE); |
3999 | + g_assert_cmpstr (str, ==, valstr); |
4000 | + g_variant_unref (value); |
4001 | + g_free (valstr); |
4002 | +} |
4003 | + |
4004 | +static void |
4005 | +test_varargs (void) |
4006 | +{ |
4007 | + { |
4008 | + GVariantBuilder array; |
4009 | + |
4010 | + g_variant_builder_init (&array, G_VARIANT_TYPE_ARRAY); |
4011 | + g_variant_builder_add_parsed (&array, "{'size', <(%i, %i)> }", 800, 600); |
4012 | + g_variant_builder_add (&array, "{sv}", "title", |
4013 | + g_variant_new_string ("Test case")); |
4014 | + g_variant_builder_add_value (&array, |
4015 | + g_variant_new_dict_entry (g_variant_new_string ("temperature"), |
4016 | + g_variant_new_variant ( |
4017 | + g_variant_new_double (37.5)))); |
4018 | + check_and_free (g_variant_new ("(ma{sv}m(a{sv})ma{sv}ii)", |
4019 | + NULL, FALSE, NULL, &array, 7777, 8888), |
4020 | + "(nothing, nothing, {'size': <(800, 600)>, " |
4021 | + "'title': <'Test case'>, " |
4022 | + "'temperature': <37.5>}, " |
4023 | + "7777, 8888)"); |
4024 | + |
4025 | + check_and_free (g_variant_new ("(imimimmimmimmi)", |
4026 | + 123, |
4027 | + FALSE, 321, |
4028 | + TRUE, 123, |
4029 | + FALSE, TRUE, 321, |
4030 | + TRUE, FALSE, 321, |
4031 | + TRUE, TRUE, 123), |
4032 | + "(123, nothing, 123, nothing, just nothing, 123)"); |
4033 | + |
4034 | + check_and_free (g_variant_new ("(ybnixd)", |
4035 | + 'a', 1, 22, 33, (guint64) 44, 5.5), |
4036 | + "(0x61, true, 22, 33, 44, 5.5)"); |
4037 | + |
4038 | + check_and_free (g_variant_new ("(@y?*rv)", |
4039 | + g_variant_new ("y", 'a'), |
4040 | + g_variant_new ("y", 'b'), |
4041 | + g_variant_new ("y", 'c'), |
4042 | + g_variant_new ("(y)", 'd'), |
4043 | + g_variant_new ("y", 'e')), |
4044 | + "(0x61, 0x62, 0x63, (0x64,), <byte 0x65>)"); |
4045 | + } |
4046 | + |
4047 | + { |
4048 | + GVariantBuilder array; |
4049 | + GVariantIter iter; |
4050 | + GVariant *value; |
4051 | + gchar *number; |
4052 | + gboolean just; |
4053 | + gint i, val; |
4054 | + |
4055 | + g_variant_builder_init (&array, G_VARIANT_TYPE_ARRAY); |
4056 | + for (i = 0; i < 100; i++) |
4057 | + { |
4058 | + number = g_strdup_printf ("%d", i); |
4059 | + g_variant_builder_add (&array, "s", number); |
4060 | + g_free (number); |
4061 | + } |
4062 | + |
4063 | + value = g_variant_builder_end (&array); |
4064 | + g_variant_iter_init (&iter, value); |
4065 | + |
4066 | + i = 0; |
4067 | + while (g_variant_iter_loop (&iter, "s", &number)) |
4068 | + { |
4069 | + gchar *check = g_strdup_printf ("%d", i++); |
4070 | + g_assert_cmpstr (number, ==, check); |
4071 | + g_free (check); |
4072 | + } |
4073 | + g_assert (number == NULL); |
4074 | + g_assert (i == 100); |
4075 | + |
4076 | + g_variant_unref (value); |
4077 | + |
4078 | + g_variant_builder_init (&array, G_VARIANT_TYPE_ARRAY); |
4079 | + for (i = 0; i < 100; i++) |
4080 | + g_variant_builder_add (&array, "mi", i % 2 == 0, i); |
4081 | + value = g_variant_builder_end (&array); |
4082 | + |
4083 | + i = 0; |
4084 | + g_variant_iter_init (&iter, value); |
4085 | + while (g_variant_iter_loop (&iter, "mi", NULL, &val)) |
4086 | + g_assert (val == i++ || val == 0); |
4087 | + g_assert (i == 100); |
4088 | + |
4089 | + i = 0; |
4090 | + g_variant_iter_init (&iter, value); |
4091 | + while (g_variant_iter_loop (&iter, "mi", &just, &val)) |
4092 | + { |
4093 | + gint this = i++; |
4094 | + |
4095 | + if (this % 2 == 0) |
4096 | + { |
4097 | + g_assert (just); |
4098 | + g_assert (val == this); |
4099 | + } |
4100 | + else |
4101 | + { |
4102 | + g_assert (!just); |
4103 | + g_assert (val == 0); |
4104 | + } |
4105 | + } |
4106 | + g_assert (i == 100); |
4107 | + |
4108 | + g_variant_unref (value); |
4109 | + } |
4110 | + |
4111 | + { |
4112 | + const gchar *strvector[] = {"/hello", "/world", NULL}; |
4113 | + const gchar *test_strs[] = {"/foo", "/bar", "/baz" }; |
4114 | + GVariantBuilder builder; |
4115 | + GVariantIter *array; |
4116 | + GVariantIter tuple; |
4117 | + const gchar **strv; |
4118 | + gchar **my_strv; |
4119 | + GVariant *value; |
4120 | + gchar *str; |
4121 | + gint i; |
4122 | + |
4123 | + g_variant_builder_init (&builder, G_VARIANT_TYPE ("as")); |
4124 | + g_variant_builder_add (&builder, "s", "/foo"); |
4125 | + g_variant_builder_add (&builder, "s", "/bar"); |
4126 | + g_variant_builder_add (&builder, "s", "/baz"); |
4127 | + value = g_variant_new("(as^as^a&s)", &builder, strvector, strvector); |
4128 | + g_variant_iter_init (&tuple, value); |
4129 | + g_variant_iter_next (&tuple, "as", &array); |
4130 | + |
4131 | + i = 0; |
4132 | + while (g_variant_iter_loop (array, "s", &str)) |
4133 | + g_assert_cmpstr (str, ==, test_strs[i++]); |
4134 | + g_assert (i == 3); |
4135 | + |
4136 | + g_variant_iter_free (array); |
4137 | + |
4138 | + /* start over */ |
4139 | + g_variant_iter_init (&tuple, value); |
4140 | + g_variant_iter_next (&tuple, "as", &array); |
4141 | + |
4142 | + i = 0; |
4143 | + while (g_variant_iter_loop (array, "&s", &str)) |
4144 | + g_assert_cmpstr (str, ==, test_strs[i++]); |
4145 | + g_assert (i == 3); |
4146 | + |
4147 | + g_variant_iter_free (array); |
4148 | + |
4149 | + g_variant_iter_next (&tuple, "^a&s", &strv); |
4150 | + g_variant_iter_next (&tuple, "^as", &my_strv); |
4151 | + |
4152 | + g_assert_cmpstr (strv[0], ==, "/hello"); |
4153 | + g_assert_cmpstr (strv[1], ==, "/world"); |
4154 | + g_assert (strv[2] == NULL); |
4155 | + g_assert_cmpstr (my_strv[0], ==, "/hello"); |
4156 | + g_assert_cmpstr (my_strv[1], ==, "/world"); |
4157 | + g_assert (my_strv[2] == NULL); |
4158 | + |
4159 | + g_variant_unref (value); |
4160 | + g_strfreev (my_strv); |
4161 | + g_free (strv); |
4162 | + } |
4163 | + |
4164 | + { |
4165 | + const gchar *strvector[] = {"/hello", "/world", NULL}; |
4166 | + const gchar *test_strs[] = {"/foo", "/bar", "/baz" }; |
4167 | + GVariantBuilder builder; |
4168 | + GVariantIter *array; |
4169 | + GVariantIter tuple; |
4170 | + const gchar **strv; |
4171 | + gchar **my_strv; |
4172 | + GVariant *value; |
4173 | + gchar *str; |
4174 | + gint i; |
4175 | + |
4176 | + g_variant_builder_init (&builder, G_VARIANT_TYPE_OBJECT_PATH_ARRAY); |
4177 | + g_variant_builder_add (&builder, "o", "/foo"); |
4178 | + g_variant_builder_add (&builder, "o", "/bar"); |
4179 | + g_variant_builder_add (&builder, "o", "/baz"); |
4180 | + value = g_variant_new("(ao^ao^a&o)", &builder, strvector, strvector); |
4181 | + g_variant_iter_init (&tuple, value); |
4182 | + g_variant_iter_next (&tuple, "ao", &array); |
4183 | + |
4184 | + i = 0; |
4185 | + while (g_variant_iter_loop (array, "o", &str)) |
4186 | + g_assert_cmpstr (str, ==, test_strs[i++]); |
4187 | + g_assert (i == 3); |
4188 | + |
4189 | + g_variant_iter_free (array); |
4190 | + |
4191 | + /* start over */ |
4192 | + g_variant_iter_init (&tuple, value); |
4193 | + g_variant_iter_next (&tuple, "ao", &array); |
4194 | + |
4195 | + i = 0; |
4196 | + while (g_variant_iter_loop (array, "&o", &str)) |
4197 | + g_assert_cmpstr (str, ==, test_strs[i++]); |
4198 | + g_assert (i == 3); |
4199 | + |
4200 | + g_variant_iter_free (array); |
4201 | + |
4202 | + g_variant_iter_next (&tuple, "^a&o", &strv); |
4203 | + g_variant_iter_next (&tuple, "^ao", &my_strv); |
4204 | + |
4205 | + g_assert_cmpstr (strv[0], ==, "/hello"); |
4206 | + g_assert_cmpstr (strv[1], ==, "/world"); |
4207 | + g_assert (strv[2] == NULL); |
4208 | + g_assert_cmpstr (my_strv[0], ==, "/hello"); |
4209 | + g_assert_cmpstr (my_strv[1], ==, "/world"); |
4210 | + g_assert (my_strv[2] == NULL); |
4211 | + |
4212 | + g_variant_unref (value); |
4213 | + g_strfreev (my_strv); |
4214 | + g_free (strv); |
4215 | + } |
4216 | + |
4217 | + { |
4218 | + const gchar *strvector[] = { "i", "ii", "iii", "iv", "v", "vi", NULL }; |
4219 | + GVariantBuilder builder; |
4220 | + GVariantIter iter; |
4221 | + GVariantIter *i2; |
4222 | + GVariantIter *i3; |
4223 | + GVariant *value; |
4224 | + GVariant *sub; |
4225 | + gchar **strv; |
4226 | + gint i; |
4227 | + |
4228 | + g_variant_builder_init (&builder, G_VARIANT_TYPE ("aas")); |
4229 | + g_variant_builder_open (&builder, G_VARIANT_TYPE ("as")); |
4230 | + for (i = 0; i < 6; i++) |
4231 | + if (i & 1) |
4232 | + g_variant_builder_add (&builder, "s", strvector[i]); |
4233 | + else |
4234 | + g_variant_builder_add (&builder, "&s", strvector[i]); |
4235 | + g_variant_builder_close (&builder); |
4236 | + g_variant_builder_add (&builder, "^as", strvector); |
4237 | + g_variant_builder_add (&builder, "^as", strvector); |
4238 | + value = g_variant_new ("aas", &builder); |
4239 | + |
4240 | + g_variant_iter_init (&iter, value); |
4241 | + while (g_variant_iter_loop (&iter, "^as", &strv)) |
4242 | + for (i = 0; i < 6; i++) |
4243 | + g_assert_cmpstr (strv[i], ==, strvector[i]); |
4244 | + |
4245 | + g_variant_iter_init (&iter, value); |
4246 | + while (g_variant_iter_loop (&iter, "^a&s", &strv)) |
4247 | + for (i = 0; i < 6; i++) |
4248 | + g_assert_cmpstr (strv[i], ==, strvector[i]); |
4249 | + |
4250 | + g_variant_iter_init (&iter, value); |
4251 | + while (g_variant_iter_loop (&iter, "as", &i2)) |
4252 | + { |
4253 | + gchar *str; |
4254 | + |
4255 | + i = 0; |
4256 | + while (g_variant_iter_loop (i2, "s", &str)) |
4257 | + g_assert_cmpstr (str, ==, strvector[i++]); |
4258 | + g_assert (i == 6); |
4259 | + } |
4260 | + |
4261 | + g_variant_iter_init (&iter, value); |
4262 | + i3 = g_variant_iter_copy (&iter); |
4263 | + while (g_variant_iter_loop (&iter, "@as", &sub)) |
4264 | + { |
4265 | + gchar *str = g_variant_print (sub, TRUE); |
4266 | + g_assert_cmpstr (str, ==, |
4267 | + "['i', 'ii', 'iii', 'iv', 'v', 'vi']"); |
4268 | + g_free (str); |
4269 | + } |
4270 | + |
4271 | + g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, |
4272 | + "*NULL has already been returned*"); |
4273 | + g_variant_iter_next_value (&iter); |
4274 | + g_test_assert_expected_messages (); |
4275 | + |
4276 | + while (g_variant_iter_loop (i3, "*", &sub)) |
4277 | + { |
4278 | + gchar *str = g_variant_print (sub, TRUE); |
4279 | + g_assert_cmpstr (str, ==, |
4280 | + "['i', 'ii', 'iii', 'iv', 'v', 'vi']"); |
4281 | + g_free (str); |
4282 | + } |
4283 | + |
4284 | + g_variant_iter_free (i3); |
4285 | + |
4286 | + for (i = 0; i < g_variant_n_children (value); i++) |
4287 | + { |
4288 | + gint j; |
4289 | + |
4290 | + g_variant_get_child (value, i, "*", &sub); |
4291 | + |
4292 | + for (j = 0; j < g_variant_n_children (sub); j++) |
4293 | + { |
4294 | + const gchar *str = NULL; |
4295 | + GVariant *cval; |
4296 | + |
4297 | + g_variant_get_child (sub, j, "&s", &str); |
4298 | + g_assert_cmpstr (str, ==, strvector[j]); |
4299 | + |
4300 | + cval = g_variant_get_child_value (sub, j); |
4301 | + g_variant_get (cval, "&s", &str); |
4302 | + g_assert_cmpstr (str, ==, strvector[j]); |
4303 | + g_variant_unref (cval); |
4304 | + } |
4305 | + |
4306 | + g_variant_unref (sub); |
4307 | + } |
4308 | + |
4309 | + g_variant_unref (value); |
4310 | + } |
4311 | + |
4312 | + { |
4313 | + gboolean justs[10]; |
4314 | + GVariant *value; |
4315 | + |
4316 | + GVariant *vval; |
4317 | + guchar byteval; |
4318 | + gboolean bval; |
4319 | + gint16 i16val; |
4320 | + guint16 u16val; |
4321 | + gint32 i32val; |
4322 | + guint32 u32val; |
4323 | + gint64 i64val; |
4324 | + guint64 u64val; |
4325 | + gdouble dval; |
4326 | + gint32 hval; |
4327 | + |
4328 | + /* test all 'nothing' */ |
4329 | + value = g_variant_new ("(mymbmnmqmimumxmtmhmdmv)", |
4330 | + FALSE, 'a', |
4331 | + FALSE, TRUE, |
4332 | + FALSE, (gint16) 123, |
4333 | + FALSE, (guint16) 123, |
4334 | + FALSE, (gint32) 123, |
4335 | + FALSE, (guint32) 123, |
4336 | + FALSE, (gint64) 123, |
4337 | + FALSE, (guint64) 123, |
4338 | + FALSE, (gint32) -1, |
4339 | + FALSE, (gdouble) 37.5, |
4340 | + NULL); |
4341 | + |
4342 | + /* both NULL */ |
4343 | + g_variant_get (value, "(mymbmnmqmimumxmtmhmdmv)", |
4344 | + NULL, NULL, |
4345 | + NULL, NULL, |
4346 | + NULL, NULL, |
4347 | + NULL, NULL, |
4348 | + NULL, NULL, |
4349 | + NULL, NULL, |
4350 | + NULL, NULL, |
4351 | + NULL, NULL, |
4352 | + NULL, NULL, |
4353 | + NULL, NULL, |
4354 | + NULL); |
4355 | + |
4356 | + /* NULL values */ |
4357 | + memset (justs, 1, sizeof justs); |
4358 | + g_variant_get (value, "(mymbmnmqmimumxmtmhmdmv)", |
4359 | + &justs[0], NULL, |
4360 | + &justs[1], NULL, |
4361 | + &justs[2], NULL, |
4362 | + &justs[3], NULL, |
4363 | + &justs[4], NULL, |
4364 | + &justs[5], NULL, |
4365 | + &justs[6], NULL, |
4366 | + &justs[7], NULL, |
4367 | + &justs[8], NULL, |
4368 | + &justs[9], NULL, |
4369 | + NULL); |
4370 | + g_assert (!(justs[0] || justs[1] || justs[2] || justs[3] || justs[4] || |
4371 | + justs[5] || justs[6] || justs[7] || justs[8] || justs[9])); |
4372 | + |
4373 | + /* both non-NULL */ |
4374 | + memset (justs, 1, sizeof justs); |
4375 | + byteval = i16val = u16val = i32val = u32val = i64val = u64val = hval = 88; |
4376 | + vval = (void *) 1; |
4377 | + bval = TRUE; |
4378 | + dval = 88.88; |
4379 | + g_variant_get (value, "(mymbmnmqmimumxmtmhmdmv)", |
4380 | + &justs[0], &byteval, |
4381 | + &justs[1], &bval, |
4382 | + &justs[2], &i16val, |
4383 | + &justs[3], &u16val, |
4384 | + &justs[4], &i32val, |
4385 | + &justs[5], &u32val, |
4386 | + &justs[6], &i64val, |
4387 | + &justs[7], &u64val, |
4388 | + &justs[8], &hval, |
4389 | + &justs[9], &dval, |
4390 | + &vval); |
4391 | + g_assert (!(justs[0] || justs[1] || justs[2] || justs[3] || justs[4] || |
4392 | + justs[5] || justs[6] || justs[7] || justs[8] || justs[9])); |
4393 | + g_assert (byteval == '\0' && bval == FALSE); |
4394 | + g_assert (i16val == 0 && u16val == 0 && i32val == 0 && |
4395 | + u32val == 0 && i64val == 0 && u64val == 0 && |
4396 | + hval == 0 && dval == 0.0); |
4397 | + g_assert (vval == NULL); |
4398 | + |
4399 | + /* NULL justs */ |
4400 | + byteval = i16val = u16val = i32val = u32val = i64val = u64val = hval = 88; |
4401 | + vval = (void *) 1; |
4402 | + bval = TRUE; |
4403 | + dval = 88.88; |
4404 | + g_variant_get (value, "(mymbmnmqmimumxmtmhmdmv)", |
4405 | + NULL, &byteval, |
4406 | + NULL, &bval, |
4407 | + NULL, &i16val, |
4408 | + NULL, &u16val, |
4409 | + NULL, &i32val, |
4410 | + NULL, &u32val, |
4411 | + NULL, &i64val, |
4412 | + NULL, &u64val, |
4413 | + NULL, &hval, |
4414 | + NULL, &dval, |
4415 | + &vval); |
4416 | + g_assert (byteval == '\0' && bval == FALSE); |
4417 | + g_assert (i16val == 0 && u16val == 0 && i32val == 0 && |
4418 | + u32val == 0 && i64val == 0 && u64val == 0 && |
4419 | + hval == 0 && dval == 0.0); |
4420 | + g_assert (vval == NULL); |
4421 | + |
4422 | + g_variant_unref (value); |
4423 | + |
4424 | + |
4425 | + /* test all 'just' */ |
4426 | + value = g_variant_new ("(mymbmnmqmimumxmtmhmdmv)", |
4427 | + TRUE, 'a', |
4428 | + TRUE, TRUE, |
4429 | + TRUE, (gint16) 123, |
4430 | + TRUE, (guint16) 123, |
4431 | + TRUE, (gint32) 123, |
4432 | + TRUE, (guint32) 123, |
4433 | + TRUE, (gint64) 123, |
4434 | + TRUE, (guint64) 123, |
4435 | + TRUE, (gint32) -1, |
4436 | + TRUE, (gdouble) 37.5, |
4437 | + g_variant_new ("()")); |
4438 | + |
4439 | + /* both NULL */ |
4440 | + g_variant_get (value, "(mymbmnmqmimumxmtmhmdmv)", |
4441 | + NULL, NULL, |
4442 | + NULL, NULL, |
4443 | + NULL, NULL, |
4444 | + NULL, NULL, |
4445 | + NULL, NULL, |
4446 | + NULL, NULL, |
4447 | + NULL, NULL, |
4448 | + NULL, NULL, |
4449 | + NULL, NULL, |
4450 | + NULL, NULL, |
4451 | + NULL); |
4452 | + |
4453 | + /* NULL values */ |
4454 | + memset (justs, 0, sizeof justs); |
4455 | + g_variant_get (value, "(mymbmnmqmimumxmtmhmdmv)", |
4456 | + &justs[0], NULL, |
4457 | + &justs[1], NULL, |
4458 | + &justs[2], NULL, |
4459 | + &justs[3], NULL, |
4460 | + &justs[4], NULL, |
4461 | + &justs[5], NULL, |
4462 | + &justs[6], NULL, |
4463 | + &justs[7], NULL, |
4464 | + &justs[8], NULL, |
4465 | + &justs[9], NULL, |
4466 | + NULL); |
4467 | + g_assert (justs[0] && justs[1] && justs[2] && justs[3] && justs[4] && |
4468 | + justs[5] && justs[6] && justs[7] && justs[8] && justs[9]); |
4469 | + |
4470 | + /* both non-NULL */ |
4471 | + memset (justs, 0, sizeof justs); |
4472 | + byteval = i16val = u16val = i32val = u32val = i64val = u64val = hval = 88; |
4473 | + vval = (void *) 1; |
4474 | + bval = FALSE; |
4475 | + dval = 88.88; |
4476 | + g_variant_get (value, "(mymbmnmqmimumxmtmhmdmv)", |
4477 | + &justs[0], &byteval, |
4478 | + &justs[1], &bval, |
4479 | + &justs[2], &i16val, |
4480 | + &justs[3], &u16val, |
4481 | + &justs[4], &i32val, |
4482 | + &justs[5], &u32val, |
4483 | + &justs[6], &i64val, |
4484 | + &justs[7], &u64val, |
4485 | + &justs[8], &hval, |
4486 | + &justs[9], &dval, |
4487 | + &vval); |
4488 | + g_assert (justs[0] && justs[1] && justs[2] && justs[3] && justs[4] && |
4489 | + justs[5] && justs[6] && justs[7] && justs[8] && justs[9]); |
4490 | + g_assert (byteval == 'a' && bval == TRUE); |
4491 | + g_assert (i16val == 123 && u16val == 123 && i32val == 123 && |
4492 | + u32val == 123 && i64val == 123 && u64val == 123 && |
4493 | + hval == -1 && dval == 37.5); |
4494 | + g_assert (g_variant_is_of_type (vval, G_VARIANT_TYPE_UNIT)); |
4495 | + g_variant_unref (vval); |
4496 | + |
4497 | + /* NULL justs */ |
4498 | + byteval = i16val = u16val = i32val = u32val = i64val = u64val = hval = 88; |
4499 | + vval = (void *) 1; |
4500 | + bval = TRUE; |
4501 | + dval = 88.88; |
4502 | + g_variant_get (value, "(mymbmnmqmimumxmtmhmdmv)", |
4503 | + NULL, &byteval, |
4504 | + NULL, &bval, |
4505 | + NULL, &i16val, |
4506 | + NULL, &u16val, |
4507 | + NULL, &i32val, |
4508 | + NULL, &u32val, |
4509 | + NULL, &i64val, |
4510 | + NULL, &u64val, |
4511 | + NULL, &hval, |
4512 | + NULL, &dval, |
4513 | + &vval); |
4514 | + g_assert (byteval == 'a' && bval == TRUE); |
4515 | + g_assert (i16val == 123 && u16val == 123 && i32val == 123 && |
4516 | + u32val == 123 && i64val == 123 && u64val == 123 && |
4517 | + hval == -1 && dval == 37.5); |
4518 | + g_assert (g_variant_is_of_type (vval, G_VARIANT_TYPE_UNIT)); |
4519 | + g_variant_unref (vval); |
4520 | + |
4521 | + g_variant_unref (value); |
4522 | + } |
4523 | + |
4524 | + { |
4525 | + GVariant *value; |
4526 | + gchar *str; |
4527 | + |
4528 | + value = g_variant_new ("(masas)", NULL, NULL); |
4529 | + g_variant_ref_sink (value); |
4530 | + |
4531 | + str = g_variant_print (value, TRUE); |
4532 | + g_assert_cmpstr (str, ==, "(@mas nothing, @as [])"); |
4533 | + g_variant_unref (value); |
4534 | + g_free (str); |
4535 | + |
4536 | + if (do_failed_test ("*which type of empty array*")) |
4537 | + g_variant_new ("(a{s*})", NULL); |
4538 | + } |
4539 | + |
4540 | + g_variant_type_info_assert_no_infos (); |
4541 | +} |
4542 | + |
4543 | +static void |
4544 | +hash_get (GVariant *value, |
4545 | + const gchar *format, |
4546 | + ...) |
4547 | +{ |
4548 | + const gchar *endptr = NULL; |
4549 | + gboolean hash; |
4550 | + va_list ap; |
4551 | + |
4552 | + hash = g_str_has_suffix (format, "#"); |
4553 | + |
4554 | + va_start (ap, format); |
4555 | + g_variant_get_va (value, format, hash ? &endptr : NULL, &ap); |
4556 | + va_end (ap); |
4557 | + |
4558 | + if (hash) |
4559 | + g_assert (*endptr == '#'); |
4560 | +} |
4561 | + |
4562 | +static GVariant * |
4563 | +hash_new (const gchar *format, |
4564 | + ...) |
4565 | +{ |
4566 | + const gchar *endptr = NULL; |
4567 | + GVariant *value; |
4568 | + gboolean hash; |
4569 | + va_list ap; |
4570 | + |
4571 | + hash = g_str_has_suffix (format, "#"); |
4572 | + |
4573 | + va_start (ap, format); |
4574 | + value = g_variant_new_va (format, hash ? &endptr : NULL, &ap); |
4575 | + va_end (ap); |
4576 | + |
4577 | + if (hash) |
4578 | + g_assert (*endptr == '#'); |
4579 | + |
4580 | + return value; |
4581 | +} |
4582 | + |
4583 | +static void |
4584 | +test_valist (void) |
4585 | +{ |
4586 | + GVariant *value; |
4587 | + gint32 x; |
4588 | + |
4589 | + x = 0; |
4590 | + value = hash_new ("i", 234); |
4591 | + hash_get (value, "i", &x); |
4592 | + g_assert (x == 234); |
4593 | + g_variant_unref (value); |
4594 | + |
4595 | + x = 0; |
4596 | + value = hash_new ("i#", 234); |
4597 | + hash_get (value, "i#", &x); |
4598 | + g_assert (x == 234); |
4599 | + g_variant_unref (value); |
4600 | + |
4601 | + g_variant_type_info_assert_no_infos (); |
4602 | +} |
4603 | + |
4604 | +static void |
4605 | +test_builder_memory (void) |
4606 | +{ |
4607 | + GVariantBuilder *hb; |
4608 | + GVariantBuilder sb; |
4609 | + |
4610 | + hb = g_variant_builder_new (G_VARIANT_TYPE_ARRAY); |
4611 | + g_variant_builder_open (hb, G_VARIANT_TYPE_ARRAY); |
4612 | + g_variant_builder_open (hb, G_VARIANT_TYPE_ARRAY); |
4613 | + g_variant_builder_open (hb, G_VARIANT_TYPE_ARRAY); |
4614 | + g_variant_builder_add (hb, "s", "some value"); |
4615 | + g_variant_builder_ref (hb); |
4616 | + g_variant_builder_unref (hb); |
4617 | + g_variant_builder_unref (hb); |
4618 | + |
4619 | + hb = g_variant_builder_new (G_VARIANT_TYPE_ARRAY); |
4620 | + g_variant_builder_unref (hb); |
4621 | + |
4622 | + hb = g_variant_builder_new (G_VARIANT_TYPE_ARRAY); |
4623 | + g_variant_builder_clear (hb); |
4624 | + g_variant_builder_unref (hb); |
4625 | + |
4626 | + g_variant_builder_init (&sb, G_VARIANT_TYPE_ARRAY); |
4627 | + g_variant_builder_open (&sb, G_VARIANT_TYPE_ARRAY); |
4628 | + g_variant_builder_open (&sb, G_VARIANT_TYPE_ARRAY); |
4629 | + g_variant_builder_add (&sb, "s", "some value"); |
4630 | + g_variant_builder_clear (&sb); |
4631 | + |
4632 | + g_variant_type_info_assert_no_infos (); |
4633 | +} |
4634 | + |
4635 | +static void |
4636 | +test_hashing (void) |
4637 | +{ |
4638 | + GVariant *items[4096]; |
4639 | + GHashTable *table; |
4640 | + gint i; |
4641 | + |
4642 | + table = g_hash_table_new_full (g_variant_hash, g_variant_equal, |
4643 | + (GDestroyNotify ) g_variant_unref, |
4644 | + NULL); |
4645 | + |
4646 | + for (i = 0; i < G_N_ELEMENTS (items); i++) |
4647 | + { |
4648 | + TreeInstance *tree; |
4649 | + gint j; |
4650 | + |
4651 | + again: |
4652 | + tree = tree_instance_new (NULL, 0); |
4653 | + items[i] = tree_instance_get_gvariant (tree); |
4654 | + tree_instance_free (tree); |
4655 | + |
4656 | + for (j = 0; j < i; j++) |
4657 | + if (g_variant_equal (items[i], items[j])) |
4658 | + { |
4659 | + g_variant_unref (items[i]); |
4660 | + goto again; |
4661 | + } |
4662 | + |
4663 | + g_hash_table_insert (table, |
4664 | + g_variant_ref_sink (items[i]), |
4665 | + GINT_TO_POINTER (i)); |
4666 | + } |
4667 | + |
4668 | + for (i = 0; i < G_N_ELEMENTS (items); i++) |
4669 | + { |
4670 | + gpointer result; |
4671 | + |
4672 | + result = g_hash_table_lookup (table, items[i]); |
4673 | + g_assert_cmpint (GPOINTER_TO_INT (result), ==, i); |
4674 | + } |
4675 | + |
4676 | + g_hash_table_unref (table); |
4677 | + |
4678 | + g_variant_type_info_assert_no_infos (); |
4679 | +} |
4680 | + |
4681 | +static void |
4682 | +test_gv_byteswap (void) |
4683 | +{ |
4684 | +#if G_BYTE_ORDER == G_LITTLE_ENDIAN |
4685 | +# define native16(x) x, 0 |
4686 | +# define swapped16(x) 0, x |
4687 | +#else |
4688 | +# define native16(x) 0, x |
4689 | +# define swapped16(x) x, 0 |
4690 | +#endif |
4691 | + /* all kinds of of crazy randomised testing already performed on the |
4692 | + * byteswapper in the /gvariant/serialiser/byteswap test and all kinds |
4693 | + * of crazy randomised testing performed against the serialiser |
4694 | + * normalisation functions in the /gvariant/serialiser/fuzz/ tests. |
4695 | + * |
4696 | + * just test a few simple cases here to make sure they each work |
4697 | + */ |
4698 | + guchar validbytes[] = { 'a', '\0', swapped16(66), 2, |
4699 | + 0, |
4700 | + 'b', '\0', swapped16(77), 2, |
4701 | + 5, 11 }; |
4702 | + guchar corruptbytes[] = { 'a', '\0', swapped16(66), 2, |
4703 | + 0, |
4704 | + 'b', '\0', swapped16(77), 2, |
4705 | + 6, 11 }; |
4706 | + guint valid_data[4], corrupt_data[4]; |
4707 | + GVariant *value, *swapped; |
4708 | + gchar *string, *string2; |
4709 | + |
4710 | + memcpy (valid_data, validbytes, sizeof validbytes); |
4711 | + memcpy (corrupt_data, corruptbytes, sizeof corruptbytes); |
4712 | + |
4713 | + /* trusted */ |
4714 | + value = g_variant_new_from_data (G_VARIANT_TYPE ("a(sn)"), |
4715 | + valid_data, sizeof validbytes, TRUE, |
4716 | + NULL, NULL); |
4717 | + swapped = g_variant_byteswap (value); |
4718 | + g_variant_unref (value); |
4719 | + g_assert (g_variant_get_size (swapped) == 13); |
4720 | + string = g_variant_print (swapped, FALSE); |
4721 | + g_variant_unref (swapped); |
4722 | + g_assert_cmpstr (string, ==, "[('a', 66), ('b', 77)]"); |
4723 | + g_free (string); |
4724 | + |
4725 | + /* untrusted but valid */ |
4726 | + value = g_variant_new_from_data (G_VARIANT_TYPE ("a(sn)"), |
4727 | + valid_data, sizeof validbytes, FALSE, |
4728 | + NULL, NULL); |
4729 | + swapped = g_variant_byteswap (value); |
4730 | + g_variant_unref (value); |
4731 | + g_assert (g_variant_get_size (swapped) == 13); |
4732 | + string = g_variant_print (swapped, FALSE); |
4733 | + g_variant_unref (swapped); |
4734 | + g_assert_cmpstr (string, ==, "[('a', 66), ('b', 77)]"); |
4735 | + g_free (string); |
4736 | + |
4737 | + /* untrusted, invalid */ |
4738 | + value = g_variant_new_from_data (G_VARIANT_TYPE ("a(sn)"), |
4739 | + corrupt_data, sizeof corruptbytes, FALSE, |
4740 | + NULL, NULL); |
4741 | + string = g_variant_print (value, FALSE); |
4742 | + swapped = g_variant_byteswap (value); |
4743 | + g_variant_unref (value); |
4744 | + g_assert (g_variant_get_size (swapped) == 13); |
4745 | + value = g_variant_byteswap (swapped); |
4746 | + g_variant_unref (swapped); |
4747 | + string2 = g_variant_print (value, FALSE); |
4748 | + g_assert (g_variant_get_size (value) == 13); |
4749 | + g_variant_unref (value); |
4750 | + g_assert_cmpstr (string, ==, string2); |
4751 | + g_free (string2); |
4752 | + g_free (string); |
4753 | +} |
4754 | + |
4755 | +static void |
4756 | +test_parser (void) |
4757 | +{ |
4758 | + TreeInstance *tree; |
4759 | + GVariant *parsed; |
4760 | + GVariant *value; |
4761 | + gchar *pt, *p; |
4762 | + gchar *res; |
4763 | + |
4764 | + tree = tree_instance_new (NULL, 3); |
4765 | + value = tree_instance_get_gvariant (tree); |
4766 | + tree_instance_free (tree); |
4767 | + |
4768 | + pt = g_variant_print (value, TRUE); |
4769 | + p = g_variant_print (value, FALSE); |
4770 | + |
4771 | + parsed = g_variant_parse (NULL, pt, NULL, NULL, NULL); |
4772 | + res = g_variant_print (parsed, FALSE); |
4773 | + g_assert_cmpstr (p, ==, res); |
4774 | + g_variant_unref (parsed); |
4775 | + g_free (res); |
4776 | + |
4777 | + parsed = g_variant_parse (g_variant_get_type (value), p, |
4778 | + NULL, NULL, NULL); |
4779 | + res = g_variant_print (parsed, TRUE); |
4780 | + g_assert_cmpstr (pt, ==, res); |
4781 | + g_variant_unref (parsed); |
4782 | + g_free (res); |
4783 | + |
4784 | + g_variant_unref (value); |
4785 | + g_free (pt); |
4786 | + g_free (p); |
4787 | +} |
4788 | + |
4789 | +static void |
4790 | +test_parses (void) |
4791 | +{ |
4792 | + gint i; |
4793 | + |
4794 | + for (i = 0; i < 100; i++) |
4795 | + { |
4796 | + test_parser (); |
4797 | + } |
4798 | + |
4799 | + /* mini test */ |
4800 | + { |
4801 | + GError *error = NULL; |
4802 | + gchar str[128]; |
4803 | + GVariant *val; |
4804 | + gchar *p, *p2; |
4805 | + |
4806 | + for (i = 0; i < 127; i++) |
4807 | + str[i] = i + 1; |
4808 | + str[i] = 0; |
4809 | + |
4810 | + val = g_variant_new_string (str); |
4811 | + p = g_variant_print (val, FALSE); |
4812 | + g_variant_unref (val); |
4813 | + |
4814 | + val = g_variant_parse (NULL, p, NULL, NULL, &error); |
4815 | + p2 = g_variant_print (val, FALSE); |
4816 | + |
4817 | + g_assert_cmpstr (str, ==, g_variant_get_string (val, NULL)); |
4818 | + g_assert_cmpstr (p, ==, p2); |
4819 | + |
4820 | + g_variant_unref (val); |
4821 | + g_free (p2); |
4822 | + g_free (p); |
4823 | + } |
4824 | + |
4825 | + /* another mini test */ |
4826 | + { |
4827 | + const gchar *end; |
4828 | + GVariant *value; |
4829 | + |
4830 | + value = g_variant_parse (G_VARIANT_TYPE_INT32, "1 2 3", NULL, &end, NULL); |
4831 | + g_assert_cmpint (g_variant_get_int32 (value), ==, 1); |
4832 | + /* make sure endptr returning works */ |
4833 | + g_assert_cmpstr (end, ==, " 2 3"); |
4834 | + g_variant_unref (value); |
4835 | + } |
4836 | + |
4837 | + /* unicode mini test */ |
4838 | + { |
4839 | + /* ał𝄞 */ |
4840 | + const gchar orig[] = "a\xc5\x82\xf0\x9d\x84\x9e \t\n"; |
4841 | + GVariant *value; |
4842 | + gchar *printed; |
4843 | + |
4844 | + value = g_variant_new_string (orig); |
4845 | + printed = g_variant_print (value, FALSE); |
4846 | + g_variant_unref (value); |
4847 | + |
4848 | + g_assert_cmpstr (printed, ==, "'a\xc5\x82\xf0\x9d\x84\x9e \\t\\n'"); |
4849 | + value = g_variant_parse (NULL, printed, NULL, NULL, NULL); |
4850 | + g_assert_cmpstr (g_variant_get_string (value, NULL), ==, orig); |
4851 | + g_variant_unref (value); |
4852 | + g_free (printed); |
4853 | + } |
4854 | + |
4855 | + /* inf/nan mini test */ |
4856 | + { |
4857 | + const gchar *tests[] = { "inf", "-inf", "nan" }; |
4858 | + GVariant *value; |
4859 | + gchar *printed; |
4860 | + gint i; |
4861 | + |
4862 | + for (i = 0; i < G_N_ELEMENTS (tests); i++) |
4863 | + { |
4864 | + GError *error = NULL; |
4865 | + value = g_variant_parse (NULL, tests[i], NULL, NULL, &error); |
4866 | + printed = g_variant_print (value, FALSE); |
4867 | + g_assert (g_str_has_prefix (printed, tests[i])); |
4868 | + g_free (printed); |
4869 | + g_variant_unref (value); |
4870 | + } |
4871 | + } |
4872 | + |
4873 | + g_variant_type_info_assert_no_infos (); |
4874 | +} |
4875 | + |
4876 | +static void |
4877 | +test_parse_failures (void) |
4878 | +{ |
4879 | + const gchar *test[] = { |
4880 | + "[1, 2,", "6:", "expected value", |
4881 | + "", "0:", "expected value", |
4882 | + "(1, 2,", "6:", "expected value", |
4883 | + "<1", "2:", "expected `>'", |
4884 | + "[]", "0-2:", "unable to infer", |
4885 | + "(,", "1:", "expected value", |
4886 | + "[4,'']", "1-2,3-5:", "common type", |
4887 | + "[4, '', 5]", "1-2,4-6:", "common type", |
4888 | + "['', 4, 5]", "1-3,5-6:", "common type", |
4889 | + "[4, 5, '']", "1-2,7-9:", "common type", |
4890 | + "[[4], [], ['']]", "1-4,10-14:", "common type", |
4891 | + "[[], [4], ['']]", "5-8,10-14:", "common type", |
4892 | + "just", "4:", "expected value", |
4893 | + "nothing", "0-7:", "unable to infer", |
4894 | + "just [4, '']", "6-7,9-11:", "common type", |
4895 | + "[[4,'']]", "2-3,4-6:", "common type", |
4896 | + "([4,''],)", "2-3,4-6:", "common type", |
4897 | + "(4)", "2:", "`,'", |
4898 | + "{}", "0-2:", "unable to infer", |
4899 | + "{[1,2],[3,4]}", "0-13:", "basic types", |
4900 | + "{[1,2]:[3,4]}", "0-13:", "basic types", |
4901 | + "justt", "0-5:", "unknown keyword", |
4902 | + "nothng", "0-6:", "unknown keyword", |
4903 | + "uint33", "0-6:", "unknown keyword", |
4904 | + "@mi just ''", "9-11:", "can not parse as", |
4905 | + "@ai ['']", "5-7:", "can not parse as", |
4906 | + "@(i) ('',)", "6-8:", "can not parse as", |
4907 | + "[[], 5]", "1-3,5-6:", "common type", |
4908 | + "[[5], 5]", "1-4,6-7:", "common type", |
4909 | + "5 5", "2:", "expected end of input", |
4910 | + "[5, [5, '']]", "5-6,8-10:", "common type", |
4911 | + "@i just 5", "3-9:", "can not parse as", |
4912 | + "@i nothing", "3-10:", "can not parse as", |
4913 | + "@i []", "3-5:", "can not parse as", |
4914 | + "@i ()", "3-5:", "can not parse as", |
4915 | + "@ai (4,)", "4-8:", "can not parse as", |
4916 | + "@(i) []", "5-7:", "can not parse as", |
4917 | + "(5 5)", "3:", "expected `,'", |
4918 | + "[5 5]", "3:", "expected `,' or `]'", |
4919 | + "(5, 5 5)", "6:", "expected `,' or `)'", |
4920 | + "[5, 5 5]", "6:", "expected `,' or `]'", |
4921 | + "<@i []>", "4-6:", "can not parse as", |
4922 | + "<[5 5]>", "4:", "expected `,' or `]'", |
4923 | + "{[4,''],5}", "2-3,4-6:", "common type", |
4924 | + "{5,[4,'']}", "4-5,6-8:", "common type", |
4925 | + "@i {1,2}", "3-8:", "can not parse as", |
4926 | + "{@i '', 5}", "4-6:", "can not parse as", |
4927 | + "{5, @i ''}", "7-9:", "can not parse as", |
4928 | + "@ai {}", "4-6:", "can not parse as", |
4929 | + "{@i '': 5}", "4-6:", "can not parse as", |
4930 | + "{5: @i ''}", "7-9:", "can not parse as", |
4931 | + "{<4,5}", "3:", "expected `>'", |
4932 | + "{4,<5}", "5:", "expected `>'", |
4933 | + "{4,5,6}", "4:", "expected `}'", |
4934 | + "{5 5}", "3:", "expected `:' or `,'", |
4935 | + "{4: 5: 6}", "5:", "expected `,' or `}'", |
4936 | + "{4:5,<6:7}", "7:", "expected `>'", |
4937 | + "{4:5,6:<7}", "9:", "expected `>'", |
4938 | + "{4:5,6 7}", "7:", "expected `:'", |
4939 | + "@o 'foo'", "3-8:", "object path", |
4940 | + "@g 'zzz'", "3-8:", "signature", |
4941 | + "@i true", "3-7:", "can not parse as", |
4942 | + "@z 4", "0-2:", "invalid type", |
4943 | + "@a* []", "0-3:", "definite", |
4944 | + "@ai [3 3]", "7:", "expected `,' or `]'", |
4945 | + "18446744073709551616", "0-20:", "too big for any type", |
4946 | + "-18446744073709551616", "0-21:", "too big for any type", |
4947 | + "byte 256", "5-8:", "out of range for type", |
4948 | + "byte -1", "5-7:", "out of range for type", |
4949 | + "int16 32768", "6-11:", "out of range for type", |
4950 | + "int16 -32769", "6-12:", "out of range for type", |
4951 | + "uint16 -1", "7-9:", "out of range for type", |
4952 | + "uint16 65536", "7-12:", "out of range for type", |
4953 | + "2147483648", "0-10:", "out of range for type", |
4954 | + "-2147483649", "0-11:", "out of range for type", |
4955 | + "uint32 -1", "7-9:", "out of range for type", |
4956 | + "uint32 4294967296", "7-17:", "out of range for type", |
4957 | + "@x 9223372036854775808", "3-22:", "out of range for type", |
4958 | + "@x -9223372036854775809", "3-23:", "out of range for type", |
4959 | + "@t -1", "3-5:", "out of range for type", |
4960 | + "@t 18446744073709551616", "3-23:", "too big for any type", |
4961 | + "handle 2147483648", "7-17:", "out of range for type", |
4962 | + "handle -2147483649", "7-18:", "out of range for type", |
4963 | + "1.798e308", "0-9:", "too big for any type", |
4964 | + "37.5a488", "4-5:", "invalid character", |
4965 | + "0x7ffgf", "5-6:", "invalid character", |
4966 | + "07758", "4-5:", "invalid character", |
4967 | + "123a5", "3-4:", "invalid character", |
4968 | + "@ai 123", "4-7:", "can not parse as", |
4969 | + "'\"\\'", "0-4:", "unterminated string", |
4970 | + "'\"\\'\\", "0-5:", "unterminated string", |
4971 | + "boolean 4", "8-9:", "can not parse as", |
4972 | + "int32 true", "6-10:", "can not parse as", |
4973 | + "[double 5, int32 5]", "1-9,11-18:", "common type", |
4974 | + "string 4", "7-8:", "can not parse as" |
4975 | + }; |
4976 | + gint i; |
4977 | + |
4978 | + for (i = 0; i < G_N_ELEMENTS (test); i += 3) |
4979 | + { |
4980 | + GError *error = NULL; |
4981 | + GVariant *value; |
4982 | + |
4983 | + value = g_variant_parse (NULL, test[i], NULL, NULL, &error); |
4984 | + g_assert (value == NULL); |
4985 | + |
4986 | + if (!strstr (error->message, test[i+2])) |
4987 | + g_error ("test %d: Can't find `%s' in `%s'", i / 3, |
4988 | + test[i+2], error->message); |
4989 | + |
4990 | + if (!g_str_has_prefix (error->message, test[i+1])) |
4991 | + g_error ("test %d: Expected location `%s' in `%s'", i / 3, |
4992 | + test[i+1], error->message); |
4993 | + |
4994 | + g_error_free (error); |
4995 | + } |
4996 | +} |
4997 | + |
4998 | +static void |
4999 | +test_parse_positional (void) |
5000 | +{ |
The diff has been truncated for viewing.
thanks, setting as "merged" since we got the new glib