]>
Commit | Line | Data |
---|---|---|
fb08dde0 | 1 | /* |
41836a9f | 2 | * QDict Module |
fb08dde0 LC |
3 | * |
4 | * Copyright (C) 2009 Red Hat Inc. | |
5 | * | |
6 | * Authors: | |
7 | * Luiz Capitulino <lcapitulino@redhat.com> | |
8 | * | |
41836a9f LC |
9 | * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. |
10 | * See the COPYING.LIB file in the top-level directory. | |
fb08dde0 LC |
11 | */ |
12 | ||
f2ad72b3 | 13 | #include "qemu/osdep.h" |
01b2ffce | 14 | #include "qapi/qmp/qnum.h" |
7b1b5d19 PB |
15 | #include "qapi/qmp/qdict.h" |
16 | #include "qapi/qmp/qbool.h" | |
47e6b297 | 17 | #include "qapi/qmp/qlist.h" |
15280c36 | 18 | #include "qapi/qmp/qnull.h" |
7b1b5d19 | 19 | #include "qapi/qmp/qstring.h" |
603476c2 | 20 | #include "qapi/error.h" |
1de7afc9 | 21 | #include "qemu/queue.h" |
fb08dde0 | 22 | #include "qemu-common.h" |
f348b6d1 | 23 | #include "qemu/cutils.h" |
fb08dde0 | 24 | |
fb08dde0 LC |
25 | /** |
26 | * qdict_new(): Create a new QDict | |
27 | * | |
28 | * Return strong reference. | |
29 | */ | |
30 | QDict *qdict_new(void) | |
31 | { | |
32 | QDict *qdict; | |
33 | ||
7267c094 | 34 | qdict = g_malloc0(sizeof(*qdict)); |
55e1819c | 35 | qobject_init(QOBJECT(qdict), QTYPE_QDICT); |
fb08dde0 LC |
36 | |
37 | return qdict; | |
38 | } | |
39 | ||
fb08dde0 LC |
40 | /** |
41 | * tdb_hash(): based on the hash agorithm from gdbm, via tdb | |
42 | * (from module-init-tools) | |
43 | */ | |
44 | static unsigned int tdb_hash(const char *name) | |
45 | { | |
46 | unsigned value; /* Used to compute the hash value. */ | |
47 | unsigned i; /* Used to cycle through random values. */ | |
48 | ||
49 | /* Set the initial value from the key size. */ | |
50 | for (value = 0x238F13AF * strlen(name), i=0; name[i]; i++) | |
51 | value = (value + (((const unsigned char *)name)[i] << (i*5 % 24))); | |
52 | ||
53 | return (1103515243 * value + 12345); | |
54 | } | |
55 | ||
56 | /** | |
57 | * alloc_entry(): allocate a new QDictEntry | |
58 | */ | |
59 | static QDictEntry *alloc_entry(const char *key, QObject *value) | |
60 | { | |
61 | QDictEntry *entry; | |
62 | ||
7267c094 AL |
63 | entry = g_malloc0(sizeof(*entry)); |
64 | entry->key = g_strdup(key); | |
fb08dde0 LC |
65 | entry->value = value; |
66 | ||
67 | return entry; | |
68 | } | |
69 | ||
0d078b2a LC |
70 | /** |
71 | * qdict_entry_value(): Return qdict entry value | |
72 | * | |
73 | * Return weak reference. | |
74 | */ | |
75 | QObject *qdict_entry_value(const QDictEntry *entry) | |
76 | { | |
77 | return entry->value; | |
78 | } | |
79 | ||
80 | /** | |
81 | * qdict_entry_key(): Return qdict entry key | |
82 | * | |
83 | * Return a *pointer* to the string, it has to be duplicated before being | |
84 | * stored. | |
85 | */ | |
86 | const char *qdict_entry_key(const QDictEntry *entry) | |
87 | { | |
88 | return entry->key; | |
89 | } | |
90 | ||
fb08dde0 LC |
91 | /** |
92 | * qdict_find(): List lookup function | |
93 | */ | |
94 | static QDictEntry *qdict_find(const QDict *qdict, | |
c8bc3cd7 | 95 | const char *key, unsigned int bucket) |
fb08dde0 LC |
96 | { |
97 | QDictEntry *entry; | |
98 | ||
c8bc3cd7 | 99 | QLIST_FOREACH(entry, &qdict->table[bucket], next) |
fb08dde0 LC |
100 | if (!strcmp(entry->key, key)) |
101 | return entry; | |
102 | ||
103 | return NULL; | |
104 | } | |
105 | ||
106 | /** | |
107 | * qdict_put_obj(): Put a new QObject into the dictionary | |
108 | * | |
109 | * Insert the pair 'key:value' into 'qdict', if 'key' already exists | |
110 | * its 'value' will be replaced. | |
111 | * | |
112 | * This is done by freeing the reference to the stored QObject and | |
113 | * storing the new one in the same entry. | |
114 | * | |
115 | * NOTE: ownership of 'value' is transferred to the QDict | |
116 | */ | |
117 | void qdict_put_obj(QDict *qdict, const char *key, QObject *value) | |
118 | { | |
c8bc3cd7 | 119 | unsigned int bucket; |
fb08dde0 LC |
120 | QDictEntry *entry; |
121 | ||
c8bc3cd7 LC |
122 | bucket = tdb_hash(key) % QDICT_BUCKET_MAX; |
123 | entry = qdict_find(qdict, key, bucket); | |
fb08dde0 LC |
124 | if (entry) { |
125 | /* replace key's value */ | |
cb3e7f08 | 126 | qobject_unref(entry->value); |
fb08dde0 LC |
127 | entry->value = value; |
128 | } else { | |
129 | /* allocate a new entry */ | |
130 | entry = alloc_entry(key, value); | |
c8bc3cd7 | 131 | QLIST_INSERT_HEAD(&qdict->table[bucket], entry, next); |
29ec3156 | 132 | qdict->size++; |
fb08dde0 | 133 | } |
fb08dde0 LC |
134 | } |
135 | ||
15280c36 MA |
136 | void qdict_put_int(QDict *qdict, const char *key, int64_t value) |
137 | { | |
138 | qdict_put(qdict, key, qnum_from_int(value)); | |
139 | } | |
140 | ||
141 | void qdict_put_bool(QDict *qdict, const char *key, bool value) | |
142 | { | |
143 | qdict_put(qdict, key, qbool_from_bool(value)); | |
144 | } | |
145 | ||
146 | void qdict_put_str(QDict *qdict, const char *key, const char *value) | |
147 | { | |
148 | qdict_put(qdict, key, qstring_from_str(value)); | |
149 | } | |
150 | ||
151 | void qdict_put_null(QDict *qdict, const char *key) | |
152 | { | |
153 | qdict_put(qdict, key, qnull()); | |
154 | } | |
155 | ||
fb08dde0 LC |
156 | /** |
157 | * qdict_get(): Lookup for a given 'key' | |
158 | * | |
159 | * Return a weak reference to the QObject associated with 'key' if | |
160 | * 'key' is present in the dictionary, NULL otherwise. | |
161 | */ | |
162 | QObject *qdict_get(const QDict *qdict, const char *key) | |
163 | { | |
164 | QDictEntry *entry; | |
165 | ||
c8bc3cd7 | 166 | entry = qdict_find(qdict, key, tdb_hash(key) % QDICT_BUCKET_MAX); |
fb08dde0 LC |
167 | return (entry == NULL ? NULL : entry->value); |
168 | } | |
169 | ||
170 | /** | |
171 | * qdict_haskey(): Check if 'key' exists | |
172 | * | |
173 | * Return 1 if 'key' exists in the dict, 0 otherwise | |
174 | */ | |
175 | int qdict_haskey(const QDict *qdict, const char *key) | |
176 | { | |
c8bc3cd7 LC |
177 | unsigned int bucket = tdb_hash(key) % QDICT_BUCKET_MAX; |
178 | return (qdict_find(qdict, key, bucket) == NULL ? 0 : 1); | |
fb08dde0 LC |
179 | } |
180 | ||
181 | /** | |
182 | * qdict_size(): Return the size of the dictionary | |
183 | */ | |
184 | size_t qdict_size(const QDict *qdict) | |
185 | { | |
186 | return qdict->size; | |
187 | } | |
188 | ||
acc3b033 MA |
189 | /** |
190 | * qdict_get_double(): Get an number mapped by 'key' | |
191 | * | |
01b2ffce | 192 | * This function assumes that 'key' exists and it stores a QNum. |
acc3b033 MA |
193 | * |
194 | * Return number mapped by 'key'. | |
195 | */ | |
196 | double qdict_get_double(const QDict *qdict, const char *key) | |
197 | { | |
7dc847eb | 198 | return qnum_get_double(qobject_to(QNum, qdict_get(qdict, key))); |
acc3b033 MA |
199 | } |
200 | ||
fb08dde0 LC |
201 | /** |
202 | * qdict_get_int(): Get an integer mapped by 'key' | |
203 | * | |
204 | * This function assumes that 'key' exists and it stores a | |
01b2ffce | 205 | * QNum representable as int. |
fb08dde0 LC |
206 | * |
207 | * Return integer mapped by 'key'. | |
208 | */ | |
209 | int64_t qdict_get_int(const QDict *qdict, const char *key) | |
210 | { | |
7dc847eb | 211 | return qnum_get_int(qobject_to(QNum, qdict_get(qdict, key))); |
fb08dde0 LC |
212 | } |
213 | ||
cd4dde36 LC |
214 | /** |
215 | * qdict_get_bool(): Get a bool mapped by 'key' | |
216 | * | |
217 | * This function assumes that 'key' exists and it stores a | |
218 | * QBool object. | |
219 | * | |
220 | * Return bool mapped by 'key'. | |
221 | */ | |
34acbc95 | 222 | bool qdict_get_bool(const QDict *qdict, const char *key) |
cd4dde36 | 223 | { |
7dc847eb | 224 | return qbool_get_bool(qobject_to(QBool, qdict_get(qdict, key))); |
cd4dde36 LC |
225 | } |
226 | ||
f2e17508 | 227 | /** |
b25f23e7 | 228 | * qdict_get_qlist(): If @qdict maps @key to a QList, return it, else NULL. |
f2e17508 LC |
229 | */ |
230 | QList *qdict_get_qlist(const QDict *qdict, const char *key) | |
231 | { | |
7dc847eb | 232 | return qobject_to(QList, qdict_get(qdict, key)); |
f2e17508 LC |
233 | } |
234 | ||
df10ce6a | 235 | /** |
b25f23e7 | 236 | * qdict_get_qdict(): If @qdict maps @key to a QDict, return it, else NULL. |
df10ce6a LC |
237 | */ |
238 | QDict *qdict_get_qdict(const QDict *qdict, const char *key) | |
239 | { | |
7dc847eb | 240 | return qobject_to(QDict, qdict_get(qdict, key)); |
df10ce6a LC |
241 | } |
242 | ||
fb08dde0 LC |
243 | /** |
244 | * qdict_get_str(): Get a pointer to the stored string mapped | |
245 | * by 'key' | |
246 | * | |
247 | * This function assumes that 'key' exists and it stores a | |
248 | * QString object. | |
249 | * | |
250 | * Return pointer to the string mapped by 'key'. | |
251 | */ | |
252 | const char *qdict_get_str(const QDict *qdict, const char *key) | |
253 | { | |
7dc847eb | 254 | return qstring_get_str(qobject_to(QString, qdict_get(qdict, key))); |
fb08dde0 LC |
255 | } |
256 | ||
257 | /** | |
258 | * qdict_get_try_int(): Try to get integer mapped by 'key' | |
259 | * | |
01b2ffce MAL |
260 | * Return integer mapped by 'key', if it is not present in the |
261 | * dictionary or if the stored object is not a QNum representing an | |
262 | * integer, 'def_value' will be returned. | |
fb08dde0 LC |
263 | */ |
264 | int64_t qdict_get_try_int(const QDict *qdict, const char *key, | |
83aba69e | 265 | int64_t def_value) |
fb08dde0 | 266 | { |
7dc847eb | 267 | QNum *qnum = qobject_to(QNum, qdict_get(qdict, key)); |
01b2ffce MAL |
268 | int64_t val; |
269 | ||
270 | if (!qnum || !qnum_get_try_int(qnum, &val)) { | |
271 | return def_value; | |
272 | } | |
fb08dde0 | 273 | |
01b2ffce | 274 | return val; |
fb08dde0 LC |
275 | } |
276 | ||
35006ac8 LC |
277 | /** |
278 | * qdict_get_try_bool(): Try to get a bool mapped by 'key' | |
279 | * | |
280 | * Return bool mapped by 'key', if it is not present in the | |
281 | * dictionary or if the stored object is not of QBool type | |
282 | * 'def_value' will be returned. | |
283 | */ | |
34acbc95 | 284 | bool qdict_get_try_bool(const QDict *qdict, const char *key, bool def_value) |
35006ac8 | 285 | { |
7dc847eb | 286 | QBool *qbool = qobject_to(QBool, qdict_get(qdict, key)); |
35006ac8 | 287 | |
14b61600 | 288 | return qbool ? qbool_get_bool(qbool) : def_value; |
35006ac8 LC |
289 | } |
290 | ||
fb08dde0 LC |
291 | /** |
292 | * qdict_get_try_str(): Try to get a pointer to the stored string | |
293 | * mapped by 'key' | |
294 | * | |
295 | * Return a pointer to the string mapped by 'key', if it is not present | |
296 | * in the dictionary or if the stored object is not of QString type | |
297 | * NULL will be returned. | |
298 | */ | |
299 | const char *qdict_get_try_str(const QDict *qdict, const char *key) | |
300 | { | |
7dc847eb | 301 | QString *qstr = qobject_to(QString, qdict_get(qdict, key)); |
fb08dde0 | 302 | |
7f027843 | 303 | return qstr ? qstring_get_str(qstr) : NULL; |
fb08dde0 LC |
304 | } |
305 | ||
21f800d3 LC |
306 | /** |
307 | * qdict_iter(): Iterate over all the dictionary's stored values. | |
308 | * | |
309 | * This function allows the user to provide an iterator, which will be | |
310 | * called for each stored value in the dictionary. | |
311 | */ | |
312 | void qdict_iter(const QDict *qdict, | |
313 | void (*iter)(const char *key, QObject *obj, void *opaque), | |
314 | void *opaque) | |
315 | { | |
316 | int i; | |
317 | QDictEntry *entry; | |
318 | ||
c8bc3cd7 | 319 | for (i = 0; i < QDICT_BUCKET_MAX; i++) { |
21f800d3 LC |
320 | QLIST_FOREACH(entry, &qdict->table[i], next) |
321 | iter(entry->key, entry->value, opaque); | |
322 | } | |
323 | } | |
324 | ||
f2b07f35 LC |
325 | static QDictEntry *qdict_next_entry(const QDict *qdict, int first_bucket) |
326 | { | |
327 | int i; | |
328 | ||
329 | for (i = first_bucket; i < QDICT_BUCKET_MAX; i++) { | |
330 | if (!QLIST_EMPTY(&qdict->table[i])) { | |
331 | return QLIST_FIRST(&qdict->table[i]); | |
332 | } | |
333 | } | |
334 | ||
335 | return NULL; | |
336 | } | |
337 | ||
338 | /** | |
339 | * qdict_first(): Return first qdict entry for iteration. | |
340 | */ | |
341 | const QDictEntry *qdict_first(const QDict *qdict) | |
342 | { | |
343 | return qdict_next_entry(qdict, 0); | |
344 | } | |
345 | ||
346 | /** | |
347 | * qdict_next(): Return next qdict entry in an iteration. | |
348 | */ | |
349 | const QDictEntry *qdict_next(const QDict *qdict, const QDictEntry *entry) | |
350 | { | |
351 | QDictEntry *ret; | |
352 | ||
353 | ret = QLIST_NEXT(entry, next); | |
354 | if (!ret) { | |
355 | unsigned int bucket = tdb_hash(entry->key) % QDICT_BUCKET_MAX; | |
356 | ret = qdict_next_entry(qdict, bucket + 1); | |
357 | } | |
358 | ||
359 | return ret; | |
360 | } | |
361 | ||
b382bc9a KW |
362 | /** |
363 | * qdict_clone_shallow(): Clones a given QDict. Its entries are not copied, but | |
364 | * another reference is added. | |
365 | */ | |
366 | QDict *qdict_clone_shallow(const QDict *src) | |
367 | { | |
368 | QDict *dest; | |
369 | QDictEntry *entry; | |
370 | int i; | |
371 | ||
372 | dest = qdict_new(); | |
373 | ||
374 | for (i = 0; i < QDICT_BUCKET_MAX; i++) { | |
375 | QLIST_FOREACH(entry, &src->table[i], next) { | |
cb3e7f08 | 376 | qobject_ref(entry->value); |
b382bc9a KW |
377 | qdict_put_obj(dest, entry->key, entry->value); |
378 | } | |
379 | } | |
380 | ||
381 | return dest; | |
382 | } | |
383 | ||
fb08dde0 LC |
384 | /** |
385 | * qentry_destroy(): Free all the memory allocated by a QDictEntry | |
386 | */ | |
387 | static void qentry_destroy(QDictEntry *e) | |
388 | { | |
389 | assert(e != NULL); | |
390 | assert(e->key != NULL); | |
391 | assert(e->value != NULL); | |
392 | ||
cb3e7f08 | 393 | qobject_unref(e->value); |
7267c094 AL |
394 | g_free(e->key); |
395 | g_free(e); | |
fb08dde0 LC |
396 | } |
397 | ||
398 | /** | |
399 | * qdict_del(): Delete a 'key:value' pair from the dictionary | |
400 | * | |
401 | * This will destroy all data allocated by this entry. | |
402 | */ | |
403 | void qdict_del(QDict *qdict, const char *key) | |
404 | { | |
405 | QDictEntry *entry; | |
406 | ||
c8bc3cd7 | 407 | entry = qdict_find(qdict, key, tdb_hash(key) % QDICT_BUCKET_MAX); |
fb08dde0 | 408 | if (entry) { |
72cf2d4f | 409 | QLIST_REMOVE(entry, next); |
fb08dde0 LC |
410 | qentry_destroy(entry); |
411 | qdict->size--; | |
412 | } | |
413 | } | |
414 | ||
b38dd678 HR |
415 | /** |
416 | * qdict_is_equal(): Test whether the two QDicts are equal | |
417 | * | |
418 | * Here, equality means whether they contain the same keys and whether | |
419 | * the respective values are in turn equal (i.e. invoking | |
420 | * qobject_is_equal() on them yields true). | |
421 | */ | |
422 | bool qdict_is_equal(const QObject *x, const QObject *y) | |
423 | { | |
7dc847eb HR |
424 | const QDict *dict_x = qobject_to(QDict, x); |
425 | const QDict *dict_y = qobject_to(QDict, y); | |
b38dd678 HR |
426 | const QDictEntry *e; |
427 | ||
428 | if (qdict_size(dict_x) != qdict_size(dict_y)) { | |
429 | return false; | |
430 | } | |
431 | ||
432 | for (e = qdict_first(dict_x); e; e = qdict_next(dict_x, e)) { | |
433 | const QObject *obj_x = qdict_entry_value(e); | |
434 | const QObject *obj_y = qdict_get(dict_y, qdict_entry_key(e)); | |
435 | ||
436 | if (!qobject_is_equal(obj_x, obj_y)) { | |
437 | return false; | |
438 | } | |
439 | } | |
440 | ||
441 | return true; | |
442 | } | |
443 | ||
fb08dde0 LC |
444 | /** |
445 | * qdict_destroy_obj(): Free all the memory allocated by a QDict | |
446 | */ | |
55e1819c | 447 | void qdict_destroy_obj(QObject *obj) |
fb08dde0 LC |
448 | { |
449 | int i; | |
450 | QDict *qdict; | |
451 | ||
452 | assert(obj != NULL); | |
7dc847eb | 453 | qdict = qobject_to(QDict, obj); |
fb08dde0 | 454 | |
c8bc3cd7 | 455 | for (i = 0; i < QDICT_BUCKET_MAX; i++) { |
72cf2d4f | 456 | QDictEntry *entry = QLIST_FIRST(&qdict->table[i]); |
fb08dde0 | 457 | while (entry) { |
72cf2d4f BS |
458 | QDictEntry *tmp = QLIST_NEXT(entry, next); |
459 | QLIST_REMOVE(entry, next); | |
fb08dde0 LC |
460 | qentry_destroy(entry); |
461 | entry = tmp; | |
462 | } | |
463 | } | |
464 | ||
7267c094 | 465 | g_free(qdict); |
fb08dde0 | 466 | } |
f660dc6a | 467 | |
7990d2c9 KW |
468 | /** |
469 | * qdict_copy_default(): If no entry mapped by 'key' exists in 'dst' yet, the | |
470 | * value of 'key' in 'src' is copied there (and the refcount increased | |
471 | * accordingly). | |
472 | */ | |
473 | void qdict_copy_default(QDict *dst, QDict *src, const char *key) | |
474 | { | |
475 | QObject *val; | |
476 | ||
477 | if (qdict_haskey(dst, key)) { | |
478 | return; | |
479 | } | |
480 | ||
481 | val = qdict_get(src, key); | |
482 | if (val) { | |
cb3e7f08 | 483 | qobject_ref(val); |
7990d2c9 KW |
484 | qdict_put_obj(dst, key, val); |
485 | } | |
486 | } | |
487 | ||
488 | /** | |
489 | * qdict_set_default_str(): If no entry mapped by 'key' exists in 'dst' yet, a | |
490 | * new QString initialised by 'val' is put there. | |
491 | */ | |
492 | void qdict_set_default_str(QDict *dst, const char *key, const char *val) | |
493 | { | |
494 | if (qdict_haskey(dst, key)) { | |
495 | return; | |
496 | } | |
497 | ||
46f5ac20 | 498 | qdict_put_str(dst, key, val); |
7990d2c9 KW |
499 | } |
500 | ||
9f23fc0c HR |
501 | static void qdict_flatten_qdict(QDict *qdict, QDict *target, |
502 | const char *prefix); | |
503 | ||
504 | static void qdict_flatten_qlist(QList *qlist, QDict *target, const char *prefix) | |
505 | { | |
506 | QObject *value; | |
507 | const QListEntry *entry; | |
508 | char *new_key; | |
509 | int i; | |
510 | ||
511 | /* This function is never called with prefix == NULL, i.e., it is always | |
512 | * called from within qdict_flatten_q(list|dict)(). Therefore, it does not | |
513 | * need to remove list entries during the iteration (the whole list will be | |
514 | * deleted eventually anyway from qdict_flatten_qdict()). */ | |
515 | assert(prefix); | |
516 | ||
517 | entry = qlist_first(qlist); | |
518 | ||
519 | for (i = 0; entry; entry = qlist_next(entry), i++) { | |
520 | value = qlist_entry_obj(entry); | |
521 | new_key = g_strdup_printf("%s.%i", prefix, i); | |
522 | ||
523 | if (qobject_type(value) == QTYPE_QDICT) { | |
7dc847eb | 524 | qdict_flatten_qdict(qobject_to(QDict, value), target, new_key); |
9f23fc0c | 525 | } else if (qobject_type(value) == QTYPE_QLIST) { |
7dc847eb | 526 | qdict_flatten_qlist(qobject_to(QList, value), target, new_key); |
9f23fc0c HR |
527 | } else { |
528 | /* All other types are moved to the target unchanged. */ | |
cb3e7f08 | 529 | qobject_ref(value); |
9f23fc0c HR |
530 | qdict_put_obj(target, new_key, value); |
531 | } | |
532 | ||
533 | g_free(new_key); | |
534 | } | |
535 | } | |
536 | ||
537 | static void qdict_flatten_qdict(QDict *qdict, QDict *target, const char *prefix) | |
f660dc6a KW |
538 | { |
539 | QObject *value; | |
540 | const QDictEntry *entry, *next; | |
6273d113 | 541 | char *new_key; |
f660dc6a KW |
542 | bool delete; |
543 | ||
544 | entry = qdict_first(qdict); | |
545 | ||
546 | while (entry != NULL) { | |
547 | ||
548 | next = qdict_next(qdict, entry); | |
549 | value = qdict_entry_value(entry); | |
550 | new_key = NULL; | |
551 | delete = false; | |
552 | ||
553 | if (prefix) { | |
f660dc6a | 554 | new_key = g_strdup_printf("%s.%s", prefix, entry->key); |
f660dc6a KW |
555 | } |
556 | ||
557 | if (qobject_type(value) == QTYPE_QDICT) { | |
4d5977ea KW |
558 | /* Entries of QDicts are processed recursively, the QDict object |
559 | * itself disappears. */ | |
7dc847eb | 560 | qdict_flatten_qdict(qobject_to(QDict, value), target, |
9f23fc0c HR |
561 | new_key ? new_key : entry->key); |
562 | delete = true; | |
563 | } else if (qobject_type(value) == QTYPE_QLIST) { | |
7dc847eb | 564 | qdict_flatten_qlist(qobject_to(QList, value), target, |
9f23fc0c | 565 | new_key ? new_key : entry->key); |
f660dc6a | 566 | delete = true; |
4d5977ea KW |
567 | } else if (prefix) { |
568 | /* All other objects are moved to the target unchanged. */ | |
cb3e7f08 | 569 | qobject_ref(value); |
4d5977ea KW |
570 | qdict_put_obj(target, new_key, value); |
571 | delete = true; | |
f660dc6a KW |
572 | } |
573 | ||
6273d113 KW |
574 | g_free(new_key); |
575 | ||
f660dc6a KW |
576 | if (delete) { |
577 | qdict_del(qdict, entry->key); | |
578 | ||
579 | /* Restart loop after modifying the iterated QDict */ | |
580 | entry = qdict_first(qdict); | |
581 | continue; | |
582 | } | |
583 | ||
584 | entry = next; | |
585 | } | |
586 | } | |
587 | ||
588 | /** | |
589 | * qdict_flatten(): For each nested QDict with key x, all fields with key y | |
9f23fc0c HR |
590 | * are moved to this QDict and their key is renamed to "x.y". For each nested |
591 | * QList with key x, the field at index y is moved to this QDict with the key | |
592 | * "x.y" (i.e., the reverse of what qdict_array_split() does). | |
593 | * This operation is applied recursively for nested QDicts and QLists. | |
f660dc6a KW |
594 | */ |
595 | void qdict_flatten(QDict *qdict) | |
596 | { | |
9f23fc0c | 597 | qdict_flatten_qdict(qdict, qdict, NULL); |
f660dc6a | 598 | } |
5726d872 BC |
599 | |
600 | /* extract all the src QDict entries starting by start into dst */ | |
601 | void qdict_extract_subqdict(QDict *src, QDict **dst, const char *start) | |
602 | ||
603 | { | |
604 | const QDictEntry *entry, *next; | |
605 | const char *p; | |
606 | ||
607 | *dst = qdict_new(); | |
608 | entry = qdict_first(src); | |
609 | ||
610 | while (entry != NULL) { | |
611 | next = qdict_next(src, entry); | |
612 | if (strstart(entry->key, start, &p)) { | |
cb3e7f08 | 613 | qobject_ref(entry->value); |
5726d872 BC |
614 | qdict_put_obj(*dst, p, entry->value); |
615 | qdict_del(src, entry->key); | |
616 | } | |
617 | entry = next; | |
618 | } | |
619 | } | |
05a8c222 | 620 | |
bd50530a | 621 | static int qdict_count_prefixed_entries(const QDict *src, const char *start) |
bae3f92a HR |
622 | { |
623 | const QDictEntry *entry; | |
bd50530a | 624 | int count = 0; |
bae3f92a HR |
625 | |
626 | for (entry = qdict_first(src); entry; entry = qdict_next(src, entry)) { | |
627 | if (strstart(entry->key, start, NULL)) { | |
bd50530a KW |
628 | if (count == INT_MAX) { |
629 | return -ERANGE; | |
630 | } | |
631 | count++; | |
bae3f92a HR |
632 | } |
633 | } | |
634 | ||
bd50530a | 635 | return count; |
bae3f92a HR |
636 | } |
637 | ||
05a8c222 HR |
638 | /** |
639 | * qdict_array_split(): This function moves array-like elements of a QDict into | |
bae3f92a HR |
640 | * a new QList. Every entry in the original QDict with a key "%u" or one |
641 | * prefixed "%u.", where %u designates an unsigned integer starting at 0 and | |
05a8c222 | 642 | * incrementally counting up, will be moved to a new QDict at index %u in the |
bae3f92a HR |
643 | * output QList with the key prefix removed, if that prefix is "%u.". If the |
644 | * whole key is just "%u", the whole QObject will be moved unchanged without | |
645 | * creating a new QDict. The function terminates when there is no entry in the | |
646 | * QDict with a prefix directly (incrementally) following the last one; it also | |
647 | * returns if there are both entries with "%u" and "%u." for the same index %u. | |
648 | * Example: {"0.a": 42, "0.b": 23, "1.x": 0, "4.y": 1, "o.o": 7, "2": 66} | |
649 | * (or {"1.x": 0, "4.y": 1, "0.a": 42, "o.o": 7, "0.b": 23, "2": 66}) | |
650 | * => [{"a": 42, "b": 23}, {"x": 0}, 66] | |
651 | * and {"4.y": 1, "o.o": 7} (remainder of the old QDict) | |
05a8c222 HR |
652 | */ |
653 | void qdict_array_split(QDict *src, QList **dst) | |
654 | { | |
655 | unsigned i; | |
656 | ||
657 | *dst = qlist_new(); | |
658 | ||
659 | for (i = 0; i < UINT_MAX; i++) { | |
bae3f92a HR |
660 | QObject *subqobj; |
661 | bool is_subqdict; | |
05a8c222 | 662 | QDict *subqdict; |
bae3f92a | 663 | char indexstr[32], prefix[32]; |
05a8c222 HR |
664 | size_t snprintf_ret; |
665 | ||
bae3f92a HR |
666 | snprintf_ret = snprintf(indexstr, 32, "%u", i); |
667 | assert(snprintf_ret < 32); | |
668 | ||
669 | subqobj = qdict_get(src, indexstr); | |
670 | ||
05a8c222 HR |
671 | snprintf_ret = snprintf(prefix, 32, "%u.", i); |
672 | assert(snprintf_ret < 32); | |
673 | ||
bd50530a KW |
674 | /* Overflow is the same as positive non-zero results */ |
675 | is_subqdict = qdict_count_prefixed_entries(src, prefix); | |
bae3f92a HR |
676 | |
677 | // There may be either a single subordinate object (named "%u") or | |
678 | // multiple objects (each with a key prefixed "%u."), but not both. | |
679 | if (!subqobj == !is_subqdict) { | |
05a8c222 HR |
680 | break; |
681 | } | |
682 | ||
bae3f92a HR |
683 | if (is_subqdict) { |
684 | qdict_extract_subqdict(src, &subqdict, prefix); | |
685 | assert(qdict_size(subqdict) > 0); | |
686 | } else { | |
cb3e7f08 | 687 | qobject_ref(subqobj); |
bae3f92a HR |
688 | qdict_del(src, indexstr); |
689 | } | |
690 | ||
691 | qlist_append_obj(*dst, subqobj ?: QOBJECT(subqdict)); | |
05a8c222 HR |
692 | } |
693 | } | |
9c526812 | 694 | |
603476c2 DB |
695 | /** |
696 | * qdict_split_flat_key: | |
697 | * @key: the key string to split | |
698 | * @prefix: non-NULL pointer to hold extracted prefix | |
699 | * @suffix: non-NULL pointer to remaining suffix | |
700 | * | |
701 | * Given a flattened key such as 'foo.0.bar', split it into two parts | |
702 | * at the first '.' separator. Allows double dot ('..') to escape the | |
703 | * normal separator. | |
704 | * | |
705 | * e.g. | |
706 | * 'foo.0.bar' -> prefix='foo' and suffix='0.bar' | |
707 | * 'foo..0.bar' -> prefix='foo.0' and suffix='bar' | |
708 | * | |
709 | * The '..' sequence will be unescaped in the returned 'prefix' | |
710 | * string. The 'suffix' string will be left in escaped format, so it | |
711 | * can be fed back into the qdict_split_flat_key() key as the input | |
712 | * later. | |
713 | * | |
714 | * The caller is responsible for freeing the string returned in @prefix | |
715 | * using g_free(). | |
716 | */ | |
717 | static void qdict_split_flat_key(const char *key, char **prefix, | |
718 | const char **suffix) | |
719 | { | |
720 | const char *separator; | |
721 | size_t i, j; | |
722 | ||
723 | /* Find first '.' separator, but if there is a pair '..' | |
724 | * that acts as an escape, so skip over '..' */ | |
725 | separator = NULL; | |
726 | do { | |
727 | if (separator) { | |
728 | separator += 2; | |
729 | } else { | |
730 | separator = key; | |
731 | } | |
732 | separator = strchr(separator, '.'); | |
733 | } while (separator && separator[1] == '.'); | |
734 | ||
735 | if (separator) { | |
736 | *prefix = g_strndup(key, separator - key); | |
737 | *suffix = separator + 1; | |
738 | } else { | |
739 | *prefix = g_strdup(key); | |
740 | *suffix = NULL; | |
741 | } | |
742 | ||
743 | /* Unescape the '..' sequence into '.' */ | |
744 | for (i = 0, j = 0; (*prefix)[i] != '\0'; i++, j++) { | |
745 | if ((*prefix)[i] == '.') { | |
746 | assert((*prefix)[i + 1] == '.'); | |
747 | i++; | |
748 | } | |
749 | (*prefix)[j] = (*prefix)[i]; | |
750 | } | |
751 | (*prefix)[j] = '\0'; | |
752 | } | |
753 | ||
754 | /** | |
755 | * qdict_is_list: | |
756 | * @maybe_list: dict to check if keys represent list elements. | |
757 | * | |
758 | * Determine whether all keys in @maybe_list are valid list elements. | |
759 | * If @maybe_list is non-zero in length and all the keys look like | |
760 | * valid list indexes, this will return 1. If @maybe_list is zero | |
761 | * length or all keys are non-numeric then it will return 0 to indicate | |
762 | * it is a normal qdict. If there is a mix of numeric and non-numeric | |
763 | * keys, or the list indexes are non-contiguous, an error is reported. | |
764 | * | |
765 | * Returns: 1 if a valid list, 0 if a dict, -1 on error | |
766 | */ | |
767 | static int qdict_is_list(QDict *maybe_list, Error **errp) | |
768 | { | |
769 | const QDictEntry *ent; | |
770 | ssize_t len = 0; | |
771 | ssize_t max = -1; | |
772 | int is_list = -1; | |
773 | int64_t val; | |
774 | ||
775 | for (ent = qdict_first(maybe_list); ent != NULL; | |
776 | ent = qdict_next(maybe_list, ent)) { | |
777 | ||
b30d1886 | 778 | if (qemu_strtoi64(ent->key, NULL, 10, &val) == 0) { |
603476c2 DB |
779 | if (is_list == -1) { |
780 | is_list = 1; | |
781 | } else if (!is_list) { | |
782 | error_setg(errp, | |
783 | "Cannot mix list and non-list keys"); | |
784 | return -1; | |
785 | } | |
786 | len++; | |
787 | if (val > max) { | |
788 | max = val; | |
789 | } | |
790 | } else { | |
791 | if (is_list == -1) { | |
792 | is_list = 0; | |
793 | } else if (is_list) { | |
794 | error_setg(errp, | |
795 | "Cannot mix list and non-list keys"); | |
796 | return -1; | |
797 | } | |
798 | } | |
799 | } | |
800 | ||
801 | if (is_list == -1) { | |
802 | assert(!qdict_size(maybe_list)); | |
803 | is_list = 0; | |
804 | } | |
805 | ||
806 | /* NB this isn't a perfect check - e.g. it won't catch | |
807 | * a list containing '1', '+1', '01', '3', but that | |
808 | * does not matter - we've still proved that the | |
809 | * input is a list. It is up the caller to do a | |
810 | * stricter check if desired */ | |
811 | if (len != (max + 1)) { | |
812 | error_setg(errp, "List indices are not contiguous, " | |
813 | "saw %zd elements but %zd largest index", | |
814 | len, max); | |
815 | return -1; | |
816 | } | |
817 | ||
818 | return is_list; | |
819 | } | |
820 | ||
821 | /** | |
822 | * qdict_crumple: | |
823 | * @src: the original flat dictionary (only scalar values) to crumple | |
824 | * | |
825 | * Takes a flat dictionary whose keys use '.' separator to indicate | |
826 | * nesting, and values are scalars, and crumples it into a nested | |
827 | * structure. | |
828 | * | |
829 | * To include a literal '.' in a key name, it must be escaped as '..' | |
830 | * | |
831 | * For example, an input of: | |
832 | * | |
833 | * { 'foo.0.bar': 'one', 'foo.0.wizz': '1', | |
834 | * 'foo.1.bar': 'two', 'foo.1.wizz': '2' } | |
835 | * | |
836 | * will result in an output of: | |
837 | * | |
838 | * { | |
839 | * 'foo': [ | |
840 | * { 'bar': 'one', 'wizz': '1' }, | |
841 | * { 'bar': 'two', 'wizz': '2' } | |
842 | * ], | |
843 | * } | |
844 | * | |
845 | * The following scenarios in the input dict will result in an | |
846 | * error being returned: | |
847 | * | |
848 | * - Any values in @src are non-scalar types | |
849 | * - If keys in @src imply that a particular level is both a | |
850 | * list and a dict. e.g., "foo.0.bar" and "foo.eek.bar". | |
851 | * - If keys in @src imply that a particular level is a list, | |
852 | * but the indices are non-contiguous. e.g. "foo.0.bar" and | |
853 | * "foo.2.bar" without any "foo.1.bar" present. | |
854 | * - If keys in @src represent list indexes, but are not in | |
855 | * the "%zu" format. e.g. "foo.+0.bar" | |
856 | * | |
857 | * Returns: either a QDict or QList for the nested data structure, or NULL | |
858 | * on error | |
859 | */ | |
860 | QObject *qdict_crumple(const QDict *src, Error **errp) | |
861 | { | |
862 | const QDictEntry *ent; | |
863 | QDict *two_level, *multi_level = NULL; | |
864 | QObject *dst = NULL, *child; | |
865 | size_t i; | |
866 | char *prefix = NULL; | |
867 | const char *suffix = NULL; | |
868 | int is_list; | |
869 | ||
870 | two_level = qdict_new(); | |
871 | ||
872 | /* Step 1: split our totally flat dict into a two level dict */ | |
873 | for (ent = qdict_first(src); ent != NULL; ent = qdict_next(src, ent)) { | |
874 | if (qobject_type(ent->value) == QTYPE_QDICT || | |
875 | qobject_type(ent->value) == QTYPE_QLIST) { | |
876 | error_setg(errp, "Value %s is not a scalar", | |
877 | ent->key); | |
878 | goto error; | |
879 | } | |
880 | ||
881 | qdict_split_flat_key(ent->key, &prefix, &suffix); | |
882 | ||
883 | child = qdict_get(two_level, prefix); | |
884 | if (suffix) { | |
532fb532 HR |
885 | QDict *child_dict = qobject_to(QDict, child); |
886 | if (!child_dict) { | |
887 | if (child) { | |
603476c2 DB |
888 | error_setg(errp, "Key %s prefix is already set as a scalar", |
889 | prefix); | |
890 | goto error; | |
891 | } | |
532fb532 HR |
892 | |
893 | child_dict = qdict_new(); | |
894 | qdict_put_obj(two_level, prefix, QOBJECT(child_dict)); | |
603476c2 | 895 | } |
532fb532 | 896 | |
cb3e7f08 | 897 | qobject_ref(ent->value); |
532fb532 | 898 | qdict_put_obj(child_dict, suffix, ent->value); |
603476c2 DB |
899 | } else { |
900 | if (child) { | |
901 | error_setg(errp, "Key %s prefix is already set as a dict", | |
902 | prefix); | |
903 | goto error; | |
904 | } | |
cb3e7f08 | 905 | qobject_ref(ent->value); |
603476c2 DB |
906 | qdict_put_obj(two_level, prefix, ent->value); |
907 | } | |
908 | ||
909 | g_free(prefix); | |
910 | prefix = NULL; | |
911 | } | |
912 | ||
913 | /* Step 2: optionally process the two level dict recursively | |
914 | * into a multi-level dict */ | |
915 | multi_level = qdict_new(); | |
916 | for (ent = qdict_first(two_level); ent != NULL; | |
917 | ent = qdict_next(two_level, ent)) { | |
532fb532 HR |
918 | QDict *dict = qobject_to(QDict, ent->value); |
919 | if (dict) { | |
920 | child = qdict_crumple(dict, errp); | |
603476c2 DB |
921 | if (!child) { |
922 | goto error; | |
923 | } | |
924 | ||
925 | qdict_put_obj(multi_level, ent->key, child); | |
926 | } else { | |
cb3e7f08 | 927 | qobject_ref(ent->value); |
603476c2 DB |
928 | qdict_put_obj(multi_level, ent->key, ent->value); |
929 | } | |
930 | } | |
cb3e7f08 | 931 | qobject_unref(two_level); |
603476c2 DB |
932 | two_level = NULL; |
933 | ||
934 | /* Step 3: detect if we need to turn our dict into list */ | |
935 | is_list = qdict_is_list(multi_level, errp); | |
936 | if (is_list < 0) { | |
937 | goto error; | |
938 | } | |
939 | ||
940 | if (is_list) { | |
941 | dst = QOBJECT(qlist_new()); | |
942 | ||
943 | for (i = 0; i < qdict_size(multi_level); i++) { | |
944 | char *key = g_strdup_printf("%zu", i); | |
945 | ||
946 | child = qdict_get(multi_level, key); | |
947 | g_free(key); | |
948 | ||
949 | if (!child) { | |
950 | error_setg(errp, "Missing list index %zu", i); | |
951 | goto error; | |
952 | } | |
953 | ||
cb3e7f08 | 954 | qobject_ref(child); |
7dc847eb | 955 | qlist_append_obj(qobject_to(QList, dst), child); |
603476c2 | 956 | } |
cb3e7f08 | 957 | qobject_unref(multi_level); |
603476c2 DB |
958 | multi_level = NULL; |
959 | } else { | |
960 | dst = QOBJECT(multi_level); | |
961 | } | |
962 | ||
963 | return dst; | |
964 | ||
965 | error: | |
966 | g_free(prefix); | |
cb3e7f08 MAL |
967 | qobject_unref(multi_level); |
968 | qobject_unref(two_level); | |
969 | qobject_unref(dst); | |
603476c2 DB |
970 | return NULL; |
971 | } | |
972 | ||
bd50530a KW |
973 | /** |
974 | * qdict_array_entries(): Returns the number of direct array entries if the | |
975 | * sub-QDict of src specified by the prefix in subqdict (or src itself for | |
976 | * prefix == "") is valid as an array, i.e. the length of the created list if | |
977 | * the sub-QDict would become empty after calling qdict_array_split() on it. If | |
978 | * the array is not valid, -EINVAL is returned. | |
979 | */ | |
980 | int qdict_array_entries(QDict *src, const char *subqdict) | |
981 | { | |
982 | const QDictEntry *entry; | |
983 | unsigned i; | |
984 | unsigned entries = 0; | |
985 | size_t subqdict_len = strlen(subqdict); | |
986 | ||
987 | assert(!subqdict_len || subqdict[subqdict_len - 1] == '.'); | |
988 | ||
989 | /* qdict_array_split() loops until UINT_MAX, but as we want to return | |
990 | * negative errors, we only have a signed return value here. Any additional | |
991 | * entries will lead to -EINVAL. */ | |
992 | for (i = 0; i < INT_MAX; i++) { | |
993 | QObject *subqobj; | |
994 | int subqdict_entries; | |
de4905f4 | 995 | char *prefix = g_strdup_printf("%s%u.", subqdict, i); |
bd50530a | 996 | |
de4905f4 | 997 | subqdict_entries = qdict_count_prefixed_entries(src, prefix); |
bd50530a | 998 | |
de4905f4 PX |
999 | /* Remove ending "." */ |
1000 | prefix[strlen(prefix) - 1] = 0; | |
1001 | subqobj = qdict_get(src, prefix); | |
bd50530a | 1002 | |
de4905f4 | 1003 | g_free(prefix); |
bd50530a | 1004 | |
bd50530a KW |
1005 | if (subqdict_entries < 0) { |
1006 | return subqdict_entries; | |
1007 | } | |
1008 | ||
1009 | /* There may be either a single subordinate object (named "%u") or | |
1010 | * multiple objects (each with a key prefixed "%u."), but not both. */ | |
1011 | if (subqobj && subqdict_entries) { | |
1012 | return -EINVAL; | |
1013 | } else if (!subqobj && !subqdict_entries) { | |
1014 | break; | |
1015 | } | |
1016 | ||
1017 | entries += subqdict_entries ? subqdict_entries : 1; | |
1018 | } | |
1019 | ||
1020 | /* Consider everything handled that isn't part of the given sub-QDict */ | |
1021 | for (entry = qdict_first(src); entry; entry = qdict_next(src, entry)) { | |
1022 | if (!strstart(qdict_entry_key(entry), subqdict, NULL)) { | |
1023 | entries++; | |
1024 | } | |
1025 | } | |
1026 | ||
1027 | /* Anything left in the sub-QDict that wasn't handled? */ | |
1028 | if (qdict_size(src) != entries) { | |
1029 | return -EINVAL; | |
1030 | } | |
1031 | ||
1032 | return i; | |
1033 | } | |
1034 | ||
9c526812 HR |
1035 | /** |
1036 | * qdict_join(): Absorb the src QDict into the dest QDict, that is, move all | |
1037 | * elements from src to dest. | |
1038 | * | |
1039 | * If an element from src has a key already present in dest, it will not be | |
1040 | * moved unless overwrite is true. | |
1041 | * | |
1042 | * If overwrite is true, the conflicting values in dest will be discarded and | |
1043 | * replaced by the corresponding values from src. | |
1044 | * | |
1045 | * Therefore, with overwrite being true, the src QDict will always be empty when | |
1046 | * this function returns. If overwrite is false, the src QDict will be empty | |
1047 | * iff there were no conflicts. | |
1048 | */ | |
1049 | void qdict_join(QDict *dest, QDict *src, bool overwrite) | |
1050 | { | |
1051 | const QDictEntry *entry, *next; | |
1052 | ||
1053 | entry = qdict_first(src); | |
1054 | while (entry) { | |
1055 | next = qdict_next(src, entry); | |
1056 | ||
1057 | if (overwrite || !qdict_haskey(dest, entry->key)) { | |
cb3e7f08 | 1058 | qobject_ref(entry->value); |
9c526812 HR |
1059 | qdict_put_obj(dest, entry->key, entry->value); |
1060 | qdict_del(src, entry->key); | |
1061 | } | |
1062 | ||
1063 | entry = next; | |
1064 | } | |
1065 | } | |
bcebf102 KW |
1066 | |
1067 | /** | |
1068 | * qdict_rename_keys(): Rename keys in qdict according to the replacements | |
1069 | * specified in the array renames. The array must be terminated by an entry | |
1070 | * with from = NULL. | |
1071 | * | |
1072 | * The renames are performed individually in the order of the array, so entries | |
1073 | * may be renamed multiple times and may or may not conflict depending on the | |
1074 | * order of the renames array. | |
1075 | * | |
1076 | * Returns true for success, false in error cases. | |
1077 | */ | |
1078 | bool qdict_rename_keys(QDict *qdict, const QDictRenames *renames, Error **errp) | |
1079 | { | |
1080 | QObject *qobj; | |
1081 | ||
1082 | while (renames->from) { | |
1083 | if (qdict_haskey(qdict, renames->from)) { | |
1084 | if (qdict_haskey(qdict, renames->to)) { | |
1085 | error_setg(errp, "'%s' and its alias '%s' can't be used at the " | |
1086 | "same time", renames->to, renames->from); | |
1087 | return false; | |
1088 | } | |
1089 | ||
1090 | qobj = qdict_get(qdict, renames->from); | |
cb3e7f08 | 1091 | qobject_ref(qobj); |
bcebf102 KW |
1092 | qdict_put_obj(qdict, renames->to, qobj); |
1093 | qdict_del(qdict, renames->from); | |
1094 | } | |
1095 | ||
1096 | renames++; | |
1097 | } | |
1098 | return true; | |
1099 | } |