1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | #include <xmmspriv/xmms_collection.h> |
19 | #include <sqlite3.h> |
20 | #include <string.h> |
21 | #include <stdlib.h> |
22 | #include <glib.h> |
23 | |
24 | struct db_info { |
25 | sqlite3 *db; |
26 | GHashTable **ht; |
27 | xmmsv_t *coll; |
28 | }; |
29 | |
30 | typedef enum { |
31 | XMMS_COLLECTION1_TYPE_REFERENCE, |
32 | XMMS_COLLECTION1_TYPE_UNION, |
33 | XMMS_COLLECTION1_TYPE_INTERSECTION, |
34 | XMMS_COLLECTION1_TYPE_COMPLEMENT, |
35 | XMMS_COLLECTION1_TYPE_HAS, |
36 | XMMS_COLLECTION1_TYPE_EQUALS, |
37 | XMMS_COLLECTION1_TYPE_MATCH, |
38 | XMMS_COLLECTION1_TYPE_SMALLER, |
39 | XMMS_COLLECTION1_TYPE_GREATER, |
40 | XMMS_COLLECTION1_TYPE_IDLIST, |
41 | XMMS_COLLECTION1_TYPE_QUEUE, |
42 | XMMS_COLLECTION1_TYPE_PARTYSHUFFLE, |
43 | XMMS_COLLECTION1_TYPE_LAST = XMMS_COLLECTION1_TYPE_PARTYSHUFFLE |
44 | } xmmsv_coll1_type_t; |
45 | |
46 | void collection_restore (sqlite3 *db, GHashTable **ht); |
47 | static xmmsv_t *xmms_collection_dbread_operator (sqlite3 *db, gint id, xmmsv_coll_type_t type); |
48 | |
49 | |
50 | static xmmsv_t * |
51 | create_coll (xmmsv_coll1_type_t type) |
52 | { |
53 | xmmsv_t *ret; |
54 | xmmsv_coll_type_t new_type; |
55 | const char *idlist_type = NULL((void*)0); |
56 | |
57 | switch (type) { |
58 | case XMMS_COLLECTION1_TYPE_REFERENCE: |
59 | new_type = XMMS_COLLECTION_TYPE_REFERENCE; |
60 | break; |
61 | case XMMS_COLLECTION1_TYPE_UNION: |
62 | new_type = XMMS_COLLECTION_TYPE_UNION; |
63 | break; |
64 | case XMMS_COLLECTION1_TYPE_INTERSECTION: |
65 | new_type = XMMS_COLLECTION_TYPE_INTERSECTION; |
66 | break; |
67 | case XMMS_COLLECTION1_TYPE_COMPLEMENT: |
68 | new_type = XMMS_COLLECTION_TYPE_COMPLEMENT; |
69 | break; |
70 | |
71 | case XMMS_COLLECTION1_TYPE_HAS: |
72 | new_type = XMMS_COLLECTION_TYPE_HAS; |
73 | break; |
74 | case XMMS_COLLECTION1_TYPE_EQUALS: |
75 | new_type = XMMS_COLLECTION_TYPE_EQUALS; |
76 | break; |
77 | case XMMS_COLLECTION1_TYPE_MATCH: |
78 | new_type = XMMS_COLLECTION_TYPE_MATCH; |
79 | break; |
80 | case XMMS_COLLECTION1_TYPE_SMALLER: |
81 | new_type = XMMS_COLLECTION_TYPE_SMALLER; |
82 | break; |
83 | case XMMS_COLLECTION1_TYPE_GREATER: |
84 | new_type = XMMS_COLLECTION_TYPE_GREATER; |
85 | break; |
86 | |
87 | case XMMS_COLLECTION1_TYPE_IDLIST: |
88 | idlist_type = "list"; |
89 | break; |
90 | case XMMS_COLLECTION1_TYPE_QUEUE: |
91 | idlist_type = "queue"; |
92 | break; |
93 | case XMMS_COLLECTION1_TYPE_PARTYSHUFFLE: |
94 | idlist_type = "pshuffle"; |
95 | break; |
96 | } |
97 | |
98 | if (idlist_type != NULL((void*)0)) { |
99 | ret = xmmsv_new_coll (XMMS_COLLECTION_TYPE_IDLIST); |
100 | xmmsv_coll_attribute_set_string (ret, "type", idlist_type); |
101 | } else { |
102 | ret = xmmsv_new_coll (new_type); |
103 | } |
104 | |
105 | return ret; |
106 | } |
107 | |
108 | |
109 | static xmmsv_t * |
110 | augment_coll (xmmsv_t *coll) |
111 | { |
112 | xmmsv_t *ret = coll; |
113 | const char *key; |
114 | |
115 | switch (xmmsv_coll_get_type (coll)) { |
116 | case XMMS_COLLECTION_TYPE_HAS: |
117 | case XMMS_COLLECTION_TYPE_MATCH: |
118 | case XMMS_COLLECTION_TYPE_TOKEN: |
119 | case XMMS_COLLECTION_TYPE_EQUALS: |
120 | case XMMS_COLLECTION_TYPE_NOTEQUAL: |
121 | case XMMS_COLLECTION_TYPE_SMALLER: |
122 | case XMMS_COLLECTION_TYPE_SMALLEREQ: |
123 | case XMMS_COLLECTION_TYPE_GREATER: |
124 | case XMMS_COLLECTION_TYPE_GREATEREQ: |
125 | if (xmmsv_coll_attribute_get_string (coll, "field", &key) |
126 | && strcmp (key, "id") == 0) { |
127 | xmmsv_coll_attribute_set_string (coll, "type", "id"); |
128 | } else { |
129 | xmmsv_coll_attribute_set_string (coll, "type", "value"); |
130 | } |
131 | break; |
132 | |
133 | case XMMS_COLLECTION_TYPE_REFERENCE: |
134 | if (xmmsv_coll_attribute_get_string (coll, "reference", &key) |
135 | && strcmp (key, "All Media") == 0) { |
136 | ret = xmmsv_new_coll (XMMS_COLLECTION_TYPE_UNIVERSE); |
137 | xmmsv_unref (coll); |
138 | } |
139 | break; |
140 | |
141 | default: |
142 | break; |
143 | } |
144 | |
145 | return ret; |
146 | } |
147 | |
148 | static int |
149 | restore_callback (void *userdata, int columns, char **col_strs, char **col_names) |
150 | { |
151 | struct db_info *info = userdata; |
152 | static gint previd = -1; |
153 | gint id, type, nsid, i; |
| 1 | 'nsid' declared without an initial value | |
|
154 | const gchar *label; |
155 | static xmmsv_t *coll = NULL((void*)0); |
156 | |
157 | for (i = 0; i < columns; i++) { |
| 2 | | Assuming 'i' is < 'columns' | |
|
| 3 | | Loop condition is true. Entering loop body | |
|
| 7 | | Assuming 'i' is < 'columns' | |
|
| 8 | | Loop condition is true. Entering loop body | |
|
| 10 | | Assuming 'i' is >= 'columns' | |
|
| 11 | | Loop condition is false. Execution continues on line 170 | |
|
158 | if (!strcmp (col_names[i], "id")) { |
| 4 | | Assuming the condition is false | |
|
| |
| |
159 | id = atoi (col_strs[i]); |
160 | } else if (!strcmp (col_names[i], "type")) { |
| |
161 | type = atoi (col_strs[i]); |
162 | } else if (!strcmp (col_names[i], "nsid")) { |
163 | nsid = atoi (col_strs[i]); |
164 | } else if (!strcmp (col_names[i], "label")) { |
165 | label = col_strs[i]; |
166 | } |
167 | } |
168 | |
169 | |
170 | if (previd < 0 || id != previd) { |
171 | coll = xmms_collection_dbread_operator (info->db, id, type); |
172 | previd = id; |
173 | } |
174 | else { |
175 | xmmsv_ref (coll); |
176 | } |
177 | |
178 | g_hash_table_replace (info->ht[nsid], g_strdup (label), coll); |
| 12 | | Array subscript is undefined |
|
179 | |
180 | return 0; |
181 | } |
182 | |
183 | void |
184 | collection_restore (sqlite3 *db, GHashTable **ht) |
185 | { |
186 | const gchar *query; |
187 | struct db_info info; |
188 | |
189 | info.db = db; |
190 | info.ht = ht; |
191 | |
192 | |
193 | query = "SELECT op.id AS id, lbl.name AS label, " |
194 | " lbl.namespace AS nsid, op.type AS type " |
195 | "FROM CollectionOperators AS op, CollectionLabels as lbl " |
196 | "WHERE op.id=lbl.collid " |
197 | "ORDER BY id"; |
198 | sqlite3_exec (db, query, restore_callback, &info, NULL((void*)0)); |
199 | } |
200 | |
201 | static int |
202 | attribute_callback (void *userdata, int cols, char **col_strs, char **col_names) |
203 | { |
204 | xmmsv_t *coll = userdata; |
205 | const gchar *key, *value; |
206 | int i; |
207 | |
208 | for (i = 0; i < cols; i++) { |
209 | if (!strcmp (col_names[i], "key")) { |
210 | key = col_strs[i]; |
211 | } else if (!strcmp (col_names[i], "value")) { |
212 | value = col_strs[i]; |
213 | } |
214 | } |
215 | xmmsv_coll_attribute_set_string (coll, key, value); |
216 | |
217 | return 0; |
218 | } |
219 | static int |
220 | idlist_callback (void *userdata, int cols, char **col_strs, char **col_names) |
221 | { |
222 | xmmsv_t *coll = userdata; |
223 | int i; |
224 | |
225 | for (i = 0; i < cols; i++) { |
226 | if (!strcmp (col_names[i], "mid")) { |
227 | xmmsv_coll_idlist_append (coll, atoi (col_strs[i])); |
228 | } |
229 | } |
230 | |
231 | return 0; |
232 | } |
233 | static int |
234 | operator_callback (void *userdata, int cols, char **col_strs, char **col_names) |
235 | { |
236 | struct db_info *info = userdata; |
237 | xmmsv_t *coll = info->coll; |
238 | xmmsv_t *op; |
239 | int i; |
240 | gint id; |
241 | gint type; |
242 | |
243 | for (i = 0; i < cols; i++) { |
244 | if (!strcmp (col_names[i], "id")) { |
245 | id = atoi (col_strs[i]); |
246 | } else if (!strcmp (col_names[i], "type")) { |
247 | type = atoi (col_strs[i]); |
248 | } |
249 | } |
250 | |
251 | |
252 | op = xmms_collection_dbread_operator (info->db, id, type); |
253 | xmmsv_coll_add_operand (coll, op); |
254 | xmmsv_unref (op); |
255 | |
256 | return 0; |
257 | } |
258 | |
259 | static xmmsv_t * |
260 | xmms_collection_dbread_operator (sqlite3 *db, gint id, xmmsv_coll_type_t type) |
261 | { |
262 | xmmsv_t *coll; |
263 | gchar query[256]; |
264 | struct db_info info; |
265 | |
266 | coll = create_coll ((xmmsv_coll1_type_t) type); |
267 | |
268 | |
269 | g_snprintf (query, sizeof (query), |
270 | "SELECT attr.key AS key, attr.value AS value " |
271 | "FROM CollectionOperators AS op, CollectionAttributes AS attr " |
272 | "WHERE op.id=%d AND attr.collid=op.id", id); |
273 | |
274 | sqlite3_exec (db, query, attribute_callback, coll, NULL((void*)0)); |
275 | |
276 | |
277 | g_snprintf (query, sizeof (query), |
278 | "SELECT idl.mid AS mid " |
279 | "FROM CollectionOperators AS op, CollectionIdlists AS idl " |
280 | "WHERE op.id=%d AND idl.collid=op.id " |
281 | "ORDER BY idl.position", id); |
282 | |
283 | sqlite3_exec (db, query, idlist_callback, coll, NULL((void*)0)); |
284 | |
285 | |
286 | g_snprintf (query, sizeof (query), |
287 | "SELECT op.id AS id, op.type AS type " |
288 | "FROM CollectionOperators AS op, CollectionConnections AS conn " |
289 | "WHERE conn.to_id=%d AND conn.from_id=op.id", id); |
290 | |
291 | info.db = db; |
292 | info.coll = coll; |
293 | sqlite3_exec (db, query, operator_callback, &info, NULL((void*)0)); |
294 | |
295 | return augment_coll (coll); |
296 | } |