From 9d310890a068e1aafaf16a4fb0f815641e1090b3 Mon Sep 17 00:00:00 2001 From: Rebecca Wallander Date: Wed, 15 Apr 2026 12:32:01 +0200 Subject: [PATCH] Add Omnidrive BD raw support --- Aaru.Core/Devices/Dumping/Sbc/Dump.cs | 70 ++-- Aaru.Core/Devices/Dumping/Sbc/Error.cs | 8 + Aaru.Core/Devices/Dumping/Sbc/RawBd.cs | 320 ++++++++++++++++++ Aaru.Core/Devices/Dumping/Sbc/Trim.cs | 8 + Aaru.Core/Devices/Reader.cs | 5 +- Aaru.Core/Devices/ReaderSCSI.cs | 49 ++- Aaru.Decoders/Bluray/DI.cs | 8 + Aaru.Decoders/Bluray/DataFrame.cs | 5 +- Aaru.Devices/Device/ScsiCommands/OmniDrive.cs | 64 +++- Aaru.Localization/Core.Designer.cs | 6 + Aaru.Localization/Core.es.resx | 3 + Aaru.Localization/Core.resx | 3 + 12 files changed, 509 insertions(+), 40 deletions(-) create mode 100644 Aaru.Core/Devices/Dumping/Sbc/RawBd.cs diff --git a/Aaru.Core/Devices/Dumping/Sbc/Dump.cs b/Aaru.Core/Devices/Dumping/Sbc/Dump.cs index eff0b5830..16fe2717d 100644 --- a/Aaru.Core/Devices/Dumping/Sbc/Dump.cs +++ b/Aaru.Core/Devices/Dumping/Sbc/Dump.cs @@ -1,4 +1,4 @@ -// /*************************************************************************** +// /*************************************************************************** // Aaru Data Preservation Suite // ---------------------------------------------------------------------------- // @@ -80,6 +80,7 @@ partial class Dump var containsFloppyPage = false; const ushort sbcProfile = 0x0001; const uint DvdLeadinSectors = 4096; // Usable Lead-in before LBA 0 per DVD spec (PSN 0x02F000–0x02FFFF) + const uint BdFallbackNegativeSectors = 4832 * 32; // Usable lead-in clusters before LBA 0 per BD spec double totalDuration = 0; double currentSpeed = 0; double maxSpeed = double.MinValue; @@ -237,7 +238,7 @@ partial class Dump break; } - if(scsiReader.FindReadCommand()) + if(scsiReader.FindReadCommand(dskType)) { AaruLogging.WriteLine(Localization.Core.ERROR_Cannot_find_correct_read_command_0, scsiReader.ErrorMessage); StoppingErrorMessage?.Invoke(Localization.Core.Unable_to_read_medium); @@ -327,7 +328,7 @@ partial class Dump scsiReader.otp = decodedPfi?.TrackPath ?? false; if(scsiReader.HldtstReadRaw) blocksToRead = 1; - if(scsiReader.OmniDriveReadRaw) blocksToRead = 31; + if(scsiReader.OmniDriveReadRaw) blocksToRead = scsiReader.OmniDriveReadRawBluray ? 7u : 31u; UpdateStatus?.Invoke(string.Format(Localization.Core.Reading_0_raw_bytes_1_cooked_bytes_per_sector, longBlockSize, @@ -442,7 +443,8 @@ partial class Dump mediaTags.TryGetValue(MediaTagType.BD_DI, out byte[] di); DI.DiscInformation? decodedDi = DI.Decode(di); - if(decodedDi.HasValue) nominalNegativeSectors = decodedDi.Value.Units[0].FirstAun; + if(scsiReader.OmniDriveReadRawBluray) + nominalNegativeSectors = BdFallbackNegativeSectors; sense = _dev.ReadDiscInformation(out byte[] readBuffer, out _, @@ -871,35 +873,53 @@ partial class Dump if(scsiReader.HldtstReadRaw || scsiReader.ReadBuffer3CReadRaw || scsiReader.OmniDriveReadRaw) { - uint nominalForRawDvd = 0; - uint overflowForRawDvd = 0; + uint nominalForRaw = 0; + uint overflowForRaw = 0; if(scsiReader.OmniDriveReadRaw && outputFormat is IWritableOpticalImage optImg) { if(optImg.OpticalCapabilities.HasFlag(OpticalImageCapabilities.CanStoreNegativeSectors)) - nominalForRawDvd = nominalNegativeSectors; + nominalForRaw = nominalNegativeSectors; if(optImg.OpticalCapabilities.HasFlag(OpticalImageCapabilities.CanStoreOverflowSectors)) - overflowForRawDvd = 100u; + overflowForRaw = scsiReader.OmniDriveReadRawBluray ? 0x432u : 100u; } - ReadRawDvdData(blocks, - blocksToRead, - blockSize, - currentTry, - extents, - ref currentSpeed, - ref minSpeed, - ref maxSpeed, - ref totalDuration, - scsiReader, - mhddLog, - ibgLog, - ref imageWriteDuration, - ref newTrim, - discKey ?? null, - nominalForRawDvd, - overflowForRawDvd); + if(scsiReader.OmniDriveReadRawBluray) + ReadRawBdData(blocks, + blocksToRead, + blockSize, + currentTry, + extents, + ref currentSpeed, + ref minSpeed, + ref maxSpeed, + ref totalDuration, + scsiReader, + mhddLog, + ibgLog, + ref imageWriteDuration, + ref newTrim, + nominalForRaw, + overflowForRaw); + else + ReadRawDvdData(blocks, + blocksToRead, + blockSize, + currentTry, + extents, + ref currentSpeed, + ref minSpeed, + ref maxSpeed, + ref totalDuration, + scsiReader, + mhddLog, + ibgLog, + ref imageWriteDuration, + ref newTrim, + discKey ?? null, + nominalForRaw, + overflowForRaw); } else { diff --git a/Aaru.Core/Devices/Dumping/Sbc/Error.cs b/Aaru.Core/Devices/Dumping/Sbc/Error.cs index 42bc32f5c..ccf7f25a3 100644 --- a/Aaru.Core/Devices/Dumping/Sbc/Error.cs +++ b/Aaru.Core/Devices/Dumping/Sbc/Error.cs @@ -342,6 +342,14 @@ partial class Dump } else { + if(scsiReader.OmniDriveReadRawBluray) + { + _resume.BadBlocks.Remove(badSector); + outputFormat.WriteSectorLong(buffer, badSector, false, SectorStatus.Dumped); + + continue; + } + var cmi = new byte[1]; byte[] key = buffer.Skip(7).Take(5).ToArray(); diff --git a/Aaru.Core/Devices/Dumping/Sbc/RawBd.cs b/Aaru.Core/Devices/Dumping/Sbc/RawBd.cs new file mode 100644 index 000000000..4d91beb48 --- /dev/null +++ b/Aaru.Core/Devices/Dumping/Sbc/RawBd.cs @@ -0,0 +1,320 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : RawBd.cs +// Author(s) : Rebecca Wallander +// +// --[ 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-2026 Natalia Portillo +// Copyright © 2020-2026 Rebecca Wallander +// ****************************************************************************/ + +using System; +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.Logging; +using Humanizer; + +// ReSharper disable JoinDeclarationAndInitializer +// ReSharper disable InlineOutVariableDeclaration +// ReSharper disable TooWideLocalVariableScope + +namespace Aaru.Core.Devices.Dumping; + +partial class Dump +{ + /// + /// Dumps raw Blu-ray sectors (2052-byte DataFrames) when dumping from a SCSI Block Commands compliant device. + /// Supports OmniDrive raw reading. + /// + /// 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 + /// Lead-in sectors to read when drive and format supports negative sectors + /// Leadout sectors to read when drive and format supports overflow sectors + void ReadRawBdData(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, uint nominalNegativeSectors, + uint overflowSectors) + { + ulong sectorSpeedStart = 0; + bool sense; + byte[] buffer; + uint blocksToRead = maxBlocksToRead; + var outputFormat = _outputPlugin as IWritableImage; + + if(outputFormat is null) + { + ErrorMessage?.Invoke(Localization.Core.Output_format_not_initialized); + return; + } + + InitProgress?.Invoke(); + + // Phase 1: Lead-in (negative LBA) — OmniDrive only. Read from nominalNegativeSectors up to -1. + if(nominalNegativeSectors > 0) + { + UpdateStatus?.Invoke(Localization.Core.Reading_lead_in_sectors); + + for(ulong sectorAddress = nominalNegativeSectors; sectorAddress >= 1;) + { + if(_aborted) + { + currentTry.Extents = ExtentsConverter.ToMetadata(extents); + UpdateStatus?.Invoke(Localization.Core.Aborted); + + break; + } + + uint toRead = (uint)Math.Min(sectorAddress, blocksToRead); + + 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, + sectorAddress, + nominalNegativeSectors, + ByteSize.FromMegabytes(currentSpeed).Per(_oneSecond).Humanize()), + (long)(nominalNegativeSectors - sectorAddress + toRead), + (long)nominalNegativeSectors); + + sense = scsiReader.ReadBlocks(out buffer, sectorAddress, toRead, out double cmdDuration, out _, out _, true); + totalDuration += cmdDuration; + + if(!sense && !_dev.Error) + { + mhddLog.Write((ulong)-(long)sectorAddress, cmdDuration, toRead); + ibgLog.Write((ulong)-(long)sectorAddress, currentSpeed * 1024); + + // ReadBlocks returns sectors in logical order (-N..-1); WriteSectorsLong expects ascending order. + byte[] writeBuffer = new byte[buffer.Length]; + for(uint i = 0; i < toRead; i++) + Array.Copy(buffer, (int)(i * blockSize), writeBuffer, (int)((toRead - 1 - i) * blockSize), + (int)blockSize); + + _writeStopwatch.Restart(); + outputFormat.WriteSectorsLong(writeBuffer, + sectorAddress - toRead + 1, + true, + toRead, + Enumerable.Repeat(SectorStatus.Dumped, (int)toRead).ToArray()); + imageWriteDuration += _writeStopwatch.Elapsed.TotalSeconds; + _writeStopwatch.Stop(); + } + else + { + if(_stopOnError) return; + + _writeStopwatch.Restart(); + outputFormat.WriteSectorsLong(new byte[blockSize * toRead], + sectorAddress, + true, + toRead, + Enumerable.Repeat(SectorStatus.NotDumped, (int)toRead).ToArray()); + imageWriteDuration += _writeStopwatch.Elapsed.TotalSeconds; + _writeStopwatch.Stop(); + } + + if(sectorAddress <= 1) break; + sectorAddress -= toRead; + sectorSpeedStart += toRead; + double elapsed = _speedStopwatch.Elapsed.TotalSeconds; + if(elapsed > 0) + { + currentSpeed = (double)sectorSpeedStart * blockSize / (1048576d * elapsed); + sectorSpeedStart = 0; + _speedStopwatch.Restart(); + } + } + + UpdateStatus?.Invoke(Localization.Core.Reading_data_sectors); + } + + // Phase 2: Data zone + for(ulong i = _resume.NextBlock; i < blocks; i += blocksToRead) + { + if(_aborted) + { + currentTry.Extents = ExtentsConverter.ToMetadata(extents); + UpdateStatus?.Invoke(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(); + outputFormat.WriteSectorsLong(buffer, + i, + false, + blocksToRead, + Enumerable.Repeat(SectorStatus.Dumped, (int)blocksToRead).ToArray()); + + imageWriteDuration += _writeStopwatch.Elapsed.TotalSeconds; + extents.Add(i, blocksToRead, true); + _mediaGraph?.PaintSectorsGood(i, blocksToRead); + } + else + { + if(_stopOnError) return; + + if(i + _skip > blocks) _skip = (uint)(blocks - i); + + _writeStopwatch.Restart(); + outputFormat.WriteSectorsLong(new byte[blockSize * _skip], + i, + false, + _skip, + Enumerable.Repeat(SectorStatus.NotDumped, (int)_skip).ToArray()); + + 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); + AaruLogging.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(); + } + + // Phase 3: Leadout (overflow sectors) — OmniDrive only + if(overflowSectors > 0) + { + UpdateStatus?.Invoke(Localization.Core.Reading_lead_out_sectors); + + blocksToRead = maxBlocksToRead; + for(ulong lba = blocks; lba < blocks + overflowSectors; lba += blocksToRead) + { + if(_aborted) + { + currentTry.Extents = ExtentsConverter.ToMetadata(extents); + UpdateStatus?.Invoke(Localization.Core.Aborted); + + break; + } + + uint toRead = (uint)(blocks + overflowSectors - lba); + if(toRead > blocksToRead) toRead = blocksToRead; + + 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, + lba, + blocks + overflowSectors, + ByteSize.FromMegabytes(currentSpeed).Per(_oneSecond).Humanize()), + (long)lba, + (long)(blocks + overflowSectors)); + + sense = scsiReader.ReadBlocks(out buffer, lba, toRead, out double cmdDuration, out _, out _); + totalDuration += cmdDuration; + + if(!sense && !_dev.Error) + { + mhddLog.Write(lba, cmdDuration, toRead); + ibgLog.Write(lba, currentSpeed * 1024); + + _writeStopwatch.Restart(); + outputFormat.WriteSectorsLong(buffer, + lba, + false, + toRead, + Enumerable.Repeat(SectorStatus.Dumped, (int)toRead).ToArray()); + imageWriteDuration += _writeStopwatch.Elapsed.TotalSeconds; + } + else + { + if(_stopOnError) return; + + _writeStopwatch.Restart(); + outputFormat.WriteSectorsLong(new byte[blockSize * toRead], + lba, + false, + toRead, + Enumerable.Repeat(SectorStatus.NotDumped, (int)toRead).ToArray()); + imageWriteDuration += _writeStopwatch.Elapsed.TotalSeconds; + } + + _writeStopwatch.Stop(); + sectorSpeedStart += toRead; + double elapsed = _speedStopwatch.Elapsed.TotalSeconds; + if(elapsed > 0) + { + currentSpeed = (double)sectorSpeedStart * blockSize / (1048576d * elapsed); + sectorSpeedStart = 0; + _speedStopwatch.Restart(); + } + } + } + + _speedStopwatch.Stop(); + _resume.BadBlocks = _resume.BadBlocks.Distinct().ToList(); + + EndProgress?.Invoke(); + } +} diff --git a/Aaru.Core/Devices/Dumping/Sbc/Trim.cs b/Aaru.Core/Devices/Dumping/Sbc/Trim.cs index f23cfda1e..9932b2a18 100644 --- a/Aaru.Core/Devices/Dumping/Sbc/Trim.cs +++ b/Aaru.Core/Devices/Dumping/Sbc/Trim.cs @@ -110,6 +110,14 @@ partial class Dump } else { + if(scsiReader.OmniDriveReadRawBluray) + { + _resume.BadBlocks.Remove(badSector); + outputFormat.WriteSectorLong(buffer, badSector, false, SectorStatus.Dumped); + + continue; + } + var cmi = new byte[1]; byte[] key = buffer.Skip(7).Take(5).ToArray(); diff --git a/Aaru.Core/Devices/Reader.cs b/Aaru.Core/Devices/Reader.cs index 8e6dcb93a..4935ba83a 100644 --- a/Aaru.Core/Devices/Reader.cs +++ b/Aaru.Core/Devices/Reader.cs @@ -36,6 +36,7 @@ using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Structs.Devices.ATA; using Aaru.Core.Logging; using Aaru.Devices; +using Aaru.CommonTypes; namespace Aaru.Core.Devices; @@ -104,7 +105,7 @@ sealed partial class Reader } } - internal bool FindReadCommand() + internal bool FindReadCommand(MediaType mediaType = MediaType.Unknown) { switch(_dev.Type) { @@ -112,7 +113,7 @@ sealed partial class Reader return AtaFindReadCommand(); case DeviceType.ATAPI: case DeviceType.SCSI: - return ScsiFindReadCommand(); + return ScsiFindReadCommand(mediaType); default: ErrorMessage = string.Format(Localization.Core.Unknown_device_type_0, _dev.Type); diff --git a/Aaru.Core/Devices/ReaderSCSI.cs b/Aaru.Core/Devices/ReaderSCSI.cs index 06409fd99..d481a7991 100644 --- a/Aaru.Core/Devices/ReaderSCSI.cs +++ b/Aaru.Core/Devices/ReaderSCSI.cs @@ -31,9 +31,11 @@ // ****************************************************************************/ using System; +using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Structs.Devices.SCSI; using Aaru.Decoders.SCSI; using Aaru.Logging; +using Aaru.CommonTypes; namespace Aaru.Core.Devices; @@ -56,12 +58,24 @@ sealed partial class Reader public bool HldtstReadRaw; public uint layerbreak; public bool OmniDriveReadRaw; + public bool OmniDriveReadRawBluray; public bool ReadBuffer3CReadRaw; public bool otp; ulong ScsiGetBlocks() => ScsiGetBlockSize() ? 0 : Blocks; - bool ScsiFindReadCommand() + static bool IsBlurayMedia(MediaType mediaType) => + mediaType is MediaType.BDROM or + MediaType.BDR or + MediaType.BDRE or + MediaType.BDRXL or + MediaType.BDREXL or + MediaType.UHDBD or + MediaType.PS3BD or + MediaType.PS4BD or + MediaType.PS5BD; + + bool ScsiFindReadCommand(MediaType mediaType = MediaType.Unknown) { if(Blocks == 0) GetDeviceBlocks(); @@ -591,6 +605,22 @@ sealed partial class Reader // Try OmniDrive on drives with OmniDrive firmware (standard descramble=1 and Nintendo descramble=0) if(_dev.IsOmniDriveFirmware()) { + OmniDriveReadRawBluray = false; + + if(IsBlurayMedia(mediaType)) + { + OmniDriveReadRawBluray = !_dev.OmniDriveReadRawBd(out _, + out senseBuf, + 0, + 1, + _timeout, + out _, + true, + true); + OmniDriveReadRaw = OmniDriveReadRawBluray; + } + else + { bool omniStandardOk = !_dev.OmniDriveReadRawDvd(out _, out senseBuf, 0, 1, _timeout, out _, true, true); OmniDriveReadRaw = omniStandardOk @@ -606,12 +636,13 @@ sealed partial class Reader null, false, 0); + } } if(HldtstReadRaw || _plextorReadRaw || ReadBuffer3CReadRaw || OmniDriveReadRaw) { CanReadRaw = true; - LongBlockSize = 2064; + LongBlockSize = OmniDriveReadRawBluray ? 2052u : 2064u; } // READ LONG (10) for some DVD drives @@ -644,7 +675,8 @@ sealed partial class Reader else if(_plextorReadRaw) AaruLogging.WriteLine($"[slateblue1]{Localization.Core.Using_Plextor_raw_DVD_reading}[/]"); else if(OmniDriveReadRaw) - AaruLogging.WriteLine($"[slateblue1]{Localization.Core.Using_OmniDrive_raw_DVD_reading}[/]"); + AaruLogging.WriteLine( + $"[slateblue1]{(OmniDriveReadRawBluray ? Localization.Core.Using_OmniDrive_raw_BD_reading : Localization.Core.Using_OmniDrive_raw_DVD_reading)}[/]"); else if(ReadBuffer3CReadRaw) AaruLogging.WriteLine($"[slateblue1]{Localization.Core.Using_ReadBuffer_3C_raw_DVD_reading}[/]"); } @@ -712,7 +744,7 @@ sealed partial class Reader BlocksToRead = 1; else if(OmniDriveReadRaw) { - BlocksToRead = (uint)Math.Min(31, startWithBlocks); + BlocksToRead = (uint)Math.Min(OmniDriveReadRawBluray ? 7 : 31, startWithBlocks); return false; } else if(_read6) @@ -865,7 +897,14 @@ sealed partial class Reader { uint lba = negative ? (uint)(-(long)block) : (uint)block; - if(OmniDriveNintendoMode) + if(OmniDriveReadRawBluray) + sense = _dev.OmniDriveReadRawBd(out buffer, + out senseBuf, + lba, + count, + _timeout, + out duration); + else if(OmniDriveNintendoMode) { ulong regularDataEndExclusive = Blocks + 1; diff --git a/Aaru.Decoders/Bluray/DI.cs b/Aaru.Decoders/Bluray/DI.cs index e55bf5625..0e4d113f7 100644 --- a/Aaru.Decoders/Bluray/DI.cs +++ b/Aaru.Decoders/Bluray/DI.cs @@ -118,6 +118,14 @@ public static class DI { if(DIResponse == null) return null; + // Handle if the size has been stripped from the DI + if(DIResponse.Length == 4096) + { + byte[] tmp2 = new byte[4100]; + Array.Copy(DIResponse, 0, tmp2, 4, 4096); + DIResponse = tmp2; + } + if(DIResponse.Length != 4100) { AaruLogging.Debug(MODULE_NAME, diff --git a/Aaru.Decoders/Bluray/DataFrame.cs b/Aaru.Decoders/Bluray/DataFrame.cs index f3e22304e..9ad4b5011 100644 --- a/Aaru.Decoders/Bluray/DataFrame.cs +++ b/Aaru.Decoders/Bluray/DataFrame.cs @@ -28,11 +28,12 @@ using Aaru.Decoders.Bluray; namespace Aaru.Decoders.Bluray; -/// Blu-ray DataFrame: 2048 bytes main_data + 4 bytes EDC (redumper raw .sbram). +/// Blu-ray DataFrame: 2048 bytes main_data + 4 bytes EDC. public static class DataFrame { - /// Total size of one BD DataFrame in a Redumper .sbram file. + /// Total size of one BD DataFrame. public const int Size = 2048 + 4; + public const int UserControlDataSize = 18; /// Descrambles a 2052-byte frame in place (ISO/IEC 30190 LFSR XOR). public static void Descramble(Span frame, int lba, bool nintendo) diff --git a/Aaru.Devices/Device/ScsiCommands/OmniDrive.cs b/Aaru.Devices/Device/ScsiCommands/OmniDrive.cs index 30d961709..b920de843 100644 --- a/Aaru.Devices/Device/ScsiCommands/OmniDrive.cs +++ b/Aaru.Devices/Device/ScsiCommands/OmniDrive.cs @@ -37,12 +37,16 @@ using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Structs.Devices.SCSI; using Aaru.Logging; using Aaru.Decoders.DVD; +using BlurayDataFrame = Aaru.Decoders.Bluray.DataFrame; using NintendoSector = Aaru.Decoders.Nintendo.Sector; namespace Aaru.Devices; public partial class Device { + const int OMNIDRIVE_BD_DATA_FRAME_SIZE = BlurayDataFrame.Size; + const int OMNIDRIVE_BD_TRANSFER_PER_LBA = OMNIDRIVE_BD_DATA_FRAME_SIZE + BlurayDataFrame.UserControlDataSize; + readonly NintendoSector _nintendoSectorDecoder = new NintendoSector(); readonly Sector _dvdSectorDecoder = new Sector(); enum OmniDriveDiscType @@ -67,7 +71,7 @@ public partial class Device return (byte)(d | (r << 2) | (f << 3) | (s << 4)); } - static void FillOmniDriveReadDvdCdb(Span cdb, uint lba, uint transferLength, byte cdbByte1) + static void FillOmniDriveReadCdb(Span cdb, uint lba, uint transferLength, byte cdbByte1) { cdb.Clear(); cdb[0] = (byte)ScsiCommands.ReadOmniDrive; @@ -129,7 +133,7 @@ public partial class Device Span cdb = CdbBuffer[..12]; buffer = new byte[2064 * transferLength]; - FillOmniDriveReadDvdCdb(cdb, + FillOmniDriveReadCdb(cdb, lba, transferLength, EncodeOmniDriveReadCdb1(OmniDriveDiscType.DVD, false, fua, descramble)); @@ -147,6 +151,54 @@ public partial class Device return sense; } + /// Reads raw Blu-ray sectors (2052-byte DataFrame) directly by LBA on OmniDrive firmware. + /// true if the command failed and contains the sense buffer. + /// Buffer where the raw Blu-ray DataFrame response will be stored. + /// Sense buffer. + /// Start block address (LBA). + /// Number of 2052-byte sectors to read. + /// Timeout in seconds. + /// Duration in milliseconds it took for the device to execute the command. + /// Set to true if the command should use FUA. + /// Set to true if the data should be descrambled by the device. + public bool OmniDriveReadRawBd(out byte[] buffer, out ReadOnlySpan senseBuffer, uint lba, uint transferLength, + uint timeout, out double duration, bool fua = false, bool descramble = true) + { + senseBuffer = SenseBuffer; + Span cdb = CdbBuffer[..12]; + byte[] deviceBuffer = new byte[OMNIDRIVE_BD_TRANSFER_PER_LBA * transferLength]; + buffer = new byte[OMNIDRIVE_BD_DATA_FRAME_SIZE * transferLength]; + + FillOmniDriveReadCdb(cdb, + lba, + transferLength, + EncodeOmniDriveReadCdb1(OmniDriveDiscType.BD, false, fua, descramble)); + + LastError = SendScsiCommand(cdb, ref deviceBuffer, timeout, ScsiDirection.In, out duration, out bool sense); + + if(sense) + { + Error = LastError != 0; + + return true; + } + + for(uint i = 0; i < transferLength; i++) + { + int deviceOffset = (int)(i * OMNIDRIVE_BD_TRANSFER_PER_LBA); + int dataOffset = (int)(i * OMNIDRIVE_BD_DATA_FRAME_SIZE); + Array.Copy(deviceBuffer, deviceOffset, buffer, dataOffset, OMNIDRIVE_BD_DATA_FRAME_SIZE); + + if(descramble && !Decoders.Bluray.Sector.CheckEdc(buffer.AsSpan(dataOffset, OMNIDRIVE_BD_DATA_FRAME_SIZE).ToArray())) return true; + } + + Error = LastError != 0; + + AaruLogging.Debug(SCSI_MODULE_NAME, "OmniDrive READ RAW BD took {0} ms", duration); + + return false; + } + /// /// Reads Nintendo GameCube/Wii DVD sectors (2064 bytes) on OmniDrive. The drive returns DVD-layer data with /// drive-side DVD descramble off; this method applies per-sector Nintendo XOR descramble and returns the result. @@ -171,10 +223,10 @@ public partial class Device Span cdb = CdbBuffer[..12]; buffer = new byte[2064 * transferLength]; - FillOmniDriveReadDvdCdb(cdb, - lba, - transferLength, - EncodeOmniDriveReadCdb1(OmniDriveDiscType.DVD, false, fua, false)); + FillOmniDriveReadCdb(cdb, + lba, + transferLength, + EncodeOmniDriveReadCdb1(OmniDriveDiscType.DVD, false, fua, false)); LastError = SendScsiCommand(cdb, ref buffer, timeout, ScsiDirection.In, out duration, out bool sense); diff --git a/Aaru.Localization/Core.Designer.cs b/Aaru.Localization/Core.Designer.cs index f82327f6f..2ed0511b0 100644 --- a/Aaru.Localization/Core.Designer.cs +++ b/Aaru.Localization/Core.Designer.cs @@ -6857,6 +6857,12 @@ namespace Aaru.Localization { } } + public static string Using_OmniDrive_raw_BD_reading { + get { + return ResourceManager.GetString("Using_OmniDrive_raw_BD_reading", resourceCulture); + } + } + public static string Using_ReadBuffer_3C_raw_DVD_reading { get { return ResourceManager.GetString("Using_ReadBuffer_3C_raw_DVD_reading", resourceCulture); diff --git a/Aaru.Localization/Core.es.resx b/Aaru.Localization/Core.es.resx index f51bef025..fbe00b521 100644 --- a/Aaru.Localization/Core.es.resx +++ b/Aaru.Localization/Core.es.resx @@ -3286,6 +3286,9 @@ No tiene sentido hacerlo y supondría demasiado esfuerzo para la cinta. [slateblue1]Usando lectura de [fuchsia]DVD sin procesar de OmniDrive[/].[/] + + [slateblue1]Usando lectura de [fuchsia]Blu-ray sin procesar de OmniDrive[/].[/] + [slateblue1]Usando lectura de [fuchsia]DVD sin procesar de Plextor[/].[/] diff --git a/Aaru.Localization/Core.resx b/Aaru.Localization/Core.resx index 633647b5e..b2a4bd8a1 100644 --- a/Aaru.Localization/Core.resx +++ b/Aaru.Localization/Core.resx @@ -3511,6 +3511,9 @@ It has no sense to do it, and it will put too much strain on the tape. [slateblue1]Using [fuchsia]OmniDrive[/] raw DVD reading[/] + + [slateblue1]Using [fuchsia]OmniDrive[/] raw Blu-ray reading[/] + [slateblue1]Using [fuchsia]ReadBuffer 3C raw DVD[/] reading[/]