summaryrefslogtreecommitdiffstatshomepage
path: root/src/tools
diff options
context:
space:
mode:
author R. Belmont <rb6502@users.noreply.github.com>2012-03-04 02:17:35 +0000
committer R. Belmont <rb6502@users.noreply.github.com>2012-03-04 02:17:35 +0000
commitbb993d1174a63b09b040251dec236a0a2c60aeb2 (patch)
tree76497c6e90eb4f2d0fb92d69f1a6c15e81a84e1f /src/tools
parentb89d7c94c7a2000cb896eb7fd0efa5cc012c672f (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/tools')
-rw-r--r--src/tools/chdman.c329
1 files changed, 220 insertions, 109 deletions
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 &params)
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 &params)
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 &params)
// 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 &params)
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 &params)
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 &params)
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");
}