Bug Summary

File:build-analysis/../src/lib/xmmstypes/xmmsv_dict.c
Warning:line 243, column 3
Use of memory after it is freed

Annotated Source Code

1/* XMMS2 - X Music Multiplexer System
2 * Copyright (C) 2003-2017 XMMS2 Team
3 *
4 * PLUGINS ARE NOT CONSIDERED TO BE DERIVED WORK !!!
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 */
16
17#include <stdlib.h>
18#include <string.h>
19
20#include <xmmscpriv/xmmsv.h>
21#include <xmmscpriv/xmms_list.h>
22
23typedef struct xmmsv_dict_data_St {
24 uint32_t hash;
25 char *str;
26 xmmsv_t *value;
27} xmmsv_dict_data_t;
28
29struct xmmsv_dict_internal_St {
30 int elems;
31 int size;
32 xmmsv_dict_data_t *data;
33
34 x_list_t *iterators;
35};
36
37struct xmmsv_dict_iter_St {
38 int pos;
39 xmmsv_dict_internal_t *parent;
40};
41
42static void _xmmsv_dict_iter_free (xmmsv_dict_iter_t *it);
43
44#define HASH_MASK(table)((1 << (table)->size) - 1) ((1 << (table)->size) - 1)
45#define HASH_FILL_LIM7 7
46#define DELETED_STR((char*)-1) ((char*)-1)
47#define DICT_INIT_DATA(s){.hash = _xmmsv_dict_hash (s, strlen (s)), .str = (char*)s} {.hash = _xmmsv_dict_hash (s, strlen (s)), .str = (char*)s}
48#define START_SIZE2 2
49
50/* MurmurHash2, by Austin Appleby */
51static uint32_t
52_xmmsv_dict_hash (const void *key, int len)
53{
54 /* 'm' and 'r' are mixing constants generated offline.
55 * They're not really 'magic', they just happen to work well.
56 */
57 const uint32_t seed = 0x12345678;
58 const uint32_t m = 0x5bd1e995;
59 const int r = 24;
60
61 /* Initialize the hash to a 'random' value */
62 uint32_t h = seed ^ len;
63
64 /* Mix 4 bytes at a time into the hash */
65 const unsigned char * data = (const unsigned char *)key;
66
67 while (len >= 4)
68 {
69 uint32_t k = data [0]
70 | data [1] << 8
71 | data [2] << 16
72 | data [3] << 24;
73
74 k *= m;
75 k ^= k >> r;
76 k *= m;
77
78 h *= m;
79 h ^= k;
80
81 data += 4;
82 len -= 4;
83 }
84
85 /* Handle the last few bytes of the input array */
86 switch (len)
87 {
88 case 3: h ^= data[2] << 16;
89 case 2: h ^= data[1] << 8;
90 case 1: h ^= data[0];
91 h *= m;
92 };
93
94 /* Do a few final mixes of the hash to ensure the last few
95 * bytes are well-incorporated.
96 */
97 h ^= h >> 13;
98 h *= m;
99 h ^= h >> 15;
100
101 return h;
102}
103
104/* Searches the hash table for an entry matching the hash and string in data.
105 * It will save the found position in pos.
106 * If a deleted position was found before the key, it will be saved in deleted
107 * Returns 1 if the entry was found, 0 otherwise
108 */
109static int
110_xmmsv_dict_search (xmmsv_dict_internal_t *dict, xmmsv_dict_data_t data,
111 int *pos, int *deleted)
112{
113 int bucket = data.hash & HASH_MASK (dict)((1 << (dict)->size) - 1);
114 int stop = bucket;
115 int size = 1 << dict->size;
116
117 *deleted = -1;
118
119 while (dict->data[bucket].str != NULL((void*)0)) {
120 /* If this is a free entry we save it in the free pointer */
121 if (dict->data[bucket].str == DELETED_STR((char*)-1)) {
122 if (*deleted == -1) {
123 *deleted = bucket;
124 }
125 /* If we found the entry we save it in the pos pointer */
126 } else if (dict->data[bucket].hash == data.hash
127 && strcmp (dict->data[bucket].str, data.str) == 0) {
128 *pos = bucket;
129 return 1;
130 }
131
132 /* If we hit the end we roll around */
133 if (++bucket >= size)
134 bucket = 0;
135 /* If we have checked the whole table we exit */
136 if (bucket == stop)
137 break;
138 }
139
140 /* Save the position to the first free entry
141 * (or the start bucket if we made it the whole way around
142 * without finding the entry and without finding any empty
143 * entries, but in that case free is set, since there have to
144 * be atleast 1 deleted or empty entry in the table)
145 */
146 *pos = bucket;
147 return 0;
148}
149
150/* Inserts data into the hash table */
151static void
152_xmmsv_dict_insert (xmmsv_dict_internal_t *dict, xmmsv_dict_data_t data, int alloc)
153{
154 int pos, deleted;
155
156 if (_xmmsv_dict_search (dict, data, &pos, &deleted)) {
157 /* If the key already exists we change the data*/
158 xmmsv_unref (dict->data[pos].value);
159 dict->data[pos].value = data.value;
160 } else {
161 /* Otherwise we insert a new entry */
162 if (alloc)
163 data.str = strdup (data.str);
164 dict->elems++;
165 /* If we found a deleted entry before an empty one we use the free entry */
166 if (deleted != -1) {
167 dict->data[deleted] = data;
168 } else {
169 dict->data[pos] = data;
170 }
171 }
172}
173
174/* Remove an entry at the given position
175 */
176static void
177_xmmsv_dict_remove (xmmsv_dict_internal_t *dict, int pos)
178{
179 free ((void*)dict->data[pos].str);
180 dict->data[pos].str = DELETED_STR((char*)-1);
181 xmmsv_unref (dict->data[pos].value);
182 dict->data[pos].value = NULL((void*)0);
183 dict->elems--;
184}
185
186/* Resizes the hash table by creating a new data table
187 * twice the size of the old one
188 */
189static void
190_xmmsv_dict_resize (xmmsv_dict_internal_t *dict)
191{
192 int i;
193 xmmsv_dict_data_t *old_data;
194
195 /* Double the table size */
196 dict->size++;
197 dict->elems = 0;
198 old_data = dict->data;
199 dict->data = x_new0 (xmmsv_dict_data_t, 1 << dict->size)calloc (1, sizeof (xmmsv_dict_data_t) * (1 << dict->
size))
;
200
201 /* Insert all the entries in the old table into the new one */
202 for (i = 0; i < (1 << (dict->size - 1)); i++) {
203 if (old_data[i].str != NULL((void*)0)) {
204 _xmmsv_dict_insert (dict, old_data[i], 0);
205 }
206 }
207
208 free (old_data);
209}
210
211static xmmsv_dict_internal_t *
212_xmmsv_dict_new (void)
213{
214 xmmsv_dict_internal_t *dict;
215
216 dict = x_new0 (xmmsv_dict_internal_t, 1)calloc (1, sizeof (xmmsv_dict_internal_t) * (1));
217 if (!dict) {
218 x_oom ()xmmsc_log ("xmmsc/xmmstypes", XMMS_LOG_LEVEL_FAIL, "Out of memory in %s at %s:%d"
, __FUNCTION__, "../src/lib/xmmstypes/xmmsv_dict.c", 218)
;
219 return NULL((void*)0);
220 }
221
222 dict->size = 2;
223 dict->data = x_new0 (xmmsv_dict_data_t, (1 << dict->size))calloc (1, sizeof (xmmsv_dict_data_t) * ((1 << dict->
size)))
;
224
225 if (!dict->data) {
226 x_oom ()xmmsc_log ("xmmsc/xmmstypes", XMMS_LOG_LEVEL_FAIL, "Out of memory in %s at %s:%d"
, __FUNCTION__, "../src/lib/xmmstypes/xmmsv_dict.c", 226)
;
227 free (dict);
228 return NULL((void*)0);
229 }
230
231 return dict;
232}
233
234void
235_xmmsv_dict_free (xmmsv_dict_internal_t *dict)
236{
237 xmmsv_dict_iter_t *it;
238 int i;
239
240 /* free iterators */
241 while (dict->iterators) {
1
Loop condition is true. Entering loop body
5
Loop condition is true. Entering loop body
242 it = (xmmsv_dict_iter_t *) dict->iterators->data;
243 _xmmsv_dict_iter_free (it);
2
Calling '_xmmsv_dict_iter_free'
4
Returning; memory was released via 1st parameter
6
Use of memory after it is freed
244 }
245
246 for (i = (1 << dict->size) - 1; i >= 0; i--) {
247 if (dict->data[i].str != NULL((void*)0)) {
248 if (dict->data[i].str != DELETED_STR((char*)-1)) {
249 free (dict->data[i].str);
250 xmmsv_unref (dict->data[i].value);
251 }
252 dict->data[i].str = NULL((void*)0);
253 }
254 }
255 free (dict->data);
256 free (dict);
257}
258
259/**
260 * Allocates a new dict #xmmsv_t.
261 * @return The new #xmmsv_t. Must be unreferenced with
262 * #xmmsv_unref.
263 */
264xmmsv_t *
265xmmsv_new_dict (void)
266{
267 xmmsv_t *val = _xmmsv_new (XMMSV_TYPE_DICT);
268
269 if (val) {
270 val->value.dict = _xmmsv_dict_new ();
271 }
272
273 return val;
274}
275
276int
277xmmsv_dict_has_key (xmmsv_t *dictv, const char *key)
278{
279 return xmmsv_dict_get (dictv, key, NULL((void*)0));
280}
281
282/**
283 * Get a #XMMSV_TYPE_LIST of all the keys.
284 *
285 * @param val A xmmsv_t containing a dict.
286 * @param keys Pointer that will own the reference
287 * to the new list containing the dict keys.
288 * @return 1 upon success otherwise 0
289 */
290int xmmsv_dict_keys (xmmsv_t *dictv, xmmsv_t **keys)
291{
292 xmmsv_dict_iter_t *it;
293 const char *key;
294
295 x_return_val_if_fail (keys, 0)if (!(keys)) { xmmsc_log ("xmmsc/xmmstypes", XMMS_LOG_LEVEL_FAIL
, "Check '%s' failed in %s at %s:%d", "keys", __FUNCTION__, "../src/lib/xmmstypes/xmmsv_dict.c"
, 295); return (0); }
;
296 x_return_val_if_fail (xmmsv_get_dict_iter (dictv, &it), 0)if (!(xmmsv_get_dict_iter (dictv, &it))) { xmmsc_log ("xmmsc/xmmstypes"
, XMMS_LOG_LEVEL_FAIL, "Check '%s' failed in %s at %s:%d", "xmmsv_get_dict_iter (dictv, &it)"
, __FUNCTION__, "../src/lib/xmmstypes/xmmsv_dict.c", 296); return
(0); }
;
297
298 *keys = xmmsv_new_list ();
299 xmmsv_list_restrict_type (*keys, XMMSV_TYPE_STRING);
300 while (xmmsv_dict_iter_pair (it, &key, NULL((void*)0))) {
301 xmmsv_list_append_string (*keys, key);
302 xmmsv_dict_iter_next (it);
303 }
304
305 xmmsv_dict_iter_explicit_destroy (it);
306
307 return 1;
308}
309
310/**
311 * Get a #XMMSV_TYPE_LIST of all the values.
312 *
313 * @param val A xmmsv_t containing a dict.
314 * @param keys Pointer that will own the reference
315 * to the new list containing the dict values.
316 * @return 1 upon success otherwise 0
317 */
318int xmmsv_dict_values (xmmsv_t *dictv, xmmsv_t **values)
319{
320 xmmsv_dict_iter_t *it;
321 xmmsv_t *value;
322
323 x_return_val_if_fail (values, 0)if (!(values)) { xmmsc_log ("xmmsc/xmmstypes", XMMS_LOG_LEVEL_FAIL
, "Check '%s' failed in %s at %s:%d", "values", __FUNCTION__,
"../src/lib/xmmstypes/xmmsv_dict.c", 323); return (0); }
;
324 x_return_val_if_fail (xmmsv_get_dict_iter (dictv, &it), 0)if (!(xmmsv_get_dict_iter (dictv, &it))) { xmmsc_log ("xmmsc/xmmstypes"
, XMMS_LOG_LEVEL_FAIL, "Check '%s' failed in %s at %s:%d", "xmmsv_get_dict_iter (dictv, &it)"
, __FUNCTION__, "../src/lib/xmmstypes/xmmsv_dict.c", 324); return
(0); }
;
325
326 *values = xmmsv_new_list ();
327 while (xmmsv_dict_iter_pair (it, NULL((void*)0), &value)) {
328 xmmsv_list_append (*values, value);
329 xmmsv_dict_iter_next (it);
330 }
331
332 xmmsv_dict_iter_explicit_destroy (it);
333
334 return 1;
335}
336
337/**
338 * Gets the type of a dict entry.
339 *
340 * @param val A xmmsv_t containing a dict.
341 * @param key The key in the dict.
342 * @return The type of the entry or #XMMSV_TYPE_NONE if something goes wrong.
343 */
344xmmsv_type_t
345xmmsv_dict_entry_get_type (xmmsv_t *val, const char *key)
346{
347 xmmsv_t *v;
348
349 if (!xmmsv_dict_get (val, key, &v)) {
350 return XMMSV_TYPE_NONE;
351 }
352
353 return xmmsv_get_type (v);
354}
355
356/**
357 * Get the element corresponding to the given key in the dict #xmmsv_t
358 * (if it exists). This function does not increase the refcount of
359 * the element, the reference is still owned by the dict.
360 *
361 * @param dictv A #xmmsv_t containing a dict.
362 * @param key The key in the dict.
363 * @param val Pointer set to a borrowed reference to the element
364 * corresponding to the given key in the dict.
365 * @return 1 upon success otherwise 0
366 */
367int
368xmmsv_dict_get (xmmsv_t *dictv, const char *key, xmmsv_t **val)
369{
370 xmmsv_dict_internal_t *dict;
371 int ret = 0;
372 int pos, deleted;
373
374 x_return_val_if_fail (key, 0)if (!(key)) { xmmsc_log ("xmmsc/xmmstypes", XMMS_LOG_LEVEL_FAIL
, "Check '%s' failed in %s at %s:%d", "key", __FUNCTION__, "../src/lib/xmmstypes/xmmsv_dict.c"
, 374); return (0); }
;
375 x_return_val_if_fail (dictv, 0)if (!(dictv)) { xmmsc_log ("xmmsc/xmmstypes", XMMS_LOG_LEVEL_FAIL
, "Check '%s' failed in %s at %s:%d", "dictv", __FUNCTION__, "../src/lib/xmmstypes/xmmsv_dict.c"
, 375); return (0); }
;
376 x_return_val_if_fail (xmmsv_is_type (dictv, XMMSV_TYPE_DICT), 0)if (!(xmmsv_is_type (dictv, XMMSV_TYPE_DICT))) { xmmsc_log ("xmmsc/xmmstypes"
, XMMS_LOG_LEVEL_FAIL, "Check '%s' failed in %s at %s:%d", "xmmsv_is_type (dictv, XMMSV_TYPE_DICT)"
, __FUNCTION__, "../src/lib/xmmstypes/xmmsv_dict.c", 376); return
(0); }
;
377
378 xmmsv_dict_data_t data = DICT_INIT_DATA (key){.hash = _xmmsv_dict_hash (key, strlen (key)), .str = (char*)
key}
;
379 dict = dictv->value.dict;
380
381 if (_xmmsv_dict_search (dict, data, &pos, &deleted)) {
382 /* If there was a deleted entry before the one we found
383 * we can optimize a little by moving the entry to the
384 * deleted slot (and thus closer to the actual bucket it
385 * belongs to)
386 */
387 if (deleted != -1) {
388 dict->data[deleted] = dict->data[pos];
389 dict->data[pos].str = DELETED_STR((char*)-1);
390 }
391 if (val != NULL((void*)0)) {
392 *val = dict->data[pos].value;
393 }
394 ret = 1;
395 }
396
397 return ret;
398}
399
400/**
401 * Insert an element under the given key in the dict #xmmsv_t. If the
402 * key already referenced an element, that element is unref'd and
403 * replaced by the new one.
404 *
405 * @param dictv A #xmmsv_t containing a dict.
406 * @param key The key in the dict.
407 * @param val The new element to insert in the dict.
408 * @return 1 upon success otherwise 0
409 */
410int
411xmmsv_dict_set (xmmsv_t *dictv, const char *key, xmmsv_t *val)
412{
413 xmmsv_dict_internal_t *dict;
414 int ret = 1;
415
416 x_return_val_if_fail (key, 0)if (!(key)) { xmmsc_log ("xmmsc/xmmstypes", XMMS_LOG_LEVEL_FAIL
, "Check '%s' failed in %s at %s:%d", "key", __FUNCTION__, "../src/lib/xmmstypes/xmmsv_dict.c"
, 416); return (0); }
;
417 x_return_val_if_fail (val, 0)if (!(val)) { xmmsc_log ("xmmsc/xmmstypes", XMMS_LOG_LEVEL_FAIL
, "Check '%s' failed in %s at %s:%d", "val", __FUNCTION__, "../src/lib/xmmstypes/xmmsv_dict.c"
, 417); return (0); }
;
418 x_return_val_if_fail (dictv, 0)if (!(dictv)) { xmmsc_log ("xmmsc/xmmstypes", XMMS_LOG_LEVEL_FAIL
, "Check '%s' failed in %s at %s:%d", "dictv", __FUNCTION__, "../src/lib/xmmstypes/xmmsv_dict.c"
, 418); return (0); }
;
419 x_return_val_if_fail (xmmsv_is_type (dictv, XMMSV_TYPE_DICT), 0)if (!(xmmsv_is_type (dictv, XMMSV_TYPE_DICT))) { xmmsc_log ("xmmsc/xmmstypes"
, XMMS_LOG_LEVEL_FAIL, "Check '%s' failed in %s at %s:%d", "xmmsv_is_type (dictv, XMMSV_TYPE_DICT)"
, __FUNCTION__, "../src/lib/xmmstypes/xmmsv_dict.c", 419); return
(0); }
;
420
421 xmmsv_dict_data_t data = DICT_INIT_DATA (key){.hash = _xmmsv_dict_hash (key, strlen (key)), .str = (char*)
key}
;
422 data.value = xmmsv_ref (val);
423 dict = dictv->value.dict;
424
425 /* Resize if fill is too high */
426 if (((dict->elems * 10) >> dict->size) > HASH_FILL_LIM7) {
427 _xmmsv_dict_resize (dict);
428 }
429
430 _xmmsv_dict_insert (dict, data, 1);
431
432 return ret;
433}
434
435/**
436 * Remove the element corresponding to a given key in the dict
437 * #xmmsv_t (if it exists).
438 *
439 * @param dictv A #xmmsv_t containing a dict.
440 * @param key The key in the dict.
441 * @return 1 upon success otherwise 0
442 */
443int
444xmmsv_dict_remove (xmmsv_t *dictv, const char *key)
445{
446 xmmsv_dict_internal_t *dict;
447 int pos, deleted;
448 int ret = 0;
449
450 x_return_val_if_fail (key, 0)if (!(key)) { xmmsc_log ("xmmsc/xmmstypes", XMMS_LOG_LEVEL_FAIL
, "Check '%s' failed in %s at %s:%d", "key", __FUNCTION__, "../src/lib/xmmstypes/xmmsv_dict.c"
, 450); return (0); }
;
451 x_return_val_if_fail (dictv, 0)if (!(dictv)) { xmmsc_log ("xmmsc/xmmstypes", XMMS_LOG_LEVEL_FAIL
, "Check '%s' failed in %s at %s:%d", "dictv", __FUNCTION__, "../src/lib/xmmstypes/xmmsv_dict.c"
, 451); return (0); }
;
452 x_return_val_if_fail (xmmsv_is_type (dictv, XMMSV_TYPE_DICT), 0)if (!(xmmsv_is_type (dictv, XMMSV_TYPE_DICT))) { xmmsc_log ("xmmsc/xmmstypes"
, XMMS_LOG_LEVEL_FAIL, "Check '%s' failed in %s at %s:%d", "xmmsv_is_type (dictv, XMMSV_TYPE_DICT)"
, __FUNCTION__, "../src/lib/xmmstypes/xmmsv_dict.c", 452); return
(0); }
;
453
454 xmmsv_dict_data_t data = DICT_INIT_DATA (key){.hash = _xmmsv_dict_hash (key, strlen (key)), .str = (char*)
key}
;
455 dict = dictv->value.dict;
456
457 /* If we find the entry we free the string and mark it as deleted */
458 if (_xmmsv_dict_search (dict, data, &pos, &deleted)) {
459 _xmmsv_dict_remove (dict, pos);
460 ret = 1;
461 }
462
463 return ret;
464}
465
466/**
467 * Empty the dict of all its elements.
468 *
469 * @param dictv A #xmmsv_t containing a dict.
470 * @return 1 upon success otherwise 0
471 */
472int
473xmmsv_dict_clear (xmmsv_t *dictv)
474{
475 int i;
476 xmmsv_dict_internal_t *dict;
477
478 x_return_val_if_fail (dictv, 0)if (!(dictv)) { xmmsc_log ("xmmsc/xmmstypes", XMMS_LOG_LEVEL_FAIL
, "Check '%s' failed in %s at %s:%d", "dictv", __FUNCTION__, "../src/lib/xmmstypes/xmmsv_dict.c"
, 478); return (0); }
;
479 x_return_val_if_fail (xmmsv_is_type (dictv, XMMSV_TYPE_DICT), 0)if (!(xmmsv_is_type (dictv, XMMSV_TYPE_DICT))) { xmmsc_log ("xmmsc/xmmstypes"
, XMMS_LOG_LEVEL_FAIL, "Check '%s' failed in %s at %s:%d", "xmmsv_is_type (dictv, XMMSV_TYPE_DICT)"
, __FUNCTION__, "../src/lib/xmmstypes/xmmsv_dict.c", 479); return
(0); }
;
480
481 dict = dictv->value.dict;
482
483 for (i = (1 << dict->size) - 1; i >= 0; i--) {
484 if (dict->data[i].str != NULL((void*)0)) {
485 if (dict->data[i].str != DELETED_STR((char*)-1)) {
486 free (dict->data[i].str);
487 xmmsv_unref (dict->data[i].value);
488 }
489 dict->data[i].str = NULL((void*)0);
490 }
491 }
492
493 return 1;
494}
495
496/**
497 * Apply a function to each key-element pair in the list. No
498 * particular order is assumed.
499 *
500 * @param dictv A #xmmsv_t containing a dict.
501 * @param function The function to apply to each key-element pair.
502 * @param user_data User data passed to the foreach function.
503 * @return 1 upon success otherwise 0
504 */
505int
506xmmsv_dict_foreach (xmmsv_t *dictv, xmmsv_dict_foreach_func func,
507 void *user_data)
508{
509 xmmsv_dict_iter_t *it;
510 const char *key;
511 xmmsv_t *v;
512
513 x_return_val_if_fail (dictv, 0)if (!(dictv)) { xmmsc_log ("xmmsc/xmmstypes", XMMS_LOG_LEVEL_FAIL
, "Check '%s' failed in %s at %s:%d", "dictv", __FUNCTION__, "../src/lib/xmmstypes/xmmsv_dict.c"
, 513); return (0); }
;
514 x_return_val_if_fail (xmmsv_is_type (dictv, XMMSV_TYPE_DICT), 0)if (!(xmmsv_is_type (dictv, XMMSV_TYPE_DICT))) { xmmsc_log ("xmmsc/xmmstypes"
, XMMS_LOG_LEVEL_FAIL, "Check '%s' failed in %s at %s:%d", "xmmsv_is_type (dictv, XMMSV_TYPE_DICT)"
, __FUNCTION__, "../src/lib/xmmstypes/xmmsv_dict.c", 514); return
(0); }
;
515 x_return_val_if_fail (xmmsv_get_dict_iter (dictv, &it), 0)if (!(xmmsv_get_dict_iter (dictv, &it))) { xmmsc_log ("xmmsc/xmmstypes"
, XMMS_LOG_LEVEL_FAIL, "Check '%s' failed in %s at %s:%d", "xmmsv_get_dict_iter (dictv, &it)"
, __FUNCTION__, "../src/lib/xmmstypes/xmmsv_dict.c", 515); return
(0); }
;
516
517 while (xmmsv_dict_iter_pair (it, &key, &v)) {
518 func (key, v, user_data);
519 xmmsv_dict_iter_next (it);
520 }
521
522 _xmmsv_dict_iter_free (it);
523
524 return 1;
525}
526
527/**
528 * Return the size of the dict.
529 *
530 * @param dictv The #xmmsv_t containing the dict.
531 * @return The size of the dict, or -1 if dict is invalid.
532 */
533int
534xmmsv_dict_get_size (xmmsv_t *dictv)
535{
536 x_return_val_if_fail (dictv, -1)if (!(dictv)) { xmmsc_log ("xmmsc/xmmstypes", XMMS_LOG_LEVEL_FAIL
, "Check '%s' failed in %s at %s:%d", "dictv", __FUNCTION__, "../src/lib/xmmstypes/xmmsv_dict.c"
, 536); return (-1); }
;
537 x_return_val_if_fail (xmmsv_is_type (dictv, XMMSV_TYPE_DICT), -1)if (!(xmmsv_is_type (dictv, XMMSV_TYPE_DICT))) { xmmsc_log ("xmmsc/xmmstypes"
, XMMS_LOG_LEVEL_FAIL, "Check '%s' failed in %s at %s:%d", "xmmsv_is_type (dictv, XMMSV_TYPE_DICT)"
, __FUNCTION__, "../src/lib/xmmstypes/xmmsv_dict.c", 537); return
(-1); }
;
538
539 return dictv->value.dict->elems;
540}
541
542static xmmsv_dict_iter_t *
543_xmmsv_dict_iter_new (xmmsv_dict_internal_t *d)
544{
545 xmmsv_dict_iter_t *it;
546
547 it = x_new0 (xmmsv_dict_iter_t, 1)calloc (1, sizeof (xmmsv_dict_iter_t) * (1));
548 if (!it) {
549 x_oom ()xmmsc_log ("xmmsc/xmmstypes", XMMS_LOG_LEVEL_FAIL, "Out of memory in %s at %s:%d"
, __FUNCTION__, "../src/lib/xmmstypes/xmmsv_dict.c", 549)
;
550 return NULL((void*)0);
551 }
552
553 it->parent = d;
554 xmmsv_dict_iter_first (it);
555
556 /* register iterator into parent */
557 d->iterators = x_list_prepend (d->iterators, it);
558
559 return it;
560}
561
562static void
563_xmmsv_dict_iter_free (xmmsv_dict_iter_t *it)
564{
565 /* unref iterator from dict and free it */
566 it->parent->iterators = x_list_remove (it->parent->iterators, it);
567 free (it);
3
Memory is released
568}
569
570/**
571 * Retrieves a dict iterator from a dict #xmmsv_t.
572 *
573 * @param val a #xmmsv_t containing a dict.
574 * @param it An #xmmsv_dict_iter_t that can be used to access the dict
575 * data. The iterator will be freed when the value is freed.
576 * @return 1 upon success otherwise 0
577 */
578int
579xmmsv_get_dict_iter (const xmmsv_t *val, xmmsv_dict_iter_t **it)
580{
581 xmmsv_dict_iter_t *new_it;
582
583 if (!val || val->type != XMMSV_TYPE_DICT) {
584 *it = NULL((void*)0);
585 return 0;
586 }
587
588 new_it = _xmmsv_dict_iter_new (val->value.dict);
589 if (!new_it) {
590 *it = NULL((void*)0);
591 return 0;
592 }
593
594 *it = new_it;
595
596 return 1;
597}
598
599/**
600 * Explicitly free dict iterator.
601 *
602 * Immediately frees any resources used by this iterator. The iterator
603 * is freed automatically when the dict is freed, but this function is
604 * useful when the dict can be long lived.
605 *
606 * @param it iterator to free
607 *
608 */
609void
610xmmsv_dict_iter_explicit_destroy (xmmsv_dict_iter_t *it)
611{
612 _xmmsv_dict_iter_free (it);
613}
614
615/**
616 * Get the key-element pair currently pointed at by the iterator. This
617 * function does not increase the refcount of the element, the
618 * reference is still owned by the dict.
619 *
620 * @param it A #xmmsv_dict_iter_t.
621 * @param key Pointer set to the key pointed at by the iterator.
622 * @param val Pointer set to a borrowed reference to the element
623 * pointed at by the iterator.
624 * @return 1 upon success otherwise 0
625 */
626int
627xmmsv_dict_iter_pair (xmmsv_dict_iter_t *it, const char **key,
628 xmmsv_t **val)
629{
630 if (!xmmsv_dict_iter_valid (it)) {
631 return 0;
632 }
633
634 if (key) {
635 *key = it->parent->data[it->pos].str;
636 }
637
638 if (val) {
639 *val = it->parent->data[it->pos].value;
640 }
641
642 return 1;
643}
644
645/**
646 * Check whether the iterator is valid and points to a valid pair.
647 *
648 * @param it A #xmmsv_dict_iter_t.
649 * @return 1 if the iterator is valid, 0 otherwise
650 */
651int
652xmmsv_dict_iter_valid (xmmsv_dict_iter_t *it)
653{
654 return it && (it->pos < (1 << it->parent->size))
655 && it->parent->data[it->pos].str != NULL((void*)0)
656 && it->parent->data[it->pos].str != DELETED_STR((char*)-1);
657}
658
659/**
660 * Rewind the iterator to the start of the dict.
661 *
662 * @param it A #xmmsv_dict_iter_t.
663 * @return 1 upon success otherwise 0
664 */
665void
666xmmsv_dict_iter_first (xmmsv_dict_iter_t *it)
667{
668 x_return_if_fail (it)if (!(it)) { xmmsc_log ("xmmsc/xmmstypes", XMMS_LOG_LEVEL_FAIL
, "Check '%s' failed in %s at %s:%d", "it", __FUNCTION__, "../src/lib/xmmstypes/xmmsv_dict.c"
, 668); return; }
;
669 xmmsv_dict_internal_t *d = it->parent;
670
671 for (it->pos = 0
672 ; it->pos < (1 << d->size) && (d->data[it->pos].str == NULL((void*)0) || d->data[it->pos].str == DELETED_STR((char*)-1))
673 ; it->pos++);
674}
675
676/**
677 * Advance the iterator to the next pair in the dict.
678 *
679 * @param it A #xmmsv_dict_iter_t.
680 * @return 1 upon success otherwise 0
681 */
682void
683xmmsv_dict_iter_next (xmmsv_dict_iter_t *it)
684{
685 x_return_if_fail (it)if (!(it)) { xmmsc_log ("xmmsc/xmmstypes", XMMS_LOG_LEVEL_FAIL
, "Check '%s' failed in %s at %s:%d", "it", __FUNCTION__, "../src/lib/xmmstypes/xmmsv_dict.c"
, 685); return; }
;
686 xmmsv_dict_internal_t *d = it->parent;
687
688 for (it->pos++
689 ; it->pos < (1 << d->size) && (d->data[it->pos].str == NULL((void*)0) || d->data[it->pos].str == DELETED_STR((char*)-1))
690 ; it->pos++);
691}
692
693/**
694 * Move the iterator to the pair with the given key (if it exists)
695 * or move it to the position where the key would have to be
696 * put (if it doesn't exist yet).
697 *
698 * @param it A #xmmsv_dict_iter_t.
699 * @param key The key to seek for.
700 * @return 1 upon success otherwise 0
701 */
702int
703xmmsv_dict_iter_find (xmmsv_dict_iter_t *it, const char *key)
704{
705 x_return_val_if_fail (xmmsv_dict_iter_valid (it), 0)if (!(xmmsv_dict_iter_valid (it))) { xmmsc_log ("xmmsc/xmmstypes"
, XMMS_LOG_LEVEL_FAIL, "Check '%s' failed in %s at %s:%d", "xmmsv_dict_iter_valid (it)"
, __FUNCTION__, "../src/lib/xmmstypes/xmmsv_dict.c", 705); return
(0); }
;
706
707 xmmsv_dict_iter_first (it);
708
709 for (xmmsv_dict_iter_first (it)
710 ; xmmsv_dict_iter_valid (it)
711 ; xmmsv_dict_iter_next (it)) {
712 const char *s;
713
714 xmmsv_dict_iter_pair (it, &s, NULL((void*)0));
715 if (strcmp (s, key) == 0)
716 return 1;
717 }
718
719 return 0;
720}
721
722/**
723 * Replace the element of the pair currently pointed to by the
724 * iterator.
725 *
726 * @param it A #xmmsv_dict_iter_t.
727 * @param val The element to set in the pair.
728 * @return 1 upon success otherwise 0
729 */
730int
731xmmsv_dict_iter_set (xmmsv_dict_iter_t *it, xmmsv_t *val)
732{
733 x_return_val_if_fail (xmmsv_dict_iter_valid (it), 0)if (!(xmmsv_dict_iter_valid (it))) { xmmsc_log ("xmmsc/xmmstypes"
, XMMS_LOG_LEVEL_FAIL, "Check '%s' failed in %s at %s:%d", "xmmsv_dict_iter_valid (it)"
, __FUNCTION__, "../src/lib/xmmstypes/xmmsv_dict.c", 733); return
(0); }
;
734 x_return_val_if_fail (val, 0)if (!(val)) { xmmsc_log ("xmmsc/xmmstypes", XMMS_LOG_LEVEL_FAIL
, "Check '%s' failed in %s at %s:%d", "val", __FUNCTION__, "../src/lib/xmmstypes/xmmsv_dict.c"
, 734); return (0); }
;
735
736 /* In case old value is new value, ref first. */
737 xmmsv_ref (val);
738 xmmsv_unref (it->parent->data[it->pos].value);
739 it->parent->data[it->pos].value = val;
740
741 return 1;
742}
743
744/**
745 * Remove the pair in the dict pointed at by the iterator.
746 *
747 * @param it A #xmmsv_dict_iter_t.
748 * @return 1 upon success otherwise 0
749 */
750int
751xmmsv_dict_iter_remove (xmmsv_dict_iter_t *it)
752{
753 x_return_val_if_fail (xmmsv_dict_iter_valid (it), 0)if (!(xmmsv_dict_iter_valid (it))) { xmmsc_log ("xmmsc/xmmstypes"
, XMMS_LOG_LEVEL_FAIL, "Check '%s' failed in %s at %s:%d", "xmmsv_dict_iter_valid (it)"
, __FUNCTION__, "../src/lib/xmmstypes/xmmsv_dict.c", 753); return
(0); }
;
754
755 _xmmsv_dict_remove (it->parent, it->pos);
756 xmmsv_dict_iter_next (it);
757
758 return 1;
759}
760
761/* macro-magically define dict extractors */
762#define GEN_DICT_EXTRACTOR_FUNC(typename, type)int xmmsv_dict_entry_get_typename (xmmsv_t *val, const char *
key, type *r) { xmmsv_t *v; if (!xmmsv_dict_get (val, key, &
v)) { return 0; } return xmmsv_get_typename (v, r); }
\
763 int \
764 xmmsv_dict_entry_get_##typename (xmmsv_t *val, const char *key, \
765 type *r) \
766 { \
767 xmmsv_t *v; \
768 if (!xmmsv_dict_get (val, key, &v)) { \
769 return 0; \
770 } \
771 return xmmsv_get_##typename (v, r); \
772 }
773
774GEN_DICT_EXTRACTOR_FUNC (string, const char *)int xmmsv_dict_entry_get_string (xmmsv_t *val, const char *key
, const char * *r) { xmmsv_t *v; if (!xmmsv_dict_get (val, key
, &v)) { return 0; } return xmmsv_get_string (v, r); }
775GEN_DICT_EXTRACTOR_FUNC (int32, int32_t)int xmmsv_dict_entry_get_int32 (xmmsv_t *val, const char *key
, int32_t *r) { xmmsv_t *v; if (!xmmsv_dict_get (val, key, &
v)) { return 0; } return xmmsv_get_int32 (v, r); }
776GEN_DICT_EXTRACTOR_FUNC (int64, int64_t)int xmmsv_dict_entry_get_int64 (xmmsv_t *val, const char *key
, int64_t *r) { xmmsv_t *v; if (!xmmsv_dict_get (val, key, &
v)) { return 0; } return xmmsv_get_int64 (v, r); }
777GEN_DICT_EXTRACTOR_FUNC (float, float)int xmmsv_dict_entry_get_float (xmmsv_t *val, const char *key
, float *r) { xmmsv_t *v; if (!xmmsv_dict_get (val, key, &
v)) { return 0; } return xmmsv_get_float (v, r); }
778
779int
780xmmsv_dict_entry_get_coll (xmmsv_t *val, const char *key, xmmsv_t **r)
781{
782 return xmmsv_dict_get (val, key, r);
783}
784
785/* macro-magically define dict set functions */
786#define GEN_DICT_SET_FUNC(typename, type)int xmmsv_dict_set_typename (xmmsv_t *dict, const char *key, type
elem) { int ret; xmmsv_t *v; v = xmmsv_new_typename (elem); ret
= xmmsv_dict_set (dict, key, v); xmmsv_unref (v); return ret
; }
\
787 int \
788 xmmsv_dict_set_##typename (xmmsv_t *dict, const char *key, type elem) \
789 { \
790 int ret; \
791 xmmsv_t *v; \
792 \
793 v = xmmsv_new_##typename (elem); \
794 ret = xmmsv_dict_set (dict, key, v); \
795 xmmsv_unref (v); \
796 \
797 return ret; \
798 }
799
800GEN_DICT_SET_FUNC (string, const char *)int xmmsv_dict_set_string (xmmsv_t *dict, const char *key, const
char * elem) { int ret; xmmsv_t *v; v = xmmsv_new_string (elem
); ret = xmmsv_dict_set (dict, key, v); xmmsv_unref (v); return
ret; }
801GEN_DICT_SET_FUNC (int, int64_t)int xmmsv_dict_set_int (xmmsv_t *dict, const char *key, int64_t
elem) { int ret; xmmsv_t *v; v = xmmsv_new_int (elem); ret =
xmmsv_dict_set (dict, key, v); xmmsv_unref (v); return ret; }
802GEN_DICT_SET_FUNC (float, float)int xmmsv_dict_set_float (xmmsv_t *dict, const char *key, float
elem) { int ret; xmmsv_t *v; v = xmmsv_new_float (elem); ret
= xmmsv_dict_set (dict, key, v); xmmsv_unref (v); return ret
; }
803
804int
805xmmsv_dict_set_coll (xmmsv_t *dict, const char *key, xmmsv_t *elem)
806{
807 return xmmsv_dict_set (dict, key, elem);
808}
809
810/* macro-magically define dict_iter extractors */
811#define GEN_DICT_ITER_EXTRACTOR_FUNC(typename, type)int xmmsv_dict_iter_pair_typename (xmmsv_dict_iter_t *it, const
char **key, type *r) { xmmsv_t *v; if (!xmmsv_dict_iter_pair
(it, key, &v)) { return 0; } if (r) { return xmmsv_get_typename
(v, r); } else { return 1; } }
\
812 int \
813 xmmsv_dict_iter_pair_##typename (xmmsv_dict_iter_t *it, \
814 const char **key, \
815 type *r) \
816 { \
817 xmmsv_t *v; \
818 if (!xmmsv_dict_iter_pair (it, key, &v)) { \
819 return 0; \
820 } \
821 if (r) { \
822 return xmmsv_get_##typename (v, r); \
823 } else { \
824 return 1; \
825 } \
826 }
827
828GEN_DICT_ITER_EXTRACTOR_FUNC (string, const char *)int xmmsv_dict_iter_pair_string (xmmsv_dict_iter_t *it, const
char **key, const char * *r) { xmmsv_t *v; if (!xmmsv_dict_iter_pair
(it, key, &v)) { return 0; } if (r) { return xmmsv_get_string
(v, r); } else { return 1; } }
829GEN_DICT_ITER_EXTRACTOR_FUNC (int32, int32_t)int xmmsv_dict_iter_pair_int32 (xmmsv_dict_iter_t *it, const char
**key, int32_t *r) { xmmsv_t *v; if (!xmmsv_dict_iter_pair (
it, key, &v)) { return 0; } if (r) { return xmmsv_get_int32
(v, r); } else { return 1; } }
830GEN_DICT_ITER_EXTRACTOR_FUNC (int64, int64_t)int xmmsv_dict_iter_pair_int64 (xmmsv_dict_iter_t *it, const char
**key, int64_t *r) { xmmsv_t *v; if (!xmmsv_dict_iter_pair (
it, key, &v)) { return 0; } if (r) { return xmmsv_get_int64
(v, r); } else { return 1; } }
831GEN_DICT_ITER_EXTRACTOR_FUNC (float, float)int xmmsv_dict_iter_pair_float (xmmsv_dict_iter_t *it, const char
**key, float *r) { xmmsv_t *v; if (!xmmsv_dict_iter_pair (it
, key, &v)) { return 0; } if (r) { return xmmsv_get_float
(v, r); } else { return 1; } }
832
833int
834xmmsv_dict_iter_pair_coll (xmmsv_dict_iter_t *it, const char **key, xmmsv_t **r)
835{
836 return xmmsv_dict_iter_pair (it, key, r);
837}
838
839/* macro-magically define dict_iter set functions */
840#define GEN_DICT_ITER_SET_FUNC(typename, type)int xmmsv_dict_iter_set_typename (xmmsv_dict_iter_t *it, type
elem) { int ret; xmmsv_t *v; v = xmmsv_new_typename (elem); ret
= xmmsv_dict_iter_set (it, v); xmmsv_unref (v); return ret; }
\
841 int \
842 xmmsv_dict_iter_set_##typename (xmmsv_dict_iter_t *it, type elem) \
843 { \
844 int ret; \
845 xmmsv_t *v; \
846 \
847 v = xmmsv_new_##typename (elem); \
848 ret = xmmsv_dict_iter_set (it, v); \
849 xmmsv_unref (v); \
850 \
851 return ret; \
852 }
853
854GEN_DICT_ITER_SET_FUNC (string, const char *)int xmmsv_dict_iter_set_string (xmmsv_dict_iter_t *it, const char
* elem) { int ret; xmmsv_t *v; v = xmmsv_new_string (elem); ret
= xmmsv_dict_iter_set (it, v); xmmsv_unref (v); return ret; }
855GEN_DICT_ITER_SET_FUNC (int, int64_t)int xmmsv_dict_iter_set_int (xmmsv_dict_iter_t *it, int64_t elem
) { int ret; xmmsv_t *v; v = xmmsv_new_int (elem); ret = xmmsv_dict_iter_set
(it, v); xmmsv_unref (v); return ret; }
856GEN_DICT_ITER_SET_FUNC (float, float)int xmmsv_dict_iter_set_float (xmmsv_dict_iter_t *it, float elem
) { int ret; xmmsv_t *v; v = xmmsv_new_float (elem); ret = xmmsv_dict_iter_set
(it, v); xmmsv_unref (v); return ret; }
857
858int
859xmmsv_dict_iter_set_coll (xmmsv_dict_iter_t *it, xmmsv_t *elem)
860{
861 return xmmsv_dict_iter_set (it, elem);
862}