+static int handlepbp(const char *isofile) {
+ struct {
+ unsigned int sig;
+ unsigned int dontcare[8];
+ unsigned int psar_offs;
+ } pbp_hdr;
+ struct {
+ unsigned char type;
+ unsigned char pad0;
+ unsigned char track;
+ char index0[3];
+ char pad1;
+ char index1[3];
+ } toc_entry;
+ struct {
+ unsigned int offset;
+ unsigned int size;
+ unsigned int dontcare[6];
+ } index_entry;
+ char psar_sig[11];
+ off_t psisoimg_offs, cdimg_base;
+ unsigned int t, cd_length;
+ unsigned int offsettab[8];
+ unsigned int psar_offs, index_entry_size, index_entry_offset;
+ const char *ext = NULL;
+ int i, ret;
+
+ if (strlen(isofile) >= 4)
+ ext = isofile + strlen(isofile) - 4;
+ if (ext == NULL || strcasecmp(ext, ".pbp") != 0)
+ return -1;
+
+ numtracks = 0;
+
+ ret = fread(&pbp_hdr, 1, sizeof(pbp_hdr), cdHandle);
+ if (ret != sizeof(pbp_hdr)) {
+ SysPrintf("failed to read pbp\n");
+ goto fail_io;
+ }
+
+ psar_offs = SWAP32(pbp_hdr.psar_offs);
+
+ ret = fseeko(cdHandle, psar_offs, SEEK_SET);
+ if (ret != 0) {
+ SysPrintf("failed to seek to %x\n", psar_offs);
+ goto fail_io;
+ }
+
+ psisoimg_offs = psar_offs;
+ if (fread(psar_sig, 1, sizeof(psar_sig), cdHandle) != sizeof(psar_sig))
+ goto fail_io;
+ psar_sig[10] = 0;
+ if (strcmp(psar_sig, "PSTITLEIMG") == 0) {
+ // multidisk image?
+ ret = fseeko(cdHandle, psar_offs + 0x200, SEEK_SET);
+ if (ret != 0) {
+ SysPrintf("failed to seek to %x\n", psar_offs + 0x200);
+ goto fail_io;
+ }
+
+ if (fread(&offsettab, 1, sizeof(offsettab), cdHandle) != sizeof(offsettab)) {
+ SysPrintf("failed to read offsettab\n");
+ goto fail_io;
+ }
+
+ for (i = 0; i < sizeof(offsettab) / sizeof(offsettab[0]); i++) {
+ if (offsettab[i] == 0)
+ break;
+ }
+ cdrIsoMultidiskCount = i;
+ if (cdrIsoMultidiskCount == 0) {
+ SysPrintf("multidisk eboot has 0 images?\n");
+ goto fail_io;
+ }
+
+ if (cdrIsoMultidiskSelect >= cdrIsoMultidiskCount)
+ cdrIsoMultidiskSelect = 0;
+
+ psisoimg_offs += SWAP32(offsettab[cdrIsoMultidiskSelect]);
+
+ ret = fseeko(cdHandle, psisoimg_offs, SEEK_SET);
+ if (ret != 0) {
+ SysPrintf("failed to seek to %llx\n", (long long)psisoimg_offs);
+ goto fail_io;
+ }
+
+ if (fread(psar_sig, 1, sizeof(psar_sig), cdHandle) != sizeof(psar_sig))
+ goto fail_io;
+ psar_sig[10] = 0;
+ }
+
+ if (strcmp(psar_sig, "PSISOIMG00") != 0) {
+ SysPrintf("bad psar_sig: %s\n", psar_sig);
+ goto fail_io;
+ }
+
+ // seek to TOC
+ ret = fseeko(cdHandle, psisoimg_offs + 0x800, SEEK_SET);
+ if (ret != 0) {
+ SysPrintf("failed to seek to %llx\n", (long long)psisoimg_offs + 0x800);
+ goto fail_io;
+ }
+
+ // first 3 entries are special
+ fseek(cdHandle, sizeof(toc_entry), SEEK_CUR);
+ if (fread(&toc_entry, 1, sizeof(toc_entry), cdHandle) != sizeof(toc_entry))
+ goto fail_io;
+ numtracks = btoi(toc_entry.index1[0]);
+
+ if (fread(&toc_entry, 1, sizeof(toc_entry), cdHandle) != sizeof(toc_entry))
+ goto fail_io;
+ cd_length = btoi(toc_entry.index1[0]) * 60 * 75 +
+ btoi(toc_entry.index1[1]) * 75 + btoi(toc_entry.index1[2]);
+
+ for (i = 1; i <= numtracks; i++) {
+ if (fread(&toc_entry, 1, sizeof(toc_entry), cdHandle) != sizeof(toc_entry))
+ goto fail_io;
+
+ ti[i].type = (toc_entry.type == 1) ? CDDA : DATA;
+
+ ti[i].start_offset = btoi(toc_entry.index0[0]) * 60 * 75 +
+ btoi(toc_entry.index0[1]) * 75 + btoi(toc_entry.index0[2]);
+ ti[i].start_offset *= 2352;
+ ti[i].start[0] = btoi(toc_entry.index1[0]);
+ ti[i].start[1] = btoi(toc_entry.index1[1]);
+ ti[i].start[2] = btoi(toc_entry.index1[2]);
+
+ if (i > 1) {
+ t = msf2sec(ti[i].start) - msf2sec(ti[i - 1].start);
+ sec2msf(t, ti[i - 1].length);
+ }
+ }
+ t = cd_length - ti[numtracks].start_offset / 2352;
+ sec2msf(t, ti[numtracks].length);
+
+ // seek to ISO index
+ ret = fseeko(cdHandle, psisoimg_offs + 0x4000, SEEK_SET);
+ if (ret != 0) {
+ SysPrintf("failed to seek to ISO index\n");
+ goto fail_io;
+ }
+
+ compr_img = calloc(1, sizeof(*compr_img));
+ if (compr_img == NULL)
+ goto fail_io;
+
+ compr_img->block_shift = 4;
+ compr_img->current_block = (unsigned int)-1;
+
+ compr_img->index_len = (0x100000 - 0x4000) / sizeof(index_entry);
+ compr_img->index_table = malloc((compr_img->index_len + 1) * sizeof(compr_img->index_table[0]));
+ if (compr_img->index_table == NULL)
+ goto fail_io;
+
+ cdimg_base = psisoimg_offs + 0x100000;
+ for (i = 0; i < compr_img->index_len; i++) {
+ ret = fread(&index_entry, 1, sizeof(index_entry), cdHandle);
+ if (ret != sizeof(index_entry)) {
+ SysPrintf("failed to read index_entry #%d\n", i);
+ goto fail_index;
+ }
+
+ index_entry_size = SWAP32(index_entry.size);
+ index_entry_offset = SWAP32(index_entry.offset);
+
+ if (index_entry_size == 0)
+ break;
+
+ compr_img->index_table[i] = cdimg_base + index_entry_offset;
+ }
+ compr_img->index_table[i] = cdimg_base + index_entry_offset + index_entry_size;
+
+ return 0;
+
+fail_index:
+ free(compr_img->index_table);
+ compr_img->index_table = NULL;
+ goto done;
+
+fail_io:
+ SysPrintf(_("File IO error in <%s:%s>.\n"), __FILE__, __func__);
+ rewind(cdHandle);
+
+done:
+ if (compr_img != NULL) {
+ free(compr_img);
+ compr_img = NULL;
+ }
+ return -1;
+}
+
+static int handlecbin(const char *isofile) {
+ struct
+ {
+ char magic[4];
+ unsigned int header_size;
+ unsigned long long total_bytes;
+ unsigned int block_size;
+ unsigned char ver; // 1
+ unsigned char align;
+ 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 (strlen(isofile) >= 5)
+ ext = isofile + strlen(isofile) - 5;
+ if (ext == NULL || (strcasecmp(ext + 1, ".cbn") != 0 && strcasecmp(ext, ".cbin") != 0))
+ return -1;
+
+ ret = fread(&ciso_hdr, 1, sizeof(ciso_hdr), cdHandle);
+ if (ret != sizeof(ciso_hdr)) {
+ SysPrintf("failed to read ciso header\n");
+ 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");
+ 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);
+ goto fail_io;
+ }
+ }
+
+ compr_img = calloc(1, sizeof(*compr_img));
+ if (compr_img == NULL)
+ goto fail_io;
+
+ compr_img->block_shift = 0;
+ compr_img->current_block = (unsigned int)-1;
+
+ compr_img->index_len = ciso_hdr.total_bytes / ciso_hdr.block_size;
+ index_table = malloc((compr_img->index_len + 1) * sizeof(index_table[0]));
+ if (index_table == NULL)
+ goto fail_io;
+
+ 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 = index_table[i];
+ plain = index & 0x80000000;
+ index &= 0x7fffffff;
+ compr_img->index_table[i] = (off_t)index << ciso_hdr.align;
+ if (plain)
+ compr_img->index_table[i] |= OFF_T_MSB;
+ }
+
+ return 0;
+
+fail_index:
+ free(index_table);
+fail_io:
+ if (compr_img != NULL) {
+ free(compr_img);
+ compr_img = NULL;
+ }
+ rewind(cdHandle);
+ return -1;
+}
+
+#ifdef HAVE_CHD
+static int handlechd(const char *isofile) {
+ int frame_offset = 150;
+ int file_offset = 0;
+
+ 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)
+ goto fail_io;
+
+ if (Config.CHD_Precache && (chd_precache(chd_img->chd) != CHDERR_NONE))
+ goto fail_io;
+
+ chd_img->header = chd_get_header(chd_img->chd);
+
+ chd_img->buffer = malloc(chd_img->header->hunkbytes * 2);
+ if (chd_img->buffer == NULL)
+ goto fail_io;
+
+ chd_img->sectors_per_hunk = chd_img->header->hunkbytes / (CD_FRAMESIZE_RAW + SUB_FRAMESIZE);
+ chd_img->current_hunk[0] = (unsigned int)-1;
+ chd_img->current_hunk[1] = (unsigned int)-1;
+
+ cddaBigEndian = TRUE;
+
+ numtracks = 0;
+ memset(ti, 0, sizeof(ti));
+
+ while (1)
+ {
+ struct {
+ char type[64];
+ char subtype[32];
+ char pgtype[32];
+ char pgsub[32];
+ uint32_t track;
+ uint32_t frames;
+ uint32_t pregap;
+ uint32_t postgap;
+ } md = {};
+ char meta[256];
+ uint32_t meta_size = 0;
+
+ if (chd_get_metadata(chd_img->chd, CDROM_TRACK_METADATA2_TAG, numtracks, meta, sizeof(meta), &meta_size, NULL, NULL) == CHDERR_NONE)
+ sscanf(meta, CDROM_TRACK_METADATA2_FORMAT, &md.track, md.type, md.subtype, &md.frames, &md.pregap, md.pgtype, md.pgsub, &md.postgap);
+ else if (chd_get_metadata(chd_img->chd, CDROM_TRACK_METADATA_TAG, numtracks, meta, sizeof(meta), &meta_size, NULL, NULL) == CHDERR_NONE)
+ sscanf(meta, CDROM_TRACK_METADATA_FORMAT, &md.track, md.type, md.subtype, &md.frames);
+ else
+ break;
+
+ SysPrintf("chd: %s\n", meta);
+
+ if (md.track == 1) {
+ if (!strncmp(md.subtype, "RW", 2)) {
+ subChanMixed = TRUE;
+ if (!strcmp(md.subtype, "RW_RAW"))
+ subChanRaw = TRUE;
+ }
+ }
+
+ ti[md.track].type = !strncmp(md.type, "AUDIO", 5) ? CDDA : DATA;
+
+ sec2msf(frame_offset + md.pregap, ti[md.track].start);
+ sec2msf(md.frames, ti[md.track].length);
+
+ ti[md.track].start_offset = file_offset + md.pregap;
+
+ // XXX: what about postgap?
+ frame_offset += md.frames;
+ file_offset += md.frames;
+ numtracks++;
+ }
+
+ if (numtracks)
+ return 0;
+
+fail_io:
+ if (chd_img != NULL) {
+ free(chd_img->buffer);
+ free(chd_img);
+ chd_img = NULL;
+ }
+ return -1;
+}
+#endif
+