diff options
Diffstat (limited to 'trunk/src/lib/util/chdcd.c')
-rw-r--r-- | trunk/src/lib/util/chdcd.c | 1020 |
1 files changed, 1020 insertions, 0 deletions
diff --git a/trunk/src/lib/util/chdcd.c b/trunk/src/lib/util/chdcd.c new file mode 100644 index 00000000000..0c827e36098 --- /dev/null +++ b/trunk/src/lib/util/chdcd.c @@ -0,0 +1,1020 @@ +/*************************************************************************** + + TOC parser for CHD compression frontend + Handles CDRDAO .toc, CDRWIN .cue, and Sega GDROM .gdi + + Copyright Nicola Salmoria and the MAME Team. + Visit http://mamedev.org for licensing and usage restrictions. + +***************************************************************************/ + +#include <ctype.h> +#include <stdlib.h> +#include "osdcore.h" +#include "chd.h" +#include "chdcd.h" +#include "corefile.h" + + + +/*************************************************************************** + CONSTANTS & DEFINES +***************************************************************************/ + +#define TOKENIZE i = tokenize( linebuffer, i, sizeof(linebuffer), token, sizeof(token) ); + + + +/*************************************************************************** + GLOBAL VARIABLES +***************************************************************************/ + +static char linebuffer[512]; + + + +/*************************************************************************** + IMPLEMENTATION +***************************************************************************/ + +static astring get_file_path(astring &path) +{ + int pos = path.rchr( 0, '\\'); + if (pos!=-1) { + path = path.substr(0,pos+1); + } else { + pos = path.rchr( 0, '/'); + path = path.substr(0,pos+1); + } + return path; +} +/*------------------------------------------------- + get_file_size - get the size of a file +-------------------------------------------------*/ + +static UINT64 get_file_size(const char *filename) +{ + osd_file *file; + UINT64 filesize = 0; + file_error filerr; + + filerr = osd_open(filename, OPEN_FLAG_READ, &file, &filesize); + if (filerr == FILERR_NONE) + osd_close(file); + + return filesize; +} + + +/*------------------------------------------------- + tokenize - get a token from the line buffer +-------------------------------------------------*/ + +static int tokenize( const char *linebuffer, int i, int linebuffersize, char *token, int tokensize ) +{ + int j = 0; + int singlequote = 0; + int doublequote = 0; + + while ((i < linebuffersize) && isspace((UINT8)linebuffer[i])) + { + i++; + } + + while ((i < linebuffersize) && (j < tokensize)) + { + if (!singlequote && linebuffer[i] == '"' ) + { + doublequote = !doublequote; + } + else if (!doublequote && linebuffer[i] == '\'') + { + singlequote = !singlequote; + } + else if (!singlequote && !doublequote && isspace((UINT8)linebuffer[i])) + { + break; + } + else + { + token[j] = linebuffer[i]; + j++; + } + + i++; + } + + token[j] = '\0'; + + return i; +} + + +/*------------------------------------------------- + msf_to_frames - convert m:s:f into a number of frames +-------------------------------------------------*/ + +static int msf_to_frames( char *token ) +{ + int m = 0; + int s = 0; + int f = 0; + + if( sscanf( token, "%d:%d:%d", &m, &s, &f ) == 1 ) + { + f = m; + } + else + { + /* convert to just frames */ + s += (m * 60); + f += (s * 75); + } + + return f; +} + +/*------------------------------------------------- + parse_wav_sample - takes a .WAV file, verifies + that the file is 16 bits, and returns the + length in bytes of the data and the offset in + bytes to where the data starts in the file. +-------------------------------------------------*/ +static UINT32 parse_wav_sample(char *filename, UINT32 *dataoffs) +{ + unsigned long offset = 0; + UINT32 length, rate, filesize; + UINT16 bits, temp16; + char buf[32]; + osd_file *file; + file_error filerr; + UINT64 fsize = 0; + UINT32 actual; + + filerr = osd_open(filename, OPEN_FLAG_READ, &file, &fsize); + if (filerr != FILERR_NONE) + { + osd_close(file); + return 0; + } + + /* read the core header and make sure it's a WAVE file */ + osd_read(file, buf, 0, 4, &actual); + offset += actual; + if (offset < 4) + return 0; + if (memcmp(&buf[0], "RIFF", 4) != 0) + return 0; + + /* get the total size */ + osd_read(file, &filesize, offset, 4, &actual); + offset += actual; + if (offset < 8) + return 0; + filesize = LITTLE_ENDIANIZE_INT32(filesize); + + /* read the RIFF file type and make sure it's a WAVE file */ + osd_read(file, buf, offset, 4, &actual); + offset += actual; + if (offset < 12) + return 0; + if (memcmp(&buf[0], "WAVE", 4) != 0) + return 0; + + /* seek until we find a format tag */ + while (1) + { + osd_read(file, buf, offset, 4, &actual); + offset += actual; + osd_read(file, &length, offset, 4, &actual); + offset += actual; + length = LITTLE_ENDIANIZE_INT32(length); + if (memcmp(&buf[0], "fmt ", 4) == 0) + break; + + /* seek to the next block */ + offset += length; + if (offset >= filesize) + return 0; + } + + /* read the format -- make sure it is PCM */ + osd_read(file, &temp16, offset, 2, &actual); + offset += actual; + temp16 = LITTLE_ENDIANIZE_INT16(temp16); + if (temp16 != 1) + return 0; + + /* number of channels -- only mono is supported */ + osd_read(file, &temp16, offset, 2, &actual); + offset += actual; + temp16 = LITTLE_ENDIANIZE_INT16(temp16); + if (temp16 != 2) + return 0; + + /* sample rate */ + osd_read(file, &rate, offset, 4, &actual); + offset += actual; + rate = LITTLE_ENDIANIZE_INT32(rate); + if (rate != 44100) + return 0; + + /* bytes/second and block alignment are ignored */ + osd_read(file, buf, offset, 6, &actual); + offset += actual; + + /* bits/sample */ + osd_read(file, &bits, offset, 2, &actual); + offset += actual; + if (bits != 16) + return 0; + + /* seek past any extra data */ + offset += length - 16; + + /* seek until we find a data tag */ + while (1) + { + osd_read(file, buf, offset, 4, &actual); + offset += actual; + osd_read(file, &length, offset, 4, &actual); + offset += actual; + length = LITTLE_ENDIANIZE_INT32(length); + if (memcmp(&buf[0], "data", 4) == 0) + break; + + /* seek to the next block */ + offset += length; + if (offset >= filesize) + return 0; + } + + /* if there was a 0 length data block, we're done */ + if (length == 0) + return 0; + + osd_close(file); + + *dataoffs = offset; + + return length; +} + +UINT16 read_uint16(FILE *infile) +{ + UINT16 res = 0; + unsigned char buffer[2]; + + fread(buffer, 2, 1, infile); + + res = buffer[1] | buffer[0]<<8; + + return res; +} + +UINT32 read_uint32(FILE *infile) +{ + UINT32 res = 0; + unsigned char buffer[4]; + + fread(buffer, 4, 1, infile); + + res = buffer[3] | buffer[2]<<8 | buffer[1]<<16 | buffer[0]<<24; + + return res; +} + +UINT64 read_uint64(FILE *infile) +{ + UINT64 res0 = U64(0), res1 = U64(0); + UINT64 res; + unsigned char buffer[8]; + + fread(buffer, 8, 1, infile); + + res0 = buffer[3] | buffer[2]<<8 | buffer[1]<<16 | buffer[0]<<24; + res1 = buffer[7] | buffer[6]<<8 | buffer[5]<<16 | buffer[4]<<24; + + res = res0<<32 | res1; + + return res; +} + +/*------------------------------------------------- + chdcd_parse_toc - parse a CDRWin format CUE file +-------------------------------------------------*/ + +chd_error chdcd_parse_nero(const char *tocfname, cdrom_toc *outtoc, chdcd_track_input_info *outinfo) +{ + FILE *infile; + unsigned char buffer[12]; + UINT32 chain_offs, chunk_size; + int done = 0; + + astring path = astring(tocfname); + + infile = fopen(tocfname, "rt"); + path = get_file_path(path); + + if (infile == (FILE *)NULL) + { + return CHDERR_FILE_NOT_FOUND; + } + + /* clear structures */ + memset(outtoc, 0, sizeof(cdrom_toc)); + memset(outinfo, 0, sizeof(chdcd_track_input_info)); + + // seek to 12 bytes before the end + fseek(infile, -12, SEEK_END); + fread(buffer, 12, 1, infile); + + if (memcmp(buffer, "NER5", 4)) + { + printf("ERROR: Not a Nero 5.5 or later image!\n"); + fclose(infile); + return CHDERR_FILE_NOT_FOUND; + } + + chain_offs = buffer[11] | (buffer[10]<<8) | (buffer[9]<<16) | (buffer[8]<<24); + + if ((buffer[7] != 0) || (buffer[6] != 0) || (buffer[5] != 0) || (buffer[4] != 0)) + { + printf("ERROR: File size is > 4GB, this version of CHDMAN cannot handle it."); + fclose(infile); + return CHDERR_FILE_NOT_FOUND; + } + +// printf("NER5 detected, chain offset: %x\n", chain_offs); + + while (!done) + { + UINT32 offset; + UINT8 start, end; + int track; + + fseek(infile, chain_offs, SEEK_SET); + fread(buffer, 8, 1, infile); + + chunk_size = (buffer[7] | buffer[6]<<8 | buffer[5]<<16 | buffer[4]<<24); + +// printf("Chunk type: %c%c%c%c, size %x\n", buffer[0], buffer[1], buffer[2], buffer[3], chunk_size); + + // we want the DAOX chunk, which has the TOC information + if (!memcmp(buffer, "DAOX", 4)) + { + // skip second chunk size and UPC code + fseek(infile, 16, SEEK_CUR); + + read_uint32(infile); + fread(&start, 1, 1, infile); + fread(&end, 1, 1, infile); + +// printf("TOC type: %08x. Start track %d End track: %d\n", toc_type, start, end); + + outtoc->numtrks = (end-start) + 1; + + offset = 0; + for (track = start; track <= end; track++) + { + UINT32 size, mode; + UINT64 index0, index1, index2; + + fseek(infile, 12, SEEK_CUR); // skip ISRC code + size = read_uint16(infile); + mode = read_uint32(infile); + index0 = read_uint64(infile); + index1 = read_uint64(infile); + index2 = read_uint64(infile); + +// printf("Track %d: sector size %d mode %x index0 %llx index1 %llx index2 %llx (pregap %d sectors, length %d sectors)\n", track, size, mode, index0, index1, index2, (UINT32)(index1-index0)/size, (UINT32)(index2-index1)/size); + strncpy(outinfo->fname[track-1], path.cstr(), 256); + strncat(outinfo->fname[track-1], tocfname, 256); + outinfo->offset[track-1] = offset + (UINT32)(index1-index0); + outinfo->idx0offs[track-1] = 0; + outinfo->idx1offs[track-1] = 0; + + switch (mode>>24) + { + case 0x00: // 2048 byte data + outtoc->tracks[track-1].trktype = CD_TRACK_MODE1; + outinfo->swap[track-1] = 0; + break; + + case 0x06: // 2352 byte mode 2 raw + outtoc->tracks[track-1].trktype = CD_TRACK_MODE2_RAW; + outinfo->swap[track-1] = 0; + break; + + case 0x07: // 2352 byte audio + outtoc->tracks[track-1].trktype = CD_TRACK_AUDIO; + outinfo->swap[track-1] = 1; + break; + + default: + printf("ERROR: Unknown track type %x, contact MAMEDEV!\n", mode>>24); + break; + } + + outtoc->tracks[track-1].datasize = size; + + outtoc->tracks[track-1].subtype = CD_SUB_NONE; + outtoc->tracks[track-1].subsize = 0; + + outtoc->tracks[track-1].pregap = (UINT32)(index1-index0)/size; + outtoc->tracks[track-1].frames = (UINT32)(index2-index1)/size; + outtoc->tracks[track-1].postgap = 0; + outtoc->tracks[track-1].pgtype = 0; + outtoc->tracks[track-1].pgsub = CD_SUB_NONE; + outtoc->tracks[track-1].pgdatasize = 0; + outtoc->tracks[track-1].pgsubsize = 0; + + offset += (UINT32)index2-index1; + } + } + + if (!memcmp(buffer, "END!", 4)) + { + done = 1; + } + else + { + chain_offs += chunk_size + 8; + } + } + + fclose(infile); + + return CHDERR_NONE; +} + +/*------------------------------------------------- + chdcd_parse_gdi - parse a Sega GD-ROM rip +-------------------------------------------------*/ + +static chd_error chdcd_parse_gdi(const char *tocfname, cdrom_toc *outtoc, chdcd_track_input_info *outinfo) +{ + FILE *infile; + int i, numtracks; + //int chdpos=0; + + astring path = astring(tocfname); + + infile = fopen(tocfname, "rt"); + path = get_file_path(path); + + if (infile == (FILE *)NULL) + { + return CHDERR_FILE_NOT_FOUND; + } + + /* clear structures */ + memset(outtoc, 0, sizeof(cdrom_toc)); + memset(outinfo, 0, sizeof(chdcd_track_input_info)); + + + fgets(linebuffer,511,infile); + numtracks=atoi(linebuffer); + + for(i=0;i<numtracks;++i) + { + char *tok; + int trknum; + int trksize,trktype; + int sz; + int hunks; + + + fgets(linebuffer,511,infile); + + tok=strtok(linebuffer," "); + + trknum=atoi(tok)-1; + + outinfo->swap[trknum]=0; + outinfo->offset[trknum]=0; + + //outtoc->tracks[trknum].trktype = CD_TRACK_MODE1; + outtoc->tracks[trknum].datasize = 0; + outtoc->tracks[trknum].subtype = CD_SUB_NONE; + outtoc->tracks[trknum].subsize = 0; + + tok=strtok(NULL," "); + outtoc->tracks[trknum].physframeofs=atoi(tok); + + tok=strtok(NULL," "); + trktype=atoi(tok); + + tok=strtok(NULL," "); + trksize=atoi(tok); + + if(trktype==4 && trksize==2352) + { + outtoc->tracks[trknum].trktype=CD_TRACK_MODE1_RAW; + outtoc->tracks[trknum].datasize=2352; + } + if(trktype==4 && trksize==2048) + { + outtoc->tracks[trknum].trktype=CD_TRACK_MODE1; + outtoc->tracks[trknum].datasize=2048; + } + if(trktype==0) + { + //assert(trksize==2352); + outtoc->tracks[trknum].trktype=CD_TRACK_AUDIO; + outtoc->tracks[trknum].datasize=2352; + } + + astring name; + + tok=strtok(NULL," "); + name = tok; + if (tok[0]=='"') { + do { + tok=strtok(NULL," "); + if (tok!=NULL) { + name += " "; + name += tok; + } + } while(tok!=NULL && (strrchr(tok,'"')-tok !=(strlen(tok)-1))); + name = name.delchr('"'); + } + strncpy(outinfo->fname[trknum], path.cstr(), 256); + strncat(outinfo->fname[trknum], name, 256); + + sz=get_file_size(outinfo->fname[trknum]); + + outtoc->tracks[trknum].frames=sz/trksize; + outtoc->tracks[trknum].extraframes=0; + + if(trknum!=0) + { + int dif=outtoc->tracks[trknum].physframeofs-(outtoc->tracks[trknum-1].frames+outtoc->tracks[trknum-1].physframeofs); + outtoc->tracks[trknum-1].frames+=dif; + } + +/* + if(trknum!=0) + { + outtoc->tracks[trknum-1].extraframes=outtoc->tracks[trknum].physframeofs-(outtoc->tracks[trknum-1].frames+outtoc->tracks[trknum-1].physframeofs); + } +*/ + hunks = (outtoc->tracks[trknum].frames+CD_FRAMES_PER_HUNK - 1) / CD_FRAMES_PER_HUNK; + outtoc->tracks[trknum].extraframes = hunks * CD_FRAMES_PER_HUNK - outtoc->tracks[trknum].frames; + + //chdpos+=outtoc->tracks[trknum].frames+outtoc->tracks[trknum].extraframes; + + } + /* + for(i=0;i<numtracks;++i) + { + printf("%s %d %d %d\n",outinfo->fname[i],outtoc->tracks[i].frames,outtoc->tracks[i].extraframes,outtoc->tracks[i].physframeofs); + } + */ + /* close the input TOC */ + fclose(infile); + + /* store the number of tracks found */ + outtoc->numtrks = numtracks; + + return CHDERR_NONE; +} + +/*------------------------------------------------- + chdcd_parse_toc - parse a CDRWin format CUE file +-------------------------------------------------*/ + +chd_error chdcd_parse_cue(const char *tocfname, cdrom_toc *outtoc, chdcd_track_input_info *outinfo) +{ + FILE *infile; + int i, trknum; + static char token[128]; + static char lastfname[256]; + UINT32 wavlen, wavoffs; + astring path = astring(tocfname); + + infile = fopen(tocfname, "rt"); + path = get_file_path(path); + if (infile == (FILE *)NULL) + { + return CHDERR_FILE_NOT_FOUND; + } + + /* clear structures */ + memset(outtoc, 0, sizeof(cdrom_toc)); + memset(outinfo, 0, sizeof(chdcd_track_input_info)); + + trknum = -1; + wavoffs = wavlen = 0; + + while (!feof(infile)) + { + /* get the next line */ + fgets(linebuffer, 511, infile); + + /* if EOF didn't hit, keep going */ + if (!feof(infile)) + { + i = 0; + + TOKENIZE + + if (!strcmp(token, "FILE")) + { + /* found the data file for a track */ + TOKENIZE + + /* keep the filename */ + strncpy(lastfname, path.cstr(), 256); + strncat(lastfname, token, 256); + + /* get the file type */ + TOKENIZE + + if (!strcmp(token, "BINARY")) + { + outinfo->swap[trknum] = 0; + } + else if (!strcmp(token, "MOTOROLA")) + { + outinfo->swap[trknum] = 1; + } + else if (!strcmp(token, "WAVE")) + { + wavlen = parse_wav_sample(lastfname, &wavoffs); + if (!wavlen) + { + file_error err; + core_file *fhand; + + err = core_fopen(lastfname, OPEN_FLAG_READ, &fhand); + if (err != FILERR_NONE) printf("holy moley!\n"); + else core_fclose(fhand); + + printf("ERROR: couldn't read [%s] or not a valid .WAV\n", lastfname); + return CHDERR_FILE_NOT_FOUND; + } + } + else + { + printf("ERROR: Unhandled track type %s\n", token); + return CHDERR_FILE_NOT_FOUND; + } + } + else if (!strcmp(token, "TRACK")) + { + /* get the track number */ + TOKENIZE + trknum = strtoul(token, NULL, 10) - 1; + + /* next token on the line is the track type */ + TOKENIZE + + if (wavlen != 0) + { + outtoc->tracks[trknum].trktype = CD_TRACK_AUDIO; + outtoc->tracks[trknum].frames = wavlen/2352; + outinfo->offset[trknum] = wavoffs; + wavoffs = wavlen = 0; + } + else + { + outtoc->tracks[trknum].trktype = CD_TRACK_MODE1; + outtoc->tracks[trknum].datasize = 0; + outinfo->offset[trknum] = 0; + } + outtoc->tracks[trknum].subtype = CD_SUB_NONE; + outtoc->tracks[trknum].subsize = 0; + outtoc->tracks[trknum].pregap = 0; + outinfo->idx0offs[trknum] = -1; + outinfo->idx1offs[trknum] = 0; + + strncpy(outinfo->fname[trknum], lastfname, 256); // default filename to the last one +// printf("trk %d: fname %s offset %d\n", trknum, &outinfo->fname[trknum][0], outinfo->offset[trknum]); + + cdrom_convert_type_string_to_track_info(token, &outtoc->tracks[trknum]); + if (outtoc->tracks[trknum].datasize == 0) + { + printf("ERROR: Unknown track type [%s]. Contact MAMEDEV.\n", token); + return CHDERR_FILE_NOT_FOUND; + } + + /* next (optional) token on the line is the subcode type */ + TOKENIZE + + cdrom_convert_subtype_string_to_track_info(token, &outtoc->tracks[trknum]); + } + else if (!strcmp(token, "INDEX")) /* only in bin/cue files */ + { + int idx, frames; + + /* get index number */ + TOKENIZE + idx = strtoul(token, NULL, 10); + + /* get index */ + TOKENIZE + frames = msf_to_frames( token ); + + if (idx == 0) + { + outinfo->idx0offs[trknum] = frames; + } + else if (idx == 1) + { + outinfo->idx1offs[trknum] = frames; + if ((outtoc->tracks[trknum].pregap == 0) && (outinfo->idx0offs[trknum] != -1)) + { + outtoc->tracks[trknum].pregap = frames - outinfo->idx0offs[trknum]; + } + } + } + else if (!strcmp(token, "PREGAP")) + { + int frames; + + /* get index */ + TOKENIZE + frames = msf_to_frames( token ); + + outtoc->tracks[trknum].pregap = frames; + } + else if (!strcmp(token, "POSTGAP")) + { + int frames; + + /* get index */ + TOKENIZE + frames = msf_to_frames( token ); + + outtoc->tracks[trknum].postgap = frames; + } + } + } + + /* close the input CUE */ + fclose(infile); + + /* store the number of tracks found */ + outtoc->numtrks = trknum + 1; + + /* now go over the files again and set the lengths */ + for (trknum = 0; trknum < outtoc->numtrks; trknum++) + { + UINT64 tlen = 0; + + // this is true for cue/bin and cue/iso, and we need it for cue/wav since .WAV is little-endian + if (outtoc->tracks[trknum].trktype == CD_TRACK_AUDIO) + { + outinfo->swap[trknum] = 1; + } + + // don't do this for .WAV tracks, we already have their length and offset filled out + if (outinfo->offset[trknum] == 0) + { + // is this the last track? + if (trknum == (outtoc->numtrks-1)) + { + /* if we have the same filename as the last track, do it that way */ + if (!strcmp(&outinfo->fname[trknum][0], &outinfo->fname[trknum-1][0])) + { + tlen = get_file_size(outinfo->fname[trknum]); + if (tlen == 0) + { + printf("ERROR: couldn't find bin file [%s]\n", outinfo->fname[trknum-1]); + return CHDERR_FILE_NOT_FOUND; + } + outinfo->offset[trknum] = outinfo->offset[trknum-1] + outtoc->tracks[trknum-1].frames * (outtoc->tracks[trknum-1].datasize + outtoc->tracks[trknum-1].subsize); + outtoc->tracks[trknum].frames = (tlen - outinfo->offset[trknum]) / (outtoc->tracks[trknum].datasize + outtoc->tracks[trknum].subsize); + } + else /* data files are different */ + { + tlen = get_file_size(outinfo->fname[trknum]); + if (tlen == 0) + { + printf("ERROR: couldn't find bin file [%s]\n", outinfo->fname[trknum-1]); + return CHDERR_FILE_NOT_FOUND; + } + tlen /= (outtoc->tracks[trknum].datasize + outtoc->tracks[trknum].subsize); + outtoc->tracks[trknum].frames = tlen; + outinfo->offset[trknum] = 0; + } + } + else + { + /* if we have the same filename as the next track, do it that way */ + if (!strcmp(&outinfo->fname[trknum][0], &outinfo->fname[trknum+1][0])) + { + outtoc->tracks[trknum].frames = outinfo->idx1offs[trknum+1] - outinfo->idx1offs[trknum]; + + if (trknum == 0) // track 0 offset is 0 + { + outinfo->offset[trknum] = 0; + } + else + { + outinfo->offset[trknum] = outinfo->offset[trknum-1] + outtoc->tracks[trknum-1].frames * (outtoc->tracks[trknum-1].datasize + outtoc->tracks[trknum-1].subsize); + } + + if (!outtoc->tracks[trknum].frames) + { + printf("ERROR: unable to determine size of track %d, missing INDEX 01 markers?\n", trknum+1); + return CHDERR_FILE_NOT_FOUND; + } + } + else /* data files are different */ + { + tlen = get_file_size(outinfo->fname[trknum]); + if (tlen == 0) + { + printf("ERROR: couldn't find bin file [%s]\n", outinfo->fname[trknum]); + return CHDERR_FILE_NOT_FOUND; + } + tlen /= (outtoc->tracks[trknum].datasize + outtoc->tracks[trknum].subsize); + outtoc->tracks[trknum].frames = tlen; + outinfo->offset[trknum] = 0; + } + } + } + printf("trk %d: %d frames @ offset %d\n", trknum+1, outtoc->tracks[trknum].frames, outinfo->offset[trknum]); + } + + return CHDERR_NONE; +} + +/*------------------------------------------------- + chdcd_parse_toc - parse a CDRDAO format TOC file +-------------------------------------------------*/ + +chd_error chdcd_parse_toc(const char *tocfname, cdrom_toc *outtoc, chdcd_track_input_info *outinfo) +{ + FILE *infile; + int i, trknum; + static char token[128]; + + if (strstr(tocfname,".gdi")) + { + return chdcd_parse_gdi(tocfname, outtoc, outinfo); + } + + if (strstr(tocfname,".cue")) + { + return chdcd_parse_cue(tocfname, outtoc, outinfo); + } + + if (strstr(tocfname,".nrg")) + { + return chdcd_parse_nero(tocfname, outtoc, outinfo); + } + + astring path = astring(tocfname); + + infile = fopen(tocfname, "rt"); + path = get_file_path(path); + + if (infile == (FILE *)NULL) + { + return CHDERR_FILE_NOT_FOUND; + } + + /* clear structures */ + memset(outtoc, 0, sizeof(cdrom_toc)); + memset(outinfo, 0, sizeof(chdcd_track_input_info)); + + trknum = -1; + + while (!feof(infile)) + { + /* get the next line */ + fgets(linebuffer, 511, infile); + + /* if EOF didn't hit, keep going */ + if (!feof(infile)) + { + i = 0; + + TOKENIZE + + if ((!strcmp(token, "DATAFILE")) || (!strcmp(token, "AUDIOFILE")) || (!strcmp(token, "FILE"))) + { + int f; + + /* found the data file for a track */ + TOKENIZE + + /* keep the filename */ + strncpy(outinfo->fname[trknum], path.cstr(), 256); + strncat(outinfo->fname[trknum], token, 256); + + /* get either the offset or the length */ + TOKENIZE + + if (!strcmp(token, "SWAP")) + { + TOKENIZE + + outinfo->swap[trknum] = 1; + } + else + { + outinfo->swap[trknum] = 0; + } + + if (token[0] == '#') + { + /* it's a decimal offset, use it */ + f = strtoul(&token[1], NULL, 10); + } + else if (isdigit((UINT8)token[0])) + { + /* convert the time to an offset */ + f = msf_to_frames( token ); + + f *= (outtoc->tracks[trknum].datasize + outtoc->tracks[trknum].subsize); + } + else + { + f = 0; + } + + outinfo->offset[trknum] = f; + + TOKENIZE + + if (isdigit((UINT8)token[0])) + { + // this could be the length or an offset from the previous field. + f = msf_to_frames( token ); + + TOKENIZE + + if (isdigit((UINT8)token[0])) + { + // it was an offset. + f *= (outtoc->tracks[trknum].datasize + outtoc->tracks[trknum].subsize); + + outinfo->offset[trknum] += f; + + // this is the length. + f = msf_to_frames( token ); + } + } + else if( trknum == 0 && outinfo->offset[trknum] != 0 ) + { + /* the 1st track might have a length with no offset */ + f = outinfo->offset[trknum] / (outtoc->tracks[trknum].datasize + outtoc->tracks[trknum].subsize); + outinfo->offset[trknum] = 0; + } + else + { + /* guesstimate the track length? */ + f = 0; + } + + outtoc->tracks[trknum].frames = f; + } + else if (!strcmp(token, "TRACK")) + { + trknum++; + + /* next token on the line is the track type */ + TOKENIZE + + outtoc->tracks[trknum].trktype = CD_TRACK_MODE1; + outtoc->tracks[trknum].datasize = 0; + outtoc->tracks[trknum].subtype = CD_SUB_NONE; + outtoc->tracks[trknum].subsize = 0; + + cdrom_convert_type_string_to_track_info(token, &outtoc->tracks[trknum]); + if (outtoc->tracks[trknum].datasize == 0) + { + printf("ERROR: Unknown track type [%s]. Contact MAMEDEV.\n", token); + return CHDERR_FILE_NOT_FOUND; + } + + /* next (optional) token on the line is the subcode type */ + TOKENIZE + + cdrom_convert_subtype_string_to_track_info(token, &outtoc->tracks[trknum]); + } + else if (!strcmp(token, "START")) + { + int frames; + + /* get index */ + TOKENIZE + frames = msf_to_frames( token ); + + outtoc->tracks[trknum].pregap = frames; + } + } + } + + /* close the input TOC */ + fclose(infile); + + /* store the number of tracks found */ + outtoc->numtrks = trknum + 1; + + return CHDERR_NONE; +} |