add CHD support.
[pcsx_rearmed.git] / libpcsxcore / cdriso.c
index 6f59579..fb074e5 100644 (file)
@@ -27,6 +27,7 @@
 
 #include <errno.h>
 #include <zlib.h>
+#include <chd.h>
 
 #ifdef _WIN32
 #define WIN32_LEAN_AND_MEAN
@@ -93,6 +94,15 @@ static struct {
        unsigned int sector_in_blk;
 } *compr_img;
 
+static struct {
+       unsigned char (*buffer)[CD_FRAMESIZE_RAW + SUB_FRAMESIZE];
+       chd_file* chd;
+       const chd_header* header;
+       unsigned int sectors_per_hunk;
+       unsigned int current_hunk;
+       unsigned int sector_in_hunk;
+} *chd_img;
+
 int (*cdimg_read_func)(FILE *f, unsigned int base, void *dest, int sector);
 
 char* CALLBACK CDR__getDriveLetter(void);
@@ -1029,6 +1039,78 @@ fail_io:
        return -1;
 }
 
+static int handlechd(const char *isofile) {
+       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;
+
+   chd_img->header = chd_get_header(chd_img->chd);
+
+   chd_img->buffer = malloc(chd_img->header->hunkbytes);
+   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 = (unsigned int)-1;
+
+   cddaBigEndian = TRUE;
+
+       numtracks = 0;
+       int frame_offset = 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;
+
+               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);
+
+      if (!strcmp(md.type, md.pgtype))
+         frame_offset += md.pregap;
+
+      ti[md.track].start_offset = frame_offset * CD_FRAMESIZE_RAW;
+
+               frame_offset += (md.frames + 3) & ~3;
+               frame_offset += md.postgap;
+               numtracks++;
+       }
+
+       if (numtracks)
+               return 0;
+
+fail_io:
+       if (chd_img != NULL) {
+               free(chd_img->buffer);
+               free(chd_img);
+               chd_img = NULL;
+       }
+       return -1;
+}
+
 // this function tries to get the .sub file of the given .img
 static int opensubfile(const char *isoname) {
        char            subname[MAXPATHLEN];
@@ -1190,6 +1272,30 @@ finish:
        return CD_FRAMESIZE_RAW;
 }
 
+static int cdread_chd(FILE *f, unsigned int base, void *dest, int sector)
+{
+       int hunk;
+
+       if (base)
+               sector += base / CD_FRAMESIZE_RAW;
+
+       hunk = sector / chd_img->sectors_per_hunk;
+       chd_img->sector_in_hunk = sector % chd_img->sectors_per_hunk;
+
+       if (hunk == chd_img->current_hunk)
+               goto finish;
+
+       chd_read(chd_img->chd, hunk, chd_img->buffer);
+
+       chd_img->current_hunk = hunk;
+
+finish:
+       if (dest != cdbuffer) // copy avoid HACK
+               memcpy(dest, chd_img->buffer[chd_img->sector_in_hunk],
+                       CD_FRAMESIZE_RAW);
+       return CD_FRAMESIZE_RAW;
+}
+
 static int cdread_2048(FILE *f, unsigned int base, void *dest, int sector)
 {
        int ret;
@@ -1209,6 +1315,10 @@ static unsigned char * CALLBACK ISOgetBuffer_compr(void) {
        return compr_img->buff_raw[compr_img->sector_in_blk] + 12;
 }
 
+static unsigned char * CALLBACK ISOgetBuffer_chd(void) {
+       return chd_img->buffer[chd_img->sector_in_hunk] + 12;
+}
+
 static unsigned char * CALLBACK ISOgetBuffer(void) {
        return cdbuffer + 12;
 }
@@ -1276,6 +1386,11 @@ static long CALLBACK ISOopen(void) {
                CDR_getBuffer = ISOgetBuffer_compr;
                cdimg_read_func = cdread_compressed;
        }
+       else if (handlechd(GetIsoFile()) == 0) {
+               SysPrintf("[chd]");
+               CDR_getBuffer = ISOgetBuffer_chd;
+               cdimg_read_func = cdread_chd;
+       }
 
        if (!subChanMixed && opensubfile(GetIsoFile()) == 0) {
                SysPrintf("[+sub]");
@@ -1364,6 +1479,13 @@ static long CALLBACK ISOclose(void) {
                compr_img = NULL;
        }
 
+       if (chd_img != NULL) {
+               chd_close(chd_img->chd);
+               free(chd_img->buffer);
+               free(chd_img);
+               chd_img = NULL;
+       }
+
        for (i = 1; i <= numtracks; i++) {
                if (ti[i].handle != NULL) {
                        fclose(ti[i].handle);