diff options
author | 2012-03-04 02:17:35 +0000 | |
---|---|---|
committer | 2012-03-04 02:17:35 +0000 | |
commit | bb993d1174a63b09b040251dec236a0a2c60aeb2 (patch) | |
tree | 76497c6e90eb4f2d0fb92d69f1a6c15e81a84e1f /src | |
parent | b89d7c94c7a2000cb896eb7fd0efa5cc012c672f (diff) |
chdman: Correct processing of GDI files, add ability to extractcd to .gdi, verified perfect checksum round-tripping on .GDI files. [R. Belmont]
Diffstat (limited to 'src')
-rw-r--r-- | src/lib/util/cdrom.c | 75 | ||||
-rw-r--r-- | src/lib/util/cdrom.h | 6 | ||||
-rw-r--r-- | src/lib/util/chd.c | 4 | ||||
-rw-r--r-- | src/lib/util/chd.h | 2 | ||||
-rw-r--r-- | src/lib/util/chdcd.c | 50 | ||||
-rw-r--r-- | src/tools/chdman.c | 329 |
6 files changed, 306 insertions, 160 deletions
diff --git a/src/lib/util/cdrom.c b/src/lib/util/cdrom.c index d0977a1f534..9178fb5e5b3 100644 --- a/src/lib/util/cdrom.c +++ b/src/lib/util/cdrom.c @@ -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); - - err = chd->write_metadata(CDROM_TRACK_METADATA2_TAG, i, metadata); + 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); + } + 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; } diff --git a/src/lib/util/cdrom.h b/src/lib/util/cdrom.h index 7ac5bead1b7..6a2832e21f8 100644 --- a/src/lib/util/cdrom.h +++ b/src/lib/util/cdrom.h @@ -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]; }; diff --git a/src/lib/util/chd.c b/src/lib/util/chd.c index eda906740f5..697d1ea7889 100644 --- a/src/lib/util/chd.c +++ b/src/lib/util/chd.c @@ -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 diff --git a/src/lib/util/chd.h b/src/lib/util/chd.h index 4eb54371e09..4ae65830dba 100644 --- a/src/lib/util/chd.h +++ b/src/lib/util/chd.h @@ -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'); diff --git a/src/lib/util/chdcd.c b/src/lib/util/chdcd.c index 49eed70fce6..360258c9ea4 100644 --- a/src/lib/util/chdcd.c +++ b/src/lib/util/chdcd.c @@ -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) diff --git a/src/tools/chdman.c b/src/tools/chdman.c index b9ceb1b4d40..b37f9eaceb7 100644 --- a/src/tools/chdman.c +++ b/src/tools/chdman.c @@ -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) - { - // first track specifies the file - if (tracknum == 0) - core_fprintf(file, "FILE \"%s\" BINARY\n", filename); - - // determine submode - astring tempstr; - switch (info.trktype) - { - case CD_TRACK_MODE1: - case CD_TRACK_MODE1_RAW: - tempstr.format("MODE1/%04d", info.datasize); - 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_AUDIO: - tempstr.cpy("AUDIO"); - break; - } - - // output TRACK entry - core_fprintf(file, " TRACK %02d %s\n", tracknum + 1, tempstr.cstr()); - - // output PREGAP - if (info.pregap > 0) - core_fprintf(file, " PREGAP %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)); - - // output POSTGAP - if (info.postgap > 0) - core_fprintf(file, " POSTGAP %s\n", msf_string_from_frames(tempstr, info.postgap)); - } - - // 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); - - // 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"); - } + if (mode == MODE_GDI) + { + int mode = 0, size = 2048; + + switch (info.trktype) + { + case CD_TRACK_MODE1: + mode = 0; + size = 2048; + break; + + case CD_TRACK_MODE1_RAW: + mode = 4; + size = 2352; + break; + + case CD_TRACK_MODE2: + mode = 4; + size = 2336; + break; + + case CD_TRACK_MODE2_FORM1: + mode = 4; + size = 2048; + break; + + case CD_TRACK_MODE2_FORM2: + mode = 4; + size = 2324; + break; + + case CD_TRACK_MODE2_FORM_MIX: + mode = 4; + size = 2336; + break; + + 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); + + // determine submode + astring tempstr; + switch (info.trktype) + { + case CD_TRACK_MODE1: + case CD_TRACK_MODE1_RAW: + tempstr.format("MODE1/%04d", info.datasize); + 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_AUDIO: + tempstr.cpy("AUDIO"); + break; + } + + // output TRACK entry + core_fprintf(file, " TRACK %02d %s\n", tracknum + 1, tempstr.cstr()); + + // output PREGAP + if (info.pregap > 0) + core_fprintf(file, " PREGAP %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)); + + // 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"); } |