core, groundwork for chd support

still needs some scrutiny, and build integration is missing
This commit is contained in:
kub 2021-03-04 20:48:02 +01:00
parent 4da84f9454
commit 15ca715228
18 changed files with 411 additions and 100 deletions

View file

@ -9,7 +9,7 @@
#include "../pico_int.h"
#include "genplus_macros.h"
#include "cdd.h"
#include "cue.h"
#include "cd_parse.h"
#ifdef USE_LIBRETRO_VFS
#include "file_stream_transforms.h"
@ -90,7 +90,7 @@ int load_cd_image(const char *cd_img_name, int *type)
int iso_name_len, missed, cd_img_sectors;
char tmp_name[256], tmp_ext[10], tmp_ext_u[10];
track_t *tracks = cdd.toc.tracks;
cue_data_t *cue_data = NULL;
cd_data_t *cue_data = NULL;
pm_file *pmf;
if (PicoCDLoadProgressCB != NULL)
@ -103,16 +103,21 @@ int load_cd_image(const char *cd_img_name, int *type)
if (cue_data != NULL) {
cd_img_name = cue_data->tracks[1].fname;
*type = cue_data->tracks[1].type;
} else {
cue_data = chd_parse(cd_img_name);
if (cue_data != NULL)
*type = cue_data->tracks[1].type;
}
pmf = pm_open(cd_img_name);
if (pmf == NULL)
{
if (cue_data != NULL)
cue_destroy(cue_data);
cdparse_destroy(cue_data);
return -1;
}
tracks[0].fd = pmf;
tracks[0].fname = strdup(cd_img_name);
if (*type == CT_ISO)
cd_img_sectors = pmf->size >>= 11; // size in sectors
@ -131,7 +136,7 @@ int load_cd_image(const char *cd_img_name, int *type)
if (cue_data != NULL)
{
if (cue_data->tracks[2].fname == NULL) {
if (cue_data->track_count > 1 && cue_data->tracks[2].fname == NULL) {
// NULL fname means track2 is in same file as track1
lba = tracks[0].end = cue_data->tracks[2].sector_offset;
}
@ -157,6 +162,7 @@ int load_cd_image(const char *cd_img_name, int *type)
{
// assume raw, ignore header for wav..
tracks[index].fd = f;
tracks[index].fname = strdup(cue_data->tracks[n].fname);
tracks[index].offset = cue_data->tracks[n].sector_offset;
length = f->size / 2352;
}
@ -189,8 +195,8 @@ int load_cd_image(const char *cd_img_name, int *type)
tracks[index].end = lba;
sprintf_lba(tmp_ext, sizeof(tmp_ext), tracks[index].start);
elprintf(EL_STATUS, "Track %2i: %s %9i AUDIO %s",
n, tmp_ext, length, cue_data->tracks[n].fname);
elprintf(EL_STATUS, "Track %2i: %s %9i AUDIO %s", n, tmp_ext, length,
cue_data->tracks[n].fname ? cue_data->tracks[n].fname : "");
}
goto finish;
}
@ -269,7 +275,7 @@ finish:
PicoCDLoadProgressCB(cd_img_name, 100);
if (cue_data != NULL)
cue_destroy(cue_data);
cdparse_destroy(cue_data);
return 0;
}

View file

@ -8,15 +8,20 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "cue.h"
#include "../pico_int.h"
#include "cd_parse.h"
// #define elprintf(w,f,...) printf(f "\n",##__VA_ARGS__);
#ifdef USE_LIBRETRO_VFS
#include "file_stream_transforms.h"
#endif
#if defined(USE_LIBCHDR)
#include "libchdr/chd.h"
#include "libchdr/cdrom.h"
#endif
#ifdef _MSC_VER
#define snprintf _snprintf
#endif
@ -75,7 +80,8 @@ static int get_ext(const char *fname, char ext[4],
if (len > 0)
pos = len;
strcpy(ext, fname + pos + 1);
strncpy(ext, fname + pos + 1, 4/*sizeof(ext)*/-1);
ext[4/*sizeof(ext)*/-1] = '\0';
if (base != NULL) {
if (pos + 1 < base_size)
@ -111,15 +117,110 @@ static int file_openable(const char *fname)
#define BEGINS(buff,str) (strncmp(buff,str,sizeof(str)-1) == 0)
/* note: tracks[0] is not used */
cue_data_t *cue_parse(const char *fname)
cd_data_t *chd_parse(const char *fname)
{
cd_data_t *data = NULL;
#if defined(USE_LIBCHDR)
cd_data_t *tmp;
int count = 0, count_alloc = 2;
int sectors = 0;
char metadata[256];
chd_file *cf = NULL;
if (fname == NULL || *fname == '\0')
return NULL;
if (chd_open(fname, CHD_OPEN_READ, NULL, &cf) != CHDERR_NONE)
goto out;
data = calloc(1, sizeof(*data) + count_alloc * sizeof(cd_track_t));
if (data == NULL)
goto out;
// get track info
while (count < CD_MAX_TRACKS) {
int track = 0, frames = 0, pregap = 0, postgap = 0;
char type[16], subtype[16], pgtype[16], pgsub[16];
type[0] = subtype[0] = pgtype[0] = pgsub[0] = 0;
// get metadata for track
if (chd_get_metadata(cf, CDROM_TRACK_METADATA2_TAG, count,
metadata, sizeof(metadata), 0, 0, 0) == CHDERR_NONE) {
if (sscanf(metadata, CDROM_TRACK_METADATA2_FORMAT,
&track, &type[0], &subtype[0], &frames,
&pregap, &pgtype[0], &pgsub[0], &postgap) != 8)
break;
}
else if (chd_get_metadata(cf, CDROM_TRACK_METADATA_TAG, count,
metadata, sizeof(metadata), 0, 0, 0) == CHDERR_NONE) {
if (sscanf(metadata, CDROM_TRACK_METADATA_FORMAT,
&track, &type[0], &subtype[0], &frames) != 4)
break;
}
else break; // all tracks completed
// metadata sanity check
if (track != count + 1 || frames < 0 || pregap < 0)
break;
// allocate track structure
count ++;
if (count >= count_alloc) {
count_alloc *= 2;
tmp = realloc(data, sizeof(*data) + count_alloc * sizeof(cd_track_t));
if (tmp == NULL) {
count--;
break;
}
data = tmp;
}
memset(&data->tracks[count], 0, sizeof(data->tracks[0]));
if (count == 1) { // binary code
data->tracks[count].fname = strdup(fname);
if (!strcmp(type, "MODE1_RAW") || !strcmp(type, "MODE2_RAW")) {
data->tracks[count].type = CT_BIN;
} else if (!strcmp(type, "MODE1") || !strcmp(type, "MODE2_FORM1")) {
data->tracks[count].type = CT_ISO;
} else
break;
} else { // audio
if (strcmp(type, "AUDIO"))
break;
data->tracks[count].type = CT_CHD;
}
data->tracks[count].pregap = pregap;
if (pgtype[0] != 'V') // VAUDIO includes pregap in file
pregap = 0;
data->tracks[count].sector_offset = sectors + pregap;
data->tracks[count].sector_xlength = frames - pregap;
sectors += (((frames + CD_TRACK_PADDING - 1) / CD_TRACK_PADDING) * CD_TRACK_PADDING);
}
// check if image id OK, i.e. there are tracks, and length <= 80 min
if (count && sectors < (80*60*75)) {
data->track_count = count;
} else {
free(data);
data = NULL;
}
out:
if (cf)
chd_close(cf);
#endif
return data;
}
cd_data_t *cue_parse(const char *fname)
{
char current_file[256], *current_filep, cue_base[256];
char buff[256], buff2[32], ext[4], *p;
int ret, count = 0, count_alloc = 2, pending_pregap = 0;
size_t current_filep_size, fname_len;
cue_data_t *data = NULL;
cd_data_t *data = NULL, *tmp;
FILE *f = NULL;
void *tmp;
if (fname == NULL || (fname_len = strlen(fname)) == 0)
return NULL;
@ -156,14 +257,13 @@ cue_data_t *cue_parse(const char *fname)
p = strrchr(cue_base, '.');
if (p) p[1] = '\0';
data = calloc(1, sizeof(*data) + count_alloc * sizeof(cue_track));
data = calloc(1, sizeof(*data) + count_alloc * sizeof(cd_track_t));
if (data == NULL)
goto out;
while (!feof(f))
{
tmp = fgets(buff, sizeof(buff), f);
if (tmp == NULL)
if (fgets(buff, sizeof(buff), f) == NULL)
break;
mystrip(buff);
@ -180,7 +280,7 @@ cue_data_t *cue_parse(const char *fname)
count++;
if (count >= count_alloc) {
count_alloc *= 2;
tmp = realloc(data, sizeof(*data) + count_alloc * sizeof(cue_track));
tmp = realloc(data, sizeof(*data) + count_alloc * sizeof(cd_track_t));
if (tmp == NULL) {
count--;
break;
@ -344,7 +444,7 @@ out:
}
void cue_destroy(cue_data_t *data)
void cdparse_destroy(cd_data_t *data)
{
int c;
@ -360,7 +460,7 @@ void cue_destroy(cue_data_t *data)
#if 0
int main(int argc, char *argv[])
{
cue_data_t *data = cue_parse(argv[1]);
cd_data_t *data = cue_parse(argv[1]);
int c;
if (data == NULL) return 1;
@ -370,7 +470,7 @@ int main(int argc, char *argv[])
data->tracks[c].sector_offset / (75*60), data->tracks[c].sector_offset / 75 % 60,
data->tracks[c].sector_offset % 75, data->tracks[c].pregap, data->tracks[c].fname);
cue_destroy(data);
cdparse_destroy(data);
return 0;
}

5
pico/cd/cd_parse.h Normal file
View file

@ -0,0 +1,5 @@
cd_data_t *chd_parse(const char *fname);
cd_data_t *cue_parse(const char *fname);
void cdparse_destroy(cd_data_t *data);

View file

@ -38,7 +38,7 @@
#include "../pico_int.h"
#include "genplus_macros.h"
#include "cue.h"
#include "cd_parse.h"
#include "cdd.h"
#ifdef USE_LIBTREMOR
@ -321,6 +321,7 @@ int cdd_load(const char *filename, int type)
ret = (type == CT_BIN) ? 2352 : 2048;
if (ret != cdd.sectorSize)
elprintf(EL_STATUS|EL_ANOMALY, "cd: type detection mismatch");
pm_sectorsize(cdd.sectorSize, cdd.toc.tracks[0].fd);
/* read CD image header + security code */
pm_read(header + 0x10, 0x200, cdd.toc.tracks[0].fd);
@ -448,6 +449,9 @@ int cdd_unload(void)
{
pm_close(cdd.toc.tracks[0].fd);
cdd.toc.tracks[0].fd = NULL;
if (cdd.toc.tracks[0].fname)
free(cdd.toc.tracks[0].fd);
cdd.toc.tracks[0].fname = NULL;
}
for (i = 1; i < cdd.toc.last; i++)
@ -466,7 +470,11 @@ int cdd_unload(void)
if (Pico_mcd->cdda_type == CT_MP3)
fclose(cdd.toc.tracks[i].fd);
else
pm_close(cdd.toc.tracks[0].fd);
pm_close(cdd.toc.tracks[i].fd);
cdd.toc.tracks[i].fd = NULL;
if (cdd.toc.tracks[i].fname)
free(cdd.toc.tracks[i].fd);
cdd.toc.tracks[i].fname = NULL;
/* detect single file images */
if (cdd.toc.tracks[i+1].fd == cdd.toc.tracks[i].fd)

View file

@ -60,6 +60,7 @@
/* CD track */
typedef struct
{
char *fname;
void *fd;
#ifdef USE_LIBTREMOR
OggVorbis_File vf;

View file

@ -1,29 +0,0 @@
typedef enum
{
CT_UNKNOWN = 0,
CT_ISO = 1, /* 2048 B/sector */
CT_BIN = 2, /* 2352 B/sector */
CT_MP3 = 3,
CT_WAV = 4
} cue_track_type;
typedef struct
{
char *fname;
int pregap; /* pregap for current track */
int sector_offset; /* in current file */
int sector_xlength;
cue_track_type type;
} cue_track;
typedef struct
{
int track_count;
cue_track tracks[0];
} cue_data_t;
cue_data_t *cue_parse(const char *fname);
void cue_destroy(cue_data_t *data);