mirror of
https://github.com/holub/mame
synced 2025-05-12 00:58:53 +03:00
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:
parent
b89d7c94c7
commit
bb993d1174
@ -702,11 +702,11 @@ chd_error cdrom_parse_metadata(chd_file *chd, cdrom_toc *toc)
|
||||
/* start with no tracks */
|
||||
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];
|
||||
cdrom_track_info *track;
|
||||
|
||||
pregap = postgap = 0;
|
||||
pregap = postgap = padframes = 0;
|
||||
|
||||
/* fetch the metadata for this track */
|
||||
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
|
||||
{
|
||||
err = chd->read_metadata(CDROM_TRACK_METADATA2_TAG, toc->numtrks, metadata);
|
||||
if (err != CHDERR_NONE)
|
||||
break;
|
||||
/* parse the metadata */
|
||||
type[0] = subtype[0] = 0;
|
||||
pregap = postgap = 0;
|
||||
if (sscanf(metadata, CDROM_TRACK_METADATA2_FORMAT, &tracknum, type, subtype, &frames, &pregap, pgtype, pgsub, &postgap) != 8)
|
||||
return CHDERR_INVALID_DATA;
|
||||
if (tracknum == 0 || tracknum > CD_MAX_TRACKS)
|
||||
return CHDERR_INVALID_DATA;
|
||||
track = &toc->tracks[tracknum - 1];
|
||||
if (err == CHDERR_NONE)
|
||||
{
|
||||
/* parse the metadata */
|
||||
type[0] = subtype[0] = 0;
|
||||
pregap = postgap = 0;
|
||||
if (sscanf(metadata, CDROM_TRACK_METADATA2_FORMAT, &tracknum, type, subtype, &frames, &pregap, pgtype, pgsub, &postgap) != 8)
|
||||
return CHDERR_INVALID_DATA;
|
||||
if (tracknum == 0 || tracknum > CD_MAX_TRACKS)
|
||||
return CHDERR_INVALID_DATA;
|
||||
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 */
|
||||
@ -749,6 +770,7 @@ chd_error cdrom_parse_metadata(chd_file *chd, cdrom_toc *toc)
|
||||
|
||||
/* set the frames and extra frames data */
|
||||
track->frames = frames;
|
||||
track->padframes = padframes;
|
||||
int padded = (frames + CD_TRACK_PADDING - 1) / CD_TRACK_PADDING;
|
||||
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)
|
||||
return CHDERR_NONE;
|
||||
|
||||
printf("toc->numtrks = %d?!\n", toc->numtrks);
|
||||
|
||||
/* look for old-style metadata */
|
||||
dynamic_buffer 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].subsize = FLIPENDIAN_INT32(toc->tracks[i].subsize);
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -826,13 +851,25 @@ chd_error cdrom_write_metadata(chd_file *chd, const cdrom_toc *toc)
|
||||
/* write the metadata */
|
||||
for (i = 0; i < toc->numtrks; i++)
|
||||
{
|
||||
astring metadata;
|
||||
metadata.format(CDROM_TRACK_METADATA2_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].pregap,
|
||||
cdrom_get_type_string(toc->tracks[i].pgtype), cdrom_get_subtype_string(toc->tracks[i].pgsub),
|
||||
toc->tracks[i].postgap);
|
||||
astring metadata;
|
||||
if (!(toc->flags & CD_FLAG_GDROM))
|
||||
{
|
||||
metadata.format(CDROM_TRACK_METADATA2_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].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)
|
||||
return err;
|
||||
}
|
||||
|
@ -84,7 +84,7 @@ enum
|
||||
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
|
||||
@ -109,6 +109,9 @@ struct cdrom_track_info
|
||||
UINT32 pgdatasize; /* size of 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 */
|
||||
UINT32 physframeofs; /* frame number on the real CD this track starts at */
|
||||
UINT32 chdframeofs; /* frame number this track starts at on the CHD */
|
||||
@ -118,6 +121,7 @@ struct cdrom_track_info
|
||||
struct cdrom_toc
|
||||
{
|
||||
UINT32 numtrks; /* number of tracks */
|
||||
UINT32 flags; /* see FLAG_ above */
|
||||
cdrom_track_info tracks[CD_MAX_TRACKS];
|
||||
};
|
||||
|
||||
|
@ -58,6 +58,7 @@
|
||||
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_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";
|
||||
|
||||
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
|
||||
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_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;
|
||||
|
||||
// otherwise, just map 1:1 with the hunk size
|
||||
|
@ -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;
|
||||
const chd_metadata_tag CDROM_TRACK_METADATA2_TAG = CHD_MAKE_TAG('C','H','T','2');
|
||||
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
|
||||
const chd_metadata_tag AV_METADATA_TAG = CHD_MAKE_TAG('A','V','A','V');
|
||||
|
@ -1,7 +1,7 @@
|
||||
/***************************************************************************
|
||||
|
||||
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.
|
||||
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)
|
||||
@ -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].pgdatasize = 0;
|
||||
outtoc.tracks[track-1].pgsubsize = 0;
|
||||
outtoc.tracks[track-1].padframes = 0;
|
||||
|
||||
offset += (UINT32)index2-index1;
|
||||
}
|
||||
@ -455,7 +456,6 @@ static chd_error chdcd_parse_gdi(const char *tocfname, cdrom_toc &outtoc, chdcd_
|
||||
{
|
||||
FILE *infile;
|
||||
int i, numtracks;
|
||||
//int chdpos=0;
|
||||
|
||||
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));
|
||||
outinfo.reset();
|
||||
|
||||
outtoc.flags = CD_FLAG_GDROM;
|
||||
|
||||
fgets(linebuffer,511,infile);
|
||||
numtracks=atoi(linebuffer);
|
||||
@ -481,8 +482,6 @@ static chd_error chdcd_parse_gdi(const char *tocfname, cdrom_toc &outtoc, chdcd_
|
||||
int trknum;
|
||||
int trksize,trktype;
|
||||
int sz;
|
||||
int hunks;
|
||||
|
||||
|
||||
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].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].subsize = 0;
|
||||
|
||||
@ -519,7 +517,6 @@ static chd_error chdcd_parse_gdi(const char *tocfname, cdrom_toc &outtoc, chdcd_
|
||||
}
|
||||
if(trktype==0)
|
||||
{
|
||||
//assert(trksize==2352);
|
||||
outtoc.tracks[trknum].trktype=CD_TRACK_AUDIO;
|
||||
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);
|
||||
|
||||
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].extraframes=0;
|
||||
outtoc.tracks[trknum].frames = sz/trksize;
|
||||
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);
|
||||
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 */
|
||||
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)
|
||||
@ -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].subsize = 0;
|
||||
outtoc.tracks[trknum].pregap = 0;
|
||||
outtoc.tracks[trknum].padframes = 0;
|
||||
outinfo.track[trknum].idx0offs = -1;
|
||||
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].subtype = CD_SUB_NONE;
|
||||
outtoc.tracks[trknum].subsize = 0;
|
||||
outtoc.tracks[trknum].padframes = 0;
|
||||
|
||||
cdrom_convert_type_string_to_track_info(token, &outtoc.tracks[trknum]);
|
||||
if (outtoc.tracks[trknum].datasize == 0)
|
||||
|
@ -64,6 +64,11 @@ const UINT32 IDE_SECTOR_SIZE = 512;
|
||||
// temporary input buffer size
|
||||
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
|
||||
#define REQUIRED "~"
|
||||
|
||||
@ -113,7 +118,6 @@ const UINT32 TEMP_BUFFER_SIZE = 32 * 1024 * 1024;
|
||||
#define OPTION_NUMPROCESSORS "numprocessors"
|
||||
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// FUNCTION PROTOTYPES
|
||||
//**************************************************************************
|
||||
@ -318,17 +322,25 @@ public:
|
||||
UINT32 bytesperframe = trackinfo.datasize + trackinfo.subsize;
|
||||
UINT64 src_track_start = m_info.track[tracknum].offset;
|
||||
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
|
||||
UINT64 src_frame_start = src_track_start + ((offset - startoffs) / CD_FRAME_SIZE) * bytesperframe;
|
||||
if (src_frame_start < src_track_end)
|
||||
{
|
||||
// read it in
|
||||
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());
|
||||
// read it in, or pad if we're into the padframes
|
||||
if (src_frame_start >= pad_track_start)
|
||||
{
|
||||
memset(dest, 0, bytesperframe);
|
||||
}
|
||||
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
|
||||
if (m_info.track[tracknum].swap)
|
||||
@ -1156,93 +1168,139 @@ static void compress_common(chd_file_compressor &chd)
|
||||
// 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 (cuemode)
|
||||
if (mode == MODE_GDI)
|
||||
{
|
||||
// first track specifies the file
|
||||
if (tracknum == 0)
|
||||
core_fprintf(file, "FILE \"%s\" BINARY\n", filename);
|
||||
int mode = 0, size = 2048;
|
||||
|
||||
// determine submode
|
||||
astring tempstr;
|
||||
switch (info.trktype)
|
||||
{
|
||||
case CD_TRACK_MODE1:
|
||||
case CD_TRACK_MODE1_RAW:
|
||||
tempstr.format("MODE1/%04d", info.datasize);
|
||||
break;
|
||||
switch (info.trktype)
|
||||
{
|
||||
case CD_TRACK_MODE1:
|
||||
mode = 0;
|
||||
size = 2048;
|
||||
break;
|
||||
|
||||
case CD_TRACK_MODE2:
|
||||
case CD_TRACK_MODE2_FORM1:
|
||||
case CD_TRACK_MODE2_FORM2:
|
||||
case CD_TRACK_MODE2_FORM_MIX:
|
||||
case CD_TRACK_MODE2_RAW:
|
||||
tempstr.format("MODE2/%04d", info.datasize);
|
||||
break;
|
||||
case CD_TRACK_MODE1_RAW:
|
||||
mode = 4;
|
||||
size = 2352;
|
||||
break;
|
||||
|
||||
case CD_TRACK_AUDIO:
|
||||
tempstr.cpy("AUDIO");
|
||||
break;
|
||||
}
|
||||
case CD_TRACK_MODE2:
|
||||
mode = 4;
|
||||
size = 2336;
|
||||
break;
|
||||
|
||||
// output TRACK entry
|
||||
core_fprintf(file, " TRACK %02d %s\n", tracknum + 1, tempstr.cstr());
|
||||
case CD_TRACK_MODE2_FORM1:
|
||||
mode = 4;
|
||||
size = 2048;
|
||||
break;
|
||||
|
||||
// output PREGAP
|
||||
if (info.pregap > 0)
|
||||
core_fprintf(file, " PREGAP %s\n", msf_string_from_frames(tempstr, info.pregap));
|
||||
case CD_TRACK_MODE2_FORM2:
|
||||
mode = 4;
|
||||
size = 2324;
|
||||
break;
|
||||
|
||||
// output track data
|
||||
core_fprintf(file, " INDEX 01 %s\n", msf_string_from_frames(tempstr, frameoffs));
|
||||
case CD_TRACK_MODE2_FORM_MIX:
|
||||
mode = 4;
|
||||
size = 2336;
|
||||
break;
|
||||
|
||||
// output POSTGAP
|
||||
if (info.postgap > 0)
|
||||
core_fprintf(file, " POSTGAP %s\n", msf_string_from_frames(tempstr, info.postgap));
|
||||
case CD_TRACK_MODE2_RAW:
|
||||
mode = 4;
|
||||
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
|
||||
else
|
||||
{
|
||||
// header on the first track
|
||||
if (tracknum == 0)
|
||||
core_fprintf(file, "CD_ROM\n\n\n");
|
||||
core_fprintf(file, "// Track %d\n", tracknum + 1);
|
||||
// determine submode
|
||||
astring tempstr;
|
||||
switch (info.trktype)
|
||||
{
|
||||
case CD_TRACK_MODE1:
|
||||
case CD_TRACK_MODE1_RAW:
|
||||
tempstr.format("MODE1/%04d", info.datasize);
|
||||
break;
|
||||
|
||||
// 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());
|
||||
case CD_TRACK_MODE2:
|
||||
case CD_TRACK_MODE2_FORM1:
|
||||
case CD_TRACK_MODE2_FORM2:
|
||||
case CD_TRACK_MODE2_FORM_MIX:
|
||||
case CD_TRACK_MODE2_RAW:
|
||||
tempstr.format("MODE2/%04d", info.datasize);
|
||||
break;
|
||||
|
||||
// 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");
|
||||
}
|
||||
case CD_TRACK_AUDIO:
|
||||
tempstr.cpy("AUDIO");
|
||||
break;
|
||||
}
|
||||
|
||||
// output pregap
|
||||
astring tempstr;
|
||||
if (info.pregap > 0)
|
||||
core_fprintf(file, "ZERO %s %s\n", modesubmode.cstr(), msf_string_from_frames(tempstr, info.pregap));
|
||||
// output TRACK entry
|
||||
core_fprintf(file, " TRACK %02d %s\n", tracknum + 1, tempstr.cstr());
|
||||
|
||||
// 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));
|
||||
// output PREGAP
|
||||
if (info.pregap > 0)
|
||||
core_fprintf(file, " PREGAP %s\n", msf_string_from_frames(tempstr, info.pregap));
|
||||
|
||||
// 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));
|
||||
// output track data
|
||||
core_fprintf(file, " INDEX 01 %s\n", msf_string_from_frames(tempstr, frameoffs));
|
||||
|
||||
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 ¶ms)
|
||||
int chop = default_name.rchr(0, '.');
|
||||
if (chop != -1)
|
||||
default_name.substr(0, chop);
|
||||
char basename[128];
|
||||
strncpy(basename, default_name.cstr(), 127);
|
||||
default_name.cat(".bin");
|
||||
if (output_bin_file_str == NULL)
|
||||
output_bin_file_str = &default_name;
|
||||
@ -2210,38 +2270,86 @@ static void do_extract_cd(parameters_t ¶ms)
|
||||
core_file *output_toc_file = NULL;
|
||||
try
|
||||
{
|
||||
// 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());
|
||||
bool cuemode = (output_file_str->find(".cue") != -1);
|
||||
int mode = MODE_NORMAL;
|
||||
|
||||
if (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
|
||||
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());
|
||||
if (mode != MODE_GDI)
|
||||
{
|
||||
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
|
||||
UINT64 total_bytes = 0;
|
||||
for (int tracknum = 0; tracknum < toc->numtrks; tracknum++)
|
||||
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
|
||||
UINT64 outputoffs = 0;
|
||||
UINT32 discoffs = 0;
|
||||
dynamic_buffer buffer;
|
||||
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
|
||||
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
|
||||
// the subdata size in the buffer calculation.
|
||||
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");
|
||||
output_frame_size = trackinfo.datasize;
|
||||
}
|
||||
@ -2251,7 +2359,8 @@ static void do_extract_cd(parameters_t ¶ms)
|
||||
|
||||
// now read and output the actual data
|
||||
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));
|
||||
|
||||
@ -2259,7 +2368,7 @@ static void do_extract_cd(parameters_t ¶ms)
|
||||
cdrom_read_data(cdrom, cdrom_get_track_start(cdrom, tracknum) + frame, &buffer[bufferoffs], trackinfo.trktype);
|
||||
|
||||
// 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)
|
||||
{
|
||||
UINT8 swaptemp = buffer[bufferoffs + swapindex];
|
||||
@ -2270,14 +2379,14 @@ static void do_extract_cd(parameters_t ¶ms)
|
||||
discoffs++;
|
||||
|
||||
// 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]);
|
||||
bufferoffs += trackinfo.subsize;
|
||||
}
|
||||
|
||||
// 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);
|
||||
UINT32 byteswritten = core_fwrite(output_bin_file, buffer, bufferoffs);
|
||||
@ -2287,10 +2396,12 @@ static void do_extract_cd(parameters_t ¶ms)
|
||||
bufferoffs = 0;
|
||||
}
|
||||
}
|
||||
|
||||
discoffs += trackinfo.padframes;
|
||||
}
|
||||
|
||||
// finish up
|
||||
core_fclose(output_bin_file);
|
||||
core_fclose(output_bin_file);
|
||||
core_fclose(output_toc_file);
|
||||
printf("Extraction complete \n");
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user