diff --git a/.idea/.idea.Aaru/.idea/codeStyles/codeStyleConfig.xml b/.idea/.idea.Aaru/.idea/codeStyles/codeStyleConfig.xml
index 79ee123c2..6e6eec114 100644
--- a/.idea/.idea.Aaru/.idea/codeStyles/codeStyleConfig.xml
+++ b/.idea/.idea.Aaru/.idea/codeStyles/codeStyleConfig.xml
@@ -1,5 +1,6 @@
+
\ No newline at end of file
diff --git a/Aaru.Core/Devices/Dumping/Sbc/Cache.cs b/Aaru.Core/Devices/Dumping/Sbc/Cache.cs
new file mode 100644
index 000000000..c6e727ed4
--- /dev/null
+++ b/Aaru.Core/Devices/Dumping/Sbc/Cache.cs
@@ -0,0 +1,213 @@
+// /***************************************************************************
+// Aaru Data Preservation Suite
+// ----------------------------------------------------------------------------
+//
+// Filename : Cache.cs
+// Author(s) : Natalia Portillo
+//
+// --[ License ] --------------------------------------------------------------
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as
+// published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+//
+// ----------------------------------------------------------------------------
+// Copyright © 2011-2023 Natalia Portillo
+// Copyright © 2020-2023 Rebecca Wallander
+// ****************************************************************************/
+
+using System.Linq;
+using Aaru.CommonTypes.AaruMetadata;
+using Aaru.CommonTypes.Enums;
+using Aaru.CommonTypes.Extents;
+using Aaru.CommonTypes.Interfaces;
+using Aaru.Core.Logging;
+using Aaru.Decryption.DVD;
+using Humanizer;
+using Humanizer.Bytes;
+using DVDDecryption = Aaru.Decryption.DVD.Dump;
+
+// ReSharper disable JoinDeclarationAndInitializer
+// ReSharper disable InlineOutVariableDeclaration
+// ReSharper disable TooWideLocalVariableScope
+
+namespace Aaru.Core.Devices.Dumping;
+
+partial class Dump
+{
+ ///
+ /// Dumps data when dumping from a SCSI Block Commands compliant device,
+ /// and reads the data from the device cache
+ ///
+ /// Media blocks
+ /// Maximum number of blocks to read in a single command
+ /// Block size in bytes
+ /// Resume information
+ /// Correctly dump extents
+ /// Current speed
+ /// Minimum speed
+ /// Maximum speed
+ /// Total time spent in commands
+ /// SCSI reader
+ /// MHDD log
+ /// ImgBurn log
+ /// Total time spent writing to image
+ /// Set if we need to start a trim
+ /// The DVD disc key
+ void ReadCacheData(in ulong blocks, in uint maxBlocksToRead, in uint blockSize, DumpHardware currentTry,
+ ExtentsULong extents, ref double currentSpeed, ref double minSpeed, ref double maxSpeed,
+ ref double totalDuration, Reader scsiReader, MhddLog mhddLog, IbgLog ibgLog,
+ ref double imageWriteDuration, ref bool newTrim, byte[] discKey)
+ {
+ ulong sectorSpeedStart = 0;
+ bool sense;
+ byte[] buffer;
+ uint blocksToRead = maxBlocksToRead;
+ var outputFormat = _outputPlugin as IWritableImage;
+
+ InitProgress?.Invoke();
+
+ if(scsiReader.HldtstReadRaw && _resume.NextBlock > 0)
+ // The HL-DT-ST buffer is stored and read in 96-sector chunks. If we start to read at an LBA which is
+ // not modulo 96, the data will not be correctly fetched. Therefore, we begin every resume read with
+ // filling the buffer at a known offset.
+ // TODO: This is very ugly and there probably exist a more elegant way to solve this issue.
+ scsiReader.ReadBlock(out _, _resume.NextBlock - (_resume.NextBlock % 96) + 1, out _, out _, out _);
+
+ for(ulong i = _resume.NextBlock; i < blocks; i += blocksToRead)
+ {
+ if(_aborted)
+ {
+ currentTry.Extents = ExtentsConverter.ToMetadata(extents);
+ UpdateStatus?.Invoke(Localization.Core.Aborted);
+ _dumpLog.WriteLine(Localization.Core.Aborted);
+
+ break;
+ }
+
+ if(blocks - i < blocksToRead)
+ blocksToRead = (uint)(blocks - i);
+
+ if(currentSpeed > maxSpeed && currentSpeed > 0)
+ maxSpeed = currentSpeed;
+
+ if(currentSpeed < minSpeed && currentSpeed > 0)
+ 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);
+
+ sense = scsiReader.ReadBlocks(out buffer, i, blocksToRead, out double cmdDuration, out _, out _);
+ totalDuration += cmdDuration;
+
+ if(!sense && !_dev.Error)
+ {
+ mhddLog.Write(i, cmdDuration, blocksToRead);
+ ibgLog.Write(i, currentSpeed * 1024);
+
+ _writeStopwatch.Restart();
+
+ byte[] tmpBuf;
+ byte[] cmi = new byte[blocksToRead];
+
+ for(uint j = 0; j < blocksToRead; j++)
+ {
+ byte[] key = buffer.Skip((int)((2064 * j) + 7)).Take(5).ToArray();
+
+ if(key.All(static k => k == 0))
+ {
+ outputFormat.WriteSectorTag(new byte[]
+ {
+ 0, 0, 0, 0, 0
+ }, i + j, SectorTagType.DvdTitleKeyDecrypted);
+
+ _resume.MissingTitleKeys.Remove(i + j);
+
+ continue;
+ }
+
+ CSS.DecryptTitleKey(discKey, key, out tmpBuf);
+ outputFormat.WriteSectorTag(tmpBuf, i + j, SectorTagType.DvdTitleKeyDecrypted);
+ _resume.MissingTitleKeys.Remove(i + j);
+
+ if(_storeEncrypted)
+ continue;
+
+ cmi[j] = buffer[2064 * j + 6];
+ }
+
+ // Todo: Flag in the outputFormat that a sector has been decrypted
+ if(!_storeEncrypted)
+ {
+ ErrorNumber errno =
+ outputFormat.ReadSectorsTag(i, blocksToRead, SectorTagType.DvdTitleKeyDecrypted,
+ out byte[] titleKey);
+
+ if(errno != ErrorNumber.NoError)
+ ErrorMessage?.Invoke(string.Format(Localization.Core.Error_retrieving_title_key_for_sector_0,
+ i));
+ else
+ buffer = CSS.DecryptSectorLong(buffer, titleKey, cmi, blocksToRead);
+ }
+
+ outputFormat.WriteSectorsLong(buffer, i, blocksToRead);
+
+ imageWriteDuration += _writeStopwatch.Elapsed.TotalSeconds;
+ extents.Add(i, blocksToRead, true);
+ _mediaGraph?.PaintSectorsGood(i, blocksToRead);
+ }
+ else
+ {
+ // TODO: Reset device after X errors
+ if(_stopOnError)
+ return; // TODO: Return more cleanly
+
+ if(i + _skip > blocks)
+ _skip = (uint)(blocks - i);
+
+ // Write empty data
+ _writeStopwatch.Restart();
+ outputFormat.WriteSectors(new byte[blockSize * _skip], i, _skip);
+ imageWriteDuration += _writeStopwatch.Elapsed.TotalSeconds;
+
+ for(ulong b = i; b < i + _skip; b++)
+ _resume.BadBlocks.Add(b);
+
+ mhddLog.Write(i, cmdDuration < 500 ? 65535 : cmdDuration, _skip);
+
+ ibgLog.Write(i, 0);
+ _dumpLog.WriteLine(Localization.Core.Skipping_0_blocks_from_errored_block_1, _skip, i);
+ i += _skip - blocksToRead;
+ newTrim = true;
+ }
+
+ _writeStopwatch.Stop();
+ sectorSpeedStart += blocksToRead;
+ _resume.NextBlock = i + blocksToRead;
+
+ double elapsed = _speedStopwatch.Elapsed.TotalSeconds;
+
+ if(elapsed <= 0)
+ continue;
+
+ currentSpeed = sectorSpeedStart * blockSize / (1048576 * elapsed);
+ sectorSpeedStart = 0;
+ _speedStopwatch.Restart();
+ }
+
+ _speedStopwatch.Stop();
+ _resume.BadBlocks = _resume.BadBlocks.Distinct().ToList();
+
+ EndProgress?.Invoke();
+ }
+}
\ No newline at end of file
diff --git a/Aaru.Core/Devices/Dumping/Sbc/Data.cs b/Aaru.Core/Devices/Dumping/Sbc/Data.cs
index 1e6da47f4..67f94ec0c 100644
--- a/Aaru.Core/Devices/Dumping/Sbc/Data.cs
+++ b/Aaru.Core/Devices/Dumping/Sbc/Data.cs
@@ -159,7 +159,7 @@ void ReadSbcData(in ulong blocks, in uint maxBlocksToRead, in uint blockSize
// According to libdvdcss, if the key is all zeroes, the sector is actually
// not encrypted even if the CMI says it is.
- if(titleKey.Value.Key.All(k => k == 0))
+ if(titleKey.Value.Key.All(static k => k == 0))
{
outputFormat.WriteSectorTag(new byte[]
{
diff --git a/Aaru.Core/Devices/Dumping/Sbc/Dump.cs b/Aaru.Core/Devices/Dumping/Sbc/Dump.cs
index f51dcb145..d577bb234 100644
--- a/Aaru.Core/Devices/Dumping/Sbc/Dump.cs
+++ b/Aaru.Core/Devices/Dumping/Sbc/Dump.cs
@@ -776,10 +776,19 @@ void Sbc(Dictionary mediaTags, MediaType dskType, bool opt
}
else
{
- ReadSbcData(blocks, blocksToRead, blockSize, currentTry, extents, ref currentSpeed, ref minSpeed,
- ref maxSpeed, ref totalDuration, scsiReader, mhddLog, ibgLog, ref imageWriteDuration,
- ref newTrim, ref dvdDecrypt,
- mediaTags.TryGetValue(MediaTagType.DVD_DiscKey_Decrypted, out byte[] tag) ? tag : null);
+ mediaTags.TryGetValue(MediaTagType.DVD_DiscKey_Decrypted, out byte[] discKey);
+ if(scsiReader.HldtstReadRaw)
+ {
+ ReadCacheData(blocks, blocksToRead, blockSize, currentTry, extents, ref currentSpeed, ref minSpeed,
+ ref maxSpeed, ref totalDuration, scsiReader, mhddLog, ibgLog, ref imageWriteDuration,
+ ref newTrim, discKey ?? null);
+ }
+ else
+ {
+ ReadSbcData(blocks, blocksToRead, blockSize, currentTry, extents, ref currentSpeed, ref minSpeed,
+ ref maxSpeed, ref totalDuration, scsiReader, mhddLog, ibgLog, ref imageWriteDuration,
+ ref newTrim, ref dvdDecrypt, discKey ?? null);
+ }
}
_dumpStopwatch.Stop();
diff --git a/Aaru.Core/Devices/Dumping/Sbc/Error.cs b/Aaru.Core/Devices/Dumping/Sbc/Error.cs
index 61aeee883..4c8203bdd 100644
--- a/Aaru.Core/Devices/Dumping/Sbc/Error.cs
+++ b/Aaru.Core/Devices/Dumping/Sbc/Error.cs
@@ -266,6 +266,13 @@ void RetrySbcData(Reader scsiReader, DumpHardware currentTry, ExtentsULong
pass));
}
+ if(scsiReader.HldtstReadRaw)
+ // The HL-DT-ST buffer is stored and read in 96-sector chunks. If we start to read at an LBA which is
+ // not modulo 96, the data will not be correctly fetched. Therefore, we begin every recovery read with
+ // filling the buffer at a known offset.
+ // TODO: This is very ugly and there probably exist a more elegant way to solve this issue.
+ scsiReader.ReadBlock(out _, badSector - (badSector % 96) + 1, out _, out _, out _);
+
sense = scsiReader.ReadBlock(out buffer, badSector, out double cmdDuration, out recoveredError,
out blankCheck);
diff --git a/Aaru.Core/Devices/ReaderSCSI.cs b/Aaru.Core/Devices/ReaderSCSI.cs
index a43fa5543..43df1f1b7 100644
--- a/Aaru.Core/Devices/ReaderSCSI.cs
+++ b/Aaru.Core/Devices/ReaderSCSI.cs
@@ -31,6 +31,7 @@
// ****************************************************************************/
using System;
+using System.Linq;
using Aaru.CommonTypes.Structs.Devices.SCSI;
using Aaru.Console;
using Aaru.Decoders.SCSI;
@@ -40,7 +41,7 @@ namespace Aaru.Core.Devices;
sealed partial class Reader
{
// TODO: Raw reading
- bool _hldtstReadRaw;
+ public bool HldtstReadRaw;
bool _plextorReadRaw;
bool _read10;
bool _read12;
@@ -478,7 +479,7 @@ bool ScsiFindReadCommand()
switch(_dev.Manufacturer)
{
case "HL-DT-ST":
- _hldtstReadRaw = !_dev.HlDtStReadRawDvd(out _, out senseBuf, 0, 1, _timeout, out _);
+ HldtstReadRaw = !_dev.HlDtStReadRawDvd(out _, out senseBuf, 0, 1, _timeout, out _);
break;
case "PLEXTOR":
@@ -487,7 +488,7 @@ bool ScsiFindReadCommand()
break;
}
- if(_hldtstReadRaw || _plextorReadRaw)
+ if(HldtstReadRaw || _plextorReadRaw)
{
CanReadRaw = true;
LongBlockSize = 2064;
@@ -518,7 +519,7 @@ bool ScsiFindReadCommand()
AaruConsole.WriteLine(Localization.Core.Using_SyQuest_READ_LONG_10_command);
else if(_syqReadLong6)
AaruConsole.WriteLine(Localization.Core.Using_SyQuest_READ_LONG_6_command);
- else if(_hldtstReadRaw)
+ else if(HldtstReadRaw)
AaruConsole.WriteLine(Localization.Core.Using_HL_DT_ST_raw_DVD_reading);
else if(_plextorReadRaw)
AaruConsole.WriteLine(Localization.Core.Using_Plextor_raw_DVD_reading);
@@ -584,7 +585,11 @@ bool ScsiGetBlocksToRead(uint startWithBlocks)
while(true)
{
- if(_read6)
+ if(HldtstReadRaw)
+ {
+ BlocksToRead = 1;
+ }
+ else if(_read6)
{
_dev.Read6(out _, out _, 0, LogicalBlockSize, (byte)BlocksToRead, _timeout, out _);
@@ -668,10 +673,13 @@ bool ScsiReadBlocks(out byte[] buffer, ulong block, uint count, out double durat
sense = _dev.SyQuestReadLong6(out buffer, out senseBuf, (uint)block, LongBlockSize, _timeout,
out duration);
}
- else if(_hldtstReadRaw)
+ else if(HldtstReadRaw)
{
- sense = _dev.HlDtStReadRawDvd(out buffer, out senseBuf, (uint)block, LongBlockSize, _timeout,
- out duration);
+ // We need to fill the buffer before reading it with the HL-DT-ST command. We don't care about sense,
+ // because the data can be wrong anyway, so we need to check the buffer data instead.
+ _dev.Read12(out buffer, out senseBuf, 0, false, false, false, false, (uint)(block), LogicalBlockSize, 0,
+ 16, false, _timeout, out duration);
+ sense = _dev.HlDtStReadRawDvd(out buffer, out senseBuf, (uint)block, count, _timeout, out duration);
}
else if(_plextorReadRaw)
{
diff --git a/Aaru.Decoders b/Aaru.Decoders
index 089ba5273..a0bb12a7c 160000
--- a/Aaru.Decoders
+++ b/Aaru.Decoders
@@ -1 +1 @@
-Subproject commit 089ba527329920d2106af7f7d190a8bcb3f37a13
+Subproject commit a0bb12a7c681239ab196a080e6891cd2a4811693
diff --git a/Aaru.Decryption b/Aaru.Decryption
index 605e00ed8..3aa48889d 160000
--- a/Aaru.Decryption
+++ b/Aaru.Decryption
@@ -1 +1 @@
-Subproject commit 605e00ed85de6a875ff930b039565460ba43c7df
+Subproject commit 3aa48889dd89ef22d346328bda8e23668dcd196a
diff --git a/Aaru.Devices/Device/ScsiCommands/HL-DT-ST.cs b/Aaru.Devices/Device/ScsiCommands/HL-DT-ST.cs
index b4f9d0cb3..2deeea2ca 100644
--- a/Aaru.Devices/Device/ScsiCommands/HL-DT-ST.cs
+++ b/Aaru.Devices/Device/ScsiCommands/HL-DT-ST.cs
@@ -30,12 +30,19 @@
// Copyright © 2011-2023 Natalia Portillo
// ****************************************************************************/
+using System;
+using System.Collections.Generic;
+using Aaru.CommonTypes.Enums;
using Aaru.Console;
+using Aaru.Decoders.DVD;
+using Aaru.Helpers;
namespace Aaru.Devices;
public partial class Device
{
+ readonly Sector _decoding = new();
+
/// Reads a "raw" sector from DVD on HL-DT-ST drives.
/// true if the command failed and contains the sense buffer.
/// Buffer where the HL-DT-ST READ DVD (RAW) response will be stored
@@ -51,15 +58,17 @@ public bool HlDtStReadRawDvd(out byte[] buffer, out byte[] senseBuffer, uint lba
var cdb = new byte[12];
buffer = new byte[2064 * transferLength];
+ uint cacheDataOffset = 0x80000000 + (lba % 96 * 2064);
+
cdb[0] = (byte)ScsiCommands.HlDtStVendor;
cdb[1] = 0x48;
cdb[2] = 0x49;
cdb[3] = 0x54;
cdb[4] = 0x01;
- cdb[6] = (byte)((lba & 0xFF000000) >> 24);
- cdb[7] = (byte)((lba & 0xFF0000) >> 16);
- cdb[8] = (byte)((lba & 0xFF00) >> 8);
- cdb[9] = (byte)(lba & 0xFF);
+ cdb[6] = (byte)((cacheDataOffset & 0xFF000000) >> 24);
+ cdb[7] = (byte)((cacheDataOffset & 0xFF0000) >> 16);
+ cdb[8] = (byte)((cacheDataOffset & 0xFF00) >> 8);
+ cdb[9] = (byte)(cacheDataOffset & 0xFF);
cdb[10] = (byte)((buffer.Length & 0xFF00) >> 8);
cdb[11] = (byte)(buffer.Length & 0xFF);
@@ -70,6 +79,38 @@ public bool HlDtStReadRawDvd(out byte[] buffer, out byte[] senseBuffer, uint lba
AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.HL_DT_ST_READ_DVD_RAW_took_0_ms, duration);
+ if(!CheckSectorNumber(buffer, lba, transferLength))
+ return true;
+
+ if(_decoding.Scramble(buffer, transferLength, out byte[] scrambledBuffer) != ErrorNumber.NoError)
+ return true;
+
+ buffer = scrambledBuffer;
return sense;
}
+
+ ///
+ /// Makes sure the data's sector number is the one expected.
+ ///
+ /// Data buffer
+ /// First consecutive LBA of the buffer
+ /// How many blocks to in buffer
+ /// false if any sector is not matching expected value, else true
+ static bool CheckSectorNumber(IReadOnlyList buffer, uint firstLba, uint transferLength)
+ {
+ for(int i = 0; i < transferLength; i++)
+ {
+ byte[] sectorBuffer =
+ {
+ 0x0, buffer[1 + (2064 * i)], buffer[2 + (2064 * i)], buffer[3 + (2064 * i)]
+ };
+
+ uint sectorNumber = BigEndianBitConverter.ToUInt32(sectorBuffer, 0);
+
+ if(sectorNumber != firstLba + i + 0x30000)
+ return false;
+ }
+
+ return true;
+ }
}
\ No newline at end of file
diff --git a/Aaru.Images/AaruFormat/Write.cs b/Aaru.Images/AaruFormat/Write.cs
index 8a6dcc493..e693fe7e2 100644
--- a/Aaru.Images/AaruFormat/Write.cs
+++ b/Aaru.Images/AaruFormat/Write.cs
@@ -577,6 +577,39 @@ public bool Create(string path, MediaType mediaType, Dictionary
AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Memory_snapshot_0_bytes,
GC.GetTotalMemory(false));
+ break;
+ case DataType.DvdSectorId:
+ _sectorId = data;
+
+ if(!_imageInfo.ReadableSectorTags.Contains(SectorTagType.DvdSectorInformation))
+ _imageInfo.ReadableSectorTags.Add(SectorTagType.DvdSectorInformation);
+
+ if(!_imageInfo.ReadableSectorTags.Contains(SectorTagType.DvdSectorNumber))
+ _imageInfo.ReadableSectorTags.Add(SectorTagType.DvdSectorNumber);
+
+ AaruConsole.DebugWriteLine("Aaru Format plugin", Localization.Memory_snapshot_0_bytes,
+ GC.GetTotalMemory(false));
+
+ break;
+ case DataType.DvdSectorIed:
+ _sectorIed = data;
+
+ if(!_imageInfo.ReadableSectorTags.Contains(SectorTagType.DvdSectorIed))
+ _imageInfo.ReadableSectorTags.Add(SectorTagType.DvdSectorIed);
+
+ AaruConsole.DebugWriteLine("Aaru Format plugin", Localization.Memory_snapshot_0_bytes,
+ GC.GetTotalMemory(false));
+
+ break;
+ case DataType.DvdSectorEdc:
+ _sectorEdc = data;
+
+ if(!_imageInfo.ReadableSectorTags.Contains(SectorTagType.DvdSectorEdc))
+ _imageInfo.ReadableSectorTags.Add(SectorTagType.DvdSectorEdc);
+
+ AaruConsole.DebugWriteLine("Aaru Format plugin", Localization.Memory_snapshot_0_bytes,
+ GC.GetTotalMemory(false));
+
break;
default:
MediaTagType mediaTagType = GetMediaTagTypeForDataType(blockHeader.type);
@@ -2025,7 +2058,9 @@ public bool WriteSectorLong(byte[] data, ulong sectorAddress)
if(track.Sequence == 0 && track.StartSector == 0 && track.EndSector == 0)
track.Type = TrackType.Data;
- if(data.Length == 2064 && _imageInfo.MediaType == MediaType.DVDROM)
+ if(data.Length == 2064 &&
+ (_imageInfo.MediaType == MediaType.DVDROM ||
+ _imageInfo.MediaType == MediaType.PS2DVD))
{
sector = new byte[2048];
_sectorId ??= new byte[_imageInfo.Sectors * 4];
@@ -2444,6 +2479,7 @@ public bool WriteSectorsLong(byte[] data, ulong sectorAddress, uint length)
switch(_imageInfo.MediaType)
{
case MediaType.DVDROM:
+ case MediaType.PS2DVD:
if(data.Length % 2064 != 0)
{
ErrorMessage = Localization.Incorrect_data_size;
diff --git a/Aaru.Images/ZZZRawImage/Read.cs b/Aaru.Images/ZZZRawImage/Read.cs
index ceaa2c75f..cbaa249d8 100644
--- a/Aaru.Images/ZZZRawImage/Read.cs
+++ b/Aaru.Images/ZZZRawImage/Read.cs
@@ -1341,9 +1341,13 @@ public ErrorNumber ReadSectors(ulong sectorAddress, uint length, out byte[] buff
{
if(_rawDvd)
{
- byte[] sector = br.ReadBytes((int)(sectorSize + sectorSkip + sectorOffset));
- sector = _decoding.Scramble(sector);
- Array.Copy(sector, sectorOffset, buffer, i * sectorSize, sectorSize);
+ byte[] sector = br.ReadBytes((int)(sectorSize + sectorSkip + sectorOffset));
+ ErrorNumber error = _decoding.Scramble(sector, out byte[] scrambled);
+
+ if(error != ErrorNumber.NoError)
+ return error;
+
+ Array.Copy(scrambled, sectorOffset, buffer, i * sectorSize, sectorSize);
}
else
{
@@ -1741,9 +1745,13 @@ public ErrorNumber ReadSectorsLong(ulong sectorAddress, uint length, out byte[]
{
for(var i = 0; i < length; i++)
{
- byte[] sector = br.ReadBytes((int)sectorSize);
- sector = _decoding.Scramble(sector);
- Array.Copy(sector, 0, buffer, i * sectorSize, sectorSize);
+ byte[] sector = br.ReadBytes((int)sectorSize);
+ ErrorNumber error = _decoding.Scramble(sector, out byte[] scrambled);
+
+ if(error != ErrorNumber.NoError)
+ return error;
+
+ Array.Copy(scrambled, 0, buffer, i * sectorSize, sectorSize);
}
}
else if(sectorSkip == 0)