using System.Collections.Generic; using System.Linq; using Aaru.CommonTypes.Enums; using Aaru.Localization; using Aaru.Logging; namespace Aaru.Core.Image; public partial class Convert { /// /// Converts negative sectors (pre-gap) from input to output image /// Handles both long and short sector formats with progress indication /// Also converts associated sector tags if present /// /// Error code if conversion fails in non-force mode ErrorNumber ConvertNegativeSectors(bool useLong) { if(_aborted) return ErrorNumber.NoError; ErrorNumber errno = ErrorNumber.NoError; InitProgress?.Invoke(); List notDumped = []; // There's no -0 for(uint i = 1; i <= _negativeSectors; i++) { if(_aborted) break; byte[] sector; UpdateProgress?.Invoke(string.Format(UI.Converting_negative_sector_0_of_1, i, _negativeSectors), i, _negativeSectors); bool result; SectorStatus sectorStatus; if(useLong) { errno = _inputImage.ReadSectorLong(i, true, out sector, out sectorStatus); if(errno == ErrorNumber.NoError) { if(sectorStatus == SectorStatus.NotDumped) { notDumped.Add(i); continue; } result = _outputImage.WriteSectorLong(sector, i, true, sectorStatus); } else { result = true; if(_force) ErrorMessage?.Invoke(string.Format(UI.Error_0_reading_negative_sector_1_continuing, errno, i)); else { StoppingErrorMessage?.Invoke(string.Format(UI.Error_0_reading_negative_sector_1_not_continuing, errno, i)); return errno; } } } else { errno = _inputImage.ReadSector(i, true, out sector, out sectorStatus); if(errno == ErrorNumber.NoError) { if(sectorStatus == SectorStatus.NotDumped) { notDumped.Add(i); continue; } result = _outputImage.WriteSector(sector, i, true, sectorStatus); } else { result = true; if(_force) ErrorMessage?.Invoke(string.Format(UI.Error_0_reading_negative_sector_1_continuing, errno, i)); else { StoppingErrorMessage?.Invoke(string.Format(UI.Error_0_reading_negative_sector_1_not_continuing, errno, i)); return errno; } } } if(result) continue; if(_force) { ErrorMessage?.Invoke(string.Format(UI.Error_0_writing_negative_sector_1_continuing, _outputImage.ErrorMessage, i)); } else { StoppingErrorMessage?.Invoke(string.Format(UI.Error_0_writing_negative_sector_1_not_continuing, _outputImage.ErrorMessage, i)); return ErrorNumber.WriteError; } } EndProgress?.Invoke(); foreach(SectorTagType tag in _inputImage.Info.ReadableSectorTags.TakeWhile(_ => useLong) .TakeWhile(_ => !_aborted)) { switch(tag) { case SectorTagType.AppleSonyTag: case SectorTagType.AppleProfileTag: case SectorTagType.PriamDataTowerTag: case SectorTagType.CdSectorSync: case SectorTagType.CdSectorHeader: case SectorTagType.CdSectorSubHeader: case SectorTagType.CdSectorEdc: case SectorTagType.CdSectorEccP: case SectorTagType.CdSectorEccQ: case SectorTagType.CdSectorEcc: // These tags are inline in long sector continue; case SectorTagType.CdTrackFlags: case SectorTagType.CdTrackIsrc: case SectorTagType.CdTrackText: // These tags are track tags continue; } if(_force && !_outputImage.SupportedSectorTags.Contains(tag)) continue; InitProgress?.Invoke(); for(uint i = 1; i <= _negativeSectors; i++) { if(_aborted) break; if(notDumped.Contains(i)) continue; UpdateProgress?.Invoke(string.Format(UI.Converting_tag_1_for_negative_sector_0, i, tag), i, _negativeSectors); bool result; errno = _inputImage.ReadSectorTag(i, true, tag, out byte[] sector); if(errno == ErrorNumber.NoError) result = _outputImage.WriteSectorTag(sector, i, true, tag); else { result = true; if(_force) AaruLogging.Error(UI.Error_0_reading_negative_sector_1_continuing, errno, i); else { AaruLogging.Error(UI.Error_0_reading_negative_sector_1_not_continuing, errno, i); return errno; } } if(result) continue; if(_force) AaruLogging.Error(UI.Error_0_writing_negative_sector_1_continuing, _outputImage.ErrorMessage, i); else { AaruLogging.Error(UI.Error_0_writing_negative_sector_1_not_continuing, _outputImage.ErrorMessage, i); return ErrorNumber.WriteError; } } } return errno; } /// /// Converts overflow sectors (lead-out) from input to output image /// Handles both long and short sector formats with progress indication /// Also converts associated sector tags if present /// /// Error code if conversion fails in non-force mode ErrorNumber ConvertOverflowSectors(bool useLong) { if(_aborted) return ErrorNumber.NoError; ErrorNumber errno = ErrorNumber.NoError; InitProgress?.Invoke(); List notDumped = []; for(uint i = 0; i < _overflowSectors; i++) { if(_aborted) break; byte[] sector; UpdateProgress?.Invoke(string.Format(UI.Converting_overflow_sector_0_of_1, i, _overflowSectors), i, _overflowSectors); bool result; SectorStatus sectorStatus; if(useLong) { errno = _inputImage.ReadSectorLong(_inputImage.Info.Sectors + i, false, out sector, out sectorStatus); if(errno == ErrorNumber.NoError) { if(sectorStatus == SectorStatus.NotDumped) { notDumped.Add(i); continue; } result = _outputImage.WriteSectorLong(sector, _inputImage.Info.Sectors + i, false, sectorStatus); } else { result = true; if(_force) ErrorMessage?.Invoke(string.Format(UI.Error_0_reading_overflow_sector_1_continuing, errno, i)); else { StoppingErrorMessage?.Invoke(string.Format(UI.Error_0_reading_overflow_sector_1_not_continuing, errno, i)); return errno; } } } else { errno = _inputImage.ReadSector(_inputImage.Info.Sectors + i, false, out sector, out sectorStatus); if(errno == ErrorNumber.NoError) { if(sectorStatus == SectorStatus.NotDumped) { notDumped.Add(i); continue; } result = _outputImage.WriteSector(sector, _inputImage.Info.Sectors + i, false, sectorStatus); } else { result = true; if(_force) ErrorMessage?.Invoke(string.Format(UI.Error_0_reading_overflow_sector_1_continuing, errno, i)); else { StoppingErrorMessage?.Invoke(string.Format(UI.Error_0_reading_overflow_sector_1_not_continuing, errno, i)); return errno; } } } if(result) continue; if(_force) { ErrorMessage?.Invoke(string.Format(UI.Error_0_writing_overflow_sector_1_continuing, _outputImage.ErrorMessage, i)); } else { StoppingErrorMessage?.Invoke(string.Format(UI.Error_0_writing_overflow_sector_1_not_continuing, _outputImage.ErrorMessage, i)); return ErrorNumber.WriteError; } } EndProgress?.Invoke(); foreach(SectorTagType tag in _inputImage.Info.ReadableSectorTags.TakeWhile(_ => useLong) .TakeWhile(_ => !_aborted)) { switch(tag) { case SectorTagType.AppleSonyTag: case SectorTagType.AppleProfileTag: case SectorTagType.PriamDataTowerTag: case SectorTagType.CdSectorSync: case SectorTagType.CdSectorHeader: case SectorTagType.CdSectorSubHeader: case SectorTagType.CdSectorEdc: case SectorTagType.CdSectorEccP: case SectorTagType.CdSectorEccQ: case SectorTagType.CdSectorEcc: // These tags are inline in long sector continue; case SectorTagType.CdTrackFlags: case SectorTagType.CdTrackIsrc: case SectorTagType.CdTrackText: // These tags are track tags continue; } if(_force && !_outputImage.SupportedSectorTags.Contains(tag)) continue; InitProgress?.Invoke(); for(uint i = 1; i <= _overflowSectors; i++) { if(_aborted) break; if(notDumped.Contains(i)) continue; UpdateProgress?.Invoke(string.Format(UI.Converting_tag_1_for_overflow_sector_0, i, tag), i, _overflowSectors); bool result; errno = _inputImage.ReadSectorTag(_inputImage.Info.Sectors + i, false, tag, out byte[] sector); if(errno == ErrorNumber.NoError) result = _outputImage.WriteSectorTag(sector, _inputImage.Info.Sectors + i, false, tag); else { result = true; if(_force) { ErrorMessage?.Invoke(string.Format(UI.Error_0_reading_overflow_sector_1_continuing, errno, _inputImage.Info.Sectors + i)); } else { StoppingErrorMessage?.Invoke(string.Format(UI.Error_0_reading_overflow_sector_1_not_continuing, errno, _inputImage.Info.Sectors + i)); return errno; } } if(result) continue; if(_force) { ErrorMessage?.Invoke(string.Format(UI.Error_0_writing_overflow_sector_1_continuing, _outputImage.ErrorMessage, _inputImage.Info.Sectors + i)); } else { StoppingErrorMessage?.Invoke(string.Format(UI.Error_0_writing_overflow_sector_1_not_continuing, _outputImage.ErrorMessage, _inputImage.Info.Sectors + i)); return ErrorNumber.WriteError; } } EndProgress?.Invoke(); } return errno; } }