+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)
+{
+ fseek(f, base + sector * CD_FRAMESIZE_RAW, SEEK_SET);
+ return fread(dest, 1, CD_FRAMESIZE_RAW, f);
+}
+
+static int cdread_sub_mixed(FILE *f, unsigned int base, void *dest, int sector)
+{
+ int ret;
+
+ fseek(f, base + sector * (CD_FRAMESIZE_RAW + SUB_FRAMESIZE), SEEK_SET);
+ ret = fread(dest, 1, CD_FRAMESIZE_RAW, f);
+ if (fread(subbuffer, 1, SUB_FRAMESIZE, f) != SUB_FRAMESIZE)
+ goto fail_io;
+
+ if (subChanRaw) DecodeRawSubData();
+ goto done;
+
+fail_io:
+#ifndef NDEBUG
+ SysPrintf(_("File IO error in <%s:%s>.\n"), __FILE__, __func__);
+#endif
+
+done:
+ return ret;
+}
+
+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 int cdread_chd(FILE *f, unsigned int base, void *dest, int sector)
+{
+ int hunk;
+
+ if (base)
+ 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)
+ {
+ chd_read(chd_img->chd, hunk, chd_img->buffer);
+ chd_img->current_hunk = hunk;
+ }
+
+ if (dest != cdbuffer) // copy avoid HACK
+ memcpy(dest, chd_img->buffer[chd_img->sector_in_hunk],
+ CD_FRAMESIZE_RAW);
+ if (subChanMixed) {
+ memcpy(subbuffer, chd_img->buffer[chd_img->sector_in_hunk] + CD_FRAMESIZE_RAW,
+ SUB_FRAMESIZE);
+ if (subChanRaw)
+ DecodeRawSubData();
+ }
+ return CD_FRAMESIZE_RAW;
+}
+#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 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_img->buffer[chd_img->sector_in_hunk] + 12;
+}
+#endif
+
+static unsigned char * CALLBACK ISOgetBuffer(void) {
+ return cdbuffer + 12;
+}
+