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"
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 /** @file */
32 
33 /* Default source preferences for accessing "propdicts" */
34 const 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 
46 typedef struct xmmsv_list_St xmmsv_list_t;
47 typedef struct xmmsv_dict_St xmmsv_dict_t;
48 
49 
50 typedef struct xmmsv_bin_St {
51  unsigned char *data;
52  uint32_t len;
53 } xmmsv_bin_t;
54 
55 struct 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 
65 static xmmsv_list_t *xmmsv_list_new (void);
66 static void xmmsv_list_free (xmmsv_list_t *l);
67 static int xmmsv_list_resize (xmmsv_list_t *l, int newsize);
68 static int _xmmsv_list_insert (xmmsv_list_t *l, int pos, xmmsv_t *val);
69 static int _xmmsv_list_append (xmmsv_list_t *l, xmmsv_t *val);
70 static int _xmmsv_list_remove (xmmsv_list_t *l, int pos);
71 static int _xmmsv_list_move (xmmsv_list_t *l, int old_pos, int new_pos);
72 static void _xmmsv_list_clear (xmmsv_list_t *l);
73 
74 static xmmsv_dict_t *xmmsv_dict_new (void);
75 static void xmmsv_dict_free (xmmsv_dict_t *dict);
76 
77 
78 struct xmmsv_list_iter_St {
79  xmmsv_list_t *parent;
80  int position;
81 };
82 
83 static xmmsv_list_iter_t *xmmsv_list_iter_new (xmmsv_list_t *l);
84 static void xmmsv_list_iter_free (xmmsv_list_iter_t *it);
85 
86 
87 static xmmsv_dict_iter_t *xmmsv_dict_iter_new (xmmsv_dict_t *d);
88 static void xmmsv_dict_iter_free (xmmsv_dict_iter_t *it);
89 
90 
91 
92 struct 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 
116 static xmmsv_t *xmmsv_new (xmmsv_type_t type);
117 static void xmmsv_free (xmmsv_t *val);
118 static 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  */
128 xmmsv_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  */
142 xmmsv_t *
143 xmmsv_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  */
160 xmmsv_t *
161 xmmsv_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  */
179 xmmsv_t *
180 xmmsv_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  */
201 xmmsv_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  */
224 xmmsv_t *
225 xmmsv_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  */
249 xmmsv_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  */
267 xmmsv_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  */
287 xmmsv_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  */
302 void
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  */
319 static xmmsv_t *
320 xmmsv_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  */
339 static void
340 xmmsv_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  */
407 int
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  */
424 int
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  */
436 int
437 xmmsv_is_list (const xmmsv_t *val)
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  */
448 int
449 xmmsv_is_dict (const xmmsv_t *val)
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  */
461 const 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  */
482 xmmsv_t *
483 xmmsv_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  */
508 xmmsv_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 
533 GEN_DICT_EXTRACTOR_FUNC (string, const char *)
534 GEN_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 
552 GEN_DICT_SET_FUNC (string, const char *)
553 GEN_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 
574 GEN_DICT_ITER_EXTRACTOR_FUNC (string, const char *)
575 GEN_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 
593 GEN_DICT_ITER_SET_FUNC (string, const char *)
594 GEN_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 
609 GEN_LIST_EXTRACTOR_FUNC (string, const char *)
610 GEN_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 
628 GEN_LIST_SET_FUNC (string, const char *)
629 GEN_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 
647 GEN_LIST_INSERT_FUNC (string, const char *)
648 GEN_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 
666 GEN_LIST_APPEND_FUNC (string, const char *)
667 GEN_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 
682 GEN_LIST_ITER_EXTRACTOR_FUNC (string, const char *)
683 GEN_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 
701 GEN_LIST_ITER_INSERT_FUNC (string, const char *)
702 GEN_LIST_ITER_INSERT_FUNC (int, int32_t)
704 
705 static int
706 source_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  */
724 static int
725 find_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  */
751 xmmsv_t *
752 xmmsv_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  */
803 int
804 xmmsv_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  */
822 int
823 xmmsv_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  */
841 int
842 xmmsv_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  */
862 int
863 xmmsv_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  */
882 int
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  */
903 int
904 xmmsv_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  */
925 int
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  */
954 int
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 
978 static xmmsv_list_t *
979 xmmsv_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 
994 static void
995 xmmsv_list_free (xmmsv_list_t *l)
996 {
997  xmmsv_list_iter_t *it;
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 
1015 static int
1016 xmmsv_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 
1033 static int
1034 _xmmsv_list_insert (xmmsv_list_t *l, int pos, xmmsv_t *val)
1035 {
1036  xmmsv_list_iter_t *it;
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 
1080 static int
1081 _xmmsv_list_append (xmmsv_list_t *l, xmmsv_t *val)
1082 {
1083  return _xmmsv_list_insert (l, l->size, val);
1084 }
1085 
1086 static int
1087 _xmmsv_list_remove (xmmsv_list_t *l, int pos)
1088 {
1089  xmmsv_list_iter_t *it;
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 
1127 static int
1128 _xmmsv_list_move (xmmsv_list_t *l, int old_pos, int new_pos)
1129 {
1130  xmmsv_t *v;
1131  xmmsv_list_iter_t *it;
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 
1179 static void
1180 _xmmsv_list_clear (xmmsv_list_t *l)
1181 {
1182  xmmsv_list_iter_t *it;
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  */
1217 int
1218 xmmsv_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  */
1248 int
1249 xmmsv_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  */
1281 int
1282 xmmsv_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  */
1299 int
1300 xmmsv_list_remove (xmmsv_t *listv, int pos)
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  */
1322 int
1323 xmmsv_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  */
1339 int
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  */
1355 int
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  */
1374 int
1376  void* user_data)
1377 {
1378  xmmsv_list_iter_t *it;
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);
1388  xmmsv_list_iter_next (it);
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  */
1402 int
1404 {
1405  x_return_val_if_fail (listv, -1);
1407 
1408  return listv->value.list->size;
1409 }
1410 
1411 
1412 int
1414 {
1415  xmmsv_list_iter_t *it;
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);
1427  xmmsv_list_iter_next (it);
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 
1439 static xmmsv_list_iter_t *
1440 xmmsv_list_iter_new (xmmsv_list_t *l)
1441 {
1442  xmmsv_list_iter_t *it;
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 
1459 static void
1460 xmmsv_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  */
1477 void
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  */
1494 int
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  */
1511 int
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  */
1522 void
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  */
1535 void
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  */
1552 void
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  */
1567 void
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  */
1586 int
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  */
1605 int
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  */
1619 xmmsv_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  */
1635 int
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  */
1651 int
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 
1661 struct 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 
1667 struct xmmsv_dict_iter_St {
1668  /* iterator of the contained flatlist */
1669  xmmsv_list_iter_t *lit;
1670  xmmsv_dict_t *parent;
1671 };
1672 
1673 static xmmsv_dict_t *
1674 xmmsv_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 
1689 static void
1690 xmmsv_dict_free (xmmsv_dict_t *dict)
1691 {
1692  xmmsv_dict_iter_t *it;
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  */
1716 int
1717 xmmsv_dict_get (xmmsv_t *dictv, const char *key, xmmsv_t **val)
1718 {
1719  xmmsv_dict_iter_t *it;
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  */
1751 int
1752 xmmsv_dict_set (xmmsv_t *dictv, const char *key, xmmsv_t *val)
1753 {
1754  xmmsv_dict_iter_t *it;
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  */
1802 int
1803 xmmsv_dict_remove (xmmsv_t *dictv, const char *key)
1804 {
1805  xmmsv_dict_iter_t *it;
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  */
1832 int
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  */
1852 int
1854  void *user_data)
1855 {
1856  xmmsv_dict_iter_t *it;
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);
1867  xmmsv_dict_iter_next (it);
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  */
1881 int
1883 {
1884  x_return_val_if_fail (dictv, -1);
1886 
1887  return dictv->value.dict->flatlist->size / 2;
1888 }
1889 
1890 static xmmsv_dict_iter_t *
1891 xmmsv_dict_iter_new (xmmsv_dict_t *d)
1892 {
1893  xmmsv_dict_iter_t *it;
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 
1910 static void
1911 xmmsv_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  */
1930 void
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  */
1947 int
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  */
1982 int
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  */
1994 void
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  */
2008 void
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  */
2027 int
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  */
2100 int
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  */
2127 int
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  */
2166 xmmsv_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 
2215 err:
2216  free (url);
2217  return NULL;
2218 }
2219 
2220 xmmsv_t *
2221 xmmsv_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 
2251 xmmsv_t *
2252 xmmsv_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 
2277 xmmsv_t *
2278 xmmsv_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  */
2303 int
2304 xmmsv_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;
2322  xmmsv_dict_iter_t *it;
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 
2423 static 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  */
2443 int
2444 xmmsv_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  */
2471 static int
2472 absolutify_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 
2491 int
2492 xmmsv_dict_has_key (xmmsv_t *dictv, const char *key)
2493 {
2494  return xmmsv_dict_get (dictv, key, NULL);
2495 }
2496 
2497 
2498 xmmsv_t *
2499 xmmsv_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 
2510 xmmsv_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 
2523 int
2524 xmmsv_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 
2552 int
2553 xmmsv_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 
2566 int
2567 xmmsv_bitbuffer_put_bits (xmmsv_t *v, int bits, int d)
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 
2609 int
2610 xmmsv_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 
2621 int
2622 xmmsv_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 
2635 int
2637 {
2638  v->value.bit.pos = (v->value.bit.pos + 7) % 8;
2639  return 1;
2640 }
2641 
2642 int
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 
2652 int
2654 {
2655  return v->value.bit.pos;
2656 }
2657 
2658 int
2660 {
2661  return xmmsv_bitbuffer_goto (v, 0);
2662 }
2663 
2664 int
2666 {
2667  return xmmsv_bitbuffer_goto (v, v->value.bit.len);
2668 }
2669 
2670 int
2672 {
2673  return v->value.bit.len;
2674 }
2675 
2676 const unsigned char *
2678 {
2679  return v->value.bit.buf;
2680 }
2681 
2682 /*
2683  *
2684  *
2685  */
2686 
2687 /*
2688 xmmsv_t *
2689 xmmsv_serialize (xmmsv_t *val)
2690 {
2691  switch (xmmsv_get_type (val)) {
2692  case XMMSV_TYPE_NONE:
2693  break;
2694 
2695  }
2696 }
2697 */
void xmmsv_list_iter_first(xmmsv_list_iter_t *it)
Rewind the iterator to the start of the list.
Definition: value.c:1523
xmmsv_t * xmmsv_bitbuffer_new_ro(const unsigned char *v, int len)
Definition: value.c:2499
#define x_return_val_if_fail(expr, val)
Definition: xmmsc_util.h:13
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
struct xmmsv_list_iter_St xmmsv_list_iter_t
Definition: xmmsv_list.h:69
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
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
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
int xmmsv_list_clear(xmmsv_t *listv)
Empty the list from all its elements.
Definition: value.c:1356
struct xmmsv_list_St xmmsv_list_t
Definition: value.c:46
xmmsv_t * xmmsv_new_error(const char *errstr)
Allocates a new error xmmsv_t.
Definition: value.c:143
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
struct xmmsv_St xmmsv_t
Definition: xmmsv_general.h:48
#define GEN_LIST_INSERT_FUNC(typename, type)
Definition: value.c:633
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
xmmsv_t * xmmsv_new_none(void)
Allocates a new empty xmmsv_t.
Definition: value.c:129
xmmsv_t * xmmsv_decode_url(const xmmsv_t *inv)
Decode an URL-encoded string.
Definition: value.c:2167
#define x_malloc(size)
Definition: xmmsc_util.h:19
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
xmmsv_t * xmmsv_build_list_va(xmmsv_t *first_entry, va_list ap)
Definition: value.c:2252
xmmsv_t * xmmsv_new_string(const char *s)
Allocates a new string xmmsv_t.
Definition: value.c:180
xmmsv_coll_t * xmmsv_coll_ref(xmmsv_coll_t *coll)
Increases the references for the xmmsv_coll_t.
Definition: coll.c:61
int xmmsv_get_int(const xmmsv_t *val, int32_t *r)
Retrieves a signed integer from the value.
Definition: value.c:823
#define GEN_LIST_EXTRACTOR_FUNC(typename, type)
Definition: value.c:598
x_list_t * x_list_remove(x_list_t *list, const void *data)
Definition: xlist.c:197
int xmmsv_list_iter_tell(const xmmsv_list_iter_t *it)
Tell the position of the iterator.
Definition: value.c:1606
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
int xmmsv_bitbuffer_get_data(xmmsv_t *v, unsigned char *b, int len)
Definition: value.c:2553
void xmmsv_dict_iter_next(xmmsv_dict_iter_t *it)
Advance the iterator to the next pair in the dict.
Definition: value.c:2009
xmmsv_t * xmmsv_new_dict(void)
Allocates a new dict xmmsv_t.
Definition: value.c:268
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
#define GEN_LIST_ITER_INSERT_FUNC(typename, type)
Definition: value.c:687
x_list_t * next
Definition: xmms_list.h:41
int xmmsv_list_restrict_type(xmmsv_t *listv, xmmsv_type_t type)
Definition: value.c:1413
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 * data
Definition: xmms_list.h:40
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
void xmmsv_dict_iter_explicit_destroy(xmmsv_dict_iter_t *it)
Explicitly free dict iterator.
Definition: value.c:1931
void(* xmmsv_dict_foreach_func)(const char *key, xmmsv_t *value, void *user_data)
Definition: xmmsv_dict.h:56
int xmmsv_bitbuffer_pos(xmmsv_t *v)
Definition: value.c:2653
int xmmsv_bitbuffer_goto(xmmsv_t *v, int pos)
Definition: value.c:2643
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
#define GEN_DICT_ITER_SET_FUNC(typename, type)
Definition: value.c:579
int xmmsv_is_list(const xmmsv_t *val)
Check if the value stores a list.
Definition: value.c:437
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_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_is_type(const xmmsv_t *val, xmmsv_type_t t)
Check if value is of specified type.
Definition: value.c:408
void xmmsv_list_iter_next(xmmsv_list_iter_t *it)
Advance the iterator to the next element in the list.
Definition: value.c:1553
const unsigned char * xmmsv_bitbuffer_buffer(xmmsv_t *v)
Definition: value.c:2677
int xmmsv_is_dict(const xmmsv_t *val)
Check if the value stores a dict.
Definition: value.c:449
xmmsv_t * xmmsv_new_list(void)
Allocates a new list xmmsv_t.
Definition: value.c:250
void xmmsv_list_iter_explicit_destroy(xmmsv_list_iter_t *it)
Explicitly free list iterator.
Definition: value.c:1478
struct xmmsv_coll_St xmmsv_coll_t
Definition: xmmsv_coll.h:28
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
void xmmsv_list_iter_prev(xmmsv_list_iter_t *it)
Move the iterator to the previous element in the list.
Definition: value.c:1568
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
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_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_bitbuffer_put_bits(xmmsv_t *v, int bits, int d)
Definition: value.c:2567
int xmmsv_get_uint(const xmmsv_t *val, uint32_t *r)
Retrieves a unsigned integer from the value.
Definition: value.c:842
#define GEN_LIST_APPEND_FUNC(typename, type)
Definition: value.c:652
int xmmsv_bitbuffer_put_bits_at(xmmsv_t *v, int bits, int d, int offset)
Definition: value.c:2610
#define XMMSV_TYPE_UINT32
int xmmsv_bitbuffer_align(xmmsv_t *v)
Definition: value.c:2636
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
xmmsv_t * xmmsv_new_coll(xmmsv_coll_t *c)
Allocates a new collection xmmsv_t.
Definition: value.c:202
xmmsv_type_t
Definition: xmmsv_general.h:35
int xmmsv_bitbuffer_len(xmmsv_t *v)
Definition: value.c:2671
xmmsv_type_t xmmsv_get_type(const xmmsv_t *val)
Get the type of the value.
Definition: value.c:392
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
xmmsv_t * xmmsv_new_int(int32_t i)
Allocates a new integer xmmsv_t.
Definition: value.c:161
int xmmsv_list_get_size(xmmsv_t *listv)
Return the size of the list.
Definition: value.c:1403
xmmsv_t * xmmsv_build_dict(const char *firstkey,...)
Definition: value.c:2221
xmmsv_t * xmmsv_ref(xmmsv_t *val)
References the xmmsv_t.
Definition: value.c:288
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
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_list_iter_last(xmmsv_list_iter_t *it)
Move the iterator to end of the list.
Definition: value.c:1536
#define x_new0(type, num)
Definition: xmmsc_util.h:16
#define x_oom()
Definition: xmmsc_util.h:15
int xmmsv_utf8_validate(const char *str)
Check if a string is valid UTF-8.
Definition: value.c:2444
int xmmsv_bitbuffer_rewind(xmmsv_t *v)
Definition: value.c:2659
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
#define GEN_DICT_SET_FUNC(typename, type)
Definition: value.c:538
#define MIN(a, b)
Definition: xmmsc_util.h:36
struct xmmsv_bin_St xmmsv_bin_t
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
int xmmsv_bitbuffer_put_data(xmmsv_t *v, const unsigned char *b, int len)
Definition: value.c:2622
xmmsv_t * xmmsv_build_list(xmmsv_t *first_entry,...)
Definition: value.c:2278
#define x_return_if_fail(expr)
Definition: xmmsc_util.h:12
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_get_string(const xmmsv_t *val, const char **r)
Retrieves a string from the value.
Definition: value.c:863
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
int xmmsv_bitbuffer_end(xmmsv_t *v)
Definition: value.c:2665
int xmmsv_is_error(const xmmsv_t *val)
Check if the value stores an error.
Definition: value.c:425
int xmmsv_bitbuffer_get_bits(xmmsv_t *v, int bits, int *res)
Definition: value.c:2524
x_list_t * x_list_prepend(x_list_t *list, void *data)
Definition: xlist.c:85
#define GEN_LIST_ITER_EXTRACTOR_FUNC(typename, type)
Definition: value.c:671
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
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
#define GEN_DICT_ITER_EXTRACTOR_FUNC(typename, type)
Definition: value.c:557
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
struct xmmsv_dict_St xmmsv_dict_t
Definition: value.c:47
void(* xmmsv_list_foreach_func)(xmmsv_t *value, void *user_data)
Definition: xmmsv_list.h:66
#define GEN_DICT_EXTRACTOR_FUNC(typename, type)
Definition: value.c:521
struct xmmsv_dict_iter_St xmmsv_dict_iter_t
Definition: xmmsv_dict.h:59
xmmsv_t * xmmsv_new_bin(const unsigned char *data, unsigned int len)
Allocates a new binary data xmmsv_t.
Definition: value.c:225
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_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
#define GEN_LIST_SET_FUNC(typename, type)
Definition: value.c:614
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
int xmmsv_dict_get_size(xmmsv_t *dictv)
Return the size of the dict.
Definition: value.c:1882
int xmmsv_dict_has_key(xmmsv_t *dictv, const char *key)
Definition: value.c:2492
int xmmsv_dict_clear(xmmsv_t *dictv)
Empty the dict of all its elements.
Definition: value.c:1833
const char * default_source_pref[]
Definition: value.c:34
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
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_bitbuffer_new(void)
Definition: value.c:2511
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