in cores/genesis/core/cd_hw/cdd.c [309:1160]
int cdd_load(char *filename, char *header)
{
char fname[256+10];
char line[128];
char *ptr, *lptr;
cdStream *fd;
/* assume CD image file by default */
int isCDfile = 1;
/* first unmount any loaded disc */
cdd_unload();
/* open file */
fd = cdStreamOpen(filename);
if (!fd)
return (-1);
#if defined(USE_LIBCHDR)
if (!memcmp(".chd", &filename[strlen(filename) - 4], 4) || !memcmp(".CHD", &filename[strlen(filename) - 4], 4))
{
int sectors = 0;
char metadata[256];
const chd_header *head;
/* open CHD file */
if (chd_open_file(fd, CHD_OPEN_READ, NULL, &cdd.chd.file) != CHDERR_NONE)
{
chd_close(cdd.chd.file);
cdStreamClose(fd);
return -1;
}
/* retrieve CHD header */
head = chd_get_header(cdd.chd.file);
/* detect invalid hunk size */
if ((head->hunkbytes == 0) || (head->hunkbytes % CD_FRAME_SIZE))
{
chd_close(cdd.chd.file);
cdStreamClose(fd);
return -1;
}
/* allocate hunk buffer */
cdd.chd.hunk = (uint8 *)malloc(head->hunkbytes);
if (!cdd.chd.hunk)
{
chd_close(cdd.chd.file);
cdStreamClose(fd);
return -1;
}
/* initialize hunk size (usually fixed to 8 sectors) */
cdd.chd.hunkbytes = head->hunkbytes;
/* initialize buffered hunk index */
cdd.chd.hunknum = -1;
/* retrieve tracks informations */
for (cdd.toc.last = 0; cdd.toc.last < 99; cdd.toc.last++)
{
int tracknum = 0, frames = 0, pregap = 0, postgap = 0;
char type[16], subtype[16], pgtype[16], pgsub[16];
type[0] = subtype[0] = pgtype[0] = pgsub[0] = 0;
/* attempt fetch either complete or partial metadata for current track */
if (chd_get_metadata(cdd.chd.file, CDROM_TRACK_METADATA2_TAG, cdd.toc.last, metadata, 256, 0, 0, 0) == CHDERR_NONE)
{
if (sscanf(metadata, CDROM_TRACK_METADATA2_FORMAT, &tracknum, &type[0], &subtype[0], &frames, &pregap, &pgtype[0], &pgsub[0], &postgap) != 8)
break;
}
else if (chd_get_metadata(cdd.chd.file, CDROM_TRACK_METADATA_TAG, cdd.toc.last, metadata, 256, 0, 0, 0) == CHDERR_NONE)
{
if (sscanf(metadata, CDROM_TRACK_METADATA_FORMAT, &tracknum, &type[0], &subtype[0], &frames) != 4)
break;
}
/* no more track */
else break;
/* detect out of order track number or invalid parameter */
if ((tracknum != (cdd.toc.last + 1)) || (frames < 0) || (pregap < 0) || (postgap < 0))
break;
/* detect track type */
if (cdd.toc.last)
{
/* CD-ROM track supported only for first track */
if (strcmp(type, "AUDIO"))
break;
/* Audio track start LBA (adjusted with pregap length) */
cdd.toc.tracks[cdd.toc.last].start = cdd.toc.end + pregap;
}
else
{
/* COOKED format (2048 bytes data blocks) */
if (!strcmp(type, "MODE1"))
cdd.sectorSize = 2048;
/* RAW format (2352 bytes data blocks) */
else if (!strcmp(type, "MODE1_RAW"))
cdd.sectorSize = 2352;
/* unsupported track format */
else if (strcmp(type, "AUDIO"))
break;
/* Data track start LBA (2s pause assumed by default) */
cdd.toc.tracks[0].start = 0;
}
/* detect pregap type */
if (pgtype[0] != 'V')
{
/* clear pause length for further calculations (not included in CHD file) */
pregap = 0;
}
/* track end LBA (remove included pause from CHD track length) */
cdd.toc.tracks[cdd.toc.last].end = cdd.toc.tracks[cdd.toc.last].start + frames - pregap;
/* CHD file offset for current track */
cdd.toc.tracks[cdd.toc.last].offset = (sectors + pregap - cdd.toc.tracks[cdd.toc.last].start) * CD_FRAME_SIZE;
/* update TOC end with postgap length */
cdd.toc.end = cdd.toc.tracks[cdd.toc.last].end + postgap;
/* update CHD file sector count (adjusted with end of the track padding) */
sectors += (((frames + CD_TRACK_PADDING - 1) / CD_TRACK_PADDING) * CD_TRACK_PADDING);
/* indicate valid track file */
cdd.toc.tracks[cdd.toc.last].fd = fd;
}
/* valid CD-ROM image file ? */
if (cdd.sectorSize)
{
/* read first chunk of data */
cdd.chd.hunknum = cdd.toc.tracks[0].offset / cdd.chd.hunkbytes;
chd_read(cdd.chd.file, cdd.chd.hunknum, cdd.chd.hunk);
/* copy CD image header + security code */
memcpy(header, cdd.chd.hunk + (cdd.toc.tracks[0].offset % cdd.chd.hunkbytes) + 0x10, 0x210);
/* there is a valid DATA track */
cdd.toc.tracks[0].type = TYPE_CDROM;
}
/* valid CD image ? */
if (cdd.toc.last && (cdd.toc.end < (100*60*75)))
{
/* Lead-out */
cdd.toc.tracks[cdd.toc.last].start = cdd.toc.end;
/* CD mounted */
cdd.loaded = 1;
return 1;
}
/* invalid CHD file */
chd_close(cdd.chd.file);
cdStreamClose(fd);
return -1;
}
#endif
/* save a copy of base filename */
strncpy(fname, filename, 256);
/* check loaded file extension */
if (memcmp(".cue", &filename[strlen(filename) - 4], 4) && memcmp(".CUE", &filename[strlen(filename) - 4], 4))
{
int len;
/* read first 16 bytes */
cdStreamRead(header, 0x10, 1, fd);
/* look for valid CD image identifier */
if (!memcmp("SEGADISCSYSTEM", header, 14))
{
/* COOKED format (2048 bytes data blocks) */
cdd.sectorSize = 2048;
}
else
{
/* read next 16 bytes */
cdStreamRead(header, 0x10, 1, fd);
/* look for valid CD image identifier */
if (!memcmp("SEGADISCSYSTEM", header, 14))
{
/* RAW format (2352 bytes data blocks) */
cdd.sectorSize = 2352;
}
}
/* valid CD image file ? */
if (cdd.sectorSize)
{
/* read CD image header + security code */
cdStreamRead(header + 0x10, 0x200, 1, fd);
/* initialize first track file descriptor */
cdd.toc.tracks[0].fd = fd;
/* this is a valid DATA track */
cdd.toc.tracks[0].type = TYPE_CDROM;
/* DATA track end LBA (based on DATA file length) */
cdStreamSeek(fd, 0, SEEK_END);
cdd.toc.tracks[0].end = cdStreamTell(fd) / cdd.sectorSize;
/* DATA track length should be at least 2s (BIOS requirement) */
if (cdd.toc.tracks[0].end < 150)
{
cdd.toc.tracks[0].end = 150;
}
/* DATA track start LBA (logical block 0) */
cdStreamSeek(fd, 0, SEEK_SET);
cdd.toc.tracks[0].start = 0;
/* initialize TOC */
cdd.toc.end = cdd.toc.tracks[0].end;
cdd.toc.last = 1;
}
else
{
/* this is not a CD image file */
isCDfile = 0;
/* close file */
cdStreamClose(fd);
}
/* automatically try to mount CD associated CUE file */
len = strlen(fname);
while ((len && (fname[len] != '.')) || (len > 251)) len--;
strcpy(&fname[len], ".cue");
fd = cdStreamOpen(fname);
}
/* parse CUE file */
if (fd)
{
int mm, ss, bb, pregap = 0;
/* DATA track already loaded ? */
if (cdd.toc.last)
{
/* skip first track */
while (cdStreamGets(line, 128, fd))
{
if (strstr(line, "INDEX 01") && !strstr(line, "INDEX 1"))
break;
}
}
/* read lines until end of file */
while (cdStreamGets(line, 128, fd))
{
/* skip any SPACE characters */
lptr = line;
while (*lptr == 0x20) lptr++;
/* decode FILE commands */
if (!(memcmp(lptr, "FILE", 4)))
{
/* retrieve current path */
ptr = fname + strlen(fname) - 1;
while ((ptr - fname) && (*ptr != '/') && (*ptr != '\\')) ptr--;
if (ptr - fname) ptr++;
/* skip "FILE" attribute */
lptr += 4;
/* skip SPACE characters */
while (*lptr == 0x20) lptr++;
/* retrieve full filename */
if (*lptr == '\"')
{
/* skip first DOUBLE QUOTE character */
lptr++;
while ((*lptr != '\"') && (lptr <= (line + 128)) && (ptr < (fname + 255)))
*ptr++ = *lptr++;
}
else
{
/* no DOUBLE QUOTE used */
while ((*lptr != 0x20) && (lptr <= (line + 128)) && (ptr < (fname + 255)))
*ptr++ = *lptr++;
}
*ptr = 0;
/* open current track file descriptor */
cdd.toc.tracks[cdd.toc.last].fd = cdStreamOpen(fname);
if (!cdd.toc.tracks[cdd.toc.last].fd)
{
/* error opening file */
break;
}
/* reset current file PREGAP length */
pregap = 0;
/* reset current track file read offset */
cdd.toc.tracks[cdd.toc.last].offset = 0;
/* check supported audio file types */
if (!strstr(lptr,"BINARY") && !strstr(lptr,"MOTOROLA"))
{
/* read file header */
unsigned char head[28];
cdStreamSeek(cdd.toc.tracks[cdd.toc.last].fd, 8, SEEK_SET);
cdStreamRead(head, 28, 1, cdd.toc.tracks[cdd.toc.last].fd);
cdStreamSeek(cdd.toc.tracks[cdd.toc.last].fd, 0, SEEK_SET);
/* autodetect WAVE file header (44.1KHz 16-bit stereo format only) */
if (!memcmp(head, waveHeader, 28))
{
/* look for 'data' chunk id */
int dataOffset = 0;
cdStreamSeek(cdd.toc.tracks[cdd.toc.last].fd, 36, SEEK_SET);
while (cdStreamRead(head, 4, 1, cdd.toc.tracks[cdd.toc.last].fd))
{
if (!memcmp(head, "data", 4))
{
dataOffset = cdStreamTell(cdd.toc.tracks[cdd.toc.last].fd) + 4;
cdStreamSeek(cdd.toc.tracks[cdd.toc.last].fd, 0, SEEK_SET);
break;
}
cdStreamSeek(cdd.toc.tracks[cdd.toc.last].fd, -2, SEEK_CUR);
}
/* check if 'data' chunk has not been found */
if (!dataOffset)
{
/* invalid WAVE file */
cdStreamClose(cdd.toc.tracks[cdd.toc.last].fd);
cdd.toc.tracks[cdd.toc.last].fd = 0;
break;
}
/* adjust current track file read offset with WAVE header length */
cdd.toc.tracks[cdd.toc.last].offset -= dataOffset;
}
#if defined(USE_LIBTREMOR) || defined(USE_LIBVORBIS)
else if (!ov_open_callbacks(cdd.toc.tracks[cdd.toc.last].fd,&cdd.toc.tracks[cdd.toc.last].vf,0,0,cb))
{
/* retrieve stream infos */
vorbis_info *info = ov_info(&cdd.toc.tracks[cdd.toc.last].vf,-1);
if (!info || (info->rate != 44100) || (info->channels != 2))
{
/* unsupported VORBIS file format (stereo @44.1kHz only) */
ov_clear(&cdd.toc.tracks[cdd.toc.last].vf);
cdd.toc.tracks[cdd.toc.last].fd = 0;
break;
}
}
#endif
else
{
/* unsupported audio file */
cdStreamClose(cdd.toc.tracks[cdd.toc.last].fd);
cdd.toc.tracks[cdd.toc.last].fd = 0;
break;
}
}
}
/* decode TRACK commands */
else if ((sscanf(lptr, "TRACK %02d %*s", &bb)) || (sscanf(lptr, "TRACK %d %*s", &bb)))
{
/* check track number */
if (bb != (cdd.toc.last + 1))
{
/* close any opened file */
if (cdd.toc.tracks[cdd.toc.last].fd)
{
cdStreamClose(cdd.toc.tracks[cdd.toc.last].fd);
cdd.toc.tracks[cdd.toc.last].fd = 0;
}
/* missing tracks */
break;
}
/* autodetect DATA track (first track only) */
if (!cdd.toc.last)
{
/* CD-ROM Mode 1 support only */
if (strstr(lptr,"MODE1/2048"))
{
/* COOKED format (2048 bytes / block) */
cdd.sectorSize = 2048;
}
else if (strstr(lptr,"MODE1/2352"))
{
/* RAW format (2352 bytes / block) */
cdd.sectorSize = 2352;
/* skip 16-byte header */
cdStreamSeek(cdd.toc.tracks[0].fd, 0x10, SEEK_SET);
}
if (cdd.sectorSize)
{
/* this is a valid DATA track */
cdd.toc.tracks[0].type = TYPE_CDROM;
/* read CD image header + security code */
cdStreamRead(header, 0x210, 1, cdd.toc.tracks[0].fd);
cdStreamSeek(cdd.toc.tracks[0].fd, 0, SEEK_SET);
}
}
else
{
/* check if same file is used for consecutive tracks */
if (!cdd.toc.tracks[cdd.toc.last].fd)
{
/* clear previous track end time */
cdd.toc.tracks[cdd.toc.last - 1].end = 0;
}
}
}
/* decode PREGAP commands */
else if (sscanf(lptr, "PREGAP %02d:%02d:%02d", &mm, &ss, &bb) == 3)
{
/* increment current file PREGAP length */
pregap += bb + ss*75 + mm*60*75;
}
/* decode INDEX commands */
else if ((sscanf(lptr, "INDEX 00 %02d:%02d:%02d", &mm, &ss, &bb) == 3) ||
(sscanf(lptr, "INDEX 0 %02d:%02d:%02d", &mm, &ss, &bb) == 3))
{
/* check if previous track end time needs to be set */
if (cdd.toc.last && !cdd.toc.tracks[cdd.toc.last - 1].end)
{
/* set previous track end time (current file absolute time + PREGAP length) */
cdd.toc.tracks[cdd.toc.last - 1].end = bb + ss*75 + mm*60*75 + pregap;
}
}
else if ((sscanf(lptr, "INDEX 01 %02d:%02d:%02d", &mm, &ss, &bb) == 3) ||
(sscanf(lptr, "INDEX 1 %02d:%02d:%02d", &mm, &ss, &bb) == 3))
{
/* adjust current track file read offset with current file PREGAP length (only used for AUDIO track) */
cdd.toc.tracks[cdd.toc.last].offset += pregap * 2352;
/* check if a single file is used for consecutive tracks */
if (!cdd.toc.tracks[cdd.toc.last].fd)
{
/* use common file descriptor */
cdd.toc.tracks[cdd.toc.last].fd = cdd.toc.tracks[0].fd;
/* current track start time (based on current file absolute time + PREGAP length) */
cdd.toc.tracks[cdd.toc.last].start = bb + ss*75 + mm*60*75 + pregap;
/* check if previous track end time needs to be set */
if (cdd.toc.last && !cdd.toc.tracks[cdd.toc.last - 1].end)
{
/* set previous track end time (based on current track start time, ignoring any "PREGAP"-type pause if no INDEX00) */
cdd.toc.tracks[cdd.toc.last - 1].end = cdd.toc.tracks[cdd.toc.last].start;
}
}
else
{
/* current file start time (based on previous track end time + PREGAP length) */
cdd.toc.tracks[cdd.toc.last].start = cdd.toc.end + pregap;
/* adjust current track file read offset with previous track end time (only used for AUDIO track) */
cdd.toc.tracks[cdd.toc.last].offset += cdd.toc.end * 2352;
#if defined(USE_LIBTREMOR) || defined(USE_LIBVORBIS)
if (cdd.toc.tracks[cdd.toc.last].vf.datasource)
{
/* convert read offset to PCM sample offset */
cdd.toc.tracks[cdd.toc.last].offset = cdd.toc.tracks[cdd.toc.last].offset / 4;
/* current track end time */
cdd.toc.tracks[cdd.toc.last].end = cdd.toc.tracks[cdd.toc.last].start + ov_pcm_total(&cdd.toc.tracks[cdd.toc.last].vf,-1)/588;
if (cdd.toc.tracks[cdd.toc.last].end <= cdd.toc.tracks[cdd.toc.last].start)
{
/* invalid length */
ov_clear(&cdd.toc.tracks[cdd.toc.last].vf);
cdd.toc.tracks[cdd.toc.last].fd = 0;
cdd.toc.tracks[cdd.toc.last].end = 0;
cdd.toc.tracks[cdd.toc.last].start = 0;
cdd.toc.tracks[cdd.toc.last].offset = 0;
break;
}
#ifdef DISABLE_MANY_OGG_OPEN_FILES
/* close VORBIS file structure to save memory */
ogg_free(cdd.toc.last);
#endif
}
else
#endif
{
/* current track end time */
cdStreamSeek(cdd.toc.tracks[cdd.toc.last].fd, 0, SEEK_END);
if (cdd.toc.tracks[cdd.toc.last].type)
{
/* DATA track length */
cdd.toc.tracks[cdd.toc.last].end = cdd.toc.tracks[cdd.toc.last].start + ((cdStreamTell(cdd.toc.tracks[cdd.toc.last].fd) + cdd.sectorSize - 1) / cdd.sectorSize);
}
else
{
/* AUDIO track length */
cdd.toc.tracks[cdd.toc.last].end = cdd.toc.tracks[cdd.toc.last].start + ((cdStreamTell(cdd.toc.tracks[cdd.toc.last].fd) + 2351) / 2352);
}
cdStreamSeek(cdd.toc.tracks[cdd.toc.last].fd, 0, SEEK_SET);
}
/* adjust track start time (based on current file start time + index absolute time) */
cdd.toc.tracks[cdd.toc.last].start += (bb + ss*75 + mm*60*75);
/* update TOC end */
cdd.toc.end = cdd.toc.tracks[cdd.toc.last].end;
}
/* increment track number */
cdd.toc.last++;
/* max. 99 tracks */
if (cdd.toc.last == 99) break;
}
}
/* check if last track end time needs to be set */
if (cdd.toc.last && !cdd.toc.tracks[cdd.toc.last - 1].end)
{
/* adjust TOC end with current file PREGAP length */
cdd.toc.end += pregap;
/* last track end time */
cdd.toc.tracks[cdd.toc.last - 1].end = cdd.toc.end;
}
/* close any incomplete track file */
#if defined(USE_LIBTREMOR) || defined(USE_LIBVORBIS)
if (cdd.toc.tracks[cdd.toc.last].vf.datasource)
{
ov_clear(&cdd.toc.tracks[cdd.toc.last].vf);
}
else
#endif
if (cdd.toc.tracks[cdd.toc.last].fd)
{
cdStreamClose(cdd.toc.tracks[cdd.toc.last].fd);
}
/* close CUE file */
cdStreamClose(fd);
}
else
{
int i, offset = 1;
/* set pointer at the end of filename */
ptr = fname + strlen(fname) - 4;
/* autodetect audio track file extensions */
for (i=0; i<SUPPORTED_EXT; i++)
{
/* auto-detect wrong initial track index */
sprintf(ptr, extensions[i], cdd.toc.last);
fd = cdStreamOpen(fname);
if (fd)
{
offset = 0;
break;
}
sprintf(ptr, extensions[i], cdd.toc.last + 1);
fd = cdStreamOpen(fname);
if (fd) break;
}
/* repeat until no more valid track files can be found */
while (fd)
{
/* read file HEADER */
unsigned char head[28];
cdStreamSeek(fd, 8, SEEK_SET);
cdStreamRead(head, 28, 1, fd);
cdStreamSeek(fd, 0, SEEK_SET);
/* check if this is a valid WAVE file (44.1KHz 16-bit stereo format only) */
if (!memcmp(head, waveHeader, 28))
{
/* look for 'data' chunk id */
int dataOffset = 0;
cdStreamSeek(fd, 36, SEEK_SET);
while (cdStreamRead(head, 4, 1, fd))
{
if (!memcmp(head, "data", 4))
{
dataOffset = cdStreamTell(fd) + 4;
break;
}
cdStreamSeek(fd, -2, SEEK_CUR);
}
/* check if 'data' chunk has not been found */
if (!dataOffset)
{
/* invalid WAVE file */
cdStreamClose(fd);
break;
}
/* initialize current track file descriptor */
cdd.toc.tracks[cdd.toc.last].fd = fd;
/* initialize current track start time (based on previous track end time) */
cdd.toc.tracks[cdd.toc.last].start = cdd.toc.end;
/* add default 2s PAUSE between tracks */
cdd.toc.tracks[cdd.toc.last].start += 150;
/* current track end time */
cdStreamSeek(fd, 0, SEEK_END);
cdd.toc.tracks[cdd.toc.last].end = cdd.toc.tracks[cdd.toc.last].start + ((cdStreamTell(fd) - dataOffset + 2351) / 2352);
/* initialize file read offset for current track */
cdd.toc.tracks[cdd.toc.last].offset = cdd.toc.tracks[cdd.toc.last].start * 2352;
/* auto-detect PAUSE within audio files */
cdStreamSeek(fd, 100 * 2352, SEEK_SET);
cdStreamRead(head, 4, 1, fd);
cdStreamSeek(fd, 0, SEEK_SET);
if (*(int32 *)head == 0)
{
/* assume 2s PAUSE is included at the beginning of the file */
cdd.toc.tracks[cdd.toc.last].offset -= 150 * 2352;
cdd.toc.tracks[cdd.toc.last].end -= 150;
}
/* update TOC end */
cdd.toc.end = cdd.toc.tracks[cdd.toc.last].end;
/* adjust file read offset for current track with WAVE header length */
cdd.toc.tracks[cdd.toc.last].offset -= dataOffset;
/* increment track number */
cdd.toc.last++;
}
#if defined(USE_LIBTREMOR) || defined(USE_LIBVORBIS)
else if (!ov_open_callbacks(fd,&cdd.toc.tracks[cdd.toc.last].vf,0,0,cb))
{
/* retrieve stream infos */
vorbis_info *info = ov_info(&cdd.toc.tracks[cdd.toc.last].vf,-1);
if (!info || (info->rate != 44100) || (info->channels != 2))
{
/* unsupported OGG file */
ov_clear(&cdd.toc.tracks[cdd.toc.last].vf);
break;
}
/* initialize current track file descriptor */
cdd.toc.tracks[cdd.toc.last].fd = fd;
/* initialize current track start time (based on previous track end time) */
cdd.toc.tracks[cdd.toc.last].start = cdd.toc.end;
/* add default 2s PAUSE between tracks */
cdd.toc.tracks[cdd.toc.last].start += 150;
/* current track end time */
cdd.toc.tracks[cdd.toc.last].end = cdd.toc.tracks[cdd.toc.last].start + ((ov_pcm_total(&cdd.toc.tracks[cdd.toc.last].vf,-1) + 587) / 588);
if (cdd.toc.tracks[cdd.toc.last].end <= cdd.toc.tracks[cdd.toc.last].start)
{
/* invalid file length */
ov_clear(&cdd.toc.tracks[cdd.toc.last].vf);
cdd.toc.tracks[cdd.toc.last].fd = 0;
cdd.toc.tracks[cdd.toc.last].end = 0;
cdd.toc.tracks[cdd.toc.last].start = 0;
break;
}
/* initialize file read offset for current track */
cdd.toc.tracks[cdd.toc.last].offset = cdd.toc.tracks[cdd.toc.last].start * 588;
/* auto-detect PAUSE within audio files */
ov_pcm_seek(&cdd.toc.tracks[cdd.toc.last].vf, 100 * 588);
#if defined(USE_LIBVORBIS)
ov_read(&cdd.toc.tracks[cdd.toc.last].vf, (char *)head, 32, 0, 2, 1, 0);
#else
ov_read(&cdd.toc.tracks[cdd.toc.last].vf, (char *)head, 32, 0);
#endif
ov_pcm_seek(&cdd.toc.tracks[cdd.toc.last].vf, 0);
if (*(int32 *)head == 0)
{
/* assume 2s PAUSE is included at the beginning of the file */
cdd.toc.tracks[cdd.toc.last].offset -= 150 * 588;
cdd.toc.tracks[cdd.toc.last].end -= 150;
}
#ifdef DISABLE_MANY_OGG_OPEN_FILES
/* close VORBIS file structure to save memory */
ogg_free(cdd.toc.last);
#endif
/* update TOC end */
cdd.toc.end = cdd.toc.tracks[cdd.toc.last].end;
/* increment track number */
cdd.toc.last++;
}
#endif
else
{
/* unsupported audio file format */
cdStreamClose(fd);
break;
}
/* max. 99 tracks */
if (cdd.toc.last == 99) break;
/* try to open next audio track file */
sprintf(ptr, extensions[i], cdd.toc.last + offset);
fd = cdStreamOpen(fname);
}
}
/* CD tracks found ? */
if (cdd.toc.last)
{
/* Lead-out */
cdd.toc.tracks[cdd.toc.last].start = cdd.toc.end;
/* CD mounted */
cdd.loaded = 1;
/* Valid DATA track found ? */
if (cdd.toc.tracks[0].type)
{
/* simulate audio tracks if none found */
if (cdd.toc.last == 1)
{
/* some games require exact TOC infos */
if (strstr(header + 0x180,"T-95035") != NULL)
{
/* Snatcher */
cdd.toc.last = cdd.toc.end = 0;
do
{
cdd.toc.tracks[cdd.toc.last].start = cdd.toc.end;
cdd.toc.tracks[cdd.toc.last].end = cdd.toc.tracks[cdd.toc.last].start + toc_snatcher[cdd.toc.last];
cdd.toc.end = cdd.toc.tracks[cdd.toc.last].end;
cdd.toc.last++;
}
while (cdd.toc.last < 21);
}
else if (strstr(header + 0x180,"T-127015") != NULL)
{
/* Lunar - The Silver Star */
cdd.toc.last = cdd.toc.end = 0;
do
{
cdd.toc.tracks[cdd.toc.last].start = cdd.toc.end;
cdd.toc.tracks[cdd.toc.last].end = cdd.toc.tracks[cdd.toc.last].start + toc_lunar[cdd.toc.last];
cdd.toc.end = cdd.toc.tracks[cdd.toc.last].end;
cdd.toc.last++;
}
while (cdd.toc.last < 52);
}
else if (strstr(header + 0x180,"T-113045") != NULL)
{
/* Shadow of the Beast II */
cdd.toc.last = cdd.toc.end = 0;
do
{
cdd.toc.tracks[cdd.toc.last].start = cdd.toc.end;
cdd.toc.tracks[cdd.toc.last].end = cdd.toc.tracks[cdd.toc.last].start + toc_shadow[cdd.toc.last];
cdd.toc.end = cdd.toc.tracks[cdd.toc.last].end;
cdd.toc.last++;
}
while (cdd.toc.last < 15);
}
else if (strstr(header + 0x180,"T-143025") != NULL)
{
/* Dungeon Explorer */
cdd.toc.last = cdd.toc.end = 0;
do
{
cdd.toc.tracks[cdd.toc.last].start = cdd.toc.end;
cdd.toc.tracks[cdd.toc.last].end = cdd.toc.tracks[cdd.toc.last].start + toc_dungeon[cdd.toc.last];
cdd.toc.end = cdd.toc.tracks[cdd.toc.last].end;
cdd.toc.last++;
}
while (cdd.toc.last < 13);
}
else if (strstr(header + 0x180,"MK-4410") != NULL)
{
/* Final Fight CD (USA, Europe) */
cdd.toc.last = cdd.toc.end = 0;
do
{
cdd.toc.tracks[cdd.toc.last].start = cdd.toc.end;
cdd.toc.tracks[cdd.toc.last].end = cdd.toc.tracks[cdd.toc.last].start + toc_ffight[cdd.toc.last];
cdd.toc.end = cdd.toc.tracks[cdd.toc.last].end;
cdd.toc.last++;
}
while (cdd.toc.last < 26);
}
else if (strstr(header + 0x180,"G-6013") != NULL)
{
/* Final Fight CD (Japan) */
cdd.toc.last = cdd.toc.end = 0;
do
{
cdd.toc.tracks[cdd.toc.last].start = cdd.toc.end;
cdd.toc.tracks[cdd.toc.last].end = cdd.toc.tracks[cdd.toc.last].start + toc_ffightj[cdd.toc.last];
cdd.toc.end = cdd.toc.tracks[cdd.toc.last].end;
cdd.toc.last++;
}
while (cdd.toc.last < 29);
}
else
{
/* default TOC (99 tracks & 2s per audio tracks) */
do
{
cdd.toc.tracks[cdd.toc.last].start = cdd.toc.end + 2*75;
cdd.toc.tracks[cdd.toc.last].end = cdd.toc.tracks[cdd.toc.last].start + 2*75;
cdd.toc.end = cdd.toc.tracks[cdd.toc.last].end;
cdd.toc.last++;
}
while ((cdd.toc.last < 99) && (cdd.toc.end < 56*60*75));
}
}
}
/* Automatically try to open associated subcode data file */
strncpy(&fname[strlen(fname) - 4], ".sub", 4);
cdd.toc.sub = cdStreamOpen(fname);
/* return 1 if loaded file is CD image file */
return (isCDfile);
}
/* no CD image file loaded */
return 0;
}