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