From 66f0161638959af43b5b75db73ccf0d822265dc4 Mon Sep 17 00:00:00 2001 From: Natalia Portillo Date: Mon, 6 Jul 2026 04:39:22 +0100 Subject: [PATCH] Add specific OmniDrive code for CD-i Ready handling and deactivate it because unicorns appeared. --- Aaru.Core/Devices/Dumping/CompactDisc/Dump.cs | 34 ++ .../Devices/Dumping/CompactDisc/OmniDrive.cs | 338 +++++++++++++++++- Aaru.Localization/UI.Designer.cs | 12 + Aaru.Localization/UI.es.resx | 6 + Aaru.Localization/UI.resx | 6 + 5 files changed, 389 insertions(+), 7 deletions(-) diff --git a/Aaru.Core/Devices/Dumping/CompactDisc/Dump.cs b/Aaru.Core/Devices/Dumping/CompactDisc/Dump.cs index 306285fd3..f56e8a0ff 100644 --- a/Aaru.Core/Devices/Dumping/CompactDisc/Dump.cs +++ b/Aaru.Core/Devices/Dumping/CompactDisc/Dump.cs @@ -958,6 +958,38 @@ sealed partial class Dump if(_skipCdireadyHole) { + // This codepath is disabled because it's doing strange things, let the OmniDrive behave like a normal drive here + /* + if(_omnidrive) + { + OmniDriveReadCdiReady(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); + } + else + { + */ ReadCdiReady(blockSize, ref currentSpeed, currentTry, @@ -982,6 +1014,8 @@ sealed partial class Dump offsetBytes, sectorsForOffset, smallestPregapLbaPerTrack); + + //} } } diff --git a/Aaru.Core/Devices/Dumping/CompactDisc/OmniDrive.cs b/Aaru.Core/Devices/Dumping/CompactDisc/OmniDrive.cs index 56d531e65..1260afdbc 100644 --- a/Aaru.Core/Devices/Dumping/CompactDisc/OmniDrive.cs +++ b/Aaru.Core/Devices/Dumping/CompactDisc/OmniDrive.cs @@ -43,6 +43,7 @@ using Aaru.Core.Logging; using Aaru.Decoders.CD; using Aaru.Decoders.SCSI; using Aaru.Devices; +using Aaru.Localization; using Aaru.Logging; using Humanizer; using Track = Aaru.CommonTypes.Structs.Track; @@ -110,7 +111,7 @@ partial class Dump if(_absurdSpeed) { - UpdateStatus?.Invoke("[slateblue1]Yes, sir! Setting absurd speed sir![/]"); + UpdateStatus?.Invoke(UI.Yes__sir__Setting_absurd_speed_sir); _dev.SetCdSpeed(out _, RotationalControl.ClvAndImpureCav, 0xFFFF, 0, _dev.Timeout, out _); } @@ -121,7 +122,7 @@ partial class Dump if(t is null) { - UpdateStatus?.Invoke("[slateblue1]Setting speed to [teal]8x[/] for scrambled reading.[/]"); + UpdateStatus?.Invoke(UI.Setting_speed_to_8x_for_scrambled_reading); _dev.SetCdSpeed(out _, RotationalControl.ClvAndImpureCav, 1416, 0, _dev.Timeout, out _); } @@ -147,7 +148,7 @@ partial class Dump } else { - UpdateStatus?.Invoke("[slateblue1]Setting speed to [teal]8x[/] for scrambled reading.[/]"); + UpdateStatus?.Invoke(UI.Setting_speed_to_8x_for_scrambled_reading); _dev.SetCdSpeed(out _, RotationalControl.ClvAndImpureCav, 1416, 0, _dev.Timeout, out _); } @@ -226,11 +227,7 @@ partial class Dump } } else - { - UpdateStatus?.Invoke("[slateblue1]Setting speed to [teal]8x[/] for scrambled reading.[/]"); - _dev.SetCdSpeed(out _, RotationalControl.ClvAndImpureCav, 1416, 0, _dev.Timeout, out _); - } speedSectorCounter = 0; } @@ -503,4 +500,331 @@ partial class Dump _resume.BadBlocks = [.. _resume.BadBlocks.Distinct()]; } + + /// Reads all the hidden track in CD-i Ready discs + /// Total number of positive sectors + /// Size of the read sector in bytes + /// Current read speed + /// Current dump hardware try + /// Extents + /// IMGBurn log + /// Duration of image write + /// Lead-out extents + /// Maximum speed + /// MHDD log + /// Minimum speed + /// Read offset + /// Sectors needed to fix offset + /// Subchannel size in bytes + /// Drive's maximum supported subchannel + /// Total commands duration + /// Is the drive returning CD-i Ready hidden track as audio? + /// Disc tracks + /// Subchannel log + /// Subchannel desired to save + /// List of disc ISRCs + /// Disc media catalogue number + /// List of subchannels not yet dumped correctly + /// List of smallest pregap relative address per track + void OmniDriveReadCdiReady(uint blockSize, ref double currentSpeed, DumpHardware currentTry, ExtentsULong extents, + IbgLog ibgLog, ref double imageWriteDuration, ExtentsULong leadOutExtents, + ref double maxSpeed, MhddLog mhddLog, ref double minSpeed, uint subSize, + MmcSubchannel supportedSubchannel, ref double totalDuration, Track[] tracks, + SubchannelLog subLog, MmcSubchannel desiredSubchannel, Dictionary isrcs, + ref string mcn, HashSet subchannelExtents, ulong blocks, bool cdiReadyReadAsAudio, + int offsetBytes, int sectorsForOffset, Dictionary smallestPregapLbaPerTrack) + { + ulong sectorSpeedStart = 0; // Used to calculate correct speed + bool sense; // Sense indicator + byte[] cmdBuf; // Data buffer + ReadOnlySpan 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; + var speedSectorCounter = 0; + + if(firstTrack is null) return; + + if(_absurdSpeed) + { + UpdateStatus?.Invoke(UI.Yes__sir__Setting_absurd_speed_sir); + + _dev.SetCdSpeed(out _, RotationalControl.ClvAndImpureCav, 0xFFFF, 0, _dev.Timeout, out _); + } + else if(_hyperSpeed) + { + Track t = tracks.FirstOrDefault(t => t.StartSector <= _resume.NextBlock && + t.EndSector >= _resume.NextBlock); + + if(t is null) + { + UpdateStatus?.Invoke(UI.Setting_speed_to_8x_for_scrambled_reading); + + _dev.SetCdSpeed(out _, RotationalControl.ClvAndImpureCav, 1416, 0, _dev.Timeout, out _); + } + else if(t.Type == TrackType.Audio) + { + UpdateStatus?.Invoke(Localization.Core.Setting_speed_to_8x_for_audio_reading); + + _dev.SetCdSpeed(out _, RotationalControl.ClvAndImpureCav, 1416, 0, _dev.Timeout, out _); + } + else + { + 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; + + if(_speed is 0 or > 0xFFFF) _speed = 0xFFFF; + + _dev.SetCdSpeed(out _, RotationalControl.ClvAndImpureCav, (ushort)_speed, 0, _dev.Timeout, out _); + } + } + else + { + UpdateStatus?.Invoke(UI.Setting_speed_to_8x_for_scrambled_reading); + + _dev.SetCdSpeed(out _, RotationalControl.ClvAndImpureCav, 1416, 0, _dev.Timeout, out _); + } + + InitProgress?.Invoke(); + + for(ulong i = _resume.NextBlock; i <= firstTrack.EndSector; i += blocksToRead) + { + if(_aborted) + { + currentTry.Extents = ExtentsConverter.ToMetadata(extents); + UpdateStatus?.Invoke(Localization.Core.Aborted); + + break; + } + + var firstSectorToRead = (uint)i; + + blocksToRead = _maximumReadable; + + if(blocksToRead == 1) blocksToRead += (uint)sectorsForOffset; + + if(offsetBytes < 0) + { + if(i == 0) + firstSectorToRead = uint.MaxValue - (uint)(sectorsForOffset - 1); // -1 + else + firstSectorToRead -= (uint)sectorsForOffset; + } + + if(speedSectorCounter > 1000) + { + if(_absurdSpeed) + _dev.SetCdSpeed(out _, RotationalControl.ClvAndImpureCav, 0xFFFF, 0, _dev.Timeout, out _); + else if(_hyperSpeed) + { + Track t = tracks.FirstOrDefault(t => t.StartSector <= _resume.NextBlock && + t.EndSector >= _resume.NextBlock); + + if(t is null || t.Type == TrackType.Audio) + _dev.SetCdSpeed(out _, RotationalControl.ClvAndImpureCav, 1416, 0, _dev.Timeout, out _); + else + { + if(_speed is 0 or > 0xFFFF) _speed = 0xFFFF; + + _dev.SetCdSpeed(out _, + RotationalControl.ClvAndImpureCav, + (ushort)_speed, + 0, + _dev.Timeout, + out _); + } + } + else + _dev.SetCdSpeed(out _, RotationalControl.ClvAndImpureCav, 1416, 0, _dev.Timeout, out _); + + speedSectorCounter = 0; + } + else + speedSectorCounter += (int)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, + i, + blocks, + ByteSize.FromMegabytes(currentSpeed).Per(_oneSecond).Humanize()), + (long)i, + (long)blocks); + + _speedStopwatch.Start(); + + sense = _dev.OmniDriveReadCd(out cmdBuf, + out senseBuf, + firstSectorToRead, + blocksToRead, + _dev.Timeout, + out cmdDuration); + + // OmniDrive seems to be doing something crazy, the command should return scrambled sectors, but as + // CD-i Ready is "magic", it seems to be making it return descrambled sectors here, so let's check + var dorothy = new byte[2352]; + var scrambled = true; + Array.Copy(cmdBuf, 0, dorothy, 0, 2352); + if(IsData(dorothy) && !IsScrambledData(dorothy, (int)firstSectorToRead, out _)) scrambled = false; + + totalDuration += cmdDuration; + _speedStopwatch.Stop(); + double elapsed; + + if(!sense && !_dev.Error) + { + if(scrambled) + { + FixOffsetData(offsetBytes, + sectorSize, + sectorsForOffset, + supportedSubchannel, + ref blocksToRead, + subSize, + ref cmdBuf, + blockSize, + false); + } + + mhddLog.Write(i, cmdDuration); + ibgLog.Write(i, currentSpeed * 1024); + extents.Add(i, blocksToRead, true); + _writeStopwatch.Restart(); + + List paintBad = []; + + if(supportedSubchannel != MmcSubchannel.None) + { + var data = new byte[sectorSize * blocksToRead]; + var sub = new byte[subSize * blocksToRead]; + var tmpData = new byte[sectorSize]; + var sectorStatus = new SectorStatus[blocksToRead]; + + for(var b = 0; b < blocksToRead; b++) + { + sectorStatus[b] = SectorStatus.Dumped; + Array.Copy(cmdBuf, (int)(0 + b * blockSize), tmpData, 0, sectorSize); + if(scrambled) tmpData = Sector.Scramble(tmpData); + SectorFixResult fixedStatus = CdChecksums.FixSector(tmpData); + + if(fixedStatus == SectorFixResult.Correct) _correctSectors++; + if(fixedStatus == SectorFixResult.Fixed) _fixedSectors++; + + if(fixedStatus == SectorFixResult.CouldNotFix) // Damaged + { + sectorStatus[b] = SectorStatus.Errored; + _resume.BadBlocks.Add(i + (ulong)b); + paintBad.Add(i + (ulong)b); + } + + Array.Copy(tmpData, 0, data, sectorSize * b, sectorSize); + + Array.Copy(cmdBuf, (int)(sectorSize + b * blockSize), sub, subSize * b, subSize); + } + + outputOptical.WriteSectorsLong(data, i, false, blocksToRead, sectorStatus); + + bool indexesChanged = Media.CompactDisc.WriteSubchannelToImage(supportedSubchannel, + desiredSubchannel, + sub, + i, + blocksToRead, + subLog, + isrcs, + 1, + ref mcn, + tracks, + subchannelExtents, + _fixSubchannelPosition, + outputOptical, + _fixSubchannel, + _fixSubchannelCrc, + UpdateStatus, + smallestPregapLbaPerTrack, + true, + out List newPregapSectors); + + // Set tracks and go back + if(indexesChanged) + { + outputOptical.SetTracks(tracks.ToList()); + + _resume.BadBlocks.AddRange(newPregapSectors); + + if(i >= blocksToRead) + i -= blocksToRead; + else + i = 0; + + if(i > 0) i--; + + continue; + } + } + else + { + var tmpData = new byte[sectorSize]; + var data = new byte[sectorSize * blocksToRead]; + var status = new SectorStatus[blocksToRead]; + + for(var b = 0; b < blocksToRead; b++) + { + status[b] = SectorStatus.Dumped; + Array.Copy(cmdBuf, (int)(b * sectorSize), tmpData, 0, sectorSize); + if(scrambled) tmpData = Sector.Scramble(tmpData); + SectorFixResult fixedStatus = CdChecksums.FixSector(tmpData); + if(fixedStatus == SectorFixResult.Correct) _correctSectors++; + if(fixedStatus == SectorFixResult.Fixed) _fixedSectors++; + + if(fixedStatus == SectorFixResult.CouldNotFix) // Damaged + { + _resume.BadBlocks.Add(i + (ulong)b); + paintBad.Add(i + (ulong)b); + status[b] = SectorStatus.Errored; + } + + Array.Copy(tmpData, 0, data, sectorSize * b, sectorSize); + } + + outputOptical.WriteSectorsLong(data, i, false, blocksToRead, status); + } + + imageWriteDuration += _writeStopwatch.Elapsed.TotalSeconds; + + _mediaGraph?.PaintSectorsGood(i, blocksToRead); + } + else + { + _errorLog?.WriteLine(i, _dev.Error, _dev.LastError, senseBuf.ToArray()); + + _resume.NextBlock = firstTrack.EndSector + 1; + + break; + } + + _writeStopwatch.Stop(); + sectorSpeedStart += blocksToRead; + + _resume.NextBlock = i + blocksToRead; + + elapsed = _speedStopwatch.Elapsed.TotalSeconds; + + if(elapsed <= 0 || sectorSpeedStart * blockSize < 524288) continue; + + currentSpeed = sectorSpeedStart * blockSize / (1048576 * elapsed); + sectorSpeedStart = 0; + _speedStopwatch.Reset(); + } + + _speedStopwatch.Stop(); + EndProgress?.Invoke(); + } } \ No newline at end of file diff --git a/Aaru.Localization/UI.Designer.cs b/Aaru.Localization/UI.Designer.cs index 6e0d02978..6216170ad 100644 --- a/Aaru.Localization/UI.Designer.cs +++ b/Aaru.Localization/UI.Designer.cs @@ -11387,5 +11387,17 @@ namespace Aaru.Localization { return ResourceManager.GetString("Detected_Omnidrive", resourceCulture); } } + + public static string Yes__sir__Setting_absurd_speed_sir { + get { + return ResourceManager.GetString("Yes__sir__Setting_absurd_speed_sir", resourceCulture); + } + } + + public static string Setting_speed_to_8x_for_scrambled_reading { + get { + return ResourceManager.GetString("Setting_speed_to_8x_for_scrambled_reading", resourceCulture); + } + } } } diff --git a/Aaru.Localization/UI.es.resx b/Aaru.Localization/UI.es.resx index a5aa92d62..5c50fdfb7 100644 --- a/Aaru.Localization/UI.es.resx +++ b/Aaru.Localization/UI.es.resx @@ -5689,4 +5689,10 @@ Probadores: [slateblue1]Detectada [/][#FFFFFF]O[/][#FFAFC8]m[/][#74D7EE]n[/][#E40303]i[/][#FF8C00]D[/][#FFED00]r[/][#008026]i[/][#004DFF]v[/][#750787]e[/][#613915]![/][000000]![/] [slateblue1]versión[/] [purple]{0}.{1}.{2}[/] + + [slateblue1]¡Sí señor! ¡Velocidad absurda señor![/] + + + [slateblue1]Estableciendo velocidad a [teal]8x[/] para la lectura codificada.[/] + \ No newline at end of file diff --git a/Aaru.Localization/UI.resx b/Aaru.Localization/UI.resx index 0b3573819..29953eb78 100644 --- a/Aaru.Localization/UI.resx +++ b/Aaru.Localization/UI.resx @@ -5773,4 +5773,10 @@ Do you want to continue? [slateblue1]Detected [/][#FFFFFF]O[/][#FFAFC8]m[/][#74D7EE]n[/][#E40303]i[/][#FF8C00]D[/][#FFED00]r[/][#008026]i[/][#004DFF]v[/][#750787]e[/][#613915]![/][000000]![/] [slateblue1]version[/] [purple]{0}.{1}.{2}[/] + + [slateblue1]Yes, sir! Setting absurd speed sir![/] + + + [slateblue1]Setting speed to [teal]8x[/] for scrambled reading.[/] + \ No newline at end of file