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