* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
- * 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307 USA. *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *
***************************************************************************/
#include "psxcommon.h"
#include "ppf.h"
#ifdef _WIN32
+#define WIN32_LEAN_AND_MEAN
#include <process.h>
#include <windows.h>
+#define strcasecmp _stricmp
+#define usleep(x) Sleep((x) / 1000)
#else
#include <pthread.h>
#include <sys/time.h>
#include <unistd.h>
#endif
+#include <errno.h>
#include <zlib.h>
+#define OFF_T_MSB ((off_t)1 << (sizeof(off_t) * 8 - 1))
+
unsigned int cdrIsoMultidiskCount;
unsigned int cdrIsoMultidiskSelect;
static boolean subChanRaw = FALSE;
static boolean subChanMissing = FALSE;
+static boolean multifile = FALSE;
+
static unsigned char cdbuffer[CD_FRAMESIZE_RAW];
static unsigned char subbuffer[SUB_FRAMESIZE];
* XXX: there could be multiple pregaps but PSX dumps only have one? */
static unsigned int pregapOffset;
+#define cddaCurPos cdda_cur_sector
+
// compressed image stuff
static struct {
unsigned char buff_raw[16][CD_FRAMESIZE_RAW];
unsigned char buff_compressed[CD_FRAMESIZE_RAW * 16 + 100];
- unsigned int *index_table;
+ off_t *index_table;
unsigned int index_len;
unsigned int block_shift;
unsigned int current_block;
static void DecodeRawSubData(void);
-extern void *hCDRDriver;
-
struct trackinfo {
- enum {DATA, CDDA} type;
+ enum {DATA=1, CDDA} type;
char start[3]; // MSF-format
char length[3]; // MSF-format
FILE *handle; // for multi-track images CDDA
static int parsetoc(const char *isofile) {
char tocname[MAXPATHLEN];
FILE *fi;
- char linebuf[256], dummy[256], name[256];
+ char linebuf[256], tmp[256], name[256];
char *token;
char time[20], time2[20];
- unsigned int t, sector_offs;
+ unsigned int t, sector_offs, sector_size;
+ unsigned int current_zero_gap = 0;
numtracks = 0;
return -1;
}
}
+ // check if it's really a TOC named as a .cue
+ fgets(linebuf, sizeof(linebuf), fi);
+ token = strtok(linebuf, " ");
+ if (token && strncmp(token, "CD", 2) != 0 && strcmp(token, "CATALOG") != 0) {
+ fclose(fi);
+ return -1;
+ }
+ fseek(fi, 0, SEEK_SET);
}
memset(&ti, 0, sizeof(ti));
cddaBigEndian = TRUE; // cdrdao uses big-endian for CD Audio
+ sector_size = CD_FRAMESIZE_RAW;
sector_offs = 2 * 75;
// parse the .toc file
while (fgets(linebuf, sizeof(linebuf), fi) != NULL) {
// search for tracks
- strncpy(dummy, linebuf, sizeof(linebuf));
- token = strtok(dummy, " ");
+ strncpy(tmp, linebuf, sizeof(linebuf));
+ token = strtok(tmp, " ");
if (token == NULL) continue;
if (!strcmp(token, "TRACK")) {
+ sector_offs += current_zero_gap;
+ current_zero_gap = 0;
+
// get type of track
token = strtok(NULL, " ");
numtracks++;
// check if this image contains mixed subchannel data
token = strtok(NULL, " ");
- if (token != NULL && !strncmp(token, "RW_RAW", 6)) {
+ if (token != NULL && !strncmp(token, "RW", 2)) {
+ sector_size = CD_FRAMESIZE_RAW + SUB_FRAMESIZE;
subChanMixed = TRUE;
- subChanRaw = TRUE;
+ if (!strncmp(token, "RW_RAW", 6))
+ subChanRaw = TRUE;
}
}
else if (!strncmp(token, "AUDIO", 5)) {
if (ti[numtracks].type == CDDA) {
sscanf(linebuf, "DATAFILE \"%[^\"]\" #%d %8s", name, &t, time2);
ti[numtracks].start_offset = t;
- t /= CD_FRAMESIZE_RAW + (subChanMixed ? SUB_FRAMESIZE : 0);
- t += sector_offs;
+ t = t / sector_size + sector_offs;
sec2msf(t, (char *)&ti[numtracks].start);
tok2msf((char *)&time2, (char *)&ti[numtracks].length);
}
else if (!strcmp(token, "FILE")) {
sscanf(linebuf, "FILE \"%[^\"]\" #%d %8s %8s", name, &t, time, time2);
tok2msf((char *)&time, (char *)&ti[numtracks].start);
+ t += msf2sec(ti[numtracks].start) * sector_size;
ti[numtracks].start_offset = t;
- t /= CD_FRAMESIZE_RAW + (subChanMixed ? SUB_FRAMESIZE : 0);
- t += msf2sec(ti[numtracks].start) + sector_offs;
+ t = t / sector_size + sector_offs;
sec2msf(t, (char *)&ti[numtracks].start);
tok2msf((char *)&time2, (char *)&ti[numtracks].length);
}
- else if (!strcmp(token, "ZERO")) {
- sscanf(linebuf, "ZERO AUDIO RW_RAW %8s", time);
- tok2msf((char *)&time, dummy);
- sector_offs += msf2sec(dummy);
+ else if (!strcmp(token, "ZERO") || !strcmp(token, "SILENCE")) {
+ // skip unneeded optional fields
+ while (token != NULL) {
+ token = strtok(NULL, " ");
+ if (strchr(token, ':') != NULL)
+ break;
+ }
+ if (token != NULL) {
+ tok2msf(token, tmp);
+ current_zero_gap = msf2sec(tmp);
+ }
if (numtracks > 1) {
t = ti[numtracks - 1].start_offset;
- t /= CD_FRAMESIZE_RAW + (subChanMixed ? SUB_FRAMESIZE : 0);
+ t /= sector_size;
pregapOffset = t + msf2sec(ti[numtracks - 1].length);
}
}
+ else if (!strcmp(token, "START")) {
+ token = strtok(NULL, " ");
+ if (token != NULL && strchr(token, ':')) {
+ tok2msf(token, tmp);
+ t = msf2sec(tmp);
+ ti[numtracks].start_offset += (t - current_zero_gap) * sector_size;
+ t = msf2sec(ti[numtracks].start) + t;
+ sec2msf(t, (char *)&ti[numtracks].start);
+ }
+ }
}
fclose(fi);
// build a path for files referenced in .cue
strncpy(filepath, cuename, sizeof(filepath));
- tmp = strrchr(filepath, '/') + 1;
- if (tmp == NULL)
- tmp = strrchr(filepath, '\\') + 1;
+ tmp = strrchr(filepath, '/');
if (tmp == NULL)
+ tmp = strrchr(filepath, '\\');
+ if (tmp != NULL)
+ tmp++;
+ else
tmp = filepath;
*tmp = 0;
filepath[sizeof(filepath) - 1] = 0;
pregapOffset = -1; // mark to fill track start_offset
}
else if (!strcmp(token, "FILE")) {
- t = sscanf(linebuf, " FILE \"%256[^\"]\"", tmpb);
+ t = sscanf(linebuf, " FILE \"%255[^\"]\"", tmpb);
if (t != 1)
- sscanf(linebuf, " FILE %256s", tmpb);
+ sscanf(linebuf, " FILE %255s", tmpb);
// absolute path?
ti[numtracks + 1].handle = fopen(tmpb, "rb");
}
// update global offset if this is not first file in this .cue
- if (numtracks + 1 > 1)
+ if (numtracks + 1 > 1) {
+ multifile = 1;
sector_offs += file_len;
+ }
file_len = 0;
if (ti[numtracks + 1].handle == NULL) {
unsigned int dontcare[6];
} index_entry;
char psar_sig[11];
- unsigned int t, cd_length, cdimg_base;
- unsigned int offsettab[8], psisoimg_offs;
+ off_t psisoimg_offs, cdimg_base;
+ unsigned int t, cd_length;
+ unsigned int offsettab[8];
const char *ext = NULL;
int i, ret;
if (ext == NULL || (strcmp(ext, ".pbp") != 0 && strcmp(ext, ".PBP") != 0))
return -1;
+ fseeko(cdHandle, 0, SEEK_SET);
+
numtracks = 0;
ret = fread(&pbp_hdr, 1, sizeof(pbp_hdr), cdHandle);
goto fail_io;
}
- ret = fseek(cdHandle, pbp_hdr.psar_offs, SEEK_SET);
+ ret = fseeko(cdHandle, pbp_hdr.psar_offs, SEEK_SET);
if (ret != 0) {
SysPrintf("failed to seek to %x\n", pbp_hdr.psar_offs);
goto fail_io;
psar_sig[10] = 0;
if (strcmp(psar_sig, "PSTITLEIMG") == 0) {
// multidisk image?
- ret = fseek(cdHandle, pbp_hdr.psar_offs + 0x200, SEEK_SET);
+ ret = fseeko(cdHandle, pbp_hdr.psar_offs + 0x200, SEEK_SET);
if (ret != 0) {
SysPrintf("failed to seek to %x\n", pbp_hdr.psar_offs + 0x200);
goto fail_io;
psisoimg_offs += offsettab[cdrIsoMultidiskSelect];
- ret = fseek(cdHandle, psisoimg_offs, SEEK_SET);
+ ret = fseeko(cdHandle, psisoimg_offs, SEEK_SET);
if (ret != 0) {
- SysPrintf("failed to seek to %x\n", psisoimg_offs);
+ SysPrintf("failed to seek to %llx\n", (long long)psisoimg_offs);
goto fail_io;
}
}
// seek to TOC
- ret = fseek(cdHandle, psisoimg_offs + 0x800, SEEK_SET);
+ ret = fseeko(cdHandle, psisoimg_offs + 0x800, SEEK_SET);
if (ret != 0) {
- SysPrintf("failed to seek to %x\n", psisoimg_offs + 0x800);
+ SysPrintf("failed to seek to %llx\n", (long long)psisoimg_offs + 0x800);
goto fail_io;
}
sec2msf(t, ti[numtracks].length);
// seek to ISO index
- ret = fseek(cdHandle, psisoimg_offs + 0x4000, SEEK_SET);
+ ret = fseeko(cdHandle, psisoimg_offs + 0x4000, SEEK_SET);
if (ret != 0) {
SysPrintf("failed to seek to ISO index\n");
goto fail_io;
unsigned char rsv_06[2];
} ciso_hdr;
const char *ext = NULL;
+ unsigned int *index_table = NULL;
unsigned int index = 0, plain;
int i, ret;
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;
}
if (ciso_hdr.header_size != 0 && ciso_hdr.header_size != sizeof(ciso_hdr)) {
- ret = fseek(cdHandle, ciso_hdr.header_size, SEEK_SET);
+ 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;
compr_img->current_block = (unsigned int)-1;
compr_img->index_len = ciso_hdr.total_bytes / ciso_hdr.block_size;
- compr_img->index_table = malloc((compr_img->index_len + 1) * sizeof(compr_img->index_table[0]));
- if (compr_img->index_table == NULL)
+ index_table = malloc((compr_img->index_len + 1) * sizeof(index_table[0]));
+ if (index_table == NULL)
goto fail_io;
- ret = fread(compr_img->index_table, sizeof(compr_img->index_table[0]), compr_img->index_len, cdHandle);
+ ret = fread(index_table, sizeof(index_table[0]), compr_img->index_len, cdHandle);
if (ret != compr_img->index_len) {
SysPrintf("failed to read index table\n");
goto fail_index;
}
+ compr_img->index_table = malloc((compr_img->index_len + 1) * sizeof(compr_img->index_table[0]));
+ if (compr_img->index_table == NULL)
+ goto fail_index;
+
for (i = 0; i < compr_img->index_len + 1; i++) {
- index = compr_img->index_table[i];
+ index = index_table[i];
plain = index & 0x80000000;
index &= 0x7fffffff;
- compr_img->index_table[i] = (index << ciso_hdr.align) | plain;
+ compr_img->index_table[i] = (off_t)index << ciso_hdr.align;
+ if (plain)
+ compr_img->index_table[i] |= OFF_T_MSB;
}
- if ((long long)index << ciso_hdr.align >= 0x80000000ll)
- SysPrintf("warning: ciso img too large, expect problems\n");
return 0;
fail_index:
- free(compr_img->index_table);
- compr_img->index_table = NULL;
+ free(index_table);
fail_io:
if (compr_img != NULL) {
free(compr_img);
return ret;
}
-static int uncompress2(void *out, unsigned long *out_size, void *in, unsigned long in_size)
+static int uncompress2_pcsx(void *out, unsigned long *out_size, void *in, unsigned long in_size)
{
static z_stream z;
int ret = 0;
static int cdread_compressed(FILE *f, unsigned int base, void *dest, int sector)
{
unsigned long cdbuffer_size, cdbuffer_size_expect;
- unsigned int start_byte, size;
+ unsigned int size;
int is_compressed;
+ off_t start_byte;
int ret, block;
if (base)
return -1;
}
- start_byte = compr_img->index_table[block] & 0x7fffffff;
- if (fseek(cdHandle, start_byte, SEEK_SET) != 0) {
- SysPrintf("seek error for block %d at %x: ",
- block, start_byte);
+ start_byte = compr_img->index_table[block] & ~OFF_T_MSB;
+ if (fseeko(cdHandle, start_byte, SEEK_SET) != 0) {
+ SysPrintf("seek error for block %d at %llx: ",
+ block, (long long)start_byte);
perror(NULL);
return -1;
}
- is_compressed = !(compr_img->index_table[block] & 0x80000000);
- size = (compr_img->index_table[block + 1] & 0x7fffffff) - start_byte;
+ is_compressed = !(compr_img->index_table[block] & OFF_T_MSB);
+ size = (compr_img->index_table[block + 1] & ~OFF_T_MSB) - start_byte;
if (size > sizeof(compr_img->buff_compressed)) {
SysPrintf("block %d is too large: %u\n", block, size);
return -1;
if (is_compressed) {
cdbuffer_size_expect = sizeof(compr_img->buff_raw[0]) << compr_img->block_shift;
cdbuffer_size = cdbuffer_size_expect;
- ret = uncompress2(compr_img->buff_raw[0], &cdbuffer_size, compr_img->buff_compressed, size);
+ ret = uncompress2_pcsx(compr_img->buff_raw[0], &cdbuffer_size, compr_img->buff_compressed, size);
if (ret != 0) {
SysPrintf("uncompress failed with %d for block %d, sector %d\n",
ret, block, sector);
// file for playback
static long CALLBACK ISOopen(void) {
boolean isMode1ISO = FALSE;
+ char alt_bin_filename[MAXPATHLEN];
+ const char *bin_filename;
if (cdHandle != NULL) {
return 0; // it's already open
cdHandle = fopen(GetIsoFile(), "rb");
if (cdHandle == NULL) {
+ SysPrintf(_("Could't open '%s' for reading: %s\n"),
+ GetIsoFile(), strerror(errno));
return -1;
}
subChanRaw = FALSE;
pregapOffset = 0;
cdrIsoMultidiskCount = 1;
+ multifile = 0;
CDR_getBuffer = ISOgetBuffer;
cdimg_read_func = cdread_normal;
- if (parsecue(GetIsoFile()) == 0) {
- SysPrintf("[+cue]");
- }
- else if (parsetoc(GetIsoFile()) == 0) {
+ if (parsetoc(GetIsoFile()) == 0) {
SysPrintf("[+toc]");
}
else if (parseccd(GetIsoFile()) == 0) {
else if (parsemds(GetIsoFile()) == 0) {
SysPrintf("[+mds]");
}
+ else if (parsecue(GetIsoFile()) == 0) {
+ SysPrintf("[+cue]");
+ }
if (handlepbp(GetIsoFile()) == 0) {
SysPrintf("[pbp]");
CDR_getBuffer = ISOgetBuffer_compr;
SysPrintf("[+sbi]");
}
+ fseeko(cdHandle, 0, SEEK_END);
+
+ // maybe user selected metadata file instead of main .bin ..
+ bin_filename = GetIsoFile();
+ if (ftello(cdHandle) < 2352 * 0x10) {
+ static const char *exts[] = { ".bin", ".BIN", ".img", ".IMG" };
+ FILE *tmpf = NULL;
+ size_t i;
+ char *p;
+
+ strncpy(alt_bin_filename, bin_filename, sizeof(alt_bin_filename));
+ alt_bin_filename[MAXPATHLEN - 1] = '\0';
+ if (strlen(alt_bin_filename) >= 4) {
+ p = alt_bin_filename + strlen(alt_bin_filename) - 4;
+ for (i = 0; i < sizeof(exts) / sizeof(exts[0]); i++) {
+ strcpy(p, exts[i]);
+ tmpf = fopen(alt_bin_filename, "rb");
+ if (tmpf != NULL)
+ break;
+ }
+ }
+ if (tmpf != NULL) {
+ bin_filename = alt_bin_filename;
+ fclose(cdHandle);
+ cdHandle = tmpf;
+ fseeko(cdHandle, 0, SEEK_END);
+ }
+ }
+
// guess whether it is mode1/2048
- fseek(cdHandle, 0, SEEK_END);
- if (ftell(cdHandle) % 2048 == 0) {
+ if (ftello(cdHandle) % 2048 == 0) {
unsigned int modeTest = 0;
fseek(cdHandle, 0, SEEK_SET);
fread(&modeTest, 4, 1, cdHandle);
// make sure we have another handle open for cdda
if (numtracks > 1 && ti[1].handle == NULL) {
- ti[1].handle = fopen(GetIsoFile(), "rb");
+ ti[1].handle = fopen(bin_filename, "rb");
}
cdda_cur_sector = 0;
cdda_file_offset = 0;
}
}
numtracks = 0;
+ ti[1].type = 0;
UnloadSBI();
+ memset(cdbuffer, 0, sizeof(cdbuffer));
+ CDR_getBuffer = ISOgetBuffer;
+
return 0;
}
// byte 2 - minute
static long CALLBACK ISOgetTD(unsigned char track, unsigned char *buffer) {
if (track == 0) {
- // CD length according pcsxr-svn (done a bit different here)
unsigned int sect;
unsigned char time[3];
sect = msf2sec(ti[numtracks].start) + msf2sec(ti[numtracks].length);
// uses bcd format
static long CALLBACK ISOreadTrack(unsigned char *time) {
int sector = MSF2SECT(btoi(time[0]), btoi(time[1]), btoi(time[2]));
+ long ret;
if (cdHandle == NULL) {
return -1;
}
}
- cdimg_read_func(cdHandle, 0, cdbuffer, sector);
+ ret = cdimg_read_func(cdHandle, 0, cdbuffer, sector);
+ if (ret < 0)
+ return -1;
if (subHandle != NULL) {
fseek(subHandle, sector * SUB_FRAMESIZE, SEEK_SET);
}
static long CALLBACK ISOgetStatus(struct CdrStat *stat) {
- int sec;
-
+ u32 sect;
+
CDR__getStatus(stat);
-
+
if (playing) {
stat->Type = 0x02;
stat->Status |= 0x80;
}
else {
- stat->Type = 0x01;
+ // BIOS - boot ID (CD type)
+ stat->Type = ti[1].type;
+ }
+
+ // relative -> absolute time
+ sect = cddaCurPos;
+ sec2msf(sect, (char *)stat->Time);
+
+ 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;
+
+ cddaCurPos = msf2sec((char *)msf);
+
+ // find current track index
+ for (track = numtracks; ; track--) {
+ track_start = msf2sec(ti[track].start);
+ if (track_start <= cddaCurPos)
+ break;
+ if (track == 1)
+ break;
}
- sec = cdda_cur_sector;
- sec2msf(sec, (char *)stat->Time);
+ // data tracks play silent
+ if (ti[track].type != CDDA) {
+ memset(buffer, 0, CD_FRAMESIZE_RAW);
+ return 0;
+ }
+
+ file = 1;
+ if (multifile) {
+ // find the file that contains this track
+ for (file = track; file > 1; file--)
+ if (ti[file].handle != NULL)
+ break;
+ }
+
+ ret = cdimg_read_func(ti[file].handle, ti[track].start_offset,
+ buffer, cddaCurPos - track_start);
+ if (ret != CD_FRAMESIZE_RAW) {
+ memset(buffer, 0, CD_FRAMESIZE_RAW);
+ return -1;
+ }
+
+ if (cddaBigEndian) {
+ 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;
+ }
+ }
return 0;
}
CDR_stop = ISOstop;
CDR_getBufferSub = ISOgetBufferSub;
CDR_getStatus = ISOgetStatus;
+ CDR_readCDDA = ISOreadCDDA;
CDR_getDriveLetter = CDR__getDriveLetter;
CDR_configure = CDR__configure;