diff --git a/DiscImageChef.Core/Devices/Dumping/CompactDisc/Dump.cs b/DiscImageChef.Core/Devices/Dumping/CompactDisc/Dump.cs index c1c242562..577083131 100644 --- a/DiscImageChef.Core/Devices/Dumping/CompactDisc/Dump.cs +++ b/DiscImageChef.Core/Devices/Dumping/CompactDisc/Dump.cs @@ -123,20 +123,6 @@ namespace DiscImageChef.Core.Devices.Dumping return; } - // Search for read offset in master database - cdOffset = _ctx.CdOffsets.FirstOrDefault(d => d.Manufacturer == _dev.Manufacturer && d.Model == _dev.Model); - - if(cdOffset is null) - { - _dumpLog.WriteLine("CD reading offset not found in database."); - UpdateStatus?.Invoke("CD reading offset not found in database."); - } - else - { - _dumpLog.WriteLine($"CD reading offset is {cdOffset.Offset} samples."); - UpdateStatus?.Invoke($"CD reading offset is {cdOffset.Offset} samples."); - } - // Check subchannels support supportsPqSubchannel = SupportsPqSubchannel(_dev, _dumpLog, UpdateStatus); supportsRwSubchannel = SupportsRwSubchannel(_dev, _dumpLog, UpdateStatus); @@ -839,9 +825,24 @@ namespace DiscImageChef.Core.Devices.Dumping // Check offset if(_fixOffset) { - _fixOffset = Media.Info.CompactDisc.GetOffset(cdOffset, _dbDev, _debug, _dev, dskType, _dumpLog, - out offsetBytes, readcd, out sectorsForOffset, tracks, - UpdateStatus); + if(tracks.All(t => t.TrackType != TrackType.Audio)) + { + // No audio tracks so no need to fix offset + _dumpLog.WriteLine("No audio tracks, disabling offset fix."); + UpdateStatus.Invoke("No audio tracks, disabling offset fix."); + + _fixOffset = false; + } + + if(!readcd) + { + _dumpLog.WriteLine("READ CD command is not supported, disabling offset fix. Dump may not be correct."); + + UpdateStatus?. + Invoke("READ CD command is not supported, disabling offset fix. Dump may not be correct."); + + _fixOffset = false; + } } else if(tracks.Any(t => t.TrackType == TrackType.Audio)) { @@ -849,6 +850,90 @@ namespace DiscImageChef.Core.Devices.Dumping UpdateStatus?.Invoke("There are audio tracks and offset fixing is disabled, dump may not be correct."); } + // Search for read offset in master database + cdOffset = _ctx.CdOffsets.FirstOrDefault(d => d.Manufacturer == _dev.Manufacturer && d.Model == _dev.Model); + + Media.Info.CompactDisc.GetOffset(cdOffset, _dbDev, _debug, _dev, dskType, _dumpLog, tracks, UpdateStatus, + out int? driveOffset, out int? combinedOffset); + + if(combinedOffset is null) + { + if(driveOffset is null) + { + _dumpLog.WriteLine("Drive reading offset not found in database."); + UpdateStatus?.Invoke("Drive reading offset not found in database."); + _dumpLog.WriteLine("Disc offset cannot be calculated."); + UpdateStatus?.Invoke("Disc offset cannot be calculated."); + + if(tracks.Any(t => t.TrackType == TrackType.Audio)) + { + _dumpLog.WriteLine("Dump may not be correct."); + + UpdateStatus?.Invoke("Dump may not be correct."); + } + + if(_fixOffset) + _fixOffset = false; + } + else + { + _dumpLog.WriteLine($"Drive reading offset is {driveOffset} bytes ({driveOffset / 4} samples)."); + UpdateStatus?.Invoke($"Drive reading offset is {driveOffset} bytes ({driveOffset / 4} samples)."); + + _dumpLog.WriteLine("Disc write offset is unknown, dump may not be correct."); + UpdateStatus?.Invoke("Disc write offset is unknown, dump may not be correct."); + + offsetBytes = driveOffset.Value; + + sectorsForOffset = offsetBytes / (int)sectorSize; + + if(sectorsForOffset < 0) + sectorsForOffset *= -1; + + if(offsetBytes % sectorSize != 0) + sectorsForOffset++; + } + } + else + { + offsetBytes = combinedOffset.Value; + sectorsForOffset = offsetBytes / (int)sectorSize; + + if(sectorsForOffset < 0) + sectorsForOffset *= -1; + + if(offsetBytes % sectorSize != 0) + sectorsForOffset++; + + if(driveOffset is null) + { + _dumpLog.WriteLine("Drive reading offset not found in database."); + UpdateStatus?.Invoke("Drive reading offset not found in database."); + _dumpLog.WriteLine($"Combined disc and drive offsets are {offsetBytes} bytes ({offsetBytes / 4} samples)."); + + UpdateStatus?. + Invoke($"Combined disc and drive offsets are {offsetBytes} bytes ({offsetBytes / 4} samples)."); + } + else + { + _dumpLog.WriteLine($"Drive reading offset is {driveOffset} bytes ({driveOffset / 4} samples)."); + UpdateStatus?.Invoke($"Drive reading offset is {driveOffset} bytes ({driveOffset / 4} samples)."); + + int? discOffset = offsetBytes - driveOffset; + + _dumpLog.WriteLine($"Disc offsets is {discOffset} bytes ({discOffset / 4} samples)"); + + UpdateStatus?.Invoke($"Disc offsets is {discOffset} bytes ({discOffset / 4} samples)"); + } + } + + if(!_fixOffset || + tracks.All(t => t.TrackType != TrackType.Audio)) + { + offsetBytes = 0; + sectorsForOffset = 0; + } + mhddLog = new MhddLog(_outputPrefix + ".mhddlog.bin", _dev, blocks, blockSize, _maximumReadable); ibgLog = new IbgLog(_outputPrefix + ".ibg", 0x0008); diff --git a/DiscImageChef.Core/Media/Info/CompactDisc.cs b/DiscImageChef.Core/Media/Info/CompactDisc.cs index 62d28ba7d..0a67decb7 100644 --- a/DiscImageChef.Core/Media/Info/CompactDisc.cs +++ b/DiscImageChef.Core/Media/Info/CompactDisc.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics.CodeAnalysis; using System.Linq; using DiscImageChef.CommonTypes; using DiscImageChef.CommonTypes.Enums; @@ -21,61 +22,50 @@ namespace DiscImageChef.Core.Media.Info /// Opened device /// Detected disk type /// Dump log if applicable - /// Set to combined offset, in bytes - /// If device supports READ CD command - /// Sectors needed to fix offset /// Disc track list /// UpdateStatus event + /// Drive offset + /// Combined offset /// true if offset could be found, false otherwise - public static bool GetOffset(CdOffset cdOffset, Device dbDev, bool debug, DiscImageChef.Devices.Device dev, - MediaType dskType, DumpLog dumpLog, out int offsetBytes, bool readcd, - out int sectorsForOffset, Track[] tracks, UpdateStatusHandler updateStatus) + [SuppressMessage("ReSharper", "TooWideLocalVariableScope")] + public static void GetOffset(CdOffset cdOffset, Device dbDev, bool debug, DiscImageChef.Devices.Device dev, + MediaType dskType, DumpLog dumpLog, Track[] tracks, + UpdateStatusHandler updateStatus, out int? driveOffset, out int? combinedOffset) { byte[] cmdBuf; bool sense; + ulong minute; + ulong second; + ulong frame; + ulong remainder; + byte[] sectorSync; + byte[] tmpBuf; + Track dataTrack = default; + Track audioTrack = default; bool offsetFound = false; const uint sectorSize = 2352; - offsetBytes = 0; - sectorsForOffset = 0; + driveOffset = cdOffset?.Offset * 4; + combinedOffset = null; if(dskType != MediaType.VideoNowColor) { - if(tracks.All(t => t.TrackType != TrackType.Audio)) - { - // No audio tracks so no need to fix offset - dumpLog?.WriteLine("No audio tracks, disabling offset fix."); - updateStatus?.Invoke("No audio tracks, disabling offset fix."); - - return false; - } - - if(!readcd) - { - dumpLog?.WriteLine("READ CD command is not supported, disabling offset fix. Dump may not be correct."); - - updateStatus?. - Invoke("READ CD command is not supported, disabling offset fix. Dump may not be correct."); - - return false; - } - if(tracks.Any(t => t.TrackType != TrackType.Audio)) { - Track dataTrack = tracks.FirstOrDefault(t => t.TrackType != TrackType.Audio); + dataTrack = tracks.FirstOrDefault(t => t.TrackType != TrackType.Audio); if(dataTrack.TrackSequence != 0) { dataTrack.TrackStartSector += 151; // Calculate MSF - ulong minute = dataTrack.TrackStartSector / 4500; - ulong second = (dataTrack.TrackStartSector - (minute * 4500)) / 75; - ulong frame = dataTrack.TrackStartSector - (minute * 4500) - (second * 75); + minute = dataTrack.TrackStartSector / 4500; + second = (dataTrack.TrackStartSector - (minute * 4500)) / 75; + frame = dataTrack.TrackStartSector - (minute * 4500) - (second * 75); dataTrack.TrackStartSector -= 151; // Convert to BCD - ulong remainder = minute % 10; + remainder = minute % 10; minute = ((minute / 10) * 16) + remainder; remainder = second % 10; second = ((second / 10) * 16) + remainder; @@ -87,13 +77,13 @@ namespace DiscImageChef.Core.Media.Info second ^= 0x80; // Build sync - byte[] sectorSync = + sectorSync = new byte[] { 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, (byte)minute, (byte)second, (byte)frame }; - byte[] tmpBuf = new byte[sectorSync.Length]; + tmpBuf = new byte[sectorSync.Length]; // Plextor READ CDDA if(dbDev?.ATAPI?.RemovableMedias?.Any(d => d.SupportsPlextorReadCDDA == true) == true || @@ -113,8 +103,8 @@ namespace DiscImageChef.Core.Media.Info if(!tmpBuf.SequenceEqual(sectorSync)) continue; - offsetBytes = i - 2352; - offsetFound = true; + combinedOffset = i - 2352; + offsetFound = true; break; } @@ -140,8 +130,8 @@ namespace DiscImageChef.Core.Media.Info if(!tmpBuf.SequenceEqual(sectorSync)) continue; - offsetBytes = i - 2352; - offsetFound = true; + combinedOffset = i - 2352; + offsetFound = true; break; } @@ -150,152 +140,105 @@ namespace DiscImageChef.Core.Media.Info } } + if(offsetFound) + return; + // Try to get another the offset some other way, we need an audio track just after a data track, same session - if(!offsetFound) + + for(int i = 1; i < tracks.Length; i++) { - Track dataTrack = default; - Track audioTrack = default; + if(tracks[i - 1].TrackType == TrackType.Audio || + tracks[i].TrackType != TrackType.Audio) + continue; - for(int i = 1; i < tracks.Length; i++) - { - if(tracks[i - 1].TrackType == TrackType.Audio || - tracks[i].TrackType != TrackType.Audio) - continue; + dataTrack = tracks[i - 1]; + audioTrack = tracks[i]; - dataTrack = tracks[i - 1]; - audioTrack = tracks[i]; - - break; - } - - // Found them - if(dataTrack.TrackSequence != 0 && - audioTrack.TrackSequence != 0) - { - sense = dev.ReadCd(out cmdBuf, out _, (uint)audioTrack.TrackStartSector, sectorSize, 3, - MmcSectorTypes.Cdda, false, false, false, MmcHeaderCodes.None, true, false, - MmcErrorField.None, MmcSubchannel.None, dev.Timeout, out _); - - if(!sense && - !dev.Error) - { - dataTrack.TrackEndSector += 150; - - // Calculate MSF - ulong minute = dataTrack.TrackEndSector / 4500; - ulong second = (dataTrack.TrackEndSector - (minute * 4500)) / 75; - ulong frame = dataTrack.TrackEndSector - (minute * 4500) - (second * 75); - - dataTrack.TrackEndSector -= 150; - - // Convert to BCD - ulong remainder = minute % 10; - minute = ((minute / 10) * 16) + remainder; - remainder = second % 10; - second = ((second / 10) * 16) + remainder; - remainder = frame % 10; - frame = ((frame / 10) * 16) + remainder; - - // Scramble M and S - minute ^= 0x01; - second ^= 0x80; - - // Build sync - byte[] sectorSync = - { - 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, (byte)minute, - (byte)second, (byte)frame - }; - - byte[] tmpBuf = new byte[sectorSync.Length]; - - for(int i = 0; i < cmdBuf.Length - sectorSync.Length; i++) - { - Array.Copy(cmdBuf, i, tmpBuf, 0, sectorSync.Length); - - if(!tmpBuf.SequenceEqual(sectorSync)) - continue; - - offsetBytes = i + 2352; - offsetFound = true; - - break; - } - - if(!offsetFound && - audioTrack.TrackPregap > 0) - { - sense = dev.ReadCd(out byte[] dataBuf, out _, (uint)dataTrack.TrackEndSector, - sectorSize, 1, MmcSectorTypes.AllTypes, false, false, true, - MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None, - MmcSubchannel.None, dev.Timeout, out _); - - if(!sense && - !dev.Error) - { - for(int i = 0; i < dataBuf.Length; i++) - dataBuf[i] ^= Sector.ScrambleTable[i]; - - for(int i = 0; i < 2352; i++) - { - byte[] dataSide = new byte[2352 - i]; - byte[] audioSide = new byte[2352 - i]; - - Array.Copy(dataBuf, i, dataSide, 0, dataSide.Length); - Array.Copy(cmdBuf, 0, audioSide, 0, audioSide.Length); - - if(!dataSide.SequenceEqual(audioSide)) - continue; - - offsetBytes = audioSide.Length; - offsetFound = true; - - break; - } - } - } - } - } + break; } - if(cdOffset is null) + if(dataTrack.TrackSequence == 0 || + audioTrack.TrackSequence == 0) + return; + + // Found them + sense = dev.ReadCd(out cmdBuf, out _, (uint)audioTrack.TrackStartSector, sectorSize, 3, + MmcSectorTypes.Cdda, false, false, false, MmcHeaderCodes.None, true, false, + MmcErrorField.None, MmcSubchannel.None, dev.Timeout, out _); + + if(sense || dev.Error) + return; + + dataTrack.TrackEndSector += 150; + + // Calculate MSF + minute = dataTrack.TrackEndSector / 4500; + second = (dataTrack.TrackEndSector - (minute * 4500)) / 75; + frame = dataTrack.TrackEndSector - (minute * 4500) - (second * 75); + + dataTrack.TrackEndSector -= 150; + + // Convert to BCD + remainder = minute % 10; + minute = ((minute / 10) * 16) + remainder; + remainder = second % 10; + second = ((second / 10) * 16) + remainder; + remainder = frame % 10; + frame = ((frame / 10) * 16) + remainder; + + // Scramble M and S + minute ^= 0x01; + second ^= 0x80; + + // Build sync + sectorSync = new byte[] { - if(offsetFound) - { - dumpLog?.WriteLine($"Combined disc and drive offsets are {offsetBytes} bytes"); - updateStatus?.Invoke($"Combined disc and drive offsets are {offsetBytes} bytes"); - } - else - { - dumpLog?. - WriteLine("Drive read offset is unknown, disabling offset fix. Dump may not be correct."); + 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, (byte)minute, (byte)second, + (byte)frame + }; - updateStatus?. - Invoke("Drive read offset is unknown, disabling offset fix. Dump may not be correct."); + tmpBuf = new byte[sectorSync.Length]; - return false; - } + for(int i = 0; i < cmdBuf.Length - sectorSync.Length; i++) + { + Array.Copy(cmdBuf, i, tmpBuf, 0, sectorSync.Length); + + if(!tmpBuf.SequenceEqual(sectorSync)) + continue; + + combinedOffset = i + 2352; + offsetFound = true; + + break; } - else + + if(offsetFound || audioTrack.TrackPregap <= 0) + return; + + sense = dev.ReadCd(out byte[] dataBuf, out _, (uint)dataTrack.TrackEndSector, sectorSize, 1, + MmcSectorTypes.AllTypes, false, false, true, MmcHeaderCodes.AllHeaders, true, true, + MmcErrorField.None, MmcSubchannel.None, dev.Timeout, out _); + + if(sense || dev.Error) + return; + + for(int i = 0; i < dataBuf.Length; i++) + dataBuf[i] ^= Sector.ScrambleTable[i]; + + for(int i = 0; i < 2352; i++) { - if(offsetFound) - { - dumpLog?. - WriteLine($"Disc offsets is {offsetBytes - (cdOffset.Offset * 4)} bytes ({(offsetBytes / 4) - cdOffset.Offset} samples)"); + byte[] dataSide = new byte[2352 - i]; + byte[] audioSide = new byte[2352 - i]; - updateStatus?. - Invoke($"Disc offsets is {offsetBytes - (cdOffset.Offset * 4)} bytes ({(offsetBytes / 4) - cdOffset.Offset} samples)"); - } - else - { - dumpLog?.WriteLine("Disc write offset is unknown, dump may not be correct."); - updateStatus?.Invoke("Disc write offset is unknown, dump may not be correct."); + Array.Copy(dataBuf, i, dataSide, 0, dataSide.Length); + Array.Copy(cmdBuf, 0, audioSide, 0, audioSide.Length); - offsetBytes = cdOffset.Offset * 4; - } + if(!dataSide.SequenceEqual(audioSide)) + continue; - dumpLog?.WriteLine($"Offset is {offsetBytes} bytes."); - updateStatus?.Invoke($"Offset is {offsetBytes} bytes."); + combinedOffset = audioSide.Length; + + break; } } else @@ -325,21 +268,11 @@ namespace DiscImageChef.Core.Media.Info } else { - offsetBytes = MMC.GetVideoNowColorOffset(videoNowColorFrame); - dumpLog?.WriteLine($"VideoNow Color frame is offset {offsetBytes} bytes."); - updateStatus?.Invoke($"VideoNow Color frame is offset {offsetBytes} bytes."); + combinedOffset = MMC.GetVideoNowColorOffset(videoNowColorFrame); + dumpLog?.WriteLine($"VideoNow Color frame is offset {combinedOffset} bytes."); + updateStatus?.Invoke($"VideoNow Color frame is offset {combinedOffset} bytes."); } } - - sectorsForOffset = offsetBytes / (int)sectorSize; - - if(sectorsForOffset < 0) - sectorsForOffset *= -1; - - if(offsetBytes % sectorSize != 0) - sectorsForOffset++; - - return offsetFound; } } } \ No newline at end of file diff --git a/DiscImageChef/Commands/Media/Info.cs b/DiscImageChef/Commands/Media/Info.cs index 15459bd88..ff32784e6 100644 --- a/DiscImageChef/Commands/Media/Info.cs +++ b/DiscImageChef/Commands/Media/Info.cs @@ -580,37 +580,55 @@ namespace DiscImageChef.Commands.Media track.TrackSequence, track.TrackStartSector, track.TrackEndSector, track.TrackPregap, track.TrackType); - CdOffset cdOffset = null; - - if(dbDev != null) - { - // Search for read offset in master database - cdOffset = ctx.CdOffsets.FirstOrDefault(d => d.Manufacturer == dev.Manufacturer && - d.Model == dev.Model); - } - - bool gotOffset = CompactDisc.GetOffset(cdOffset, dbDev, debug, dev, scsiInfo.MediaType, null, - out int offsetBytes, true, out _, tracks, null); - DicConsole.WriteLine(); DicConsole.WriteLine("Offsets:"); - DicConsole.WriteLine(cdOffset != null - ? $"Drive offset is {cdOffset.Offset * 4} bytes ({cdOffset.Offset} samples)" - : "Drive offset is unknown"); + CdOffset cdOffset = null; - if(gotOffset) + // Search for read offset in master database + cdOffset = ctx.CdOffsets.FirstOrDefault(d => d.Manufacturer == dev.Manufacturer && + d.Model == dev.Model); + + CompactDisc.GetOffset(cdOffset, dbDev, debug, dev, scsiInfo.MediaType, null, tracks, null, + out int? driveOffset, out int? combinedOffset); + + if(combinedOffset is null) { - DicConsole.WriteLine($"Combined offset is {offsetBytes} bytes ({offsetBytes / 4} samples)"); + if(driveOffset is null) + { + DicConsole.WriteLine("Drive reading offset not found in database."); + DicConsole.WriteLine("Disc offset cannot be calculated."); + } + else + { + DicConsole. + WriteLine($"Drive reading offset is {driveOffset} bytes ({driveOffset / 4} samples)."); - DicConsole.WriteLine(cdOffset != null - ? $"Disc offset is {offsetBytes - (cdOffset.Offset * 4)} bytes ({(offsetBytes / 4) - cdOffset.Offset} samples)" - : "Disc offset is unknown"); + DicConsole.WriteLine("Disc write offset is unknown."); + } } else { - DicConsole.WriteLine("Combined offset is unknown"); - DicConsole.WriteLine("Disc offset is unknown"); + int offsetBytes = combinedOffset.Value; + + if(driveOffset is null) + { + DicConsole.WriteLine("Drive reading offset not found in database."); + + DicConsole. + WriteLine($"Combined disc and drive offset are {offsetBytes} bytes ({offsetBytes / 4} samples)."); + } + else + { + DicConsole. + WriteLine($"Drive reading offset is {driveOffset} bytes ({driveOffset / 4} samples)."); + + DicConsole.WriteLine($"Combined offset is {offsetBytes} bytes ({offsetBytes / 4} samples)"); + + int? discOffset = offsetBytes - driveOffset; + + DicConsole.WriteLine($"Disc offset is {discOffset} bytes ({discOffset / 4} samples)"); + } } } }