summaryrefslogtreecommitdiffstatshomepage
path: root/src/lib/util/cdrom.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/util/cdrom.cpp')
-rw-r--r--src/lib/util/cdrom.cpp428
1 files changed, 300 insertions, 128 deletions
diff --git a/src/lib/util/cdrom.cpp b/src/lib/util/cdrom.cpp
index 159a9c964a1..d9074bfd838 100644
--- a/src/lib/util/cdrom.cpp
+++ b/src/lib/util/cdrom.cpp
@@ -21,6 +21,7 @@
#include "corestr.h"
#include "multibyte.h"
#include "osdfile.h"
+#include "path.h"
#include "strformat.h"
#include <cassert>
@@ -180,6 +181,9 @@ cdrom_file::cdrom_file(std::string_view inputfile)
track.logframeofs = track.pregap;
}
+ if ((cdtoc.flags & CD_FLAG_MULTISESSION) && cdtrack_info.track[i].leadin != -1)
+ logofs += cdtrack_info.track[i].leadin;
+
track.physframeofs = physofs;
track.chdframeofs = 0;
track.logframeofs += logofs;
@@ -191,8 +195,13 @@ cdrom_file::cdrom_file(std::string_view inputfile)
physofs += track.frames;
logofs += track.frames;
+ if ((cdtoc.flags & CD_FLAG_MULTISESSION) && cdtrack_info.track[i].leadout != -1)
+ logofs += cdtrack_info.track[i].leadout;
+
if (EXTRA_VERBOSE)
- printf("Track %02d is format %d subtype %d datasize %d subsize %d frames %d extraframes %d pregap %d pgmode %d presize %d postgap %d logofs %d physofs %d chdofs %d logframes %d pad %d\n", i+1,
+ printf("session %d track %02d is format %d subtype %d datasize %d subsize %d frames %d extraframes %d pregap %d pgmode %d presize %d postgap %d logofs %d physofs %d chdofs %d logframes %d pad %d\n",
+ track.session+1,
+ i+1,
track.trktype,
track.subtype,
track.datasize,
@@ -290,7 +299,9 @@ cdrom_file::cdrom_file(chd_file *_chd)
logofs += track.frames;
if (EXTRA_VERBOSE)
- printf("Track %02d is format %d subtype %d datasize %d subsize %d frames %d extraframes %d pregap %d pgmode %d presize %d postgap %d logofs %d physofs %d chdofs %d logframes %d pad %d\n", i+1,
+ printf("session %d track %02d is format %d subtype %d datasize %d subsize %d frames %d extraframes %d pregap %d pgmode %d presize %d postgap %d logofs %d physofs %d chdofs %d logframes %d pad %d\n",
+ track.session+1,
+ i+1,
track.trktype,
track.subtype,
track.datasize,
@@ -583,6 +594,27 @@ uint32_t cdrom_file::get_track(uint32_t frame) const
return track;
}
+uint32_t cdrom_file::get_track_index(uint32_t frame) const
+{
+ const uint32_t track = get_track(frame);
+ const uint32_t track_start = get_track_start(track);
+ const uint32_t index_offset = frame - track_start;
+ int index = 0;
+
+ for (int i = 0; i < std::size(cdtrack_info.track[track].idx); i++)
+ {
+ if (index_offset >= cdtrack_info.track[track].idx[i])
+ index = i;
+ else
+ break;
+ }
+
+ if (cdtrack_info.track[track].idx[index] == -1)
+ index = 1; // valid index not found, default to index 1
+
+ return index;
+}
+
/***************************************************************************
EXTRA UTILITIES
@@ -868,70 +900,57 @@ std::error_condition cdrom_file::parse_metadata(chd_file *chd, toc &toc)
/* clear structures */
memset(&toc, 0, sizeof(toc));
+ toc.numsessions = 1;
+
/* start with no tracks */
for (toc.numtrks = 0; toc.numtrks < MAX_TRACKS; toc.numtrks++)
{
- int tracknum = -1, frames = 0, pregap, postgap, padframes;
+ int tracknum, frames, pregap, postgap, padframes;
char type[16], subtype[16], pgtype[16], pgsub[16];
track_info *track;
- pregap = postgap = padframes = 0;
+ tracknum = -1;
+ frames = pregap = postgap = padframes = 0;
+ std::fill(std::begin(type), std::end(type), 0);
+ std::fill(std::begin(subtype), std::end(subtype), 0);
+ std::fill(std::begin(pgtype), std::end(pgtype), 0);
+ std::fill(std::begin(pgsub), std::end(pgsub), 0);
/* fetch the metadata for this track */
- err = chd->read_metadata(CDROM_TRACK_METADATA_TAG, toc.numtrks, metadata);
- if (!err)
+ if (!chd->read_metadata(CDROM_TRACK_METADATA_TAG, toc.numtrks, metadata))
{
- /* parse the metadata */
- type[0] = subtype[0] = 0;
- pgtype[0] = pgsub[0] = 0;
if (sscanf(metadata.c_str(), CDROM_TRACK_METADATA_FORMAT, &tracknum, type, subtype, &frames) != 4)
return chd_file::error::INVALID_DATA;
- if (tracknum == 0 || tracknum > MAX_TRACKS)
+ }
+ else if (!chd->read_metadata(CDROM_TRACK_METADATA2_TAG, toc.numtrks, metadata))
+ {
+ if (sscanf(metadata.c_str(), CDROM_TRACK_METADATA2_FORMAT, &tracknum, type, subtype, &frames, &pregap, pgtype, pgsub, &postgap) != 8)
return chd_file::error::INVALID_DATA;
- track = &toc.tracks[tracknum - 1];
}
else
{
- err = chd->read_metadata(CDROM_TRACK_METADATA2_TAG, toc.numtrks, metadata);
+ /* fall through to GD-ROM detection */
+ err = chd->read_metadata(GDROM_OLD_METADATA_TAG, toc.numtrks, metadata);
if (!err)
- {
- /* parse the metadata */
- type[0] = subtype[0] = 0;
- pregap = postgap = 0;
- if (sscanf(metadata.c_str(), CDROM_TRACK_METADATA2_FORMAT, &tracknum, type, subtype, &frames, &pregap, pgtype, pgsub, &postgap) != 8)
- return chd_file::error::INVALID_DATA;
- if (tracknum == 0 || tracknum > MAX_TRACKS)
- return chd_file::error::INVALID_DATA;
- track = &toc.tracks[tracknum - 1];
- }
+ /* legacy GDROM track was detected */
+ toc.flags |= CD_FLAG_GDROMLE;
else
- {
- err = chd->read_metadata(GDROM_OLD_METADATA_TAG, toc.numtrks, metadata);
- if (!err)
- /* legacy GDROM track was detected */
- toc.flags |= CD_FLAG_GDROMLE;
- else
- err = chd->read_metadata(GDROM_TRACK_METADATA_TAG, toc.numtrks, metadata);
+ err = chd->read_metadata(GDROM_TRACK_METADATA_TAG, toc.numtrks, metadata);
- if (!err)
- {
- /* parse the metadata */
- type[0] = subtype[0] = 0;
- pregap = postgap = 0;
- if (sscanf(metadata.c_str(), GDROM_TRACK_METADATA_FORMAT, &tracknum, type, subtype, &frames, &padframes, &pregap, pgtype, pgsub, &postgap) != 9)
- return chd_file::error::INVALID_DATA;
- if (tracknum == 0 || tracknum > MAX_TRACKS)
- return chd_file::error::INVALID_DATA;
- track = &toc.tracks[tracknum - 1];
- toc.flags |= CD_FLAG_GDROM;
- }
- else
- {
- break;
- }
- }
+ if (err)
+ break;
+
+ if (sscanf(metadata.c_str(), GDROM_TRACK_METADATA_FORMAT, &tracknum, type, subtype, &frames, &padframes, &pregap, pgtype, pgsub, &postgap) != 9)
+ return chd_file::error::INVALID_DATA;
+
+ toc.flags |= CD_FLAG_GDROM;
}
+ if (tracknum == 0 || tracknum > MAX_TRACKS)
+ return chd_file::error::INVALID_DATA;
+
+ track = &toc.tracks[tracknum - 1];
+
/* extract the track type and determine the data size */
track->trktype = CD_TRACK_MODE1;
track->datasize = 0;
@@ -986,8 +1005,11 @@ std::error_condition cdrom_file::parse_metadata(chd_file *chd, toc &toc)
auto *mrp = reinterpret_cast<uint32_t *>(&oldmetadata[0]);
toc.numtrks = *mrp++;
+ toc.numsessions = 1;
+
for (int i = 0; i < MAX_TRACKS; i++)
{
+ toc.tracks[i].session = 0;
toc.tracks[i].trktype = *mrp++;
toc.tracks[i].subtype = *mrp++;
toc.tracks[i].datasize = *mrp++;
@@ -1045,7 +1067,16 @@ std::error_condition cdrom_file::write_metadata(chd_file *chd, const toc &toc)
for (int i = 0; i < toc.numtrks; i++)
{
std::string metadata;
- if (!(toc.flags & CD_FLAG_GDROM))
+ if (toc.flags & CD_FLAG_GDROM)
+ {
+ metadata = util::string_format(GDROM_TRACK_METADATA_FORMAT, i + 1, get_type_string(toc.tracks[i].trktype),
+ get_subtype_string(toc.tracks[i].subtype), toc.tracks[i].frames, toc.tracks[i].padframes,
+ toc.tracks[i].pregap, get_type_string(toc.tracks[i].pgtype),
+ get_subtype_string(toc.tracks[i].pgsub), toc.tracks[i].postgap);
+
+ err = chd->write_metadata(GDROM_TRACK_METADATA_TAG, i, metadata);
+ }
+ else
{
char submode[32];
@@ -1065,15 +1096,6 @@ std::error_condition cdrom_file::write_metadata(chd_file *chd, const toc &toc)
toc.tracks[i].postgap);
err = chd->write_metadata(CDROM_TRACK_METADATA2_TAG, i, metadata);
}
- else
- {
- metadata = util::string_format(GDROM_TRACK_METADATA_FORMAT, i + 1, get_type_string(toc.tracks[i].trktype),
- get_subtype_string(toc.tracks[i].subtype), toc.tracks[i].frames, toc.tracks[i].padframes,
- toc.tracks[i].pregap, get_type_string(toc.tracks[i].pgtype),
- get_subtype_string(toc.tracks[i].pgsub), toc.tracks[i].postgap);
-
- err = chd->write_metadata(GDROM_TRACK_METADATA_TAG, i, metadata);
- }
if (err)
return err;
}
@@ -1833,6 +1855,8 @@ std::error_condition cdrom_file::parse_nero(std::string_view tocfname, toc &outt
memset(&outtoc, 0, sizeof(outtoc));
outinfo.reset();
+ outtoc.numsessions = 1;
+
// seek to 12 bytes before the end
fseek(infile, -12, SEEK_END);
fread(buffer, 12, 1, infile);
@@ -1895,8 +1919,7 @@ std::error_condition cdrom_file::parse_nero(std::string_view tocfname, toc &outt
// printf("Track %d: sector size %d mode %x index0 %llx index1 %llx track_end %llx (pregap %d sectors, length %d sectors)\n", track, size, mode, index0, index1, track_end, (uint32_t)(index1-index0)/size, (uint32_t)(track_end-index1)/size);
outinfo.track[track-1].fname.assign(tocfname);
outinfo.track[track-1].offset = offset + (uint32_t)(index1-index0);
- outinfo.track[track-1].idx0offs = 0;
- outinfo.track[track-1].idx1offs = 0;
+ outinfo.track[track-1].idx[0] = outinfo.track[track-1].idx[1] = 0;
switch (mode)
{
@@ -2016,11 +2039,11 @@ std::error_condition cdrom_file::parse_iso(std::string_view tocfname, toc &outto
outtoc.numtrks = 1;
+ outtoc.numsessions = 1;
outinfo.track[0].fname = tocfname;
outinfo.track[0].offset = 0;
- outinfo.track[0].idx0offs = 0;
- outinfo.track[0].idx1offs = 0;
+ outinfo.track[0].idx[0] = outinfo.track[0].idx[1] = 0;
if ((size % 2048)==0 ) {
outtoc.tracks[0].trktype = CD_TRACK_MODE1;
@@ -2189,6 +2212,7 @@ std::error_condition cdrom_file::parse_gdi(std::string_view tocfname, toc &outto
/* store the number of tracks found */
outtoc.numtrks = numtracks;
+ outtoc.numsessions = 1;
return std::error_condition();
}
@@ -2215,13 +2239,15 @@ std::error_condition cdrom_file::parse_gdi(std::string_view tocfname, toc &outto
std::error_condition cdrom_file::parse_cue(std::string_view tocfname, toc &outtoc, track_input_info &outinfo)
{
- int i, trknum;
+ int i, trknum, sessionnum, session_pregap;
char token[512];
std::string lastfname;
uint32_t wavlen, wavoffs;
std::string path = std::string(tocfname);
const bool is_gdrom = is_gdicue(tocfname);
enum gdi_area current_area = SINGLE_DENSITY;
+ bool is_multibin = false;
+ int leadin = -1;
FILE *infile = fopen(path.c_str(), "rt");
if (!infile)
@@ -2237,6 +2263,8 @@ std::error_condition cdrom_file::parse_cue(std::string_view tocfname, toc &outto
trknum = -1;
wavoffs = wavlen = 0;
+ sessionnum = 0;
+ session_pregap = 0;
if (is_gdrom)
{
@@ -2261,13 +2289,65 @@ std::error_condition cdrom_file::parse_cue(std::string_view tocfname, toc &outto
if (!strcmp(token, "REM"))
{
- /* TODO: sessions are notated using REM commands: "REM SESSION 01" */
-
/* skip to actual data of REM command */
while (i < std::size(linebuffer) && isspace((uint8_t)linebuffer[i]))
i++;
- if (is_gdrom && !strncmp(linebuffer+i, "SINGLE-DENSITY AREA", 19))
+ if (!strncmp(linebuffer+i, "SESSION", 7))
+ {
+ /* IsoBuster extension */
+ TOKENIZE
+
+ /* get the session number */
+ TOKENIZE
+
+ sessionnum = strtoul(token, nullptr, 10) - 1;
+
+ if (sessionnum >= 1) /* don't consider it a multisession CD unless there's actually more than 1 session */
+ outtoc.flags |= CD_FLAG_MULTISESSION;
+ }
+ else if ((outtoc.flags & CD_FLAG_MULTISESSION) && !strncmp(linebuffer+i, "PREGAP", 6))
+ {
+ /*
+ Redump extension? PREGAP associated with the session instead of the track
+
+ DiscImageCreator - Older versions would write a bogus value here (and maybe session lead-in and lead-out).
+ These should be considered bad dumps and will not be supported.
+ */
+ TOKENIZE
+
+ /* get pregap time */
+ TOKENIZE
+ session_pregap = msf_to_frames( token );
+ }
+ else if (!strncmp(linebuffer+i, "LEAD-OUT", 8))
+ {
+ /*
+ IsoBuster and ImgBurn (single bin file) - Lead-out time is the start of the lead-out
+ lead-out time - MSF of last track of session = size of last track
+
+ Redump and DiscImageCreator (multiple bins) - Lead-out time is the duration of just the lead-out
+ */
+ TOKENIZE
+
+ /* get lead-out time */
+ TOKENIZE
+ int leadout_offset = msf_to_frames( token );
+ outinfo.track[trknum].leadout = leadout_offset;
+ }
+ else if (!strncmp(linebuffer+i, "LEAD-IN", 7))
+ {
+ /*
+ IsoBuster and ImgBurn (single bin file) - Not used?
+ Redump and DiscImageCreator (multiple bins) - Lead-in time is the duration of just the lead-in
+ */
+ TOKENIZE
+
+ /* get lead-in time */
+ TOKENIZE
+ leadin = msf_to_frames( token );
+ }
+ else if (is_gdrom && !strncmp(linebuffer+i, "SINGLE-DENSITY AREA", 19))
{
/* single-density area starts LBA = 0 */
current_area = SINGLE_DENSITY;
@@ -2284,7 +2364,10 @@ std::error_condition cdrom_file::parse_cue(std::string_view tocfname, toc &outto
TOKENIZE
/* keep the filename */
+ std::string prevfname = lastfname;
lastfname.assign(path).append(token);
+ if (prevfname.length() > 0 && lastfname.compare(prevfname) != 0)
+ is_multibin = true;
/* get the file type */
TOKENIZE
@@ -2323,6 +2406,7 @@ std::error_condition cdrom_file::parse_cue(std::string_view tocfname, toc &outto
/* next token on the line is the track type */
TOKENIZE
+ outtoc.tracks[trknum].session = sessionnum;
outtoc.tracks[trknum].subtype = CD_SUB_NONE;
outtoc.tracks[trknum].subsize = 0;
outtoc.tracks[trknum].pgsub = CD_SUB_NONE;
@@ -2330,9 +2414,26 @@ std::error_condition cdrom_file::parse_cue(std::string_view tocfname, toc &outto
outtoc.tracks[trknum].padframes = 0;
outtoc.tracks[trknum].datasize = 0;
outtoc.tracks[trknum].multicuearea = is_gdrom ? current_area : 0;
- outinfo.track[trknum].idx0offs = -1;
- outinfo.track[trknum].idx1offs = 0;
outinfo.track[trknum].offset = 0;
+ std::fill(std::begin(outinfo.track[trknum].idx), std::end(outinfo.track[trknum].idx), -1);
+
+ outinfo.track[trknum].leadout = -1;
+ outinfo.track[trknum].leadin = leadin; /* use previously saved lead-in value */
+ leadin = -1;
+
+ if (session_pregap != 0)
+ {
+ /*
+ associated the pregap from the session transition with the lead-in to simplify things for now.
+ setting it as the proper pregap for the track causes logframeofs of the last dummy entry in the TOC
+ to become 2s later than it should. this might be an issue with how pgdatasize = 0 pregaps are handled.
+ */
+ if (outinfo.track[trknum].leadin == -1)
+ outinfo.track[trknum].leadin = session_pregap;
+ else
+ outinfo.track[trknum].leadin += session_pregap;
+ session_pregap = 0;
+ }
if (wavlen != 0)
{
@@ -2341,7 +2442,7 @@ std::error_condition cdrom_file::parse_cue(std::string_view tocfname, toc &outto
wavoffs = wavlen = 0;
}
- outinfo.track[trknum].fname.assign(lastfname); // default filename to the last one
+ outinfo.track[trknum].fname.assign(lastfname); /* default filename to the last one */
if (EXTRA_VERBOSE)
{
@@ -2368,7 +2469,7 @@ std::error_condition cdrom_file::parse_cue(std::string_view tocfname, toc &outto
convert_subtype_string_to_track_info(token, &outtoc.tracks[trknum]);
}
- else if (!strcmp(token, "INDEX")) /* only in bin/cue files */
+ else if (!strcmp(token, "INDEX"))
{
int idx, frames;
@@ -2380,22 +2481,25 @@ std::error_condition cdrom_file::parse_cue(std::string_view tocfname, toc &outto
TOKENIZE
frames = msf_to_frames( token );
- if (idx == 0)
+ if (idx < 0 || idx > MAX_INDEX)
{
- outinfo.track[trknum].idx0offs = frames;
+ printf("ERROR: encountered invalid index %d\n", idx);
+ return chd_file::error::INVALID_DATA;
}
- else if (idx == 1)
+
+ outinfo.track[trknum].idx[idx] = frames;
+
+ if (idx == 1)
{
- outinfo.track[trknum].idx1offs = frames;
- if ((outtoc.tracks[trknum].pregap == 0) && (outinfo.track[trknum].idx0offs != -1))
+ if (outtoc.tracks[trknum].pregap == 0 && outinfo.track[trknum].idx[0] != -1)
{
- outtoc.tracks[trknum].pregap = frames - outinfo.track[trknum].idx0offs;
+ outtoc.tracks[trknum].pregap = frames - outinfo.track[trknum].idx[0];
outtoc.tracks[trknum].pgtype = outtoc.tracks[trknum].trktype;
outtoc.tracks[trknum].pgdatasize = outtoc.tracks[trknum].datasize;
}
- else // pregap sectors not in file, but we're always using idx0ofs for track length calc now
+ else if (outinfo.track[trknum].idx[0] == -1) /* pregap sectors not in file, but we're always using idx 0 for track length calc now */
{
- outinfo.track[trknum].idx0offs = frames;
+ outinfo.track[trknum].idx[0] = frames;
}
}
}
@@ -2419,6 +2523,28 @@ std::error_condition cdrom_file::parse_cue(std::string_view tocfname, toc &outto
outtoc.tracks[trknum].postgap = frames;
}
+ else if (!strcmp(token, "FLAGS"))
+ {
+ outtoc.tracks[trknum].control_flags = 0;
+
+ /* keep looping over remaining tokens in FLAGS line until there's no more to read */
+ while (i < std::size(linebuffer))
+ {
+ int last_idx = i;
+
+ TOKENIZE
+
+ if (i == last_idx)
+ break;
+
+ if (!strcmp(token, "DCP"))
+ outtoc.tracks[trknum].control_flags |= CD_FLAG_CONTROL_DIGITAL_COPY_PERMITTED;
+ else if (!strcmp(token, "4CH"))
+ outtoc.tracks[trknum].control_flags |= CD_FLAG_CONTROL_4CH;
+ else if (!strcmp(token, "PRE"))
+ outtoc.tracks[trknum].control_flags |= CD_FLAG_CONTROL_PREEMPHASIS;
+ }
+ }
}
}
@@ -2427,82 +2553,126 @@ std::error_condition cdrom_file::parse_cue(std::string_view tocfname, toc &outto
/* store the number of tracks found */
outtoc.numtrks = trknum + 1;
+ outtoc.numsessions = sessionnum + 1;
/* now go over the files again and set the lengths */
for (trknum = 0; trknum < outtoc.numtrks; trknum++)
{
uint64_t tlen = 0;
- // this is true for cue/bin and cue/iso, and we need it for cue/wav since .WAV is little-endian
+ if (outinfo.track[trknum].idx[1] == -1)
+ {
+ /* index 1 should always be set */
+ printf("ERROR: track %d is missing INDEX 01 marker\n", trknum+1);
+ return chd_file::error::INVALID_DATA;
+ }
+
+ /* this is true for cue/bin and cue/iso, and we need it for cue/wav since .WAV is little-endian */
if (outtoc.tracks[trknum].trktype == CD_TRACK_AUDIO)
{
outinfo.track[trknum].swap = true;
}
- // don't do this for .WAV tracks, we already have their length and offset filled out
- if (outinfo.track[trknum].offset == 0)
+ /* don't do this for .WAV tracks, we already have their length and offset filled out */
+ if (outinfo.track[trknum].offset != 0)
+ continue;
+
+ if (trknum+1 >= outtoc.numtrks && trknum > 0 && (outinfo.track[trknum].fname.compare(outinfo.track[trknum-1].fname)==0))
{
- // is this the last track?
- if (trknum == (outtoc.numtrks-1))
+ /* if the last track's filename is the same as the previous track */
+ tlen = get_file_size(outinfo.track[trknum].fname);
+ if (tlen == 0)
{
- /* if we have the same filename as the last track, do it that way */
- if (trknum != 0 && (outinfo.track[trknum].fname.compare(outinfo.track[trknum-1].fname)==0))
+ printf("ERROR: couldn't find bin file [%s]\n", outinfo.track[trknum-1].fname.c_str());
+ return std::errc::no_such_file_or_directory;
+ }
+
+ outinfo.track[trknum].offset = outinfo.track[trknum-1].offset + outtoc.tracks[trknum-1].frames * (outtoc.tracks[trknum-1].datasize + outtoc.tracks[trknum-1].subsize);
+ outtoc.tracks[trknum].frames = (tlen - outinfo.track[trknum].offset) / (outtoc.tracks[trknum].datasize + outtoc.tracks[trknum].subsize);
+ }
+ else if (trknum+1 < outtoc.numtrks && outinfo.track[trknum].fname.compare(outinfo.track[trknum+1].fname)==0)
+ {
+ /* if the current filename is the same as the next track */
+ outtoc.tracks[trknum].frames = outinfo.track[trknum+1].idx[0] - outinfo.track[trknum].idx[0];
+
+ if (outtoc.tracks[trknum].frames == 0)
+ {
+ printf("ERROR: unable to determine size of track %d, missing INDEX 01 markers?\n", trknum+1);
+ return chd_file::error::INVALID_DATA;
+ }
+
+ if (trknum > 0)
+ {
+ const uint32_t previous_track_raw_size = outtoc.tracks[trknum-1].frames * (outtoc.tracks[trknum-1].datasize + outtoc.tracks[trknum-1].subsize);
+ outinfo.track[trknum].offset = outinfo.track[trknum-1].offset + previous_track_raw_size;
+ }
+ }
+ else if (outtoc.tracks[trknum].frames == 0)
+ {
+ /* if the filenames between tracks are different */
+ tlen = get_file_size(outinfo.track[trknum].fname);
+ if (tlen == 0)
+ {
+ printf("ERROR: couldn't find bin file [%s]\n", outinfo.track[trknum-1].fname.c_str());
+ return std::errc::no_such_file_or_directory;
+ }
+
+ outtoc.tracks[trknum].frames = tlen / (outtoc.tracks[trknum].datasize + outtoc.tracks[trknum].subsize);
+ outinfo.track[trknum].offset = 0;
+ }
+
+ if (outtoc.flags & CD_FLAG_MULTISESSION)
+ {
+ if (is_multibin)
+ {
+ if (outinfo.track[trknum].leadout == -1 && trknum + 1 < outtoc.numtrks && outtoc.tracks[trknum].session != outtoc.tracks[trknum+1].session)
{
- tlen = get_file_size(outinfo.track[trknum].fname);
- if (tlen == 0)
- {
- printf("ERROR: couldn't find bin file [%s]\n", outinfo.track[trknum-1].fname.c_str());
- return std::errc::no_such_file_or_directory;
- }
- outinfo.track[trknum].offset = outinfo.track[trknum-1].offset + outtoc.tracks[trknum-1].frames * (outtoc.tracks[trknum-1].datasize + outtoc.tracks[trknum-1].subsize);
- outtoc.tracks[trknum].frames = (tlen - outinfo.track[trknum].offset) / (outtoc.tracks[trknum].datasize + outtoc.tracks[trknum].subsize);
+ /* add a standard lead-out to the last track before changing sessions */
+ outinfo.track[trknum].leadout = outtoc.tracks[trknum].session == 0 ? 6750 : 2250; /* first session lead-out (1m30s0f) is longer than the rest (0m30s0f) */
}
- else /* data files are different */
+
+ if (outinfo.track[trknum].leadin == -1 && trknum > 0 && outtoc.tracks[trknum].session != outtoc.tracks[trknum-1].session)
{
- tlen = get_file_size(outinfo.track[trknum].fname);
- if (tlen == 0)
- {
- printf("ERROR: couldn't find bin file [%s]\n", outinfo.track[trknum-1].fname.c_str());
- return std::errc::no_such_file_or_directory;
- }
- tlen /= (outtoc.tracks[trknum].datasize + outtoc.tracks[trknum].subsize);
- outtoc.tracks[trknum].frames = tlen;
- outinfo.track[trknum].offset = 0;
+ /* add a standard lead-in to the first track of a new session */
+ outinfo.track[trknum].leadin = 4500; /* lead-in (1m0s0f) */
}
}
else
{
- /* if we have the same filename as the next track, do it that way */
- if (outinfo.track[trknum].fname.compare(outinfo.track[trknum+1].fname)==0)
+ if (outinfo.track[trknum].leadout != -1)
{
- outtoc.tracks[trknum].frames = outinfo.track[trknum+1].idx0offs - outinfo.track[trknum].idx0offs;
-
- if (trknum == 0) // track 0 offset is 0
+ /*
+ if a lead-out time is specified in a multisession CD then the size of the previous track needs to be trimmed
+ to use the lead-out time instead of the idx 0 of the next track
+ */
+ const int endframes = outinfo.track[trknum].leadout - outinfo.track[trknum].idx[0];
+ if (outtoc.tracks[trknum].frames >= endframes)
{
- outinfo.track[trknum].offset = 0;
- }
- else
- {
- outinfo.track[trknum].offset = outinfo.track[trknum-1].offset + outtoc.tracks[trknum-1].frames * (outtoc.tracks[trknum-1].datasize + outtoc.tracks[trknum-1].subsize);
- }
+ outtoc.tracks[trknum].frames = endframes; /* trim track length */
- if (!outtoc.tracks[trknum].frames)
- {
- printf("ERROR: unable to determine size of track %d, missing INDEX 01 markers?\n", trknum+1);
- return chd_file::error::INVALID_DATA;
+ if (trknum + 1 < outtoc.numtrks)
+ {
+ /* lead-out value becomes just the duration between the lead-out to the pre-gap of the next track */
+ outinfo.track[trknum].leadout = outinfo.track[trknum+1].idx[0] - outinfo.track[trknum].leadout;
+ }
}
}
- else /* data files are different */
+
+ if (trknum > 0 && outinfo.track[trknum-1].leadout != -1)
{
- tlen = get_file_size(outinfo.track[trknum].fname);
- if (tlen == 0)
+ /*
+ ImgBurn bin/cue have dummy data to pad between the lead-out and the start of the next track.
+ DiscImageCreator img/cue does not have any data between the lead-out and the start of the next track.
+
+ Detecting by extension is an awful way to handle this but there's no other way to determine what format
+ the data will be in since we don't know the exact length of the last track just from the cue.
+ */
+ if (!core_filename_ends_with(outinfo.track[trknum-1].fname, ".img"))
{
- printf("ERROR: couldn't find bin file [%s]\n", outinfo.track[trknum].fname.c_str());
- return std::errc::no_such_file_or_directory;
+ outtoc.tracks[trknum-1].padframes += outinfo.track[trknum-1].leadout;
+ outtoc.tracks[trknum].frames -= outinfo.track[trknum-1].leadout;
+ outinfo.track[trknum].offset += outinfo.track[trknum-1].leadout * (outtoc.tracks[trknum].datasize + outtoc.tracks[trknum].subsize);
}
- tlen /= (outtoc.tracks[trknum].datasize + outtoc.tracks[trknum].subsize);
- outtoc.tracks[trknum].frames = tlen;
- outinfo.track[trknum].offset = 0;
}
}
}
@@ -2523,7 +2693,7 @@ std::error_condition cdrom_file::parse_cue(std::string_view tocfname, toc &outto
outinfo.track[trknum].offset += this_offset;
outtoc.tracks[trknum].frames -= this_pregap;
- outinfo.track[trknum].idx1offs -= this_pregap;
+ outinfo.track[trknum].idx[1] -= this_pregap;
outtoc.tracks[trknum].pregap = 0;
outtoc.tracks[trknum].pgtype = 0;
@@ -2551,7 +2721,8 @@ std::error_condition cdrom_file::parse_cue(std::string_view tocfname, toc &outto
if (EXTRA_VERBOSE)
for (trknum = 0; trknum < outtoc.numtrks; trknum++)
{
- printf("trk %d: %d frames @ offset %d, pad=%d, split=%d, area=%d, phys=%d, pregap=%d, pgtype=%d, pgdatasize=%d, idx0=%d, idx1=%d, dataframes=%d\n",
+ printf("session %d trk %d: %d frames @ offset %d, pad=%d, split=%d, area=%d, phys=%d, pregap=%d, pgtype=%d, pgdatasize=%d, idx0=%d, idx1=%d, dataframes=%d\n",
+ outtoc.tracks[trknum].session+1,
trknum+1,
outtoc.tracks[trknum].frames,
outinfo.track[trknum].offset,
@@ -2562,8 +2733,8 @@ std::error_condition cdrom_file::parse_cue(std::string_view tocfname, toc &outto
outtoc.tracks[trknum].pregap,
outtoc.tracks[trknum].pgtype,
outtoc.tracks[trknum].pgdatasize,
- outinfo.track[trknum].idx0offs,
- outinfo.track[trknum].idx1offs,
+ outinfo.track[trknum].idx[0],
+ outinfo.track[trknum].idx[1],
outtoc.tracks[trknum].frames - outtoc.tracks[trknum].padframes);
}
@@ -2832,6 +3003,7 @@ std::error_condition cdrom_file::parse_toc(std::string_view tocfname, toc &outto
/* store the number of tracks found */
outtoc.numtrks = trknum + 1;
+ outtoc.numsessions = 1;
return std::error_condition();
}