Move CD user data reading to a separate file.

This commit is contained in:
2020-01-01 18:31:14 +00:00
parent c2a3c7bffe
commit 423f14c4b1
4 changed files with 377 additions and 279 deletions

View File

@@ -70,7 +70,6 @@ namespace DiscImageChef.Core.Devices.Dumping
ExtentsULong audioExtents; // Extents with audio sectors
ulong blocks; // Total number of positive sectors
uint blockSize; // Size of the read sector in bytes
uint blocksToRead = 0; // How many sectors to read at once
CdOffset cdOffset; // Read offset from database
byte[] cmdBuf = null; // Data buffer
double cmdDuration = 0; // Command execution time
@@ -116,7 +115,6 @@ namespace DiscImageChef.Core.Devices.Dumping
int firstTrackLastSession; // Number of first track in last session
bool hiddenTrack; // Disc has a hidden track before track 1
bool nextData; // Next cluster of sectors is all data;
MmcSubchannel supportedSubchannel; // Drive's maximum supported subchannel
DateTime timeSpeedStart; // Time of start for speed calculation
@@ -919,7 +917,6 @@ namespace DiscImageChef.Core.Devices.Dumping
ibgLog = new IbgLog(_outputPrefix + ".ibg", 0x0008);
audioExtents = new ExtentsULong();
nextData = tracks[0].TrackType != TrackType.Audio;
foreach(Track audioTrack in tracks.Where(t => t.TrackType == TrackType.Audio))
{
@@ -942,283 +939,12 @@ namespace DiscImageChef.Core.Devices.Dumping
}
// Start reading
start = DateTime.UtcNow;
currentSpeed = 0;
sectorSpeedStart = 0;
timeSpeedStart = DateTime.UtcNow;
InitProgress?.Invoke();
start = DateTime.UtcNow;
for(ulong i = _resume.NextBlock; (long)i <= lastSector; i += blocksToRead)
{
if(_aborted)
{
currentTry.Extents = ExtentsConverter.ToMetadata(extents);
UpdateStatus?.Invoke("Aborted!");
_dumpLog.WriteLine("Aborted!");
break;
}
while(leadOutExtents.Contains(i))
{
i++;
}
if((long)i > lastSector)
break;
uint firstSectorToRead = (uint)i;
if((lastSector + 1) - (long)i < _maximumReadable)
_maximumReadable = (uint)((lastSector + 1) - (long)i);
blocksToRead = 0;
bool inData = nextData;
for(ulong j = i; j < i + _maximumReadable; j++)
{
if(nextData)
{
if(audioExtents.Contains(j))
{
nextData = false;
break;
}
blocksToRead++;
}
else
{
if(!audioExtents.Contains(j))
{
nextData = true;
break;
}
blocksToRead++;
}
}
if(blocksToRead == 1)
blocksToRead = 2;
if(_fixOffset && !inData)
{
// TODO: FreeBSD bug
if(offsetBytes < 0)
{
if(i == 0)
firstSectorToRead = uint.MaxValue - (uint)(sectorsForOffset - 1); // -1
else
firstSectorToRead -= (uint)sectorsForOffset;
}
}
#pragma warning disable RECS0018 // Comparison of floating point numbers with equality operator
// ReSharper disable CompareOfFloatsByEqualityOperator
if(currentSpeed > maxSpeed &&
currentSpeed != 0)
maxSpeed = currentSpeed;
if(currentSpeed < minSpeed &&
currentSpeed != 0)
minSpeed = currentSpeed;
// ReSharper restore CompareOfFloatsByEqualityOperator
#pragma warning restore RECS0018 // Comparison of floating point numbers with equality operator
UpdateProgress?.Invoke($"Reading sector {i} of {blocks} ({currentSpeed:F3} MiB/sec.)", (long)i,
(long)blocks);
if(readcd)
{
sense = _dev.ReadCd(out cmdBuf, out senseBuf, firstSectorToRead, blockSize, blocksToRead,
MmcSectorTypes.AllTypes, false, false, true, MmcHeaderCodes.AllHeaders, true,
true, MmcErrorField.None, supportedSubchannel, _dev.Timeout, out cmdDuration);
totalDuration += cmdDuration;
}
else if(read16)
{
sense = _dev.Read16(out cmdBuf, out senseBuf, 0, false, true, false, firstSectorToRead, blockSize,
0, blocksToRead, false, _dev.Timeout, out cmdDuration);
}
else if(read12)
{
sense = _dev.Read12(out cmdBuf, out senseBuf, 0, false, true, false, false, firstSectorToRead,
blockSize, 0, blocksToRead, false, _dev.Timeout, out cmdDuration);
}
else if(read10)
{
sense = _dev.Read10(out cmdBuf, out senseBuf, 0, false, true, false, false, firstSectorToRead,
blockSize, 0, (ushort)blocksToRead, _dev.Timeout, out cmdDuration);
}
else if(read6)
{
sense = _dev.Read6(out cmdBuf, out senseBuf, firstSectorToRead, blockSize, (byte)blocksToRead,
_dev.Timeout, out cmdDuration);
}
// Because one block has been partially used to fix the offset
if(_fixOffset &&
!inData &&
offsetBytes != 0)
{
int offsetFix = offsetBytes < 0 ? offsetFix = (int)(sectorSize - (offsetBytes * -1))
: offsetFix = offsetBytes;
if(supportedSubchannel != MmcSubchannel.None)
{
// Deinterleave subchannel
byte[] data = new byte[sectorSize * blocksToRead];
byte[] sub = new byte[subSize * blocksToRead];
for(int b = 0; b < blocksToRead; b++)
{
Array.Copy(cmdBuf, (int)(0 + (b * blockSize)), data, sectorSize * b, sectorSize);
Array.Copy(cmdBuf, (int)(sectorSize + (b * blockSize)), sub, subSize * b, subSize);
}
tmpBuf = new byte[sectorSize * (blocksToRead - sectorsForOffset)];
Array.Copy(data, offsetFix, tmpBuf, 0, tmpBuf.Length);
data = tmpBuf;
blocksToRead -= (uint)sectorsForOffset;
// Reinterleave subchannel
cmdBuf = new byte[blockSize * blocksToRead];
for(int b = 0; b < blocksToRead; b++)
{
Array.Copy(data, sectorSize * b, cmdBuf, (int)(0 + (b * blockSize)), sectorSize);
Array.Copy(sub, subSize * b, cmdBuf, (int)(sectorSize + (b * blockSize)), subSize);
}
}
else
{
tmpBuf = new byte[blockSize * (blocksToRead - sectorsForOffset)];
Array.Copy(cmdBuf, offsetFix, tmpBuf, 0, tmpBuf.Length);
cmdBuf = tmpBuf;
blocksToRead -= (uint)sectorsForOffset;
}
}
if(!sense &&
!_dev.Error)
{
mhddLog.Write(i, cmdDuration);
ibgLog.Write(i, currentSpeed * 1024);
extents.Add(i, blocksToRead, true);
DateTime writeStart = DateTime.Now;
if(supportedSubchannel != MmcSubchannel.None)
{
byte[] data = new byte[sectorSize * blocksToRead];
byte[] sub = new byte[subSize * blocksToRead];
for(int b = 0; b < blocksToRead; b++)
{
Array.Copy(cmdBuf, (int)(0 + (b * blockSize)), data, sectorSize * b, sectorSize);
Array.Copy(cmdBuf, (int)(sectorSize + (b * blockSize)), sub, subSize * b, subSize);
}
_outputPlugin.WriteSectorsLong(data, i, blocksToRead);
_outputPlugin.WriteSectorsTag(sub, i, blocksToRead, SectorTagType.CdSectorSubchannel);
}
else
{
if(supportsLongSectors)
{
_outputPlugin.WriteSectorsLong(cmdBuf, i, blocksToRead);
}
else
{
if(cmdBuf.Length % sectorSize == 0)
{
byte[] data = new byte[2048 * blocksToRead];
for(int b = 0; b < blocksToRead; b++)
Array.Copy(cmdBuf, (int)(16 + (b * blockSize)), data, 2048 * b, 2048);
_outputPlugin.WriteSectors(data, i, blocksToRead);
}
else
{
_outputPlugin.WriteSectorsLong(cmdBuf, i, blocksToRead);
}
}
}
imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds;
}
else
{
// TODO: Reset device after X errors
if(_stopOnError)
return; // TODO: Return more cleanly
if(i + _skip > blocks)
_skip = (uint)(blocks - i);
// Write empty data
DateTime writeStart = DateTime.Now;
if(supportedSubchannel != MmcSubchannel.None)
{
_outputPlugin.WriteSectorsLong(new byte[sectorSize * _skip], i, _skip);
_outputPlugin.WriteSectorsTag(new byte[subSize * _skip], i, _skip,
SectorTagType.CdSectorSubchannel);
}
else
{
if(supportsLongSectors)
{
_outputPlugin.WriteSectorsLong(new byte[blockSize * _skip], i, _skip);
}
else
{
if(cmdBuf.Length % sectorSize == 0)
_outputPlugin.WriteSectors(new byte[2048 * _skip], i, _skip);
else
_outputPlugin.WriteSectorsLong(new byte[blockSize * _skip], i, _skip);
}
}
imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds;
for(ulong b = i; b < i + _skip; b++)
_resume.BadBlocks.Add(b);
DicConsole.DebugWriteLine("Dump-Media", "READ error:\n{0}", Sense.PrettifySense(senseBuf));
mhddLog.Write(i, cmdDuration < 500 ? 65535 : cmdDuration);
ibgLog.Write(i, 0);
_dumpLog.WriteLine("Skipping {0} blocks from errored block {1}.", _skip, i);
i += _skip - blocksToRead;
newTrim = true;
}
sectorSpeedStart += blocksToRead;
_resume.NextBlock = i + blocksToRead;
double elapsed = (DateTime.UtcNow - timeSpeedStart).TotalSeconds;
if(elapsed < 1)
continue;
currentSpeed = (sectorSpeedStart * blockSize) / (1048576 * elapsed);
sectorSpeedStart = 0;
timeSpeedStart = DateTime.UtcNow;
}
EndProgress?.Invoke();
ReadCdData(audioExtents, blocks, blockSize, ref currentSpeed, currentTry, extents, ibgLog,
ref imageWriteDuration, lastSector, leadOutExtents, ref maxSpeed, mhddLog, ref minSpeed,
out newTrim, tracks[0].TrackType != TrackType.Audio, offsetBytes, read6, read10, read12, read16,
readcd, sectorsForOffset, subSize, supportedSubchannel, supportsLongSectors, ref totalDuration);
// TODO: Enable when underlying images support lead-outs
/*