From 6f5fed529994b68f58c288b766e7eef221ee7aa2 Mon Sep 17 00:00:00 2001 From: Natalia Portillo Date: Tue, 3 Mar 2026 16:01:43 +0000 Subject: [PATCH] [WinOnCD] Implement missing methods. --- Aaru.Images/WinOnCD/Open.cs | 37 +- Aaru.Images/WinOnCD/Read.cs | 542 +++++++++++++++++++++++++++ Aaru.Images/WinOnCD/Unimplemented.cs | 112 ------ Aaru.Images/WinOnCD/Verify.cs | 65 ++++ Aaru.Images/WinOnCD/WinOnCD.cs | 11 +- 5 files changed, 648 insertions(+), 119 deletions(-) create mode 100644 Aaru.Images/WinOnCD/Read.cs delete mode 100644 Aaru.Images/WinOnCD/Unimplemented.cs create mode 100644 Aaru.Images/WinOnCD/Verify.cs diff --git a/Aaru.Images/WinOnCD/Open.cs b/Aaru.Images/WinOnCD/Open.cs index 9374f3c76..3b056d6f5 100644 --- a/Aaru.Images/WinOnCD/Open.cs +++ b/Aaru.Images/WinOnCD/Open.cs @@ -96,9 +96,11 @@ public sealed partial class WinOnCD } // Step 3: Process track blocks and build tracks, sessions, and partitions - Tracks = []; - Sessions = []; - Partitions = []; + Tracks = []; + Sessions = []; + Partitions = []; + _trackFlags = new Dictionary(); + _trackIsrcs = new Dictionary(); var lastSession = 0; var lastPoint = 0; @@ -308,6 +310,14 @@ public sealed partial class WinOnCD Type = trackType.Humanize() }; + // Store C2D flags for this track + _trackFlags[trackSequence] = (byte)entry.flags; + + // Store ISRC if present + string isrc = Encoding.ASCII.GetString(entry.isrc).TrimEnd('\0'); + + if(!string.IsNullOrWhiteSpace(isrc)) _trackIsrcs[trackSequence] = isrc; + Tracks.Add(track); Partitions.Add(partition); } @@ -333,7 +343,26 @@ public sealed partial class WinOnCD if(!string.IsNullOrWhiteSpace(description)) _imageInfo.Comments = description; - if(header.has_upc_ean != 0) _imageInfo.MediaBarcode = Encoding.ASCII.GetString(header.upc_ean).TrimEnd('\0'); + if(header.has_upc_ean != 0) + { + _mcn = Encoding.ASCII.GetString(header.upc_ean).TrimEnd('\0'); + _imageInfo.MediaBarcode = _mcn; + _imageInfo.ReadableMediaTags.Add(MediaTagType.CD_MCN); + } + + // Read CD-Text if present + if(header.size_cdtext > 0) + { + long cdTextOffset = header.offset_tracks + header.num_track_blocks * Marshal.SizeOf(); + + stream.Seek(cdTextOffset, SeekOrigin.Begin); + _cdtext = new byte[header.size_cdtext]; + stream.EnsureRead(_cdtext, 0, (int)header.size_cdtext); + _imageInfo.ReadableMediaTags.Add(MediaTagType.CD_TEXT); + } + + if(_trackIsrcs.Count > 0 && !_imageInfo.ReadableSectorTags.Contains(SectorTagType.CdTrackIsrc)) + _imageInfo.ReadableSectorTags.Add(SectorTagType.CdTrackIsrc); // Determine media type based on tracks var hasData = false; diff --git a/Aaru.Images/WinOnCD/Read.cs b/Aaru.Images/WinOnCD/Read.cs new file mode 100644 index 000000000..0bc108319 --- /dev/null +++ b/Aaru.Images/WinOnCD/Read.cs @@ -0,0 +1,542 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Read.cs +// Author(s) : Natalia Portillo +// +// Component : Disc image plugins. +// +// --[ Description ] ---------------------------------------------------------- +// +// Reads WinOnCD disc images. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2026 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Structs; +using Aaru.Helpers; +using Session = Aaru.CommonTypes.Structs.Session; + +namespace Aaru.Images; + +public sealed partial class WinOnCD +{ + /// + public ErrorNumber ReadSector(ulong sectorAddress, uint track, out byte[] buffer, out SectorStatus sectorStatus) + { + buffer = null; + sectorStatus = SectorStatus.NotDumped; + + Track trk = Tracks.FirstOrDefault(t => t.Sequence == track); + + if(trk is null) return ErrorNumber.SectorNotFound; + + if(sectorAddress < trk.StartSector || sectorAddress > trk.EndSector) return ErrorNumber.OutOfRange; + + ulong offsetInTrack = sectorAddress - trk.StartSector; + int stride = trk.RawBytesPerSector + (trk.SubchannelType != TrackSubchannelType.None ? 96 : 0); + var fileOffset = (long)(trk.FileOffset + offsetInTrack * (ulong)stride); + + if(trk.RawBytesPerSector == trk.BytesPerSector) + { + buffer = new byte[trk.BytesPerSector]; + _imageStream.Seek(fileOffset, SeekOrigin.Begin); + _imageStream.EnsureRead(buffer, 0, trk.BytesPerSector); + } + else + { + var rawSector = new byte[trk.RawBytesPerSector]; + _imageStream.Seek(fileOffset, SeekOrigin.Begin); + _imageStream.EnsureRead(rawSector, 0, trk.RawBytesPerSector); + + buffer = new byte[trk.BytesPerSector]; + + switch(trk.Type) + { + case TrackType.CdMode1 when trk.RawBytesPerSector == 2352: + Array.Copy(rawSector, 16, buffer, 0, trk.BytesPerSector); + + break; + case TrackType.CdMode2Formless when trk.RawBytesPerSector == 2352: + Array.Copy(rawSector, 16, buffer, 0, trk.BytesPerSector); + + break; + default: + Array.Copy(rawSector, 0, buffer, 0, trk.BytesPerSector); + + break; + } + } + + sectorStatus = SectorStatus.Dumped; + + return ErrorNumber.NoError; + } + + /// + public ErrorNumber ReadSectors(ulong sectorAddress, uint length, uint track, out byte[] buffer, + out SectorStatus[] sectorStatus) + { + buffer = null; + sectorStatus = null; + + Track trk = Tracks.FirstOrDefault(t => t.Sequence == track); + + if(trk is null) return ErrorNumber.SectorNotFound; + + if(sectorAddress + length - 1 > trk.EndSector) return ErrorNumber.OutOfRange; + + using var ms = new MemoryStream(); + sectorStatus = new SectorStatus[length]; + + for(uint i = 0; i < length; i++) + { + ErrorNumber errno = ReadSector(sectorAddress + i, track, out byte[] sectorData, out SectorStatus status); + + if(errno != ErrorNumber.NoError) return errno; + + ms.Write(sectorData, 0, sectorData.Length); + sectorStatus[i] = status; + } + + buffer = ms.ToArray(); + + return ErrorNumber.NoError; + } + + /// + public ErrorNumber ReadSector(ulong sectorAddress, bool negative, out byte[] buffer, out SectorStatus sectorStatus) + { + buffer = null; + sectorStatus = SectorStatus.NotDumped; + + if(negative) return ErrorNumber.NotSupported; + + Track trk = Tracks.FirstOrDefault(t => sectorAddress >= t.StartSector && sectorAddress <= t.EndSector); + + if(trk is null) return ErrorNumber.SectorNotFound; + + return ReadSector(sectorAddress, trk.Sequence, out buffer, out sectorStatus); + } + + /// + public ErrorNumber ReadSectors(ulong sectorAddress, bool negative, uint length, out byte[] buffer, + out SectorStatus[] sectorStatus) + { + buffer = null; + sectorStatus = null; + + if(negative) return ErrorNumber.NotSupported; + + Track trk = Tracks.FirstOrDefault(t => sectorAddress >= t.StartSector && sectorAddress <= t.EndSector); + + if(trk is null) return ErrorNumber.SectorNotFound; + + return ReadSectors(sectorAddress, length, trk.Sequence, out buffer, out sectorStatus); + } + + /// + public ErrorNumber ReadSectorLong(ulong sectorAddress, uint track, out byte[] buffer, out SectorStatus sectorStatus) + { + buffer = null; + sectorStatus = SectorStatus.NotDumped; + + Track trk = Tracks.FirstOrDefault(t => t.Sequence == track); + + if(trk is null) return ErrorNumber.SectorNotFound; + + if(sectorAddress < trk.StartSector || sectorAddress > trk.EndSector) return ErrorNumber.OutOfRange; + + ulong offsetInTrack = sectorAddress - trk.StartSector; + int stride = trk.RawBytesPerSector + (trk.SubchannelType != TrackSubchannelType.None ? 96 : 0); + var fileOffset = (long)(trk.FileOffset + offsetInTrack * (ulong)stride); + + switch(trk.Type) + { + case TrackType.Audio: + { + buffer = new byte[2352]; + _imageStream.Seek(fileOffset, SeekOrigin.Begin); + _imageStream.EnsureRead(buffer, 0, 2352); + + break; + } + case TrackType.CdMode1: + { + if(trk.RawBytesPerSector >= 2352) + { + buffer = new byte[2352]; + _imageStream.Seek(fileOffset, SeekOrigin.Begin); + _imageStream.EnsureRead(buffer, 0, 2352); + } + else + { + var userData = new byte[trk.RawBytesPerSector]; + _imageStream.Seek(fileOffset, SeekOrigin.Begin); + _imageStream.EnsureRead(userData, 0, trk.RawBytesPerSector); + + buffer = new byte[2352]; + Array.Copy(userData, 0, buffer, 16, trk.RawBytesPerSector); + _sectorBuilder.ReconstructPrefix(ref buffer, TrackType.CdMode1, (long)sectorAddress); + _sectorBuilder.ReconstructEcc(ref buffer, TrackType.CdMode1); + } + + break; + } + case TrackType.CdMode2Form1: + { + var userData = new byte[trk.RawBytesPerSector]; + _imageStream.Seek(fileOffset, SeekOrigin.Begin); + _imageStream.EnsureRead(userData, 0, trk.RawBytesPerSector); + + buffer = new byte[2352]; + Array.Copy(userData, 0, buffer, 24, trk.RawBytesPerSector); + _sectorBuilder.ReconstructPrefix(ref buffer, TrackType.CdMode2Form1, (long)sectorAddress); + _sectorBuilder.ReconstructEcc(ref buffer, TrackType.CdMode2Form1); + + break; + } + case TrackType.CdMode2Form2: + { + var userData = new byte[trk.RawBytesPerSector]; + _imageStream.Seek(fileOffset, SeekOrigin.Begin); + _imageStream.EnsureRead(userData, 0, trk.RawBytesPerSector); + + buffer = new byte[2352]; + Array.Copy(userData, 0, buffer, 24, trk.RawBytesPerSector); + _sectorBuilder.ReconstructPrefix(ref buffer, TrackType.CdMode2Form2, (long)sectorAddress); + _sectorBuilder.ReconstructEcc(ref buffer, TrackType.CdMode2Form2); + + break; + } + case TrackType.CdMode2Formless: + { + if(trk.RawBytesPerSector >= 2352) + { + buffer = new byte[2352]; + _imageStream.Seek(fileOffset, SeekOrigin.Begin); + _imageStream.EnsureRead(buffer, 0, 2352); + } + else + { + buffer = new byte[2352]; + _sectorBuilder.ReconstructPrefix(ref buffer, TrackType.CdMode2Formless, (long)sectorAddress); + + _imageStream.Seek(fileOffset, SeekOrigin.Begin); + _imageStream.EnsureRead(buffer, 16, trk.RawBytesPerSector); + } + + break; + } + default: + return ErrorNumber.NotSupported; + } + + sectorStatus = SectorStatus.Dumped; + + return ErrorNumber.NoError; + } + + /// + public ErrorNumber ReadSectorsLong(ulong sectorAddress, uint length, uint track, out byte[] buffer, + out SectorStatus[] sectorStatus) + { + buffer = null; + sectorStatus = null; + + Track trk = Tracks.FirstOrDefault(t => t.Sequence == track); + + if(trk is null) return ErrorNumber.SectorNotFound; + + if(sectorAddress + length - 1 > trk.EndSector) return ErrorNumber.OutOfRange; + + using var ms = new MemoryStream(); + sectorStatus = new SectorStatus[length]; + + for(uint i = 0; i < length; i++) + { + ErrorNumber errno = + ReadSectorLong(sectorAddress + i, track, out byte[] sectorData, out SectorStatus status); + + if(errno != ErrorNumber.NoError) return errno; + + ms.Write(sectorData, 0, sectorData.Length); + sectorStatus[i] = status; + } + + buffer = ms.ToArray(); + + return ErrorNumber.NoError; + } + + /// + public ErrorNumber ReadSectorLong(ulong sectorAddress, bool negative, out byte[] buffer, + out SectorStatus sectorStatus) + { + buffer = null; + sectorStatus = SectorStatus.NotDumped; + + if(negative) return ErrorNumber.NotSupported; + + Track trk = Tracks.FirstOrDefault(t => sectorAddress >= t.StartSector && sectorAddress <= t.EndSector); + + if(trk is null) return ErrorNumber.SectorNotFound; + + return ReadSectorLong(sectorAddress, trk.Sequence, out buffer, out sectorStatus); + } + + /// + public ErrorNumber ReadSectorsLong(ulong sectorAddress, bool negative, uint length, out byte[] buffer, + out SectorStatus[] sectorStatus) + { + buffer = null; + sectorStatus = null; + + if(negative) return ErrorNumber.NotSupported; + + Track trk = Tracks.FirstOrDefault(t => sectorAddress >= t.StartSector && sectorAddress <= t.EndSector); + + if(trk is null) return ErrorNumber.SectorNotFound; + + return ReadSectorsLong(sectorAddress, length, trk.Sequence, out buffer, out sectorStatus); + } + + /// + public ErrorNumber ReadSectorTag(ulong sectorAddress, uint track, SectorTagType tag, out byte[] buffer) + { + buffer = null; + + Track trk = Tracks.FirstOrDefault(t => t.Sequence == track); + + if(trk is null) return ErrorNumber.SectorNotFound; + + if(sectorAddress < trk.StartSector || sectorAddress > trk.EndSector) return ErrorNumber.OutOfRange; + + switch(tag) + { + case SectorTagType.CdTrackFlags: + { + var cdFlags = (CdFlags)0; + + if(_trackFlags.TryGetValue(trk.Sequence, out byte c2dFlags)) + { + if((c2dFlags & (byte)C2dFlag.PreEmphasis) != 0) cdFlags |= CdFlags.PreEmphasis; + if((c2dFlags & (byte)C2dFlag.Copyright) != 0) cdFlags |= CdFlags.CopyPermitted; + if((c2dFlags & (byte)C2dFlag.Data) != 0) cdFlags |= CdFlags.DataTrack; + } + else if(trk.Type != TrackType.Audio) cdFlags = CdFlags.DataTrack; + + buffer = [(byte)cdFlags]; + + return ErrorNumber.NoError; + } + case SectorTagType.CdSectorSync: + case SectorTagType.CdSectorHeader: + case SectorTagType.CdSectorEdc: + case SectorTagType.CdSectorEccP: + case SectorTagType.CdSectorEccQ: + case SectorTagType.CdSectorEcc: + if(trk.Type == TrackType.Audio) return ErrorNumber.NotSupported; + + break; + case SectorTagType.CdSectorSubHeader: + if(trk.Type != TrackType.CdMode2Form1 && + trk.Type != TrackType.CdMode2Form2 && + trk.Type != TrackType.CdMode2Formless) + return ErrorNumber.NotSupported; + + break; + case SectorTagType.CdTrackIsrc: + if(!_trackIsrcs.TryGetValue(trk.Sequence, out string isrc)) return ErrorNumber.NoData; + + buffer = Encoding.ASCII.GetBytes(isrc); + + return ErrorNumber.NoError; + case SectorTagType.CdSectorSubchannel: + if(trk.SubchannelType == TrackSubchannelType.None) return ErrorNumber.NotSupported; + + { + ulong offsetInTrack = sectorAddress - trk.StartSector; + int stride = trk.RawBytesPerSector + 96; + var fileOffset = (long)(trk.FileOffset + offsetInTrack * (ulong)stride); + + buffer = new byte[96]; + _imageStream.Seek(fileOffset + trk.RawBytesPerSector, SeekOrigin.Begin); + _imageStream.EnsureRead(buffer, 0, 96); + } + + return ErrorNumber.NoError; + default: + return ErrorNumber.NotSupported; + } + + ErrorNumber errno = ReadSectorLong(sectorAddress, track, out byte[] fullSector, out SectorStatus _); + + if(errno != ErrorNumber.NoError) return errno; + + switch(tag) + { + case SectorTagType.CdSectorSync: + buffer = new byte[12]; + Array.Copy(fullSector, 0, buffer, 0, 12); + + break; + case SectorTagType.CdSectorHeader: + buffer = new byte[4]; + Array.Copy(fullSector, 12, buffer, 0, 4); + + break; + case SectorTagType.CdSectorSubHeader: + buffer = new byte[8]; + Array.Copy(fullSector, 16, buffer, 0, 8); + + break; + case SectorTagType.CdSectorEdc: + buffer = new byte[4]; + + if(trk.Type == TrackType.CdMode1) + Array.Copy(fullSector, 2064, buffer, 0, 4); + else if(trk.Type == TrackType.CdMode2Form1) + Array.Copy(fullSector, 2072, buffer, 0, 4); + else + return ErrorNumber.NotSupported; + + break; + case SectorTagType.CdSectorEccP: + if(trk.Type == TrackType.CdMode2Formless) return ErrorNumber.NotSupported; + + buffer = new byte[172]; + Array.Copy(fullSector, 2076, buffer, 0, 172); + + break; + case SectorTagType.CdSectorEccQ: + if(trk.Type == TrackType.CdMode2Formless) return ErrorNumber.NotSupported; + + buffer = new byte[104]; + Array.Copy(fullSector, 2248, buffer, 0, 104); + + break; + case SectorTagType.CdSectorEcc: + if(trk.Type == TrackType.CdMode2Formless) return ErrorNumber.NotSupported; + + buffer = new byte[276]; + Array.Copy(fullSector, 2076, buffer, 0, 276); + + break; + } + + return ErrorNumber.NoError; + } + + /// + public ErrorNumber ReadSectorsTag(ulong sectorAddress, uint length, uint track, SectorTagType tag, + out byte[] buffer) + { + buffer = null; + + Track trk = Tracks.FirstOrDefault(t => t.Sequence == track); + + if(trk is null) return ErrorNumber.SectorNotFound; + + if(sectorAddress + length - 1 > trk.EndSector) return ErrorNumber.OutOfRange; + + if(tag == SectorTagType.CdTrackFlags) return ReadSectorTag(sectorAddress, track, tag, out buffer); + + using var ms = new MemoryStream(); + + for(uint i = 0; i < length; i++) + { + ErrorNumber errno = ReadSectorTag(sectorAddress + i, track, tag, out byte[] tagData); + + if(errno != ErrorNumber.NoError) return errno; + + ms.Write(tagData, 0, tagData.Length); + } + + buffer = ms.ToArray(); + + return ErrorNumber.NoError; + } + + /// + public ErrorNumber ReadSectorTag(ulong sectorAddress, bool negative, SectorTagType tag, out byte[] buffer) + { + buffer = null; + + if(negative) return ErrorNumber.NotSupported; + + Track trk = Tracks.FirstOrDefault(t => sectorAddress >= t.StartSector && sectorAddress <= t.EndSector); + + if(trk is null) return ErrorNumber.SectorNotFound; + + return ReadSectorTag(sectorAddress, trk.Sequence, tag, out buffer); + } + + /// + public ErrorNumber ReadSectorsTag(ulong sectorAddress, bool negative, uint length, SectorTagType tag, + out byte[] buffer) + { + buffer = null; + + if(negative) return ErrorNumber.NotSupported; + + Track trk = Tracks.FirstOrDefault(t => sectorAddress >= t.StartSector && sectorAddress <= t.EndSector); + + if(trk is null) return ErrorNumber.SectorNotFound; + + return ReadSectorsTag(sectorAddress, length, trk.Sequence, tag, out buffer); + } + + /// + public ErrorNumber ReadMediaTag(MediaTagType tag, out byte[] buffer) + { + buffer = null; + + switch(tag) + { + case MediaTagType.CD_MCN: + if(_mcn == null) return ErrorNumber.NoData; + + buffer = Encoding.ASCII.GetBytes(_mcn); + + return ErrorNumber.NoError; + case MediaTagType.CD_TEXT: + if(_cdtext == null) return ErrorNumber.NoData; + + buffer = _cdtext; + + return ErrorNumber.NoError; + default: + return ErrorNumber.NotSupported; + } + } + + /// + public List GetSessionTracks(Session session) => Tracks.Where(t => t.Session == session.Sequence).ToList(); + + /// + public List GetSessionTracks(ushort session) => Tracks.Where(t => t.Session == session).ToList(); +} \ No newline at end of file diff --git a/Aaru.Images/WinOnCD/Unimplemented.cs b/Aaru.Images/WinOnCD/Unimplemented.cs deleted file mode 100644 index 84fd07e66..000000000 --- a/Aaru.Images/WinOnCD/Unimplemented.cs +++ /dev/null @@ -1,112 +0,0 @@ -// /*************************************************************************** -// Aaru Data Preservation Suite -// ---------------------------------------------------------------------------- -// -// Filename : Unimplemented.cs -// Author(s) : Natalia Portillo -// -// Component : Disc image plugins. -// -// --[ Description ] ---------------------------------------------------------- -// -// Manages WinOnCD disc images. -// -// --[ License ] -------------------------------------------------------------- -// -// This library is free software; you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as -// published by the Free Software Foundation; either version 2.1 of the -// License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, see . -// -// ---------------------------------------------------------------------------- -// Copyright © 2011-2026 Natalia Portillo -// ****************************************************************************/ - - -using System; -using System.Collections.Generic; -using Aaru.CommonTypes.Enums; -using Aaru.CommonTypes.Structs; - -namespace Aaru.Images; - -public sealed partial class WinOnCD -{ - /// - public ErrorNumber ReadMediaTag(MediaTagType tag, out byte[] buffer) => throw new NotImplementedException(); - - /// - public ErrorNumber - ReadSector(ulong sectorAddress, bool negative, out byte[] buffer, out SectorStatus sectorStatus) => - throw new NotImplementedException(); - - /// - public ErrorNumber ReadSectorLong(ulong sectorAddress, bool negative, out byte[] buffer, - out SectorStatus sectorStatus) => throw new NotImplementedException(); - - /// - public ErrorNumber ReadSectors(ulong sectorAddress, bool negative, uint length, out byte[] buffer, - out SectorStatus[] sectorStatus) => throw new NotImplementedException(); - - /// - public ErrorNumber ReadSectorsLong(ulong sectorAddress, bool negative, uint length, out byte[] buffer, - out SectorStatus[] sectorStatus) => throw new NotImplementedException(); - - /// - public ErrorNumber ReadSectorsTag(ulong sectorAddress, bool negative, uint length, SectorTagType tag, - out byte[] buffer) => throw new NotImplementedException(); - - /// - public ErrorNumber ReadSectorTag(ulong sectorAddress, bool negative, SectorTagType tag, out byte[] buffer) => - throw new NotImplementedException(); - - /// - public bool? VerifySector(ulong sectorAddress) => throw new NotImplementedException(); - - /// - public bool? VerifySectors(ulong sectorAddress, uint length, out List failingLbas, - out List unknownLbas) => throw new NotImplementedException(); - - /// - public ErrorNumber ReadSector(ulong sectorAddress, uint track, out byte[] buffer, out SectorStatus sectorStatus) => - throw new NotImplementedException(); - - /// - public ErrorNumber ReadSectorTag(ulong sectorAddress, uint track, SectorTagType tag, out byte[] buffer) => - throw new NotImplementedException(); - - /// - public ErrorNumber ReadSectors(ulong sectorAddress, uint length, uint track, out byte[] buffer, - out SectorStatus[] sectorStatus) => throw new NotImplementedException(); - - /// - public ErrorNumber ReadSectorsTag(ulong sectorAddress, uint length, uint track, SectorTagType tag, - out byte[] buffer) => throw new NotImplementedException(); - - /// - public ErrorNumber - ReadSectorLong(ulong sectorAddress, uint track, out byte[] buffer, out SectorStatus sectorStatus) => - throw new NotImplementedException(); - - /// - public ErrorNumber ReadSectorsLong(ulong sectorAddress, uint length, uint track, out byte[] buffer, - out SectorStatus[] sectorStatus) => throw new NotImplementedException(); - - /// - public List GetSessionTracks(Session session) => throw new NotImplementedException(); - - /// - public List GetSessionTracks(ushort session) => throw new NotImplementedException(); - - /// - public bool? VerifySectors(ulong sectorAddress, uint length, uint track, out List failingLbas, - out List unknownLbas) => throw new NotImplementedException(); -} \ No newline at end of file diff --git a/Aaru.Images/WinOnCD/Verify.cs b/Aaru.Images/WinOnCD/Verify.cs new file mode 100644 index 000000000..6b5106a63 --- /dev/null +++ b/Aaru.Images/WinOnCD/Verify.cs @@ -0,0 +1,65 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Verify.cs +// Author(s) : Natalia Portillo +// +// Component : Disc image plugins. +// +// --[ Description ] ---------------------------------------------------------- +// +// Verifies WinOnCD disc images. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2026 Natalia Portillo +// ****************************************************************************/ + +using System.Collections.Generic; + +namespace Aaru.Images; + +public sealed partial class WinOnCD +{ + /// + public bool? VerifySector(ulong sectorAddress) => null; + + /// + public bool? VerifySectors(ulong sectorAddress, uint length, out List failingLbas, + out List unknownLbas) + { + failingLbas = []; + unknownLbas = []; + + for(ulong i = 0; i < length; i++) unknownLbas.Add(sectorAddress + i); + + return null; + } + + /// + public bool? VerifySectors(ulong sectorAddress, uint length, uint track, out List failingLbas, + out List unknownLbas) + { + failingLbas = []; + unknownLbas = []; + + for(ulong i = 0; i < length; i++) unknownLbas.Add(sectorAddress + i); + + return null; + } +} \ No newline at end of file diff --git a/Aaru.Images/WinOnCD/WinOnCD.cs b/Aaru.Images/WinOnCD/WinOnCD.cs index 8407cec3f..92e6a18e5 100644 --- a/Aaru.Images/WinOnCD/WinOnCD.cs +++ b/Aaru.Images/WinOnCD/WinOnCD.cs @@ -30,6 +30,7 @@ // Copyright © 2011-2026 Natalia Portillo // ****************************************************************************/ +using System.Collections.Generic; using System.IO; using Aaru.CommonTypes.Interfaces; using Aaru.CommonTypes.Structs; @@ -40,10 +41,14 @@ namespace Aaru.Images; public sealed partial class WinOnCD : IOpticalMediaImage { const string MODULE_NAME = "WinOnCD plugin"; + byte[] _cdtext; - ImageInfo _imageInfo; - Stream _imageStream; - SectorBuilder _sectorBuilder; + ImageInfo _imageInfo; + Stream _imageStream; + string _mcn; + SectorBuilder _sectorBuilder; + Dictionary _trackFlags; + Dictionary _trackIsrcs; public WinOnCD() => _imageInfo = new ImageInfo {