Files
Aaru/Aaru.Images/AaruFormat/Read.cs

404 lines
15 KiB
C#

using System;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
using Aaru.CommonTypes.Enums;
using Aaru.CommonTypes.Structs;
namespace Aaru.Images;
public sealed partial class AaruFormat
{
// AARU_EXPORT int32_t AARU_CALL aaruf_read_media_tag(void *context, uint8_t *data, const int32_t tag, uint32_t *length)
[LibraryImport("libaaruformat", EntryPoint = "aaruf_read_media_tag", SetLastError = true)]
[UnmanagedCallConv(CallConvs = [typeof(CallConvStdcall)])]
private static partial Status aaruf_read_media_tag(IntPtr context, byte[] data, MediaTagType tag, ref uint length);
// AARU_EXPORT int32_t AARU_CALL aaruf_read_sector(void *context, const uint64_t sector_address, bool negative,
// uint8_t *data, uint32_t *length, uint8_t *sector_status)
[LibraryImport("libaaruformat", EntryPoint = "aaruf_read_sector", SetLastError = true)]
[UnmanagedCallConv(CallConvs = [typeof(CallConvStdcall)])]
private static partial Status aaruf_read_sector(IntPtr context, ulong sectorAddress,
[MarshalAs(UnmanagedType.I4)] bool negative, byte[] data,
ref uint length, out byte sectorStatus);
// AARU_EXPORT int32_t AARU_CALL aaruf_read_track_sector(void *context, uint8_t *data, const uint64_t sector_address,
// uint32_t *length, const uint8_t track, uint8_t *sector_status)
[LibraryImport("libaaruformat", EntryPoint = "aaruf_read_track_sector", SetLastError = true)]
[UnmanagedCallConv(CallConvs = [typeof(CallConvStdcall)])]
private static partial Status aaruf_read_track_sector(IntPtr context, byte[] data, ulong sectorAddress,
ref uint length, byte track, out byte sectorStatus);
// AARU_EXPORT int32_t AARU_CALL aaruf_read_sector_long(void *context, const uint64_t sector_address, bool negative,
// uint8_t *data, uint32_t *length, uint8_t *sector_status)
[LibraryImport("libaaruformat", EntryPoint = "aaruf_read_sector_long", SetLastError = true)]
[UnmanagedCallConv(CallConvs = [typeof(CallConvStdcall)])]
private static partial Status aaruf_read_sector_long(IntPtr context, ulong sectorAddress,
[MarshalAs(UnmanagedType.I4)] bool negative, byte[] data,
ref uint length, out byte sectorStatus);
// AARU_EXPORT int32_t AARU_CALL aaruf_read_sector_tag(const void *context, const uint64_t sector_address,
// const bool negative, uint8_t *buffer, uint32_t *length,
// const int32_t tag)
[LibraryImport("libaaruformat", EntryPoint = "aaruf_read_sector_tag", SetLastError = true)]
[UnmanagedCallConv(CallConvs = [typeof(CallConvStdcall)])]
private static partial Status aaruf_read_sector_tag(IntPtr context, ulong sectorAddress,
[MarshalAs(UnmanagedType.I4)] bool negative, byte[] buffer,
ref uint length, SectorTagType tag);
#region IWritableOpticalImage Members
/// <inheritdoc />
public ErrorNumber ReadMediaTag(MediaTagType tag, out byte[] buffer)
{
buffer = null;
uint length = 0;
Status res = aaruf_read_media_tag(_context, buffer, tag, ref length);
if(res != Status.BufferTooSmall) return StatusToErrorNumber(res);
buffer = new byte[length];
res = aaruf_read_media_tag(_context, buffer, tag, ref length);
return StatusToErrorNumber(res);
}
/// <inheritdoc />
public ErrorNumber ReadSector(ulong sectorAddress, bool negative, out byte[] buffer, out SectorStatus sectorStatus)
{
buffer = null;
uint length = 0;
sectorStatus = SectorStatus.NotDumped;
Status res = aaruf_read_sector(_context, sectorAddress, negative, buffer, ref length, out _);
// Sector not dumped
if(res == Status.SectorNotDumped && length > 0)
{
buffer = new byte[length];
return ErrorNumber.NoError;
}
if(res != Status.BufferTooSmall) return StatusToErrorNumber(res);
buffer = new byte[length];
res = aaruf_read_sector(_context, sectorAddress, negative, buffer, ref length, out byte libSectorStatus);
sectorStatus = (SectorStatus)libSectorStatus;
// Sector not dumped
if(res != Status.SectorNotDumped || length <= 0) return StatusToErrorNumber(res);
buffer = new byte[length];
return ErrorNumber.NoError;
}
/// <inheritdoc />
public ErrorNumber ReadSector(ulong sectorAddress, uint track, out byte[] buffer, out SectorStatus sectorStatus)
{
buffer = null;
uint length = 0;
sectorStatus = SectorStatus.NotDumped;
Status res = aaruf_read_track_sector(_context, buffer, sectorAddress, ref length, (byte)track, out _);
// Sector not dumped
if(res == Status.SectorNotDumped && length > 0)
{
buffer = new byte[length];
return ErrorNumber.NoError;
}
if(res != Status.BufferTooSmall) return StatusToErrorNumber(res);
buffer = new byte[length];
res = aaruf_read_track_sector(_context,
buffer,
sectorAddress,
ref length,
(byte)track,
out byte libSectorStatus);
sectorStatus = (SectorStatus)libSectorStatus;
// Sector not dumped
if(res != Status.SectorNotDumped || length <= 0) return StatusToErrorNumber(res);
buffer = new byte[length];
return ErrorNumber.NoError;
}
/// <inheritdoc />
public ErrorNumber ReadSectorLong(ulong sectorAddress, bool negative, out byte[] buffer,
out SectorStatus sectorStatus)
{
buffer = null;
uint length = 0;
sectorStatus = SectorStatus.NotDumped;
Status res = aaruf_read_sector_long(_context, sectorAddress, negative, buffer, ref length, out _);
// Sector not dumped
if(res == Status.SectorNotDumped && length > 0)
{
buffer = new byte[length];
return ErrorNumber.NoError;
}
if(res != Status.BufferTooSmall) return StatusToErrorNumber(res);
buffer = new byte[length];
res = aaruf_read_sector_long(_context, sectorAddress, negative, buffer, ref length, out byte libSectorStatus);
sectorStatus = (SectorStatus)libSectorStatus;
// Sector not dumped
if(res != Status.SectorNotDumped || length <= 0) return StatusToErrorNumber(res);
buffer = new byte[length];
return ErrorNumber.NoError;
}
/// <inheritdoc />
public ErrorNumber ReadSectorTag(ulong sectorAddress, bool negative, SectorTagType tag, out byte[] buffer)
{
buffer = null;
switch(tag)
{
// Due to how we cache the tracks, we need to handle ISRC tags ourselves
case SectorTagType.CdTrackIsrc when _trackIsrcs != null:
{
if(_trackIsrcs.TryGetValue((int)sectorAddress, out string isrc))
{
buffer = new byte[13];
byte[] isrcBytes = Encoding.UTF8.GetBytes(isrc ?? "");
Array.Copy(isrcBytes, 0, buffer, 0, Math.Min(isrcBytes.Length, 13));
return ErrorNumber.NoError;
}
break;
}
// Due to how we cache the tracks, we need to handle Track Flags ourselves
case SectorTagType.CdTrackFlags when _trackFlags != null:
{
if(_trackFlags.TryGetValue((int)sectorAddress, out byte flags))
{
buffer = new byte[1];
buffer[0] = flags;
return ErrorNumber.NoError;
}
break;
}
}
uint length = 0;
Status res = aaruf_read_sector_tag(_context, sectorAddress, negative, buffer, ref length, tag);
if(res != Status.BufferTooSmall && res != Status.IncorrectDataSize) return StatusToErrorNumber(res);
buffer = new byte[length];
res = aaruf_read_sector_tag(_context, sectorAddress, negative, buffer, ref length, tag);
return StatusToErrorNumber(res);
}
/// <inheritdoc />
public ErrorNumber ReadSectors(ulong sectorAddress, bool negative, uint length, out byte[] buffer,
out SectorStatus[] sectorStatus)
{
MemoryStream ms = new();
sectorStatus = new SectorStatus[length];
for(uint i = 0; i < length; i++)
{
ErrorNumber res = ReadSector(sectorAddress + i,
negative,
out byte[] sectorBuffer,
out SectorStatus singleSectorStatus);
if(res != ErrorNumber.NoError)
{
buffer = ms.ToArray();
sectorStatus[i] = singleSectorStatus;
return res;
}
ms.Write(sectorBuffer, 0, sectorBuffer.Length);
}
buffer = ms.ToArray();
return ErrorNumber.NoError;
}
/// <inheritdoc />
public ErrorNumber ReadSectorsLong(ulong sectorAddress, bool negative, uint length, out byte[] buffer,
out SectorStatus[] sectorStatus)
{
MemoryStream ms = new();
sectorStatus = new SectorStatus[length];
for(uint i = 0; i < length; i++)
{
ErrorNumber res = ReadSectorLong(sectorAddress + i,
negative,
out byte[] sectorBuffer,
out SectorStatus singleSectorStatus);
if(res != ErrorNumber.NoError)
{
buffer = ms.ToArray();
sectorStatus[i] = singleSectorStatus;
return res;
}
ms.Write(sectorBuffer, 0, sectorBuffer.Length);
}
buffer = ms.ToArray();
return ErrorNumber.NoError;
}
/// <inheritdoc />
public ErrorNumber ReadSectorsTag(ulong sectorAddress, bool negative, uint length, SectorTagType tag,
out byte[] buffer)
{
MemoryStream ms = new();
for(uint i = 0; i < length; i++)
{
ErrorNumber res = ReadSectorTag(sectorAddress + i, negative, tag, out byte[] sectorBuffer);
if(res != ErrorNumber.NoError)
{
buffer = ms.ToArray();
return res;
}
ms.Write(sectorBuffer, 0, sectorBuffer.Length);
}
buffer = ms.ToArray();
return ErrorNumber.NoError;
}
/// <inheritdoc />
public ErrorNumber ReadSectorTag(ulong sectorAddress, uint track, SectorTagType tag, out byte[] buffer)
{
buffer = null;
if(_imageInfo.MetadataMediaType != MetadataMediaType.OpticalDisc) return ErrorNumber.NotSupported;
if(Tracks == null) return ErrorNumber.SectorNotFound;
Track trk = Tracks.FirstOrDefault(t => t.Sequence == track);
return trk?.Sequence != track
? ErrorNumber.SectorNotFound
: ReadSectorTag(trk.StartSector + sectorAddress, false, tag, out buffer);
}
/// <inheritdoc />
public ErrorNumber ReadSectors(ulong sectorAddress, uint length, uint track, out byte[] buffer,
out SectorStatus[] sectorStatus)
{
buffer = null;
sectorStatus = null;
if(_imageInfo.MetadataMediaType != MetadataMediaType.OpticalDisc) return ErrorNumber.NotSupported;
if(Tracks == null) return ErrorNumber.SectorNotFound;
Track trk = Tracks.FirstOrDefault(t => t.Sequence == track);
if(trk?.Sequence != track) return ErrorNumber.SectorNotFound;
return trk.StartSector + sectorAddress + length > trk.EndSector + 1
? ErrorNumber.OutOfRange
: ReadSectors(trk.StartSector + sectorAddress, false, length, out buffer, out sectorStatus);
}
/// <inheritdoc />
public ErrorNumber ReadSectorsTag(ulong sectorAddress, uint length, uint track, SectorTagType tag,
out byte[] buffer)
{
buffer = null;
if(_imageInfo.MetadataMediaType != MetadataMediaType.OpticalDisc) return ErrorNumber.NotSupported;
if(Tracks == null) return ErrorNumber.SectorNotFound;
Track trk = Tracks.FirstOrDefault(t => t.Sequence == track);
return trk?.Sequence != track
? ErrorNumber.SectorNotFound
: trk.StartSector + sectorAddress + length > trk.EndSector + 1
? ErrorNumber.OutOfRange
: ReadSectorsTag(trk.StartSector + sectorAddress, false, length, tag, out buffer);
}
/// <inheritdoc />
public ErrorNumber ReadSectorLong(ulong sectorAddress, uint track, out byte[] buffer, out SectorStatus sectorStatus)
{
buffer = null;
sectorStatus = SectorStatus.NotDumped;
if(_imageInfo.MetadataMediaType != MetadataMediaType.OpticalDisc) return ErrorNumber.NotSupported;
if(Tracks == null) return ErrorNumber.SectorNotFound;
Track trk = Tracks.FirstOrDefault(t => t.Sequence == track);
return trk?.Sequence != track
? ErrorNumber.SectorNotFound
: ReadSectorLong(trk.StartSector + sectorAddress, false, out buffer, out sectorStatus);
}
/// <inheritdoc />
public ErrorNumber ReadSectorsLong(ulong sectorAddress, uint length, uint track, out byte[] buffer,
out SectorStatus[] sectorStatus)
{
buffer = null;
sectorStatus = null;
if(_imageInfo.MetadataMediaType != MetadataMediaType.OpticalDisc) return ErrorNumber.NotSupported;
if(Tracks == null) return ErrorNumber.SectorNotFound;
Track trk = Tracks.FirstOrDefault(t => t.Sequence == track);
return trk?.Sequence != track
? ErrorNumber.SectorNotFound
: trk.StartSector + sectorAddress + length > trk.EndSector + 1
? ErrorNumber.OutOfRange
: ReadSectorsLong(trk.StartSector + sectorAddress, false, length, out buffer, out sectorStatus);
}
#endregion
}