diff options
Diffstat (limited to 'src/lib/util/cdrom.cpp')
-rw-r--r-- | src/lib/util/cdrom.cpp | 428 |
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(); } |