| File: | build-analysis/../src/xmms/fetchspec.c |
| Warning: | line 410, column 32 Function call argument is an uninitialized value |
| 1 | /* XMMS2 - X Music Multiplexer System | |||
| 2 | * Copyright (C) 2003-2017 XMMS2 Team | |||
| 3 | * | |||
| 4 | * PLUGINS ARE NOT CONSIDERED TO BE DERIVED WORK !!! | |||
| 5 | * | |||
| 6 | * This library is free software; you can redistribute it and/or | |||
| 7 | * modify it under the terms of the GNU Lesser General Public | |||
| 8 | * License as published by the Free Software Foundation; either | |||
| 9 | * version 2.1 of the License, or (at your option) any later version. | |||
| 10 | * | |||
| 11 | * This library is distributed in the hope that it will be useful, | |||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
| 14 | * Lesser General Public License for more details. | |||
| 15 | */ | |||
| 16 | #include <xmmspriv/xmms_fetch_spec.h> | |||
| 17 | #include <xmmspriv/xmms_fetch_info.h> | |||
| 18 | #include <xmms/xmms_log.h> | |||
| 19 | #include <string.h> | |||
| 20 | #include <stdlib.h> | |||
| 21 | ||||
| 22 | static gboolean | |||
| 23 | metadata_value_from_string (const gchar *name, guint32 *value) | |||
| 24 | { | |||
| 25 | if (name == NULL((void*)0)) { | |||
| 26 | return FALSE(0); | |||
| 27 | } else if (strcmp (name, "id") == 0) { | |||
| 28 | *value = METADATA_ID; | |||
| 29 | } else if (strcmp (name, "field") == 0) { | |||
| 30 | *value = METADATA_KEY; | |||
| 31 | } else if (strcmp (name, "value") == 0) { | |||
| 32 | *value = METADATA_VALUE; | |||
| 33 | } else if (strcmp (name, "source") == 0) { | |||
| 34 | *value = METADATA_SOURCE; | |||
| 35 | } else { | |||
| 36 | return FALSE(0); | |||
| 37 | } | |||
| 38 | ||||
| 39 | return TRUE(!(0)); | |||
| 40 | } | |||
| 41 | ||||
| 42 | static gboolean | |||
| 43 | aggregate_value_from_string (const gchar *name, guint32 *value) | |||
| 44 | { | |||
| 45 | if (name == NULL((void*)0)) { | |||
| 46 | return FALSE(0); | |||
| 47 | } else if (strcmp (name, "first") == 0) { | |||
| 48 | *value = AGGREGATE_FIRST; | |||
| 49 | } else if (strcmp (name, "sum") == 0) { | |||
| 50 | *value = AGGREGATE_SUM; | |||
| 51 | } else if (strcmp (name, "max") == 0) { | |||
| 52 | *value = AGGREGATE_MAX; | |||
| 53 | } else if (strcmp (name, "min") == 0) { | |||
| 54 | *value = AGGREGATE_MIN; | |||
| 55 | } else if (strcmp (name, "list") == 0) { | |||
| 56 | *value = AGGREGATE_LIST; | |||
| 57 | } else if (strcmp (name, "set") == 0) { | |||
| 58 | *value = AGGREGATE_SET; | |||
| 59 | } else if (strcmp (name, "random") == 0) { | |||
| 60 | *value = AGGREGATE_RANDOM; | |||
| 61 | } else if (strcmp (name, "avg") == 0) { | |||
| 62 | *value = AGGREGATE_AVG; | |||
| 63 | } else { | |||
| 64 | return FALSE(0); | |||
| 65 | } | |||
| 66 | ||||
| 67 | return TRUE(!(0)); | |||
| 68 | } | |||
| 69 | ||||
| 70 | /** | |||
| 71 | * Sanitize the 'get' property of a 'metadata' fetch specification. | |||
| 72 | */ | |||
| 73 | static xmmsv_t * | |||
| 74 | normalize_metadata_get (xmmsv_t *fetch, xmms_error_t *err) | |||
| 75 | { | |||
| 76 | xmmsv_list_iter_t *it; | |||
| 77 | xmmsv_t *get, *list; | |||
| 78 | guint32 values; | |||
| 79 | ||||
| 80 | if (!xmmsv_dict_get (fetch, "get", &get) || | |||
| 81 | xmmsv_get_type (get) != XMMSV_TYPE_LIST || | |||
| 82 | xmmsv_list_get_size (get) < 1) { | |||
| 83 | const gchar *message = "'get' must be a non-empty list of strings."; | |||
| 84 | xmms_error_set (err, XMMS_ERROR_INVAL, message); | |||
| 85 | return NULL((void*)0); | |||
| 86 | } | |||
| 87 | ||||
| 88 | list = xmmsv_new_list (); | |||
| 89 | values = 0; | |||
| 90 | ||||
| 91 | /* Scan for duplicates or invalid values */ | |||
| 92 | xmmsv_get_list_iter (get, &it); | |||
| 93 | while (xmmsv_list_iter_valid (it)) { | |||
| 94 | const gchar *value = NULL((void*)0); | |||
| 95 | guint32 get_as_int, mask; | |||
| 96 | ||||
| 97 | xmmsv_list_iter_entry_string (it, &value); | |||
| 98 | ||||
| 99 | if (!metadata_value_from_string (value, &get_as_int)) { | |||
| 100 | const gchar *message = "'get' entries must be 'id', 'field', 'value' or 'source'."; | |||
| 101 | xmms_error_set (err, XMMS_ERROR_INVAL, message); | |||
| 102 | xmmsv_unref (list); | |||
| 103 | return NULL((void*)0); | |||
| 104 | } | |||
| 105 | ||||
| 106 | mask = 1 << (get_as_int + 1); | |||
| 107 | if (values & mask) { | |||
| 108 | const gchar *message = "'get' entries must be unique."; | |||
| 109 | xmms_error_set (err, XMMS_ERROR_INVAL, message); | |||
| 110 | xmmsv_unref (list); | |||
| 111 | return NULL((void*)0); | |||
| 112 | } | |||
| 113 | ||||
| 114 | values |= mask; | |||
| 115 | ||||
| 116 | xmmsv_list_append_int (list, get_as_int); | |||
| 117 | xmmsv_list_iter_next (it); | |||
| 118 | } | |||
| 119 | ||||
| 120 | return list; | |||
| 121 | } | |||
| 122 | ||||
| 123 | static xmmsv_t * | |||
| 124 | normalize_metadata_fields (xmmsv_t *fetch, xmms_error_t *err) | |||
| 125 | { | |||
| 126 | gpointer SENTINEL = GINT_TO_POINTER (0x31337)((gpointer) (glong) (0x31337)); | |||
| 127 | GHashTable *table; | |||
| 128 | ||||
| 129 | xmmsv_list_iter_t *it; | |||
| 130 | xmmsv_t *fields; | |||
| 131 | ||||
| 132 | if (!xmmsv_dict_get (fetch, "fields", &fields)) { | |||
| 133 | /* No fields means that we should fetch all fields */ | |||
| 134 | return NULL((void*)0); | |||
| 135 | } | |||
| 136 | ||||
| 137 | if (xmmsv_get_type (fields) != XMMSV_TYPE_LIST) { | |||
| 138 | const gchar *message = "'fields' must be a list of strings."; | |||
| 139 | xmms_error_set (err, XMMS_ERROR_INVAL, message); | |||
| 140 | return NULL((void*)0); | |||
| 141 | } | |||
| 142 | ||||
| 143 | if (xmmsv_list_get_size (fields) < 1) { | |||
| 144 | /* No fields means that we should fetch all fields */ | |||
| 145 | return NULL((void*)0); | |||
| 146 | } | |||
| 147 | ||||
| 148 | table = g_hash_table_new (g_str_hash, g_str_equal); | |||
| 149 | ||||
| 150 | xmmsv_get_list_iter (fields, &it); | |||
| 151 | while (xmmsv_list_iter_valid (it)) { | |||
| 152 | const gchar *value = NULL((void*)0); | |||
| 153 | ||||
| 154 | if (!xmmsv_list_iter_entry_string (it, &value)) { | |||
| 155 | const gchar *message = "'fields' entries must be of string type."; | |||
| 156 | xmms_error_set (err, XMMS_ERROR_INVAL, message); | |||
| 157 | g_hash_table_unref (table); | |||
| 158 | return NULL((void*)0); | |||
| 159 | } | |||
| 160 | ||||
| 161 | if (g_hash_table_lookup (table, (gpointer) value) == SENTINEL) { | |||
| 162 | const gchar *message = "'fields' entries must be unique."; | |||
| 163 | xmms_error_set (err, XMMS_ERROR_INVAL, message); | |||
| 164 | g_hash_table_unref (table); | |||
| 165 | return NULL((void*)0); | |||
| 166 | } | |||
| 167 | ||||
| 168 | g_hash_table_insert (table, (gpointer) value, SENTINEL); | |||
| 169 | ||||
| 170 | xmmsv_list_iter_next (it); | |||
| 171 | } | |||
| 172 | ||||
| 173 | g_hash_table_unref (table); | |||
| 174 | ||||
| 175 | return fields; | |||
| 176 | } | |||
| 177 | ||||
| 178 | ||||
| 179 | static s4_sourcepref_t * | |||
| 180 | normalize_source_preferences (xmmsv_t *fetch, s4_sourcepref_t *prefs, xmms_error_t *err) | |||
| 181 | { | |||
| 182 | s4_sourcepref_t *sp; | |||
| 183 | xmmsv_list_iter_t *it; | |||
| 184 | const char **strv; | |||
| 185 | const gchar *str; | |||
| 186 | xmmsv_t *list; | |||
| 187 | gint length, idx; | |||
| 188 | ||||
| 189 | if (!xmmsv_dict_get (fetch, "source-preference", &list)) { | |||
| 190 | return s4_sourcepref_ref (prefs); | |||
| 191 | } | |||
| 192 | ||||
| 193 | if (xmmsv_get_type (list) != XMMSV_TYPE_LIST) { | |||
| 194 | const gchar *message = "'source-preference' must be a list of strings."; | |||
| 195 | xmms_error_set (err, XMMS_ERROR_INVAL, message); | |||
| 196 | return NULL((void*)0); | |||
| 197 | } | |||
| 198 | ||||
| 199 | length = xmmsv_list_get_size (list); | |||
| 200 | if (length == 0) { | |||
| 201 | return s4_sourcepref_ref (prefs); | |||
| 202 | } | |||
| 203 | ||||
| 204 | strv = g_new0 (const char *, length + 1)((const char * *) g_malloc0_n ((length + 1), sizeof (const char *))); | |||
| 205 | ||||
| 206 | idx = 0; | |||
| 207 | ||||
| 208 | xmmsv_get_list_iter (list, &it); | |||
| 209 | while (xmmsv_list_iter_valid (it)) { | |||
| 210 | if (!xmmsv_list_iter_entry_string (it, &str)) { | |||
| 211 | const gchar *message = "'source-preference' must be a list of strings."; | |||
| 212 | xmms_error_set (err, XMMS_ERROR_INVAL, message); | |||
| 213 | g_free (strv); | |||
| 214 | return NULL((void*)0); | |||
| 215 | } | |||
| 216 | ||||
| 217 | strv[idx++] = str; | |||
| 218 | ||||
| 219 | xmmsv_list_iter_next (it); | |||
| 220 | } | |||
| 221 | ||||
| 222 | sp = s4_sourcepref_create (strv); | |||
| 223 | g_free (strv); | |||
| 224 | ||||
| 225 | return sp; | |||
| 226 | } | |||
| 227 | ||||
| 228 | static gint | |||
| 229 | normalize_aggregate_function (xmmsv_t *fetch, xmms_error_t *err) | |||
| 230 | { | |||
| 231 | const gchar *name; | |||
| 232 | guint32 aggregate; | |||
| 233 | ||||
| 234 | if (xmmsv_dict_entry_get_type (fetch, "aggregate") == XMMSV_TYPE_NONE) { | |||
| 235 | xmmsv_dict_set_string (fetch, "aggregate", "first"); | |||
| 236 | } | |||
| 237 | ||||
| 238 | /* Default to first as the aggregation function */ | |||
| 239 | if (!xmmsv_dict_entry_get_string (fetch, "aggregate", &name)) { | |||
| 240 | xmms_error_set (err, XMMS_ERROR_INVAL, "'aggregate' must be a string."); | |||
| 241 | return -1; | |||
| 242 | } | |||
| 243 | ||||
| 244 | if (!aggregate_value_from_string (name, &aggregate)) { | |||
| 245 | const gchar *message = "'aggregate' must be 'first', 'sum', 'max', 'min', 'list', 'set', 'random', or 'avg'"; | |||
| 246 | xmms_error_set (err, XMMS_ERROR_INVAL, message); | |||
| 247 | return -1; | |||
| 248 | } | |||
| 249 | ||||
| 250 | return aggregate; | |||
| 251 | } | |||
| 252 | ||||
| 253 | ||||
| 254 | static xmms_fetch_spec_t * | |||
| 255 | xmms_fetch_spec_new_metadata (xmmsv_t *fetch, xmms_fetch_info_t *info, | |||
| 256 | s4_sourcepref_t *prefs, xmms_error_t *err) | |||
| 257 | { | |||
| 258 | xmms_fetch_spec_t *ret = NULL((void*)0); | |||
| 259 | s4_sourcepref_t *sp; | |||
| 260 | const gchar *key; | |||
| 261 | xmmsv_t *gets, *fields; | |||
| 262 | gint i, size, aggregate, get; | |||
| 263 | ||||
| 264 | aggregate = normalize_aggregate_function (fetch, err); | |||
| 265 | if (xmms_error_iserror (err)((err)->code != XMMS_ERROR_NONE)) { | |||
| 266 | return NULL((void*)0); | |||
| 267 | } | |||
| 268 | ||||
| 269 | fields = normalize_metadata_fields (fetch, err); | |||
| 270 | if (xmms_error_iserror (err)((err)->code != XMMS_ERROR_NONE)) { | |||
| 271 | return NULL((void*)0); | |||
| 272 | } | |||
| 273 | ||||
| 274 | gets = normalize_metadata_get (fetch, err); | |||
| 275 | if (xmms_error_iserror (err)((err)->code != XMMS_ERROR_NONE)) { | |||
| 276 | return NULL((void*)0); | |||
| 277 | } | |||
| 278 | ||||
| 279 | sp = normalize_source_preferences (fetch, prefs, err); | |||
| 280 | if (xmms_error_iserror (err)((err)->code != XMMS_ERROR_NONE)) { | |||
| 281 | xmmsv_unref (gets); | |||
| 282 | return NULL((void*)0); | |||
| 283 | } | |||
| 284 | ||||
| 285 | ret = g_new0 (xmms_fetch_spec_t, 1)((xmms_fetch_spec_t *) g_malloc0_n ((1), sizeof (xmms_fetch_spec_t ))); | |||
| 286 | ret->type = FETCH_METADATA; | |||
| 287 | ret->data.metadata.aggr_func = aggregate; | |||
| 288 | ||||
| 289 | for (i = 0; i < 4 && xmmsv_list_get_intxmmsv_list_get_int32 (gets, i, &get); i++) { | |||
| 290 | ret->data.metadata.get[i] = get; | |||
| 291 | } | |||
| 292 | ret->data.metadata.get_size = i; | |||
| 293 | ||||
| 294 | if (fields != NULL((void*)0)) { | |||
| 295 | size = xmmsv_list_get_size (fields); | |||
| 296 | ret->data.metadata.col_count = size; | |||
| 297 | ret->data.metadata.cols = g_new (gint32, size)((gint32 *) g_malloc_n ((size), sizeof (gint32))); | |||
| 298 | for (i = 0; xmmsv_list_get_string (fields, i, &key); i++) { | |||
| 299 | ret->data.metadata.cols[i] = xmms_fetch_info_add_key (info, fetch, key, sp); | |||
| 300 | } | |||
| 301 | } else { | |||
| 302 | /* No fields requested, fetching all available */ | |||
| 303 | ret->data.metadata.col_count = 1; | |||
| 304 | ret->data.metadata.cols = g_new0 (gint32, 1)((gint32 *) g_malloc0_n ((1), sizeof (gint32))); | |||
| 305 | ret->data.metadata.cols[0] = xmms_fetch_info_add_key (info, fetch, NULL((void*)0), sp); | |||
| 306 | } | |||
| 307 | ||||
| 308 | s4_sourcepref_unref (sp); | |||
| 309 | xmmsv_unref (gets); | |||
| 310 | ||||
| 311 | return ret; | |||
| 312 | } | |||
| 313 | ||||
| 314 | static gboolean | |||
| 315 | cluster_by_from_string (const gchar *name, gint *value) | |||
| 316 | { | |||
| 317 | if (name == NULL((void*)0)) { | |||
| 318 | return FALSE(0); | |||
| 319 | } else if (strcmp (name, "id") == 0) { | |||
| 320 | *value = CLUSTER_BY_ID; | |||
| 321 | } else if (strcmp (name, "position") == 0) { | |||
| 322 | *value = CLUSTER_BY_POSITION; | |||
| 323 | } else if (strcmp (name, "value") == 0) { | |||
| 324 | *value = CLUSTER_BY_VALUE; | |||
| 325 | } else { | |||
| 326 | return FALSE(0); | |||
| 327 | } | |||
| 328 | ||||
| 329 | return TRUE(!(0)); | |||
| 330 | } | |||
| 331 | ||||
| 332 | /** | |||
| 333 | * Decodes a cluster fetch specification from a dictionary. | |||
| 334 | * The 'cluster-by' must be one of 'id', 'position' or 'value'. If set | |||
| 335 | * to 'value', then an additional 'cluster-field' will be used to specify | |||
| 336 | * which meta data attribute to cluster on. | |||
| 337 | */ | |||
| 338 | static xmms_fetch_spec_t * | |||
| 339 | xmms_fetch_spec_new_cluster (xmmsv_t *fetch, xmms_fetch_info_t *info, | |||
| 340 | s4_sourcepref_t *prefs, xmms_error_t *err) | |||
| 341 | { | |||
| 342 | xmmsv_t *cluster_by, *cluster_field, *cluster_data; | |||
| 343 | xmms_fetch_spec_t *data, *spec = NULL((void*)0); | |||
| 344 | s4_sourcepref_t *sp; | |||
| 345 | const gchar *value = NULL((void*)0); | |||
| 346 | const gchar *field = NULL((void*)0); | |||
| 347 | const gchar *fallback = NULL((void*)0); | |||
| 348 | gint cluster_type; | |||
| 349 | ||||
| 350 | if (!xmmsv_dict_get (fetch, "cluster-by", &cluster_by)) { | |||
| 351 | cluster_by = xmmsv_new_string ("value"); | |||
| 352 | xmmsv_dict_set (fetch, "cluster-by", cluster_by); | |||
| 353 | xmmsv_unref (cluster_by); | |||
| 354 | } | |||
| 355 | ||||
| 356 | if (!xmmsv_dict_entry_get_string (fetch, "cluster-by", &value)) { | |||
| 357 | const gchar *message = "'cluster-by' must be a string."; | |||
| 358 | xmms_error_set (err, XMMS_ERROR_INVAL, message); | |||
| 359 | return NULL((void*)0); | |||
| 360 | } | |||
| 361 | ||||
| 362 | xmmsv_get_string (cluster_by, &value); | |||
| 363 | ||||
| 364 | if (!cluster_by_from_string (value, &cluster_type)) { | |||
| 365 | const gchar *message = "'cluster-by' must be 'id', 'position', or 'value'."; | |||
| 366 | xmms_error_set (err, XMMS_ERROR_INVAL, message); | |||
| 367 | return NULL((void*)0); | |||
| 368 | } | |||
| 369 | ||||
| 370 | if (cluster_type == CLUSTER_BY_VALUE) { | |||
| 371 | if (!xmmsv_dict_entry_get_string (fetch, "cluster-field", &field)) { | |||
| 372 | const gchar *message = "'cluster-field' must if 'cluster-by' is 'value'."; | |||
| 373 | xmms_error_set (err, XMMS_ERROR_INVAL, message); | |||
| 374 | return NULL((void*)0); | |||
| 375 | } | |||
| 376 | } | |||
| 377 | ||||
| 378 | if (!xmmsv_dict_get (fetch, "data", &cluster_data)) { | |||
| 379 | const gchar *message = "Required field 'data' not set in cluster."; | |||
| 380 | xmms_error_set (err, XMMS_ERROR_INVAL, message); | |||
| 381 | return NULL((void*)0); | |||
| 382 | } | |||
| 383 | ||||
| 384 | if (xmmsv_dict_entry_get_type (fetch, "cluster-fallback") == XMMSV_TYPE_NONE) { | |||
| 385 | fallback = NULL((void*)0); | |||
| 386 | } else if (!xmmsv_dict_entry_get_string (fetch, "cluster-fallback", &fallback)) { | |||
| 387 | const gchar *message = "Optional field 'default' must be a string."; | |||
| 388 | xmms_error_set (err, XMMS_ERROR_INVAL, message); | |||
| 389 | return NULL((void*)0); | |||
| 390 | } | |||
| 391 | ||||
| 392 | sp = normalize_source_preferences (fetch, prefs, err); | |||
| 393 | if (xmms_error_iserror (err)((err)->code != XMMS_ERROR_NONE)) { | |||
| 394 | return NULL((void*)0); | |||
| 395 | } | |||
| 396 | ||||
| 397 | data = xmms_fetch_spec_new (cluster_data, info, sp, err); | |||
| 398 | if (xmms_error_iserror (err)((err)->code != XMMS_ERROR_NONE)) { | |||
| 399 | s4_sourcepref_unref (sp); | |||
| 400 | return NULL((void*)0); | |||
| 401 | } | |||
| 402 | ||||
| 403 | spec = g_new0 (xmms_fetch_spec_t, 1)((xmms_fetch_spec_t *) g_malloc0_n ((1), sizeof (xmms_fetch_spec_t ))); | |||
| 404 | spec->data.cluster.data = data; | |||
| 405 | spec->data.cluster.type = cluster_type; | |||
| 406 | spec->data.cluster.fallback = fallback; | |||
| 407 | ||||
| 408 | switch (spec->data.cluster.type) { | |||
| 409 | case CLUSTER_BY_ID: | |||
| 410 | spec->data.cluster.column = xmms_fetch_info_add_song_id(info, cluster_field); | |||
| ||||
| 411 | break; | |||
| 412 | case CLUSTER_BY_VALUE: | |||
| 413 | xmmsv_dict_get (fetch, "cluster-field", &cluster_field); | |||
| 414 | spec->data.cluster.column = xmms_fetch_info_add_key (info, cluster_field, | |||
| 415 | field, sp); | |||
| 416 | break; | |||
| 417 | case CLUSTER_BY_POSITION: | |||
| 418 | /* do nothing */ | |||
| 419 | break; | |||
| 420 | default: | |||
| 421 | g_assert_not_reached ()do { g_assertion_message_expr ("core", "../src/xmms/fetchspec.c" , 421, ((const char*) (__func__)), ((void*)0)); } while (0); | |||
| 422 | } | |||
| 423 | ||||
| 424 | s4_sourcepref_unref (sp); | |||
| 425 | ||||
| 426 | return spec; | |||
| 427 | } | |||
| 428 | ||||
| 429 | static xmms_fetch_spec_t * | |||
| 430 | xmms_fetch_spec_new_cluster_list (xmmsv_t *fetch, xmms_fetch_info_t *info, | |||
| 431 | s4_sourcepref_t *prefs, xmms_error_t *err) | |||
| 432 | { | |||
| 433 | xmms_fetch_spec_t *spec; | |||
| 434 | ||||
| 435 | spec = xmms_fetch_spec_new_cluster (fetch, info, prefs, err); | |||
| 436 | if (spec != NULL((void*)0)) | |||
| 437 | spec->type = FETCH_CLUSTER_LIST; | |||
| 438 | ||||
| 439 | return spec; | |||
| 440 | } | |||
| 441 | ||||
| 442 | ||||
| 443 | static xmms_fetch_spec_t * | |||
| 444 | xmms_fetch_spec_new_cluster_dict (xmmsv_t *fetch, xmms_fetch_info_t *info, | |||
| 445 | s4_sourcepref_t *prefs, xmms_error_t *err) | |||
| 446 | { | |||
| 447 | xmms_fetch_spec_t *spec; | |||
| 448 | ||||
| 449 | spec = xmms_fetch_spec_new_cluster (fetch, info, prefs, err); | |||
| 450 | if (spec != NULL((void*)0)) | |||
| 451 | spec->type = FETCH_CLUSTER_DICT; | |||
| 452 | ||||
| 453 | return spec; | |||
| 454 | } | |||
| 455 | ||||
| 456 | ||||
| 457 | static xmms_fetch_spec_t * | |||
| 458 | xmms_fetch_spec_new_organize (xmmsv_t *fetch, xmms_fetch_info_t *info, | |||
| 459 | s4_sourcepref_t *prefs, xmms_error_t *err) | |||
| 460 | { | |||
| 461 | xmms_fetch_spec_t *spec; | |||
| 462 | xmmsv_dict_iter_t *it; | |||
| 463 | s4_sourcepref_t *sp; | |||
| 464 | xmmsv_t *org_data; | |||
| 465 | gint org_idx; | |||
| 466 | ||||
| 467 | if (!xmmsv_dict_get (fetch, "data", &org_data)) { | |||
| 468 | xmms_error_set (err, XMMS_ERROR_INVAL, "Required field 'data' not set in organize."); | |||
| 469 | return NULL((void*)0); | |||
| 470 | } | |||
| 471 | ||||
| 472 | if (xmmsv_get_type (org_data) != XMMSV_TYPE_DICT) { | |||
| 473 | xmms_error_set (err, XMMS_ERROR_INVAL, "Field 'data' in organize must be a dict."); | |||
| 474 | return NULL((void*)0); | |||
| 475 | } | |||
| 476 | ||||
| 477 | sp = normalize_source_preferences (fetch, prefs, err); | |||
| 478 | if (xmms_error_iserror (err)((err)->code != XMMS_ERROR_NONE)) { | |||
| 479 | return NULL((void*)0); | |||
| 480 | } | |||
| 481 | ||||
| 482 | spec = g_new0 (xmms_fetch_spec_t, 1)((xmms_fetch_spec_t *) g_malloc0_n ((1), sizeof (xmms_fetch_spec_t ))); | |||
| 483 | spec->type = FETCH_ORGANIZE; | |||
| 484 | ||||
| 485 | spec->data.organize.count = xmmsv_dict_get_size (org_data); | |||
| 486 | spec->data.organize.keys = g_new0 (const char *, spec->data.organize.count)((const char * *) g_malloc0_n ((spec->data.organize.count) , sizeof (const char *))); | |||
| 487 | spec->data.organize.data = g_new0 (xmms_fetch_spec_t *, spec->data.organize.count)((xmms_fetch_spec_t * *) g_malloc0_n ((spec->data.organize .count), sizeof (xmms_fetch_spec_t *))); | |||
| 488 | ||||
| 489 | org_idx = 0; | |||
| 490 | xmmsv_get_dict_iter (org_data, &it); | |||
| 491 | while (xmmsv_dict_iter_valid (it)) { | |||
| 492 | xmms_fetch_spec_t *orgee; | |||
| 493 | const gchar *str; | |||
| 494 | xmmsv_t *entry; | |||
| 495 | ||||
| 496 | xmmsv_dict_iter_pair (it, &str, &entry); | |||
| 497 | ||||
| 498 | orgee = xmms_fetch_spec_new (entry, info, sp, err); | |||
| 499 | if (xmms_error_iserror (err)((err)->code != XMMS_ERROR_NONE)) { | |||
| 500 | xmms_fetch_spec_free (spec); | |||
| 501 | spec = NULL((void*)0); | |||
| 502 | break; | |||
| 503 | } | |||
| 504 | ||||
| 505 | spec->data.organize.keys[org_idx] = str; | |||
| 506 | spec->data.organize.data[org_idx] = orgee; | |||
| 507 | ||||
| 508 | org_idx++; | |||
| 509 | xmmsv_dict_iter_next (it); | |||
| 510 | } | |||
| 511 | xmmsv_dict_iter_explicit_destroy (it); | |||
| 512 | ||||
| 513 | s4_sourcepref_unref (sp); | |||
| 514 | ||||
| 515 | return spec; | |||
| 516 | } | |||
| 517 | ||||
| 518 | static xmms_fetch_spec_t * | |||
| 519 | xmms_fetch_spec_new_count (xmmsv_t *fetch, xmms_fetch_info_t *info, | |||
| 520 | s4_sourcepref_t *prefs, xmms_error_t *err) | |||
| 521 | { | |||
| 522 | xmms_fetch_spec_t *ret; | |||
| 523 | ||||
| 524 | ret = g_new0 (xmms_fetch_spec_t, 1)((xmms_fetch_spec_t *) g_malloc0_n ((1), sizeof (xmms_fetch_spec_t ))); | |||
| 525 | ret->type = FETCH_COUNT; | |||
| 526 | ||||
| 527 | return ret; | |||
| 528 | } | |||
| 529 | ||||
| 530 | ||||
| 531 | ||||
| 532 | /** | |||
| 533 | * Converts a fetch specification in xmmsv_t form into a | |||
| 534 | * fetch_spec_t structure | |||
| 535 | */ | |||
| 536 | xmms_fetch_spec_t * | |||
| 537 | xmms_fetch_spec_new (xmmsv_t *fetch, xmms_fetch_info_t *info, | |||
| 538 | s4_sourcepref_t *prefs, xmms_error_t *err) | |||
| 539 | { | |||
| 540 | const char *type; | |||
| 541 | ||||
| 542 | if (xmmsv_get_type (fetch) != XMMSV_TYPE_DICT) { | |||
| ||||
| 543 | xmms_error_set (err, XMMS_ERROR_INVAL, "A fetch specification must be a dict."); | |||
| 544 | return NULL((void*)0); | |||
| 545 | } | |||
| 546 | ||||
| 547 | if (xmmsv_dict_entry_get_type (fetch, "type") == XMMSV_TYPE_NONE) { | |||
| 548 | xmmsv_dict_set_string (fetch, "type", "metadata"); | |||
| 549 | } | |||
| 550 | ||||
| 551 | if (!xmmsv_dict_entry_get_string (fetch, "type", &type)) { | |||
| 552 | xmms_error_set (err, XMMS_ERROR_INVAL, "A fetch specification must have a type."); | |||
| 553 | return NULL((void*)0); | |||
| 554 | } | |||
| 555 | ||||
| 556 | if (strcmp (type, "metadata") == 0) { | |||
| 557 | return xmms_fetch_spec_new_metadata (fetch, info, prefs, err); | |||
| 558 | } else if (strcmp (type, "cluster-list") == 0) { | |||
| 559 | return xmms_fetch_spec_new_cluster_list (fetch, info, prefs, err); | |||
| 560 | } else if (strcmp (type, "cluster-dict") == 0) { | |||
| 561 | return xmms_fetch_spec_new_cluster_dict (fetch, info, prefs, err); | |||
| 562 | } else if (strcmp (type, "organize") == 0) { | |||
| 563 | return xmms_fetch_spec_new_organize (fetch, info, prefs, err); | |||
| 564 | } else if (strcmp (type, "count") == 0) { | |||
| 565 | return xmms_fetch_spec_new_count (fetch, info, prefs, err); | |||
| 566 | } | |||
| 567 | ||||
| 568 | xmms_error_set (err, XMMS_ERROR_INVAL, "Unknown fetch type."); | |||
| 569 | ||||
| 570 | return NULL((void*)0); | |||
| 571 | } | |||
| 572 | ||||
| 573 | ||||
| 574 | void | |||
| 575 | xmms_fetch_spec_free (xmms_fetch_spec_t *spec) | |||
| 576 | { | |||
| 577 | int i; | |||
| 578 | if (spec == NULL((void*)0)) | |||
| 579 | return; | |||
| 580 | ||||
| 581 | switch (spec->type) { | |||
| 582 | case FETCH_METADATA: | |||
| 583 | g_free (spec->data.metadata.cols); | |||
| 584 | break; | |||
| 585 | case FETCH_CLUSTER_DICT: | |||
| 586 | case FETCH_CLUSTER_LIST: | |||
| 587 | xmms_fetch_spec_free (spec->data.cluster.data); | |||
| 588 | break; | |||
| 589 | case FETCH_ORGANIZE: | |||
| 590 | for (i = 0; i < spec->data.organize.count; i++) { | |||
| 591 | xmms_fetch_spec_free (spec->data.organize.data[i]); | |||
| 592 | } | |||
| 593 | ||||
| 594 | g_free (spec->data.organize.keys); | |||
| 595 | g_free (spec->data.organize.data); | |||
| 596 | break; | |||
| 597 | case FETCH_COUNT: /* Nothing to free */ | |||
| 598 | break; | |||
| 599 | default: | |||
| 600 | g_assert_not_reached ()do { g_assertion_message_expr ("core", "../src/xmms/fetchspec.c" , 600, ((const char*) (__func__)), ((void*)0)); } while (0); | |||
| 601 | } | |||
| 602 | ||||
| 603 | g_free (spec); | |||
| 604 | } |