+static int cdread_normal(FILE *f, void *dest, int sector, int offset)
+{
+ fseek(f, sector * CD_FRAMESIZE_RAW + offset, SEEK_SET);
+ return fread(dest, 1, CD_FRAMESIZE_RAW - offset, f);
+}
+
+static int cdread_sub_mixed(FILE *f, void *dest, int sector, int offset)
+{
+ int ret;
+
+ fseek(f, sector * (CD_FRAMESIZE_RAW + SUB_FRAMESIZE) + offset, SEEK_SET);
+ ret = fread(dest, 1, CD_FRAMESIZE_RAW - offset, f);
+ fread(subbuffer, 1, SUB_FRAMESIZE, f);
+
+ if (subChanRaw) DecodeRawSubData();
+
+ return ret;
+}
+
+static int uncompress2(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, void *dest, int sector, int offset)
+{
+ unsigned int start_byte, size;
+ unsigned long cdbuffer_size;
+ int ret, block;
+
+ block = sector >> 4;
+ compr_img->sector_in_blk = sector & 15;
+
+ if (block == compr_img->current_block) {
+ //printf("hit sect %d\n", sector);
+ goto finish;
+ }
+
+ if (sector >= compr_img->index_len * 16) {
+ fprintf(stderr, "sector %d is past img end\n", sector);
+ return -1;
+ }
+
+ start_byte = compr_img->index_table[block];
+ if (fseek(cdHandle, start_byte, SEEK_SET) != 0) {
+ fprintf(stderr, "seek error for block %d at %x: ",
+ block, start_byte);
+ perror(NULL);
+ return -1;
+ }
+
+ size = compr_img->index_table[block + 1] - start_byte;
+ if (size > sizeof(compr_img->buff_compressed)) {
+ fprintf(stderr, "block %d is too large: %u\n", block, size);
+ return -1;
+ }
+
+ if (fread(compr_img->buff_compressed, 1, size, cdHandle) != size) {
+ fprintf(stderr, "read error for block %d at %x: ", block, start_byte);
+ perror(NULL);
+ return -1;
+ }
+
+ cdbuffer_size = sizeof(compr_img->buff_raw[0]) * 16;
+ ret = uncompress2(compr_img->buff_raw[0], &cdbuffer_size, compr_img->buff_compressed, size);
+ if (ret != 0) {
+ fprintf(stderr, "uncompress failed with %d for block %d, sector %d\n",
+ ret, block, sector);
+ return -1;
+ }
+ if (cdbuffer_size != sizeof(compr_img->buff_raw[0]) * 16)
+ fprintf(stderr, "cdbuffer_size: %lu != %d, sector %d\n", cdbuffer_size,
+ sizeof(compr_img->buff_raw[0]) * 16, 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] + offset,
+ CD_FRAMESIZE_RAW - offset);
+ return CD_FRAMESIZE_RAW - offset;
+}
+
+static int cdread_2048(FILE *f, void *dest, int sector, int offset)
+{
+ int ret;
+
+ fseek(f, sector * 2048, SEEK_SET);
+ ret = fread((char *)dest + 12, 1, 2048, f);
+
+ // not really necessary, fake mode 2 header
+ memset(cdbuffer, 0, 12);
+ sec2msf(sector + 2 * 75, (char *)cdbuffer);
+ cdbuffer[3] = 1;
+
+ return ret;
+}
+
+static unsigned char * CALLBACK ISOgetBuffer_compr(void) {
+ return compr_img->buff_raw[compr_img->sector_in_blk] + 12;
+}
+
+static unsigned char * CALLBACK ISOgetBuffer(void) {
+ return cdbuffer;
+}
+