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