diff --git a/.idea/.idea.DiscImageChef/.idea/contentModel.xml b/.idea/.idea.DiscImageChef/.idea/contentModel.xml index eeefcb0ce..68876f183 100644 --- a/.idea/.idea.DiscImageChef/.idea/contentModel.xml +++ b/.idea/.idea.DiscImageChef/.idea/contentModel.xml @@ -291,6 +291,7 @@ + diff --git a/DiscImageChef.Core/Devices/Dumping/CompactDisc.cs b/DiscImageChef.Core/Devices/Dumping/CompactDisc.cs index c4b1edbe8..3edfbe8dd 100644 --- a/DiscImageChef.Core/Devices/Dumping/CompactDisc.cs +++ b/DiscImageChef.Core/Devices/Dumping/CompactDisc.cs @@ -1329,206 +1329,9 @@ namespace DiscImageChef.Core.Devices.Dumping // Check offset if(_fixOffset) { - 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."); - - _fixOffset = false; - } - else 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 - { - bool offsetFound = false; - - if(tracks.Any(t => t.TrackType != TrackType.Audio)) - { - Track 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); - - dataTrack.TrackStartSector -= 151; - - // 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 - }; - - tmpBuf = new byte[sectorSync.Length]; - - // Plextor READ CDDA - if(_dbDev?.ATAPI?.RemovableMedias?.Any(d => d.SupportsPlextorReadCDDA == true) == - true || - _dbDev?.SCSI?.RemovableMedias?.Any(d => d.SupportsPlextorReadCDDA == true) == true || - _dev.Manufacturer.ToLowerInvariant() == - "plextor") - { - sense = _dev.PlextorReadCdDa(out cmdBuf, out senseBuf, - (uint)dataTrack.TrackStartSector, sectorSize, 3, - PlextorSubchannel.None, _dev.Timeout, out _); - - if(!sense && - !_dev.Error) - { - 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(_debug || - _dbDev?.ATAPI?.RemovableMedias?.Any(d => d.CanReadCdScrambled == true) == true || - _dbDev?.SCSI?.RemovableMedias?.Any(d => d.CanReadCdScrambled == true) == true || - _dev.Manufacturer.ToLowerInvariant() == "hl-dt-st") - { - sense = _dev.ReadCd(out cmdBuf, out senseBuf, (uint)dataTrack.TrackStartSector, - sectorSize, 3, MmcSectorTypes.Cdda, false, false, false, - MmcHeaderCodes.None, true, false, MmcErrorField.None, - MmcSubchannel.None, _dev.Timeout, out _); - - if(!sense && - !_dev.Error) - { - 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(cdOffset is null) - { - 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."); - - UpdateStatus?. - Invoke("Drive read offset is unknown, disabling offset fix. Dump may not be correct."); - - _fixOffset = false; - } - } - else - { - if(offsetFound) - { - _dumpLog. - WriteLine($"Disc offsets is {offsetBytes - (cdOffset.Offset * 4)} bytes ({(offsetBytes / 4) - cdOffset.Offset} samples)"); - - 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."); - - offsetBytes = cdOffset.Offset * 4; - } - - _dumpLog.WriteLine($"Offset is {offsetBytes} bytes."); - UpdateStatus?.Invoke($"Offset is {offsetBytes} bytes."); - } - } - } - else - { - byte[] videoNowColorFrame = new byte[9 * sectorSize]; - - sense = _dev.ReadCd(out cmdBuf, out senseBuf, 0, sectorSize, 9, MmcSectorTypes.AllTypes, false, - false, true, MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None, - MmcSubchannel.None, _dev.Timeout, out _); - - if(sense || _dev.Error) - { - sense = _dev.ReadCd(out cmdBuf, out senseBuf, 0, sectorSize, 9, MmcSectorTypes.Cdda, false, - false, true, MmcHeaderCodes.None, true, true, MmcErrorField.None, - MmcSubchannel.None, _dev.Timeout, out _); - - if(sense || _dev.Error) - { - videoNowColorFrame = null; - } - } - - if(videoNowColorFrame is null) - { - _dumpLog.WriteLine("Could not find VideoNow Color frame offset, dump may not be correct."); - UpdateStatus?.Invoke("Could not find VideoNow Color frame offset, dump may not be correct."); - } - else - { - offsetBytes = MMC.GetVideoNowColorOffset(videoNowColorFrame); - _dumpLog.WriteLine($"VideoNow Color frame is offset {offsetBytes} bytes."); - UpdateStatus?.Invoke($"VideoNow Color frame is offset {offsetBytes} bytes."); - } - } - - sectorsForOffset = offsetBytes / (int)sectorSize; - - if(sectorsForOffset < 0) - sectorsForOffset *= -1; - - if(offsetBytes % sectorSize != 0) - sectorsForOffset++; + _fixOffset = Media.Info.CompactDisc.GetOffset(cdOffset, _dbDev, _debug, _dev, dskType, _dumpLog, + out offsetBytes, readcd, out sectorsForOffset, tracks, + UpdateStatus); } else if(tracks.Any(t => t.TrackType == TrackType.Audio)) { diff --git a/DiscImageChef.Core/DiscImageChef.Core.csproj b/DiscImageChef.Core/DiscImageChef.Core.csproj index d617f8236..0aefb933b 100644 --- a/DiscImageChef.Core/DiscImageChef.Core.csproj +++ b/DiscImageChef.Core/DiscImageChef.Core.csproj @@ -61,6 +61,7 @@ + diff --git a/DiscImageChef.Core/Media/Info/CompactDisc.cs b/DiscImageChef.Core/Media/Info/CompactDisc.cs new file mode 100644 index 000000000..c9c20c2d6 --- /dev/null +++ b/DiscImageChef.Core/Media/Info/CompactDisc.cs @@ -0,0 +1,236 @@ +using System; +using System.Linq; +using DiscImageChef.CommonTypes; +using DiscImageChef.CommonTypes.Enums; +using DiscImageChef.CommonTypes.Structs; +using DiscImageChef.Core.Logging; +using DiscImageChef.Core.Media.Detection; +using DiscImageChef.Database.Models; +using DiscImageChef.Devices; +using Device = DiscImageChef.Database.Models.Device; + +namespace DiscImageChef.Core.Media.Info +{ + public static class CompactDisc + { + /// Gets the offset bytes from a Compact Disc + /// Offset entry from database + /// Device entry from database + /// Debug + /// 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 + /// 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) + { + byte[] cmdBuf; + bool sense; + bool offsetFound = false; + const uint sectorSize = 2352; + offsetBytes = 0; + sectorsForOffset = 0; + + 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); + + 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); + + dataTrack.TrackStartSector -= 151; + + // 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]; + + // Plextor READ CDDA + if(dbDev?.ATAPI?.RemovableMedias?.Any(d => d.SupportsPlextorReadCDDA == true) == true || + dbDev?.SCSI?.RemovableMedias?.Any(d => d.SupportsPlextorReadCDDA == true) == true || + dev.Manufacturer.ToLowerInvariant() == "plextor") + { + sense = dev.PlextorReadCdDa(out cmdBuf, out _, (uint)dataTrack.TrackStartSector, sectorSize, + 3, PlextorSubchannel.None, dev.Timeout, out _); + + if(!sense && + !dev.Error) + { + 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(debug || + dbDev?.ATAPI?.RemovableMedias?.Any(d => d.CanReadCdScrambled == true) == true || + dbDev?.SCSI?.RemovableMedias?.Any(d => d.CanReadCdScrambled == true) == true || + dev.Manufacturer.ToLowerInvariant() == "hl-dt-st") + { + sense = dev.ReadCd(out cmdBuf, out _, (uint)dataTrack.TrackStartSector, sectorSize, 3, + MmcSectorTypes.Cdda, false, false, false, MmcHeaderCodes.None, true, + false, MmcErrorField.None, MmcSubchannel.None, dev.Timeout, out _); + + if(!sense && + !dev.Error) + { + 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(cdOffset is null) + { + 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."); + + updateStatus?. + Invoke("Drive read offset is unknown, disabling offset fix. Dump may not be correct."); + + return false; + } + } + else + { + if(offsetFound) + { + dumpLog. + WriteLine($"Disc offsets is {offsetBytes - (cdOffset.Offset * 4)} bytes ({(offsetBytes / 4) - cdOffset.Offset} samples)"); + + 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."); + + offsetBytes = cdOffset.Offset * 4; + } + + dumpLog?.WriteLine($"Offset is {offsetBytes} bytes."); + updateStatus?.Invoke($"Offset is {offsetBytes} bytes."); + } + } + else + { + byte[] videoNowColorFrame = new byte[9 * sectorSize]; + + sense = dev.ReadCd(out cmdBuf, out _, 0, sectorSize, 9, MmcSectorTypes.AllTypes, false, false, true, + MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None, MmcSubchannel.None, + dev.Timeout, out _); + + if(sense || dev.Error) + { + sense = dev.ReadCd(out cmdBuf, out _, 0, sectorSize, 9, MmcSectorTypes.Cdda, false, false, true, + MmcHeaderCodes.None, true, true, MmcErrorField.None, MmcSubchannel.None, + dev.Timeout, out _); + + if(sense || dev.Error) + { + videoNowColorFrame = null; + } + } + + if(videoNowColorFrame is null) + { + dumpLog?.WriteLine("Could not find VideoNow Color frame offset, dump may not be correct."); + updateStatus?.Invoke("Could not find VideoNow Color frame offset, dump may not be correct."); + } + else + { + offsetBytes = MMC.GetVideoNowColorOffset(videoNowColorFrame); + dumpLog?.WriteLine($"VideoNow Color frame is offset {offsetBytes} bytes."); + updateStatus?.Invoke($"VideoNow Color frame is offset {offsetBytes} bytes."); + } + } + + sectorsForOffset = offsetBytes / (int)sectorSize; + + if(sectorsForOffset < 0) + sectorsForOffset *= -1; + + if(offsetBytes % sectorSize != 0) + sectorsForOffset++; + + return offsetFound; + } + } +} \ No newline at end of file