+static int opensbifile(const char *isoname) {
+ char sbiname[MAXPATHLEN], disknum[MAXPATHLEN] = "0";
+ int s;
+
+ strncpy(sbiname, isoname, sizeof(sbiname));
+ sbiname[MAXPATHLEN - 1] = '\0';
+ if (strlen(sbiname) >= 4) {
+ if (cdrIsoMultidiskCount > 1) {
+ sprintf(disknum, "_%i.sbi", cdrIsoMultidiskSelect + 1);
+ strcpy(sbiname + strlen(sbiname) - 4, disknum);
+ }
+ else
+ strcpy(sbiname + strlen(sbiname) - 4, ".sbi");
+ }
+ else {
+ return -1;
+ }
+
+ fseek(cdHandle, 0, SEEK_END);
+ s = ftell(cdHandle) / 2352;
+
+ return LoadSBI(sbiname, s);
+}
+
+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))
+ goto fail_io;
+ ret = fread(dest, 1, CD_FRAMESIZE_RAW, f);
+ if (ret <= 0)
+ goto fail_io;
+ return ret;
+
+fail_io:
+ // often happens in cdda gaps of a split cue/bin, so not logged
+ //SysPrintf("File IO error %d, base %u, sector %u\n", errno, base, sector);
+ return -1;
+}
+
+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))
+ goto fail_io;
+ ret = fread(dest, 1, CD_FRAMESIZE_RAW, f);
+ if (ret <= 0)
+ goto fail_io;
+ return ret;
+
+fail_io:
+ //SysPrintf("File IO error %d, base %u, sector %u\n", errno, base, sector);
+ return -1;
+}
+
+static int cdread_sub_sub_mixed(FILE *f, int sector)
+{
+ if (fseek(f, sector * (CD_FRAMESIZE_RAW + SUB_FRAMESIZE) + CD_FRAMESIZE_RAW, SEEK_SET))
+ goto fail_io;
+ if (fread(subbuffer, 1, SUB_FRAMESIZE, f) != SUB_FRAMESIZE)
+ goto fail_io;
+
+ return SUB_FRAMESIZE;
+
+fail_io:
+ SysPrintf("subchannel: file IO error %d, sector %u\n", errno, sector);
+ return -1;
+}
+
+static int uncompress2_pcsx(void *out, unsigned long *out_size, void *in, unsigned long in_size)
+{
+ static z_stream z;
+ int ret = 0;
+
+ if (z.zalloc == NULL) {
+ // XXX: one-time leak here..
+ z.next_in = Z_NULL;
+ z.avail_in = 0;
+ z.zalloc = Z_NULL;
+ z.zfree = Z_NULL;
+ z.opaque = Z_NULL;
+ ret = inflateInit2(&z, -15);
+ }
+ else
+ ret = inflateReset(&z);
+ if (ret != Z_OK)
+ return ret;
+
+ z.next_in = in;
+ z.avail_in = in_size;
+ z.next_out = out;
+ z.avail_out = *out_size;
+
+ ret = inflate(&z, Z_NO_FLUSH);
+ //inflateEnd(&z);
+
+ *out_size -= z.avail_out;
+ return ret == 1 ? 0 : ret;
+}
+
+static int cdread_compressed(FILE *f, unsigned int base, void *dest, int sector)
+{
+ unsigned long cdbuffer_size, cdbuffer_size_expect;
+ unsigned int size;
+ int is_compressed;
+ off_t start_byte;
+ int ret, block;
+
+ if (base)
+ sector += base / 2352;
+
+ block = sector >> compr_img->block_shift;
+ compr_img->sector_in_blk = sector & ((1 << compr_img->block_shift) - 1);
+
+ if (block == compr_img->current_block) {
+ //printf("hit sect %d\n", sector);
+ goto finish;
+ }
+
+ if (sector >= compr_img->index_len * 16) {
+ SysPrintf("sector %d is past img end\n", sector);
+ return -1;
+ }
+
+ 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] & 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 (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);
+ perror(NULL);
+ 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_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);
+ return -1;
+ }
+ if (cdbuffer_size != cdbuffer_size_expect)
+ SysPrintf("cdbuffer_size: %lu != %lu, sector %d\n", cdbuffer_size,
+ cdbuffer_size_expect, sector);
+ }
+
+ // done at last!
+ compr_img->current_block = block;
+
+finish:
+ if (dest != cdbuffer) // copy avoid HACK
+ memcpy(dest, compr_img->buff_raw[compr_img->sector_in_blk],
+ CD_FRAMESIZE_RAW);
+ return CD_FRAMESIZE_RAW;
+}
+
+#ifdef HAVE_CHD
+static unsigned char *chd_get_sector(unsigned int current_buffer, unsigned int sector_in_hunk)
+{
+ return chd_img->buffer
+ + current_buffer * chd_img->header->hunkbytes
+ + sector_in_hunk * (CD_FRAMESIZE_RAW + SUB_FRAMESIZE);
+}
+
+static int cdread_chd(FILE *f, unsigned int base, void *dest, int sector)
+{
+ int hunk;
+
+ sector += base;
+
+ hunk = sector / chd_img->sectors_per_hunk;
+ chd_img->sector_in_hunk = sector % chd_img->sectors_per_hunk;
+
+ if (hunk == chd_img->current_hunk[0])
+ chd_img->current_buffer = 0;
+ else if (hunk == chd_img->current_hunk[1])
+ chd_img->current_buffer = 1;
+ else
+ {
+ chd_read(chd_img->chd, hunk, chd_img->buffer +
+ chd_img->current_buffer * chd_img->header->hunkbytes);
+ chd_img->current_hunk[chd_img->current_buffer] = hunk;
+ }
+
+ if (dest != cdbuffer) // copy avoid HACK
+ 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)
+{
+ unsigned int sector_in_hunk;
+ unsigned int buffer;
+ int hunk;
+
+ if (!subChanMixed)
+ return -1;
+
+ hunk = sector / chd_img->sectors_per_hunk;
+ sector_in_hunk = sector % chd_img->sectors_per_hunk;
+
+ if (hunk == chd_img->current_hunk[0])
+ buffer = 0;
+ else if (hunk == chd_img->current_hunk[1])
+ buffer = 1;
+ else
+ {
+ buffer = chd_img->current_buffer ^ 1;
+ chd_read(chd_img->chd, hunk, chd_img->buffer +
+ buffer * chd_img->header->hunkbytes);
+ chd_img->current_hunk[buffer] = hunk;
+ }
+
+ memcpy(subbuffer, chd_get_sector(buffer, sector_in_hunk) + CD_FRAMESIZE_RAW, SUB_FRAMESIZE);
+ return SUB_FRAMESIZE;
+}
+#endif
+
+static int cdread_2048(FILE *f, unsigned int base, void *dest, int sector)
+{
+ int ret;
+
+ fseek(f, base + sector * 2048, SEEK_SET);
+ ret = fread((char *)dest + 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;
+
+ return 12*2 + ret;
+}
+
+static unsigned char * CALLBACK 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;
+}
+#endif
+
+static unsigned char * CALLBACK ISOgetBuffer(void) {
+ return cdbuffer + 12;
+}
+