Add support for negative sectors to read and write sector calls in images.

This commit is contained in:
2025-10-23 03:07:43 +01:00
parent 0c19fe1b11
commit 69738f5f1a
289 changed files with 2676 additions and 1352 deletions

View File

@@ -300,6 +300,7 @@ partial class Dump
outputOptical.WriteSectorsLong(data,
i + r,
false,
1,
Enumerable.Repeat(SectorStatus.Dumped, 1).ToArray());
@@ -333,7 +334,7 @@ partial class Dump
}
}
else
outputOptical.WriteSectorsLong(cmdBuf, i + r, 1, [SectorStatus.Dumped]);
outputOptical.WriteSectorsLong(cmdBuf, i + r, false, 1, [SectorStatus.Dumped]);
imageWriteDuration += _writeStopwatch.Elapsed.TotalSeconds;
@@ -410,6 +411,7 @@ partial class Dump
outputOptical.WriteSectorsLong(data,
i,
false,
blocksToRead,
Enumerable.Repeat(SectorStatus.Dumped, (int)blocksToRead).ToArray());
@@ -466,16 +468,20 @@ partial class Dump
outputOptical.WriteSectorsLong(data,
i,
false,
blocksToRead,
Enumerable.Repeat(SectorStatus.Dumped, (int)blocksToRead)
.ToArray());
}
else
{
outputOptical.WriteSectorsLong(cmdBuf,
i,
false,
blocksToRead,
Enumerable.Repeat(SectorStatus.Dumped, (int)blocksToRead)
.ToArray());
}
}
imageWriteDuration += _writeStopwatch.Elapsed.TotalSeconds;

View File

@@ -776,11 +776,14 @@ partial class Dump
Array.Copy(cmdBuf, sectorSize, sub, 0, subSize);
if(supportsLongSectors)
{
outputFormat.WriteSectorsLong(data,
i + r,
false,
1,
Enumerable.Repeat(SectorStatus.Dumped, (int)blocksToRead)
.ToArray());
}
else
{
var cooked = new MemoryStream();
@@ -795,6 +798,7 @@ partial class Dump
outputFormat.WriteSectors(cooked.ToArray(),
i,
false,
blocksToRead,
Enumerable.Repeat(SectorStatus.Dumped, (int)blocksToRead)
.ToArray());
@@ -844,7 +848,7 @@ partial class Dump
else
{
if(supportsLongSectors)
outputFormat.WriteSectorsLong(cmdBuf, i + r, 1, [SectorStatus.Dumped]);
outputFormat.WriteSectorsLong(cmdBuf, i + r, false, 1, [SectorStatus.Dumped]);
else
{
var cooked = new MemoryStream();
@@ -859,6 +863,7 @@ partial class Dump
outputFormat.WriteSectors(cooked.ToArray(),
i,
false,
blocksToRead,
Enumerable.Repeat(SectorStatus.Dumped, (int)blocksToRead)
.ToArray());
@@ -878,12 +883,17 @@ partial class Dump
if(supportedSubchannel != MmcSubchannel.None)
{
outputFormat.WriteSectorsLong(new byte[sectorSize], i + r, 1, [SectorStatus.Errored]);
outputFormat.WriteSectorsLong(new byte[sectorSize],
i + r,
false,
1,
[SectorStatus.Errored]);
if(desiredSubchannel != MmcSubchannel.None)
{
outputFormat.WriteSectorsTag(new byte[subSize],
i + r,
false,
1,
SectorTagType.CdSectorSubchannel);
}
@@ -891,16 +901,23 @@ partial class Dump
else
{
if(supportsLongSectors)
outputFormat.WriteSectorsLong(new byte[blockSize], i + r, 1, [SectorStatus.Errored]);
outputFormat.WriteSectorsLong(new byte[blockSize],
i + r,
false,
1,
[SectorStatus.Errored]);
else
{
if(cmdBuf.Length % sectorSize == 0)
outputFormat.WriteSectors(new byte[2048], i + r, 1, [SectorStatus.Errored]);
outputFormat.WriteSectors(new byte[2048], i + r, false, 1, [SectorStatus.Errored]);
else
{
outputFormat.WriteSectorsLong(new byte[blockSize],
i + r,
false,
1,
[SectorStatus.Errored]);
}
}
}
@@ -977,11 +994,14 @@ partial class Dump
}
if(supportsLongSectors)
{
outputFormat.WriteSectorsLong(data,
i,
false,
blocksToRead,
Enumerable.Repeat(SectorStatus.Dumped, (int)blocksToRead)
.ToArray());
}
else
{
var cooked = new MemoryStream();
@@ -996,6 +1016,7 @@ partial class Dump
outputFormat.WriteSectors(cooked.ToArray(),
i,
false,
blocksToRead,
Enumerable.Repeat(SectorStatus.Dumped, (int)blocksToRead).ToArray());
}
@@ -1043,11 +1064,14 @@ partial class Dump
else
{
if(supportsLongSectors)
{
outputFormat.WriteSectorsLong(cmdBuf,
i,
false,
blocksToRead,
Enumerable.Repeat(SectorStatus.Dumped, (int)blocksToRead)
.ToArray());
}
else
{
var cooked = new MemoryStream();
@@ -1062,6 +1086,7 @@ partial class Dump
outputFormat.WriteSectors(cooked.ToArray(),
i,
false,
blocksToRead,
Enumerable.Repeat(SectorStatus.Dumped, (int)blocksToRead).ToArray());
}
@@ -1097,6 +1122,7 @@ partial class Dump
{
outputFormat.WriteSectorsLong(new byte[sectorSize * _skip],
i,
false,
_skip,
Enumerable.Repeat(SectorStatus.NotDumped, (int)_skip).ToArray());
@@ -1104,6 +1130,7 @@ partial class Dump
{
outputFormat.WriteSectorsTag(new byte[subSize * _skip],
i,
false,
_skip,
SectorTagType.CdSectorSubchannel);
}
@@ -1111,23 +1138,32 @@ partial class Dump
else
{
if(supportsLongSectors)
{
outputFormat.WriteSectorsLong(new byte[blockSize * _skip],
i,
false,
_skip,
Enumerable.Repeat(SectorStatus.NotDumped, (int)_skip).ToArray());
}
else
{
if(cmdBuf.Length % sectorSize == 0)
{
outputFormat.WriteSectors(new byte[2048 * _skip],
i,
false,
_skip,
Enumerable.Repeat(SectorStatus.NotDumped, (int)_skip).ToArray());
}
else
{
outputFormat.WriteSectorsLong(new byte[blockSize * _skip],
i,
false,
_skip,
Enumerable.Repeat(SectorStatus.NotDumped, (int)_skip)
.ToArray());
}
}
}

View File

@@ -87,21 +87,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; // 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
@@ -113,11 +113,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 = [];
bool cdiReadyReadAsAudio = false;
var cdiReadyReadAsAudio = false;
uint firstLba;
var outputOptical = _outputPlugin as IWritableOpticalImage;
@@ -541,7 +541,7 @@ sealed partial class Dump
ErrorMessage?.Invoke(Localization.Core.Output_format_does_not_support_pregaps_continuing);
}
for(int t = 1; t < tracks.Length; t++) tracks[t - 1].EndSector = tracks[t].StartSector - 1;
for(var t = 1; t < tracks.Length; t++) tracks[t - 1].EndSector = tracks[t].StartSector - 1;
tracks[^1].EndSector = (ulong)lastSector;
blocks = (ulong)(lastSector + 1);
@@ -626,7 +626,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);
}
@@ -715,7 +715,7 @@ sealed partial class Dump
continue;
}
int bufOffset = 0;
var bufOffset = 0;
while(cmdBuf[0 + bufOffset] != 0x00 ||
cmdBuf[1 + bufOffset] != 0xFF ||
@@ -928,7 +928,7 @@ sealed partial class Dump
_dev.LastError));
}
bool cdiWithHiddenTrack1 = false;
var cdiWithHiddenTrack1 = false;
if(dskType is MediaType.CDIREADY && tracks.Min(t => t.Sequence) == 1)
{
@@ -978,7 +978,10 @@ sealed partial class Dump
{
foreach(Track imgTrack in outputOptical.Tracks)
{
errno = outputOptical.ReadSectorTag(imgTrack.Sequence, SectorTagType.CdTrackIsrc, out byte[] isrcBytes);
errno = outputOptical.ReadSectorTag(imgTrack.Sequence,
false,
SectorTagType.CdTrackIsrc,
out byte[] isrcBytes);
if(errno == ErrorNumber.NoError) isrcs[(byte)imgTrack.Sequence] = Encoding.ASCII.GetString(isrcBytes);
@@ -1041,7 +1044,7 @@ sealed partial class Dump
UpdateStatus?.Invoke(string.Format(Localization.Core.Setting_flags_for_track_0, track.Sequence));
outputOptical.WriteSectorTag([kvp.Value], kvp.Key, SectorTagType.CdTrackFlags);
outputOptical.WriteSectorTag([kvp.Value], kvp.Key, false, SectorTagType.CdTrackFlags);
}
// Set MCN
@@ -1079,8 +1082,9 @@ sealed partial class Dump
foreach(int sub in _resume.BadSubchannels) subchannelExtents.Add(sub);
if(_resume.NextBlock < blocks)
for(ulong i = _resume.NextBlock; i < blocks; i++)
subchannelExtents.Add((int)i);
{
for(ulong i = _resume.NextBlock; i < blocks; i++) subchannelExtents.Add((int)i);
}
}
if(_resume.NextBlock > 0)
@@ -1495,8 +1499,9 @@ sealed partial class Dump
supportsLongSectors);
foreach(Tuple<ulong, ulong> leadoutExtent in leadOutExtents.ToArray())
for(ulong e = leadoutExtent.Item1; e <= leadoutExtent.Item2; e++)
subchannelExtents.Remove((int)e);
{
for(ulong e = leadoutExtent.Item1; e <= leadoutExtent.Item2; e++) subchannelExtents.Remove((int)e);
}
if(subchannelExtents.Count > 0 && _retryPasses > 0 && _retrySubchannel)
{
@@ -1583,7 +1588,10 @@ sealed partial class Dump
foreach(KeyValuePair<byte, string> isrc in isrcs)
{
// TODO: Track tags
if(!outputOptical.WriteSectorTag(Encoding.ASCII.GetBytes(isrc.Value), isrc.Key, SectorTagType.CdTrackIsrc))
if(!outputOptical.WriteSectorTag(Encoding.ASCII.GetBytes(isrc.Value),
isrc.Key,
false,
SectorTagType.CdTrackIsrc))
continue;
UpdateStatus?.Invoke(string.Format(Localization.Core.Setting_ISRC_for_track_0_to_1, isrc.Key, isrc.Value));

View File

@@ -466,9 +466,8 @@ partial class Dump
// MEDIUM ERROR, retry with ignore error below
if(decSense is { ASC: 0x11 })
{
if(!sectorsNotEvenPartial.Contains(badSector)) sectorsNotEvenPartial.Add(badSector);
}
if(!sectorsNotEvenPartial.Contains(badSector))
sectorsNotEvenPartial.Add(badSector);
}
// Because one block has been partially used to fix the offset
@@ -510,9 +509,9 @@ partial class Dump
Array.Copy(cmdBuf, sectorSize, sub, 0, subSize);
if(supportsLongSectors)
outputOptical.WriteSectorLong(data, badSector, SectorStatus.Dumped);
outputOptical.WriteSectorLong(data, badSector, false, SectorStatus.Dumped);
else
outputOptical.WriteSector(Sector.GetUserData(data), badSector, SectorStatus.Dumped);
outputOptical.WriteSector(Sector.GetUserData(data), badSector, false, SectorStatus.Dumped);
bool indexesChanged = Media.CompactDisc.WriteSubchannelToImage(supportedSubchannel,
desiredSubchannel,
@@ -543,9 +542,9 @@ partial class Dump
else
{
if(supportsLongSectors)
outputOptical.WriteSectorLong(cmdBuf, badSector, SectorStatus.Dumped);
outputOptical.WriteSectorLong(cmdBuf, badSector, false, SectorStatus.Dumped);
else
outputOptical.WriteSector(Sector.GetUserData(cmdBuf), badSector, SectorStatus.Dumped);
outputOptical.WriteSector(Sector.GetUserData(cmdBuf), badSector, false, SectorStatus.Dumped);
}
}
@@ -663,9 +662,9 @@ partial class Dump
Array.Copy(cmdBuf, sectorSize, sub, 0, subSize);
if(supportsLongSectors)
outputOptical.WriteSectorLong(data, badSector, SectorStatus.Errored);
outputOptical.WriteSectorLong(data, badSector, false, SectorStatus.Errored);
else
outputOptical.WriteSector(Sector.GetUserData(data), badSector, SectorStatus.Errored);
outputOptical.WriteSector(Sector.GetUserData(data), badSector, false, SectorStatus.Errored);
bool indexesChanged = Media.CompactDisc.WriteSubchannelToImage(supportedSubchannel,
desiredSubchannel,
@@ -696,9 +695,12 @@ partial class Dump
else
{
if(supportsLongSectors)
outputOptical.WriteSectorLong(cmdBuf, badSector, SectorStatus.Errored);
outputOptical.WriteSectorLong(cmdBuf, badSector, false, SectorStatus.Errored);
else
outputOptical.WriteSector(Sector.GetUserData(cmdBuf), badSector, SectorStatus.Errored);
outputOptical.WriteSector(Sector.GetUserData(cmdBuf),
badSector,
false,
SectorStatus.Errored);
}
}

View File

@@ -217,6 +217,7 @@ partial class Dump
outputOptical.WriteSectorsLong(data,
i,
false,
_maximumReadable,
Enumerable.Repeat(SectorStatus.Dumped, (int)_maximumReadable)
.ToArray());
@@ -251,11 +252,14 @@ partial class Dump
}
}
else
{
outputOptical.WriteSectors(cmdBuf,
i,
false,
_maximumReadable,
Enumerable.Repeat(SectorStatus.Dumped, (int)_maximumReadable)
.ToArray());
}
imageWriteDuration += _writeStopwatch.Elapsed.TotalSeconds;
}
@@ -271,15 +275,16 @@ partial class Dump
if(supportedSubchannel != MmcSubchannel.None)
{
outputOptical.WriteSectorsLong(new byte[sectorSize * _skip], i, 1, new SectorStatus[1]);
outputOptical.WriteSectorsLong(new byte[sectorSize * _skip], i, false, 1, new SectorStatus[1]);
outputOptical.WriteSectorsTag(new byte[subSize * _skip],
i,
false,
1,
SectorTagType.CdSectorSubchannel);
}
else
outputOptical.WriteSectors(new byte[blockSize * _skip], i, 1, new SectorStatus[1]);
outputOptical.WriteSectors(new byte[blockSize * _skip], i, false, 1, new SectorStatus[1]);
imageWriteDuration += _writeStopwatch.Elapsed.TotalSeconds;
@@ -464,6 +469,7 @@ partial class Dump
outputOptical.WriteSectorsLong(data,
i,
false,
_maximumReadable,
Enumerable.Repeat(SectorStatus.Dumped, (int)_maximumReadable)
.ToArray());
@@ -498,11 +504,14 @@ partial class Dump
}
}
else
{
outputOptical.WriteSectors(cmdBuf,
i,
false,
_maximumReadable,
Enumerable.Repeat(SectorStatus.Dumped, (int)_maximumReadable)
.ToArray());
}
imageWriteDuration += _writeStopwatch.Elapsed.TotalSeconds;
}
@@ -518,18 +527,19 @@ partial class Dump
if(supportedSubchannel != MmcSubchannel.None)
{
outputOptical.WriteSectorsLong(new byte[sectorSize * _skip], i, 1, new SectorStatus[1]);
outputOptical.WriteSectorsLong(new byte[sectorSize * _skip], i, false, 1, new SectorStatus[1]);
if(desiredSubchannel != MmcSubchannel.None)
{
outputOptical.WriteSectorsTag(new byte[subSize * _skip],
i,
false,
1,
SectorTagType.CdSectorSubchannel);
}
}
else
outputOptical.WriteSectors(new byte[blockSize * _skip], i, 1, new SectorStatus[1]);
outputOptical.WriteSectors(new byte[blockSize * _skip], i, false, 1, new SectorStatus[1]);
imageWriteDuration += _writeStopwatch.Elapsed.TotalSeconds;

View File

@@ -102,9 +102,9 @@ partial class Dump
}
if(supportsLongSectors)
outputOptical.WriteSectorLong(sector, s, SectorStatus.Dumped);
outputOptical.WriteSectorLong(sector, s, false, SectorStatus.Dumped);
else
outputOptical.WriteSector(Sector.GetUserData(sector), s, SectorStatus.Dumped);
outputOptical.WriteSector(Sector.GetUserData(sector), s, false, SectorStatus.Dumped);
_resume.BadBlocks.Remove(s);
extents.Add(s);
@@ -145,7 +145,7 @@ partial class Dump
byte[] sub = Subchannel.Generate((int)s, track?.Sequence ?? 0, (int)pregap, (int)trackStart, flags, index);
outputOptical.WriteSectorsTag(sub, s, 1, SectorTagType.CdSectorSubchannel);
outputOptical.WriteSectorsTag(sub, s, false, 1, SectorTagType.CdSectorSubchannel);
subLog?.WriteEntry(sub, true, (long)s, 1, true, false);
subchannelExtents.Remove((int)s);

View File

@@ -424,9 +424,9 @@ partial class Dump
Array.Copy(cmdBuf, sectorSize, sub, 0, subSize);
if(supportsLongSectors)
outputOptical.WriteSectorLong(data, badSector, SectorStatus.Dumped);
outputOptical.WriteSectorLong(data, badSector, false, SectorStatus.Dumped);
else
outputOptical.WriteSector(Sector.GetUserData(data), badSector, SectorStatus.Dumped);
outputOptical.WriteSector(Sector.GetUserData(data), badSector, false, SectorStatus.Dumped);
ulong trkStartBefore = track.StartSector;
@@ -468,9 +468,9 @@ partial class Dump
}
if(supportsLongSectors)
outputOptical.WriteSectorLong(cmdBuf, badSector, SectorStatus.Dumped);
outputOptical.WriteSectorLong(cmdBuf, badSector, false, SectorStatus.Dumped);
else
outputOptical.WriteSector(Sector.GetUserData(cmdBuf), badSector, SectorStatus.Dumped);
outputOptical.WriteSector(Sector.GetUserData(cmdBuf), badSector, false, SectorStatus.Dumped);
}
_trimStopwatch.Stop();