diff --git a/Aaru.Core/Devices/Dumping/ATA.cs b/Aaru.Core/Devices/Dumping/ATA.cs index 05d089562..99060138e 100644 --- a/Aaru.Core/Devices/Dumping/ATA.cs +++ b/Aaru.Core/Devices/Dumping/ATA.cs @@ -45,6 +45,7 @@ using Aaru.Core.Graphics; using Aaru.Core.Logging; using Aaru.Decoders.ATA; using Aaru.Decoders.PCMCIA; +using Aaru.Images; using Aaru.Logging; using Humanizer; using Identify = Aaru.CommonTypes.Structs.Devices.ATA.Identify; @@ -250,6 +251,8 @@ public partial class Dump return; } + if(outputFormat is AaruFormat aif && _errorRecovery > 0) aif.SetErasureCodingAuto((byte)_errorRecovery); + // Setting geometry outputFormat.SetGeometry(cylinders, heads, sectors); diff --git a/Aaru.Core/Devices/Dumping/CompactDisc/Dump.cs b/Aaru.Core/Devices/Dumping/CompactDisc/Dump.cs index 1194b484d..ec95d5d7a 100644 --- a/Aaru.Core/Devices/Dumping/CompactDisc/Dump.cs +++ b/Aaru.Core/Devices/Dumping/CompactDisc/Dump.cs @@ -49,6 +49,7 @@ using Aaru.Core.Media.Detection; using Aaru.Database.Models; using Aaru.Decoders.CD; using Aaru.Devices; +using Aaru.Images; using Aaru.Logging; using Humanizer; using Spectre.Console; @@ -971,6 +972,8 @@ sealed partial class Dump return; } + if(outputOptical is AaruFormat aif && _errorRecovery > 0) aif.SetErasureCodingAuto((byte)_errorRecovery); + ErrorNumber errno = outputOptical.ReadMediaTag(MediaTagType.CD_MCN, out byte[] mcnBytes); if(errno == ErrorNumber.NoError) mcn = Encoding.ASCII.GetString(mcnBytes); @@ -1083,9 +1086,8 @@ 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) @@ -1511,9 +1513,8 @@ sealed partial class Dump supportsLongSectors); foreach(Tuple 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) { diff --git a/Aaru.Core/Devices/Dumping/Dump.cs b/Aaru.Core/Devices/Dumping/Dump.cs index 194ed510d..57822ced5 100644 --- a/Aaru.Core/Devices/Dumping/Dump.cs +++ b/Aaru.Core/Devices/Dumping/Dump.cs @@ -83,6 +83,7 @@ public partial class Dump readonly Stopwatch _dumpStopwatch; readonly Encoding _encoding; readonly ErrorLog _errorLog; + readonly int _errorRecovery; readonly bool _fixSubchannel; readonly bool _fixSubchannelCrc; readonly bool _fixSubchannelPosition; @@ -103,6 +104,7 @@ public partial class Dump readonly bool _retrySubchannel; readonly Stopwatch _sidecarStopwatch; readonly Stopwatch _speedStopwatch; + readonly bool _startReverse; readonly bool _stopOnError; readonly bool _storeEncrypted; readonly DumpSubchannel _subchannel; @@ -125,7 +127,6 @@ public partial class Dump bool _skipCdireadyHole; int _speed; int _speedMultiplier; - readonly bool _startReverse; bool _supportsPlextorD8; bool _useBufferedReads; @@ -183,7 +184,7 @@ public partial class Dump bool fixSubchannel, bool fixSubchannelCrc, bool skipCdireadyHole, ErrorLog errorLog, bool generateSubchannels, uint maximumReadable, bool useBufferedReads, bool storeEncrypted, bool titleKeys, uint ignoreCdrRunOuts, bool createGraph, uint dimensions, bool paranoia, - bool cureParanoia, bool bypassWiiDecryption, bool startReverse) + bool cureParanoia, bool bypassWiiDecryption, bool startReverse, int errorRecovery) { _doResume = doResume; _dev = dev; @@ -229,6 +230,7 @@ public partial class Dump _cureParanoia = cureParanoia; _bypassWiiDecryption = bypassWiiDecryption; _startReverse = startReverse; + _errorRecovery = errorRecovery; _dumpStopwatch = new Stopwatch(); _sidecarStopwatch = new Stopwatch(); _speedStopwatch = new Stopwatch(); diff --git a/Aaru.Core/Devices/Dumping/MiniDisc.cs b/Aaru.Core/Devices/Dumping/MiniDisc.cs index 2d1ebd48c..df34a6c38 100644 --- a/Aaru.Core/Devices/Dumping/MiniDisc.cs +++ b/Aaru.Core/Devices/Dumping/MiniDisc.cs @@ -46,6 +46,7 @@ using Aaru.Core.Graphics; using Aaru.Core.Logging; using Aaru.Decoders.SCSI; using Aaru.Devices; +using Aaru.Images; using Aaru.Logging; using Humanizer; using Version = Aaru.CommonTypes.Interop.Version; @@ -223,6 +224,8 @@ partial class Dump return; } + if(outputFormat is AaruFormat aif && _errorRecovery > 0) aif.SetErasureCodingAuto((byte)_errorRecovery); + _dumpStopwatch.Restart(); double imageWriteDuration = 0; diff --git a/Aaru.Core/Devices/Dumping/PlayStationPortable/MemoryStick.cs b/Aaru.Core/Devices/Dumping/PlayStationPortable/MemoryStick.cs index 959ab80d5..0297f6c56 100644 --- a/Aaru.Core/Devices/Dumping/PlayStationPortable/MemoryStick.cs +++ b/Aaru.Core/Devices/Dumping/PlayStationPortable/MemoryStick.cs @@ -46,6 +46,7 @@ using Aaru.Core.Graphics; using Aaru.Core.Logging; using Aaru.Decoders.SCSI; using Aaru.Devices; +using Aaru.Images; using Aaru.Logging; using Humanizer; using Version = Aaru.CommonTypes.Interop.Version; @@ -142,6 +143,8 @@ public partial class Dump return; } + if(outputFormat is AaruFormat aif && _errorRecovery > 0) aif.SetErasureCodingAuto((byte)_errorRecovery); + _dumpStopwatch.Restart(); double imageWriteDuration = 0; diff --git a/Aaru.Core/Devices/Dumping/PlayStationPortable/UMD.cs b/Aaru.Core/Devices/Dumping/PlayStationPortable/UMD.cs index 12b5cebd3..40b660814 100644 --- a/Aaru.Core/Devices/Dumping/PlayStationPortable/UMD.cs +++ b/Aaru.Core/Devices/Dumping/PlayStationPortable/UMD.cs @@ -43,6 +43,7 @@ using Aaru.Core.Graphics; using Aaru.Core.Logging; using Aaru.Decoders.SCSI; using Aaru.Devices; +using Aaru.Images; using Aaru.Logging; using Humanizer; using Track = Aaru.CommonTypes.Structs.Track; @@ -169,6 +170,8 @@ public partial class Dump return; } + if(outputOptical is AaruFormat aif && _errorRecovery > 0) aif.SetErasureCodingAuto((byte)_errorRecovery); + _dumpStopwatch.Restart(); double imageWriteDuration = 0; diff --git a/Aaru.Core/Devices/Dumping/SSC.cs b/Aaru.Core/Devices/Dumping/SSC.cs index bfc27d089..3127c3371 100644 --- a/Aaru.Core/Devices/Dumping/SSC.cs +++ b/Aaru.Core/Devices/Dumping/SSC.cs @@ -48,6 +48,7 @@ using Aaru.Decoders.SCSI; using Aaru.Decoders.SCSI.SSC; using Aaru.Devices; using Aaru.Helpers; +using Aaru.Images; using Aaru.Logging; using Humanizer; using TapeFile = Aaru.CommonTypes.Structs.TapeFile; @@ -283,8 +284,9 @@ partial class Dump Modes.DecodedMode? decMode = null; if(!sense && !_dev.Error) - if(Modes.DecodeMode10(cmdBuf, _dev.ScsiType).HasValue) - decMode = Modes.DecodeMode10(cmdBuf, _dev.ScsiType); + { + if(Modes.DecodeMode10(cmdBuf, _dev.ScsiType).HasValue) decMode = Modes.DecodeMode10(cmdBuf, _dev.ScsiType); + } UpdateStatus?.Invoke(Localization.Core.Requesting_MODE_SENSE_6); @@ -312,8 +314,9 @@ partial class Dump if(sense || _dev.Error) sense = _dev.ModeSense(out cmdBuf, out senseBuf, 5, out duration); if(!sense && !_dev.Error) - if(Modes.DecodeMode6(cmdBuf, _dev.ScsiType).HasValue) - decMode = Modes.DecodeMode6(cmdBuf, _dev.ScsiType); + { + if(Modes.DecodeMode6(cmdBuf, _dev.ScsiType).HasValue) decMode = Modes.DecodeMode6(cmdBuf, _dev.ScsiType); + } // TODO: Check partitions page if(decMode.HasValue) @@ -834,6 +837,8 @@ partial class Dump return; } + if(outputTape is AaruFormat aif && _errorRecovery > 0) aif.SetErasureCodingAuto((byte)_errorRecovery); + _dumpStopwatch.Restart(); var mhddLog = new MhddLog(_outputPrefix + ".mhddlog.bin", _dev, blocks, blockSize, 1, _private); var ibgLog = new IbgLog(_outputPrefix + ".ibg", 0x0008); diff --git a/Aaru.Core/Devices/Dumping/Sbc/Dump.cs b/Aaru.Core/Devices/Dumping/Sbc/Dump.cs index 9bc81a079..86c636ad5 100644 --- a/Aaru.Core/Devices/Dumping/Sbc/Dump.cs +++ b/Aaru.Core/Devices/Dumping/Sbc/Dump.cs @@ -35,7 +35,6 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; -using System.Net.Http.Headers; using System.Text.Json; using Aaru.CommonTypes; using Aaru.CommonTypes.AaruMetadata; @@ -76,16 +75,16 @@ partial class Dump DVDDecryption dvdDecrypt = null) { bool sense; - byte scsiMediumType = 0; - byte scsiDensityCode = 0; + byte scsiMediumType = 0; + byte scsiDensityCode = 0; var containsFloppyPage = false; - const ushort sbcProfile = 0x0001; - const uint DvdLeadinSectors = 4096; // Usable Lead-in before LBA 0 per DVD spec (PSN 0x02F000–0x02FFFF) - double totalDuration = 0; - double currentSpeed = 0; - double maxSpeed = double.MinValue; - double minSpeed = double.MaxValue; - Modes.DecodedMode? decMode = null; + const ushort sbcProfile = 0x0001; + const uint DvdLeadinSectors = 4096; // Usable Lead-in before LBA 0 per DVD spec (PSN 0x02F000–0x02FFFF) + double totalDuration = 0; + double currentSpeed = 0; + double maxSpeed = double.MinValue; + double minSpeed = double.MaxValue; + Modes.DecodedMode? decMode = null; bool ret; ExtentsULong blankExtents = null; var outputFormat = _outputPlugin as IWritableImage; @@ -325,9 +324,9 @@ partial class Dump scsiReader.layerbreak = decodedPfi?.Layer0EndPSN ?? 0; if(scsiReader.layerbreak == 0) scsiReader.layerbreak = decodedPfi?.DataAreaEndPSN ?? 0; - scsiReader.otp = decodedPfi?.TrackPath ?? false; + scsiReader.otp = decodedPfi?.TrackPath ?? false; - if(scsiReader.HldtstReadRaw) blocksToRead = 1; + if(scsiReader.HldtstReadRaw) blocksToRead = 1; if(scsiReader.OmniDriveReadRaw) blocksToRead = 31; UpdateStatus?.Invoke(string.Format(Localization.Core.Reading_0_raw_bytes_1_cooked_bytes_per_sector, @@ -345,7 +344,8 @@ partial class Dump { if(!scsiReader.OmniDriveReadRaw) { - StoppingErrorMessage?.Invoke(Localization.Core.Dumping_Nintendo_GameCube_or_Wii_discs_is_not_yet_implemented); + StoppingErrorMessage?.Invoke(Localization.Core + .Dumping_Nintendo_GameCube_or_Wii_discs_is_not_yet_implemented); return; } @@ -410,6 +410,8 @@ partial class Dump return; } + if(outputFormat is AaruFormat aif && _errorRecovery > 0) aif.SetErasureCodingAuto((byte)_errorRecovery); + imageCreated = true; } @@ -428,13 +430,13 @@ partial class Dump if(decodedPfi.HasValue) nominalNegativeSectors = decodedPfi.Value.DataAreaStartPSN; if(scsiReader.OmniDriveReadRaw && - decodedPfi.HasValue && - ((dskType >= MediaType.DVDROM && dskType <= MediaType.DVDDownload) - || dskType == MediaType.PS2DVD - || dskType == MediaType.PS3DVD - || dskType == MediaType.Nuon - || dskType == MediaType.GOD - || dskType == MediaType.WOD)) + decodedPfi.HasValue && + (dskType >= MediaType.DVDROM && dskType <= MediaType.DVDDownload || + dskType == MediaType.PS2DVD || + dskType == MediaType.PS3DVD || + dskType == MediaType.Nuon || + dskType == MediaType.GOD || + dskType == MediaType.WOD)) nominalNegativeSectors = Math.Min(nominalNegativeSectors, DvdLeadinSectors); mediaTags.TryGetValue(MediaTagType.BD_DI, out byte[] di); @@ -587,6 +589,9 @@ partial class Dump return; } + if(outputFormat is AaruFormat aif && _errorRecovery > 0) + aif.SetErasureCodingAuto((byte)_errorRecovery); + imageCreated = true; #if DEBUG @@ -722,6 +727,8 @@ partial class Dump return; } + if(outputFormat is AaruFormat aif && _errorRecovery > 0) aif.SetErasureCodingAuto((byte)_errorRecovery); + if(writeSingleOpticalTrack) { UpdateStatus?.Invoke(Localization.Core @@ -811,8 +818,7 @@ partial class Dump var newTrim = false; - if(ngcwMode && !InitializeNgcwContext(dskType, scsiReader, outputFormat)) - return; + if(ngcwMode && !InitializeNgcwContext(dskType, scsiReader, outputFormat)) return; if(mediaTags.TryGetValue(MediaTagType.DVD_CMI, out byte[] cmi) && Settings.Settings.Current.EnableDecryption && @@ -849,33 +855,35 @@ partial class Dump if(scsiReader.HldtstReadRaw || scsiReader.ReadBuffer3CReadRaw || scsiReader.OmniDriveReadRaw) { - uint nominalForRawDvd = 0; + uint nominalForRawDvd = 0; uint overflowForRawDvd = 0; + if(scsiReader.OmniDriveReadRaw && outputFormat is IWritableOpticalImage optImg) { if(optImg.OpticalCapabilities.HasFlag(OpticalImageCapabilities.CanStoreNegativeSectors)) nominalForRawDvd = nominalNegativeSectors; + if(optImg.OpticalCapabilities.HasFlag(OpticalImageCapabilities.CanStoreOverflowSectors)) overflowForRawDvd = 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); + blocksToRead, + blockSize, + currentTry, + extents, + ref currentSpeed, + ref minSpeed, + ref maxSpeed, + ref totalDuration, + scsiReader, + mhddLog, + ibgLog, + ref imageWriteDuration, + ref newTrim, + discKey ?? null, + nominalForRawDvd, + overflowForRawDvd); } else { @@ -962,8 +970,8 @@ partial class Dump // Unnecessary since keys are already in raw data !scsiReader.ReadBuffer3CReadRaw && - !scsiReader.OmniDriveReadRaw && - !scsiReader.HldtstReadRaw && + !scsiReader.OmniDriveReadRaw && + !scsiReader.HldtstReadRaw && mediaTag is not null) RetryTitleKeys(dvdDecrypt, mediaTag, ref totalDuration); diff --git a/Aaru.Core/Devices/Dumping/SecureDigital.cs b/Aaru.Core/Devices/Dumping/SecureDigital.cs index aa863ddfe..f93aff8ba 100644 --- a/Aaru.Core/Devices/Dumping/SecureDigital.cs +++ b/Aaru.Core/Devices/Dumping/SecureDigital.cs @@ -46,6 +46,7 @@ using Aaru.Core.Graphics; using Aaru.Core.Logging; using Aaru.Decoders.MMC; using Aaru.Decoders.SecureDigital; +using Aaru.Images; using Aaru.Logging; using Humanizer; using CSD = Aaru.Decoders.MMC.CSD; @@ -457,6 +458,8 @@ public partial class Dump return; } + if(outputFormat is AaruFormat aif && _errorRecovery > 0) aif.SetErasureCodingAuto((byte)_errorRecovery); + if(cid != null) { switch(_dev.Type) diff --git a/Aaru.Core/Devices/Dumping/XGD.cs b/Aaru.Core/Devices/Dumping/XGD.cs index c1a1d21e5..15536132b 100644 --- a/Aaru.Core/Devices/Dumping/XGD.cs +++ b/Aaru.Core/Devices/Dumping/XGD.cs @@ -48,6 +48,7 @@ using Aaru.Decoders.DVD; using Aaru.Decoders.SCSI; using Aaru.Decoders.Xbox; using Aaru.Devices; +using Aaru.Images; using Aaru.Logging; using Humanizer; using Device = Aaru.Devices.Remote.Device; @@ -515,6 +516,8 @@ partial class Dump return; } + if(outputFormat is AaruFormat aif && _errorRecovery > 0) aif.SetErasureCodingAuto((byte)_errorRecovery); + _dumpStopwatch.Restart(); double imageWriteDuration = 0; @@ -1088,9 +1091,8 @@ partial class Dump List tmpList = []; foreach(ulong ur in _resume.BadBlocks) - { - for(ulong i = ur; i < ur + blocksToRead; i++) tmpList.Add(i); - } + for(ulong i = ur; i < ur + blocksToRead; i++) + tmpList.Add(i); tmpList.Sort(); diff --git a/Aaru.Core/Image/Convert/Convert.cs b/Aaru.Core/Image/Convert/Convert.cs index ad5957b2c..3889c6159 100644 --- a/Aaru.Core/Image/Convert/Convert.cs +++ b/Aaru.Core/Image/Convert/Convert.cs @@ -27,6 +27,7 @@ public partial class Convert readonly string _driveManufacturer; readonly string _driveModel; readonly string _driveSerialNumber; + readonly int _errorRecovery; readonly bool _fixSubchannel; readonly bool _fixSubchannelCrc; readonly bool _fixSubchannelPosition; @@ -64,7 +65,7 @@ public partial class Convert PluginRegister plugins, bool fixSubchannelPosition, bool fixSubchannel, bool fixSubchannelCrc, bool generateSubchannels, (uint cylinders, uint heads, uint sectors)? geometryValues, Resume resume, Metadata sidecar, bool bypassPs3Decryption, bool bypassWiiuDecryption, bool bypassWiiDecryption, - string inputPath = null) + string inputPath, int errorRecovery) { _inputImage = inputImage; _outputImage = outputImage; @@ -102,6 +103,7 @@ public partial class Convert _bypassWiiuDecryption = bypassWiiuDecryption; _bypassWiiDecryption = bypassWiiDecryption; _inputPath = inputPath; + _errorRecovery = errorRecovery; } public ErrorNumber Start() diff --git a/Aaru.Core/Image/Convert/Create.cs b/Aaru.Core/Image/Convert/Create.cs index 900eb1416..57b6a48b7 100644 --- a/Aaru.Core/Image/Convert/Create.cs +++ b/Aaru.Core/Image/Convert/Create.cs @@ -1,4 +1,5 @@ using Aaru.CommonTypes.Enums; +using Aaru.Images; using Aaru.Localization; namespace Aaru.Core.Image; @@ -26,6 +27,8 @@ public partial class Convert _overflowSectors, _inputImage.Info.SectorSize); + if(_outputImage is AaruFormat aif && _errorRecovery > 0) aif.SetErasureCodingAuto((byte)_errorRecovery); + EndProgress?.Invoke(); if(created) return ErrorNumber.NoError; diff --git a/Aaru.Core/Image/Merge/Create.cs b/Aaru.Core/Image/Merge/Create.cs index 87bd81347..681a791ae 100644 --- a/Aaru.Core/Image/Merge/Create.cs +++ b/Aaru.Core/Image/Merge/Create.cs @@ -1,6 +1,7 @@ using Aaru.CommonTypes; using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Interfaces; +using Aaru.Images; using Aaru.Localization; namespace Aaru.Core.Image; @@ -23,6 +24,8 @@ public sealed partial class Merger overflowSectors, primaryImage.Info.SectorSize); + if(outputImage is AaruFormat aif && errorRecovery > 0) aif.SetErasureCodingAuto((byte)errorRecovery); + EndProgress?.Invoke(); if(created) return ErrorNumber.NoError; diff --git a/Aaru.Core/Image/Merge/Merger.cs b/Aaru.Core/Image/Merge/Merger.cs index de7693a30..c63bfb9de 100644 --- a/Aaru.Core/Image/Merge/Merger.cs +++ b/Aaru.Core/Image/Merge/Merger.cs @@ -6,6 +6,7 @@ using Aaru.CommonTypes.AaruMetadata; using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Interfaces; using Aaru.CommonTypes.Metadata; +using Aaru.Images; using Aaru.Localization; using File = System.IO.File; using MediaType = Aaru.CommonTypes.MediaType; @@ -49,7 +50,8 @@ public sealed partial class Merger bool generateSubchannels, bool decrypt, bool ignoreNegativeSectors, - bool ignoreOverflowSectors + bool ignoreOverflowSectors, + int errorRecovery ) { const string MODULE_NAME = "Image merger"; @@ -144,6 +146,23 @@ public sealed partial class Merger UpdateStatus?.Invoke(string.Format(UI.Output_image_format_0, outputFormat.Name)); + if(errorRecovery > 0) + { + if(outputFormat is not AaruFormat) + { + StoppingErrorMessage?.Invoke(UI.Error_recovery_is_only_supported_in_AaruFormat); + + return ErrorNumber.NotSupported; + } + + if(errorRecovery > 100) + { + StoppingErrorMessage?.Invoke(UI.Maximum_error_recovery_is_100); + + return ErrorNumber.InvalidArgument; + } + } + if(primaryImage.Info.Sectors != secondaryImage.Info.Sectors) { StoppingErrorMessage?.Invoke(UI.Images_have_different_number_of_sectors_cannot_merge); @@ -220,13 +239,13 @@ public sealed partial class Merger InitProgress?.Invoke(); PulseProgress?.Invoke(UI.Calculating_sectors_to_merge); - List sectorsToCopyFromSecondImage = - CalculateSectorsToCopy(primaryImage, secondaryImage, primaryResume, secondaryResume, overrideSectorsList); + List sectorsToCopyFromSecondImage = + CalculateSectorsToCopy(primaryImage, secondaryImage, primaryResume, secondaryResume, overrideSectorsList); EndProgress?.Invoke(); // Flux images might contain no decoded data, which results in a sector count of 0. We allow this if the image contains flux. - var containsFlux = primaryImage is IFluxImage || secondaryImage is IFluxImage; + bool containsFlux = primaryImage is IFluxImage || secondaryImage is IFluxImage; if(sectorsToCopyFromSecondImage.Count == 0 && !containsFlux) { @@ -349,7 +368,7 @@ public sealed partial class Merger if(primaryImage is IFluxImage primaryFlux && outputFormat is IWritableFluxImage outputFlux) { - IFluxImage secondaryFlux = secondaryImage as IFluxImage; + var secondaryFlux = secondaryImage as IFluxImage; UpdateStatus?.Invoke(secondaryFlux != null ? UI.Flux_merge_primary_then_secondary_appended diff --git a/Aaru.Gui/ViewModels/Windows/ImageConvertViewModel.cs b/Aaru.Gui/ViewModels/Windows/ImageConvertViewModel.cs index 55c7ec544..407c6578a 100644 --- a/Aaru.Gui/ViewModels/Windows/ImageConvertViewModel.cs +++ b/Aaru.Gui/ViewModels/Windows/ImageConvertViewModel.cs @@ -352,7 +352,8 @@ public sealed partial class ImageConvertViewModel : ViewModelBase false, false, false, - SourceText); + SourceText, + 0); // Prepare UI await Dispatcher.UIThread.InvokeAsync(() => diff --git a/Aaru.Gui/ViewModels/Windows/MediaDumpViewModel.cs b/Aaru.Gui/ViewModels/Windows/MediaDumpViewModel.cs index f2b651f52..0be8908b4 100644 --- a/Aaru.Gui/ViewModels/Windows/MediaDumpViewModel.cs +++ b/Aaru.Gui/ViewModels/Windows/MediaDumpViewModel.cs @@ -762,7 +762,8 @@ public sealed partial class MediaDumpViewModel : ViewModelBase Paranoia, CureParanoia, BypassWiiDecryption, - false); + false, + 0); new Thread(DoWork).Start(); } diff --git a/Aaru.Localization/UI.Designer.cs b/Aaru.Localization/UI.Designer.cs index 2ef6e5706..5da2885bd 100644 --- a/Aaru.Localization/UI.Designer.cs +++ b/Aaru.Localization/UI.Designer.cs @@ -11231,5 +11231,23 @@ namespace Aaru.Localization { return ResourceManager.GetString("Start_reverse_error_retry", resourceCulture); } } + + public static string Add_error_recovery { + get { + return ResourceManager.GetString("Add_error_recovery", resourceCulture); + } + } + + public static string Error_recovery_is_only_supported_in_AaruFormat { + get { + return ResourceManager.GetString("Error_recovery_is_only_supported_in_AaruFormat", resourceCulture); + } + } + + public static string Maximum_error_recovery_is_100 { + get { + return ResourceManager.GetString("Maximum_error_recovery_is_100", resourceCulture); + } + } } } diff --git a/Aaru.Localization/UI.es.resx b/Aaru.Localization/UI.es.resx index d15987146..148621ca1 100644 --- a/Aaru.Localization/UI.es.resx +++ b/Aaru.Localization/UI.es.resx @@ -5611,4 +5611,13 @@ Probadores: Comenzar reintentos de errores al revés. + + Añade el porcentaje especificado de recuperación de errores (sólo AaruFormat). + + + La recuperación de errores solo está soportada en AaruFormat + + + La recuperación de errores máxima es 100% + \ No newline at end of file diff --git a/Aaru.Localization/UI.resx b/Aaru.Localization/UI.resx index 21b9bc461..0a4315eb9 100644 --- a/Aaru.Localization/UI.resx +++ b/Aaru.Localization/UI.resx @@ -5695,4 +5695,13 @@ Do you want to continue? Start error retrying in reverse. + + Add the specified percentage of error recovery (only AaruFormat). + + + Error recovery is only supported in AaruFormat + + + Maximum error recovery is 100% + \ No newline at end of file diff --git a/Aaru/Commands/Image/Convert.cs b/Aaru/Commands/Image/Convert.cs index 5b0826f9f..7ba3226b3 100644 --- a/Aaru/Commands/Image/Convert.cs +++ b/Aaru/Commands/Image/Convert.cs @@ -44,6 +44,7 @@ using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Interfaces; using Aaru.CommonTypes.Metadata; using Aaru.Core; +using Aaru.Images; using Aaru.Localization; using Aaru.Logging; using Schemas; @@ -234,6 +235,23 @@ sealed class ConvertImageCommand : Command if(outputFormat == null) return (int)ErrorNumber.FormatNotFound; + if(settings.ErrorRecovery > 0) + { + if(outputFormat is not AaruFormat) + { + AaruLogging.Error(UI.Error_recovery_is_only_supported_in_AaruFormat); + + return (int)ErrorNumber.NotSupported; + } + + if(settings.ErrorRecovery > 100) + { + AaruLogging.Error(UI.Maximum_error_recovery_is_100); + + return (int)ErrorNumber.InvalidArgument; + } + } + if(settings.Verbose) AaruLogging.Verbose(UI.Output_image_format_0_1, outputFormat.Name, outputFormat.Id); else @@ -274,7 +292,8 @@ sealed class ConvertImageCommand : Command settings.BypassPs3Decryption, settings.BypassWiiuDecryption, settings.BypassWiiDecryption, - settings.InputPath); + settings.InputPath, + settings.ErrorRecovery); ErrorNumber errno = ErrorNumber.NoError; @@ -560,6 +579,7 @@ sealed class ConvertImageCommand : Command AaruLogging.Debug(MODULE_NAME, "--aaru-metadata={0}", Markup.Escape(settings.AaruMetadata ?? "")); AaruLogging.Debug(MODULE_NAME, "--ignore-negative-sectors={0}", settings.IgnoreNegativeSectors); AaruLogging.Debug(MODULE_NAME, "--ignore-overflow-sectors={0}", settings.IgnoreOverflowSectors); + AaruLogging.Debug(MODULE_NAME, "--error-recovery={0}", settings.ErrorRecovery); AaruLogging.Debug(MODULE_NAME, UI.Parsed_options); @@ -758,5 +778,9 @@ sealed class ConvertImageCommand : Command [DefaultValue(false)] [CommandOption("--ignore-overflow-sectors")] public bool IgnoreOverflowSectors { get; init; } + [LocalizedDescription(nameof(UI.Add_error_recovery))] + [DefaultValue(0)] + [CommandOption("--error-recovery")] + public int ErrorRecovery { get; set; } } } \ No newline at end of file diff --git a/Aaru/Commands/Image/Merge.cs b/Aaru/Commands/Image/Merge.cs index 070666531..ab46658d4 100644 --- a/Aaru/Commands/Image/Merge.cs +++ b/Aaru/Commands/Image/Merge.cs @@ -72,7 +72,8 @@ class MergeCommand : AsyncCommand settings.GenerateSubchannels, settings.Decrypt, settings.IgnoreNegativeSectors, - settings.IgnoreOverflowSectors); + settings.IgnoreOverflowSectors, + settings.ErrorRecovery); ErrorNumber errno = ErrorNumber.NoError; @@ -188,6 +189,7 @@ class MergeCommand : AsyncCommand AaruLogging.Debug(MODULE_NAME, "--sectors-file={0}", Markup.Escape(settings.SectorsFile ?? "")); AaruLogging.Debug(MODULE_NAME, "--ignore-negative-sectors={0}", settings.IgnoreNegativeSectors); AaruLogging.Debug(MODULE_NAME, "--ignore-overflow-sectors={0}", settings.IgnoreOverflowSectors); + AaruLogging.Debug(MODULE_NAME, "--error-recovery={0}", settings.ErrorRecovery); AaruLogging.Debug(MODULE_NAME, UI.Parsed_options); @@ -326,5 +328,9 @@ class MergeCommand : AsyncCommand [DefaultValue(false)] [CommandOption("--ignore-overflow-sectors")] public bool IgnoreOverflowSectors { get; init; } + [LocalizedDescription(nameof(UI.Add_error_recovery))] + [DefaultValue(0)] + [CommandOption("--error-recovery")] + public int ErrorRecovery { get; set; } } } \ No newline at end of file diff --git a/Aaru/Commands/Media/Dump.cs b/Aaru/Commands/Media/Dump.cs index d86175fa9..e3cc188c1 100644 --- a/Aaru/Commands/Media/Dump.cs +++ b/Aaru/Commands/Media/Dump.cs @@ -51,6 +51,7 @@ using Aaru.CommonTypes.Structs.Devices.SCSI; using Aaru.Core; using Aaru.Core.Devices.Dumping; using Aaru.Core.Logging; +using Aaru.Images; using Aaru.Localization; using Aaru.Logging; using Schemas; @@ -126,6 +127,7 @@ sealed class DumpMediaCommand : Command AaruLogging.Debug(MODULE_NAME, "--cure-paranoia={0}", settings.CureParanoia); AaruLogging.Debug(MODULE_NAME, "--raw={0}", settings.Raw); AaruLogging.Debug(MODULE_NAME, "--start-reverse={0}", settings.StartReverse); + AaruLogging.Debug(MODULE_NAME, "--error-recovery={0}", settings.ErrorRecovery); Dictionary parsedOptions = Options.Parse(settings.Options); AaruLogging.Debug(MODULE_NAME, UI.Parsed_options); @@ -480,6 +482,23 @@ sealed class DumpMediaCommand : Command IBaseWritableImage outputFormat = candidates[0]; + if(settings.ErrorRecovery > 0) + { + if(outputFormat is not AaruFormat) + { + AaruLogging.Error(UI.Error_recovery_is_only_supported_in_AaruFormat); + + return (int)ErrorNumber.NotSupported; + } + + if(settings.ErrorRecovery > 100) + { + AaruLogging.Error(UI.Maximum_error_recovery_is_100); + + return (int)ErrorNumber.InvalidArgument; + } + } + DeviceLog.StartLog(dev, settings.Private); if(settings.Verbose) @@ -530,7 +549,8 @@ sealed class DumpMediaCommand : Command settings.Paranoia, settings.CureParanoia, settings.BypassWiiDecryption, - settings.StartReverse); + settings.StartReverse, + settings.ErrorRecovery); AnsiConsole.Progress() .AutoClear(true) @@ -806,6 +826,10 @@ sealed class DumpMediaCommand : Command [LocalizedDescription(nameof(UI.Start_reverse_error_retry))] [CommandOption("--start-reverse")] public bool StartReverse { get; init; } + [LocalizedDescription(nameof(UI.Add_error_recovery))] + [DefaultValue(0)] + [CommandOption("--error-recovery")] + public int ErrorRecovery { get; set; } } #endregion