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 <string.h> 00020 #include <ctype.h> 00021 00022 #include "xmmsc/xmmsc_idnumbers.h" 00023 #include "xmmsc/xmmsv.h" 00024 #include "xmmsc/xmmsv_coll.h" 00025 #include "xmmsc/xmmsc_util.h" 00026 #include "xmmspriv/xmms_list.h" 00027 00028 00029 struct xmmsv_coll_St { 00030 00031 /* refcounting */ 00032 int ref; 00033 00034 xmmsv_coll_type_t type; 00035 xmmsv_t *operands; 00036 xmmsv_t *attributes; 00037 00038 /* List of ids, 0-terminated. */ 00039 uint32_t *idlist; 00040 size_t idlist_size; 00041 size_t idlist_allocated; 00042 00043 }; 00044 00045 00046 static void xmmsv_coll_free (xmmsv_coll_t *coll); 00047 00048 static int xmmsv_coll_idlist_resize (xmmsv_coll_t *coll, size_t newsize); 00049 00050 00051 /** 00052 * @defgroup CollectionStructure CollectionStructure 00053 * @ingroup Collections 00054 * @brief The API to be used to work with collection structures. 00055 * 00056 * @{ 00057 */ 00058 00059 /** 00060 * Increases the references for the #xmmsv_coll_t 00061 * 00062 * @param coll the collection to reference. 00063 * @return coll 00064 */ 00065 xmmsv_coll_t * 00066 xmmsv_coll_ref (xmmsv_coll_t *coll) 00067 { 00068 x_return_val_if_fail (coll, NULL); 00069 00070 coll->ref++; 00071 00072 return coll; 00073 } 00074 00075 /** 00076 * Allocate a new collection of the given type. 00077 * The pointer will have to be deallocated using #xmmsv_coll_unref. 00078 * 00079 * @param type the #xmmsv_coll_type_t specifying the type of collection to create. 00080 * @return a pointer to the newly created collection, or NULL if the type is invalid. 00081 */ 00082 xmmsv_coll_t* 00083 xmmsv_coll_new (xmmsv_coll_type_t type) 00084 { 00085 xmmsv_coll_t *coll; 00086 00087 x_return_val_if_fail (type <= XMMS_COLLECTION_TYPE_LAST, NULL); 00088 00089 coll = x_new0 (xmmsv_coll_t, 1); 00090 if (!coll) { 00091 x_oom (); 00092 return NULL; 00093 } 00094 00095 if (!(coll->idlist = x_new0 (uint32_t, 1))) { 00096 x_oom (); 00097 free (coll); 00098 return NULL; 00099 } 00100 coll->idlist_size = 1; 00101 coll->idlist_allocated = 1; 00102 00103 coll->ref = 0; 00104 coll->type = type; 00105 00106 coll->operands = xmmsv_new_list (); 00107 xmmsv_list_restrict_type (coll->operands, XMMSV_TYPE_COLL); 00108 00109 coll->attributes = xmmsv_new_dict (); 00110 00111 /* user must give this back */ 00112 xmmsv_coll_ref (coll); 00113 00114 return coll; 00115 } 00116 00117 /** 00118 * Free the memory owned by the collection. 00119 * You probably want to use #xmmsv_coll_unref instead, which handles 00120 * reference counting. 00121 * 00122 * @param coll the collection to free. 00123 */ 00124 static void 00125 xmmsv_coll_free (xmmsv_coll_t *coll) 00126 { 00127 x_return_if_fail (coll); 00128 00129 /* Unref all the operands and attributes */ 00130 xmmsv_unref (coll->operands); 00131 00132 xmmsv_unref (coll->attributes); 00133 00134 free (coll->idlist); 00135 00136 free (coll); 00137 } 00138 00139 /** 00140 * Decreases the references for the #xmmsv_coll_t 00141 * When the number of references reaches 0 it will 00142 * be freed and all its operands unreferenced as well. 00143 * 00144 * @param coll the collection to unref. 00145 */ 00146 void 00147 xmmsv_coll_unref (xmmsv_coll_t *coll) 00148 { 00149 x_return_if_fail (coll); 00150 x_api_error_if (coll->ref < 1, "with a freed collection",); 00151 00152 coll->ref--; 00153 if (coll->ref == 0) { 00154 xmmsv_coll_free (coll); 00155 } 00156 } 00157 00158 00159 /** 00160 * Set the list of ids in the given collection. 00161 * The list must be 0-terminated. 00162 * Note that the idlist is only relevant for idlist collections. 00163 * 00164 * @param coll the collection to modify. 00165 * @param ids the 0-terminated list of ids to store in the collection. 00166 */ 00167 void 00168 xmmsv_coll_set_idlist (xmmsv_coll_t *coll, unsigned int ids[]) 00169 { 00170 unsigned int i; 00171 unsigned int size = 0; 00172 00173 x_return_if_fail (coll); 00174 00175 while (ids[size] != 0) { 00176 ++size; 00177 } 00178 ++size; 00179 00180 free (coll->idlist); 00181 if (!(coll->idlist = x_new0 (uint32_t, size))) { 00182 x_oom (); 00183 return; 00184 } 00185 00186 for (i = 0; i < size; ++i) { 00187 coll->idlist[i] = ids[i]; 00188 } 00189 00190 coll->idlist_size = size; 00191 coll->idlist_allocated = size; 00192 } 00193 00194 static int 00195 _xmmsv_coll_operand_find (xmmsv_list_iter_t *it, xmmsv_coll_t *op) 00196 { 00197 xmmsv_coll_t *c; 00198 xmmsv_t *v; 00199 00200 while (xmmsv_list_iter_valid (it)) { 00201 xmmsv_list_iter_entry (it, &v); 00202 if (xmmsv_get_coll (v, &c)) { 00203 if (c == op) { 00204 return 1; 00205 } 00206 } 00207 xmmsv_list_iter_next (it); 00208 } 00209 return 0; 00210 } 00211 00212 /** 00213 * Add the operand to the given collection. 00214 * @param coll The collection to add the operand to. 00215 * @param op The operand to add. 00216 */ 00217 void 00218 xmmsv_coll_add_operand (xmmsv_coll_t *coll, xmmsv_coll_t *op) 00219 { 00220 xmmsv_list_iter_t *it; 00221 xmmsv_t *v; 00222 x_return_if_fail (coll); 00223 x_return_if_fail (op); 00224 00225 /* we used to check if it already existed here before */ 00226 if (!xmmsv_get_list_iter (coll->operands, &it)) 00227 return; 00228 00229 if (_xmmsv_coll_operand_find (it, op)) { 00230 x_api_warning ("with an operand already in operand list"); 00231 xmmsv_list_iter_explicit_destroy (it); 00232 return; 00233 } 00234 00235 xmmsv_list_iter_explicit_destroy (it); 00236 00237 v = xmmsv_new_coll (op); 00238 x_return_if_fail (v); 00239 xmmsv_list_append (coll->operands, v); 00240 xmmsv_unref (v); 00241 } 00242 00243 /** 00244 * Remove all the occurences of the operand in the given collection. 00245 * @param coll The collection to remove the operand from. 00246 * @param op The operand to remove. 00247 */ 00248 void 00249 xmmsv_coll_remove_operand (xmmsv_coll_t *coll, xmmsv_coll_t *op) 00250 { 00251 xmmsv_list_iter_t *it; 00252 00253 x_return_if_fail (coll); 00254 x_return_if_fail (op); 00255 00256 if (!xmmsv_get_list_iter (coll->operands, &it)) 00257 return; 00258 00259 if (_xmmsv_coll_operand_find (it, op)) { 00260 xmmsv_list_iter_remove (it); 00261 } else { 00262 x_api_warning ("with an operand not in operand list"); 00263 } 00264 xmmsv_list_iter_explicit_destroy (it); 00265 } 00266 00267 00268 /** 00269 * Append a value to the idlist. 00270 * @param coll The collection to update. 00271 * @param id The id to append to the idlist. 00272 * @return TRUE on success, false otherwise. 00273 */ 00274 int 00275 xmmsv_coll_idlist_append (xmmsv_coll_t *coll, unsigned int id) 00276 { 00277 x_return_val_if_fail (coll, 0); 00278 00279 return xmmsv_coll_idlist_insert (coll, coll->idlist_size - 1, id); 00280 } 00281 00282 /** 00283 * Insert a value at a given position in the idlist. 00284 * @param coll The collection to update. 00285 * @param id The id to insert in the idlist. 00286 * @param index The position at which to insert the value. 00287 * @return TRUE on success, false otherwise. 00288 */ 00289 int 00290 xmmsv_coll_idlist_insert (xmmsv_coll_t *coll, unsigned int index, unsigned int id) 00291 { 00292 int i; 00293 x_return_val_if_fail (coll, 0); 00294 00295 if (index >= coll->idlist_size) { 00296 return 0; 00297 } 00298 00299 /* We need more memory, reallocate */ 00300 if (coll->idlist_size == coll->idlist_allocated) { 00301 int success; 00302 size_t double_size = coll->idlist_allocated * 2; 00303 success = xmmsv_coll_idlist_resize (coll, double_size); 00304 x_return_val_if_fail (success, 0); 00305 } 00306 00307 for (i = coll->idlist_size; i > index; i--) { 00308 coll->idlist[i] = coll->idlist[i - 1]; 00309 } 00310 00311 coll->idlist[index] = id; 00312 coll->idlist_size++; 00313 00314 return 1; 00315 } 00316 00317 /** 00318 * Move a value of the idlist to a new position. 00319 * @param coll The collection to update. 00320 * @param index The index of the value to move. 00321 * @param newindex The newindex to which to move the value. 00322 * @return TRUE on success, false otherwise. 00323 */ 00324 int 00325 xmmsv_coll_idlist_move (xmmsv_coll_t *coll, unsigned int index, unsigned int newindex) 00326 { 00327 int i; 00328 uint32_t tmp; 00329 00330 x_return_val_if_fail (coll, 0); 00331 00332 if ((index >= coll->idlist_size - 1) || (newindex >= coll->idlist_size - 1)) { 00333 return 0; 00334 } 00335 00336 tmp = coll->idlist[index]; 00337 if (index < newindex) { 00338 for (i = index; i < newindex; i++) { 00339 coll->idlist[i] = coll->idlist[i + 1]; 00340 } 00341 } 00342 else if (index > newindex) { 00343 for (i = index; i > newindex; i--) { 00344 coll->idlist[i] = coll->idlist[i - 1]; 00345 } 00346 } 00347 coll->idlist[newindex] = tmp; 00348 00349 return 1; 00350 } 00351 00352 /** 00353 * Remove the value at a given index from the idlist. 00354 * @param coll The collection to update. 00355 * @param index The index at which to remove the value. 00356 * @return TRUE on success, false otherwise. 00357 */ 00358 int 00359 xmmsv_coll_idlist_remove (xmmsv_coll_t *coll, unsigned int index) 00360 { 00361 int i; 00362 size_t half_size; 00363 00364 x_return_val_if_fail (coll, 0); 00365 00366 if (index >= coll->idlist_size - 1) { 00367 return 0; 00368 } 00369 00370 coll->idlist_size--; 00371 for (i = index; i < coll->idlist_size; i++) { 00372 coll->idlist[i] = coll->idlist[i + 1]; 00373 } 00374 00375 /* Reduce memory usage by two if possible */ 00376 half_size = coll->idlist_allocated / 2; 00377 if (coll->idlist_size <= half_size) { 00378 xmmsv_coll_idlist_resize (coll, half_size); 00379 } 00380 00381 return 1; 00382 } 00383 00384 /** 00385 * Empties the idlist. 00386 * @param coll The collection to update. 00387 * @return TRUE on success, false otherwise. 00388 */ 00389 int 00390 xmmsv_coll_idlist_clear (xmmsv_coll_t *coll) 00391 { 00392 unsigned int empty[] = { 0 }; 00393 00394 x_return_val_if_fail (coll, 0); 00395 00396 xmmsv_coll_set_idlist (coll, empty); 00397 00398 return 1; 00399 } 00400 00401 /** 00402 * Retrieves the value at the given position in the idlist. 00403 * @param coll The collection to update. 00404 * @param index The position of the value to retrieve. 00405 * @param val The pointer at which to store the found value. 00406 * @return TRUE on success, false otherwise. 00407 */ 00408 int 00409 xmmsv_coll_idlist_get_index (xmmsv_coll_t *coll, unsigned int index, uint32_t *val) 00410 { 00411 x_return_val_if_fail (coll, 0); 00412 00413 if (index >= (coll->idlist_size - 1)) { 00414 return 0; 00415 } 00416 00417 *val = coll->idlist[index]; 00418 00419 return 1; 00420 } 00421 00422 /** 00423 * Sets the value at the given position in the idlist. 00424 * @param coll The collection to update. 00425 * @param index The position of the value to set. 00426 * @param val The new value. 00427 * @return TRUE on success, false otherwise. 00428 */ 00429 int 00430 xmmsv_coll_idlist_set_index (xmmsv_coll_t *coll, unsigned int index, uint32_t val) 00431 { 00432 x_return_val_if_fail (coll, 0); 00433 00434 if (index >= (coll->idlist_size - 1)) { 00435 return 0; 00436 } 00437 00438 coll->idlist[index] = val; 00439 00440 return 1; 00441 } 00442 00443 /** 00444 * Get the size of the idlist. 00445 * @param coll The collection to update. 00446 * @return The size of the idlist. 00447 */ 00448 size_t 00449 xmmsv_coll_idlist_get_size (xmmsv_coll_t *coll) 00450 { 00451 x_return_val_if_fail (coll, 0); 00452 00453 return coll->idlist_size - 1; 00454 } 00455 00456 00457 00458 /** 00459 * Return the type of the collection. 00460 * @param coll The collection to consider. 00461 * @return The #xmmsv_coll_type_t of the collection, or -1 if invalid. 00462 */ 00463 xmmsv_coll_type_t 00464 xmmsv_coll_get_type (xmmsv_coll_t *coll) 00465 { 00466 x_return_val_if_fail (coll, -1); 00467 00468 return coll->type; 00469 } 00470 00471 /** 00472 * Return the list of ids stored in the collection. 00473 * The list is owned by the collection. 00474 * Note that this must not be confused with the content of the 00475 * collection, which must be queried using xmmsc_coll_query_ids! 00476 * 00477 * @param coll The collection to consider. 00478 * @return The 0-terminated list of ids. 00479 */ 00480 uint32_t* 00481 xmmsv_coll_get_idlist (xmmsv_coll_t *coll) 00482 { 00483 x_return_null_if_fail (coll); 00484 00485 return coll->idlist; 00486 } 00487 00488 xmmsv_t * 00489 xmmsv_coll_operands_get (xmmsv_coll_t *coll) 00490 { 00491 x_return_val_if_fail (coll, NULL); 00492 00493 return coll->operands; 00494 } 00495 00496 xmmsv_t * 00497 xmmsv_coll_attributes_get (xmmsv_coll_t *coll) 00498 { 00499 x_return_val_if_fail (coll, NULL); 00500 00501 return coll->attributes; 00502 } 00503 00504 /** 00505 * Set an attribute in the given collection. 00506 * 00507 * @param coll The collection in which to set the attribute. 00508 * @param key The name of the attribute to set. 00509 * @param value The value of the attribute. 00510 */ 00511 void 00512 xmmsv_coll_attribute_set (xmmsv_coll_t *coll, const char *key, const char *value) 00513 { 00514 xmmsv_t *v; 00515 00516 v = xmmsv_new_string (value); 00517 x_return_if_fail (v); 00518 00519 xmmsv_dict_set (coll->attributes, key, v); 00520 xmmsv_unref (v); 00521 } 00522 00523 /** 00524 * Remove an attribute from the given collection. 00525 * The return value indicated whether the attribute was found (and 00526 * removed) 00527 * 00528 * @param coll The collection to remove the attribute from. 00529 * @param key The name of the attribute to remove. 00530 * @return 1 upon success, 0 otherwise 00531 */ 00532 int 00533 xmmsv_coll_attribute_remove (xmmsv_coll_t *coll, const char *key) 00534 { 00535 return xmmsv_dict_remove (coll->attributes, key); 00536 } 00537 00538 /** 00539 * Retrieve the value of the attribute of the given collection. 00540 * The return value is 1 if the attribute was found and 0 otherwise. 00541 * The value of the attribute is owned by the collection and must not 00542 * be freed by the caller. 00543 * 00544 * @param coll The collection to retrieve the attribute from. 00545 * @param key The name of the attribute. 00546 * @param value The value of the attribute if found (owned by the collection). 00547 * @return 1 if the attribute was found, 0 otherwise 00548 */ 00549 int 00550 xmmsv_coll_attribute_get (xmmsv_coll_t *coll, const char *key, char **value) 00551 { 00552 if (xmmsv_dict_entry_get_string (coll->attributes, key, value)) { 00553 return 1; 00554 } 00555 *value = NULL; 00556 return 0; 00557 } 00558 00559 00560 00561 struct attr_fe_data { 00562 xmmsv_coll_attribute_foreach_func func; 00563 void *userdata; 00564 }; 00565 00566 static void 00567 attr_fe_func (const char *key, xmmsv_t *val, void *user_data) 00568 { 00569 struct attr_fe_data *d = user_data; 00570 const char *v; 00571 int r; 00572 00573 r = xmmsv_get_string (val, &v); 00574 x_return_if_fail (r) 00575 00576 d->func (key, v, d->userdata); 00577 } 00578 /** 00579 * Iterate over all key/value-pair of the collection attributes. 00580 * 00581 * Calls specified function for each key/value-pair of the attribute list. 00582 * 00583 * void function (const char *key, const char *value, void *user_data); 00584 * 00585 * @param coll the #xmmsv_coll_t. 00586 * @param func function that is called for each key/value-pair 00587 * @param user_data extra data passed to func 00588 */ 00589 void 00590 xmmsv_coll_attribute_foreach (xmmsv_coll_t *coll, 00591 xmmsv_coll_attribute_foreach_func func, 00592 void *user_data) 00593 { 00594 struct attr_fe_data d = {func, user_data}; 00595 xmmsv_dict_foreach (coll->attributes, attr_fe_func, &d); 00596 } 00597 00598 /** 00599 * Return a collection referencing the whole media library, 00600 * that is a reference to the "All Media" collection. 00601 * The returned structure must be unref'd using #xmmsv_coll_unref 00602 * after usage. 00603 * 00604 * @return a collection referring to the "All Media" collection. 00605 */ 00606 xmmsv_coll_t* 00607 xmmsv_coll_universe () 00608 { 00609 xmmsv_coll_t *univ = xmmsv_coll_new (XMMS_COLLECTION_TYPE_REFERENCE); 00610 xmmsv_coll_attribute_set (univ, "reference", "All Media"); 00611 /* FIXME: namespace? */ 00612 00613 return univ; 00614 } 00615 00616 /** @} */ 00617 00618 00619 00620 /** @internal */ 00621 00622 00623 static int 00624 xmmsv_coll_idlist_resize (xmmsv_coll_t *coll, size_t newsize) 00625 { 00626 uint32_t *newmem; 00627 00628 newmem = realloc (coll->idlist, newsize * sizeof (uint32_t)); 00629 00630 if (newmem == NULL) { 00631 x_oom (); 00632 return 0; 00633 } 00634 00635 coll->idlist = newmem; 00636 coll->idlist_allocated = newsize; 00637 00638 return 1; 00639 }