Always calculate offset.

This commit is contained in:
2020-01-06 22:29:01 +00:00
parent 14140ed420
commit eff08a571d
3 changed files with 258 additions and 222 deletions

View File

@@ -123,20 +123,6 @@ namespace DiscImageChef.Core.Devices.Dumping
return; 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 // Check subchannels support
supportsPqSubchannel = SupportsPqSubchannel(_dev, _dumpLog, UpdateStatus); supportsPqSubchannel = SupportsPqSubchannel(_dev, _dumpLog, UpdateStatus);
supportsRwSubchannel = SupportsRwSubchannel(_dev, _dumpLog, UpdateStatus); supportsRwSubchannel = SupportsRwSubchannel(_dev, _dumpLog, UpdateStatus);
@@ -839,9 +825,24 @@ namespace DiscImageChef.Core.Devices.Dumping
// Check offset // Check offset
if(_fixOffset) if(_fixOffset)
{ {
_fixOffset = Media.Info.CompactDisc.GetOffset(cdOffset, _dbDev, _debug, _dev, dskType, _dumpLog, if(tracks.All(t => t.TrackType != TrackType.Audio))
out offsetBytes, readcd, out sectorsForOffset, tracks, {
UpdateStatus); // 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)) 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."); 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); mhddLog = new MhddLog(_outputPrefix + ".mhddlog.bin", _dev, blocks, blockSize, _maximumReadable);
ibgLog = new IbgLog(_outputPrefix + ".ibg", 0x0008); ibgLog = new IbgLog(_outputPrefix + ".ibg", 0x0008);

View File

@@ -1,4 +1,5 @@
using System; using System;
using System.Diagnostics.CodeAnalysis;
using System.Linq; using System.Linq;
using DiscImageChef.CommonTypes; using DiscImageChef.CommonTypes;
using DiscImageChef.CommonTypes.Enums; using DiscImageChef.CommonTypes.Enums;
@@ -21,61 +22,50 @@ namespace DiscImageChef.Core.Media.Info
/// <param name="dev">Opened device</param> /// <param name="dev">Opened device</param>
/// <param name="dskType">Detected disk type</param> /// <param name="dskType">Detected disk type</param>
/// <param name="dumpLog">Dump log if applicable</param> /// <param name="dumpLog">Dump log if applicable</param>
/// <param name="offsetBytes">Set to combined offset, in bytes</param>
/// <param name="readcd">If device supports READ CD command</param>
/// <param name="sectorsForOffset">Sectors needed to fix offset</param>
/// <param name="tracks">Disc track list</param> /// <param name="tracks">Disc track list</param>
/// <param name="updateStatus">UpdateStatus event</param> /// <param name="updateStatus">UpdateStatus event</param>
/// <param name="driveOffset">Drive offset</param>
/// <param name="combinedOffset">Combined offset</param>
/// <returns><c>true</c> if offset could be found, <c>false</c> otherwise</returns> /// <returns><c>true</c> if offset could be found, <c>false</c> otherwise</returns>
public static bool GetOffset(CdOffset cdOffset, Device dbDev, bool debug, DiscImageChef.Devices.Device dev, [SuppressMessage("ReSharper", "TooWideLocalVariableScope")]
MediaType dskType, DumpLog dumpLog, out int offsetBytes, bool readcd, public static void GetOffset(CdOffset cdOffset, Device dbDev, bool debug, DiscImageChef.Devices.Device dev,
out int sectorsForOffset, Track[] tracks, UpdateStatusHandler updateStatus) MediaType dskType, DumpLog dumpLog, Track[] tracks,
UpdateStatusHandler updateStatus, out int? driveOffset, out int? combinedOffset)
{ {
byte[] cmdBuf; byte[] cmdBuf;
bool sense; bool sense;
ulong minute;
ulong second;
ulong frame;
ulong remainder;
byte[] sectorSync;
byte[] tmpBuf;
Track dataTrack = default;
Track audioTrack = default;
bool offsetFound = false; bool offsetFound = false;
const uint sectorSize = 2352; const uint sectorSize = 2352;
offsetBytes = 0; driveOffset = cdOffset?.Offset * 4;
sectorsForOffset = 0; combinedOffset = null;
if(dskType != MediaType.VideoNowColor) 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)) 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) if(dataTrack.TrackSequence != 0)
{ {
dataTrack.TrackStartSector += 151; dataTrack.TrackStartSector += 151;
// Calculate MSF // Calculate MSF
ulong minute = dataTrack.TrackStartSector / 4500; minute = dataTrack.TrackStartSector / 4500;
ulong second = (dataTrack.TrackStartSector - (minute * 4500)) / 75; second = (dataTrack.TrackStartSector - (minute * 4500)) / 75;
ulong frame = dataTrack.TrackStartSector - (minute * 4500) - (second * 75); frame = dataTrack.TrackStartSector - (minute * 4500) - (second * 75);
dataTrack.TrackStartSector -= 151; dataTrack.TrackStartSector -= 151;
// Convert to BCD // Convert to BCD
ulong remainder = minute % 10; remainder = minute % 10;
minute = ((minute / 10) * 16) + remainder; minute = ((minute / 10) * 16) + remainder;
remainder = second % 10; remainder = second % 10;
second = ((second / 10) * 16) + remainder; second = ((second / 10) * 16) + remainder;
@@ -87,13 +77,13 @@ namespace DiscImageChef.Core.Media.Info
second ^= 0x80; second ^= 0x80;
// Build sync // Build sync
byte[] sectorSync = sectorSync = new byte[]
{ {
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, (byte)minute, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, (byte)minute,
(byte)second, (byte)frame (byte)second, (byte)frame
}; };
byte[] tmpBuf = new byte[sectorSync.Length]; tmpBuf = new byte[sectorSync.Length];
// Plextor READ CDDA // Plextor READ CDDA
if(dbDev?.ATAPI?.RemovableMedias?.Any(d => d.SupportsPlextorReadCDDA == true) == true || if(dbDev?.ATAPI?.RemovableMedias?.Any(d => d.SupportsPlextorReadCDDA == true) == true ||
@@ -113,8 +103,8 @@ namespace DiscImageChef.Core.Media.Info
if(!tmpBuf.SequenceEqual(sectorSync)) if(!tmpBuf.SequenceEqual(sectorSync))
continue; continue;
offsetBytes = i - 2352; combinedOffset = i - 2352;
offsetFound = true; offsetFound = true;
break; break;
} }
@@ -140,8 +130,8 @@ namespace DiscImageChef.Core.Media.Info
if(!tmpBuf.SequenceEqual(sectorSync)) if(!tmpBuf.SequenceEqual(sectorSync))
continue; continue;
offsetBytes = i - 2352; combinedOffset = i - 2352;
offsetFound = true; offsetFound = true;
break; 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 // 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; if(tracks[i - 1].TrackType == TrackType.Audio ||
Track audioTrack = default; tracks[i].TrackType != TrackType.Audio)
continue;
for(int i = 1; i < tracks.Length; i++) dataTrack = tracks[i - 1];
{ audioTrack = tracks[i];
if(tracks[i - 1].TrackType == TrackType.Audio ||
tracks[i].TrackType != TrackType.Audio)
continue;
dataTrack = tracks[i - 1]; break;
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;
}
}
}
}
}
} }
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) 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, (byte)minute, (byte)second,
{ (byte)frame
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?. tmpBuf = new byte[sectorSync.Length];
Invoke("Drive read offset is unknown, disabling offset fix. Dump may not be correct.");
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) byte[] dataSide = new byte[2352 - i];
{ byte[] audioSide = new byte[2352 - i];
dumpLog?.
WriteLine($"Disc offsets is {offsetBytes - (cdOffset.Offset * 4)} bytes ({(offsetBytes / 4) - cdOffset.Offset} samples)");
updateStatus?. Array.Copy(dataBuf, i, dataSide, 0, dataSide.Length);
Invoke($"Disc offsets is {offsetBytes - (cdOffset.Offset * 4)} bytes ({(offsetBytes / 4) - cdOffset.Offset} samples)"); Array.Copy(cmdBuf, 0, audioSide, 0, audioSide.Length);
}
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; if(!dataSide.SequenceEqual(audioSide))
} continue;
dumpLog?.WriteLine($"Offset is {offsetBytes} bytes."); combinedOffset = audioSide.Length;
updateStatus?.Invoke($"Offset is {offsetBytes} bytes.");
break;
} }
} }
else else
@@ -325,21 +268,11 @@ namespace DiscImageChef.Core.Media.Info
} }
else else
{ {
offsetBytes = MMC.GetVideoNowColorOffset(videoNowColorFrame); combinedOffset = MMC.GetVideoNowColorOffset(videoNowColorFrame);
dumpLog?.WriteLine($"VideoNow Color frame is offset {offsetBytes} bytes."); dumpLog?.WriteLine($"VideoNow Color frame is offset {combinedOffset} bytes.");
updateStatus?.Invoke($"VideoNow Color frame is offset {offsetBytes} 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;
} }
} }
} }

View File

@@ -580,37 +580,55 @@ namespace DiscImageChef.Commands.Media
track.TrackSequence, track.TrackStartSector, track.TrackEndSector, track.TrackSequence, track.TrackStartSector, track.TrackEndSector,
track.TrackPregap, track.TrackType); 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();
DicConsole.WriteLine("Offsets:"); DicConsole.WriteLine("Offsets:");
DicConsole.WriteLine(cdOffset != null CdOffset cdOffset = null;
? $"Drive offset is {cdOffset.Offset * 4} bytes ({cdOffset.Offset} samples)"
: "Drive offset is unknown");
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 DicConsole.WriteLine("Disc write offset is unknown.");
? $"Disc offset is {offsetBytes - (cdOffset.Offset * 4)} bytes ({(offsetBytes / 4) - cdOffset.Offset} samples)" }
: "Disc offset is unknown");
} }
else else
{ {
DicConsole.WriteLine("Combined offset is unknown"); int offsetBytes = combinedOffset.Value;
DicConsole.WriteLine("Disc offset is unknown");
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)");
}
} }
} }
} }