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