chdman: Correct processing of GDI files, add ability to extractcd to .gdi, verified perfect checksum round-tripping on .GDI files. [R. Belmont]

This commit is contained in:
R. Belmont 2012-03-04 02:17:35 +00:00
parent b89d7c94c7
commit bb993d1174
6 changed files with 289 additions and 143 deletions

View File

@ -702,11 +702,11 @@ chd_error cdrom_parse_metadata(chd_file *chd, cdrom_toc *toc)
/* start with no tracks */ /* start with no tracks */
for (toc->numtrks = 0; toc->numtrks < CD_MAX_TRACKS; toc->numtrks++) for (toc->numtrks = 0; toc->numtrks < CD_MAX_TRACKS; toc->numtrks++)
{ {
int tracknum = -1, frames = 0, pregap, postgap; int tracknum = -1, frames = 0, pregap, postgap, padframes;
char type[16], subtype[16], pgtype[16], pgsub[16]; char type[16], subtype[16], pgtype[16], pgsub[16];
cdrom_track_info *track; cdrom_track_info *track;
pregap = postgap = 0; pregap = postgap = padframes = 0;
/* fetch the metadata for this track */ /* fetch the metadata for this track */
err = chd->read_metadata(CDROM_TRACK_METADATA_TAG, toc->numtrks, metadata); err = chd->read_metadata(CDROM_TRACK_METADATA_TAG, toc->numtrks, metadata);
@ -723,16 +723,37 @@ chd_error cdrom_parse_metadata(chd_file *chd, cdrom_toc *toc)
else else
{ {
err = chd->read_metadata(CDROM_TRACK_METADATA2_TAG, toc->numtrks, metadata); err = chd->read_metadata(CDROM_TRACK_METADATA2_TAG, toc->numtrks, metadata);
if (err != CHDERR_NONE) if (err == CHDERR_NONE)
break; {
/* parse the metadata */ /* parse the metadata */
type[0] = subtype[0] = 0; type[0] = subtype[0] = 0;
pregap = postgap = 0; pregap = postgap = 0;
if (sscanf(metadata, CDROM_TRACK_METADATA2_FORMAT, &tracknum, type, subtype, &frames, &pregap, pgtype, pgsub, &postgap) != 8) if (sscanf(metadata, CDROM_TRACK_METADATA2_FORMAT, &tracknum, type, subtype, &frames, &pregap, pgtype, pgsub, &postgap) != 8)
return CHDERR_INVALID_DATA; return CHDERR_INVALID_DATA;
if (tracknum == 0 || tracknum > CD_MAX_TRACKS) if (tracknum == 0 || tracknum > CD_MAX_TRACKS)
return CHDERR_INVALID_DATA; return CHDERR_INVALID_DATA;
track = &toc->tracks[tracknum - 1]; track = &toc->tracks[tracknum - 1];
}
else
{
err = chd->read_metadata(GDROM_TRACK_METADATA_TAG, toc->numtrks, metadata);
if (err == CHDERR_NONE)
{
/* parse the metadata */
type[0] = subtype[0] = 0;
pregap = postgap = 0;
if (sscanf(metadata, GDROM_TRACK_METADATA_FORMAT, &tracknum, type, subtype, &frames, &padframes, &pregap, pgtype, pgsub, &postgap) != 9)
return CHDERR_INVALID_DATA;
if (tracknum == 0 || tracknum > CD_MAX_TRACKS)
return CHDERR_INVALID_DATA;
track = &toc->tracks[tracknum - 1];
}
else
{
break;
}
}
} }
/* extract the track type and determine the data size */ /* extract the track type and determine the data size */
@ -749,6 +770,7 @@ chd_error cdrom_parse_metadata(chd_file *chd, cdrom_toc *toc)
/* set the frames and extra frames data */ /* set the frames and extra frames data */
track->frames = frames; track->frames = frames;
track->padframes = padframes;
int padded = (frames + CD_TRACK_PADDING - 1) / CD_TRACK_PADDING; int padded = (frames + CD_TRACK_PADDING - 1) / CD_TRACK_PADDING;
track->extraframes = padded * CD_TRACK_PADDING - frames; track->extraframes = padded * CD_TRACK_PADDING - frames;
@ -769,6 +791,8 @@ chd_error cdrom_parse_metadata(chd_file *chd, cdrom_toc *toc)
if (toc->numtrks > 0) if (toc->numtrks > 0)
return CHDERR_NONE; return CHDERR_NONE;
printf("toc->numtrks = %d?!\n", toc->numtrks);
/* look for old-style metadata */ /* look for old-style metadata */
dynamic_buffer oldmetadata; dynamic_buffer oldmetadata;
err = chd->read_metadata(CDROM_OLD_METADATA_TAG, 0, oldmetadata); err = chd->read_metadata(CDROM_OLD_METADATA_TAG, 0, oldmetadata);
@ -806,6 +830,7 @@ chd_error cdrom_parse_metadata(chd_file *chd, cdrom_toc *toc)
toc->tracks[i].datasize = FLIPENDIAN_INT32(toc->tracks[i].datasize); toc->tracks[i].datasize = FLIPENDIAN_INT32(toc->tracks[i].datasize);
toc->tracks[i].subsize = FLIPENDIAN_INT32(toc->tracks[i].subsize); toc->tracks[i].subsize = FLIPENDIAN_INT32(toc->tracks[i].subsize);
toc->tracks[i].frames = FLIPENDIAN_INT32(toc->tracks[i].frames); toc->tracks[i].frames = FLIPENDIAN_INT32(toc->tracks[i].frames);
toc->tracks[i].padframes = FLIPENDIAN_INT32(toc->tracks[i].padframes);
toc->tracks[i].extraframes = FLIPENDIAN_INT32(toc->tracks[i].extraframes); toc->tracks[i].extraframes = FLIPENDIAN_INT32(toc->tracks[i].extraframes);
} }
} }
@ -826,13 +851,25 @@ chd_error cdrom_write_metadata(chd_file *chd, const cdrom_toc *toc)
/* write the metadata */ /* write the metadata */
for (i = 0; i < toc->numtrks; i++) for (i = 0; i < toc->numtrks; i++)
{ {
astring metadata; astring metadata;
metadata.format(CDROM_TRACK_METADATA2_FORMAT, i + 1, cdrom_get_type_string(toc->tracks[i].trktype), if (!(toc->flags & CD_FLAG_GDROM))
cdrom_get_subtype_string(toc->tracks[i].subtype), toc->tracks[i].frames, toc->tracks[i].pregap, {
cdrom_get_type_string(toc->tracks[i].pgtype), cdrom_get_subtype_string(toc->tracks[i].pgsub), metadata.format(CDROM_TRACK_METADATA2_FORMAT, i + 1, cdrom_get_type_string(toc->tracks[i].trktype),
toc->tracks[i].postgap); cdrom_get_subtype_string(toc->tracks[i].subtype), toc->tracks[i].frames, toc->tracks[i].pregap,
cdrom_get_type_string(toc->tracks[i].pgtype), cdrom_get_subtype_string(toc->tracks[i].pgsub),
toc->tracks[i].postgap);
err = chd->write_metadata(CDROM_TRACK_METADATA2_TAG, i, metadata); err = chd->write_metadata(CDROM_TRACK_METADATA2_TAG, i, metadata);
}
else
{
metadata.format(GDROM_TRACK_METADATA_FORMAT, i + 1, cdrom_get_type_string(toc->tracks[i].trktype),
cdrom_get_subtype_string(toc->tracks[i].subtype), toc->tracks[i].frames, toc->tracks[i].padframes,
toc->tracks[i].pregap, cdrom_get_type_string(toc->tracks[i].pgtype),
cdrom_get_subtype_string(toc->tracks[i].pgsub), toc->tracks[i].postgap);
err = chd->write_metadata(GDROM_TRACK_METADATA_TAG, i, metadata);
}
if (err != CHDERR_NONE) if (err != CHDERR_NONE)
return err; return err;
} }

View File

@ -84,7 +84,7 @@ enum
CD_SUB_NONE /* no subcode data stored */ CD_SUB_NONE /* no subcode data stored */
}; };
#define CD_FLAG_GDROM 0x00000001 // disc is a GD-ROM, all tracks should be stored with GD-ROM metadata
/*************************************************************************** /***************************************************************************
TYPE DEFINITIONS TYPE DEFINITIONS
@ -109,6 +109,9 @@ struct cdrom_track_info
UINT32 pgdatasize; /* size of data in each sector of the pregap */ UINT32 pgdatasize; /* size of data in each sector of the pregap */
UINT32 pgsubsize; /* size of subchannel data in each sector of the pregap */ UINT32 pgsubsize; /* size of subchannel data in each sector of the pregap */
/* fields used in CHDMAN only */
UINT32 padframes; /* number of frames of padding to add to the end of the track; needed for GDI */
/* fields used in MAME only */ /* fields used in MAME only */
UINT32 physframeofs; /* frame number on the real CD this track starts at */ UINT32 physframeofs; /* frame number on the real CD this track starts at */
UINT32 chdframeofs; /* frame number this track starts at on the CHD */ UINT32 chdframeofs; /* frame number this track starts at on the CHD */
@ -118,6 +121,7 @@ struct cdrom_track_info
struct cdrom_toc struct cdrom_toc
{ {
UINT32 numtrks; /* number of tracks */ UINT32 numtrks; /* number of tracks */
UINT32 flags; /* see FLAG_ above */
cdrom_track_info tracks[CD_MAX_TRACKS]; cdrom_track_info tracks[CD_MAX_TRACKS];
}; };

View File

@ -58,6 +58,7 @@
const char *HARD_DISK_METADATA_FORMAT = "CYLS:%d,HEADS:%d,SECS:%d,BPS:%d"; const char *HARD_DISK_METADATA_FORMAT = "CYLS:%d,HEADS:%d,SECS:%d,BPS:%d";
const char *CDROM_TRACK_METADATA_FORMAT = "TRACK:%d TYPE:%s SUBTYPE:%s FRAMES:%d"; const char *CDROM_TRACK_METADATA_FORMAT = "TRACK:%d TYPE:%s SUBTYPE:%s FRAMES:%d";
const char *CDROM_TRACK_METADATA2_FORMAT = "TRACK:%d TYPE:%s SUBTYPE:%s FRAMES:%d PREGAP:%d PGTYPE:%s PGSUB:%s POSTGAP:%d"; const char *CDROM_TRACK_METADATA2_FORMAT = "TRACK:%d TYPE:%s SUBTYPE:%s FRAMES:%d PREGAP:%d PGTYPE:%s PGSUB:%s POSTGAP:%d";
const char *GDROM_TRACK_METADATA_FORMAT = "TRACK:%d TYPE:%s SUBTYPE:%s FRAMES:%d PAD:%d PREGAP:%d PGTYPE:%s PGSUB:%s POSTGAP:%d";
const char *AV_METADATA_FORMAT = "FPS:%d.%06d WIDTH:%d HEIGHT:%d INTERLACED:%d CHANNELS:%d SAMPLERATE:%d"; const char *AV_METADATA_FORMAT = "FPS:%d.%06d WIDTH:%d HEIGHT:%d INTERLACED:%d CHANNELS:%d SAMPLERATE:%d";
static const UINT32 METADATA_HEADER_SIZE = 16; // metadata header size static const UINT32 METADATA_HEADER_SIZE = 16; // metadata header size
@ -1440,7 +1441,8 @@ UINT32 chd_file::guess_unitbytes()
// look for CD-ROM metadata; if found, then the unit size == CD frame size // look for CD-ROM metadata; if found, then the unit size == CD frame size
if (read_metadata(CDROM_OLD_METADATA_TAG, 0, metadata) == CHDERR_NONE || if (read_metadata(CDROM_OLD_METADATA_TAG, 0, metadata) == CHDERR_NONE ||
read_metadata(CDROM_TRACK_METADATA_TAG, 0, metadata) == CHDERR_NONE || read_metadata(CDROM_TRACK_METADATA_TAG, 0, metadata) == CHDERR_NONE ||
read_metadata(CDROM_TRACK_METADATA2_TAG, 0, metadata) == CHDERR_NONE) read_metadata(CDROM_TRACK_METADATA2_TAG, 0, metadata) == CHDERR_NONE ||
read_metadata(GDROM_TRACK_METADATA_TAG, 0, metadata) == CHDERR_NONE)
return CD_FRAME_SIZE; return CD_FRAME_SIZE;
// otherwise, just map 1:1 with the hunk size // otherwise, just map 1:1 with the hunk size

View File

@ -254,6 +254,8 @@ const chd_metadata_tag CDROM_TRACK_METADATA_TAG = CHD_MAKE_TAG('C','H','T','R');
extern const char *CDROM_TRACK_METADATA_FORMAT; extern const char *CDROM_TRACK_METADATA_FORMAT;
const chd_metadata_tag CDROM_TRACK_METADATA2_TAG = CHD_MAKE_TAG('C','H','T','2'); const chd_metadata_tag CDROM_TRACK_METADATA2_TAG = CHD_MAKE_TAG('C','H','T','2');
extern const char *CDROM_TRACK_METADATA2_FORMAT; extern const char *CDROM_TRACK_METADATA2_FORMAT;
const chd_metadata_tag GDROM_TRACK_METADATA_TAG = CHD_MAKE_TAG('C','H','G','T');
extern const char *GDROM_TRACK_METADATA_FORMAT;
// standard A/V metadata // standard A/V metadata
const chd_metadata_tag AV_METADATA_TAG = CHD_MAKE_TAG('A','V','A','V'); const chd_metadata_tag AV_METADATA_TAG = CHD_MAKE_TAG('A','V','A','V');

View File

@ -1,7 +1,7 @@
/*************************************************************************** /***************************************************************************
TOC parser for CHD compression frontend TOC parser for CHD compression frontend
Handles CDRDAO .toc, CDRWIN .cue, and Sega GDROM .gdi Handles CDRDAO .toc, CDRWIN .cue, Nero .nrg, and Sega GDROM .gdi
Copyright Nicola Salmoria and the MAME Team. Copyright Nicola Salmoria and the MAME Team.
Visit http://mamedev.org for licensing and usage restrictions. Visit http://mamedev.org for licensing and usage restrictions.
@ -301,7 +301,7 @@ UINT64 read_uint64(FILE *infile)
} }
/*------------------------------------------------- /*-------------------------------------------------
chdcd_parse_nero - parse a Nero format image file chdcd_parse_nero - parse a Nero .NRG file
-------------------------------------------------*/ -------------------------------------------------*/
chd_error chdcd_parse_nero(const char *tocfname, cdrom_toc &outtoc, chdcd_track_input_info &outinfo) chd_error chdcd_parse_nero(const char *tocfname, cdrom_toc &outtoc, chdcd_track_input_info &outinfo)
@ -427,6 +427,7 @@ chd_error chdcd_parse_nero(const char *tocfname, cdrom_toc &outtoc, chdcd_track_
outtoc.tracks[track-1].pgsub = CD_SUB_NONE; outtoc.tracks[track-1].pgsub = CD_SUB_NONE;
outtoc.tracks[track-1].pgdatasize = 0; outtoc.tracks[track-1].pgdatasize = 0;
outtoc.tracks[track-1].pgsubsize = 0; outtoc.tracks[track-1].pgsubsize = 0;
outtoc.tracks[track-1].padframes = 0;
offset += (UINT32)index2-index1; offset += (UINT32)index2-index1;
} }
@ -455,7 +456,6 @@ static chd_error chdcd_parse_gdi(const char *tocfname, cdrom_toc &outtoc, chdcd_
{ {
FILE *infile; FILE *infile;
int i, numtracks; int i, numtracks;
//int chdpos=0;
astring path = astring(tocfname); astring path = astring(tocfname);
@ -471,6 +471,7 @@ static chd_error chdcd_parse_gdi(const char *tocfname, cdrom_toc &outtoc, chdcd_
memset(&outtoc, 0, sizeof(outtoc)); memset(&outtoc, 0, sizeof(outtoc));
outinfo.reset(); outinfo.reset();
outtoc.flags = CD_FLAG_GDROM;
fgets(linebuffer,511,infile); fgets(linebuffer,511,infile);
numtracks=atoi(linebuffer); numtracks=atoi(linebuffer);
@ -481,8 +482,6 @@ static chd_error chdcd_parse_gdi(const char *tocfname, cdrom_toc &outtoc, chdcd_
int trknum; int trknum;
int trksize,trktype; int trksize,trktype;
int sz; int sz;
int hunks;
fgets(linebuffer,511,infile); fgets(linebuffer,511,infile);
@ -493,8 +492,7 @@ static chd_error chdcd_parse_gdi(const char *tocfname, cdrom_toc &outtoc, chdcd_
outinfo.track[trknum].swap=false; outinfo.track[trknum].swap=false;
outinfo.track[trknum].offset=0; outinfo.track[trknum].offset=0;
//outtoc.tracks[trknum].trktype = CD_TRACK_MODE1; outtoc.tracks[trknum].datasize = 0;
outtoc.tracks[trknum].datasize = 0;
outtoc.tracks[trknum].subtype = CD_SUB_NONE; outtoc.tracks[trknum].subtype = CD_SUB_NONE;
outtoc.tracks[trknum].subsize = 0; outtoc.tracks[trknum].subsize = 0;
@ -519,7 +517,6 @@ static chd_error chdcd_parse_gdi(const char *tocfname, cdrom_toc &outtoc, chdcd_
} }
if(trktype==0) if(trktype==0)
{ {
//assert(trksize==2352);
outtoc.tracks[trknum].trktype=CD_TRACK_AUDIO; outtoc.tracks[trknum].trktype=CD_TRACK_AUDIO;
outtoc.tracks[trknum].datasize=2352; outtoc.tracks[trknum].datasize=2352;
} }
@ -540,35 +537,26 @@ static chd_error chdcd_parse_gdi(const char *tocfname, cdrom_toc &outtoc, chdcd_
} }
outinfo.track[trknum].fname.cpy(path).cat(name); outinfo.track[trknum].fname.cpy(path).cat(name);
sz=get_file_size(outinfo.track[trknum].fname); sz = get_file_size(outinfo.track[trknum].fname);
outtoc.tracks[trknum].frames=sz/trksize; outtoc.tracks[trknum].frames = sz/trksize;
outtoc.tracks[trknum].extraframes=0; outtoc.tracks[trknum].padframes = 0;
if(trknum!=0) if (trknum != 0)
{ {
int dif=outtoc.tracks[trknum].physframeofs-(outtoc.tracks[trknum-1].frames+outtoc.tracks[trknum-1].physframeofs); int dif=outtoc.tracks[trknum].physframeofs-(outtoc.tracks[trknum-1].frames+outtoc.tracks[trknum-1].physframeofs);
outtoc.tracks[trknum-1].frames+=dif; outtoc.tracks[trknum-1].frames += dif;
outtoc.tracks[trknum-1].padframes = dif;
} }
/*
if(trknum!=0)
{
outtoc.tracks[trknum-1].extraframes=outtoc.tracks[trknum].physframeofs-(outtoc.tracks[trknum-1].frames+outtoc.tracks[trknum-1].physframeofs);
}
*/
hunks = (outtoc.tracks[trknum].frames+CD_FRAMES_PER_HUNK - 1) / CD_FRAMES_PER_HUNK;
outtoc.tracks[trknum].extraframes = hunks * CD_FRAMES_PER_HUNK - outtoc.tracks[trknum].frames;
//chdpos+=outtoc.tracks[trknum].frames+outtoc.tracks[trknum].extraframes;
} }
/*
for(i=0;i<numtracks;++i) #if 0
for(i=0; i < numtracks; i++)
{ {
printf("%s %d %d %d\n",outinfo.track[i].fname,outtoc.tracks[i].frames,outtoc.tracks[i].extraframes,outtoc.tracks[i].physframeofs); printf("%s %d %d %d (true %d)\n", outinfo.track[i].fname.cstr(), outtoc.tracks[i].frames, outtoc.tracks[i].padframes, outtoc.tracks[i].physframeofs, outtoc.tracks[i].frames - outtoc.tracks[i].padframes);
} }
*/ #endif
/* close the input TOC */ /* close the input TOC */
fclose(infile); fclose(infile);
@ -579,7 +567,7 @@ static chd_error chdcd_parse_gdi(const char *tocfname, cdrom_toc &outtoc, chdcd_
} }
/*------------------------------------------------- /*-------------------------------------------------
chdcd_parse_cue - parse a CDRWin format CUE file chdcd_parse_toc - parse a CDRWin format CUE file
-------------------------------------------------*/ -------------------------------------------------*/
chd_error chdcd_parse_cue(const char *tocfname, cdrom_toc &outtoc, chdcd_track_input_info &outinfo) chd_error chdcd_parse_cue(const char *tocfname, cdrom_toc &outtoc, chdcd_track_input_info &outinfo)
@ -683,6 +671,7 @@ chd_error chdcd_parse_cue(const char *tocfname, cdrom_toc &outtoc, chdcd_track_i
outtoc.tracks[trknum].subtype = CD_SUB_NONE; outtoc.tracks[trknum].subtype = CD_SUB_NONE;
outtoc.tracks[trknum].subsize = 0; outtoc.tracks[trknum].subsize = 0;
outtoc.tracks[trknum].pregap = 0; outtoc.tracks[trknum].pregap = 0;
outtoc.tracks[trknum].padframes = 0;
outinfo.track[trknum].idx0offs = -1; outinfo.track[trknum].idx0offs = -1;
outinfo.track[trknum].idx1offs = 0; outinfo.track[trknum].idx1offs = 0;
@ -988,6 +977,7 @@ chd_error chdcd_parse_toc(const char *tocfname, cdrom_toc &outtoc, chdcd_track_i
outtoc.tracks[trknum].datasize = 0; outtoc.tracks[trknum].datasize = 0;
outtoc.tracks[trknum].subtype = CD_SUB_NONE; outtoc.tracks[trknum].subtype = CD_SUB_NONE;
outtoc.tracks[trknum].subsize = 0; outtoc.tracks[trknum].subsize = 0;
outtoc.tracks[trknum].padframes = 0;
cdrom_convert_type_string_to_track_info(token, &outtoc.tracks[trknum]); cdrom_convert_type_string_to_track_info(token, &outtoc.tracks[trknum]);
if (outtoc.tracks[trknum].datasize == 0) if (outtoc.tracks[trknum].datasize == 0)

View File

@ -64,6 +64,11 @@ const UINT32 IDE_SECTOR_SIZE = 512;
// temporary input buffer size // temporary input buffer size
const UINT32 TEMP_BUFFER_SIZE = 32 * 1024 * 1024; const UINT32 TEMP_BUFFER_SIZE = 32 * 1024 * 1024;
// modes
const int MODE_NORMAL = 0;
const int MODE_CUEBIN = 1;
const int MODE_GDI = 2;
// command modifier // command modifier
#define REQUIRED "~" #define REQUIRED "~"
@ -113,7 +118,6 @@ const UINT32 TEMP_BUFFER_SIZE = 32 * 1024 * 1024;
#define OPTION_NUMPROCESSORS "numprocessors" #define OPTION_NUMPROCESSORS "numprocessors"
//************************************************************************** //**************************************************************************
// FUNCTION PROTOTYPES // FUNCTION PROTOTYPES
//************************************************************************** //**************************************************************************
@ -318,17 +322,25 @@ public:
UINT32 bytesperframe = trackinfo.datasize + trackinfo.subsize; UINT32 bytesperframe = trackinfo.datasize + trackinfo.subsize;
UINT64 src_track_start = m_info.track[tracknum].offset; UINT64 src_track_start = m_info.track[tracknum].offset;
UINT64 src_track_end = src_track_start + bytesperframe * trackinfo.frames; UINT64 src_track_end = src_track_start + bytesperframe * trackinfo.frames;
while (length_remaining != 0 && offset < endoffs) UINT64 pad_track_start = src_track_end - (m_toc.tracks[tracknum].padframes * bytesperframe);
while (length_remaining != 0 && offset < endoffs)
{ {
// determine start of current frame // determine start of current frame
UINT64 src_frame_start = src_track_start + ((offset - startoffs) / CD_FRAME_SIZE) * bytesperframe; UINT64 src_frame_start = src_track_start + ((offset - startoffs) / CD_FRAME_SIZE) * bytesperframe;
if (src_frame_start < src_track_end) if (src_frame_start < src_track_end)
{ {
// read it in // read it in, or pad if we're into the padframes
core_fseek(m_file, src_frame_start, SEEK_SET); if (src_frame_start >= pad_track_start)
UINT32 count = core_fread(m_file, dest, bytesperframe); {
if (count != bytesperframe) memset(dest, 0, bytesperframe);
report_error(1, "Error reading input file (%s)'", m_lastfile.cstr()); }
else
{
core_fseek(m_file, src_frame_start, SEEK_SET);
UINT32 count = core_fread(m_file, dest, bytesperframe);
if (count != bytesperframe)
report_error(1, "Error reading input file (%s)'", m_lastfile.cstr());
}
// swap if appropriate // swap if appropriate
if (m_info.track[tracknum].swap) if (m_info.track[tracknum].swap)
@ -1156,93 +1168,139 @@ static void compress_common(chd_file_compressor &chd)
// to a CUE file // to a CUE file
//------------------------------------------------- //-------------------------------------------------
void output_track_metadata(bool cuemode, core_file *file, int tracknum, const cdrom_track_info &info, const char *filename, UINT32 frameoffs, UINT64 discoffs) void output_track_metadata(int mode, core_file *file, int tracknum, const cdrom_track_info &info, const char *filename, UINT32 frameoffs, UINT64 discoffs)
{ {
// CUE mode? if (mode == MODE_GDI)
if (cuemode)
{ {
// first track specifies the file int mode = 0, size = 2048;
if (tracknum == 0)
core_fprintf(file, "FILE \"%s\" BINARY\n", filename);
// determine submode switch (info.trktype)
astring tempstr; {
switch (info.trktype) case CD_TRACK_MODE1:
{ mode = 0;
case CD_TRACK_MODE1: size = 2048;
case CD_TRACK_MODE1_RAW: break;
tempstr.format("MODE1/%04d", info.datasize);
break;
case CD_TRACK_MODE2: case CD_TRACK_MODE1_RAW:
case CD_TRACK_MODE2_FORM1: mode = 4;
case CD_TRACK_MODE2_FORM2: size = 2352;
case CD_TRACK_MODE2_FORM_MIX: break;
case CD_TRACK_MODE2_RAW:
tempstr.format("MODE2/%04d", info.datasize);
break;
case CD_TRACK_AUDIO: case CD_TRACK_MODE2:
tempstr.cpy("AUDIO"); mode = 4;
break; size = 2336;
} break;
// output TRACK entry case CD_TRACK_MODE2_FORM1:
core_fprintf(file, " TRACK %02d %s\n", tracknum + 1, tempstr.cstr()); mode = 4;
size = 2048;
break;
// output PREGAP case CD_TRACK_MODE2_FORM2:
if (info.pregap > 0) mode = 4;
core_fprintf(file, " PREGAP %s\n", msf_string_from_frames(tempstr, info.pregap)); size = 2324;
break;
// output track data case CD_TRACK_MODE2_FORM_MIX:
core_fprintf(file, " INDEX 01 %s\n", msf_string_from_frames(tempstr, frameoffs)); mode = 4;
size = 2336;
break;
// output POSTGAP case CD_TRACK_MODE2_RAW:
if (info.postgap > 0) mode = 4;
core_fprintf(file, " POSTGAP %s\n", msf_string_from_frames(tempstr, info.postgap)); size = 2352;
break;
case CD_TRACK_AUDIO:
mode = 0;
size = 2352;
break;
}
core_fprintf(file, "%d %d %d %d %s %lld\n", tracknum+1, frameoffs, mode, size, filename, discoffs);
} }
else if (mode == MODE_CUEBIN)
{
// first track specifies the file
if (tracknum == 0)
core_fprintf(file, "FILE \"%s\" BINARY\n", filename);
// non-CUE mode // determine submode
else astring tempstr;
{ switch (info.trktype)
// header on the first track {
if (tracknum == 0) case CD_TRACK_MODE1:
core_fprintf(file, "CD_ROM\n\n\n"); case CD_TRACK_MODE1_RAW:
core_fprintf(file, "// Track %d\n", tracknum + 1); tempstr.format("MODE1/%04d", info.datasize);
break;
// write out the track type case CD_TRACK_MODE2:
astring modesubmode; case CD_TRACK_MODE2_FORM1:
if (info.subtype != CD_SUB_NONE) case CD_TRACK_MODE2_FORM2:
modesubmode.format("%s %s", cdrom_get_type_string(info.trktype), cdrom_get_subtype_string(info.subtype)); case CD_TRACK_MODE2_FORM_MIX:
else case CD_TRACK_MODE2_RAW:
modesubmode.format("%s", cdrom_get_type_string(info.trktype)); tempstr.format("MODE2/%04d", info.datasize);
core_fprintf(file, "TRACK %s\n", modesubmode.cstr()); break;
// write out the attributes case CD_TRACK_AUDIO:
core_fprintf(file, "NO COPY\n"); tempstr.cpy("AUDIO");
if (info.trktype == CD_TRACK_AUDIO) break;
{ }
core_fprintf(file, "NO PRE_EMPHASIS\n");
core_fprintf(file, "TWO_CHANNEL_AUDIO\n");
}
// output pregap // output TRACK entry
astring tempstr; core_fprintf(file, " TRACK %02d %s\n", tracknum + 1, tempstr.cstr());
if (info.pregap > 0)
core_fprintf(file, "ZERO %s %s\n", modesubmode.cstr(), msf_string_from_frames(tempstr, info.pregap));
// all tracks but the first one have a file offset // output PREGAP
if (tracknum > 0) if (info.pregap > 0)
core_fprintf(file, "DATAFILE \"%s\" #%d %s // length in bytes: %d\n", filename, UINT32(discoffs), msf_string_from_frames(tempstr, info.frames), info.frames * (info.datasize + info.subsize)); core_fprintf(file, " PREGAP %s\n", msf_string_from_frames(tempstr, info.pregap));
else
core_fprintf(file, "DATAFILE \"%s\" %s // length in bytes: %d\n", filename, msf_string_from_frames(tempstr, info.frames), info.frames * (info.datasize + info.subsize));
// tracks with pregaps get a START marker too // output track data
if (info.pregap > 0) core_fprintf(file, " INDEX 01 %s\n", msf_string_from_frames(tempstr, frameoffs));
core_fprintf(file, "START %s\n", msf_string_from_frames(tempstr, info.pregap));
core_fprintf(file, "\n\n"); // output POSTGAP
} if (info.postgap > 0)
core_fprintf(file, " POSTGAP %s\n", msf_string_from_frames(tempstr, info.postgap));
}
// non-CUE mode
else if (mode == MODE_NORMAL)
{
// header on the first track
if (tracknum == 0)
core_fprintf(file, "CD_ROM\n\n\n");
core_fprintf(file, "// Track %d\n", tracknum + 1);
// write out the track type
astring modesubmode;
if (info.subtype != CD_SUB_NONE)
modesubmode.format("%s %s", cdrom_get_type_string(info.trktype), cdrom_get_subtype_string(info.subtype));
else
modesubmode.format("%s", cdrom_get_type_string(info.trktype));
core_fprintf(file, "TRACK %s\n", modesubmode.cstr());
// write out the attributes
core_fprintf(file, "NO COPY\n");
if (info.trktype == CD_TRACK_AUDIO)
{
core_fprintf(file, "NO PRE_EMPHASIS\n");
core_fprintf(file, "TWO_CHANNEL_AUDIO\n");
}
// output pregap
astring tempstr;
if (info.pregap > 0)
core_fprintf(file, "ZERO %s %s\n", modesubmode.cstr(), msf_string_from_frames(tempstr, info.pregap));
// all tracks but the first one have a file offset
if (tracknum > 0)
core_fprintf(file, "DATAFILE \"%s\" #%d %s // length in bytes: %d\n", filename, UINT32(discoffs), msf_string_from_frames(tempstr, info.frames), info.frames * (info.datasize + info.subsize));
else
core_fprintf(file, "DATAFILE \"%s\" %s // length in bytes: %d\n", filename, msf_string_from_frames(tempstr, info.frames), info.frames * (info.datasize + info.subsize));
// tracks with pregaps get a START marker too
if (info.pregap > 0)
core_fprintf(file, "START %s\n", msf_string_from_frames(tempstr, info.pregap));
core_fprintf(file, "\n\n");
}
} }
@ -2194,6 +2252,8 @@ static void do_extract_cd(parameters_t &params)
int chop = default_name.rchr(0, '.'); int chop = default_name.rchr(0, '.');
if (chop != -1) if (chop != -1)
default_name.substr(0, chop); default_name.substr(0, chop);
char basename[128];
strncpy(basename, default_name.cstr(), 127);
default_name.cat(".bin"); default_name.cat(".bin");
if (output_bin_file_str == NULL) if (output_bin_file_str == NULL)
output_bin_file_str = &default_name; output_bin_file_str = &default_name;
@ -2210,38 +2270,86 @@ static void do_extract_cd(parameters_t &params)
core_file *output_toc_file = NULL; core_file *output_toc_file = NULL;
try try
{ {
// process output file int mode = MODE_NORMAL;
file_error filerr = core_fopen(*output_file_str, OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_NO_BOM, &output_toc_file);
if (filerr != FILERR_NONE) if (output_file_str->find(".cue") != -1)
report_error(1, "Unable to open file (%s)", output_file_str->cstr()); {
bool cuemode = (output_file_str->find(".cue") != -1); mode = MODE_CUEBIN;
}
else if (output_file_str->find(".gdi") != -1)
{
mode = MODE_GDI;
}
// process output file
file_error filerr = core_fopen(*output_file_str, OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_NO_BOM, &output_toc_file);
if (filerr != FILERR_NONE)
report_error(1, "Unable to open file (%s)", output_file_str->cstr());
// process output BIN file // process output BIN file
filerr = core_fopen(*output_bin_file_str, OPEN_FLAG_WRITE | OPEN_FLAG_CREATE, &output_bin_file); if (mode != MODE_GDI)
if (filerr != FILERR_NONE) {
report_error(1, "Unable to open file (%s)", output_bin_file_str->cstr()); filerr = core_fopen(*output_bin_file_str, OPEN_FLAG_WRITE | OPEN_FLAG_CREATE, &output_bin_file);
if (filerr != FILERR_NONE)
report_error(1, "Unable to open file (%s)", output_bin_file_str->cstr());
}
// determine total frames // determine total frames
UINT64 total_bytes = 0; UINT64 total_bytes = 0;
for (int tracknum = 0; tracknum < toc->numtrks; tracknum++) for (int tracknum = 0; tracknum < toc->numtrks; tracknum++)
total_bytes += toc->tracks[tracknum].frames * (toc->tracks[tracknum].datasize + toc->tracks[tracknum].subsize); total_bytes += toc->tracks[tracknum].frames * (toc->tracks[tracknum].datasize + toc->tracks[tracknum].subsize);
// GDI must start with the # of tracks
if (mode == MODE_GDI)
{
core_fprintf(output_toc_file, "%d\n", toc->numtrks);
}
// iterate over tracks and copy all data // iterate over tracks and copy all data
UINT64 outputoffs = 0; UINT64 outputoffs = 0;
UINT32 discoffs = 0; UINT32 discoffs = 0;
dynamic_buffer buffer; dynamic_buffer buffer;
for (int tracknum = 0; tracknum < toc->numtrks; tracknum++) for (int tracknum = 0; tracknum < toc->numtrks; tracknum++)
{ {
astring trackbin_name(basename);
if (mode == MODE_GDI)
{
char temp[8];
sprintf(temp, "%02d", tracknum+1);
trackbin_name.cat(temp);
trackbin_name.cat(".bin");
if (output_bin_file)
{
core_fclose(output_bin_file);
output_bin_file = NULL;
}
filerr = core_fopen(trackbin_name, OPEN_FLAG_WRITE | OPEN_FLAG_CREATE, &output_bin_file);
if (filerr != FILERR_NONE)
report_error(1, "Unable to open file (%s)", trackbin_name.cstr());
outputoffs = 0;
}
// output the metadata about the track to the TOC file // output the metadata about the track to the TOC file
const cdrom_track_info &trackinfo = toc->tracks[tracknum]; const cdrom_track_info &trackinfo = toc->tracks[tracknum];
output_track_metadata(cuemode, output_toc_file, tracknum, trackinfo, *output_bin_file_str, discoffs, outputoffs); if (mode == MODE_GDI)
{
output_track_metadata(mode, output_toc_file, tracknum, trackinfo, trackbin_name, discoffs, outputoffs);
}
else
{
output_track_metadata(mode, output_toc_file, tracknum, trackinfo, *output_bin_file_str, discoffs, outputoffs);
}
// If this is bin/cue output and the CHD contains subdata, warn the user and don't include // If this is bin/cue output and the CHD contains subdata, warn the user and don't include
// the subdata size in the buffer calculation. // the subdata size in the buffer calculation.
UINT32 output_frame_size = trackinfo.datasize + ((trackinfo.subtype != CD_SUB_NONE) ? trackinfo.subsize : 0); UINT32 output_frame_size = trackinfo.datasize + ((trackinfo.subtype != CD_SUB_NONE) ? trackinfo.subsize : 0);
if (trackinfo.subtype != CD_SUB_NONE && cuemode) if (trackinfo.subtype != CD_SUB_NONE && ((mode == MODE_CUEBIN) || (mode == MODE_GDI)))
{ {
printf("Warning: Track %d has subcode data. bin/cue format cannot contain subcode data and it will be omitted.\n", tracknum+1); printf("Warning: Track %d has subcode data. bin/cue and gdi formats cannot contain subcode data and it will be omitted.\n", tracknum+1);
printf(" : This may affect usage of the output image. Use bin/toc output to keep all data.\n"); printf(" : This may affect usage of the output image. Use bin/toc output to keep all data.\n");
output_frame_size = trackinfo.datasize; output_frame_size = trackinfo.datasize;
} }
@ -2251,7 +2359,8 @@ static void do_extract_cd(parameters_t &params)
// now read and output the actual data // now read and output the actual data
UINT32 bufferoffs = 0; UINT32 bufferoffs = 0;
for (int frame = 0; frame < trackinfo.frames; frame++) UINT32 actualframes = trackinfo.frames - trackinfo.padframes;
for (UINT32 frame = 0; frame < actualframes; frame++)
{ {
progress(false, "Extracting, %.1f%% complete... \r", 100.0 * double(outputoffs) / double(total_bytes)); progress(false, "Extracting, %.1f%% complete... \r", 100.0 * double(outputoffs) / double(total_bytes));
@ -2259,7 +2368,7 @@ static void do_extract_cd(parameters_t &params)
cdrom_read_data(cdrom, cdrom_get_track_start(cdrom, tracknum) + frame, &buffer[bufferoffs], trackinfo.trktype); cdrom_read_data(cdrom, cdrom_get_track_start(cdrom, tracknum) + frame, &buffer[bufferoffs], trackinfo.trktype);
// for CDRWin, audio tracks must be reversed // for CDRWin, audio tracks must be reversed
if (cuemode && (trackinfo.trktype == CD_TRACK_AUDIO)) if ((mode == MODE_CUEBIN) && (trackinfo.trktype == CD_TRACK_AUDIO))
for (int swapindex = 0; swapindex < trackinfo.datasize; swapindex += 2) for (int swapindex = 0; swapindex < trackinfo.datasize; swapindex += 2)
{ {
UINT8 swaptemp = buffer[bufferoffs + swapindex]; UINT8 swaptemp = buffer[bufferoffs + swapindex];
@ -2270,14 +2379,14 @@ static void do_extract_cd(parameters_t &params)
discoffs++; discoffs++;
// read the subcode data // read the subcode data
if (trackinfo.subtype != CD_SUB_NONE && !cuemode) if (trackinfo.subtype != CD_SUB_NONE && (mode == MODE_NORMAL))
{ {
cdrom_read_subcode(cdrom, cdrom_get_track_start(cdrom, tracknum) + frame, &buffer[bufferoffs]); cdrom_read_subcode(cdrom, cdrom_get_track_start(cdrom, tracknum) + frame, &buffer[bufferoffs]);
bufferoffs += trackinfo.subsize; bufferoffs += trackinfo.subsize;
} }
// write it out if we need to // write it out if we need to
if (bufferoffs == buffer.count() || frame == trackinfo.frames - 1) if (bufferoffs == buffer.count() || frame == actualframes - 1)
{ {
core_fseek(output_bin_file, outputoffs, SEEK_SET); core_fseek(output_bin_file, outputoffs, SEEK_SET);
UINT32 byteswritten = core_fwrite(output_bin_file, buffer, bufferoffs); UINT32 byteswritten = core_fwrite(output_bin_file, buffer, bufferoffs);
@ -2287,10 +2396,12 @@ static void do_extract_cd(parameters_t &params)
bufferoffs = 0; bufferoffs = 0;
} }
} }
discoffs += trackinfo.padframes;
} }
// finish up // finish up
core_fclose(output_bin_file); core_fclose(output_bin_file);
core_fclose(output_toc_file); core_fclose(output_toc_file);
printf("Extraction complete \n"); printf("Extraction complete \n");
} }