[Core/SCD] improved .cue file parsing

This commit is contained in:
EkeEke 2013-06-18 01:31:25 +02:00
parent 6635ab7ebf
commit 15d96065ba

View File

@ -250,7 +250,7 @@ int cdd_load(char *filename, char *header)
char fname[256]; char fname[256];
char line[128]; char line[128];
char *ptr = 0; char *ptr = 0;
char *lptr; char *lptr = 0;
FILE *fd; FILE *fd;
/* first unmount any loaded disc */ /* first unmount any loaded disc */
@ -260,11 +260,7 @@ int cdd_load(char *filename, char *header)
fd = fopen(filename, "rb"); fd = fopen(filename, "rb");
/* save a copy of base filename */ /* save a copy of base filename */
if (strlen(filename) < 256) strncpy(fname, filename, 256);
{
strncpy(fname, filename, strlen(filename));
fname[strlen(filename)] = 0;
}
/* autodetect .cue file */ /* autodetect .cue file */
if (!memcmp(".cue", &filename[strlen(filename) - 4], 4) || !memcmp(".CUE", &filename[strlen(filename) - 4], 4)) if (!memcmp(".cue", &filename[strlen(filename) - 4], 4) || !memcmp(".CUE", &filename[strlen(filename) - 4], 4))
@ -272,7 +268,6 @@ int cdd_load(char *filename, char *header)
if (fd) if (fd)
{ {
/* find first FILE command */ /* find first FILE command */
lptr = strstr(line, "FILE");
while (!lptr) while (!lptr)
{ {
if (fgets(line, 128, fd) == NULL) if (fgets(line, 128, fd) == NULL)
@ -297,7 +292,7 @@ int cdd_load(char *filename, char *header)
if (ptr - fname) ptr++; if (ptr - fname) ptr++;
/* append filename characters after filepath */ /* append filename characters after filepath */
while ((*lptr != '\"') && memcmp(lptr, " BINARY", 7)) while ((*lptr != '\"') && memcmp(lptr, " BINARY", 7) && (ptr < (fname + 255)))
{ {
*ptr++ = *lptr++; *ptr++ = *lptr++;
} }
@ -352,6 +347,7 @@ int cdd_load(char *filename, char *header)
/* close binary file */ /* close binary file */
fclose(cdd.toc.tracks[0].fd); fclose(cdd.toc.tracks[0].fd);
cdd.toc.tracks[0].fd = 0;
/* not a CD image file */ /* not a CD image file */
return 0; return 0;
@ -369,11 +365,11 @@ int cdd_load(char *filename, char *header)
/* read CD image header + security code */ /* read CD image header + security code */
fread(header + 0x10, 0x200, 1, cdd.toc.tracks[0].fd); fread(header + 0x10, 0x200, 1, cdd.toc.tracks[0].fd);
/* DATA track length (default) */ /* DATA track start time (based on DATA file length) */
fseek(cdd.toc.tracks[0].fd, 0, SEEK_END); fseek(cdd.toc.tracks[0].fd, 0, SEEK_END);
cdd.toc.tracks[0].end = ftell(cdd.toc.tracks[0].fd) / cdd.sectorSize; cdd.toc.tracks[0].end = ftell(cdd.toc.tracks[0].fd) / cdd.sectorSize;
/* DATA track start (logical block 0) */ /* DATA track start time (logical block 0) */
fseek(cdd.toc.tracks[0].fd, 0, SEEK_SET); fseek(cdd.toc.tracks[0].fd, 0, SEEK_SET);
cdd.toc.tracks[0].start = 0; cdd.toc.tracks[0].start = 0;
@ -406,13 +402,6 @@ int cdd_load(char *filename, char *header)
/* decode FILE commands */ /* decode FILE commands */
if (!(memcmp(lptr, "FILE", 4))) if (!(memcmp(lptr, "FILE", 4)))
{ {
/* check supported file types */
if (!strstr(lptr," BINARY") && !strstr(lptr," WAV"))
{
/* unsupported file type */
break;
}
/* skip "FILE" attribute */ /* skip "FILE" attribute */
lptr += 4; lptr += 4;
@ -425,13 +414,13 @@ int cdd_load(char *filename, char *header)
if (ptr - fname) ptr++; if (ptr - fname) ptr++;
/* append filename characters after filepath */ /* append filename characters after filepath */
while ((*lptr != '\"') && memcmp(lptr, " BINARY", 7) && memcmp(lptr, " WAV", 4)) while ((*lptr != '\"') && (lptr <= (line + 128)) && (ptr < (fname + 255)))
{ {
*ptr++ = *lptr++; *ptr++ = *lptr++;
} }
*ptr = 0; *ptr = 0;
/* open file & initialize AUDIO track file descriptor */ /* open file & initialize track file descriptor */
cdd.toc.tracks[cdd.toc.last].fd = fopen(fname, "rb"); cdd.toc.tracks[cdd.toc.last].fd = fopen(fname, "rb");
if (!cdd.toc.tracks[cdd.toc.last].fd) if (!cdd.toc.tracks[cdd.toc.last].fd)
{ {
@ -441,6 +430,47 @@ int cdd_load(char *filename, char *header)
/* reset current file PREGAP length */ /* reset current file PREGAP length */
pregap = 0; pregap = 0;
/* reset current file read offset */
cdd.toc.tracks[cdd.toc.last].offset = 0;
/* check supported file types */
if (!strstr(lptr,"BINARY"))
{
/* read file header */
unsigned char head[32];
fseek(cdd.toc.tracks[cdd.toc.last].fd, 8, SEEK_SET);
fread(head, 32, 1, cdd.toc.tracks[cdd.toc.last].fd);
fseek(cdd.toc.tracks[cdd.toc.last].fd, 0, SEEK_SET);
/* autodetect WAVE file header (16-bit stereo @44.1kHz only) */
if (!memcmp(head, waveHeader, 32))
{
/* adjust current track file read offset with WAVE header length */
cdd.toc.tracks[cdd.toc.last].offset -= 44;
}
#ifdef USE_LIBTREMOR
else if (!ov_open(cdd.toc.tracks[cdd.toc.last].fd,&cdd.toc.tracks[cdd.toc.last].vf,0,0))
{
/* 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 */
fclose(cdd.toc.tracks[cdd.toc.last].fd);
cdd.toc.tracks[cdd.toc.last].fd = 0;
break;
}
}
} }
/* decode TRACK commands */ /* decode TRACK commands */
@ -453,6 +483,7 @@ int cdd_load(char *filename, char *header)
if (cdd.toc.tracks[cdd.toc.last].fd) if (cdd.toc.tracks[cdd.toc.last].fd)
{ {
fclose(cdd.toc.tracks[cdd.toc.last].fd); fclose(cdd.toc.tracks[cdd.toc.last].fd);
cdd.toc.tracks[cdd.toc.last].fd = 0;
} }
/* missing tracks */ /* missing tracks */
@ -462,7 +493,7 @@ int cdd_load(char *filename, char *header)
/* check if a single file is used for all tracks */ /* check if a single file is used for all tracks */
if (!cdd.toc.tracks[cdd.toc.last].fd) if (!cdd.toc.tracks[cdd.toc.last].fd)
{ {
/* clear previous track end index */ /* clear previous track end time */
cdd.toc.tracks[cdd.toc.last - 1].end = 0; cdd.toc.tracks[cdd.toc.last - 1].end = 0;
} }
} }
@ -481,60 +512,72 @@ int cdd_load(char *filename, char *header)
/* check if a single file is used for all tracks */ /* check if a single file is used for all tracks */
if (!cdd.toc.tracks[cdd.toc.last].fd) if (!cdd.toc.tracks[cdd.toc.last].fd)
{ {
/* set previous track end index */ /* set previous track end time */
cdd.toc.tracks[cdd.toc.last - 1].end = bb + ss*75 + mm*60*75 + pregap; 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) || else if ((sscanf(lptr, "INDEX 01 %02d:%02d:%02d", &mm, &ss, &bb) == 3) ||
(sscanf(lptr, "INDEX 1 %02d:%02d:%02d", &mm, &ss, &bb) == 3)) (sscanf(lptr, "INDEX 1 %02d:%02d:%02d", &mm, &ss, &bb) == 3))
{ {
char id[4]; /* adjust file read offset for current track with current file PREGAP length */
cdd.toc.tracks[cdd.toc.last].offset += pregap * 2352;
/* set file read offset for current track with current file PREGAP length */
cdd.toc.tracks[cdd.toc.last].offset = pregap * 2352;
/* check if a single file is used for all tracks */ /* check if a single file is used for all tracks */
if (!cdd.toc.tracks[cdd.toc.last].fd) if (!cdd.toc.tracks[cdd.toc.last].fd)
{ {
/* previous track end index already set (through INDEX00 command) ? */
if (cdd.toc.tracks[cdd.toc.last - 1].end == 0)
{
/* if not, set previous track end index */
cdd.toc.tracks[cdd.toc.last - 1].end = bb + ss*75 + mm*60*75;
}
/* current track start index */
cdd.toc.tracks[cdd.toc.last].start = bb + ss*75 + mm*60*75 + pregap;
/* use common file descriptor */ /* use common file descriptor */
cdd.toc.tracks[cdd.toc.last].fd = cdd.toc.tracks[0].fd; cdd.toc.tracks[cdd.toc.last].fd = cdd.toc.tracks[0].fd;
/* current track start time (based on current absolute time) */
cdd.toc.tracks[cdd.toc.last].start = bb + ss*75 + mm*60*75 + pregap;
/* check if previous track end time has not been already set (through INDEX00 command) */
if (cdd.toc.tracks[cdd.toc.last - 1].end == 0)
{
/* set previous track end time (based on current absolute timee) */
cdd.toc.tracks[cdd.toc.last - 1].end = bb + ss*75 + mm*60*75;
}
} }
else else
{ {
/* adjust file read offset with previous track end index */ /* current track start time (based on previous track end time) */
cdd.toc.tracks[cdd.toc.last].start = cdd.toc.end + bb + ss*75 + mm*60*75 + pregap;
/* adjust file read offset with previous track end time */
cdd.toc.tracks[cdd.toc.last].offset += cdd.toc.end * 2352; cdd.toc.tracks[cdd.toc.last].offset += cdd.toc.end * 2352;
/* current track start index */ #ifdef USE_LIBTREMOR
cdd.toc.tracks[cdd.toc.last].start = (cdd.toc.tracks[cdd.toc.last].offset / 2352) + bb + ss*75 + mm*60*75; 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 index */ /* 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;
}
}
else
#endif
{
/* current track end time */
fseek(cdd.toc.tracks[cdd.toc.last].fd, 0, SEEK_END); fseek(cdd.toc.tracks[cdd.toc.last].fd, 0, SEEK_END);
cdd.toc.tracks[cdd.toc.last].end = cdd.toc.tracks[cdd.toc.last].start + ((ftell(cdd.toc.tracks[cdd.toc.last].fd) + 2351) / 2352); cdd.toc.tracks[cdd.toc.last].end = cdd.toc.tracks[cdd.toc.last].start + ((ftell(cdd.toc.tracks[cdd.toc.last].fd) + 2351) / 2352);
fseek(cdd.toc.tracks[cdd.toc.last].fd, 0, SEEK_SET);
}
/* update TOC end */ /* update TOC end */
cdd.toc.end = cdd.toc.tracks[cdd.toc.last].end; cdd.toc.end = cdd.toc.tracks[cdd.toc.last].end;
} }
/* autodetect WAVE header (note: sometime found in BIN files as well) */
fseek(cdd.toc.tracks[cdd.toc.last].fd, (cdd.toc.tracks[cdd.toc.last].start * 2352) - cdd.toc.tracks[cdd.toc.last].offset, SEEK_SET);
fread(id, 4, 1, cdd.toc.tracks[cdd.toc.last].fd);
if (!memcmp(id,"RIFF",4))
{
/* adjust current track file read offset with WAVE header length */
cdd.toc.tracks[cdd.toc.last].offset -= 44;
}
fseek(cdd.toc.tracks[cdd.toc.last].fd, 0, SEEK_SET);
/* increment track number */ /* increment track number */
cdd.toc.last++; cdd.toc.last++;
} }
@ -598,13 +641,13 @@ int cdd_load(char *filename, char *header)
/* initialize current track file descriptor */ /* initialize current track file descriptor */
cdd.toc.tracks[cdd.toc.last].fd = fd; cdd.toc.tracks[cdd.toc.last].fd = fd;
/* initialize current track start index with previous track end index */ /* initialize current track start time (based on previous track end time) */
cdd.toc.tracks[cdd.toc.last].start = cdd.toc.end; cdd.toc.tracks[cdd.toc.last].start = cdd.toc.end;
/* add default 2s PAUSE between tracks */ /* add default 2s PAUSE between tracks */
cdd.toc.tracks[cdd.toc.last].start += 150; cdd.toc.tracks[cdd.toc.last].start += 150;
/* current track end index */ /* current track end time */
fseek(fd, 0, SEEK_END); fseek(fd, 0, SEEK_END);
cdd.toc.tracks[cdd.toc.last].end = cdd.toc.tracks[cdd.toc.last].start + ((ftell(fd) + 2351) / 2352); cdd.toc.tracks[cdd.toc.last].end = cdd.toc.tracks[cdd.toc.last].start + ((ftell(fd) + 2351) / 2352);
@ -614,13 +657,13 @@ int cdd_load(char *filename, char *header)
/* auto-detect PAUSE within audio files */ /* auto-detect PAUSE within audio files */
fseek(fd, 100 * 2352, SEEK_SET); fseek(fd, 100 * 2352, SEEK_SET);
fread(head, 4, 1, fd); fread(head, 4, 1, fd);
fseek(fd, 0, SEEK_SET);
if (*(int32 *)head == 0) if (*(int32 *)head == 0)
{ {
/* assume 2s PAUSE is included at the beginning of the file */ /* 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].offset -= 150 * 2352;
cdd.toc.tracks[cdd.toc.last].end -= 150; cdd.toc.tracks[cdd.toc.last].end -= 150;
} }
fseek(fd, 0, SEEK_SET);
/* update TOC end */ /* update TOC end */
cdd.toc.end = cdd.toc.tracks[cdd.toc.last].end; cdd.toc.end = cdd.toc.tracks[cdd.toc.last].end;
@ -646,17 +689,17 @@ int cdd_load(char *filename, char *header)
/* initialize current track file descriptor */ /* initialize current track file descriptor */
cdd.toc.tracks[cdd.toc.last].fd = fd; cdd.toc.tracks[cdd.toc.last].fd = fd;
/* initialize current track start index with previous track end index */ /* initialize current track start time (based on previous track end time) */
cdd.toc.tracks[cdd.toc.last].start = cdd.toc.end; cdd.toc.tracks[cdd.toc.last].start = cdd.toc.end;
/* add default 2s PAUSE between tracks */ /* add default 2s PAUSE between tracks */
cdd.toc.tracks[cdd.toc.last].start += 150; cdd.toc.tracks[cdd.toc.last].start += 150;
/* current track end index */ /* 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; 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) if (cdd.toc.tracks[cdd.toc.last].end <= cdd.toc.tracks[cdd.toc.last].start)
{ {
/* invalid length */ /* invalid file length */
ov_clear(&cdd.toc.tracks[cdd.toc.last].vf); ov_clear(&cdd.toc.tracks[cdd.toc.last].vf);
cdd.toc.tracks[cdd.toc.last].fd = 0; cdd.toc.tracks[cdd.toc.last].fd = 0;
cdd.toc.tracks[cdd.toc.last].end = 0; cdd.toc.tracks[cdd.toc.last].end = 0;
@ -667,13 +710,13 @@ int cdd_load(char *filename, char *header)
/* auto-detect PAUSE within audio files */ /* auto-detect PAUSE within audio files */
ov_pcm_seek(&cdd.toc.tracks[cdd.toc.last].vf, 100 * 588); ov_pcm_seek(&cdd.toc.tracks[cdd.toc.last].vf, 100 * 588);
ov_read(&cdd.toc.tracks[cdd.toc.last].vf, (char *)head, 32, 0); ov_read(&cdd.toc.tracks[cdd.toc.last].vf, (char *)head, 32, 0);
ov_pcm_seek(&cdd.toc.tracks[cdd.toc.last].vf, 0);
if (*(int32 *)head == 0) if (*(int32 *)head == 0)
{ {
/* assume 2s PAUSE is included at the beginning of the file */ /* 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].offset -= 150 * 588;
cdd.toc.tracks[cdd.toc.last].end -= 150; cdd.toc.tracks[cdd.toc.last].end -= 150;
} }
ov_pcm_seek(&cdd.toc.tracks[cdd.toc.last].vf, 0);
/* update TOC end */ /* update TOC end */
cdd.toc.end = cdd.toc.tracks[cdd.toc.last].end; cdd.toc.end = cdd.toc.tracks[cdd.toc.last].end;