XMMS2
value.c
Go to the documentation of this file.
1/* XMMS2 - X Music Multiplexer System
2 * Copyright (C) 2003-2011 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 <stdio.h>
18#include <stdlib.h>
19#include <stdarg.h>
20#include <string.h>
21#include <ctype.h>
22#include <assert.h>
23
24#include "xmmsc/xmmsv.h"
27#include "xmmsc/xmmsc_stdbool.h"
28#include "xmmsc/xmmsc_util.h"
29#include "xmmspriv/xmms_list.h"
30
31/** @file */
32
33/* Default source preferences for accessing "propdicts" */
34const char *default_source_pref[] = {
35 "server",
36 "client/*",
37 "plugin/playlist",
38 "plugin/id3v2",
39 "plugin/segment",
40 "plugin/*",
41 "*",
42 NULL
43};
44
45
46typedef struct xmmsv_list_St xmmsv_list_t;
47typedef struct xmmsv_dict_St xmmsv_dict_t;
48
49
50typedef struct xmmsv_bin_St {
51 unsigned char *data;
52 uint32_t len;
54
55struct xmmsv_list_St {
56 xmmsv_t **list;
57 xmmsv_t *parent_value;
58 int size;
59 int allocated;
60 bool restricted;
61 xmmsv_type_t restricttype;
62 x_list_t *iterators;
63};
64
65static xmmsv_list_t *xmmsv_list_new (void);
66static void xmmsv_list_free (xmmsv_list_t *l);
67static int xmmsv_list_resize (xmmsv_list_t *l, int newsize);
68static int _xmmsv_list_insert (xmmsv_list_t *l, int pos, xmmsv_t *val);
69static int _xmmsv_list_append (xmmsv_list_t *l, xmmsv_t *val);
70static int _xmmsv_list_remove (xmmsv_list_t *l, int pos);
71static int _xmmsv_list_move (xmmsv_list_t *l, int old_pos, int new_pos);
72static void _xmmsv_list_clear (xmmsv_list_t *l);
73
74static xmmsv_dict_t *xmmsv_dict_new (void);
75static void xmmsv_dict_free (xmmsv_dict_t *dict);
76
77
78struct xmmsv_list_iter_St {
79 xmmsv_list_t *parent;
80 int position;
81};
82
83static xmmsv_list_iter_t *xmmsv_list_iter_new (xmmsv_list_t *l);
84static void xmmsv_list_iter_free (xmmsv_list_iter_t *it);
85
86
87static xmmsv_dict_iter_t *xmmsv_dict_iter_new (xmmsv_dict_t *d);
88static void xmmsv_dict_iter_free (xmmsv_dict_iter_t *it);
89
90
91
92struct xmmsv_St {
93 union {
94 char *error;
95 int32_t int32;
96 char *string;
97 xmmsv_coll_t *coll;
98 xmmsv_bin_t bin;
99 xmmsv_list_t *list;
100 xmmsv_dict_t *dict;
101
102 struct {
103 bool ro;
104 unsigned char *buf;
105 int alloclen; /* in bits */
106 int len; /* in bits */
107 int pos; /* in bits */
108 } bit;
109 } value;
110 xmmsv_type_t type;
111
112 int ref; /* refcounting */
113};
114
115
116static xmmsv_t *xmmsv_new (xmmsv_type_t type);
117static void xmmsv_free (xmmsv_t *val);
118static int absolutify_and_validate_pos (int *pos, int size, int allow_append);
119
120
121
122
123/**
124 * Allocates a new empty #xmmsv_t.
125 * @return The new #xmmsv_t. Must be unreferenced with
126 * #xmmsv_unref.
127 */
128xmmsv_t *
130{
131 xmmsv_t *val = xmmsv_new (XMMSV_TYPE_NONE);
132 return val;
133}
134
135/**
136 * Allocates a new error #xmmsv_t.
137 * @param s The error message to store in the #xmmsv_t. The
138 * string is copied in the value.
139 * @return The new #xmmsv_t. Must be unreferenced with
140 * #xmmsv_unref.
141 */
142xmmsv_t *
143xmmsv_new_error (const char *errstr)
144{
145 xmmsv_t *val = xmmsv_new (XMMSV_TYPE_ERROR);
146
147 if (val) {
148 val->value.error = strdup (errstr);
149 }
150
151 return val;
152}
153
154/**
155 * Allocates a new integer #xmmsv_t.
156 * @param i The value to store in the #xmmsv_t.
157 * @return The new #xmmsv_t. Must be unreferenced with
158 * #xmmsv_unref.
159 */
160xmmsv_t *
161xmmsv_new_int (int32_t i)
162{
163 xmmsv_t *val = xmmsv_new (XMMSV_TYPE_INT32);
164
165 if (val) {
166 val->value.int32 = i;
167 }
168
169 return val;
170}
171
172/**
173 * Allocates a new string #xmmsv_t.
174 * @param s The value to store in the #xmmsv_t. The string is
175 * copied in the value.
176 * @return The new #xmmsv_t. Must be unreferenced with
177 * #xmmsv_unref.
178 */
179xmmsv_t *
180xmmsv_new_string (const char *s)
181{
182 xmmsv_t *val;
183
184 x_return_val_if_fail (s, NULL);
186
187 val = xmmsv_new (XMMSV_TYPE_STRING);
188 if (val) {
189 val->value.string = strdup (s);
190 }
191
192 return val;
193}
194
195/**
196 * Allocates a new collection #xmmsv_t.
197 * @param s The value to store in the #xmmsv_t.
198 * @return The new #xmmsv_t. Must be unreferenced with
199 * #xmmsv_unref.
200 */
201xmmsv_t *
203{
204 xmmsv_t *val;
205
206 x_return_val_if_fail (c, NULL);
207
208 val = xmmsv_new (XMMSV_TYPE_COLL);
209 if (val) {
210 val->value.coll = c;
211 xmmsv_coll_ref (c);
212 }
213
214 return val;
215}
216
217/**
218 * Allocates a new binary data #xmmsv_t.
219 * @param data The data to store in the #xmmsv_t.
220 * @param len The size of the data.
221 * @return The new #xmmsv_t. Must be unreferenced with
222 * #xmmsv_unref.
223 */
224xmmsv_t *
225xmmsv_new_bin (const unsigned char *data, unsigned int len)
226{
227 xmmsv_t *val = xmmsv_new (XMMSV_TYPE_BIN);
228
229 if (val) {
230 /* copy the data! */
231 val->value.bin.data = x_malloc (len);
232 if (!val->value.bin.data) {
233 free (val);
234 x_oom ();
235 return NULL;
236 }
237 memcpy (val->value.bin.data, data, len);
238 val->value.bin.len = len;
239 }
240
241 return val;
242}
243
244/**
245 * Allocates a new list #xmmsv_t.
246 * @return The new #xmmsv_t. Must be unreferenced with
247 * #xmmsv_unref.
248 */
249xmmsv_t *
251{
252 xmmsv_t *val = xmmsv_new (XMMSV_TYPE_LIST);
253
254 if (val) {
255 val->value.list = xmmsv_list_new ();
256 val->value.list->parent_value = val;
257 }
258
259 return val;
260}
261
262/**
263 * Allocates a new dict #xmmsv_t.
264 * @return The new #xmmsv_t. Must be unreferenced with
265 * #xmmsv_unref.
266 */
267xmmsv_t *
269{
270 xmmsv_t *val = xmmsv_new (XMMSV_TYPE_DICT);
271
272 if (val) {
273 val->value.dict = xmmsv_dict_new ();
274 }
275
276 return val;
277}
278
279
280
281/**
282 * References the #xmmsv_t
283 *
284 * @param val the value to reference.
285 * @return val
286 */
287xmmsv_t *
289{
290 x_return_val_if_fail (val, NULL);
291 val->ref++;
292
293 return val;
294}
295
296/**
297 * Decreases the references for the #xmmsv_t
298 * When the number of references reaches 0 it will
299 * be freed. And thus all data you extracted from it
300 * will be deallocated.
301 */
302void
304{
305 x_return_if_fail (val);
306 x_api_error_if (val->ref < 1, "with a freed value",);
307
308 val->ref--;
309 if (val->ref == 0) {
310 xmmsv_free (val);
311 }
312}
313
314
315/**
316 * Allocates new #xmmsv_t and references it.
317 * @internal
318 */
319static xmmsv_t *
320xmmsv_new (xmmsv_type_t type)
321{
322 xmmsv_t *val;
323
324 val = x_new0 (xmmsv_t, 1);
325 if (!val) {
326 x_oom ();
327 return NULL;
328 }
329
330 val->type = type;
331
332 return xmmsv_ref (val);
333}
334
335/**
336 * Free a #xmmsv_t along with its internal data.
337 * @internal
338 */
339static void
340xmmsv_free (xmmsv_t *val)
341{
342 x_return_if_fail (val);
343
344 switch (val->type) {
345 case XMMSV_TYPE_NONE :
346 case XMMSV_TYPE_END :
347 case XMMSV_TYPE_INT32 :
348 break;
349 case XMMSV_TYPE_ERROR :
350 free (val->value.error);
351 val->value.error = NULL;
352 break;
353 case XMMSV_TYPE_STRING :
354 free (val->value.string);
355 val->value.string = NULL;
356 break;
357 case XMMSV_TYPE_COLL:
358 xmmsv_coll_unref (val->value.coll);
359 val->value.coll = NULL;
360 break;
361 case XMMSV_TYPE_BIN :
362 free (val->value.bin.data);
363 val->value.bin.len = 0;
364 break;
365 case XMMSV_TYPE_LIST:
366 xmmsv_list_free (val->value.list);
367 val->value.list = NULL;
368 break;
369 case XMMSV_TYPE_DICT:
370 xmmsv_dict_free (val->value.dict);
371 val->value.dict = NULL;
372 break;
374 if (!val->value.bit.ro && val->value.bit.buf) {
375 free (val->value.bit.buf);
376 }
377 val->value.bit.buf = NULL;
378 break;
379 }
380
381 free (val);
382}
383
384
385/**
386 * Get the type of the value.
387 *
388 * @param val a #xmmsv_t to get the type from.
389 * @returns The data type in the value.
390 */
393{
394 x_api_error_if (!val, "NULL value",
396
397 return val->type;
398}
399
400/**
401 * Check if value is of specified type.
402 *
403 * @param val #xmmsv_t to check.
404 * @param t #xmmsv_type_t to check for.
405 * @return 1 if value is of specified type, 0 otherwise.
406 */
407int
409{
410 x_api_error_if (!val, "NULL value", 0);
411
412 return (xmmsv_get_type (val) == t);
413}
414
415
416/* Merely legacy aliases */
417
418/**
419 * Check if the value stores an error.
420 *
421 * @param val a #xmmsv_t
422 * @return 1 if error was encountered, 0 otherwise.
423 */
424int
426{
427 return xmmsv_is_type (val, XMMSV_TYPE_ERROR);
428}
429
430/**
431 * Check if the value stores a list.
432 *
433 * @param val a #xmmsv_t
434 * @return 1 if value stores a list, 0 otherwise.
435 */
436int
438{
439 return xmmsv_is_type (val, XMMSV_TYPE_LIST);
440}
441
442/**
443 * Check if the value stores a dict.
444 *
445 * @param val a #xmmsv_t
446 * @return 1 if value stores a dict, 0 otherwise.
447 */
448int
450{
451 return xmmsv_is_type (val, XMMSV_TYPE_DICT);
452}
453
454/**
455 * Legacy alias to retrieve the error string from an
456 * #xmmsv_t. Obsolete now, use #xmmsv_get_error instead!
457 *
458 * @param val an error #xmmsv_t
459 * @return the error string if valid, NULL otherwise.
460 */
461const char *
463{
464 if (!val || val->type != XMMSV_TYPE_ERROR) {
465 return NULL;
466 }
467
468 return val->value.error;
469}
470
471/**
472 * Helper function to build a list #xmmsv_t containing the
473 * strings from the input array.
474 *
475 * @param array An array of C strings. Must be NULL-terminated if num
476 * is -1.
477 * @param num The optional number of elements to read from the array. Set to
478 * -1 if the array is NULL-terminated.
479 * @return An #xmmsv_t containing the list of strings. Must be
480 * unreffed manually when done.
481 */
482xmmsv_t *
483xmmsv_make_stringlist (char *array[], int num)
484{
485 xmmsv_t *list, *elem;
486 int i;
487
488 list = xmmsv_new_list ();
489 if (array) {
490 for (i = 0; (num >= 0 && i < num) || array[i]; i++) {
491 elem = xmmsv_new_string (array[i]);
492 xmmsv_list_append (list, elem);
493 xmmsv_unref (elem);
494 }
495 }
496
497 return list;
498}
499
500/**
501 * Gets the type of a dict entry.
502 *
503 * @param val A xmmsv_t containing a dict.
504 * @param key The key in the dict.
505 * @return The type of the entry or #XMMSV_TYPE_NONE if something goes wrong.
506 */
508xmmsv_dict_entry_get_type (xmmsv_t *val, const char *key)
509{
510 xmmsv_t *v;
511
512 if (!xmmsv_dict_get (val, key, &v)) {
513 return XMMSV_TYPE_NONE;
514 }
515
516 return xmmsv_get_type (v);
517}
518
519
520/* macro-magically define dict extractors */
521#define GEN_DICT_EXTRACTOR_FUNC(typename, type) \
522 int \
523 xmmsv_dict_entry_get_##typename (xmmsv_t *val, const char *key, \
524 type *r) \
525 { \
526 xmmsv_t *v; \
527 if (!xmmsv_dict_get (val, key, &v)) { \
528 return 0; \
529 } \
530 return xmmsv_get_##typename (v, r); \
531 }
532
533GEN_DICT_EXTRACTOR_FUNC (string, const char *)
534GEN_DICT_EXTRACTOR_FUNC (int, int32_t)
536
537/* macro-magically define dict set functions */
538#define GEN_DICT_SET_FUNC(typename, type) \
539 int \
540 xmmsv_dict_set_##typename (xmmsv_t *dict, const char *key, type elem) \
541 { \
542 int ret; \
543 xmmsv_t *v; \
544 \
545 v = xmmsv_new_##typename (elem); \
546 ret = xmmsv_dict_set (dict, key, v); \
547 xmmsv_unref (v); \
548 \
549 return ret; \
550 }
551
552GEN_DICT_SET_FUNC (string, const char *)
553GEN_DICT_SET_FUNC (int, int32_t)
555
556/* macro-magically define dict_iter extractors */
557#define GEN_DICT_ITER_EXTRACTOR_FUNC(typename, type) \
558 int \
559 xmmsv_dict_iter_pair_##typename (xmmsv_dict_iter_t *it, \
560 const char **key, \
561 type *r) \
562 { \
563 xmmsv_t *v; \
564 if (!xmmsv_dict_iter_pair (it, key, &v)) { \
565 return 0; \
566 } \
567 if (r) { \
568 return xmmsv_get_##typename (v, r); \
569 } else { \
570 return 1; \
571 } \
572 }
573
574GEN_DICT_ITER_EXTRACTOR_FUNC (string, const char *)
575GEN_DICT_ITER_EXTRACTOR_FUNC (int, int32_t)
577
578/* macro-magically define dict_iter set functions */
579#define GEN_DICT_ITER_SET_FUNC(typename, type) \
580 int \
581 xmmsv_dict_iter_set_##typename (xmmsv_dict_iter_t *it, type elem) \
582 { \
583 int ret; \
584 xmmsv_t *v; \
585 \
586 v = xmmsv_new_##typename (elem); \
587 ret = xmmsv_dict_iter_set (it, v); \
588 xmmsv_unref (v); \
589 \
590 return ret; \
591 }
592
593GEN_DICT_ITER_SET_FUNC (string, const char *)
594GEN_DICT_ITER_SET_FUNC (int, int32_t)
596
597/* macro-magically define list extractors */
598#define GEN_LIST_EXTRACTOR_FUNC(typename, type) \
599 int \
600 xmmsv_list_get_##typename (xmmsv_t *val, int pos, type *r) \
601 { \
602 xmmsv_t *v; \
603 if (!xmmsv_list_get (val, pos, &v)) { \
604 return 0; \
605 } \
606 return xmmsv_get_##typename (v, r); \
607 }
608
609GEN_LIST_EXTRACTOR_FUNC (string, const char *)
610GEN_LIST_EXTRACTOR_FUNC (int, int32_t)
612
613/* macro-magically define list set functions */
614#define GEN_LIST_SET_FUNC(typename, type) \
615 int \
616 xmmsv_list_set_##typename (xmmsv_t *list, int pos, type elem) \
617 { \
618 int ret; \
619 xmmsv_t *v; \
620 \
621 v = xmmsv_new_##typename (elem); \
622 ret = xmmsv_list_set (list, pos, v); \
623 xmmsv_unref (v); \
624 \
625 return ret; \
626 }
627
628GEN_LIST_SET_FUNC (string, const char *)
629GEN_LIST_SET_FUNC (int, int32_t)
631
632/* macro-magically define list insert functions */
633#define GEN_LIST_INSERT_FUNC(typename, type) \
634 int \
635 xmmsv_list_insert_##typename (xmmsv_t *list, int pos, type elem) \
636 { \
637 int ret; \
638 xmmsv_t *v; \
639 \
640 v = xmmsv_new_##typename (elem); \
641 ret = xmmsv_list_insert (list, pos, v); \
642 xmmsv_unref (v); \
643 \
644 return ret; \
645 }
646
647GEN_LIST_INSERT_FUNC (string, const char *)
648GEN_LIST_INSERT_FUNC (int, int32_t)
650
651/* macro-magically define list append functions */
652#define GEN_LIST_APPEND_FUNC(typename, type) \
653 int \
654 xmmsv_list_append_##typename (xmmsv_t *list, type elem) \
655 { \
656 int ret; \
657 xmmsv_t *v; \
658 \
659 v = xmmsv_new_##typename (elem); \
660 ret = xmmsv_list_append (list, v); \
661 xmmsv_unref (v); \
662 \
663 return ret; \
664 }
665
666GEN_LIST_APPEND_FUNC (string, const char *)
667GEN_LIST_APPEND_FUNC (int, int32_t)
669
670/* macro-magically define list_iter extractors */
671#define GEN_LIST_ITER_EXTRACTOR_FUNC(typename, type) \
672 int \
673 xmmsv_list_iter_entry_##typename (xmmsv_list_iter_t *it, type *r) \
674 { \
675 xmmsv_t *v; \
676 if (!xmmsv_list_iter_entry (it, &v)) { \
677 return 0; \
678 } \
679 return xmmsv_get_##typename (v, r); \
680 }
681
682GEN_LIST_ITER_EXTRACTOR_FUNC (string, const char *)
683GEN_LIST_ITER_EXTRACTOR_FUNC (int, int32_t)
685
686/* macro-magically define list_iter insert functions */
687#define GEN_LIST_ITER_INSERT_FUNC(typename, type) \
688 int \
689 xmmsv_list_iter_insert_##typename (xmmsv_list_iter_t *it, type elem) \
690 { \
691 int ret; \
692 xmmsv_t *v; \
693 \
694 v = xmmsv_new_##typename (elem); \
695 ret = xmmsv_list_iter_insert (it, v); \
696 xmmsv_unref (v); \
697 \
698 return ret; \
699 }
700
701GEN_LIST_ITER_INSERT_FUNC (string, const char *)
702GEN_LIST_ITER_INSERT_FUNC (int, int32_t)
704
705static int
706source_match_pattern (const char *source, const char *pattern)
707{
708 int match = 0;
709 int lpos = strlen (pattern) - 1;
710
711 if (strcasecmp (pattern, source) == 0) {
712 match = 1;
713 } else if (lpos >= 0 && pattern[lpos] == '*' &&
714 (lpos == 0 || strncasecmp (source, pattern, lpos) == 0)) {
715 match = 1;
716 }
717
718 return match;
719}
720
721/* Return the index of the source in the source prefs list, or -1 if
722 * no match.
723 */
724static int
725find_match_index (const char *source, const char **src_prefs)
726{
727 int i, match = -1;
728
729 for (i = 0; src_prefs[i]; i++) {
730 if (source_match_pattern (source, src_prefs[i])) {
731 match = i;
732 break;
733 }
734 }
735
736 return match;
737}
738
739/**
740 * Helper function to transform a key-source-value dict-of-dict
741 * #xmmsv_t (formerly a propdict) to a regular key-value dict, given a
742 * list of source preference.
743 *
744 * @param propdict A key-source-value dict-of-dict #xmmsv_t.
745 * @param src_prefs A list of source names or patterns. Must be
746 * NULL-terminated. If this argument is NULL, the
747 * default source preferences is used.
748 * @return An #xmmsv_t containing a simple key-value dict. Must be
749 * unreffed manually when done.
750 */
751xmmsv_t *
752xmmsv_propdict_to_dict (xmmsv_t *propdict, const char **src_prefs)
753{
754 xmmsv_t *dict, *source_dict, *value, *best_value;
755 xmmsv_dict_iter_t *key_it, *source_it;
756 const char *key, *source;
757 const char **local_prefs;
758 int match_index, best_index;
759
760 dict = xmmsv_new_dict ();
761
762 local_prefs = src_prefs ? src_prefs : default_source_pref;
763
764 xmmsv_get_dict_iter (propdict, &key_it);
765 while (xmmsv_dict_iter_valid (key_it)) {
766 xmmsv_dict_iter_pair (key_it, &key, &source_dict);
767
768 best_value = NULL;
769 best_index = -1;
770 xmmsv_get_dict_iter (source_dict, &source_it);
771 while (xmmsv_dict_iter_valid (source_it)) {
772 xmmsv_dict_iter_pair (source_it, &source, &value);
773 match_index = find_match_index (source, local_prefs);
774 /* keep first match or better match */
775 if (match_index >= 0 && (best_index < 0 ||
776 match_index < best_index)) {
777 best_value = value;
778 best_index = match_index;
779 }
780 xmmsv_dict_iter_next (source_it);
781 }
782
783 /* Note: we do not insert a key-value pair if no source matches */
784 if (best_value) {
785 xmmsv_dict_set (dict, key, best_value);
786 }
787
788 xmmsv_dict_iter_next (key_it);
789 }
790
791 return dict;
792}
793
794
795/**
796 * Retrieves an error string describing the server error from the
797 * value.
798 *
799 * @param val a #xmmsv_t containing a integer.
800 * @param r the return error.
801 * @return 1 upon success otherwise 0
802 */
803int
804xmmsv_get_error (const xmmsv_t *val, const char **r)
805{
806 if (!val || val->type != XMMSV_TYPE_ERROR) {
807 return 0;
808 }
809
810 *r = val->value.error;
811
812 return 1;
813}
814
815/**
816 * Retrieves a signed integer from the value.
817 *
818 * @param val a #xmmsv_t containing an integer.
819 * @param r the return integer.
820 * @return 1 upon success otherwise 0
821 */
822int
823xmmsv_get_int (const xmmsv_t *val, int32_t *r)
824{
825 if (!val || val->type != XMMSV_TYPE_INT32) {
826 return 0;
827 }
828
829 *r = val->value.int32;
830
831 return 1;
832}
833
834/**
835 * Retrieves a unsigned integer from the value.
836 *
837 * @param val a #xmmsv_t containing an unsigned integer.
838 * @param r the return unsigned integer.
839 * @return 1 upon success otherwise 0
840 */
841int
842xmmsv_get_uint (const xmmsv_t *val, uint32_t *r)
843{
844 if (!val)
845 return 0;
846 if (val->type != XMMSV_TYPE_INT32)
847 return 0;
848
849 *r = val->value.int32;
850
851 return 1;
852}
853
854/**
855 * Retrieves a string from the value.
856 *
857 * @param val a #xmmsv_t containing a string.
858 * @param r the return string. This string is owned by the value and
859 * will be freed when the value is freed.
860 * @return 1 upon success otherwise 0
861 */
862int
863xmmsv_get_string (const xmmsv_t *val, const char **r)
864{
865 if (!val || val->type != XMMSV_TYPE_STRING) {
866 return 0;
867 }
868
869 *r = val->value.string;
870
871 return 1;
872}
873
874/**
875 * Retrieves a collection from the value.
876 *
877 * @param val a #xmmsv_t containing a collection.
878 * @param c the return collection. This collection is owned by the
879 * value and will be unref'd when the value is freed.
880 * @return 1 upon success otherwise 0
881 */
882int
884{
885 if (!val || val->type != XMMSV_TYPE_COLL) {
886 return 0;
887 }
888
889 *c = val->value.coll;
890
891 return 1;
892}
893
894/**
895 * Retrieves binary data from the value.
896 *
897 * @param val a #xmmsv_t containing a string.
898 * @param r the return data. This data is owned by the value and will
899 * be freed when the value is freed.
900 * @param rlen the return length of data.
901 * @return 1 upon success otherwise 0
902 */
903int
904xmmsv_get_bin (const xmmsv_t *val, const unsigned char **r, unsigned int *rlen)
905{
906 if (!val || val->type != XMMSV_TYPE_BIN) {
907 return 0;
908 }
909
910 *r = val->value.bin.data;
911 *rlen = val->value.bin.len;
912
913 return 1;
914}
915
916
917/**
918 * Retrieves a list iterator from a list #xmmsv_t.
919 *
920 * @param val a #xmmsv_t containing a list.
921 * @param it An #xmmsv_list_iter_t that can be used to access the list
922 * data. The iterator will be freed when the value is freed.
923 * @return 1 upon success otherwise 0
924 */
925int
927{
928 xmmsv_list_iter_t *new_it;
929
930 if (!val || val->type != XMMSV_TYPE_LIST) {
931 *it = NULL;
932 return 0;
933 }
934
935 new_it = xmmsv_list_iter_new (val->value.list);
936 if (!new_it) {
937 *it = NULL;
938 return 0;
939 }
940
941 *it = new_it;
942
943 return 1;
944}
945
946/**
947 * Retrieves a dict iterator from a dict #xmmsv_t.
948 *
949 * @param val a #xmmsv_t containing a dict.
950 * @param it An #xmmsv_dict_iter_t that can be used to access the dict
951 * data. The iterator will be freed when the value is freed.
952 * @return 1 upon success otherwise 0
953 */
954int
956{
957 xmmsv_dict_iter_t *new_it;
958
959 if (!val || val->type != XMMSV_TYPE_DICT) {
960 *it = NULL;
961 return 0;
962 }
963
964 new_it = xmmsv_dict_iter_new (val->value.dict);
965 if (!new_it) {
966 *it = NULL;
967 return 0;
968 }
969
970 *it = new_it;
971
972 return 1;
973}
974
975
976/* List stuff */
977
978static xmmsv_list_t *
979xmmsv_list_new (void)
980{
981 xmmsv_list_t *list;
982
983 list = x_new0 (xmmsv_list_t, 1);
984 if (!list) {
985 x_oom ();
986 return NULL;
987 }
988
989 /* list is all empty for now! */
990
991 return list;
992}
993
994static void
995xmmsv_list_free (xmmsv_list_t *l)
996{
998 int i;
999
1000 /* free iterators */
1001 while (l->iterators) {
1002 it = (xmmsv_list_iter_t *) l->iterators->data;
1003 xmmsv_list_iter_free (it);
1004 }
1005
1006 /* unref contents */
1007 for (i = 0; i < l->size; i++) {
1008 xmmsv_unref (l->list[i]);
1009 }
1010
1011 free (l->list);
1012 free (l);
1013}
1014
1015static int
1016xmmsv_list_resize (xmmsv_list_t *l, int newsize)
1017{
1018 xmmsv_t **newmem;
1019
1020 newmem = realloc (l->list, newsize * sizeof (xmmsv_t *));
1021
1022 if (newsize != 0 && newmem == NULL) {
1023 x_oom ();
1024 return 0;
1025 }
1026
1027 l->list = newmem;
1028 l->allocated = newsize;
1029
1030 return 1;
1031}
1032
1033static int
1034_xmmsv_list_insert (xmmsv_list_t *l, int pos, xmmsv_t *val)
1035{
1037 x_list_t *n;
1038
1039 if (!absolutify_and_validate_pos (&pos, l->size, 1)) {
1040 return 0;
1041 }
1042
1043 if (l->restricted) {
1044 x_return_val_if_fail (xmmsv_is_type (val, l->restricttype), 0);
1045 }
1046
1047 /* We need more memory, reallocate */
1048 if (l->size == l->allocated) {
1049 int success;
1050 size_t double_size;
1051 if (l->allocated > 0) {
1052 double_size = l->allocated << 1;
1053 } else {
1054 double_size = 1;
1055 }
1056 success = xmmsv_list_resize (l, double_size);
1057 x_return_val_if_fail (success, 0);
1058 }
1059
1060 /* move existing items out of the way */
1061 if (l->size > pos) {
1062 memmove (l->list + pos + 1, l->list + pos,
1063 (l->size - pos) * sizeof (xmmsv_t *));
1064 }
1065
1066 l->list[pos] = xmmsv_ref (val);
1067 l->size++;
1068
1069 /* update iterators pos */
1070 for (n = l->iterators; n; n = n->next) {
1071 it = (xmmsv_list_iter_t *) n->data;
1072 if (it->position > pos) {
1073 it->position++;
1074 }
1075 }
1076
1077 return 1;
1078}
1079
1080static int
1081_xmmsv_list_append (xmmsv_list_t *l, xmmsv_t *val)
1082{
1083 return _xmmsv_list_insert (l, l->size, val);
1084}
1085
1086static int
1087_xmmsv_list_remove (xmmsv_list_t *l, int pos)
1088{
1090 int half_size;
1091 x_list_t *n;
1092
1093 /* prevent removing after the last element */
1094 if (!absolutify_and_validate_pos (&pos, l->size, 0)) {
1095 return 0;
1096 }
1097
1098 xmmsv_unref (l->list[pos]);
1099
1100 l->size--;
1101
1102 /* fill the gap */
1103 if (pos < l->size) {
1104 memmove (l->list + pos, l->list + pos + 1,
1105 (l->size - pos) * sizeof (xmmsv_t *));
1106 }
1107
1108 /* Reduce memory usage by two if possible */
1109 half_size = l->allocated >> 1;
1110 if (l->size <= half_size) {
1111 int success;
1112 success = xmmsv_list_resize (l, half_size);
1113 x_return_val_if_fail (success, 0);
1114 }
1115
1116 /* update iterator pos */
1117 for (n = l->iterators; n; n = n->next) {
1118 it = (xmmsv_list_iter_t *) n->data;
1119 if (it->position > pos) {
1120 it->position--;
1121 }
1122 }
1123
1124 return 1;
1125}
1126
1127static int
1128_xmmsv_list_move (xmmsv_list_t *l, int old_pos, int new_pos)
1129{
1130 xmmsv_t *v;
1132 x_list_t *n;
1133
1134 if (!absolutify_and_validate_pos (&old_pos, l->size, 0)) {
1135 return 0;
1136 }
1137 if (!absolutify_and_validate_pos (&new_pos, l->size, 0)) {
1138 return 0;
1139 }
1140
1141 v = l->list[old_pos];
1142 if (old_pos < new_pos) {
1143 memmove (l->list + old_pos, l->list + old_pos + 1,
1144 (new_pos - old_pos) * sizeof (xmmsv_t *));
1145 l->list[new_pos] = v;
1146
1147 /* update iterator pos */
1148 for (n = l->iterators; n; n = n->next) {
1149 it = (xmmsv_list_iter_t *) n->data;
1150 if (it->position >= old_pos && it->position <= new_pos) {
1151 if (it->position == old_pos) {
1152 it->position = new_pos;
1153 } else {
1154 it->position--;
1155 }
1156 }
1157 }
1158 } else {
1159 memmove (l->list + new_pos + 1, l->list + new_pos,
1160 (old_pos - new_pos) * sizeof (xmmsv_t *));
1161 l->list[new_pos] = v;
1162
1163 /* update iterator pos */
1164 for (n = l->iterators; n; n = n->next) {
1165 it = (xmmsv_list_iter_t *) n->data;
1166 if (it->position >= new_pos && it->position <= old_pos) {
1167 if (it->position == old_pos) {
1168 it->position = new_pos;
1169 } else {
1170 it->position++;
1171 }
1172 }
1173 }
1174 }
1175
1176 return 1;
1177}
1178
1179static void
1180_xmmsv_list_clear (xmmsv_list_t *l)
1181{
1183 x_list_t *n;
1184 int i;
1185
1186 /* unref all stored values */
1187 for (i = 0; i < l->size; i++) {
1188 xmmsv_unref (l->list[i]);
1189 }
1190
1191 /* free list, declare empty */
1192 free (l->list);
1193 l->list = NULL;
1194
1195 l->size = 0;
1196 l->allocated = 0;
1197
1198 /* reset iterator pos */
1199 for (n = l->iterators; n; n = n->next) {
1200 it = (xmmsv_list_iter_t *) n->data;
1201 it->position = 0;
1202 }
1203}
1204
1205/**
1206 * Get the element at the given position in the list #xmmsv_t. This
1207 * function does not increase the refcount of the element, the
1208 * reference is still owned by the list.
1209 *
1210 * @param listv A #xmmsv_t containing a list.
1211 * @param pos The position in the list. If negative, start counting
1212 * from the end (-1 is the last element, etc).
1213 * @param val Pointer set to a borrowed reference to the element at
1214 * the given position in the list.
1215 * @return 1 upon success otherwise 0
1216 */
1217int
1218xmmsv_list_get (xmmsv_t *listv, int pos, xmmsv_t **val)
1219{
1220 xmmsv_list_t *l;
1221
1222 x_return_val_if_fail (listv, 0);
1224
1225 l = listv->value.list;
1226
1227 /* prevent accessing after the last element */
1228 if (!absolutify_and_validate_pos (&pos, l->size, 0)) {
1229 return 0;
1230 }
1231
1232 if (val) {
1233 *val = l->list[pos];
1234 }
1235
1236 return 1;
1237}
1238
1239/**
1240 * Set the element at the given position in the list #xmmsv_t.
1241 *
1242 * @param listv A #xmmsv_t containing a list.
1243 * @param pos The position in the list. If negative, start counting
1244 * from the end (-1 is the last element, etc).
1245 * @param val The element to put at the given position in the list.
1246 * @return 1 upon success otherwise 0
1247 */
1248int
1249xmmsv_list_set (xmmsv_t *listv, int pos, xmmsv_t *val)
1250{
1251 xmmsv_t *old_val;
1252 xmmsv_list_t *l;
1253
1254 x_return_val_if_fail (listv, 0);
1255 x_return_val_if_fail (val, 0);
1257
1258 l = listv->value.list;
1259
1260 if (!absolutify_and_validate_pos (&pos, l->size, 0)) {
1261 return 0;
1262 }
1263
1264 old_val = l->list[pos];
1265 l->list[pos] = xmmsv_ref (val);
1266 xmmsv_unref (old_val);
1267
1268 return 1;
1269}
1270
1271/**
1272 * Insert an element at the given position in the list #xmmsv_t.
1273 * The list will hold a reference to the element until it's removed.
1274 *
1275 * @param listv A #xmmsv_t containing a list.
1276 * @param pos The position in the list. If negative, start counting
1277 * from the end (-1 is the last element, etc).
1278 * @param val The element to insert.
1279 * @return 1 upon success otherwise 0
1280 */
1281int
1282xmmsv_list_insert (xmmsv_t *listv, int pos, xmmsv_t *val)
1283{
1284 x_return_val_if_fail (listv, 0);
1286 x_return_val_if_fail (val, 0);
1287
1288 return _xmmsv_list_insert (listv->value.list, pos, val);
1289}
1290
1291/**
1292 * Remove the element at the given position from the list #xmmsv_t.
1293 *
1294 * @param listv A #xmmsv_t containing a list.
1295 * @param pos The position in the list. If negative, start counting
1296 * from the end (-1 is the last element, etc).
1297 * @return 1 upon success otherwise 0
1298 */
1299int
1301{
1302 x_return_val_if_fail (listv, 0);
1304
1305 return _xmmsv_list_remove (listv->value.list, pos);
1306}
1307
1308/**
1309 * Move the element from position #old to position #new.
1310 *
1311 * #xmmsv_list_iter_t's remain pointing at their element (which might or might
1312 * not be at a different position).
1313 *
1314 * @param listv A #xmmsv_t containing a list
1315 * @param old The original position in the list. If negative, start counting
1316 * from the end (-1 is the last element, etc.)
1317 * @param new The new position in the list. If negative start counting from the
1318 * end (-1 is the last element, etc.) For the sake of counting the
1319 * element to be moved is still at its old position.
1320 * @return 1 upon success otherwise 0
1321 */
1322int
1323xmmsv_list_move (xmmsv_t *listv, int old_pos, int new_pos)
1324{
1325 x_return_val_if_fail (listv, 0);
1327
1328 return _xmmsv_list_move (listv->value.list, old_pos, new_pos);
1329}
1330
1331/**
1332 * Append an element to the end of the list #xmmsv_t.
1333 * The list will hold a reference to the element until it's removed.
1334 *
1335 * @param listv A #xmmsv_t containing a list.
1336 * @param val The element to append.
1337 * @return 1 upon success otherwise 0
1338 */
1339int
1341{
1342 x_return_val_if_fail (listv, 0);
1344 x_return_val_if_fail (val, 0);
1345
1346 return _xmmsv_list_append (listv->value.list, val);
1347}
1348
1349/**
1350 * Empty the list from all its elements.
1351 *
1352 * @param listv A #xmmsv_t containing a list.
1353 * @return 1 upon success otherwise 0
1354 */
1355int
1357{
1358 x_return_val_if_fail (listv, 0);
1360
1361 _xmmsv_list_clear (listv->value.list);
1362
1363 return 1;
1364}
1365
1366/**
1367 * Apply a function to each element in the list, in sequential order.
1368 *
1369 * @param listv A #xmmsv_t containing a list.
1370 * @param function The function to apply to each element.
1371 * @param user_data User data passed to the foreach function.
1372 * @return 1 upon success otherwise 0
1373 */
1374int
1376 void* user_data)
1377{
1379 xmmsv_t *v;
1380
1381 x_return_val_if_fail (listv, 0);
1383 x_return_val_if_fail (xmmsv_get_list_iter (listv, &it), 0);
1384
1385 while (xmmsv_list_iter_valid (it)) {
1386 xmmsv_list_iter_entry (it, &v);
1387 func (v, user_data);
1389 }
1390
1391 xmmsv_list_iter_free (it);
1392
1393 return 1;
1394}
1395
1396/**
1397 * Return the size of the list.
1398 *
1399 * @param listv The #xmmsv_t containing the list.
1400 * @return The size of the list, or -1 if listv is invalid.
1401 */
1402int
1404{
1405 x_return_val_if_fail (listv, -1);
1407
1408 return listv->value.list->size;
1409}
1410
1411
1412int
1414{
1416 xmmsv_t *v;
1417
1418 x_return_val_if_fail (listv, 0);
1420
1421 x_return_val_if_fail (!listv->value.list->restricted, 0);
1422
1423 x_return_val_if_fail (xmmsv_get_list_iter (listv, &it), 0);
1424 while (xmmsv_list_iter_valid (it)) {
1425 xmmsv_list_iter_entry (it, &v);
1426 x_return_val_if_fail (xmmsv_is_type (v, type), 0);
1428 }
1429
1430 xmmsv_list_iter_free (it);
1431
1432 listv->value.list->restricted = true;
1433 listv->value.list->restricttype = type;
1434
1435 return 1;
1436}
1437
1438
1439static xmmsv_list_iter_t *
1440xmmsv_list_iter_new (xmmsv_list_t *l)
1441{
1443
1444 it = x_new0 (xmmsv_list_iter_t, 1);
1445 if (!it) {
1446 x_oom ();
1447 return NULL;
1448 }
1449
1450 it->parent = l;
1451 it->position = 0;
1452
1453 /* register iterator into parent */
1454 l->iterators = x_list_prepend (l->iterators, it);
1455
1456 return it;
1457}
1458
1459static void
1460xmmsv_list_iter_free (xmmsv_list_iter_t *it)
1461{
1462 /* unref iterator from list and free it */
1463 it->parent->iterators = x_list_remove (it->parent->iterators, it);
1464 free (it);
1465}
1466
1467/**
1468 * Explicitly free list iterator.
1469 *
1470 * Immediately frees any resources used by this iterator. The iterator
1471 * is freed automatically when the list is freed, but this function is
1472 * useful when the list can be long lived.
1473 *
1474 * @param it iterator to free
1475 *
1476 */
1477void
1479{
1480 xmmsv_list_iter_free (it);
1481}
1482
1483/**
1484 * Get the element currently pointed at by the iterator. This function
1485 * does not increase the refcount of the element, the reference is
1486 * still owned by the list. If iterator does not point on a valid
1487 * element xmmsv_list_iter_entry returns 0 and leaves val untouched.
1488 *
1489 * @param it A #xmmsv_list_iter_t.
1490 * @param val Pointer set to a borrowed reference to the element
1491 * pointed at by the iterator.
1492 * @return 1 upon success otherwise 0
1493 */
1494int
1496{
1497 if (!xmmsv_list_iter_valid (it))
1498 return 0;
1499
1500 *val = it->parent->list[it->position];
1501
1502 return 1;
1503}
1504
1505/**
1506 * Check whether the iterator is valid and points to a valid element.
1507 *
1508 * @param it A #xmmsv_list_iter_t.
1509 * @return 1 if the iterator is valid, 0 otherwise
1510 */
1511int
1513{
1514 return it && (it->position < it->parent->size) && (it->position >= 0);
1515}
1516
1517/**
1518 * Rewind the iterator to the start of the list.
1519 *
1520 * @param it A #xmmsv_list_iter_t.
1521 */
1522void
1524{
1525 x_return_if_fail (it);
1526
1527 it->position = 0;
1528}
1529
1530/**
1531 * Move the iterator to end of the list.
1532 *
1533 * @param listv A #xmmsv_list_iter_t.
1534 */
1535void
1537{
1538 x_return_if_fail (it);
1539
1540 if (it->parent->size > 0) {
1541 it->position = it->parent->size - 1;
1542 } else {
1543 it->position = it->parent->size;
1544 }
1545}
1546
1547/**
1548 * Advance the iterator to the next element in the list.
1549 *
1550 * @param it A #xmmsv_list_iter_t.
1551 */
1552void
1554{
1555 x_return_if_fail (it);
1556
1557 if (it->position < it->parent->size) {
1558 it->position++;
1559 }
1560}
1561
1562/**
1563 * Move the iterator to the previous element in the list.
1564 *
1565 * @param listv A #xmmsv_list_iter_t.
1566 */
1567void
1569{
1570 x_return_if_fail (it);
1571
1572 if (it->position >= 0) {
1573 it->position--;
1574 }
1575}
1576
1577
1578/**
1579 * Move the iterator to the n-th element in the list.
1580 *
1581 * @param it A #xmmsv_list_iter_t.
1582 * @param pos The position in the list. If negative, start counting
1583 * from the end (-1 is the last element, etc).
1584 * @return 1 upon success otherwise 0
1585 */
1586int
1588{
1589 x_return_val_if_fail (it, 0);
1590
1591 if (!absolutify_and_validate_pos (&pos, it->parent->size, 1)) {
1592 return 0;
1593 }
1594 it->position = pos;
1595
1596 return 1;
1597}
1598
1599/**
1600 * Tell the position of the iterator.
1601 *
1602 * @param it A #xmmsv_list_iter_t.
1603 * @return The position of the iterator, or -1 if invalid.
1604 */
1605int
1607{
1608 x_return_val_if_fail (it, -1);
1609
1610 return it->position;
1611}
1612
1613/**
1614 * Return the parent #xmmsv_t of an iterator.
1615 *
1616 * @param it A #xmmsv_list_iter_t.
1617 * @return The parent #xmmsv_t of the iterator, or NULL if invalid.
1618 */
1619xmmsv_t*
1621{
1622 x_return_val_if_fail (it, NULL);
1623
1624 return it->parent->parent_value;
1625}
1626
1627/**
1628 * Insert an element in the list at the position pointed at by the
1629 * iterator.
1630 *
1631 * @param it A #xmmsv_list_iter_t.
1632 * @param val The element to insert.
1633 * @return 1 upon success otherwise 0
1634 */
1635int
1637{
1638 x_return_val_if_fail (it, 0);
1639 x_return_val_if_fail (val, 0);
1640
1641 return _xmmsv_list_insert (it->parent, it->position, val);
1642}
1643
1644/**
1645 * Remove the element in the list at the position pointed at by the
1646 * iterator.
1647 *
1648 * @param it A #xmmsv_list_iter_t.
1649 * @return 1 upon success otherwise 0
1650 */
1651int
1653{
1654 x_return_val_if_fail (it, 0);
1655
1656 return _xmmsv_list_remove (it->parent, it->position);
1657}
1658
1659/* Dict stuff */
1660
1661struct xmmsv_dict_St {
1662 /* dict implemented as a flat [key1, val1, key2, val2, ...] list */
1663 xmmsv_list_t *flatlist;
1664 x_list_t *iterators;
1665};
1666
1667struct xmmsv_dict_iter_St {
1668 /* iterator of the contained flatlist */
1669 xmmsv_list_iter_t *lit;
1670 xmmsv_dict_t *parent;
1671};
1672
1673static xmmsv_dict_t *
1674xmmsv_dict_new (void)
1675{
1676 xmmsv_dict_t *dict;
1677
1678 dict = x_new0 (xmmsv_dict_t, 1);
1679 if (!dict) {
1680 x_oom ();
1681 return NULL;
1682 }
1683
1684 dict->flatlist = xmmsv_list_new ();
1685
1686 return dict;
1687}
1688
1689static void
1690xmmsv_dict_free (xmmsv_dict_t *dict)
1691{
1693
1694 /* free iterators */
1695 while (dict->iterators) {
1696 it = (xmmsv_dict_iter_t *) dict->iterators->data;
1697 xmmsv_dict_iter_free (it);
1698 }
1699
1700 xmmsv_list_free (dict->flatlist);
1701
1702 free (dict);
1703}
1704
1705/**
1706 * Get the element corresponding to the given key in the dict #xmmsv_t
1707 * (if it exists). This function does not increase the refcount of
1708 * the element, the reference is still owned by the dict.
1709 *
1710 * @param dictv A #xmmsv_t containing a dict.
1711 * @param key The key in the dict.
1712 * @param val Pointer set to a borrowed reference to the element
1713 * corresponding to the given key in the dict.
1714 * @return 1 upon success otherwise 0
1715 */
1716int
1717xmmsv_dict_get (xmmsv_t *dictv, const char *key, xmmsv_t **val)
1718{
1720 int ret = 1;
1721
1722 x_return_val_if_fail (key, 0);
1723 x_return_val_if_fail (dictv, 0);
1725 x_return_val_if_fail (xmmsv_get_dict_iter (dictv, &it), 0);
1726
1727 if (!xmmsv_dict_iter_find (it, key)) {
1728 ret = 0;
1729 }
1730
1731 /* If found, return value and success */
1732 if (ret && val) {
1733 xmmsv_dict_iter_pair (it, NULL, val);
1734 }
1735
1736 xmmsv_dict_iter_free (it);
1737
1738 return ret;
1739}
1740
1741/**
1742 * Insert an element under the given key in the dict #xmmsv_t. If the
1743 * key already referenced an element, that element is unref'd and
1744 * replaced by the new one.
1745 *
1746 * @param dictv A #xmmsv_t containing a dict.
1747 * @param key The key in the dict.
1748 * @param val The new element to insert in the dict.
1749 * @return 1 upon success otherwise 0
1750 */
1751int
1752xmmsv_dict_set (xmmsv_t *dictv, const char *key, xmmsv_t *val)
1753{
1755 int ret;
1756
1757 x_return_val_if_fail (key, 0);
1758 x_return_val_if_fail (val, 0);
1759 x_return_val_if_fail (dictv, 0);
1761 x_return_val_if_fail (xmmsv_get_dict_iter (dictv, &it), 0);
1762
1763 /* if key already present, replace value */
1764 if (xmmsv_dict_iter_find (it, key)) {
1765 ret = xmmsv_dict_iter_set (it, val);
1766
1767 /* else, insert a new key-value pair */
1768 } else {
1769 xmmsv_t *keyval;
1770
1771 keyval = xmmsv_new_string (key);
1772
1773 ret = xmmsv_list_iter_insert (it->lit, keyval);
1774 if (ret) {
1775 xmmsv_list_iter_next (it->lit);
1776 ret = xmmsv_list_iter_insert (it->lit, val);
1777 if (!ret) {
1778 /* we added the key, but we couldn't add the value.
1779 * we remove the key again to put the dictionary back
1780 * in a consistent state.
1781 */
1782 it->lit->position--;
1783 xmmsv_list_iter_remove (it->lit);
1784 }
1785 }
1786 xmmsv_unref (keyval);
1787 }
1788
1789 xmmsv_dict_iter_free (it);
1790
1791 return ret;
1792}
1793
1794/**
1795 * Remove the element corresponding to a given key in the dict
1796 * #xmmsv_t (if it exists).
1797 *
1798 * @param dictv A #xmmsv_t containing a dict.
1799 * @param key The key in the dict.
1800 * @return 1 upon success otherwise 0
1801 */
1802int
1803xmmsv_dict_remove (xmmsv_t *dictv, const char *key)
1804{
1806 int ret = 1;
1807
1808 x_return_val_if_fail (key, 0);
1809 x_return_val_if_fail (dictv, 0);
1811 x_return_val_if_fail (xmmsv_get_dict_iter (dictv, &it), 0);
1812
1813 if (!xmmsv_dict_iter_find (it, key)) {
1814 ret = 0;
1815 } else {
1816 ret = xmmsv_list_iter_remove (it->lit) &&
1817 xmmsv_list_iter_remove (it->lit);
1818 /* FIXME: cleanup if only the first fails */
1819 }
1820
1821 xmmsv_dict_iter_free (it);
1822
1823 return ret;
1824}
1825
1826/**
1827 * Empty the dict of all its elements.
1828 *
1829 * @param dictv A #xmmsv_t containing a dict.
1830 * @return 1 upon success otherwise 0
1831 */
1832int
1834{
1835 x_return_val_if_fail (dictv, 0);
1837
1838 _xmmsv_list_clear (dictv->value.dict->flatlist);
1839
1840 return 1;
1841}
1842
1843/**
1844 * Apply a function to each key-element pair in the list. No
1845 * particular order is assumed.
1846 *
1847 * @param dictv A #xmmsv_t containing a dict.
1848 * @param function The function to apply to each key-element pair.
1849 * @param user_data User data passed to the foreach function.
1850 * @return 1 upon success otherwise 0
1851 */
1852int
1854 void *user_data)
1855{
1857 const char *key;
1858 xmmsv_t *v;
1859
1860 x_return_val_if_fail (dictv, 0);
1862 x_return_val_if_fail (xmmsv_get_dict_iter (dictv, &it), 0);
1863
1864 while (xmmsv_dict_iter_valid (it)) {
1865 xmmsv_dict_iter_pair (it, &key, &v);
1866 func (key, v, user_data);
1868 }
1869
1870 xmmsv_dict_iter_free (it);
1871
1872 return 1;
1873}
1874
1875/**
1876 * Return the size of the dict.
1877 *
1878 * @param dictv The #xmmsv_t containing the dict.
1879 * @return The size of the dict, or -1 if dict is invalid.
1880 */
1881int
1883{
1884 x_return_val_if_fail (dictv, -1);
1886
1887 return dictv->value.dict->flatlist->size / 2;
1888}
1889
1890static xmmsv_dict_iter_t *
1891xmmsv_dict_iter_new (xmmsv_dict_t *d)
1892{
1894
1895 it = x_new0 (xmmsv_dict_iter_t, 1);
1896 if (!it) {
1897 x_oom ();
1898 return NULL;
1899 }
1900
1901 it->lit = xmmsv_list_iter_new (d->flatlist);
1902 it->parent = d;
1903
1904 /* register iterator into parent */
1905 d->iterators = x_list_prepend (d->iterators, it);
1906
1907 return it;
1908}
1909
1910static void
1911xmmsv_dict_iter_free (xmmsv_dict_iter_t *it)
1912{
1913 /* we don't free the parent list iter, already managed by the flatlist */
1914
1915 /* unref iterator from dict and free it */
1916 it->parent->iterators = x_list_remove (it->parent->iterators, it);
1917 free (it);
1918}
1919
1920/**
1921 * Explicitly free dict iterator.
1922 *
1923 * Immediately frees any resources used by this iterator. The iterator
1924 * is freed automatically when the dict is freed, but this function is
1925 * useful when the dict can be long lived.
1926 *
1927 * @param it iterator to free
1928 *
1929 */
1930void
1932{
1933 xmmsv_dict_iter_free (it);
1934}
1935
1936/**
1937 * Get the key-element pair currently pointed at by the iterator. This
1938 * function does not increase the refcount of the element, the
1939 * reference is still owned by the dict.
1940 *
1941 * @param it A #xmmsv_dict_iter_t.
1942 * @param key Pointer set to the key pointed at by the iterator.
1943 * @param val Pointer set to a borrowed reference to the element
1944 * pointed at by the iterator.
1945 * @return 1 upon success otherwise 0
1946 */
1947int
1949 xmmsv_t **val)
1950{
1951 unsigned int orig;
1952 xmmsv_t *v;
1953
1954 if (!xmmsv_dict_iter_valid (it)) {
1955 return 0;
1956 }
1957
1958 /* FIXME: avoid leaking abstraction! */
1959 orig = it->lit->position;
1960
1961 if (key) {
1962 xmmsv_list_iter_entry (it->lit, &v);
1963 xmmsv_get_string (v, key);
1964 }
1965
1966 if (val) {
1967 xmmsv_list_iter_next (it->lit);
1968 xmmsv_list_iter_entry (it->lit, val);
1969 }
1970
1971 it->lit->position = orig;
1972
1973 return 1;
1974}
1975
1976/**
1977 * Check whether the iterator is valid and points to a valid pair.
1978 *
1979 * @param it A #xmmsv_dict_iter_t.
1980 * @return 1 if the iterator is valid, 0 otherwise
1981 */
1982int
1984{
1985 return it && xmmsv_list_iter_valid (it->lit);
1986}
1987
1988/**
1989 * Rewind the iterator to the start of the dict.
1990 *
1991 * @param it A #xmmsv_dict_iter_t.
1992 * @return 1 upon success otherwise 0
1993 */
1994void
1996{
1997 x_return_if_fail (it);
1998
1999 xmmsv_list_iter_first (it->lit);
2000}
2001
2002/**
2003 * Advance the iterator to the next pair in the dict.
2004 *
2005 * @param it A #xmmsv_dict_iter_t.
2006 * @return 1 upon success otherwise 0
2007 */
2008void
2010{
2011 x_return_if_fail (it);
2012
2013 /* skip a pair */
2014 xmmsv_list_iter_next (it->lit);
2015 xmmsv_list_iter_next (it->lit);
2016}
2017
2018/**
2019 * Move the iterator to the pair with the given key (if it exists)
2020 * or move it to the position where the key would have to be
2021 * put (if it doesn't exist yet).
2022 *
2023 * @param it A #xmmsv_dict_iter_t.
2024 * @param key The key to seek for.
2025 * @return 1 upon success otherwise 0
2026 */
2027int
2029{
2030 xmmsv_t *val;
2031 const char *k;
2032 int s, dict_size, cmp, left, right;
2033
2034 x_return_val_if_fail (it, 0);
2035 x_return_val_if_fail (key, 0);
2036
2037 /* how many key-value pairs does this dictionary contain? */
2038 dict_size = it->parent->flatlist->size / 2;
2039
2040 /* if it's empty, point the iterator at the beginning of
2041 * the list and report failure.
2042 */
2043 if (!dict_size) {
2044 xmmsv_list_iter_seek (it->lit, 0);
2045
2046 return 0;
2047 }
2048
2049 /* perform binary search for the given key */
2050 left = 0;
2051 right = dict_size - 1;
2052
2053 while (left <= right) {
2054 int mid = left + ((right - left) / 2);
2055
2056 /* jump to the middle of the current search area */
2057 xmmsv_list_iter_seek (it->lit, mid * 2);
2058 xmmsv_list_iter_entry (it->lit, &val);
2059
2060 /* get the key at this slot */
2061 s = xmmsv_get_string (val, &k);
2062 x_return_val_if_fail (s, 0);
2063
2064 /* and compare it to the given key */
2065 cmp = strcmp (k, key);
2066
2067 /* hooray, we found the key. */
2068 if (cmp == 0)
2069 return 1;
2070
2071 /* go on searching the left or the right hand side. */
2072 if (cmp < 0) {
2073 left = mid + 1;
2074 } else {
2075 right = mid - 1;
2076 }
2077 }
2078
2079 /* if we get down here, we failed to find the key
2080 * in the dictionary.
2081 * now, move the iterator so that it points to the slot
2082 * where the key would be inserted.
2083 */
2084 if (cmp < 0) {
2085 xmmsv_list_iter_next (it->lit);
2086 xmmsv_list_iter_next (it->lit);
2087 }
2088
2089 return 0;
2090}
2091
2092/**
2093 * Replace the element of the pair currently pointed to by the
2094 * iterator.
2095 *
2096 * @param it A #xmmsv_dict_iter_t.
2097 * @param val The element to set in the pair.
2098 * @return 1 upon success otherwise 0
2099 */
2100int
2102{
2103 unsigned int orig;
2104 int ret;
2105
2107
2108 /* FIXME: avoid leaking abstraction! */
2109 orig = it->lit->position;
2110
2111 xmmsv_list_iter_next (it->lit);
2112 xmmsv_list_iter_remove (it->lit);
2113 ret = xmmsv_list_iter_insert (it->lit, val);
2114 /* FIXME: check remove success, swap operations? */
2115
2116 it->lit->position = orig;
2117
2118 return ret;
2119}
2120
2121/**
2122 * Remove the pair in the dict pointed at by the iterator.
2123 *
2124 * @param it A #xmmsv_dict_iter_t.
2125 * @return 1 upon success otherwise 0
2126 */
2127int
2129{
2130 int ret = 0;
2131
2132 ret = xmmsv_list_iter_remove (it->lit) &&
2133 xmmsv_list_iter_remove (it->lit);
2134 /* FIXME: cleanup if only the first fails */
2135
2136 return ret;
2137}
2138
2139
2140
2141/**
2142 * Decode an URL-encoded string.
2143 *
2144 * Some strings (currently only the url of media) has no known
2145 * encoding, and must be encoded in an UTF-8 clean way. This is done
2146 * similar to the url encoding web browsers do. This functions decodes
2147 * a string encoded in that way. OBSERVE that the decoded string HAS
2148 * NO KNOWN ENCODING and you cannot display it on screen in a 100%
2149 * guaranteed correct way (a good heuristic is to try to validate the
2150 * decoded string as UTF-8, and if it validates assume that it is an
2151 * UTF-8 encoded string, and otherwise fall back to some other
2152 * encoding).
2153 *
2154 * Do not use this function if you don't understand the
2155 * implications. The best thing is not to try to display the url at
2156 * all.
2157 *
2158 * Note that the fact that the string has NO KNOWN ENCODING and CAN
2159 * NOT BE DISPLAYED does not stop you from open the file if it is a
2160 * local file (if it starts with "file://").
2161 *
2162 * @param url the #xmmsv_t containing a url-encoded string
2163 * @return a new #xmmsv_t containing the decoded string as a XMMSV_BIN or NULL on failure
2164 *
2165 */
2166xmmsv_t *
2168{
2169 int i = 0, j = 0;
2170 const char *ins;
2171 unsigned char *url;
2172 xmmsv_t *ret;
2173
2174 if (!xmmsv_get_string (inv, &ins)) {
2175 return NULL;
2176 }
2177
2178 url = x_malloc (strlen (ins));
2179 if (!url) {
2180 x_oom ();
2181 return NULL;
2182 }
2183
2184 while (ins[i]) {
2185 unsigned char chr = ins[i++];
2186
2187 if (chr == '+') {
2188 chr = ' ';
2189 } else if (chr == '%') {
2190 char ts[3];
2191 char *t;
2192
2193 ts[0] = ins[i++];
2194 if (!ts[0])
2195 goto err;
2196 ts[1] = ins[i++];
2197 if (!ts[1])
2198 goto err;
2199 ts[2] = '\0';
2200
2201 chr = strtoul (ts, &t, 16);
2202
2203 if (t != &ts[2])
2204 goto err;
2205 }
2206
2207 url[j++] = chr;
2208 }
2209
2210 ret = xmmsv_new_bin (url, j);
2211 free (url);
2212
2213 return ret;
2214
2215err:
2216 free (url);
2217 return NULL;
2218}
2219
2220xmmsv_t *
2221xmmsv_build_dict (const char *firstkey, ...)
2222{
2223 va_list ap;
2224 const char *key;
2225 xmmsv_t *val, *res;
2226
2227 res = xmmsv_new_dict ();
2228 if (!res)
2229 return NULL;
2230
2231 va_start (ap, firstkey);
2232
2233 key = firstkey;
2234 do {
2235 val = va_arg (ap, xmmsv_t *);
2236
2237 if (!xmmsv_dict_set (res, key, val)) {
2238 xmmsv_unref (res);
2239 res = NULL;
2240 break;
2241 }
2242 xmmsv_unref (val);
2243 key = va_arg (ap, const char *);
2244 } while (key);
2245
2246 va_end (ap);
2247
2248 return res;
2249}
2250
2251xmmsv_t *
2252xmmsv_build_list_va (xmmsv_t *first_entry, va_list ap)
2253{
2254 xmmsv_t *val, *res;
2255
2256 res = xmmsv_new_list ();
2257 if (!res)
2258 return NULL;
2259
2260 val = first_entry;
2261
2262 while (val) {
2263 if (!xmmsv_list_append (res, val)) {
2264 xmmsv_unref (res);
2265 res = NULL;
2266 break;
2267 }
2268
2269 xmmsv_unref (val);
2270
2271 val = va_arg (ap, xmmsv_t *);
2272 }
2273
2274 return res;
2275}
2276
2277xmmsv_t *
2278xmmsv_build_list (xmmsv_t *first_entry, ...)
2279{
2280 va_list ap;
2281 xmmsv_t *res;
2282
2283 va_start (ap, first_entry);
2284 res = xmmsv_build_list_va (first_entry, ap);
2285 va_end (ap);
2286
2287 return res;
2288}
2289
2290
2291/**
2292 * This function will make a pretty string about the information in
2293 * xmmsv dict.
2294 *
2295 * @param target A allocated char *
2296 * @param len Length of target
2297 * @param fmt A format string to use. You can insert items from the dict by
2298 * using specialformat "${field}".
2299 * @param val The #xmmsv_t that contains the dict.
2300 *
2301 * @returns The number of chars written to target
2302 */
2303int
2304xmmsv_dict_format (char *target, int len, const char *fmt, xmmsv_t *val)
2305{
2306 const char *pos;
2307
2308 if (!target) {
2309 return 0;
2310 }
2311
2312 if (!fmt) {
2313 return 0;
2314 }
2315
2316 memset (target, 0, len);
2317
2318 pos = fmt;
2319 while (strlen (target) + 1 < len) {
2320 char *next_key, *key, *end;
2321 int keylen;
2323 xmmsv_t *v;
2324
2325 next_key = strstr (pos, "${");
2326 if (!next_key) {
2327 strncat (target, pos, len - strlen (target) - 1);
2328 break;
2329 }
2330
2331 strncat (target, pos, MIN (next_key - pos, len - strlen (target) - 1));
2332 keylen = strcspn (next_key + 2, "}");
2333 key = malloc (keylen + 1);
2334
2335 if (!key) {
2336 fprintf (stderr, "Unable to allocate %u bytes of memory, OOM?", keylen);
2337 break;
2338 }
2339
2340 memset (key, 0, keylen + 1);
2341 strncpy (key, next_key + 2, keylen);
2342
2343 xmmsv_get_dict_iter (val, &it);
2344
2345 if (strcmp (key, "seconds") == 0) {
2346 int duration;
2347
2348 if (xmmsv_dict_iter_find (it, "duration")) {
2349 xmmsv_dict_iter_pair (it, NULL, &v);
2350 xmmsv_get_int (v, &duration);
2351 } else {
2352 duration = 0;
2353 }
2354
2355 if (!duration) {
2356 strncat (target, "00", len - strlen (target) - 1);
2357 } else {
2358 char seconds[10];
2359 /* rounding */
2360 duration += 500;
2361 snprintf (seconds, sizeof (seconds), "%02d", (duration/1000)%60);
2362 strncat (target, seconds, len - strlen (target) - 1);
2363 }
2364 } else if (strcmp (key, "minutes") == 0) {
2365 int duration;
2366
2367 if (xmmsv_dict_iter_find (it, "duration")) {
2368 xmmsv_dict_iter_pair (it, NULL, &v);
2369 xmmsv_get_int (v, &duration);
2370 } else {
2371 duration = 0;
2372 }
2373
2374 if (!duration) {
2375 strncat (target, "00", len - strlen (target) - 1);
2376 } else {
2377 char minutes[10];
2378 /* rounding */
2379 duration += 500;
2380 snprintf (minutes, sizeof (minutes), "%02d", duration/60000);
2381 strncat (target, minutes, len - strlen (target) - 1);
2382 }
2383 } else {
2384 const char *result = NULL;
2385 char tmp[12];
2386
2387 if (xmmsv_dict_iter_find (it, key)) {
2388 xmmsv_dict_iter_pair (it, NULL, &v);
2389
2390 xmmsv_type_t type = xmmsv_get_type (v);
2391 if (type == XMMSV_TYPE_STRING) {
2392 xmmsv_get_string (v, &result);
2393 } else if (type == XMMSV_TYPE_UINT32) {
2394 uint32_t ui;
2395 xmmsv_get_uint (v, &ui);
2396 snprintf (tmp, 12, "%u", ui);
2397 result = tmp;
2398 } else if (type == XMMSV_TYPE_INT32) {
2399 int32_t i;
2400 xmmsv_get_int (v, &i);
2401 snprintf (tmp, 12, "%d", i);
2402 result = tmp;
2403 }
2404 }
2405
2406 if (result)
2407 strncat (target, result, len - strlen (target) - 1);
2408 }
2409
2410 free (key);
2411 end = strchr (next_key, '}');
2412
2413 if (!end) {
2414 break;
2415 }
2416
2417 pos = end + 1;
2418 }
2419
2420 return strlen (target);
2421}
2422
2423static int
2424_xmmsv_utf8_charlen (unsigned char c)
2425{
2426 if ((c & 0x80) == 0) {
2427 return 1;
2428 } else if ((c & 0x60) == 0x40) {
2429 return 2;
2430 } else if ((c & 0x70) == 0x60) {
2431 return 3;
2432 } else if ((c & 0x78) == 0x70) {
2433 return 4;
2434 }
2435 return 0;
2436}
2437
2438
2439/**
2440 * Check if a string is valid UTF-8.
2441 *
2442 */
2443int
2444xmmsv_utf8_validate (const char *str)
2445{
2446 int i = 0;
2447
2448 for (;;) {
2449 unsigned char c = str[i++];
2450 int l;
2451 if (!c) {
2452 /* NUL - end of string */
2453 return 1;
2454 }
2455
2456 l = _xmmsv_utf8_charlen (c);
2457 if (l == 0)
2458 return 0;
2459 while (l-- > 1) {
2460 if ((str[i++] & 0xC0) != 0x80)
2461 return 0;
2462 }
2463 }
2464}
2465
2466
2467
2468/**
2469 * @internal
2470 */
2471static int
2472absolutify_and_validate_pos (int *pos, int size, int allow_append)
2473{
2474 x_return_val_if_fail (size >= 0, 0);
2475
2476 if (*pos < 0) {
2477 if (-*pos > size)
2478 return 0;
2479 *pos = size + *pos;
2480 }
2481
2482 if (*pos > size)
2483 return 0;
2484
2485 if (!allow_append && *pos == size)
2486 return 0;
2487
2488 return 1;
2489}
2490
2491int
2492xmmsv_dict_has_key (xmmsv_t *dictv, const char *key)
2493{
2494 return xmmsv_dict_get (dictv, key, NULL);
2495}
2496
2497
2498xmmsv_t *
2499xmmsv_bitbuffer_new_ro (const unsigned char *v, int len)
2500{
2501 xmmsv_t *val;
2502
2503 val = xmmsv_new (XMMSV_TYPE_BITBUFFER);
2504 val->value.bit.buf = (unsigned char *) v;
2505 val->value.bit.len = len * 8;
2506 val->value.bit.ro = true;
2507 return val;
2508}
2509
2510xmmsv_t *
2512{
2513 xmmsv_t *val;
2514
2515 val = xmmsv_new (XMMSV_TYPE_BITBUFFER);
2516 val->value.bit.buf = NULL;
2517 val->value.bit.len = 0;
2518 val->value.bit.ro = false;
2519 return val;
2520}
2521
2522
2523int
2524xmmsv_bitbuffer_get_bits (xmmsv_t *v, int bits, int *res)
2525{
2526 int i, t, r;
2527
2528 x_api_error_if (bits < 1, "less than one bit requested", 0);
2529
2530 if (bits == 1) {
2531 int pos = v->value.bit.pos;
2532
2533 if (pos >= v->value.bit.len)
2534 return 0;
2535 r = (v->value.bit.buf[pos / 8] >> (7-(pos % 8)) & 1);
2536 v->value.bit.pos += 1;
2537 *res = r;
2538 return 1;
2539 }
2540
2541 r = 0;
2542 for (i = 0; i < bits; i++) {
2543 t = 0;
2544 if (!xmmsv_bitbuffer_get_bits (v, 1, &t))
2545 return 0;
2546 r = (r << 1) | t;
2547 }
2548 *res = r;
2549 return 1;
2550}
2551
2552int
2553xmmsv_bitbuffer_get_data (xmmsv_t *v, unsigned char *b, int len)
2554{
2555 while (len) {
2556 int t;
2557 if (!xmmsv_bitbuffer_get_bits (v, 8, &t))
2558 return 0;
2559 *b = t;
2560 b++;
2561 len--;
2562 }
2563 return 1;
2564}
2565
2566int
2568{
2569 unsigned char t;
2570 int pos;
2571 int i;
2572
2573 x_api_error_if (v->value.bit.ro, "write to readonly bitbuffer", 0);
2574 x_api_error_if (bits < 1, "less than one bit requested", 0);
2575
2576 if (bits == 1) {
2577 pos = v->value.bit.pos;
2578
2579 if (pos >= v->value.bit.alloclen) {
2580 int ol, nl;
2581 nl = v->value.bit.alloclen * 2;
2582 ol = v->value.bit.alloclen;
2583 nl = nl < 128 ? 128 : nl;
2584 nl = (nl + 7) & ~7;
2585 v->value.bit.buf = realloc (v->value.bit.buf, nl / 8);
2586 memset (v->value.bit.buf + ol / 8, 0, (nl - ol) / 8);
2587 v->value.bit.alloclen = nl;
2588 }
2589 t = v->value.bit.buf[pos / 8];
2590
2591 t = (t & (~(1<<(7-(pos % 8))))) | (d << (7-(pos % 8)));
2592
2593 v->value.bit.buf[pos / 8] = t;
2594
2595 v->value.bit.pos += 1;
2596 if (v->value.bit.pos > v->value.bit.len)
2597 v->value.bit.len = v->value.bit.pos;
2598 return 1;
2599 }
2600
2601 for (i = 0; i < bits; i++) {
2602 if (!xmmsv_bitbuffer_put_bits (v, 1, !!(d & (1 << (bits-i-1)))))
2603 return 0;
2604 }
2605
2606 return 1;
2607}
2608
2609int
2610xmmsv_bitbuffer_put_bits_at (xmmsv_t *v, int bits, int d, int offset)
2611{
2612 int prevpos;
2613 prevpos = xmmsv_bitbuffer_pos (v);
2614 if (!xmmsv_bitbuffer_goto (v, offset))
2615 return 0;
2616 if (!xmmsv_bitbuffer_put_bits (v, bits, d))
2617 return 0;
2618 return xmmsv_bitbuffer_goto (v, prevpos);
2619}
2620
2621int
2622xmmsv_bitbuffer_put_data (xmmsv_t *v, const unsigned char *b, int len)
2623{
2624 while (len) {
2625 int t;
2626 t = *b;
2627 if (!xmmsv_bitbuffer_put_bits (v, 8, t))
2628 return 0;
2629 b++;
2630 len--;
2631 }
2632 return 1;
2633}
2634
2635int
2637{
2638 v->value.bit.pos = (v->value.bit.pos + 7) % 8;
2639 return 1;
2640}
2641
2642int
2644{
2645 x_api_error_if (pos < 0, "negative position", 0);
2646 x_api_error_if (pos > v->value.bit.len, "position after buffer end", 0);
2647
2648 v->value.bit.pos = pos;
2649 return 1;
2650}
2651
2652int
2654{
2655 return v->value.bit.pos;
2656}
2657
2658int
2660{
2661 return xmmsv_bitbuffer_goto (v, 0);
2662}
2663
2664int
2666{
2667 return xmmsv_bitbuffer_goto (v, v->value.bit.len);
2668}
2669
2670int
2672{
2673 return v->value.bit.len;
2674}
2675
2676const unsigned char *
2678{
2679 return v->value.bit.buf;
2680}
2681
2682/*
2683 *
2684 *
2685 */
2686
2687/*
2688xmmsv_t *
2689xmmsv_serialize (xmmsv_t *val)
2690{
2691 switch (xmmsv_get_type (val)) {
2692 case XMMSV_TYPE_NONE:
2693 break;
2694
2695 }
2696}
2697*/
int xmmsv_bitbuffer_get_bits(xmmsv_t *v, int bits, int *res)
Definition value.c:2524
xmmsv_t * xmmsv_bitbuffer_new(void)
Definition value.c:2511
int xmmsv_bitbuffer_put_bits_at(xmmsv_t *v, int bits, int d, int offset)
Definition value.c:2610
int xmmsv_bitbuffer_len(xmmsv_t *v)
Definition value.c:2671
int xmmsv_bitbuffer_end(xmmsv_t *v)
Definition value.c:2665
xmmsv_t * xmmsv_bitbuffer_new_ro(const unsigned char *v, int len)
Definition value.c:2499
int xmmsv_bitbuffer_align(xmmsv_t *v)
Definition value.c:2636
int xmmsv_bitbuffer_pos(xmmsv_t *v)
Definition value.c:2653
int xmmsv_bitbuffer_put_data(xmmsv_t *v, const unsigned char *b, int len)
Definition value.c:2622
int xmmsv_bitbuffer_goto(xmmsv_t *v, int pos)
Definition value.c:2643
const unsigned char * xmmsv_bitbuffer_buffer(xmmsv_t *v)
Definition value.c:2677
int xmmsv_bitbuffer_get_data(xmmsv_t *v, unsigned char *b, int len)
Definition value.c:2553
int xmmsv_bitbuffer_rewind(xmmsv_t *v)
Definition value.c:2659
int xmmsv_bitbuffer_put_bits(xmmsv_t *v, int bits, int d)
Definition value.c:2567
xmmsv_t * xmmsv_build_list(xmmsv_t *first_entry,...)
Definition value.c:2278
xmmsv_t * xmmsv_build_list_va(xmmsv_t *first_entry, va_list ap)
Definition value.c:2252
xmmsv_t * xmmsv_build_dict(const char *firstkey,...)
Definition value.c:2221
xmmsv_coll_t * xmmsv_coll_ref(xmmsv_coll_t *coll)
Increases the references for the xmmsv_coll_t.
Definition coll.c:61
void xmmsv_coll_unref(xmmsv_coll_t *coll)
Decreases the references for the xmmsv_coll_t When the number of references reaches 0 it will be free...
Definition coll.c:140
const char * xmmsv_get_error_old(const xmmsv_t *val)
Legacy alias to retrieve the error string from an xmmsv_t.
Definition value.c:462
int xmmsv_get_uint(const xmmsv_t *val, uint32_t *r)
Retrieves a unsigned integer from the value.
Definition value.c:842
int xmmsv_is_dict(const xmmsv_t *val)
Check if the value stores a dict.
Definition value.c:449
#define XMMSV_TYPE_UINT32
int xmmsv_is_list(const xmmsv_t *val)
Check if the value stores a list.
Definition value.c:437
void xmmsv_dict_iter_next(xmmsv_dict_iter_t *it)
Advance the iterator to the next pair in the dict.
Definition value.c:2009
void xmmsv_dict_iter_explicit_destroy(xmmsv_dict_iter_t *it)
Explicitly free dict iterator.
Definition value.c:1931
int xmmsv_dict_iter_remove(xmmsv_dict_iter_t *it)
Remove the pair in the dict pointed at by the iterator.
Definition value.c:2128
struct xmmsv_dict_iter_St xmmsv_dict_iter_t
Definition xmmsv_dict.h:59
int xmmsv_dict_iter_set(xmmsv_dict_iter_t *it, xmmsv_t *val)
Replace the element of the pair currently pointed to by the iterator.
Definition value.c:2101
int xmmsv_dict_iter_find(xmmsv_dict_iter_t *it, const char *key)
Move the iterator to the pair with the given key (if it exists) or move it to the position where the ...
Definition value.c:2028
int xmmsv_dict_iter_pair(xmmsv_dict_iter_t *it, const char **key, xmmsv_t **val)
Get the key-element pair currently pointed at by the iterator.
Definition value.c:1948
int xmmsv_get_dict_iter(const xmmsv_t *val, xmmsv_dict_iter_t **it)
Retrieves a dict iterator from a dict xmmsv_t.
Definition value.c:955
int xmmsv_dict_foreach(xmmsv_t *dictv, xmmsv_dict_foreach_func func, void *user_data)
Apply a function to each key-element pair in the list.
Definition value.c:1853
void xmmsv_dict_iter_first(xmmsv_dict_iter_t *it)
Rewind the iterator to the start of the dict.
Definition value.c:1995
void(* xmmsv_dict_foreach_func)(const char *key, xmmsv_t *value, void *user_data)
Definition xmmsv_dict.h:56
int xmmsv_dict_iter_valid(xmmsv_dict_iter_t *it)
Check whether the iterator is valid and points to a valid pair.
Definition value.c:1983
int xmmsv_dict_get_size(xmmsv_t *dictv)
Return the size of the dict.
Definition value.c:1882
int xmmsv_dict_set(xmmsv_t *dictv, const char *key, xmmsv_t *val)
Insert an element under the given key in the dict xmmsv_t.
Definition value.c:1752
xmmsv_t * xmmsv_new_dict(void)
Allocates a new dict xmmsv_t.
Definition value.c:268
int xmmsv_dict_get(xmmsv_t *dictv, const char *key, xmmsv_t **val)
Get the element corresponding to the given key in the dict xmmsv_t (if it exists).
Definition value.c:1717
int xmmsv_dict_clear(xmmsv_t *dictv)
Empty the dict of all its elements.
Definition value.c:1833
int xmmsv_dict_remove(xmmsv_t *dictv, const char *key)
Remove the element corresponding to a given key in the dict xmmsv_t (if it exists).
Definition value.c:1803
int xmmsv_dict_has_key(xmmsv_t *dictv, const char *key)
Definition value.c:2492
xmmsv_type_t xmmsv_dict_entry_get_type(xmmsv_t *val, const char *key)
Gets the type of a dict entry.
Definition value.c:508
int xmmsv_get_list_iter(const xmmsv_t *val, xmmsv_list_iter_t **it)
Retrieves a list iterator from a list xmmsv_t.
Definition value.c:926
void xmmsv_list_iter_next(xmmsv_list_iter_t *it)
Advance the iterator to the next element in the list.
Definition value.c:1553
int xmmsv_list_iter_tell(const xmmsv_list_iter_t *it)
Tell the position of the iterator.
Definition value.c:1606
int xmmsv_list_foreach(xmmsv_t *listv, xmmsv_list_foreach_func func, void *user_data)
Apply a function to each element in the list, in sequential order.
Definition value.c:1375
struct xmmsv_list_iter_St xmmsv_list_iter_t
Definition xmmsv_list.h:69
void xmmsv_list_iter_last(xmmsv_list_iter_t *it)
Move the iterator to end of the list.
Definition value.c:1536
int xmmsv_list_iter_remove(xmmsv_list_iter_t *it)
Remove the element in the list at the position pointed at by the iterator.
Definition value.c:1652
xmmsv_t * xmmsv_list_iter_get_parent(const xmmsv_list_iter_t *it)
Return the parent xmmsv_t of an iterator.
Definition value.c:1620
void(* xmmsv_list_foreach_func)(xmmsv_t *value, void *user_data)
Definition xmmsv_list.h:66
int xmmsv_list_iter_seek(xmmsv_list_iter_t *it, int pos)
Move the iterator to the n-th element in the list.
Definition value.c:1587
int xmmsv_list_iter_entry(xmmsv_list_iter_t *it, xmmsv_t **val)
Get the element currently pointed at by the iterator.
Definition value.c:1495
void xmmsv_list_iter_first(xmmsv_list_iter_t *it)
Rewind the iterator to the start of the list.
Definition value.c:1523
int xmmsv_list_iter_insert(xmmsv_list_iter_t *it, xmmsv_t *val)
Insert an element in the list at the position pointed at by the iterator.
Definition value.c:1636
void xmmsv_list_iter_explicit_destroy(xmmsv_list_iter_t *it)
Explicitly free list iterator.
Definition value.c:1478
void xmmsv_list_iter_prev(xmmsv_list_iter_t *it)
Move the iterator to the previous element in the list.
Definition value.c:1568
int xmmsv_list_iter_valid(xmmsv_list_iter_t *it)
Check whether the iterator is valid and points to a valid element.
Definition value.c:1512
int xmmsv_list_get(xmmsv_t *listv, int pos, xmmsv_t **val)
Get the element at the given position in the list xmmsv_t.
Definition value.c:1218
xmmsv_t * xmmsv_new_list(void)
Allocates a new list xmmsv_t.
Definition value.c:250
int xmmsv_list_remove(xmmsv_t *listv, int pos)
Remove the element at the given position from the list xmmsv_t.
Definition value.c:1300
int xmmsv_list_restrict_type(xmmsv_t *listv, xmmsv_type_t type)
Definition value.c:1413
int xmmsv_list_get_size(xmmsv_t *listv)
Return the size of the list.
Definition value.c:1403
int xmmsv_list_move(xmmsv_t *listv, int old_pos, int new_pos)
Move the element from position #old to position #new.
Definition value.c:1323
int xmmsv_list_clear(xmmsv_t *listv)
Empty the list from all its elements.
Definition value.c:1356
int xmmsv_list_insert(xmmsv_t *listv, int pos, xmmsv_t *val)
Insert an element at the given position in the list xmmsv_t.
Definition value.c:1282
int xmmsv_list_set(xmmsv_t *listv, int pos, xmmsv_t *val)
Set the element at the given position in the list xmmsv_t.
Definition value.c:1249
int xmmsv_list_append(xmmsv_t *listv, xmmsv_t *val)
Append an element to the end of the list xmmsv_t.
Definition value.c:1340
xmmsv_t * xmmsv_decode_url(const xmmsv_t *inv)
Decode an URL-encoded string.
Definition value.c:2167
xmmsv_t * xmmsv_propdict_to_dict(xmmsv_t *propdict, const char **src_prefs)
Helper function to transform a key-source-value dict-of-dict xmmsv_t (formerly a propdict) to a regul...
Definition value.c:752
xmmsv_t * xmmsv_make_stringlist(char *array[], int num)
Helper function to build a list xmmsv_t containing the strings from the input array.
Definition value.c:483
int xmmsv_dict_format(char *target, int len, const char *fmt, xmmsv_t *val)
This function will make a pretty string about the information in xmmsv dict.
Definition value.c:2304
int xmmsv_utf8_validate(const char *str)
Check if a string is valid UTF-8.
Definition value.c:2444
void xmmsv_unref(xmmsv_t *val)
Decreases the references for the xmmsv_t When the number of references reaches 0 it will be freed.
Definition value.c:303
xmmsv_t * xmmsv_new_none(void)
Allocates a new empty xmmsv_t.
Definition value.c:129
int xmmsv_get_coll(const xmmsv_t *val, xmmsv_coll_t **c)
Retrieves a collection from the value.
Definition value.c:883
xmmsv_t * xmmsv_ref(xmmsv_t *val)
References the xmmsv_t.
Definition value.c:288
xmmsv_t * xmmsv_new_string(const char *s)
Allocates a new string xmmsv_t.
Definition value.c:180
int xmmsv_get_string(const xmmsv_t *val, const char **r)
Retrieves a string from the value.
Definition value.c:863
int xmmsv_is_type(const xmmsv_t *val, xmmsv_type_t t)
Check if value is of specified type.
Definition value.c:408
struct xmmsv_St xmmsv_t
xmmsv_t * xmmsv_new_coll(xmmsv_coll_t *c)
Allocates a new collection xmmsv_t.
Definition value.c:202
int xmmsv_get_int(const xmmsv_t *val, int32_t *r)
Retrieves a signed integer from the value.
Definition value.c:823
xmmsv_type_t
int xmmsv_get_error(const xmmsv_t *val, const char **r)
Retrieves an error string describing the server error from the value.
Definition value.c:804
xmmsv_type_t xmmsv_get_type(const xmmsv_t *val)
Get the type of the value.
Definition value.c:392
xmmsv_t * xmmsv_new_int(int32_t i)
Allocates a new integer xmmsv_t.
Definition value.c:161
xmmsv_t * xmmsv_new_bin(const unsigned char *data, unsigned int len)
Allocates a new binary data xmmsv_t.
Definition value.c:225
xmmsv_t * xmmsv_new_error(const char *errstr)
Allocates a new error xmmsv_t.
Definition value.c:143
int xmmsv_is_error(const xmmsv_t *val)
Check if the value stores an error.
Definition value.c:425
int xmmsv_get_bin(const xmmsv_t *val, const unsigned char **r, unsigned int *rlen)
Retrieves binary data from the value.
Definition value.c:904
@ XMMSV_TYPE_NONE
@ XMMSV_TYPE_DICT
@ XMMSV_TYPE_END
@ XMMSV_TYPE_COLL
@ XMMSV_TYPE_BIN
@ XMMSV_TYPE_ERROR
@ XMMSV_TYPE_INT32
@ XMMSV_TYPE_BITBUFFER
@ XMMSV_TYPE_STRING
@ XMMSV_TYPE_LIST
x_list_t * next
Definition xmms_list.h:41
void * data
Definition xmms_list.h:40
#define GEN_DICT_SET_FUNC(typename, type)
Definition value.c:538
#define GEN_LIST_APPEND_FUNC(typename, type)
Definition value.c:652
#define GEN_DICT_ITER_SET_FUNC(typename, type)
Definition value.c:579
#define GEN_LIST_SET_FUNC(typename, type)
Definition value.c:614
const char * default_source_pref[]
Definition value.c:34
struct xmmsv_dict_St xmmsv_dict_t
Definition value.c:47
#define GEN_LIST_ITER_EXTRACTOR_FUNC(typename, type)
Definition value.c:671
struct xmmsv_list_St xmmsv_list_t
Definition value.c:46
struct xmmsv_bin_St xmmsv_bin_t
#define GEN_DICT_ITER_EXTRACTOR_FUNC(typename, type)
Definition value.c:557
#define GEN_LIST_ITER_INSERT_FUNC(typename, type)
Definition value.c:687
#define GEN_LIST_EXTRACTOR_FUNC(typename, type)
Definition value.c:598
#define GEN_DICT_EXTRACTOR_FUNC(typename, type)
Definition value.c:521
#define GEN_LIST_INSERT_FUNC(typename, type)
Definition value.c:633
x_list_t * x_list_remove(x_list_t *list, const void *data)
Definition xlist.c:197
x_list_t * x_list_prepend(x_list_t *list, void *data)
Definition xlist.c:85
#define x_malloc(size)
Definition xmmsc_util.h:19
#define MIN(a, b)
Definition xmmsc_util.h:36
#define x_return_val_if_fail(expr, val)
Definition xmmsc_util.h:13
#define x_return_if_fail(expr)
Definition xmmsc_util.h:12
#define x_new0(type, num)
Definition xmmsc_util.h:16
#define x_oom()
Definition xmmsc_util.h:15
struct xmmsv_coll_St xmmsv_coll_t
Definition xmmsv_coll.h:28