Mercurial > hg > xmms-sid
comparison src/xs_length.c @ 359:b1a858b8cb1a
Re-indentation all (non-generated) code.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Mon, 07 Nov 2005 09:50:04 +0000 |
parents | 961212302eb9 |
children | 4611f1194941 |
comparison
equal
deleted
inserted
replaced
358:4f247b19c9ea | 359:b1a858b8cb1a |
---|---|
31 | 31 |
32 /* Database handling functions | 32 /* Database handling functions |
33 */ | 33 */ |
34 static t_xs_sldb_node *xs_sldb_node_new(void) | 34 static t_xs_sldb_node *xs_sldb_node_new(void) |
35 { | 35 { |
36 t_xs_sldb_node *pResult; | 36 t_xs_sldb_node *pResult; |
37 | 37 |
38 /* Allocate memory for new node */ | 38 /* Allocate memory for new node */ |
39 pResult = (t_xs_sldb_node *) g_malloc0(sizeof(t_xs_sldb_node)); | 39 pResult = (t_xs_sldb_node *) g_malloc0(sizeof(t_xs_sldb_node)); |
40 if (!pResult) return NULL; | 40 if (!pResult) |
41 | 41 return NULL; |
42 return pResult; | 42 |
43 } | 43 return pResult; |
44 | 44 } |
45 | 45 |
46 static void xs_sldb_node_free(t_xs_sldb_node *pNode) | 46 |
47 { | 47 static void xs_sldb_node_free(t_xs_sldb_node * pNode) |
48 if (pNode) | 48 { |
49 { | 49 if (pNode) { |
50 /* Nothing much to do here ... */ | 50 /* Nothing much to do here ... */ |
51 g_free(pNode); | 51 g_free(pNode); |
52 } | 52 } |
53 } | 53 } |
54 | 54 |
55 | 55 |
56 /* Insert given node to db linked list | 56 /* Insert given node to db linked list |
57 */ | 57 */ |
58 static void xs_sldb_node_insert(t_xs_sldb *db, t_xs_sldb_node *pNode) | 58 static void xs_sldb_node_insert(t_xs_sldb * db, t_xs_sldb_node * pNode) |
59 { | 59 { |
60 assert(db); | 60 assert(db); |
61 | 61 |
62 if (db->pNodes) | 62 if (db->pNodes) { |
63 { | 63 /* The first node's pPrev points to last node */ |
64 /* The first node's pPrev points to last node */ | 64 LPREV = db->pNodes->pPrev; /* New node's prev = Previous last node */ |
65 LPREV = db->pNodes->pPrev; /* New node's prev = Previous last node */ | 65 db->pNodes->pPrev->pNext = pNode; /* Previous last node's next = New node */ |
66 db->pNodes->pPrev->pNext = pNode; /* Previous last node's next = New node */ | 66 db->pNodes->pPrev = pNode; /* New last node = New node */ |
67 db->pNodes->pPrev = pNode; /* New last node = New node */ | 67 LNEXT = NULL; /* But next is NULL! */ |
68 LNEXT = NULL; /* But next is NULL! */ | 68 } else { |
69 } else { | 69 db->pNodes = pNode; /* First node ... */ |
70 db->pNodes = pNode; /* First node ... */ | 70 LPREV = pNode; /* ... it's also last */ |
71 LPREV = pNode; /* ... it's also last */ | 71 LNEXT = NULL; /* But next is NULL! */ |
72 LNEXT = NULL; /* But next is NULL! */ | 72 } |
73 } | |
74 } | 73 } |
75 | 74 |
76 | 75 |
77 /* Parses a time-entry in SLDB format | 76 /* Parses a time-entry in SLDB format |
78 */ | 77 */ |
79 static gint32 xs_sldb_gettime(gchar *pcStr, size_t *piPos) | 78 static gint32 xs_sldb_gettime(gchar * pcStr, size_t * piPos) |
80 { | 79 { |
81 gint32 iResult, iTemp; | 80 gint32 iResult, iTemp; |
82 | 81 |
83 /* Check if it starts with a digit */ | 82 /* Check if it starts with a digit */ |
84 if (isdigit(pcStr[*piPos])) | 83 if (isdigit(pcStr[*piPos])) { |
85 { | 84 /* Get minutes-field */ |
86 /* Get minutes-field */ | 85 iResult = 0; |
87 iResult = 0; | 86 while (isdigit(pcStr[*piPos])) |
88 while (isdigit(pcStr[*piPos])) | 87 iResult = (iResult * 10) + (pcStr[(*piPos)++] - '0'); |
89 iResult = (iResult * 10) + (pcStr[(*piPos)++] - '0'); | 88 |
90 | 89 iResult *= 60; |
91 iResult *= 60; | 90 |
92 | 91 /* Check the field separator char */ |
93 /* Check the field separator char */ | 92 if (pcStr[*piPos] == ':') { |
94 if (pcStr[*piPos] == ':') | 93 /* Get seconds-field */ |
95 { | 94 (*piPos)++; |
96 /* Get seconds-field */ | 95 iTemp = 0; |
96 while (isdigit(pcStr[*piPos])) | |
97 iTemp = (iTemp * 10) + (pcStr[(*piPos)++] - '0'); | |
98 | |
99 iResult += iTemp; | |
100 } else | |
101 iResult = -2; | |
102 } else | |
103 iResult = -1; | |
104 | |
105 /* Ignore and skip the possible attributes */ | |
106 while (pcStr[*piPos] && !isspace(pcStr[*piPos])) | |
97 (*piPos)++; | 107 (*piPos)++; |
98 iTemp = 0; | 108 |
99 while (isdigit(pcStr[*piPos])) | 109 return iResult; |
100 iTemp = (iTemp * 10) + (pcStr[(*piPos)++] - '0'); | |
101 | |
102 iResult += iTemp; | |
103 } else | |
104 iResult = -2; | |
105 } else | |
106 iResult = -1; | |
107 | |
108 /* Ignore and skip the possible attributes */ | |
109 while (pcStr[*piPos] && !isspace(pcStr[*piPos])) (*piPos)++; | |
110 | |
111 return iResult; | |
112 } | 110 } |
113 | 111 |
114 | 112 |
115 /* Read database to memory | 113 /* Read database to memory |
116 */ | 114 */ |
117 gint xs_sldb_read(t_xs_sldb *db, gchar *dbFilename) | 115 gint xs_sldb_read(t_xs_sldb * db, gchar * dbFilename) |
118 { | 116 { |
119 FILE *inFile; | 117 FILE *inFile; |
120 gchar inLine[XS_BUF_SIZE]; | 118 gchar inLine[XS_BUF_SIZE]; |
121 size_t lineNum, linePos; | 119 size_t lineNum, linePos; |
122 gboolean iOK; | 120 gboolean iOK; |
123 t_xs_sldb_node *tmpNode; | 121 t_xs_sldb_node *tmpNode; |
124 assert(db); | 122 assert(db); |
125 | 123 |
126 /* Try to open the file */ | 124 /* Try to open the file */ |
127 if ((inFile = fopen(dbFilename, "ra")) == NULL) | 125 if ((inFile = fopen(dbFilename, "ra")) == NULL) { |
128 { | 126 XSERR("Could not open SongLengthDB '%s'\n", dbFilename); |
129 XSERR("Could not open SongLengthDB '%s'\n", dbFilename); | 127 return -1; |
130 return -1; | 128 } |
131 } | 129 |
132 | 130 /* Read and parse the data */ |
133 /* Read and parse the data */ | 131 lineNum = 0; |
134 lineNum = 0; | 132 |
135 | 133 while (!feof(inFile)) { |
136 while (!feof(inFile)) | 134 fgets(inLine, XS_BUF_SIZE, inFile); |
137 { | 135 inLine[XS_BUF_SIZE - 1] = 0; |
138 fgets(inLine, XS_BUF_SIZE, inFile); | 136 lineNum++; |
139 inLine[XS_BUF_SIZE-1] = 0; | 137 |
140 lineNum++; | 138 /* Check if it is datafield */ |
141 | 139 if (isxdigit(inLine[0])) { |
142 /* Check if it is datafield */ | 140 /* Check the length of the hash */ |
143 if (isxdigit(inLine[0])) | 141 linePos = 0; |
144 { | 142 while (isxdigit(inLine[linePos])) |
145 /* Check the length of the hash */ | 143 linePos++; |
146 linePos = 0; | 144 |
147 while (isxdigit(inLine[linePos])) linePos++; | 145 if (linePos != XS_MD5HASH_LENGTH_CH) { |
148 | 146 XSERR("Invalid hash in SongLengthDB file '%s' line #%d!\n", dbFilename, lineNum); |
149 if (linePos != XS_MD5HASH_LENGTH_CH) | 147 } else { |
150 { | 148 /* Allocate new node */ |
151 XSERR("Invalid hash in SongLengthDB file '%s' line #%d!\n", | 149 if ((tmpNode = xs_sldb_node_new()) == NULL) { |
152 dbFilename, lineNum); | 150 XSERR("Error allocating new node. Fatal error.\n"); |
153 } else { | 151 exit(5); |
154 /* Allocate new node */ | 152 } |
155 if ((tmpNode = xs_sldb_node_new()) == NULL) | 153 |
156 { | 154 /* Get hash value */ |
157 XSERR("Error allocating new node. Fatal error.\n"); | |
158 exit(5); | |
159 } | |
160 | |
161 /* Get hash value */ | |
162 #if (XS_MD5HASH_LENGTH != 16) | 155 #if (XS_MD5HASH_LENGTH != 16) |
163 #error Mismatch in hashcode length. Fix here. | 156 #error Mismatch in hashcode length. Fix here. |
164 #endif | 157 #endif |
165 sscanf(&inLine[0], "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x", | 158 sscanf(&inLine[0], "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x", |
166 (guint *) &(tmpNode->md5Hash[0]), (guint *) &(tmpNode->md5Hash[1]), | 159 (guint *) & (tmpNode->md5Hash[0]), (guint *) & (tmpNode->md5Hash[1]), |
167 (guint *) &(tmpNode->md5Hash[2]), (guint *) &(tmpNode->md5Hash[3]), | 160 (guint *) & (tmpNode->md5Hash[2]), (guint *) & (tmpNode->md5Hash[3]), |
168 (guint *) &(tmpNode->md5Hash[4]), (guint *) &(tmpNode->md5Hash[5]), | 161 (guint *) & (tmpNode->md5Hash[4]), (guint *) & (tmpNode->md5Hash[5]), |
169 (guint *) &(tmpNode->md5Hash[6]), (guint *) &(tmpNode->md5Hash[7]), | 162 (guint *) & (tmpNode->md5Hash[6]), (guint *) & (tmpNode->md5Hash[7]), |
170 (guint *) &(tmpNode->md5Hash[8]), (guint *) &(tmpNode->md5Hash[9]), | 163 (guint *) & (tmpNode->md5Hash[8]), (guint *) & (tmpNode->md5Hash[9]), |
171 (guint *) &(tmpNode->md5Hash[10]), (guint *) &(tmpNode->md5Hash[11]), | 164 (guint *) & (tmpNode->md5Hash[10]), (guint *) & (tmpNode->md5Hash[11]), |
172 (guint *) &(tmpNode->md5Hash[12]), (guint *) &(tmpNode->md5Hash[13]), | 165 (guint *) & (tmpNode->md5Hash[12]), (guint *) & (tmpNode->md5Hash[13]), |
173 (guint *) &(tmpNode->md5Hash[14]), (guint *) &(tmpNode->md5Hash[15])); | 166 (guint *) & (tmpNode->md5Hash[14]), (guint *) & (tmpNode->md5Hash[15])); |
174 | 167 |
175 /* Get playtimes */ | 168 /* Get playtimes */ |
176 if (inLine[linePos] != 0) | 169 if (inLine[linePos] != 0) { |
177 { | 170 if (inLine[linePos] != '=') { |
178 if (inLine[linePos] != '=') | 171 XSERR("'=' expected in SongLengthDB file '%s' line #%d, column #%d\n", |
179 { | 172 dbFilename, lineNum, linePos); |
180 XSERR("'=' expected in SongLengthDB file '%s' line #%d, column #%d\n", | 173 |
181 dbFilename, lineNum, linePos); | 174 xs_sldb_node_free(tmpNode); |
182 | 175 } else { |
183 xs_sldb_node_free(tmpNode); | 176 /* First playtime is after '=' */ |
184 } else { | 177 linePos++; |
185 /* First playtime is after '=' */ | 178 iOK = TRUE; |
186 linePos++; | 179 |
187 iOK = TRUE; | 180 while ((linePos < strlen(inLine)) && iOK) { |
188 | 181 xs_findnext(inLine, &linePos); |
189 while ((linePos < strlen(inLine)) && iOK) | 182 |
190 { | 183 if (tmpNode->nLengths < XS_STIL_MAXENTRY) { |
191 xs_findnext(inLine, &linePos); | 184 tmpNode->sLengths[tmpNode->nLengths] = |
192 | 185 xs_sldb_gettime(inLine, &linePos); |
193 if (tmpNode->nLengths < XS_STIL_MAXENTRY) | 186 tmpNode->nLengths++; |
194 { | 187 } else |
195 tmpNode->sLengths[tmpNode->nLengths] = | 188 iOK = FALSE; |
196 xs_sldb_gettime(inLine, &linePos); | 189 } |
197 tmpNode->nLengths++; | 190 |
198 } else | 191 /* Add an node to db in memory */ |
199 iOK = FALSE; | 192 if (iOK) |
193 xs_sldb_node_insert(db, tmpNode); | |
194 else | |
195 xs_sldb_node_free(tmpNode); | |
196 } | |
197 } | |
200 } | 198 } |
201 | 199 } else if ((inLine[0] != ';') && (inLine[0] != '[')) { |
202 /* Add an node to db in memory */ | 200 XSERR("Invalid line in SongLengthDB file '%s' line #%d\n", dbFilename, lineNum); |
203 if (iOK) | |
204 xs_sldb_node_insert(db, tmpNode); | |
205 else | |
206 xs_sldb_node_free(tmpNode); | |
207 } | 201 } |
208 } | 202 |
209 } | 203 } /* while */ |
210 } else | 204 |
211 if ((inLine[0] != ';') && (inLine[0] != '[')) | 205 /* Close the file */ |
212 { | 206 fclose(inFile); |
213 XSERR("Invalid line in SongLengthDB file '%s' line #%d\n", | 207 |
214 dbFilename, lineNum); | 208 return 0; |
215 } | |
216 | |
217 } /* while */ | |
218 | |
219 /* Close the file */ | |
220 fclose(inFile); | |
221 | |
222 return 0; | |
223 } | 209 } |
224 | 210 |
225 | 211 |
226 /* Compare two given MD5-hashes. | 212 /* Compare two given MD5-hashes. |
227 * Return: 0 if equal | 213 * Return: 0 if equal |
228 * negative if testHash1 < testHash2 | 214 * negative if testHash1 < testHash2 |
229 * positive if testHash1 > testHash2 | 215 * positive if testHash1 > testHash2 |
230 */ | 216 */ |
231 static gint xs_sldb_cmphash(t_xs_md5hash testHash1, t_xs_md5hash testHash2) | 217 static gint xs_sldb_cmphash(t_xs_md5hash testHash1, t_xs_md5hash testHash2) |
232 { | 218 { |
233 register gint i, res = 0; | 219 register gint i, res = 0; |
234 | 220 |
235 /* Compute difference of hashes */ | 221 /* Compute difference of hashes */ |
236 for (i = 0; (i < XS_MD5HASH_LENGTH) && (!res); i++) | 222 for (i = 0; (i < XS_MD5HASH_LENGTH) && (!res); i++) |
237 res = (testHash1[i] - testHash2[i]); | 223 res = (testHash1[i] - testHash2[i]); |
238 | 224 |
239 return res; | 225 return res; |
240 } | 226 } |
241 | 227 |
242 | 228 |
243 /* Get node from db index via binary search | 229 /* Get node from db index via binary search |
244 */ | 230 */ |
245 static t_xs_sldb_node * xs_sldb_get_node(t_xs_sldb *db, t_xs_md5hash pHash) | 231 static t_xs_sldb_node *xs_sldb_get_node(t_xs_sldb * db, t_xs_md5hash pHash) |
246 { | 232 { |
247 gint iStartNode, iEndNode, iQNode, r, i; | 233 gint iStartNode, iEndNode, iQNode, r, i; |
248 gboolean iFound; | 234 gboolean iFound; |
249 t_xs_sldb_node *pResult; | 235 t_xs_sldb_node *pResult; |
250 | 236 |
251 /* Check the database pointers */ | 237 /* Check the database pointers */ |
252 if (!db || !db->pNodes || !db->ppIndex) | 238 if (!db || !db->pNodes || !db->ppIndex) |
253 return NULL; | 239 return NULL; |
254 | 240 |
255 /* Look-up via index using binary search */ | 241 /* Look-up via index using binary search */ |
256 pResult = NULL; | 242 pResult = NULL; |
257 iStartNode = 0; | 243 iStartNode = 0; |
258 iEndNode = (db->n - 1); | 244 iEndNode = (db->n - 1); |
259 iQNode = (iEndNode / 2); | 245 iQNode = (iEndNode / 2); |
260 iFound = FALSE; | |
261 | |
262 while ((!iFound) && ((iEndNode - iStartNode) > 128)) | |
263 { | |
264 r = xs_sldb_cmphash(pHash, db->ppIndex[iQNode]->md5Hash); | |
265 if (r < 0) | |
266 { | |
267 /* Hash was in the <- LEFT side */ | |
268 iEndNode = iQNode; | |
269 iQNode = iStartNode + ((iEndNode - iStartNode) / 2); | |
270 } else | |
271 if (r > 0) | |
272 { | |
273 /* Hash was in the RIGHT -> side */ | |
274 iStartNode = iQNode; | |
275 iQNode = iStartNode + ((iEndNode - iStartNode) / 2); | |
276 } else | |
277 iFound = TRUE; | |
278 } | |
279 | |
280 /* If not found already */ | |
281 if (!iFound) | |
282 { | |
283 /* Search the are linearly */ | |
284 iFound = FALSE; | 246 iFound = FALSE; |
285 i = iStartNode; | 247 |
286 while ((i <= iEndNode) && (!iFound)) | 248 while ((!iFound) && ((iEndNode - iStartNode) > 128)) { |
287 { | 249 r = xs_sldb_cmphash(pHash, db->ppIndex[iQNode]->md5Hash); |
288 if (xs_sldb_cmphash(pHash, db->ppIndex[i]->md5Hash) == 0) | 250 if (r < 0) { |
251 /* Hash was in the <- LEFT side */ | |
252 iEndNode = iQNode; | |
253 iQNode = iStartNode + ((iEndNode - iStartNode) / 2); | |
254 } else if (r > 0) { | |
255 /* Hash was in the RIGHT -> side */ | |
256 iStartNode = iQNode; | |
257 iQNode = iStartNode + ((iEndNode - iStartNode) / 2); | |
258 } else | |
289 iFound = TRUE; | 259 iFound = TRUE; |
260 } | |
261 | |
262 /* If not found already */ | |
263 if (!iFound) { | |
264 /* Search the are linearly */ | |
265 iFound = FALSE; | |
266 i = iStartNode; | |
267 while ((i <= iEndNode) && (!iFound)) { | |
268 if (xs_sldb_cmphash(pHash, db->ppIndex[i]->md5Hash) == 0) | |
269 iFound = TRUE; | |
290 else | 270 else |
291 i++; | 271 i++; |
292 } | 272 } |
293 | 273 |
294 /* Check the result */ | 274 /* Check the result */ |
295 if (iFound) | 275 if (iFound) |
296 pResult = db->ppIndex[i]; | 276 pResult = db->ppIndex[i]; |
297 | 277 |
298 } else { | 278 } else { |
299 /* Found via binary search */ | 279 /* Found via binary search */ |
300 pResult = db->ppIndex[iQNode]; | 280 pResult = db->ppIndex[iQNode]; |
301 } | 281 } |
302 | 282 |
303 return pResult; | 283 return pResult; |
304 } | 284 } |
305 | 285 |
306 | 286 |
307 /* Compare two nodes | 287 /* Compare two nodes |
308 */ | 288 */ |
309 static gint xs_sldb_cmp(const void *pNode1, const void *pNode2) | 289 static gint xs_sldb_cmp(const void *pNode1, const void *pNode2) |
310 { | 290 { |
311 /* We assume here that we never ever get NULL-pointers or similar */ | 291 /* We assume here that we never ever get NULL-pointers or similar */ |
312 return xs_sldb_cmphash((*(t_xs_sldb_node **) pNode1)->md5Hash, | 292 return xs_sldb_cmphash((*(t_xs_sldb_node **) pNode1)->md5Hash, (*(t_xs_sldb_node **) pNode2)->md5Hash); |
313 (*(t_xs_sldb_node **) pNode2)->md5Hash); | |
314 } | 293 } |
315 | 294 |
316 | 295 |
317 /* (Re)create index | 296 /* (Re)create index |
318 */ | 297 */ |
319 gint xs_sldb_index(t_xs_sldb *db) | 298 gint xs_sldb_index(t_xs_sldb * db) |
320 { | 299 { |
321 t_xs_sldb_node *pCurr; | 300 t_xs_sldb_node *pCurr; |
322 gint i; | 301 gint i; |
323 assert(db); | 302 assert(db); |
324 | 303 |
325 /* Free old index */ | 304 /* Free old index */ |
326 if (db->ppIndex) | 305 if (db->ppIndex) { |
327 { | 306 g_free(db->ppIndex); |
328 g_free(db->ppIndex); | 307 db->ppIndex = NULL; |
329 db->ppIndex = NULL; | 308 } |
330 } | 309 |
331 | 310 /* Get size of db */ |
332 /* Get size of db */ | |
333 pCurr = db->pNodes; | |
334 db->n = 0; | |
335 while (pCurr) | |
336 { | |
337 db->n++; | |
338 pCurr = pCurr->pNext; | |
339 } | |
340 | |
341 /* Check number of nodes */ | |
342 if (db->n > 0) | |
343 { | |
344 /* Allocate memory for index-table */ | |
345 db->ppIndex = (t_xs_sldb_node **) g_malloc(sizeof(t_xs_sldb_node *) * db->n); | |
346 if (!db->ppIndex) return -1; | |
347 | |
348 /* Get node-pointers to table */ | |
349 i = 0; | |
350 pCurr = db->pNodes; | 311 pCurr = db->pNodes; |
351 while (pCurr && (i < db->n)) | 312 db->n = 0; |
352 { | 313 while (pCurr) { |
353 db->ppIndex[i++] = pCurr; | 314 db->n++; |
354 pCurr = pCurr->pNext; | 315 pCurr = pCurr->pNext; |
316 } | |
317 | |
318 /* Check number of nodes */ | |
319 if (db->n > 0) { | |
320 /* Allocate memory for index-table */ | |
321 db->ppIndex = (t_xs_sldb_node **) g_malloc(sizeof(t_xs_sldb_node *) * db->n); | |
322 if (!db->ppIndex) | |
323 return -1; | |
324 | |
325 /* Get node-pointers to table */ | |
326 i = 0; | |
327 pCurr = db->pNodes; | |
328 while (pCurr && (i < db->n)) { | |
329 db->ppIndex[i++] = pCurr; | |
330 pCurr = pCurr->pNext; | |
355 } | 331 } |
356 | 332 |
357 /* Sort the indexes */ | 333 /* Sort the indexes */ |
358 qsort(db->ppIndex, db->n, sizeof(t_xs_sldb_node *), xs_sldb_cmp); | 334 qsort(db->ppIndex, db->n, sizeof(t_xs_sldb_node *), xs_sldb_cmp); |
359 } | 335 } |
360 | 336 |
361 return 0; | 337 return 0; |
362 } | 338 } |
363 | 339 |
364 | 340 |
365 /* Free a given song-length database | 341 /* Free a given song-length database |
366 */ | 342 */ |
367 void xs_sldb_free(t_xs_sldb *db) | 343 void xs_sldb_free(t_xs_sldb * db) |
368 { | 344 { |
369 t_xs_sldb_node *pCurr, *pNext; | 345 t_xs_sldb_node *pCurr, *pNext; |
370 | 346 |
371 if (!db) return; | 347 if (!db) |
372 | 348 return; |
373 /* Free the memory allocated for nodes */ | 349 |
374 pCurr = db->pNodes; | 350 /* Free the memory allocated for nodes */ |
375 while (pCurr) | 351 pCurr = db->pNodes; |
376 { | 352 while (pCurr) { |
377 pNext = pCurr->pNext; | 353 pNext = pCurr->pNext; |
378 xs_sldb_node_free(pCurr); | 354 xs_sldb_node_free(pCurr); |
379 pCurr = pNext; | 355 pCurr = pNext; |
380 } | 356 } |
381 | 357 |
382 db->pNodes = NULL; | 358 db->pNodes = NULL; |
383 | 359 |
384 /* Free memory allocated for index */ | 360 /* Free memory allocated for index */ |
385 if (db->ppIndex) | 361 if (db->ppIndex) { |
386 { | 362 g_free(db->ppIndex); |
387 g_free(db->ppIndex); | 363 db->ppIndex = NULL; |
388 db->ppIndex = NULL; | 364 } |
389 } | 365 |
390 | 366 /* Free structure */ |
391 /* Free structure */ | 367 db->n = 0; |
392 db->n = 0; | 368 g_free(db); |
393 g_free(db); | |
394 } | 369 } |
395 | 370 |
396 | 371 |
397 /* Compute md5hash of given SID-file | 372 /* Compute md5hash of given SID-file |
398 */ | 373 */ |
399 typedef struct { | 374 typedef struct |
400 gchar magicID[4]; /* "PSID" / "RSID" magic identifier */ | 375 { |
401 guint16 version, /* Version number */ | 376 gchar magicID[4]; /* "PSID" / "RSID" magic identifier */ |
402 dataOffset, /* Start of actual c64 data in file */ | 377 guint16 version, /* Version number */ |
403 loadAddress, /* Loading address */ | 378 dataOffset, /* Start of actual c64 data in file */ |
404 initAddress, /* Initialization address */ | 379 loadAddress, /* Loading address */ |
405 playAddress, /* Play one frame */ | 380 initAddress, /* Initialization address */ |
406 nSongs, /* Number of subsongs */ | 381 playAddress, /* Play one frame */ |
407 startSong; /* Default starting song */ | 382 nSongs, /* Number of subsongs */ |
408 guint32 speed; /* Speed */ | 383 startSong; /* Default starting song */ |
409 gchar sidName[32]; /* Descriptive text-fields, ASCIIZ */ | 384 guint32 speed; /* Speed */ |
410 gchar sidAuthor[32]; | 385 gchar sidName[32]; /* Descriptive text-fields, ASCIIZ */ |
411 gchar sidCopyright[32]; | 386 gchar sidAuthor[32]; |
387 gchar sidCopyright[32]; | |
412 } t_xs_psidv1_header; | 388 } t_xs_psidv1_header; |
413 | 389 |
414 | 390 |
415 typedef struct { | 391 typedef struct |
416 guint16 flags; /* Flags */ | 392 { |
417 guint8 startPage, | 393 guint16 flags; /* Flags */ |
418 pageLength; | 394 guint8 startPage, pageLength; |
419 guint16 reserved; | 395 guint16 reserved; |
420 } t_xs_psidv2_header; | 396 } t_xs_psidv2_header; |
421 | 397 |
422 | 398 |
423 static gint xs_get_sid_hash(gchar *pcFilename, t_xs_md5hash hash) | 399 static gint xs_get_sid_hash(gchar * pcFilename, t_xs_md5hash hash) |
424 { | 400 { |
425 FILE *inFile; | 401 FILE *inFile; |
426 t_xs_md5state inState; | 402 t_xs_md5state inState; |
427 t_xs_psidv1_header psidH; | 403 t_xs_psidv1_header psidH; |
428 t_xs_psidv2_header psidH2; | 404 t_xs_psidv2_header psidH2; |
429 #ifdef XS_BUF_DYNAMIC | 405 #ifdef XS_BUF_DYNAMIC |
430 guint8 *songData; | 406 guint8 *songData; |
431 #else | 407 #else |
432 guint8 songData[XS_SIDBUF_SIZE]; | 408 guint8 songData[XS_SIDBUF_SIZE]; |
433 #endif | 409 #endif |
434 guint8 ib8[2], i8; | 410 guint8 ib8[2], i8; |
435 gint iIndex, iRes; | 411 gint iIndex, iRes; |
436 | 412 |
437 /* Try to open the file */ | 413 /* Try to open the file */ |
438 if ((inFile = fopen(pcFilename, "rb")) == NULL) | 414 if ((inFile = fopen(pcFilename, "rb")) == NULL) |
439 return -1; | 415 return -1; |
440 | 416 |
441 /* Read PSID header in */ | 417 /* Read PSID header in */ |
442 xs_rd_str(inFile, psidH.magicID, sizeof(psidH.magicID)); | 418 xs_rd_str(inFile, psidH.magicID, sizeof(psidH.magicID)); |
443 if ((psidH.magicID[0] != 'P' && psidH.magicID[0] != 'R') || | 419 if ((psidH.magicID[0] != 'P' && psidH.magicID[0] != 'R') || |
444 (psidH.magicID[1] != 'S') || (psidH.magicID[2] != 'I') || (psidH.magicID[3] != 'D')) | 420 (psidH.magicID[1] != 'S') || (psidH.magicID[2] != 'I') || (psidH.magicID[3] != 'D')) { |
445 { | 421 fclose(inFile); |
446 fclose(inFile); | 422 return -2; |
447 return -2; | 423 } |
448 } | 424 |
449 | 425 psidH.version = xs_rd_be16(inFile); |
450 psidH.version = xs_rd_be16(inFile); | 426 psidH.dataOffset = xs_rd_be16(inFile); |
451 psidH.dataOffset = xs_rd_be16(inFile); | 427 psidH.loadAddress = xs_rd_be16(inFile); |
452 psidH.loadAddress = xs_rd_be16(inFile); | 428 psidH.initAddress = xs_rd_be16(inFile); |
453 psidH.initAddress = xs_rd_be16(inFile); | 429 psidH.playAddress = xs_rd_be16(inFile); |
454 psidH.playAddress = xs_rd_be16(inFile); | 430 psidH.nSongs = xs_rd_be16(inFile); |
455 psidH.nSongs = xs_rd_be16(inFile); | 431 psidH.startSong = xs_rd_be16(inFile); |
456 psidH.startSong = xs_rd_be16(inFile); | 432 psidH.speed = xs_rd_be32(inFile); |
457 psidH.speed = xs_rd_be32(inFile); | 433 |
458 | 434 xs_rd_str(inFile, psidH.sidName, sizeof(psidH.sidName)); |
459 xs_rd_str(inFile, psidH.sidName, sizeof(psidH.sidName)); | 435 xs_rd_str(inFile, psidH.sidAuthor, sizeof(psidH.sidAuthor)); |
460 xs_rd_str(inFile, psidH.sidAuthor, sizeof(psidH.sidAuthor)); | 436 xs_rd_str(inFile, psidH.sidCopyright, sizeof(psidH.sidCopyright)); |
461 xs_rd_str(inFile, psidH.sidCopyright, sizeof(psidH.sidCopyright)); | 437 |
462 | 438 /* Check if we need to load PSIDv2NG header ... */ |
463 /* Check if we need to load PSIDv2NG header ... */ | 439 if (psidH.version == 2) { |
464 if (psidH.version == 2) | 440 /* Yes, we need to */ |
465 { | 441 psidH2.flags = xs_rd_be16(inFile); |
466 /* Yes, we need to */ | 442 psidH2.startPage = fgetc(inFile); |
467 psidH2.flags = xs_rd_be16(inFile); | 443 psidH2.pageLength = fgetc(inFile); |
468 psidH2.startPage = fgetc(inFile); | 444 psidH2.reserved = xs_rd_be16(inFile); |
469 psidH2.pageLength = fgetc(inFile); | 445 } |
470 psidH2.reserved = xs_rd_be16(inFile); | |
471 } | |
472 | |
473 #ifdef XS_BUF_DYNAMIC | 446 #ifdef XS_BUF_DYNAMIC |
474 /* Allocate buffer */ | 447 /* Allocate buffer */ |
475 songData = (guint8 *) g_malloc(XS_SIDBUF_SIZE * sizeof(guint8)); | 448 songData = (guint8 *) g_malloc(XS_SIDBUF_SIZE * sizeof(guint8)); |
476 if (!songData) | 449 if (!songData) { |
477 { | 450 fclose(inFile); |
478 fclose(inFile); | 451 return -3; |
479 return -3; | 452 } |
480 } | |
481 #endif | 453 #endif |
482 | 454 |
483 /* Read data to buffer */ | 455 /* Read data to buffer */ |
484 iRes = fread(songData, sizeof(guint8), XS_SIDBUF_SIZE, inFile); | 456 iRes = fread(songData, sizeof(guint8), XS_SIDBUF_SIZE, inFile); |
485 fclose(inFile); | 457 fclose(inFile); |
486 | 458 |
487 /* Initialize and start MD5-hash calculation */ | 459 /* Initialize and start MD5-hash calculation */ |
488 xs_md5_init(&inState); | 460 xs_md5_init(&inState); |
489 if (psidH.loadAddress == 0) | 461 if (psidH.loadAddress == 0) { |
490 { | 462 /* Strip load address (2 first bytes) */ |
491 /* Strip load address (2 first bytes) */ | 463 xs_md5_append(&inState, &songData[2], iRes - 2); |
492 xs_md5_append(&inState, &songData[2], iRes-2); | |
493 } else { | 464 } else { |
494 /* Append "as is" */ | 465 /* Append "as is" */ |
495 xs_md5_append(&inState, songData, iRes); | 466 xs_md5_append(&inState, songData, iRes); |
496 } | 467 } |
497 | 468 |
498 | 469 |
499 #ifdef XS_BUF_DYNAMIC | 470 #ifdef XS_BUF_DYNAMIC |
500 /* Free buffer */ | 471 /* Free buffer */ |
501 g_free(songData); | 472 g_free(songData); |
502 #endif | 473 #endif |
503 | 474 |
504 /* Append header data to hash */ | 475 /* Append header data to hash */ |
505 #define XSADDHASH(QDATAB) { ib8[0] = (QDATAB & 0xff); ib8[1] = (QDATAB >> 8); xs_md5_append(&inState, (guint8 *) &ib8, sizeof(ib8)); } | 476 #define XSADDHASH(QDATAB) { ib8[0] = (QDATAB & 0xff); ib8[1] = (QDATAB >> 8); xs_md5_append(&inState, (guint8 *) &ib8, sizeof(ib8)); } |
506 | 477 |
507 XSADDHASH(psidH.initAddress) | 478 XSADDHASH(psidH.initAddress) |
508 XSADDHASH(psidH.playAddress) | 479 XSADDHASH(psidH.playAddress) |
509 XSADDHASH(psidH.nSongs) | 480 XSADDHASH(psidH.nSongs) |
510 | |
511 #undef XSADDHASH | 481 #undef XSADDHASH |
512 | 482 /* Append song speed data to hash */ |
513 /* Append song speed data to hash */ | 483 i8 = 0; |
514 i8 = 0; | 484 for (iIndex = 0; (iIndex < psidH.nSongs) && (iIndex < 32); iIndex++) { |
515 for (iIndex = 0; (iIndex < psidH.nSongs) && (iIndex < 32); iIndex++) | 485 i8 = (psidH.speed & (1 << iIndex)) ? 60 : 0; |
516 { | |
517 i8 = (psidH.speed & (1 << iIndex)) ? 60 : 0; | |
518 xs_md5_append(&inState, &i8, sizeof(i8)); | |
519 } | |
520 | |
521 /* Rest of songs (more than 32) */ | |
522 for (iIndex = 32; iIndex < psidH.nSongs; iIndex++) | |
523 { | |
524 xs_md5_append(&inState, &i8, sizeof(i8)); | |
525 } | |
526 | |
527 | |
528 /* PSIDv2NG specific */ | |
529 if (psidH.version == 2) | |
530 { | |
531 /* SEE SIDPLAY HEADERS FOR INFO */ | |
532 i8 = (psidH2.flags >> 2) & 3; | |
533 if (i8 == 2) | |
534 xs_md5_append(&inState, &i8, sizeof(i8)); | 486 xs_md5_append(&inState, &i8, sizeof(i8)); |
535 } | 487 } |
536 | 488 |
537 /* Calculate the hash */ | 489 /* Rest of songs (more than 32) */ |
538 xs_md5_finish(&inState, hash); | 490 for (iIndex = 32; iIndex < psidH.nSongs; iIndex++) { |
539 | 491 xs_md5_append(&inState, &i8, sizeof(i8)); |
540 return 0; | 492 } |
493 | |
494 | |
495 /* PSIDv2NG specific */ | |
496 if (psidH.version == 2) { | |
497 /* SEE SIDPLAY HEADERS FOR INFO */ | |
498 i8 = (psidH2.flags >> 2) & 3; | |
499 if (i8 == 2) | |
500 xs_md5_append(&inState, &i8, sizeof(i8)); | |
501 } | |
502 | |
503 /* Calculate the hash */ | |
504 xs_md5_finish(&inState, hash); | |
505 | |
506 return 0; | |
541 } | 507 } |
542 | 508 |
543 | 509 |
544 /* Get song lengths | 510 /* Get song lengths |
545 */ | 511 */ |
546 t_xs_sldb_node * xs_sldb_get(t_xs_sldb *db, gchar *pcFilename) | 512 t_xs_sldb_node *xs_sldb_get(t_xs_sldb * db, gchar * pcFilename) |
547 { | 513 { |
548 t_xs_sldb_node *pResult; | 514 t_xs_sldb_node *pResult; |
549 t_xs_md5hash dbHash; | 515 t_xs_md5hash dbHash; |
550 | 516 |
551 /* Get the hash and then look up from db */ | 517 /* Get the hash and then look up from db */ |
552 if (xs_get_sid_hash(pcFilename, dbHash) == 0) | 518 if (xs_get_sid_hash(pcFilename, dbHash) == 0) |
553 pResult = xs_sldb_get_node(db, dbHash); | 519 pResult = xs_sldb_get_node(db, dbHash); |
554 else | 520 else |
555 pResult = NULL; | 521 pResult = NULL; |
556 | 522 |
557 return pResult; | 523 return pResult; |
558 } | 524 } |
559 | 525 |
560 | 526 |
561 /* | 527 /* |
562 * These should be moved out of this module some day ... | 528 * These should be moved out of this module some day ... |
563 */ | 529 */ |
564 static t_xs_sldb *xs_sldb_db = NULL; | 530 static t_xs_sldb *xs_sldb_db = NULL; |
565 XS_MUTEX(xs_sldb_db); | 531 XS_MUTEX(xs_sldb_db); |
566 | 532 |
567 gint xs_songlen_init(void) | 533 gint xs_songlen_init(void) |
568 { | 534 { |
569 XS_MUTEX_LOCK(xs_cfg); | 535 XS_MUTEX_LOCK(xs_cfg); |
570 | 536 |
571 if (!xs_cfg.songlenDBPath) | 537 if (!xs_cfg.songlenDBPath) { |
572 { | 538 XS_MUTEX_UNLOCK(xs_cfg); |
573 XS_MUTEX_UNLOCK(xs_cfg); | 539 return -1; |
574 return -1; | 540 } |
575 } | 541 |
576 | 542 XS_MUTEX_LOCK(xs_sldb_db); |
577 XS_MUTEX_LOCK(xs_sldb_db); | 543 |
578 | 544 /* Check if already initialized */ |
579 /* Check if already initialized */ | 545 if (xs_sldb_db) |
580 if (xs_sldb_db) xs_sldb_free(xs_sldb_db); | 546 xs_sldb_free(xs_sldb_db); |
581 | 547 |
582 /* Allocate database */ | 548 /* Allocate database */ |
583 xs_sldb_db = (t_xs_sldb *) g_malloc0(sizeof(t_xs_sldb)); | 549 xs_sldb_db = (t_xs_sldb *) g_malloc0(sizeof(t_xs_sldb)); |
584 if (!xs_sldb_db) | 550 if (!xs_sldb_db) { |
585 { | 551 XS_MUTEX_UNLOCK(xs_cfg); |
586 XS_MUTEX_UNLOCK(xs_cfg); | 552 XS_MUTEX_UNLOCK(xs_sldb_db); |
587 XS_MUTEX_UNLOCK(xs_sldb_db); | 553 return -2; |
588 return -2; | 554 } |
589 } | 555 |
590 | 556 /* Read the database */ |
591 /* Read the database */ | 557 if (xs_sldb_read(xs_sldb_db, xs_cfg.songlenDBPath) != 0) { |
592 if (xs_sldb_read(xs_sldb_db, xs_cfg.songlenDBPath) != 0) | 558 xs_sldb_free(xs_sldb_db); |
593 { | 559 xs_sldb_db = NULL; |
594 xs_sldb_free(xs_sldb_db); | 560 XS_MUTEX_UNLOCK(xs_cfg); |
595 xs_sldb_db = NULL; | 561 XS_MUTEX_UNLOCK(xs_sldb_db); |
596 XS_MUTEX_UNLOCK(xs_cfg); | 562 return -3; |
597 XS_MUTEX_UNLOCK(xs_sldb_db); | 563 } |
598 return -3; | 564 |
599 } | 565 /* Create index */ |
600 | 566 if (xs_sldb_index(xs_sldb_db) != 0) { |
601 /* Create index */ | 567 xs_sldb_free(xs_sldb_db); |
602 if (xs_sldb_index(xs_sldb_db) != 0) | 568 xs_sldb_db = NULL; |
603 { | 569 XS_MUTEX_UNLOCK(xs_cfg); |
604 xs_sldb_free(xs_sldb_db); | 570 XS_MUTEX_UNLOCK(xs_sldb_db); |
605 xs_sldb_db = NULL; | 571 return -4; |
606 XS_MUTEX_UNLOCK(xs_cfg); | 572 } |
607 XS_MUTEX_UNLOCK(xs_sldb_db); | 573 |
608 return -4; | 574 XS_MUTEX_UNLOCK(xs_cfg); |
609 } | 575 XS_MUTEX_UNLOCK(xs_sldb_db); |
610 | 576 return 0; |
611 XS_MUTEX_UNLOCK(xs_cfg); | |
612 XS_MUTEX_UNLOCK(xs_sldb_db); | |
613 return 0; | |
614 } | 577 } |
615 | 578 |
616 | 579 |
617 void xs_songlen_close(void) | 580 void xs_songlen_close(void) |
618 { | 581 { |
619 XS_MUTEX_LOCK(xs_sldb_db); | 582 XS_MUTEX_LOCK(xs_sldb_db); |
620 xs_sldb_free(xs_sldb_db); | 583 xs_sldb_free(xs_sldb_db); |
621 xs_sldb_db = NULL; | 584 xs_sldb_db = NULL; |
622 XS_MUTEX_UNLOCK(xs_sldb_db); | 585 XS_MUTEX_UNLOCK(xs_sldb_db); |
623 } | 586 } |
624 | 587 |
625 | 588 |
626 t_xs_sldb_node * xs_songlen_get(gchar *pcFilename) | 589 t_xs_sldb_node *xs_songlen_get(gchar * pcFilename) |
627 { | 590 { |
628 t_xs_sldb_node *pResult; | 591 t_xs_sldb_node *pResult; |
629 | 592 |
630 XS_MUTEX_LOCK(xs_sldb_db); | 593 XS_MUTEX_LOCK(xs_sldb_db); |
631 | 594 |
632 if (xs_cfg.songlenDBEnable && xs_sldb_db) | 595 if (xs_cfg.songlenDBEnable && xs_sldb_db) |
633 pResult = xs_sldb_get(xs_sldb_db, pcFilename); | 596 pResult = xs_sldb_get(xs_sldb_db, pcFilename); |
634 else | 597 else |
635 pResult = NULL; | 598 pResult = NULL; |
636 | 599 |
637 XS_MUTEX_UNLOCK(xs_sldb_db); | 600 XS_MUTEX_UNLOCK(xs_sldb_db); |
638 | 601 |
639 return pResult; | 602 return pResult; |
640 } | 603 } |
641 |