mirror of
https://github.com/aaru-dps/Aaru.git
synced 2025-12-16 19:24:25 +00:00
Add raw DVD reading with HL-DT-ST command (#823)
This commit is contained in:
committed by
GitHub
parent
a2c6b8961a
commit
1153a270a9
@@ -1,5 +1,6 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<state>
|
||||
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
|
||||
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" />
|
||||
</state>
|
||||
</component>
|
||||
213
Aaru.Core/Devices/Dumping/Sbc/Cache.cs
Normal file
213
Aaru.Core/Devices/Dumping/Sbc/Cache.cs
Normal file
@@ -0,0 +1,213 @@
|
||||
// /***************************************************************************
|
||||
// Aaru Data Preservation Suite
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Cache.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// --[ 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 <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// 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
|
||||
{
|
||||
/// <summary>
|
||||
/// Dumps data when dumping from a SCSI Block Commands compliant device,
|
||||
/// and reads the data from the device cache
|
||||
/// </summary>
|
||||
/// <param name="blocks">Media blocks</param>
|
||||
/// <param name="maxBlocksToRead">Maximum number of blocks to read in a single command</param>
|
||||
/// <param name="blockSize">Block size in bytes</param>
|
||||
/// <param name="currentTry">Resume information</param>
|
||||
/// <param name="extents">Correctly dump extents</param>
|
||||
/// <param name="currentSpeed">Current speed</param>
|
||||
/// <param name="minSpeed">Minimum speed</param>
|
||||
/// <param name="maxSpeed">Maximum speed</param>
|
||||
/// <param name="totalDuration">Total time spent in commands</param>
|
||||
/// <param name="scsiReader">SCSI reader</param>
|
||||
/// <param name="mhddLog">MHDD log</param>
|
||||
/// <param name="ibgLog">ImgBurn log</param>
|
||||
/// <param name="imageWriteDuration">Total time spent writing to image</param>
|
||||
/// <param name="newTrim">Set if we need to start a trim</param>
|
||||
/// <param name="discKey">The DVD disc key</param>
|
||||
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();
|
||||
}
|
||||
}
|
||||
@@ -159,7 +159,7 @@ partial class Dump
|
||||
|
||||
// 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[]
|
||||
{
|
||||
|
||||
@@ -775,11 +775,20 @@ partial class Dump
|
||||
ref newTrim, ref blankExtents);
|
||||
}
|
||||
else
|
||||
{
|
||||
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,
|
||||
mediaTags.TryGetValue(MediaTagType.DVD_DiscKey_Decrypted, out byte[] tag) ? tag : null);
|
||||
ref newTrim, ref dvdDecrypt, discKey ?? null);
|
||||
}
|
||||
}
|
||||
|
||||
_dumpStopwatch.Stop();
|
||||
|
||||
@@ -266,6 +266,13 @@ partial class Dump
|
||||
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);
|
||||
|
||||
|
||||
@@ -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 @@ sealed partial class Reader
|
||||
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 @@ sealed partial class Reader
|
||||
break;
|
||||
}
|
||||
|
||||
if(_hldtstReadRaw || _plextorReadRaw)
|
||||
if(HldtstReadRaw || _plextorReadRaw)
|
||||
{
|
||||
CanReadRaw = true;
|
||||
LongBlockSize = 2064;
|
||||
@@ -518,7 +519,7 @@ sealed partial class Reader
|
||||
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 @@ sealed partial class Reader
|
||||
|
||||
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 @@ sealed partial class Reader
|
||||
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)
|
||||
{
|
||||
|
||||
Submodule Aaru.Decoders updated: 089ba52732...fd04357f56
Submodule Aaru.Decryption updated: 605e00ed85...4a9bf0fa9d
@@ -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();
|
||||
|
||||
/// <summary>Reads a "raw" sector from DVD on HL-DT-ST drives.</summary>
|
||||
/// <returns><c>true</c> if the command failed and <paramref name="senseBuffer" /> contains the sense buffer.</returns>
|
||||
/// <param name="buffer">Buffer where the HL-DT-ST READ DVD (RAW) response will be stored</param>
|
||||
@@ -51,15 +58,17 @@ public partial class Device
|
||||
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 partial class Device
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Makes sure the data's sector number is the one expected.
|
||||
/// </summary>
|
||||
/// <param name="buffer">Data buffer</param>
|
||||
/// <param name="firstLba">First consecutive LBA of the buffer</param>
|
||||
/// <param name="transferLength">How many blocks to in buffer</param>
|
||||
/// <returns><c>false</c> if any sector is not matching expected value, else <c>true</c></returns>
|
||||
static bool CheckSectorNumber(IReadOnlyList<byte> 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;
|
||||
}
|
||||
}
|
||||
@@ -577,6 +577,39 @@ public sealed partial class AaruFormat
|
||||
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,23 @@ public sealed partial class AaruFormat
|
||||
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 ||
|
||||
_imageInfo.MediaType == MediaType.SACD ||
|
||||
_imageInfo.MediaType == MediaType.PS3DVD ||
|
||||
_imageInfo.MediaType == MediaType.DVDR ||
|
||||
_imageInfo.MediaType == MediaType.DVDRW ||
|
||||
_imageInfo.MediaType == MediaType.DVDPR ||
|
||||
_imageInfo.MediaType == MediaType.DVDPRW ||
|
||||
_imageInfo.MediaType == MediaType.DVDPRWDL ||
|
||||
_imageInfo.MediaType == MediaType.DVDRDL ||
|
||||
_imageInfo.MediaType == MediaType.DVDPRDL ||
|
||||
_imageInfo.MediaType == MediaType.DVDRAM ||
|
||||
_imageInfo.MediaType == MediaType.DVDRWDL ||
|
||||
_imageInfo.MediaType == MediaType.DVDDownload ||
|
||||
_imageInfo.MediaType == MediaType.Nuon
|
||||
))
|
||||
{
|
||||
sector = new byte[2048];
|
||||
_sectorId ??= new byte[_imageInfo.Sectors * 4];
|
||||
@@ -2444,6 +2493,21 @@ public sealed partial class AaruFormat
|
||||
switch(_imageInfo.MediaType)
|
||||
{
|
||||
case MediaType.DVDROM:
|
||||
case MediaType.PS2DVD:
|
||||
case MediaType.SACD:
|
||||
case MediaType.DVDROM:
|
||||
case MediaType.DVDR:
|
||||
case MediaType.DVDRW:
|
||||
case MediaType.DVDPR:
|
||||
case MediaType.DVDPRW:
|
||||
case MediaType.DVDPRWDL:
|
||||
case MediaType.DVDRDL:
|
||||
case MediaType.DVDPRDL:
|
||||
case MediaType.DVDRAM:
|
||||
case MediaType.DVDRWDL:
|
||||
case MediaType.DVDDownload:
|
||||
case MediaType.PS3DVD:
|
||||
case MediaType.Nuon:
|
||||
if(data.Length % 2064 != 0)
|
||||
{
|
||||
ErrorMessage = Localization.Incorrect_data_size;
|
||||
|
||||
@@ -1342,8 +1342,12 @@ public sealed partial class ZZZRawImage
|
||||
if(_rawDvd)
|
||||
{
|
||||
byte[] sector = br.ReadBytes((int)(sectorSize + sectorSkip + sectorOffset));
|
||||
sector = _decoding.Scramble(sector);
|
||||
Array.Copy(sector, sectorOffset, buffer, i * sectorSize, sectorSize);
|
||||
ErrorNumber error = _decoding.Scramble(sector, out byte[] scrambled);
|
||||
|
||||
if(error != ErrorNumber.NoError)
|
||||
return error;
|
||||
|
||||
Array.Copy(scrambled, sectorOffset, buffer, i * sectorSize, sectorSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1742,8 +1746,12 @@ public sealed partial class ZZZRawImage
|
||||
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);
|
||||
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)
|
||||
|
||||
Reference in New Issue
Block a user