XMMS2
src/lib/xmmstypes/value.c
Go to the documentation of this file.
00001 /*  XMMS2 - X Music Multiplexer System
00002  *  Copyright (C) 2003-2011 XMMS2 Team
00003  *
00004  *  PLUGINS ARE NOT CONSIDERED TO BE DERIVED WORK !!!
00005  *
00006  *  This library is free software; you can redistribute it and/or
00007  *  modify it under the terms of the GNU Lesser General Public
00008  *  License as published by the Free Software Foundation; either
00009  *  version 2.1 of the License, or (at your option) any later version.
00010  *
00011  *  This library is distributed in the hope that it will be useful,
00012  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  *  Lesser General Public License for more details.
00015  */
00016 
00017 #include <stdio.h>
00018 #include <stdlib.h>
00019 #include <stdarg.h>
00020 #include <string.h>
00021 #include <ctype.h>
00022 #include <assert.h>
00023 
00024 #include "xmmsc/xmmsv.h"
00025 #include "xmmsc/xmmsc_idnumbers.h"
00026 #include "xmmsc/xmmsc_errorcodes.h"
00027 #include "xmmsc/xmmsc_stdbool.h"
00028 #include "xmmsc/xmmsc_util.h"
00029 #include "xmmspriv/xmms_list.h"
00030 
00031 /** @file */
00032 
00033 /* Default source preferences for accessing "propdicts" */
00034 const char *default_source_pref[] = {
00035     "server",
00036     "client/*",
00037     "plugin/playlist",
00038     "plugin/id3v2",
00039     "plugin/segment",
00040     "plugin/*",
00041     "*",
00042     NULL
00043 };
00044 
00045 
00046 typedef struct xmmsv_list_St xmmsv_list_t;
00047 typedef struct xmmsv_dict_St xmmsv_dict_t;
00048 
00049 
00050 typedef struct xmmsv_bin_St {
00051     unsigned char *data;
00052     uint32_t len;
00053 } xmmsv_bin_t;
00054 
00055 struct xmmsv_list_St {
00056     xmmsv_t **list;
00057     xmmsv_t *parent_value;
00058     int size;
00059     int allocated;
00060     bool restricted;
00061     xmmsv_type_t restricttype;
00062     x_list_t *iterators;
00063 };
00064 
00065 static xmmsv_list_t *xmmsv_list_new (void);
00066 static void xmmsv_list_free (xmmsv_list_t *l);
00067 static int xmmsv_list_resize (xmmsv_list_t *l, int newsize);
00068 static int _xmmsv_list_insert (xmmsv_list_t *l, int pos, xmmsv_t *val);
00069 static int _xmmsv_list_append (xmmsv_list_t *l, xmmsv_t *val);
00070 static int _xmmsv_list_remove (xmmsv_list_t *l, int pos);
00071 static int _xmmsv_list_move (xmmsv_list_t *l, int old_pos, int new_pos);
00072 static void _xmmsv_list_clear (xmmsv_list_t *l);
00073 
00074 static xmmsv_dict_t *xmmsv_dict_new (void);
00075 static void xmmsv_dict_free (xmmsv_dict_t *dict);
00076 
00077 
00078 struct xmmsv_list_iter_St {
00079     xmmsv_list_t *parent;
00080     int position;
00081 };
00082 
00083 static xmmsv_list_iter_t *xmmsv_list_iter_new (xmmsv_list_t *l);
00084 static void xmmsv_list_iter_free (xmmsv_list_iter_t *it);
00085 
00086 
00087 static xmmsv_dict_iter_t *xmmsv_dict_iter_new (xmmsv_dict_t *d);
00088 static void xmmsv_dict_iter_free (xmmsv_dict_iter_t *it);
00089 
00090 
00091 
00092 struct xmmsv_St {
00093     union {
00094         char *error;
00095         int32_t int32;
00096         char *string;
00097         xmmsv_coll_t *coll;
00098         xmmsv_bin_t bin;
00099         xmmsv_list_t *list;
00100         xmmsv_dict_t *dict;
00101 
00102         struct {
00103             bool ro;
00104             unsigned char *buf;
00105             int alloclen; /* in bits */
00106             int len; /* in bits */
00107             int pos; /* in bits */
00108         } bit;
00109     } value;
00110     xmmsv_type_t type;
00111 
00112     int ref;  /* refcounting */
00113 };
00114 
00115 
00116 static xmmsv_t *xmmsv_new (xmmsv_type_t type);
00117 static void xmmsv_free (xmmsv_t *val);
00118 static int absolutify_and_validate_pos (int *pos, int size, int allow_append);
00119 
00120 
00121 
00122 
00123 /**
00124  * Allocates a new empty #xmmsv_t.
00125  * @return The new #xmmsv_t. Must be unreferenced with
00126  * #xmmsv_unref.
00127  */
00128 xmmsv_t *
00129 xmmsv_new_none (void)
00130 {
00131     xmmsv_t *val = xmmsv_new (XMMSV_TYPE_NONE);
00132     return val;
00133 }
00134 
00135 /**
00136  * Allocates a new error #xmmsv_t.
00137  * @param s The error message to store in the #xmmsv_t. The
00138  * string is copied in the value.
00139  * @return The new #xmmsv_t. Must be unreferenced with
00140  * #xmmsv_unref.
00141  */
00142 xmmsv_t *
00143 xmmsv_new_error (const char *errstr)
00144 {
00145     xmmsv_t *val = xmmsv_new (XMMSV_TYPE_ERROR);
00146 
00147     if (val) {
00148         val->value.error = strdup (errstr);
00149     }
00150 
00151     return val;
00152 }
00153 
00154 /**
00155  * Allocates a new integer #xmmsv_t.
00156  * @param i The value to store in the #xmmsv_t.
00157  * @return The new #xmmsv_t. Must be unreferenced with
00158  * #xmmsv_unref.
00159  */
00160 xmmsv_t *
00161 xmmsv_new_int (int32_t i)
00162 {
00163     xmmsv_t *val = xmmsv_new (XMMSV_TYPE_INT32);
00164 
00165     if (val) {
00166         val->value.int32 = i;
00167     }
00168 
00169     return val;
00170 }
00171 
00172 /**
00173  * Allocates a new string #xmmsv_t.
00174  * @param s The value to store in the #xmmsv_t. The string is
00175  * copied in the value.
00176  * @return The new #xmmsv_t. Must be unreferenced with
00177  * #xmmsv_unref.
00178  */
00179 xmmsv_t *
00180 xmmsv_new_string (const char *s)
00181 {
00182     xmmsv_t *val;
00183 
00184     x_return_val_if_fail (s, NULL);
00185     x_return_val_if_fail (xmmsv_utf8_validate (s), NULL);
00186 
00187     val = xmmsv_new (XMMSV_TYPE_STRING);
00188     if (val) {
00189         val->value.string = strdup (s);
00190     }
00191 
00192     return val;
00193 }
00194 
00195 /**
00196  * Allocates a new collection #xmmsv_t.
00197  * @param s The value to store in the #xmmsv_t.
00198  * @return The new #xmmsv_t. Must be unreferenced with
00199  * #xmmsv_unref.
00200  */
00201 xmmsv_t *
00202 xmmsv_new_coll (xmmsv_coll_t *c)
00203 {
00204     xmmsv_t *val;
00205 
00206     x_return_val_if_fail (c, NULL);
00207 
00208     val = xmmsv_new (XMMSV_TYPE_COLL);
00209     if (val) {
00210         val->value.coll = c;
00211         xmmsv_coll_ref (c);
00212     }
00213 
00214     return val;
00215 }
00216 
00217 /**
00218  * Allocates a new binary data #xmmsv_t.
00219  * @param data The data to store in the #xmmsv_t.
00220  * @param len The size of the data.
00221  * @return The new #xmmsv_t. Must be unreferenced with
00222  * #xmmsv_unref.
00223  */
00224 xmmsv_t *
00225 xmmsv_new_bin (const unsigned char *data, unsigned int len)
00226 {
00227     xmmsv_t *val = xmmsv_new (XMMSV_TYPE_BIN);
00228 
00229     if (val) {
00230         /* copy the data! */
00231         val->value.bin.data = x_malloc (len);
00232         if (!val->value.bin.data) {
00233             free (val);
00234             x_oom ();
00235             return NULL;
00236         }
00237         memcpy (val->value.bin.data, data, len);
00238         val->value.bin.len = len;
00239     }
00240 
00241     return val;
00242 }
00243 
00244 /**
00245  * Allocates a new list #xmmsv_t.
00246  * @return The new #xmmsv_t. Must be unreferenced with
00247  * #xmmsv_unref.
00248  */
00249 xmmsv_t *
00250 xmmsv_new_list (void)
00251 {
00252     xmmsv_t *val = xmmsv_new (XMMSV_TYPE_LIST);
00253 
00254     if (val) {
00255         val->value.list = xmmsv_list_new ();
00256         val->value.list->parent_value = val;
00257     }
00258 
00259     return val;
00260 }
00261 
00262 /**
00263  * Allocates a new dict #xmmsv_t.
00264  * @return The new #xmmsv_t. Must be unreferenced with
00265  * #xmmsv_unref.
00266  */
00267 xmmsv_t *
00268 xmmsv_new_dict (void)
00269 {
00270     xmmsv_t *val = xmmsv_new (XMMSV_TYPE_DICT);
00271 
00272     if (val) {
00273         val->value.dict = xmmsv_dict_new ();
00274     }
00275 
00276     return val;
00277 }
00278 
00279 
00280 
00281 /**
00282  * References the #xmmsv_t
00283  *
00284  * @param val the value to reference.
00285  * @return val
00286  */
00287 xmmsv_t *
00288 xmmsv_ref (xmmsv_t *val)
00289 {
00290     x_return_val_if_fail (val, NULL);
00291     val->ref++;
00292 
00293     return val;
00294 }
00295 
00296 /**
00297  * Decreases the references for the #xmmsv_t
00298  * When the number of references reaches 0 it will
00299  * be freed. And thus all data you extracted from it
00300  * will be deallocated.
00301  */
00302 void
00303 xmmsv_unref (xmmsv_t *val)
00304 {
00305     x_return_if_fail (val);
00306     x_api_error_if (val->ref < 1, "with a freed value",);
00307 
00308     val->ref--;
00309     if (val->ref == 0) {
00310         xmmsv_free (val);
00311     }
00312 }
00313 
00314 
00315 /**
00316  * Allocates new #xmmsv_t and references it.
00317  * @internal
00318  */
00319 static xmmsv_t *
00320 xmmsv_new (xmmsv_type_t type)
00321 {
00322     xmmsv_t *val;
00323 
00324     val = x_new0 (xmmsv_t, 1);
00325     if (!val) {
00326         x_oom ();
00327         return NULL;
00328     }
00329 
00330     val->type = type;
00331 
00332     return xmmsv_ref (val);
00333 }
00334 
00335 /**
00336  * Free a #xmmsv_t along with its internal data.
00337  * @internal
00338  */
00339 static void
00340 xmmsv_free (xmmsv_t *val)
00341 {
00342     x_return_if_fail (val);
00343 
00344     switch (val->type) {
00345         case XMMSV_TYPE_NONE :
00346         case XMMSV_TYPE_END :
00347         case XMMSV_TYPE_INT32 :
00348             break;
00349         case XMMSV_TYPE_ERROR :
00350             free (val->value.error);
00351             val->value.error = NULL;
00352             break;
00353         case XMMSV_TYPE_STRING :
00354             free (val->value.string);
00355             val->value.string = NULL;
00356             break;
00357         case XMMSV_TYPE_COLL:
00358             xmmsv_coll_unref (val->value.coll);
00359             val->value.coll = NULL;
00360             break;
00361         case XMMSV_TYPE_BIN :
00362             free (val->value.bin.data);
00363             val->value.bin.len = 0;
00364             break;
00365         case XMMSV_TYPE_LIST:
00366             xmmsv_list_free (val->value.list);
00367             val->value.list = NULL;
00368             break;
00369         case XMMSV_TYPE_DICT:
00370             xmmsv_dict_free (val->value.dict);
00371             val->value.dict = NULL;
00372             break;
00373         case XMMSV_TYPE_BITBUFFER:
00374             if (!val->value.bit.ro && val->value.bit.buf) {
00375                 free (val->value.bit.buf);
00376             }
00377             val->value.bit.buf = NULL;
00378             break;
00379     }
00380 
00381     free (val);
00382 }
00383 
00384 
00385 /**
00386  * Get the type of the value.
00387  *
00388  * @param val a #xmmsv_t to get the type from.
00389  * @returns The data type in the value.
00390  */
00391 xmmsv_type_t
00392 xmmsv_get_type (const xmmsv_t *val)
00393 {
00394     x_api_error_if (!val, "NULL value",
00395                     XMMSV_TYPE_NONE);
00396 
00397     return val->type;
00398 }
00399 
00400 /**
00401  * Check if value is of specified type.
00402  *
00403  * @param val #xmmsv_t to check.
00404  * @param t #xmmsv_type_t to check for.
00405  * @return 1 if value is of specified type, 0 otherwise.
00406  */
00407 int
00408 xmmsv_is_type (const xmmsv_t *val, xmmsv_type_t t)
00409 {
00410     x_api_error_if (!val, "NULL value", 0);
00411 
00412     return (xmmsv_get_type (val) == t);
00413 }
00414 
00415 
00416 /* Merely legacy aliases */
00417 
00418 /**
00419  * Check if the value stores an error.
00420  *
00421  * @param val a #xmmsv_t
00422  * @return 1 if error was encountered, 0 otherwise.
00423  */
00424 int
00425 xmmsv_is_error (const xmmsv_t *val)
00426 {
00427     return xmmsv_is_type (val, XMMSV_TYPE_ERROR);
00428 }
00429 
00430 /**
00431  * Check if the value stores a list.
00432  *
00433  * @param val a #xmmsv_t
00434  * @return 1 if value stores a list, 0 otherwise.
00435  */
00436 int
00437 xmmsv_is_list (const xmmsv_t *val)
00438 {
00439     return xmmsv_is_type (val, XMMSV_TYPE_LIST);
00440 }
00441 
00442 /**
00443  * Check if the value stores a dict.
00444  *
00445  * @param val a #xmmsv_t
00446  * @return 1 if value stores a dict, 0 otherwise.
00447  */
00448 int
00449 xmmsv_is_dict (const xmmsv_t *val)
00450 {
00451     return xmmsv_is_type (val, XMMSV_TYPE_DICT);
00452 }
00453 
00454 /**
00455  * Legacy alias to retrieve the error string from an
00456  * #xmmsv_t. Obsolete now, use #xmmsv_get_error instead!
00457  *
00458  * @param val an error #xmmsv_t
00459  * @return the error string if valid, NULL otherwise.
00460  */
00461 const char *
00462 xmmsv_get_error_old (const xmmsv_t *val)
00463 {
00464     if (!val || val->type != XMMSV_TYPE_ERROR) {
00465         return NULL;
00466     }
00467 
00468     return val->value.error;
00469 }
00470 
00471 /**
00472  * Helper function to build a list #xmmsv_t containing the
00473  * strings from the input array.
00474  *
00475  * @param array An array of C strings. Must be NULL-terminated if num
00476  *              is -1.
00477  * @param num The optional number of elements to read from the array. Set to
00478  *            -1 if the array is NULL-terminated.
00479  * @return An #xmmsv_t containing the list of strings. Must be
00480  *         unreffed manually when done.
00481  */
00482 xmmsv_t *
00483 xmmsv_make_stringlist (char *array[], int num)
00484 {
00485     xmmsv_t *list, *elem;
00486     int i;
00487 
00488     list = xmmsv_new_list ();
00489     if (array) {
00490         for (i = 0; (num >= 0 && i < num) || array[i]; i++) {
00491             elem = xmmsv_new_string (array[i]);
00492             xmmsv_list_append (list, elem);
00493             xmmsv_unref (elem);
00494         }
00495     }
00496 
00497     return list;
00498 }
00499 
00500 /**
00501  * Gets the type of a dict entry.
00502  *
00503  * @param val A xmmsv_t containing a dict.
00504  * @param key The key in the dict.
00505  * @return The type of the entry or #XMMSV_TYPE_NONE if something goes wrong.
00506  */
00507 xmmsv_type_t
00508 xmmsv_dict_entry_get_type (xmmsv_t *val, const char *key)
00509 {
00510     xmmsv_t *v;
00511 
00512     if (!xmmsv_dict_get (val, key, &v)) {
00513         return XMMSV_TYPE_NONE;
00514     }
00515 
00516     return xmmsv_get_type (v);
00517 }
00518 
00519 
00520 /* macro-magically define dict extractors */
00521 #define GEN_DICT_EXTRACTOR_FUNC(typename, type)         \
00522     int                             \
00523     xmmsv_dict_entry_get_##typename (xmmsv_t *val, const char *key, \
00524                                      type *r)           \
00525     {                               \
00526         xmmsv_t *v;                     \
00527         if (!xmmsv_dict_get (val, key, &v)) {           \
00528             return 0;                   \
00529         }                           \
00530         return xmmsv_get_##typename (v, r);         \
00531     }
00532 
00533 GEN_DICT_EXTRACTOR_FUNC (string, const char *)
00534 GEN_DICT_EXTRACTOR_FUNC (int, int32_t)
00535 GEN_DICT_EXTRACTOR_FUNC (coll, xmmsv_coll_t *)
00536 
00537 /* macro-magically define dict set functions */
00538 #define GEN_DICT_SET_FUNC(typename, type) \
00539     int \
00540     xmmsv_dict_set_##typename (xmmsv_t *dict, const char *key, type elem) \
00541     { \
00542         int ret; \
00543         xmmsv_t *v; \
00544  \
00545         v = xmmsv_new_##typename (elem); \
00546         ret = xmmsv_dict_set (dict, key, v); \
00547         xmmsv_unref (v); \
00548  \
00549         return ret; \
00550     }
00551 
00552 GEN_DICT_SET_FUNC (string, const char *)
00553 GEN_DICT_SET_FUNC (int, int32_t)
00554 GEN_DICT_SET_FUNC (coll, xmmsv_coll_t *)
00555 
00556 /* macro-magically define dict_iter extractors */
00557 #define GEN_DICT_ITER_EXTRACTOR_FUNC(typename, type) \
00558     int \
00559     xmmsv_dict_iter_pair_##typename (xmmsv_dict_iter_t *it, \
00560                                      const char **key, \
00561                                      type *r) \
00562     { \
00563         xmmsv_t *v; \
00564         if (!xmmsv_dict_iter_pair (it, key, &v)) { \
00565             return 0; \
00566         } \
00567         if (r) { \
00568             return xmmsv_get_##typename (v, r); \
00569         } else { \
00570             return 1; \
00571         } \
00572     }
00573 
00574 GEN_DICT_ITER_EXTRACTOR_FUNC (string, const char *)
00575 GEN_DICT_ITER_EXTRACTOR_FUNC (int, int32_t)
00576 GEN_DICT_ITER_EXTRACTOR_FUNC (coll, xmmsv_coll_t *)
00577 
00578 /* macro-magically define dict_iter set functions */
00579 #define GEN_DICT_ITER_SET_FUNC(typename, type) \
00580     int \
00581     xmmsv_dict_iter_set_##typename (xmmsv_dict_iter_t *it, type elem) \
00582     { \
00583         int ret; \
00584         xmmsv_t *v; \
00585  \
00586         v = xmmsv_new_##typename (elem); \
00587         ret = xmmsv_dict_iter_set (it, v); \
00588         xmmsv_unref (v); \
00589  \
00590         return ret; \
00591     }
00592 
00593 GEN_DICT_ITER_SET_FUNC (string, const char *)
00594 GEN_DICT_ITER_SET_FUNC (int, int32_t)
00595 GEN_DICT_ITER_SET_FUNC (coll, xmmsv_coll_t *)
00596 
00597 /* macro-magically define list extractors */
00598 #define GEN_LIST_EXTRACTOR_FUNC(typename, type) \
00599     int \
00600     xmmsv_list_get_##typename (xmmsv_t *val, int pos, type *r) \
00601     { \
00602         xmmsv_t *v; \
00603         if (!xmmsv_list_get (val, pos, &v)) { \
00604             return 0; \
00605         } \
00606         return xmmsv_get_##typename (v, r); \
00607     }
00608 
00609 GEN_LIST_EXTRACTOR_FUNC (string, const char *)
00610 GEN_LIST_EXTRACTOR_FUNC (int, int32_t)
00611 GEN_LIST_EXTRACTOR_FUNC (coll, xmmsv_coll_t *)
00612 
00613 /* macro-magically define list set functions */
00614 #define GEN_LIST_SET_FUNC(typename, type) \
00615     int \
00616     xmmsv_list_set_##typename (xmmsv_t *list, int pos, type elem) \
00617     { \
00618         int ret; \
00619         xmmsv_t *v; \
00620  \
00621         v = xmmsv_new_##typename (elem); \
00622         ret = xmmsv_list_set (list, pos, v); \
00623         xmmsv_unref (v); \
00624  \
00625         return ret; \
00626     }
00627 
00628 GEN_LIST_SET_FUNC (string, const char *)
00629 GEN_LIST_SET_FUNC (int, int32_t)
00630 GEN_LIST_SET_FUNC (coll, xmmsv_coll_t *)
00631 
00632 /* macro-magically define list insert functions */
00633 #define GEN_LIST_INSERT_FUNC(typename, type) \
00634     int \
00635     xmmsv_list_insert_##typename (xmmsv_t *list, int pos, type elem) \
00636     { \
00637         int ret; \
00638         xmmsv_t *v; \
00639  \
00640         v = xmmsv_new_##typename (elem); \
00641         ret = xmmsv_list_insert (list, pos, v); \
00642         xmmsv_unref (v); \
00643  \
00644         return ret; \
00645     }
00646 
00647 GEN_LIST_INSERT_FUNC (string, const char *)
00648 GEN_LIST_INSERT_FUNC (int, int32_t)
00649 GEN_LIST_INSERT_FUNC (coll, xmmsv_coll_t *)
00650 
00651 /* macro-magically define list append functions */
00652 #define GEN_LIST_APPEND_FUNC(typename, type) \
00653     int \
00654     xmmsv_list_append_##typename (xmmsv_t *list, type elem) \
00655     { \
00656         int ret; \
00657         xmmsv_t *v; \
00658  \
00659         v = xmmsv_new_##typename (elem); \
00660         ret = xmmsv_list_append (list, v); \
00661         xmmsv_unref (v); \
00662  \
00663         return ret; \
00664     }
00665 
00666 GEN_LIST_APPEND_FUNC (string, const char *)
00667 GEN_LIST_APPEND_FUNC (int, int32_t)
00668 GEN_LIST_APPEND_FUNC (coll, xmmsv_coll_t *)
00669 
00670 /* macro-magically define list_iter extractors */
00671 #define GEN_LIST_ITER_EXTRACTOR_FUNC(typename, type) \
00672     int \
00673     xmmsv_list_iter_entry_##typename (xmmsv_list_iter_t *it, type *r) \
00674     { \
00675         xmmsv_t *v; \
00676         if (!xmmsv_list_iter_entry (it, &v)) { \
00677             return 0; \
00678         } \
00679         return xmmsv_get_##typename (v, r); \
00680     }
00681 
00682 GEN_LIST_ITER_EXTRACTOR_FUNC (string, const char *)
00683 GEN_LIST_ITER_EXTRACTOR_FUNC (int, int32_t)
00684 GEN_LIST_ITER_EXTRACTOR_FUNC (coll, xmmsv_coll_t *)
00685 
00686 /* macro-magically define list_iter insert functions */
00687 #define GEN_LIST_ITER_INSERT_FUNC(typename, type) \
00688     int \
00689     xmmsv_list_iter_insert_##typename (xmmsv_list_iter_t *it, type elem) \
00690     { \
00691         int ret; \
00692         xmmsv_t *v; \
00693  \
00694         v = xmmsv_new_##typename (elem); \
00695         ret = xmmsv_list_iter_insert (it, v); \
00696         xmmsv_unref (v); \
00697  \
00698         return ret; \
00699     }
00700 
00701 GEN_LIST_ITER_INSERT_FUNC (string, const char *)
00702 GEN_LIST_ITER_INSERT_FUNC (int, int32_t)
00703 GEN_LIST_ITER_INSERT_FUNC (coll, xmmsv_coll_t *)
00704 
00705 static int
00706 source_match_pattern (const char *source, const char *pattern)
00707 {
00708     int match = 0;
00709     int lpos = strlen (pattern) - 1;
00710 
00711     if (strcasecmp (pattern, source) == 0) {
00712         match = 1;
00713     } else if (lpos >= 0 && pattern[lpos] == '*' &&
00714                (lpos == 0 || strncasecmp (source, pattern, lpos) == 0)) {
00715         match = 1;
00716     }
00717 
00718     return match;
00719 }
00720 
00721 /* Return the index of the source in the source prefs list, or -1 if
00722  * no match.
00723  */
00724 static int
00725 find_match_index (const char *source, const char **src_prefs)
00726 {
00727     int i, match = -1;
00728 
00729     for (i = 0; src_prefs[i]; i++) {
00730         if (source_match_pattern (source, src_prefs[i])) {
00731             match = i;
00732             break;
00733         }
00734     }
00735 
00736     return match;
00737 }
00738 
00739 /**
00740  * Helper function to transform a key-source-value dict-of-dict
00741  * #xmmsv_t (formerly a propdict) to a regular key-value dict, given a
00742  * list of source preference.
00743  *
00744  * @param propdict A key-source-value dict-of-dict #xmmsv_t.
00745  * @param src_prefs A list of source names or patterns. Must be
00746  *                  NULL-terminated. If this argument is NULL, the
00747  *                  default source preferences is used.
00748  * @return An #xmmsv_t containing a simple key-value dict. Must be
00749  *         unreffed manually when done.
00750  */
00751 xmmsv_t *
00752 xmmsv_propdict_to_dict (xmmsv_t *propdict, const char **src_prefs)
00753 {
00754     xmmsv_t *dict, *source_dict, *value, *best_value;
00755     xmmsv_dict_iter_t *key_it, *source_it;
00756     const char *key, *source;
00757     const char **local_prefs;
00758     int match_index, best_index;
00759 
00760     dict = xmmsv_new_dict ();
00761 
00762     local_prefs = src_prefs ? src_prefs : default_source_pref;
00763 
00764     xmmsv_get_dict_iter (propdict, &key_it);
00765     while (xmmsv_dict_iter_valid (key_it)) {
00766         xmmsv_dict_iter_pair (key_it, &key, &source_dict);
00767 
00768         best_value = NULL;
00769         best_index = -1;
00770         xmmsv_get_dict_iter (source_dict, &source_it);
00771         while (xmmsv_dict_iter_valid (source_it)) {
00772             xmmsv_dict_iter_pair (source_it, &source, &value);
00773             match_index = find_match_index (source, local_prefs);
00774             /* keep first match or better match */
00775             if (match_index >= 0 && (best_index < 0 ||
00776                                      match_index < best_index)) {
00777                 best_value = value;
00778                 best_index = match_index;
00779             }
00780             xmmsv_dict_iter_next (source_it);
00781         }
00782 
00783         /* Note: we do not insert a key-value pair if no source matches */
00784         if (best_value) {
00785             xmmsv_dict_set (dict, key, best_value);
00786         }
00787 
00788         xmmsv_dict_iter_next (key_it);
00789     }
00790 
00791     return dict;
00792 }
00793 
00794 
00795 /**
00796  * Retrieves an error string describing the server error from the
00797  * value.
00798  *
00799  * @param val a #xmmsv_t containing a integer.
00800  * @param r the return error.
00801  * @return 1 upon success otherwise 0
00802  */
00803 int
00804 xmmsv_get_error (const xmmsv_t *val, const char **r)
00805 {
00806     if (!val || val->type != XMMSV_TYPE_ERROR) {
00807         return 0;
00808     }
00809 
00810     *r = val->value.error;
00811 
00812     return 1;
00813 }
00814 
00815 /**
00816  * Retrieves a signed integer from the value.
00817  *
00818  * @param val a #xmmsv_t containing an integer.
00819  * @param r the return integer.
00820  * @return 1 upon success otherwise 0
00821  */
00822 int
00823 xmmsv_get_int (const xmmsv_t *val, int32_t *r)
00824 {
00825     if (!val || val->type != XMMSV_TYPE_INT32) {
00826         return 0;
00827     }
00828 
00829     *r = val->value.int32;
00830 
00831     return 1;
00832 }
00833 
00834 /**
00835  * Retrieves a unsigned integer from the value.
00836  *
00837  * @param val a #xmmsv_t containing an unsigned integer.
00838  * @param r the return unsigned integer.
00839  * @return 1 upon success otherwise 0
00840  */
00841 int
00842 xmmsv_get_uint (const xmmsv_t *val, uint32_t *r)
00843 {
00844     if (!val)
00845         return 0;
00846     if (val->type != XMMSV_TYPE_INT32)
00847         return 0;
00848 
00849     *r = val->value.int32;
00850 
00851     return 1;
00852 }
00853 
00854 /**
00855  * Retrieves a string from the value.
00856  *
00857  * @param val a #xmmsv_t containing a string.
00858  * @param r the return string. This string is owned by the value and
00859  * will be freed when the value is freed.
00860  * @return 1 upon success otherwise 0
00861  */
00862 int
00863 xmmsv_get_string (const xmmsv_t *val, const char **r)
00864 {
00865     if (!val || val->type != XMMSV_TYPE_STRING) {
00866         return 0;
00867     }
00868 
00869     *r = val->value.string;
00870 
00871     return 1;
00872 }
00873 
00874 /**
00875  * Retrieves a collection from the value.
00876  *
00877  * @param val a #xmmsv_t containing a collection.
00878  * @param c the return collection. This collection is owned by the
00879  * value and will be unref'd when the value is freed.
00880  * @return 1 upon success otherwise 0
00881  */
00882 int
00883 xmmsv_get_coll (const xmmsv_t *val, xmmsv_coll_t **c)
00884 {
00885     if (!val || val->type != XMMSV_TYPE_COLL) {
00886         return 0;
00887     }
00888 
00889     *c = val->value.coll;
00890 
00891     return 1;
00892 }
00893 
00894 /**
00895  * Retrieves binary data from the value.
00896  *
00897  * @param val a #xmmsv_t containing a string.
00898  * @param r the return data. This data is owned by the value and will
00899  * be freed when the value is freed.
00900  * @param rlen the return length of data.
00901  * @return 1 upon success otherwise 0
00902  */
00903 int
00904 xmmsv_get_bin (const xmmsv_t *val, const unsigned char **r, unsigned int *rlen)
00905 {
00906     if (!val || val->type != XMMSV_TYPE_BIN) {
00907         return 0;
00908     }
00909 
00910     *r = val->value.bin.data;
00911     *rlen = val->value.bin.len;
00912 
00913     return 1;
00914 }
00915 
00916 
00917 /**
00918  * Retrieves a list iterator from a list #xmmsv_t.
00919  *
00920  * @param val a #xmmsv_t containing a list.
00921  * @param it An #xmmsv_list_iter_t that can be used to access the list
00922  *           data. The iterator will be freed when the value is freed.
00923  * @return 1 upon success otherwise 0
00924  */
00925 int
00926 xmmsv_get_list_iter (const xmmsv_t *val, xmmsv_list_iter_t **it)
00927 {
00928     xmmsv_list_iter_t *new_it;
00929 
00930     if (!val || val->type != XMMSV_TYPE_LIST) {
00931         *it = NULL;
00932         return 0;
00933     }
00934 
00935     new_it = xmmsv_list_iter_new (val->value.list);
00936     if (!new_it) {
00937         *it = NULL;
00938         return 0;
00939     }
00940 
00941     *it = new_it;
00942 
00943     return 1;
00944 }
00945 
00946 /**
00947  * Retrieves a dict iterator from a dict #xmmsv_t.
00948  *
00949  * @param val a #xmmsv_t containing a dict.
00950  * @param it An #xmmsv_dict_iter_t that can be used to access the dict
00951  *           data. The iterator will be freed when the value is freed.
00952  * @return 1 upon success otherwise 0
00953  */
00954 int
00955 xmmsv_get_dict_iter (const xmmsv_t *val, xmmsv_dict_iter_t **it)
00956 {
00957     xmmsv_dict_iter_t *new_it;
00958 
00959     if (!val || val->type != XMMSV_TYPE_DICT) {
00960         *it = NULL;
00961         return 0;
00962     }
00963 
00964     new_it = xmmsv_dict_iter_new (val->value.dict);
00965     if (!new_it) {
00966         *it = NULL;
00967         return 0;
00968     }
00969 
00970     *it = new_it;
00971 
00972     return 1;
00973 }
00974 
00975 
00976 /* List stuff */
00977 
00978 static xmmsv_list_t *
00979 xmmsv_list_new (void)
00980 {
00981     xmmsv_list_t *list;
00982 
00983     list = x_new0 (xmmsv_list_t, 1);
00984     if (!list) {
00985         x_oom ();
00986         return NULL;
00987     }
00988 
00989     /* list is all empty for now! */
00990 
00991     return list;
00992 }
00993 
00994 static void
00995 xmmsv_list_free (xmmsv_list_t *l)
00996 {
00997     xmmsv_list_iter_t *it;
00998     int i;
00999 
01000     /* free iterators */
01001     while (l->iterators) {
01002         it = (xmmsv_list_iter_t *) l->iterators->data;
01003         xmmsv_list_iter_free (it);
01004     }
01005 
01006     /* unref contents */
01007     for (i = 0; i < l->size; i++) {
01008         xmmsv_unref (l->list[i]);
01009     }
01010 
01011     free (l->list);
01012     free (l);
01013 }
01014 
01015 static int
01016 xmmsv_list_resize (xmmsv_list_t *l, int newsize)
01017 {
01018     xmmsv_t **newmem;
01019 
01020     newmem = realloc (l->list, newsize * sizeof (xmmsv_t *));
01021 
01022     if (newsize != 0 && newmem == NULL) {
01023         x_oom ();
01024         return 0;
01025     }
01026 
01027     l->list = newmem;
01028     l->allocated = newsize;
01029 
01030     return 1;
01031 }
01032 
01033 static int
01034 _xmmsv_list_insert (xmmsv_list_t *l, int pos, xmmsv_t *val)
01035 {
01036     xmmsv_list_iter_t *it;
01037     x_list_t *n;
01038 
01039     if (!absolutify_and_validate_pos (&pos, l->size, 1)) {
01040         return 0;
01041     }
01042 
01043     if (l->restricted) {
01044         x_return_val_if_fail (xmmsv_is_type (val, l->restricttype), 0);
01045     }
01046 
01047     /* We need more memory, reallocate */
01048     if (l->size == l->allocated) {
01049         int success;
01050         size_t double_size;
01051         if (l->allocated > 0) {
01052             double_size = l->allocated << 1;
01053         } else {
01054             double_size = 1;
01055         }
01056         success = xmmsv_list_resize (l, double_size);
01057         x_return_val_if_fail (success, 0);
01058     }
01059 
01060     /* move existing items out of the way */
01061     if (l->size > pos) {
01062         memmove (l->list + pos + 1, l->list + pos,
01063                  (l->size - pos) * sizeof (xmmsv_t *));
01064     }
01065 
01066     l->list[pos] = xmmsv_ref (val);
01067     l->size++;
01068 
01069     /* update iterators pos */
01070     for (n = l->iterators; n; n = n->next) {
01071         it = (xmmsv_list_iter_t *) n->data;
01072         if (it->position > pos) {
01073             it->position++;
01074         }
01075     }
01076 
01077     return 1;
01078 }
01079 
01080 static int
01081 _xmmsv_list_append (xmmsv_list_t *l, xmmsv_t *val)
01082 {
01083     return _xmmsv_list_insert (l, l->size, val);
01084 }
01085 
01086 static int
01087 _xmmsv_list_remove (xmmsv_list_t *l, int pos)
01088 {
01089     xmmsv_list_iter_t *it;
01090     int half_size;
01091     x_list_t *n;
01092 
01093     /* prevent removing after the last element */
01094     if (!absolutify_and_validate_pos (&pos, l->size, 0)) {
01095         return 0;
01096     }
01097 
01098     xmmsv_unref (l->list[pos]);
01099 
01100     l->size--;
01101 
01102     /* fill the gap */
01103     if (pos < l->size) {
01104         memmove (l->list + pos, l->list + pos + 1,
01105                  (l->size - pos) * sizeof (xmmsv_t *));
01106     }
01107 
01108     /* Reduce memory usage by two if possible */
01109     half_size = l->allocated >> 1;
01110     if (l->size <= half_size) {
01111         int success;
01112         success = xmmsv_list_resize (l, half_size);
01113         x_return_val_if_fail (success, 0);
01114     }
01115 
01116     /* update iterator pos */
01117     for (n = l->iterators; n; n = n->next) {
01118         it = (xmmsv_list_iter_t *) n->data;
01119         if (it->position > pos) {
01120             it->position--;
01121         }
01122     }
01123 
01124     return 1;
01125 }
01126 
01127 static int
01128 _xmmsv_list_move (xmmsv_list_t *l, int old_pos, int new_pos)
01129 {
01130     xmmsv_t *v;
01131     xmmsv_list_iter_t *it;
01132     x_list_t *n;
01133 
01134     if (!absolutify_and_validate_pos (&old_pos, l->size, 0)) {
01135         return 0;
01136     }
01137     if (!absolutify_and_validate_pos (&new_pos, l->size, 0)) {
01138         return 0;
01139     }
01140 
01141     v = l->list[old_pos];
01142     if (old_pos < new_pos) {
01143         memmove (l->list + old_pos, l->list + old_pos + 1,
01144                  (new_pos - old_pos) * sizeof (xmmsv_t *));
01145         l->list[new_pos] = v;
01146 
01147         /* update iterator pos */
01148         for (n = l->iterators; n; n = n->next) {
01149             it = (xmmsv_list_iter_t *) n->data;
01150             if (it->position >= old_pos && it->position <= new_pos) {
01151                 if (it->position == old_pos) {
01152                     it->position = new_pos;
01153                 } else {
01154                     it->position--;
01155                 }
01156             }
01157         }
01158     } else {
01159         memmove (l->list + new_pos + 1, l->list + new_pos,
01160                  (old_pos - new_pos) * sizeof (xmmsv_t *));
01161         l->list[new_pos] = v;
01162 
01163         /* update iterator pos */
01164         for (n = l->iterators; n; n = n->next) {
01165             it = (xmmsv_list_iter_t *) n->data;
01166             if (it->position >= new_pos && it->position <= old_pos) {
01167                 if (it->position == old_pos) {
01168                     it->position = new_pos;
01169                 } else {
01170                     it->position++;
01171                 }
01172             }
01173         }
01174     }
01175 
01176     return 1;
01177 }
01178 
01179 static void
01180 _xmmsv_list_clear (xmmsv_list_t *l)
01181 {
01182     xmmsv_list_iter_t *it;
01183     x_list_t *n;
01184     int i;
01185 
01186     /* unref all stored values */
01187     for (i = 0; i < l->size; i++) {
01188         xmmsv_unref (l->list[i]);
01189     }
01190 
01191     /* free list, declare empty */
01192     free (l->list);
01193     l->list = NULL;
01194 
01195     l->size = 0;
01196     l->allocated = 0;
01197 
01198     /* reset iterator pos */
01199     for (n = l->iterators; n; n = n->next) {
01200         it = (xmmsv_list_iter_t *) n->data;
01201         it->position = 0;
01202     }
01203 }
01204 
01205 /**
01206  * Get the element at the given position in the list #xmmsv_t. This
01207  * function does not increase the refcount of the element, the
01208  * reference is still owned by the list.
01209  *
01210  * @param listv A #xmmsv_t containing a list.
01211  * @param pos The position in the list. If negative, start counting
01212  *            from the end (-1 is the last element, etc).
01213  * @param val Pointer set to a borrowed reference to the element at
01214  *            the given position in the list.
01215  * @return 1 upon success otherwise 0
01216  */
01217 int
01218 xmmsv_list_get (xmmsv_t *listv, int pos, xmmsv_t **val)
01219 {
01220     xmmsv_list_t *l;
01221 
01222     x_return_val_if_fail (listv, 0);
01223     x_return_val_if_fail (xmmsv_is_type (listv, XMMSV_TYPE_LIST), 0);
01224 
01225     l = listv->value.list;
01226 
01227     /* prevent accessing after the last element */
01228     if (!absolutify_and_validate_pos (&pos, l->size, 0)) {
01229         return 0;
01230     }
01231 
01232     if (val) {
01233         *val = l->list[pos];
01234     }
01235 
01236     return 1;
01237 }
01238 
01239 /**
01240  * Set the element at the given position in the list #xmmsv_t.
01241  *
01242  * @param listv A #xmmsv_t containing a list.
01243  * @param pos The position in the list. If negative, start counting
01244  *            from the end (-1 is the last element, etc).
01245  * @param val The element to put at the given position in the list.
01246  * @return 1 upon success otherwise 0
01247  */
01248 int
01249 xmmsv_list_set (xmmsv_t *listv, int pos, xmmsv_t *val)
01250 {
01251     xmmsv_t *old_val;
01252     xmmsv_list_t *l;
01253 
01254     x_return_val_if_fail (listv, 0);
01255     x_return_val_if_fail (val, 0);
01256     x_return_val_if_fail (xmmsv_is_type (listv, XMMSV_TYPE_LIST), 0);
01257 
01258     l = listv->value.list;
01259 
01260     if (!absolutify_and_validate_pos (&pos, l->size, 0)) {
01261         return 0;
01262     }
01263 
01264     old_val = l->list[pos];
01265     l->list[pos] = xmmsv_ref (val);
01266     xmmsv_unref (old_val);
01267 
01268     return 1;
01269 }
01270 
01271 /**
01272  * Insert an element at the given position in the list #xmmsv_t.
01273  * The list will hold a reference to the element until it's removed.
01274  *
01275  * @param listv A #xmmsv_t containing a list.
01276  * @param pos The position in the list. If negative, start counting
01277  *            from the end (-1 is the last element, etc).
01278  * @param val The element to insert.
01279  * @return 1 upon success otherwise 0
01280  */
01281 int
01282 xmmsv_list_insert (xmmsv_t *listv, int pos, xmmsv_t *val)
01283 {
01284     x_return_val_if_fail (listv, 0);
01285     x_return_val_if_fail (xmmsv_is_type (listv, XMMSV_TYPE_LIST), 0);
01286     x_return_val_if_fail (val, 0);
01287 
01288     return _xmmsv_list_insert (listv->value.list, pos, val);
01289 }
01290 
01291 /**
01292  * Remove the element at the given position from the list #xmmsv_t.
01293  *
01294  * @param listv A #xmmsv_t containing a list.
01295  * @param pos The position in the list. If negative, start counting
01296  *            from the end (-1 is the last element, etc).
01297  * @return 1 upon success otherwise 0
01298  */
01299 int
01300 xmmsv_list_remove (xmmsv_t *listv, int pos)
01301 {
01302     x_return_val_if_fail (listv, 0);
01303     x_return_val_if_fail (xmmsv_is_type (listv, XMMSV_TYPE_LIST), 0);
01304 
01305     return _xmmsv_list_remove (listv->value.list, pos);
01306 }
01307 
01308 /**
01309  * Move the element from position #old to position #new.
01310  *
01311  * #xmmsv_list_iter_t's remain pointing at their element (which might or might
01312  * not be at a different position).
01313  *
01314  * @param listv A #xmmsv_t containing a list
01315  * @param old The original position in the list. If negative, start counting
01316  *            from the end (-1 is the last element, etc.)
01317  * @param new The new position in the list. If negative start counting from the
01318  *            end (-1 is the last element, etc.) For the sake of counting the
01319  *            element to be moved is still at its old position.
01320  * @return 1 upon success otherwise 0
01321  */
01322 int
01323 xmmsv_list_move (xmmsv_t *listv, int old_pos, int new_pos)
01324 {
01325     x_return_val_if_fail (listv, 0);
01326     x_return_val_if_fail (xmmsv_is_type (listv, XMMSV_TYPE_LIST), 0);
01327 
01328     return _xmmsv_list_move (listv->value.list, old_pos, new_pos);
01329 }
01330 
01331 /**
01332  * Append an element to the end of the list #xmmsv_t.
01333  * The list will hold a reference to the element until it's removed.
01334  *
01335  * @param listv A #xmmsv_t containing a list.
01336  * @param val The element to append.
01337  * @return 1 upon success otherwise 0
01338  */
01339 int
01340 xmmsv_list_append (xmmsv_t *listv, xmmsv_t *val)
01341 {
01342     x_return_val_if_fail (listv, 0);
01343     x_return_val_if_fail (xmmsv_is_type (listv, XMMSV_TYPE_LIST), 0);
01344     x_return_val_if_fail (val, 0);
01345 
01346     return _xmmsv_list_append (listv->value.list, val);
01347 }
01348 
01349 /**
01350  * Empty the list from all its elements.
01351  *
01352  * @param listv A #xmmsv_t containing a list.
01353  * @return 1 upon success otherwise 0
01354  */
01355 int
01356 xmmsv_list_clear (xmmsv_t *listv)
01357 {
01358     x_return_val_if_fail (listv, 0);
01359     x_return_val_if_fail (xmmsv_is_type (listv, XMMSV_TYPE_LIST), 0);
01360 
01361     _xmmsv_list_clear (listv->value.list);
01362 
01363     return 1;
01364 }
01365 
01366 /**
01367  * Apply a function to each element in the list, in sequential order.
01368  *
01369  * @param listv A #xmmsv_t containing a list.
01370  * @param function The function to apply to each element.
01371  * @param user_data User data passed to the foreach function.
01372  * @return 1 upon success otherwise 0
01373  */
01374 int
01375 xmmsv_list_foreach (xmmsv_t *listv, xmmsv_list_foreach_func func,
01376                     void* user_data)
01377 {
01378     xmmsv_list_iter_t *it;
01379     xmmsv_t *v;
01380 
01381     x_return_val_if_fail (listv, 0);
01382     x_return_val_if_fail (xmmsv_is_type (listv, XMMSV_TYPE_LIST), 0);
01383     x_return_val_if_fail (xmmsv_get_list_iter (listv, &it), 0);
01384 
01385     while (xmmsv_list_iter_valid (it)) {
01386         xmmsv_list_iter_entry (it, &v);
01387         func (v, user_data);
01388         xmmsv_list_iter_next (it);
01389     }
01390 
01391     xmmsv_list_iter_free (it);
01392 
01393     return 1;
01394 }
01395 
01396 /**
01397  * Return the size of the list.
01398  *
01399  * @param listv The #xmmsv_t containing the list.
01400  * @return The size of the list, or -1 if listv is invalid.
01401  */
01402 int
01403 xmmsv_list_get_size (xmmsv_t *listv)
01404 {
01405     x_return_val_if_fail (listv, -1);
01406     x_return_val_if_fail (xmmsv_is_type (listv, XMMSV_TYPE_LIST), -1);
01407 
01408     return listv->value.list->size;
01409 }
01410 
01411 
01412 int
01413 xmmsv_list_restrict_type (xmmsv_t *listv, xmmsv_type_t type)
01414 {
01415     xmmsv_list_iter_t *it;
01416     xmmsv_t *v;
01417 
01418     x_return_val_if_fail (listv, 0);
01419     x_return_val_if_fail (xmmsv_is_type (listv, XMMSV_TYPE_LIST), 0);
01420 
01421     x_return_val_if_fail (!listv->value.list->restricted, 0);
01422 
01423     x_return_val_if_fail (xmmsv_get_list_iter (listv, &it), 0);
01424     while (xmmsv_list_iter_valid (it)) {
01425         xmmsv_list_iter_entry (it, &v);
01426         x_return_val_if_fail (xmmsv_is_type (v, type), 0);
01427         xmmsv_list_iter_next (it);
01428     }
01429 
01430     xmmsv_list_iter_free (it);
01431 
01432     listv->value.list->restricted = true;
01433     listv->value.list->restricttype = type;
01434 
01435     return 1;
01436 }
01437 
01438 
01439 static xmmsv_list_iter_t *
01440 xmmsv_list_iter_new (xmmsv_list_t *l)
01441 {
01442     xmmsv_list_iter_t *it;
01443 
01444     it = x_new0 (xmmsv_list_iter_t, 1);
01445     if (!it) {
01446         x_oom ();
01447         return NULL;
01448     }
01449 
01450     it->parent = l;
01451     it->position = 0;
01452 
01453     /* register iterator into parent */
01454     l->iterators = x_list_prepend (l->iterators, it);
01455 
01456     return it;
01457 }
01458 
01459 static void
01460 xmmsv_list_iter_free (xmmsv_list_iter_t *it)
01461 {
01462     /* unref iterator from list and free it */
01463     it->parent->iterators = x_list_remove (it->parent->iterators, it);
01464     free (it);
01465 }
01466 
01467 /**
01468  * Explicitly free list iterator.
01469  *
01470  * Immediately frees any resources used by this iterator. The iterator
01471  * is freed automatically when the list is freed, but this function is
01472  * useful when the list can be long lived.
01473  *
01474  * @param it iterator to free
01475  *
01476  */
01477 void
01478 xmmsv_list_iter_explicit_destroy (xmmsv_list_iter_t *it)
01479 {
01480     xmmsv_list_iter_free (it);
01481 }
01482 
01483 /**
01484  * Get the element currently pointed at by the iterator. This function
01485  * does not increase the refcount of the element, the reference is
01486  * still owned by the list. If iterator does not point on a valid
01487  * element xmmsv_list_iter_entry returns 0 and leaves val untouched.
01488  *
01489  * @param it A #xmmsv_list_iter_t.
01490  * @param val Pointer set to a borrowed reference to the element
01491  *            pointed at by the iterator.
01492  * @return 1 upon success otherwise 0
01493  */
01494 int
01495 xmmsv_list_iter_entry (xmmsv_list_iter_t *it, xmmsv_t **val)
01496 {
01497     if (!xmmsv_list_iter_valid (it))
01498         return 0;
01499 
01500     *val = it->parent->list[it->position];
01501 
01502     return 1;
01503 }
01504 
01505 /**
01506  * Check whether the iterator is valid and points to a valid element.
01507  *
01508  * @param it A #xmmsv_list_iter_t.
01509  * @return 1 if the iterator is valid, 0 otherwise
01510  */
01511 int
01512 xmmsv_list_iter_valid (xmmsv_list_iter_t *it)
01513 {
01514     return it && (it->position < it->parent->size) && (it->position >= 0);
01515 }
01516 
01517 /**
01518  * Rewind the iterator to the start of the list.
01519  *
01520  * @param it A #xmmsv_list_iter_t.
01521  */
01522 void
01523 xmmsv_list_iter_first (xmmsv_list_iter_t *it)
01524 {
01525     x_return_if_fail (it);
01526 
01527     it->position = 0;
01528 }
01529 
01530 /**
01531  * Move the iterator to end of the list.
01532  *
01533  * @param listv A #xmmsv_list_iter_t.
01534  */
01535 void
01536 xmmsv_list_iter_last (xmmsv_list_iter_t *it)
01537 {
01538     x_return_if_fail (it);
01539 
01540     if (it->parent->size > 0) {
01541         it->position = it->parent->size - 1;
01542     } else {
01543         it->position = it->parent->size;
01544     }
01545 }
01546 
01547 /**
01548  * Advance the iterator to the next element in the list.
01549  *
01550  * @param it A #xmmsv_list_iter_t.
01551  */
01552 void
01553 xmmsv_list_iter_next (xmmsv_list_iter_t *it)
01554 {
01555     x_return_if_fail (it);
01556 
01557     if (it->position < it->parent->size) {
01558         it->position++;
01559     }
01560 }
01561 
01562 /**
01563  * Move the iterator to the previous element in the list.
01564  *
01565  * @param listv A #xmmsv_list_iter_t.
01566  */
01567 void
01568 xmmsv_list_iter_prev (xmmsv_list_iter_t *it)
01569 {
01570     x_return_if_fail (it);
01571 
01572     if (it->position >= 0) {
01573         it->position--;
01574     }
01575 }
01576 
01577 
01578 /**
01579  * Move the iterator to the n-th element in the list.
01580  *
01581  * @param it A #xmmsv_list_iter_t.
01582  * @param pos The position in the list. If negative, start counting
01583  *            from the end (-1 is the last element, etc).
01584  * @return 1 upon success otherwise 0
01585  */
01586 int
01587 xmmsv_list_iter_seek (xmmsv_list_iter_t *it, int pos)
01588 {
01589     x_return_val_if_fail (it, 0);
01590 
01591     if (!absolutify_and_validate_pos (&pos, it->parent->size, 1)) {
01592         return 0;
01593     }
01594     it->position = pos;
01595 
01596     return 1;
01597 }
01598 
01599 /**
01600  * Tell the position of the iterator.
01601  *
01602  * @param it A #xmmsv_list_iter_t.
01603  * @return The position of the iterator, or -1 if invalid.
01604  */
01605 int
01606 xmmsv_list_iter_tell (const xmmsv_list_iter_t *it)
01607 {
01608     x_return_val_if_fail (it, -1);
01609 
01610     return it->position;
01611 }
01612 
01613 /**
01614  * Return the parent #xmmsv_t of an iterator.
01615  *
01616  * @param it A #xmmsv_list_iter_t.
01617  * @return The parent #xmmsv_t of the iterator, or NULL if invalid.
01618  */
01619 xmmsv_t*
01620 xmmsv_list_iter_get_parent (const xmmsv_list_iter_t *it)
01621 {
01622     x_return_val_if_fail (it, NULL);
01623 
01624     return it->parent->parent_value;
01625 }
01626 
01627 /**
01628  * Insert an element in the list at the position pointed at by the
01629  * iterator.
01630  *
01631  * @param it A #xmmsv_list_iter_t.
01632  * @param val The element to insert.
01633  * @return 1 upon success otherwise 0
01634  */
01635 int
01636 xmmsv_list_iter_insert (xmmsv_list_iter_t *it, xmmsv_t *val)
01637 {
01638     x_return_val_if_fail (it, 0);
01639     x_return_val_if_fail (val, 0);
01640 
01641     return _xmmsv_list_insert (it->parent, it->position, val);
01642 }
01643 
01644 /**
01645  * Remove the element in the list at the position pointed at by the
01646  * iterator.
01647  *
01648  * @param it A #xmmsv_list_iter_t.
01649  * @return 1 upon success otherwise 0
01650  */
01651 int
01652 xmmsv_list_iter_remove (xmmsv_list_iter_t *it)
01653 {
01654     x_return_val_if_fail (it, 0);
01655 
01656     return _xmmsv_list_remove (it->parent, it->position);
01657 }
01658 
01659 /* Dict stuff */
01660 
01661 struct xmmsv_dict_St {
01662     /* dict implemented as a flat [key1, val1, key2, val2, ...] list */
01663     xmmsv_list_t *flatlist;
01664     x_list_t *iterators;
01665 };
01666 
01667 struct xmmsv_dict_iter_St {
01668     /* iterator of the contained flatlist */
01669     xmmsv_list_iter_t *lit;
01670     xmmsv_dict_t *parent;
01671 };
01672 
01673 static xmmsv_dict_t *
01674 xmmsv_dict_new (void)
01675 {
01676     xmmsv_dict_t *dict;
01677 
01678     dict = x_new0 (xmmsv_dict_t, 1);
01679     if (!dict) {
01680         x_oom ();
01681         return NULL;
01682     }
01683 
01684     dict->flatlist = xmmsv_list_new ();
01685 
01686     return dict;
01687 }
01688 
01689 static void
01690 xmmsv_dict_free (xmmsv_dict_t *dict)
01691 {
01692     xmmsv_dict_iter_t *it;
01693 
01694     /* free iterators */
01695     while (dict->iterators) {
01696         it = (xmmsv_dict_iter_t *) dict->iterators->data;
01697         xmmsv_dict_iter_free (it);
01698     }
01699 
01700     xmmsv_list_free (dict->flatlist);
01701 
01702     free (dict);
01703 }
01704 
01705 /**
01706  * Get the element corresponding to the given key in the dict #xmmsv_t
01707  * (if it exists).  This function does not increase the refcount of
01708  * the element, the reference is still owned by the dict.
01709  *
01710  * @param dictv A #xmmsv_t containing a dict.
01711  * @param key The key in the dict.
01712  * @param val Pointer set to a borrowed reference to the element
01713  *            corresponding to the given key in the dict.
01714  * @return 1 upon success otherwise 0
01715  */
01716 int
01717 xmmsv_dict_get (xmmsv_t *dictv, const char *key, xmmsv_t **val)
01718 {
01719     xmmsv_dict_iter_t *it;
01720     int ret = 1;
01721 
01722     x_return_val_if_fail (key, 0);
01723     x_return_val_if_fail (dictv, 0);
01724     x_return_val_if_fail (xmmsv_is_type (dictv, XMMSV_TYPE_DICT), 0);
01725     x_return_val_if_fail (xmmsv_get_dict_iter (dictv, &it), 0);
01726 
01727     if (!xmmsv_dict_iter_find (it, key)) {
01728         ret = 0;
01729     }
01730 
01731     /* If found, return value and success */
01732     if (ret && val) {
01733         xmmsv_dict_iter_pair (it, NULL, val);
01734     }
01735 
01736     xmmsv_dict_iter_free (it);
01737 
01738     return ret;
01739 }
01740 
01741 /**
01742  * Insert an element under the given key in the dict #xmmsv_t. If the
01743  * key already referenced an element, that element is unref'd and
01744  * replaced by the new one.
01745  *
01746  * @param dictv A #xmmsv_t containing a dict.
01747  * @param key The key in the dict.
01748  * @param val The new element to insert in the dict.
01749  * @return 1 upon success otherwise 0
01750  */
01751 int
01752 xmmsv_dict_set (xmmsv_t *dictv, const char *key, xmmsv_t *val)
01753 {
01754     xmmsv_dict_iter_t *it;
01755     int ret;
01756 
01757     x_return_val_if_fail (key, 0);
01758     x_return_val_if_fail (val, 0);
01759     x_return_val_if_fail (dictv, 0);
01760     x_return_val_if_fail (xmmsv_is_type (dictv, XMMSV_TYPE_DICT), 0);
01761     x_return_val_if_fail (xmmsv_get_dict_iter (dictv, &it), 0);
01762 
01763     /* if key already present, replace value */
01764     if (xmmsv_dict_iter_find (it, key)) {
01765         ret = xmmsv_dict_iter_set (it, val);
01766 
01767     /* else, insert a new key-value pair */
01768     } else {
01769         xmmsv_t *keyval;
01770 
01771         keyval = xmmsv_new_string (key);
01772 
01773         ret = xmmsv_list_iter_insert (it->lit, keyval);
01774         if (ret) {
01775             xmmsv_list_iter_next (it->lit);
01776             ret = xmmsv_list_iter_insert (it->lit, val);
01777             if (!ret) {
01778                 /* we added the key, but we couldn't add the value.
01779                  * we remove the key again to put the dictionary back
01780                  * in a consistent state.
01781                  */
01782                 it->lit->position--;
01783                 xmmsv_list_iter_remove (it->lit);
01784             }
01785         }
01786         xmmsv_unref (keyval);
01787     }
01788 
01789     xmmsv_dict_iter_free (it);
01790 
01791     return ret;
01792 }
01793 
01794 /**
01795  * Remove the element corresponding to a given key in the dict
01796  * #xmmsv_t (if it exists).
01797  *
01798  * @param dictv A #xmmsv_t containing a dict.
01799  * @param key The key in the dict.
01800  * @return 1 upon success otherwise 0
01801  */
01802 int
01803 xmmsv_dict_remove (xmmsv_t *dictv, const char *key)
01804 {
01805     xmmsv_dict_iter_t *it;
01806     int ret = 1;
01807 
01808     x_return_val_if_fail (key, 0);
01809     x_return_val_if_fail (dictv, 0);
01810     x_return_val_if_fail (xmmsv_is_type (dictv, XMMSV_TYPE_DICT), 0);
01811     x_return_val_if_fail (xmmsv_get_dict_iter (dictv, &it), 0);
01812 
01813     if (!xmmsv_dict_iter_find (it, key)) {
01814         ret = 0;
01815     } else {
01816         ret = xmmsv_list_iter_remove (it->lit) &&
01817               xmmsv_list_iter_remove (it->lit);
01818         /* FIXME: cleanup if only the first fails */
01819     }
01820 
01821     xmmsv_dict_iter_free (it);
01822 
01823     return ret;
01824 }
01825 
01826 /**
01827  * Empty the dict of all its elements.
01828  *
01829  * @param dictv A #xmmsv_t containing a dict.
01830  * @return 1 upon success otherwise 0
01831  */
01832 int
01833 xmmsv_dict_clear (xmmsv_t *dictv)
01834 {
01835     x_return_val_if_fail (dictv, 0);
01836     x_return_val_if_fail (xmmsv_is_type (dictv, XMMSV_TYPE_DICT), 0);
01837 
01838     _xmmsv_list_clear (dictv->value.dict->flatlist);
01839 
01840     return 1;
01841 }
01842 
01843 /**
01844  * Apply a function to each key-element pair in the list. No
01845  * particular order is assumed.
01846  *
01847  * @param dictv A #xmmsv_t containing a dict.
01848  * @param function The function to apply to each key-element pair.
01849  * @param user_data User data passed to the foreach function.
01850  * @return 1 upon success otherwise 0
01851  */
01852 int
01853 xmmsv_dict_foreach (xmmsv_t *dictv, xmmsv_dict_foreach_func func,
01854                     void *user_data)
01855 {
01856     xmmsv_dict_iter_t *it;
01857     const char *key;
01858     xmmsv_t *v;
01859 
01860     x_return_val_if_fail (dictv, 0);
01861     x_return_val_if_fail (xmmsv_is_type (dictv, XMMSV_TYPE_DICT), 0);
01862     x_return_val_if_fail (xmmsv_get_dict_iter (dictv, &it), 0);
01863 
01864     while (xmmsv_dict_iter_valid (it)) {
01865         xmmsv_dict_iter_pair (it, &key, &v);
01866         func (key, v, user_data);
01867         xmmsv_dict_iter_next (it);
01868     }
01869 
01870     xmmsv_dict_iter_free (it);
01871 
01872     return 1;
01873 }
01874 
01875 /**
01876  * Return the size of the dict.
01877  *
01878  * @param dictv The #xmmsv_t containing the dict.
01879  * @return The size of the dict, or -1 if dict is invalid.
01880  */
01881 int
01882 xmmsv_dict_get_size (xmmsv_t *dictv)
01883 {
01884     x_return_val_if_fail (dictv, -1);
01885     x_return_val_if_fail (xmmsv_is_type (dictv, XMMSV_TYPE_DICT), -1);
01886 
01887     return dictv->value.dict->flatlist->size / 2;
01888 }
01889 
01890 static xmmsv_dict_iter_t *
01891 xmmsv_dict_iter_new (xmmsv_dict_t *d)
01892 {
01893     xmmsv_dict_iter_t *it;
01894 
01895     it = x_new0 (xmmsv_dict_iter_t, 1);
01896     if (!it) {
01897         x_oom ();
01898         return NULL;
01899     }
01900 
01901     it->lit = xmmsv_list_iter_new (d->flatlist);
01902     it->parent = d;
01903 
01904     /* register iterator into parent */
01905     d->iterators = x_list_prepend (d->iterators, it);
01906 
01907     return it;
01908 }
01909 
01910 static void
01911 xmmsv_dict_iter_free (xmmsv_dict_iter_t *it)
01912 {
01913     /* we don't free the parent list iter, already managed by the flatlist */
01914 
01915     /* unref iterator from dict and free it */
01916     it->parent->iterators = x_list_remove (it->parent->iterators, it);
01917     free (it);
01918 }
01919 
01920 /**
01921  * Explicitly free dict iterator.
01922  *
01923  * Immediately frees any resources used by this iterator. The iterator
01924  * is freed automatically when the dict is freed, but this function is
01925  * useful when the dict can be long lived.
01926  *
01927  * @param it iterator to free
01928  *
01929  */
01930 void
01931 xmmsv_dict_iter_explicit_destroy (xmmsv_dict_iter_t *it)
01932 {
01933     xmmsv_dict_iter_free (it);
01934 }
01935 
01936 /**
01937  * Get the key-element pair currently pointed at by the iterator. This
01938  * function does not increase the refcount of the element, the
01939  * reference is still owned by the dict.
01940  *
01941  * @param it A #xmmsv_dict_iter_t.
01942  * @param key Pointer set to the key pointed at by the iterator.
01943  * @param val Pointer set to a borrowed reference to the element
01944  *            pointed at by the iterator.
01945  * @return 1 upon success otherwise 0
01946  */
01947 int
01948 xmmsv_dict_iter_pair (xmmsv_dict_iter_t *it, const char **key,
01949                       xmmsv_t **val)
01950 {
01951     unsigned int orig;
01952     xmmsv_t *v;
01953 
01954     if (!xmmsv_dict_iter_valid (it)) {
01955         return 0;
01956     }
01957 
01958     /* FIXME: avoid leaking abstraction! */
01959     orig = it->lit->position;
01960 
01961     if (key) {
01962         xmmsv_list_iter_entry (it->lit, &v);
01963         xmmsv_get_string (v, key);
01964     }
01965 
01966     if (val) {
01967         xmmsv_list_iter_next (it->lit);
01968         xmmsv_list_iter_entry (it->lit, val);
01969     }
01970 
01971     it->lit->position = orig;
01972 
01973     return 1;
01974 }
01975 
01976 /**
01977  * Check whether the iterator is valid and points to a valid pair.
01978  *
01979  * @param it A #xmmsv_dict_iter_t.
01980  * @return 1 if the iterator is valid, 0 otherwise
01981  */
01982 int
01983 xmmsv_dict_iter_valid (xmmsv_dict_iter_t *it)
01984 {
01985     return it && xmmsv_list_iter_valid (it->lit);
01986 }
01987 
01988 /**
01989  * Rewind the iterator to the start of the dict.
01990  *
01991  * @param it A #xmmsv_dict_iter_t.
01992  * @return 1 upon success otherwise 0
01993  */
01994 void
01995 xmmsv_dict_iter_first (xmmsv_dict_iter_t *it)
01996 {
01997     x_return_if_fail (it);
01998 
01999     xmmsv_list_iter_first (it->lit);
02000 }
02001 
02002 /**
02003  * Advance the iterator to the next pair in the dict.
02004  *
02005  * @param it A #xmmsv_dict_iter_t.
02006  * @return 1 upon success otherwise 0
02007  */
02008 void
02009 xmmsv_dict_iter_next (xmmsv_dict_iter_t *it)
02010 {
02011     x_return_if_fail (it);
02012 
02013     /* skip a pair */
02014     xmmsv_list_iter_next (it->lit);
02015     xmmsv_list_iter_next (it->lit);
02016 }
02017 
02018 /**
02019  * Move the iterator to the pair with the given key (if it exists)
02020  * or move it to the position where the key would have to be
02021  * put (if it doesn't exist yet).
02022  *
02023  * @param it A #xmmsv_dict_iter_t.
02024  * @param key The key to seek for.
02025  * @return 1 upon success otherwise 0
02026  */
02027 int
02028 xmmsv_dict_iter_find (xmmsv_dict_iter_t *it, const char *key)
02029 {
02030     xmmsv_t *val;
02031     const char *k;
02032     int s, dict_size, cmp, left, right;
02033 
02034     x_return_val_if_fail (it, 0);
02035     x_return_val_if_fail (key, 0);
02036 
02037     /* how many key-value pairs does this dictionary contain? */
02038     dict_size = it->parent->flatlist->size / 2;
02039 
02040     /* if it's empty, point the iterator at the beginning of
02041      * the list and report failure.
02042      */
02043     if (!dict_size) {
02044         xmmsv_list_iter_seek (it->lit, 0);
02045 
02046         return 0;
02047     }
02048 
02049     /* perform binary search for the given key */
02050     left = 0;
02051     right = dict_size - 1;
02052 
02053     while (left <= right) {
02054         int mid = left + ((right - left) / 2);
02055 
02056         /* jump to the middle of the current search area */
02057         xmmsv_list_iter_seek (it->lit, mid * 2);
02058         xmmsv_list_iter_entry (it->lit, &val);
02059 
02060         /* get the key at this slot */
02061         s = xmmsv_get_string (val, &k);
02062         x_return_val_if_fail (s, 0);
02063 
02064         /* and compare it to the given key */
02065         cmp = strcmp (k, key);
02066 
02067         /* hooray, we found the key. */
02068         if (cmp == 0)
02069             return 1;
02070 
02071         /* go on searching the left or the right hand side. */
02072         if (cmp < 0) {
02073             left = mid + 1;
02074         } else {
02075             right = mid - 1;
02076         }
02077     }
02078 
02079     /* if we get down here, we failed to find the key
02080      * in the dictionary.
02081      * now, move the iterator so that it points to the slot
02082      * where the key would be inserted.
02083      */
02084     if (cmp < 0) {
02085         xmmsv_list_iter_next (it->lit);
02086         xmmsv_list_iter_next (it->lit);
02087     }
02088 
02089     return 0;
02090 }
02091 
02092 /**
02093  * Replace the element of the pair currently pointed to by the
02094  * iterator.
02095  *
02096  * @param it A #xmmsv_dict_iter_t.
02097  * @param val The element to set in the pair.
02098  * @return 1 upon success otherwise 0
02099  */
02100 int
02101 xmmsv_dict_iter_set (xmmsv_dict_iter_t *it, xmmsv_t *val)
02102 {
02103     unsigned int orig;
02104     int ret;
02105 
02106     x_return_val_if_fail (xmmsv_dict_iter_valid (it), 0);
02107 
02108     /* FIXME: avoid leaking abstraction! */
02109     orig = it->lit->position;
02110 
02111     xmmsv_list_iter_next (it->lit);
02112     xmmsv_list_iter_remove (it->lit);
02113     ret = xmmsv_list_iter_insert (it->lit, val);
02114     /* FIXME: check remove success, swap operations? */
02115 
02116     it->lit->position = orig;
02117 
02118     return ret;
02119 }
02120 
02121 /**
02122  * Remove the pair in the dict pointed at by the iterator.
02123  *
02124  * @param it A #xmmsv_dict_iter_t.
02125  * @return 1 upon success otherwise 0
02126  */
02127 int
02128 xmmsv_dict_iter_remove (xmmsv_dict_iter_t *it)
02129 {
02130     int ret = 0;
02131 
02132     ret = xmmsv_list_iter_remove (it->lit) &&
02133           xmmsv_list_iter_remove (it->lit);
02134     /* FIXME: cleanup if only the first fails */
02135 
02136     return ret;
02137 }
02138 
02139 
02140 
02141 /**
02142  * Decode an URL-encoded string.
02143  *
02144  * Some strings (currently only the url of media) has no known
02145  * encoding, and must be encoded in an UTF-8 clean way. This is done
02146  * similar to the url encoding web browsers do. This functions decodes
02147  * a string encoded in that way. OBSERVE that the decoded string HAS
02148  * NO KNOWN ENCODING and you cannot display it on screen in a 100%
02149  * guaranteed correct way (a good heuristic is to try to validate the
02150  * decoded string as UTF-8, and if it validates assume that it is an
02151  * UTF-8 encoded string, and otherwise fall back to some other
02152  * encoding).
02153  *
02154  * Do not use this function if you don't understand the
02155  * implications. The best thing is not to try to display the url at
02156  * all.
02157  *
02158  * Note that the fact that the string has NO KNOWN ENCODING and CAN
02159  * NOT BE DISPLAYED does not stop you from open the file if it is a
02160  * local file (if it starts with "file://").
02161  *
02162  * @param url the #xmmsv_t containing a url-encoded string
02163  * @return a new #xmmsv_t containing the decoded string as a XMMSV_BIN or NULL on failure
02164  *
02165  */
02166 xmmsv_t *
02167 xmmsv_decode_url (const xmmsv_t *inv)
02168 {
02169     int i = 0, j = 0;
02170     const char *ins;
02171     unsigned char *url;
02172     xmmsv_t *ret;
02173 
02174     if (!xmmsv_get_string (inv, &ins)) {
02175         return NULL;
02176     }
02177 
02178     url = x_malloc (strlen (ins));
02179     if (!url) {
02180         x_oom ();
02181         return NULL;
02182     }
02183 
02184     while (ins[i]) {
02185         unsigned char chr = ins[i++];
02186 
02187         if (chr == '+') {
02188             chr = ' ';
02189         } else if (chr == '%') {
02190             char ts[3];
02191             char *t;
02192 
02193             ts[0] = ins[i++];
02194             if (!ts[0])
02195                 goto err;
02196             ts[1] = ins[i++];
02197             if (!ts[1])
02198                 goto err;
02199             ts[2] = '\0';
02200 
02201             chr = strtoul (ts, &t, 16);
02202 
02203             if (t != &ts[2])
02204                 goto err;
02205         }
02206 
02207         url[j++] = chr;
02208     }
02209 
02210     ret = xmmsv_new_bin (url, j);
02211     free (url);
02212 
02213     return ret;
02214 
02215 err:
02216     free (url);
02217     return NULL;
02218 }
02219 
02220 xmmsv_t *
02221 xmmsv_build_dict (const char *firstkey, ...)
02222 {
02223     va_list ap;
02224     const char *key;
02225     xmmsv_t *val, *res;
02226 
02227     res = xmmsv_new_dict ();
02228     if (!res)
02229         return NULL;
02230 
02231     va_start (ap, firstkey);
02232 
02233     key = firstkey;
02234     do {
02235         val = va_arg (ap, xmmsv_t *);
02236 
02237         if (!xmmsv_dict_set (res, key, val)) {
02238             xmmsv_unref (res);
02239             res = NULL;
02240             break;
02241         }
02242         xmmsv_unref (val);
02243         key = va_arg (ap, const char *);
02244     } while (key);
02245 
02246     va_end (ap);
02247 
02248     return res;
02249 }
02250 
02251 xmmsv_t *
02252 xmmsv_build_list_va (xmmsv_t *first_entry, va_list ap)
02253 {
02254     xmmsv_t *val, *res;
02255 
02256     res = xmmsv_new_list ();
02257     if (!res)
02258         return NULL;
02259 
02260     val = first_entry;
02261 
02262     while (val) {
02263         if (!xmmsv_list_append (res, val)) {
02264             xmmsv_unref (res);
02265             res = NULL;
02266             break;
02267         }
02268 
02269         xmmsv_unref (val);
02270 
02271         val = va_arg (ap, xmmsv_t *);
02272     }
02273 
02274     return res;
02275 }
02276 
02277 xmmsv_t *
02278 xmmsv_build_list (xmmsv_t *first_entry, ...)
02279 {
02280     va_list ap;
02281     xmmsv_t *res;
02282 
02283     va_start (ap, first_entry);
02284     res = xmmsv_build_list_va (first_entry, ap);
02285     va_end (ap);
02286 
02287     return res;
02288 }
02289 
02290 
02291 /**
02292  * This function will make a pretty string about the information in
02293  * xmmsv dict.
02294  *
02295  * @param target A allocated char *
02296  * @param len Length of target
02297  * @param fmt A format string to use. You can insert items from the dict by
02298  * using specialformat "${field}".
02299  * @param val The #xmmsv_t that contains the dict.
02300  *
02301  * @returns The number of chars written to target
02302  */
02303 int
02304 xmmsv_dict_format (char *target, int len, const char *fmt, xmmsv_t *val)
02305 {
02306     const char *pos;
02307 
02308     if (!target) {
02309         return 0;
02310     }
02311 
02312     if (!fmt) {
02313         return 0;
02314     }
02315 
02316     memset (target, 0, len);
02317 
02318     pos = fmt;
02319     while (strlen (target) + 1 < len) {
02320         char *next_key, *key, *end;
02321         int keylen;
02322         xmmsv_dict_iter_t *it;
02323         xmmsv_t *v;
02324 
02325         next_key = strstr (pos, "${");
02326         if (!next_key) {
02327             strncat (target, pos, len - strlen (target) - 1);
02328             break;
02329         }
02330 
02331         strncat (target, pos, MIN (next_key - pos, len - strlen (target) - 1));
02332         keylen = strcspn (next_key + 2, "}");
02333         key = malloc (keylen + 1);
02334 
02335         if (!key) {
02336             fprintf (stderr, "Unable to allocate %u bytes of memory, OOM?", keylen);
02337             break;
02338         }
02339 
02340         memset (key, 0, keylen + 1);
02341         strncpy (key, next_key + 2, keylen);
02342 
02343         xmmsv_get_dict_iter (val, &it);
02344 
02345         if (strcmp (key, "seconds") == 0) {
02346             int duration;
02347 
02348             if (xmmsv_dict_iter_find (it, "duration")) {
02349                 xmmsv_dict_iter_pair (it, NULL, &v);
02350                 xmmsv_get_int (v, &duration);
02351             } else {
02352                 duration = 0;
02353             }
02354 
02355             if (!duration) {
02356                 strncat (target, "00", len - strlen (target) - 1);
02357             } else {
02358                 char seconds[10];
02359                 /* rounding */
02360                 duration += 500;
02361                 snprintf (seconds, sizeof (seconds), "%02d", (duration/1000)%60);
02362                 strncat (target, seconds, len - strlen (target) - 1);
02363             }
02364         } else if (strcmp (key, "minutes") == 0) {
02365             int duration;
02366 
02367             if (xmmsv_dict_iter_find (it, "duration")) {
02368                 xmmsv_dict_iter_pair (it, NULL, &v);
02369                 xmmsv_get_int (v, &duration);
02370             } else {
02371                 duration = 0;
02372             }
02373 
02374             if (!duration) {
02375                 strncat (target, "00", len - strlen (target) - 1);
02376             } else {
02377                 char minutes[10];
02378                 /* rounding */
02379                 duration += 500;
02380                 snprintf (minutes, sizeof (minutes), "%02d", duration/60000);
02381                 strncat (target, minutes, len - strlen (target) - 1);
02382             }
02383         } else {
02384             const char *result = NULL;
02385             char tmp[12];
02386 
02387             if (xmmsv_dict_iter_find (it, key)) {
02388                 xmmsv_dict_iter_pair (it, NULL, &v);
02389 
02390                 xmmsv_type_t type = xmmsv_get_type (v);
02391                 if (type == XMMSV_TYPE_STRING) {
02392                     xmmsv_get_string (v, &result);
02393                 } else if (type == XMMSV_TYPE_UINT32) {
02394                     uint32_t ui;
02395                     xmmsv_get_uint (v, &ui);
02396                     snprintf (tmp, 12, "%u", ui);
02397                     result = tmp;
02398                 } else if (type == XMMSV_TYPE_INT32) {
02399                     int32_t i;
02400                     xmmsv_get_int (v, &i);
02401                     snprintf (tmp, 12, "%d", i);
02402                     result = tmp;
02403                 }
02404             }
02405 
02406             if (result)
02407                 strncat (target, result, len - strlen (target) - 1);
02408         }
02409 
02410         free (key);
02411         end = strchr (next_key, '}');
02412 
02413         if (!end) {
02414             break;
02415         }
02416 
02417         pos = end + 1;
02418     }
02419 
02420     return strlen (target);
02421 }
02422 
02423 static int
02424 _xmmsv_utf8_charlen (unsigned char c)
02425 {
02426     if ((c & 0x80) == 0) {
02427         return 1;
02428     } else if ((c & 0x60) == 0x40) {
02429         return 2;
02430     } else if ((c & 0x70) == 0x60) {
02431         return 3;
02432     } else if ((c & 0x78) == 0x70) {
02433         return 4;
02434     }
02435     return 0;
02436 }
02437 
02438 
02439 /**
02440  * Check if a string is valid UTF-8.
02441  *
02442  */
02443 int
02444 xmmsv_utf8_validate (const char *str)
02445 {
02446     int i = 0;
02447 
02448     for (;;) {
02449         unsigned char c = str[i++];
02450         int l;
02451         if (!c) {
02452             /* NUL - end of string */
02453             return 1;
02454         }
02455 
02456         l = _xmmsv_utf8_charlen (c);
02457         if (l == 0)
02458             return 0;
02459         while (l-- > 1) {
02460             if ((str[i++] & 0xC0) != 0x80)
02461                 return 0;
02462         }
02463     }
02464 }
02465 
02466 
02467 
02468 /**
02469  * @internal
02470  */
02471 static int
02472 absolutify_and_validate_pos (int *pos, int size, int allow_append)
02473 {
02474     x_return_val_if_fail (size >= 0, 0);
02475 
02476     if (*pos < 0) {
02477         if (-*pos > size)
02478             return 0;
02479         *pos = size + *pos;
02480     }
02481 
02482     if (*pos > size)
02483         return 0;
02484 
02485     if (!allow_append && *pos == size)
02486         return 0;
02487 
02488     return 1;
02489 }
02490 
02491 int
02492 xmmsv_dict_has_key (xmmsv_t *dictv, const char *key)
02493 {
02494     return xmmsv_dict_get (dictv, key, NULL);
02495 }
02496 
02497 
02498 xmmsv_t *
02499 xmmsv_bitbuffer_new_ro (const unsigned char *v, int len)
02500 {
02501     xmmsv_t *val;
02502 
02503     val = xmmsv_new (XMMSV_TYPE_BITBUFFER);
02504     val->value.bit.buf = (unsigned char *) v;
02505     val->value.bit.len = len * 8;
02506     val->value.bit.ro = true;
02507     return val;
02508 }
02509 
02510 xmmsv_t *
02511 xmmsv_bitbuffer_new (void)
02512 {
02513     xmmsv_t *val;
02514 
02515     val = xmmsv_new (XMMSV_TYPE_BITBUFFER);
02516     val->value.bit.buf = NULL;
02517     val->value.bit.len = 0;
02518     val->value.bit.ro = false;
02519     return val;
02520 }
02521 
02522 
02523 int
02524 xmmsv_bitbuffer_get_bits (xmmsv_t *v, int bits, int *res)
02525 {
02526     int i, t, r;
02527 
02528     x_api_error_if (bits < 1, "less than one bit requested", 0);
02529 
02530     if (bits == 1) {
02531         int pos = v->value.bit.pos;
02532 
02533         if (pos >= v->value.bit.len)
02534             return 0;
02535         r = (v->value.bit.buf[pos / 8] >> (7-(pos % 8)) & 1);
02536         v->value.bit.pos += 1;
02537         *res = r;
02538         return 1;
02539     }
02540 
02541     r = 0;
02542     for (i = 0; i < bits; i++) {
02543         t = 0;
02544         if (!xmmsv_bitbuffer_get_bits (v, 1, &t))
02545             return 0;
02546         r = (r << 1) | t;
02547     }
02548     *res = r;
02549     return 1;
02550 }
02551 
02552 int
02553 xmmsv_bitbuffer_get_data (xmmsv_t *v, unsigned char *b, int len)
02554 {
02555     while (len) {
02556         int t;
02557         if (!xmmsv_bitbuffer_get_bits (v, 8, &t))
02558             return 0;
02559         *b = t;
02560         b++;
02561         len--;
02562     }
02563     return 1;
02564 }
02565 
02566 int
02567 xmmsv_bitbuffer_put_bits (xmmsv_t *v, int bits, int d)
02568 {
02569     unsigned char t;
02570     int pos;
02571     int i;
02572 
02573     x_api_error_if (v->value.bit.ro, "write to readonly bitbuffer", 0);
02574     x_api_error_if (bits < 1, "less than one bit requested", 0);
02575 
02576     if (bits == 1) {
02577         pos = v->value.bit.pos;
02578 
02579         if (pos >= v->value.bit.alloclen) {
02580             int ol, nl;
02581             nl = v->value.bit.alloclen * 2;
02582             ol = v->value.bit.alloclen;
02583             nl = nl < 128 ? 128 : nl;
02584             nl = (nl + 7) & ~7;
02585             v->value.bit.buf = realloc (v->value.bit.buf, nl / 8);
02586             memset (v->value.bit.buf + ol / 8, 0, (nl - ol) / 8);
02587             v->value.bit.alloclen = nl;
02588         }
02589         t = v->value.bit.buf[pos / 8];
02590 
02591         t = (t & (~(1<<(7-(pos % 8))))) | (d << (7-(pos % 8)));
02592 
02593         v->value.bit.buf[pos / 8] = t;
02594 
02595         v->value.bit.pos += 1;
02596         if (v->value.bit.pos > v->value.bit.len)
02597             v->value.bit.len = v->value.bit.pos;
02598         return 1;
02599     }
02600 
02601     for (i = 0; i < bits; i++) {
02602         if (!xmmsv_bitbuffer_put_bits (v, 1, !!(d & (1 << (bits-i-1)))))
02603             return 0;
02604     }
02605 
02606     return 1;
02607 }
02608 
02609 int
02610 xmmsv_bitbuffer_put_bits_at (xmmsv_t *v, int bits, int d, int offset)
02611 {
02612     int prevpos;
02613     prevpos = xmmsv_bitbuffer_pos (v);
02614     if (!xmmsv_bitbuffer_goto (v, offset))
02615         return 0;
02616     if (!xmmsv_bitbuffer_put_bits (v, bits, d))
02617         return 0;
02618     return xmmsv_bitbuffer_goto (v, prevpos);
02619 }
02620 
02621 int
02622 xmmsv_bitbuffer_put_data (xmmsv_t *v, const unsigned char *b, int len)
02623 {
02624     while (len) {
02625         int t;
02626         t = *b;
02627         if (!xmmsv_bitbuffer_put_bits (v, 8, t))
02628             return 0;
02629         b++;
02630         len--;
02631     }
02632     return 1;
02633 }
02634 
02635 int
02636 xmmsv_bitbuffer_align (xmmsv_t *v)
02637 {
02638     v->value.bit.pos = (v->value.bit.pos + 7) % 8;
02639     return 1;
02640 }
02641 
02642 int
02643 xmmsv_bitbuffer_goto (xmmsv_t *v, int pos)
02644 {
02645     x_api_error_if (pos < 0, "negative position", 0);
02646     x_api_error_if (pos > v->value.bit.len, "position after buffer end", 0);
02647 
02648     v->value.bit.pos = pos;
02649     return 1;
02650 }
02651 
02652 int
02653 xmmsv_bitbuffer_pos (xmmsv_t *v)
02654 {
02655     return v->value.bit.pos;
02656 }
02657 
02658 int
02659 xmmsv_bitbuffer_rewind (xmmsv_t *v)
02660 {
02661     return xmmsv_bitbuffer_goto (v, 0);
02662 }
02663 
02664 int
02665 xmmsv_bitbuffer_end (xmmsv_t *v)
02666 {
02667     return xmmsv_bitbuffer_goto (v, v->value.bit.len);
02668 }
02669 
02670 int
02671 xmmsv_bitbuffer_len (xmmsv_t *v)
02672 {
02673     return v->value.bit.len;
02674 }
02675 
02676 const unsigned char *
02677 xmmsv_bitbuffer_buffer (xmmsv_t *v)
02678 {
02679     return v->value.bit.buf;
02680 }
02681 
02682 /*
02683  *
02684  *
02685  */
02686 
02687 /*
02688 xmmsv_t *
02689 xmmsv_serialize (xmmsv_t *val)
02690 {
02691     switch (xmmsv_get_type (val)) {
02692     case XMMSV_TYPE_NONE:
02693         break;
02694 
02695     }
02696 }
02697 */