mirror of
https://github.com/aaru-dps/Aaru.git
synced 2025-12-16 19:24:25 +00:00
[Aaru.Core] Reformat and cleanup.
This commit is contained in:
@@ -59,12 +59,9 @@ partial class Dump
|
||||
if(sector?.Length != 2352)
|
||||
return false;
|
||||
|
||||
byte[] syncMark =
|
||||
{
|
||||
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00
|
||||
};
|
||||
byte[] syncMark = { 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00 };
|
||||
|
||||
byte[] testMark = new byte[12];
|
||||
var testMark = new byte[12];
|
||||
Array.Copy(sector, 0, testMark, 0, 12);
|
||||
|
||||
return syncMark.SequenceEqual(testMark) && (sector[0xF] == 0 || sector[0xF] == 1 || sector[0xF] == 2);
|
||||
@@ -82,19 +79,16 @@ partial class Dump
|
||||
if(sector?.Length != 2352)
|
||||
return false;
|
||||
|
||||
byte[] syncMark =
|
||||
{
|
||||
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00
|
||||
};
|
||||
byte[] syncMark = { 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00 };
|
||||
|
||||
byte[] testMark = new byte[12];
|
||||
var testMark = new byte[12];
|
||||
|
||||
for(int i = 0; i <= 2336; i++)
|
||||
for(var i = 0; i <= 2336; i++)
|
||||
{
|
||||
Array.Copy(sector, i, testMark, 0, 12);
|
||||
|
||||
if(!syncMark.SequenceEqual(testMark) ||
|
||||
(sector[i + 0xF] != 0x60 && sector[i + 0xF] != 0x61 && sector[i + 0xF] != 0x62))
|
||||
sector[i + 0xF] != 0x60 && sector[i + 0xF] != 0x61 && sector[i + 0xF] != 0x62)
|
||||
continue;
|
||||
|
||||
// De-scramble M and S
|
||||
@@ -103,17 +97,17 @@ partial class Dump
|
||||
int frame = sector[i + 14];
|
||||
|
||||
// Convert to binary
|
||||
minute = (minute / 16 * 10) + (minute & 0x0F);
|
||||
second = (second / 16 * 10) + (second & 0x0F);
|
||||
frame = (frame / 16 * 10) + (frame & 0x0F);
|
||||
minute = minute / 16 * 10 + (minute & 0x0F);
|
||||
second = second / 16 * 10 + (second & 0x0F);
|
||||
frame = frame / 16 * 10 + (frame & 0x0F);
|
||||
|
||||
// Calculate the first found LBA
|
||||
int lba = (minute * 60 * 75) + (second * 75) + frame - 150;
|
||||
int lba = minute * 60 * 75 + second * 75 + frame - 150;
|
||||
|
||||
// Calculate the difference between the found LBA and the requested one
|
||||
int diff = wantedLba - lba;
|
||||
|
||||
offset = i + (2352 * diff);
|
||||
offset = i + 2352 * diff;
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -156,12 +150,12 @@ partial class Dump
|
||||
bool cdiReadyReadAsAudio, int offsetBytes, int sectorsForOffset,
|
||||
Dictionary<byte, int> smallestPregapLbaPerTrack)
|
||||
{
|
||||
ulong sectorSpeedStart = 0; // Used to calculate correct speed
|
||||
bool sense; // Sense indicator
|
||||
byte[] cmdBuf; // Data buffer
|
||||
byte[] senseBuf; // Sense buffer
|
||||
double cmdDuration; // Command execution time
|
||||
const uint sectorSize = 2352; // Full sector size
|
||||
ulong sectorSpeedStart = 0; // Used to calculate correct speed
|
||||
bool sense; // Sense indicator
|
||||
byte[] cmdBuf; // Data buffer
|
||||
byte[] senseBuf; // Sense buffer
|
||||
double cmdDuration; // Command execution time
|
||||
const uint sectorSize = 2352; // Full sector size
|
||||
Track firstTrack = tracks.FirstOrDefault();
|
||||
uint blocksToRead; // How many sectors to read at once
|
||||
var outputOptical = _outputPlugin as IWritableOpticalImage;
|
||||
@@ -190,7 +184,7 @@ partial class Dump
|
||||
break;
|
||||
}
|
||||
|
||||
uint firstSectorToRead = (uint)i;
|
||||
var firstSectorToRead = (uint)i;
|
||||
|
||||
blocksToRead = _maximumReadable;
|
||||
|
||||
@@ -198,6 +192,7 @@ partial class Dump
|
||||
blocksToRead += (uint)sectorsForOffset;
|
||||
|
||||
if(cdiReadyReadAsAudio)
|
||||
{
|
||||
if(offsetBytes < 0)
|
||||
{
|
||||
if(i == 0)
|
||||
@@ -205,6 +200,7 @@ partial class Dump
|
||||
else
|
||||
firstSectorToRead -= (uint)sectorsForOffset;
|
||||
}
|
||||
}
|
||||
|
||||
if(currentSpeed > maxSpeed &&
|
||||
currentSpeed > 0)
|
||||
@@ -215,8 +211,10 @@ partial class Dump
|
||||
minSpeed = currentSpeed;
|
||||
|
||||
UpdateProgress?.
|
||||
Invoke(string.Format(Localization.Core.Reading_sector_0_of_1_2, i, blocks, ByteSize.FromMegabytes(currentSpeed).Per(_oneSecond).Humanize()),
|
||||
(long)i, (long)blocks);
|
||||
Invoke(
|
||||
string.Format(Localization.Core.Reading_sector_0_of_1_2, i, blocks,
|
||||
ByteSize.FromMegabytes(currentSpeed).Per(_oneSecond).Humanize()),
|
||||
(long)i, (long)blocks);
|
||||
|
||||
sense = _dev.ReadCd(out cmdBuf, out senseBuf, firstSectorToRead, blockSize, blocksToRead,
|
||||
MmcSectorTypes.AllTypes, false, false, true, MmcHeaderCodes.AllHeaders, true, true,
|
||||
@@ -228,11 +226,14 @@ partial class Dump
|
||||
|
||||
// Overcome the track mode change drive error
|
||||
if(sense)
|
||||
{
|
||||
for(uint r = 0; r < _maximumReadable; r++)
|
||||
{
|
||||
UpdateProgress?.
|
||||
Invoke(string.Format(Localization.Core.Reading_sector_0_of_1_2, i + r, blocks, ByteSize.FromMegabytes(currentSpeed).Per(_oneSecond).Humanize()),
|
||||
(long)i + r, (long)blocks);
|
||||
Invoke(
|
||||
string.Format(Localization.Core.Reading_sector_0_of_1_2, i + r, blocks,
|
||||
ByteSize.FromMegabytes(currentSpeed).Per(_oneSecond).Humanize()),
|
||||
(long)i + r, (long)blocks);
|
||||
|
||||
sense = _dev.ReadCd(out cmdBuf, out senseBuf, (uint)(i + r), blockSize, (uint)sectorsForOffset + 1,
|
||||
MmcSectorTypes.AllTypes, false, false, true, MmcHeaderCodes.AllHeaders, true,
|
||||
@@ -249,13 +250,15 @@ partial class Dump
|
||||
_writeStopwatch.Restart();
|
||||
|
||||
if(cdiReadyReadAsAudio)
|
||||
FixOffsetData(offsetBytes, sectorSize, sectorsForOffset, supportedSubchannel,
|
||||
ref blocksToRead, subSize, ref cmdBuf, blockSize, false);
|
||||
{
|
||||
FixOffsetData(offsetBytes, sectorSize, sectorsForOffset, supportedSubchannel,
|
||||
ref blocksToRead, subSize, ref cmdBuf, blockSize, false);
|
||||
}
|
||||
|
||||
if(supportedSubchannel != MmcSubchannel.None)
|
||||
{
|
||||
byte[] data = new byte[sectorSize];
|
||||
byte[] sub = new byte[subSize];
|
||||
var data = new byte[sectorSize];
|
||||
var sub = new byte[subSize];
|
||||
|
||||
Array.Copy(cmdBuf, 0, data, 0, sectorSize);
|
||||
|
||||
@@ -318,6 +321,7 @@ partial class Dump
|
||||
sectorSpeedStart = 0;
|
||||
_speedStopwatch.Restart();
|
||||
}
|
||||
}
|
||||
|
||||
_speedStopwatch.Restart();
|
||||
|
||||
@@ -325,8 +329,10 @@ partial class Dump
|
||||
!_dev.Error)
|
||||
{
|
||||
if(cdiReadyReadAsAudio)
|
||||
{
|
||||
FixOffsetData(offsetBytes, sectorSize, sectorsForOffset, supportedSubchannel, ref blocksToRead,
|
||||
subSize, ref cmdBuf, blockSize, false);
|
||||
subSize, ref cmdBuf, blockSize, false);
|
||||
}
|
||||
|
||||
mhddLog.Write(i, cmdDuration);
|
||||
ibgLog.Write(i, currentSpeed * 1024);
|
||||
@@ -335,31 +341,31 @@ partial class Dump
|
||||
|
||||
if(supportedSubchannel != MmcSubchannel.None)
|
||||
{
|
||||
byte[] data = new byte[sectorSize * blocksToRead];
|
||||
byte[] sub = new byte[subSize * blocksToRead];
|
||||
byte[] tmpData = new byte[sectorSize];
|
||||
var data = new byte[sectorSize * blocksToRead];
|
||||
var sub = new byte[subSize * blocksToRead];
|
||||
var tmpData = new byte[sectorSize];
|
||||
|
||||
for(int b = 0; b < blocksToRead; b++)
|
||||
for(var b = 0; b < blocksToRead; b++)
|
||||
{
|
||||
if(cdiReadyReadAsAudio)
|
||||
{
|
||||
Array.Copy(cmdBuf, (int)(0 + (b * blockSize)), tmpData, 0, sectorSize);
|
||||
Array.Copy(cmdBuf, (int)(0 + b * blockSize), tmpData, 0, sectorSize);
|
||||
tmpData = Sector.Scramble(tmpData);
|
||||
Array.Copy(tmpData, 0, data, sectorSize * b, sectorSize);
|
||||
}
|
||||
else
|
||||
Array.Copy(cmdBuf, (int)(0 + (b * blockSize)), data, sectorSize * b, sectorSize);
|
||||
Array.Copy(cmdBuf, (int)(0 + b * blockSize), data, sectorSize * b, sectorSize);
|
||||
|
||||
Array.Copy(cmdBuf, (int)(sectorSize + (b * blockSize)), sub, subSize * b, subSize);
|
||||
Array.Copy(cmdBuf, (int)(sectorSize + b * blockSize), sub, subSize * b, subSize);
|
||||
}
|
||||
|
||||
outputOptical.WriteSectorsLong(data, i, blocksToRead);
|
||||
|
||||
bool indexesChanged = Media.CompactDisc.WriteSubchannelToImage(supportedSubchannel,
|
||||
desiredSubchannel, sub, i, blocksToRead, subLog, isrcs, 1, ref mcn, tracks,
|
||||
subchannelExtents, _fixSubchannelPosition, outputOptical, _fixSubchannel,
|
||||
_fixSubchannelCrc, _dumpLog, UpdateStatus, smallestPregapLbaPerTrack, true,
|
||||
out List<ulong> newPregapSectors);
|
||||
desiredSubchannel, sub, i, blocksToRead, subLog, isrcs, 1, ref mcn, tracks,
|
||||
subchannelExtents, _fixSubchannelPosition, outputOptical, _fixSubchannel,
|
||||
_fixSubchannelCrc, _dumpLog, UpdateStatus, smallestPregapLbaPerTrack, true,
|
||||
out List<ulong> newPregapSectors);
|
||||
|
||||
// Set tracks and go back
|
||||
if(indexesChanged)
|
||||
@@ -384,10 +390,10 @@ partial class Dump
|
||||
{
|
||||
if(cdiReadyReadAsAudio)
|
||||
{
|
||||
byte[] tmpData = new byte[sectorSize];
|
||||
byte[] data = new byte[sectorSize * blocksToRead];
|
||||
var tmpData = new byte[sectorSize];
|
||||
var data = new byte[sectorSize * blocksToRead];
|
||||
|
||||
for(int b = 0; b < blocksToRead; b++)
|
||||
for(var b = 0; b < blocksToRead; b++)
|
||||
{
|
||||
Array.Copy(cmdBuf, (int)(b * sectorSize), tmpData, 0, sectorSize);
|
||||
tmpData = Sector.Scramble(tmpData);
|
||||
|
||||
@@ -100,31 +100,31 @@ partial class Dump
|
||||
Dictionary<byte, string> isrcs, ref string mcn, HashSet<int> subchannelExtents,
|
||||
Dictionary<byte, int> smallestPregapLbaPerTrack)
|
||||
{
|
||||
ulong sectorSpeedStart = 0; // Used to calculate correct speed
|
||||
uint blocksToRead; // How many sectors to read at once
|
||||
bool sense = true; // Sense indicator
|
||||
byte[] cmdBuf = null; // Data buffer
|
||||
byte[] senseBuf = null; // Sense buffer
|
||||
double cmdDuration = 0; // Command execution time
|
||||
const uint sectorSize = 2352; // Full sector size
|
||||
ulong sectorSpeedStart = 0; // Used to calculate correct speed
|
||||
uint blocksToRead; // How many sectors to read at once
|
||||
var sense = true; // Sense indicator
|
||||
byte[] cmdBuf = null; // Data buffer
|
||||
byte[] senseBuf = null; // Sense buffer
|
||||
double cmdDuration = 0; // Command execution time
|
||||
const uint sectorSize = 2352; // Full sector size
|
||||
newTrim = false;
|
||||
PlextorSubchannel supportedPlextorSubchannel;
|
||||
var outputFormat = _outputPlugin as IWritableImage;
|
||||
|
||||
supportedPlextorSubchannel = supportedSubchannel switch
|
||||
{
|
||||
MmcSubchannel.None => PlextorSubchannel.None,
|
||||
MmcSubchannel.Raw => PlextorSubchannel.Pack,
|
||||
MmcSubchannel.Q16 => PlextorSubchannel.Q16,
|
||||
_ => PlextorSubchannel.None
|
||||
};
|
||||
{
|
||||
MmcSubchannel.None => PlextorSubchannel.None,
|
||||
MmcSubchannel.Raw => PlextorSubchannel.Pack,
|
||||
MmcSubchannel.Q16 => PlextorSubchannel.Q16,
|
||||
_ => PlextorSubchannel.None
|
||||
};
|
||||
|
||||
InitProgress?.Invoke();
|
||||
|
||||
int currentReadSpeed = _speed;
|
||||
bool crossingLeadOut = false;
|
||||
bool failedCrossingLeadOut = false;
|
||||
bool skippingLead = false;
|
||||
int currentReadSpeed = _speed;
|
||||
var crossingLeadOut = false;
|
||||
var failedCrossingLeadOut = false;
|
||||
var skippingLead = false;
|
||||
|
||||
for(ulong i = _resume.NextBlock; (long)i <= lastSector; i += blocksToRead)
|
||||
{
|
||||
@@ -148,7 +148,7 @@ partial class Dump
|
||||
if((long)i > lastSector)
|
||||
break;
|
||||
|
||||
uint firstSectorToRead = (uint)i;
|
||||
var firstSectorToRead = (uint)i;
|
||||
|
||||
Track track = tracks.OrderBy(t => t.StartSector).LastOrDefault(t => i >= t.StartSector);
|
||||
|
||||
@@ -213,6 +213,7 @@ partial class Dump
|
||||
}
|
||||
|
||||
if(_fixOffset && !inData)
|
||||
{
|
||||
if(offsetBytes < 0)
|
||||
{
|
||||
if(i == 0)
|
||||
@@ -223,6 +224,7 @@ partial class Dump
|
||||
if(blocksToRead <= sectorsForOffset)
|
||||
blocksToRead += (uint)sectorsForOffset;
|
||||
}
|
||||
}
|
||||
|
||||
switch(inData)
|
||||
{
|
||||
@@ -237,11 +239,13 @@ partial class Dump
|
||||
break;
|
||||
case true when currentReadSpeed != _speed:
|
||||
{
|
||||
_dumpLog.WriteLine(_speed == 0xFFFF ? Localization.Core.Setting_speed_to_MAX_for_data_reading
|
||||
_dumpLog.WriteLine(_speed == 0xFFFF
|
||||
? Localization.Core.Setting_speed_to_MAX_for_data_reading
|
||||
: string.Format(Localization.Core.Setting_speed_to_0_x_for_data_reading,
|
||||
_speed));
|
||||
|
||||
UpdateStatus?.Invoke(_speed == 0xFFFF ? Localization.Core.Setting_speed_to_MAX_for_data_reading
|
||||
UpdateStatus?.Invoke(_speed == 0xFFFF
|
||||
? Localization.Core.Setting_speed_to_MAX_for_data_reading
|
||||
: string.Format(Localization.Core.Setting_speed_to_0_x_for_data_reading,
|
||||
_speed));
|
||||
|
||||
@@ -274,8 +278,10 @@ partial class Dump
|
||||
minSpeed = currentSpeed;
|
||||
|
||||
UpdateProgress?.
|
||||
Invoke(string.Format(Localization.Core.Reading_sector_0_of_1_2, i, blocks, ByteSize.FromMegabytes(currentSpeed).Per(_oneSecond).Humanize()),
|
||||
(long)i, (long)blocks);
|
||||
Invoke(
|
||||
string.Format(Localization.Core.Reading_sector_0_of_1_2, i, blocks,
|
||||
ByteSize.FromMegabytes(currentSpeed).Per(_oneSecond).Humanize()),
|
||||
(long)i, (long)blocks);
|
||||
|
||||
if(crossingLeadOut &&
|
||||
failedCrossingLeadOut &&
|
||||
@@ -304,10 +310,10 @@ partial class Dump
|
||||
// Try to workaround firmware
|
||||
if(decSense?.ASC == 0x64)
|
||||
{
|
||||
bool goBackTrackTypeChange = false;
|
||||
var goBackTrackTypeChange = false;
|
||||
|
||||
// Go one for one as the drive does not tell us which one failed
|
||||
for(int bi = 0; bi < blocksToRead; bi++)
|
||||
for(var bi = 0; bi < blocksToRead; bi++)
|
||||
{
|
||||
sense = _dev.ReadCd(out cmdBuf, out senseBuf, (uint)(firstSectorToRead + bi), blockSize,
|
||||
1, MmcSectorTypes.AllTypes, false, false, true,
|
||||
@@ -360,6 +366,7 @@ partial class Dump
|
||||
if(sense)
|
||||
|
||||
// Try reading one less every time
|
||||
{
|
||||
for(uint bi = blocksToRead; bi > 0; bi--)
|
||||
{
|
||||
sense = _dev.ReadCd(out cmdBuf, out senseBuf, firstSectorToRead, blockSize, bi,
|
||||
@@ -374,6 +381,7 @@ partial class Dump
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -404,17 +412,25 @@ partial class Dump
|
||||
totalDuration += cmdDuration;
|
||||
}
|
||||
else if(read16)
|
||||
{
|
||||
sense = _dev.Read16(out cmdBuf, out senseBuf, 0, false, false, false, firstSectorToRead, blockSize, 0,
|
||||
blocksToRead, false, _dev.Timeout, out cmdDuration);
|
||||
}
|
||||
else if(read12)
|
||||
{
|
||||
sense = _dev.Read12(out cmdBuf, out senseBuf, 0, false, false, false, false, firstSectorToRead,
|
||||
blockSize, 0, blocksToRead, false, _dev.Timeout, out cmdDuration);
|
||||
}
|
||||
else if(read10)
|
||||
{
|
||||
sense = _dev.Read10(out cmdBuf, out senseBuf, 0, false, false, 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);
|
||||
}
|
||||
|
||||
double elapsed;
|
||||
|
||||
@@ -428,12 +444,14 @@ partial class Dump
|
||||
for(uint r = 0; r < blocksToRead; r++)
|
||||
{
|
||||
UpdateProgress?.
|
||||
Invoke(string.Format(Localization.Core.Reading_sector_0_of_1_2, i + r, blocks, ByteSize.FromMegabytes(currentSpeed).Per(_oneSecond).Humanize()),
|
||||
(long)i + r, (long)blocks);
|
||||
Invoke(
|
||||
string.Format(Localization.Core.Reading_sector_0_of_1_2, i + r, blocks,
|
||||
ByteSize.FromMegabytes(currentSpeed).Per(_oneSecond).Humanize()),
|
||||
(long)i + r, (long)blocks);
|
||||
|
||||
if(_supportsPlextorD8)
|
||||
{
|
||||
int adjustment = 0;
|
||||
var adjustment = 0;
|
||||
|
||||
if(offsetBytes < 0)
|
||||
adjustment = -sectorsForOffset;
|
||||
@@ -447,10 +465,10 @@ partial class Dump
|
||||
|
||||
if(!sense)
|
||||
{
|
||||
uint sectorsForFix = (uint)(1 + sectorsForOffset);
|
||||
var sectorsForFix = (uint)(1 + sectorsForOffset);
|
||||
|
||||
FixOffsetData(offsetBytes, sectorSize, sectorsForOffset, supportedSubchannel,
|
||||
ref sectorsForFix, subSize, ref cmdBuf, blockSize, false);
|
||||
FixOffsetData(offsetBytes, sectorSize, sectorsForOffset, supportedSubchannel,
|
||||
ref sectorsForFix, subSize, ref cmdBuf, blockSize, false);
|
||||
|
||||
// TODO: Implement sector validity
|
||||
cmdBuf = Sector.Scramble(cmdBuf);
|
||||
@@ -466,17 +484,25 @@ partial class Dump
|
||||
totalDuration += cmdDuration;
|
||||
}
|
||||
else if(read16)
|
||||
{
|
||||
sense = _dev.Read16(out cmdBuf, out senseBuf, 0, false, true, false, i + r, blockSize, 0, 1,
|
||||
false, _dev.Timeout, out cmdDuration);
|
||||
}
|
||||
else if(read12)
|
||||
{
|
||||
sense = _dev.Read12(out cmdBuf, out senseBuf, 0, false, true, false, false, (uint)(i + r),
|
||||
blockSize, 0, 1, false, _dev.Timeout, out cmdDuration);
|
||||
}
|
||||
else if(read10)
|
||||
{
|
||||
sense = _dev.Read10(out cmdBuf, out senseBuf, 0, false, true, false, false, (uint)(i + r),
|
||||
blockSize, 0, 1, _dev.Timeout, out cmdDuration);
|
||||
}
|
||||
else if(read6)
|
||||
{
|
||||
sense = _dev.Read6(out cmdBuf, out senseBuf, (uint)(i + r), blockSize, 1, _dev.Timeout,
|
||||
out cmdDuration);
|
||||
}
|
||||
|
||||
if(!sense &&
|
||||
!_dev.Error)
|
||||
@@ -488,8 +514,8 @@ partial class Dump
|
||||
|
||||
if(supportedSubchannel != MmcSubchannel.None)
|
||||
{
|
||||
byte[] data = new byte[sectorSize];
|
||||
byte[] sub = new byte[subSize];
|
||||
var data = new byte[sectorSize];
|
||||
var sub = new byte[subSize];
|
||||
|
||||
Array.Copy(cmdBuf, 0, data, 0, sectorSize);
|
||||
|
||||
@@ -499,12 +525,12 @@ partial class Dump
|
||||
outputFormat.WriteSectorsLong(data, i + r, 1);
|
||||
else
|
||||
{
|
||||
var cooked = new MemoryStream();
|
||||
byte[] sector = new byte[sectorSize];
|
||||
var cooked = new MemoryStream();
|
||||
var sector = new byte[sectorSize];
|
||||
|
||||
for(int b = 0; b < blocksToRead; b++)
|
||||
for(var b = 0; b < blocksToRead; b++)
|
||||
{
|
||||
Array.Copy(cmdBuf, (int)(0 + (b * blockSize)), sector, 0, sectorSize);
|
||||
Array.Copy(cmdBuf, (int)(0 + b * blockSize), sector, 0, sectorSize);
|
||||
byte[] cookedSector = Sector.GetUserData(sector);
|
||||
cooked.Write(cookedSector, 0, cookedSector.Length);
|
||||
}
|
||||
@@ -546,10 +572,10 @@ partial class Dump
|
||||
outputFormat.WriteSectorsLong(cmdBuf, i + r, 1);
|
||||
else
|
||||
{
|
||||
var cooked = new MemoryStream();
|
||||
byte[] sector = new byte[sectorSize];
|
||||
var cooked = new MemoryStream();
|
||||
var sector = new byte[sectorSize];
|
||||
|
||||
for(int b = 0; b < blocksToRead; b++)
|
||||
for(var b = 0; b < blocksToRead; b++)
|
||||
{
|
||||
Array.Copy(cmdBuf, (int)(b * sectorSize), sector, 0, sectorSize);
|
||||
byte[] cookedSector = Sector.GetUserData(sector);
|
||||
@@ -576,8 +602,10 @@ partial class Dump
|
||||
outputFormat.WriteSectorsLong(new byte[sectorSize], i + r, 1);
|
||||
|
||||
if(desiredSubchannel != MmcSubchannel.None)
|
||||
{
|
||||
outputFormat.WriteSectorsTag(new byte[subSize], i + r, 1,
|
||||
SectorTagType.CdSectorSubchannel);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -632,7 +660,7 @@ partial class Dump
|
||||
{
|
||||
if(crossingLeadOut && failedCrossingLeadOut)
|
||||
{
|
||||
byte[] tmp = new byte[cmdBuf.Length + blockSize];
|
||||
var tmp = new byte[cmdBuf.Length + blockSize];
|
||||
Array.Copy(cmdBuf, 0, tmp, 0, cmdBuf.Length);
|
||||
}
|
||||
|
||||
@@ -640,8 +668,10 @@ partial class Dump
|
||||
if(_fixOffset &&
|
||||
!inData &&
|
||||
offsetBytes != 0)
|
||||
{
|
||||
FixOffsetData(offsetBytes, sectorSize, sectorsForOffset, supportedSubchannel, ref blocksToRead,
|
||||
subSize, ref cmdBuf, blockSize, failedCrossingLeadOut);
|
||||
subSize, ref cmdBuf, blockSize, failedCrossingLeadOut);
|
||||
}
|
||||
|
||||
mhddLog.Write(i, cmdDuration, blocksToRead);
|
||||
ibgLog.Write(i, currentSpeed * 1024);
|
||||
@@ -650,26 +680,26 @@ partial class Dump
|
||||
|
||||
if(supportedSubchannel != MmcSubchannel.None)
|
||||
{
|
||||
byte[] data = new byte[sectorSize * blocksToRead];
|
||||
byte[] sub = new byte[subSize * blocksToRead];
|
||||
var data = new byte[sectorSize * blocksToRead];
|
||||
var sub = new byte[subSize * blocksToRead];
|
||||
|
||||
for(int b = 0; b < blocksToRead; b++)
|
||||
for(var b = 0; b < blocksToRead; b++)
|
||||
{
|
||||
Array.Copy(cmdBuf, (int)(0 + (b * blockSize)), data, sectorSize * b, sectorSize);
|
||||
Array.Copy(cmdBuf, (int)(0 + b * blockSize), data, sectorSize * b, sectorSize);
|
||||
|
||||
Array.Copy(cmdBuf, (int)(sectorSize + (b * blockSize)), sub, subSize * b, subSize);
|
||||
Array.Copy(cmdBuf, (int)(sectorSize + b * blockSize), sub, subSize * b, subSize);
|
||||
}
|
||||
|
||||
if(supportsLongSectors)
|
||||
outputFormat.WriteSectorsLong(data, i, blocksToRead);
|
||||
else
|
||||
{
|
||||
var cooked = new MemoryStream();
|
||||
byte[] sector = new byte[sectorSize];
|
||||
var cooked = new MemoryStream();
|
||||
var sector = new byte[sectorSize];
|
||||
|
||||
for(int b = 0; b < blocksToRead; b++)
|
||||
for(var b = 0; b < blocksToRead; b++)
|
||||
{
|
||||
Array.Copy(cmdBuf, (int)(0 + (b * blockSize)), sector, 0, sectorSize);
|
||||
Array.Copy(cmdBuf, (int)(0 + b * blockSize), sector, 0, sectorSize);
|
||||
byte[] cookedSector = Sector.GetUserData(sector);
|
||||
cooked.Write(cookedSector, 0, cookedSector.Length);
|
||||
}
|
||||
@@ -678,10 +708,10 @@ partial class Dump
|
||||
}
|
||||
|
||||
bool indexesChanged = Media.CompactDisc.WriteSubchannelToImage(supportedSubchannel,
|
||||
desiredSubchannel, sub, i, blocksToRead, subLog, isrcs, (byte)track.Sequence, ref mcn,
|
||||
tracks, subchannelExtents, _fixSubchannelPosition, outputFormat as IWritableOpticalImage,
|
||||
_fixSubchannel, _fixSubchannelCrc, _dumpLog, UpdateStatus, smallestPregapLbaPerTrack, true,
|
||||
out List<ulong> newPregapSectors);
|
||||
desiredSubchannel, sub, i, blocksToRead, subLog, isrcs, (byte)track.Sequence, ref mcn,
|
||||
tracks, subchannelExtents, _fixSubchannelPosition, outputFormat as IWritableOpticalImage,
|
||||
_fixSubchannel, _fixSubchannelCrc, _dumpLog, UpdateStatus, smallestPregapLbaPerTrack, true,
|
||||
out List<ulong> newPregapSectors);
|
||||
|
||||
// Set tracks and go back
|
||||
if(indexesChanged)
|
||||
@@ -711,10 +741,10 @@ partial class Dump
|
||||
outputFormat.WriteSectorsLong(cmdBuf, i, blocksToRead);
|
||||
else
|
||||
{
|
||||
var cooked = new MemoryStream();
|
||||
byte[] sector = new byte[sectorSize];
|
||||
var cooked = new MemoryStream();
|
||||
var sector = new byte[sectorSize];
|
||||
|
||||
for(int b = 0; b < blocksToRead; b++)
|
||||
for(var b = 0; b < blocksToRead; b++)
|
||||
{
|
||||
Array.Copy(cmdBuf, (int)(b * sectorSize), sector, 0, sectorSize);
|
||||
byte[] cookedSector = Sector.GetUserData(sector);
|
||||
@@ -759,8 +789,10 @@ partial class Dump
|
||||
outputFormat.WriteSectorsLong(new byte[sectorSize * _skip], i, _skip);
|
||||
|
||||
if(desiredSubchannel != MmcSubchannel.None)
|
||||
{
|
||||
outputFormat.WriteSectorsTag(new byte[subSize * _skip], i, _skip,
|
||||
SectorTagType.CdSectorSubchannel);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -86,21 +86,21 @@ sealed partial class Dump
|
||||
MhddLog mhddLog; // MHDD log
|
||||
double minSpeed = double.MaxValue; // Minimum speed
|
||||
bool newTrim; // Is trim a new one?
|
||||
int offsetBytes = 0; // Read offset
|
||||
bool read6 = false; // Device supports READ(6)
|
||||
bool read10 = false; // Device supports READ(10)
|
||||
bool read12 = false; // Device supports READ(12)
|
||||
bool read16 = false; // Device supports READ(16)
|
||||
bool readcd = true; // Device supports READ CD
|
||||
var offsetBytes = 0; // Read offset
|
||||
var read6 = false; // Device supports READ(6)
|
||||
var read10 = false; // Device supports READ(10)
|
||||
var read12 = false; // Device supports READ(12)
|
||||
var read16 = false; // Device supports READ(16)
|
||||
var readcd = true; // Device supports READ CD
|
||||
bool ret; // Image writing return status
|
||||
const uint sectorSize = 2352; // Full sector size
|
||||
int sectorsForOffset = 0; // Sectors needed to fix offset
|
||||
bool sense = true; // Sense indicator
|
||||
var sectorsForOffset = 0; // Sectors needed to fix offset
|
||||
var sense = true; // Sense indicator
|
||||
int sessions; // Number of sessions in disc
|
||||
SubchannelLog subLog = null; // Subchannel log
|
||||
uint subSize = 0; // Subchannel size in bytes
|
||||
TrackSubchannelType subType = TrackSubchannelType.None; // Track subchannel type
|
||||
bool supportsLongSectors = true; // Supports reading EDC and ECC
|
||||
var supportsLongSectors = true; // Supports reading EDC and ECC
|
||||
bool supportsPqSubchannel; // Supports reading PQ subchannel
|
||||
bool supportsRwSubchannel; // Supports reading RW subchannel
|
||||
byte[] tmpBuf; // Temporary buffer
|
||||
@@ -112,11 +112,11 @@ sealed partial class Dump
|
||||
bool hiddenTrack; // Disc has a hidden track before track 1
|
||||
MmcSubchannel supportedSubchannel; // Drive's maximum supported subchannel
|
||||
MmcSubchannel desiredSubchannel; // User requested subchannel
|
||||
bool bcdSubchannel = false; // Subchannel positioning is in BCD
|
||||
var bcdSubchannel = false; // Subchannel positioning is in BCD
|
||||
Dictionary<byte, string> isrcs = new();
|
||||
string mcn = null;
|
||||
HashSet<int> subchannelExtents = new();
|
||||
bool cdiReadyReadAsAudio = false;
|
||||
var cdiReadyReadAsAudio = false;
|
||||
uint firstLba;
|
||||
var outputOptical = _outputPlugin as IWritableOpticalImage;
|
||||
|
||||
@@ -133,7 +133,7 @@ sealed partial class Dump
|
||||
return;
|
||||
}
|
||||
|
||||
tracks = GetCdTracks(_dev, _dumpLog, _force, out lastSector, leadOutStarts, mediaTags, StoppingErrorMessage,
|
||||
tracks = GetCdTracks(_dev, _dumpLog, _force, out lastSector, leadOutStarts, mediaTags, StoppingErrorMessage,
|
||||
out toc, trackFlags, UpdateStatus);
|
||||
|
||||
if(tracks is null)
|
||||
@@ -219,7 +219,8 @@ sealed partial class Dump
|
||||
desiredSubchannel = MmcSubchannel.None;
|
||||
|
||||
break;
|
||||
default: throw new ArgumentOutOfRangeException();
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
|
||||
if(desiredSubchannel == MmcSubchannel.Q16 && supportsPqSubchannel)
|
||||
@@ -361,7 +362,7 @@ sealed partial class Dump
|
||||
// Check if subchannel is BCD
|
||||
if(supportedSubchannel != MmcSubchannel.None)
|
||||
{
|
||||
sense = _dev.ReadCd(out cmdBuf, out _, (((firstLba / 75) + 1) * 75) + 35, blockSize, 1,
|
||||
sense = _dev.ReadCd(out cmdBuf, out _, (firstLba / 75 + 1) * 75 + 35, blockSize, 1,
|
||||
MmcSectorTypes.AllTypes, false, false, true, MmcHeaderCodes.AllHeaders, true, true,
|
||||
MmcErrorField.None, supportedSubchannel, _dev.Timeout, out _);
|
||||
|
||||
@@ -454,7 +455,7 @@ sealed partial class Dump
|
||||
ErrorMessage?.Invoke(Localization.Core.Output_format_does_not_support_pregaps_continuing);
|
||||
}
|
||||
|
||||
for(int t = 1; t < tracks.Length; t++)
|
||||
for(var t = 1; t < tracks.Length; t++)
|
||||
tracks[t - 1].EndSector = tracks[t].StartSector - 1;
|
||||
|
||||
tracks[^1].EndSector = (ulong)lastSector;
|
||||
@@ -502,6 +503,7 @@ sealed partial class Dump
|
||||
|
||||
// Check if output format supports all disc tags we have retrieved so far
|
||||
foreach(MediaTagType tag in mediaTags.Keys.Where(tag => !outputOptical.SupportedMediaTags.Contains(tag)))
|
||||
{
|
||||
if(_force)
|
||||
{
|
||||
_dumpLog.WriteLine(Localization.Core.Output_format_does_not_support_0_continuing, tag);
|
||||
@@ -516,15 +518,16 @@ sealed partial class Dump
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(leadOutStarts.Any())
|
||||
{
|
||||
UpdateStatus?.Invoke(Localization.Core.Solving_lead_outs);
|
||||
|
||||
foreach(KeyValuePair<int, long> leadOuts in leadOutStarts)
|
||||
foreach(Track trk in tracks.Where(trk => trk.Session == leadOuts.Key).
|
||||
Where(trk => trk.EndSector >= (ulong)leadOuts.Value))
|
||||
trk.EndSector = (ulong)leadOuts.Value - 1;
|
||||
foreach(Track trk in tracks.Where(trk => trk.Session == leadOuts.Key).
|
||||
Where(trk => trk.EndSector >= (ulong)leadOuts.Value))
|
||||
trk.EndSector = (ulong)leadOuts.Value - 1;
|
||||
|
||||
var dataExtents = new ExtentsULong();
|
||||
|
||||
@@ -533,7 +536,7 @@ sealed partial class Dump
|
||||
|
||||
Tuple<ulong, ulong>[] dataExtentsArray = dataExtents.ToArray();
|
||||
|
||||
for(int i = 0; i < dataExtentsArray.Length - 1; i++)
|
||||
for(var i = 0; i < dataExtentsArray.Length - 1; i++)
|
||||
leadOutExtents.Add(dataExtentsArray[i].Item2 + 1, dataExtentsArray[i + 1].Item1 - 1);
|
||||
}
|
||||
|
||||
@@ -610,7 +613,7 @@ sealed partial class Dump
|
||||
continue;
|
||||
}
|
||||
|
||||
int bufOffset = 0;
|
||||
var bufOffset = 0;
|
||||
|
||||
while(cmdBuf[0 + bufOffset] != 0x00 ||
|
||||
cmdBuf[1 + bufOffset] != 0xFF ||
|
||||
@@ -716,6 +719,7 @@ sealed partial class Dump
|
||||
|
||||
// Check if something prevents from dumping the first track pregap
|
||||
if(_dumpFirstTrackPregap && readcd)
|
||||
{
|
||||
if(!outputOptical.SupportedMediaTags.Contains(MediaTagType.CD_FirstTrackPregap))
|
||||
{
|
||||
if(_force)
|
||||
@@ -739,6 +743,7 @@ sealed partial class Dump
|
||||
|
||||
_dumpFirstTrackPregap = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Try how many blocks are readable at once
|
||||
while(true)
|
||||
@@ -798,7 +803,7 @@ sealed partial class Dump
|
||||
_dev.LastError));
|
||||
}
|
||||
|
||||
bool cdiWithHiddenTrack1 = false;
|
||||
var cdiWithHiddenTrack1 = false;
|
||||
|
||||
if(dskType is MediaType.CDIREADY &&
|
||||
tracks.Min(t => t.Sequence) == 1)
|
||||
@@ -811,12 +816,12 @@ sealed partial class Dump
|
||||
if(_dumpFirstTrackPregap && readcd)
|
||||
ReadCdFirstTrackPregap(blockSize, ref currentSpeed, mediaTags, supportedSubchannel, ref totalDuration);
|
||||
|
||||
_dumpLog.WriteLine(Localization.Core.Reading_0_sectors_at_a_time, _maximumReadable);
|
||||
_dumpLog.WriteLine(Localization.Core.Device_reports_0_blocks_1_bytes, blocks, blocks * blockSize);
|
||||
_dumpLog.WriteLine(Localization.Core.Device_can_read_0_blocks_at_a_time, _maximumReadable);
|
||||
_dumpLog.WriteLine(Localization.Core.Reading_0_sectors_at_a_time, _maximumReadable);
|
||||
_dumpLog.WriteLine(Localization.Core.Device_reports_0_blocks_1_bytes, blocks, blocks * blockSize);
|
||||
_dumpLog.WriteLine(Localization.Core.Device_can_read_0_blocks_at_a_time, _maximumReadable);
|
||||
_dumpLog.WriteLine(Localization.Core.Device_reports_0_bytes_per_logical_block, blockSize);
|
||||
_dumpLog.WriteLine(Localization.Core.SCSI_device_type_0, _dev.ScsiType);
|
||||
_dumpLog.WriteLine(Localization.Core.Media_identified_as_0, dskType);
|
||||
_dumpLog.WriteLine(Localization.Core.SCSI_device_type_0, _dev.ScsiType);
|
||||
_dumpLog.WriteLine(Localization.Core.Media_identified_as_0, dskType);
|
||||
|
||||
UpdateStatus?.Invoke(string.Format(Localization.Core.Reading_0_sectors_at_a_time, _maximumReadable));
|
||||
|
||||
@@ -849,6 +854,7 @@ sealed partial class Dump
|
||||
mcn = Encoding.ASCII.GetString(mcnBytes);
|
||||
|
||||
if(outputOptical.Tracks != null)
|
||||
{
|
||||
foreach(Track imgTrack in outputOptical.Tracks)
|
||||
{
|
||||
errno = outputOptical.ReadSectorTag(imgTrack.Sequence, SectorTagType.CdTrackIsrc, out byte[] isrcBytes);
|
||||
@@ -868,6 +874,7 @@ sealed partial class Dump
|
||||
foreach(KeyValuePair<ushort, int> imgIdx in imgTrack.Indexes)
|
||||
trk.Indexes[imgIdx.Key] = imgIdx.Value;
|
||||
}
|
||||
}
|
||||
|
||||
// Send track list to output plugin. This may fail if subchannel is set but unsupported.
|
||||
ret = outputOptical.SetTracks(tracks.ToList());
|
||||
@@ -923,10 +930,7 @@ sealed partial class Dump
|
||||
_dumpLog.WriteLine(Localization.Core.Setting_flags_for_track_0, track.Sequence);
|
||||
UpdateStatus?.Invoke(string.Format(Localization.Core.Setting_flags_for_track_0, track.Sequence));
|
||||
|
||||
outputOptical.WriteSectorTag(new[]
|
||||
{
|
||||
kvp.Value
|
||||
}, kvp.Key, SectorTagType.CdTrackFlags);
|
||||
outputOptical.WriteSectorTag(new[] { kvp.Value }, kvp.Key, SectorTagType.CdTrackFlags);
|
||||
}
|
||||
|
||||
// Set MCN
|
||||
@@ -947,6 +951,7 @@ sealed partial class Dump
|
||||
|
||||
// Set ISRCs
|
||||
if(supportedSubchannel == MmcSubchannel.None)
|
||||
{
|
||||
foreach(Track trk in tracks)
|
||||
{
|
||||
sense = _dev.ReadIsrc((byte)trk.Sequence, out string isrc, out _, out _, _dev.Timeout, out _);
|
||||
@@ -957,8 +962,9 @@ sealed partial class Dump
|
||||
isrcs[(byte)trk.Sequence] = isrc;
|
||||
|
||||
UpdateStatus?.Invoke(string.Format(Localization.Core.Found_ISRC_for_track_0_1, trk.Sequence, isrc));
|
||||
_dumpLog.WriteLine(string.Format(Localization.Core.Found_ISRC_for_track_0_1, trk.Sequence, isrc));
|
||||
_dumpLog.WriteLine(string.Format(Localization.Core.Found_ISRC_for_track_0_1, trk.Sequence, isrc));
|
||||
}
|
||||
}
|
||||
|
||||
if(supportedSubchannel != MmcSubchannel.None &&
|
||||
desiredSubchannel != MmcSubchannel.None)
|
||||
@@ -971,8 +977,10 @@ sealed partial class Dump
|
||||
subchannelExtents.Add(sub);
|
||||
|
||||
if(_resume.NextBlock < blocks)
|
||||
{
|
||||
for(ulong i = _resume.NextBlock; i < blocks; i++)
|
||||
subchannelExtents.Add((int)i);
|
||||
}
|
||||
}
|
||||
|
||||
if(_resume.NextBlock > 0)
|
||||
@@ -986,8 +994,10 @@ sealed partial class Dump
|
||||
|
||||
#if DEBUG
|
||||
foreach(Track trk in tracks)
|
||||
{
|
||||
UpdateStatus?.Invoke(string.Format(Localization.Core.Track_0_starts_at_LBA_1_and_ends_at_LBA_2,
|
||||
trk.Sequence, trk.StartSector, trk.EndSector));
|
||||
}
|
||||
#endif
|
||||
|
||||
// Check offset
|
||||
@@ -1135,8 +1145,10 @@ sealed partial class Dump
|
||||
_mediaGraph = new BlockMap((int)_dimensions, (int)_dimensions, blocks);
|
||||
|
||||
if(_mediaGraph is not null)
|
||||
{
|
||||
foreach(Tuple<ulong, ulong> e in extents.ToArray())
|
||||
_mediaGraph?.PaintSectorsGood(e.Item1, (uint)(e.Item2 - e.Item1 + 2));
|
||||
}
|
||||
|
||||
_mediaGraph?.PaintSectorsBad(_resume.BadBlocks);
|
||||
}
|
||||
@@ -1149,10 +1161,12 @@ sealed partial class Dump
|
||||
// Set speed
|
||||
if(_speedMultiplier >= 0)
|
||||
{
|
||||
_dumpLog.WriteLine(_speed == 0xFFFF ? Localization.Core.Setting_speed_to_MAX_for_data_reading
|
||||
_dumpLog.WriteLine(_speed == 0xFFFF
|
||||
? Localization.Core.Setting_speed_to_MAX_for_data_reading
|
||||
: string.Format(Localization.Core.Setting_speed_to_0_x_for_data_reading, _speed));
|
||||
|
||||
UpdateStatus?.Invoke(_speed == 0xFFFF ? Localization.Core.Setting_speed_to_MAX_for_data_reading
|
||||
UpdateStatus?.Invoke(_speed == 0xFFFF
|
||||
? Localization.Core.Setting_speed_to_MAX_for_data_reading
|
||||
: string.Format(Localization.Core.Setting_speed_to_0_x_for_data_reading, _speed));
|
||||
|
||||
_speed *= _speedMultiplier;
|
||||
@@ -1266,10 +1280,12 @@ sealed partial class Dump
|
||||
}
|
||||
|
||||
if(_skipCdireadyHole)
|
||||
{
|
||||
ReadCdiReady(blockSize, ref currentSpeed, currentTry, extents, ibgLog, ref imageWriteDuration,
|
||||
leadOutExtents, ref maxSpeed, mhddLog, ref minSpeed, subSize, supportedSubchannel,
|
||||
ref totalDuration, tracks, subLog, desiredSubchannel, isrcs, ref mcn, subchannelExtents,
|
||||
blocks, cdiReadyReadAsAudio, offsetBytes, sectorsForOffset, smallestPregapLbaPerTrack);
|
||||
}
|
||||
}
|
||||
|
||||
ReadCdData(audioExtents, blocks, blockSize, ref currentSpeed, currentTry, extents, ibgLog,
|
||||
@@ -1314,33 +1330,40 @@ sealed partial class Dump
|
||||
ByteSize.FromBytes(blockSize * (blocks + 1)).
|
||||
Per(imageWriteDuration.Seconds())));
|
||||
|
||||
TrimCdUserData(audioExtents, blockSize, currentTry, extents, newTrim, offsetBytes, read6, read10, read12,
|
||||
read16, readcd, sectorsForOffset, subSize, supportedSubchannel, supportsLongSectors,
|
||||
TrimCdUserData(audioExtents, blockSize, currentTry, extents, newTrim, offsetBytes, read6, read10, read12,
|
||||
read16, readcd, sectorsForOffset, subSize, supportedSubchannel, supportsLongSectors,
|
||||
ref totalDuration, subLog, desiredSubchannel, tracks, isrcs, ref mcn, subchannelExtents,
|
||||
smallestPregapLbaPerTrack);
|
||||
|
||||
if(dskType is MediaType.CDR or MediaType.CDRW &&
|
||||
_resume.BadBlocks.Count > 0 &&
|
||||
_ignoreCdrRunOuts > 0)
|
||||
{
|
||||
HandleCdrRunOutSectors(blocks, desiredSubchannel, extents, subchannelExtents, subLog, supportsLongSectors,
|
||||
trackFlags, tracks);
|
||||
}
|
||||
|
||||
RetryCdUserData(audioExtents, blockSize, currentTry, extents, offsetBytes, readcd, sectorsForOffset, subSize,
|
||||
supportedSubchannel, ref totalDuration, subLog, desiredSubchannel, tracks, isrcs, ref mcn,
|
||||
subchannelExtents, smallestPregapLbaPerTrack, supportsLongSectors);
|
||||
|
||||
foreach(Tuple<ulong, ulong> leadoutExtent in leadOutExtents.ToArray())
|
||||
{
|
||||
for(ulong e = leadoutExtent.Item1; e <= leadoutExtent.Item2; e++)
|
||||
subchannelExtents.Remove((int)e);
|
||||
}
|
||||
|
||||
if(subchannelExtents.Count > 0 &&
|
||||
_retryPasses > 0 &&
|
||||
_retrySubchannel)
|
||||
{
|
||||
RetrySubchannel(readcd, subSize, supportedSubchannel, ref totalDuration, subLog, desiredSubchannel, tracks,
|
||||
isrcs, ref mcn, subchannelExtents, smallestPregapLbaPerTrack);
|
||||
isrcs, ref mcn, subchannelExtents, smallestPregapLbaPerTrack);
|
||||
}
|
||||
|
||||
// Write media tags to image
|
||||
if(!_aborted)
|
||||
{
|
||||
foreach(KeyValuePair<MediaTagType, byte[]> tag in mediaTags)
|
||||
{
|
||||
if(tag.Value is null)
|
||||
@@ -1361,6 +1384,7 @@ sealed partial class Dump
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
_resume.BadBlocks.Sort();
|
||||
|
||||
@@ -1376,8 +1400,10 @@ sealed partial class Dump
|
||||
if(_generateSubchannels &&
|
||||
outputOptical.SupportedSectorTags.Contains(SectorTagType.CdSectorSubchannel) &&
|
||||
!_aborted)
|
||||
{
|
||||
Media.CompactDisc.GenerateSubchannels(subchannelExtents, tracks, trackFlags, blocks, subLog, _dumpLog,
|
||||
InitProgress, UpdateProgress, EndProgress, outputOptical);
|
||||
}
|
||||
|
||||
// TODO: Disc ID
|
||||
var metadata = new CommonTypes.Structs.ImageInfo
|
||||
@@ -1387,8 +1413,10 @@ sealed partial class Dump
|
||||
};
|
||||
|
||||
if(!outputOptical.SetImageInfo(metadata))
|
||||
{
|
||||
ErrorMessage?.Invoke(Localization.Core.Error_0_setting_metadata + Environment.NewLine +
|
||||
outputOptical.ErrorMessage);
|
||||
}
|
||||
|
||||
outputOptical.SetDumpHardware(_resume.Tries);
|
||||
|
||||
@@ -1455,31 +1483,38 @@ sealed partial class Dump
|
||||
double totalChkDuration = 0;
|
||||
|
||||
if(_metadata)
|
||||
{
|
||||
WriteOpticalSidecar(blockSize, blocks, dskType, null, mediaTags, sessions, out totalChkDuration,
|
||||
discOffset);
|
||||
}
|
||||
|
||||
_dumpStopwatch.Stop();
|
||||
UpdateStatus?.Invoke("");
|
||||
|
||||
UpdateStatus?.
|
||||
Invoke(string.Format(Localization.Core.Took_a_total_of_0_1_processing_commands_2_checksumming_3_writing_4_closing,
|
||||
_dumpStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second),
|
||||
totalDuration.Milliseconds().Humanize(minUnit: TimeUnit.Second),
|
||||
totalChkDuration.Milliseconds().Humanize(minUnit: TimeUnit.Second),
|
||||
imageWriteDuration.Seconds().Humanize(minUnit: TimeUnit.Second),
|
||||
_imageCloseStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second)));
|
||||
Invoke(string.Format(
|
||||
Localization.Core.Took_a_total_of_0_1_processing_commands_2_checksumming_3_writing_4_closing,
|
||||
_dumpStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second),
|
||||
totalDuration.Milliseconds().Humanize(minUnit: TimeUnit.Second),
|
||||
totalChkDuration.Milliseconds().Humanize(minUnit: TimeUnit.Second),
|
||||
imageWriteDuration.Seconds().Humanize(minUnit: TimeUnit.Second),
|
||||
_imageCloseStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second)));
|
||||
|
||||
UpdateStatus?.Invoke(string.Format(Localization.Core.Average_speed_0,
|
||||
ByteSize.FromBytes(blockSize * (blocks + 1)).
|
||||
Per(totalDuration.Milliseconds()).Humanize()));
|
||||
|
||||
if(maxSpeed > 0)
|
||||
{
|
||||
UpdateStatus?.Invoke(string.Format(Localization.Core.Fastest_speed_burst_0,
|
||||
ByteSize.FromMegabytes(maxSpeed).Per(_oneSecond).Humanize()));
|
||||
}
|
||||
|
||||
if(minSpeed is > 0 and < double.MaxValue)
|
||||
{
|
||||
UpdateStatus?.Invoke(string.Format(Localization.Core.Slowest_speed_burst_0,
|
||||
ByteSize.FromMegabytes(minSpeed).Per(_oneSecond).Humanize()));
|
||||
}
|
||||
|
||||
UpdateStatus?.Invoke(string.Format(Localization.Core._0_sectors_could_not_be_read, _resume.BadBlocks.Count));
|
||||
|
||||
|
||||
@@ -79,7 +79,7 @@ partial class Dump
|
||||
ref string mcn, HashSet<int> subchannelExtents,
|
||||
Dictionary<byte, int> smallestPregapLbaPerTrack, bool supportsLongSectors)
|
||||
{
|
||||
bool sense = true; // Sense indicator
|
||||
var sense = true; // Sense indicator
|
||||
byte[] cmdBuf = null; // Data buffer
|
||||
double cmdDuration; // Command execution time
|
||||
const uint sectorSize = 2352; // Full sector size
|
||||
@@ -88,21 +88,21 @@ partial class Dump
|
||||
var outputOptical = _outputPlugin as IWritableOpticalImage;
|
||||
|
||||
supportedPlextorSubchannel = supportedSubchannel switch
|
||||
{
|
||||
MmcSubchannel.None => PlextorSubchannel.None,
|
||||
MmcSubchannel.Raw => PlextorSubchannel.Pack,
|
||||
MmcSubchannel.Q16 => PlextorSubchannel.Q16,
|
||||
_ => PlextorSubchannel.None
|
||||
};
|
||||
{
|
||||
MmcSubchannel.None => PlextorSubchannel.None,
|
||||
MmcSubchannel.Raw => PlextorSubchannel.Pack,
|
||||
MmcSubchannel.Q16 => PlextorSubchannel.Q16,
|
||||
_ => PlextorSubchannel.None
|
||||
};
|
||||
|
||||
if(_resume.BadBlocks.Count <= 0 ||
|
||||
_aborted ||
|
||||
_retryPasses <= 0)
|
||||
return;
|
||||
|
||||
int pass = 1;
|
||||
bool forward = true;
|
||||
bool runningPersistent = false;
|
||||
var pass = 1;
|
||||
var forward = true;
|
||||
var runningPersistent = false;
|
||||
|
||||
Modes.ModePage? currentModePage = null;
|
||||
byte[] md6;
|
||||
@@ -125,9 +125,11 @@ partial class Dump
|
||||
Modes.DecodedMode? dcMode10 = Modes.DecodeMode10(cmdBuf, PeripheralDeviceTypes.MultiMediaDevice);
|
||||
|
||||
if(dcMode10?.Pages != null)
|
||||
{
|
||||
foreach(Modes.ModePage modePage in dcMode10.Value.Pages.Where(modePage =>
|
||||
modePage is { Page: 0x01, Subpage: 0x00 }))
|
||||
currentModePage = modePage;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -135,9 +137,11 @@ partial class Dump
|
||||
Modes.DecodedMode? dcMode6 = Modes.DecodeMode6(cmdBuf, PeripheralDeviceTypes.MultiMediaDevice);
|
||||
|
||||
if(dcMode6?.Pages != null)
|
||||
{
|
||||
foreach(Modes.ModePage modePage in dcMode6.Value.Pages.Where(modePage =>
|
||||
modePage is { Page: 0x01, Subpage: 0x00 }))
|
||||
currentModePage = modePage;
|
||||
}
|
||||
}
|
||||
|
||||
if(currentModePage == null)
|
||||
@@ -203,11 +207,11 @@ partial class Dump
|
||||
}
|
||||
|
||||
InitProgress?.Invoke();
|
||||
cdRepeatRetry:
|
||||
cdRepeatRetry:
|
||||
ulong[] tmpArray = _resume.BadBlocks.ToArray();
|
||||
List<ulong> sectorsNotEvenPartial = new();
|
||||
|
||||
for(int i = 0; i < tmpArray.Length; i++)
|
||||
for(var i = 0; i < tmpArray.Length; i++)
|
||||
{
|
||||
ulong badSector = tmpArray[i];
|
||||
|
||||
@@ -220,24 +224,32 @@ partial class Dump
|
||||
}
|
||||
|
||||
if(forward)
|
||||
{
|
||||
PulseProgress?.Invoke(runningPersistent
|
||||
? string.
|
||||
Format(Localization.Core.Retrying_sector_0_pass_1_recovering_partial_data_forward,
|
||||
badSector, pass)
|
||||
Format(
|
||||
Localization.Core.
|
||||
Retrying_sector_0_pass_1_recovering_partial_data_forward,
|
||||
badSector, pass)
|
||||
: string.Format(Localization.Core.Retrying_sector_0_pass_1_forward, badSector,
|
||||
pass));
|
||||
}
|
||||
else
|
||||
{
|
||||
PulseProgress?.Invoke(runningPersistent
|
||||
? string.
|
||||
Format(Localization.Core.Retrying_sector_0_pass_1_recovering_partial_data_reverse,
|
||||
badSector, pass)
|
||||
Format(
|
||||
Localization.Core.
|
||||
Retrying_sector_0_pass_1_recovering_partial_data_reverse,
|
||||
badSector, pass)
|
||||
: string.Format(Localization.Core.Retrying_sector_0_pass_1_reverse, badSector,
|
||||
pass));
|
||||
}
|
||||
|
||||
Track track = tracks.OrderBy(t => t.StartSector).LastOrDefault(t => badSector >= t.StartSector);
|
||||
|
||||
byte sectorsToReRead = 1;
|
||||
uint badSectorToReRead = (uint)badSector;
|
||||
var badSectorToReRead = (uint)badSector;
|
||||
|
||||
if(_fixOffset &&
|
||||
audioExtents.Contains(badSector) &&
|
||||
@@ -256,7 +268,7 @@ partial class Dump
|
||||
|
||||
if(_supportsPlextorD8 && audioExtents.Contains(badSector))
|
||||
{
|
||||
sense = ReadPlextorWithSubchannel(out cmdBuf, out senseBuf, badSectorToReRead, blockSize,
|
||||
sense = ReadPlextorWithSubchannel(out cmdBuf, out senseBuf, badSectorToReRead, blockSize,
|
||||
sectorsToReRead, supportedPlextorSubchannel, out cmdDuration);
|
||||
|
||||
totalDuration += cmdDuration;
|
||||
@@ -324,8 +336,10 @@ partial class Dump
|
||||
|
||||
// MEDIUM ERROR, retry with ignore error below
|
||||
if(decSense is { ASC: 0x11 })
|
||||
{
|
||||
if(!sectorsNotEvenPartial.Contains(badSector))
|
||||
sectorsNotEvenPartial.Add(badSector);
|
||||
}
|
||||
}
|
||||
|
||||
// Because one block has been partially used to fix the offset
|
||||
@@ -336,7 +350,7 @@ partial class Dump
|
||||
uint blocksToRead = sectorsToReRead;
|
||||
|
||||
FixOffsetData(offsetBytes, sectorSize, sectorsForOffset, supportedSubchannel, ref blocksToRead, subSize,
|
||||
ref cmdBuf, blockSize, false);
|
||||
ref cmdBuf, blockSize, false);
|
||||
}
|
||||
|
||||
if(!sense &&
|
||||
@@ -357,10 +371,10 @@ partial class Dump
|
||||
|
||||
if(supportedSubchannel != MmcSubchannel.None)
|
||||
{
|
||||
byte[] data = new byte[sectorSize];
|
||||
byte[] sub = new byte[subSize];
|
||||
Array.Copy(cmdBuf, 0, data, 0, sectorSize);
|
||||
Array.Copy(cmdBuf, sectorSize, sub, 0, subSize);
|
||||
var data = new byte[sectorSize];
|
||||
var sub = new byte[subSize];
|
||||
Array.Copy(cmdBuf, 0, data, 0, sectorSize);
|
||||
Array.Copy(cmdBuf, sectorSize, sub, 0, subSize);
|
||||
|
||||
if(supportsLongSectors)
|
||||
outputOptical.WriteSectorLong(data, badSector);
|
||||
@@ -454,7 +468,7 @@ partial class Dump
|
||||
|
||||
InitProgress?.Invoke();
|
||||
|
||||
for(int i = 0; i < sectorsNotEvenPartial.Count; i++)
|
||||
for(var i = 0; i < sectorsNotEvenPartial.Count; i++)
|
||||
{
|
||||
ulong badSector = sectorsNotEvenPartial[i];
|
||||
|
||||
@@ -492,10 +506,10 @@ partial class Dump
|
||||
|
||||
if(supportedSubchannel != MmcSubchannel.None)
|
||||
{
|
||||
byte[] data = new byte[sectorSize];
|
||||
byte[] sub = new byte[subSize];
|
||||
Array.Copy(cmdBuf, 0, data, 0, sectorSize);
|
||||
Array.Copy(cmdBuf, sectorSize, sub, 0, subSize);
|
||||
var data = new byte[sectorSize];
|
||||
var sub = new byte[subSize];
|
||||
Array.Copy(cmdBuf, 0, data, 0, sectorSize);
|
||||
Array.Copy(cmdBuf, sectorSize, sub, 0, subSize);
|
||||
|
||||
if(supportsLongSectors)
|
||||
outputOptical.WriteSectorLong(data, badSector);
|
||||
@@ -532,10 +546,7 @@ partial class Dump
|
||||
var md = new Modes.DecodedMode
|
||||
{
|
||||
Header = new Modes.ModeHeader(),
|
||||
Pages = new[]
|
||||
{
|
||||
currentModePage.Value
|
||||
}
|
||||
Pages = new[] { currentModePage.Value }
|
||||
};
|
||||
|
||||
md6 = Modes.EncodeMode6(md, _dev.ScsiType);
|
||||
@@ -568,7 +579,7 @@ partial class Dump
|
||||
Dictionary<byte, string> isrcs, ref string mcn, HashSet<int> subchannelExtents,
|
||||
Dictionary<byte, int> smallestPregapLbaPerTrack)
|
||||
{
|
||||
bool sense = true; // Sense indicator
|
||||
var sense = true; // Sense indicator
|
||||
byte[] cmdBuf = null; // Data buffer
|
||||
double cmdDuration; // Command execution time
|
||||
byte[] senseBuf = null; // Sense buffer
|
||||
@@ -580,22 +591,22 @@ partial class Dump
|
||||
return;
|
||||
|
||||
supportedPlextorSubchannel = supportedSubchannel switch
|
||||
{
|
||||
MmcSubchannel.Raw => PlextorSubchannel.All,
|
||||
MmcSubchannel.Q16 => PlextorSubchannel.Q16,
|
||||
MmcSubchannel.Rw => PlextorSubchannel.Pack,
|
||||
_ => PlextorSubchannel.None
|
||||
};
|
||||
{
|
||||
MmcSubchannel.Raw => PlextorSubchannel.All,
|
||||
MmcSubchannel.Q16 => PlextorSubchannel.Q16,
|
||||
MmcSubchannel.Rw => PlextorSubchannel.Pack,
|
||||
_ => PlextorSubchannel.None
|
||||
};
|
||||
|
||||
if(_aborted)
|
||||
return;
|
||||
|
||||
int pass = 1;
|
||||
bool forward = true;
|
||||
var pass = 1;
|
||||
var forward = true;
|
||||
|
||||
InitProgress?.Invoke();
|
||||
|
||||
cdRepeatRetry:
|
||||
cdRepeatRetry:
|
||||
|
||||
_resume.BadSubchannels = new List<int>();
|
||||
_resume.BadSubchannels.AddRange(subchannelExtents);
|
||||
@@ -608,7 +619,7 @@ partial class Dump
|
||||
|
||||
foreach(int bs in tmpArray)
|
||||
{
|
||||
uint badSector = (uint)bs;
|
||||
var badSector = (uint)bs;
|
||||
|
||||
Track track = tracks.OrderBy(t => t.StartSector).LastOrDefault(t => badSector >= t.StartSector);
|
||||
|
||||
|
||||
@@ -91,7 +91,7 @@ partial class Dump
|
||||
{
|
||||
byte[] cmdBuf = null; // Data buffer
|
||||
const uint sectorSize = 2352; // Full sector size
|
||||
bool sense = true; // Sense indicator
|
||||
var sense = true; // Sense indicator
|
||||
byte[] senseBuf = null;
|
||||
var outputOptical = _outputPlugin as IWritableOpticalImage;
|
||||
|
||||
@@ -101,6 +101,7 @@ partial class Dump
|
||||
InitProgress?.Invoke();
|
||||
|
||||
foreach((ulong item1, ulong item2) in leadOutExtents.ToArray())
|
||||
{
|
||||
for(ulong i = item1; i <= item2; i++)
|
||||
{
|
||||
if(_aborted)
|
||||
@@ -133,14 +134,20 @@ partial class Dump
|
||||
totalDuration += cmdDuration;
|
||||
}
|
||||
else if(read16)
|
||||
{
|
||||
sense = _dev.Read16(out cmdBuf, out senseBuf, 0, false, true, false, i, blockSize, 0, 1, false,
|
||||
_dev.Timeout, out cmdDuration);
|
||||
}
|
||||
else if(read12)
|
||||
{
|
||||
sense = _dev.Read12(out cmdBuf, out senseBuf, 0, false, true, false, false, (uint)i, blockSize, 0,
|
||||
1, false, _dev.Timeout, out cmdDuration);
|
||||
}
|
||||
else if(read10)
|
||||
{
|
||||
sense = _dev.Read10(out cmdBuf, out senseBuf, 0, false, true, false, false, (uint)i, blockSize, 0,
|
||||
1, _dev.Timeout, out cmdDuration);
|
||||
}
|
||||
else if(read6)
|
||||
sense = _dev.Read6(out cmdBuf, out senseBuf, (uint)i, blockSize, 1, _dev.Timeout, out cmdDuration);
|
||||
|
||||
@@ -155,14 +162,14 @@ partial class Dump
|
||||
|
||||
if(supportedSubchannel != MmcSubchannel.None)
|
||||
{
|
||||
byte[] data = new byte[sectorSize * _maximumReadable];
|
||||
byte[] sub = new byte[subSize * _maximumReadable];
|
||||
var data = new byte[sectorSize * _maximumReadable];
|
||||
var sub = new byte[subSize * _maximumReadable];
|
||||
|
||||
for(int b = 0; b < _maximumReadable; b++)
|
||||
for(var b = 0; b < _maximumReadable; b++)
|
||||
{
|
||||
Array.Copy(cmdBuf, (int)(0 + (b * blockSize)), data, sectorSize * b, sectorSize);
|
||||
Array.Copy(cmdBuf, (int)(0 + b * blockSize), data, sectorSize * b, sectorSize);
|
||||
|
||||
Array.Copy(cmdBuf, (int)(sectorSize + (b * blockSize)), sub, subSize * b, subSize);
|
||||
Array.Copy(cmdBuf, (int)(sectorSize + b * blockSize), sub, subSize * b, subSize);
|
||||
}
|
||||
|
||||
outputOptical.WriteSectorsLong(data, i, _maximumReadable);
|
||||
@@ -222,6 +229,7 @@ partial class Dump
|
||||
|
||||
_resume.NextBlock = i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
EndProgress?.Invoke();
|
||||
}
|
||||
@@ -265,7 +273,7 @@ partial class Dump
|
||||
{
|
||||
byte[] cmdBuf = null; // Data buffer
|
||||
const uint sectorSize = 2352; // Full sector size
|
||||
bool sense = true; // Sense indicator
|
||||
var sense = true; // Sense indicator
|
||||
byte[] senseBuf = null;
|
||||
var outputOptical = _outputPlugin as IWritableOpticalImage;
|
||||
|
||||
@@ -274,6 +282,7 @@ partial class Dump
|
||||
InitProgress?.Invoke();
|
||||
|
||||
foreach((ulong item1, ulong item2) in leadOutExtents.ToArray())
|
||||
{
|
||||
for(ulong i = item1; i <= item2; i++)
|
||||
{
|
||||
if(_aborted)
|
||||
@@ -306,14 +315,20 @@ partial class Dump
|
||||
totalDuration += cmdDuration;
|
||||
}
|
||||
else if(read16)
|
||||
{
|
||||
sense = _dev.Read16(out cmdBuf, out senseBuf, 0, false, true, false, i, blockSize, 0, 1, false,
|
||||
_dev.Timeout, out cmdDuration);
|
||||
}
|
||||
else if(read12)
|
||||
{
|
||||
sense = _dev.Read12(out cmdBuf, out senseBuf, 0, false, true, false, false, (uint)i, blockSize, 0,
|
||||
1, false, _dev.Timeout, out cmdDuration);
|
||||
}
|
||||
else if(read10)
|
||||
{
|
||||
sense = _dev.Read10(out cmdBuf, out senseBuf, 0, false, true, false, false, (uint)i, blockSize, 0,
|
||||
1, _dev.Timeout, out cmdDuration);
|
||||
}
|
||||
else if(read6)
|
||||
sense = _dev.Read6(out cmdBuf, out senseBuf, (uint)i, blockSize, 1, _dev.Timeout, out cmdDuration);
|
||||
|
||||
@@ -328,14 +343,14 @@ partial class Dump
|
||||
|
||||
if(supportedSubchannel != MmcSubchannel.None)
|
||||
{
|
||||
byte[] data = new byte[sectorSize * _maximumReadable];
|
||||
byte[] sub = new byte[subSize * _maximumReadable];
|
||||
var data = new byte[sectorSize * _maximumReadable];
|
||||
var sub = new byte[subSize * _maximumReadable];
|
||||
|
||||
for(int b = 0; b < _maximumReadable; b++)
|
||||
for(var b = 0; b < _maximumReadable; b++)
|
||||
{
|
||||
Array.Copy(cmdBuf, (int)(0 + (b * blockSize)), data, sectorSize * b, sectorSize);
|
||||
Array.Copy(cmdBuf, (int)(0 + b * blockSize), data, sectorSize * b, sectorSize);
|
||||
|
||||
Array.Copy(cmdBuf, (int)(sectorSize + (b * blockSize)), sub, subSize * b, subSize);
|
||||
Array.Copy(cmdBuf, (int)(sectorSize + b * blockSize), sub, subSize * b, subSize);
|
||||
}
|
||||
|
||||
outputOptical.WriteSectorsLong(data, i, _maximumReadable);
|
||||
@@ -375,8 +390,10 @@ partial class Dump
|
||||
outputOptical.WriteSectorsLong(new byte[sectorSize * _skip], i, 1);
|
||||
|
||||
if(desiredSubchannel != MmcSubchannel.None)
|
||||
{
|
||||
outputOptical.WriteSectorsTag(new byte[subSize * _skip], i, 1,
|
||||
SectorTagType.CdSectorSubchannel);
|
||||
}
|
||||
}
|
||||
else
|
||||
outputOptical.WriteSectors(new byte[blockSize * _skip], i, 1);
|
||||
@@ -394,6 +411,7 @@ partial class Dump
|
||||
if(!double.IsInfinity(newSpeed))
|
||||
currentSpeed = newSpeed;
|
||||
}
|
||||
}
|
||||
|
||||
EndProgress?.Invoke();
|
||||
}
|
||||
|
||||
@@ -58,20 +58,20 @@ partial class Dump
|
||||
if(cmdBuf.Length == 0)
|
||||
return;
|
||||
|
||||
int offsetFix = offsetBytes < 0 ? (int)((sectorSize * sectorsForOffset) + offsetBytes) : offsetBytes;
|
||||
int offsetFix = offsetBytes < 0 ? (int)(sectorSize * sectorsForOffset + offsetBytes) : offsetBytes;
|
||||
|
||||
byte[] tmpBuf;
|
||||
|
||||
if(supportedSubchannel != MmcSubchannel.None)
|
||||
{
|
||||
// De-interleave subchannel
|
||||
byte[] data = new byte[sectorSize * blocksToRead];
|
||||
byte[] sub = new byte[subSize * blocksToRead];
|
||||
var data = new byte[sectorSize * blocksToRead];
|
||||
var sub = new byte[subSize * blocksToRead];
|
||||
|
||||
for(int b = 0; b < blocksToRead; b++)
|
||||
for(var 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);
|
||||
Array.Copy(cmdBuf, (int)(0 + b * blockSize), data, sectorSize * b, sectorSize);
|
||||
Array.Copy(cmdBuf, (int)(sectorSize + b * blockSize), sub, subSize * b, subSize);
|
||||
}
|
||||
|
||||
if(failedCrossingLeadOut)
|
||||
@@ -95,10 +95,10 @@ partial class Dump
|
||||
// Re-interleave subchannel
|
||||
cmdBuf = new byte[blockSize * blocksToRead];
|
||||
|
||||
for(int b = 0; b < blocksToRead; b++)
|
||||
for(var 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);
|
||||
Array.Copy(data, sectorSize * b, cmdBuf, (int)(0 + b * blockSize), sectorSize);
|
||||
Array.Copy(sub, subSize * b, cmdBuf, (int)(sectorSize + b * blockSize), subSize);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
@@ -46,8 +46,8 @@ partial class Dump
|
||||
/// <param name="supportedPlextorSubchannel">Supported subchannel type</param>
|
||||
/// <param name="cmdDuration">Time spent sending commands to the drive</param>
|
||||
/// <returns><c>true</c> if an error occured, <c>false</c> otherwise</returns>
|
||||
bool ReadPlextorWithSubchannel(out byte[] cmdBuf, out byte[] senseBuf, uint firstSectorToRead, uint blockSize,
|
||||
uint blocksToRead, PlextorSubchannel supportedPlextorSubchannel,
|
||||
bool ReadPlextorWithSubchannel(out byte[] cmdBuf, out byte[] senseBuf, uint firstSectorToRead, uint blockSize,
|
||||
uint blocksToRead, PlextorSubchannel supportedPlextorSubchannel,
|
||||
out double cmdDuration)
|
||||
{
|
||||
bool sense;
|
||||
@@ -93,18 +93,19 @@ partial class Dump
|
||||
return true;
|
||||
|
||||
sense = _dev.PlextorReadCdDa(out byte[] subBuf, out senseBuf, firstSectorToRead, subSize, blocksToRead,
|
||||
supportedPlextorSubchannel == PlextorSubchannel.Pack ? PlextorSubchannel.All
|
||||
supportedPlextorSubchannel == PlextorSubchannel.Pack
|
||||
? PlextorSubchannel.All
|
||||
: supportedPlextorSubchannel, 0, out cmdDuration);
|
||||
|
||||
if(sense)
|
||||
return true;
|
||||
|
||||
cmdBuf = new byte[(2352 * blocksToRead) + (subSize * blocksToRead)];
|
||||
cmdBuf = new byte[2352 * blocksToRead + subSize * blocksToRead];
|
||||
|
||||
for(int b = 0; b < blocksToRead; b++)
|
||||
for(var b = 0; b < blocksToRead; b++)
|
||||
{
|
||||
Array.Copy(dataBuf, 2352 * b, cmdBuf, (2352 + subSize) * b, 2352);
|
||||
Array.Copy(subBuf, subSize * b, cmdBuf, ((2352 + subSize) * b) + 2352, subSize);
|
||||
Array.Copy(dataBuf, 2352 * b, cmdBuf, (2352 + subSize) * b, 2352);
|
||||
Array.Copy(subBuf, subSize * b, cmdBuf, (2352 + subSize) * b + 2352, subSize);
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
@@ -62,20 +62,21 @@ partial class Dump
|
||||
void ReadCdFirstTrackPregap(uint blockSize, ref double currentSpeed, Dictionary<MediaTagType, byte[]> mediaTags,
|
||||
MmcSubchannel supportedSubchannel, ref double totalDuration)
|
||||
{
|
||||
bool sense; // Sense indicator
|
||||
byte[] cmdBuf; // Data buffer
|
||||
double cmdDuration; // Command execution time
|
||||
ulong sectorSpeedStart = 0; // Used to calculate correct speed
|
||||
bool gotFirstTrackPregap = false;
|
||||
int firstTrackPregapSectorsGood = 0;
|
||||
var firstTrackPregapMs = new MemoryStream();
|
||||
bool sense; // Sense indicator
|
||||
byte[] cmdBuf; // Data buffer
|
||||
double cmdDuration; // Command execution time
|
||||
ulong sectorSpeedStart = 0; // Used to calculate correct speed
|
||||
var gotFirstTrackPregap = false;
|
||||
var firstTrackPregapSectorsGood = 0;
|
||||
var firstTrackPregapMs = new MemoryStream();
|
||||
|
||||
_dumpLog.WriteLine(Localization.Core.Reading_first_track_pregap);
|
||||
UpdateStatus?.Invoke(Localization.Core.Reading_first_track_pregap);
|
||||
InitProgress?.Invoke();
|
||||
_speedStopwatch.Restart();
|
||||
|
||||
for(int firstTrackPregapBlock = -150; firstTrackPregapBlock < 0 && _resume.NextBlock == 0;
|
||||
for(int firstTrackPregapBlock = -150;
|
||||
firstTrackPregapBlock < 0 && _resume.NextBlock == 0;
|
||||
firstTrackPregapBlock++)
|
||||
{
|
||||
if(_aborted)
|
||||
@@ -153,7 +154,7 @@ partial class Dump
|
||||
bool supportsPqSubchannel, bool supportsRwSubchannel,
|
||||
Database.Models.Device dbDev, out bool inexactPositioning, bool dumping)
|
||||
{
|
||||
bool sense = true; // Sense indicator
|
||||
var sense = true; // Sense indicator
|
||||
byte[] subBuf = null;
|
||||
int posQ;
|
||||
uint retries;
|
||||
@@ -169,7 +170,8 @@ partial class Dump
|
||||
// Check if subchannel is BCD
|
||||
for(retries = 0; retries < 10; retries++)
|
||||
{
|
||||
sense = supportsRwSubchannel ? GetSectorForPregapRaw(dev, 11, dbDev, out subBuf, false)
|
||||
sense = supportsRwSubchannel
|
||||
? GetSectorForPregapRaw(dev, 11, dbDev, out subBuf, false)
|
||||
: GetSectorForPregapQ16(dev, 11, out subBuf, false);
|
||||
|
||||
if(sense)
|
||||
@@ -181,11 +183,11 @@ partial class Dump
|
||||
}
|
||||
|
||||
AaruConsole.DebugWriteLine(PREGAP_MODULE_NAME, bcd switch
|
||||
{
|
||||
true => Localization.Core.Subchannel_is_BCD,
|
||||
false => Localization.Core.Subchannel_is_not_BCD,
|
||||
_ => Localization.Core.Could_not_detect_drive_subchannel_BCD
|
||||
});
|
||||
{
|
||||
true => Localization.Core.Subchannel_is_BCD,
|
||||
false => Localization.Core.Subchannel_is_not_BCD,
|
||||
_ => Localization.Core.Could_not_detect_drive_subchannel_BCD
|
||||
});
|
||||
|
||||
if(bcd is null)
|
||||
{
|
||||
@@ -202,10 +204,10 @@ partial class Dump
|
||||
foreach(Track t in tracks)
|
||||
pregaps[t.Sequence] = 0;
|
||||
|
||||
for(int t = 0; t < tracks.Length; t++)
|
||||
for(var t = 0; t < tracks.Length; t++)
|
||||
{
|
||||
Track track = tracks[t];
|
||||
int trackRetries = 0;
|
||||
var trackRetries = 0;
|
||||
|
||||
// First track of each session has at least 150 sectors of pregap and is not always readable
|
||||
if(tracks.Where(trk => trk.Session == track.Session).MinBy(trk => trk.Sequence).Sequence == track.Sequence)
|
||||
@@ -239,14 +241,14 @@ partial class Dump
|
||||
AaruConsole.DebugWriteLine(PREGAP_MODULE_NAME, Localization.Core.Track_0, track.Sequence);
|
||||
|
||||
int lba = (int)track.StartSector - 1;
|
||||
bool pregapFound = false;
|
||||
var pregapFound = false;
|
||||
Track previousTrack = tracks.FirstOrDefault(trk => trk.Sequence == track.Sequence - 1);
|
||||
|
||||
bool goneBack = false;
|
||||
bool goFront = false;
|
||||
bool forward = false;
|
||||
bool crcOk = false;
|
||||
bool previousPregapIsPreviousTrack = false;
|
||||
var goneBack = false;
|
||||
var goFront = false;
|
||||
var forward = false;
|
||||
var crcOk = false;
|
||||
var previousPregapIsPreviousTrack = false;
|
||||
|
||||
// Check if pregap is 0
|
||||
for(retries = 0; retries < 10 && !pregapFound; retries++)
|
||||
@@ -294,7 +296,7 @@ partial class Dump
|
||||
subBuf[6] = 0;
|
||||
|
||||
// Fix BCD numbering
|
||||
for(int i = 1; i < 10; i++)
|
||||
for(var i = 1; i < 10; i++)
|
||||
{
|
||||
if((subBuf[i] & 0xF0) > 0xA0)
|
||||
subBuf[i] &= 0x7F;
|
||||
@@ -309,12 +311,14 @@ partial class Dump
|
||||
crcOk = crc[0] == subBuf[10] && crc[1] == subBuf[11];
|
||||
|
||||
if(crcOk)
|
||||
{
|
||||
AaruConsole.DebugWriteLine(PREGAP_MODULE_NAME,
|
||||
Localization.Core.
|
||||
LBA_0_Try_1_Sense_2_Q_FIXED_3_4_5_6_7_8_9_10_11_12_CRC_13_14_Calculated_CRC_15_16,
|
||||
lba, retries + 1, sense, subBuf[0], subBuf[1], subBuf[2], subBuf[3],
|
||||
subBuf[4], subBuf[5], subBuf[6], subBuf[7], subBuf[8], subBuf[9],
|
||||
subBuf[10], subBuf[11], crc[0], crc[1]);
|
||||
}
|
||||
else
|
||||
continue;
|
||||
}
|
||||
@@ -325,7 +329,7 @@ partial class Dump
|
||||
if((subBuf[0] & 0xF) != 1)
|
||||
continue;
|
||||
|
||||
posQ = (subBuf[7] * 60 * 75) + (subBuf[8] * 75) + subBuf[9] - 150;
|
||||
posQ = subBuf[7] * 60 * 75 + subBuf[8] * 75 + subBuf[9] - 150;
|
||||
|
||||
if(subBuf[1] != track.Sequence - 1 ||
|
||||
subBuf[2] == 0 ||
|
||||
@@ -348,10 +352,12 @@ partial class Dump
|
||||
{
|
||||
// Some drives crash if you try to read just before the previous read, so seek away first
|
||||
if(!forward)
|
||||
{
|
||||
sense = supportsRwSubchannel
|
||||
? GetSectorForPregapRaw(dev, (uint)lba - 10, dbDev, out subBuf,
|
||||
track.Type == TrackType.Audio)
|
||||
: GetSectorForPregapQ16(dev, (uint)lba - 10, out subBuf, track.Type == TrackType.Audio);
|
||||
}
|
||||
|
||||
for(retries = 0; retries < 10; retries++)
|
||||
{
|
||||
@@ -394,7 +400,7 @@ partial class Dump
|
||||
subBuf[6] = 0;
|
||||
|
||||
// Fix BCD numbering
|
||||
for(int i = 1; i < 10; i++)
|
||||
for(var i = 1; i < 10; i++)
|
||||
{
|
||||
if((subBuf[i] & 0xF0) > 0xA0)
|
||||
subBuf[i] &= 0x7F;
|
||||
@@ -435,8 +441,8 @@ partial class Dump
|
||||
{
|
||||
if(pregaps[track.Sequence] == 0)
|
||||
{
|
||||
if((previousTrack.Type == TrackType.Audio && track.Type != TrackType.Audio) ||
|
||||
(previousTrack.Type != TrackType.Audio && track.Type == TrackType.Audio))
|
||||
if(previousTrack.Type == TrackType.Audio && track.Type != TrackType.Audio ||
|
||||
previousTrack.Type != TrackType.Audio && track.Type == TrackType.Audio)
|
||||
{
|
||||
dumpLog?.WriteLine(Localization.Core.
|
||||
Could_not_read_subchannel_for_this_track_supposing_hundred_fifty_sectors);
|
||||
@@ -457,13 +463,17 @@ partial class Dump
|
||||
{
|
||||
dumpLog?.
|
||||
WriteLine(string.
|
||||
Format(Localization.Core.Could_not_read_subchannel_for_this_track_supposing_0_sectors,
|
||||
pregaps[track.Sequence]));
|
||||
Format(
|
||||
Localization.Core.
|
||||
Could_not_read_subchannel_for_this_track_supposing_0_sectors,
|
||||
pregaps[track.Sequence]));
|
||||
|
||||
updateStatus?.
|
||||
Invoke(string.
|
||||
Format(Localization.Core.Could_not_read_subchannel_for_this_track_supposing_0_sectors,
|
||||
pregaps[track.Sequence]));
|
||||
Format(
|
||||
Localization.Core.
|
||||
Could_not_read_subchannel_for_this_track_supposing_0_sectors,
|
||||
pregaps[track.Sequence]));
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -552,7 +562,7 @@ partial class Dump
|
||||
previousPregapIsPreviousTrack = false;
|
||||
|
||||
// Pregap according to Q position
|
||||
posQ = (subBuf[7] * 60 * 75) + (subBuf[8] * 75) + subBuf[9] - 150;
|
||||
posQ = subBuf[7] * 60 * 75 + subBuf[8] * 75 + subBuf[9] - 150;
|
||||
int diff = posQ - lba;
|
||||
int pregapQ = (int)track.StartSector - lba;
|
||||
|
||||
@@ -614,7 +624,7 @@ partial class Dump
|
||||
if(dumping)
|
||||
{
|
||||
// Minus five, to ensure dumping will fix if there is a pregap LBA 0
|
||||
int red = 5;
|
||||
var red = 5;
|
||||
|
||||
while(trk.Pregap > 0 &&
|
||||
red > 0)
|
||||
@@ -643,7 +653,7 @@ partial class Dump
|
||||
/// <param name="audioTrack">Set if it is an audio track</param>
|
||||
/// <returns><c>true</c> if read correctly, <c>false</c> otherwise</returns>
|
||||
static bool GetSectorForPregapRaw(Device dev, uint lba, Database.Models.Device dbDev, out byte[] subBuf,
|
||||
bool audioTrack)
|
||||
bool audioTrack)
|
||||
{
|
||||
byte[] cmdBuf;
|
||||
bool sense;
|
||||
@@ -656,9 +666,11 @@ partial class Dump
|
||||
out _);
|
||||
|
||||
if(sense)
|
||||
{
|
||||
sense = dev.ReadCd(out cmdBuf, out _, lba, 2448, 1, MmcSectorTypes.AllTypes, false, false, true,
|
||||
MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None, MmcSubchannel.Raw,
|
||||
dev.Timeout, out _);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -667,14 +679,16 @@ partial class Dump
|
||||
dev.Timeout, out _);
|
||||
|
||||
if(sense)
|
||||
{
|
||||
sense = dev.ReadCd(out cmdBuf, out _, lba, 2448, 1, MmcSectorTypes.Cdda, false, false, false,
|
||||
MmcHeaderCodes.None, true, false, MmcErrorField.None, MmcSubchannel.Raw, dev.Timeout,
|
||||
out _);
|
||||
}
|
||||
}
|
||||
|
||||
if(!sense)
|
||||
{
|
||||
byte[] tmpBuf = new byte[96];
|
||||
var tmpBuf = new byte[96];
|
||||
Array.Copy(cmdBuf, 2352, tmpBuf, 0, 96);
|
||||
subBuf = DeinterleaveQ(tmpBuf);
|
||||
}
|
||||
@@ -685,9 +699,11 @@ partial class Dump
|
||||
out _);
|
||||
|
||||
if(sense)
|
||||
{
|
||||
sense = dev.ReadCd(out cmdBuf, out _, lba, 96, 1, MmcSectorTypes.Cdda, false, false, false,
|
||||
MmcHeaderCodes.None, false, false, MmcErrorField.None, MmcSubchannel.Raw,
|
||||
dev.Timeout, out _);
|
||||
}
|
||||
|
||||
if(!sense)
|
||||
subBuf = DeinterleaveQ(cmdBuf);
|
||||
@@ -724,9 +740,11 @@ partial class Dump
|
||||
out _);
|
||||
|
||||
if(sense)
|
||||
{
|
||||
sense = dev.ReadCd(out cmdBuf, out _, lba, 2368, 1, MmcSectorTypes.AllTypes, false, false, true,
|
||||
MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None, MmcSubchannel.Q16,
|
||||
dev.Timeout, out _);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -735,9 +753,11 @@ partial class Dump
|
||||
dev.Timeout, out _);
|
||||
|
||||
if(sense)
|
||||
{
|
||||
sense = dev.ReadCd(out cmdBuf, out _, lba, 2368, 1, MmcSectorTypes.Cdda, false, false, false,
|
||||
MmcHeaderCodes.None, true, false, MmcErrorField.None, MmcSubchannel.Q16, dev.Timeout,
|
||||
out _);
|
||||
}
|
||||
}
|
||||
|
||||
if(!sense)
|
||||
@@ -752,9 +772,11 @@ partial class Dump
|
||||
out _);
|
||||
|
||||
if(sense)
|
||||
{
|
||||
sense = dev.ReadCd(out cmdBuf, out _, lba, 16, 1, MmcSectorTypes.Cdda, false, false, false,
|
||||
MmcHeaderCodes.None, false, false, MmcErrorField.None, MmcSubchannel.Q16,
|
||||
dev.Timeout, out _);
|
||||
}
|
||||
|
||||
if(!sense)
|
||||
subBuf = cmdBuf;
|
||||
@@ -768,10 +790,10 @@ partial class Dump
|
||||
/// <returns>De-interleaved Q subchannel</returns>
|
||||
static byte[] DeinterleaveQ(byte[] subchannel)
|
||||
{
|
||||
int[] q = new int[subchannel.Length / 8];
|
||||
var q = new int[subchannel.Length / 8];
|
||||
|
||||
// De-interlace Q subchannel
|
||||
for(int iq = 0; iq < subchannel.Length; iq += 8)
|
||||
for(var iq = 0; iq < subchannel.Length; iq += 8)
|
||||
{
|
||||
q[iq / 8] = (subchannel[iq] & 0x40) << 1;
|
||||
q[iq / 8] += subchannel[iq + 1] & 0x40;
|
||||
@@ -783,9 +805,9 @@ partial class Dump
|
||||
q[iq / 8] += (subchannel[iq + 7] & 0x40) >> 6;
|
||||
}
|
||||
|
||||
byte[] deQ = new byte[q.Length];
|
||||
var deQ = new byte[q.Length];
|
||||
|
||||
for(int iq = 0; iq < q.Length; iq++)
|
||||
for(var iq = 0; iq < q.Length; iq++)
|
||||
deQ[iq] = (byte)q[iq];
|
||||
|
||||
return deQ;
|
||||
@@ -795,29 +817,29 @@ partial class Dump
|
||||
/// <param name="q">Q subchannel</param>
|
||||
static void BinaryToBcdQ(byte[] q)
|
||||
{
|
||||
q[1] = (byte)(((q[1] / 10) << 4) + (q[1] % 10));
|
||||
q[2] = (byte)(((q[2] / 10) << 4) + (q[2] % 10));
|
||||
q[3] = (byte)(((q[3] / 10) << 4) + (q[3] % 10));
|
||||
q[4] = (byte)(((q[4] / 10) << 4) + (q[4] % 10));
|
||||
q[5] = (byte)(((q[5] / 10) << 4) + (q[5] % 10));
|
||||
q[6] = (byte)(((q[6] / 10) << 4) + (q[6] % 10));
|
||||
q[7] = (byte)(((q[7] / 10) << 4) + (q[7] % 10));
|
||||
q[8] = (byte)(((q[8] / 10) << 4) + (q[8] % 10));
|
||||
q[9] = (byte)(((q[9] / 10) << 4) + (q[9] % 10));
|
||||
q[1] = (byte)((q[1] / 10 << 4) + q[1] % 10);
|
||||
q[2] = (byte)((q[2] / 10 << 4) + q[2] % 10);
|
||||
q[3] = (byte)((q[3] / 10 << 4) + q[3] % 10);
|
||||
q[4] = (byte)((q[4] / 10 << 4) + q[4] % 10);
|
||||
q[5] = (byte)((q[5] / 10 << 4) + q[5] % 10);
|
||||
q[6] = (byte)((q[6] / 10 << 4) + q[6] % 10);
|
||||
q[7] = (byte)((q[7] / 10 << 4) + q[7] % 10);
|
||||
q[8] = (byte)((q[8] / 10 << 4) + q[8] % 10);
|
||||
q[9] = (byte)((q[9] / 10 << 4) + q[9] % 10);
|
||||
}
|
||||
|
||||
/// <summary>In place converts Q subchannel from BCD to binary numbering</summary>
|
||||
/// <param name="q">Q subchannel</param>
|
||||
static void BcdToBinaryQ(byte[] q)
|
||||
{
|
||||
q[1] = (byte)((q[1] / 16 * 10) + (q[1] & 0x0F));
|
||||
q[2] = (byte)((q[2] / 16 * 10) + (q[2] & 0x0F));
|
||||
q[3] = (byte)((q[3] / 16 * 10) + (q[3] & 0x0F));
|
||||
q[4] = (byte)((q[4] / 16 * 10) + (q[4] & 0x0F));
|
||||
q[5] = (byte)((q[5] / 16 * 10) + (q[5] & 0x0F));
|
||||
q[6] = (byte)((q[6] / 16 * 10) + (q[6] & 0x0F));
|
||||
q[7] = (byte)((q[7] / 16 * 10) + (q[7] & 0x0F));
|
||||
q[8] = (byte)((q[8] / 16 * 10) + (q[8] & 0x0F));
|
||||
q[9] = (byte)((q[9] / 16 * 10) + (q[9] & 0x0F));
|
||||
q[1] = (byte)(q[1] / 16 * 10 + (q[1] & 0x0F));
|
||||
q[2] = (byte)(q[2] / 16 * 10 + (q[2] & 0x0F));
|
||||
q[3] = (byte)(q[3] / 16 * 10 + (q[3] & 0x0F));
|
||||
q[4] = (byte)(q[4] / 16 * 10 + (q[4] & 0x0F));
|
||||
q[5] = (byte)(q[5] / 16 * 10 + (q[5] & 0x0F));
|
||||
q[6] = (byte)(q[6] / 16 * 10 + (q[6] & 0x0F));
|
||||
q[7] = (byte)(q[7] / 16 * 10 + (q[7] & 0x0F));
|
||||
q[8] = (byte)(q[8] / 16 * 10 + (q[8] & 0x0F));
|
||||
q[9] = (byte)(q[9] / 16 * 10 + (q[9] & 0x0F));
|
||||
}
|
||||
}
|
||||
@@ -55,10 +55,12 @@ partial class Dump
|
||||
|
||||
// Count how many run end sectors are detected as bad blocks
|
||||
for(ulong i = blocks - 1; i > blocks - 1 - _ignoreCdrRunOuts; i--)
|
||||
{
|
||||
if(_resume.BadBlocks.Contains(i))
|
||||
runOutSectors.Add(i);
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
if(runOutSectors.Count == 0)
|
||||
return;
|
||||
@@ -76,20 +78,26 @@ partial class Dump
|
||||
if(track is null)
|
||||
continue;
|
||||
|
||||
byte[] sector = new byte[2352];
|
||||
var sector = new byte[2352];
|
||||
|
||||
switch(track.Type)
|
||||
{
|
||||
case TrackType.Audio: break;
|
||||
case TrackType.Audio:
|
||||
break;
|
||||
case TrackType.Data:
|
||||
sector = new byte[2048];
|
||||
|
||||
break;
|
||||
case TrackType.CdMode1: break;
|
||||
case TrackType.CdMode2Formless: break;
|
||||
case TrackType.CdMode2Form1: break;
|
||||
case TrackType.CdMode2Form2: break;
|
||||
default: continue;
|
||||
case TrackType.CdMode1:
|
||||
break;
|
||||
case TrackType.CdMode2Formless:
|
||||
break;
|
||||
case TrackType.CdMode2Form1:
|
||||
break;
|
||||
case TrackType.CdMode2Form2:
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
|
||||
if(track.Type != TrackType.Audio &&
|
||||
|
||||
@@ -52,7 +52,7 @@ partial class Dump
|
||||
/// <param name="sessions">Sessions</param>
|
||||
/// <param name="firstTrackLastSession">First track in last session</param>
|
||||
void ReadCdTags(ref MediaType mediaType, Dictionary<MediaTagType, byte[]> mediaTags, out int sessions,
|
||||
out int firstTrackLastSession)
|
||||
out int firstTrackLastSession)
|
||||
{
|
||||
byte[] cmdBuf; // Data buffer
|
||||
bool sense; // Sense indicator
|
||||
@@ -93,12 +93,14 @@ partial class Dump
|
||||
|
||||
if(discInfo.HasValue &&
|
||||
mediaType == MediaType.CD)
|
||||
{
|
||||
mediaType = discInfo.Value.DiscType switch
|
||||
{
|
||||
0x10 => MediaType.CDI,
|
||||
0x20 => MediaType.CDROMXA,
|
||||
_ => mediaType
|
||||
};
|
||||
{
|
||||
0x10 => MediaType.CDI,
|
||||
0x20 => MediaType.CDROMXA,
|
||||
_ => mediaType
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
_dumpLog.WriteLine(Localization.Core.Reading_PMA);
|
||||
|
||||
@@ -60,9 +60,9 @@ partial class Dump
|
||||
/// <param name="trackFlags">Track flags</param>
|
||||
/// <param name="updateStatus">Update status handler</param>
|
||||
/// <returns>List of tracks</returns>
|
||||
public static Track[] GetCdTracks(Device dev, DumpLog dumpLog, bool force, out long lastSector,
|
||||
Dictionary<int, long> leadOutStarts, Dictionary<MediaTagType, byte[]> mediaTags,
|
||||
ErrorMessageHandler stoppingErrorMessage, out FullTOC.CDFullTOC? toc,
|
||||
public static Track[] GetCdTracks(Device dev, DumpLog dumpLog, bool force, out long lastSector,
|
||||
Dictionary<int, long> leadOutStarts, Dictionary<MediaTagType, byte[]> mediaTags,
|
||||
ErrorMessageHandler stoppingErrorMessage, out FullTOC.CDFullTOC? toc,
|
||||
Dictionary<byte, byte> trackFlags, UpdateStatusHandler updateStatus)
|
||||
{
|
||||
byte[] cmdBuf; // Data buffer
|
||||
@@ -101,6 +101,7 @@ partial class Dump
|
||||
toc.Value.TrackDescriptors.OrderBy(track => track.POINT).ToArray();
|
||||
|
||||
foreach(FullTOC.TrackDataDescriptor trk in sortedTracks.Where(trk => trk.ADR is 1 or 4))
|
||||
{
|
||||
switch(trk.POINT)
|
||||
{
|
||||
case >= 0x01 and <= 0x63:
|
||||
@@ -109,10 +110,11 @@ partial class Dump
|
||||
Sequence = trk.POINT,
|
||||
Session = trk.SessionNumber,
|
||||
Type = (TocControl)(trk.CONTROL & 0x0D) == TocControl.DataTrack ||
|
||||
(TocControl)(trk.CONTROL & 0x0D) == TocControl.DataTrackIncremental ? TrackType.Data
|
||||
(TocControl)(trk.CONTROL & 0x0D) == TocControl.DataTrackIncremental
|
||||
? TrackType.Data
|
||||
: TrackType.Audio,
|
||||
StartSector =
|
||||
(ulong)((trk.PHOUR * 3600 * 75) + (trk.PMIN * 60 * 75) + (trk.PSEC * 75) + trk.PFRAME -
|
||||
(ulong)(trk.PHOUR * 3600 * 75 + trk.PMIN * 60 * 75 + trk.PSEC * 75 + trk.PFRAME -
|
||||
150),
|
||||
BytesPerSector = (int)sectorSize,
|
||||
RawBytesPerSector = (int)sectorSize
|
||||
@@ -159,7 +161,7 @@ partial class Dump
|
||||
phour = trk.PHOUR;
|
||||
}
|
||||
|
||||
lastSector = (phour * 3600 * 75) + (pmin * 60 * 75) + (psec * 75) + pframe - 150;
|
||||
lastSector = phour * 3600 * 75 + pmin * 60 * 75 + psec * 75 + pframe - 150;
|
||||
leadOutStarts?.Add(trk.SessionNumber, lastSector + 1);
|
||||
|
||||
break;
|
||||
@@ -167,11 +169,13 @@ partial class Dump
|
||||
case 0xA0 when trk.ADR == 1:
|
||||
leadoutTrackType =
|
||||
(TocControl)(trk.CONTROL & 0x0D) == TocControl.DataTrack ||
|
||||
(TocControl)(trk.CONTROL & 0x0D) == TocControl.DataTrackIncremental ? TrackType.Data
|
||||
(TocControl)(trk.CONTROL & 0x0D) == TocControl.DataTrackIncremental
|
||||
? TrackType.Data
|
||||
: TrackType.Audio;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -194,8 +198,10 @@ partial class Dump
|
||||
}
|
||||
|
||||
if(oldToc.HasValue)
|
||||
{
|
||||
foreach(TOC.CDTOCTrackDataDescriptor trk in oldToc.Value.TrackDescriptors.OrderBy(t => t.TrackNumber).
|
||||
Where(trk => trk.ADR is 1 or 4))
|
||||
{
|
||||
switch(trk.TrackNumber)
|
||||
{
|
||||
case >= 0x01 and <= 0x63:
|
||||
@@ -205,7 +211,8 @@ partial class Dump
|
||||
Session = 1,
|
||||
Type = (TocControl)(trk.CONTROL & 0x0D) == TocControl.DataTrack ||
|
||||
(TocControl)(trk.CONTROL & 0x0D) == TocControl.DataTrackIncremental
|
||||
? TrackType.Data : TrackType.Audio,
|
||||
? TrackType.Data
|
||||
: TrackType.Audio,
|
||||
StartSector = trk.TrackStartAddress,
|
||||
BytesPerSector = (int)sectorSize,
|
||||
RawBytesPerSector = (int)sectorSize
|
||||
@@ -217,13 +224,16 @@ partial class Dump
|
||||
case 0xAA:
|
||||
leadoutTrackType =
|
||||
(TocControl)(trk.CONTROL & 0x0D) == TocControl.DataTrack ||
|
||||
(TocControl)(trk.CONTROL & 0x0D) == TocControl.DataTrackIncremental ? TrackType.Data
|
||||
(TocControl)(trk.CONTROL & 0x0D) == TocControl.DataTrackIncremental
|
||||
? TrackType.Data
|
||||
: TrackType.Audio;
|
||||
|
||||
lastSector = trk.TrackStartAddress - 1;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(trackList.Count == 0)
|
||||
@@ -251,7 +261,7 @@ partial class Dump
|
||||
|
||||
if(!sense)
|
||||
{
|
||||
byte[] temp = new byte[8];
|
||||
var temp = new byte[8];
|
||||
|
||||
Array.Copy(cmdBuf, 0, temp, 0, 8);
|
||||
Array.Reverse(temp);
|
||||
@@ -262,7 +272,7 @@ partial class Dump
|
||||
sense = dev.ReadCapacity(out cmdBuf, out _, dev.Timeout, out _);
|
||||
|
||||
if(!sense)
|
||||
lastSector = ((cmdBuf[0] << 24) + (cmdBuf[1] << 16) + (cmdBuf[2] << 8) + cmdBuf[3]) & 0xFFFFFFFF;
|
||||
lastSector = (cmdBuf[0] << 24) + (cmdBuf[1] << 16) + (cmdBuf[2] << 8) + cmdBuf[3] & 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
if(lastSector > 0)
|
||||
|
||||
@@ -83,7 +83,7 @@ partial class Dump
|
||||
Dictionary<byte, string> isrcs, ref string mcn, HashSet<int> subchannelExtents,
|
||||
Dictionary<byte, int> smallestPregapLbaPerTrack)
|
||||
{
|
||||
bool sense = true; // Sense indicator
|
||||
var sense = true; // Sense indicator
|
||||
byte[] cmdBuf = null; // Data buffer
|
||||
double cmdDuration = 0; // Command execution time
|
||||
const uint sectorSize = 2352; // Full sector size
|
||||
@@ -92,12 +92,12 @@ partial class Dump
|
||||
var outputOptical = _outputPlugin as IWritableOpticalImage;
|
||||
|
||||
supportedPlextorSubchannel = supportedSubchannel switch
|
||||
{
|
||||
MmcSubchannel.None => PlextorSubchannel.None,
|
||||
MmcSubchannel.Raw => PlextorSubchannel.Pack,
|
||||
MmcSubchannel.Q16 => PlextorSubchannel.Q16,
|
||||
_ => PlextorSubchannel.None
|
||||
};
|
||||
{
|
||||
MmcSubchannel.None => PlextorSubchannel.None,
|
||||
MmcSubchannel.Raw => PlextorSubchannel.Pack,
|
||||
MmcSubchannel.Q16 => PlextorSubchannel.Q16,
|
||||
_ => PlextorSubchannel.None
|
||||
};
|
||||
|
||||
if(_resume.BadBlocks.Count <= 0 ||
|
||||
_aborted ||
|
||||
@@ -110,10 +110,10 @@ partial class Dump
|
||||
InitProgress?.Invoke();
|
||||
_trimStopwatch.Restart();
|
||||
|
||||
trimStart:
|
||||
trimStart:
|
||||
ulong[] tmpArray = _resume.BadBlocks.ToArray();
|
||||
|
||||
for(int b = 0; b < tmpArray.Length; b++)
|
||||
for(var b = 0; b < tmpArray.Length; b++)
|
||||
{
|
||||
ulong badSector = tmpArray[b];
|
||||
|
||||
@@ -131,7 +131,7 @@ partial class Dump
|
||||
Track track = tracks.OrderBy(t => t.StartSector).LastOrDefault(t => badSector >= t.StartSector);
|
||||
|
||||
byte sectorsToTrim = 1;
|
||||
uint badSectorToRead = (uint)badSector;
|
||||
var badSectorToRead = (uint)badSector;
|
||||
|
||||
if(_fixOffset &&
|
||||
audioExtents.Contains(badSector) &&
|
||||
@@ -149,8 +149,10 @@ partial class Dump
|
||||
}
|
||||
|
||||
if(_supportsPlextorD8 && audioExtents.Contains(badSector))
|
||||
{
|
||||
sense = ReadPlextorWithSubchannel(out cmdBuf, out senseBuf, badSectorToRead, blockSize, sectorsToTrim,
|
||||
supportedPlextorSubchannel, out cmdDuration);
|
||||
}
|
||||
else if(readcd)
|
||||
{
|
||||
if(audioExtents.Contains(badSector))
|
||||
@@ -202,17 +204,25 @@ partial class Dump
|
||||
totalDuration += cmdDuration;
|
||||
}
|
||||
else if(read16)
|
||||
{
|
||||
sense = _dev.Read16(out cmdBuf, out senseBuf, 0, false, true, false, badSectorToRead, blockSize, 0,
|
||||
sectorsToTrim, false, _dev.Timeout, out cmdDuration);
|
||||
}
|
||||
else if(read12)
|
||||
{
|
||||
sense = _dev.Read12(out cmdBuf, out senseBuf, 0, false, true, false, false, badSectorToRead, blockSize,
|
||||
0, sectorsToTrim, false, _dev.Timeout, out cmdDuration);
|
||||
}
|
||||
else if(read10)
|
||||
{
|
||||
sense = _dev.Read10(out cmdBuf, out senseBuf, 0, false, true, false, false, badSectorToRead, blockSize,
|
||||
0, sectorsToTrim, _dev.Timeout, out cmdDuration);
|
||||
}
|
||||
else if(read6)
|
||||
{
|
||||
sense = _dev.Read6(out cmdBuf, out senseBuf, badSectorToRead, blockSize, sectorsToTrim, _dev.Timeout,
|
||||
out cmdDuration);
|
||||
}
|
||||
|
||||
totalDuration += cmdDuration;
|
||||
|
||||
@@ -239,15 +249,15 @@ partial class Dump
|
||||
uint blocksToRead = sectorsToTrim;
|
||||
|
||||
FixOffsetData(offsetBytes, sectorSize, sectorsForOffset, supportedSubchannel, ref blocksToRead, subSize,
|
||||
ref cmdBuf, blockSize, false);
|
||||
ref cmdBuf, blockSize, false);
|
||||
}
|
||||
|
||||
if(supportedSubchannel != MmcSubchannel.None)
|
||||
{
|
||||
byte[] data = new byte[sectorSize];
|
||||
byte[] sub = new byte[subSize];
|
||||
Array.Copy(cmdBuf, 0, data, 0, sectorSize);
|
||||
Array.Copy(cmdBuf, sectorSize, sub, 0, subSize);
|
||||
var data = new byte[sectorSize];
|
||||
var sub = new byte[subSize];
|
||||
Array.Copy(cmdBuf, 0, data, 0, sectorSize);
|
||||
Array.Copy(cmdBuf, sectorSize, sub, 0, subSize);
|
||||
|
||||
if(supportsLongSectors)
|
||||
outputOptical.WriteSectorLong(data, badSector);
|
||||
|
||||
Reference in New Issue
Block a user