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 | } |