XMMS2
|
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 */