1 /* OpenCP Module Player
2 * copyright (c) '94-'10 Niklas Beisert <nbeisert@physik.tu-muenchen.de>
3 * copyright (c) '04-'21 Stian Skjelstad <stian.skjelstad@gmail.com>
4 *
5 * Module information DataBase (and some other related stuff=
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 *
21 * revision history: (please note changes here)
22 * -ss04?????? Stian Skjelstad <stian@nixia.no
23 * -first release (splited out from pfilesel.c)
24 */
25
26 #include "config.h"
27 #include <errno.h>
28 #include <fcntl.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <sys/stat.h>
33 #include <sys/types.h>
34 #include <unistd.h>
35 #include "types.h"
36 #include "boot/plinkman.h"
37 #include "boot/psetting.h"
38 #include "dirdb.h"
39 #include "filesystem.h"
40 #include "mdb.h"
41 #include "pfilesel.h"
42 #include "stuff/compat.h"
43 #include "stuff/imsrtns.h"
44
45 #ifdef MDB_DEBUG
46 #define DEBUG_PRINT(...) do { fprintf(stderr, __VA_ARGS__); } while (0)
47 #else
48 #define DEBUG_PRINT(...) {}
49 #endif
50
51 struct __attribute__((packed)) modinfoentry
52 {
53 uint8_t flags;
54 union
55 {
56 struct __attribute__((packed))
57 {
58 uint8_t modtype; /* 1 */
59 uint32_t comref; /* 5 */
60 uint32_t compref; /* 9 */
61 uint32_t futref; /* 13 */
62 char name[12]; /* 25 */
63 uint32_t size; /* 29 */
64 char modname[32]; /* 61 */
65 uint32_t date; /* 65 */
66 uint16_t playtime; /* 67 */
67 uint8_t channels; /* 68 */
68 uint8_t moduleflags;/* 69 */
69 /* last uint8_t flags2 is up-padding for the top uint8_t and so on.. */
70 } gen;
71
72 struct __attribute__((packed))
73 {
74 char unusedfill1[6]; /* 1 */
75 char comment[63];
76 } com;
77
78 struct __attribute__((packed))
79 {
80 char composer[32];
81 char style[31];
82 } comp;
83 } mie;
84 };
85 #define gen mie.gen
86 #define comp mie.comp
87
88 struct __attribute__((packed)) mdbheader
89 {
90 char sig[60];
91 uint32_t entries;
92 };
93 const char mdbsigv1[60] = "Cubic Player Module Information Data Base\x1B\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
94
95 static struct modinfoentry *mdbData;
96 static uint32_t mdbNum;
97 static int mdbDirty;
98 static uint32_t *mdbReloc;
99 static uint32_t mdbGenNum;
100 static uint32_t mdbGenMax;
101
mdbGetModTypeString(unsigned char type)102 const char *mdbGetModTypeString(unsigned char type)
103 {
104 return fsTypeNames[type&UINT8_MAX];
105 }
106
mdbGetModuleType(uint32_t mdb_ref)107 int mdbGetModuleType(uint32_t mdb_ref)
108 {
109 if (mdb_ref>=mdbNum)
110 return -1;
111 if ((mdbData[mdb_ref].flags&(MDB_USED|MDB_BLOCKTYPE))!=(MDB_USED|MDB_GENERAL))
112 return -1;
113 return mdbData[mdb_ref].gen.modtype;
114 }
115
mdbReadModType(const char * str)116 uint8_t mdbReadModType(const char *str)
117 {
118 int v=255;
119 int i;
120 for (i=0; i<256; i++)
121 if (!strcasecmp(str, fsTypeNames[i]))
122 v=i;
123 return v;
124 }
125
126
mdbInfoRead(uint32_t mdb_ref)127 int mdbInfoRead(uint32_t mdb_ref)
128 {
129 if (mdb_ref>=mdbNum)
130 {
131 DEBUG_PRINT ("mdbInfoRead(0x%08"PRIx32") => -1 due to out of range\n", mdb_ref);
132 return -1;
133 }
134 if ((mdbData[mdb_ref].flags&(MDB_USED|MDB_BLOCKTYPE))!=(MDB_USED|MDB_GENERAL))
135 {
136 DEBUG_PRINT ("mdbInfoRead(0x%08"PRIx32") => -1 due to entry not being USED + GENERAL\n", mdb_ref);
137 return -1;
138 }
139 #ifdef MDB_DEBUG
140 if (mdbData[mdb_ref].gen.modtype==mtUnRead)
141 {
142 DEBUG_PRINT ("mdbInfoRead(0x%08"PRIx32") => 0 due to mtUnRead\n", mdb_ref);
143 } else {
144 DEBUG_PRINT ("mdbInfoRead(0x%08"PRIx32") => 1 due to modtype != mtUnRead\n", mdb_ref);
145 }
146 #endif
147 return mdbData[mdb_ref].gen.modtype!=mtUnRead;
148 }
149
150 /* This thing will end up with a register of all valid pre-interprators for modules and friends
151 */
152 static struct mdbreadinforegstruct *mdbReadInfos=NULL;
153
mdbRegisterReadInfo(struct mdbreadinforegstruct * r)154 void mdbRegisterReadInfo(struct mdbreadinforegstruct *r)
155 {
156 r->next=mdbReadInfos;
157 mdbReadInfos=r;
158 if (r->Event)
159 r->Event(mdbEvInit);
160 }
161
mdbUnregisterReadInfo(struct mdbreadinforegstruct * r)162 void mdbUnregisterReadInfo(struct mdbreadinforegstruct *r)
163 {
164 struct mdbreadinforegstruct *root=mdbReadInfos;
165 if (root==r)
166 {
167 mdbReadInfos=r->next;
168 return;
169 }
170 while (root)
171 {
172 if (root->next==r)
173 {
174 root->next=root->next->next;
175 return;
176 }
177 if (!root->next)
178 return;
179 root=root->next;
180 }
181 }
182
mdbReadMemInfo(struct moduleinfostruct * m,const char * buf,int len)183 int mdbReadMemInfo(struct moduleinfostruct *m, const char *buf, int len)
184 {
185 struct mdbreadinforegstruct *rinfos;
186
187 DEBUG_PRINT ("mdbReaadMemInfo(buf=%p len=%d)\n", buf, len);
188
189 for (rinfos=mdbReadInfos; rinfos; rinfos=rinfos->next)
190 if (rinfos->ReadMemInfo)
191 if (rinfos->ReadMemInfo(m, buf, len))
192 return 1;
193 return 0;
194 }
195
mdbReadInfo(struct moduleinfostruct * m,struct ocpfilehandle_t * f)196 int mdbReadInfo(struct moduleinfostruct *m, struct ocpfilehandle_t *f)
197 {
198 char mdbScanBuf[1084];
199 struct mdbreadinforegstruct *rinfos;
200 int maxl;
201
202 DEBUG_PRINT ("mdbReadInfo(f=%p)\n", f);
203
204 if (f->seek_set (f, 0) < 0)
205 {
206 return 1;
207 }
208 memset (mdbScanBuf, 0, sizeof (mdbScanBuf));
209 maxl = f->read (f, mdbScanBuf, sizeof (mdbScanBuf));
210
211 {
212 char *path;
213 dirdbGetName_internalstr (f->dirdb_ref, &path);
214 DEBUG_PRINT (" mdbReadMemInfo(%s %p %d)\n", path, mdbScanBuf, maxl);
215 }
216
217 if (mdbReadMemInfo(m, mdbScanBuf, maxl))
218 return 1;
219
220 for (rinfos=mdbReadInfos; rinfos; rinfos=rinfos->next)
221 if (rinfos->ReadInfo)
222 if (rinfos->ReadInfo(m, f, mdbScanBuf, maxl))
223 return 1;
224
225 return m->modtype==mtUnRead;
226 }
227
mdbGetNew(void)228 static uint32_t mdbGetNew(void)
229 {
230 uint32_t i;
231
232 for (i=0; i<mdbNum; i++)
233 if (!(mdbData[i].flags&MDB_USED))
234 break;
235 if (i==mdbNum)
236 {
237 void *t;
238 uint32_t j;
239 mdbNum+=64;
240 if (!(t=realloc(mdbData, mdbNum*sizeof(*mdbData))))
241 return UINT32_MAX;
242 mdbData=(struct modinfoentry *)t;
243 memset(mdbData+i, 0, (mdbNum-i)*sizeof(*mdbData));
244 for (j=i; j<mdbNum; j++)
245 mdbData[j].flags|=MDB_DIRTY;
246 }
247 mdbDirty=1;
248
249 DEBUG_PRINT("mdbGetNew() => 0x%08"PRIx32"\n", i);
250
251 return i;
252 }
253
mdbWriteModuleInfo(uint32_t mdb_ref,struct moduleinfostruct * m)254 int mdbWriteModuleInfo(uint32_t mdb_ref, struct moduleinfostruct *m)
255 {
256 DEBUG_PRINT("mdbWriteModuleInfo(0x%"PRIx32", %p)\n", mdb_ref, m);
257
258 if (mdb_ref>=mdbNum)
259 {
260 DEBUG_PRINT ("mdbWriteModuleInfo, mdb_ref(%d)<mdbNum(%d)\n", mdb_ref, mdbNum);
261 return 0;
262 }
263 if ((mdbData[mdb_ref].flags&(MDB_USED|MDB_BLOCKTYPE))!=(MDB_USED|MDB_GENERAL))
264 {
265 DEBUG_PRINT ("mdbWriteModuleInfo (mdbData[mdb_ref].flags&(MDB_USED|MDB_BLOCKTYPE))!=(MDB_USED|MDB_GENERAL) Failed\n");
266 return 0;
267 }
268
269 m->flags1=MDB_USED|MDB_DIRTY|MDB_GENERAL|(m->flags1&(MDB_VIRTUAL|MDB_BIGMODULE|MDB_RESERVED));
270 m->flags2=MDB_DIRTY|MDB_COMPOSER;
271 m->flags3=MDB_DIRTY|MDB_COMMENT;
272 m->flags4=MDB_DIRTY|MDB_FUTURE;
273
274 if (*m->composer||*m->style)
275 m->flags2|=MDB_USED;
276 if (*m->comment)
277 m->flags3|=MDB_USED;
278
279 /* free the old references */
280 if (m->comref!=UINT32_MAX)
281 mdbData[m->comref].flags=MDB_DIRTY;
282 if (m->compref!=UINT32_MAX)
283 mdbData[m->compref].flags=MDB_DIRTY;
284 if (m->futref!=UINT32_MAX)
285 mdbData[m->futref].flags=MDB_DIRTY;
286 m->compref=UINT32_MAX;
287 m->comref=UINT32_MAX;
288 m->futref=UINT32_MAX;
289
290 /* allocate new ones */
291 if (m->flags2&MDB_USED)
292 {
293 m->compref=mdbGetNew();
294 if (m->compref!=UINT32_MAX)
295 memcpy(mdbData+m->compref, &m->flags2, sizeof(*mdbData));
296 }
297 if (m->flags3&MDB_USED)
298 {
299 m->comref=mdbGetNew();
300 if (m->comref!=UINT32_MAX)
301 memcpy(mdbData+m->comref, &m->flags3, sizeof(*mdbData));
302 }
303 if (m->flags4&MDB_USED)
304 {
305 m->futref=mdbGetNew();
306 if (m->futref!=UINT32_MAX)
307 memcpy(mdbData+m->futref, &m->flags4, sizeof(*mdbData));
308 }
309
310 memcpy(mdbData+mdb_ref, m, sizeof(*mdbData));
311 mdbDirty=1;
312 return 1;
313 }
314
mdbScan(struct ocpfile_t * file,uint32_t mdb_ref)315 void mdbScan(struct ocpfile_t *file, uint32_t mdb_ref)
316 {
317 DEBUG_PRINT ("mdbScan(file=%p, mdb_ref=0x%08"PRIx32")\n", file, mdb_ref);
318 if (!file)
319 {
320 return;
321 }
322
323 if (file->is_nodetect)
324 {
325 return;
326 }
327
328 if (!mdbInfoRead(mdb_ref)) /* use mdbReadInfo again here ? */
329 {
330 struct moduleinfostruct mdbEditBuf;
331 struct ocpfilehandle_t *f;
332 if (!(f=file->open(file)))
333 {
334 return;
335 }
336 mdbGetModuleInfo(&mdbEditBuf, mdb_ref);
337 mdbReadInfo(&mdbEditBuf, f);
338 f->unref (f);
339 mdbWriteModuleInfo(mdb_ref, &mdbEditBuf);
340 }
341 }
342
miecmp(const void * a,const void * b)343 static int miecmp(const void *a, const void *b)
344 {
345 struct modinfoentry *c=&mdbData[*(uint32_t *)a];
346 struct modinfoentry *d=&mdbData[*(uint32_t *)b];
347 if (c->gen.size==d->gen.size)
348 return memcmp(c->gen.name, d->gen.name, 12);
349 if (c->gen.size<d->gen.size)
350 return -1;
351 else
352 return 1;
353 }
354
mdbInit(void)355 int mdbInit(void)
356 {
357 char *path;
358 int f;
359 struct mdbheader header;
360 uint32_t i;
361
362 mdbDirty=0;
363 mdbData=0;
364 mdbNum=0;
365 mdbReloc=0;
366 mdbGenNum=0;
367 mdbGenMax=0;
368
369 makepath_malloc (&path, 0, cfConfigDir, "CPMODNFO.DAT", 0);
370
371 if ((f=open(path, O_RDONLY))<0)
372 {
373 fprintf (stderr, "open(%s): %s\n", path, strerror (errno));
374 free (path);
375 return 1;
376 }
377
378 fprintf(stderr, "Loading %s .. ", path);
379 free (path); path = 0;
380
381 if (read(f, &header, sizeof(header))!=sizeof(header))
382 {
383 fprintf(stderr, "No header\n");
384 close(f);
385 return 1;
386 }
387
388 if (memcmp(header.sig, mdbsigv1, sizeof(mdbsigv1)))
389 {
390 fprintf(stderr, "Invalid header\n");
391 close(f);
392 return 1;
393 }
394
395 mdbNum=uint32_little(header.entries);
396 if (!mdbNum)
397 {
398 close(f);
399 fprintf(stderr, "EOF\n");
400 return 1;
401 }
402
403 mdbData=malloc(sizeof(struct modinfoentry)*mdbNum);
404 if (!mdbData)
405 return 0;
406 if (read(f, mdbData, mdbNum*sizeof(*mdbData))!=(signed)(mdbNum*sizeof(*mdbData)))
407 {
408 mdbNum=0;
409 free(mdbData);
410 mdbData=0;
411 close(f);
412 fprintf(stderr, "EOF\n");
413 return 1;
414 }
415 close(f);
416
417 for (i=0; i<mdbNum; i++)
418 {
419 if ((mdbData[i].flags&(MDB_BLOCKTYPE|MDB_USED))==(MDB_USED|MDB_GENERAL))
420 {
421 DEBUG_PRINT("0x%08"PRIx32" is USED GENERAL\n", i);
422 mdbGenMax++;
423 }
424 }
425
426 if (mdbGenMax)
427 {
428 mdbReloc=malloc(sizeof(uint32_t)*mdbGenMax);
429 if (!mdbReloc)
430 return 0;
431 for (i=0; i<mdbNum; i++)
432 if ((mdbData[i].flags&(MDB_BLOCKTYPE|MDB_USED))==(MDB_USED|MDB_GENERAL))
433 mdbReloc[mdbGenNum++]=i;
434
435 qsort(mdbReloc, mdbGenNum, sizeof(*mdbReloc), miecmp);
436 #ifdef MDB_DEBUG
437 for (i=0; i<mdbGenMax; i++)
438 {
439 DEBUG_PRINT("%5"PRId32" => 0x%08"PRIx32" %"PRId32" %c%c%c%c%c%c%c%c%c%c%c%c\n", i, mdbReloc[i], mdbData[mdbReloc[i]].gen.size, mdbData[mdbReloc[i]].gen.name[0], mdbData[mdbReloc[i]].gen.name[1], mdbData[mdbReloc[i]].gen.name[2], mdbData[mdbReloc[i]].gen.name[3], mdbData[mdbReloc[i]].gen.name[4], mdbData[mdbReloc[i]].gen.name[5], mdbData[mdbReloc[i]].gen.name[6], mdbData[mdbReloc[i]].gen.name[7], mdbData[mdbReloc[i]].gen.name[8], mdbData[mdbReloc[i]].gen.name[9], mdbData[mdbReloc[i]].gen.name[10], mdbData[mdbReloc[i]].gen.name[11]);
440 }
441 #endif
442 }
443
444 fprintf(stderr, "Done\n");
445
446 return 1;
447 }
448
mdbUpdate(void)449 void mdbUpdate(void)
450 {
451 char *path;
452 int f;
453 uint32_t i, j;
454 struct mdbheader header;
455
456 DEBUG_PRINT("mdbUpdate: mdbDirty=%d fsWriteModInfo=%d\n", mdbDirty, fsWriteModInfo);
457
458 if (!mdbDirty||!fsWriteModInfo)
459 return;
460 mdbDirty=0;
461
462 makepath_malloc (&path, 0, cfConfigDir, "CPMODNFO.DAT", 0);
463 if ((f=open(path, O_WRONLY|O_CREAT, S_IREAD|S_IWRITE))<0)
464 {
465 fprintf (stderr, "open(%s): %s\n", path, strerror (errno));
466 free (path);
467 return;
468 }
469
470 lseek(f, 0, SEEK_SET);
471 memcpy(header.sig, mdbsigv1, sizeof(mdbsigv1));
472 header.entries = uint32_little(mdbNum);
473 while (1)
474 {
475 ssize_t res;
476 res = write(f, &header, sizeof(header));
477 if (res < 0)
478 {
479 if (errno==EAGAIN)
480 continue;
481 if (errno==EINTR)
482 continue;
483 fprintf(stderr, __FILE__ " write() to %s failed: %s\n", path, strerror(errno));
484 exit(1);
485 } else if (res != sizeof(header))
486 {
487 fprintf(stderr, __FILE__ " write() to %s returned only partial data\n", path);
488 exit(1);
489 } else
490 break;
491 }
492 i=0;
493 while (i<mdbNum)
494 {
495 if (!(mdbData[i].flags&MDB_DIRTY))
496 {
497 i++;
498 continue;
499 }
500 for (j=i; j<mdbNum; j++)
501 if (mdbData[j].flags&MDB_DIRTY)
502 mdbData[j].flags&=~MDB_DIRTY;
503 else
504 break;
505 lseek(f, (uint64_t)64+(uint64_t)i*sizeof(*mdbData), SEEK_SET);
506 while (1)
507 {
508 ssize_t res;
509
510 DEBUG_PRINT(" [0x%08"PRIx32" -> 0x%08"PRIx32"] DIRTY\n", i, j);
511 res = write(f, mdbData+i, (j-i)*sizeof(*mdbData));
512 if (res < 0)
513 {
514 if (errno==EAGAIN)
515 continue;
516 if (errno==EINTR)
517 continue;
518 fprintf(stderr, __FILE__ " write() to %s failed: %s\n", path, strerror(errno));
519 exit(1);
520 } else if (res != (signed)((j-i)*sizeof(*mdbData)))
521 {
522 fprintf(stderr, __FILE__ " write() to %s returned only partial data\n", path);
523 exit(1);
524 } else
525 break;
526 }
527 i=j;
528 }
529 free (path);
530 lseek(f, 0, SEEK_END);
531 close(f);
532 }
533
mdbClose(void)534 void mdbClose(void)
535 {
536 mdbUpdate();
537 free(mdbData);
538 free(mdbReloc);
539 }
540
mdbGetModuleReference(const char * name,uint32_t size)541 static uint32_t mdbGetModuleReference(const char *name, uint32_t size)
542 {
543 uint32_t i;
544
545 uint32_t *min=mdbReloc;
546 uint32_t num=mdbGenNum;
547 uint32_t mn;
548 struct modinfoentry *m;
549
550 /* Iterate fast.. If size to to big, set current to be the minimum, and
551 * set the current to point in the new center, else half the current.
552 *
553 * That code is VERY clever. Took me some minutes to read it :-) nice
554 * work guys
555 * - Stian
556 */
557
558 DEBUG_PRINT("mdbGetModuleReference(%s %"PRId32")\n", name, size);
559 while (num)
560 {
561 struct modinfoentry *m=&mdbData[min[num>>1]];
562 int ret;
563 #ifdef MDB_DEBUG
564 {
565 uint32_t x;
566 for (x = 0; x < num; x++)
567 {
568 DEBUG_PRINT(" %08x %"PRId32" %c%c%c%c%c%c%c%c%c%c%c%c\n",
569 min[x],
570 mdbData[min[x]].gen.size,
571 mdbData[min[x]].gen.name[0],
572 mdbData[min[x]].gen.name[1],
573 mdbData[min[x]].gen.name[2],
574 mdbData[min[x]].gen.name[3],
575 mdbData[min[x]].gen.name[4],
576 mdbData[min[x]].gen.name[5],
577 mdbData[min[x]].gen.name[6],
578 mdbData[min[x]].gen.name[7],
579 mdbData[min[x]].gen.name[8],
580 mdbData[min[x]].gen.name[9],
581 mdbData[min[x]].gen.name[10],
582 mdbData[min[x]].gen.name[11]);
583 }
584 DEBUG_PRINT("----------\n");
585 }
586 #endif
587 if (size==m->gen.size)
588 ret=memcmp(name, m->gen.name, 12);
589 else
590 if (size<m->gen.size)
591 ret=-1;
592 else
593 ret=1;
594 if (!ret)
595 {
596 DEBUG_PRINT("mdbGetModuleReference(%s %"PRId32") => mdbReloc => 0x%08"PRIx32"\n", name, size, min[num>>1]);
597 return min[num>>1];
598 }
599 if (ret<0)
600 num>>=1;
601 else {
602 min+=(num>>1)+1;
603 num=(num-1)>>1;
604 }
605 }
606 mn=min-mdbReloc;
607
608 i=mdbGetNew();
609 if (i==UINT32_MAX)
610 return UINT32_MAX;
611 if (mdbGenNum==mdbGenMax)
612 {
613 void *n;
614 mdbGenMax+=512;
615 if (!(n=realloc(mdbReloc, sizeof (*mdbReloc)*mdbGenMax)))
616 return UINT32_MAX;
617 mdbReloc=(uint32_t *)n;
618 }
619
620 memmovel(mdbReloc+mn+1, mdbReloc+mn, mdbGenNum-mn);
621 mdbReloc[mn]=(uint32_t)i;
622 mdbGenNum++;
623
624 m=&mdbData[i];
625 m->flags=MDB_DIRTY|MDB_USED|MDB_GENERAL;
626 memcpy(m->gen.name, name, 12);
627 m->gen.size=size;
628 m->gen.modtype=UINT8_MAX;
629 m->gen.comref=UINT32_MAX;
630 m->gen.compref=UINT32_MAX;
631 m->gen.futref=UINT32_MAX;
632 memset(m->gen.modname, 0, 32);
633 m->gen.date=0;
634 m->gen.playtime=0;
635 m->gen.channels=0;
636 m->gen.moduleflags=0;
637 mdbDirty=1;
638 DEBUG_PRINT("mdbGetModuleReference(%s %"PRId32") => new => 0x%08"PRIx32"\n", name, size, i);
639 return (uint32_t)i;
640 }
641
642 #warning Remake the hash to acculate overflow characters into the character 6 and 7... it will break old databases
mdbGetModuleReference2(uint32_t dirdb_ref,uint32_t size)643 uint32_t mdbGetModuleReference2 (uint32_t dirdb_ref, uint32_t size)
644 {
645 char shortname[13];
646 char *temppath;
647 char *lastdot;
648 int length;
649
650 dirdbGetName_internalstr (dirdb_ref, &temppath);
651 if (!temppath)
652 {
653 return DIRDB_NOPARENT;
654 }
655
656 /* the "hash" is created using the former fs12name() function */
657 length = strlen (temppath);
658
659 shortname[12] = 0;
660 if ((lastdot=rindex(temppath + 1, '.'))) /* we allow files to start with, hence temppath + 1 */
661 {
662 /* delta is the length until the dot */
663 int delta = lastdot - temppath;
664
665 if ((delta) < 8)
666 { /* if the text before the dot is shorter than 8, pad it with spaces */
667 strncpy (shortname, temppath, delta);
668 strncpy (shortname + delta, " ", 8 - delta);
669 } else { /* or we take only the first 8 characters */
670 strncpy (shortname, temppath, 8);
671 }
672
673 /* grab the dot, and upto 3 characters following it */
674 if (strlen (lastdot) < 4)
675 { /* if the text including the dot is shorter than 4, pad it with spaces */
676 strcpy (shortname + 8, lastdot);
677 strncpy (shortname + 8 + strlen (lastdot), " ", 4 - strlen(lastdot));
678 } else { /* or we take only the first 4 characters, eg .foo instead of .foobar, and also accept things like .mod as is */
679 strncpy (shortname + 8, lastdot, 4);
680 }
681 } else { /* we would normally never HASH such a filename */
682 strncpy(shortname, temppath, 12);
683 if ((length=strlen(temppath))<12)
684 {
685 strncpy(shortname+length, " ", 12-length);
686 }
687 }
688
689 return mdbGetModuleReference (shortname, size);
690 }
691
mdbGetModuleInfo(struct moduleinfostruct * m,uint32_t mdb_ref)692 int mdbGetModuleInfo(struct moduleinfostruct *m, uint32_t mdb_ref)
693 {
694 memset(m, 0, sizeof(struct moduleinfostruct));
695 if (mdb_ref>=mdbNum) /* needed, since we else might index mdbData wrong */
696 goto invalid;
697 if ((mdbData[mdb_ref].flags&(MDB_USED|MDB_BLOCKTYPE))!=(MDB_USED|MDB_GENERAL))
698 {
699 invalid:
700 m->modtype=UINT8_MAX;
701 m->comref=UINT32_MAX;
702 m->compref=UINT32_MAX;
703 m->futref=UINT32_MAX;
704 return 0;
705 }
706 memcpy(m, mdbData+mdb_ref, sizeof(*mdbData));
707 if (m->compref!=UINT32_MAX)
708 {
709 if ((m->compref < mdbNum) && ((mdbData[m->compref].flags & MDB_BLOCKTYPE) == MDB_COMPOSER))
710 {
711 memcpy(&m->flags2, mdbData+m->compref, sizeof(*mdbData));
712 } else {
713 fprintf (stderr, "[mdb] warning - invalid compref\n");
714 m->compref=UINT32_MAX;
715 }
716 }
717 if (m->comref!=UINT32_MAX)
718 {
719 if ((m->comref < mdbNum) && ((mdbData[m->comref].flags & MDB_BLOCKTYPE) == MDB_COMMENT))
720 {
721 memcpy(&m->flags3, mdbData+m->comref, sizeof(*mdbData));
722 } else {
723 fprintf (stderr, "[mdb] warning - invalid comref\n");
724 m->comref=UINT32_MAX;
725 }
726 }
727 if (m->futref!=UINT32_MAX)
728 {
729 if ((m->futref < mdbNum) && ((mdbData[m->comref].flags & MDB_BLOCKTYPE) == MDB_FUTURE))
730 {
731 memcpy(&m->flags4, mdbData+m->futref, sizeof(*mdbData));
732 } else {
733 fprintf (stderr, "[mdb] warning - invalid futref\n");
734 m->futref=UINT32_MAX;
735 }
736 }
737 return 1;
738 }
739