X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=libpcsxcore%2Fcdriso.c;h=515370f756d2a0ec88d232fa9e8ea8382709dc1f;hb=HEAD;hp=eeb2c351a28c47f70ca5400f549f36e6403414ac;hpb=9165d434d935746da54484381ebbee754e899680;p=pcsx_rearmed.git diff --git a/libpcsxcore/cdriso.c b/libpcsxcore/cdriso.c index eeb2c351..4c4bff6f 100644 --- a/libpcsxcore/cdriso.c +++ b/libpcsxcore/cdriso.c @@ -20,26 +20,32 @@ ***************************************************************************/ #include "psxcommon.h" -#include "plugins.h" #include "cdrom.h" #include "cdriso.h" #include "ppf.h" +#include +#include +#ifdef HAVE_CHD +#include +#endif + #ifdef _WIN32 -#define WIN32_LEAN_AND_MEAN -#include -#include #define strcasecmp _stricmp -#elif P_HAVE_PTHREAD -#include -#include +#else +#include +#include #include #endif -#include -#include -#ifdef HAVE_CHD -#include "libchdr/chd.h" +#ifdef USE_LIBRETRO_VFS +#include +#undef fseeko +#undef ftello +#undef rewind +#define ftello rftell +#define fseeko rfseek +#define rewind(f_) rfseek(f_, 0, SEEK_SET) #endif #define OFF_T_MSB ((off_t)1 << (sizeof(off_t) * 8 - 1)) @@ -48,7 +54,6 @@ unsigned int cdrIsoMultidiskCount; unsigned int cdrIsoMultidiskSelect; static FILE *cdHandle = NULL; -static FILE *cddaHandle = NULL; static FILE *subHandle = NULL; static boolean subChanMixed = FALSE; @@ -57,9 +62,7 @@ static boolean subChanRaw = FALSE; static boolean multifile = FALSE; static unsigned char cdbuffer[CD_FRAMESIZE_RAW]; -static unsigned char subbuffer[SUB_FRAMESIZE]; -static boolean playing = FALSE; static boolean cddaBigEndian = FALSE; /* Frame offset into CD image where pregap data would be found if it was there. * If a game seeks there we must *not* return subchannel data since it's @@ -67,8 +70,6 @@ static boolean cddaBigEndian = FALSE; * XXX: there could be multiple pregaps but PSX dumps only have one? */ static unsigned int pregapOffset; -static unsigned int cddaCurPos; - // compressed image stuff static struct { unsigned char buff_raw[16][CD_FRAMESIZE_RAW]; @@ -90,19 +91,14 @@ static struct { unsigned int current_buffer; unsigned int sector_in_hunk; } *chd_img; +#else +#define chd_img 0 #endif static int (*cdimg_read_func)(FILE *f, unsigned int base, void *dest, int sector); -static int (*cdimg_read_sub_func)(FILE *f, int sector); - -char* CALLBACK CDR__getDriveLetter(void); -long CALLBACK CDR__configure(void); -long CALLBACK CDR__test(void); -void CALLBACK CDR__about(void); -long CALLBACK CDR__setfilename(char *filename); -long CALLBACK CDR__getStatus(struct CdrStat *stat); +static int (*cdimg_read_sub_func)(FILE *f, int sector, void *dest); -static void DecodeRawSubData(void); +static void DecodeRawSubData(unsigned char *subbuffer); struct trackinfo { enum {DATA=1, CDDA} type; @@ -118,11 +114,13 @@ static int numtracks = 0; static struct trackinfo ti[MAXTRACKS]; // get a sector from a msf-array -static unsigned int msf2sec(char *msf) { +static unsigned int msf2sec(const void *msf_) { + const unsigned char *msf = msf_; return ((msf[0] * 60 + msf[1]) * 75) + msf[2]; } -static void sec2msf(unsigned int s, char *msf) { +static void sec2msf(unsigned int s, void *msf_) { + unsigned char *msf = msf_; msf[0] = s / 75 / 60; s = s - msf[0] * 75 * 60; msf[1] = s / 75; @@ -159,6 +157,39 @@ static void tok2msf(char *time, char *msf) { } } +static off_t get_size(FILE *f) +{ + off_t old, size; +#if !defined(USE_LIBRETRO_VFS) + struct stat st; + if (fstat(fileno(f), &st) == 0) + return st.st_size; +#endif + old = ftello(f); + fseeko(f, 0, SEEK_END); + size = ftello(f); + fseeko(f, old, SEEK_SET); + return size; +} + +// Some c libs like newlib default buffering to just 1k which is less than +// cd sector size which is bad for performance. +// Note that NULL setvbuf() is implemented differently by different libs +// (newlib mallocs a buffer of given size and glibc ignores size and uses it's own). +static void set_static_stdio_buffer(FILE *f) +{ +#if !defined(fopen) // no stdio redirect + static char buf[16 * 1024]; + if (f) { + int r; + errno = 0; + r = setvbuf(f, buf, _IOFBF, sizeof(buf)); + if (r) + SysPrintf("cdriso: setvbuf %d %d\n", r, errno); + } +#endif +} + // this function tries to get the .toc file of the given .bin // the necessary data is put into the ti (trackinformation)-array static int parsetoc(const char *isofile) { @@ -202,7 +233,8 @@ static int parsetoc(const char *isofile) { // check if it's really a TOC named as a .cue if (fgets(linebuf, sizeof(linebuf), fi) != NULL) { token = strtok(linebuf, " "); - if (token && strncmp(token, "CD", 2) != 0 && strcmp(token, "CATALOG") != 0) { + if (token && strncmp(token, "CD", 2) != 0) { + // && strcmp(token, "CATALOG") != 0) - valid for a real .cue fclose(fi); return -1; } @@ -312,6 +344,7 @@ static int parsecue(const char *isofile) { char filepath[MAXPATHLEN]; char *incue_fname; FILE *fi; + FILE *ftmp = NULL; char *token; char time[20]; char *tmp; @@ -325,18 +358,21 @@ static int parsecue(const char *isofile) { // copy name of the iso and change extension from .bin to .cue strncpy(cuename, isofile, sizeof(cuename)); cuename[MAXPATHLEN - 1] = '\0'; - if (strlen(cuename) >= 4) { + if (strlen(cuename) < 4) + return -1; + if (strcasecmp(cuename + strlen(cuename) - 4, ".cue") == 0) { + // it's already open as cdHandle + fi = cdHandle; + } + else { // If 'isofile' is a '.cd' file, use it as a .cue file // and don't try to search the additional .cue file if (strncasecmp(cuename + strlen(cuename) - 4, ".cd", 3) != 0 ) - strcpy(cuename + strlen(cuename) - 4, ".cue"); - } - else { - return -1; - } + strcpy(cuename + strlen(cuename) - 4, ".cue"); - if ((fi = fopen(cuename, "r")) == NULL) { - return -1; + if ((ftmp = fopen(cuename, "r")) == NULL) + return -1; + fi = ftmp; } // Some stupid tutorials wrongly tell users to use cdrdao to rip a @@ -346,10 +382,11 @@ static int parsecue(const char *isofile) { if (!strncmp(linebuf, "CD_ROM_XA", 9)) { // Don't proceed further, as this is actually a .toc file rather // than a .cue file. - fclose(fi); + if (ftmp) + fclose(ftmp); return parsetoc(isofile); } - fseek(fi, 0, SEEK_SET); + rewind(fi); } // build a path for files referenced in .cue @@ -457,25 +494,24 @@ static int parsecue(const char *isofile) { SysPrintf(_("\ncould not open: %s\n"), filepath); continue; } - fseek(ti[numtracks + 1].handle, 0, SEEK_END); - file_len = ftell(ti[numtracks + 1].handle) / 2352; - - if (numtracks == 0 && strlen(isofile) >= 4 && - (strcmp(isofile + strlen(isofile) - 4, ".cue") == 0 || - strncasecmp(isofile + strlen(isofile) - 4, ".cd", 3) == 0)) { - // user selected .cue/.cdX as image file, use it's data track instead - fclose(cdHandle); - cdHandle = fopen(filepath, "rb"); - } + file_len = get_size(ti[numtracks + 1].handle) / 2352; } } - fclose(fi); + if (ftmp) + fclose(ftmp); // if there are no tracks detected, then it's not a cue file if (!numtracks) return -1; + // the data track handle is always in cdHandle + if (ti[1].handle) { + fclose(cdHandle); + cdHandle = ti[1].handle; + ti[1].handle = NULL; + set_static_stdio_buffer(cdHandle); + } return 0; } @@ -530,8 +566,7 @@ static int parseccd(const char *isofile) { // Fill out the last track's end based on size if (numtracks >= 1) { - fseek(cdHandle, 0, SEEK_END); - t = ftell(cdHandle) / 2352 - msf2sec(ti[numtracks].start) + 2 * 75; + t = get_size(cdHandle) / 2352 - msf2sec(ti[numtracks].start) + 2 * 75; sec2msf(t, ti[numtracks].length); } @@ -686,11 +721,9 @@ static int handlepbp(const char *isofile) { if (strlen(isofile) >= 4) ext = isofile + strlen(isofile) - 4; - if (ext == NULL || (strcmp(ext, ".pbp") != 0 && strcmp(ext, ".PBP") != 0)) + if (ext == NULL || strcasecmp(ext, ".pbp") != 0) return -1; - fseeko(cdHandle, 0, SEEK_SET); - numtracks = 0; ret = fread(&pbp_hdr, 1, sizeof(pbp_hdr), cdHandle); @@ -839,9 +872,8 @@ fail_index: goto done; fail_io: -#ifndef NDEBUG SysPrintf(_("File IO error in <%s:%s>.\n"), __FILE__, __func__); -#endif + rewind(cdHandle); done: if (compr_img != NULL) { @@ -872,23 +904,21 @@ static int handlecbin(const char *isofile) { if (ext == NULL || (strcasecmp(ext + 1, ".cbn") != 0 && strcasecmp(ext, ".cbin") != 0)) return -1; - fseek(cdHandle, 0, SEEK_SET); - ret = fread(&ciso_hdr, 1, sizeof(ciso_hdr), cdHandle); if (ret != sizeof(ciso_hdr)) { SysPrintf("failed to read ciso header\n"); - return -1; + goto fail_io; } if (strncmp(ciso_hdr.magic, "CISO", 4) != 0 || ciso_hdr.total_bytes <= 0 || ciso_hdr.block_size <= 0) { SysPrintf("bad ciso header\n"); - return -1; + goto fail_io; } if (ciso_hdr.header_size != 0 && ciso_hdr.header_size != sizeof(ciso_hdr)) { ret = fseeko(cdHandle, ciso_hdr.header_size, SEEK_SET); if (ret != 0) { SysPrintf("failed to seek to %x\n", ciso_hdr.header_size); - return -1; + goto fail_io; } } @@ -932,6 +962,7 @@ fail_io: free(compr_img); compr_img = NULL; } + rewind(cdHandle); return -1; } @@ -939,13 +970,23 @@ fail_io: static int handlechd(const char *isofile) { int frame_offset = 150; int file_offset = 0; + int is_chd_ext = 0; + chd_error err; + if (strlen(isofile) >= 3) { + const char *ext = isofile + strlen(isofile) - 3; + is_chd_ext = !strcasecmp(ext, "chd"); + } chd_img = calloc(1, sizeof(*chd_img)); if (chd_img == NULL) goto fail_io; - if(chd_open(isofile, CHD_OPEN_READ, NULL, &chd_img->chd) != CHDERR_NONE) + err = chd_open_file(cdHandle, CHD_OPEN_READ, NULL, &chd_img->chd); + if (err != CHDERR_NONE) { + if (is_chd_ext) + SysPrintf("chd_open: %d\n", err); goto fail_io; + } if (Config.CHD_Precache && (chd_precache(chd_img->chd) != CHDERR_NONE)) goto fail_io; @@ -1038,9 +1079,8 @@ static int opensubfile(const char *isoname) { } subHandle = fopen(subname, "rb"); - if (subHandle == NULL) { + if (subHandle == NULL) return -1; - } return 0; } @@ -1057,14 +1097,13 @@ static int opensbifile(const char *isoname) { strcpy(sbiname + strlen(sbiname) - 4, disknum); } else - strcpy(sbiname + strlen(sbiname) - 4, ".sbi"); + strcpy(sbiname + strlen(sbiname) - 4, ".sbi"); } else { return -1; } - fseek(cdHandle, 0, SEEK_END); - s = ftell(cdHandle) / 2352; + s = msf2sec(ti[1].length); return LoadSBI(sbiname, s); } @@ -1072,7 +1111,11 @@ static int opensbifile(const char *isoname) { static int cdread_normal(FILE *f, unsigned int base, void *dest, int sector) { int ret; - if (fseek(f, base + sector * CD_FRAMESIZE_RAW, SEEK_SET)) + if (!f) + return -1; + if (!dest) + dest = cdbuffer; + if (fseeko(f, base + sector * CD_FRAMESIZE_RAW, SEEK_SET)) goto fail_io; ret = fread(dest, 1, CD_FRAMESIZE_RAW, f); if (ret <= 0) @@ -1089,7 +1132,11 @@ static int cdread_sub_mixed(FILE *f, unsigned int base, void *dest, int sector) { int ret; - if (fseek(f, base + sector * (CD_FRAMESIZE_RAW + SUB_FRAMESIZE), SEEK_SET)) + if (!f) + return -1; + if (!dest) + dest = cdbuffer; + if (fseeko(f, base + sector * (CD_FRAMESIZE_RAW + SUB_FRAMESIZE), SEEK_SET)) goto fail_io; ret = fread(dest, 1, CD_FRAMESIZE_RAW, f); if (ret <= 0) @@ -1101,14 +1148,16 @@ fail_io: return -1; } -static int cdread_sub_sub_mixed(FILE *f, int sector) +static int cdread_sub_sub_mixed(FILE *f, int sector, void *buffer) { - if (fseek(f, sector * (CD_FRAMESIZE_RAW + SUB_FRAMESIZE) + CD_FRAMESIZE_RAW, SEEK_SET)) + if (!f) + return -1; + if (fseeko(f, sector * (CD_FRAMESIZE_RAW + SUB_FRAMESIZE) + CD_FRAMESIZE_RAW, SEEK_SET)) goto fail_io; - if (fread(subbuffer, 1, SUB_FRAMESIZE, f) != SUB_FRAMESIZE) + if (fread(buffer, 1, SUB_FRAMESIZE, f) != SUB_FRAMESIZE) goto fail_io; - return SUB_FRAMESIZE; + return 0; fail_io: SysPrintf("subchannel: file IO error %d, sector %u\n", errno, sector); @@ -1154,6 +1203,8 @@ static int cdread_compressed(FILE *f, unsigned int base, void *dest, int sector) off_t start_byte; int ret, block; + if (!cdHandle) + return -1; if (base) sector += base / 2352; @@ -1187,7 +1238,7 @@ static int cdread_compressed(FILE *f, unsigned int base, void *dest, int sector) if (fread(is_compressed ? compr_img->buff_compressed : compr_img->buff_raw[0], 1, size, cdHandle) != size) { - SysPrintf("read error for block %d at %x: ", block, start_byte); + SysPrintf("read error for block %d at %lx: ", block, (long)start_byte); perror(NULL); return -1; } @@ -1210,7 +1261,7 @@ static int cdread_compressed(FILE *f, unsigned int base, void *dest, int sector) compr_img->current_block = block; finish: - if (dest != cdbuffer) // copy avoid HACK + if (dest != NULL) memcpy(dest, compr_img->buff_raw[compr_img->sector_in_blk], CD_FRAMESIZE_RAW); return CD_FRAMESIZE_RAW; @@ -1244,13 +1295,13 @@ static int cdread_chd(FILE *f, unsigned int base, void *dest, int sector) chd_img->current_hunk[chd_img->current_buffer] = hunk; } - if (dest != cdbuffer) // copy avoid HACK + if (dest != NULL) memcpy(dest, chd_get_sector(chd_img->current_buffer, chd_img->sector_in_hunk), CD_FRAMESIZE_RAW); return CD_FRAMESIZE_RAW; } -static int cdread_sub_chd(FILE *f, int sector) +static int cdread_sub_chd(FILE *f, int sector, void *buffer_ptr) { unsigned int sector_in_hunk; unsigned int buffer; @@ -1274,46 +1325,56 @@ static int cdread_sub_chd(FILE *f, int sector) chd_img->current_hunk[buffer] = hunk; } - memcpy(subbuffer, chd_get_sector(buffer, sector_in_hunk) + CD_FRAMESIZE_RAW, SUB_FRAMESIZE); - return SUB_FRAMESIZE; + memcpy(buffer_ptr, chd_get_sector(buffer, sector_in_hunk) + CD_FRAMESIZE_RAW, SUB_FRAMESIZE); + return 0; } #endif static int cdread_2048(FILE *f, unsigned int base, void *dest, int sector) { + unsigned char *dst = dest ? dest : cdbuffer; int ret; - fseek(f, base + sector * 2048, SEEK_SET); - ret = fread((char *)dest + 12 * 2, 1, 2048, f); + if (!f) + return -1; + + fseeko(f, base + sector * 2048, SEEK_SET); + ret = fread(dst + 12 * 2, 1, 2048, f); // not really necessary, fake mode 2 header - memset(cdbuffer, 0, 12 * 2); - sec2msf(sector + 2 * 75, (char *)&cdbuffer[12]); - cdbuffer[12 + 3] = 1; + memset(dst, 0, 12 * 2); + sec2msf(sector + 2 * 75, dst + 12); + dst[12 + 0] = itob(dst[12 + 0]); + dst[12 + 1] = itob(dst[12 + 1]); + dst[12 + 2] = itob(dst[12 + 2]); + dst[12 + 3] = 1; return 12*2 + ret; } -static unsigned char * CALLBACK ISOgetBuffer_compr(void) { - return compr_img->buff_raw[compr_img->sector_in_blk] + 12; +static void * ISOgetBuffer_normal(void) { + return cdbuffer + 12; +} + +static void * ISOgetBuffer_compr(void) { + return compr_img->buff_raw[compr_img->sector_in_blk] + 12; } #ifdef HAVE_CHD -static unsigned char * CALLBACK ISOgetBuffer_chd(void) { - return chd_get_sector(chd_img->current_buffer, chd_img->sector_in_hunk) + 12; +static void * ISOgetBuffer_chd(void) { + return chd_get_sector(chd_img->current_buffer, chd_img->sector_in_hunk) + 12; } #endif -static unsigned char * CALLBACK ISOgetBuffer(void) { - return cdbuffer + 12; -} +void * (*ISOgetBuffer)(void) = ISOgetBuffer_normal; static void PrintTracks(void) { int i; for (i = 1; i <= numtracks; i++) { SysPrintf(_("Track %.2d (%s) - Start %.2d:%.2d:%.2d, Length %.2d:%.2d:%.2d\n"), - i, (ti[i].type == DATA ? "DATA" : "AUDIO"), + i, (ti[i].type == DATA ? "DATA" : + (ti[i].type == CDDA ? "AUDIO" : "UNKNOWN")), ti[i].start[0], ti[i].start[1], ti[i].start[2], ti[i].length[0], ti[i].length[1], ti[i].length[2]); } @@ -1321,26 +1382,29 @@ static void PrintTracks(void) { // This function is invoked by the front-end when opening an ISO // file for playback -static long CALLBACK ISOopen(void) { +int ISOopen(const char *fname) +{ boolean isMode1ISO = FALSE; char alt_bin_filename[MAXPATHLEN]; const char *bin_filename; char image_str[1024]; - int is_chd = 0; + off_t size_main; - if (cdHandle != NULL) { + if (cdHandle || chd_img) { return 0; // it's already open } - cdHandle = fopen(GetIsoFile(), "rb"); + cdHandle = fopen(fname, "rb"); if (cdHandle == NULL) { SysPrintf(_("Could't open '%s' for reading: %s\n"), - GetIsoFile(), strerror(errno)); + fname, strerror(errno)); return -1; } + set_static_stdio_buffer(cdHandle); + size_main = get_size(cdHandle); snprintf(image_str, sizeof(image_str) - 6*4 - 1, - "Loaded CD Image: %s", GetIsoFile()); + "Loaded CD Image: %s", fname); cddaBigEndian = FALSE; subChanMixed = FALSE; @@ -1349,54 +1413,51 @@ static long CALLBACK ISOopen(void) { cdrIsoMultidiskCount = 1; multifile = 0; - CDR_getBuffer = ISOgetBuffer; + ISOgetBuffer = ISOgetBuffer_normal; cdimg_read_func = cdread_normal; cdimg_read_sub_func = NULL; - if (parsetoc(GetIsoFile()) == 0) { + if (parsetoc(fname) == 0) { strcat(image_str, "[+toc]"); } - else if (parseccd(GetIsoFile()) == 0) { + else if (parseccd(fname) == 0) { strcat(image_str, "[+ccd]"); } - else if (parsemds(GetIsoFile()) == 0) { + else if (parsemds(fname) == 0) { strcat(image_str, "[+mds]"); } - else if (parsecue(GetIsoFile()) == 0) { + else if (parsecue(fname) == 0) { strcat(image_str, "[+cue]"); } - if (handlepbp(GetIsoFile()) == 0) { + if (handlepbp(fname) == 0) { strcat(image_str, "[+pbp]"); - CDR_getBuffer = ISOgetBuffer_compr; + ISOgetBuffer = ISOgetBuffer_compr; cdimg_read_func = cdread_compressed; } - else if (handlecbin(GetIsoFile()) == 0) { + else if (handlecbin(fname) == 0) { strcat(image_str, "[+cbin]"); - CDR_getBuffer = ISOgetBuffer_compr; + ISOgetBuffer = ISOgetBuffer_compr; cdimg_read_func = cdread_compressed; } #ifdef HAVE_CHD - else if (handlechd(GetIsoFile()) == 0) { + else if (handlechd(fname) == 0) { strcat(image_str, "[+chd]"); - CDR_getBuffer = ISOgetBuffer_chd; + ISOgetBuffer = ISOgetBuffer_chd; cdimg_read_func = cdread_chd; cdimg_read_sub_func = cdread_sub_chd; - is_chd = 1; } #endif - if (!subChanMixed && opensubfile(GetIsoFile()) == 0) { + if (!subChanMixed && opensubfile(fname) == 0) { strcat(image_str, "[+sub]"); } - if (opensbifile(GetIsoFile()) == 0) { + if (opensbifile(fname) == 0) { strcat(image_str, "[+sbi]"); } - fseeko(cdHandle, 0, SEEK_END); - // maybe user selected metadata file instead of main .bin .. - bin_filename = GetIsoFile(); - if (ftello(cdHandle) < 2352 * 0x10) { + bin_filename = fname; + if (cdHandle && size_main < 2352 * 0x10) { static const char *exts[] = { ".bin", ".BIN", ".img", ".IMG" }; FILE *tmpf = NULL; size_t i; @@ -1417,32 +1478,28 @@ static long CALLBACK ISOopen(void) { bin_filename = alt_bin_filename; fclose(cdHandle); cdHandle = tmpf; - fseeko(cdHandle, 0, SEEK_END); + set_static_stdio_buffer(cdHandle); + size_main = get_size(cdHandle); } } // guess whether it is mode1/2048 - if (ftello(cdHandle) % 2048 == 0) { + if (cdHandle && cdimg_read_func == cdread_normal && size_main % 2048 == 0) { unsigned int modeTest = 0; - fseek(cdHandle, 0, SEEK_SET); if (!fread(&modeTest, sizeof(modeTest), 1, cdHandle)) { -#ifndef NDEBUG SysPrintf(_("File IO error in <%s:%s>.\n"), __FILE__, __func__); -#endif - return -1; } if (SWAP32(modeTest) != 0xffffff00) { strcat(image_str, "[2048]"); isMode1ISO = TRUE; } } - fseek(cdHandle, 0, SEEK_SET); - SysPrintf("%s.\n", image_str); + SysPrintf("%s (%lld bytes).\n", image_str, (long long)size_main); PrintTracks(); - if (subChanMixed && !is_chd) { + if (subChanMixed && cdimg_read_func == cdread_normal) { cdimg_read_func = cdread_sub_mixed; cdimg_read_sub_func = cdread_sub_sub_mixed; } @@ -1451,15 +1508,11 @@ static long CALLBACK ISOopen(void) { cdimg_read_sub_func = NULL; } - // make sure we have another handle open for cdda - if (numtracks > 1 && ti[1].handle == NULL) { - ti[1].handle = fopen(bin_filename, "rb"); - } - return 0; } -static long CALLBACK ISOclose(void) { +int ISOclose(void) +{ int i; if (cdHandle != NULL) { @@ -1470,15 +1523,13 @@ static long CALLBACK ISOclose(void) { fclose(subHandle); subHandle = NULL; } - playing = FALSE; - cddaHandle = NULL; if (compr_img != NULL) { free(compr_img->index_table); free(compr_img); compr_img = NULL; } - + #ifdef HAVE_CHD if (chd_img != NULL) { chd_close(chd_img->chd); @@ -1499,28 +1550,31 @@ static long CALLBACK ISOclose(void) { UnloadSBI(); memset(cdbuffer, 0, sizeof(cdbuffer)); - CDR_getBuffer = ISOgetBuffer; + ISOgetBuffer = ISOgetBuffer_normal; return 0; } -static long CALLBACK ISOinit(void) { +int ISOinit(void) +{ assert(cdHandle == NULL); assert(subHandle == NULL); + numtracks = 0; return 0; // do nothing } -static long CALLBACK ISOshutdown(void) { - ISOclose(); - return 0; +int ISOshutdown(void) +{ + return ISOclose(); } // return Starting and Ending Track // buffer: // byte 0 - start track // byte 1 - end track -static long CALLBACK ISOgetTN(unsigned char *buffer) { +int ISOgetTN(unsigned char *buffer) +{ buffer[0] = 1; if (numtracks > 0) { @@ -1535,23 +1589,18 @@ static long CALLBACK ISOgetTN(unsigned char *buffer) { // return Track Time // buffer: -// byte 0 - frame +// byte 0 - minute // byte 1 - second -// byte 2 - minute -static long CALLBACK ISOgetTD(unsigned char track, unsigned char *buffer) { +// byte 2 - frame +int ISOgetTD(int track, unsigned char *buffer) +{ if (track == 0) { unsigned int sect; - unsigned char time[3]; sect = msf2sec(ti[numtracks].start) + msf2sec(ti[numtracks].length); - sec2msf(sect, (char *)time); - buffer[2] = time[0]; - buffer[1] = time[1]; - buffer[0] = time[2]; + sec2msf(sect, buffer); } else if (numtracks > 0 && track <= numtracks) { - buffer[2] = ti[track].start[0]; - buffer[1] = ti[track].start[1]; - buffer[0] = ti[track].start[2]; + memcpy(buffer, ti[track].start, 3); } else { buffer[2] = 0; @@ -1563,7 +1612,7 @@ static long CALLBACK ISOgetTD(unsigned char track, unsigned char *buffer) { } // decode 'raw' subchannel data ripped by cdrdao -static void DecodeRawSubData(void) { +static void DecodeRawSubData(unsigned char *subbuffer) { unsigned char subQData[12]; int i; @@ -1579,94 +1628,85 @@ static void DecodeRawSubData(void) { } // read track -// time: byte 0 - minute; byte 1 - second; byte 2 - frame -// uses bcd format -static boolean CALLBACK ISOreadTrack(unsigned char *time) { - int sector = MSF2SECT(btoi(time[0]), btoi(time[1]), btoi(time[2])); +// time: byte 0 - minute; byte 1 - second; byte 2 - frame (non-bcd) +// buf: if NULL, data is kept in internal buffer accessible by ISOgetBuffer() +int ISOreadTrack(const unsigned char *time, void *buf) +{ + int sector = msf2sec(time); long ret; - if (cdHandle == NULL) { - return 0; - } + if (!cdHandle && !chd_img) + return -1; + if (numtracks > 1 && sector >= msf2sec(ti[2].start)) + return ISOreadCDDA(time, buf); + + sector -= 2 * 75; if (pregapOffset && sector >= pregapOffset) sector -= 2 * 75; - ret = cdimg_read_func(cdHandle, 0, cdbuffer, sector); - if (ret < 12*2 + 2048) - return 0; - - return 1; -} + ret = cdimg_read_func(cdHandle, 0, buf, sector); + if (ret < 12*2 + 2048) { + if (buf && multifile && sector >= msf2sec(ti[1].length)) { + // assume a gap not backed by a file + memset(buf, 0, CD_FRAMESIZE_RAW); + return 0; + } + return -1; + } -// plays cdda audio -// sector: byte 0 - minute; byte 1 - second; byte 2 - frame -// does NOT uses bcd format -static long CALLBACK ISOplay(unsigned char *time) { - playing = TRUE; return 0; } -// stops cdda audio -static long CALLBACK ISOstop(void) { - playing = FALSE; - return 0; -} +// read subchannel data +int ISOreadSub(const unsigned char *time, void *buffer) +{ + int ret, sector = MSF2SECT(time[0], time[1], time[2]); -// gets subchannel data -static unsigned char* CALLBACK ISOgetBufferSub(int sector) { if (pregapOffset && sector >= pregapOffset) { sector -= 2 * 75; if (sector < pregapOffset) // ? - return NULL; + return -1; } if (cdimg_read_sub_func != NULL) { - if (cdimg_read_sub_func(cdHandle, sector) != SUB_FRAMESIZE) - return NULL; + if ((ret = cdimg_read_sub_func(cdHandle, sector, buffer))) + return ret; } else if (subHandle != NULL) { - if (fseek(subHandle, sector * SUB_FRAMESIZE, SEEK_SET)) - return NULL; - if (fread(subbuffer, 1, SUB_FRAMESIZE, subHandle) != SUB_FRAMESIZE) - return NULL; + if (fseeko(subHandle, sector * SUB_FRAMESIZE, SEEK_SET)) + return -1; + if (fread(buffer, 1, SUB_FRAMESIZE, subHandle) != SUB_FRAMESIZE) + return -1; } else { - return NULL; + return -1; } - if (subChanRaw) DecodeRawSubData(); - return subbuffer; + if (subChanRaw) + DecodeRawSubData(buffer); + return 0; } -static long CALLBACK ISOgetStatus(struct CdrStat *stat) { - u32 sect; - +int ISOgetStatus(struct CdrStat *stat) +{ CDR__getStatus(stat); - if (playing) { - stat->Type = 0x02; - stat->Status |= 0x80; - } - else { - // BIOS - boot ID (CD type) - stat->Type = ti[1].type; - } - - // relative -> absolute time - sect = cddaCurPos; - sec2msf(sect, (char *)stat->Time); + // BIOS - boot ID (CD type) + stat->Type = ti[1].type; return 0; } // read CDDA sector into buffer -long CALLBACK ISOreadCDDA(unsigned char m, unsigned char s, unsigned char f, unsigned char *buffer) { - unsigned char msf[3] = {m, s, f}; - unsigned int file, track, track_start = 0; - int ret; +int ISOreadCDDA(const unsigned char *time, void *buffer) +{ + unsigned int track, track_start = 0; + FILE *handle = cdHandle; + unsigned int cddaCurPos; + int ret, ret_clear = -1; - cddaCurPos = msf2sec((char *)msf); + cddaCurPos = msf2sec(time); // find current track index for (track = numtracks; ; track--) { @@ -1679,63 +1719,46 @@ long CALLBACK ISOreadCDDA(unsigned char m, unsigned char s, unsigned char f, uns // data tracks play silent if (ti[track].type != CDDA) { - memset(buffer, 0, CD_FRAMESIZE_RAW); - return 0; + ret_clear = 0; + goto clear_return; } - file = 1; if (multifile) { // find the file that contains this track - for (file = track; file > 1; file--) - if (ti[file].handle != NULL) + unsigned int file; + for (file = track; file > 1; file--) { + if (ti[file].handle != NULL) { + handle = ti[file].handle; break; + } + } } + if (!handle && !chd_img) + goto clear_return; - ret = cdimg_read_func(ti[file].handle, ti[track].start_offset, + ret = cdimg_read_func(handle, ti[track].start_offset, buffer, cddaCurPos - track_start); if (ret != CD_FRAMESIZE_RAW) { - memset(buffer, 0, CD_FRAMESIZE_RAW); - return -1; + if (multifile && cddaCurPos - track_start >= msf2sec(ti[track].length)) + ret_clear = 0; // gap + goto clear_return; } - if (cddaBigEndian) { + if (cddaBigEndian && buffer) { + unsigned char tmp, *buf = buffer; int i; - unsigned char tmp; for (i = 0; i < CD_FRAMESIZE_RAW / 2; i++) { - tmp = buffer[i * 2]; - buffer[i * 2] = buffer[i * 2 + 1]; - buffer[i * 2 + 1] = tmp; + tmp = buf[i * 2]; + buf[i * 2] = buf[i * 2 + 1]; + buf[i * 2 + 1] = tmp; } } return 0; -} -void cdrIsoInit(void) { - CDR_init = ISOinit; - CDR_shutdown = ISOshutdown; - CDR_open = ISOopen; - CDR_close = ISOclose; - CDR_getTN = ISOgetTN; - CDR_getTD = ISOgetTD; - CDR_readTrack = ISOreadTrack; - CDR_getBuffer = ISOgetBuffer; - CDR_play = ISOplay; - CDR_stop = ISOstop; - CDR_getBufferSub = ISOgetBufferSub; - CDR_getStatus = ISOgetStatus; - CDR_readCDDA = ISOreadCDDA; - - CDR_getDriveLetter = CDR__getDriveLetter; - CDR_configure = CDR__configure; - CDR_test = CDR__test; - CDR_about = CDR__about; - CDR_setfilename = CDR__setfilename; - - numtracks = 0; -} - -int cdrIsoActive(void) { - return (cdHandle != NULL); +clear_return: + if (buffer) + memset(buffer, 0, CD_FRAMESIZE_RAW); + return ret_clear; }