mirror of
https://github.com/aaru-dps/Aaru.git
synced 2025-12-16 19:24:25 +00:00
[Aaru.Images] Reformat and cleanup.
This commit is contained in:
@@ -45,25 +45,25 @@ namespace Aaru.DiscImages;
|
||||
/// <summary>Implements reading A2R flux images</summary>
|
||||
public sealed partial class A2R : IFluxImage, IMediaImage, IWritableImage, IWritableFluxImage
|
||||
{
|
||||
ImageInfo _imageInfo;
|
||||
Stream _a2rStream;
|
||||
IFilter _a2rFilter;
|
||||
FileStream _writingStream;
|
||||
A2rHeader Header;
|
||||
Dictionary<string, string> Meta;
|
||||
InfoChunkV2 _infoChunkV2;
|
||||
InfoChunkV3 _infoChunkV3;
|
||||
List<StreamCapture> _a2rCaptures;
|
||||
uint _currentResolution;
|
||||
const string MODULE_NAME = "A2R plugin";
|
||||
List<StreamCapture> _a2rCaptures;
|
||||
IFilter _a2rFilter;
|
||||
Stream _a2rStream;
|
||||
|
||||
// Offset from the start of the current RWCP to the next capture
|
||||
uint _currentCaptureOffset = 16;
|
||||
uint _currentResolution;
|
||||
|
||||
// 53 = A2R header, INFO header, INFO data
|
||||
long _currentRwcpStart = 53;
|
||||
long _currentRwcpStart = 53;
|
||||
ImageInfo _imageInfo;
|
||||
InfoChunkV2 _infoChunkV2;
|
||||
InfoChunkV3 _infoChunkV3;
|
||||
FileStream _writingStream;
|
||||
A2rHeader Header;
|
||||
Dictionary<string, string> Meta;
|
||||
|
||||
public A2R()
|
||||
{
|
||||
public A2R() =>
|
||||
_imageInfo = new ImageInfo
|
||||
{
|
||||
ReadableSectorTags = new List<SectorTagType>(),
|
||||
@@ -87,7 +87,4 @@ public sealed partial class A2R : IFluxImage, IMediaImage, IWritableImage, IWrit
|
||||
DriveSerialNumber = null,
|
||||
DriveFirmwareRevision = null
|
||||
};
|
||||
}
|
||||
|
||||
const string MODULE_NAME = "A2R plugin";
|
||||
}
|
||||
@@ -49,6 +49,11 @@ public sealed partial class A2R
|
||||
0x49, 0x4E, 0x46, 0x4F // INFO
|
||||
};
|
||||
|
||||
readonly byte[] _metaChunkSignature =
|
||||
{
|
||||
0x4D, 0x45, 0x54, 0x41 // META
|
||||
};
|
||||
|
||||
readonly byte[] _rwcpChunkSignature =
|
||||
{
|
||||
0x52, 0x57, 0x43, 0x50 // RWCP
|
||||
@@ -59,11 +64,6 @@ public sealed partial class A2R
|
||||
0x53, 0x4C, 0x56, 0x44 // SLVD
|
||||
};
|
||||
|
||||
readonly byte[] _metaChunkSignature =
|
||||
{
|
||||
0x4D, 0x45, 0x54, 0x41 // META
|
||||
};
|
||||
|
||||
readonly byte[] _strmChunkSignature =
|
||||
{
|
||||
0x53, 0x54, 0x52, 0x4D // STRM
|
||||
|
||||
@@ -36,15 +36,28 @@ namespace Aaru.DiscImages;
|
||||
|
||||
public sealed partial class A2R
|
||||
{
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
public enum A2rDriveType : byte
|
||||
{
|
||||
SS_525_40trk_quarterStep = 0x1, DS_35_80trk_appleCLV = 0x2, DS_525_80trk = 0x3,
|
||||
DS_525_40trk = 0x4, DS_35_80trk = 0x5, DS_8 = 0x6
|
||||
}
|
||||
#region A2rDiskType enum
|
||||
|
||||
public enum A2rDiskType : byte
|
||||
{
|
||||
_525 = 0x01, _35 = 0x2,
|
||||
_525 = 0x01,
|
||||
_35 = 0x2
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region A2rDriveType enum
|
||||
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
public enum A2rDriveType : byte
|
||||
{
|
||||
SS_525_40trk_quarterStep = 0x1,
|
||||
DS_35_80trk_appleCLV = 0x2,
|
||||
DS_525_80trk = 0x3,
|
||||
DS_525_40trk = 0x4,
|
||||
DS_35_80trk = 0x5,
|
||||
DS_8 = 0x6
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -40,8 +40,8 @@ namespace Aaru.DiscImages;
|
||||
public sealed partial class A2R
|
||||
{
|
||||
/// <summary>
|
||||
/// Takes a Head, Track and Sub-Track representation, as well as the <c>MediaType</c>,
|
||||
/// and converts it to the Track representation used by A2R.
|
||||
/// Takes a Head, Track and Sub-Track representation, as well as the <c>MediaType</c>,
|
||||
/// and converts it to the Track representation used by A2R.
|
||||
/// </summary>
|
||||
/// <param name="head">The head number</param>
|
||||
/// <param name="track">The track number</param>
|
||||
@@ -51,14 +51,14 @@ public sealed partial class A2R
|
||||
static long HeadTrackSubToA2rLocation(uint head, ushort track, byte subTrack, MediaType mediaType)
|
||||
{
|
||||
if(mediaType == MediaType.Apple32SS)
|
||||
return head + (track * 4) + subTrack;
|
||||
return head + track * 4 + subTrack;
|
||||
|
||||
return head + (track * 2);
|
||||
return head + track * 2;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Takes a Head, Track and Sub-Track representation, as well as the <c>A2rDriveType</c>,
|
||||
/// and converts it to the Track representation used by A2R.
|
||||
/// Takes a Head, Track and Sub-Track representation, as well as the <c>A2rDriveType</c>,
|
||||
/// and converts it to the Track representation used by A2R.
|
||||
/// </summary>
|
||||
/// <param name="head">The head number</param>
|
||||
/// <param name="track">The track number</param>
|
||||
@@ -68,22 +68,22 @@ public sealed partial class A2R
|
||||
static long HeadTrackSubToA2rLocation(uint head, ushort track, byte subTrack, A2rDriveType driveType)
|
||||
{
|
||||
if(driveType == A2rDriveType.SS_525_40trk_quarterStep)
|
||||
return head + (track * 4) + subTrack;
|
||||
return head + track * 4 + subTrack;
|
||||
|
||||
return head + (track * 2);
|
||||
return head + track * 2;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Takes an A2R location and a <c>MediaType</c>, and converts it to a Head, Track and Sub-Track representation
|
||||
/// used by the internal representation. The <c>MediaType</c> is needed because the track location is different
|
||||
/// for different types of media sources.
|
||||
/// Takes an A2R location and a <c>MediaType</c>, and converts it to a Head, Track and Sub-Track representation
|
||||
/// used by the internal representation. The <c>MediaType</c> is needed because the track location is different
|
||||
/// for different types of media sources.
|
||||
/// </summary>
|
||||
/// <param name="location">A2R format location</param>
|
||||
/// <param name="mediaType"></param>
|
||||
/// <param name="head">The head number</param>
|
||||
/// <param name="track">The track number</param>
|
||||
/// <param name="subTrack">The sub-track number</param>
|
||||
static void A2rLocationToHeadTrackSub(uint location, MediaType mediaType, out uint head, out ushort track,
|
||||
static void A2rLocationToHeadTrackSub(uint location, MediaType mediaType, out uint head, out ushort track,
|
||||
out byte subTrack)
|
||||
{
|
||||
if(mediaType == MediaType.Apple32SS)
|
||||
@@ -101,8 +101,8 @@ public sealed partial class A2R
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Takes a single number flux (uint length) and converts it to a flux in the
|
||||
/// internal representation format (byte length)
|
||||
/// Takes a single number flux (uint length) and converts it to a flux in the
|
||||
/// internal representation format (byte length)
|
||||
/// </summary>
|
||||
/// <param name="ticks">The <c>uint</c> flux representation</param>
|
||||
/// <returns>The <c>byte[]</c> flux representation</returns>
|
||||
@@ -111,12 +111,11 @@ public sealed partial class A2R
|
||||
uint over = ticks / 255;
|
||||
|
||||
if(over == 0)
|
||||
return new[]
|
||||
{
|
||||
(byte)ticks
|
||||
};
|
||||
{
|
||||
return new[] { (byte)ticks };
|
||||
}
|
||||
|
||||
byte[] expanded = new byte[over + 1];
|
||||
var expanded = new byte[over + 1];
|
||||
|
||||
Array.Fill(expanded, (byte)255, 0, (int)over);
|
||||
expanded[^1] = (byte)(ticks % 255);
|
||||
@@ -125,8 +124,8 @@ public sealed partial class A2R
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Takes a flux representation in the internal format (byte length) and converts it to
|
||||
/// an array of single number fluxes (uint length)
|
||||
/// Takes a flux representation in the internal format (byte length) and converts it to
|
||||
/// an array of single number fluxes (uint length)
|
||||
/// </summary>
|
||||
/// <param name="flux">The <c>byte[]</c> flux representation</param>
|
||||
/// <returns>The <c>uint</c> flux representation</returns>
|
||||
@@ -151,9 +150,9 @@ public sealed partial class A2R
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A2R has two types of flux capture types; "timing" and "xtiming". The only difference is the length of the
|
||||
/// capture, with "timing" being about 1¼ revolutions. This function returns <c>true</c> if the flux buffer is "timing"
|
||||
/// and <c>false</c> otherwise.
|
||||
/// A2R has two types of flux capture types; "timing" and "xtiming". The only difference is the length of the
|
||||
/// capture, with "timing" being about 1¼ revolutions. This function returns <c>true</c> if the flux buffer is "timing"
|
||||
/// and <c>false</c> otherwise.
|
||||
/// </summary>
|
||||
/// <param name="resolution">The resolution of the flux capture</param>
|
||||
/// <param name="buffer">The flux data</param>
|
||||
|
||||
@@ -39,6 +39,8 @@ namespace Aaru.DiscImages;
|
||||
|
||||
public sealed partial class A2R
|
||||
{
|
||||
#region IFluxImage Members
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Identify(IFilter imageFilter)
|
||||
{
|
||||
@@ -48,10 +50,12 @@ public sealed partial class A2R
|
||||
if(stream.Length < 8)
|
||||
return false;
|
||||
|
||||
byte[] hdr = new byte[4];
|
||||
var hdr = new byte[4];
|
||||
|
||||
stream.EnsureRead(hdr, 0, 4);
|
||||
|
||||
return _a2rV2Signature.SequenceEqual(hdr) || _a2rV3Signature.SequenceEqual(hdr);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -41,44 +41,61 @@ namespace Aaru.DiscImages;
|
||||
|
||||
public sealed partial class A2R
|
||||
{
|
||||
bool IsWritingRwcps { get; set; }
|
||||
|
||||
#region IFluxImage Members
|
||||
|
||||
/// <inheritdoc />
|
||||
public ImageInfo Info => _imageInfo;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Name => Localization.A2R_Name;
|
||||
|
||||
/// <inheritdoc />
|
||||
public Guid Id => new("7497c26a-fe44-4b50-a2e6-de50a9f3c13f");
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Author => Authors.RebeccaWallander;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Format => "A2R";
|
||||
|
||||
/// <inheritdoc />
|
||||
public List<DumpHardware> DumpHardware => null;
|
||||
|
||||
/// <inheritdoc />
|
||||
public Metadata AaruMetadata => null;
|
||||
|
||||
#endregion
|
||||
|
||||
#region IWritableImage Members
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<string> KnownExtensions => new[]
|
||||
{
|
||||
".a2r"
|
||||
};
|
||||
public IEnumerable<string> KnownExtensions => new[] { ".a2r" };
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<MediaTagType> SupportedMediaTags => null;
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<MediaType> SupportedMediaTypes => new[]
|
||||
{
|
||||
// TODO: A2R supports a lot more formats, please add more whence tested.
|
||||
MediaType.DOS_35_DS_DD_9, MediaType.DOS_35_HD, MediaType.DOS_525_DS_DD_9, MediaType.DOS_525_HD,
|
||||
MediaType.Apple32SS,
|
||||
MediaType.Unknown
|
||||
MediaType.Apple32SS, MediaType.Unknown
|
||||
};
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<(string name, Type type, string description, object @default)> SupportedOptions =>
|
||||
Array.Empty<(string name, Type type, string description, object @default)>();
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<SectorTagType> SupportedSectorTags => Array.Empty<SectorTagType>();
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsWriting { get; private set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public string ErrorMessage { get; private set; }
|
||||
|
||||
bool IsWritingRwcps { get; set; }
|
||||
#endregion
|
||||
}
|
||||
@@ -45,6 +45,8 @@ namespace Aaru.DiscImages;
|
||||
|
||||
public sealed partial class A2R
|
||||
{
|
||||
#region IFluxImage Members
|
||||
|
||||
/// <inheritdoc />
|
||||
public ErrorNumber Open(IFilter imageFilter)
|
||||
{
|
||||
@@ -53,7 +55,7 @@ public sealed partial class A2R
|
||||
|
||||
_a2rFilter = imageFilter;
|
||||
|
||||
byte[] hdr = new byte[Marshal.SizeOf<A2rHeader>()];
|
||||
var hdr = new byte[Marshal.SizeOf<A2rHeader>()];
|
||||
_a2rStream.EnsureRead(hdr, 0, Marshal.SizeOf<A2rHeader>());
|
||||
|
||||
Header = Marshal.ByteArrayToStructureLittleEndian<A2rHeader>(hdr);
|
||||
@@ -61,13 +63,13 @@ public sealed partial class A2R
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.signature = \"{0}\"",
|
||||
StringHandlers.CToString(Header.signature));
|
||||
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.version = {0}", Header.version);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.version = {0}", Header.version);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.highBitTest = {0:X2}", Header.highBitTest);
|
||||
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.lineTest = {0:X2} {1:X2} {2:X2}", Header.lineTest[0],
|
||||
Header.lineTest[1], Header.lineTest[2]);
|
||||
|
||||
byte[] infoMagic = new byte[4];
|
||||
var infoMagic = new byte[4];
|
||||
_a2rStream.EnsureRead(infoMagic, 0, 4);
|
||||
|
||||
// There must be an INFO chunk after the header (at byte 16)
|
||||
@@ -80,7 +82,7 @@ public sealed partial class A2R
|
||||
{
|
||||
case 0x32:
|
||||
{
|
||||
byte[] infoChnk = new byte[Marshal.SizeOf<InfoChunkV2>()];
|
||||
var infoChnk = new byte[Marshal.SizeOf<InfoChunkV2>()];
|
||||
_a2rStream.EnsureRead(infoChnk, 0, Marshal.SizeOf<InfoChunkV2>());
|
||||
_infoChunkV2 = Marshal.ByteArrayToStructureLittleEndian<InfoChunkV2>(infoChnk);
|
||||
|
||||
@@ -118,14 +120,15 @@ public sealed partial class A2R
|
||||
_imageInfo.MediaType = MediaType.Apple32SS;
|
||||
|
||||
break;
|
||||
default: return ErrorNumber.OutOfRange;
|
||||
default:
|
||||
return ErrorNumber.OutOfRange;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case 0x33:
|
||||
{
|
||||
byte[] infoChk = new byte[Marshal.SizeOf<InfoChunkV3>()];
|
||||
var infoChk = new byte[Marshal.SizeOf<InfoChunkV3>()];
|
||||
_a2rStream.EnsureRead(infoChk, 0, Marshal.SizeOf<InfoChunkV3>());
|
||||
_infoChunkV3 = Marshal.ByteArrayToStructureLittleEndian<InfoChunkV3>(infoChk);
|
||||
|
||||
@@ -191,7 +194,8 @@ public sealed partial class A2R
|
||||
_imageInfo.Cylinders = 40;
|
||||
|
||||
break;
|
||||
default: return ErrorNumber.OutOfRange;
|
||||
default:
|
||||
return ErrorNumber.OutOfRange;
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -202,7 +206,7 @@ public sealed partial class A2R
|
||||
|
||||
while(_a2rStream.Position < _a2rStream.Length)
|
||||
{
|
||||
byte[] chunkHdr = new byte[Marshal.SizeOf<ChunkHeader>()];
|
||||
var chunkHdr = new byte[Marshal.SizeOf<ChunkHeader>()];
|
||||
_a2rStream.EnsureRead(chunkHdr, 0, Marshal.SizeOf<ChunkHeader>());
|
||||
ChunkHeader chunkHeader = Marshal.ByteArrayToStructureLittleEndian<ChunkHeader>(chunkHdr);
|
||||
_a2rStream.Seek(-Marshal.SizeOf<ChunkHeader>(), SeekOrigin.Current);
|
||||
@@ -210,7 +214,7 @@ public sealed partial class A2R
|
||||
switch(chunkHeader.chunkId)
|
||||
{
|
||||
case var rwcp when rwcp.SequenceEqual(_rwcpChunkSignature):
|
||||
byte[] rwcpBuffer = new byte[Marshal.SizeOf<RwcpChunkHeader>()];
|
||||
var rwcpBuffer = new byte[Marshal.SizeOf<RwcpChunkHeader>()];
|
||||
_a2rStream.EnsureRead(rwcpBuffer, 0, Marshal.SizeOf<RwcpChunkHeader>());
|
||||
RwcpChunkHeader rwcpChunk = Marshal.ByteArrayToStructureLittleEndian<RwcpChunkHeader>(rwcpBuffer);
|
||||
|
||||
@@ -222,11 +226,11 @@ public sealed partial class A2R
|
||||
captureType = (byte)_a2rStream.ReadByte()
|
||||
};
|
||||
|
||||
byte[] location = new byte[2];
|
||||
var location = new byte[2];
|
||||
_a2rStream.EnsureRead(location, 0, 2);
|
||||
capture.location = BitConverter.ToUInt16(location);
|
||||
|
||||
A2rLocationToHeadTrackSub(capture.location, _imageInfo.MediaType, out capture.head,
|
||||
A2rLocationToHeadTrackSub(capture.location, _imageInfo.MediaType, out capture.head,
|
||||
out capture.track, out capture.subTrack);
|
||||
|
||||
if(capture.head + 1 > _imageInfo.Heads)
|
||||
@@ -238,14 +242,14 @@ public sealed partial class A2R
|
||||
capture.numberOfIndexSignals = (byte)_a2rStream.ReadByte();
|
||||
capture.indexSignals = new uint[capture.numberOfIndexSignals];
|
||||
|
||||
for(int i = 0; capture.numberOfIndexSignals > i; i++)
|
||||
for(var i = 0; capture.numberOfIndexSignals > i; i++)
|
||||
{
|
||||
byte[] index = new byte[4];
|
||||
var index = new byte[4];
|
||||
_a2rStream.EnsureRead(index, 0, 4);
|
||||
capture.indexSignals[i] = BitConverter.ToUInt32(index);
|
||||
}
|
||||
|
||||
byte[] dataSize = new byte[4];
|
||||
var dataSize = new byte[4];
|
||||
_a2rStream.EnsureRead(dataSize, 0, 4);
|
||||
capture.captureDataSize = BitConverter.ToUInt32(dataSize);
|
||||
|
||||
@@ -264,7 +268,7 @@ public sealed partial class A2R
|
||||
|
||||
_a2rStream.Seek(Marshal.SizeOf<ChunkHeader>(), SeekOrigin.Current);
|
||||
|
||||
byte[] metadataBuffer = new byte[chunkHeader.chunkSize];
|
||||
var metadataBuffer = new byte[chunkHeader.chunkSize];
|
||||
_a2rStream.EnsureRead(metadataBuffer, 0, (int)chunkHeader.chunkSize);
|
||||
|
||||
string metaData = Encoding.UTF8.GetString(metadataBuffer);
|
||||
@@ -286,9 +290,10 @@ public sealed partial class A2R
|
||||
_imageInfo.MediaTitle = title;
|
||||
|
||||
break;
|
||||
case var slvd when slvd.SequenceEqual(_slvdChunkSignature): return ErrorNumber.NotImplemented;
|
||||
case var slvd when slvd.SequenceEqual(_slvdChunkSignature):
|
||||
return ErrorNumber.NotImplemented;
|
||||
case var strm when strm.SequenceEqual(_strmChunkSignature):
|
||||
byte[] strmBuffer = new byte[Marshal.SizeOf<ChunkHeader>()];
|
||||
var strmBuffer = new byte[Marshal.SizeOf<ChunkHeader>()];
|
||||
_a2rStream.EnsureRead(strmBuffer, 0, Marshal.SizeOf<ChunkHeader>());
|
||||
ChunkHeader strmChunk = Marshal.ByteArrayToStructureLittleEndian<ChunkHeader>(strmBuffer);
|
||||
|
||||
@@ -305,7 +310,7 @@ public sealed partial class A2R
|
||||
numberOfIndexSignals = 1
|
||||
};
|
||||
|
||||
A2rLocationToHeadTrackSub(capture.location, _imageInfo.MediaType, out capture.head,
|
||||
A2rLocationToHeadTrackSub(capture.location, _imageInfo.MediaType, out capture.head,
|
||||
out capture.track, out capture.subTrack);
|
||||
|
||||
if(capture.head + 1 > _imageInfo.Heads)
|
||||
@@ -314,11 +319,11 @@ public sealed partial class A2R
|
||||
if(capture.track + 1 > _imageInfo.Cylinders)
|
||||
_imageInfo.Cylinders = (uint)(capture.track + 1);
|
||||
|
||||
byte[] dataSize = new byte[4];
|
||||
var dataSize = new byte[4];
|
||||
_a2rStream.EnsureRead(dataSize, 0, 4);
|
||||
capture.captureDataSize = BitConverter.ToUInt32(dataSize);
|
||||
|
||||
byte[] index = new byte[4];
|
||||
var index = new byte[4];
|
||||
_a2rStream.EnsureRead(index, 0, 4);
|
||||
capture.indexSignals[0] = BitConverter.ToUInt32(index);
|
||||
|
||||
@@ -349,7 +354,7 @@ public sealed partial class A2R
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ErrorNumber ReadFluxIndexResolution(uint head, ushort track, byte subTrack, uint captureIndex,
|
||||
public ErrorNumber ReadFluxIndexResolution(uint head, ushort track, byte subTrack, uint captureIndex,
|
||||
out ulong resolution)
|
||||
{
|
||||
resolution = StreamCaptureAtIndex(head, track, subTrack, captureIndex).resolution;
|
||||
@@ -358,7 +363,7 @@ public sealed partial class A2R
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ErrorNumber ReadFluxDataResolution(uint head, ushort track, byte subTrack, uint captureIndex,
|
||||
public ErrorNumber ReadFluxDataResolution(uint head, ushort track, byte subTrack, uint captureIndex,
|
||||
out ulong resolution)
|
||||
{
|
||||
resolution = StreamCaptureAtIndex(head, track, subTrack, captureIndex).resolution;
|
||||
@@ -367,7 +372,7 @@ public sealed partial class A2R
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ErrorNumber ReadFluxResolution(uint head, ushort track, byte subTrack, uint captureIndex,
|
||||
public ErrorNumber ReadFluxResolution(uint head, ushort track, byte subTrack, uint captureIndex,
|
||||
out ulong indexResolution, out ulong dataResolution)
|
||||
{
|
||||
indexResolution = dataResolution = StreamCaptureAtIndex(head, track, subTrack, captureIndex).resolution;
|
||||
@@ -376,8 +381,8 @@ public sealed partial class A2R
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ErrorNumber ReadFluxCapture(uint head, ushort track, byte subTrack, uint captureIndex,
|
||||
out ulong indexResolution, out ulong dataResolution, out byte[] indexBuffer,
|
||||
public ErrorNumber ReadFluxCapture(uint head, ushort track, byte subTrack, uint captureIndex,
|
||||
out ulong indexResolution, out ulong dataResolution, out byte[] indexBuffer,
|
||||
out byte[] dataBuffer)
|
||||
{
|
||||
dataBuffer = indexBuffer = null;
|
||||
@@ -399,7 +404,7 @@ public sealed partial class A2R
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ErrorNumber ReadFluxIndexCapture(uint head, ushort track, byte subTrack, uint captureIndex,
|
||||
public ErrorNumber ReadFluxIndexCapture(uint head, ushort track, byte subTrack, uint captureIndex,
|
||||
out byte[] buffer)
|
||||
{
|
||||
buffer = null;
|
||||
@@ -414,7 +419,7 @@ public sealed partial class A2R
|
||||
|
||||
uint previousTicks = 0;
|
||||
|
||||
for(int i = 0; i < capture.numberOfIndexSignals; i++)
|
||||
for(var i = 0; i < capture.numberOfIndexSignals; i++)
|
||||
{
|
||||
uint ticks = capture.indexSignals[i] - previousTicks;
|
||||
tmpBuffer.AddRange(UInt32ToFluxRepresentation(ticks));
|
||||
@@ -461,6 +466,10 @@ public sealed partial class A2R
|
||||
return ErrorNumber.NoError;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IMediaImage Members
|
||||
|
||||
/// <inheritdoc />
|
||||
public ErrorNumber ReadMediaTag(MediaTagType tag, out byte[] buffer) => throw new NotImplementedException();
|
||||
|
||||
@@ -486,6 +495,8 @@ public sealed partial class A2R
|
||||
public ErrorNumber ReadSectorTag(ulong sectorAddress, SectorTagType tag, out byte[] buffer) =>
|
||||
throw new NotImplementedException();
|
||||
|
||||
#endregion
|
||||
|
||||
StreamCapture StreamCaptureAtIndex(uint head, ushort track, byte subTrack, uint captureIndex)
|
||||
{
|
||||
long index = HeadTrackSubToA2rLocation(head, track, subTrack, _imageInfo.MediaType);
|
||||
|
||||
@@ -36,6 +36,8 @@ namespace Aaru.DiscImages;
|
||||
|
||||
public sealed partial class A2R
|
||||
{
|
||||
#region Nested type: A2rHeader
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct A2rHeader
|
||||
{
|
||||
@@ -47,6 +49,10 @@ public sealed partial class A2R
|
||||
public byte[] lineTest; // Should always be 0x0A 0x0D 0x0A
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Nested type: ChunkHeader
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct ChunkHeader
|
||||
{
|
||||
@@ -55,6 +61,10 @@ public sealed partial class A2R
|
||||
public uint chunkSize;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Nested type: InfoChunkV2
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct InfoChunkV2
|
||||
{
|
||||
@@ -67,6 +77,10 @@ public sealed partial class A2R
|
||||
public byte synchronized;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Nested type: InfoChunkV3
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct InfoChunkV3
|
||||
{
|
||||
@@ -80,6 +94,10 @@ public sealed partial class A2R
|
||||
public byte hardSectorCount;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Nested type: RwcpChunkHeader
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct RwcpChunkHeader
|
||||
{
|
||||
@@ -90,6 +108,24 @@ public sealed partial class A2R
|
||||
public byte[] reserved;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Nested type: SlvdChunkHeader
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct SlvdChunkHeader
|
||||
{
|
||||
public ChunkHeader header;
|
||||
public byte version;
|
||||
public uint resolution;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 11)]
|
||||
public byte[] reserved;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Nested type: StreamCapture
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct StreamCapture
|
||||
{
|
||||
@@ -106,15 +142,9 @@ public sealed partial class A2R
|
||||
public byte subTrack;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct SlvdChunkHeader
|
||||
{
|
||||
public ChunkHeader header;
|
||||
public byte version;
|
||||
public uint resolution;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 11)]
|
||||
public byte[] reserved;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Nested type: TrackHeader
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct TrackHeader
|
||||
@@ -129,4 +159,6 @@ public sealed partial class A2R
|
||||
public uint[] indexSignals;
|
||||
public uint fluxDataSize;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -45,9 +45,88 @@ namespace Aaru.DiscImages;
|
||||
|
||||
public sealed partial class A2R
|
||||
{
|
||||
#region IWritableFluxImage Members
|
||||
|
||||
/// <inheritdoc />
|
||||
public ErrorNumber WriteFluxCapture(ulong indexResolution, ulong dataResolution, byte[] indexBuffer,
|
||||
byte[] dataBuffer, uint head, ushort track, byte subTrack, uint captureIndex)
|
||||
{
|
||||
if(!IsWriting)
|
||||
{
|
||||
ErrorMessage = Localization.Tried_to_write_on_a_non_writable_image;
|
||||
|
||||
return ErrorNumber.WriteError;
|
||||
}
|
||||
|
||||
// An RWCP chunk can only have one capture resolution. If the resolution changes we need to create a new chunk.
|
||||
if(_currentResolution != dataResolution)
|
||||
{
|
||||
if(IsWritingRwcps)
|
||||
{
|
||||
CloseRwcpChunk();
|
||||
|
||||
_writingStream.Seek(_currentRwcpStart, SeekOrigin.Begin);
|
||||
WriteRwcpHeader();
|
||||
|
||||
_currentRwcpStart = _writingStream.Length;
|
||||
_currentCaptureOffset = 16;
|
||||
}
|
||||
|
||||
IsWritingRwcps = true;
|
||||
|
||||
_currentResolution = (uint)dataResolution;
|
||||
}
|
||||
|
||||
_writingStream.Seek(_currentRwcpStart + _currentCaptureOffset + Marshal.SizeOf<ChunkHeader>(),
|
||||
SeekOrigin.Begin);
|
||||
|
||||
_writingStream.WriteByte(0x43);
|
||||
|
||||
_writingStream.WriteByte(IsCaptureTypeTiming(dataResolution, dataBuffer) ? (byte)1 : (byte)3);
|
||||
|
||||
_writingStream.
|
||||
Write(
|
||||
BitConverter.GetBytes((ushort)HeadTrackSubToA2rLocation(head, track, subTrack, _infoChunkV3.driveType)),
|
||||
0, 2);
|
||||
|
||||
List<uint> a2rIndices = FluxRepresentationsToUInt32List(indexBuffer);
|
||||
|
||||
if(a2rIndices[0] == 0)
|
||||
a2rIndices.RemoveAt(0);
|
||||
|
||||
_writingStream.WriteByte((byte)a2rIndices.Count);
|
||||
|
||||
long previousIndex = 0;
|
||||
|
||||
foreach(uint index in a2rIndices)
|
||||
{
|
||||
_writingStream.Write(BitConverter.GetBytes(index + previousIndex), 0, 4);
|
||||
previousIndex += index;
|
||||
}
|
||||
|
||||
_writingStream.Write(BitConverter.GetBytes(dataBuffer.Length), 0, 4);
|
||||
_writingStream.Write(dataBuffer, 0, dataBuffer.Length);
|
||||
|
||||
_currentCaptureOffset += (uint)(9 + a2rIndices.Count * 4 + dataBuffer.Length);
|
||||
|
||||
return ErrorNumber.NoError;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ErrorNumber WriteFluxIndexCapture(ulong resolution, byte[] index, uint head, ushort track, byte subTrack,
|
||||
uint captureIndex) => ErrorNumber.NoError;
|
||||
|
||||
/// <inheritdoc />
|
||||
public ErrorNumber WriteFluxDataCapture(ulong resolution, byte[] data, uint head, ushort track, byte subTrack,
|
||||
uint captureIndex) => ErrorNumber.NoError;
|
||||
|
||||
#endregion
|
||||
|
||||
#region IWritableImage Members
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Create(string path, MediaType mediaType, Dictionary<string, string> options, ulong sectors,
|
||||
uint sectorSize)
|
||||
uint sectorSize)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -69,12 +148,12 @@ public sealed partial class A2R
|
||||
Header.lineTest = "\n\r\n"u8.ToArray();
|
||||
|
||||
_infoChunkV3.driveType = mediaType switch
|
||||
{
|
||||
MediaType.DOS_525_DS_DD_9 => A2rDriveType.DS_525_40trk,
|
||||
MediaType.Apple32SS => A2rDriveType.SS_525_40trk_quarterStep,
|
||||
MediaType.Unknown => A2rDriveType.DS_35_80trk,
|
||||
_ => _infoChunkV3.driveType
|
||||
};
|
||||
{
|
||||
MediaType.DOS_525_DS_DD_9 => A2rDriveType.DS_525_40trk,
|
||||
MediaType.Apple32SS => A2rDriveType.SS_525_40trk_quarterStep,
|
||||
MediaType.Unknown => A2rDriveType.DS_35_80trk,
|
||||
_ => _infoChunkV3.driveType
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -134,7 +213,7 @@ public sealed partial class A2R
|
||||
_infoChunkV3.hardSectorCount = 0;
|
||||
|
||||
Meta.Add("image_date", DateTime.Now.ToString("O"));
|
||||
Meta.Add("title", imageInfo.MediaTitle);
|
||||
Meta.Add("title", imageInfo.MediaTitle);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -169,80 +248,10 @@ public sealed partial class A2R
|
||||
/// <inheritdoc />
|
||||
public bool WriteSectorsLong(byte[] data, ulong sectorAddress, uint length) => throw new NotImplementedException();
|
||||
|
||||
/// <inheritdoc />
|
||||
public ErrorNumber WriteFluxCapture(ulong indexResolution, ulong dataResolution, byte[] indexBuffer,
|
||||
byte[] dataBuffer, uint head, ushort track, byte subTrack, uint captureIndex)
|
||||
{
|
||||
if(!IsWriting)
|
||||
{
|
||||
ErrorMessage = Localization.Tried_to_write_on_a_non_writable_image;
|
||||
|
||||
return ErrorNumber.WriteError;
|
||||
}
|
||||
|
||||
// An RWCP chunk can only have one capture resolution. If the resolution changes we need to create a new chunk.
|
||||
if(_currentResolution != dataResolution)
|
||||
{
|
||||
if(IsWritingRwcps)
|
||||
{
|
||||
CloseRwcpChunk();
|
||||
|
||||
_writingStream.Seek(_currentRwcpStart, SeekOrigin.Begin);
|
||||
WriteRwcpHeader();
|
||||
|
||||
_currentRwcpStart = _writingStream.Length;
|
||||
_currentCaptureOffset = 16;
|
||||
}
|
||||
|
||||
IsWritingRwcps = true;
|
||||
|
||||
_currentResolution = (uint)dataResolution;
|
||||
}
|
||||
|
||||
_writingStream.Seek(_currentRwcpStart + _currentCaptureOffset + Marshal.SizeOf<ChunkHeader>(),
|
||||
SeekOrigin.Begin);
|
||||
|
||||
_writingStream.WriteByte(0x43);
|
||||
|
||||
_writingStream.WriteByte(IsCaptureTypeTiming(dataResolution, dataBuffer) ? (byte)1 : (byte)3);
|
||||
|
||||
_writingStream.
|
||||
Write(BitConverter.GetBytes((ushort)HeadTrackSubToA2rLocation(head, track, subTrack, _infoChunkV3.driveType)),
|
||||
0, 2);
|
||||
|
||||
List<uint> a2rIndices = FluxRepresentationsToUInt32List(indexBuffer);
|
||||
|
||||
if(a2rIndices[0] == 0)
|
||||
a2rIndices.RemoveAt(0);
|
||||
|
||||
_writingStream.WriteByte((byte)a2rIndices.Count);
|
||||
|
||||
long previousIndex = 0;
|
||||
|
||||
foreach(uint index in a2rIndices)
|
||||
{
|
||||
_writingStream.Write(BitConverter.GetBytes(index + previousIndex), 0, 4);
|
||||
previousIndex += index;
|
||||
}
|
||||
|
||||
_writingStream.Write(BitConverter.GetBytes(dataBuffer.Length), 0, 4);
|
||||
_writingStream.Write(dataBuffer, 0, dataBuffer.Length);
|
||||
|
||||
_currentCaptureOffset += (uint)(9 + (a2rIndices.Count * 4) + dataBuffer.Length);
|
||||
|
||||
return ErrorNumber.NoError;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ErrorNumber WriteFluxIndexCapture(ulong resolution, byte[] index, uint head, ushort track, byte subTrack,
|
||||
uint captureIndex) => ErrorNumber.NoError;
|
||||
|
||||
/// <inheritdoc />
|
||||
public ErrorNumber WriteFluxDataCapture(ulong resolution, byte[] data, uint head, ushort track, byte subTrack,
|
||||
uint captureIndex) => ErrorNumber.NoError;
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// writes the header to an RWCP chunk, up to and including the reserved bytes, to stream.
|
||||
/// writes the header to an RWCP chunk, up to and including the reserved bytes, to stream.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
ErrorNumber WriteRwcpHeader()
|
||||
@@ -254,15 +263,12 @@ public sealed partial class A2R
|
||||
return ErrorNumber.WriteError;
|
||||
}
|
||||
|
||||
_writingStream.Write(_rwcpChunkSignature, 0, 4);
|
||||
_writingStream.Write(_rwcpChunkSignature, 0, 4);
|
||||
_writingStream.Write(BitConverter.GetBytes(_currentCaptureOffset + 1), 0, 4);
|
||||
_writingStream.WriteByte(1);
|
||||
_writingStream.Write(BitConverter.GetBytes(_currentResolution), 0, 4);
|
||||
|
||||
byte[] reserved =
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
byte[] reserved = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
|
||||
_writingStream.Write(reserved, 0, 11);
|
||||
|
||||
@@ -270,7 +276,7 @@ public sealed partial class A2R
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the entire INFO chunk to stream.
|
||||
/// Writes the entire INFO chunk to stream.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
ErrorNumber WriteInfoChunk()
|
||||
@@ -282,7 +288,7 @@ public sealed partial class A2R
|
||||
return ErrorNumber.WriteError;
|
||||
}
|
||||
|
||||
_writingStream.Write(_infoChunkV3.header.chunkId, 0, 4);
|
||||
_writingStream.Write(_infoChunkV3.header.chunkId, 0, 4);
|
||||
_writingStream.Write(BitConverter.GetBytes(_infoChunkV3.header.chunkSize), 0, 4);
|
||||
_writingStream.WriteByte(_infoChunkV3.version);
|
||||
_writingStream.Write(_infoChunkV3.creator, 0, 32);
|
||||
@@ -295,7 +301,7 @@ public sealed partial class A2R
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the entire META chunk to stream.
|
||||
/// Writes the entire META chunk to stream.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
ErrorNumber WriteMetaChunk()
|
||||
@@ -313,13 +319,13 @@ public sealed partial class A2R
|
||||
Aggregate(static (concat, str) => $"{concat}\n{str}") + '\n');
|
||||
|
||||
_writingStream.Write(BitConverter.GetBytes((uint)metaString.Length), 0, 4);
|
||||
_writingStream.Write(metaString, 0, metaString.Length);
|
||||
_writingStream.Write(metaString, 0, metaString.Length);
|
||||
|
||||
return ErrorNumber.NoError;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the closing byte to an RWCP chunk signaling its end, to stream.
|
||||
/// Writes the closing byte to an RWCP chunk signaling its end, to stream.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
ErrorNumber CloseRwcpChunk()
|
||||
|
||||
@@ -35,8 +35,8 @@
|
||||
<NoWarn>CS1591;CS1574</NoWarn>
|
||||
</PropertyGroup>
|
||||
<ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
|
||||
<InternalsVisibleTo Include="Aaru.Tests" />
|
||||
<InternalsVisibleTo Include="Aaru.Tests.Devices" />
|
||||
<InternalsVisibleTo Include="Aaru.Tests"/>
|
||||
<InternalsVisibleTo Include="Aaru.Tests.Devices"/>
|
||||
</ItemGroup>
|
||||
<PropertyGroup>
|
||||
<NrtRevisionFormat>$(Version)+{chash:8}</NrtRevisionFormat>
|
||||
@@ -44,25 +44,25 @@
|
||||
<NrtShowRevision>true</NrtShowRevision>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Claunia.Encoding" Version="1.9.2" />
|
||||
<PackageReference Include="Claunia.RsrcFork" Version="1.2.0" />
|
||||
<PackageReference Include="DotNetZip" Version="1.16.0" />
|
||||
<PackageReference Include="plist-cil" Version="2.2.0" />
|
||||
<PackageReference Include="SharpCompress" Version="0.34.0" />
|
||||
<PackageReference Include="System.Text.Json" Version="8.0.0-rc.1.23419.4" />
|
||||
<PackageReference Include="System.ValueTuple" Version="4.5.0" />
|
||||
<PackageReference Include="Unclassified.NetRevisionTask" Version="0.4.3" PrivateAssets="all" />
|
||||
<PackageReference Include="Claunia.Encoding" Version="1.9.2"/>
|
||||
<PackageReference Include="Claunia.RsrcFork" Version="1.2.0"/>
|
||||
<PackageReference Include="DotNetZip" Version="1.16.0"/>
|
||||
<PackageReference Include="plist-cil" Version="2.2.0"/>
|
||||
<PackageReference Include="SharpCompress" Version="0.34.0"/>
|
||||
<PackageReference Include="System.Text.Json" Version="8.0.0-rc.1.23419.4"/>
|
||||
<PackageReference Include="System.ValueTuple" Version="4.5.0"/>
|
||||
<PackageReference Include="Unclassified.NetRevisionTask" Version="0.4.3" PrivateAssets="all"/>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Aaru.CommonTypes\Aaru.CommonTypes.csproj" />
|
||||
<ProjectReference Include="..\Aaru.Checksums\Aaru.Checksums.csproj" />
|
||||
<ProjectReference Include="..\Aaru.Compression\Aaru.Compression.csproj" />
|
||||
<ProjectReference Include="..\Aaru.Database\Aaru.Database.csproj" />
|
||||
<ProjectReference Include="..\Aaru.Helpers\Aaru.Helpers.csproj" />
|
||||
<ProjectReference Include="..\Aaru.Console\Aaru.Console.csproj" />
|
||||
<ProjectReference Include="..\Aaru.Decoders\Aaru.Decoders.csproj" />
|
||||
<ProjectReference Include="..\Aaru.Filters\Aaru.Filters.csproj" />
|
||||
<ProjectReference Include="..\Aaru.Settings\Aaru.Settings.csproj" />
|
||||
<ProjectReference Include="..\Aaru.CommonTypes\Aaru.CommonTypes.csproj"/>
|
||||
<ProjectReference Include="..\Aaru.Checksums\Aaru.Checksums.csproj"/>
|
||||
<ProjectReference Include="..\Aaru.Compression\Aaru.Compression.csproj"/>
|
||||
<ProjectReference Include="..\Aaru.Database\Aaru.Database.csproj"/>
|
||||
<ProjectReference Include="..\Aaru.Helpers\Aaru.Helpers.csproj"/>
|
||||
<ProjectReference Include="..\Aaru.Console\Aaru.Console.csproj"/>
|
||||
<ProjectReference Include="..\Aaru.Decoders\Aaru.Decoders.csproj"/>
|
||||
<ProjectReference Include="..\Aaru.Filters\Aaru.Filters.csproj"/>
|
||||
<ProjectReference Include="..\Aaru.Settings\Aaru.Settings.csproj"/>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="..\LICENSE.LGPL">
|
||||
@@ -74,6 +74,6 @@
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Aaru.Generators\Aaru.Generators.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
|
||||
<ProjectReference Include="..\Aaru.Generators\Aaru.Generators.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false"/>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -2,92 +2,92 @@
|
||||
xmlns:s="clr-namespace:System;assembly=mscorlib"
|
||||
xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xml:space="preserve">
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=aaruformat/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=alcohol120/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean
|
||||
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=anex86/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=apple2mg/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=appledos/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=applenib/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=apridisk/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=blindwrite4/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=blindwrite5/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean
|
||||
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=blu/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean
|
||||
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=byteaddressable/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean
|
||||
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=cdrdao/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean
|
||||
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=cdrwin/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean
|
||||
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=chd/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean
|
||||
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=ciscopy/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean
|
||||
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=clonecd/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean
|
||||
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=copyqm/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=copytape/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean
|
||||
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=cpcdsk/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean
|
||||
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=d88/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean
|
||||
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=dart/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean
|
||||
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=dim/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=discferret/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=discjuggler/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=diskcopy42/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=diskdupe/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=dridiskcopy/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean
|
||||
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=gdi/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean
|
||||
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=hdcopy/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean
|
||||
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=imd/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=kryoflux/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean
|
||||
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=localization/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=maxidisk/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean
|
||||
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=ndif/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean
|
||||
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=nero/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean
|
||||
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=nhdr0/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=parallels/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=partclone/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=partimage/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean
|
||||
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=qcow/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean
|
||||
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=qcow2/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean
|
||||
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=qed/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean
|
||||
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=raydim/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean
|
||||
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=rside/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=savedskf/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean
|
||||
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=supercardpro/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean
|
||||
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=t98/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=teledisk/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean
|
||||
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=udif/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean
|
||||
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=ukvfdi/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean
|
||||
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=vdi/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean
|
||||
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=vhd/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean
|
||||
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=vhdx/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=virtual98/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean
|
||||
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=vmware/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=wcdiskimage/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=zzzrawimage/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=alcohol120/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean
|
||||
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=anex86/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=apple2mg/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=appledos/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=applenib/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=apridisk/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=blindwrite4/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=blindwrite5/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean
|
||||
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=blu/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean
|
||||
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=byteaddressable/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean
|
||||
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=cdrdao/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean
|
||||
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=cdrwin/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean
|
||||
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=chd/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean
|
||||
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=ciscopy/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean
|
||||
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=clonecd/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean
|
||||
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=copyqm/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=copytape/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean
|
||||
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=cpcdsk/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean
|
||||
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=d88/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean
|
||||
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=dart/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean
|
||||
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=dim/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=discferret/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=discjuggler/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=diskcopy42/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=diskdupe/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=dridiskcopy/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean
|
||||
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=gdi/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean
|
||||
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=hdcopy/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean
|
||||
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=imd/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=kryoflux/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean
|
||||
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=localization/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=maxidisk/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean
|
||||
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=ndif/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean
|
||||
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=nero/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean
|
||||
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=nhdr0/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=parallels/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=partclone/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=partimage/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean
|
||||
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=qcow/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean
|
||||
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=qcow2/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean
|
||||
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=qed/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean
|
||||
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=raydim/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean
|
||||
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=rside/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=savedskf/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean
|
||||
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=supercardpro/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean
|
||||
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=t98/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=teledisk/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean
|
||||
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=udif/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean
|
||||
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=ukvfdi/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean
|
||||
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=vdi/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean
|
||||
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=vhd/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean
|
||||
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=vhdx/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=virtual98/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean
|
||||
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=vmware/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=wcdiskimage/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=zzzrawimage/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
|
||||
@@ -83,7 +83,8 @@ namespace Aaru.DiscImages;
|
||||
/// <summary>Implements reading and writing AaruFormat media images</summary>
|
||||
public sealed partial class AaruFormat : IWritableOpticalImage, IVerifiableImage, IWritableTapeImage
|
||||
{
|
||||
bool _alreadyWrittenZero;
|
||||
const string MODULE_NAME = "Aaru Format plugin";
|
||||
bool _alreadyWrittenZero;
|
||||
/// <summary>Cache of uncompressed blocks.</summary>
|
||||
Dictionary<ulong, byte[]> _blockCache;
|
||||
/// <summary>Cache of block headers.</summary>
|
||||
@@ -129,10 +130,10 @@ public sealed partial class AaruFormat : IWritableOpticalImage, IVerifiableImage
|
||||
long _outMemoryDdtPosition;
|
||||
bool _rewinded;
|
||||
byte[] _sectorCprMai;
|
||||
byte[] _sectorIed;
|
||||
byte[] _sectorId;
|
||||
byte[] _sectorEdc;
|
||||
byte[] _sectorDecryptedTitleKey;
|
||||
byte[] _sectorEdc;
|
||||
byte[] _sectorId;
|
||||
byte[] _sectorIed;
|
||||
/// <summary>Cache for data that prefixes the user data on a sector (e.g. sync).</summary>
|
||||
byte[] _sectorPrefix;
|
||||
uint[] _sectorPrefixDdt;
|
||||
@@ -187,6 +188,4 @@ public sealed partial class AaruFormat : IWritableOpticalImage, IVerifiableImage
|
||||
DriveSerialNumber = null,
|
||||
DriveFirmwareRevision = null
|
||||
};
|
||||
|
||||
const string MODULE_NAME = "Aaru Format plugin";
|
||||
}
|
||||
@@ -55,12 +55,12 @@ public sealed partial class AaruFormat
|
||||
for(uint i = 0; i < 256; i++)
|
||||
{
|
||||
uint edc = i;
|
||||
uint j = (uint)((i << 1) ^ ((i & 0x80) == 0x80 ? 0x11D : 0));
|
||||
var j = (uint)(i << 1 ^ ((i & 0x80) == 0x80 ? 0x11D : 0));
|
||||
_eccFTable[i] = (byte)j;
|
||||
_eccBTable[i ^ j] = (byte)i;
|
||||
|
||||
for(j = 0; j < 8; j++)
|
||||
edc = (edc >> 1) ^ ((edc & 1) > 0 ? 0xD8018001 : 0);
|
||||
edc = edc >> 1 ^ ((edc & 1) > 0 ? 0xD8018001 : 0);
|
||||
|
||||
_edcTable[i] = edc;
|
||||
}
|
||||
@@ -93,13 +93,13 @@ public sealed partial class AaruFormat
|
||||
if(!correctEccQ)
|
||||
return false;
|
||||
|
||||
uint storedEdc = BitConverter.ToUInt32(sector, 0x810);
|
||||
var storedEdc = BitConverter.ToUInt32(sector, 0x810);
|
||||
uint edc = 0;
|
||||
int size = 0x810;
|
||||
int pos = 0;
|
||||
var size = 0x810;
|
||||
var pos = 0;
|
||||
|
||||
for(; size > 0; size--)
|
||||
edc = (edc >> 8) ^ _edcTable[(edc ^ sector[pos++]) & 0xFF];
|
||||
edc = edc >> 8 ^ _edcTable[(edc ^ sector[pos++]) & 0xFF];
|
||||
|
||||
uint calculatedEdc = edc;
|
||||
|
||||
@@ -111,7 +111,7 @@ public sealed partial class AaruFormat
|
||||
if(!_initedEdc)
|
||||
EccInit();
|
||||
|
||||
byte[] zeroAddress = new byte[4];
|
||||
var zeroAddress = new byte[4];
|
||||
|
||||
bool correctEccP = CheckEcc(zeroAddress, sector, 86, 24, 2, 86, sector, 0, 0x10, 0x81C);
|
||||
|
||||
@@ -123,28 +123,28 @@ public sealed partial class AaruFormat
|
||||
if(!correctEccQ)
|
||||
return false;
|
||||
|
||||
uint storedEdc = BitConverter.ToUInt32(sector, 0x818);
|
||||
var storedEdc = BitConverter.ToUInt32(sector, 0x818);
|
||||
uint edc = 0;
|
||||
int size = 0x808;
|
||||
int pos = 0x10;
|
||||
var size = 0x808;
|
||||
var pos = 0x10;
|
||||
|
||||
for(; size > 0; size--)
|
||||
edc = (edc >> 8) ^ _edcTable[(edc ^ sector[pos++]) & 0xFF];
|
||||
edc = edc >> 8 ^ _edcTable[(edc ^ sector[pos++]) & 0xFF];
|
||||
|
||||
uint calculatedEdc = edc;
|
||||
|
||||
return calculatedEdc == storedEdc;
|
||||
}
|
||||
|
||||
bool CheckEcc(byte[] address, byte[] data, uint majorCount, uint minorCount, uint majorMult, uint minorInc,
|
||||
byte[] ecc, int addressOffset, int dataOffset, int eccOffset)
|
||||
bool CheckEcc(byte[] address, byte[] data, uint majorCount, uint minorCount, uint majorMult, uint minorInc,
|
||||
byte[] ecc, int addressOffset, int dataOffset, int eccOffset)
|
||||
{
|
||||
uint size = majorCount * minorCount;
|
||||
uint major;
|
||||
|
||||
for(major = 0; major < majorCount; major++)
|
||||
{
|
||||
uint idx = ((major >> 1) * majorMult) + (major & 1);
|
||||
uint idx = (major >> 1) * majorMult + (major & 1);
|
||||
byte eccA = 0;
|
||||
byte eccB = 0;
|
||||
uint minor;
|
||||
@@ -172,15 +172,15 @@ public sealed partial class AaruFormat
|
||||
return true;
|
||||
}
|
||||
|
||||
void WriteEcc(byte[] address, byte[] data, uint majorCount, uint minorCount, uint majorMult, uint minorInc,
|
||||
ref byte[] ecc, int addressOffset, int dataOffset, int eccOffset)
|
||||
void WriteEcc(byte[] address, byte[] data, uint majorCount, uint minorCount, uint majorMult, uint minorInc,
|
||||
ref byte[] ecc, int addressOffset, int dataOffset, int eccOffset)
|
||||
{
|
||||
uint size = majorCount * minorCount;
|
||||
uint major;
|
||||
|
||||
for(major = 0; major < majorCount; major++)
|
||||
{
|
||||
uint idx = ((major >> 1) * majorMult) + (major & 1);
|
||||
uint idx = (major >> 1) * majorMult + (major & 1);
|
||||
byte eccA = 0;
|
||||
byte eccB = 0;
|
||||
uint minor;
|
||||
@@ -206,7 +206,7 @@ public sealed partial class AaruFormat
|
||||
|
||||
void EccWriteSector(byte[] address, byte[] data, ref byte[] ecc, int addressOffset, int dataOffset, int eccOffset)
|
||||
{
|
||||
WriteEcc(address, data, 86, 24, 2, 86, ref ecc, addressOffset, dataOffset, eccOffset); // P
|
||||
WriteEcc(address, data, 86, 24, 2, 86, ref ecc, addressOffset, dataOffset, eccOffset); // P
|
||||
WriteEcc(address, data, 52, 43, 86, 88, ref ecc, addressOffset, dataOffset, eccOffset + 0xAC); // Q
|
||||
}
|
||||
|
||||
@@ -214,7 +214,7 @@ public sealed partial class AaruFormat
|
||||
((byte)((pos + 150) / 75 / 60), (byte)((pos + 150) / 75 % 60), (byte)((pos + 150) % 75));
|
||||
|
||||
static void ReconstructPrefix(ref byte[] sector, // must point to a full 2352-byte sector
|
||||
TrackType type, long lba)
|
||||
TrackType type, long lba)
|
||||
{
|
||||
//
|
||||
// Sync
|
||||
@@ -234,9 +234,9 @@ public sealed partial class AaruFormat
|
||||
|
||||
(byte minute, byte second, byte frame) msf = LbaToMsf(lba);
|
||||
|
||||
sector[0x00C] = (byte)(((msf.minute / 10) << 4) + (msf.minute % 10));
|
||||
sector[0x00D] = (byte)(((msf.second / 10) << 4) + (msf.second % 10));
|
||||
sector[0x00E] = (byte)(((msf.frame / 10) << 4) + (msf.frame % 10));
|
||||
sector[0x00C] = (byte)((msf.minute / 10 << 4) + msf.minute % 10);
|
||||
sector[0x00D] = (byte)((msf.second / 10 << 4) + msf.second % 10);
|
||||
sector[0x00E] = (byte)((msf.frame / 10 << 4) + msf.frame % 10);
|
||||
|
||||
switch(type)
|
||||
{
|
||||
@@ -264,12 +264,13 @@ public sealed partial class AaruFormat
|
||||
sector[0x013] = sector[0x017];
|
||||
|
||||
break;
|
||||
default: return;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void ReconstructEcc(ref byte[] sector, // must point to a full 2352-byte sector
|
||||
TrackType type)
|
||||
TrackType type)
|
||||
{
|
||||
byte[] computedEdc;
|
||||
|
||||
@@ -305,10 +306,11 @@ public sealed partial class AaruFormat
|
||||
sector[0x92F] = computedEdc[3];
|
||||
|
||||
break;
|
||||
default: return;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
byte[] zeroAddress = new byte[4];
|
||||
var zeroAddress = new byte[4];
|
||||
|
||||
switch(type)
|
||||
{
|
||||
@@ -334,7 +336,8 @@ public sealed partial class AaruFormat
|
||||
EccWriteSector(zeroAddress, sector, ref sector, 0, 0x10, 0x81C);
|
||||
|
||||
break;
|
||||
default: return;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
@@ -350,7 +353,7 @@ public sealed partial class AaruFormat
|
||||
int pos = srcOffset;
|
||||
|
||||
for(; size > 0; size--)
|
||||
edc = (edc >> 8) ^ _edcTable[(edc ^ src[pos++]) & 0xFF];
|
||||
edc = edc >> 8 ^ _edcTable[(edc ^ src[pos++]) & 0xFF];
|
||||
|
||||
return edc;
|
||||
}
|
||||
|
||||
@@ -43,19 +43,19 @@ public sealed partial class AaruFormat
|
||||
if(interleaved == null)
|
||||
return null;
|
||||
|
||||
int[] p = new int[interleaved.Length / 8];
|
||||
int[] q = new int[interleaved.Length / 8];
|
||||
int[] r = new int[interleaved.Length / 8];
|
||||
int[] s = new int[interleaved.Length / 8];
|
||||
int[] t = new int[interleaved.Length / 8];
|
||||
int[] u = new int[interleaved.Length / 8];
|
||||
int[] v = new int[interleaved.Length / 8];
|
||||
int[] w = new int[interleaved.Length / 8];
|
||||
var p = new int[interleaved.Length / 8];
|
||||
var q = new int[interleaved.Length / 8];
|
||||
var r = new int[interleaved.Length / 8];
|
||||
var s = new int[interleaved.Length / 8];
|
||||
var t = new int[interleaved.Length / 8];
|
||||
var u = new int[interleaved.Length / 8];
|
||||
var v = new int[interleaved.Length / 8];
|
||||
var w = new int[interleaved.Length / 8];
|
||||
|
||||
var stopwatch = new Stopwatch();
|
||||
stopwatch.Start();
|
||||
|
||||
for(int i = 0; i < interleaved.Length; i += 8)
|
||||
for(var i = 0; i < interleaved.Length; i += 8)
|
||||
{
|
||||
p[i / 8] = interleaved[i] & 0x80;
|
||||
p[i / 8] += (interleaved[i + 1] & 0x80) >> 1;
|
||||
@@ -133,7 +133,7 @@ public sealed partial class AaruFormat
|
||||
stopwatch.Stop();
|
||||
TimeSpan deinterleave = stopwatch.Elapsed;
|
||||
|
||||
byte[] sequential = new byte[interleaved.Length];
|
||||
var sequential = new byte[interleaved.Length];
|
||||
stopwatch.Restart();
|
||||
|
||||
int qStart = p.Length * 1;
|
||||
@@ -144,7 +144,7 @@ public sealed partial class AaruFormat
|
||||
int vStart = p.Length * 6;
|
||||
int wStart = p.Length * 7;
|
||||
|
||||
for(int i = 0; i < p.Length; i++)
|
||||
for(var i = 0; i < p.Length; i++)
|
||||
{
|
||||
sequential[i] = (byte)p[i];
|
||||
sequential[qStart + i] = (byte)q[i];
|
||||
@@ -176,14 +176,14 @@ public sealed partial class AaruFormat
|
||||
if(sequential == null)
|
||||
return null;
|
||||
|
||||
int[] p = new int[sequential.Length / 8];
|
||||
int[] q = new int[sequential.Length / 8];
|
||||
int[] r = new int[sequential.Length / 8];
|
||||
int[] s = new int[sequential.Length / 8];
|
||||
int[] t = new int[sequential.Length / 8];
|
||||
int[] u = new int[sequential.Length / 8];
|
||||
int[] v = new int[sequential.Length / 8];
|
||||
int[] w = new int[sequential.Length / 8];
|
||||
var p = new int[sequential.Length / 8];
|
||||
var q = new int[sequential.Length / 8];
|
||||
var r = new int[sequential.Length / 8];
|
||||
var s = new int[sequential.Length / 8];
|
||||
var t = new int[sequential.Length / 8];
|
||||
var u = new int[sequential.Length / 8];
|
||||
var v = new int[sequential.Length / 8];
|
||||
var w = new int[sequential.Length / 8];
|
||||
|
||||
int qStart = p.Length * 1;
|
||||
int rStart = p.Length * 2;
|
||||
@@ -196,7 +196,7 @@ public sealed partial class AaruFormat
|
||||
var stopwatch = new Stopwatch();
|
||||
stopwatch.Start();
|
||||
|
||||
for(int i = 0; i < p.Length; i++)
|
||||
for(var i = 0; i < p.Length; i++)
|
||||
{
|
||||
p[i] = sequential[i];
|
||||
q[i] = sequential[qStart + i];
|
||||
@@ -211,10 +211,10 @@ public sealed partial class AaruFormat
|
||||
stopwatch.Stop();
|
||||
TimeSpan desequentialize = stopwatch.Elapsed;
|
||||
|
||||
byte[] interleaved = new byte[sequential.Length];
|
||||
var interleaved = new byte[sequential.Length];
|
||||
stopwatch.Restart();
|
||||
|
||||
for(int i = 0; i < interleaved.Length; i += 8)
|
||||
for(var i = 0; i < interleaved.Length; i += 8)
|
||||
{
|
||||
interleaved[i] = (byte)((p[i / 8] & 0x80) == 0x80 ? 0x80 : 0);
|
||||
interleaved[i + 1] += (byte)((p[i / 8] & 0x40) == 0x40 ? 0x80 : 0);
|
||||
|
||||
@@ -36,6 +36,77 @@ namespace Aaru.DiscImages;
|
||||
|
||||
public sealed partial class AaruFormat
|
||||
{
|
||||
#region Nested type: BlockType
|
||||
|
||||
/// <summary>List of known blocks types</summary>
|
||||
enum BlockType : uint
|
||||
{
|
||||
/// <summary>Block containing data</summary>
|
||||
DataBlock = 0x4B4C4244,
|
||||
/// <summary>Block containing a deduplication table</summary>
|
||||
DeDuplicationTable = 0x2A544444,
|
||||
/// <summary>Block containing the index</summary>
|
||||
Index = 0x58444E49,
|
||||
/// <summary>Block containing the index</summary>
|
||||
Index2 = 0x32584449,
|
||||
/// <summary>Block containing logical geometry</summary>
|
||||
GeometryBlock = 0x4D4F4547,
|
||||
/// <summary>Block containing metadata</summary>
|
||||
MetadataBlock = 0x4154454D,
|
||||
/// <summary>Block containing optical disc tracks</summary>
|
||||
TracksBlock = 0x534B5254,
|
||||
/// <summary>Block containing CICM XML metadata</summary>
|
||||
CicmBlock = 0x4D434943,
|
||||
/// <summary>Block containing contents checksums</summary>
|
||||
ChecksumBlock = 0x4D534B43,
|
||||
/// <summary>TODO: Block containing data position measurements</summary>
|
||||
DataPositionMeasurementBlock = 0x2A4D5044,
|
||||
/// <summary>TODO: Block containing a snapshot index</summary>
|
||||
SnapshotBlock = 0x50414E53,
|
||||
/// <summary>TODO: Block containing how to locate the parent image</summary>
|
||||
ParentBlock = 0x544E5250,
|
||||
/// <summary>Block containing an array of hardware used to create the image</summary>
|
||||
DumpHardwareBlock = 0x2A504D44,
|
||||
/// <summary>Block containing list of files for a tape image</summary>
|
||||
TapeFileBlock = 0x454C4654,
|
||||
/// <summary>Block containing list of partitions for a tape image</summary>
|
||||
TapePartitionBlock = 0x54425054,
|
||||
/// <summary>Block containing list of indexes for Compact Disc tracks</summary>
|
||||
CompactDiscIndexesBlock = 0x58494443,
|
||||
/// <summary>Block containing JSON version of Aaru Metadata</summary>
|
||||
AaruMetadataJsonBlock = 0x444D534A
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Nested type: CdFixFlags
|
||||
|
||||
enum CdFixFlags : uint
|
||||
{
|
||||
NotDumped = 0x10000000,
|
||||
Correct = 0x20000000,
|
||||
Mode2Form1Ok = 0x30000000,
|
||||
Mode2Form2Ok = 0x40000000,
|
||||
Mode2Form2NoCrc = 0x50000000
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Nested type: ChecksumAlgorithm
|
||||
|
||||
enum ChecksumAlgorithm : byte
|
||||
{
|
||||
Invalid = 0,
|
||||
Md5 = 1,
|
||||
Sha1 = 2,
|
||||
Sha256 = 3,
|
||||
SpamSum = 4
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Nested type: CompressionType
|
||||
|
||||
/// <summary>List of known compression types</summary>
|
||||
enum CompressionType : ushort
|
||||
{
|
||||
@@ -49,6 +120,10 @@ public sealed partial class AaruFormat
|
||||
LzmaClauniaSubchannelTransform = 3
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Nested type: DataType
|
||||
|
||||
/// <summary>List of known data types</summary>
|
||||
enum DataType : ushort
|
||||
{
|
||||
@@ -226,54 +301,5 @@ public sealed partial class AaruFormat
|
||||
DvdSectorEdc = 85
|
||||
}
|
||||
|
||||
/// <summary>List of known blocks types</summary>
|
||||
enum BlockType : uint
|
||||
{
|
||||
/// <summary>Block containing data</summary>
|
||||
DataBlock = 0x4B4C4244,
|
||||
/// <summary>Block containing a deduplication table</summary>
|
||||
DeDuplicationTable = 0x2A544444,
|
||||
/// <summary>Block containing the index</summary>
|
||||
Index = 0x58444E49,
|
||||
/// <summary>Block containing the index</summary>
|
||||
Index2 = 0x32584449,
|
||||
/// <summary>Block containing logical geometry</summary>
|
||||
GeometryBlock = 0x4D4F4547,
|
||||
/// <summary>Block containing metadata</summary>
|
||||
MetadataBlock = 0x4154454D,
|
||||
/// <summary>Block containing optical disc tracks</summary>
|
||||
TracksBlock = 0x534B5254,
|
||||
/// <summary>Block containing CICM XML metadata</summary>
|
||||
CicmBlock = 0x4D434943,
|
||||
/// <summary>Block containing contents checksums</summary>
|
||||
ChecksumBlock = 0x4D534B43,
|
||||
/// <summary>TODO: Block containing data position measurements</summary>
|
||||
DataPositionMeasurementBlock = 0x2A4D5044,
|
||||
/// <summary>TODO: Block containing a snapshot index</summary>
|
||||
SnapshotBlock = 0x50414E53,
|
||||
/// <summary>TODO: Block containing how to locate the parent image</summary>
|
||||
ParentBlock = 0x544E5250,
|
||||
/// <summary>Block containing an array of hardware used to create the image</summary>
|
||||
DumpHardwareBlock = 0x2A504D44,
|
||||
/// <summary>Block containing list of files for a tape image</summary>
|
||||
TapeFileBlock = 0x454C4654,
|
||||
/// <summary>Block containing list of partitions for a tape image</summary>
|
||||
TapePartitionBlock = 0x54425054,
|
||||
/// <summary>Block containing list of indexes for Compact Disc tracks</summary>
|
||||
CompactDiscIndexesBlock = 0x58494443,
|
||||
/// <summary>Block containing JSON version of Aaru Metadata</summary>
|
||||
AaruMetadataJsonBlock = 0x444D534A
|
||||
}
|
||||
|
||||
enum ChecksumAlgorithm : byte
|
||||
{
|
||||
Invalid = 0, Md5 = 1, Sha1 = 2,
|
||||
Sha256 = 3, SpamSum = 4
|
||||
}
|
||||
|
||||
enum CdFixFlags : uint
|
||||
{
|
||||
NotDumped = 0x10000000, Correct = 0x20000000, Mode2Form1Ok = 0x30000000,
|
||||
Mode2Form2Ok = 0x40000000, Mode2Form2NoCrc = 0x50000000
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
@@ -57,8 +57,10 @@ public sealed partial class AaruFormat
|
||||
_imageInfo.DriveModel = decoded.ProductName;
|
||||
|
||||
if(string.IsNullOrWhiteSpace(_imageInfo.DriveFirmwareRevision))
|
||||
{
|
||||
_imageInfo.DriveFirmwareRevision =
|
||||
$"{(decoded.ProductRevision & 0xF0) >> 4:X2}.{decoded.ProductRevision & 0x0F:X2}";
|
||||
}
|
||||
|
||||
if(string.IsNullOrWhiteSpace(_imageInfo.DriveSerialNumber))
|
||||
_imageInfo.DriveSerialNumber = $"{decoded.ProductSerialNumber}";
|
||||
@@ -76,8 +78,10 @@ public sealed partial class AaruFormat
|
||||
_imageInfo.DriveModel = decoded.ProductName;
|
||||
|
||||
if(string.IsNullOrWhiteSpace(_imageInfo.DriveFirmwareRevision))
|
||||
{
|
||||
_imageInfo.DriveFirmwareRevision =
|
||||
$"{(decoded.ProductRevision & 0xF0) >> 4:X2}.{decoded.ProductRevision & 0x0F:X2}";
|
||||
}
|
||||
|
||||
if(string.IsNullOrWhiteSpace(_imageInfo.DriveSerialNumber))
|
||||
_imageInfo.DriveSerialNumber = $"{decoded.ProductSerialNumber}";
|
||||
@@ -104,7 +108,7 @@ public sealed partial class AaruFormat
|
||||
}
|
||||
|
||||
// Search for ATA or ATAPI IDENTIFY
|
||||
if(!_mediaTags.TryGetValue(MediaTagType.ATA_IDENTIFY, out byte[] ataIdentify) &&
|
||||
if(!_mediaTags.TryGetValue(MediaTagType.ATA_IDENTIFY, out byte[] ataIdentify) &&
|
||||
!_mediaTags.TryGetValue(MediaTagType.ATAPI_IDENTIFY, out ataIdentify))
|
||||
return;
|
||||
|
||||
@@ -118,6 +122,7 @@ public sealed partial class AaruFormat
|
||||
string[] separated = identify.Model.Split(' ');
|
||||
|
||||
if(separated.Length == 1)
|
||||
{
|
||||
if(string.IsNullOrWhiteSpace(_imageInfo.DriveModel))
|
||||
_imageInfo.DriveModel = separated[0];
|
||||
else
|
||||
@@ -128,6 +133,7 @@ public sealed partial class AaruFormat
|
||||
if(string.IsNullOrWhiteSpace(_imageInfo.DriveModel))
|
||||
_imageInfo.DriveModel = separated[^1];
|
||||
}
|
||||
}
|
||||
|
||||
if(string.IsNullOrWhiteSpace(_imageInfo.DriveFirmwareRevision))
|
||||
_imageInfo.DriveFirmwareRevision = identify.FirmwareRevision;
|
||||
@@ -235,8 +241,10 @@ public sealed partial class AaruFormat
|
||||
case MediaType.VideoNow:
|
||||
case MediaType.VideoNowColor:
|
||||
case MediaType.VideoNowXp:
|
||||
case MediaType.CVD: return MetadataMediaType.OpticalDisc;
|
||||
default: return MetadataMediaType.BlockMedia;
|
||||
case MediaType.CVD:
|
||||
return MetadataMediaType.OpticalDisc;
|
||||
default:
|
||||
return MetadataMediaType.BlockMedia;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -252,7 +260,7 @@ public sealed partial class AaruFormat
|
||||
long oldPosition = _imageStream.Position;
|
||||
_imageStream.Position = _outMemoryDdtPosition + Marshal.SizeOf<DdtHeader>();
|
||||
_imageStream.Position += (long)(sectorAddress * sizeof(ulong));
|
||||
byte[] temp = new byte[sizeof(ulong)];
|
||||
var temp = new byte[sizeof(ulong)];
|
||||
_imageStream.EnsureRead(temp, 0, sizeof(ulong));
|
||||
_imageStream.Position = oldPosition;
|
||||
entry = BitConverter.ToUInt64(temp, 0);
|
||||
@@ -287,153 +295,246 @@ public sealed partial class AaruFormat
|
||||
|
||||
// Converts between image data type and Aaru media tag type
|
||||
static MediaTagType GetMediaTagTypeForDataType(DataType type) => type switch
|
||||
{
|
||||
DataType.CompactDiscPartialToc => MediaTagType.CD_TOC,
|
||||
DataType.CompactDiscSessionInfo => MediaTagType.CD_SessionInfo,
|
||||
DataType.CompactDiscToc => MediaTagType.CD_FullTOC,
|
||||
DataType.CompactDiscPma => MediaTagType.CD_PMA,
|
||||
DataType.CompactDiscAtip => MediaTagType.CD_ATIP,
|
||||
DataType.CompactDiscLeadInCdText => MediaTagType.CD_TEXT,
|
||||
DataType.DvdPfi => MediaTagType.DVD_PFI,
|
||||
DataType.DvdLeadInCmi => MediaTagType.DVD_CMI,
|
||||
DataType.DvdDiscKey => MediaTagType.DVD_DiscKey,
|
||||
DataType.DvdBca => MediaTagType.DVD_BCA,
|
||||
DataType.DvdDmi => MediaTagType.DVD_DMI,
|
||||
DataType.DvdMediaIdentifier => MediaTagType.DVD_MediaIdentifier,
|
||||
DataType.DvdMediaKeyBlock => MediaTagType.DVD_MKB,
|
||||
DataType.DvdRamDds => MediaTagType.DVDRAM_DDS,
|
||||
DataType.DvdRamMediumStatus => MediaTagType.DVDRAM_MediumStatus,
|
||||
DataType.DvdRamSpareArea => MediaTagType.DVDRAM_SpareArea,
|
||||
DataType.DvdRRmd => MediaTagType.DVDR_RMD,
|
||||
DataType.DvdRPrerecordedInfo => MediaTagType.DVDR_PreRecordedInfo,
|
||||
DataType.DvdRMediaIdentifier => MediaTagType.DVDR_MediaIdentifier,
|
||||
DataType.DvdRPfi => MediaTagType.DVDR_PFI,
|
||||
DataType.DvdAdip => MediaTagType.DVD_ADIP,
|
||||
DataType.HdDvdCpi => MediaTagType.HDDVD_CPI,
|
||||
DataType.HdDvdMediumStatus => MediaTagType.HDDVD_MediumStatus,
|
||||
DataType.DvdDlLayerCapacity => MediaTagType.DVDDL_LayerCapacity,
|
||||
DataType.DvdDlMiddleZoneAddress => MediaTagType.DVDDL_MiddleZoneAddress,
|
||||
DataType.DvdDlJumpIntervalSize => MediaTagType.DVDDL_JumpIntervalSize,
|
||||
DataType.DvdDlManualLayerJumpLba => MediaTagType.DVDDL_ManualLayerJumpLBA,
|
||||
DataType.BlurayDi => MediaTagType.BD_DI,
|
||||
DataType.BlurayBca => MediaTagType.BD_BCA,
|
||||
DataType.BlurayDds => MediaTagType.BD_DDS,
|
||||
DataType.BlurayCartridgeStatus => MediaTagType.BD_CartridgeStatus,
|
||||
DataType.BluraySpareArea => MediaTagType.BD_SpareArea,
|
||||
DataType.AacsVolumeIdentifier => MediaTagType.AACS_VolumeIdentifier,
|
||||
DataType.AacsSerialNumber => MediaTagType.AACS_SerialNumber,
|
||||
DataType.AacsMediaIdentifier => MediaTagType.AACS_MediaIdentifier,
|
||||
DataType.AacsMediaKeyBlock => MediaTagType.AACS_MKB,
|
||||
DataType.AacsDataKeys => MediaTagType.AACS_DataKeys,
|
||||
DataType.AacsLbaExtents => MediaTagType.AACS_LBAExtents,
|
||||
DataType.CprmMediaKeyBlock => MediaTagType.AACS_CPRM_MKB,
|
||||
DataType.HybridRecognizedLayers => MediaTagType.Hybrid_RecognizedLayers,
|
||||
DataType.ScsiMmcWriteProtection => MediaTagType.MMC_WriteProtection,
|
||||
DataType.ScsiMmcDiscInformation => MediaTagType.MMC_DiscInformation,
|
||||
DataType.ScsiMmcTrackResourcesInformation => MediaTagType.MMC_TrackResourcesInformation,
|
||||
DataType.ScsiMmcPowResourcesInformation => MediaTagType.MMC_POWResourcesInformation,
|
||||
DataType.ScsiInquiry => MediaTagType.SCSI_INQUIRY,
|
||||
DataType.ScsiModePage2A => MediaTagType.SCSI_MODEPAGE_2A,
|
||||
DataType.AtaIdentify => MediaTagType.ATA_IDENTIFY,
|
||||
DataType.AtapiIdentify => MediaTagType.ATAPI_IDENTIFY,
|
||||
DataType.PcmciaCis => MediaTagType.PCMCIA_CIS,
|
||||
DataType.SecureDigitalCid => MediaTagType.SD_CID,
|
||||
DataType.SecureDigitalCsd => MediaTagType.SD_CSD,
|
||||
DataType.SecureDigitalScr => MediaTagType.SD_SCR,
|
||||
DataType.SecureDigitalOcr => MediaTagType.SD_OCR,
|
||||
DataType.MultiMediaCardCid => MediaTagType.MMC_CID,
|
||||
DataType.MultiMediaCardCsd => MediaTagType.MMC_CSD,
|
||||
DataType.MultiMediaCardOcr => MediaTagType.MMC_OCR,
|
||||
DataType.MultiMediaCardExtendedCsd => MediaTagType.MMC_ExtendedCSD,
|
||||
DataType.XboxSecuritySector => MediaTagType.Xbox_SecuritySector,
|
||||
DataType.FloppyLeadOut => MediaTagType.Floppy_LeadOut,
|
||||
DataType.DvdDiscControlBlock => MediaTagType.DCB,
|
||||
DataType.CompactDiscFirstTrackPregap => MediaTagType.CD_FirstTrackPregap,
|
||||
DataType.CompactDiscLeadOut => MediaTagType.CD_LeadOut,
|
||||
DataType.ScsiModeSense6 => MediaTagType.SCSI_MODESENSE_6,
|
||||
DataType.ScsiModeSense10 => MediaTagType.SCSI_MODESENSE_10,
|
||||
DataType.UsbDescriptors => MediaTagType.USB_Descriptors,
|
||||
DataType.XboxDmi => MediaTagType.Xbox_DMI,
|
||||
DataType.XboxPfi => MediaTagType.Xbox_PFI,
|
||||
DataType.CompactDiscMediaCatalogueNumber => MediaTagType.CD_MCN,
|
||||
DataType.CompactDiscLeadIn => MediaTagType.CD_LeadIn,
|
||||
DataType.DvdDiscKeyDecrypted => MediaTagType.DVD_DiscKey_Decrypted,
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
};
|
||||
{
|
||||
DataType.CompactDiscPartialToc => MediaTagType.
|
||||
CD_TOC,
|
||||
DataType.CompactDiscSessionInfo =>
|
||||
MediaTagType.CD_SessionInfo,
|
||||
DataType.CompactDiscToc => MediaTagType.
|
||||
CD_FullTOC,
|
||||
DataType.CompactDiscPma => MediaTagType.CD_PMA,
|
||||
DataType.CompactDiscAtip => MediaTagType.
|
||||
CD_ATIP,
|
||||
DataType.CompactDiscLeadInCdText =>
|
||||
MediaTagType.CD_TEXT,
|
||||
DataType.DvdPfi => MediaTagType.DVD_PFI,
|
||||
DataType.DvdLeadInCmi => MediaTagType.DVD_CMI,
|
||||
DataType.DvdDiscKey =>
|
||||
MediaTagType.DVD_DiscKey,
|
||||
DataType.DvdBca => MediaTagType.DVD_BCA,
|
||||
DataType.DvdDmi => MediaTagType.DVD_DMI,
|
||||
DataType.DvdMediaIdentifier => MediaTagType.
|
||||
DVD_MediaIdentifier,
|
||||
DataType.DvdMediaKeyBlock => MediaTagType.
|
||||
DVD_MKB,
|
||||
DataType.DvdRamDds => MediaTagType.DVDRAM_DDS,
|
||||
DataType.DvdRamMediumStatus => MediaTagType.
|
||||
DVDRAM_MediumStatus,
|
||||
DataType.DvdRamSpareArea => MediaTagType.
|
||||
DVDRAM_SpareArea,
|
||||
DataType.DvdRRmd => MediaTagType.DVDR_RMD,
|
||||
DataType.DvdRPrerecordedInfo => MediaTagType.
|
||||
DVDR_PreRecordedInfo,
|
||||
DataType.DvdRMediaIdentifier => MediaTagType.
|
||||
DVDR_MediaIdentifier,
|
||||
DataType.DvdRPfi => MediaTagType.DVDR_PFI,
|
||||
DataType.DvdAdip => MediaTagType.DVD_ADIP,
|
||||
DataType.HdDvdCpi => MediaTagType.HDDVD_CPI,
|
||||
DataType.HdDvdMediumStatus => MediaTagType.
|
||||
HDDVD_MediumStatus,
|
||||
DataType.DvdDlLayerCapacity => MediaTagType.
|
||||
DVDDL_LayerCapacity,
|
||||
DataType.DvdDlMiddleZoneAddress =>
|
||||
MediaTagType.DVDDL_MiddleZoneAddress,
|
||||
DataType.DvdDlJumpIntervalSize => MediaTagType.
|
||||
DVDDL_JumpIntervalSize,
|
||||
DataType.DvdDlManualLayerJumpLba =>
|
||||
MediaTagType.DVDDL_ManualLayerJumpLBA,
|
||||
DataType.BlurayDi => MediaTagType.BD_DI,
|
||||
DataType.BlurayBca => MediaTagType.BD_BCA,
|
||||
DataType.BlurayDds => MediaTagType.BD_DDS,
|
||||
DataType.BlurayCartridgeStatus => MediaTagType.
|
||||
BD_CartridgeStatus,
|
||||
DataType.BluraySpareArea => MediaTagType.
|
||||
BD_SpareArea,
|
||||
DataType.AacsVolumeIdentifier => MediaTagType.
|
||||
AACS_VolumeIdentifier,
|
||||
DataType.AacsSerialNumber => MediaTagType.
|
||||
AACS_SerialNumber,
|
||||
DataType.AacsMediaIdentifier => MediaTagType.
|
||||
AACS_MediaIdentifier,
|
||||
DataType.AacsMediaKeyBlock => MediaTagType.
|
||||
AACS_MKB,
|
||||
DataType.AacsDataKeys => MediaTagType.
|
||||
AACS_DataKeys,
|
||||
DataType.AacsLbaExtents => MediaTagType.
|
||||
AACS_LBAExtents,
|
||||
DataType.CprmMediaKeyBlock => MediaTagType.
|
||||
AACS_CPRM_MKB,
|
||||
DataType.HybridRecognizedLayers =>
|
||||
MediaTagType.Hybrid_RecognizedLayers,
|
||||
DataType.ScsiMmcWriteProtection =>
|
||||
MediaTagType.MMC_WriteProtection,
|
||||
DataType.ScsiMmcDiscInformation =>
|
||||
MediaTagType.MMC_DiscInformation,
|
||||
DataType.ScsiMmcTrackResourcesInformation =>
|
||||
MediaTagType.MMC_TrackResourcesInformation,
|
||||
DataType.ScsiMmcPowResourcesInformation =>
|
||||
MediaTagType.MMC_POWResourcesInformation,
|
||||
DataType.ScsiInquiry => MediaTagType.
|
||||
SCSI_INQUIRY,
|
||||
DataType.ScsiModePage2A => MediaTagType.
|
||||
SCSI_MODEPAGE_2A,
|
||||
DataType.AtaIdentify => MediaTagType.
|
||||
ATA_IDENTIFY,
|
||||
DataType.AtapiIdentify => MediaTagType.
|
||||
ATAPI_IDENTIFY,
|
||||
DataType.PcmciaCis => MediaTagType.PCMCIA_CIS,
|
||||
DataType.SecureDigitalCid => MediaTagType.
|
||||
SD_CID,
|
||||
DataType.SecureDigitalCsd => MediaTagType.
|
||||
SD_CSD,
|
||||
DataType.SecureDigitalScr => MediaTagType.
|
||||
SD_SCR,
|
||||
DataType.SecureDigitalOcr => MediaTagType.
|
||||
SD_OCR,
|
||||
DataType.MultiMediaCardCid => MediaTagType.
|
||||
MMC_CID,
|
||||
DataType.MultiMediaCardCsd => MediaTagType.
|
||||
MMC_CSD,
|
||||
DataType.MultiMediaCardOcr => MediaTagType.
|
||||
MMC_OCR,
|
||||
DataType.MultiMediaCardExtendedCsd =>
|
||||
MediaTagType.MMC_ExtendedCSD,
|
||||
DataType.XboxSecuritySector => MediaTagType.
|
||||
Xbox_SecuritySector,
|
||||
DataType.FloppyLeadOut => MediaTagType.
|
||||
Floppy_LeadOut,
|
||||
DataType.DvdDiscControlBlock => MediaTagType.
|
||||
DCB,
|
||||
DataType.CompactDiscFirstTrackPregap =>
|
||||
MediaTagType.CD_FirstTrackPregap,
|
||||
DataType.CompactDiscLeadOut => MediaTagType.
|
||||
CD_LeadOut,
|
||||
DataType.ScsiModeSense6 => MediaTagType.
|
||||
SCSI_MODESENSE_6,
|
||||
DataType.ScsiModeSense10 => MediaTagType.
|
||||
SCSI_MODESENSE_10,
|
||||
DataType.UsbDescriptors => MediaTagType.
|
||||
USB_Descriptors,
|
||||
DataType.XboxDmi => MediaTagType.Xbox_DMI,
|
||||
DataType.XboxPfi => MediaTagType.Xbox_PFI,
|
||||
DataType.CompactDiscMediaCatalogueNumber =>
|
||||
MediaTagType.CD_MCN,
|
||||
DataType.CompactDiscLeadIn => MediaTagType.
|
||||
CD_LeadIn,
|
||||
DataType.DvdDiscKeyDecrypted => MediaTagType.
|
||||
DVD_DiscKey_Decrypted,
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
};
|
||||
|
||||
// Converts between Aaru media tag type and image data type
|
||||
static DataType GetDataTypeForMediaTag(MediaTagType tag) => tag switch
|
||||
{
|
||||
MediaTagType.CD_TOC => DataType.CompactDiscPartialToc,
|
||||
MediaTagType.CD_SessionInfo => DataType.CompactDiscSessionInfo,
|
||||
MediaTagType.CD_FullTOC => DataType.CompactDiscToc,
|
||||
MediaTagType.CD_PMA => DataType.CompactDiscPma,
|
||||
MediaTagType.CD_ATIP => DataType.CompactDiscAtip,
|
||||
MediaTagType.CD_TEXT => DataType.CompactDiscLeadInCdText,
|
||||
MediaTagType.DVD_PFI => DataType.DvdPfi,
|
||||
MediaTagType.DVD_CMI => DataType.DvdLeadInCmi,
|
||||
MediaTagType.DVD_DiscKey => DataType.DvdDiscKey,
|
||||
MediaTagType.DVD_BCA => DataType.DvdBca,
|
||||
MediaTagType.DVD_DMI => DataType.DvdDmi,
|
||||
MediaTagType.DVD_MediaIdentifier => DataType.DvdMediaIdentifier,
|
||||
MediaTagType.DVD_MKB => DataType.DvdMediaKeyBlock,
|
||||
MediaTagType.DVDRAM_DDS => DataType.DvdRamDds,
|
||||
MediaTagType.DVDRAM_MediumStatus => DataType.DvdRamMediumStatus,
|
||||
MediaTagType.DVDRAM_SpareArea => DataType.DvdRamSpareArea,
|
||||
MediaTagType.DVDR_RMD => DataType.DvdRRmd,
|
||||
MediaTagType.DVDR_PreRecordedInfo => DataType.DvdRPrerecordedInfo,
|
||||
MediaTagType.DVDR_MediaIdentifier => DataType.DvdRMediaIdentifier,
|
||||
MediaTagType.DVDR_PFI => DataType.DvdRPfi,
|
||||
MediaTagType.DVD_ADIP => DataType.DvdAdip,
|
||||
MediaTagType.HDDVD_CPI => DataType.HdDvdCpi,
|
||||
MediaTagType.HDDVD_MediumStatus => DataType.HdDvdMediumStatus,
|
||||
MediaTagType.DVDDL_LayerCapacity => DataType.DvdDlLayerCapacity,
|
||||
MediaTagType.DVDDL_MiddleZoneAddress => DataType.DvdDlMiddleZoneAddress,
|
||||
MediaTagType.DVDDL_JumpIntervalSize => DataType.DvdDlJumpIntervalSize,
|
||||
MediaTagType.DVDDL_ManualLayerJumpLBA => DataType.DvdDlManualLayerJumpLba,
|
||||
MediaTagType.BD_DI => DataType.BlurayDi,
|
||||
MediaTagType.BD_BCA => DataType.BlurayBca,
|
||||
MediaTagType.BD_DDS => DataType.BlurayDds,
|
||||
MediaTagType.BD_CartridgeStatus => DataType.BlurayCartridgeStatus,
|
||||
MediaTagType.BD_SpareArea => DataType.BluraySpareArea,
|
||||
MediaTagType.AACS_VolumeIdentifier => DataType.AacsVolumeIdentifier,
|
||||
MediaTagType.AACS_SerialNumber => DataType.AacsSerialNumber,
|
||||
MediaTagType.AACS_MediaIdentifier => DataType.AacsMediaIdentifier,
|
||||
MediaTagType.AACS_MKB => DataType.AacsMediaKeyBlock,
|
||||
MediaTagType.AACS_DataKeys => DataType.AacsDataKeys,
|
||||
MediaTagType.AACS_LBAExtents => DataType.AacsLbaExtents,
|
||||
MediaTagType.AACS_CPRM_MKB => DataType.CprmMediaKeyBlock,
|
||||
MediaTagType.Hybrid_RecognizedLayers => DataType.HybridRecognizedLayers,
|
||||
MediaTagType.MMC_WriteProtection => DataType.ScsiMmcWriteProtection,
|
||||
MediaTagType.MMC_DiscInformation => DataType.ScsiMmcDiscInformation,
|
||||
MediaTagType.MMC_TrackResourcesInformation => DataType.ScsiMmcTrackResourcesInformation,
|
||||
MediaTagType.MMC_POWResourcesInformation => DataType.ScsiMmcPowResourcesInformation,
|
||||
MediaTagType.SCSI_INQUIRY => DataType.ScsiInquiry,
|
||||
MediaTagType.SCSI_MODEPAGE_2A => DataType.ScsiModePage2A,
|
||||
MediaTagType.ATA_IDENTIFY => DataType.AtaIdentify,
|
||||
MediaTagType.ATAPI_IDENTIFY => DataType.AtapiIdentify,
|
||||
MediaTagType.PCMCIA_CIS => DataType.PcmciaCis,
|
||||
MediaTagType.SD_CID => DataType.SecureDigitalCid,
|
||||
MediaTagType.SD_CSD => DataType.SecureDigitalCsd,
|
||||
MediaTagType.SD_SCR => DataType.SecureDigitalScr,
|
||||
MediaTagType.SD_OCR => DataType.SecureDigitalOcr,
|
||||
MediaTagType.MMC_CID => DataType.MultiMediaCardCid,
|
||||
MediaTagType.MMC_CSD => DataType.MultiMediaCardCsd,
|
||||
MediaTagType.MMC_OCR => DataType.MultiMediaCardOcr,
|
||||
MediaTagType.MMC_ExtendedCSD => DataType.MultiMediaCardExtendedCsd,
|
||||
MediaTagType.Xbox_SecuritySector => DataType.XboxSecuritySector,
|
||||
MediaTagType.Floppy_LeadOut => DataType.FloppyLeadOut,
|
||||
MediaTagType.DCB => DataType.DvdDiscControlBlock,
|
||||
MediaTagType.CD_FirstTrackPregap => DataType.CompactDiscFirstTrackPregap,
|
||||
MediaTagType.CD_LeadOut => DataType.CompactDiscLeadOut,
|
||||
MediaTagType.SCSI_MODESENSE_6 => DataType.ScsiModeSense6,
|
||||
MediaTagType.SCSI_MODESENSE_10 => DataType.ScsiModeSense10,
|
||||
MediaTagType.USB_Descriptors => DataType.UsbDescriptors,
|
||||
MediaTagType.Xbox_DMI => DataType.XboxDmi,
|
||||
MediaTagType.Xbox_PFI => DataType.XboxPfi,
|
||||
MediaTagType.CD_MCN => DataType.CompactDiscMediaCatalogueNumber,
|
||||
MediaTagType.CD_LeadIn => DataType.CompactDiscLeadIn,
|
||||
MediaTagType.DVD_DiscKey_Decrypted => DataType.DvdDiscKeyDecrypted,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(tag), tag, null)
|
||||
};
|
||||
{
|
||||
MediaTagType.CD_TOC => DataType.
|
||||
CompactDiscPartialToc,
|
||||
MediaTagType.CD_SessionInfo => DataType.
|
||||
CompactDiscSessionInfo,
|
||||
MediaTagType.CD_FullTOC => DataType.CompactDiscToc,
|
||||
MediaTagType.CD_PMA => DataType.CompactDiscPma,
|
||||
MediaTagType.CD_ATIP => DataType.CompactDiscAtip,
|
||||
MediaTagType.CD_TEXT => DataType.
|
||||
CompactDiscLeadInCdText,
|
||||
MediaTagType.DVD_PFI => DataType.DvdPfi,
|
||||
MediaTagType.DVD_CMI => DataType.DvdLeadInCmi,
|
||||
MediaTagType.DVD_DiscKey => DataType.DvdDiscKey,
|
||||
MediaTagType.DVD_BCA => DataType.DvdBca,
|
||||
MediaTagType.DVD_DMI => DataType.DvdDmi,
|
||||
MediaTagType.DVD_MediaIdentifier => DataType.
|
||||
DvdMediaIdentifier,
|
||||
MediaTagType.DVD_MKB => DataType.DvdMediaKeyBlock,
|
||||
MediaTagType.DVDRAM_DDS => DataType.DvdRamDds,
|
||||
MediaTagType.DVDRAM_MediumStatus => DataType.
|
||||
DvdRamMediumStatus,
|
||||
MediaTagType.DVDRAM_SpareArea => DataType.
|
||||
DvdRamSpareArea,
|
||||
MediaTagType.DVDR_RMD => DataType.DvdRRmd,
|
||||
MediaTagType.DVDR_PreRecordedInfo => DataType.
|
||||
DvdRPrerecordedInfo,
|
||||
MediaTagType.DVDR_MediaIdentifier => DataType.
|
||||
DvdRMediaIdentifier,
|
||||
MediaTagType.DVDR_PFI => DataType.DvdRPfi,
|
||||
MediaTagType.DVD_ADIP => DataType.DvdAdip,
|
||||
MediaTagType.HDDVD_CPI => DataType.HdDvdCpi,
|
||||
MediaTagType.HDDVD_MediumStatus => DataType.
|
||||
HdDvdMediumStatus,
|
||||
MediaTagType.DVDDL_LayerCapacity => DataType.
|
||||
DvdDlLayerCapacity,
|
||||
MediaTagType.DVDDL_MiddleZoneAddress => DataType.
|
||||
DvdDlMiddleZoneAddress,
|
||||
MediaTagType.DVDDL_JumpIntervalSize => DataType.
|
||||
DvdDlJumpIntervalSize,
|
||||
MediaTagType.DVDDL_ManualLayerJumpLBA => DataType.
|
||||
DvdDlManualLayerJumpLba,
|
||||
MediaTagType.BD_DI => DataType.BlurayDi,
|
||||
MediaTagType.BD_BCA => DataType.BlurayBca,
|
||||
MediaTagType.BD_DDS => DataType.BlurayDds,
|
||||
MediaTagType.BD_CartridgeStatus => DataType.
|
||||
BlurayCartridgeStatus,
|
||||
MediaTagType.BD_SpareArea => DataType.
|
||||
BluraySpareArea,
|
||||
MediaTagType.AACS_VolumeIdentifier => DataType.
|
||||
AacsVolumeIdentifier,
|
||||
MediaTagType.AACS_SerialNumber => DataType.
|
||||
AacsSerialNumber,
|
||||
MediaTagType.AACS_MediaIdentifier => DataType.
|
||||
AacsMediaIdentifier,
|
||||
MediaTagType.AACS_MKB => DataType.AacsMediaKeyBlock,
|
||||
MediaTagType.AACS_DataKeys => DataType.AacsDataKeys,
|
||||
MediaTagType.AACS_LBAExtents => DataType.
|
||||
AacsLbaExtents,
|
||||
MediaTagType.AACS_CPRM_MKB => DataType.
|
||||
CprmMediaKeyBlock,
|
||||
MediaTagType.Hybrid_RecognizedLayers => DataType.
|
||||
HybridRecognizedLayers,
|
||||
MediaTagType.MMC_WriteProtection => DataType.
|
||||
ScsiMmcWriteProtection,
|
||||
MediaTagType.MMC_DiscInformation => DataType.
|
||||
ScsiMmcDiscInformation,
|
||||
MediaTagType.MMC_TrackResourcesInformation =>
|
||||
DataType.ScsiMmcTrackResourcesInformation,
|
||||
MediaTagType.MMC_POWResourcesInformation =>
|
||||
DataType.ScsiMmcPowResourcesInformation,
|
||||
MediaTagType.SCSI_INQUIRY => DataType.ScsiInquiry,
|
||||
MediaTagType.SCSI_MODEPAGE_2A => DataType.
|
||||
ScsiModePage2A,
|
||||
MediaTagType.ATA_IDENTIFY => DataType.AtaIdentify,
|
||||
MediaTagType.ATAPI_IDENTIFY => DataType.
|
||||
AtapiIdentify,
|
||||
MediaTagType.PCMCIA_CIS => DataType.PcmciaCis,
|
||||
MediaTagType.SD_CID => DataType.SecureDigitalCid,
|
||||
MediaTagType.SD_CSD => DataType.SecureDigitalCsd,
|
||||
MediaTagType.SD_SCR => DataType.SecureDigitalScr,
|
||||
MediaTagType.SD_OCR => DataType.SecureDigitalOcr,
|
||||
MediaTagType.MMC_CID => DataType.MultiMediaCardCid,
|
||||
MediaTagType.MMC_CSD => DataType.MultiMediaCardCsd,
|
||||
MediaTagType.MMC_OCR => DataType.MultiMediaCardOcr,
|
||||
MediaTagType.MMC_ExtendedCSD => DataType.
|
||||
MultiMediaCardExtendedCsd,
|
||||
MediaTagType.Xbox_SecuritySector => DataType.
|
||||
XboxSecuritySector,
|
||||
MediaTagType.Floppy_LeadOut => DataType.
|
||||
FloppyLeadOut,
|
||||
MediaTagType.DCB => DataType.DvdDiscControlBlock,
|
||||
MediaTagType.CD_FirstTrackPregap => DataType.
|
||||
CompactDiscFirstTrackPregap,
|
||||
MediaTagType.CD_LeadOut => DataType.
|
||||
CompactDiscLeadOut,
|
||||
MediaTagType.SCSI_MODESENSE_6 => DataType.
|
||||
ScsiModeSense6,
|
||||
MediaTagType.SCSI_MODESENSE_10 => DataType.
|
||||
ScsiModeSense10,
|
||||
MediaTagType.USB_Descriptors => DataType.
|
||||
UsbDescriptors,
|
||||
MediaTagType.Xbox_DMI => DataType.XboxDmi,
|
||||
MediaTagType.Xbox_PFI => DataType.XboxPfi,
|
||||
MediaTagType.CD_MCN => DataType.
|
||||
CompactDiscMediaCatalogueNumber,
|
||||
MediaTagType.CD_LeadIn =>
|
||||
DataType.CompactDiscLeadIn,
|
||||
MediaTagType.DVD_DiscKey_Decrypted => DataType.
|
||||
DvdDiscKeyDecrypted,
|
||||
_ => throw new ArgumentOutOfRangeException(
|
||||
nameof(tag), tag, null)
|
||||
};
|
||||
}
|
||||
@@ -38,6 +38,8 @@ namespace Aaru.DiscImages;
|
||||
|
||||
public sealed partial class AaruFormat
|
||||
{
|
||||
#region IWritableOpticalImage Members
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Identify(IFilter imageFilter)
|
||||
{
|
||||
@@ -53,4 +55,6 @@ public sealed partial class AaruFormat
|
||||
|
||||
return _header.identifier is DIC_MAGIC or AARU_MAGIC && _header.imageMajorVersion <= AARUFMT_VERSION;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -44,6 +44,8 @@ namespace Aaru.DiscImages;
|
||||
|
||||
public sealed partial class AaruFormat
|
||||
{
|
||||
#region IWritableOpticalImage Members
|
||||
|
||||
/// <inheritdoc />
|
||||
public OpticalImageCapabilities OpticalCapabilities => OpticalImageCapabilities.CanStoreAudioTracks |
|
||||
OpticalImageCapabilities.CanStoreDataTracks |
|
||||
@@ -60,33 +62,47 @@ public sealed partial class AaruFormat
|
||||
OpticalImageCapabilities.CanStoreNotCdTracks |
|
||||
OpticalImageCapabilities.CanStoreIndexes |
|
||||
OpticalImageCapabilities.CanStoreHiddenTracks;
|
||||
|
||||
/// <inheritdoc />
|
||||
public ImageInfo Info => _imageInfo;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Name => Localization.AaruFormat_Name;
|
||||
|
||||
/// <inheritdoc />
|
||||
public Guid Id => new("49360069-1784-4A2F-B723-0C844D610B0A");
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Format => "Aaru";
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Author => Authors.NataliaPortillo;
|
||||
|
||||
/// <inheritdoc />
|
||||
public List<Partition> Partitions { get; private set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public List<Track> Tracks { get; private set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public List<Session> Sessions { get; private set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public List<DumpHardware> DumpHardware { get; private set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Metadata AaruMetadata { get; private set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<MediaTagType> SupportedMediaTags => Enum.GetValues(typeof(MediaTagType)).Cast<MediaTagType>();
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<SectorTagType> SupportedSectorTags =>
|
||||
Enum.GetValues(typeof(SectorTagType)).Cast<SectorTagType>();
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<MediaType> SupportedMediaTypes => Enum.GetValues(typeof(MediaType)).Cast<MediaType>();
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<(string name, Type type, string description, object @default)> SupportedOptions => new[]
|
||||
{
|
||||
@@ -98,20 +114,23 @@ public sealed partial class AaruFormat
|
||||
("md5", typeof(bool), Localization.Calculate_and_store_MD5_of_image_user_data, false),
|
||||
("sha1", typeof(bool), Localization.Calculate_and_store_SHA1_of_image_user_data, false),
|
||||
("sha256", typeof(bool), Localization.Calculate_and_store_SHA256_of_image_user_data, false),
|
||||
("spamsum", typeof(bool), Localization.Calculate_and_store_SpamSum_of_image_user_data, false),
|
||||
("deduplicate", typeof(bool),
|
||||
Localization.Store_only_unique_sectors_This_consumes_more_memory_and_is_slower_but_its_enabled_by_default,
|
||||
true),
|
||||
("spamsum", typeof(bool), Localization.Calculate_and_store_SpamSum_of_image_user_data, false), ("deduplicate",
|
||||
typeof(bool),
|
||||
Localization.
|
||||
Store_only_unique_sectors_This_consumes_more_memory_and_is_slower_but_its_enabled_by_default,
|
||||
true),
|
||||
("compress", typeof(bool), Localization.Compress_user_data_blocks_Other_blocks_will_always_be_compressed,
|
||||
(object)true)
|
||||
};
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<string> KnownExtensions => new[]
|
||||
{
|
||||
".dicf", ".aaru", ".aaruformat", ".aaruf", ".aif"
|
||||
};
|
||||
public IEnumerable<string> KnownExtensions => new[] { ".dicf", ".aaru", ".aaruformat", ".aaruf", ".aif" };
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsWriting { get; private set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public string ErrorMessage { get; private set; }
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -63,6 +63,8 @@ namespace Aaru.DiscImages;
|
||||
|
||||
public sealed partial class AaruFormat
|
||||
{
|
||||
#region IWritableOpticalImage Members
|
||||
|
||||
/// <inheritdoc />
|
||||
public ErrorNumber Open(IFilter imageFilter)
|
||||
{
|
||||
@@ -168,7 +170,7 @@ public sealed partial class AaruFormat
|
||||
|
||||
_imageInfo.ImageSize = 0;
|
||||
|
||||
bool foundUserDataDdt = false;
|
||||
var foundUserDataDdt = false;
|
||||
_mediaTags = new Dictionary<MediaTagType, byte[]>();
|
||||
List<CompactDiscIndexEntry> compactDiscIndexes = null;
|
||||
|
||||
@@ -228,7 +230,7 @@ public sealed partial class AaruFormat
|
||||
|
||||
// Decompress media tag
|
||||
if(blockHeader.compression is CompressionType.Lzma
|
||||
or CompressionType.LzmaClauniaSubchannelTransform)
|
||||
or CompressionType.LzmaClauniaSubchannelTransform)
|
||||
{
|
||||
if(blockHeader.compression == CompressionType.LzmaClauniaSubchannelTransform &&
|
||||
entry.dataType != DataType.CdSectorSubchannel)
|
||||
@@ -243,10 +245,10 @@ public sealed partial class AaruFormat
|
||||
|
||||
var decompressStopwatch = new Stopwatch();
|
||||
decompressStopwatch.Start();
|
||||
byte[] compressedTag = new byte[blockHeader.cmpLength - LZMA_PROPERTIES_LENGTH];
|
||||
byte[] lzmaProperties = new byte[LZMA_PROPERTIES_LENGTH];
|
||||
var compressedTag = new byte[blockHeader.cmpLength - LZMA_PROPERTIES_LENGTH];
|
||||
var lzmaProperties = new byte[LZMA_PROPERTIES_LENGTH];
|
||||
_imageStream.EnsureRead(lzmaProperties, 0, LZMA_PROPERTIES_LENGTH);
|
||||
_imageStream.EnsureRead(compressedTag, 0, compressedTag.Length);
|
||||
_imageStream.EnsureRead(compressedTag, 0, compressedTag.Length);
|
||||
data = new byte[blockHeader.length];
|
||||
int decompressedLength = LZMA.DecodeBuffer(compressedTag, data, lzmaProperties);
|
||||
|
||||
@@ -487,13 +489,13 @@ public sealed partial class AaruFormat
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Decompressing_DDT);
|
||||
var ddtStopwatch = new Stopwatch();
|
||||
ddtStopwatch.Start();
|
||||
byte[] compressedDdt = new byte[ddtHeader.cmpLength - LZMA_PROPERTIES_LENGTH];
|
||||
byte[] lzmaProperties = new byte[LZMA_PROPERTIES_LENGTH];
|
||||
var compressedDdt = new byte[ddtHeader.cmpLength - LZMA_PROPERTIES_LENGTH];
|
||||
var lzmaProperties = new byte[LZMA_PROPERTIES_LENGTH];
|
||||
_imageStream.EnsureRead(lzmaProperties, 0, LZMA_PROPERTIES_LENGTH);
|
||||
_imageStream.EnsureRead(compressedDdt, 0, compressedDdt.Length);
|
||||
byte[] decompressedDdt = new byte[ddtHeader.length];
|
||||
_imageStream.EnsureRead(compressedDdt, 0, compressedDdt.Length);
|
||||
var decompressedDdt = new byte[ddtHeader.length];
|
||||
|
||||
ulong decompressedLength =
|
||||
var decompressedLength =
|
||||
(ulong)LZMA.DecodeBuffer(compressedDdt, decompressedDdt, lzmaProperties);
|
||||
|
||||
if(decompressedLength != ddtHeader.length)
|
||||
@@ -531,8 +533,9 @@ public sealed partial class AaruFormat
|
||||
default:
|
||||
AaruConsole.
|
||||
ErrorWriteLine(string.
|
||||
Format(Localization.Found_unsupported_compression_algorithm_0,
|
||||
(ushort)ddtHeader.compression));
|
||||
Format(
|
||||
Localization.Found_unsupported_compression_algorithm_0,
|
||||
(ushort)ddtHeader.compression));
|
||||
|
||||
return ErrorNumber.NotSupported;
|
||||
}
|
||||
@@ -543,7 +546,7 @@ public sealed partial class AaruFormat
|
||||
case DataType.CdSectorPrefixCorrected:
|
||||
case DataType.CdSectorSuffixCorrected:
|
||||
{
|
||||
byte[] decompressedDdt = new byte[ddtHeader.length];
|
||||
var decompressedDdt = new byte[ddtHeader.length];
|
||||
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Memory_snapshot_0_bytes,
|
||||
GC.GetTotalMemory(false));
|
||||
@@ -555,12 +558,12 @@ public sealed partial class AaruFormat
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Decompressing_DDT);
|
||||
var ddtStopwatch = new Stopwatch();
|
||||
ddtStopwatch.Start();
|
||||
byte[] compressedDdt = new byte[ddtHeader.cmpLength - LZMA_PROPERTIES_LENGTH];
|
||||
byte[] lzmaProperties = new byte[LZMA_PROPERTIES_LENGTH];
|
||||
var compressedDdt = new byte[ddtHeader.cmpLength - LZMA_PROPERTIES_LENGTH];
|
||||
var lzmaProperties = new byte[LZMA_PROPERTIES_LENGTH];
|
||||
_imageStream.EnsureRead(lzmaProperties, 0, LZMA_PROPERTIES_LENGTH);
|
||||
_imageStream.EnsureRead(compressedDdt, 0, compressedDdt.Length);
|
||||
_imageStream.EnsureRead(compressedDdt, 0, compressedDdt.Length);
|
||||
|
||||
ulong decompressedLength =
|
||||
var decompressedLength =
|
||||
(ulong)LZMA.DecodeBuffer(compressedDdt, decompressedDdt, lzmaProperties);
|
||||
|
||||
ddtStopwatch.Stop();
|
||||
@@ -595,8 +598,9 @@ public sealed partial class AaruFormat
|
||||
default:
|
||||
AaruConsole.
|
||||
ErrorWriteLine(string.
|
||||
Format(Localization.Found_unsupported_compression_algorithm_0,
|
||||
(ushort)ddtHeader.compression));
|
||||
Format(
|
||||
Localization.Found_unsupported_compression_algorithm_0,
|
||||
(ushort)ddtHeader.compression));
|
||||
|
||||
return ErrorNumber.NotSupported;
|
||||
}
|
||||
@@ -668,7 +672,7 @@ public sealed partial class AaruFormat
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Found_metadata_block_at_position_0,
|
||||
entry.offset);
|
||||
|
||||
byte[] metadata = new byte[metadataBlock.blockSize];
|
||||
var metadata = new byte[metadataBlock.blockSize];
|
||||
_imageStream.Position = (long)entry.offset;
|
||||
_imageStream.EnsureRead(metadata, 0, metadata.Length);
|
||||
|
||||
@@ -917,23 +921,23 @@ public sealed partial class AaruFormat
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Memory_snapshot_0_bytes,
|
||||
GC.GetTotalMemory(false));
|
||||
|
||||
byte[] cicmBytes = new byte[cicmBlock.length];
|
||||
var cicmBytes = new byte[cicmBlock.length];
|
||||
_imageStream.EnsureRead(cicmBytes, 0, cicmBytes.Length);
|
||||
var cicmMs = new MemoryStream(cicmBytes);
|
||||
|
||||
// The converter to AaruMetadata basically overcomes this (should?)
|
||||
#pragma warning disable IL2026
|
||||
#pragma warning disable IL2026
|
||||
var cicmXs = new XmlSerializer(typeof(CICMMetadataType));
|
||||
#pragma warning restore IL2026
|
||||
#pragma warning restore IL2026
|
||||
|
||||
try
|
||||
{
|
||||
var sr = new StreamReader(cicmMs);
|
||||
|
||||
// The converter to AaruMetadata basically overcomes this (should?)
|
||||
#pragma warning disable IL2026
|
||||
#pragma warning disable IL2026
|
||||
AaruMetadata = (CICMMetadataType)cicmXs.Deserialize(sr);
|
||||
#pragma warning restore IL2026
|
||||
#pragma warning restore IL2026
|
||||
sr.Close();
|
||||
}
|
||||
catch(XmlException ex)
|
||||
@@ -967,7 +971,7 @@ public sealed partial class AaruFormat
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Memory_snapshot_0_bytes,
|
||||
GC.GetTotalMemory(false));
|
||||
|
||||
byte[] jsonBytes = new byte[aaruMetadataBlock.length];
|
||||
var jsonBytes = new byte[aaruMetadataBlock.length];
|
||||
_imageStream.EnsureRead(jsonBytes, 0, jsonBytes.Length);
|
||||
|
||||
try
|
||||
@@ -1145,7 +1149,7 @@ public sealed partial class AaruFormat
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME,
|
||||
Localization.Found_tape_partition_block_at_position_0, entry.offset);
|
||||
|
||||
byte[] tapePartitionBytes = new byte[partitionHeader.length];
|
||||
var tapePartitionBytes = new byte[partitionHeader.length];
|
||||
_imageStream.EnsureRead(tapePartitionBytes, 0, tapePartitionBytes.Length);
|
||||
|
||||
Span<TapePartitionEntry> tapePartitions =
|
||||
@@ -1154,12 +1158,14 @@ public sealed partial class AaruFormat
|
||||
TapePartitions = new List<TapePartition>();
|
||||
|
||||
foreach(TapePartitionEntry tapePartition in tapePartitions)
|
||||
{
|
||||
TapePartitions.Add(new TapePartition
|
||||
{
|
||||
FirstBlock = tapePartition.FirstBlock,
|
||||
LastBlock = tapePartition.LastBlock,
|
||||
Number = tapePartition.Number
|
||||
});
|
||||
}
|
||||
|
||||
IsTape = true;
|
||||
|
||||
@@ -1178,12 +1184,13 @@ public sealed partial class AaruFormat
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Found_tape_file_block_at_position_0,
|
||||
entry.offset);
|
||||
|
||||
byte[] tapeFileBytes = new byte[fileHeader.length];
|
||||
var tapeFileBytes = new byte[fileHeader.length];
|
||||
_imageStream.EnsureRead(tapeFileBytes, 0, tapeFileBytes.Length);
|
||||
Span<TapeFileEntry> tapeFiles = MemoryMarshal.Cast<byte, TapeFileEntry>(tapeFileBytes);
|
||||
Files = new List<TapeFile>();
|
||||
|
||||
foreach(TapeFileEntry file in tapeFiles)
|
||||
{
|
||||
Files.Add(new TapeFile
|
||||
{
|
||||
FirstBlock = file.FirstBlock,
|
||||
@@ -1191,6 +1198,7 @@ public sealed partial class AaruFormat
|
||||
Partition = file.Partition,
|
||||
File = file.File
|
||||
});
|
||||
}
|
||||
|
||||
IsTape = true;
|
||||
|
||||
@@ -1298,12 +1306,12 @@ public sealed partial class AaruFormat
|
||||
{
|
||||
if(Tracks != null)
|
||||
{
|
||||
bool leadOutFixed = false;
|
||||
bool sessionPregapFixed = false;
|
||||
var leadOutFixed = false;
|
||||
var sessionPregapFixed = false;
|
||||
|
||||
if(_mediaTags.TryGetValue(MediaTagType.CD_FullTOC, out byte[] fullToc))
|
||||
{
|
||||
byte[] tmp = new byte[fullToc.Length + 2];
|
||||
var tmp = new byte[fullToc.Length + 2];
|
||||
Array.Copy(fullToc, 0, tmp, 2, fullToc.Length);
|
||||
tmp[0] = (byte)(fullToc.Length >> 8);
|
||||
tmp[1] = (byte)(fullToc.Length & 0xFF);
|
||||
@@ -1354,8 +1362,8 @@ public sealed partial class AaruFormat
|
||||
phour = trk.PHOUR;
|
||||
}
|
||||
|
||||
int lastSector = (phour * 3600 * 75) + (pmin * 60 * 75) + (psec * 75) + pframe - 150;
|
||||
leadOutStarts?.Add(trk.SessionNumber, lastSector + 1);
|
||||
int lastSector = phour * 3600 * 75 + pmin * 60 * 75 + psec * 75 + pframe - 150;
|
||||
leadOutStarts?.Add(trk.SessionNumber, lastSector + 1);
|
||||
}
|
||||
|
||||
foreach(KeyValuePair<int, long> leadOuts in leadOutStarts)
|
||||
@@ -1377,6 +1385,7 @@ public sealed partial class AaruFormat
|
||||
}
|
||||
|
||||
if(_header.imageMajorVersion <= 1)
|
||||
{
|
||||
foreach(Track track in Tracks)
|
||||
{
|
||||
if(track.Sequence <= 1)
|
||||
@@ -1398,13 +1407,16 @@ public sealed partial class AaruFormat
|
||||
|
||||
sessionPregapFixed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(leadOutFixed)
|
||||
AaruConsole.ErrorWriteLine(Localization.This_image_has_a_corrupted_track_list_convert_will_fix_it);
|
||||
|
||||
if(sessionPregapFixed)
|
||||
{
|
||||
AaruConsole.ErrorWriteLine(Localization.
|
||||
This_image_has_a_corrupted_track_list_a_best_effort_has_been_tried_but_may_require_manual_editing_or_redump);
|
||||
}
|
||||
}
|
||||
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Memory_snapshot_0_bytes,
|
||||
@@ -1431,9 +1443,7 @@ public sealed partial class AaruFormat
|
||||
|
||||
_trackFlags = new Dictionary<byte, byte>
|
||||
{
|
||||
{
|
||||
1, (byte)CdFlags.DataTrack
|
||||
}
|
||||
{ 1, (byte)CdFlags.DataTrack }
|
||||
};
|
||||
|
||||
_trackIsrcs = new Dictionary<byte, string>();
|
||||
@@ -1444,7 +1454,8 @@ public sealed partial class AaruFormat
|
||||
|
||||
Sessions = new List<Session>();
|
||||
|
||||
for(int i = 1; i <= Tracks.Max(t => t.Session); i++)
|
||||
for(var i = 1; i <= Tracks.Max(t => t.Session); i++)
|
||||
{
|
||||
Sessions.Add(new Session
|
||||
{
|
||||
Sequence = (ushort)i,
|
||||
@@ -1453,6 +1464,7 @@ public sealed partial class AaruFormat
|
||||
StartSector = Tracks.Where(t => t.Session == i).Min(t => t.StartSector),
|
||||
EndSector = Tracks.Where(t => t.Session == i).Max(t => t.EndSector)
|
||||
});
|
||||
}
|
||||
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Memory_snapshot_0_bytes,
|
||||
GC.GetTotalMemory(false));
|
||||
@@ -1519,8 +1531,10 @@ public sealed partial class AaruFormat
|
||||
trk.BytesPerSector = sector.Length;
|
||||
|
||||
trk.RawBytesPerSector =
|
||||
(_sectorPrefix != null && _sectorSuffix != null) ||
|
||||
(_sectorPrefixDdt != null && _sectorSuffixDdt != null) ? 2352 : sector.Length;
|
||||
_sectorPrefix != null && _sectorSuffix != null ||
|
||||
_sectorPrefixDdt != null && _sectorSuffixDdt != null
|
||||
? 2352
|
||||
: sector.Length;
|
||||
|
||||
if(_sectorSubchannel == null)
|
||||
continue;
|
||||
@@ -1539,6 +1553,7 @@ public sealed partial class AaruFormat
|
||||
GC.GetTotalMemory(false));
|
||||
|
||||
if(compactDiscIndexes != null)
|
||||
{
|
||||
foreach(CompactDiscIndexEntry compactDiscIndex in compactDiscIndexes.OrderBy(i => i.Track).
|
||||
ThenBy(i => i.Index))
|
||||
{
|
||||
@@ -1549,6 +1564,7 @@ public sealed partial class AaruFormat
|
||||
|
||||
track.Indexes[compactDiscIndex.Index] = compactDiscIndex.Lba;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1569,13 +1585,20 @@ public sealed partial class AaruFormat
|
||||
return ErrorNumber.NoError;
|
||||
|
||||
if(_imageInfo.MediaType is MediaType.CD or MediaType.CDDA or MediaType.CDG or MediaType.CDEG or MediaType.CDI
|
||||
or MediaType.CDROM or MediaType.CDROMXA or MediaType.CDPLUS or MediaType.CDMO or MediaType.CDR
|
||||
or MediaType.CDRW or MediaType.CDMRW or MediaType.VCD or MediaType.SVCD or MediaType.PCD or MediaType.DTSCD
|
||||
or MediaType.CDMIDI or MediaType.CDV or MediaType.CDIREADY or MediaType.FMTOWNS or MediaType.PS1CD
|
||||
or MediaType.PS2CD or MediaType.MEGACD or MediaType.SATURNCD or MediaType.GDROM or MediaType.GDR
|
||||
or MediaType.MilCD or MediaType.SuperCDROM2 or MediaType.JaguarCD or MediaType.ThreeDO or MediaType.PCFX
|
||||
or MediaType.NeoGeoCD or MediaType.CDTV or MediaType.CD32 or MediaType.Playdia or MediaType.Pippin
|
||||
or MediaType.VideoNow or MediaType.VideoNowColor or MediaType.VideoNowXp or MediaType.CVD)
|
||||
or MediaType.CDROM or MediaType.CDROMXA or MediaType.CDPLUS or MediaType.CDMO
|
||||
or MediaType.CDR
|
||||
or MediaType.CDRW or MediaType.CDMRW or MediaType.VCD or MediaType.SVCD or MediaType.PCD
|
||||
or MediaType.DTSCD
|
||||
or MediaType.CDMIDI or MediaType.CDV or MediaType.CDIREADY or MediaType.FMTOWNS
|
||||
or MediaType.PS1CD
|
||||
or MediaType.PS2CD or MediaType.MEGACD or MediaType.SATURNCD or MediaType.GDROM
|
||||
or MediaType.GDR
|
||||
or MediaType.MilCD or MediaType.SuperCDROM2 or MediaType.JaguarCD or MediaType.ThreeDO
|
||||
or MediaType.PCFX
|
||||
or MediaType.NeoGeoCD or MediaType.CDTV or MediaType.CD32 or MediaType.Playdia
|
||||
or MediaType.Pippin
|
||||
or MediaType.VideoNow or MediaType.VideoNowColor or MediaType.VideoNowXp
|
||||
or MediaType.CVD)
|
||||
return ErrorNumber.NoError;
|
||||
|
||||
{
|
||||
@@ -1606,7 +1629,7 @@ public sealed partial class AaruFormat
|
||||
return ErrorNumber.OutOfRange;
|
||||
|
||||
ulong ddtEntry = GetDdtEntry(sectorAddress);
|
||||
uint offsetMask = (uint)((1 << _shift) - 1);
|
||||
var offsetMask = (uint)((1 << _shift) - 1);
|
||||
ulong offset = ddtEntry & offsetMask;
|
||||
ulong blockOffset = ddtEntry >> _shift;
|
||||
|
||||
@@ -1651,9 +1674,9 @@ public sealed partial class AaruFormat
|
||||
|
||||
break;
|
||||
case CompressionType.Lzma:
|
||||
byte[] compressedBlock = new byte[blockHeader.cmpLength - LZMA_PROPERTIES_LENGTH];
|
||||
byte[] lzmaProperties = new byte[LZMA_PROPERTIES_LENGTH];
|
||||
_imageStream.EnsureRead(lzmaProperties, 0, LZMA_PROPERTIES_LENGTH);
|
||||
var compressedBlock = new byte[blockHeader.cmpLength - LZMA_PROPERTIES_LENGTH];
|
||||
var lzmaProperties = new byte[LZMA_PROPERTIES_LENGTH];
|
||||
_imageStream.EnsureRead(lzmaProperties, 0, LZMA_PROPERTIES_LENGTH);
|
||||
_imageStream.EnsureRead(compressedBlock, 0, compressedBlock.Length);
|
||||
block = new byte[blockHeader.length];
|
||||
decompressedLength = (ulong)LZMA.DecodeBuffer(compressedBlock, block, lzmaProperties);
|
||||
@@ -1672,7 +1695,7 @@ public sealed partial class AaruFormat
|
||||
|
||||
break;
|
||||
case CompressionType.Flac:
|
||||
byte[] flacBlock = new byte[blockHeader.cmpLength];
|
||||
var flacBlock = new byte[blockHeader.cmpLength];
|
||||
_imageStream.EnsureRead(flacBlock, 0, flacBlock.Length);
|
||||
block = new byte[blockHeader.length];
|
||||
decompressedLength = (ulong)FLAC.DecodeBuffer(flacBlock, block);
|
||||
@@ -1690,7 +1713,8 @@ public sealed partial class AaruFormat
|
||||
GC.GetTotalMemory(false));
|
||||
|
||||
break;
|
||||
default: return ErrorNumber.NotSupported;
|
||||
default:
|
||||
return ErrorNumber.NotSupported;
|
||||
}
|
||||
|
||||
// Check if cache needs to be emptied
|
||||
@@ -1729,7 +1753,8 @@ public sealed partial class AaruFormat
|
||||
|
||||
Track trk = Tracks.FirstOrDefault(t => t.Sequence == track);
|
||||
|
||||
return trk?.Sequence != track ? ErrorNumber.SectorNotFound
|
||||
return trk?.Sequence != track
|
||||
? ErrorNumber.SectorNotFound
|
||||
: ReadSector(trk.StartSector + sectorAddress, out buffer);
|
||||
}
|
||||
|
||||
@@ -1743,7 +1768,8 @@ public sealed partial class AaruFormat
|
||||
|
||||
Track trk = Tracks.FirstOrDefault(t => t.Sequence == track);
|
||||
|
||||
return trk?.Sequence != track ? ErrorNumber.SectorNotFound
|
||||
return trk?.Sequence != track
|
||||
? ErrorNumber.SectorNotFound
|
||||
: ReadSectorTag(trk.StartSector + sectorAddress, tag, out buffer);
|
||||
}
|
||||
|
||||
@@ -1812,15 +1838,13 @@ public sealed partial class AaruFormat
|
||||
case SectorTagType.DvdSectorNumber:
|
||||
case SectorTagType.DvdSectorIed:
|
||||
case SectorTagType.DvdSectorEdc:
|
||||
case SectorTagType.DvdTitleKeyDecrypted: break;
|
||||
case SectorTagType.DvdTitleKeyDecrypted:
|
||||
break;
|
||||
case SectorTagType.CdTrackFlags:
|
||||
if(!_trackFlags.TryGetValue((byte)sectorAddress, out byte flags))
|
||||
return ErrorNumber.NoData;
|
||||
|
||||
buffer = new[]
|
||||
{
|
||||
flags
|
||||
};
|
||||
buffer = new[] { flags };
|
||||
|
||||
return ErrorNumber.NoError;
|
||||
case SectorTagType.CdTrackIsrc:
|
||||
@@ -1830,7 +1854,8 @@ public sealed partial class AaruFormat
|
||||
buffer = Encoding.UTF8.GetBytes(isrc);
|
||||
|
||||
return ErrorNumber.NoError;
|
||||
default: return ErrorNumber.NotSupported;
|
||||
default:
|
||||
return ErrorNumber.NotSupported;
|
||||
}
|
||||
|
||||
switch(trk.Type)
|
||||
@@ -1858,7 +1883,8 @@ public sealed partial class AaruFormat
|
||||
break;
|
||||
}
|
||||
|
||||
case SectorTagType.CdSectorSubHeader: return ErrorNumber.NotSupported;
|
||||
case SectorTagType.CdSectorSubHeader:
|
||||
return ErrorNumber.NotSupported;
|
||||
case SectorTagType.CdSectorEcc:
|
||||
{
|
||||
sectorOffset = 12;
|
||||
@@ -1909,7 +1935,8 @@ public sealed partial class AaruFormat
|
||||
break;
|
||||
}
|
||||
|
||||
default: return ErrorNumber.NotSupported;
|
||||
default:
|
||||
return ErrorNumber.NotSupported;
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -1953,7 +1980,8 @@ public sealed partial class AaruFormat
|
||||
case SectorTagType.CdSectorEcc:
|
||||
case SectorTagType.CdSectorEccP:
|
||||
case SectorTagType.CdSectorEccQ:
|
||||
case SectorTagType.CdSectorEdc: return ErrorNumber.NotSupported;
|
||||
case SectorTagType.CdSectorEdc:
|
||||
return ErrorNumber.NotSupported;
|
||||
case SectorTagType.CdSectorSubchannel:
|
||||
{
|
||||
sectorOffset = 0;
|
||||
@@ -1964,7 +1992,8 @@ public sealed partial class AaruFormat
|
||||
break;
|
||||
}
|
||||
|
||||
default: return ErrorNumber.NotSupported;
|
||||
default:
|
||||
return ErrorNumber.NotSupported;
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -1984,7 +2013,8 @@ public sealed partial class AaruFormat
|
||||
break;
|
||||
}
|
||||
|
||||
default: return ErrorNumber.NotSupported;
|
||||
default:
|
||||
return ErrorNumber.NotSupported;
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -1993,6 +2023,7 @@ public sealed partial class AaruFormat
|
||||
case TrackType.Data:
|
||||
{
|
||||
if(_imageInfo.MediaType == MediaType.DVDROM)
|
||||
{
|
||||
switch(tag)
|
||||
{
|
||||
case SectorTagType.DvdSectorCmi:
|
||||
@@ -2058,15 +2089,18 @@ public sealed partial class AaruFormat
|
||||
|
||||
break;
|
||||
}
|
||||
default: return ErrorNumber.NotSupported;
|
||||
default:
|
||||
return ErrorNumber.NotSupported;
|
||||
}
|
||||
}
|
||||
else
|
||||
return ErrorNumber.NotSupported;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default: return ErrorNumber.NotSupported;
|
||||
default:
|
||||
return ErrorNumber.NotSupported;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -2085,9 +2119,11 @@ public sealed partial class AaruFormat
|
||||
return ErrorNumber.NoError;
|
||||
}
|
||||
|
||||
for(int i = 0; i < length; i++)
|
||||
Array.Copy(dataSource, (long)((sectorAddress * (sectorOffset + sectorSize + sectorSkip)) + sectorOffset),
|
||||
for(var i = 0; i < length; i++)
|
||||
{
|
||||
Array.Copy(dataSource, (long)(sectorAddress * (sectorOffset + sectorSize + sectorSkip) + sectorOffset),
|
||||
buffer, i * sectorSize, sectorSize);
|
||||
}
|
||||
|
||||
return ErrorNumber.NoError;
|
||||
}
|
||||
@@ -2105,12 +2141,13 @@ public sealed partial class AaruFormat
|
||||
if(trk?.Sequence != track)
|
||||
return ErrorNumber.SectorNotFound;
|
||||
|
||||
return trk.StartSector + sectorAddress + length > trk.EndSector + 1 ? ErrorNumber.OutOfRange
|
||||
return trk.StartSector + sectorAddress + length > trk.EndSector + 1
|
||||
? ErrorNumber.OutOfRange
|
||||
: ReadSectors(trk.StartSector + sectorAddress, length, out buffer);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ErrorNumber ReadSectorsTag(ulong sectorAddress, uint length, uint track, SectorTagType tag,
|
||||
public ErrorNumber ReadSectorsTag(ulong sectorAddress, uint length, uint track, SectorTagType tag,
|
||||
out byte[] buffer)
|
||||
{
|
||||
buffer = null;
|
||||
@@ -2306,7 +2343,7 @@ public sealed partial class AaruFormat
|
||||
else if(_mode2Subheaders != null)
|
||||
{
|
||||
Array.Copy(_mode2Subheaders, (int)sectorAddress * 8, buffer, 16, 8);
|
||||
Array.Copy(data, 0, buffer, 24, 2328);
|
||||
Array.Copy(data, 0, buffer, 24, 2328);
|
||||
}
|
||||
else
|
||||
Array.Copy(data, 0, buffer, 16, 2336);
|
||||
@@ -2323,7 +2360,8 @@ public sealed partial class AaruFormat
|
||||
case MediaType.AppleSonySS:
|
||||
case MediaType.AppleSonyDS:
|
||||
case MediaType.AppleWidget:
|
||||
case MediaType.PriamDataTower: return ReadSectorsLong(sectorAddress, 1, out buffer);
|
||||
case MediaType.PriamDataTower:
|
||||
return ReadSectorsLong(sectorAddress, 1, out buffer);
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -2342,7 +2380,8 @@ public sealed partial class AaruFormat
|
||||
|
||||
Track trk = Tracks.FirstOrDefault(t => t.Sequence == track);
|
||||
|
||||
return trk?.Sequence != track ? ErrorNumber.SectorNotFound
|
||||
return trk?.Sequence != track
|
||||
? ErrorNumber.SectorNotFound
|
||||
: ReadSectorLong(trk.StartSector + sectorAddress, out buffer);
|
||||
}
|
||||
|
||||
@@ -2373,7 +2412,8 @@ public sealed partial class AaruFormat
|
||||
{
|
||||
// These types only contain user data
|
||||
case TrackType.Audio:
|
||||
case TrackType.Data: return ReadSectors(sectorAddress, length, out buffer);
|
||||
case TrackType.Data:
|
||||
return ReadSectors(sectorAddress, length, out buffer);
|
||||
|
||||
// Join prefix (sync, header) with user data with suffix (edc, ecc p, ecc q)
|
||||
case TrackType.CdMode1:
|
||||
@@ -2505,7 +2545,7 @@ public sealed partial class AaruFormat
|
||||
for(uint i = 0; i < length; i++)
|
||||
{
|
||||
Array.Copy(_sectorSubchannel, (int)((sectorAddress + i) * tagSize), buffer,
|
||||
(int)((i * sectorSize) + 512), tagSize);
|
||||
(int)(i * sectorSize + 512), tagSize);
|
||||
|
||||
Array.Copy(data, (int)((sectorAddress + i) * 512), buffer, (int)(i * 512), 512);
|
||||
}
|
||||
@@ -2541,4 +2581,6 @@ public sealed partial class AaruFormat
|
||||
|
||||
/// <inheritdoc />
|
||||
public List<Track> GetSessionTracks(ushort session) => Tracks.Where(t => t.Sequence == session).ToList();
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -38,6 +38,8 @@ namespace Aaru.DiscImages;
|
||||
|
||||
public sealed partial class AaruFormat
|
||||
{
|
||||
#region Nested type: AaruHeader
|
||||
|
||||
/// <summary>Header, at start of file</summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Unicode)]
|
||||
struct AaruHeader
|
||||
@@ -65,6 +67,131 @@ public sealed partial class AaruFormat
|
||||
public long lastWrittenTime;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Nested type: AaruMetadataJsonBlock
|
||||
|
||||
/// <summary>Aaru Metadata JSON block</summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct AaruMetadataJsonBlock
|
||||
{
|
||||
/// <summary>Identifier, <see cref="BlockType.AaruMetadataJsonBlock" /></summary>
|
||||
public BlockType identifier;
|
||||
public uint length;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Nested type: BlockHeader
|
||||
|
||||
/// <summary>Block header, precedes block data</summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct BlockHeader
|
||||
{
|
||||
/// <summary>Identifier, <see cref="BlockType.DataBlock" /></summary>
|
||||
public BlockType identifier;
|
||||
/// <summary>Type of data contained by this block</summary>
|
||||
public DataType type;
|
||||
/// <summary>Compression algorithm used to compress the block</summary>
|
||||
public CompressionType compression;
|
||||
/// <summary>Size in bytes of each sector contained in this block</summary>
|
||||
public uint sectorSize;
|
||||
/// <summary>Compressed length for the block</summary>
|
||||
public uint cmpLength;
|
||||
/// <summary>Uncompressed length for the block</summary>
|
||||
public uint length;
|
||||
/// <summary>CRC64-ECMA of the compressed block</summary>
|
||||
public ulong cmpCrc64;
|
||||
/// <summary>CRC64-ECMA of the uncompressed block</summary>
|
||||
public ulong crc64;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Nested type: ChecksumEntry
|
||||
|
||||
/// <summary>Checksum entry, followed by checksum data itself</summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct ChecksumEntry
|
||||
{
|
||||
/// <summary>Checksum algorithm</summary>
|
||||
public ChecksumAlgorithm type;
|
||||
/// <summary>Length in bytes of checksum that follows this structure</summary>
|
||||
public uint length;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Nested type: ChecksumHeader
|
||||
|
||||
/// <summary>
|
||||
/// Checksum block, contains a checksum of all user data sectors (except for optical discs that is 2352 bytes raw
|
||||
/// sector if available
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct ChecksumHeader
|
||||
{
|
||||
/// <summary>Identifier, <see cref="BlockType.ChecksumBlock" /></summary>
|
||||
public BlockType identifier;
|
||||
/// <summary>Length in bytes of the block</summary>
|
||||
public uint length;
|
||||
/// <summary>How many checksums follow</summary>
|
||||
public byte entries;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Nested type: CicmMetadataBlock
|
||||
|
||||
/// <summary>CICM Metadata XML block</summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct CicmMetadataBlock
|
||||
{
|
||||
/// <summary>Identifier, <see cref="BlockType.CicmBlock" /></summary>
|
||||
public readonly BlockType identifier;
|
||||
public readonly uint length;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Nested type: CompactDiscIndexEntry
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct CompactDiscIndexEntry
|
||||
{
|
||||
/// <summary>How many entries follow this header</summary>
|
||||
public ushort Track;
|
||||
/// <summary>Size of the whole block, not including this header, in bytes</summary>
|
||||
public ushort Index;
|
||||
/// <summary>CRC64-ECMA of the block</summary>
|
||||
public int Lba;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Nested type: CompactDiscIndexesHeader
|
||||
|
||||
/// <summary>
|
||||
/// Compact Disc track indexes block, contains a cache of all Compact Disc indexes to not need to interpret
|
||||
/// subchannel
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct CompactDiscIndexesHeader
|
||||
{
|
||||
/// <summary>Identifier, <see cref="BlockType.CompactDiscIndexesBlock" /></summary>
|
||||
public BlockType identifier;
|
||||
/// <summary>How many entries follow this header</summary>
|
||||
public ushort entries;
|
||||
/// <summary>Size of the whole block, not including this header, in bytes</summary>
|
||||
public readonly ulong length;
|
||||
/// <summary>CRC64-ECMA of the block</summary>
|
||||
public ulong crc64;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Nested type: DdtHeader
|
||||
|
||||
/// <summary>Header for a deduplication table. Table follows it</summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct DdtHeader
|
||||
@@ -89,30 +216,71 @@ public sealed partial class AaruFormat
|
||||
public readonly ulong crc64;
|
||||
}
|
||||
|
||||
/// <summary>Header for the index, followed by entries</summary>
|
||||
#endregion
|
||||
|
||||
#region Nested type: DumpHardwareEntry
|
||||
|
||||
/// <summary>Dump hardware entry, contains length of strings that follow, in the same order as the length, this structure</summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct IndexHeader
|
||||
struct DumpHardwareEntry
|
||||
{
|
||||
/// <summary>Identifier, <see cref="BlockType.Index" /></summary>
|
||||
/// <summary>Length of UTF-8 manufacturer string</summary>
|
||||
public uint manufacturerLength;
|
||||
/// <summary>Length of UTF-8 model string</summary>
|
||||
public uint modelLength;
|
||||
/// <summary>Length of UTF-8 revision string</summary>
|
||||
public uint revisionLength;
|
||||
/// <summary>Length of UTF-8 firmware version string</summary>
|
||||
public uint firmwareLength;
|
||||
/// <summary>Length of UTF-8 serial string</summary>
|
||||
public uint serialLength;
|
||||
/// <summary>Length of UTF-8 software name string</summary>
|
||||
public uint softwareNameLength;
|
||||
/// <summary>Length of UTF-8 software version string</summary>
|
||||
public uint softwareVersionLength;
|
||||
/// <summary>Length of UTF-8 software operating system string</summary>
|
||||
public uint softwareOperatingSystemLength;
|
||||
/// <summary>How many extents are after the strings</summary>
|
||||
public uint extents;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Nested type: DumpHardwareHeader
|
||||
|
||||
/// <summary>Dump hardware block, contains a list of hardware used to dump the media on this image</summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct DumpHardwareHeader
|
||||
{
|
||||
/// <summary>Identifier, <see cref="BlockType.DumpHardwareBlock" /></summary>
|
||||
public BlockType identifier;
|
||||
/// <summary>How many entries follow this header</summary>
|
||||
public ushort entries;
|
||||
/// <summary>CRC64-ECMA of the index</summary>
|
||||
/// <summary>Size of the whole block, not including this header, in bytes</summary>
|
||||
public uint length;
|
||||
/// <summary>CRC64-ECMA of the block</summary>
|
||||
public ulong crc64;
|
||||
}
|
||||
|
||||
/// <summary>Header for the index, followed by entries</summary>
|
||||
#endregion
|
||||
|
||||
#region Nested type: GeometryBlock
|
||||
|
||||
/// <summary>Geometry block, contains physical geometry information</summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct IndexHeader2
|
||||
struct GeometryBlock
|
||||
{
|
||||
/// <summary>Identifier, <see cref="BlockType.Index2" /></summary>
|
||||
/// <summary>Identifier, <see cref="BlockType.GeometryBlock" /></summary>
|
||||
public BlockType identifier;
|
||||
/// <summary>How many entries follow this header</summary>
|
||||
public ulong entries;
|
||||
/// <summary>CRC64-ECMA of the index</summary>
|
||||
public ulong crc64;
|
||||
public uint cylinders;
|
||||
public uint heads;
|
||||
public uint sectorsPerTrack;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Nested type: IndexEntry
|
||||
|
||||
/// <summary>Index entry</summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct IndexEntry
|
||||
@@ -125,39 +293,42 @@ public sealed partial class AaruFormat
|
||||
public ulong offset;
|
||||
}
|
||||
|
||||
/// <summary>Block header, precedes block data</summary>
|
||||
#endregion
|
||||
|
||||
#region Nested type: IndexHeader
|
||||
|
||||
/// <summary>Header for the index, followed by entries</summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct BlockHeader
|
||||
struct IndexHeader
|
||||
{
|
||||
/// <summary>Identifier, <see cref="BlockType.DataBlock" /></summary>
|
||||
/// <summary>Identifier, <see cref="BlockType.Index" /></summary>
|
||||
public BlockType identifier;
|
||||
/// <summary>Type of data contained by this block</summary>
|
||||
public DataType type;
|
||||
/// <summary>Compression algorithm used to compress the block</summary>
|
||||
public CompressionType compression;
|
||||
/// <summary>Size in bytes of each sector contained in this block</summary>
|
||||
public uint sectorSize;
|
||||
/// <summary>Compressed length for the block</summary>
|
||||
public uint cmpLength;
|
||||
/// <summary>Uncompressed length for the block</summary>
|
||||
public uint length;
|
||||
/// <summary>CRC64-ECMA of the compressed block</summary>
|
||||
public ulong cmpCrc64;
|
||||
/// <summary>CRC64-ECMA of the uncompressed block</summary>
|
||||
/// <summary>How many entries follow this header</summary>
|
||||
public ushort entries;
|
||||
/// <summary>CRC64-ECMA of the index</summary>
|
||||
public ulong crc64;
|
||||
}
|
||||
|
||||
/// <summary>Geometry block, contains physical geometry information</summary>
|
||||
#endregion
|
||||
|
||||
#region Nested type: IndexHeader2
|
||||
|
||||
/// <summary>Header for the index, followed by entries</summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct GeometryBlock
|
||||
struct IndexHeader2
|
||||
{
|
||||
/// <summary>Identifier, <see cref="BlockType.GeometryBlock" /></summary>
|
||||
/// <summary>Identifier, <see cref="BlockType.Index2" /></summary>
|
||||
public BlockType identifier;
|
||||
public uint cylinders;
|
||||
public uint heads;
|
||||
public uint sectorsPerTrack;
|
||||
/// <summary>How many entries follow this header</summary>
|
||||
public ulong entries;
|
||||
/// <summary>CRC64-ECMA of the index</summary>
|
||||
public ulong crc64;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Nested type: MetadataBlock
|
||||
|
||||
/// <summary>Metadata block, contains metadata</summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct MetadataBlock
|
||||
@@ -220,18 +391,80 @@ public sealed partial class AaruFormat
|
||||
public uint driveFirmwareRevisionLength;
|
||||
}
|
||||
|
||||
/// <summary>Contains list of optical disc tracks</summary>
|
||||
#endregion
|
||||
|
||||
#region Nested type: TapeFileEntry
|
||||
|
||||
/// <summary>Tape file entry</summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct TracksHeader
|
||||
struct TapeFileEntry
|
||||
{
|
||||
/// <summary>Identifier, <see cref="BlockType.TracksBlock" /></summary>
|
||||
/// <summary>File number</summary>
|
||||
public uint File;
|
||||
/// <summary>Partition number</summary>
|
||||
public readonly byte Partition;
|
||||
/// <summary>First block, inclusive, of the file</summary>
|
||||
public ulong FirstBlock;
|
||||
/// <summary>Last block, inclusive, of the file</summary>
|
||||
public ulong LastBlock;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Nested type: TapeFileHeader
|
||||
|
||||
/// <summary>Tape file block, contains a list of all files in a tape</summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct TapeFileHeader
|
||||
{
|
||||
/// <summary>Identifier, <see cref="BlockType.TapeFileBlock" /></summary>
|
||||
public BlockType identifier;
|
||||
/// <summary>How many entries follow this header</summary>
|
||||
public ushort entries;
|
||||
public uint entries;
|
||||
/// <summary>Size of the whole block, not including this header, in bytes</summary>
|
||||
public ulong length;
|
||||
/// <summary>CRC64-ECMA of the block</summary>
|
||||
public ulong crc64;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Nested type: TapePartitionEntry
|
||||
|
||||
/// <summary>Tape partition entry</summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct TapePartitionEntry
|
||||
{
|
||||
/// <summary>Partition number</summary>
|
||||
public byte Number;
|
||||
/// <summary>First block, inclusive, of the partition</summary>
|
||||
public ulong FirstBlock;
|
||||
/// <summary>Last block, inclusive, of the partition</summary>
|
||||
public ulong LastBlock;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Nested type: TapePartitionHeader
|
||||
|
||||
/// <summary>Tape partition block, contains a list of all partitions in a tape</summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct TapePartitionHeader
|
||||
{
|
||||
/// <summary>Identifier, <see cref="BlockType.TapePartitionBlock" /></summary>
|
||||
public BlockType identifier;
|
||||
/// <summary>How many entries follow this header</summary>
|
||||
public byte entries;
|
||||
/// <summary>Size of the whole block, not including this header, in bytes</summary>
|
||||
public ulong length;
|
||||
/// <summary>CRC64-ECMA of the block</summary>
|
||||
public ulong crc64;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Nested type: TrackEntry
|
||||
|
||||
/// <summary>Optical disc track</summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
|
||||
struct TrackEntry
|
||||
@@ -255,166 +488,21 @@ public sealed partial class AaruFormat
|
||||
public byte flags;
|
||||
}
|
||||
|
||||
/// <summary>CICM Metadata XML block</summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct CicmMetadataBlock
|
||||
{
|
||||
/// <summary>Identifier, <see cref="BlockType.CicmBlock" /></summary>
|
||||
public readonly BlockType identifier;
|
||||
public readonly uint length;
|
||||
}
|
||||
#endregion
|
||||
|
||||
/// <summary>Aaru Metadata JSON block</summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct AaruMetadataJsonBlock
|
||||
{
|
||||
/// <summary>Identifier, <see cref="BlockType.AaruMetadataJsonBlock" /></summary>
|
||||
public BlockType identifier;
|
||||
public uint length;
|
||||
}
|
||||
#region Nested type: TracksHeader
|
||||
|
||||
/// <summary>Dump hardware block, contains a list of hardware used to dump the media on this image</summary>
|
||||
/// <summary>Contains list of optical disc tracks</summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct DumpHardwareHeader
|
||||
struct TracksHeader
|
||||
{
|
||||
/// <summary>Identifier, <see cref="BlockType.DumpHardwareBlock" /></summary>
|
||||
/// <summary>Identifier, <see cref="BlockType.TracksBlock" /></summary>
|
||||
public BlockType identifier;
|
||||
/// <summary>How many entries follow this header</summary>
|
||||
public ushort entries;
|
||||
/// <summary>Size of the whole block, not including this header, in bytes</summary>
|
||||
public uint length;
|
||||
/// <summary>CRC64-ECMA of the block</summary>
|
||||
public ulong crc64;
|
||||
}
|
||||
|
||||
/// <summary>Dump hardware entry, contains length of strings that follow, in the same order as the length, this structure</summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct DumpHardwareEntry
|
||||
{
|
||||
/// <summary>Length of UTF-8 manufacturer string</summary>
|
||||
public uint manufacturerLength;
|
||||
/// <summary>Length of UTF-8 model string</summary>
|
||||
public uint modelLength;
|
||||
/// <summary>Length of UTF-8 revision string</summary>
|
||||
public uint revisionLength;
|
||||
/// <summary>Length of UTF-8 firmware version string</summary>
|
||||
public uint firmwareLength;
|
||||
/// <summary>Length of UTF-8 serial string</summary>
|
||||
public uint serialLength;
|
||||
/// <summary>Length of UTF-8 software name string</summary>
|
||||
public uint softwareNameLength;
|
||||
/// <summary>Length of UTF-8 software version string</summary>
|
||||
public uint softwareVersionLength;
|
||||
/// <summary>Length of UTF-8 software operating system string</summary>
|
||||
public uint softwareOperatingSystemLength;
|
||||
/// <summary>How many extents are after the strings</summary>
|
||||
public uint extents;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checksum block, contains a checksum of all user data sectors (except for optical discs that is 2352 bytes raw
|
||||
/// sector if available
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct ChecksumHeader
|
||||
{
|
||||
/// <summary>Identifier, <see cref="BlockType.ChecksumBlock" /></summary>
|
||||
public BlockType identifier;
|
||||
/// <summary>Length in bytes of the block</summary>
|
||||
public uint length;
|
||||
/// <summary>How many checksums follow</summary>
|
||||
public byte entries;
|
||||
}
|
||||
|
||||
/// <summary>Checksum entry, followed by checksum data itself</summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct ChecksumEntry
|
||||
{
|
||||
/// <summary>Checksum algorithm</summary>
|
||||
public ChecksumAlgorithm type;
|
||||
/// <summary>Length in bytes of checksum that follows this structure</summary>
|
||||
public uint length;
|
||||
}
|
||||
|
||||
/// <summary>Tape file block, contains a list of all files in a tape</summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct TapeFileHeader
|
||||
{
|
||||
/// <summary>Identifier, <see cref="BlockType.TapeFileBlock" /></summary>
|
||||
public BlockType identifier;
|
||||
/// <summary>How many entries follow this header</summary>
|
||||
public uint entries;
|
||||
/// <summary>Size of the whole block, not including this header, in bytes</summary>
|
||||
public ulong length;
|
||||
/// <summary>CRC64-ECMA of the block</summary>
|
||||
public ulong crc64;
|
||||
}
|
||||
|
||||
/// <summary>Tape file entry</summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct TapeFileEntry
|
||||
{
|
||||
/// <summary>File number</summary>
|
||||
public uint File;
|
||||
/// <summary>Partition number</summary>
|
||||
public readonly byte Partition;
|
||||
/// <summary>First block, inclusive, of the file</summary>
|
||||
public ulong FirstBlock;
|
||||
/// <summary>Last block, inclusive, of the file</summary>
|
||||
public ulong LastBlock;
|
||||
}
|
||||
|
||||
/// <summary>Tape partition block, contains a list of all partitions in a tape</summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct TapePartitionHeader
|
||||
{
|
||||
/// <summary>Identifier, <see cref="BlockType.TapePartitionBlock" /></summary>
|
||||
public BlockType identifier;
|
||||
/// <summary>How many entries follow this header</summary>
|
||||
public byte entries;
|
||||
/// <summary>Size of the whole block, not including this header, in bytes</summary>
|
||||
public ulong length;
|
||||
/// <summary>CRC64-ECMA of the block</summary>
|
||||
public ulong crc64;
|
||||
}
|
||||
|
||||
/// <summary>Tape partition entry</summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct TapePartitionEntry
|
||||
{
|
||||
/// <summary>Partition number</summary>
|
||||
public byte Number;
|
||||
/// <summary>First block, inclusive, of the partition</summary>
|
||||
public ulong FirstBlock;
|
||||
/// <summary>Last block, inclusive, of the partition</summary>
|
||||
public ulong LastBlock;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compact Disc track indexes block, contains a cache of all Compact Disc indexes to not need to interpret
|
||||
/// subchannel
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct CompactDiscIndexesHeader
|
||||
{
|
||||
/// <summary>Identifier, <see cref="BlockType.CompactDiscIndexesBlock" /></summary>
|
||||
public BlockType identifier;
|
||||
/// <summary>How many entries follow this header</summary>
|
||||
public ushort entries;
|
||||
/// <summary>Size of the whole block, not including this header, in bytes</summary>
|
||||
public readonly ulong length;
|
||||
/// <summary>CRC64-ECMA of the block</summary>
|
||||
public ulong crc64;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct CompactDiscIndexEntry
|
||||
{
|
||||
/// <summary>How many entries follow this header</summary>
|
||||
public ushort Track;
|
||||
/// <summary>Size of the whole block, not including this header, in bytes</summary>
|
||||
public ushort Index;
|
||||
/// <summary>CRC64-ECMA of the block</summary>
|
||||
public int Lba;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
@@ -38,10 +38,14 @@ namespace Aaru.DiscImages;
|
||||
|
||||
public sealed partial class AaruFormat
|
||||
{
|
||||
#region IWritableTapeImage Members
|
||||
|
||||
/// <inheritdoc />
|
||||
public List<TapeFile> Files { get; private set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public List<TapePartition> TapePartitions { get; private set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsTape { get; private set; }
|
||||
|
||||
@@ -81,4 +85,6 @@ public sealed partial class AaruFormat
|
||||
|
||||
return IsTape = true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -41,6 +41,8 @@ namespace Aaru.DiscImages;
|
||||
|
||||
public sealed partial class AaruFormat
|
||||
{
|
||||
#region IVerifiableImage Members
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool? VerifyMediaImage()
|
||||
{
|
||||
@@ -209,6 +211,10 @@ public sealed partial class AaruFormat
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IWritableOpticalImage Members
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool? VerifySector(ulong sectorAddress)
|
||||
{
|
||||
@@ -221,7 +227,7 @@ public sealed partial class AaruFormat
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool? VerifySectors(ulong sectorAddress, uint length, out List<ulong> failingLbas,
|
||||
public bool? VerifySectors(ulong sectorAddress, uint length, out List<ulong> failingLbas,
|
||||
out List<ulong> unknownLbas)
|
||||
{
|
||||
failingLbas = new List<ulong>();
|
||||
@@ -241,12 +247,12 @@ public sealed partial class AaruFormat
|
||||
if(errno != ErrorNumber.NoError)
|
||||
return null;
|
||||
|
||||
int bps = (int)(buffer.Length / length);
|
||||
byte[] sector = new byte[bps];
|
||||
var bps = (int)(buffer.Length / length);
|
||||
var sector = new byte[bps];
|
||||
failingLbas = new List<ulong>();
|
||||
unknownLbas = new List<ulong>();
|
||||
|
||||
for(int i = 0; i < length; i++)
|
||||
for(var i = 0; i < length; i++)
|
||||
{
|
||||
Array.Copy(buffer, i * bps, sector, 0, bps);
|
||||
bool? sectorStatus = CdChecksums.CheckCdSector(sector);
|
||||
@@ -271,7 +277,7 @@ public sealed partial class AaruFormat
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool? VerifySectors(ulong sectorAddress, uint length, uint track, out List<ulong> failingLbas,
|
||||
public bool? VerifySectors(ulong sectorAddress, uint length, uint track, out List<ulong> failingLbas,
|
||||
out List<ulong> unknownLbas)
|
||||
{
|
||||
// Right now only CompactDisc sectors are verifiable
|
||||
@@ -294,10 +300,10 @@ public sealed partial class AaruFormat
|
||||
if(errno != ErrorNumber.NoError)
|
||||
return null;
|
||||
|
||||
int bps = (int)(buffer.Length / length);
|
||||
byte[] sector = new byte[bps];
|
||||
var bps = (int)(buffer.Length / length);
|
||||
var sector = new byte[bps];
|
||||
|
||||
for(int i = 0; i < length; i++)
|
||||
for(var i = 0; i < length; i++)
|
||||
{
|
||||
Array.Copy(buffer, i * bps, sector, 0, bps);
|
||||
bool? sectorStatus = CdChecksums.CheckCdSector(sector);
|
||||
@@ -320,4 +326,6 @@ public sealed partial class AaruFormat
|
||||
|
||||
return failingLbas.Count <= 0;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -42,6 +42,7 @@ namespace Aaru.DiscImages;
|
||||
/// <summary>Implements reading and writing Alcohol 120% disk images</summary>
|
||||
public sealed partial class Alcohol120 : IWritableOpticalImage
|
||||
{
|
||||
const string MODULE_NAME = "Alcohol 120% plugin";
|
||||
Footer _alcFooter;
|
||||
IFilter _alcImage;
|
||||
Dictionary<int, Session> _alcSessions;
|
||||
@@ -84,6 +85,4 @@ public sealed partial class Alcohol120 : IWritableOpticalImage
|
||||
DriveSerialNumber = null,
|
||||
DriveFirmwareRevision = null
|
||||
};
|
||||
|
||||
const string MODULE_NAME = "Alcohol 120% plugin";
|
||||
}
|
||||
@@ -36,24 +36,47 @@ namespace Aaru.DiscImages;
|
||||
|
||||
public sealed partial class Alcohol120
|
||||
{
|
||||
#region Nested type: MediumType
|
||||
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
enum MediumType : ushort
|
||||
{
|
||||
CD = 0x00, CDR = 0x01, CDRW = 0x02,
|
||||
DVD = 0x10, DVDR = 0x12
|
||||
CD = 0x00,
|
||||
CDR = 0x01,
|
||||
CDRW = 0x02,
|
||||
DVD = 0x10,
|
||||
DVDR = 0x12
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Nested type: SubchannelMode
|
||||
|
||||
enum SubchannelMode : byte
|
||||
{
|
||||
None = 0x00,
|
||||
Interleaved = 0x08
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Nested type: TrackMode
|
||||
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
enum TrackMode : byte
|
||||
{
|
||||
NoData = 0x00, DVD = 0x02, Audio = 0xA9,
|
||||
AudioAlt = 0xE9, Mode1 = 0xAA, Mode1Alt = 0xEA,
|
||||
Mode2 = 0xAB, Mode2F1 = 0xEC, Mode2F2 = 0xED,
|
||||
Mode2F1Alt = 0xAC, Mode2F2Alt = 0xAD
|
||||
NoData = 0x00,
|
||||
DVD = 0x02,
|
||||
Audio = 0xA9,
|
||||
AudioAlt = 0xE9,
|
||||
Mode1 = 0xAA,
|
||||
Mode1Alt = 0xEA,
|
||||
Mode2 = 0xAB,
|
||||
Mode2F1 = 0xEC,
|
||||
Mode2F2 = 0xED,
|
||||
Mode2F1Alt = 0xAC,
|
||||
Mode2F2Alt = 0xAD
|
||||
}
|
||||
|
||||
enum SubchannelMode : byte
|
||||
{
|
||||
None = 0x00, Interleaved = 0x08
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
@@ -44,14 +44,20 @@ public sealed partial class Alcohol120
|
||||
case TrackMode.Mode1:
|
||||
case TrackMode.Mode1Alt:
|
||||
case TrackMode.Mode2F1:
|
||||
case TrackMode.Mode2F1Alt: return 2048;
|
||||
case TrackMode.Mode2F1Alt:
|
||||
return 2048;
|
||||
case TrackMode.Mode2F2:
|
||||
case TrackMode.Mode2F2Alt: return 2324;
|
||||
case TrackMode.Mode2: return 2336;
|
||||
case TrackMode.Mode2F2Alt:
|
||||
return 2324;
|
||||
case TrackMode.Mode2:
|
||||
return 2336;
|
||||
case TrackMode.Audio:
|
||||
case TrackMode.AudioAlt: return 2352;
|
||||
case TrackMode.DVD: return 2048;
|
||||
default: return 0;
|
||||
case TrackMode.AudioAlt:
|
||||
return 2352;
|
||||
case TrackMode.DVD:
|
||||
return 2048;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,27 +66,33 @@ public sealed partial class Alcohol120
|
||||
switch(trackType)
|
||||
{
|
||||
case TrackMode.Mode1:
|
||||
case TrackMode.Mode1Alt: return TrackType.CdMode1;
|
||||
case TrackMode.Mode1Alt:
|
||||
return TrackType.CdMode1;
|
||||
case TrackMode.Mode2F1:
|
||||
case TrackMode.Mode2F1Alt: return TrackType.CdMode2Form1;
|
||||
case TrackMode.Mode2F1Alt:
|
||||
return TrackType.CdMode2Form1;
|
||||
case TrackMode.Mode2F2:
|
||||
case TrackMode.Mode2F2Alt: return TrackType.CdMode2Form2;
|
||||
case TrackMode.Mode2: return TrackType.CdMode2Formless;
|
||||
case TrackMode.Mode2F2Alt:
|
||||
return TrackType.CdMode2Form2;
|
||||
case TrackMode.Mode2:
|
||||
return TrackType.CdMode2Formless;
|
||||
case TrackMode.Audio:
|
||||
case TrackMode.AudioAlt: return TrackType.Audio;
|
||||
default: return TrackType.Data;
|
||||
case TrackMode.AudioAlt:
|
||||
return TrackType.Audio;
|
||||
default:
|
||||
return TrackType.Data;
|
||||
}
|
||||
}
|
||||
|
||||
static MediaType MediumTypeToMediaType(MediumType discType) => discType switch
|
||||
{
|
||||
MediumType.CD => MediaType.CD,
|
||||
MediumType.CDR => MediaType.CDR,
|
||||
MediumType.CDRW => MediaType.CDRW,
|
||||
MediumType.DVD => MediaType.DVDROM,
|
||||
MediumType.DVDR => MediaType.DVDR,
|
||||
_ => MediaType.Unknown
|
||||
};
|
||||
{
|
||||
MediumType.CD => MediaType.CD,
|
||||
MediumType.CDR => MediaType.CDR,
|
||||
MediumType.CDRW => MediaType.CDRW,
|
||||
MediumType.DVD => MediaType.DVDROM,
|
||||
MediumType.DVDR => MediaType.DVDR,
|
||||
_ => MediaType.Unknown
|
||||
};
|
||||
|
||||
static MediumType MediaTypeToMediumType(MediaType type)
|
||||
{
|
||||
@@ -119,30 +131,35 @@ public sealed partial class Alcohol120
|
||||
case MediaType.VideoNow:
|
||||
case MediaType.VideoNowColor:
|
||||
case MediaType.VideoNowXp:
|
||||
case MediaType.CVD: return MediumType.CD;
|
||||
case MediaType.CDR: return MediumType.CDR;
|
||||
case MediaType.CVD:
|
||||
return MediumType.CD;
|
||||
case MediaType.CDR:
|
||||
return MediumType.CDR;
|
||||
case MediaType.CDRW:
|
||||
case MediaType.CDMRW: return MediumType.CDRW;
|
||||
case MediaType.CDMRW:
|
||||
return MediumType.CDRW;
|
||||
case MediaType.DVDR:
|
||||
case MediaType.DVDRW:
|
||||
case MediaType.DVDPR:
|
||||
case MediaType.DVDRDL:
|
||||
case MediaType.DVDRWDL:
|
||||
case MediaType.DVDPRDL:
|
||||
case MediaType.DVDPRWDL: return MediumType.DVDR;
|
||||
default: return MediumType.DVD;
|
||||
case MediaType.DVDPRWDL:
|
||||
return MediumType.DVDR;
|
||||
default:
|
||||
return MediumType.DVD;
|
||||
}
|
||||
}
|
||||
|
||||
static TrackMode TrackTypeToTrackMode(TrackType type) => type switch
|
||||
{
|
||||
TrackType.Audio => TrackMode.Audio,
|
||||
TrackType.CdMode1 => TrackMode.Mode1,
|
||||
TrackType.CdMode2Formless => TrackMode.Mode2,
|
||||
TrackType.CdMode2Form1 => TrackMode.Mode2F1,
|
||||
TrackType.CdMode2Form2 => TrackMode.Mode2F2,
|
||||
_ => TrackMode.DVD
|
||||
};
|
||||
{
|
||||
TrackType.Audio => TrackMode.Audio,
|
||||
TrackType.CdMode1 => TrackMode.Mode1,
|
||||
TrackType.CdMode2Formless => TrackMode.Mode2,
|
||||
TrackType.CdMode2Form1 => TrackMode.Mode2F1,
|
||||
TrackType.CdMode2Form2 => TrackMode.Mode2F2,
|
||||
_ => TrackMode.DVD
|
||||
};
|
||||
|
||||
static (byte minute, byte second, byte frame) LbaToMsf(ulong sector) =>
|
||||
((byte)((sector + 150) / 75 / 60), (byte)((sector + 150) / 75 % 60), (byte)((sector + 150) % 75));
|
||||
|
||||
@@ -39,6 +39,8 @@ namespace Aaru.DiscImages;
|
||||
|
||||
public sealed partial class Alcohol120
|
||||
{
|
||||
#region IWritableOpticalImage Members
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Identify(IFilter imageFilter)
|
||||
{
|
||||
@@ -48,10 +50,12 @@ public sealed partial class Alcohol120
|
||||
if(stream.Length < 88)
|
||||
return false;
|
||||
|
||||
byte[] hdr = new byte[88];
|
||||
var hdr = new byte[88];
|
||||
stream.EnsureRead(hdr, 0, 88);
|
||||
Header header = Marshal.ByteArrayToStructureLittleEndian<Header>(hdr);
|
||||
|
||||
return header.signature.SequenceEqual(_alcoholSignature) && header.version[0] <= MAXIMUM_SUPPORTED_VERSION;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -43,6 +43,8 @@ namespace Aaru.DiscImages;
|
||||
|
||||
public sealed partial class Alcohol120
|
||||
{
|
||||
#region IWritableOpticalImage Members
|
||||
|
||||
/// <inheritdoc />
|
||||
public OpticalImageCapabilities OpticalCapabilities => OpticalImageCapabilities.CanStoreAudioTracks |
|
||||
OpticalImageCapabilities.CanStoreDataTracks |
|
||||
@@ -56,12 +58,16 @@ public sealed partial class Alcohol120
|
||||
OpticalImageCapabilities.CanStoreRawData |
|
||||
OpticalImageCapabilities.CanStoreCookedData |
|
||||
OpticalImageCapabilities.CanStoreMultipleTracks;
|
||||
|
||||
/// <inheritdoc />
|
||||
public ImageInfo Info => _imageInfo;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Name => Localization.Alcohol120_Name;
|
||||
|
||||
/// <inheritdoc />
|
||||
public Guid Id => new("A78FBEBA-0307-4915-BDE3-B8A3B57F843F");
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Author => Authors.NataliaPortillo;
|
||||
|
||||
@@ -153,6 +159,7 @@ public sealed partial class Alcohol120
|
||||
|
||||
/// <inheritdoc />
|
||||
public List<DumpHardware> DumpHardware => null;
|
||||
|
||||
/// <inheritdoc />
|
||||
public Metadata AaruMetadata => null;
|
||||
|
||||
@@ -161,40 +168,46 @@ public sealed partial class Alcohol120
|
||||
{
|
||||
MediaTagType.CD_FullTOC, MediaTagType.DVD_BCA, MediaTagType.DVD_DMI, MediaTagType.DVD_PFI
|
||||
};
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<SectorTagType> SupportedSectorTags => new[]
|
||||
{
|
||||
SectorTagType.CdSectorEcc, SectorTagType.CdSectorEccP, SectorTagType.CdSectorEccQ, SectorTagType.CdSectorEdc,
|
||||
SectorTagType.CdSectorHeader, SectorTagType.CdSectorSubHeader, SectorTagType.CdSectorSync,
|
||||
SectorTagType.CdTrackFlags, SectorTagType.CdSectorSubchannel
|
||||
SectorTagType.CdSectorEcc, SectorTagType.CdSectorEccP, SectorTagType.CdSectorEccQ,
|
||||
SectorTagType.CdSectorEdc, SectorTagType.CdSectorHeader, SectorTagType.CdSectorSubHeader,
|
||||
SectorTagType.CdSectorSync, SectorTagType.CdTrackFlags, SectorTagType.CdSectorSubchannel
|
||||
};
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<MediaType> SupportedMediaTypes => new[]
|
||||
{
|
||||
MediaType.BDR, MediaType.BDRE, MediaType.BDREXL, MediaType.BDROM, MediaType.UHDBD, MediaType.BDRXL,
|
||||
MediaType.CBHD, MediaType.CD, MediaType.CDDA, MediaType.CDEG, MediaType.CDG, MediaType.CDI, MediaType.CDMIDI,
|
||||
MediaType.CDMRW, MediaType.CDPLUS, MediaType.CDR, MediaType.CDROM, MediaType.CDROMXA, MediaType.CDRW,
|
||||
MediaType.CDV, MediaType.DVDDownload, MediaType.DVDPR, MediaType.DVDPRDL, MediaType.DVDPRW, MediaType.DVDPRWDL,
|
||||
MediaType.DVDR, MediaType.DVDRAM, MediaType.DVDRDL, MediaType.DVDROM, MediaType.DVDRW, MediaType.DVDRWDL,
|
||||
MediaType.EVD, MediaType.FDDVD, MediaType.DTSCD, MediaType.FVD, MediaType.HDDVDR, MediaType.HDDVDRAM,
|
||||
MediaType.HDDVDRDL, MediaType.HDDVDROM, MediaType.HDDVDRW, MediaType.HDDVDRWDL, MediaType.HDVMD, MediaType.HVD,
|
||||
MediaType.JaguarCD, MediaType.MEGACD, MediaType.PS1CD, MediaType.PS2CD, MediaType.PS2DVD, MediaType.PS3BD,
|
||||
MediaType.PS3DVD, MediaType.PS4BD, MediaType.PS5BD, MediaType.SuperCDROM2, MediaType.SVCD, MediaType.SVOD,
|
||||
MediaType.SATURNCD, MediaType.ThreeDO, MediaType.UDO, MediaType.UDO2, MediaType.UDO2_WORM, MediaType.UMD,
|
||||
MediaType.VCD, MediaType.VCDHD, MediaType.NeoGeoCD, MediaType.PCFX, MediaType.CDTV, MediaType.CD32,
|
||||
MediaType.Nuon, MediaType.Playdia, MediaType.Pippin, MediaType.FMTOWNS, MediaType.MilCD, MediaType.VideoNow,
|
||||
MediaType.VideoNowColor, MediaType.VideoNowXp, MediaType.CVD, MediaType.PCD
|
||||
MediaType.CBHD, MediaType.CD, MediaType.CDDA, MediaType.CDEG, MediaType.CDG, MediaType.CDI,
|
||||
MediaType.CDMIDI, MediaType.CDMRW, MediaType.CDPLUS, MediaType.CDR, MediaType.CDROM, MediaType.CDROMXA,
|
||||
MediaType.CDRW, MediaType.CDV, MediaType.DVDDownload, MediaType.DVDPR, MediaType.DVDPRDL, MediaType.DVDPRW,
|
||||
MediaType.DVDPRWDL, MediaType.DVDR, MediaType.DVDRAM, MediaType.DVDRDL, MediaType.DVDROM, MediaType.DVDRW,
|
||||
MediaType.DVDRWDL, MediaType.EVD, MediaType.FDDVD, MediaType.DTSCD, MediaType.FVD, MediaType.HDDVDR,
|
||||
MediaType.HDDVDRAM, MediaType.HDDVDRDL, MediaType.HDDVDROM, MediaType.HDDVDRW, MediaType.HDDVDRWDL,
|
||||
MediaType.HDVMD, MediaType.HVD, MediaType.JaguarCD, MediaType.MEGACD, MediaType.PS1CD, MediaType.PS2CD,
|
||||
MediaType.PS2DVD, MediaType.PS3BD, MediaType.PS3DVD, MediaType.PS4BD, MediaType.PS5BD,
|
||||
MediaType.SuperCDROM2, MediaType.SVCD, MediaType.SVOD, MediaType.SATURNCD, MediaType.ThreeDO, MediaType.UDO,
|
||||
MediaType.UDO2, MediaType.UDO2_WORM, MediaType.UMD, MediaType.VCD, MediaType.VCDHD, MediaType.NeoGeoCD,
|
||||
MediaType.PCFX, MediaType.CDTV, MediaType.CD32, MediaType.Nuon, MediaType.Playdia, MediaType.Pippin,
|
||||
MediaType.FMTOWNS, MediaType.MilCD, MediaType.VideoNow, MediaType.VideoNowColor, MediaType.VideoNowXp,
|
||||
MediaType.CVD, MediaType.PCD
|
||||
};
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<(string name, Type type, string description, object @default)> SupportedOptions =>
|
||||
Array.Empty<(string name, Type type, string description, object @default)>();
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<string> KnownExtensions => new[]
|
||||
{
|
||||
".mds"
|
||||
};
|
||||
public IEnumerable<string> KnownExtensions => new[] { ".mds" };
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsWriting { get; private set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public string ErrorMessage { get; private set; }
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -48,6 +48,8 @@ namespace Aaru.DiscImages;
|
||||
|
||||
public sealed partial class Alcohol120
|
||||
{
|
||||
#region IWritableOpticalImage Members
|
||||
|
||||
/// <inheritdoc />
|
||||
public ErrorNumber Open(IFilter imageFilter)
|
||||
{
|
||||
@@ -58,7 +60,7 @@ public sealed partial class Alcohol120
|
||||
return ErrorNumber.InvalidArgument;
|
||||
|
||||
_isDvd = false;
|
||||
byte[] hdr = new byte[88];
|
||||
var hdr = new byte[88];
|
||||
stream.EnsureRead(hdr, 0, 88);
|
||||
_header = Marshal.ByteArrayToStructureLittleEndian<Header>(hdr);
|
||||
|
||||
@@ -68,33 +70,41 @@ public sealed partial class Alcohol120
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.version = {0}.{1}", _header.version[0],
|
||||
_header.version[1]);
|
||||
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.type = {0}", _header.type);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.type = {0}", _header.type);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.sessions = {0}", _header.sessions);
|
||||
|
||||
for(int i = 0; i < _header.unknown1.Length; i++)
|
||||
for(var i = 0; i < _header.unknown1.Length; i++)
|
||||
{
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.unknown1[{1}] = 0x{0:X4}", _header.unknown1[i],
|
||||
i);
|
||||
}
|
||||
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.bcaLength = {0}", _header.bcaLength);
|
||||
|
||||
for(int i = 0; i < _header.unknown2.Length; i++)
|
||||
for(var i = 0; i < _header.unknown2.Length; i++)
|
||||
{
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.unknown2[{1}] = 0x{0:X8}", _header.unknown2[i],
|
||||
i);
|
||||
}
|
||||
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.bcaOffset = {0}", _header.bcaOffset);
|
||||
|
||||
for(int i = 0; i < _header.unknown3.Length; i++)
|
||||
for(var i = 0; i < _header.unknown3.Length; i++)
|
||||
{
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.unknown3[{1}] = 0x{0:X8}", _header.unknown3[i],
|
||||
i);
|
||||
}
|
||||
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.structuresOffset = {0}", _header.structuresOffset);
|
||||
|
||||
for(int i = 0; i < _header.unknown4.Length; i++)
|
||||
for(var i = 0; i < _header.unknown4.Length; i++)
|
||||
{
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.unknown4[{1}] = 0x{0:X8}", _header.unknown4[i],
|
||||
i);
|
||||
}
|
||||
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.sessionOffset = {0}", _header.sessionOffset);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.dpmOffset = {0}", _header.dpmOffset);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.dpmOffset = {0}", _header.dpmOffset);
|
||||
|
||||
if(_header.version[0] > MAXIMUM_SUPPORTED_VERSION)
|
||||
return ErrorNumber.NotSupported;
|
||||
@@ -102,9 +112,9 @@ public sealed partial class Alcohol120
|
||||
stream.Seek(_header.sessionOffset, SeekOrigin.Begin);
|
||||
_alcSessions = new Dictionary<int, Session>();
|
||||
|
||||
for(int i = 0; i < _header.sessions; i++)
|
||||
for(var i = 0; i < _header.sessions; i++)
|
||||
{
|
||||
byte[] sesHdr = new byte[24];
|
||||
var sesHdr = new byte[24];
|
||||
stream.EnsureRead(sesHdr, 0, 24);
|
||||
Session session = Marshal.SpanToStructureLittleEndian<Session>(sesHdr);
|
||||
|
||||
@@ -133,7 +143,7 @@ public sealed partial class Alcohol120
|
||||
}
|
||||
|
||||
long footerOff = 0;
|
||||
bool oldIncorrectImage = false;
|
||||
var oldIncorrectImage = false;
|
||||
|
||||
_alcTracks = new Dictionary<int, Track>();
|
||||
_alcToc = new Dictionary<int, Dictionary<int, Track>>();
|
||||
@@ -144,9 +154,9 @@ public sealed partial class Alcohol120
|
||||
stream.Seek(session.trackOffset, SeekOrigin.Begin);
|
||||
Dictionary<int, Track> sesToc = new();
|
||||
|
||||
for(int i = 0; i < session.allBlocks; i++)
|
||||
for(var i = 0; i < session.allBlocks; i++)
|
||||
{
|
||||
byte[] trkHdr = new byte[80];
|
||||
var trkHdr = new byte[80];
|
||||
stream.EnsureRead(trkHdr, 0, 80);
|
||||
Track track = Marshal.ByteArrayToStructureLittleEndian<Track>(trkHdr);
|
||||
|
||||
@@ -250,10 +260,11 @@ public sealed partial class Alcohol120
|
||||
_alcTrackExtras = new Dictionary<int, TrackExtra>();
|
||||
|
||||
foreach(Track track in _alcTracks.Values)
|
||||
{
|
||||
if(track.extraOffset > 0 &&
|
||||
!_isDvd)
|
||||
{
|
||||
byte[] extHdr = new byte[8];
|
||||
var extHdr = new byte[8];
|
||||
stream.Seek(track.extraOffset, SeekOrigin.Begin);
|
||||
stream.EnsureRead(extHdr, 0, 8);
|
||||
TrackExtra extra = Marshal.SpanToStructureLittleEndian<TrackExtra>(extHdr);
|
||||
@@ -281,33 +292,36 @@ public sealed partial class Alcohol120
|
||||
|
||||
_alcTrackExtras.Add(track.point, extra);
|
||||
}
|
||||
}
|
||||
|
||||
if(footerOff > 0)
|
||||
{
|
||||
byte[] footer = new byte[16];
|
||||
var footer = new byte[16];
|
||||
stream.Seek(footerOff, SeekOrigin.Begin);
|
||||
stream.EnsureRead(footer, 0, 16);
|
||||
_alcFooter = Marshal.SpanToStructureLittleEndian<Footer>(footer);
|
||||
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "footer.filenameOffset = {0}", _alcFooter.filenameOffset);
|
||||
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "footer.widechar = {0}", _alcFooter.widechar);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "footer.widechar = {0}", _alcFooter.widechar);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "footer.unknown1 = 0x{0:X8}", _alcFooter.unknown1);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "footer.unknown2 = 0x{0:X8}", _alcFooter.unknown2);
|
||||
}
|
||||
|
||||
string alcFile = "*.mdf";
|
||||
var alcFile = "*.mdf";
|
||||
|
||||
if(_alcFooter.filenameOffset > 0)
|
||||
{
|
||||
stream.Seek(_alcFooter.filenameOffset, SeekOrigin.Begin);
|
||||
|
||||
byte[] filename = _header.dpmOffset == 0 ? new byte[stream.Length - stream.Position]
|
||||
: new byte[_header.dpmOffset - stream.Position];
|
||||
byte[] filename = _header.dpmOffset == 0
|
||||
? new byte[stream.Length - stream.Position]
|
||||
: new byte[_header.dpmOffset - stream.Position];
|
||||
|
||||
stream.EnsureRead(filename, 0, filename.Length);
|
||||
|
||||
alcFile = _alcFooter.widechar == 1 ? StringHandlers.CToString(filename, Encoding.Unicode, true)
|
||||
alcFile = _alcFooter.widechar == 1
|
||||
? StringHandlers.CToString(filename, Encoding.Unicode, true)
|
||||
: StringHandlers.CToString(filename, Encoding.Default);
|
||||
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "footer.filename = {0}", alcFile);
|
||||
@@ -332,6 +346,7 @@ public sealed partial class Alcohol120
|
||||
int readBytes = stream.EnsureRead(_bca, 0, _bca.Length);
|
||||
|
||||
if(readBytes == _bca.Length)
|
||||
{
|
||||
switch(_header.type)
|
||||
{
|
||||
case MediumType.DVD:
|
||||
@@ -340,6 +355,7 @@ public sealed partial class Alcohol120
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_imageInfo.MediaType = MediumTypeToMediaType(_header.type);
|
||||
@@ -379,14 +395,14 @@ public sealed partial class Alcohol120
|
||||
// TODO: Second layer
|
||||
if(_header.structuresOffset > 0)
|
||||
{
|
||||
byte[] structures = new byte[4100];
|
||||
var structures = new byte[4100];
|
||||
stream.Seek(_header.structuresOffset, SeekOrigin.Begin);
|
||||
stream.EnsureRead(structures, 0, 4100);
|
||||
_dmi = new byte[2052];
|
||||
_pfi = new byte[2052];
|
||||
|
||||
// TODO: CMI
|
||||
Array.Copy(structures, 4, _dmi, 4, 2048);
|
||||
Array.Copy(structures, 4, _dmi, 4, 2048);
|
||||
Array.Copy(structures, 0x804, _pfi, 4, 2048);
|
||||
|
||||
_pfi[0] = 0x08;
|
||||
@@ -401,29 +417,35 @@ public sealed partial class Alcohol120
|
||||
if(pfi0.HasValue)
|
||||
{
|
||||
_imageInfo.MediaType = pfi0.Value.DiskCategory switch
|
||||
{
|
||||
DiskCategory.DVDPR => MediaType.DVDPR,
|
||||
DiskCategory.DVDPRDL => MediaType.DVDPRDL,
|
||||
DiskCategory.DVDPRW => MediaType.DVDPRW,
|
||||
DiskCategory.DVDPRWDL => MediaType.DVDPRWDL,
|
||||
DiskCategory.DVDR => pfi0.Value.PartVersion >= 6 ? MediaType.DVDRDL : MediaType.DVDR,
|
||||
DiskCategory.DVDRAM => MediaType.DVDRAM,
|
||||
DiskCategory.DVDRW => pfi0.Value.PartVersion >= 15 ? MediaType.DVDRWDL : MediaType.DVDRW,
|
||||
DiskCategory.HDDVDR => MediaType.HDDVDR,
|
||||
DiskCategory.HDDVDRAM => MediaType.HDDVDRAM,
|
||||
DiskCategory.HDDVDROM => MediaType.HDDVDROM,
|
||||
DiskCategory.HDDVDRW => MediaType.HDDVDRW,
|
||||
DiskCategory.Nintendo => pfi0.Value.DiscSize == DVDSize.Eighty ? MediaType.GOD : MediaType.WOD,
|
||||
DiskCategory.UMD => MediaType.UMD,
|
||||
_ => MediaType.DVDROM
|
||||
};
|
||||
{
|
||||
DiskCategory.DVDPR => MediaType.DVDPR,
|
||||
DiskCategory.DVDPRDL => MediaType.DVDPRDL,
|
||||
DiskCategory.DVDPRW => MediaType.DVDPRW,
|
||||
DiskCategory.DVDPRWDL => MediaType.DVDPRWDL,
|
||||
DiskCategory.DVDR => pfi0.Value.PartVersion >= 6
|
||||
? MediaType.DVDRDL
|
||||
: MediaType.DVDR,
|
||||
DiskCategory.DVDRAM => MediaType.DVDRAM,
|
||||
DiskCategory.DVDRW => pfi0.Value.PartVersion >= 15
|
||||
? MediaType.DVDRWDL
|
||||
: MediaType.DVDRW,
|
||||
DiskCategory.HDDVDR => MediaType.HDDVDR,
|
||||
DiskCategory.HDDVDRAM => MediaType.HDDVDRAM,
|
||||
DiskCategory.HDDVDROM => MediaType.HDDVDROM,
|
||||
DiskCategory.HDDVDRW => MediaType.HDDVDRW,
|
||||
DiskCategory.Nintendo => pfi0.Value.DiscSize == DVDSize.Eighty
|
||||
? MediaType.GOD
|
||||
: MediaType.WOD,
|
||||
DiskCategory.UMD => MediaType.UMD,
|
||||
_ => MediaType.DVDROM
|
||||
};
|
||||
|
||||
if(DMI.IsXbox(_dmi))
|
||||
_imageInfo.MediaType = MediaType.XGD;
|
||||
else if(DMI.IsXbox360(_dmi))
|
||||
_imageInfo.MediaType = MediaType.XGD2;
|
||||
|
||||
byte[] tmp = new byte[2048];
|
||||
var tmp = new byte[2048];
|
||||
Array.Copy(_dmi, 4, tmp, 0, 2048);
|
||||
_dmi = tmp;
|
||||
tmp = new byte[2048];
|
||||
@@ -437,11 +459,11 @@ public sealed partial class Alcohol120
|
||||
}
|
||||
else if(_header.type == MediumType.CD)
|
||||
{
|
||||
bool data = false;
|
||||
bool mode2 = false;
|
||||
bool firstAudio = false;
|
||||
bool firstData = false;
|
||||
bool audio = false;
|
||||
var data = false;
|
||||
var mode2 = false;
|
||||
var firstAudio = false;
|
||||
var firstData = false;
|
||||
var audio = false;
|
||||
|
||||
foreach(Track alcoholTrack in _alcTracks.Values)
|
||||
{
|
||||
@@ -480,7 +502,7 @@ public sealed partial class Alcohol120
|
||||
Sessions.Count > 1 &&
|
||||
mode2)
|
||||
_imageInfo.MediaType = MediaType.CDPLUS;
|
||||
else if((firstData && audio) || mode2)
|
||||
else if(firstData && audio || mode2)
|
||||
_imageInfo.MediaType = MediaType.CDROMXA;
|
||||
else if(!audio)
|
||||
_imageInfo.MediaType = MediaType.CDROM;
|
||||
@@ -598,7 +620,7 @@ public sealed partial class Alcohol120
|
||||
|
||||
foreach(Partition partition in Partitions)
|
||||
{
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Partition_sequence_0, partition.Sequence);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Partition_sequence_0, partition.Sequence);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "\t" + Localization.Partition_name_0, partition.Name);
|
||||
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "\t" + Localization.Partition_description_0,
|
||||
@@ -646,10 +668,7 @@ public sealed partial class Alcohol120
|
||||
byte lastSession = 0;
|
||||
var tocMs = new MemoryStream();
|
||||
|
||||
tocMs.Write(new byte[]
|
||||
{
|
||||
0, 0
|
||||
}, 0, 2); // Reserved for TOC session numbers
|
||||
tocMs.Write(new byte[] { 0, 0 }, 0, 2); // Reserved for TOC session numbers
|
||||
|
||||
foreach(KeyValuePair<int, Dictionary<int, Track>> sessionToc in _alcToc)
|
||||
{
|
||||
@@ -691,8 +710,10 @@ public sealed partial class Alcohol120
|
||||
AaruConsole.VerboseWriteLine(Localization.Alcohol_120_image_describes_a_disc_of_type_0, _imageInfo.MediaType);
|
||||
|
||||
if(oldIncorrectImage)
|
||||
{
|
||||
AaruConsole.WriteLine(Localization.
|
||||
Incorrect_Alcohol_120_image_created_by_an_old_version_of_Aaru_Convert_image_to_correct_it);
|
||||
}
|
||||
|
||||
return ErrorNumber.NoError;
|
||||
}
|
||||
@@ -724,7 +745,8 @@ public sealed partial class Alcohol120
|
||||
|
||||
return buffer != null ? ErrorNumber.NoError : ErrorNumber.NoData;
|
||||
|
||||
default: return ErrorNumber.NotSupported;
|
||||
default:
|
||||
return ErrorNumber.NotSupported;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -749,7 +771,9 @@ public sealed partial class Alcohol120
|
||||
buffer = null;
|
||||
|
||||
foreach(KeyValuePair<uint, ulong> kvp in _offsetMap)
|
||||
{
|
||||
if(sectorAddress >= kvp.Value)
|
||||
{
|
||||
foreach(Track track in _alcTracks.Values)
|
||||
{
|
||||
if(track.point != kvp.Key ||
|
||||
@@ -761,6 +785,8 @@ public sealed partial class Alcohol120
|
||||
|
||||
return ReadSectors(sectorAddress - kvp.Value, length, kvp.Key, out buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ErrorNumber.SectorNotFound;
|
||||
}
|
||||
@@ -771,7 +797,9 @@ public sealed partial class Alcohol120
|
||||
buffer = null;
|
||||
|
||||
foreach(KeyValuePair<uint, ulong> kvp in _offsetMap)
|
||||
{
|
||||
if(sectorAddress >= kvp.Value)
|
||||
{
|
||||
foreach(Track track in _alcTracks.Values)
|
||||
{
|
||||
if(track.point != kvp.Key ||
|
||||
@@ -783,6 +811,8 @@ public sealed partial class Alcohol120
|
||||
|
||||
return ReadSectorsTag(sectorAddress - kvp.Value, length, kvp.Key, tag, out buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ErrorNumber.SectorNotFound;
|
||||
}
|
||||
@@ -802,7 +832,7 @@ public sealed partial class Alcohol120
|
||||
uint sectorOffset;
|
||||
uint sectorSize;
|
||||
uint sectorSkip;
|
||||
bool mode2 = false;
|
||||
var mode2 = false;
|
||||
|
||||
switch(alcTrack.mode)
|
||||
{
|
||||
@@ -849,7 +879,8 @@ public sealed partial class Alcohol120
|
||||
break;
|
||||
}
|
||||
|
||||
default: return ErrorNumber.NotSupported;
|
||||
default:
|
||||
return ErrorNumber.NotSupported;
|
||||
}
|
||||
|
||||
switch(alcTrack.subMode)
|
||||
@@ -862,7 +893,8 @@ public sealed partial class Alcohol120
|
||||
sectorSkip += 96;
|
||||
|
||||
break;
|
||||
default: return ErrorNumber.NotSupported;
|
||||
default:
|
||||
return ErrorNumber.NotSupported;
|
||||
}
|
||||
|
||||
buffer = new byte[sectorSize * length];
|
||||
@@ -877,7 +909,7 @@ public sealed partial class Alcohol120
|
||||
}
|
||||
|
||||
uint pregapBytes = alcExtra.pregap * (sectorOffset + sectorSize + sectorSkip);
|
||||
long fileOffset = (long)alcTrack.startOffset;
|
||||
var fileOffset = (long)alcTrack.startOffset;
|
||||
|
||||
if(alcTrack.startOffset >= pregapBytes)
|
||||
fileOffset = (long)(alcTrack.startOffset - pregapBytes);
|
||||
@@ -894,9 +926,9 @@ public sealed partial class Alcohol120
|
||||
|
||||
buffer = br.ReadBytes((int)((sectorSize + sectorSkip) * length));
|
||||
|
||||
for(int i = 0; i < length; i++)
|
||||
for(var i = 0; i < length; i++)
|
||||
{
|
||||
byte[] sector = new byte[sectorSize];
|
||||
var sector = new byte[sectorSize];
|
||||
Array.Copy(buffer, (sectorSize + sectorSkip) * i, sector, 0, sectorSize);
|
||||
sector = Sector.GetUserDataFromMode2(sector);
|
||||
mode2Ms.Write(sector, 0, sector.Length);
|
||||
@@ -908,19 +940,21 @@ public sealed partial class Alcohol120
|
||||
sectorSkip == 0)
|
||||
buffer = br.ReadBytes((int)(sectorSize * length));
|
||||
else
|
||||
for(int i = 0; i < length; i++)
|
||||
{
|
||||
for(var i = 0; i < length; i++)
|
||||
{
|
||||
br.BaseStream.Seek(sectorOffset, SeekOrigin.Current);
|
||||
byte[] sector = br.ReadBytes((int)sectorSize);
|
||||
br.BaseStream.Seek(sectorSkip, SeekOrigin.Current);
|
||||
Array.Copy(sector, 0, buffer, i * sectorSize, sectorSize);
|
||||
}
|
||||
}
|
||||
|
||||
return ErrorNumber.NoError;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ErrorNumber ReadSectorsTag(ulong sectorAddress, uint length, uint track, SectorTagType tag,
|
||||
public ErrorNumber ReadSectorsTag(ulong sectorAddress, uint length, uint track, SectorTagType tag,
|
||||
out byte[] buffer)
|
||||
{
|
||||
buffer = null;
|
||||
@@ -951,15 +985,14 @@ public sealed partial class Alcohol120
|
||||
case SectorTagType.CdSectorHeader:
|
||||
case SectorTagType.CdSectorSubchannel:
|
||||
case SectorTagType.CdSectorSubHeader:
|
||||
case SectorTagType.CdSectorSync: break;
|
||||
case SectorTagType.CdSectorSync:
|
||||
break;
|
||||
case SectorTagType.CdTrackFlags:
|
||||
buffer = new[]
|
||||
{
|
||||
(byte)(alcTrack.adrCtl & 0x0F)
|
||||
};
|
||||
buffer = new[] { (byte)(alcTrack.adrCtl & 0x0F) };
|
||||
|
||||
return ErrorNumber.NoError;
|
||||
default: return ErrorNumber.NotSupported;
|
||||
default:
|
||||
return ErrorNumber.NotSupported;
|
||||
}
|
||||
|
||||
switch(alcTrack.mode)
|
||||
@@ -986,7 +1019,8 @@ public sealed partial class Alcohol120
|
||||
break;
|
||||
}
|
||||
|
||||
case SectorTagType.CdSectorSubHeader: return ErrorNumber.NotSupported;
|
||||
case SectorTagType.CdSectorSubHeader:
|
||||
return ErrorNumber.NotSupported;
|
||||
case SectorTagType.CdSectorEcc:
|
||||
{
|
||||
sectorOffset = 2076;
|
||||
@@ -1034,13 +1068,15 @@ public sealed partial class Alcohol120
|
||||
sectorSkip = 0;
|
||||
|
||||
break;
|
||||
default: return ErrorNumber.NotSupported;
|
||||
default:
|
||||
return ErrorNumber.NotSupported;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default: return ErrorNumber.NotSupported;
|
||||
default:
|
||||
return ErrorNumber.NotSupported;
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -1052,7 +1088,8 @@ public sealed partial class Alcohol120
|
||||
case SectorTagType.CdSectorHeader:
|
||||
case SectorTagType.CdSectorEcc:
|
||||
case SectorTagType.CdSectorEccP:
|
||||
case SectorTagType.CdSectorEccQ: return ErrorNumber.NotSupported;
|
||||
case SectorTagType.CdSectorEccQ:
|
||||
return ErrorNumber.NotSupported;
|
||||
case SectorTagType.CdSectorSubHeader:
|
||||
{
|
||||
sectorOffset = 0;
|
||||
@@ -1082,13 +1119,15 @@ public sealed partial class Alcohol120
|
||||
sectorSkip = 0;
|
||||
|
||||
break;
|
||||
default: return ErrorNumber.NotSupported;
|
||||
default:
|
||||
return ErrorNumber.NotSupported;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default: return ErrorNumber.NotSupported;
|
||||
default:
|
||||
return ErrorNumber.NotSupported;
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -1172,13 +1211,15 @@ public sealed partial class Alcohol120
|
||||
sectorSkip = 0;
|
||||
|
||||
break;
|
||||
default: return ErrorNumber.NotSupported;
|
||||
default:
|
||||
return ErrorNumber.NotSupported;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default: return ErrorNumber.NotSupported;
|
||||
default:
|
||||
return ErrorNumber.NotSupported;
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -1233,13 +1274,15 @@ public sealed partial class Alcohol120
|
||||
sectorSkip = 0;
|
||||
|
||||
break;
|
||||
default: return ErrorNumber.NotSupported;
|
||||
default:
|
||||
return ErrorNumber.NotSupported;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default: return ErrorNumber.NotSupported;
|
||||
default:
|
||||
return ErrorNumber.NotSupported;
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -1259,19 +1302,22 @@ public sealed partial class Alcohol120
|
||||
sectorSkip = 0;
|
||||
|
||||
break;
|
||||
default: return ErrorNumber.NotSupported;
|
||||
default:
|
||||
return ErrorNumber.NotSupported;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default: return ErrorNumber.NotSupported;
|
||||
default:
|
||||
return ErrorNumber.NotSupported;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default: return ErrorNumber.NotSupported;
|
||||
default:
|
||||
return ErrorNumber.NotSupported;
|
||||
}
|
||||
|
||||
switch(alcTrack.subMode)
|
||||
@@ -1285,7 +1331,8 @@ public sealed partial class Alcohol120
|
||||
sectorSkip += 96;
|
||||
|
||||
break;
|
||||
default: return ErrorNumber.NotSupported;
|
||||
default:
|
||||
return ErrorNumber.NotSupported;
|
||||
}
|
||||
|
||||
buffer = new byte[sectorSize * length];
|
||||
@@ -1300,7 +1347,7 @@ public sealed partial class Alcohol120
|
||||
}
|
||||
|
||||
uint pregapBytes = alcExtra.pregap * (sectorOffset + sectorSize + sectorSkip);
|
||||
long fileOffset = (long)alcTrack.startOffset;
|
||||
var fileOffset = (long)alcTrack.startOffset;
|
||||
|
||||
if(alcTrack.startOffset >= pregapBytes)
|
||||
fileOffset = (long)(alcTrack.startOffset - pregapBytes);
|
||||
@@ -1315,13 +1362,15 @@ public sealed partial class Alcohol120
|
||||
sectorSkip == 0)
|
||||
buffer = br.ReadBytes((int)(sectorSize * length));
|
||||
else
|
||||
for(int i = 0; i < length; i++)
|
||||
{
|
||||
for(var i = 0; i < length; i++)
|
||||
{
|
||||
br.BaseStream.Seek(sectorOffset, SeekOrigin.Current);
|
||||
byte[] sector = br.ReadBytes((int)sectorSize);
|
||||
br.BaseStream.Seek(sectorSkip, SeekOrigin.Current);
|
||||
Array.Copy(sector, 0, buffer, i * sectorSize, sectorSize);
|
||||
}
|
||||
}
|
||||
|
||||
return ErrorNumber.NoError;
|
||||
}
|
||||
@@ -1340,7 +1389,9 @@ public sealed partial class Alcohol120
|
||||
buffer = null;
|
||||
|
||||
foreach(KeyValuePair<uint, ulong> kvp in _offsetMap)
|
||||
{
|
||||
if(sectorAddress >= kvp.Value)
|
||||
{
|
||||
foreach(Track alcTrack in _alcTracks.Values)
|
||||
{
|
||||
if(alcTrack.point != kvp.Key ||
|
||||
@@ -1352,6 +1403,8 @@ public sealed partial class Alcohol120
|
||||
|
||||
return ReadSectorsLong(sectorAddress - kvp.Value, length, kvp.Key, out buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ErrorNumber.SectorNotFound;
|
||||
}
|
||||
@@ -1392,7 +1445,8 @@ public sealed partial class Alcohol120
|
||||
break;
|
||||
}
|
||||
|
||||
default: return ErrorNumber.NotSupported;
|
||||
default:
|
||||
return ErrorNumber.NotSupported;
|
||||
}
|
||||
|
||||
if(alcTrack.subMode == SubchannelMode.Interleaved)
|
||||
@@ -1410,7 +1464,7 @@ public sealed partial class Alcohol120
|
||||
}
|
||||
|
||||
uint pregapBytes = alcExtra.pregap * (sectorSize + sectorSkip);
|
||||
long fileOffset = (long)alcTrack.startOffset;
|
||||
var fileOffset = (long)alcTrack.startOffset;
|
||||
|
||||
if(alcTrack.startOffset >= pregapBytes)
|
||||
fileOffset = (long)(alcTrack.startOffset - pregapBytes);
|
||||
@@ -1423,7 +1477,8 @@ public sealed partial class Alcohol120
|
||||
if(sectorSkip == 0)
|
||||
buffer = br.ReadBytes((int)(sectorSize * length));
|
||||
else
|
||||
for(int i = 0; i < length; i++)
|
||||
{
|
||||
for(var i = 0; i < length; i++)
|
||||
{
|
||||
br.BaseStream.Seek(sectorOffset, SeekOrigin.Current);
|
||||
byte[] sector = br.ReadBytes((int)sectorSize);
|
||||
@@ -1431,6 +1486,7 @@ public sealed partial class Alcohol120
|
||||
|
||||
Array.Copy(sector, 0, buffer, i * sectorSize, sectorSize);
|
||||
}
|
||||
}
|
||||
|
||||
return ErrorNumber.NoError;
|
||||
}
|
||||
@@ -1447,7 +1503,8 @@ public sealed partial class Alcohol120
|
||||
foreach(Track alcTrack in _alcTracks.Values)
|
||||
{
|
||||
ushort sessionNo =
|
||||
(from ses in Sessions where alcTrack.point >= ses.StartTrack || alcTrack.point <= ses.EndTrack
|
||||
(from ses in Sessions
|
||||
where alcTrack.point >= ses.StartTrack || alcTrack.point <= ses.EndTrack
|
||||
select ses.Sequence).FirstOrDefault();
|
||||
|
||||
if(!_alcTrackExtras.TryGetValue(alcTrack.point, out TrackExtra alcExtra) ||
|
||||
@@ -1495,4 +1552,6 @@ public sealed partial class Alcohol120
|
||||
|
||||
return tracks;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -36,6 +36,21 @@ namespace Aaru.DiscImages;
|
||||
|
||||
public sealed partial class Alcohol120
|
||||
{
|
||||
#region Nested type: Footer
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct Footer
|
||||
{
|
||||
public uint filenameOffset;
|
||||
public uint widechar;
|
||||
public readonly uint unknown1;
|
||||
public readonly uint unknown2;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Nested type: Header
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct Header
|
||||
{
|
||||
@@ -60,6 +75,10 @@ public sealed partial class Alcohol120
|
||||
public readonly uint dpmOffset;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Nested type: Session
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct Session
|
||||
{
|
||||
@@ -74,6 +93,10 @@ public sealed partial class Alcohol120
|
||||
public uint trackOffset;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Nested type: Track
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct Track
|
||||
{
|
||||
@@ -101,6 +124,10 @@ public sealed partial class Alcohol120
|
||||
public byte[] unknown2;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Nested type: TrackExtra
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct TrackExtra
|
||||
{
|
||||
@@ -108,12 +135,5 @@ public sealed partial class Alcohol120
|
||||
public uint sectors;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct Footer
|
||||
{
|
||||
public uint filenameOffset;
|
||||
public uint widechar;
|
||||
public readonly uint unknown1;
|
||||
public readonly uint unknown2;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
@@ -39,6 +39,8 @@ namespace Aaru.DiscImages;
|
||||
|
||||
public sealed partial class Alcohol120
|
||||
{
|
||||
#region IWritableOpticalImage Members
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool? VerifySector(ulong sectorAddress)
|
||||
{
|
||||
@@ -48,7 +50,7 @@ public sealed partial class Alcohol120
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool? VerifySectors(ulong sectorAddress, uint length, out List<ulong> failingLbas,
|
||||
public bool? VerifySectors(ulong sectorAddress, uint length, out List<ulong> failingLbas,
|
||||
out List<ulong> unknownLbas)
|
||||
{
|
||||
failingLbas = new List<ulong>();
|
||||
@@ -58,10 +60,10 @@ public sealed partial class Alcohol120
|
||||
if(errno != ErrorNumber.NoError)
|
||||
return null;
|
||||
|
||||
int bps = (int)(buffer.Length / length);
|
||||
byte[] sector = new byte[bps];
|
||||
var bps = (int)(buffer.Length / length);
|
||||
var sector = new byte[bps];
|
||||
|
||||
for(int i = 0; i < length; i++)
|
||||
for(var i = 0; i < length; i++)
|
||||
{
|
||||
Array.Copy(buffer, i * bps, sector, 0, bps);
|
||||
bool? sectorStatus = CdChecksums.CheckCdSector(sector);
|
||||
@@ -86,7 +88,7 @@ public sealed partial class Alcohol120
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool? VerifySectors(ulong sectorAddress, uint length, uint track, out List<ulong> failingLbas,
|
||||
public bool? VerifySectors(ulong sectorAddress, uint length, uint track, out List<ulong> failingLbas,
|
||||
out List<ulong> unknownLbas)
|
||||
{
|
||||
failingLbas = new List<ulong>();
|
||||
@@ -96,10 +98,10 @@ public sealed partial class Alcohol120
|
||||
if(errno != ErrorNumber.NoError)
|
||||
return null;
|
||||
|
||||
int bps = (int)(buffer.Length / length);
|
||||
byte[] sector = new byte[bps];
|
||||
var bps = (int)(buffer.Length / length);
|
||||
var sector = new byte[bps];
|
||||
|
||||
for(int i = 0; i < length; i++)
|
||||
for(var i = 0; i < length; i++)
|
||||
{
|
||||
Array.Copy(buffer, i * bps, sector, 0, bps);
|
||||
bool? sectorStatus = CdChecksums.CheckCdSector(sector);
|
||||
@@ -122,4 +124,6 @@ public sealed partial class Alcohol120
|
||||
|
||||
return failingLbas.Count <= 0;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -47,9 +47,11 @@ namespace Aaru.DiscImages;
|
||||
|
||||
public sealed partial class Alcohol120
|
||||
{
|
||||
#region IWritableOpticalImage Members
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Create(string path, MediaType mediaType, Dictionary<string, string> options, ulong sectors,
|
||||
uint sectorSize)
|
||||
uint sectorSize)
|
||||
{
|
||||
if(!SupportedMediaTypes.Contains(mediaType))
|
||||
{
|
||||
@@ -71,8 +73,10 @@ public sealed partial class Alcohol120
|
||||
|
||||
_imageStream =
|
||||
new
|
||||
FileStream(Path.Combine(Path.GetDirectoryName(path) ?? "", Path.GetFileNameWithoutExtension(path)) + ".mdf",
|
||||
FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None);
|
||||
FileStream(
|
||||
Path.Combine(Path.GetDirectoryName(path) ?? "", Path.GetFileNameWithoutExtension(path)) +
|
||||
".mdf",
|
||||
FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None);
|
||||
}
|
||||
catch(IOException e)
|
||||
{
|
||||
@@ -248,7 +252,7 @@ public sealed partial class Alcohol120
|
||||
}
|
||||
|
||||
_imageStream.
|
||||
Seek((long)(track.FileOffset + ((sectorAddress - track.StartSector) * (ulong)track.RawBytesPerSector)),
|
||||
Seek((long)(track.FileOffset + (sectorAddress - track.StartSector) * (ulong)track.RawBytesPerSector),
|
||||
SeekOrigin.Begin);
|
||||
|
||||
_imageStream.Write(data, 0, data.Length);
|
||||
@@ -308,8 +312,9 @@ public sealed partial class Alcohol120
|
||||
{
|
||||
case TrackSubchannelType.None:
|
||||
_imageStream.
|
||||
Seek((long)(track.FileOffset + ((sectorAddress - track.StartSector) * (ulong)track.RawBytesPerSector)),
|
||||
SeekOrigin.Begin);
|
||||
Seek(
|
||||
(long)(track.FileOffset + (sectorAddress - track.StartSector) * (ulong)track.RawBytesPerSector),
|
||||
SeekOrigin.Begin);
|
||||
|
||||
_imageStream.Write(data, 0, data.Length);
|
||||
|
||||
@@ -319,8 +324,10 @@ public sealed partial class Alcohol120
|
||||
case TrackSubchannelType.Raw:
|
||||
case TrackSubchannelType.RawInterleaved:
|
||||
_imageStream.
|
||||
Seek((long)(track.FileOffset + ((sectorAddress - track.StartSector) * (ulong)(track.RawBytesPerSector + 96))),
|
||||
SeekOrigin.Begin);
|
||||
Seek(
|
||||
(long)(track.FileOffset +
|
||||
(sectorAddress - track.StartSector) * (ulong)(track.RawBytesPerSector + 96)),
|
||||
SeekOrigin.Begin);
|
||||
|
||||
for(uint i = 0; i < length; i++)
|
||||
{
|
||||
@@ -365,11 +372,13 @@ public sealed partial class Alcohol120
|
||||
return false;
|
||||
}
|
||||
|
||||
uint subchannelSize = (uint)(track.SubchannelType != TrackSubchannelType.None ? 96 : 0);
|
||||
var subchannelSize = (uint)(track.SubchannelType != TrackSubchannelType.None ? 96 : 0);
|
||||
|
||||
_imageStream.
|
||||
Seek((long)(track.FileOffset + ((sectorAddress - track.StartSector) * (ulong)(track.RawBytesPerSector + subchannelSize))),
|
||||
SeekOrigin.Begin);
|
||||
Seek(
|
||||
(long)(track.FileOffset + (sectorAddress - track.StartSector) *
|
||||
(ulong)(track.RawBytesPerSector + subchannelSize)),
|
||||
SeekOrigin.Begin);
|
||||
|
||||
_imageStream.Write(data, 0, data.Length);
|
||||
|
||||
@@ -410,13 +419,15 @@ public sealed partial class Alcohol120
|
||||
return false;
|
||||
}
|
||||
|
||||
uint subchannelSize = (uint)(track.SubchannelType != TrackSubchannelType.None ? 96 : 0);
|
||||
var subchannelSize = (uint)(track.SubchannelType != TrackSubchannelType.None ? 96 : 0);
|
||||
|
||||
for(uint i = 0; i < length; i++)
|
||||
{
|
||||
_imageStream.
|
||||
Seek((long)(track.FileOffset + ((i + sectorAddress - track.StartSector) * (ulong)(track.RawBytesPerSector + subchannelSize))),
|
||||
SeekOrigin.Begin);
|
||||
Seek(
|
||||
(long)(track.FileOffset + (i + sectorAddress - track.StartSector) *
|
||||
(ulong)(track.RawBytesPerSector + subchannelSize)),
|
||||
SeekOrigin.Begin);
|
||||
|
||||
_imageStream.Write(data, (int)(i * track.RawBytesPerSector), track.RawBytesPerSector);
|
||||
}
|
||||
@@ -435,7 +446,7 @@ public sealed partial class Alcohol120
|
||||
{
|
||||
CommonTypes.Structs.Track[] tmpTracks = tracks.OrderBy(t => t.Sequence).ToArray();
|
||||
|
||||
for(int i = 1; i < tmpTracks.Length; i++)
|
||||
for(var i = 1; i < tmpTracks.Length; i++)
|
||||
{
|
||||
CommonTypes.Structs.Track firstTrackInSession =
|
||||
tracks.FirstOrDefault(t => t.Session == tmpTracks[i].Session);
|
||||
@@ -508,11 +519,8 @@ public sealed partial class Alcohol120
|
||||
|
||||
var header = new Header
|
||||
{
|
||||
signature = _alcoholSignature,
|
||||
version = new byte[]
|
||||
{
|
||||
1, 5
|
||||
},
|
||||
signature = _alcoholSignature,
|
||||
version = new byte[] { 1, 5 },
|
||||
type = MediaTypeToMediumType(_imageInfo.MediaType),
|
||||
sessions = sessions,
|
||||
structuresOffset = (uint)(_pfi == null ? 0 : 96),
|
||||
@@ -531,7 +539,7 @@ public sealed partial class Alcohol120
|
||||
_alcToc = new Dictionary<int, Dictionary<int, Track>>();
|
||||
_writingTracks = _writingTracks.OrderBy(t => t.Session).ThenBy(t => t.Sequence).ToList();
|
||||
_alcTrackExtras = new Dictionary<int, TrackExtra>();
|
||||
long currentTrackOffset = header.sessionOffset + (Marshal.SizeOf<Session>() * sessions);
|
||||
long currentTrackOffset = header.sessionOffset + Marshal.SizeOf<Session>() * sessions;
|
||||
|
||||
byte[] tmpToc = null;
|
||||
|
||||
@@ -547,9 +555,10 @@ public sealed partial class Alcohol120
|
||||
FullTOC.CDFullTOC? decodedToc = FullTOC.Decode(tmpToc);
|
||||
|
||||
long currentExtraOffset = currentTrackOffset;
|
||||
int extraCount = 0;
|
||||
var extraCount = 0;
|
||||
|
||||
for(int i = 1; i <= sessions; i++)
|
||||
for(var i = 1; i <= sessions; i++)
|
||||
{
|
||||
if(decodedToc.HasValue)
|
||||
{
|
||||
extraCount += decodedToc.Value.TrackDescriptors.Count(t => t.SessionNumber == i);
|
||||
@@ -572,8 +581,9 @@ public sealed partial class Alcohol120
|
||||
currentExtraOffset += Marshal.SizeOf<Track>() * 2;
|
||||
extraCount += 2;
|
||||
}
|
||||
}
|
||||
|
||||
long footerOffset = currentExtraOffset + (Marshal.SizeOf<TrackExtra>() * extraCount);
|
||||
long footerOffset = currentExtraOffset + Marshal.SizeOf<TrackExtra>() * extraCount;
|
||||
|
||||
if(_bca != null)
|
||||
{
|
||||
@@ -615,7 +625,8 @@ public sealed partial class Alcohol120
|
||||
_alcToc.Add(1, _alcTracks);
|
||||
}
|
||||
else
|
||||
for(int i = 1; i <= sessions; i++)
|
||||
{
|
||||
for(var i = 1; i <= sessions; i++)
|
||||
{
|
||||
CommonTypes.Structs.Track firstTrack = _writingTracks.First(t => t.Session == i);
|
||||
CommonTypes.Structs.Track lastTrack = _writingTracks.Last(t => t.Session == i);
|
||||
@@ -637,7 +648,7 @@ public sealed partial class Alcohol120
|
||||
|
||||
Dictionary<int, Track> thisSessionTracks = new();
|
||||
_trackFlags.TryGetValue((byte)firstTrack.Sequence, out byte firstTrackControl);
|
||||
_trackFlags.TryGetValue((byte)lastTrack.Sequence, out byte lastTrackControl);
|
||||
_trackFlags.TryGetValue((byte)lastTrack.Sequence, out byte lastTrackControl);
|
||||
|
||||
if(firstTrackControl == 0 &&
|
||||
firstTrack.Type != TrackType.Audio)
|
||||
@@ -651,6 +662,7 @@ public sealed partial class Alcohol120
|
||||
|
||||
if(decodedToc?.TrackDescriptors.Any(t => t.SessionNumber == i && t.POINT is >= 0xA0 and <= 0xAF) ==
|
||||
true)
|
||||
{
|
||||
foreach(FullTOC.TrackDataDescriptor tocTrk in
|
||||
decodedToc.Value.TrackDescriptors.Where(t => t.SessionNumber == i &&
|
||||
t.POINT is >= 0xA0 and <= 0xAF))
|
||||
@@ -676,6 +688,7 @@ public sealed partial class Alcohol120
|
||||
currentTrackOffset += Marshal.SizeOf<Track>();
|
||||
currentExtraOffset += Marshal.SizeOf<TrackExtra>();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
thisSessionTracks.Add(0xA0, new Track
|
||||
@@ -689,8 +702,8 @@ public sealed partial class Alcohol120
|
||||
psec = (byte)(_imageInfo.MediaType == MediaType.CDI
|
||||
? 0x10
|
||||
: _writingTracks.Any(t => t.Type is TrackType.CdMode2Form1
|
||||
or TrackType.CdMode2Form2
|
||||
or TrackType.CdMode2Formless)
|
||||
or TrackType.CdMode2Form2
|
||||
or TrackType.CdMode2Formless)
|
||||
? 0x20
|
||||
: 0),
|
||||
extraOffset = (uint)currentExtraOffset
|
||||
@@ -766,14 +779,15 @@ public sealed partial class Alcohol120
|
||||
|
||||
alcTrk.mode = TrackTypeToTrackMode(track.Type);
|
||||
|
||||
alcTrk.subMode = track.SubchannelType != TrackSubchannelType.None ? SubchannelMode.Interleaved
|
||||
alcTrk.subMode = track.SubchannelType != TrackSubchannelType.None
|
||||
? SubchannelMode.Interleaved
|
||||
: SubchannelMode.None;
|
||||
|
||||
alcTrk.sectorSize = (ushort)(track.RawBytesPerSector +
|
||||
(track.SubchannelType != TrackSubchannelType.None ? 96 : 0));
|
||||
|
||||
alcTrk.startLba = (uint)(track.StartSector + track.Pregap);
|
||||
alcTrk.startOffset = track.FileOffset + (alcTrk.sectorSize * track.Pregap);
|
||||
alcTrk.startOffset = track.FileOffset + alcTrk.sectorSize * track.Pregap;
|
||||
alcTrk.files = 1;
|
||||
alcTrk.extraOffset = (uint)currentExtraOffset;
|
||||
alcTrk.footerOffset = (uint)footerOffset;
|
||||
@@ -788,8 +802,8 @@ public sealed partial class Alcohol120
|
||||
// Daemon Tools expect it to be like this
|
||||
alcTrk.unknown = new byte[]
|
||||
{
|
||||
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00
|
||||
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
alcTrk.unknown2 = new byte[24];
|
||||
@@ -824,6 +838,7 @@ public sealed partial class Alcohol120
|
||||
}
|
||||
|
||||
if(decodedToc?.TrackDescriptors.Any(t => t.SessionNumber == i && t.POINT >= 0xB0) == true)
|
||||
{
|
||||
foreach(FullTOC.TrackDataDescriptor tocTrk in
|
||||
decodedToc.Value.TrackDescriptors.Where(t => t.SessionNumber == i && t.POINT >= 0xB0))
|
||||
{
|
||||
@@ -848,6 +863,7 @@ public sealed partial class Alcohol120
|
||||
currentExtraOffset += Marshal.SizeOf<TrackExtra>();
|
||||
currentTrackOffset += Marshal.SizeOf<Track>();
|
||||
}
|
||||
}
|
||||
else if(i < sessions)
|
||||
{
|
||||
(byte minute, byte second, byte frame) leadoutAmsf =
|
||||
@@ -887,6 +903,7 @@ public sealed partial class Alcohol120
|
||||
|
||||
_alcToc.Add(i, thisSessionTracks);
|
||||
}
|
||||
}
|
||||
|
||||
_alcFooter = new Footer
|
||||
{
|
||||
@@ -898,8 +915,8 @@ public sealed partial class Alcohol120
|
||||
|
||||
// Write header
|
||||
_descriptorStream.Seek(0, SeekOrigin.Begin);
|
||||
byte[] block = new byte[Marshal.SizeOf<Header>()];
|
||||
nint blockPtr = System.Runtime.InteropServices.Marshal.AllocHGlobal(Marshal.SizeOf<Header>());
|
||||
var block = new byte[Marshal.SizeOf<Header>()];
|
||||
nint blockPtr = System.Runtime.InteropServices.Marshal.AllocHGlobal(Marshal.SizeOf<Header>());
|
||||
System.Runtime.InteropServices.Marshal.StructureToPtr(header, blockPtr, true);
|
||||
System.Runtime.InteropServices.Marshal.Copy(blockPtr, block, 0, block.Length);
|
||||
System.Runtime.InteropServices.Marshal.FreeHGlobal(blockPtr);
|
||||
@@ -919,10 +936,7 @@ public sealed partial class Alcohol120
|
||||
|
||||
break;
|
||||
case 2048:
|
||||
_descriptorStream.Write(new byte[]
|
||||
{
|
||||
0x08, 0x02, 0x00, 0x00
|
||||
}, 0, 4);
|
||||
_descriptorStream.Write(new byte[] { 0x08, 0x02, 0x00, 0x00 }, 0, 4);
|
||||
|
||||
_descriptorStream.Write(_dmi, 0, 2048);
|
||||
|
||||
@@ -1013,10 +1027,7 @@ public sealed partial class Alcohol120
|
||||
_descriptorStream.Write(filename, 0, filename.Length);
|
||||
|
||||
// Write filename null termination
|
||||
_descriptorStream.Write(new byte[]
|
||||
{
|
||||
0, 0
|
||||
}, 0, 2);
|
||||
_descriptorStream.Write(new byte[] { 0, 0 }, 0, 2);
|
||||
|
||||
_descriptorStream.Flush();
|
||||
_descriptorStream.Close();
|
||||
@@ -1094,8 +1105,11 @@ public sealed partial class Alcohol120
|
||||
}
|
||||
|
||||
_imageStream.
|
||||
Seek((long)(track.FileOffset + ((sectorAddress - track.StartSector) * (ulong)(track.RawBytesPerSector + 96))) + track.RawBytesPerSector,
|
||||
SeekOrigin.Begin);
|
||||
Seek(
|
||||
(long)(track.FileOffset +
|
||||
(sectorAddress - track.StartSector) * (ulong)(track.RawBytesPerSector + 96)) +
|
||||
track.RawBytesPerSector,
|
||||
SeekOrigin.Begin);
|
||||
|
||||
_imageStream.Write(data, 0, data.Length);
|
||||
|
||||
@@ -1130,7 +1144,8 @@ public sealed partial class Alcohol120
|
||||
|
||||
switch(tag)
|
||||
{
|
||||
case SectorTagType.CdTrackFlags: return WriteSectorTag(data, sectorAddress, tag);
|
||||
case SectorTagType.CdTrackFlags:
|
||||
return WriteSectorTag(data, sectorAddress, tag);
|
||||
case SectorTagType.CdSectorSubchannel:
|
||||
{
|
||||
if(track.SubchannelType == 0)
|
||||
@@ -1152,8 +1167,10 @@ public sealed partial class Alcohol120
|
||||
for(uint i = 0; i < length; i++)
|
||||
{
|
||||
_imageStream.
|
||||
Seek((long)(track.FileOffset + ((i + sectorAddress - track.StartSector) * (ulong)(track.RawBytesPerSector + 96))) + track.RawBytesPerSector,
|
||||
SeekOrigin.Begin);
|
||||
Seek(
|
||||
(long)(track.FileOffset + (i + sectorAddress - track.StartSector) *
|
||||
(ulong)(track.RawBytesPerSector + 96)) + track.RawBytesPerSector,
|
||||
SeekOrigin.Begin);
|
||||
|
||||
_imageStream.Write(data, (int)(i * 96), 96);
|
||||
}
|
||||
@@ -1172,4 +1189,6 @@ public sealed partial class Alcohol120
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool SetMetadata(Metadata metadata) => false;
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -42,10 +42,11 @@ namespace Aaru.DiscImages;
|
||||
/// <summary>Implements reading and writing Anex-86 disk images</summary>
|
||||
public sealed partial class Anex86 : IWritableImage
|
||||
{
|
||||
IFilter _anexImageFilter;
|
||||
Header _header;
|
||||
ImageInfo _imageInfo;
|
||||
FileStream _writingStream;
|
||||
const string MODULE_NAME = "Anex86 plugin";
|
||||
IFilter _anexImageFilter;
|
||||
Header _header;
|
||||
ImageInfo _imageInfo;
|
||||
FileStream _writingStream;
|
||||
|
||||
public Anex86() => _imageInfo = new ImageInfo
|
||||
{
|
||||
@@ -70,6 +71,4 @@ public sealed partial class Anex86 : IWritableImage
|
||||
DriveSerialNumber = null,
|
||||
DriveFirmwareRevision = null
|
||||
};
|
||||
|
||||
const string MODULE_NAME = "Anex86 plugin";
|
||||
}
|
||||
@@ -39,6 +39,8 @@ namespace Aaru.DiscImages;
|
||||
|
||||
public sealed partial class Anex86
|
||||
{
|
||||
#region IWritableImage Members
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Identify(IFilter imageFilter)
|
||||
{
|
||||
@@ -48,21 +50,23 @@ public sealed partial class Anex86
|
||||
if(stream.Length < Marshal.SizeOf<Header>())
|
||||
return false;
|
||||
|
||||
byte[] hdrB = new byte[Marshal.SizeOf<Header>()];
|
||||
var hdrB = new byte[Marshal.SizeOf<Header>()];
|
||||
stream.EnsureRead(hdrB, 0, hdrB.Length);
|
||||
|
||||
_header = Marshal.SpanToStructureLittleEndian<Header>(hdrB);
|
||||
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "fdihdr.unknown = {0}", _header.unknown);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "fdihdr.hddtype = {0}", _header.hddtype);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "fdihdr.hdrSize = {0}", _header.hdrSize);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "fdihdr.dskSize = {0}", _header.dskSize);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "fdihdr.bps = {0}", _header.bps);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "fdihdr.spt = {0}", _header.spt);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "fdihdr.heads = {0}", _header.heads);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "fdihdr.unknown = {0}", _header.unknown);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "fdihdr.hddtype = {0}", _header.hddtype);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "fdihdr.hdrSize = {0}", _header.hdrSize);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "fdihdr.dskSize = {0}", _header.dskSize);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "fdihdr.bps = {0}", _header.bps);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "fdihdr.spt = {0}", _header.spt);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "fdihdr.heads = {0}", _header.heads);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "fdihdr.cylinders = {0}", _header.cylinders);
|
||||
|
||||
return stream.Length == _header.hdrSize + _header.dskSize &&
|
||||
_header.dskSize == _header.bps * _header.spt * _header.heads * _header.cylinders;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -41,25 +41,32 @@ namespace Aaru.DiscImages;
|
||||
|
||||
public sealed partial class Anex86
|
||||
{
|
||||
#region IWritableImage Members
|
||||
|
||||
/// <inheritdoc />
|
||||
public ImageInfo Info => _imageInfo;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Name => Localization.Anex86_Name;
|
||||
|
||||
/// <inheritdoc />
|
||||
public Guid Id => new("0410003E-6E7B-40E6-9328-BA5651ADF6B7");
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Author => Authors.NataliaPortillo;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Format => "Anex86 disk image";
|
||||
|
||||
/// <inheritdoc />
|
||||
public List<DumpHardware> DumpHardware => null;
|
||||
|
||||
/// <inheritdoc />
|
||||
public Metadata AaruMetadata => null;
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<MediaTagType> SupportedMediaTags => Array.Empty<MediaTagType>();
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<SectorTagType> SupportedSectorTags => Array.Empty<SectorTagType>();
|
||||
|
||||
@@ -76,21 +83,24 @@ public sealed partial class Anex86
|
||||
MediaType.ACORN_35_DS_DD, MediaType.DOS_35_DS_DD_8, MediaType.DOS_35_DS_DD_9, MediaType.ACORN_35_DS_HD,
|
||||
MediaType.DOS_525_HD, MediaType.ACORN_525_DS_DD, MediaType.DOS_35_HD, MediaType.XDF_525, MediaType.DMF,
|
||||
MediaType.XDF_35, MediaType.DOS_35_ED, MediaType.FDFORMAT_35_DD, MediaType.FDFORMAT_525_HD,
|
||||
MediaType.FDFORMAT_35_HD, MediaType.NEC_35_TD, MediaType.Unknown, MediaType.GENERIC_HDD, MediaType.FlashDrive,
|
||||
MediaType.CompactFlash, MediaType.CompactFlashType2, MediaType.PCCardTypeI, MediaType.PCCardTypeII,
|
||||
MediaType.PCCardTypeIII, MediaType.PCCardTypeIV, MediaType.MetaFloppy_Mod_I, MediaType.MetaFloppy_Mod_II
|
||||
};
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<(string name, Type type, string description, object @default)> SupportedOptions =>
|
||||
Array.Empty<(string name, Type type, string description, object @default)>();
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<string> KnownExtensions => new[]
|
||||
{
|
||||
".fdi", ".hdi"
|
||||
MediaType.FDFORMAT_35_HD, MediaType.NEC_35_TD, MediaType.Unknown, MediaType.GENERIC_HDD,
|
||||
MediaType.FlashDrive, MediaType.CompactFlash, MediaType.CompactFlashType2, MediaType.PCCardTypeI,
|
||||
MediaType.PCCardTypeII, MediaType.PCCardTypeIII, MediaType.PCCardTypeIV, MediaType.MetaFloppy_Mod_I,
|
||||
MediaType.MetaFloppy_Mod_II
|
||||
};
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<(string name, Type type, string description, object @default)> SupportedOptions =>
|
||||
Array.Empty<(string name, Type type, string description, object @default)>();
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<string> KnownExtensions => new[] { ".fdi", ".hdi" };
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsWriting { get; private set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public string ErrorMessage { get; private set; }
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -41,6 +41,8 @@ namespace Aaru.DiscImages;
|
||||
|
||||
public sealed partial class Anex86
|
||||
{
|
||||
#region IWritableImage Members
|
||||
|
||||
/// <inheritdoc />
|
||||
public ErrorNumber Open(IFilter imageFilter)
|
||||
{
|
||||
@@ -50,7 +52,7 @@ public sealed partial class Anex86
|
||||
if(stream.Length < Marshal.SizeOf<Header>())
|
||||
return ErrorNumber.InvalidArgument;
|
||||
|
||||
byte[] hdrB = new byte[Marshal.SizeOf<Header>()];
|
||||
var hdrB = new byte[Marshal.SizeOf<Header>()];
|
||||
stream.EnsureRead(hdrB, 0, hdrB.Length);
|
||||
|
||||
_header = Marshal.SpanToStructureLittleEndian<Header>(hdrB);
|
||||
@@ -98,10 +100,12 @@ public sealed partial class Anex86
|
||||
|
||||
Stream stream = _anexImageFilter.GetDataForkStream();
|
||||
|
||||
stream.Seek((long)((ulong)_header.hdrSize + (sectorAddress * _imageInfo.SectorSize)), SeekOrigin.Begin);
|
||||
stream.Seek((long)((ulong)_header.hdrSize + sectorAddress * _imageInfo.SectorSize), SeekOrigin.Begin);
|
||||
|
||||
stream.EnsureRead(buffer, 0, (int)(length * _imageInfo.SectorSize));
|
||||
|
||||
return ErrorNumber.NoError;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -36,6 +36,8 @@ namespace Aaru.DiscImages;
|
||||
|
||||
public sealed partial class Anex86
|
||||
{
|
||||
#region Nested type: Header
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct Header
|
||||
{
|
||||
@@ -48,4 +50,6 @@ public sealed partial class Anex86
|
||||
public int heads;
|
||||
public int cylinders;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -36,6 +36,8 @@ namespace Aaru.DiscImages;
|
||||
|
||||
public sealed partial class Anex86
|
||||
{
|
||||
#region IWritableImage Members
|
||||
|
||||
/// <inheritdoc />
|
||||
public ErrorNumber ReadMediaTag(MediaTagType tag, out byte[] buffer)
|
||||
{
|
||||
@@ -75,4 +77,6 @@ public sealed partial class Anex86
|
||||
|
||||
return ErrorNumber.NotSupported;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -44,9 +44,11 @@ namespace Aaru.DiscImages;
|
||||
|
||||
public sealed partial class Anex86
|
||||
{
|
||||
#region IWritableImage Members
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Create(string path, MediaType mediaType, Dictionary<string, string> options, ulong sectors,
|
||||
uint sectorSize)
|
||||
uint sectorSize)
|
||||
{
|
||||
if(sectorSize == 0)
|
||||
{
|
||||
@@ -133,7 +135,7 @@ public sealed partial class Anex86
|
||||
return false;
|
||||
}
|
||||
|
||||
_writingStream.Seek((long)(4096 + (sectorAddress * _imageInfo.SectorSize)), SeekOrigin.Begin);
|
||||
_writingStream.Seek((long)(4096 + sectorAddress * _imageInfo.SectorSize), SeekOrigin.Begin);
|
||||
_writingStream.Write(data, 0, data.Length);
|
||||
|
||||
ErrorMessage = "";
|
||||
@@ -165,7 +167,7 @@ public sealed partial class Anex86
|
||||
return false;
|
||||
}
|
||||
|
||||
_writingStream.Seek((long)(4096 + (sectorAddress * _imageInfo.SectorSize)), SeekOrigin.Begin);
|
||||
_writingStream.Seek((long)(4096 + sectorAddress * _imageInfo.SectorSize), SeekOrigin.Begin);
|
||||
_writingStream.Write(data, 0, data.Length);
|
||||
|
||||
ErrorMessage = "";
|
||||
@@ -200,8 +202,8 @@ public sealed partial class Anex86
|
||||
}
|
||||
|
||||
if(_imageInfo.MediaType is MediaType.Unknown or MediaType.GENERIC_HDD or MediaType.FlashDrive
|
||||
or MediaType.CompactFlash or MediaType.CompactFlashType2 or MediaType.PCCardTypeI
|
||||
or MediaType.PCCardTypeII or MediaType.PCCardTypeIII or MediaType.PCCardTypeIV &&
|
||||
or MediaType.CompactFlash or MediaType.CompactFlashType2 or MediaType.PCCardTypeI
|
||||
or MediaType.PCCardTypeII or MediaType.PCCardTypeIII or MediaType.PCCardTypeIV &&
|
||||
_header.cylinders == 0)
|
||||
{
|
||||
_header.cylinders = (int)(_imageInfo.Sectors / 8 / 33);
|
||||
@@ -226,7 +228,7 @@ public sealed partial class Anex86
|
||||
}
|
||||
}
|
||||
|
||||
byte[] hdr = new byte[Marshal.SizeOf<Header>()];
|
||||
var hdr = new byte[Marshal.SizeOf<Header>()];
|
||||
MemoryMarshal.Write(hdr, in _header);
|
||||
|
||||
_writingStream.Seek(0, SeekOrigin.Begin);
|
||||
@@ -296,4 +298,6 @@ public sealed partial class Anex86
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool SetMetadata(Metadata metadata) => false;
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -42,11 +42,12 @@ namespace Aaru.DiscImages;
|
||||
/// <summary>Implements reading and writing XGD emulator disk images</summary>
|
||||
public sealed partial class Apple2Mg : IWritableImage
|
||||
{
|
||||
IFilter _a2MgImageFilter;
|
||||
byte[] _decodedImage;
|
||||
Header _imageHeader;
|
||||
ImageInfo _imageInfo;
|
||||
FileStream _writingStream;
|
||||
const string MODULE_NAME = "2MG plugin";
|
||||
IFilter _a2MgImageFilter;
|
||||
byte[] _decodedImage;
|
||||
Header _imageHeader;
|
||||
ImageInfo _imageInfo;
|
||||
FileStream _writingStream;
|
||||
|
||||
public Apple2Mg() => _imageInfo = new ImageInfo
|
||||
{
|
||||
@@ -71,6 +72,4 @@ public sealed partial class Apple2Mg : IWritableImage
|
||||
DriveSerialNumber = null,
|
||||
DriveFirmwareRevision = null
|
||||
};
|
||||
|
||||
const string MODULE_NAME = "2MG plugin";
|
||||
}
|
||||
@@ -58,15 +58,9 @@ public sealed partial class Apple2Mg
|
||||
/// <summary>Disk image created by Aaru, "aaru"</summary>
|
||||
const uint CREATOR_AARU = 0x75726161;
|
||||
|
||||
const uint LOCKED_DISK = 0x80000000;
|
||||
const uint VALID_VOLUME_NUMBER = 0x00000100;
|
||||
const uint VOLUME_NUMBER_MASK = 0x000000FF;
|
||||
readonly int[] _deinterleave =
|
||||
{
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
|
||||
};
|
||||
readonly int[] _interleave =
|
||||
{
|
||||
0, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 15
|
||||
};
|
||||
const uint LOCKED_DISK = 0x80000000;
|
||||
const uint VALID_VOLUME_NUMBER = 0x00000100;
|
||||
const uint VOLUME_NUMBER_MASK = 0x000000FF;
|
||||
readonly int[] _deinterleave = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
|
||||
readonly int[] _interleave = { 0, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 15 };
|
||||
}
|
||||
@@ -34,8 +34,14 @@ namespace Aaru.DiscImages;
|
||||
|
||||
public sealed partial class Apple2Mg
|
||||
{
|
||||
#region Nested type: SectorOrder
|
||||
|
||||
enum SectorOrder : uint
|
||||
{
|
||||
Dos = 0, ProDos = 1, Nibbles = 2
|
||||
Dos = 0,
|
||||
ProDos = 1,
|
||||
Nibbles = 2
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -37,14 +37,14 @@ namespace Aaru.DiscImages;
|
||||
public sealed partial class Apple2Mg
|
||||
{
|
||||
MediaType GetMediaType() => _imageInfo.Sectors switch
|
||||
{
|
||||
455 => MediaType.Apple32SS,
|
||||
910 => MediaType.Apple32DS,
|
||||
560 => MediaType.Apple33SS,
|
||||
1120 => MediaType.Apple33DS,
|
||||
800 => MediaType.AppleSonySS,
|
||||
1600 => MediaType.AppleSonyDS,
|
||||
2880 => MediaType.DOS_35_HD,
|
||||
_ => MediaType.Unknown
|
||||
};
|
||||
{
|
||||
455 => MediaType.Apple32SS,
|
||||
910 => MediaType.Apple32DS,
|
||||
560 => MediaType.Apple33SS,
|
||||
1120 => MediaType.Apple33DS,
|
||||
800 => MediaType.AppleSonySS,
|
||||
1600 => MediaType.AppleSonyDS,
|
||||
2880 => MediaType.DOS_35_HD,
|
||||
_ => MediaType.Unknown
|
||||
};
|
||||
}
|
||||
@@ -38,6 +38,8 @@ namespace Aaru.DiscImages;
|
||||
|
||||
public sealed partial class Apple2Mg
|
||||
{
|
||||
#region IWritableImage Members
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Identify(IFilter imageFilter)
|
||||
{
|
||||
@@ -47,7 +49,7 @@ public sealed partial class Apple2Mg
|
||||
if(stream.Length < 65)
|
||||
return false;
|
||||
|
||||
byte[] header = new byte[64];
|
||||
var header = new byte[64];
|
||||
stream.EnsureRead(header, 0, 64);
|
||||
|
||||
Header hdr = Marshal.SpanToStructureLittleEndian<Header>(header);
|
||||
@@ -76,4 +78,6 @@ public sealed partial class Apple2Mg
|
||||
|
||||
return hdr.CreatorSpecificOffset + hdr.CreatorSpecificSize <= stream.Length;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -41,27 +41,35 @@ namespace Aaru.DiscImages;
|
||||
|
||||
public sealed partial class Apple2Mg
|
||||
{
|
||||
#region IWritableImage Members
|
||||
|
||||
/// <inheritdoc />
|
||||
public ImageInfo Info => _imageInfo;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Name => Localization.Apple2Mg_Name;
|
||||
|
||||
/// <inheritdoc />
|
||||
public Guid Id => new("CBAF8824-BA5F-415F-953A-19A03519B2D1");
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Author => Authors.NataliaPortillo;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Format => "Apple 2IMG";
|
||||
|
||||
/// <inheritdoc />
|
||||
public List<DumpHardware> DumpHardware => null;
|
||||
|
||||
/// <inheritdoc />
|
||||
public Metadata AaruMetadata => null;
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<MediaTagType> SupportedMediaTags => Array.Empty<MediaTagType>();
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<SectorTagType> SupportedSectorTags => Array.Empty<SectorTagType>();
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<MediaType> SupportedMediaTypes => new[]
|
||||
{
|
||||
@@ -70,16 +78,19 @@ public sealed partial class Apple2Mg
|
||||
MediaType.CompactFlashType2, MediaType.PCCardTypeI, MediaType.PCCardTypeII, MediaType.PCCardTypeIII,
|
||||
MediaType.PCCardTypeIV
|
||||
};
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<(string name, Type type, string description, object @default)> SupportedOptions =>
|
||||
Array.Empty<(string name, Type type, string description, object @default)>();
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<string> KnownExtensions => new[]
|
||||
{
|
||||
".2mg"
|
||||
};
|
||||
public IEnumerable<string> KnownExtensions => new[] { ".2mg" };
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsWriting { get; private set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public string ErrorMessage { get; private set; }
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -44,6 +44,8 @@ namespace Aaru.DiscImages;
|
||||
|
||||
public sealed partial class Apple2Mg
|
||||
{
|
||||
#region IWritableImage Members
|
||||
|
||||
/// <inheritdoc />
|
||||
public ErrorNumber Open(IFilter imageFilter)
|
||||
{
|
||||
@@ -52,12 +54,12 @@ public sealed partial class Apple2Mg
|
||||
|
||||
_imageHeader = new Header();
|
||||
|
||||
byte[] header = new byte[64];
|
||||
var header = new byte[64];
|
||||
stream.EnsureRead(header, 0, 64);
|
||||
byte[] magic = new byte[4];
|
||||
byte[] creator = new byte[4];
|
||||
var magic = new byte[4];
|
||||
var creator = new byte[4];
|
||||
|
||||
Array.Copy(header, 0, magic, 0, 4);
|
||||
Array.Copy(header, 0, magic, 0, 4);
|
||||
Array.Copy(header, 4, creator, 0, 4);
|
||||
|
||||
_imageHeader = Marshal.SpanToStructureLittleEndian<Header>(header);
|
||||
@@ -74,13 +76,13 @@ public sealed partial class Apple2Mg
|
||||
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "ImageHeader.creator = \"{0}\"", Encoding.ASCII.GetString(creator));
|
||||
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "ImageHeader.headerSize = {0}", _imageHeader.HeaderSize);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "ImageHeader.version = {0}", _imageHeader.Version);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "ImageHeader.imageFormat = {0}", _imageHeader.ImageFormat);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "ImageHeader.flags = 0x{0:X8}", _imageHeader.Flags);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "ImageHeader.blocks = {0}", _imageHeader.Blocks);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "ImageHeader.headerSize = {0}", _imageHeader.HeaderSize);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "ImageHeader.version = {0}", _imageHeader.Version);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "ImageHeader.imageFormat = {0}", _imageHeader.ImageFormat);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "ImageHeader.flags = 0x{0:X8}", _imageHeader.Flags);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "ImageHeader.blocks = {0}", _imageHeader.Blocks);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "ImageHeader.dataOffset = 0x{0:X8}", _imageHeader.DataOffset);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "ImageHeader.dataSize = {0}", _imageHeader.DataSize);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "ImageHeader.dataSize = {0}", _imageHeader.DataSize);
|
||||
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "ImageHeader.commentOffset = 0x{0:X8}", _imageHeader.CommentOffset);
|
||||
|
||||
@@ -140,11 +142,13 @@ public sealed partial class Apple2Mg
|
||||
? _interleave
|
||||
: _deinterleave;
|
||||
|
||||
for(int t = 0; t < 35; t++)
|
||||
for(var t = 0; t < 35; t++)
|
||||
{
|
||||
for(int s = 0; s < 16; s++)
|
||||
Array.Copy(tmp, (t * 16 * 256) + (s * 256), _decodedImage, (t * 16 * 256) + (offsets[s] * 256),
|
||||
for(var s = 0; s < 16; s++)
|
||||
{
|
||||
Array.Copy(tmp, t * 16 * 256 + s * 256, _decodedImage, t * 16 * 256 + offsets[s] * 256,
|
||||
256);
|
||||
}
|
||||
}
|
||||
|
||||
_imageInfo.Sectors = 560;
|
||||
@@ -158,11 +162,13 @@ public sealed partial class Apple2Mg
|
||||
_decodedImage = new byte[_imageHeader.DataSize];
|
||||
offsets = _interleave;
|
||||
|
||||
for(int t = 0; t < 200; t++)
|
||||
for(var t = 0; t < 200; t++)
|
||||
{
|
||||
for(int s = 0; s < 16; s++)
|
||||
Array.Copy(tmp, (t * 16 * 256) + (s * 256), _decodedImage, (t * 16 * 256) + (offsets[s] * 256),
|
||||
for(var s = 0; s < 16; s++)
|
||||
{
|
||||
Array.Copy(tmp, t * 16 * 256 + s * 256, _decodedImage, t * 16 * 256 + offsets[s] * 256,
|
||||
256);
|
||||
}
|
||||
}
|
||||
|
||||
_imageInfo.Sectors = 1600;
|
||||
@@ -180,18 +186,19 @@ public sealed partial class Apple2Mg
|
||||
_imageInfo.ImageSize = _imageHeader.DataSize;
|
||||
|
||||
_imageInfo.Application = _imageHeader.Creator switch
|
||||
{
|
||||
CREATOR_ASIMOV => "ASIMOV2",
|
||||
CREATOR_BERNIE => "Bernie ][ the Rescue",
|
||||
CREATOR_CATAKIG => "Catakig",
|
||||
CREATOR_SHEPPY => "Sheppy's ImageMaker",
|
||||
CREATOR_SWEET => "Sweet16",
|
||||
CREATOR_XGS => "XGS",
|
||||
CREATOR_CIDER => "CiderPress",
|
||||
CREATOR_DIC => "DiscImageChef",
|
||||
CREATOR_AARU => "Aaru",
|
||||
_ => string.Format(Localization.Unknown_creator_code_0, Encoding.ASCII.GetString(creator))
|
||||
};
|
||||
{
|
||||
CREATOR_ASIMOV => "ASIMOV2",
|
||||
CREATOR_BERNIE => "Bernie ][ the Rescue",
|
||||
CREATOR_CATAKIG => "Catakig",
|
||||
CREATOR_SHEPPY => "Sheppy's ImageMaker",
|
||||
CREATOR_SWEET => "Sweet16",
|
||||
CREATOR_XGS => "XGS",
|
||||
CREATOR_CIDER => "CiderPress",
|
||||
CREATOR_DIC => "DiscImageChef",
|
||||
CREATOR_AARU => "Aaru",
|
||||
_ => string.Format(Localization.Unknown_creator_code_0,
|
||||
Encoding.ASCII.GetString(creator))
|
||||
};
|
||||
|
||||
_imageInfo.Version = _imageHeader.Version.ToString();
|
||||
|
||||
@@ -200,7 +207,7 @@ public sealed partial class Apple2Mg
|
||||
{
|
||||
stream.Seek(_imageHeader.CommentOffset, SeekOrigin.Begin);
|
||||
|
||||
byte[] comments = new byte[_imageHeader.CommentSize];
|
||||
var comments = new byte[_imageHeader.CommentSize];
|
||||
stream.EnsureRead(comments, 0, (int)_imageHeader.CommentSize);
|
||||
_imageInfo.Comments = Encoding.ASCII.GetString(comments);
|
||||
}
|
||||
@@ -289,17 +296,21 @@ public sealed partial class Apple2Mg
|
||||
buffer = new byte[length * _imageInfo.SectorSize];
|
||||
|
||||
if(_decodedImage != null)
|
||||
{
|
||||
Array.Copy(_decodedImage, (long)(sectorAddress * _imageInfo.SectorSize), buffer, 0,
|
||||
length * _imageInfo.SectorSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
Stream stream = _a2MgImageFilter.GetDataForkStream();
|
||||
|
||||
stream.Seek((long)(_imageHeader.DataOffset + (sectorAddress * _imageInfo.SectorSize)), SeekOrigin.Begin);
|
||||
stream.Seek((long)(_imageHeader.DataOffset + sectorAddress * _imageInfo.SectorSize), SeekOrigin.Begin);
|
||||
|
||||
stream.EnsureRead(buffer, 0, (int)(length * _imageInfo.SectorSize));
|
||||
}
|
||||
|
||||
return ErrorNumber.NoError;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -37,7 +37,10 @@ namespace Aaru.DiscImages;
|
||||
|
||||
public sealed partial class Apple2Mg
|
||||
{
|
||||
[SuppressMessage("ReSharper", "NotAccessedField.Local"), StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
#region Nested type: Header
|
||||
|
||||
[SuppressMessage("ReSharper", "NotAccessedField.Local")]
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct Header
|
||||
{
|
||||
/// <summary>Offset 0x00, magic</summary>
|
||||
@@ -75,4 +78,6 @@ public sealed partial class Apple2Mg
|
||||
/// <summary>Offset 0x3C, reserved, should be zero</summary>
|
||||
public readonly uint Reserved4;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -36,6 +36,8 @@ namespace Aaru.DiscImages;
|
||||
|
||||
public sealed partial class Apple2Mg
|
||||
{
|
||||
#region IWritableImage Members
|
||||
|
||||
/// <inheritdoc />
|
||||
public ErrorNumber ReadMediaTag(MediaTagType tag, out byte[] buffer)
|
||||
{
|
||||
@@ -75,4 +77,6 @@ public sealed partial class Apple2Mg
|
||||
|
||||
return ErrorNumber.NotSupported;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -44,18 +44,22 @@ namespace Aaru.DiscImages;
|
||||
|
||||
public sealed partial class Apple2Mg
|
||||
{
|
||||
#region IWritableImage Members
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Create(string path, MediaType mediaType, Dictionary<string, string> options, ulong sectors,
|
||||
uint sectorSize)
|
||||
uint sectorSize)
|
||||
{
|
||||
if(sectorSize != 512)
|
||||
{
|
||||
if(sectorSize != 256 ||
|
||||
(mediaType != MediaType.Apple32SS && mediaType != MediaType.Apple33SS))
|
||||
mediaType != MediaType.Apple32SS && mediaType != MediaType.Apple33SS)
|
||||
{
|
||||
ErrorMessage = Localization.Unsupported_sector_size;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if(!SupportedMediaTypes.Contains(mediaType))
|
||||
{
|
||||
@@ -127,7 +131,7 @@ public sealed partial class Apple2Mg
|
||||
return false;
|
||||
}
|
||||
|
||||
_writingStream.Seek((long)(0x40 + (sectorAddress * _imageInfo.SectorSize)), SeekOrigin.Begin);
|
||||
_writingStream.Seek((long)(0x40 + sectorAddress * _imageInfo.SectorSize), SeekOrigin.Begin);
|
||||
_writingStream.Write(data, 0, data.Length);
|
||||
|
||||
ErrorMessage = "";
|
||||
@@ -159,7 +163,7 @@ public sealed partial class Apple2Mg
|
||||
return false;
|
||||
}
|
||||
|
||||
_writingStream.Seek((long)(0x40 + (sectorAddress * _imageInfo.SectorSize)), SeekOrigin.Begin);
|
||||
_writingStream.Seek((long)(0x40 + sectorAddress * _imageInfo.SectorSize), SeekOrigin.Begin);
|
||||
_writingStream.Write(data, 0, data.Length);
|
||||
|
||||
ErrorMessage = "";
|
||||
@@ -193,8 +197,8 @@ public sealed partial class Apple2Mg
|
||||
return false;
|
||||
}
|
||||
|
||||
_writingStream.Seek(0x40 + (17 * 16 * 256), SeekOrigin.Begin);
|
||||
byte[] tmp = new byte[256];
|
||||
_writingStream.Seek(0x40 + 17 * 16 * 256, SeekOrigin.Begin);
|
||||
var tmp = new byte[256];
|
||||
_writingStream.EnsureRead(tmp, 0, tmp.Length);
|
||||
|
||||
bool isDos = tmp[0x01] == 17 && tmp[0x02] < 16 && tmp[0x27] <= 122 && tmp[0x34] == 35 && tmp[0x35] == 16 &&
|
||||
@@ -206,7 +210,8 @@ public sealed partial class Apple2Mg
|
||||
Creator = CREATOR_AARU,
|
||||
DataOffset = 0x40,
|
||||
DataSize = (uint)(_imageInfo.Sectors * _imageInfo.SectorSize),
|
||||
Flags = (uint)(_imageInfo.LastMediaSequence != 0 ? VALID_VOLUME_NUMBER + (_imageInfo.MediaSequence & 0xFF)
|
||||
Flags = (uint)(_imageInfo.LastMediaSequence != 0
|
||||
? VALID_VOLUME_NUMBER + (_imageInfo.MediaSequence & 0xFF)
|
||||
: 0),
|
||||
HeaderSize = 0x40,
|
||||
ImageFormat = isDos ? SectorOrder.Dos : SectorOrder.ProDos,
|
||||
@@ -224,8 +229,8 @@ public sealed partial class Apple2Mg
|
||||
_writingStream.WriteByte(0);
|
||||
}
|
||||
|
||||
byte[] hdr = new byte[Marshal.SizeOf<Header>()];
|
||||
nint hdrPtr = System.Runtime.InteropServices.Marshal.AllocHGlobal(Marshal.SizeOf<Header>());
|
||||
var hdr = new byte[Marshal.SizeOf<Header>()];
|
||||
nint hdrPtr = System.Runtime.InteropServices.Marshal.AllocHGlobal(Marshal.SizeOf<Header>());
|
||||
System.Runtime.InteropServices.Marshal.StructureToPtr(_imageHeader, hdrPtr, true);
|
||||
System.Runtime.InteropServices.Marshal.Copy(hdrPtr, hdr, 0, hdr.Length);
|
||||
System.Runtime.InteropServices.Marshal.FreeHGlobal(hdrPtr);
|
||||
@@ -276,4 +281,6 @@ public sealed partial class Apple2Mg
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool SetMetadata(Metadata metadata) => false;
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -34,12 +34,6 @@ namespace Aaru.DiscImages;
|
||||
|
||||
public sealed partial class AppleDos
|
||||
{
|
||||
readonly int[] _deinterleave =
|
||||
{
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
|
||||
};
|
||||
readonly int[] _interleave =
|
||||
{
|
||||
0, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 15
|
||||
};
|
||||
readonly int[] _deinterleave = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
|
||||
readonly int[] _interleave = { 0, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 15 };
|
||||
}
|
||||
@@ -37,6 +37,8 @@ namespace Aaru.DiscImages;
|
||||
|
||||
public sealed partial class AppleDos
|
||||
{
|
||||
#region IWritableImage Members
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Identify(IFilter imageFilter)
|
||||
{
|
||||
@@ -44,4 +46,6 @@ public sealed partial class AppleDos
|
||||
|
||||
return imageFilter.DataForkLength == 143360 && _extension is ".po" or ".do";
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -41,42 +41,52 @@ namespace Aaru.DiscImages;
|
||||
|
||||
public sealed partial class AppleDos
|
||||
{
|
||||
#region IWritableImage Members
|
||||
|
||||
/// <inheritdoc />
|
||||
public ImageInfo Info => _imageInfo;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Name => Localization.AppleDos_Name;
|
||||
|
||||
/// <inheritdoc />
|
||||
public Guid Id => new("A5828AC0-62C9-4304-81D4-EFD4AAE47360");
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Author => Authors.NataliaPortillo;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Format => _extension == ".po" ? "Apple ][ Interleaved Disk Image (ProDOS order)"
|
||||
public string Format => _extension == ".po"
|
||||
? "Apple ][ Interleaved Disk Image (ProDOS order)"
|
||||
: "Apple ][ Interleaved Disk Image (DOS order)";
|
||||
|
||||
/// <inheritdoc />
|
||||
public List<DumpHardware> DumpHardware => null;
|
||||
|
||||
/// <inheritdoc />
|
||||
public Metadata AaruMetadata => null;
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<MediaTagType> SupportedMediaTags => Array.Empty<MediaTagType>();
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<SectorTagType> SupportedSectorTags => Array.Empty<SectorTagType>();
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<MediaType> SupportedMediaTypes => new[]
|
||||
{
|
||||
MediaType.Apple33SS
|
||||
};
|
||||
public IEnumerable<MediaType> SupportedMediaTypes => new[] { MediaType.Apple33SS };
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<(string name, Type type, string description, object @default)> SupportedOptions =>
|
||||
Array.Empty<(string name, Type type, string description, object @default)>();
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<string> KnownExtensions => new[]
|
||||
{
|
||||
".do", ".po"
|
||||
};
|
||||
public IEnumerable<string> KnownExtensions => new[] { ".do", ".po" };
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsWriting { get; private set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public string ErrorMessage { get; private set; }
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -41,13 +41,15 @@ namespace Aaru.DiscImages;
|
||||
|
||||
public sealed partial class AppleDos
|
||||
{
|
||||
#region IWritableImage Members
|
||||
|
||||
/// <inheritdoc />
|
||||
public ErrorNumber Open(IFilter imageFilter)
|
||||
{
|
||||
Stream stream = imageFilter.GetDataForkStream();
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
byte[] tmp = new byte[imageFilter.DataForkLength];
|
||||
var tmp = new byte[imageFilter.DataForkLength];
|
||||
stream.EnsureRead(tmp, 0, tmp.Length);
|
||||
|
||||
_extension = Path.GetExtension(imageFilter.Filename)?.ToLower();
|
||||
@@ -71,11 +73,13 @@ public sealed partial class AppleDos
|
||||
? _interleave
|
||||
: _deinterleave;
|
||||
|
||||
for(int t = 0; t < 35; t++)
|
||||
for(var t = 0; t < 35; t++)
|
||||
{
|
||||
for(int s = 0; s < 16; s++)
|
||||
Array.Copy(tmp, (t * 16 * 256) + (s * 256), _deinterleaved, (t * 16 * 256) + (offsets[s] * 256),
|
||||
for(var s = 0; s < 16; s++)
|
||||
{
|
||||
Array.Copy(tmp, t * 16 * 256 + s * 256, _deinterleaved, t * 16 * 256 + offsets[s] * 256,
|
||||
256);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,4 +118,6 @@ public sealed partial class AppleDos
|
||||
|
||||
return ErrorNumber.NoError;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -36,6 +36,8 @@ namespace Aaru.DiscImages;
|
||||
|
||||
public sealed partial class AppleDos
|
||||
{
|
||||
#region IWritableImage Members
|
||||
|
||||
/// <inheritdoc />
|
||||
public ErrorNumber ReadSectorTag(ulong sectorAddress, SectorTagType tag, out byte[] buffer)
|
||||
{
|
||||
@@ -75,4 +77,6 @@ public sealed partial class AppleDos
|
||||
|
||||
return ErrorNumber.NotSupported;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -42,9 +42,11 @@ namespace Aaru.DiscImages;
|
||||
|
||||
public sealed partial class AppleDos
|
||||
{
|
||||
#region IWritableImage Members
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Create(string path, MediaType mediaType, Dictionary<string, string> options, ulong sectors,
|
||||
uint sectorSize)
|
||||
uint sectorSize)
|
||||
{
|
||||
if(sectorSize != 256)
|
||||
{
|
||||
@@ -61,8 +63,8 @@ public sealed partial class AppleDos
|
||||
return false;
|
||||
}
|
||||
|
||||
if((mediaType == MediaType.Apple32SS && sectors != 455) ||
|
||||
(mediaType == MediaType.Apple33SS && sectors != 560))
|
||||
if(mediaType == MediaType.Apple32SS && sectors != 455 ||
|
||||
mediaType == MediaType.Apple33SS && sectors != 560)
|
||||
{
|
||||
ErrorMessage = Localization.Incorrect_number_of_sectors_for_media;
|
||||
|
||||
@@ -189,10 +191,12 @@ public sealed partial class AppleDos
|
||||
? _interleave
|
||||
: _deinterleave;
|
||||
|
||||
for(int t = 0; t < 35; t++)
|
||||
for(int s = 0; s < 16; s++)
|
||||
Array.Copy(_deinterleaved, (t * 16 * 256) + (offsets[s] * 256), tmp, (t * 16 * 256) + (s * 256),
|
||||
256);
|
||||
for(var t = 0; t < 35; t++)
|
||||
for(var s = 0; s < 16; s++)
|
||||
{
|
||||
Array.Copy(_deinterleaved, t * 16 * 256 + offsets[s] * 256, tmp, t * 16 * 256 + s * 256,
|
||||
256);
|
||||
}
|
||||
}
|
||||
|
||||
_writingStream.Seek(0, SeekOrigin.Begin);
|
||||
@@ -234,4 +238,6 @@ public sealed partial class AppleDos
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool SetMetadata(Metadata metadata) => false;
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -42,6 +42,7 @@ namespace Aaru.DiscImages;
|
||||
/// <summary>Implements reading nibbelized Apple II disk images</summary>
|
||||
public sealed partial class AppleNib : IMediaImage
|
||||
{
|
||||
const string MODULE_NAME = "Apple NIB Plugin";
|
||||
Dictionary<ulong, byte[]> _addressFields;
|
||||
Dictionary<ulong, byte[]> _cookedSectors;
|
||||
ImageInfo _imageInfo;
|
||||
@@ -70,6 +71,4 @@ public sealed partial class AppleNib : IMediaImage
|
||||
DriveSerialNumber = null,
|
||||
DriveFirmwareRevision = null
|
||||
};
|
||||
|
||||
const string MODULE_NAME = "Apple NIB Plugin";
|
||||
}
|
||||
@@ -37,39 +37,15 @@ namespace Aaru.DiscImages;
|
||||
[SuppressMessage("ReSharper", "UnusedMember.Local")]
|
||||
public sealed partial class AppleNib
|
||||
{
|
||||
readonly byte[] _apple3Sign =
|
||||
{
|
||||
0x8D, 0xD0, 0x03, 0x4C, 0xC7, 0xA4
|
||||
};
|
||||
readonly byte[] _cpmSign =
|
||||
{
|
||||
0xA2, 0x55, 0xA9, 0x00, 0x9D, 0x00, 0x0D, 0xCA
|
||||
};
|
||||
readonly byte[] _dosSign =
|
||||
{
|
||||
0xA2, 0x02, 0x8E, 0x52
|
||||
};
|
||||
readonly ulong[] _dosSkewing =
|
||||
{
|
||||
0, 7, 14, 6, 13, 5, 12, 4, 11, 3, 10, 2, 9, 1, 8, 15
|
||||
};
|
||||
readonly byte[] _driString = "COPYRIGHT (C) 1979, DIGITAL RESEARCH"u8.ToArray();
|
||||
readonly byte[] _pascalSign =
|
||||
{
|
||||
0x08, 0xA5, 0x0F, 0x29
|
||||
};
|
||||
readonly byte[] _pascalString = "SYSTE.APPLE"u8.ToArray();
|
||||
readonly byte[] _pascal2Sign =
|
||||
{
|
||||
0xFF, 0xA2, 0x00, 0x8E
|
||||
};
|
||||
readonly byte[] _prodosString = "PRODOS"u8.ToArray();
|
||||
readonly ulong[] _proDosSkewing =
|
||||
{
|
||||
0, 8, 1, 9, 2, 10, 3, 11, 4, 12, 5, 13, 6, 14, 7, 15
|
||||
};
|
||||
readonly byte[] _sosSign =
|
||||
{
|
||||
0xC9, 0x20, 0xF0, 0x3E
|
||||
};
|
||||
readonly byte[] _apple3Sign = { 0x8D, 0xD0, 0x03, 0x4C, 0xC7, 0xA4 };
|
||||
readonly byte[] _cpmSign = { 0xA2, 0x55, 0xA9, 0x00, 0x9D, 0x00, 0x0D, 0xCA };
|
||||
readonly byte[] _dosSign = { 0xA2, 0x02, 0x8E, 0x52 };
|
||||
readonly ulong[] _dosSkewing = { 0, 7, 14, 6, 13, 5, 12, 4, 11, 3, 10, 2, 9, 1, 8, 15 };
|
||||
readonly byte[] _driString = "COPYRIGHT (C) 1979, DIGITAL RESEARCH"u8.ToArray();
|
||||
readonly byte[] _pascal2Sign = { 0xFF, 0xA2, 0x00, 0x8E };
|
||||
readonly byte[] _pascalSign = { 0x08, 0xA5, 0x0F, 0x29 };
|
||||
readonly byte[] _pascalString = "SYSTE.APPLE"u8.ToArray();
|
||||
readonly ulong[] _proDosSkewing = { 0, 8, 1, 9, 2, 10, 3, 11, 4, 12, 5, 13, 6, 14, 7, 15 };
|
||||
readonly byte[] _prodosString = "PRODOS"u8.ToArray();
|
||||
readonly byte[] _sosSign = { 0xC9, 0x20, 0xF0, 0x3E };
|
||||
}
|
||||
@@ -39,6 +39,8 @@ namespace Aaru.DiscImages;
|
||||
|
||||
public sealed partial class AppleNib
|
||||
{
|
||||
#region IMediaImage Members
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Identify(IFilter imageFilter)
|
||||
{
|
||||
@@ -48,9 +50,11 @@ public sealed partial class AppleNib
|
||||
if(stream.Length < 512)
|
||||
return false;
|
||||
|
||||
byte[] test = new byte[512];
|
||||
var test = new byte[512];
|
||||
stream.EnsureRead(test, 0, 512);
|
||||
|
||||
return Apple2.IsApple2GCR(test);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -39,19 +39,28 @@ namespace Aaru.DiscImages;
|
||||
|
||||
public sealed partial class AppleNib
|
||||
{
|
||||
#region IMediaImage Members
|
||||
|
||||
/// <inheritdoc />
|
||||
public ImageInfo Info => _imageInfo;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Name => Localization.AppleNib_Name;
|
||||
|
||||
/// <inheritdoc />
|
||||
public Guid Id => new("AE171AE8-6747-49CC-B861-9D450B7CD42E");
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Author => Authors.NataliaPortillo;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Format => "Apple nibbles";
|
||||
|
||||
/// <inheritdoc />
|
||||
public List<DumpHardware> DumpHardware => null;
|
||||
|
||||
/// <inheritdoc />
|
||||
public Metadata AaruMetadata => null;
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -44,6 +44,8 @@ namespace Aaru.DiscImages;
|
||||
|
||||
public sealed partial class AppleNib
|
||||
{
|
||||
#region IMediaImage Members
|
||||
|
||||
/// <inheritdoc />
|
||||
public ErrorNumber Open(IFilter imageFilter)
|
||||
{
|
||||
@@ -53,7 +55,7 @@ public sealed partial class AppleNib
|
||||
if(stream.Length < 512)
|
||||
return ErrorNumber.InvalidArgument;
|
||||
|
||||
byte[] buffer = new byte[stream.Length];
|
||||
var buffer = new byte[stream.Length];
|
||||
stream.EnsureRead(buffer, 0, buffer.Length);
|
||||
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Decoding_whole_image);
|
||||
@@ -62,10 +64,10 @@ public sealed partial class AppleNib
|
||||
|
||||
Dictionary<ulong, Apple2.RawSector> rawSectors = new();
|
||||
|
||||
int spt = 0;
|
||||
bool allTracksEqual = true;
|
||||
var spt = 0;
|
||||
var allTracksEqual = true;
|
||||
|
||||
for(int i = 1; i < tracks.Count; i++)
|
||||
for(var i = 1; i < tracks.Count; i++)
|
||||
allTracksEqual &= tracks[i - 1].sectors.Length == tracks[i].sectors.Length;
|
||||
|
||||
if(allTracksEqual)
|
||||
@@ -76,11 +78,12 @@ public sealed partial class AppleNib
|
||||
|
||||
// Detect ProDOS skewed disks
|
||||
if(skewed)
|
||||
{
|
||||
foreach(bool isDos in from sector in tracks[17].sectors
|
||||
where sector.addressField.sector.SequenceEqual(new byte[]
|
||||
{
|
||||
170, 170
|
||||
}) select Apple2.DecodeSector(sector) into sector0 where sector0 != null
|
||||
where sector.addressField.sector.SequenceEqual(new byte[] { 170, 170 })
|
||||
select Apple2.DecodeSector(sector)
|
||||
into sector0
|
||||
where sector0 != null
|
||||
select sector0[0x01] == 17 && sector0[0x02] < 16 && sector0[0x27] <= 122 &&
|
||||
sector0[0x34] == 35 && sector0[0x35] == 16 && sector0[0x36] == 0 &&
|
||||
sector0[0x37] == 1)
|
||||
@@ -89,16 +92,20 @@ public sealed partial class AppleNib
|
||||
skewing = _dosSkewing;
|
||||
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME,
|
||||
skewing.SequenceEqual(_dosSkewing) ? Localization.Using_DOS_skewing
|
||||
skewing.SequenceEqual(_dosSkewing)
|
||||
? Localization.Using_DOS_skewing
|
||||
: Localization.Using_ProDOS_skewing);
|
||||
}
|
||||
}
|
||||
|
||||
for(int i = 0; i < tracks.Count; i++)
|
||||
for(var i = 0; i < tracks.Count; i++)
|
||||
{
|
||||
foreach(Apple2.RawSector sector in tracks[i].sectors)
|
||||
{
|
||||
if(skewed && spt != 0)
|
||||
{
|
||||
ulong sectorNo = (ulong)((((sector.addressField.sector[0] & 0x55) << 1) |
|
||||
(sector.addressField.sector[1] & 0x55)) & 0xFF);
|
||||
var sectorNo = (ulong)(((sector.addressField.sector[0] & 0x55) << 1 |
|
||||
sector.addressField.sector[1] & 0x55) & 0xFF);
|
||||
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME,
|
||||
Localization.Hardware_sector_0_of_track_1_goes_to_logical_sector_2,
|
||||
@@ -112,6 +119,8 @@ public sealed partial class AppleNib
|
||||
rawSectors.Add(_imageInfo.Sectors, sector);
|
||||
_imageInfo.Sectors++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Got_0_sectors, _imageInfo.Sectors);
|
||||
|
||||
@@ -137,11 +146,11 @@ public sealed partial class AppleNib
|
||||
_imageInfo.MediaTitle = Path.GetFileNameWithoutExtension(imageFilter.Filename);
|
||||
|
||||
_imageInfo.MediaType = _imageInfo.Sectors switch
|
||||
{
|
||||
455 => MediaType.Apple32SS,
|
||||
560 => MediaType.Apple33SS,
|
||||
_ => MediaType.Unknown
|
||||
};
|
||||
{
|
||||
455 => MediaType.Apple32SS,
|
||||
560 => MediaType.Apple33SS,
|
||||
_ => MediaType.Unknown
|
||||
};
|
||||
|
||||
_imageInfo.SectorSize = 256;
|
||||
_imageInfo.MetadataMediaType = MetadataMediaType.BlockMedia;
|
||||
@@ -288,4 +297,6 @@ public sealed partial class AppleNib
|
||||
|
||||
return ErrorNumber.NoError;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -36,6 +36,8 @@ namespace Aaru.DiscImages;
|
||||
|
||||
public sealed partial class AppleNib
|
||||
{
|
||||
#region IMediaImage Members
|
||||
|
||||
/// <inheritdoc />
|
||||
public ErrorNumber ReadMediaTag(MediaTagType tag, out byte[] buffer)
|
||||
{
|
||||
@@ -43,4 +45,6 @@ public sealed partial class AppleNib
|
||||
|
||||
return ErrorNumber.NotSupported;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -43,7 +43,8 @@ namespace Aaru.DiscImages;
|
||||
/// <summary>Implements reading and writing Apridisk disk images</summary>
|
||||
public sealed partial class Apridisk : IWritableImage
|
||||
{
|
||||
ImageInfo _imageInfo;
|
||||
const string MODULE_NAME = "Apridisk plugin";
|
||||
ImageInfo _imageInfo;
|
||||
|
||||
// Cylinder by head, sector data matrix
|
||||
byte[][][][] _sectorsData;
|
||||
@@ -72,6 +73,4 @@ public sealed partial class Apridisk : IWritableImage
|
||||
DriveSerialNumber = null,
|
||||
DriveFirmwareRevision = null
|
||||
};
|
||||
|
||||
const string MODULE_NAME = "Apridisk plugin";
|
||||
}
|
||||
@@ -39,7 +39,7 @@ public sealed partial class Apridisk
|
||||
{
|
||||
static uint Decompress(byte[] compressed, out byte[] decompressed)
|
||||
{
|
||||
int readp = 0;
|
||||
var readp = 0;
|
||||
int cLen = compressed.Length;
|
||||
var buffer = new MemoryStream();
|
||||
|
||||
@@ -47,10 +47,10 @@ public sealed partial class Apridisk
|
||||
|
||||
while(cLen >= 3)
|
||||
{
|
||||
ushort blklen = BitConverter.ToUInt16(compressed, readp);
|
||||
var blklen = BitConverter.ToUInt16(compressed, readp);
|
||||
readp += 2;
|
||||
|
||||
for(int i = 0; i < blklen; i++)
|
||||
for(var i = 0; i < blklen; i++)
|
||||
buffer.WriteByte(compressed[readp]);
|
||||
|
||||
uLen += blklen;
|
||||
|
||||
@@ -34,14 +34,25 @@ namespace Aaru.DiscImages;
|
||||
|
||||
public sealed partial class Apridisk
|
||||
{
|
||||
enum RecordType : uint
|
||||
{
|
||||
Deleted = 0xE31D0000, Sector = 0xE31D0001, Comment = 0xE31D0002,
|
||||
Creator = 0xE31D0003
|
||||
}
|
||||
#region Nested type: CompressType
|
||||
|
||||
enum CompressType : ushort
|
||||
{
|
||||
Uncompresed = 0x9E90, Compressed = 0x3E5A
|
||||
Uncompresed = 0x9E90,
|
||||
Compressed = 0x3E5A
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Nested type: RecordType
|
||||
|
||||
enum RecordType : uint
|
||||
{
|
||||
Deleted = 0xE31D0000,
|
||||
Sector = 0xE31D0001,
|
||||
Comment = 0xE31D0002,
|
||||
Creator = 0xE31D0003
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -36,9 +36,9 @@ public sealed partial class Apridisk
|
||||
{
|
||||
(ushort cylinder, byte head, byte sector) LbaToChs(ulong lba)
|
||||
{
|
||||
ushort cylinder = (ushort)(lba / (_imageInfo.Heads * _imageInfo.SectorsPerTrack));
|
||||
byte head = (byte)(lba / _imageInfo.SectorsPerTrack % _imageInfo.Heads);
|
||||
byte sector = (byte)((lba % _imageInfo.SectorsPerTrack) + 1);
|
||||
var cylinder = (ushort)(lba / (_imageInfo.Heads * _imageInfo.SectorsPerTrack));
|
||||
var head = (byte)(lba / _imageInfo.SectorsPerTrack % _imageInfo.Heads);
|
||||
var sector = (byte)(lba % _imageInfo.SectorsPerTrack + 1);
|
||||
|
||||
return (cylinder, head, sector);
|
||||
}
|
||||
|
||||
@@ -39,6 +39,8 @@ namespace Aaru.DiscImages;
|
||||
|
||||
public sealed partial class Apridisk
|
||||
{
|
||||
#region IWritableImage Members
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Identify(IFilter imageFilter)
|
||||
{
|
||||
@@ -48,9 +50,11 @@ public sealed partial class Apridisk
|
||||
if(stream.Length < _signature.Length)
|
||||
return false;
|
||||
|
||||
byte[] sigB = new byte[_signature.Length];
|
||||
var sigB = new byte[_signature.Length];
|
||||
stream.EnsureRead(sigB, 0, _signature.Length);
|
||||
|
||||
return sigB.SequenceEqual(_signature);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -41,25 +41,32 @@ namespace Aaru.DiscImages;
|
||||
|
||||
public sealed partial class Apridisk
|
||||
{
|
||||
#region IWritableImage Members
|
||||
|
||||
/// <inheritdoc />
|
||||
public ImageInfo Info => _imageInfo;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Name => Localization.Apridisk_Name;
|
||||
|
||||
/// <inheritdoc />
|
||||
public Guid Id => new("43408CF3-6DB3-449F-A779-2B0E497C5B14");
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Author => Authors.NataliaPortillo;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Format => "ACT Apricot disk image";
|
||||
|
||||
/// <inheritdoc />
|
||||
public List<DumpHardware> DumpHardware => null;
|
||||
|
||||
/// <inheritdoc />
|
||||
public Metadata AaruMetadata => null;
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<MediaTagType> SupportedMediaTags => Array.Empty<MediaTagType>();
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<SectorTagType> SupportedSectorTags => Array.Empty<SectorTagType>();
|
||||
|
||||
@@ -69,24 +76,27 @@ public sealed partial class Apridisk
|
||||
{
|
||||
MediaType.ACORN_35_DS_DD, MediaType.ACORN_35_DS_HD, MediaType.Apricot_35, MediaType.ATARI_35_DS_DD,
|
||||
MediaType.ATARI_35_DS_DD_11, MediaType.ATARI_35_SS_DD, MediaType.ATARI_35_SS_DD_11, MediaType.DMF,
|
||||
MediaType.DMF_82, MediaType.DOS_35_DS_DD_8, MediaType.DOS_35_DS_DD_9, MediaType.DOS_35_ED, MediaType.DOS_35_HD,
|
||||
MediaType.DOS_35_SS_DD_8, MediaType.DOS_35_SS_DD_9, MediaType.DOS_525_DS_DD_8, MediaType.DOS_525_DS_DD_9,
|
||||
MediaType.DOS_525_HD, MediaType.DOS_525_SS_DD_8, MediaType.DOS_525_SS_DD_9, MediaType.FDFORMAT_35_DD,
|
||||
MediaType.FDFORMAT_35_HD, MediaType.FDFORMAT_525_DD, MediaType.FDFORMAT_525_HD, MediaType.RX50,
|
||||
MediaType.XDF_35, MediaType.XDF_525, MediaType.MetaFloppy_Mod_I, MediaType.MetaFloppy_Mod_II
|
||||
MediaType.DMF_82, MediaType.DOS_35_DS_DD_8, MediaType.DOS_35_DS_DD_9, MediaType.DOS_35_ED,
|
||||
MediaType.DOS_35_HD, MediaType.DOS_35_SS_DD_8, MediaType.DOS_35_SS_DD_9, MediaType.DOS_525_DS_DD_8,
|
||||
MediaType.DOS_525_DS_DD_9, MediaType.DOS_525_HD, MediaType.DOS_525_SS_DD_8, MediaType.DOS_525_SS_DD_9,
|
||||
MediaType.FDFORMAT_35_DD, MediaType.FDFORMAT_35_HD, MediaType.FDFORMAT_525_DD, MediaType.FDFORMAT_525_HD,
|
||||
MediaType.RX50, MediaType.XDF_35, MediaType.XDF_525, MediaType.MetaFloppy_Mod_I, MediaType.MetaFloppy_Mod_II
|
||||
};
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<(string name, Type type, string description, object @default)> SupportedOptions => new[]
|
||||
{
|
||||
("compress", typeof(bool), Localization.Enable_Apridisk_compression, (object)false)
|
||||
};
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<string> KnownExtensions => new[]
|
||||
{
|
||||
".dsk"
|
||||
};
|
||||
public IEnumerable<string> KnownExtensions => new[] { ".dsk" };
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsWriting { get; private set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public string ErrorMessage { get; private set; }
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -41,6 +41,8 @@ namespace Aaru.DiscImages;
|
||||
|
||||
public sealed partial class Apridisk
|
||||
{
|
||||
#region IWritableImage Members
|
||||
|
||||
/// <inheritdoc />
|
||||
public ErrorNumber Open(IFilter imageFilter)
|
||||
{
|
||||
@@ -58,7 +60,7 @@ public sealed partial class Apridisk
|
||||
// Count cylinders
|
||||
while(stream.Position < stream.Length)
|
||||
{
|
||||
byte[] recB = new byte[recordSize];
|
||||
var recB = new byte[recordSize];
|
||||
stream.EnsureRead(recB, 0, recordSize);
|
||||
|
||||
Record record = Marshal.SpanToStructureLittleEndian<Record>(recB);
|
||||
@@ -78,7 +80,7 @@ public sealed partial class Apridisk
|
||||
stream.Position);
|
||||
|
||||
stream.Seek(record.headerSize - recordSize, SeekOrigin.Current);
|
||||
byte[] commentB = new byte[record.dataSize];
|
||||
var commentB = new byte[record.dataSize];
|
||||
stream.EnsureRead(commentB, 0, commentB.Length);
|
||||
_imageInfo.Comments = StringHandlers.CToString(commentB);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Comment_0, _imageInfo.Comments);
|
||||
@@ -89,7 +91,7 @@ public sealed partial class Apridisk
|
||||
stream.Position);
|
||||
|
||||
stream.Seek(record.headerSize - recordSize, SeekOrigin.Current);
|
||||
byte[] creatorB = new byte[record.dataSize];
|
||||
var creatorB = new byte[record.dataSize];
|
||||
stream.EnsureRead(creatorB, 0, creatorB.Length);
|
||||
_imageInfo.Creator = StringHandlers.CToString(creatorB);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Creator_0, _imageInfo.Creator);
|
||||
@@ -120,7 +122,8 @@ public sealed partial class Apridisk
|
||||
stream.Seek(record.headerSize - recordSize + record.dataSize, SeekOrigin.Current);
|
||||
|
||||
break;
|
||||
default: return ErrorNumber.NotSupported;
|
||||
default:
|
||||
return ErrorNumber.NotSupported;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,7 +137,7 @@ public sealed partial class Apridisk
|
||||
_sectorsData = new byte[totalCylinders][][][];
|
||||
|
||||
// Total sectors per track
|
||||
uint[][] spts = new uint[totalCylinders][];
|
||||
var spts = new uint[totalCylinders][];
|
||||
|
||||
_imageInfo.Cylinders = (ushort)totalCylinders;
|
||||
_imageInfo.Heads = (byte)totalHeads;
|
||||
@@ -144,12 +147,12 @@ public sealed partial class Apridisk
|
||||
totalCylinders, totalHeads, maxSector);
|
||||
|
||||
// Create heads
|
||||
for(int i = 0; i < totalCylinders; i++)
|
||||
for(var i = 0; i < totalCylinders; i++)
|
||||
{
|
||||
_sectorsData[i] = new byte[totalHeads][][];
|
||||
spts[i] = new uint[totalHeads];
|
||||
|
||||
for(int j = 0; j < totalHeads; j++)
|
||||
for(var j = 0; j < totalHeads; j++)
|
||||
_sectorsData[i][j] = new byte[maxSector + 1][];
|
||||
}
|
||||
|
||||
@@ -162,7 +165,7 @@ public sealed partial class Apridisk
|
||||
|
||||
while(stream.Position < stream.Length)
|
||||
{
|
||||
byte[] recB = new byte[recordSize];
|
||||
var recB = new byte[recordSize];
|
||||
stream.EnsureRead(recB, 0, recordSize);
|
||||
|
||||
Record record = Marshal.SpanToStructureLittleEndian<Record>(recB);
|
||||
@@ -180,7 +183,7 @@ public sealed partial class Apridisk
|
||||
case RecordType.Sector:
|
||||
stream.Seek(record.headerSize - recordSize, SeekOrigin.Current);
|
||||
|
||||
byte[] data = new byte[record.dataSize];
|
||||
var data = new byte[record.dataSize];
|
||||
stream.EnsureRead(data, 0, data.Length);
|
||||
|
||||
spts[record.cylinder][record.head]++;
|
||||
@@ -209,8 +212,10 @@ public sealed partial class Apridisk
|
||||
for(ushort cyl = 0; cyl < _imageInfo.Cylinders; cyl++)
|
||||
{
|
||||
for(ushort head = 0; head < _imageInfo.Heads; head++)
|
||||
{
|
||||
if(spts[cyl][head] < spt)
|
||||
spt = spts[cyl][head];
|
||||
}
|
||||
}
|
||||
|
||||
_imageInfo.SectorsPerTrack = spt;
|
||||
@@ -279,4 +284,6 @@ public sealed partial class Apridisk
|
||||
|
||||
return ErrorNumber.NoError;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -36,6 +36,8 @@ namespace Aaru.DiscImages;
|
||||
|
||||
public sealed partial class Apridisk
|
||||
{
|
||||
#region Nested type: Record
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct Record
|
||||
{
|
||||
@@ -47,4 +49,6 @@ public sealed partial class Apridisk
|
||||
public byte sector;
|
||||
public ushort cylinder;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -36,6 +36,8 @@ namespace Aaru.DiscImages;
|
||||
|
||||
public sealed partial class Apridisk
|
||||
{
|
||||
#region IWritableImage Members
|
||||
|
||||
/// <inheritdoc />
|
||||
public ErrorNumber ReadMediaTag(MediaTagType tag, out byte[] buffer)
|
||||
{
|
||||
@@ -75,4 +77,6 @@ public sealed partial class Apridisk
|
||||
|
||||
return ErrorNumber.NotSupported;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -45,9 +45,11 @@ namespace Aaru.DiscImages;
|
||||
|
||||
public sealed partial class Apridisk
|
||||
{
|
||||
#region IWritableImage Members
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Create(string path, MediaType mediaType, Dictionary<string, string> options, ulong sectors,
|
||||
uint sectorSize)
|
||||
uint sectorSize)
|
||||
{
|
||||
if(!SupportedMediaTypes.Contains(mediaType))
|
||||
{
|
||||
@@ -176,7 +178,7 @@ public sealed partial class Apridisk
|
||||
_writingStream.Seek(0, SeekOrigin.Begin);
|
||||
_writingStream.Write(_signature, 0, _signature.Length);
|
||||
|
||||
byte[] hdr = new byte[Marshal.SizeOf<Record>()];
|
||||
var hdr = new byte[Marshal.SizeOf<Record>()];
|
||||
|
||||
for(ushort c = 0; c < _imageInfo.Cylinders; c++)
|
||||
{
|
||||
@@ -201,7 +203,7 @@ public sealed partial class Apridisk
|
||||
|
||||
MemoryMarshal.Write(hdr, in record);
|
||||
|
||||
_writingStream.Write(hdr, 0, hdr.Length);
|
||||
_writingStream.Write(hdr, 0, hdr.Length);
|
||||
_writingStream.Write(_sectorsData[c][h][s], 0, _sectorsData[c][h][s].Length);
|
||||
}
|
||||
}
|
||||
@@ -224,7 +226,7 @@ public sealed partial class Apridisk
|
||||
|
||||
MemoryMarshal.Write(hdr, in creatorRecord);
|
||||
|
||||
_writingStream.Write(hdr, 0, hdr.Length);
|
||||
_writingStream.Write(hdr, 0, hdr.Length);
|
||||
_writingStream.Write(creatorBytes, 0, creatorBytes.Length);
|
||||
_writingStream.WriteByte(0); // Termination
|
||||
}
|
||||
@@ -246,7 +248,7 @@ public sealed partial class Apridisk
|
||||
|
||||
MemoryMarshal.Write(hdr, in commentRecord);
|
||||
|
||||
_writingStream.Write(hdr, 0, hdr.Length);
|
||||
_writingStream.Write(hdr, 0, hdr.Length);
|
||||
_writingStream.Write(commentBytes, 0, commentBytes.Length);
|
||||
_writingStream.WriteByte(0); // Termination
|
||||
}
|
||||
@@ -331,4 +333,6 @@ public sealed partial class Apridisk
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool SetMetadata(Metadata metadata) => false;
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -42,11 +42,12 @@ namespace Aaru.DiscImages;
|
||||
/// <summary>Implements reading Basic Lisa Utility disk images</summary>
|
||||
public sealed partial class Blu : IWritableImage, IVerifiableSectorsImage
|
||||
{
|
||||
IFilter _bluImageFilter;
|
||||
int _bptag;
|
||||
BluHeader _imageHeader;
|
||||
ImageInfo _imageInfo;
|
||||
FileStream _writingStream;
|
||||
const string MODULE_NAME = "BLU plugin";
|
||||
IFilter _bluImageFilter;
|
||||
int _bptag;
|
||||
BluHeader _imageHeader;
|
||||
ImageInfo _imageInfo;
|
||||
FileStream _writingStream;
|
||||
|
||||
public Blu() => _imageInfo = new ImageInfo
|
||||
{
|
||||
@@ -72,6 +73,8 @@ public sealed partial class Blu : IWritableImage, IVerifiableSectorsImage
|
||||
DriveFirmwareRevision = null
|
||||
};
|
||||
|
||||
#region Nested type: BluHeader
|
||||
|
||||
struct BluHeader
|
||||
{
|
||||
public byte[] DeviceName;
|
||||
@@ -80,5 +83,5 @@ public sealed partial class Blu : IWritableImage, IVerifiableSectorsImage
|
||||
public ushort BytesPerBlock;
|
||||
}
|
||||
|
||||
const string MODULE_NAME = "BLU plugin";
|
||||
#endregion
|
||||
}
|
||||
@@ -39,6 +39,8 @@ namespace Aaru.DiscImages;
|
||||
|
||||
public sealed partial class Blu
|
||||
{
|
||||
#region IWritableImage Members
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Identify(IFilter imageFilter)
|
||||
{
|
||||
@@ -48,7 +50,7 @@ public sealed partial class Blu
|
||||
if(stream.Length < 0x200)
|
||||
return false;
|
||||
|
||||
byte[] header = new byte[0x17];
|
||||
var header = new byte[0x17];
|
||||
stream.EnsureRead(header, 0, 0x17);
|
||||
|
||||
var tmpHdr = new BluHeader
|
||||
@@ -61,10 +63,14 @@ public sealed partial class Blu
|
||||
tmpHdr.DeviceBlocks = BigEndianBitConverter.ToUInt32(header, 0x11) & 0x00FFFFFF;
|
||||
tmpHdr.BytesPerBlock = BigEndianBitConverter.ToUInt16(header, 0x15);
|
||||
|
||||
for(int i = 0; i < 0xD; i++)
|
||||
for(var i = 0; i < 0xD; i++)
|
||||
{
|
||||
if(tmpHdr.DeviceName[i] < 0x20)
|
||||
return false;
|
||||
}
|
||||
|
||||
return (tmpHdr.BytesPerBlock & 0xFE00) == 0x200;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -41,27 +41,35 @@ namespace Aaru.DiscImages;
|
||||
|
||||
public sealed partial class Blu
|
||||
{
|
||||
#region IWritableImage Members
|
||||
|
||||
/// <inheritdoc />
|
||||
public ImageInfo Info => _imageInfo;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Name => Localization.Blu_Name;
|
||||
|
||||
/// <inheritdoc />
|
||||
public Guid Id => new("A153E2F8-4235-432D-9A7F-20807B0BCD74");
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Author => Authors.NataliaPortillo;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Format => "Basic Lisa Utility";
|
||||
|
||||
/// <inheritdoc />
|
||||
public List<DumpHardware> DumpHardware => null;
|
||||
|
||||
/// <inheritdoc />
|
||||
public Metadata AaruMetadata => null;
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<MediaTagType> SupportedMediaTags => Array.Empty<MediaTagType>();
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<SectorTagType> SupportedSectorTags => new[]
|
||||
{
|
||||
SectorTagType.AppleSectorTag
|
||||
};
|
||||
public IEnumerable<SectorTagType> SupportedSectorTags => new[] { SectorTagType.AppleSectorTag };
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<MediaType> SupportedMediaTypes => new[]
|
||||
{
|
||||
@@ -69,16 +77,19 @@ public sealed partial class Blu
|
||||
MediaType.Unknown, MediaType.FlashDrive, MediaType.CompactFlash, MediaType.CompactFlashType2,
|
||||
MediaType.PCCardTypeI, MediaType.PCCardTypeII, MediaType.PCCardTypeIII, MediaType.PCCardTypeIV
|
||||
};
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<(string name, Type type, string description, object @default)> SupportedOptions =>
|
||||
Array.Empty<(string name, Type type, string description, object @default)>();
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<string> KnownExtensions => new[]
|
||||
{
|
||||
".blu"
|
||||
}; // Just invented
|
||||
public IEnumerable<string> KnownExtensions => new[] { ".blu" }; // Just invented
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsWriting { get; private set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public string ErrorMessage { get; private set; }
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -42,6 +42,8 @@ namespace Aaru.DiscImages;
|
||||
|
||||
public sealed partial class Blu
|
||||
{
|
||||
#region IWritableImage Members
|
||||
|
||||
/// <inheritdoc />
|
||||
public ErrorNumber Open(IFilter imageFilter)
|
||||
{
|
||||
@@ -53,7 +55,7 @@ public sealed partial class Blu
|
||||
DeviceName = new byte[0x0D]
|
||||
};
|
||||
|
||||
byte[] header = new byte[0x17];
|
||||
var header = new byte[0x17];
|
||||
stream.EnsureRead(header, 0, 0x17);
|
||||
Array.Copy(header, 0, _imageHeader.DeviceName, 0, 0x0D);
|
||||
_imageHeader.DeviceType = BigEndianBitConverter.ToUInt32(header, 0x0C) & 0x00FFFFFF;
|
||||
@@ -63,13 +65,15 @@ public sealed partial class Blu
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "ImageHeader.deviceName = \"{0}\"",
|
||||
StringHandlers.CToString(_imageHeader.DeviceName));
|
||||
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "ImageHeader.deviceType = {0}", _imageHeader.DeviceType);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "ImageHeader.deviceBlock = {0}", _imageHeader.DeviceBlocks);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "ImageHeader.deviceType = {0}", _imageHeader.DeviceType);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "ImageHeader.deviceBlock = {0}", _imageHeader.DeviceBlocks);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "ImageHeader.bytesPerBlock = {0}", _imageHeader.BytesPerBlock);
|
||||
|
||||
for(int i = 0; i < 0xD; i++)
|
||||
for(var i = 0; i < 0xD; i++)
|
||||
{
|
||||
if(_imageHeader.DeviceName[i] < 0x20)
|
||||
return ErrorNumber.InvalidArgument;
|
||||
}
|
||||
|
||||
if((_imageHeader.BytesPerBlock & 0xFE00) != 0x200)
|
||||
return ErrorNumber.InvalidArgument;
|
||||
@@ -83,7 +87,7 @@ public sealed partial class Blu
|
||||
_imageInfo.Sectors = _imageHeader.DeviceBlocks;
|
||||
_imageInfo.ImageSize = _imageHeader.DeviceBlocks * _imageHeader.BytesPerBlock;
|
||||
_bptag = _imageHeader.BytesPerBlock - 0x200;
|
||||
byte[] hdrTag = new byte[_bptag];
|
||||
var hdrTag = new byte[_bptag];
|
||||
Array.Copy(header, 0x200, hdrTag, 0, _bptag);
|
||||
|
||||
switch(StringHandlers.CToString(_imageHeader.DeviceName))
|
||||
@@ -113,7 +117,8 @@ public sealed partial class Blu
|
||||
|
||||
break;
|
||||
case PRIAM_NAME:
|
||||
_imageInfo.MediaType = _imageInfo.Sectors == 0x022C7C ? MediaType.PriamDataTower
|
||||
_imageInfo.MediaType = _imageInfo.Sectors == 0x022C7C
|
||||
? MediaType.PriamDataTower
|
||||
: MediaType.GENERIC_HDD;
|
||||
|
||||
// This values are invented...
|
||||
@@ -174,9 +179,9 @@ public sealed partial class Blu
|
||||
Stream stream = _bluImageFilter.GetDataForkStream();
|
||||
stream.Seek((long)((sectorAddress + 1) * _imageHeader.BytesPerBlock), SeekOrigin.Begin);
|
||||
|
||||
for(int i = 0; i < length; i++)
|
||||
for(var i = 0; i < length; i++)
|
||||
{
|
||||
byte[] sector = new byte[read];
|
||||
var sector = new byte[read];
|
||||
stream.EnsureRead(sector, 0, read);
|
||||
ms.Write(sector, 0, read);
|
||||
stream.Seek(skip, SeekOrigin.Current);
|
||||
@@ -211,10 +216,10 @@ public sealed partial class Blu
|
||||
Stream stream = _bluImageFilter.GetDataForkStream();
|
||||
stream.Seek((long)((sectorAddress + 1) * _imageHeader.BytesPerBlock), SeekOrigin.Begin);
|
||||
|
||||
for(int i = 0; i < length; i++)
|
||||
for(var i = 0; i < length; i++)
|
||||
{
|
||||
stream.Seek(seek, SeekOrigin.Current);
|
||||
byte[] sector = new byte[read];
|
||||
var sector = new byte[read];
|
||||
stream.EnsureRead(sector, 0, read);
|
||||
ms.Write(sector, 0, read);
|
||||
}
|
||||
@@ -246,4 +251,6 @@ public sealed partial class Blu
|
||||
|
||||
return ErrorNumber.NoError;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -36,6 +36,8 @@ namespace Aaru.DiscImages;
|
||||
|
||||
public sealed partial class Blu
|
||||
{
|
||||
#region IWritableImage Members
|
||||
|
||||
/// <inheritdoc />
|
||||
public ErrorNumber ReadMediaTag(MediaTagType tag, out byte[] buffer)
|
||||
{
|
||||
@@ -43,4 +45,6 @@ public sealed partial class Blu
|
||||
|
||||
return ErrorNumber.NotSupported;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -36,12 +36,14 @@ namespace Aaru.DiscImages;
|
||||
|
||||
public sealed partial class Blu
|
||||
{
|
||||
#region IVerifiableSectorsImage Members
|
||||
|
||||
// TODO: Check tag checksums
|
||||
/// <inheritdoc />
|
||||
public bool? VerifySector(ulong sectorAddress) => null;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool? VerifySectors(ulong sectorAddress, uint length, out List<ulong> failingLbas,
|
||||
public bool? VerifySectors(ulong sectorAddress, uint length, out List<ulong> failingLbas,
|
||||
out List<ulong> unknownLbas)
|
||||
{
|
||||
failingLbas = new List<ulong>();
|
||||
@@ -52,4 +54,6 @@ public sealed partial class Blu
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -47,9 +47,11 @@ namespace Aaru.DiscImages;
|
||||
|
||||
public sealed partial class Blu
|
||||
{
|
||||
#region IWritableImage Members
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Create(string path, MediaType mediaType, Dictionary<string, string> options, ulong sectors,
|
||||
uint sectorSize)
|
||||
uint sectorSize)
|
||||
{
|
||||
if(sectorSize != 512)
|
||||
{
|
||||
@@ -130,7 +132,7 @@ public sealed partial class Blu
|
||||
return false;
|
||||
}
|
||||
|
||||
_writingStream.Seek(longSectorSize + ((long)sectorAddress * longSectorSize), SeekOrigin.Begin);
|
||||
_writingStream.Seek(longSectorSize + (long)sectorAddress * longSectorSize, SeekOrigin.Begin);
|
||||
_writingStream.Write(data, 0, data.Length);
|
||||
|
||||
ErrorMessage = "";
|
||||
@@ -164,7 +166,7 @@ public sealed partial class Blu
|
||||
return false;
|
||||
}
|
||||
|
||||
_writingStream.Seek(longSectorSize + ((long)sectorAddress * longSectorSize), SeekOrigin.Begin);
|
||||
_writingStream.Seek(longSectorSize + (long)sectorAddress * longSectorSize, SeekOrigin.Begin);
|
||||
_writingStream.Write(data, 0, data.Length);
|
||||
|
||||
ErrorMessage = "";
|
||||
@@ -253,8 +255,8 @@ public sealed partial class Blu
|
||||
|
||||
newTag ??= new byte[longSectorSize - 512];
|
||||
|
||||
_writingStream.Seek(longSectorSize + ((long)sectorAddress * longSectorSize), SeekOrigin.Begin);
|
||||
_writingStream.Write(data, 0, 512);
|
||||
_writingStream.Seek(longSectorSize + (long)sectorAddress * longSectorSize, SeekOrigin.Begin);
|
||||
_writingStream.Write(data, 0, 512);
|
||||
_writingStream.Write(newTag, 0, newTag.Length);
|
||||
|
||||
ErrorMessage = "";
|
||||
@@ -287,7 +289,8 @@ public sealed partial class Blu
|
||||
case 536:
|
||||
case 532:
|
||||
case 524:
|
||||
case 512: break;
|
||||
case 512:
|
||||
break;
|
||||
default:
|
||||
ErrorMessage = Localization.Incorrect_data_size;
|
||||
|
||||
@@ -304,7 +307,7 @@ public sealed partial class Blu
|
||||
// Sony tag, convert to Profile
|
||||
case 12 when longSectorSize == 532:
|
||||
oldTag = new byte[12];
|
||||
Array.Copy(data, (givenSectorSize * i) + 512, oldTag, 0, 12);
|
||||
Array.Copy(data, givenSectorSize * i + 512, oldTag, 0, 12);
|
||||
newTag = LisaTag.DecodeSonyTag(oldTag)?.ToProfile().GetBytes();
|
||||
|
||||
break;
|
||||
@@ -312,7 +315,7 @@ public sealed partial class Blu
|
||||
// Sony tag, convert to Priam
|
||||
case 12:
|
||||
oldTag = new byte[12];
|
||||
Array.Copy(data, (givenSectorSize * i) + 512, oldTag, 0, 12);
|
||||
Array.Copy(data, givenSectorSize * i + 512, oldTag, 0, 12);
|
||||
newTag = LisaTag.DecodeSonyTag(oldTag)?.ToPriam().GetBytes();
|
||||
|
||||
break;
|
||||
@@ -320,14 +323,14 @@ public sealed partial class Blu
|
||||
// Profile tag, copy to Profile
|
||||
case 20 when longSectorSize == 532:
|
||||
newTag = new byte[20];
|
||||
Array.Copy(data, (givenSectorSize * i) + 512, newTag, 0, 20);
|
||||
Array.Copy(data, givenSectorSize * i + 512, newTag, 0, 20);
|
||||
|
||||
break;
|
||||
|
||||
// Profile tag, convert to Priam
|
||||
case 20:
|
||||
oldTag = new byte[20];
|
||||
Array.Copy(data, (givenSectorSize * i) + 512, oldTag, 0, 20);
|
||||
Array.Copy(data, givenSectorSize * i + 512, oldTag, 0, 20);
|
||||
newTag = LisaTag.DecodeProfileTag(oldTag)?.ToPriam().GetBytes();
|
||||
|
||||
break;
|
||||
@@ -335,7 +338,7 @@ public sealed partial class Blu
|
||||
// Priam tag, convert to Profile
|
||||
case 24 when longSectorSize == 532:
|
||||
oldTag = new byte[24];
|
||||
Array.Copy(data, (givenSectorSize * i) + 512, oldTag, 0, 24);
|
||||
Array.Copy(data, givenSectorSize * i + 512, oldTag, 0, 24);
|
||||
newTag = LisaTag.DecodePriamTag(oldTag)?.ToProfile().GetBytes();
|
||||
|
||||
break;
|
||||
@@ -343,7 +346,7 @@ public sealed partial class Blu
|
||||
// Priam tag, copy to Priam
|
||||
case 24:
|
||||
newTag = new byte[24];
|
||||
Array.Copy(data, (givenSectorSize * i) + 512, newTag, 0, 24);
|
||||
Array.Copy(data, givenSectorSize * i + 512, newTag, 0, 24);
|
||||
|
||||
break;
|
||||
case 0:
|
||||
@@ -358,9 +361,9 @@ public sealed partial class Blu
|
||||
|
||||
newTag ??= new byte[longSectorSize - 512];
|
||||
|
||||
_writingStream.Seek(longSectorSize + ((long)sectorAddress * longSectorSize), SeekOrigin.Begin);
|
||||
_writingStream.Write(data, (int)(givenSectorSize * i), 512);
|
||||
_writingStream.Write(newTag, 0, newTag.Length);
|
||||
_writingStream.Seek(longSectorSize + (long)sectorAddress * longSectorSize, SeekOrigin.Begin);
|
||||
_writingStream.Write(data, (int)(givenSectorSize * i), 512);
|
||||
_writingStream.Write(newTag, 0, newTag.Length);
|
||||
}
|
||||
|
||||
ErrorMessage = "";
|
||||
@@ -380,7 +383,7 @@ public sealed partial class Blu
|
||||
|
||||
byte[] markerTag = Encoding.UTF8.GetBytes("Aaru " + Version.GetVersion());
|
||||
byte[] driveName;
|
||||
byte[] driveType = new byte[3];
|
||||
var driveType = new byte[3];
|
||||
byte[] driveBlocks = BigEndianBitConverter.GetBytes((uint)_imageInfo.Sectors);
|
||||
int longSectorSize = _imageInfo.MediaType == MediaType.PriamDataTower ? 536 : 532;
|
||||
byte[] blockSize = BigEndianBitConverter.GetBytes((ushort)longSectorSize);
|
||||
@@ -456,4 +459,6 @@ public sealed partial class Blu
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool SetMetadata(Metadata metadata) => false;
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -43,6 +43,7 @@ namespace Aaru.DiscImages;
|
||||
/// <summary>Implements reading BlindWrite 4 disc images</summary>
|
||||
public sealed partial class BlindWrite4 : IOpticalMediaImage
|
||||
{
|
||||
const string MODULE_NAME = "BlindWrite4 plugin";
|
||||
List<TrackDescriptor> _bwTracks;
|
||||
IFilter _dataFilter, _subFilter;
|
||||
Header _header;
|
||||
@@ -71,6 +72,4 @@ public sealed partial class BlindWrite4 : IOpticalMediaImage
|
||||
DriveSerialNumber = null,
|
||||
DriveFirmwareRevision = null
|
||||
};
|
||||
|
||||
const string MODULE_NAME = "BlindWrite4 plugin";
|
||||
}
|
||||
@@ -34,8 +34,14 @@ namespace Aaru.DiscImages;
|
||||
|
||||
public sealed partial class BlindWrite4
|
||||
{
|
||||
#region Nested type: TrackType
|
||||
|
||||
enum TrackType : byte
|
||||
{
|
||||
Audio = 0, Mode1 = 1, Mode2 = 2
|
||||
Audio = 0,
|
||||
Mode1 = 1,
|
||||
Mode2 = 2
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -39,6 +39,8 @@ namespace Aaru.DiscImages;
|
||||
|
||||
public sealed partial class BlindWrite4
|
||||
{
|
||||
#region IOpticalMediaImage Members
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Identify(IFilter imageFilter)
|
||||
{
|
||||
@@ -48,9 +50,11 @@ public sealed partial class BlindWrite4
|
||||
if(stream.Length < 19)
|
||||
return false;
|
||||
|
||||
byte[] signature = new byte[19];
|
||||
var signature = new byte[19];
|
||||
stream.EnsureRead(signature, 0, 19);
|
||||
|
||||
return _bw4Signature.SequenceEqual(signature);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -41,15 +41,20 @@ namespace Aaru.DiscImages;
|
||||
|
||||
public sealed partial class BlindWrite4
|
||||
{
|
||||
#region IOpticalMediaImage Members
|
||||
|
||||
/// <inheritdoc />
|
||||
public ImageInfo Info => _imageInfo;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Name => Localization.BlindWrite4_Name;
|
||||
|
||||
/// <inheritdoc />
|
||||
public Guid Id => new("664568B2-15D4-4E64-8A7A-20BDA8B8386F");
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Author => Authors.NataliaPortillo;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Format => "BlindWrite 4 TOC file";
|
||||
|
||||
@@ -61,8 +66,12 @@ public sealed partial class BlindWrite4
|
||||
|
||||
/// <inheritdoc />
|
||||
public List<Session> Sessions { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public List<DumpHardware> DumpHardware => null;
|
||||
|
||||
/// <inheritdoc />
|
||||
public Metadata AaruMetadata => null;
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -49,6 +49,8 @@ namespace Aaru.DiscImages;
|
||||
|
||||
public sealed partial class BlindWrite4
|
||||
{
|
||||
#region IOpticalMediaImage Members
|
||||
|
||||
/// <inheritdoc />
|
||||
public ErrorNumber Open(IFilter imageFilter)
|
||||
{
|
||||
@@ -58,10 +60,10 @@ public sealed partial class BlindWrite4
|
||||
if(stream.Length < 19)
|
||||
return ErrorNumber.InvalidArgument;
|
||||
|
||||
byte[] tmpArray = new byte[19];
|
||||
byte[] tmpUShort = new byte[2];
|
||||
byte[] tmpUInt = new byte[4];
|
||||
byte[] tmpULong = new byte[8];
|
||||
var tmpArray = new byte[19];
|
||||
var tmpUShort = new byte[2];
|
||||
var tmpUInt = new byte[4];
|
||||
var tmpULong = new byte[8];
|
||||
|
||||
stream.EnsureRead(tmpArray, 0, 19);
|
||||
|
||||
@@ -129,31 +131,31 @@ public sealed partial class BlindWrite4
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.signature = {0}",
|
||||
StringHandlers.CToString(_header.Signature));
|
||||
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.unknown1 = {0}", _header.Unknown1);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.timestamp = {0}", _header.Timestamp);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.volumeIdLength = {0}", _header.VolumeIdLength);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.unknown1 = {0}", _header.Unknown1);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.timestamp = {0}", _header.Timestamp);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.volumeIdLength = {0}", _header.VolumeIdLength);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.volumeIdentifier = {0}", _header.VolumeIdentifier);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.sysIdLength = {0}", _header.SysIdLength);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.sysIdLength = {0}", _header.SysIdLength);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.systemIdentifier = {0}", _header.SystemIdentifier);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.commentsLength = {0}", _header.CommentsLength);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.comments = {0}", _header.Comments);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.commentsLength = {0}", _header.CommentsLength);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.comments = {0}", _header.Comments);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.trackDescriptors = {0}", _header.TrackDescriptors);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.dataFileLength = {0}", _header.DataFileLength);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.dataFilter = {0}", _header.DataFilter);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.dataFile = {0}", _header.DataFile);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.dataFileLength = {0}", _header.DataFileLength);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.dataFilter = {0}", _header.DataFilter);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.dataFile = {0}", _header.DataFile);
|
||||
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.subchannelFileLength = {0}",
|
||||
_header.SubchannelFileLength);
|
||||
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.subchannelFilter = {0}", _header.SubchannelFilter);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.subchannelFile = {0}", _header.SubchannelFile);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.unknown2 = {0}", _header.Unknown2);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.unknown3 = {0}", _header.Unknown3);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.unknown4.Length = {0}", _header.Unknown4.Length);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.subchannelFile = {0}", _header.SubchannelFile);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.unknown2 = {0}", _header.Unknown2);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.unknown3 = {0}", _header.Unknown3);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.unknown4.Length = {0}", _header.Unknown4.Length);
|
||||
|
||||
_bwTracks = new List<TrackDescriptor>();
|
||||
|
||||
for(int i = 0; i < _header.TrackDescriptors; i++)
|
||||
for(var i = 0; i < _header.TrackDescriptors; i++)
|
||||
{
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "stream.Position = {0}", stream.Position);
|
||||
|
||||
@@ -210,7 +212,7 @@ public sealed partial class BlindWrite4
|
||||
|
||||
track.unknown13 = new uint[2];
|
||||
|
||||
for(int j = 0; j < track.unknown13.Length; j++)
|
||||
for(var j = 0; j < track.unknown13.Length; j++)
|
||||
{
|
||||
stream.EnsureRead(tmpUInt, 0, 4);
|
||||
track.unknown13[j] = BitConverter.ToUInt32(tmpUInt, 0);
|
||||
@@ -322,67 +324,71 @@ public sealed partial class BlindWrite4
|
||||
track.isrcUpc = StringHandlers.CToString(track.isrcBytes, Encoding.Default);
|
||||
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.filenameLen = {0}", track.filenameLen);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.filename = {0}", track.filename);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.offset = {0}", track.offset);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.subchannel = {0}", track.subchannel);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.filename = {0}", track.filename);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.offset = {0}", track.offset);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.subchannel = {0}", track.subchannel);
|
||||
|
||||
for(int j = 0; j < track.unknown1.Length; j++)
|
||||
for(var j = 0; j < track.unknown1.Length; j++)
|
||||
{
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.unknown1[{1}] = 0x{0:X8}", track.unknown1[j],
|
||||
j);
|
||||
}
|
||||
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.unknown2 = {0}", track.unknown2);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.unknown3 = {0}", track.unknown3);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.session = {0}", track.session);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.unknown4 = {0}", track.unknown4);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.adrCtl = {0}", track.adrCtl);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.unknown5 = {0}", track.unknown5);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.trackMode = {0}", track.trackMode);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.unknown6 = {0}", track.unknown6);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.point = {0}", track.point);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.unknown7 = {0}", track.unknown7);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.unknown8 = {0}", track.unknown8);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.unknown9 = {0}", track.pregapOffsetAdjustment);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.unknown10 = {0}", track.unknown10);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.unknown11 = {0}", track.unknown11);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.lastSector = {0}", track.lastSector);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.unknown12 = {0}", track.unknown12);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.pregap = {0}", track.pregap);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.unknown2 = {0}", track.unknown2);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.unknown3 = {0}", track.unknown3);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.session = {0}", track.session);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.unknown4 = {0}", track.unknown4);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.adrCtl = {0}", track.adrCtl);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.unknown5 = {0}", track.unknown5);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.trackMode = {0}", track.trackMode);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.unknown6 = {0}", track.unknown6);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.point = {0}", track.point);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.unknown7 = {0}", track.unknown7);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.unknown8 = {0}", track.unknown8);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.unknown9 = {0}", track.pregapOffsetAdjustment);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.unknown10 = {0}", track.unknown10);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.unknown11 = {0}", track.unknown11);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.lastSector = {0}", track.lastSector);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.unknown12 = {0}", track.unknown12);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.pregap = {0}", track.pregap);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.startSector = {0}", track.startSector);
|
||||
|
||||
for(int j = 0; j < track.unknown13.Length; j++)
|
||||
for(var j = 0; j < track.unknown13.Length; j++)
|
||||
{
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.unknown13[{1}] = 0x{0:X8}", track.unknown13[j],
|
||||
j);
|
||||
}
|
||||
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.titleLen = {0}", track.titleLen);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.title = {0}", track.title);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.titleLen = {0}", track.titleLen);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.title = {0}", track.title);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.performerLen = {0}", track.performerLen);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.performer = {0}", track.performer);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.unkStrLen1 = {0}", track.unkStrLen1);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.unkString1 = {0}", track.unkString1);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.unkStrLen2 = {0}", track.unkStrLen2);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.unkString2 = {0}", track.unkString2);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.unkStrLen3 = {0}", track.unkStrLen3);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.unkString3 = {0}", track.unkString3);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.unkStrLen4 = {0}", track.unkStrLen4);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.unkString4 = {0}", track.unkString4);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.discIdLen = {0}", track.discIdLen);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.discId = {0}", track.discId);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.unkStrLen5 = {0}", track.unkStrLen5);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.unkString5 = {0}", track.unkString5);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.unkStrLen6 = {0}", track.unkStrLen6);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.unkString6 = {0}", track.unkString6);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.unkStrLen7 = {0}", track.unkStrLen7);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.unkString7 = {0}", track.unkString7);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.unkStrLen8 = {0}", track.unkStrLen8);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.unkString8 = {0}", track.unkString8);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.unkStrLen9 = {0}", track.unkStrLen9);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.unkString9 = {0}", track.unkString9);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.unkStrLen10 = {0}", track.unkStrLen10);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.unkString10 = {0}", track.unkString10);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.unkStrLen11 = {0}", track.unkStrLen11);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.unkString11 = {0}", track.unkString11);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.isrcLen = {0}", track.isrcLen);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.isrcUpc = {0}", track.isrcUpc);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.performer = {0}", track.performer);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.unkStrLen1 = {0}", track.unkStrLen1);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.unkString1 = {0}", track.unkString1);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.unkStrLen2 = {0}", track.unkStrLen2);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.unkString2 = {0}", track.unkString2);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.unkStrLen3 = {0}", track.unkStrLen3);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.unkString3 = {0}", track.unkString3);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.unkStrLen4 = {0}", track.unkStrLen4);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.unkString4 = {0}", track.unkString4);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.discIdLen = {0}", track.discIdLen);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.discId = {0}", track.discId);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.unkStrLen5 = {0}", track.unkStrLen5);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.unkString5 = {0}", track.unkString5);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.unkStrLen6 = {0}", track.unkStrLen6);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.unkString6 = {0}", track.unkString6);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.unkStrLen7 = {0}", track.unkStrLen7);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.unkString7 = {0}", track.unkString7);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.unkStrLen8 = {0}", track.unkStrLen8);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.unkString8 = {0}", track.unkString8);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.unkStrLen9 = {0}", track.unkStrLen9);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.unkString9 = {0}", track.unkString9);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.unkStrLen10 = {0}", track.unkStrLen10);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.unkString10 = {0}", track.unkString10);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.unkStrLen11 = {0}", track.unkStrLen11);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.unkString11 = {0}", track.unkString11);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.isrcLen = {0}", track.isrcLen);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "track.isrcUpc = {0}", track.isrcUpc);
|
||||
|
||||
_bwTracks.Add(track);
|
||||
}
|
||||
@@ -390,6 +396,7 @@ public sealed partial class BlindWrite4
|
||||
var filtersList = new FiltersList();
|
||||
|
||||
if(!string.IsNullOrEmpty(_header.DataFile))
|
||||
{
|
||||
while(true)
|
||||
{
|
||||
_dataFilter = filtersList.GetFilter(Path.Combine(imageFilter.ParentFolder, _header.DataFile));
|
||||
@@ -409,26 +416,29 @@ public sealed partial class BlindWrite4
|
||||
if(_dataFilter != null)
|
||||
break;
|
||||
|
||||
_dataFilter = filtersList.GetFilter(Path.Combine(imageFilter.ParentFolder, _header.DataFile.Split(new[]
|
||||
{
|
||||
'\\'
|
||||
}, StringSplitOptions.RemoveEmptyEntries).Last()));
|
||||
_dataFilter = filtersList.GetFilter(Path.Combine(imageFilter.ParentFolder,
|
||||
_header.DataFile.
|
||||
Split(new[] { '\\' },
|
||||
StringSplitOptions.RemoveEmptyEntries).
|
||||
Last()));
|
||||
|
||||
if(_dataFilter != null)
|
||||
break;
|
||||
|
||||
_dataFilter = filtersList.GetFilter(Path.Combine(imageFilter.ParentFolder, _header.DataFile.Split(new[]
|
||||
{
|
||||
'\\'
|
||||
}, StringSplitOptions.RemoveEmptyEntries).Last().ToLower(CultureInfo.CurrentCulture)));
|
||||
_dataFilter = filtersList.GetFilter(Path.Combine(imageFilter.ParentFolder,
|
||||
_header.DataFile.
|
||||
Split(new[] { '\\' },
|
||||
StringSplitOptions.RemoveEmptyEntries).
|
||||
Last().ToLower(CultureInfo.CurrentCulture)));
|
||||
|
||||
if(_dataFilter != null)
|
||||
break;
|
||||
|
||||
_dataFilter = filtersList.GetFilter(Path.Combine(imageFilter.ParentFolder, _header.DataFile.Split(new[]
|
||||
{
|
||||
'\\'
|
||||
}, StringSplitOptions.RemoveEmptyEntries).Last().ToUpper(CultureInfo.CurrentCulture)));
|
||||
_dataFilter = filtersList.GetFilter(Path.Combine(imageFilter.ParentFolder,
|
||||
_header.DataFile.
|
||||
Split(new[] { '\\' },
|
||||
StringSplitOptions.RemoveEmptyEntries).
|
||||
Last().ToUpper(CultureInfo.CurrentCulture)));
|
||||
|
||||
if(_dataFilter != null)
|
||||
break;
|
||||
@@ -437,6 +447,7 @@ public sealed partial class BlindWrite4
|
||||
|
||||
return ErrorNumber.NoSuchFile;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AaruConsole.ErrorWriteLine(Localization.Unable_to_find_data_file);
|
||||
@@ -454,18 +465,19 @@ public sealed partial class BlindWrite4
|
||||
_header.SubchannelFile.ToLower(CultureInfo.CurrentCulture)))) ??
|
||||
filtersList.GetFilter(Path.Combine(imageFilter.ParentFolder,
|
||||
_header.SubchannelFile.ToUpper(CultureInfo.CurrentCulture)))) ??
|
||||
filtersList.GetFilter(Path.Combine(imageFilter.ParentFolder, _header.SubchannelFile.Split(new[]
|
||||
{
|
||||
'\\'
|
||||
}, StringSplitOptions.RemoveEmptyEntries).Last()))) ??
|
||||
filtersList.GetFilter(Path.Combine(imageFilter.ParentFolder, _header.SubchannelFile.Split(new[]
|
||||
{
|
||||
'\\'
|
||||
}, StringSplitOptions.RemoveEmptyEntries).Last().ToLower(CultureInfo.CurrentCulture)))) ??
|
||||
filtersList.GetFilter(Path.Combine(imageFilter.ParentFolder, _header.SubchannelFile.Split(new[]
|
||||
{
|
||||
'\\'
|
||||
}, StringSplitOptions.RemoveEmptyEntries).Last().ToUpper(CultureInfo.CurrentCulture)));
|
||||
filtersList.GetFilter(Path.Combine(imageFilter.ParentFolder,
|
||||
_header.SubchannelFile.
|
||||
Split(new[] { '\\' },
|
||||
StringSplitOptions.RemoveEmptyEntries).Last()))) ??
|
||||
filtersList.GetFilter(Path.Combine(imageFilter.ParentFolder,
|
||||
_header.SubchannelFile.
|
||||
Split(new[] { '\\' },
|
||||
StringSplitOptions.RemoveEmptyEntries).Last().
|
||||
ToLower(CultureInfo.CurrentCulture)))) ??
|
||||
filtersList.GetFilter(Path.Combine(imageFilter.ParentFolder,
|
||||
_header.SubchannelFile.
|
||||
Split(new[] { '\\' }, StringSplitOptions.RemoveEmptyEntries).
|
||||
Last().ToUpper(CultureInfo.CurrentCulture)));
|
||||
}
|
||||
|
||||
Tracks = new List<Track>();
|
||||
@@ -477,6 +489,7 @@ public sealed partial class BlindWrite4
|
||||
_imageInfo.ReadableSectorTags.Add(SectorTagType.CdTrackFlags);
|
||||
|
||||
foreach(TrackDescriptor bwTrack in _bwTracks)
|
||||
{
|
||||
if(bwTrack.point < 0xA0)
|
||||
{
|
||||
var track = new Track
|
||||
@@ -486,6 +499,7 @@ public sealed partial class BlindWrite4
|
||||
};
|
||||
|
||||
if(!string.IsNullOrEmpty(bwTrack.filename))
|
||||
{
|
||||
do
|
||||
{
|
||||
track.Filter = filtersList.GetFilter(Path.Combine(imageFilter.ParentFolder, bwTrack.filename));
|
||||
@@ -508,20 +522,18 @@ public sealed partial class BlindWrite4
|
||||
break;
|
||||
|
||||
track.Filter = filtersList.GetFilter(Path.Combine(imageFilter.ParentFolder, bwTrack.filename.
|
||||
Split(new[]
|
||||
{
|
||||
'\\'
|
||||
}, StringSplitOptions.RemoveEmptyEntries).
|
||||
Split(new[] { '\\' },
|
||||
StringSplitOptions.
|
||||
RemoveEmptyEntries).
|
||||
Last()));
|
||||
|
||||
if(track.Filter != null)
|
||||
break;
|
||||
|
||||
track.Filter = filtersList.GetFilter(Path.Combine(imageFilter.ParentFolder, bwTrack.filename.
|
||||
Split(new[]
|
||||
{
|
||||
'\\'
|
||||
}, StringSplitOptions.RemoveEmptyEntries).
|
||||
Split(new[] { '\\' },
|
||||
StringSplitOptions.
|
||||
RemoveEmptyEntries).
|
||||
Last().ToLower(CultureInfo.
|
||||
CurrentCulture)));
|
||||
|
||||
@@ -529,23 +541,23 @@ public sealed partial class BlindWrite4
|
||||
break;
|
||||
|
||||
track.Filter = filtersList.GetFilter(Path.Combine(imageFilter.ParentFolder, bwTrack.filename.
|
||||
Split(new[]
|
||||
{
|
||||
'\\'
|
||||
}, StringSplitOptions.RemoveEmptyEntries).
|
||||
Split(new[] { '\\' },
|
||||
StringSplitOptions.
|
||||
RemoveEmptyEntries).
|
||||
Last().ToUpper(CultureInfo.
|
||||
CurrentCulture)));
|
||||
|
||||
track.Filter = _dataFilter;
|
||||
} while(true);
|
||||
}
|
||||
else
|
||||
track.Filter = _dataFilter;
|
||||
|
||||
track.File = _dataFilter.Filename;
|
||||
|
||||
track.FileOffset = bwTrack.offset + ((150 - bwTrack.pregapOffsetAdjustment) * 2352);
|
||||
track.FileOffset = bwTrack.offset + (150 - bwTrack.pregapOffsetAdjustment) * 2352;
|
||||
|
||||
track.SubchannelOffset = ((bwTrack.offset / 2352) + (150 - bwTrack.pregapOffsetAdjustment)) * 96;
|
||||
track.SubchannelOffset = (bwTrack.offset / 2352 + (150 - bwTrack.pregapOffsetAdjustment)) * 96;
|
||||
|
||||
if(bwTrack.pregap > 0)
|
||||
{
|
||||
@@ -692,6 +704,7 @@ public sealed partial class BlindWrite4
|
||||
!_imageInfo.ReadableMediaTags.Contains(MediaTagType.CD_MCN))
|
||||
_imageInfo.ReadableMediaTags.Add(MediaTagType.CD_MCN);
|
||||
}
|
||||
}
|
||||
|
||||
Sessions = new List<Session>();
|
||||
|
||||
@@ -724,8 +737,10 @@ public sealed partial class BlindWrite4
|
||||
|
||||
// As long as subchannel is written for any track, it is present for all tracks
|
||||
if(Tracks.Any(t => t.SubchannelType == TrackSubchannelType.Packed))
|
||||
{
|
||||
foreach(Track track in Tracks)
|
||||
track.SubchannelType = TrackSubchannelType.Packed;
|
||||
}
|
||||
|
||||
_imageInfo.MediaType = MediaType.CD;
|
||||
|
||||
@@ -738,11 +753,11 @@ public sealed partial class BlindWrite4
|
||||
_imageInfo.LastModificationTime = _dataFilter.LastWriteTime;
|
||||
_imageInfo.MetadataMediaType = MetadataMediaType.OpticalDisc;
|
||||
|
||||
bool data = false;
|
||||
bool mode2 = false;
|
||||
bool firstAudio = false;
|
||||
bool firstData = false;
|
||||
bool audio = false;
|
||||
var data = false;
|
||||
var mode2 = false;
|
||||
var firstAudio = false;
|
||||
var firstData = false;
|
||||
var audio = false;
|
||||
|
||||
foreach(Track bwTrack in Tracks)
|
||||
{
|
||||
@@ -759,10 +774,10 @@ public sealed partial class BlindWrite4
|
||||
audio |= bwTrack.Sequence != 1 && bwTrack.Type == CommonTypes.Enums.TrackType.Audio;
|
||||
|
||||
mode2 = bwTrack.Type switch
|
||||
{
|
||||
CommonTypes.Enums.TrackType.CdMode2Formless => true,
|
||||
_ => mode2
|
||||
};
|
||||
{
|
||||
CommonTypes.Enums.TrackType.CdMode2Formless => true,
|
||||
_ => mode2
|
||||
};
|
||||
}
|
||||
|
||||
if(!data &&
|
||||
@@ -773,7 +788,7 @@ public sealed partial class BlindWrite4
|
||||
Sessions.Count > 1 &&
|
||||
mode2)
|
||||
_imageInfo.MediaType = MediaType.CDPLUS;
|
||||
else if((firstData && audio) || mode2)
|
||||
else if(firstData && audio || mode2)
|
||||
_imageInfo.MediaType = MediaType.CDROMXA;
|
||||
else if(!audio)
|
||||
_imageInfo.MediaType = MediaType.CDROM;
|
||||
@@ -806,7 +821,8 @@ public sealed partial class BlindWrite4
|
||||
|
||||
return ErrorNumber.NoError;
|
||||
}
|
||||
default: return ErrorNumber.NotSupported;
|
||||
default:
|
||||
return ErrorNumber.NotSupported;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -830,10 +846,13 @@ public sealed partial class BlindWrite4
|
||||
{
|
||||
buffer = null;
|
||||
|
||||
foreach(KeyValuePair<uint, ulong> kvp in from kvp in _offsetMap where sectorAddress >= kvp.Value
|
||||
from track in Tracks where track.Sequence == kvp.Key
|
||||
foreach(KeyValuePair<uint, ulong> kvp in from kvp in _offsetMap
|
||||
where sectorAddress >= kvp.Value
|
||||
from track in Tracks
|
||||
where track.Sequence == kvp.Key
|
||||
where sectorAddress - kvp.Value <
|
||||
track.EndSector - track.StartSector + 1 select kvp)
|
||||
track.EndSector - track.StartSector + 1
|
||||
select kvp)
|
||||
return ReadSectors(sectorAddress - kvp.Value, length, kvp.Key, out buffer);
|
||||
|
||||
return ErrorNumber.SectorNotFound;
|
||||
@@ -844,10 +863,13 @@ public sealed partial class BlindWrite4
|
||||
{
|
||||
buffer = null;
|
||||
|
||||
foreach(KeyValuePair<uint, ulong> kvp in from kvp in _offsetMap where sectorAddress >= kvp.Value
|
||||
from track in Tracks where track.Sequence == kvp.Key
|
||||
foreach(KeyValuePair<uint, ulong> kvp in from kvp in _offsetMap
|
||||
where sectorAddress >= kvp.Value
|
||||
from track in Tracks
|
||||
where track.Sequence == kvp.Key
|
||||
where sectorAddress - kvp.Value <
|
||||
track.EndSector - track.StartSector + 1 select kvp)
|
||||
track.EndSector - track.StartSector + 1
|
||||
select kvp)
|
||||
return ReadSectorsTag(sectorAddress - kvp.Value, length, kvp.Key, tag, out buffer);
|
||||
|
||||
return ErrorNumber.SectorNotFound;
|
||||
@@ -868,7 +890,7 @@ public sealed partial class BlindWrite4
|
||||
uint sectorOffset;
|
||||
uint sectorSize;
|
||||
uint sectorSkip;
|
||||
bool mode2 = false;
|
||||
var mode2 = false;
|
||||
|
||||
switch(aaruTrack.Type)
|
||||
{
|
||||
@@ -905,7 +927,8 @@ public sealed partial class BlindWrite4
|
||||
|
||||
break;
|
||||
}
|
||||
default: return ErrorNumber.NotSupported;
|
||||
default:
|
||||
return ErrorNumber.NotSupported;
|
||||
}
|
||||
|
||||
buffer = new byte[sectorSize * length];
|
||||
@@ -923,9 +946,9 @@ public sealed partial class BlindWrite4
|
||||
|
||||
buffer = br.ReadBytes((int)(sectorSize * length));
|
||||
|
||||
for(int i = 0; i < length; i++)
|
||||
for(var i = 0; i < length; i++)
|
||||
{
|
||||
byte[] sector = new byte[sectorSize];
|
||||
var sector = new byte[sectorSize];
|
||||
Array.Copy(buffer, sectorSize * i, sector, 0, sectorSize);
|
||||
sector = Sector.GetUserDataFromMode2(sector);
|
||||
mode2Ms.Write(sector, 0, sector.Length);
|
||||
@@ -937,7 +960,8 @@ public sealed partial class BlindWrite4
|
||||
sectorSkip == 0)
|
||||
buffer = br.ReadBytes((int)(sectorSize * length));
|
||||
else
|
||||
for(int i = 0; i < length; i++)
|
||||
{
|
||||
for(var i = 0; i < length; i++)
|
||||
{
|
||||
br.BaseStream.Seek(sectorOffset, SeekOrigin.Current);
|
||||
byte[] sector = br.ReadBytes((int)sectorSize);
|
||||
@@ -945,12 +969,13 @@ public sealed partial class BlindWrite4
|
||||
|
||||
Array.Copy(sector, 0, buffer, i * sectorSize, sectorSize);
|
||||
}
|
||||
}
|
||||
|
||||
return ErrorNumber.NoError;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ErrorNumber ReadSectorsTag(ulong sectorAddress, uint length, uint track, SectorTagType tag,
|
||||
public ErrorNumber ReadSectorsTag(ulong sectorAddress, uint length, uint track, SectorTagType tag,
|
||||
out byte[] buffer)
|
||||
{
|
||||
buffer = null;
|
||||
@@ -978,18 +1003,17 @@ public sealed partial class BlindWrite4
|
||||
case SectorTagType.CdSectorHeader:
|
||||
case SectorTagType.CdSectorSubchannel:
|
||||
case SectorTagType.CdSectorSubHeader:
|
||||
case SectorTagType.CdSectorSync: break;
|
||||
case SectorTagType.CdSectorSync:
|
||||
break;
|
||||
case SectorTagType.CdTrackFlags:
|
||||
if(!_trackFlags.TryGetValue((uint)sectorAddress, out byte flag))
|
||||
return ErrorNumber.NoData;
|
||||
|
||||
buffer = new[]
|
||||
{
|
||||
flag
|
||||
};
|
||||
buffer = new[] { flag };
|
||||
|
||||
return ErrorNumber.NoError;
|
||||
default: return ErrorNumber.NotSupported;
|
||||
default:
|
||||
return ErrorNumber.NotSupported;
|
||||
}
|
||||
|
||||
switch(aaruTrack.Type)
|
||||
@@ -1013,7 +1037,8 @@ public sealed partial class BlindWrite4
|
||||
|
||||
break;
|
||||
}
|
||||
case SectorTagType.CdSectorSubHeader: return ErrorNumber.NotSupported;
|
||||
case SectorTagType.CdSectorSubHeader:
|
||||
return ErrorNumber.NotSupported;
|
||||
case SectorTagType.CdSectorEcc:
|
||||
{
|
||||
sectorOffset = 2076;
|
||||
@@ -1065,7 +1090,8 @@ public sealed partial class BlindWrite4
|
||||
case SectorTagType.CdSectorHeader:
|
||||
case SectorTagType.CdSectorEcc:
|
||||
case SectorTagType.CdSectorEccP:
|
||||
case SectorTagType.CdSectorEccQ: return ErrorNumber.NotSupported;
|
||||
case SectorTagType.CdSectorEccQ:
|
||||
return ErrorNumber.NotSupported;
|
||||
case SectorTagType.CdSectorSubHeader:
|
||||
{
|
||||
sectorOffset = 0;
|
||||
@@ -1106,36 +1132,43 @@ public sealed partial class BlindWrite4
|
||||
|
||||
break;
|
||||
}
|
||||
default: return ErrorNumber.NotSupported;
|
||||
default:
|
||||
return ErrorNumber.NotSupported;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default: return ErrorNumber.NotSupported;
|
||||
default:
|
||||
return ErrorNumber.NotSupported;
|
||||
}
|
||||
|
||||
buffer = new byte[sectorSize * length];
|
||||
|
||||
_imageStream = tag == SectorTagType.CdSectorSubchannel ? aaruTrack.SubchannelFilter.GetDataForkStream()
|
||||
_imageStream = tag == SectorTagType.CdSectorSubchannel
|
||||
? aaruTrack.SubchannelFilter.GetDataForkStream()
|
||||
: aaruTrack.Filter.GetDataForkStream();
|
||||
|
||||
var br = new BinaryReader(_imageStream);
|
||||
|
||||
br.BaseStream.
|
||||
Seek((long)(tag == SectorTagType.CdSectorSubchannel ? aaruTrack.SubchannelOffset : aaruTrack.FileOffset) + (long)(sectorAddress * (sectorOffset + sectorSize + sectorSkip)),
|
||||
SeekOrigin.Begin);
|
||||
Seek(
|
||||
(long)(tag == SectorTagType.CdSectorSubchannel ? aaruTrack.SubchannelOffset : aaruTrack.FileOffset) +
|
||||
(long)(sectorAddress * (sectorOffset + sectorSize + sectorSkip)),
|
||||
SeekOrigin.Begin);
|
||||
|
||||
if(sectorOffset == 0 &&
|
||||
sectorSkip == 0)
|
||||
buffer = br.ReadBytes((int)(sectorSize * length));
|
||||
else
|
||||
for(int i = 0; i < length; i++)
|
||||
{
|
||||
for(var i = 0; i < length; i++)
|
||||
{
|
||||
br.BaseStream.Seek(sectorOffset, SeekOrigin.Current);
|
||||
byte[] sector = br.ReadBytes((int)sectorSize);
|
||||
br.BaseStream.Seek(sectorSkip, SeekOrigin.Current);
|
||||
Array.Copy(sector, 0, buffer, i * sectorSize, sectorSize);
|
||||
}
|
||||
}
|
||||
|
||||
if(tag == SectorTagType.CdSectorSubchannel)
|
||||
buffer = Subchannel.Interleave(buffer);
|
||||
@@ -1156,10 +1189,13 @@ public sealed partial class BlindWrite4
|
||||
{
|
||||
buffer = null;
|
||||
|
||||
foreach(KeyValuePair<uint, ulong> kvp in from kvp in _offsetMap where sectorAddress >= kvp.Value
|
||||
from track in Tracks where track.Sequence == kvp.Key
|
||||
foreach(KeyValuePair<uint, ulong> kvp in from kvp in _offsetMap
|
||||
where sectorAddress >= kvp.Value
|
||||
from track in Tracks
|
||||
where track.Sequence == kvp.Key
|
||||
where sectorAddress - kvp.Value <
|
||||
track.EndSector - track.StartSector + 1 select kvp)
|
||||
track.EndSector - track.StartSector + 1
|
||||
select kvp)
|
||||
return ReadSectorsLong(sectorAddress - kvp.Value, length, kvp.Key, out buffer);
|
||||
|
||||
return ErrorNumber.SectorNotFound;
|
||||
@@ -1190,7 +1226,8 @@ public sealed partial class BlindWrite4
|
||||
|
||||
break;
|
||||
}
|
||||
default: return ErrorNumber.NotSupported;
|
||||
default:
|
||||
return ErrorNumber.NotSupported;
|
||||
}
|
||||
|
||||
_imageStream = aaruTrack.Filter.GetDataForkStream();
|
||||
@@ -1209,4 +1246,6 @@ public sealed partial class BlindWrite4
|
||||
|
||||
/// <inheritdoc />
|
||||
public List<Track> GetSessionTracks(ushort session) => Tracks.Where(track => track.Session == session).ToList();
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -37,6 +37,8 @@ namespace Aaru.DiscImages;
|
||||
|
||||
public sealed partial class BlindWrite4
|
||||
{
|
||||
#region Nested type: Header
|
||||
|
||||
struct Header
|
||||
{
|
||||
public byte[] Signature;
|
||||
@@ -58,7 +60,7 @@ public sealed partial class BlindWrite4
|
||||
public byte[] Unknown4;
|
||||
|
||||
// On memory only
|
||||
#pragma warning disable 649
|
||||
#pragma warning disable 649
|
||||
public string VolumeIdentifier;
|
||||
public string SystemIdentifier;
|
||||
public string Comments;
|
||||
@@ -66,9 +68,13 @@ public sealed partial class BlindWrite4
|
||||
public IFilter SubchannelFilter;
|
||||
public string DataFile;
|
||||
public string SubchannelFile;
|
||||
#pragma warning restore 649
|
||||
#pragma warning restore 649
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Nested type: TrackDescriptor
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct TrackDescriptor
|
||||
{
|
||||
@@ -149,4 +155,6 @@ public sealed partial class BlindWrite4
|
||||
public string unkString11;
|
||||
public string isrcUpc;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -39,6 +39,8 @@ namespace Aaru.DiscImages;
|
||||
|
||||
public sealed partial class BlindWrite4
|
||||
{
|
||||
#region IOpticalMediaImage Members
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool? VerifySector(ulong sectorAddress)
|
||||
{
|
||||
@@ -48,7 +50,7 @@ public sealed partial class BlindWrite4
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool? VerifySectors(ulong sectorAddress, uint length, out List<ulong> failingLbas,
|
||||
public bool? VerifySectors(ulong sectorAddress, uint length, out List<ulong> failingLbas,
|
||||
out List<ulong> unknownLbas)
|
||||
{
|
||||
failingLbas = new List<ulong>();
|
||||
@@ -58,10 +60,10 @@ public sealed partial class BlindWrite4
|
||||
if(errno != ErrorNumber.NoError)
|
||||
return null;
|
||||
|
||||
int bps = (int)(buffer.Length / length);
|
||||
byte[] sector = new byte[bps];
|
||||
var bps = (int)(buffer.Length / length);
|
||||
var sector = new byte[bps];
|
||||
|
||||
for(int i = 0; i < length; i++)
|
||||
for(var i = 0; i < length; i++)
|
||||
{
|
||||
Array.Copy(buffer, i * bps, sector, 0, bps);
|
||||
bool? sectorStatus = CdChecksums.CheckCdSector(sector);
|
||||
@@ -86,7 +88,7 @@ public sealed partial class BlindWrite4
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool? VerifySectors(ulong sectorAddress, uint length, uint track, out List<ulong> failingLbas,
|
||||
public bool? VerifySectors(ulong sectorAddress, uint length, uint track, out List<ulong> failingLbas,
|
||||
out List<ulong> unknownLbas)
|
||||
{
|
||||
failingLbas = new List<ulong>();
|
||||
@@ -96,10 +98,10 @@ public sealed partial class BlindWrite4
|
||||
if(errno != ErrorNumber.NoError)
|
||||
return null;
|
||||
|
||||
int bps = (int)(buffer.Length / length);
|
||||
byte[] sector = new byte[bps];
|
||||
var bps = (int)(buffer.Length / length);
|
||||
var sector = new byte[bps];
|
||||
|
||||
for(int i = 0; i < length; i++)
|
||||
for(var i = 0; i < length; i++)
|
||||
{
|
||||
Array.Copy(buffer, i * bps, sector, 0, bps);
|
||||
bool? sectorStatus = CdChecksums.CheckCdSector(sector);
|
||||
@@ -122,4 +124,6 @@ public sealed partial class BlindWrite4
|
||||
|
||||
return failingLbas.Count <= 0;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -43,6 +43,7 @@ namespace Aaru.DiscImages;
|
||||
/// <summary>Implements reading BlindWrite 5/6/7 disc images</summary>
|
||||
public sealed partial class BlindWrite5 : IOpticalMediaImage
|
||||
{
|
||||
const string MODULE_NAME = "BlindWrite5 plugin";
|
||||
byte[] _atip;
|
||||
byte[] _bca;
|
||||
List<SessionDescriptor> _bwSessions;
|
||||
@@ -84,6 +85,4 @@ public sealed partial class BlindWrite5 : IOpticalMediaImage
|
||||
DriveSerialNumber = null,
|
||||
DriveFirmwareRevision = null
|
||||
};
|
||||
|
||||
const string MODULE_NAME = "BlindWrite5 plugin";
|
||||
}
|
||||
@@ -37,15 +37,29 @@ namespace Aaru.DiscImages;
|
||||
[SuppressMessage("ReSharper", "UnusedMember.Local")]
|
||||
public sealed partial class BlindWrite5
|
||||
{
|
||||
enum TrackType : byte
|
||||
{
|
||||
NotData = 0, Audio = 1, Mode1 = 2,
|
||||
Mode2 = 3, Mode2F1 = 4, Mode2F2 = 5,
|
||||
Dvd = 6
|
||||
}
|
||||
#region Nested type: TrackSubchannel
|
||||
|
||||
enum TrackSubchannel : byte
|
||||
{
|
||||
None = 0, Q16 = 2, Linear = 4
|
||||
None = 0,
|
||||
Q16 = 2,
|
||||
Linear = 4
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Nested type: TrackType
|
||||
|
||||
enum TrackType : byte
|
||||
{
|
||||
NotData = 0,
|
||||
Audio = 1,
|
||||
Mode1 = 2,
|
||||
Mode2 = 3,
|
||||
Mode2F1 = 4,
|
||||
Mode2F2 = 5,
|
||||
Dvd = 6
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -38,55 +38,84 @@ namespace Aaru.DiscImages;
|
||||
public sealed partial class BlindWrite5
|
||||
{
|
||||
static CommonTypes.Enums.TrackType BlindWriteTrackTypeToTrackType(TrackType trackType) => trackType switch
|
||||
{
|
||||
TrackType.Mode1 => CommonTypes.Enums.TrackType.CdMode1,
|
||||
TrackType.Mode2F1 => CommonTypes.Enums.TrackType.CdMode2Form1,
|
||||
TrackType.Mode2F2 => CommonTypes.Enums.TrackType.CdMode2Form2,
|
||||
TrackType.Mode2 => CommonTypes.Enums.TrackType.CdMode2Formless,
|
||||
TrackType.Audio => CommonTypes.Enums.TrackType.Audio,
|
||||
_ => CommonTypes.Enums.TrackType.Data
|
||||
};
|
||||
{
|
||||
TrackType.Mode1 => CommonTypes.Enums.TrackType.CdMode1,
|
||||
TrackType.Mode2F1 => CommonTypes.Enums.TrackType.CdMode2Form1,
|
||||
TrackType.Mode2F2 => CommonTypes.Enums.TrackType.CdMode2Form2,
|
||||
TrackType.Mode2 => CommonTypes.Enums.TrackType.CdMode2Formless,
|
||||
TrackType.Audio => CommonTypes.Enums.TrackType.Audio,
|
||||
_ => CommonTypes.Enums.TrackType.Data
|
||||
};
|
||||
|
||||
static MediaType BlindWriteProfileToMediaType(ProfileNumber profile)
|
||||
{
|
||||
switch(profile)
|
||||
{
|
||||
case ProfileNumber.BDRE: return MediaType.BDRE;
|
||||
case ProfileNumber.BDROM: return MediaType.BDROM;
|
||||
case ProfileNumber.BDRE:
|
||||
return MediaType.BDRE;
|
||||
case ProfileNumber.BDROM:
|
||||
return MediaType.BDROM;
|
||||
case ProfileNumber.BDRRdm:
|
||||
case ProfileNumber.BDRSeq: return MediaType.BDR;
|
||||
case ProfileNumber.BDRSeq:
|
||||
return MediaType.BDR;
|
||||
case ProfileNumber.CDR:
|
||||
case ProfileNumber.HDBURNR: return MediaType.CDR;
|
||||
case ProfileNumber.HDBURNR:
|
||||
return MediaType.CDR;
|
||||
case ProfileNumber.CDROM:
|
||||
case ProfileNumber.HDBURNROM: return MediaType.CDROM;
|
||||
case ProfileNumber.HDBURNROM:
|
||||
return MediaType.CDROM;
|
||||
case ProfileNumber.CDRW:
|
||||
case ProfileNumber.HDBURNRW: return MediaType.CDRW;
|
||||
case ProfileNumber.DDCDR: return MediaType.DDCDR;
|
||||
case ProfileNumber.DDCDROM: return MediaType.DDCD;
|
||||
case ProfileNumber.DDCDRW: return MediaType.DDCDRW;
|
||||
case ProfileNumber.DVDDownload: return MediaType.DVDDownload;
|
||||
case ProfileNumber.DVDRAM: return MediaType.DVDRAM;
|
||||
case ProfileNumber.HDBURNRW:
|
||||
return MediaType.CDRW;
|
||||
case ProfileNumber.DDCDR:
|
||||
return MediaType.DDCDR;
|
||||
case ProfileNumber.DDCDROM:
|
||||
return MediaType.DDCD;
|
||||
case ProfileNumber.DDCDRW:
|
||||
return MediaType.DDCDRW;
|
||||
case ProfileNumber.DVDDownload:
|
||||
return MediaType.DVDDownload;
|
||||
case ProfileNumber.DVDRAM:
|
||||
return MediaType.DVDRAM;
|
||||
case ProfileNumber.DVDRDLJump:
|
||||
case ProfileNumber.DVDRDLSeq: return MediaType.DVDRDL;
|
||||
case ProfileNumber.DVDRDLPlus: return MediaType.DVDPRDL;
|
||||
case ProfileNumber.DVDROM: return MediaType.DVDROM;
|
||||
case ProfileNumber.DVDRPlus: return MediaType.DVDPR;
|
||||
case ProfileNumber.DVDRSeq: return MediaType.DVDR;
|
||||
case ProfileNumber.DVDRWDL: return MediaType.DVDRWDL;
|
||||
case ProfileNumber.DVDRWDLPlus: return MediaType.DVDPRWDL;
|
||||
case ProfileNumber.DVDRWPlus: return MediaType.DVDPRW;
|
||||
case ProfileNumber.DVDRDLSeq:
|
||||
return MediaType.DVDRDL;
|
||||
case ProfileNumber.DVDRDLPlus:
|
||||
return MediaType.DVDPRDL;
|
||||
case ProfileNumber.DVDROM:
|
||||
return MediaType.DVDROM;
|
||||
case ProfileNumber.DVDRPlus:
|
||||
return MediaType.DVDPR;
|
||||
case ProfileNumber.DVDRSeq:
|
||||
return MediaType.DVDR;
|
||||
case ProfileNumber.DVDRWDL:
|
||||
return MediaType.DVDRWDL;
|
||||
case ProfileNumber.DVDRWDLPlus:
|
||||
return MediaType.DVDPRWDL;
|
||||
case ProfileNumber.DVDRWPlus:
|
||||
return MediaType.DVDPRW;
|
||||
case ProfileNumber.DVDRWRes:
|
||||
case ProfileNumber.DVDRWSeq: return MediaType.DVDRW;
|
||||
case ProfileNumber.HDDVDR: return MediaType.HDDVDR;
|
||||
case ProfileNumber.HDDVDRAM: return MediaType.HDDVDRAM;
|
||||
case ProfileNumber.HDDVDRDL: return MediaType.HDDVDRDL;
|
||||
case ProfileNumber.HDDVDROM: return MediaType.HDDVDROM;
|
||||
case ProfileNumber.HDDVDRW: return MediaType.HDDVDRW;
|
||||
case ProfileNumber.HDDVDRWDL: return MediaType.HDDVDRWDL;
|
||||
case ProfileNumber.DVDRWSeq:
|
||||
return MediaType.DVDRW;
|
||||
case ProfileNumber.HDDVDR:
|
||||
return MediaType.HDDVDR;
|
||||
case ProfileNumber.HDDVDRAM:
|
||||
return MediaType.HDDVDRAM;
|
||||
case ProfileNumber.HDDVDRDL:
|
||||
return MediaType.HDDVDRDL;
|
||||
case ProfileNumber.HDDVDROM:
|
||||
return MediaType.HDDVDROM;
|
||||
case ProfileNumber.HDDVDRW:
|
||||
return MediaType.HDDVDRW;
|
||||
case ProfileNumber.HDDVDRWDL:
|
||||
return MediaType.HDDVDRWDL;
|
||||
case ProfileNumber.ASMO:
|
||||
case ProfileNumber.MOErasable: return MediaType.UnknownMO;
|
||||
case ProfileNumber.NonRemovable: return MediaType.GENERIC_HDD;
|
||||
default: return MediaType.CD;
|
||||
case ProfileNumber.MOErasable:
|
||||
return MediaType.UnknownMO;
|
||||
case ProfileNumber.NonRemovable:
|
||||
return MediaType.GENERIC_HDD;
|
||||
default:
|
||||
return MediaType.CD;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -39,6 +39,8 @@ namespace Aaru.DiscImages;
|
||||
|
||||
public sealed partial class BlindWrite5
|
||||
{
|
||||
#region IOpticalMediaImage Members
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Identify(IFilter imageFilter)
|
||||
{
|
||||
@@ -48,13 +50,15 @@ public sealed partial class BlindWrite5
|
||||
if(stream.Length < 276)
|
||||
return false;
|
||||
|
||||
byte[] signature = new byte[16];
|
||||
var signature = new byte[16];
|
||||
stream.EnsureRead(signature, 0, 16);
|
||||
|
||||
byte[] footer = new byte[16];
|
||||
var footer = new byte[16];
|
||||
stream.Seek(-16, SeekOrigin.End);
|
||||
stream.EnsureRead(footer, 0, 16);
|
||||
|
||||
return _bw5Signature.SequenceEqual(signature) && _bw5Footer.SequenceEqual(footer);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -41,15 +41,20 @@ namespace Aaru.DiscImages;
|
||||
|
||||
public sealed partial class BlindWrite5
|
||||
{
|
||||
#region IOpticalMediaImage Members
|
||||
|
||||
/// <inheritdoc />
|
||||
public ImageInfo Info => _imageInfo;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Name => Localization.BlindWrite5_Name;
|
||||
|
||||
/// <inheritdoc />
|
||||
public Guid Id => new("9CB7A381-0509-4F9F-B801-3F65434BC3EE");
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Author => Authors.NataliaPortillo;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Format => "BlindWrite 5 TOC file";
|
||||
|
||||
@@ -64,6 +69,9 @@ public sealed partial class BlindWrite5
|
||||
|
||||
/// <inheritdoc />
|
||||
public List<DumpHardware> DumpHardware => null;
|
||||
|
||||
/// <inheritdoc />
|
||||
public Metadata AaruMetadata => null;
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -56,6 +56,8 @@ namespace Aaru.DiscImages;
|
||||
|
||||
public sealed partial class BlindWrite5
|
||||
{
|
||||
#region IOpticalMediaImage Members
|
||||
|
||||
/// <inheritdoc />
|
||||
public ErrorNumber Open(IFilter imageFilter)
|
||||
{
|
||||
@@ -65,42 +67,42 @@ public sealed partial class BlindWrite5
|
||||
if(stream.Length < 276)
|
||||
return ErrorNumber.InvalidArgument;
|
||||
|
||||
byte[] hdr = new byte[260];
|
||||
var hdr = new byte[260];
|
||||
stream.EnsureRead(hdr, 0, 260);
|
||||
_header = Marshal.ByteArrayToStructureLittleEndian<Header>(hdr);
|
||||
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.signature = {0}",
|
||||
StringHandlers.CToString(_header.signature));
|
||||
|
||||
for(int i = 0; i < _header.unknown1.Length; i++)
|
||||
for(var i = 0; i < _header.unknown1.Length; i++)
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.unknown1[{1}] = 0x{0:X8}", _header.unknown1[i], i);
|
||||
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.profile = {0}", _header.profile);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.profile = {0}", _header.profile);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.sessions = {0}", _header.sessions);
|
||||
|
||||
for(int i = 0; i < _header.unknown2.Length; i++)
|
||||
for(var i = 0; i < _header.unknown2.Length; i++)
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.unknown2[{1}] = 0x{0:X8}", _header.unknown2[i], i);
|
||||
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.mcnIsValid = {0}", _header.mcnIsValid);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.mcn = {0}", StringHandlers.CToString(_header.mcn));
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.mcnIsValid = {0}", _header.mcnIsValid);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.mcn = {0}", StringHandlers.CToString(_header.mcn));
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.unknown3 = 0x{0:X4}", _header.unknown3);
|
||||
|
||||
for(int i = 0; i < _header.unknown4.Length; i++)
|
||||
for(var i = 0; i < _header.unknown4.Length; i++)
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.unknown4[{1}] = 0x{0:X8}", _header.unknown4[i], i);
|
||||
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.pmaLen = {0}", _header.pmaLen);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.atipLen = {0}", _header.atipLen);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.cdtLen = {0}", _header.cdtLen);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.pmaLen = {0}", _header.pmaLen);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.atipLen = {0}", _header.atipLen);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.cdtLen = {0}", _header.cdtLen);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.cdInfoLen = {0}", _header.cdInfoLen);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.bcaLen = {0}", _header.bcaLen);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.bcaLen = {0}", _header.bcaLen);
|
||||
|
||||
for(int i = 0; i < _header.unknown5.Length; i++)
|
||||
for(var i = 0; i < _header.unknown5.Length; i++)
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.unknown5[{1}] = 0x{0:X8}", _header.unknown5[i], i);
|
||||
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.dvdStrLen = {0}", _header.dvdStrLen);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.dvdStrLen = {0}", _header.dvdStrLen);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.dvdInfoLen = {0}", _header.dvdInfoLen);
|
||||
|
||||
for(int i = 0; i < _header.unknown6.Length; i++)
|
||||
for(var i = 0; i < _header.unknown6.Length; i++)
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.unknown6[{1}] = 0x{0:X2}", _header.unknown6[i], i);
|
||||
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.manufacturer = {0}",
|
||||
@@ -118,11 +120,11 @@ public sealed partial class BlindWrite5
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.volumeId = {0}",
|
||||
StringHandlers.CToString(_header.volumeId));
|
||||
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.mode2ALen = {0}", _header.mode2ALen);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.unkBlkLen = {0}", _header.unkBlkLen);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.dataLen = {0}", _header.dataLen);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.mode2ALen = {0}", _header.mode2ALen);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.unkBlkLen = {0}", _header.unkBlkLen);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.dataLen = {0}", _header.dataLen);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.sessionsLen = {0}", _header.sessionsLen);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.dpmLen = {0}", _header.dpmLen);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "header.dpmLen = {0}", _header.dpmLen);
|
||||
|
||||
_mode2A = new byte[_header.mode2ALen];
|
||||
|
||||
@@ -133,8 +135,10 @@ public sealed partial class BlindWrite5
|
||||
var decoded2A = ModePage_2A.Decode(_mode2A);
|
||||
|
||||
if(decoded2A is not null)
|
||||
{
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, Localization.mode_page_2A_0,
|
||||
Modes.PrettifyModePage_2A(decoded2A));
|
||||
}
|
||||
else
|
||||
_mode2A = null;
|
||||
}
|
||||
@@ -144,7 +148,7 @@ public sealed partial class BlindWrite5
|
||||
if(_unkBlock.Length > 0)
|
||||
stream.EnsureRead(_unkBlock, 0, _unkBlock.Length);
|
||||
|
||||
byte[] temp = new byte[_header.pmaLen];
|
||||
var temp = new byte[_header.pmaLen];
|
||||
|
||||
if(temp.Length > 0)
|
||||
{
|
||||
@@ -193,7 +197,7 @@ public sealed partial class BlindWrite5
|
||||
_pfi = new byte[2052];
|
||||
|
||||
// TODO: CMI
|
||||
Array.Copy(temp, 2, _dmi, 4, 2048);
|
||||
Array.Copy(temp, 2, _dmi, 4, 2048);
|
||||
Array.Copy(temp, 0x802, _pfi, 4, 2048);
|
||||
|
||||
_pfi[0] = 0x08;
|
||||
@@ -243,20 +247,20 @@ public sealed partial class BlindWrite5
|
||||
_discInformation = null;
|
||||
|
||||
// How many data blocks
|
||||
byte[] tmpArray = new byte[4];
|
||||
var tmpArray = new byte[4];
|
||||
stream.EnsureRead(tmpArray, 0, tmpArray.Length);
|
||||
uint dataBlockCount = BitConverter.ToUInt32(tmpArray, 0);
|
||||
var dataBlockCount = BitConverter.ToUInt32(tmpArray, 0);
|
||||
|
||||
stream.EnsureRead(tmpArray, 0, tmpArray.Length);
|
||||
uint dataPathLen = BitConverter.ToUInt32(tmpArray, 0);
|
||||
byte[] dataPathBytes = new byte[dataPathLen];
|
||||
var dataPathLen = BitConverter.ToUInt32(tmpArray, 0);
|
||||
var dataPathBytes = new byte[dataPathLen];
|
||||
stream.EnsureRead(dataPathBytes, 0, dataPathBytes.Length);
|
||||
_dataPath = Encoding.Unicode.GetString(dataPathBytes);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Data_path_0, _dataPath);
|
||||
|
||||
_dataFiles = new List<DataFile>();
|
||||
|
||||
for(int cD = 0; cD < dataBlockCount; cD++)
|
||||
for(var cD = 0; cD < dataBlockCount; cD++)
|
||||
{
|
||||
tmpArray = new byte[52];
|
||||
|
||||
@@ -293,28 +297,32 @@ public sealed partial class BlindWrite5
|
||||
_dataFiles.Add(dataFile);
|
||||
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "dataFile.type = 0x{0:X8}", dataFile.Type);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "dataFile.length = {0}", dataFile.Length);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "dataFile.length = {0}", dataFile.Length);
|
||||
|
||||
for(int i = 0; i < dataFile.Unknown1.Length; i++)
|
||||
for(var i = 0; i < dataFile.Unknown1.Length; i++)
|
||||
{
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "dataFile.unknown1[{1}] = {0}", dataFile.Unknown1[i],
|
||||
i);
|
||||
}
|
||||
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "dataFile.offset = {0}", dataFile.Offset);
|
||||
|
||||
for(int i = 0; i < dataFile.Unknown2.Length; i++)
|
||||
for(var i = 0; i < dataFile.Unknown2.Length; i++)
|
||||
{
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "dataFile.unknown2[{1}] = {0}", dataFile.Unknown2[i],
|
||||
i);
|
||||
}
|
||||
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "dataFile.startLba = {0}", dataFile.StartLba);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "dataFile.sectors = {0}", dataFile.Sectors);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "dataFile.startLba = {0}", dataFile.StartLba);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "dataFile.sectors = {0}", dataFile.Sectors);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "dataFile.filenameLen = {0}", dataFile.FilenameLen);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "dataFile.filename = {0}", dataFile.Filename);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "dataFile.unknown3 = {0}", dataFile.Unknown3);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "dataFile.filename = {0}", dataFile.Filename);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "dataFile.unknown3 = {0}", dataFile.Unknown3);
|
||||
}
|
||||
|
||||
_bwSessions = new List<SessionDescriptor>();
|
||||
|
||||
for(int ses = 0; ses < _header.sessions; ses++)
|
||||
for(var ses = 0; ses < _header.sessions; ses++)
|
||||
{
|
||||
var session = new SessionDescriptor();
|
||||
tmpArray = new byte[16];
|
||||
@@ -329,18 +337,18 @@ public sealed partial class BlindWrite5
|
||||
session.Tracks = new TrackDescriptor[session.Entries];
|
||||
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "session[{0}].filename = {1}", ses, session.Sequence);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "session[{0}].entries = {1}", ses, session.Entries);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "session[{0}].unknown = {1}", ses, session.Unknown);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "session[{0}].start = {1}", ses, session.Start);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "session[{0}].end = {1}", ses, session.End);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "session[{0}].entries = {1}", ses, session.Entries);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "session[{0}].unknown = {1}", ses, session.Unknown);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "session[{0}].start = {1}", ses, session.Start);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "session[{0}].end = {1}", ses, session.End);
|
||||
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "session[{0}].firstTrack = {1}", ses, session.FirstTrack);
|
||||
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "session[{0}].lastTrack = {1}", ses, session.LastTrack);
|
||||
|
||||
for(int tSeq = 0; tSeq < session.Entries; tSeq++)
|
||||
for(var tSeq = 0; tSeq < session.Entries; tSeq++)
|
||||
{
|
||||
byte[] trk = new byte[72];
|
||||
var trk = new byte[72];
|
||||
stream.EnsureRead(trk, 0, 72);
|
||||
session.Tracks[tSeq] = Marshal.ByteArrayToStructureLittleEndian<TrackDescriptor>(trk);
|
||||
|
||||
@@ -354,9 +362,11 @@ public sealed partial class BlindWrite5
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "session[{0}].track[{1}].type = {2}", ses, tSeq,
|
||||
session.Tracks[tSeq].type);
|
||||
|
||||
for(int i = 0; i < session.Tracks[tSeq].unknown1.Length; i++)
|
||||
for(var i = 0; i < session.Tracks[tSeq].unknown1.Length; i++)
|
||||
{
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "session[{0}].track[{1}].unknown1[{2}] = 0x{3:X2}",
|
||||
ses, tSeq, i, session.Tracks[tSeq].unknown1[i]);
|
||||
}
|
||||
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "session[{0}].track[{1}].unknown2 = 0x{2:X8}", ses,
|
||||
tSeq, session.Tracks[tSeq].unknown2);
|
||||
@@ -406,9 +416,11 @@ public sealed partial class BlindWrite5
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "session[{0}].track[{1}].pregap = {2}", ses, tSeq,
|
||||
session.Tracks[tSeq].pregap);
|
||||
|
||||
for(int i = 0; i < session.Tracks[tSeq].unknown6.Length; i++)
|
||||
for(var i = 0; i < session.Tracks[tSeq].unknown6.Length; i++)
|
||||
{
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "session[{0}].track[{1}].unknown6[{2}] = 0x{3:X8}",
|
||||
ses, tSeq, i, session.Tracks[tSeq].unknown6[i]);
|
||||
}
|
||||
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "session[{0}].track[{1}].startLba = {2}", ses, tSeq,
|
||||
session.Tracks[tSeq].startLba);
|
||||
@@ -416,9 +428,11 @@ public sealed partial class BlindWrite5
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "session[{0}].track[{1}].sectors = {2}", ses, tSeq,
|
||||
session.Tracks[tSeq].sectors);
|
||||
|
||||
for(int i = 0; i < session.Tracks[tSeq].unknown7.Length; i++)
|
||||
for(var i = 0; i < session.Tracks[tSeq].unknown7.Length; i++)
|
||||
{
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "session[{0}].track[{1}].unknown7[{2}] = 0x{3:X8}",
|
||||
ses, tSeq, i, session.Tracks[tSeq].unknown7[i]);
|
||||
}
|
||||
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "session[{0}].track[{1}].session = {2}", ses, tSeq,
|
||||
session.Tracks[tSeq].session);
|
||||
@@ -430,10 +444,12 @@ public sealed partial class BlindWrite5
|
||||
continue;
|
||||
|
||||
{
|
||||
for(int i = 0; i < session.Tracks[tSeq].unknown9.Length; i++)
|
||||
for(var i = 0; i < session.Tracks[tSeq].unknown9.Length; i++)
|
||||
{
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME,
|
||||
"session[{0}].track[{1}].unknown9[{2}] = 0x{3:X8}", ses, tSeq, i,
|
||||
session.Tracks[tSeq].unknown9[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -447,14 +463,16 @@ public sealed partial class BlindWrite5
|
||||
tmpArray = new byte[4];
|
||||
stream.EnsureRead(tmpArray, 0, tmpArray.Length);
|
||||
|
||||
byte[] footer = new byte[16];
|
||||
var footer = new byte[16];
|
||||
stream.EnsureRead(footer, 0, footer.Length);
|
||||
|
||||
if(_bw5Footer.SequenceEqual(footer))
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Correctly_arrived_end_of_image);
|
||||
else
|
||||
{
|
||||
AaruConsole.ErrorWriteLine(Localization.
|
||||
BlindWrite5_image_ends_after_expected_position_Probably_new_version_with_different_data_Errors_may_occur);
|
||||
}
|
||||
|
||||
_filePaths = new List<DataFileCharacteristics>();
|
||||
|
||||
@@ -577,6 +595,7 @@ public sealed partial class BlindWrite5
|
||||
long sectorSize = dataFile.Length / dataFile.Sectors;
|
||||
|
||||
if(sectorSize > 2352)
|
||||
{
|
||||
switch(sectorSize - 2352)
|
||||
{
|
||||
case 16:
|
||||
@@ -593,6 +612,7 @@ public sealed partial class BlindWrite5
|
||||
|
||||
return ErrorNumber.NotSupported;
|
||||
}
|
||||
}
|
||||
else
|
||||
chars.Subchannel = TrackSubchannelType.None;
|
||||
|
||||
@@ -609,14 +629,11 @@ public sealed partial class BlindWrite5
|
||||
Partitions = new List<Partition>();
|
||||
var fullTocStream = new MemoryStream();
|
||||
|
||||
fullTocStream.Write(new byte[]
|
||||
{
|
||||
0, 0
|
||||
}, 0, 2);
|
||||
fullTocStream.Write(new byte[] { 0, 0 }, 0, 2);
|
||||
|
||||
ulong offsetBytes = 0;
|
||||
_offsetMap = new Dictionary<uint, ulong>();
|
||||
bool isDvd = false;
|
||||
var isDvd = false;
|
||||
byte firstSession = byte.MaxValue;
|
||||
byte lastSession = 0;
|
||||
_trackFlags = new Dictionary<uint, byte>();
|
||||
@@ -643,7 +660,7 @@ public sealed partial class BlindWrite5
|
||||
|
||||
foreach(TrackDescriptor trk in ses.Tracks)
|
||||
{
|
||||
byte adrCtl = (byte)((trk.adr << 4) + trk.ctl);
|
||||
var adrCtl = (byte)((trk.adr << 4) + trk.ctl);
|
||||
fullTocStream.WriteByte((byte)trk.session);
|
||||
fullTocStream.WriteByte(adrCtl);
|
||||
fullTocStream.WriteByte(0x00);
|
||||
@@ -754,11 +771,11 @@ public sealed partial class BlindWrite5
|
||||
track.StartSector = (ulong)(trk.startLba + trk.pregap);
|
||||
track.EndSector = (ulong)(trk.sectors + trk.startLba) - 1;
|
||||
|
||||
List<DataFileCharacteristics> fileCharsForThisTrack = _filePaths.
|
||||
Where(chars => trk.startLba >= chars.StartLba &&
|
||||
trk.startLba + trk.sectors <=
|
||||
chars.StartLba + chars.Sectors).
|
||||
ToList();
|
||||
var fileCharsForThisTrack = _filePaths.
|
||||
Where(chars => trk.startLba >= chars.StartLba &&
|
||||
trk.startLba + trk.sectors <=
|
||||
chars.StartLba + chars.Sectors).
|
||||
ToList();
|
||||
|
||||
if(fileCharsForThisTrack.Count == 0 &&
|
||||
_filePaths.Any(f => Path.GetExtension(f.FilePath).ToLowerInvariant() == ".b00"))
|
||||
@@ -767,8 +784,8 @@ public sealed partial class BlindWrite5
|
||||
_filePaths.FirstOrDefault(f => Path.GetExtension(f.FilePath).ToLowerInvariant() == ".b00");
|
||||
|
||||
string filename = Path.GetFileNameWithoutExtension(splitStartChars.FilePath);
|
||||
bool lowerCaseExtension = false;
|
||||
bool lowerCaseFileName = false;
|
||||
var lowerCaseExtension = false;
|
||||
var lowerCaseFileName = false;
|
||||
string basePath;
|
||||
|
||||
bool version5 = string.Compare(Path.GetExtension(imageFilter.Filename), ".B5T",
|
||||
@@ -876,8 +893,10 @@ public sealed partial class BlindWrite5
|
||||
else if(File.Exists(Path.Combine(imageFilter.ParentFolder,
|
||||
_dataPath.ToLower(CultureInfo.CurrentCulture),
|
||||
$"{filename}.{firstExtension}")))
|
||||
{
|
||||
basePath = Path.Combine(imageFilter.ParentFolder,
|
||||
_dataPath.ToLower(CultureInfo.CurrentCulture));
|
||||
}
|
||||
else if(File.Exists(Path.Combine(imageFilter.ParentFolder,
|
||||
_dataPath.ToLower(CultureInfo.CurrentCulture), $"{filename}.b00")))
|
||||
{
|
||||
@@ -946,7 +965,10 @@ public sealed partial class BlindWrite5
|
||||
try
|
||||
{
|
||||
splitStream.
|
||||
Add(Path.Combine(basePath, $"{filename}.{(lowerCaseExtension ? firstExtensionLower : firstExtension)}"),
|
||||
Add(
|
||||
Path.Combine(
|
||||
basePath,
|
||||
$"{filename}.{(lowerCaseExtension ? firstExtensionLower : firstExtension)}"),
|
||||
FileMode.Open, FileAccess.Read);
|
||||
|
||||
splitStream.AddRange(basePath, $"{filename}.{extension}");
|
||||
@@ -962,8 +984,10 @@ public sealed partial class BlindWrite5
|
||||
track.File = $"{filename}.{extension}";
|
||||
|
||||
if(trk.startLba >= 0)
|
||||
{
|
||||
track.FileOffset =
|
||||
(ulong)((trk.startLba * splitStartChars.SectorSize) + splitStartChars.Offset);
|
||||
(ulong)(trk.startLba * splitStartChars.SectorSize + splitStartChars.Offset);
|
||||
}
|
||||
else
|
||||
track.FileOffset = (ulong)(trk.startLba * -1 * splitStartChars.SectorSize);
|
||||
|
||||
@@ -987,14 +1011,17 @@ public sealed partial class BlindWrite5
|
||||
_filePaths.Add(splitStartChars);
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach(DataFileCharacteristics chars in fileCharsForThisTrack)
|
||||
{
|
||||
track.Filter = chars.FileFilter;
|
||||
track.File = chars.FileFilter.Filename;
|
||||
|
||||
if(trk.startLba >= 0)
|
||||
{
|
||||
track.FileOffset = (ulong)((trk.startLba - chars.StartLba) * chars.SectorSize) +
|
||||
chars.Offset;
|
||||
}
|
||||
else
|
||||
track.FileOffset = (ulong)(trk.startLba * -1 * chars.SectorSize);
|
||||
|
||||
@@ -1013,6 +1040,7 @@ public sealed partial class BlindWrite5
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(track.Filter is null)
|
||||
{
|
||||
@@ -1090,7 +1118,7 @@ public sealed partial class BlindWrite5
|
||||
|
||||
foreach(Partition partition in Partitions)
|
||||
{
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Partition_sequence_0, partition.Sequence);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Partition_sequence_0, partition.Sequence);
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "\t" + Localization.Partition_name_0, partition.Name);
|
||||
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "\t" + Localization.Partition_description_0,
|
||||
@@ -1135,22 +1163,28 @@ public sealed partial class BlindWrite5
|
||||
if(pfi0.HasValue)
|
||||
{
|
||||
_imageInfo.MediaType = pfi0.Value.DiskCategory switch
|
||||
{
|
||||
DiskCategory.DVDPR => MediaType.DVDPR,
|
||||
DiskCategory.DVDPRDL => MediaType.DVDPRDL,
|
||||
DiskCategory.DVDPRW => MediaType.DVDPRW,
|
||||
DiskCategory.DVDPRWDL => MediaType.DVDPRWDL,
|
||||
DiskCategory.DVDR => pfi0.Value.PartVersion >= 6 ? MediaType.DVDRDL : MediaType.DVDR,
|
||||
DiskCategory.DVDRAM => MediaType.DVDRAM,
|
||||
DiskCategory.DVDRW => pfi0.Value.PartVersion >= 15 ? MediaType.DVDRWDL : MediaType.DVDRW,
|
||||
DiskCategory.HDDVDR => MediaType.HDDVDR,
|
||||
DiskCategory.HDDVDRAM => MediaType.HDDVDRAM,
|
||||
DiskCategory.HDDVDROM => MediaType.HDDVDROM,
|
||||
DiskCategory.HDDVDRW => MediaType.HDDVDRW,
|
||||
DiskCategory.Nintendo => pfi0.Value.DiscSize == DVDSize.Eighty ? MediaType.GOD : MediaType.WOD,
|
||||
DiskCategory.UMD => MediaType.UMD,
|
||||
_ => MediaType.DVDROM
|
||||
};
|
||||
{
|
||||
DiskCategory.DVDPR => MediaType.DVDPR,
|
||||
DiskCategory.DVDPRDL => MediaType.DVDPRDL,
|
||||
DiskCategory.DVDPRW => MediaType.DVDPRW,
|
||||
DiskCategory.DVDPRWDL => MediaType.DVDPRWDL,
|
||||
DiskCategory.DVDR => pfi0.Value.PartVersion >= 6
|
||||
? MediaType.DVDRDL
|
||||
: MediaType.DVDR,
|
||||
DiskCategory.DVDRAM => MediaType.DVDRAM,
|
||||
DiskCategory.DVDRW => pfi0.Value.PartVersion >= 15
|
||||
? MediaType.DVDRWDL
|
||||
: MediaType.DVDRW,
|
||||
DiskCategory.HDDVDR => MediaType.HDDVDR,
|
||||
DiskCategory.HDDVDRAM => MediaType.HDDVDRAM,
|
||||
DiskCategory.HDDVDROM => MediaType.HDDVDROM,
|
||||
DiskCategory.HDDVDRW => MediaType.HDDVDRW,
|
||||
DiskCategory.Nintendo => pfi0.Value.DiscSize == DVDSize.Eighty
|
||||
? MediaType.GOD
|
||||
: MediaType.WOD,
|
||||
DiskCategory.UMD => MediaType.UMD,
|
||||
_ => MediaType.DVDROM
|
||||
};
|
||||
|
||||
if(DMI.IsXbox(_dmi))
|
||||
_imageInfo.MediaType = MediaType.XGD;
|
||||
@@ -1160,11 +1194,11 @@ public sealed partial class BlindWrite5
|
||||
}
|
||||
else if(_imageInfo.MediaType is MediaType.CD or MediaType.CDROM)
|
||||
{
|
||||
bool data = false;
|
||||
bool mode2 = false;
|
||||
bool firstAudio = false;
|
||||
bool firstData = false;
|
||||
bool audio = false;
|
||||
var data = false;
|
||||
var mode2 = false;
|
||||
var firstAudio = false;
|
||||
var firstData = false;
|
||||
var audio = false;
|
||||
|
||||
foreach(Track bwTrack in Tracks)
|
||||
{
|
||||
@@ -1199,7 +1233,7 @@ public sealed partial class BlindWrite5
|
||||
Sessions.Count > 1 &&
|
||||
mode2)
|
||||
_imageInfo.MediaType = MediaType.CDPLUS;
|
||||
else if((firstData && audio) || mode2)
|
||||
else if(firstData && audio || mode2)
|
||||
_imageInfo.MediaType = MediaType.CDROMXA;
|
||||
else if(!audio)
|
||||
_imageInfo.MediaType = MediaType.CDROM;
|
||||
@@ -1229,14 +1263,15 @@ public sealed partial class BlindWrite5
|
||||
{
|
||||
PMA.CDPMA pma0 = PMA.Decode(_pma).Value;
|
||||
|
||||
foreach(uint id in from descriptor in pma0.PMADescriptors where descriptor.ADR == 2
|
||||
foreach(uint id in from descriptor in pma0.PMADescriptors
|
||||
where descriptor.ADR == 2
|
||||
select (uint)((descriptor.Min << 16) + (descriptor.Sec << 8) + descriptor.Frame))
|
||||
_imageInfo.MediaSerialNumber = $"{id & 0x00FFFFFF:X6}";
|
||||
}
|
||||
|
||||
if(_atip != null)
|
||||
{
|
||||
byte[] atipTmp = new byte[_atip.Length + 4];
|
||||
var atipTmp = new byte[_atip.Length + 4];
|
||||
Array.Copy(_atip, 0, atipTmp, 4, _atip.Length);
|
||||
atipTmp[0] = (byte)((_atip.Length & 0xFF00) >> 8);
|
||||
atipTmp[1] = (byte)(_atip.Length & 0xFF);
|
||||
@@ -1253,7 +1288,7 @@ public sealed partial class BlindWrite5
|
||||
}
|
||||
}
|
||||
|
||||
bool isBd = false;
|
||||
var isBd = false;
|
||||
|
||||
if(_imageInfo.MediaType is MediaType.BDR or MediaType.BDRE or MediaType.BDROM)
|
||||
{
|
||||
@@ -1262,12 +1297,14 @@ public sealed partial class BlindWrite5
|
||||
}
|
||||
|
||||
if(isBd && _imageInfo.Sectors > 24438784)
|
||||
{
|
||||
_imageInfo.MediaType = _imageInfo.MediaType switch
|
||||
{
|
||||
MediaType.BDR => MediaType.BDRXL,
|
||||
MediaType.BDRE => MediaType.BDREXL,
|
||||
_ => _imageInfo.MediaType
|
||||
};
|
||||
{
|
||||
MediaType.BDR => MediaType.BDRXL,
|
||||
MediaType.BDRE => MediaType.BDREXL,
|
||||
_ => _imageInfo.MediaType
|
||||
};
|
||||
}
|
||||
|
||||
AaruConsole.DebugWriteLine(MODULE_NAME, "ImageInfo.mediaType = {0}", _imageInfo.MediaType);
|
||||
|
||||
@@ -1284,10 +1321,12 @@ public sealed partial class BlindWrite5
|
||||
_imageInfo.ReadableMediaTags.Add(MediaTagType.CD_TEXT);
|
||||
|
||||
if(_bca != null)
|
||||
{
|
||||
if(isDvd)
|
||||
_imageInfo.ReadableMediaTags.Add(MediaTagType.DVD_BCA);
|
||||
else if(isBd)
|
||||
_imageInfo.ReadableMediaTags.Add(MediaTagType.BD_BCA);
|
||||
}
|
||||
|
||||
byte[] tmp;
|
||||
|
||||
@@ -1369,7 +1408,8 @@ public sealed partial class BlindWrite5
|
||||
buffer = _fullToc?.Clone() as byte[];
|
||||
|
||||
return buffer != null ? ErrorNumber.NoError : ErrorNumber.NoData;
|
||||
default: return ErrorNumber.NotSupported;
|
||||
default:
|
||||
return ErrorNumber.NotSupported;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1393,10 +1433,13 @@ public sealed partial class BlindWrite5
|
||||
{
|
||||
buffer = null;
|
||||
|
||||
foreach(KeyValuePair<uint, ulong> kvp in from kvp in _offsetMap where sectorAddress >= kvp.Value
|
||||
from track in Tracks where track.Sequence == kvp.Key
|
||||
foreach(KeyValuePair<uint, ulong> kvp in from kvp in _offsetMap
|
||||
where sectorAddress >= kvp.Value
|
||||
from track in Tracks
|
||||
where track.Sequence == kvp.Key
|
||||
where sectorAddress - kvp.Value <
|
||||
track.EndSector - track.StartSector + 1 select kvp)
|
||||
track.EndSector - track.StartSector + 1
|
||||
select kvp)
|
||||
return ReadSectors(sectorAddress - kvp.Value, length, kvp.Key, out buffer);
|
||||
|
||||
return ErrorNumber.SectorNotFound;
|
||||
@@ -1407,10 +1450,13 @@ public sealed partial class BlindWrite5
|
||||
{
|
||||
buffer = null;
|
||||
|
||||
foreach(KeyValuePair<uint, ulong> kvp in from kvp in _offsetMap where sectorAddress >= kvp.Value
|
||||
from track in Tracks where track.Sequence == kvp.Key
|
||||
foreach(KeyValuePair<uint, ulong> kvp in from kvp in _offsetMap
|
||||
where sectorAddress >= kvp.Value
|
||||
from track in Tracks
|
||||
where track.Sequence == kvp.Key
|
||||
where sectorAddress - kvp.Value <
|
||||
track.EndSector - track.StartSector + 1 select kvp)
|
||||
track.EndSector - track.StartSector + 1
|
||||
select kvp)
|
||||
return ReadSectorsTag(sectorAddress - kvp.Value, length, kvp.Key, tag, out buffer);
|
||||
|
||||
return ErrorNumber.SectorNotFound;
|
||||
@@ -1430,8 +1476,10 @@ public sealed partial class BlindWrite5
|
||||
if(length + sectorAddress > aaruTrack.EndSector - aaruTrack.StartSector + 1)
|
||||
return ErrorNumber.OutOfRange;
|
||||
|
||||
DataFileCharacteristics chars = (from characteristics in _filePaths let firstSector = characteristics.StartLba
|
||||
let lastSector = firstSector + characteristics.Sectors - 1 let wantedSector =
|
||||
DataFileCharacteristics chars = (from characteristics in _filePaths
|
||||
let firstSector = characteristics.StartLba
|
||||
let lastSector = firstSector + characteristics.Sectors - 1
|
||||
let wantedSector =
|
||||
(int)(sectorAddress + aaruTrack.StartSector)
|
||||
where wantedSector >= firstSector && wantedSector <= lastSector
|
||||
select characteristics).FirstOrDefault();
|
||||
@@ -1443,7 +1491,7 @@ public sealed partial class BlindWrite5
|
||||
uint sectorOffset;
|
||||
uint sectorSize;
|
||||
uint sectorSkip;
|
||||
bool mode2 = false;
|
||||
var mode2 = false;
|
||||
|
||||
switch(aaruTrack.Type)
|
||||
{
|
||||
@@ -1482,7 +1530,8 @@ public sealed partial class BlindWrite5
|
||||
|
||||
break;
|
||||
}
|
||||
default: return ErrorNumber.NotSupported;
|
||||
default:
|
||||
return ErrorNumber.NotSupported;
|
||||
}
|
||||
|
||||
switch(chars.Subchannel)
|
||||
@@ -1499,7 +1548,8 @@ public sealed partial class BlindWrite5
|
||||
sectorSkip += 96;
|
||||
|
||||
break;
|
||||
default: return ErrorNumber.NotSupported;
|
||||
default:
|
||||
return ErrorNumber.NotSupported;
|
||||
}
|
||||
|
||||
buffer = new byte[sectorSize * length];
|
||||
@@ -1517,9 +1567,9 @@ public sealed partial class BlindWrite5
|
||||
|
||||
buffer = br.ReadBytes((int)((sectorSize + sectorSkip) * length));
|
||||
|
||||
for(int i = 0; i < length; i++)
|
||||
for(var i = 0; i < length; i++)
|
||||
{
|
||||
byte[] sector = new byte[sectorSize];
|
||||
var sector = new byte[sectorSize];
|
||||
Array.Copy(buffer, (sectorSize + sectorSkip) * i, sector, 0, sectorSize);
|
||||
sector = Sector.GetUserDataFromMode2(sector);
|
||||
mode2Ms.Write(sector, 0, sector.Length);
|
||||
@@ -1531,19 +1581,21 @@ public sealed partial class BlindWrite5
|
||||
sectorSkip == 0)
|
||||
buffer = br.ReadBytes((int)(sectorSize * length));
|
||||
else
|
||||
for(int i = 0; i < length; i++)
|
||||
{
|
||||
for(var i = 0; i < length; i++)
|
||||
{
|
||||
br.BaseStream.Seek(sectorOffset, SeekOrigin.Current);
|
||||
byte[] sector = br.ReadBytes((int)sectorSize);
|
||||
br.BaseStream.Seek(sectorSkip, SeekOrigin.Current);
|
||||
Array.Copy(sector, 0, buffer, i * sectorSize, sectorSize);
|
||||
}
|
||||
}
|
||||
|
||||
return ErrorNumber.NoError;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ErrorNumber ReadSectorsTag(ulong sectorAddress, uint length, uint track, SectorTagType tag,
|
||||
public ErrorNumber ReadSectorsTag(ulong sectorAddress, uint length, uint track, SectorTagType tag,
|
||||
out byte[] buffer)
|
||||
{
|
||||
buffer = null;
|
||||
@@ -1557,8 +1609,10 @@ public sealed partial class BlindWrite5
|
||||
if(length + sectorAddress > aaruTrack.EndSector - aaruTrack.StartSector + 1)
|
||||
return ErrorNumber.OutOfRange;
|
||||
|
||||
DataFileCharacteristics chars = (from characteristics in _filePaths let firstSector = characteristics.StartLba
|
||||
let lastSector = firstSector + characteristics.Sectors - 1 let wantedSector =
|
||||
DataFileCharacteristics chars = (from characteristics in _filePaths
|
||||
let firstSector = characteristics.StartLba
|
||||
let lastSector = firstSector + characteristics.Sectors - 1
|
||||
let wantedSector =
|
||||
(int)(sectorAddress + aaruTrack.StartSector)
|
||||
where wantedSector >= firstSector && wantedSector <= lastSector
|
||||
select characteristics).FirstOrDefault();
|
||||
@@ -1579,18 +1633,17 @@ public sealed partial class BlindWrite5
|
||||
case SectorTagType.CdSectorHeader:
|
||||
case SectorTagType.CdSectorSubchannel:
|
||||
case SectorTagType.CdSectorSubHeader:
|
||||
case SectorTagType.CdSectorSync: break;
|
||||
case SectorTagType.CdSectorSync:
|
||||
break;
|
||||
case SectorTagType.CdTrackFlags:
|
||||
if(!_trackFlags.TryGetValue((uint)sectorAddress, out byte flag))
|
||||
return ErrorNumber.NoData;
|
||||
|
||||
buffer = new[]
|
||||
{
|
||||
flag
|
||||
};
|
||||
buffer = new[] { flag };
|
||||
|
||||
return ErrorNumber.NoError;
|
||||
default: return ErrorNumber.NotSupported;
|
||||
default:
|
||||
return ErrorNumber.NotSupported;
|
||||
}
|
||||
|
||||
uint sectorOffset;
|
||||
@@ -1618,7 +1671,8 @@ public sealed partial class BlindWrite5
|
||||
|
||||
break;
|
||||
}
|
||||
case SectorTagType.CdSectorSubHeader: return ErrorNumber.NotSupported;
|
||||
case SectorTagType.CdSectorSubHeader:
|
||||
return ErrorNumber.NotSupported;
|
||||
case SectorTagType.CdSectorEcc:
|
||||
{
|
||||
sectorOffset = 2076;
|
||||
@@ -1682,12 +1736,14 @@ public sealed partial class BlindWrite5
|
||||
return ErrorNumber.NoError;
|
||||
}
|
||||
|
||||
default: return ErrorNumber.NotSupported;
|
||||
default:
|
||||
return ErrorNumber.NotSupported;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default: return ErrorNumber.NotSupported;
|
||||
default:
|
||||
return ErrorNumber.NotSupported;
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -1699,7 +1755,8 @@ public sealed partial class BlindWrite5
|
||||
case SectorTagType.CdSectorHeader:
|
||||
case SectorTagType.CdSectorEcc:
|
||||
case SectorTagType.CdSectorEccP:
|
||||
case SectorTagType.CdSectorEccQ: return ErrorNumber.NotSupported;
|
||||
case SectorTagType.CdSectorEccQ:
|
||||
return ErrorNumber.NotSupported;
|
||||
case SectorTagType.CdSectorSubHeader:
|
||||
{
|
||||
sectorOffset = 0;
|
||||
@@ -1747,12 +1804,14 @@ public sealed partial class BlindWrite5
|
||||
return ErrorNumber.NoError;
|
||||
}
|
||||
|
||||
default: return ErrorNumber.NotSupported;
|
||||
default:
|
||||
return ErrorNumber.NotSupported;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default: return ErrorNumber.NotSupported;
|
||||
default:
|
||||
return ErrorNumber.NotSupported;
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -1847,12 +1906,14 @@ public sealed partial class BlindWrite5
|
||||
return ErrorNumber.NoError;
|
||||
}
|
||||
|
||||
default: return ErrorNumber.NotSupported;
|
||||
default:
|
||||
return ErrorNumber.NotSupported;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default: return ErrorNumber.NotSupported;
|
||||
default:
|
||||
return ErrorNumber.NotSupported;
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -1922,12 +1983,14 @@ public sealed partial class BlindWrite5
|
||||
return ErrorNumber.NoError;
|
||||
}
|
||||
|
||||
default: return ErrorNumber.NotSupported;
|
||||
default:
|
||||
return ErrorNumber.NotSupported;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default: return ErrorNumber.NotSupported;
|
||||
default:
|
||||
return ErrorNumber.NotSupported;
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -1965,20 +2028,24 @@ public sealed partial class BlindWrite5
|
||||
|
||||
return ErrorNumber.NoError;
|
||||
}
|
||||
default: return ErrorNumber.NotSupported;
|
||||
default:
|
||||
return ErrorNumber.NotSupported;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default: return ErrorNumber.NotSupported;
|
||||
default:
|
||||
return ErrorNumber.NotSupported;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default: return ErrorNumber.NotSupported;
|
||||
default:
|
||||
return ErrorNumber.NotSupported;
|
||||
}
|
||||
|
||||
if(tag != SectorTagType.CdSectorSubchannel)
|
||||
{
|
||||
switch(chars.Subchannel)
|
||||
{
|
||||
case TrackSubchannelType.None:
|
||||
@@ -1993,8 +2060,10 @@ public sealed partial class BlindWrite5
|
||||
sectorSkip += 96;
|
||||
|
||||
break;
|
||||
default: return ErrorNumber.NotSupported;
|
||||
default:
|
||||
return ErrorNumber.NotSupported;
|
||||
}
|
||||
}
|
||||
|
||||
buffer = new byte[sectorSize * length];
|
||||
|
||||
@@ -2009,23 +2078,25 @@ public sealed partial class BlindWrite5
|
||||
sectorSkip == 0)
|
||||
buffer = br.ReadBytes((int)(sectorSize * length));
|
||||
else
|
||||
for(int i = 0; i < length; i++)
|
||||
{
|
||||
for(var i = 0; i < length; i++)
|
||||
{
|
||||
br.BaseStream.Seek(sectorOffset, SeekOrigin.Current);
|
||||
byte[] sector = br.ReadBytes((int)sectorSize);
|
||||
br.BaseStream.Seek(sectorSkip, SeekOrigin.Current);
|
||||
Array.Copy(sector, 0, buffer, i * sectorSize, sectorSize);
|
||||
}
|
||||
}
|
||||
|
||||
if(tag != SectorTagType.CdSectorSubchannel)
|
||||
return ErrorNumber.NoError;
|
||||
|
||||
buffer = chars.Subchannel switch
|
||||
{
|
||||
TrackSubchannelType.Q16Interleaved => Subchannel.ConvertQToRaw(buffer),
|
||||
TrackSubchannelType.PackedInterleaved => Subchannel.Interleave(buffer),
|
||||
_ => buffer
|
||||
};
|
||||
{
|
||||
TrackSubchannelType.Q16Interleaved => Subchannel.ConvertQToRaw(buffer),
|
||||
TrackSubchannelType.PackedInterleaved => Subchannel.Interleave(buffer),
|
||||
_ => buffer
|
||||
};
|
||||
|
||||
return ErrorNumber.NoError;
|
||||
}
|
||||
@@ -2043,10 +2114,13 @@ public sealed partial class BlindWrite5
|
||||
{
|
||||
buffer = null;
|
||||
|
||||
foreach(KeyValuePair<uint, ulong> kvp in from kvp in _offsetMap where sectorAddress >= kvp.Value
|
||||
from track in Tracks where track.Sequence == kvp.Key
|
||||
foreach(KeyValuePair<uint, ulong> kvp in from kvp in _offsetMap
|
||||
where sectorAddress >= kvp.Value
|
||||
from track in Tracks
|
||||
where track.Sequence == kvp.Key
|
||||
where sectorAddress - kvp.Value <
|
||||
track.EndSector - track.StartSector + 1 select kvp)
|
||||
track.EndSector - track.StartSector + 1
|
||||
select kvp)
|
||||
return ReadSectorsLong(sectorAddress - kvp.Value, length, kvp.Key, out buffer);
|
||||
|
||||
return ErrorNumber.SectorNotFound;
|
||||
@@ -2066,8 +2140,10 @@ public sealed partial class BlindWrite5
|
||||
if(length + sectorAddress > aaruTrack.EndSector - aaruTrack.StartSector + 1)
|
||||
return ErrorNumber.OutOfRange;
|
||||
|
||||
DataFileCharacteristics chars = (from characteristics in _filePaths let firstSector = characteristics.StartLba
|
||||
let lastSector = firstSector + characteristics.Sectors - 1 let wantedSector =
|
||||
DataFileCharacteristics chars = (from characteristics in _filePaths
|
||||
let firstSector = characteristics.StartLba
|
||||
let lastSector = firstSector + characteristics.Sectors - 1
|
||||
let wantedSector =
|
||||
(int)(sectorAddress + aaruTrack.StartSector)
|
||||
where wantedSector >= firstSector && wantedSector <= lastSector
|
||||
select characteristics).FirstOrDefault();
|
||||
@@ -2102,7 +2178,8 @@ public sealed partial class BlindWrite5
|
||||
|
||||
break;
|
||||
}
|
||||
default: return ErrorNumber.NotSupported;
|
||||
default:
|
||||
return ErrorNumber.NotSupported;
|
||||
}
|
||||
|
||||
switch(chars.Subchannel)
|
||||
@@ -2119,7 +2196,8 @@ public sealed partial class BlindWrite5
|
||||
sectorSkip += 96;
|
||||
|
||||
break;
|
||||
default: return ErrorNumber.NotSupported;
|
||||
default:
|
||||
return ErrorNumber.NotSupported;
|
||||
}
|
||||
|
||||
buffer = new byte[sectorSize * length];
|
||||
@@ -2133,13 +2211,15 @@ public sealed partial class BlindWrite5
|
||||
if(sectorSkip == 0)
|
||||
buffer = br.ReadBytes((int)(sectorSize * length));
|
||||
else
|
||||
for(int i = 0; i < length; i++)
|
||||
{
|
||||
for(var i = 0; i < length; i++)
|
||||
{
|
||||
br.BaseStream.Seek(sectorOffset, SeekOrigin.Current);
|
||||
byte[] sector = br.ReadBytes((int)sectorSize);
|
||||
br.BaseStream.Seek(sectorSkip, SeekOrigin.Current);
|
||||
Array.Copy(sector, 0, buffer, i * sectorSize, sectorSize);
|
||||
}
|
||||
}
|
||||
|
||||
return ErrorNumber.NoError;
|
||||
}
|
||||
@@ -2151,4 +2231,6 @@ public sealed partial class BlindWrite5
|
||||
/// <inheritdoc />
|
||||
public List<Track> GetSessionTracks(ushort session) =>
|
||||
Tracks.Where(aaruTrack => aaruTrack.Session == session).ToList();
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -39,6 +39,50 @@ namespace Aaru.DiscImages;
|
||||
|
||||
public sealed partial class BlindWrite5
|
||||
{
|
||||
#region Nested type: DataFile
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct DataFile
|
||||
{
|
||||
public uint Type;
|
||||
public uint Length;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
|
||||
public uint[] Unknown1;
|
||||
public uint Offset;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
|
||||
public uint[] Unknown2;
|
||||
public int StartLba;
|
||||
public int Sectors;
|
||||
public uint FilenameLen;
|
||||
public byte[] FilenameBytes;
|
||||
public uint Unknown3;
|
||||
|
||||
public string Filename;
|
||||
|
||||
/// <inheritdoc />
|
||||
public readonly override string ToString() => Filename;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Nested type: DataFileCharacteristics
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct DataFileCharacteristics
|
||||
{
|
||||
public IFilter FileFilter;
|
||||
public string FilePath;
|
||||
public TrackSubchannelType Subchannel;
|
||||
public long SectorSize;
|
||||
public int StartLba;
|
||||
public int Sectors;
|
||||
public uint Offset;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Nested type: Header
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
readonly struct Header
|
||||
{
|
||||
@@ -85,28 +129,27 @@ public sealed partial class BlindWrite5
|
||||
public readonly uint dpmLen;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Nested type: SessionDescriptor
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct DataFile
|
||||
struct SessionDescriptor
|
||||
{
|
||||
public uint Type;
|
||||
public uint Length;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
|
||||
public uint[] Unknown1;
|
||||
public uint Offset;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
|
||||
public uint[] Unknown2;
|
||||
public int StartLba;
|
||||
public int Sectors;
|
||||
public uint FilenameLen;
|
||||
public byte[] FilenameBytes;
|
||||
public uint Unknown3;
|
||||
|
||||
public string Filename;
|
||||
|
||||
/// <inheritdoc />
|
||||
public readonly override string ToString() => Filename;
|
||||
public ushort Sequence;
|
||||
public byte Entries;
|
||||
public byte Unknown;
|
||||
public int Start;
|
||||
public int End;
|
||||
public ushort FirstTrack;
|
||||
public ushort LastTrack;
|
||||
public TrackDescriptor[] Tracks;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Nested type: TrackDescriptor
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
readonly struct TrackDescriptor
|
||||
{
|
||||
@@ -143,28 +186,5 @@ public sealed partial class BlindWrite5
|
||||
public readonly uint[] unknown9;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct SessionDescriptor
|
||||
{
|
||||
public ushort Sequence;
|
||||
public byte Entries;
|
||||
public byte Unknown;
|
||||
public int Start;
|
||||
public int End;
|
||||
public ushort FirstTrack;
|
||||
public ushort LastTrack;
|
||||
public TrackDescriptor[] Tracks;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct DataFileCharacteristics
|
||||
{
|
||||
public IFilter FileFilter;
|
||||
public string FilePath;
|
||||
public TrackSubchannelType Subchannel;
|
||||
public long SectorSize;
|
||||
public int StartLba;
|
||||
public int Sectors;
|
||||
public uint Offset;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
@@ -39,6 +39,8 @@ namespace Aaru.DiscImages;
|
||||
|
||||
public sealed partial class BlindWrite5
|
||||
{
|
||||
#region IOpticalMediaImage Members
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool? VerifySector(ulong sectorAddress)
|
||||
{
|
||||
@@ -48,7 +50,7 @@ public sealed partial class BlindWrite5
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool? VerifySectors(ulong sectorAddress, uint length, out List<ulong> failingLbas,
|
||||
public bool? VerifySectors(ulong sectorAddress, uint length, out List<ulong> failingLbas,
|
||||
out List<ulong> unknownLbas)
|
||||
{
|
||||
failingLbas = new List<ulong>();
|
||||
@@ -58,10 +60,10 @@ public sealed partial class BlindWrite5
|
||||
if(errno != ErrorNumber.NoError)
|
||||
return null;
|
||||
|
||||
int bps = (int)(buffer.Length / length);
|
||||
byte[] sector = new byte[bps];
|
||||
var bps = (int)(buffer.Length / length);
|
||||
var sector = new byte[bps];
|
||||
|
||||
for(int i = 0; i < length; i++)
|
||||
for(var i = 0; i < length; i++)
|
||||
{
|
||||
Array.Copy(buffer, i * bps, sector, 0, bps);
|
||||
bool? sectorStatus = CdChecksums.CheckCdSector(sector);
|
||||
@@ -86,7 +88,7 @@ public sealed partial class BlindWrite5
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool? VerifySectors(ulong sectorAddress, uint length, uint track, out List<ulong> failingLbas,
|
||||
public bool? VerifySectors(ulong sectorAddress, uint length, uint track, out List<ulong> failingLbas,
|
||||
out List<ulong> unknownLbas)
|
||||
{
|
||||
failingLbas = new List<ulong>();
|
||||
@@ -96,10 +98,10 @@ public sealed partial class BlindWrite5
|
||||
if(errno != ErrorNumber.NoError)
|
||||
return null;
|
||||
|
||||
int bps = (int)(buffer.Length / length);
|
||||
byte[] sector = new byte[bps];
|
||||
var bps = (int)(buffer.Length / length);
|
||||
var sector = new byte[bps];
|
||||
|
||||
for(int i = 0; i < length; i++)
|
||||
for(var i = 0; i < length; i++)
|
||||
{
|
||||
Array.Copy(buffer, i * bps, sector, 0, bps);
|
||||
bool? sectorStatus = CdChecksums.CheckCdSector(sector);
|
||||
@@ -122,4 +124,6 @@ public sealed partial class BlindWrite5
|
||||
|
||||
return failingLbas.Count <= 0;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -20,18 +20,27 @@ public class AtariLynx : IByteAddressableImage
|
||||
Stream _dataStream;
|
||||
ImageInfo _imageInfo;
|
||||
bool _opened;
|
||||
|
||||
#region IByteAddressableImage Members
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Author => Authors.NataliaPortillo;
|
||||
|
||||
/// <inheritdoc />
|
||||
public Metadata AaruMetadata => null;
|
||||
|
||||
/// <inheritdoc />
|
||||
public List<DumpHardware> DumpHardware => null;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Format => "Atari Lynx cartridge dump";
|
||||
|
||||
/// <inheritdoc />
|
||||
public Guid Id => new("809A6835-0486-4FD3-BD8B-2EF40C3EF97B");
|
||||
|
||||
/// <inheritdoc />
|
||||
public ImageInfo Info => _imageInfo;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Name => Localization.AtariLynx_Name;
|
||||
|
||||
@@ -48,9 +57,9 @@ public class AtariLynx : IByteAddressableImage
|
||||
return false;
|
||||
|
||||
stream.Position = 0;
|
||||
byte[] magicBytes = new byte[4];
|
||||
var magicBytes = new byte[4];
|
||||
stream.EnsureRead(magicBytes, 0, 4);
|
||||
uint magic = BitConverter.ToUInt32(magicBytes, 0);
|
||||
var magic = BitConverter.ToUInt32(magicBytes, 0);
|
||||
|
||||
// "LYNX"
|
||||
return magic == 0x584E594C;
|
||||
@@ -69,14 +78,14 @@ public class AtariLynx : IByteAddressableImage
|
||||
return ErrorNumber.InvalidArgument;
|
||||
|
||||
stream.Position = 0x0;
|
||||
byte[] magicBytes = new byte[4];
|
||||
var magicBytes = new byte[4];
|
||||
stream.EnsureRead(magicBytes, 0, 4);
|
||||
uint magic = BitConverter.ToUInt32(magicBytes, 0);
|
||||
var magic = BitConverter.ToUInt32(magicBytes, 0);
|
||||
|
||||
if(magic != 0x584E594C)
|
||||
return ErrorNumber.InvalidArgument;
|
||||
|
||||
byte[] headerBytes = new byte[64];
|
||||
var headerBytes = new byte[64];
|
||||
stream.Position = 0;
|
||||
stream.EnsureRead(headerBytes, 0, 64);
|
||||
|
||||
@@ -104,7 +113,7 @@ public class AtariLynx : IByteAddressableImage
|
||||
|
||||
var sb = new StringBuilder();
|
||||
|
||||
sb.AppendFormat(Localization.Name_0, _imageInfo.MediaTitle).AppendLine();
|
||||
sb.AppendFormat(Localization.Name_0, _imageInfo.MediaTitle).AppendLine();
|
||||
sb.AppendFormat(Localization.Manufacturer_0, _imageInfo.MediaManufacturer).AppendLine();
|
||||
|
||||
sb.AppendFormat(Localization.Bank_zero_size_0_pages_1_bytes, header.Bank0Length, header.Bank0Length * 65536).
|
||||
@@ -123,29 +132,29 @@ public class AtariLynx : IByteAddressableImage
|
||||
|
||||
/// <inheritdoc />
|
||||
public string ErrorMessage { get; private set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsWriting { get; private set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<string> KnownExtensions => new[]
|
||||
{
|
||||
".lnx"
|
||||
};
|
||||
public IEnumerable<string> KnownExtensions => new[] { ".lnx" };
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<MediaTagType> SupportedMediaTags => Array.Empty<MediaTagType>();
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<MediaType> SupportedMediaTypes => new[]
|
||||
{
|
||||
MediaType.AtariLynxCard
|
||||
};
|
||||
public IEnumerable<MediaType> SupportedMediaTypes => new[] { MediaType.AtariLynxCard };
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<(string name, Type type, string description, object @default)> SupportedOptions =>
|
||||
Array.Empty<(string name, Type type, string description, object @default)>();
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<SectorTagType> SupportedSectorTags => Array.Empty<SectorTagType>();
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Create(string path, MediaType mediaType, Dictionary<string, string> options, ulong sectors,
|
||||
uint sectorSize) => Create(path, mediaType, options, (long)sectors) == ErrorNumber.NoError;
|
||||
uint sectorSize) => Create(path, mediaType, options, (long)sectors) == ErrorNumber.NoError;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Close()
|
||||
@@ -168,8 +177,8 @@ public class AtariLynx : IByteAddressableImage
|
||||
|
||||
HandyHeader header = new()
|
||||
{
|
||||
Bank0Length = (short)(_data.Length > 4 * 131072 ? 4 * 131072 / 256 : _data.Length / 256),
|
||||
Bank1Length = (short)(_data.Length > 4 * 131072 ? (_data.Length - (4 * 131072)) / 256 : 0),
|
||||
Bank0Length = (short)(_data.Length > 4 * 131072 ? 4 * 131072 / 256 : _data.Length / 256),
|
||||
Bank1Length = (short)(_data.Length > 4 * 131072 ? (_data.Length - 4 * 131072) / 256 : 0),
|
||||
Magic = 0x584E594C,
|
||||
Manufacturer = new byte[16],
|
||||
Name = new byte[32],
|
||||
@@ -185,7 +194,7 @@ public class AtariLynx : IByteAddressableImage
|
||||
byte[] headerBytes = Marshal.StructureToByteArrayBigEndian(header);
|
||||
|
||||
_dataStream.Write(headerBytes, 0, headerBytes.Length);
|
||||
_dataStream.Write(_data, 0, _data.Length);
|
||||
_dataStream.Write(_data, 0, _data.Length);
|
||||
_dataStream.Close();
|
||||
|
||||
IsWriting = false;
|
||||
@@ -396,18 +405,21 @@ public class AtariLynx : IByteAddressableImage
|
||||
return ErrorNumber.ReadOnly;
|
||||
}
|
||||
|
||||
bool foundRom = false;
|
||||
var foundRom = false;
|
||||
|
||||
// Sanitize
|
||||
foreach(LinearMemoryDevice map in mappings.Devices)
|
||||
{
|
||||
switch(map.Type)
|
||||
{
|
||||
case LinearMemoryType.ROM when !foundRom:
|
||||
foundRom = true;
|
||||
|
||||
break;
|
||||
default: return ErrorNumber.InvalidArgument;
|
||||
default:
|
||||
return ErrorNumber.InvalidArgument;
|
||||
}
|
||||
}
|
||||
|
||||
// Cannot save in this image format anyway
|
||||
return foundRom ? ErrorNumber.NoError : ErrorNumber.InvalidArgument;
|
||||
@@ -450,7 +462,7 @@ public class AtariLynx : IByteAddressableImage
|
||||
|
||||
/// <inheritdoc />
|
||||
public ErrorNumber WriteBytes(byte[] buffer, int offset, int bytesToWrite, out int bytesWritten,
|
||||
bool advance = true) =>
|
||||
bool advance = true) =>
|
||||
WriteBytesAt(Position, buffer, offset, bytesToWrite, out bytesWritten, advance);
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -503,8 +515,13 @@ public class AtariLynx : IByteAddressableImage
|
||||
return ErrorNumber.NoError;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1), SuppressMessage("ReSharper", "MemberCanBePrivate.Local"),
|
||||
SuppressMessage("ReSharper", "FieldCanBeMadeReadOnly.Local")]
|
||||
#endregion
|
||||
|
||||
#region Nested type: HandyHeader
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
[SuppressMessage("ReSharper", "MemberCanBePrivate.Local")]
|
||||
[SuppressMessage("ReSharper", "FieldCanBeMadeReadOnly.Local")]
|
||||
struct HandyHeader
|
||||
{
|
||||
public uint Magic;
|
||||
@@ -519,4 +536,6 @@ public class AtariLynx : IByteAddressableImage
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)]
|
||||
public byte[] Spare;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -20,18 +20,27 @@ public class GameBoy : IByteAddressableImage
|
||||
Stream _dataStream;
|
||||
ImageInfo _imageInfo;
|
||||
bool _opened;
|
||||
|
||||
#region IByteAddressableImage Members
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Author => Authors.NataliaPortillo;
|
||||
|
||||
/// <inheritdoc />
|
||||
public Metadata AaruMetadata => null;
|
||||
|
||||
/// <inheritdoc />
|
||||
public List<DumpHardware> DumpHardware => null;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Format => "Nintendo Game Boy cartridge dump";
|
||||
|
||||
/// <inheritdoc />
|
||||
public Guid Id => new("04AFDB93-587E-413B-9B52-10D4A92966CF");
|
||||
|
||||
/// <inheritdoc />
|
||||
public ImageInfo Info => _imageInfo;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Name => Localization.GameBoy_Name;
|
||||
|
||||
@@ -48,9 +57,9 @@ public class GameBoy : IByteAddressableImage
|
||||
return false;
|
||||
|
||||
stream.Position = 0x104;
|
||||
byte[] magicBytes = new byte[8];
|
||||
var magicBytes = new byte[8];
|
||||
stream.EnsureRead(magicBytes, 0, 8);
|
||||
ulong magic = BitConverter.ToUInt64(magicBytes, 0);
|
||||
var magic = BitConverter.ToUInt64(magicBytes, 0);
|
||||
|
||||
return magic == 0x0B000DCC6666EDCE;
|
||||
}
|
||||
@@ -68,9 +77,9 @@ public class GameBoy : IByteAddressableImage
|
||||
return ErrorNumber.InvalidArgument;
|
||||
|
||||
stream.Position = 0x104;
|
||||
byte[] magicBytes = new byte[8];
|
||||
var magicBytes = new byte[8];
|
||||
stream.EnsureRead(magicBytes, 0, 8);
|
||||
ulong magic = BitConverter.ToUInt64(magicBytes, 0);
|
||||
var magic = BitConverter.ToUInt64(magicBytes, 0);
|
||||
|
||||
if(magic != 0x0B000DCC6666EDCE)
|
||||
return ErrorNumber.InvalidArgument;
|
||||
@@ -92,7 +101,7 @@ public class GameBoy : IByteAddressableImage
|
||||
|
||||
Header header = Marshal.ByteArrayToStructureBigEndian<Header>(_data, 0x100, Marshal.SizeOf<Header>());
|
||||
|
||||
byte[] name = new byte[(header.Name[^1] & 0x80) == 0x80 ? 15 : 16];
|
||||
var name = new byte[(header.Name[^1] & 0x80) == 0x80 ? 15 : 16];
|
||||
Array.Copy(header.Name, 0, name, 0, name.Length);
|
||||
|
||||
_imageInfo.MediaTitle = StringHandlers.CToString(name);
|
||||
@@ -134,29 +143,29 @@ public class GameBoy : IByteAddressableImage
|
||||
|
||||
/// <inheritdoc />
|
||||
public string ErrorMessage { get; private set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsWriting { get; private set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<string> KnownExtensions => new[]
|
||||
{
|
||||
".gb", ".gbc", ".sgb"
|
||||
};
|
||||
public IEnumerable<string> KnownExtensions => new[] { ".gb", ".gbc", ".sgb" };
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<MediaTagType> SupportedMediaTags => Array.Empty<MediaTagType>();
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<MediaType> SupportedMediaTypes => new[]
|
||||
{
|
||||
MediaType.GameBoyGamePak
|
||||
};
|
||||
public IEnumerable<MediaType> SupportedMediaTypes => new[] { MediaType.GameBoyGamePak };
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<(string name, Type type, string description, object @default)> SupportedOptions =>
|
||||
Array.Empty<(string name, Type type, string description, object @default)>();
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<SectorTagType> SupportedSectorTags => Array.Empty<SectorTagType>();
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Create(string path, MediaType mediaType, Dictionary<string, string> options, ulong sectors,
|
||||
uint sectorSize) => Create(path, mediaType, options, (long)sectors) == ErrorNumber.NoError;
|
||||
uint sectorSize) => Create(path, mediaType, options, (long)sectors) == ErrorNumber.NoError;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Close()
|
||||
@@ -253,8 +262,8 @@ public class GameBoy : IByteAddressableImage
|
||||
|
||||
Header header = Marshal.ByteArrayToStructureBigEndian<Header>(_data, 0x100, Marshal.SizeOf<Header>());
|
||||
|
||||
bool hasMapper = false;
|
||||
bool hasSaveRam = false;
|
||||
var hasMapper = false;
|
||||
var hasSaveRam = false;
|
||||
string mapperManufacturer = null;
|
||||
string mapperName = null;
|
||||
|
||||
@@ -474,7 +483,7 @@ public class GameBoy : IByteAddressableImage
|
||||
if(header.SramSize > 0)
|
||||
hasSaveRam = true;
|
||||
|
||||
int devices = 1;
|
||||
var devices = 1;
|
||||
|
||||
if(hasSaveRam)
|
||||
devices++;
|
||||
@@ -493,6 +502,7 @@ public class GameBoy : IByteAddressableImage
|
||||
};
|
||||
|
||||
if(hasSaveRam)
|
||||
{
|
||||
mappings.Devices[1] = new LinearMemoryDevice
|
||||
{
|
||||
Type = LinearMemoryType.SaveRAM,
|
||||
@@ -502,14 +512,17 @@ public class GameBoy : IByteAddressableImage
|
||||
Length = DecodeSaveRamSize(header.SramSize)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if(hasMapper)
|
||||
{
|
||||
mappings.Devices[^1] = new LinearMemoryDevice
|
||||
{
|
||||
Type = LinearMemoryType.Mapper,
|
||||
Manufacturer = mapperManufacturer,
|
||||
Model = mapperName
|
||||
};
|
||||
}
|
||||
|
||||
return ErrorNumber.NoError;
|
||||
}
|
||||
@@ -608,12 +621,13 @@ public class GameBoy : IByteAddressableImage
|
||||
return ErrorNumber.ReadOnly;
|
||||
}
|
||||
|
||||
bool foundRom = false;
|
||||
bool foundSaveRam = false;
|
||||
bool foundMapper = false;
|
||||
var foundRom = false;
|
||||
var foundSaveRam = false;
|
||||
var foundMapper = false;
|
||||
|
||||
// Sanitize
|
||||
foreach(LinearMemoryDevice map in mappings.Devices)
|
||||
{
|
||||
switch(map.Type)
|
||||
{
|
||||
case LinearMemoryType.ROM when !foundRom:
|
||||
@@ -628,8 +642,10 @@ public class GameBoy : IByteAddressableImage
|
||||
foundMapper = true;
|
||||
|
||||
break;
|
||||
default: return ErrorNumber.InvalidArgument;
|
||||
default:
|
||||
return ErrorNumber.InvalidArgument;
|
||||
}
|
||||
}
|
||||
|
||||
// Cannot save in this image format anyway
|
||||
return foundRom ? ErrorNumber.NoError : ErrorNumber.InvalidArgument;
|
||||
@@ -672,7 +688,7 @@ public class GameBoy : IByteAddressableImage
|
||||
|
||||
/// <inheritdoc />
|
||||
public ErrorNumber WriteBytes(byte[] buffer, int offset, int bytesToWrite, out int bytesWritten,
|
||||
bool advance = true) =>
|
||||
bool advance = true) =>
|
||||
WriteBytesAt(Position, buffer, offset, bytesToWrite, out bytesWritten, advance);
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -725,294 +741,303 @@ public class GameBoy : IByteAddressableImage
|
||||
return ErrorNumber.NoError;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
[SuppressMessage("ReSharper", "StringLiteralTypo")]
|
||||
static string DecodeLicensee(byte headerLicensee, byte[] headerLicenseeNew)
|
||||
{
|
||||
if(headerLicensee != 0x33)
|
||||
{
|
||||
return headerLicensee switch
|
||||
{
|
||||
0x00 => Localization.none_licensee,
|
||||
0x01 => "nintendo",
|
||||
0x08 => "capcom",
|
||||
0x09 => "hot-b",
|
||||
0x0A => "jaleco",
|
||||
0x0B => "coconuts",
|
||||
0x0C => "elite systems",
|
||||
0x13 => "electronic arts",
|
||||
0x18 => "hudsonsoft",
|
||||
0x19 => "itc entertainment",
|
||||
0x1A => "yanoman",
|
||||
0x1D => "clary",
|
||||
0x1F => "virgin",
|
||||
0x20 => "KSS",
|
||||
0x24 => "pcm complete",
|
||||
0x25 => "san-x",
|
||||
0x28 => "kotobuki systems",
|
||||
0x29 => "seta",
|
||||
0x30 => "infogrames",
|
||||
0x31 => "nintendo",
|
||||
0x32 => "bandai",
|
||||
0x33 => Localization.GBC_see_above,
|
||||
0x34 => "konami",
|
||||
0x35 => "hector",
|
||||
0x38 => "Capcom",
|
||||
0x39 => "Banpresto",
|
||||
0x3C => "*entertainment i",
|
||||
0x3E => "gremlin",
|
||||
0x41 => "Ubisoft",
|
||||
0x42 => "Atlus",
|
||||
0x44 => "Malibu",
|
||||
0x46 => "angel",
|
||||
0x47 => "spectrum holoby",
|
||||
0x49 => "irem",
|
||||
0x4A => "virgin",
|
||||
0x4D => "malibu",
|
||||
0x4F => "u.s. gold",
|
||||
0x50 => "absolute",
|
||||
0x51 => "acclaim",
|
||||
0x52 => "activision",
|
||||
0x53 => "american sammy",
|
||||
0x54 => "gametek",
|
||||
0x55 => "park place",
|
||||
0x56 => "ljn",
|
||||
0x57 => "matchbox",
|
||||
0x59 => "milton bradley",
|
||||
0x5A => "mindscape",
|
||||
0x5B => "romstar",
|
||||
0x5C => "naxat soft",
|
||||
0x5D => "tradewest",
|
||||
0x60 => "titus",
|
||||
0x61 => "virgin",
|
||||
0x67 => "ocean",
|
||||
0x69 => "electronic arts",
|
||||
0x6E => "elite systems",
|
||||
0x6F => "electro brain",
|
||||
0x70 => "Infogrammes",
|
||||
0x71 => "Interplay",
|
||||
0x72 => "broderbund",
|
||||
0x73 => "sculptered soft",
|
||||
0x75 => "the sales curve",
|
||||
0x78 => "t*hq",
|
||||
0x79 => "accolade",
|
||||
0x7A => "triffix entertainment",
|
||||
0x7C => "microprose",
|
||||
0x7F => "kemco",
|
||||
0x80 => "misawa entertainment",
|
||||
0x83 => "lozc",
|
||||
0x86 => "tokuma shoten intermedia",
|
||||
0x8B => "bullet-proof software",
|
||||
0x8C => "vic tokai",
|
||||
0x8E => "ape",
|
||||
0x8F => "i'max",
|
||||
0x91 => "chun soft",
|
||||
0x92 => "video system",
|
||||
0x93 => "tsuburava",
|
||||
0x95 => "varie",
|
||||
0x96 => "yonezawa/s'pal",
|
||||
0x97 => "kaneko",
|
||||
0x99 => "arc",
|
||||
0x9A => "nihon bussan",
|
||||
0x9B => "Tecmo",
|
||||
0x9C => "imagineer",
|
||||
0x9D => "Banpresto",
|
||||
0x9F => "nova",
|
||||
0xA1 => "Hori electric",
|
||||
0xA2 => "Bandai",
|
||||
0xA4 => "Konami",
|
||||
0xA6 => "kawada",
|
||||
0xA7 => "takara",
|
||||
0xA9 => "technos japan",
|
||||
0xAA => "broderbund",
|
||||
0xAC => "Toei animation",
|
||||
0xAD => "toho",
|
||||
0xAF => "Namco",
|
||||
0xB0 => "Acclaim",
|
||||
0xB1 => "ascii or nexoft",
|
||||
0xB2 => "Bandai",
|
||||
0xB4 => "Enix",
|
||||
0xB6 => "HAL",
|
||||
0xB7 => "SNK",
|
||||
0xB9 => "pony canyon",
|
||||
0xBA => "*culture brain o",
|
||||
0xBB => "Sunsoft",
|
||||
0xBD => "Sony imagesoft",
|
||||
0xBF => "sammy",
|
||||
0xC0 => "Taito",
|
||||
0xC2 => "Kemco",
|
||||
0xC3 => "Squaresoft",
|
||||
0xC4 => "tokuma shoten intermedia",
|
||||
0xC5 => "data east",
|
||||
0xC6 => "tonkin house",
|
||||
0xC8 => "koei",
|
||||
0xC9 => "ufl",
|
||||
0xCA => "ultra",
|
||||
0xCB => "vap",
|
||||
0xCC => "use",
|
||||
0xCD => "meldac",
|
||||
0xCE => "*pony canyon or",
|
||||
0xCF => "angel",
|
||||
0xD0 => "Taito",
|
||||
0xD1 => "sofel",
|
||||
0xD2 => "quest",
|
||||
0xD3 => "sigma enterprises",
|
||||
0xD4 => "ask kodansha",
|
||||
0xD6 => "naxat soft",
|
||||
0xD7 => "copya systems",
|
||||
0xD9 => "Banpresto",
|
||||
0xDA => "tomy",
|
||||
0xDB => "ljn",
|
||||
0xDD => "ncs",
|
||||
0xDE => "human",
|
||||
0xDF => "altron",
|
||||
0xE0 => "jaleco",
|
||||
0xE1 => "towachiki",
|
||||
0xE2 => "uutaka",
|
||||
0xE3 => "varie",
|
||||
0xE5 => "epoch",
|
||||
0xE7 => "athena",
|
||||
0xE8 => "asmik",
|
||||
0xE9 => "natsume",
|
||||
0xEA => "king records",
|
||||
0xEB => "atlus",
|
||||
0xEC => "Epic/Sony records",
|
||||
0xEE => "igs",
|
||||
0xF0 => "a wave",
|
||||
0xF3 => "extreme entertainment",
|
||||
0xFF => "ljn",
|
||||
_ => Localization.Unknown_licensee
|
||||
};
|
||||
{
|
||||
0x00 => Localization.none_licensee,
|
||||
0x01 => "nintendo",
|
||||
0x08 => "capcom",
|
||||
0x09 => "hot-b",
|
||||
0x0A => "jaleco",
|
||||
0x0B => "coconuts",
|
||||
0x0C => "elite systems",
|
||||
0x13 => "electronic arts",
|
||||
0x18 => "hudsonsoft",
|
||||
0x19 => "itc entertainment",
|
||||
0x1A => "yanoman",
|
||||
0x1D => "clary",
|
||||
0x1F => "virgin",
|
||||
0x20 => "KSS",
|
||||
0x24 => "pcm complete",
|
||||
0x25 => "san-x",
|
||||
0x28 => "kotobuki systems",
|
||||
0x29 => "seta",
|
||||
0x30 => "infogrames",
|
||||
0x31 => "nintendo",
|
||||
0x32 => "bandai",
|
||||
0x33 => Localization.GBC_see_above,
|
||||
0x34 => "konami",
|
||||
0x35 => "hector",
|
||||
0x38 => "Capcom",
|
||||
0x39 => "Banpresto",
|
||||
0x3C => "*entertainment i",
|
||||
0x3E => "gremlin",
|
||||
0x41 => "Ubisoft",
|
||||
0x42 => "Atlus",
|
||||
0x44 => "Malibu",
|
||||
0x46 => "angel",
|
||||
0x47 => "spectrum holoby",
|
||||
0x49 => "irem",
|
||||
0x4A => "virgin",
|
||||
0x4D => "malibu",
|
||||
0x4F => "u.s. gold",
|
||||
0x50 => "absolute",
|
||||
0x51 => "acclaim",
|
||||
0x52 => "activision",
|
||||
0x53 => "american sammy",
|
||||
0x54 => "gametek",
|
||||
0x55 => "park place",
|
||||
0x56 => "ljn",
|
||||
0x57 => "matchbox",
|
||||
0x59 => "milton bradley",
|
||||
0x5A => "mindscape",
|
||||
0x5B => "romstar",
|
||||
0x5C => "naxat soft",
|
||||
0x5D => "tradewest",
|
||||
0x60 => "titus",
|
||||
0x61 => "virgin",
|
||||
0x67 => "ocean",
|
||||
0x69 => "electronic arts",
|
||||
0x6E => "elite systems",
|
||||
0x6F => "electro brain",
|
||||
0x70 => "Infogrammes",
|
||||
0x71 => "Interplay",
|
||||
0x72 => "broderbund",
|
||||
0x73 => "sculptered soft",
|
||||
0x75 => "the sales curve",
|
||||
0x78 => "t*hq",
|
||||
0x79 => "accolade",
|
||||
0x7A => "triffix entertainment",
|
||||
0x7C => "microprose",
|
||||
0x7F => "kemco",
|
||||
0x80 => "misawa entertainment",
|
||||
0x83 => "lozc",
|
||||
0x86 => "tokuma shoten intermedia",
|
||||
0x8B => "bullet-proof software",
|
||||
0x8C => "vic tokai",
|
||||
0x8E => "ape",
|
||||
0x8F => "i'max",
|
||||
0x91 => "chun soft",
|
||||
0x92 => "video system",
|
||||
0x93 => "tsuburava",
|
||||
0x95 => "varie",
|
||||
0x96 => "yonezawa/s'pal",
|
||||
0x97 => "kaneko",
|
||||
0x99 => "arc",
|
||||
0x9A => "nihon bussan",
|
||||
0x9B => "Tecmo",
|
||||
0x9C => "imagineer",
|
||||
0x9D => "Banpresto",
|
||||
0x9F => "nova",
|
||||
0xA1 => "Hori electric",
|
||||
0xA2 => "Bandai",
|
||||
0xA4 => "Konami",
|
||||
0xA6 => "kawada",
|
||||
0xA7 => "takara",
|
||||
0xA9 => "technos japan",
|
||||
0xAA => "broderbund",
|
||||
0xAC => "Toei animation",
|
||||
0xAD => "toho",
|
||||
0xAF => "Namco",
|
||||
0xB0 => "Acclaim",
|
||||
0xB1 => "ascii or nexoft",
|
||||
0xB2 => "Bandai",
|
||||
0xB4 => "Enix",
|
||||
0xB6 => "HAL",
|
||||
0xB7 => "SNK",
|
||||
0xB9 => "pony canyon",
|
||||
0xBA => "*culture brain o",
|
||||
0xBB => "Sunsoft",
|
||||
0xBD => "Sony imagesoft",
|
||||
0xBF => "sammy",
|
||||
0xC0 => "Taito",
|
||||
0xC2 => "Kemco",
|
||||
0xC3 => "Squaresoft",
|
||||
0xC4 => "tokuma shoten intermedia",
|
||||
0xC5 => "data east",
|
||||
0xC6 => "tonkin house",
|
||||
0xC8 => "koei",
|
||||
0xC9 => "ufl",
|
||||
0xCA => "ultra",
|
||||
0xCB => "vap",
|
||||
0xCC => "use",
|
||||
0xCD => "meldac",
|
||||
0xCE => "*pony canyon or",
|
||||
0xCF => "angel",
|
||||
0xD0 => "Taito",
|
||||
0xD1 => "sofel",
|
||||
0xD2 => "quest",
|
||||
0xD3 => "sigma enterprises",
|
||||
0xD4 => "ask kodansha",
|
||||
0xD6 => "naxat soft",
|
||||
0xD7 => "copya systems",
|
||||
0xD9 => "Banpresto",
|
||||
0xDA => "tomy",
|
||||
0xDB => "ljn",
|
||||
0xDD => "ncs",
|
||||
0xDE => "human",
|
||||
0xDF => "altron",
|
||||
0xE0 => "jaleco",
|
||||
0xE1 => "towachiki",
|
||||
0xE2 => "uutaka",
|
||||
0xE3 => "varie",
|
||||
0xE5 => "epoch",
|
||||
0xE7 => "athena",
|
||||
0xE8 => "asmik",
|
||||
0xE9 => "natsume",
|
||||
0xEA => "king records",
|
||||
0xEB => "atlus",
|
||||
0xEC => "Epic/Sony records",
|
||||
0xEE => "igs",
|
||||
0xF0 => "a wave",
|
||||
0xF3 => "extreme entertainment",
|
||||
0xFF => "ljn",
|
||||
_ => Localization.Unknown_licensee
|
||||
};
|
||||
}
|
||||
|
||||
string licenseeNew = StringHandlers.CToString(headerLicenseeNew);
|
||||
|
||||
return licenseeNew switch
|
||||
{
|
||||
"00" => Localization.none_licensee,
|
||||
"01" => "Nintendo R&D1",
|
||||
"08" => "Capcom",
|
||||
"13" => "Electronic Arts",
|
||||
"18" => "Hudson Soft",
|
||||
"19" => "b-ai",
|
||||
"20" => "kss",
|
||||
"22" => "pow",
|
||||
"24" => "PCM Complete",
|
||||
"25" => "san-x",
|
||||
"28" => "Kemco Japan",
|
||||
"29" => "seta",
|
||||
"30" => "Viacom",
|
||||
"31" => "Nintendo",
|
||||
"32" => "Bandai",
|
||||
"33" => "Ocean / Acclaim",
|
||||
"34" => "Konami",
|
||||
"35" => "Hector",
|
||||
"37" => "Taito",
|
||||
"38" => "Hudson",
|
||||
"39" => "Banpresto",
|
||||
"41" => "Ubi Soft",
|
||||
"42" => "Atlus",
|
||||
"44" => "Malibu",
|
||||
"46" => "angel",
|
||||
"47" => "Bullet -Proof",
|
||||
"49" => "irem",
|
||||
"50" => "Absolute",
|
||||
"51" => "Acclaim",
|
||||
"52" => "Activision",
|
||||
"53" => "American sammy",
|
||||
"54" => "Konami",
|
||||
"55" => "Hi tech entertainment",
|
||||
"56" => "LJN",
|
||||
"57" => "Matchbox",
|
||||
"58" => "Mattel",
|
||||
"59" => "Milton Bradley",
|
||||
"60" => "Titus",
|
||||
"61" => "Virgin",
|
||||
"64" => "LucasArts",
|
||||
"67" => "Ocean",
|
||||
"69" => "Electronic Arts",
|
||||
"70" => "Infogrames",
|
||||
"71" => "Interplay",
|
||||
"72" => "Brøderbund",
|
||||
"73" => "sculptured",
|
||||
"75" => "sci",
|
||||
"78" => "THQ",
|
||||
"79" => "Accolade",
|
||||
"80" => "misawa",
|
||||
"83" => "lozc",
|
||||
"86" => "tokuma shoten i",
|
||||
"87" => "tsukuda ori",
|
||||
"91" => "Chunsoft",
|
||||
"92" => "Video system",
|
||||
"93" => "Ocean / Acclaim",
|
||||
"95" => "Varie",
|
||||
"96" => "Yonezawa / s'pal",
|
||||
"97" => "Kaneko",
|
||||
"99" => "Pack in soft",
|
||||
"A4" => "Konami",
|
||||
_ => Localization.Unknown_licensee
|
||||
};
|
||||
{
|
||||
"00" => Localization.none_licensee,
|
||||
"01" => "Nintendo R&D1",
|
||||
"08" => "Capcom",
|
||||
"13" => "Electronic Arts",
|
||||
"18" => "Hudson Soft",
|
||||
"19" => "b-ai",
|
||||
"20" => "kss",
|
||||
"22" => "pow",
|
||||
"24" => "PCM Complete",
|
||||
"25" => "san-x",
|
||||
"28" => "Kemco Japan",
|
||||
"29" => "seta",
|
||||
"30" => "Viacom",
|
||||
"31" => "Nintendo",
|
||||
"32" => "Bandai",
|
||||
"33" => "Ocean / Acclaim",
|
||||
"34" => "Konami",
|
||||
"35" => "Hector",
|
||||
"37" => "Taito",
|
||||
"38" => "Hudson",
|
||||
"39" => "Banpresto",
|
||||
"41" => "Ubi Soft",
|
||||
"42" => "Atlus",
|
||||
"44" => "Malibu",
|
||||
"46" => "angel",
|
||||
"47" => "Bullet -Proof",
|
||||
"49" => "irem",
|
||||
"50" => "Absolute",
|
||||
"51" => "Acclaim",
|
||||
"52" => "Activision",
|
||||
"53" => "American sammy",
|
||||
"54" => "Konami",
|
||||
"55" => "Hi tech entertainment",
|
||||
"56" => "LJN",
|
||||
"57" => "Matchbox",
|
||||
"58" => "Mattel",
|
||||
"59" => "Milton Bradley",
|
||||
"60" => "Titus",
|
||||
"61" => "Virgin",
|
||||
"64" => "LucasArts",
|
||||
"67" => "Ocean",
|
||||
"69" => "Electronic Arts",
|
||||
"70" => "Infogrames",
|
||||
"71" => "Interplay",
|
||||
"72" => "Brøderbund",
|
||||
"73" => "sculptured",
|
||||
"75" => "sci",
|
||||
"78" => "THQ",
|
||||
"79" => "Accolade",
|
||||
"80" => "misawa",
|
||||
"83" => "lozc",
|
||||
"86" => "tokuma shoten i",
|
||||
"87" => "tsukuda ori",
|
||||
"91" => "Chunsoft",
|
||||
"92" => "Video system",
|
||||
"93" => "Ocean / Acclaim",
|
||||
"95" => "Varie",
|
||||
"96" => "Yonezawa / s'pal",
|
||||
"97" => "Kaneko",
|
||||
"99" => "Pack in soft",
|
||||
"A4" => "Konami",
|
||||
_ => Localization.Unknown_licensee
|
||||
};
|
||||
}
|
||||
|
||||
static uint DecodeRomSize(byte headerRomType) => headerRomType switch
|
||||
{
|
||||
0 => 32768,
|
||||
1 => 65536,
|
||||
2 => 131072,
|
||||
3 => 262144,
|
||||
4 => 524288,
|
||||
5 => 1048576,
|
||||
6 => 2097152,
|
||||
7 => 4194304,
|
||||
8 => 8388608,
|
||||
0x52 => 1179648,
|
||||
0x53 => 1310720,
|
||||
0x54 => 1572864,
|
||||
_ => 0
|
||||
};
|
||||
{
|
||||
0 => 32768,
|
||||
1 => 65536,
|
||||
2 => 131072,
|
||||
3 => 262144,
|
||||
4 => 524288,
|
||||
5 => 1048576,
|
||||
6 => 2097152,
|
||||
7 => 4194304,
|
||||
8 => 8388608,
|
||||
0x52 => 1179648,
|
||||
0x53 => 1310720,
|
||||
0x54 => 1572864,
|
||||
_ => 0
|
||||
};
|
||||
|
||||
static uint DecodeSaveRamSize(byte headerRamType) => headerRamType switch
|
||||
{
|
||||
0 => 0,
|
||||
1 => 2048,
|
||||
2 => 8192,
|
||||
3 => 32768,
|
||||
4 => 131072,
|
||||
5 => 65536,
|
||||
_ => 0
|
||||
};
|
||||
{
|
||||
0 => 0,
|
||||
1 => 2048,
|
||||
2 => 8192,
|
||||
3 => 32768,
|
||||
4 => 131072,
|
||||
5 => 65536,
|
||||
_ => 0
|
||||
};
|
||||
|
||||
static string DecodeCartridgeType(byte headerRomType) => headerRomType switch
|
||||
{
|
||||
0x00 => Localization.ROM_only,
|
||||
0x01 => Localization.ROM_and_MBC1,
|
||||
0x02 => Localization.ROM_MBC1_and_RAM,
|
||||
0x03 => Localization.ROM_MBC1_RAM_and_battery,
|
||||
0x05 => Localization.ROM_and_MBC2,
|
||||
0x06 => Localization.ROM_MBC2_and_battery,
|
||||
0x08 => Localization.ROM_and_RAM,
|
||||
0x09 => Localization.ROM_RAM_and_battery,
|
||||
0x0B => Localization.ROM_and_MMM01,
|
||||
0x0C => Localization.ROM_MMM01_and_RAM,
|
||||
0x0D => Localization.ROM_MMM01_RAM_and_battery,
|
||||
0x0F => Localization.ROM_MBC3_timer_and_battery,
|
||||
0x10 => Localization.ROM_MBC3_RAM_timer_and_battery,
|
||||
0x11 => Localization.ROM_and_MBC3,
|
||||
0x12 => Localization.ROM_MBC3_and_RAM,
|
||||
0x13 => Localization.ROM_MBC3_RAM_and_battery,
|
||||
0x19 => Localization.ROM_and_MBC5,
|
||||
0x1A => Localization.ROM_MBC5_and_RAM,
|
||||
0x1B => Localization.ROM_MBC5_RAM_and_battery,
|
||||
0x1C => Localization.ROM_MBC5_and_vibration_motor,
|
||||
0x1D => Localization.ROM_MBC5_RAM_and_vibration_motor,
|
||||
0x1E => Localization.ROM_MBC5_RAM_battery_and_vibration_motor,
|
||||
0x20 => Localization.ROM_and_MBC6,
|
||||
0x22 => Localization.ROM_MBC7_RAM_battery_light_sensor_and_vibration_motor,
|
||||
0xFC => Localization.Pocket_Camera,
|
||||
0xFD => Localization.ROM_and_TAMA5,
|
||||
0xFE => Localization.ROM_and_HuC_3,
|
||||
0xFF => Localization.ROM_and_HuC_1,
|
||||
_ => Localization.Unknown_cartridge_type
|
||||
};
|
||||
{
|
||||
0x00 => Localization.ROM_only,
|
||||
0x01 => Localization.ROM_and_MBC1,
|
||||
0x02 => Localization.ROM_MBC1_and_RAM,
|
||||
0x03 => Localization.ROM_MBC1_RAM_and_battery,
|
||||
0x05 => Localization.ROM_and_MBC2,
|
||||
0x06 => Localization.ROM_MBC2_and_battery,
|
||||
0x08 => Localization.ROM_and_RAM,
|
||||
0x09 => Localization.ROM_RAM_and_battery,
|
||||
0x0B => Localization.ROM_and_MMM01,
|
||||
0x0C => Localization.ROM_MMM01_and_RAM,
|
||||
0x0D => Localization.ROM_MMM01_RAM_and_battery,
|
||||
0x0F => Localization.ROM_MBC3_timer_and_battery,
|
||||
0x10 => Localization.ROM_MBC3_RAM_timer_and_battery,
|
||||
0x11 => Localization.ROM_and_MBC3,
|
||||
0x12 => Localization.ROM_MBC3_and_RAM,
|
||||
0x13 => Localization.ROM_MBC3_RAM_and_battery,
|
||||
0x19 => Localization.ROM_and_MBC5,
|
||||
0x1A => Localization.ROM_MBC5_and_RAM,
|
||||
0x1B => Localization.ROM_MBC5_RAM_and_battery,
|
||||
0x1C => Localization.ROM_MBC5_and_vibration_motor,
|
||||
0x1D => Localization.ROM_MBC5_RAM_and_vibration_motor,
|
||||
0x1E => Localization.
|
||||
ROM_MBC5_RAM_battery_and_vibration_motor,
|
||||
0x20 => Localization.ROM_and_MBC6,
|
||||
0x22 => Localization.
|
||||
ROM_MBC7_RAM_battery_light_sensor_and_vibration_motor,
|
||||
0xFC => Localization.Pocket_Camera,
|
||||
0xFD => Localization.ROM_and_TAMA5,
|
||||
0xFE => Localization.ROM_and_HuC_3,
|
||||
0xFF => Localization.ROM_and_HuC_1,
|
||||
_ => Localization.Unknown_cartridge_type
|
||||
};
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1), SuppressMessage("ReSharper", "FieldCanBeMadeReadOnly.Local")]
|
||||
#region Nested type: Header
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
[SuppressMessage("ReSharper", "FieldCanBeMadeReadOnly.Local")]
|
||||
struct Header
|
||||
{
|
||||
/// <summary>Usually 0x00 (NOP)</summary>
|
||||
@@ -1049,4 +1074,6 @@ public class GameBoy : IByteAddressableImage
|
||||
/// <summary>Cartridge checksum</summary>
|
||||
public ushort Checksum;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -20,18 +20,27 @@ public class GameBoyAdvance : IByteAddressableImage
|
||||
Stream _dataStream;
|
||||
ImageInfo _imageInfo;
|
||||
bool _opened;
|
||||
|
||||
#region IByteAddressableImage Members
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Author => Authors.NataliaPortillo;
|
||||
|
||||
/// <inheritdoc />
|
||||
public Metadata AaruMetadata => null;
|
||||
|
||||
/// <inheritdoc />
|
||||
public List<DumpHardware> DumpHardware => null;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Format => "Nintendo Game Boy Advance cartridge dump";
|
||||
|
||||
/// <inheritdoc />
|
||||
public Guid Id => new("0040DDEB-3902-4402-9028-62915C5AA81F");
|
||||
|
||||
/// <inheritdoc />
|
||||
public ImageInfo Info => _imageInfo;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Name => Localization.GameBoyAdvance_Name;
|
||||
|
||||
@@ -48,9 +57,9 @@ public class GameBoyAdvance : IByteAddressableImage
|
||||
return false;
|
||||
|
||||
stream.Position = 4;
|
||||
byte[] magicBytes = new byte[8];
|
||||
var magicBytes = new byte[8];
|
||||
stream.EnsureRead(magicBytes, 0, 8);
|
||||
ulong magic = BitConverter.ToUInt64(magicBytes, 0);
|
||||
var magic = BitConverter.ToUInt64(magicBytes, 0);
|
||||
|
||||
return magic == 0x21A29A6951AEFF24;
|
||||
}
|
||||
@@ -68,9 +77,9 @@ public class GameBoyAdvance : IByteAddressableImage
|
||||
return ErrorNumber.InvalidArgument;
|
||||
|
||||
stream.Position = 4;
|
||||
byte[] magicBytes = new byte[8];
|
||||
var magicBytes = new byte[8];
|
||||
stream.EnsureRead(magicBytes, 0, 8);
|
||||
ulong magic = BitConverter.ToUInt64(magicBytes, 0);
|
||||
var magic = BitConverter.ToUInt64(magicBytes, 0);
|
||||
|
||||
if(magic != 0x21A29A6951AEFF24)
|
||||
return ErrorNumber.InvalidArgument;
|
||||
@@ -97,12 +106,12 @@ public class GameBoyAdvance : IByteAddressableImage
|
||||
|
||||
sb.AppendFormat(Localization.Name_0, _imageInfo.MediaTitle).AppendLine();
|
||||
|
||||
sb.AppendFormat(Localization.Device_type_0, header.DeviceType).AppendLine();
|
||||
sb.AppendFormat(Localization.Console_type_0, header.UnitCode).AppendLine();
|
||||
sb.AppendFormat(Localization.Device_type_0, header.DeviceType).AppendLine();
|
||||
sb.AppendFormat(Localization.Console_type_0, header.UnitCode).AppendLine();
|
||||
sb.AppendFormat(Localization.Product_code_AGB_0, StringHandlers.CToString(header.Code)).AppendLine();
|
||||
sb.AppendFormat(Localization.Maker_code_0, StringHandlers.CToString(header.Maker)).AppendLine();
|
||||
sb.AppendFormat(Localization.Revision_0, header.Revision).AppendLine();
|
||||
sb.AppendFormat(Localization.Header_checksum_0, header.ComplementCheck).AppendLine();
|
||||
sb.AppendFormat(Localization.Maker_code_0, StringHandlers.CToString(header.Maker)).AppendLine();
|
||||
sb.AppendFormat(Localization.Revision_0, header.Revision).AppendLine();
|
||||
sb.AppendFormat(Localization.Header_checksum_0, header.ComplementCheck).AppendLine();
|
||||
|
||||
_imageInfo.Comments = sb.ToString();
|
||||
_opened = true;
|
||||
@@ -112,29 +121,29 @@ public class GameBoyAdvance : IByteAddressableImage
|
||||
|
||||
/// <inheritdoc />
|
||||
public string ErrorMessage { get; private set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsWriting { get; private set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<string> KnownExtensions => new[]
|
||||
{
|
||||
".gba"
|
||||
};
|
||||
public IEnumerable<string> KnownExtensions => new[] { ".gba" };
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<MediaTagType> SupportedMediaTags => Array.Empty<MediaTagType>();
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<MediaType> SupportedMediaTypes => new[]
|
||||
{
|
||||
MediaType.GameBoyAdvanceGamePak
|
||||
};
|
||||
public IEnumerable<MediaType> SupportedMediaTypes => new[] { MediaType.GameBoyAdvanceGamePak };
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<(string name, Type type, string description, object @default)> SupportedOptions =>
|
||||
Array.Empty<(string name, Type type, string description, object @default)>();
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<SectorTagType> SupportedSectorTags => Array.Empty<SectorTagType>();
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Create(string path, MediaType mediaType, Dictionary<string, string> options, ulong sectors,
|
||||
uint sectorSize) => Create(path, mediaType, options, (long)sectors) == ErrorNumber.NoError;
|
||||
uint sectorSize) => Create(path, mediaType, options, (long)sectors) == ErrorNumber.NoError;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Close()
|
||||
@@ -342,11 +351,12 @@ public class GameBoyAdvance : IByteAddressableImage
|
||||
return ErrorNumber.ReadOnly;
|
||||
}
|
||||
|
||||
bool foundRom = false;
|
||||
bool foundSaveRam = false;
|
||||
var foundRom = false;
|
||||
var foundSaveRam = false;
|
||||
|
||||
// Sanitize
|
||||
foreach(LinearMemoryDevice map in mappings.Devices)
|
||||
{
|
||||
switch(map.Type)
|
||||
{
|
||||
case LinearMemoryType.ROM when !foundRom:
|
||||
@@ -357,8 +367,10 @@ public class GameBoyAdvance : IByteAddressableImage
|
||||
foundSaveRam = true;
|
||||
|
||||
break;
|
||||
default: return ErrorNumber.InvalidArgument;
|
||||
default:
|
||||
return ErrorNumber.InvalidArgument;
|
||||
}
|
||||
}
|
||||
|
||||
// Cannot save in this image format anyway
|
||||
return foundRom ? ErrorNumber.NoError : ErrorNumber.InvalidArgument;
|
||||
@@ -401,7 +413,7 @@ public class GameBoyAdvance : IByteAddressableImage
|
||||
|
||||
/// <inheritdoc />
|
||||
public ErrorNumber WriteBytes(byte[] buffer, int offset, int bytesToWrite, out int bytesWritten,
|
||||
bool advance = true) =>
|
||||
bool advance = true) =>
|
||||
WriteBytesAt(Position, buffer, offset, bytesToWrite, out bytesWritten, advance);
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -454,8 +466,13 @@ public class GameBoyAdvance : IByteAddressableImage
|
||||
return ErrorNumber.NoError;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1), SuppressMessage("ReSharper", "MemberCanBePrivate.Local"),
|
||||
SuppressMessage("ReSharper", "FieldCanBeMadeReadOnly.Local")]
|
||||
#endregion
|
||||
|
||||
#region Nested type: Header
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
[SuppressMessage("ReSharper", "MemberCanBePrivate.Local")]
|
||||
[SuppressMessage("ReSharper", "FieldCanBeMadeReadOnly.Local")]
|
||||
struct Header
|
||||
{
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
|
||||
@@ -478,4 +495,6 @@ public class GameBoyAdvance : IByteAddressableImage
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
|
||||
public byte[] Reserved2;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -22,18 +22,27 @@ public class MasterSystem : IByteAddressableImage
|
||||
ImageInfo _imageInfo;
|
||||
bool _opened;
|
||||
int _romSize;
|
||||
|
||||
#region IByteAddressableImage Members
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Author => Authors.NataliaPortillo;
|
||||
|
||||
/// <inheritdoc />
|
||||
public Metadata AaruMetadata => null;
|
||||
|
||||
/// <inheritdoc />
|
||||
public List<DumpHardware> DumpHardware => null;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Format => _gameGear ? "Sega Game Gear cartridge dump" : "Sega Master System cartridge dump";
|
||||
|
||||
/// <inheritdoc />
|
||||
public Guid Id => new("B0C02927-890D-41D0-8E95-C5D9A2A74131");
|
||||
|
||||
/// <inheritdoc />
|
||||
public ImageInfo Info => _imageInfo;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Name => Localization.MasterSystem_Name;
|
||||
|
||||
@@ -50,9 +59,9 @@ public class MasterSystem : IByteAddressableImage
|
||||
return false;
|
||||
|
||||
stream.Position = 0x7ff0;
|
||||
byte[] magicBytes = new byte[8];
|
||||
var magicBytes = new byte[8];
|
||||
stream.EnsureRead(magicBytes, 0, 8);
|
||||
ulong magic = BitConverter.ToUInt64(magicBytes, 0);
|
||||
var magic = BitConverter.ToUInt64(magicBytes, 0);
|
||||
|
||||
if(magic == 0x4147455320524D54)
|
||||
return true;
|
||||
@@ -85,12 +94,12 @@ public class MasterSystem : IByteAddressableImage
|
||||
if(stream.Length % 8192 != 0)
|
||||
return ErrorNumber.InvalidArgument;
|
||||
|
||||
int headerPosition = 0;
|
||||
var headerPosition = 0;
|
||||
|
||||
stream.Position = 0x7ff0;
|
||||
byte[] magicBytes = new byte[8];
|
||||
var magicBytes = new byte[8];
|
||||
stream.EnsureRead(magicBytes, 0, 8);
|
||||
ulong magic = BitConverter.ToUInt64(magicBytes, 0);
|
||||
var magic = BitConverter.ToUInt64(magicBytes, 0);
|
||||
|
||||
if(magic != 0x0B000DCC6666EDCE)
|
||||
headerPosition = 0x7ff0;
|
||||
@@ -135,9 +144,9 @@ public class MasterSystem : IByteAddressableImage
|
||||
|
||||
var sb = new StringBuilder();
|
||||
|
||||
int productCode = (header.ProductCode[0] & 0xF) + ((header.ProductCode[0] & 0xF0) * 10) +
|
||||
((header.ProductCode[1] & 0xF) * 100) + ((header.ProductCode[1] & 0xF0) * 1000) +
|
||||
(((header.VersionAndProduct & 0xF0) >> 4) * 10000);
|
||||
int productCode = (header.ProductCode[0] & 0xF) + (header.ProductCode[0] & 0xF0) * 10 +
|
||||
(header.ProductCode[1] & 0xF) * 100 + (header.ProductCode[1] & 0xF0) * 1000 +
|
||||
((header.VersionAndProduct & 0xF0) >> 4) * 10000;
|
||||
|
||||
sb.AppendFormat(Localization.Product_code_0, productCode).AppendLine();
|
||||
|
||||
@@ -187,24 +196,24 @@ public class MasterSystem : IByteAddressableImage
|
||||
int sizeCode = header.SizeAndRegion & 0xF;
|
||||
|
||||
_romSize = sizeCode switch
|
||||
{
|
||||
0 => 262144,
|
||||
1 => 524288,
|
||||
2 => 1048576,
|
||||
0xA => 8192,
|
||||
0xB => 16384,
|
||||
0xC => 32768,
|
||||
0xD => 49152,
|
||||
0xE => 65536,
|
||||
0xF => 131072,
|
||||
_ => 0
|
||||
};
|
||||
{
|
||||
0 => 262144,
|
||||
1 => 524288,
|
||||
2 => 1048576,
|
||||
0xA => 8192,
|
||||
0xB => 16384,
|
||||
0xC => 32768,
|
||||
0xD => 49152,
|
||||
0xE => 65536,
|
||||
0xF => 131072,
|
||||
_ => 0
|
||||
};
|
||||
|
||||
sb.AppendFormat(Localization.Region_0, region).AppendLine();
|
||||
sb.AppendFormat(Localization.Region_0, region).AppendLine();
|
||||
sb.AppendFormat(Localization.Cartridge_type_0, cartType).AppendLine();
|
||||
sb.AppendFormat(Localization.ROM_size_0_bytes, _romSize).AppendLine();
|
||||
sb.AppendFormat(Localization.Revision_0, header.VersionAndProduct & 0xF).AppendLine();
|
||||
sb.AppendFormat(Localization.Checksum_0_X4, header.Checksum).AppendLine();
|
||||
sb.AppendFormat(Localization.Revision_0, header.VersionAndProduct & 0xF).AppendLine();
|
||||
sb.AppendFormat(Localization.Checksum_0_X4, header.Checksum).AppendLine();
|
||||
|
||||
_imageInfo.Comments = sb.ToString();
|
||||
_opened = true;
|
||||
@@ -214,29 +223,32 @@ public class MasterSystem : IByteAddressableImage
|
||||
|
||||
/// <inheritdoc />
|
||||
public string ErrorMessage { get; private set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsWriting { get; private set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<string> KnownExtensions => new[]
|
||||
{
|
||||
".sms", ".gg"
|
||||
};
|
||||
public IEnumerable<string> KnownExtensions => new[] { ".sms", ".gg" };
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<MediaTagType> SupportedMediaTags => Array.Empty<MediaTagType>();
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<MediaType> SupportedMediaTypes => new[]
|
||||
{
|
||||
MediaType.MasterSystemCartridge, MediaType.GameGearCartridge
|
||||
};
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<(string name, Type type, string description, object @default)> SupportedOptions =>
|
||||
Array.Empty<(string name, Type type, string description, object @default)>();
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<SectorTagType> SupportedSectorTags => Array.Empty<SectorTagType>();
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Create(string path, MediaType mediaType, Dictionary<string, string> options, ulong sectors,
|
||||
uint sectorSize) => Create(path, mediaType, options, (long)sectors) == ErrorNumber.NoError;
|
||||
uint sectorSize) => Create(path, mediaType, options, (long)sectors) == ErrorNumber.NoError;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Close()
|
||||
@@ -444,18 +456,21 @@ public class MasterSystem : IByteAddressableImage
|
||||
return ErrorNumber.ReadOnly;
|
||||
}
|
||||
|
||||
bool foundRom = false;
|
||||
var foundRom = false;
|
||||
|
||||
// Sanitize
|
||||
foreach(LinearMemoryDevice map in mappings.Devices)
|
||||
{
|
||||
switch(map.Type)
|
||||
{
|
||||
case LinearMemoryType.ROM when !foundRom:
|
||||
foundRom = true;
|
||||
|
||||
break;
|
||||
default: return ErrorNumber.InvalidArgument;
|
||||
default:
|
||||
return ErrorNumber.InvalidArgument;
|
||||
}
|
||||
}
|
||||
|
||||
// Cannot save in this image format anyway
|
||||
return foundRom ? ErrorNumber.NoError : ErrorNumber.InvalidArgument;
|
||||
@@ -498,7 +513,7 @@ public class MasterSystem : IByteAddressableImage
|
||||
|
||||
/// <inheritdoc />
|
||||
public ErrorNumber WriteBytes(byte[] buffer, int offset, int bytesToWrite, out int bytesWritten,
|
||||
bool advance = true) =>
|
||||
bool advance = true) =>
|
||||
WriteBytesAt(Position, buffer, offset, bytesToWrite, out bytesWritten, advance);
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -551,8 +566,13 @@ public class MasterSystem : IByteAddressableImage
|
||||
return ErrorNumber.NoError;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1), SuppressMessage("ReSharper", "FieldCanBeMadeReadOnly.Local"),
|
||||
SuppressMessage("ReSharper", "MemberCanBePrivate.Local")]
|
||||
#endregion
|
||||
|
||||
#region Nested type: Header
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
[SuppressMessage("ReSharper", "FieldCanBeMadeReadOnly.Local")]
|
||||
[SuppressMessage("ReSharper", "MemberCanBePrivate.Local")]
|
||||
struct Header
|
||||
{
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
|
||||
@@ -564,4 +584,6 @@ public class MasterSystem : IByteAddressableImage
|
||||
public byte VersionAndProduct;
|
||||
public byte SizeAndRegion;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -35,18 +35,27 @@ public class Nes : IByteAddressableImage
|
||||
int _promLen;
|
||||
byte _submapper;
|
||||
bool _trainer;
|
||||
|
||||
#region IByteAddressableImage Members
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Author => Authors.NataliaPortillo;
|
||||
|
||||
/// <inheritdoc />
|
||||
public Metadata AaruMetadata => null;
|
||||
|
||||
/// <inheritdoc />
|
||||
public List<DumpHardware> DumpHardware => null;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Format => _nes20 ? "NES 2.0" : "iNES";
|
||||
|
||||
/// <inheritdoc />
|
||||
public Guid Id => new("D597A3F4-2B1C-441C-8487-0BCABC509302");
|
||||
|
||||
/// <inheritdoc />
|
||||
public ImageInfo Info => _imageInfo;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Name => Localization.Nes_Name;
|
||||
|
||||
@@ -63,9 +72,9 @@ public class Nes : IByteAddressableImage
|
||||
return false;
|
||||
|
||||
stream.Position = 0;
|
||||
byte[] magicBytes = new byte[4];
|
||||
var magicBytes = new byte[4];
|
||||
stream.EnsureRead(magicBytes, 0, 8);
|
||||
uint magic = BitConverter.ToUInt32(magicBytes, 0);
|
||||
var magic = BitConverter.ToUInt32(magicBytes, 0);
|
||||
|
||||
return magic == 0x1A53454E;
|
||||
}
|
||||
@@ -83,9 +92,9 @@ public class Nes : IByteAddressableImage
|
||||
return ErrorNumber.InvalidArgument;
|
||||
|
||||
stream.Position = 0;
|
||||
byte[] header = new byte[16];
|
||||
var header = new byte[16];
|
||||
stream.EnsureRead(header, 0, 8);
|
||||
uint magic = BitConverter.ToUInt32(header, 0);
|
||||
var magic = BitConverter.ToUInt32(header, 0);
|
||||
|
||||
if(magic != 0x1A53454E)
|
||||
return ErrorNumber.InvalidArgument;
|
||||
@@ -105,7 +114,7 @@ public class Nes : IByteAddressableImage
|
||||
NametableMirroring = (header[6] & 0x1) != 0,
|
||||
BatteryPresent = (header[6] & 0x2) != 0,
|
||||
FourScreenMode = (header[6] & 0x8) != 0,
|
||||
Mapper = (ushort)((header[6] >> 4) | (header[7] & 0xF0))
|
||||
Mapper = (ushort)(header[6] >> 4 | header[7] & 0xF0)
|
||||
};
|
||||
|
||||
if((header[7] & 0x1) != 0)
|
||||
@@ -181,7 +190,7 @@ public class Nes : IByteAddressableImage
|
||||
sb.AppendFormat(Localization.PRG_ROM_size_0_bytes, _prgLen).AppendLine();
|
||||
sb.AppendFormat(Localization.CHR_ROM_size_0_bytes, _chrLen).AppendLine();
|
||||
sb.AppendFormat(Localization.Trainer_size_0_bytes, trainerLen).AppendLine();
|
||||
sb.AppendFormat(Localization.Mapper_0, _nesHeaderInfo.Mapper).AppendLine();
|
||||
sb.AppendFormat(Localization.Mapper_0, _nesHeaderInfo.Mapper).AppendLine();
|
||||
|
||||
if(_nesHeaderInfo.BatteryPresent)
|
||||
sb.AppendLine(Localization.Has_battery_backed_RAM);
|
||||
@@ -203,11 +212,12 @@ public class Nes : IByteAddressableImage
|
||||
case NesConsoleType.Playchoice:
|
||||
sb.AppendLine(Localization.PlayChoice_10_game);
|
||||
sb.AppendFormat(Localization.INST_ROM_size_0_bytes, _instRomLen & 0xF).AppendLine();
|
||||
sb.AppendFormat(Localization.PROM_size_0_bytes, _promLen).AppendLine();
|
||||
sb.AppendFormat(Localization.PROM_size_0_bytes, _promLen).AppendLine();
|
||||
|
||||
break;
|
||||
|
||||
case NesConsoleType.Nes: break;
|
||||
case NesConsoleType.Nes:
|
||||
break;
|
||||
case NesConsoleType.Extended:
|
||||
switch(_nesHeaderInfo.ExtendedConsoleType)
|
||||
{
|
||||
@@ -216,11 +226,12 @@ public class Nes : IByteAddressableImage
|
||||
|
||||
break;
|
||||
|
||||
case NesExtendedConsoleType.Normal: break;
|
||||
case NesExtendedConsoleType.Normal:
|
||||
break;
|
||||
case NesExtendedConsoleType.Playchoice:
|
||||
sb.AppendLine(Localization.PlayChoice_10_game);
|
||||
sb.AppendFormat(Localization.INST_ROM_size_0_bytes, _instRomLen & 0xF).AppendLine();
|
||||
sb.AppendFormat(Localization.PROM_size_0_bytes, _promLen).AppendLine();
|
||||
sb.AppendFormat(Localization.PROM_size_0_bytes, _promLen).AppendLine();
|
||||
|
||||
break;
|
||||
case NesExtendedConsoleType.VT01_Monochrome:
|
||||
@@ -262,29 +273,29 @@ public class Nes : IByteAddressableImage
|
||||
|
||||
/// <inheritdoc />
|
||||
public string ErrorMessage { get; private set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsWriting { get; private set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<string> KnownExtensions => new[]
|
||||
{
|
||||
".nes"
|
||||
};
|
||||
public IEnumerable<string> KnownExtensions => new[] { ".nes" };
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<MediaTagType> SupportedMediaTags => Array.Empty<MediaTagType>();
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<MediaType> SupportedMediaTypes => new[]
|
||||
{
|
||||
MediaType.NESGamePak, MediaType.FamicomGamePak
|
||||
};
|
||||
public IEnumerable<MediaType> SupportedMediaTypes => new[] { MediaType.NESGamePak, MediaType.FamicomGamePak };
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<(string name, Type type, string description, object @default)> SupportedOptions =>
|
||||
Array.Empty<(string name, Type type, string description, object @default)>();
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<SectorTagType> SupportedSectorTags => Array.Empty<SectorTagType>();
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Create(string path, MediaType mediaType, Dictionary<string, string> options, ulong sectors,
|
||||
uint sectorSize) => Create(path, mediaType, options, (long)sectors) == ErrorNumber.NoError;
|
||||
uint sectorSize) => Create(path, mediaType, options, (long)sectors) == ErrorNumber.NoError;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Close()
|
||||
@@ -303,7 +314,7 @@ public class Nes : IByteAddressableImage
|
||||
return false;
|
||||
}
|
||||
|
||||
byte[] header = new byte[16];
|
||||
var header = new byte[16];
|
||||
|
||||
if(_nesHeaderInfo is null)
|
||||
{
|
||||
@@ -323,8 +334,8 @@ public class Nes : IByteAddressableImage
|
||||
header[1] = 0x45;
|
||||
header[2] = 0x53;
|
||||
header[3] = 0x1A;
|
||||
header[4] = (byte)((_prgLen / 16384) & 0xFF);
|
||||
header[5] = (byte)((_chrLen / 8192) & 0xFF);
|
||||
header[4] = (byte)(_prgLen / 16384 & 0xFF);
|
||||
header[5] = (byte)(_chrLen / 8192 & 0xFF);
|
||||
header[6] = (byte)((_nesHeaderInfo.Mapper & 0xF) << 4);
|
||||
|
||||
if(_nesHeaderInfo.FourScreenMode)
|
||||
@@ -339,23 +350,24 @@ public class Nes : IByteAddressableImage
|
||||
if(_nesHeaderInfo.NametableMirroring)
|
||||
header[6] |= 0x1;
|
||||
|
||||
header[7] = (byte)((_mapper & 0xF0) | 0x8);
|
||||
header[7] = (byte)(_mapper & 0xF0 | 0x8);
|
||||
header[7] |= (byte)_nesHeaderInfo.ConsoleType;
|
||||
|
||||
header[8] = (byte)((_nesHeaderInfo.Submapper << 4) | ((_nesHeaderInfo.Mapper & 0xF00) >> 4));
|
||||
header[9] = (byte)((_prgLen / 16384) >> 8);
|
||||
header[9] |= (byte)(((_chrLen / 8192) >> 4) & 0xF);
|
||||
header[8] = (byte)(_nesHeaderInfo.Submapper << 4 | (_nesHeaderInfo.Mapper & 0xF00) >> 4);
|
||||
header[9] = (byte)(_prgLen / 16384 >> 8);
|
||||
header[9] |= (byte)(_chrLen / 8192 >> 4 & 0xF);
|
||||
|
||||
// TODO: PRG-RAM, PRG-NVRAM, CHR-RAM and CHR-NVRAM sizes
|
||||
|
||||
header[12] = (byte)_nesHeaderInfo.TimingMode;
|
||||
|
||||
header[13] = _nesHeaderInfo.ConsoleType switch
|
||||
{
|
||||
NesConsoleType.Vs => (byte)(((int)_nesHeaderInfo.VsHardwareType << 4) | (int)_nesHeaderInfo.VsPpuType),
|
||||
NesConsoleType.Extended => (byte)_nesHeaderInfo.ExtendedConsoleType,
|
||||
_ => header[13]
|
||||
};
|
||||
{
|
||||
NesConsoleType.Vs => (byte)((int)_nesHeaderInfo.VsHardwareType << 4 |
|
||||
(int)_nesHeaderInfo.VsPpuType),
|
||||
NesConsoleType.Extended => (byte)_nesHeaderInfo.ExtendedConsoleType,
|
||||
_ => header[13]
|
||||
};
|
||||
|
||||
header[14] = 0;
|
||||
|
||||
@@ -470,6 +482,7 @@ public class Nes : IByteAddressableImage
|
||||
};
|
||||
|
||||
if(_chrLen > 0)
|
||||
{
|
||||
devices.Add(new LinearMemoryDevice
|
||||
{
|
||||
Type = LinearMemoryType.CharacterROM,
|
||||
@@ -478,14 +491,18 @@ public class Nes : IByteAddressableImage
|
||||
Length = (ulong)_chrLen
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if(_trainer)
|
||||
{
|
||||
devices.Add(new LinearMemoryDevice
|
||||
{
|
||||
Type = LinearMemoryType.Trainer
|
||||
});
|
||||
}
|
||||
|
||||
if(_instRomLen > 0)
|
||||
{
|
||||
devices.Add(new LinearMemoryDevice
|
||||
{
|
||||
Type = LinearMemoryType.ROM,
|
||||
@@ -494,8 +511,10 @@ public class Nes : IByteAddressableImage
|
||||
Length = (ulong)_instRomLen
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if(_promLen > 0)
|
||||
{
|
||||
devices.Add(new LinearMemoryDevice
|
||||
{
|
||||
Type = LinearMemoryType.ROM,
|
||||
@@ -504,8 +523,10 @@ public class Nes : IByteAddressableImage
|
||||
Length = (ulong)_promLen
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if(_prgRamLen > 0)
|
||||
{
|
||||
devices.Add(new LinearMemoryDevice
|
||||
{
|
||||
Type = LinearMemoryType.WorkRAM,
|
||||
@@ -514,8 +535,10 @@ public class Nes : IByteAddressableImage
|
||||
Length = (ulong)_prgRamLen
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if(_chrRamLen > 0)
|
||||
{
|
||||
devices.Add(new LinearMemoryDevice
|
||||
{
|
||||
Type = LinearMemoryType.CharacterRAM,
|
||||
@@ -524,8 +547,10 @@ public class Nes : IByteAddressableImage
|
||||
Length = (ulong)_chrRamLen
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if(_prgNvramLen > 0)
|
||||
{
|
||||
devices.Add(new LinearMemoryDevice
|
||||
{
|
||||
Type = LinearMemoryType.SaveRAM,
|
||||
@@ -534,8 +559,10 @@ public class Nes : IByteAddressableImage
|
||||
Length = (ulong)_prgNvramLen
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if(_chrNvramLen > 0)
|
||||
{
|
||||
devices.Add(new LinearMemoryDevice
|
||||
{
|
||||
Type = LinearMemoryType.CharacterRAM,
|
||||
@@ -544,6 +571,7 @@ public class Nes : IByteAddressableImage
|
||||
Length = (ulong)_chrNvramLen
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ushort mapper = _nesHeaderInfo?.Mapper ?? _mapper;
|
||||
byte submapper = _nesHeaderInfo?.Submapper ?? _submapper;
|
||||
@@ -555,11 +583,13 @@ public class Nes : IByteAddressableImage
|
||||
});
|
||||
|
||||
if(submapper != 0)
|
||||
{
|
||||
devices.Add(new LinearMemoryDevice
|
||||
{
|
||||
Type = LinearMemoryType.Mapper,
|
||||
Description = $"NES Submapper {submapper}"
|
||||
});
|
||||
}
|
||||
|
||||
mappings = new LinearMemoryMap
|
||||
{
|
||||
@@ -663,22 +693,23 @@ public class Nes : IByteAddressableImage
|
||||
return ErrorNumber.ReadOnly;
|
||||
}
|
||||
|
||||
bool foundRom = false;
|
||||
bool foundChrRom = false;
|
||||
bool foundInstRom = false;
|
||||
bool foundProm = false;
|
||||
bool foundRam = false;
|
||||
bool foundChrRam = false;
|
||||
bool foundNvram = false;
|
||||
bool foundChrNvram = false;
|
||||
bool foundMapper = false;
|
||||
bool foundSubMapper = false;
|
||||
var foundRom = false;
|
||||
var foundChrRom = false;
|
||||
var foundInstRom = false;
|
||||
var foundProm = false;
|
||||
var foundRam = false;
|
||||
var foundChrRam = false;
|
||||
var foundNvram = false;
|
||||
var foundChrNvram = false;
|
||||
var foundMapper = false;
|
||||
var foundSubMapper = false;
|
||||
|
||||
Regex regex;
|
||||
Match match;
|
||||
|
||||
// Sanitize
|
||||
foreach(LinearMemoryDevice map in mappings.Devices)
|
||||
{
|
||||
switch(map.Type)
|
||||
{
|
||||
case LinearMemoryType.ROM when !foundRom:
|
||||
@@ -730,6 +761,7 @@ public class Nes : IByteAddressableImage
|
||||
match = regex.Match(map.Description);
|
||||
|
||||
if(match.Success)
|
||||
{
|
||||
if(ushort.TryParse(match.Groups["mapper"].Value, out ushort mapper))
|
||||
{
|
||||
if(_nesHeaderInfo is null)
|
||||
@@ -739,6 +771,7 @@ public class Nes : IByteAddressableImage
|
||||
|
||||
foundMapper = true;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case LinearMemoryType.Mapper when !foundSubMapper:
|
||||
@@ -746,6 +779,7 @@ public class Nes : IByteAddressableImage
|
||||
match = regex.Match(map.Description);
|
||||
|
||||
if(match.Success)
|
||||
{
|
||||
if(byte.TryParse(match.Groups["mapper"].Value, out byte mapper))
|
||||
{
|
||||
if(_nesHeaderInfo is null)
|
||||
@@ -755,10 +789,13 @@ public class Nes : IByteAddressableImage
|
||||
|
||||
foundSubMapper = true;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
default: return ErrorNumber.InvalidArgument;
|
||||
default:
|
||||
return ErrorNumber.InvalidArgument;
|
||||
}
|
||||
}
|
||||
|
||||
return foundRom && foundMapper ? ErrorNumber.NoError : ErrorNumber.InvalidArgument;
|
||||
}
|
||||
@@ -800,7 +837,7 @@ public class Nes : IByteAddressableImage
|
||||
|
||||
/// <inheritdoc />
|
||||
public ErrorNumber WriteBytes(byte[] buffer, int offset, int bytesToWrite, out int bytesWritten,
|
||||
bool advance = true) =>
|
||||
bool advance = true) =>
|
||||
WriteBytesAt(Position, buffer, offset, bytesToWrite, out bytesWritten, advance);
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -852,4 +889,6 @@ public class Nes : IByteAddressableImage
|
||||
|
||||
return ErrorNumber.NoError;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -56,22 +56,31 @@ public class Nintendo64 : IByteAddressableImage
|
||||
bool _interleaved;
|
||||
bool _littleEndian;
|
||||
bool _opened;
|
||||
|
||||
#region IByteAddressableImage Members
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Author => Authors.NataliaPortillo;
|
||||
|
||||
/// <inheritdoc />
|
||||
public Metadata AaruMetadata => null;
|
||||
|
||||
/// <inheritdoc />
|
||||
public List<DumpHardware> DumpHardware => null;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Format => !_opened
|
||||
? "Nintendo 64 cartridge dump"
|
||||
: _interleaved
|
||||
? "Doctor V64"
|
||||
: "Mr. Backup Z64";
|
||||
|
||||
/// <inheritdoc />
|
||||
public Guid Id => new("EF1B4319-48A0-4EEC-B8E8-D0EA36F8CC92");
|
||||
|
||||
/// <inheritdoc />
|
||||
public ImageInfo Info => _imageInfo;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Name => Localization.Nintendo64_Name;
|
||||
|
||||
@@ -88,9 +97,9 @@ public class Nintendo64 : IByteAddressableImage
|
||||
return false;
|
||||
|
||||
stream.Position = 0;
|
||||
byte[] magicBytes = new byte[4];
|
||||
var magicBytes = new byte[4];
|
||||
stream.EnsureRead(magicBytes, 0, 4);
|
||||
uint magic = BitConverter.ToUInt32(magicBytes, 0);
|
||||
var magic = BitConverter.ToUInt32(magicBytes, 0);
|
||||
|
||||
switch(magic)
|
||||
{
|
||||
@@ -101,8 +110,10 @@ public class Nintendo64 : IByteAddressableImage
|
||||
case 0x12408037:
|
||||
case 0x12418037:
|
||||
case 0x37804012:
|
||||
case 0x37804112: return true;
|
||||
default: return false;
|
||||
case 0x37804112:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,9 +130,9 @@ public class Nintendo64 : IByteAddressableImage
|
||||
return ErrorNumber.InvalidArgument;
|
||||
|
||||
stream.Position = 0;
|
||||
byte[] magicBytes = new byte[4];
|
||||
var magicBytes = new byte[4];
|
||||
stream.EnsureRead(magicBytes, 0, 4);
|
||||
uint magic = BitConverter.ToUInt32(magicBytes, 0);
|
||||
var magic = BitConverter.ToUInt32(magicBytes, 0);
|
||||
|
||||
switch(magic)
|
||||
{
|
||||
@@ -149,7 +160,8 @@ public class Nintendo64 : IByteAddressableImage
|
||||
_littleEndian = false;
|
||||
|
||||
break;
|
||||
default: return ErrorNumber.InvalidArgument;
|
||||
default:
|
||||
return ErrorNumber.InvalidArgument;
|
||||
}
|
||||
|
||||
_data = new byte[imageFilter.DataForkLength];
|
||||
@@ -169,9 +181,9 @@ public class Nintendo64 : IByteAddressableImage
|
||||
|
||||
if(_littleEndian)
|
||||
{
|
||||
byte[] tmp = new byte[_data.Length];
|
||||
var tmp = new byte[_data.Length];
|
||||
|
||||
for(int i = 0; i < _data.Length; i += 4)
|
||||
for(var i = 0; i < _data.Length; i += 4)
|
||||
{
|
||||
tmp[i] = _data[i + 3];
|
||||
tmp[i + 1] = _data[i + 2];
|
||||
@@ -184,9 +196,9 @@ public class Nintendo64 : IByteAddressableImage
|
||||
|
||||
if(_interleaved)
|
||||
{
|
||||
byte[] tmp = new byte[_data.Length];
|
||||
var tmp = new byte[_data.Length];
|
||||
|
||||
for(int i = 0; i < _data.Length; i += 2)
|
||||
for(var i = 0; i < _data.Length; i += 2)
|
||||
{
|
||||
tmp[i] = _data[i + 1];
|
||||
tmp[i + 1] = _data[i];
|
||||
@@ -208,17 +220,17 @@ public class Nintendo64 : IByteAddressableImage
|
||||
}
|
||||
|
||||
_imageInfo.MediaPartNumber = StringHandlers.SpacePaddedToString(header.CartridgeId, encoding);
|
||||
_imageInfo.MediaTitle = StringHandlers.SpacePaddedToString(header.Name, encoding);
|
||||
_imageInfo.MediaTitle = StringHandlers.SpacePaddedToString(header.Name, encoding);
|
||||
|
||||
var sb = new StringBuilder();
|
||||
|
||||
sb.AppendFormat(Localization.Name_0, _imageInfo.MediaTitle).AppendLine();
|
||||
sb.AppendFormat(Localization.Region_0, DecodeCountryCode(header.CountryCode)).AppendLine();
|
||||
sb.AppendFormat(Localization.Cartridge_ID_0, _imageInfo.MediaPartNumber).AppendLine();
|
||||
sb.AppendFormat(Localization.Name_0, _imageInfo.MediaTitle).AppendLine();
|
||||
sb.AppendFormat(Localization.Region_0, DecodeCountryCode(header.CountryCode)).AppendLine();
|
||||
sb.AppendFormat(Localization.Cartridge_ID_0, _imageInfo.MediaPartNumber).AppendLine();
|
||||
sb.AppendFormat(Localization.Cartridge_type_0, (char)header.CartridgeType).AppendLine();
|
||||
sb.AppendFormat(Localization.Version_0_1, (header.Version / 10) + 1, header.Version % 10).AppendLine();
|
||||
sb.AppendFormat(Localization.CRC1_0, header.Crc1).AppendLine();
|
||||
sb.AppendFormat(Localization.CRC2_0, header.Crc2).AppendLine();
|
||||
sb.AppendFormat(Localization.Version_0_1, header.Version / 10 + 1, header.Version % 10).AppendLine();
|
||||
sb.AppendFormat(Localization.CRC1_0, header.Crc1).AppendLine();
|
||||
sb.AppendFormat(Localization.CRC2_0, header.Crc2).AppendLine();
|
||||
|
||||
_imageInfo.Comments = sb.ToString();
|
||||
_opened = true;
|
||||
@@ -669,11 +681,12 @@ public class Nintendo64 : IByteAddressableImage
|
||||
return ErrorNumber.ReadOnly;
|
||||
}
|
||||
|
||||
bool foundRom = false;
|
||||
bool foundSaveRam = false;
|
||||
var foundRom = false;
|
||||
var foundSaveRam = false;
|
||||
|
||||
// Sanitize
|
||||
foreach(LinearMemoryDevice map in mappings.Devices)
|
||||
{
|
||||
switch(map.Type)
|
||||
{
|
||||
case LinearMemoryType.ROM when !foundRom:
|
||||
@@ -686,8 +699,10 @@ public class Nintendo64 : IByteAddressableImage
|
||||
foundSaveRam = true;
|
||||
|
||||
break;
|
||||
default: return ErrorNumber.InvalidArgument;
|
||||
default:
|
||||
return ErrorNumber.InvalidArgument;
|
||||
}
|
||||
}
|
||||
|
||||
// Cannot save in this image format anyway
|
||||
return foundRom ? ErrorNumber.NoError : ErrorNumber.InvalidArgument;
|
||||
@@ -730,7 +745,7 @@ public class Nintendo64 : IByteAddressableImage
|
||||
|
||||
/// <inheritdoc />
|
||||
public ErrorNumber WriteBytes(byte[] buffer, int offset, int bytesToWrite, out int bytesWritten,
|
||||
bool advance = true) =>
|
||||
bool advance = true) =>
|
||||
WriteBytesAt(Position, buffer, offset, bytesToWrite, out bytesWritten, advance);
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -785,29 +800,29 @@ public class Nintendo64 : IByteAddressableImage
|
||||
|
||||
/// <inheritdoc />
|
||||
public string ErrorMessage { get; private set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsWriting { get; private set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<string> KnownExtensions => new[]
|
||||
{
|
||||
".n64", ".v64", ".z64"
|
||||
};
|
||||
public IEnumerable<string> KnownExtensions => new[] { ".n64", ".v64", ".z64" };
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<MediaTagType> SupportedMediaTags => Array.Empty<MediaTagType>();
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<MediaType> SupportedMediaTypes => new[]
|
||||
{
|
||||
MediaType.N64GamePak
|
||||
};
|
||||
public IEnumerable<MediaType> SupportedMediaTypes => new[] { MediaType.N64GamePak };
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<(string name, Type type, string description, object @default)> SupportedOptions =>
|
||||
Array.Empty<(string name, Type type, string description, object @default)>();
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<SectorTagType> SupportedSectorTags => Array.Empty<SectorTagType>();
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Create(string path, MediaType mediaType, Dictionary<string, string> options, ulong sectors,
|
||||
uint sectorSize) => Create(path, mediaType, options, (long)sectors) == ErrorNumber.NoError;
|
||||
uint sectorSize) => Create(path, mediaType, options, (long)sectors) == ErrorNumber.NoError;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Close()
|
||||
@@ -828,9 +843,9 @@ public class Nintendo64 : IByteAddressableImage
|
||||
|
||||
if(_interleaved)
|
||||
{
|
||||
byte[] tmp = new byte[_data.Length];
|
||||
var tmp = new byte[_data.Length];
|
||||
|
||||
for(int i = 0; i < _data.Length; i += 2)
|
||||
for(var i = 0; i < _data.Length; i += 2)
|
||||
{
|
||||
tmp[i] = _data[i + 1];
|
||||
tmp[i + 1] = _data[i];
|
||||
@@ -858,32 +873,37 @@ public class Nintendo64 : IByteAddressableImage
|
||||
/// <inheritdoc />
|
||||
public bool SetImageInfo(ImageInfo imageInfo) => true;
|
||||
|
||||
static string DecodeCountryCode(byte countryCode) => countryCode switch
|
||||
{
|
||||
0x37 => Localization.Beta,
|
||||
0x41 => Localization.Asia_NTSC,
|
||||
0x42 => Localization.Brazil,
|
||||
0x43 => Localization.China,
|
||||
0x44 => Localization.Germany,
|
||||
0x45 => Localization.North_America,
|
||||
0x46 => Localization.France,
|
||||
0x47 => Localization.Gateway_64_NTSC,
|
||||
0x48 => Localization.Netherlands,
|
||||
0x49 => Localization.Italy,
|
||||
0x4A => Localization.Japan,
|
||||
0x4B => Localization.Korea,
|
||||
0x4C => Localization.Gateway_64_PAL,
|
||||
0x4E => Localization.Canada,
|
||||
0x50 => Localization.Europe,
|
||||
0x53 => Localization.Spain,
|
||||
0x55 => Localization.Australia,
|
||||
0x57 => Localization.Scandinavia,
|
||||
0x58 => Localization.Europe,
|
||||
0x59 => Localization.Europe,
|
||||
_ => Localization.Unknown_country
|
||||
};
|
||||
#endregion
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1), SuppressMessage("ReSharper", "MemberCanBePrivate.Local")]
|
||||
static string DecodeCountryCode(byte countryCode) => countryCode switch
|
||||
{
|
||||
0x37 => Localization.Beta,
|
||||
0x41 => Localization.Asia_NTSC,
|
||||
0x42 => Localization.Brazil,
|
||||
0x43 => Localization.China,
|
||||
0x44 => Localization.Germany,
|
||||
0x45 => Localization.North_America,
|
||||
0x46 => Localization.France,
|
||||
0x47 => Localization.Gateway_64_NTSC,
|
||||
0x48 => Localization.Netherlands,
|
||||
0x49 => Localization.Italy,
|
||||
0x4A => Localization.Japan,
|
||||
0x4B => Localization.Korea,
|
||||
0x4C => Localization.Gateway_64_PAL,
|
||||
0x4E => Localization.Canada,
|
||||
0x50 => Localization.Europe,
|
||||
0x53 => Localization.Spain,
|
||||
0x55 => Localization.Australia,
|
||||
0x57 => Localization.Scandinavia,
|
||||
0x58 => Localization.Europe,
|
||||
0x59 => Localization.Europe,
|
||||
_ => Localization.Unknown_country
|
||||
};
|
||||
|
||||
#region Nested type: Header
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
[SuppressMessage("ReSharper", "MemberCanBePrivate.Local")]
|
||||
struct Header
|
||||
{
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
|
||||
@@ -908,4 +928,6 @@ public class Nintendo64 : IByteAddressableImage
|
||||
public readonly byte CountryCode;
|
||||
public readonly byte Version;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -57,12 +57,17 @@ public class SegaMegaDrive : IByteAddressableImage
|
||||
bool _opened;
|
||||
bool _smd;
|
||||
|
||||
#region IByteAddressableImage Members
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Author => Authors.NataliaPortillo;
|
||||
|
||||
/// <inheritdoc />
|
||||
public Metadata AaruMetadata => null;
|
||||
|
||||
/// <inheritdoc />
|
||||
public List<DumpHardware> DumpHardware => null;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Format => !_opened
|
||||
? "Mega Drive cartridge dump"
|
||||
@@ -71,10 +76,13 @@ public class SegaMegaDrive : IByteAddressableImage
|
||||
: _interleaved
|
||||
? "Multi Game Doctor 2"
|
||||
: "Magicom";
|
||||
|
||||
/// <inheritdoc />
|
||||
public Guid Id => new("7B1CE2E7-3BC4-4283-BFA4-F292D646DF15");
|
||||
|
||||
/// <inheritdoc />
|
||||
public ImageInfo Info => _imageInfo;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Name => Localization.SegaMegaDrive_Name;
|
||||
|
||||
@@ -90,7 +98,7 @@ public class SegaMegaDrive : IByteAddressableImage
|
||||
if(stream.Length % 512 != 0)
|
||||
return false;
|
||||
|
||||
byte[] buffer = new byte[4];
|
||||
var buffer = new byte[4];
|
||||
|
||||
stream.Position = 256;
|
||||
stream.EnsureRead(buffer, 0, 4);
|
||||
@@ -106,7 +114,7 @@ public class SegaMegaDrive : IByteAddressableImage
|
||||
if(buffer[0] == 0x45 &&
|
||||
buffer[1] == 0x41)
|
||||
{
|
||||
stream.Position = (stream.Length / 2) + 256;
|
||||
stream.Position = stream.Length / 2 + 256;
|
||||
stream.EnsureRead(buffer, 0, 2);
|
||||
|
||||
// SG
|
||||
@@ -142,7 +150,7 @@ public class SegaMegaDrive : IByteAddressableImage
|
||||
if(stream.Length % 512 != 0)
|
||||
return ErrorNumber.InvalidArgument;
|
||||
|
||||
byte[] buffer = new byte[4];
|
||||
var buffer = new byte[4];
|
||||
|
||||
stream.Position = 256;
|
||||
stream.EnsureRead(buffer, 0, 4);
|
||||
@@ -154,7 +162,7 @@ public class SegaMegaDrive : IByteAddressableImage
|
||||
if(buffer[0] == 0x45 &&
|
||||
buffer[1] == 0x41)
|
||||
{
|
||||
stream.Position = (stream.Length / 2) + 256;
|
||||
stream.Position = stream.Length / 2 + 256;
|
||||
stream.EnsureRead(buffer, 0, 2);
|
||||
|
||||
// SG
|
||||
@@ -195,18 +203,18 @@ public class SegaMegaDrive : IByteAddressableImage
|
||||
// Interleaves every 16KiB
|
||||
if(_smd)
|
||||
{
|
||||
byte[] tmp = new byte[_data.Length];
|
||||
byte[] bankIn = new byte[16384];
|
||||
byte[] bankOut = new byte[16384];
|
||||
var tmp = new byte[_data.Length];
|
||||
var bankIn = new byte[16384];
|
||||
var bankOut = new byte[16384];
|
||||
|
||||
for(int b = 0; b < _data.Length / 16384; b++)
|
||||
for(var b = 0; b < _data.Length / 16384; b++)
|
||||
{
|
||||
Array.Copy(_data, b * 16384, bankIn, 0, 16384);
|
||||
|
||||
for(int i = 0; i < 8192; i++)
|
||||
for(var i = 0; i < 8192; i++)
|
||||
{
|
||||
bankOut[(i * 2) + 1] = bankIn[i];
|
||||
bankOut[i * 2] = bankIn[i + 8192];
|
||||
bankOut[i * 2 + 1] = bankIn[i];
|
||||
bankOut[i * 2] = bankIn[i + 8192];
|
||||
}
|
||||
|
||||
Array.Copy(bankOut, 0, tmp, b * 16384, 16384);
|
||||
@@ -216,13 +224,13 @@ public class SegaMegaDrive : IByteAddressableImage
|
||||
}
|
||||
else if(_interleaved)
|
||||
{
|
||||
byte[] tmp = new byte[_data.Length];
|
||||
int half = _data.Length / 2;
|
||||
var tmp = new byte[_data.Length];
|
||||
int half = _data.Length / 2;
|
||||
|
||||
for(int i = 0; i < half; i++)
|
||||
for(var i = 0; i < half; i++)
|
||||
{
|
||||
tmp[i * 2] = _data[i];
|
||||
tmp[(i * 2) + 1] = _data[i + half];
|
||||
tmp[i * 2] = _data[i];
|
||||
tmp[i * 2 + 1] = _data[i + half];
|
||||
}
|
||||
|
||||
_data = tmp;
|
||||
@@ -310,7 +318,8 @@ public class SegaMegaDrive : IByteAddressableImage
|
||||
|
||||
sb.AppendFormat(Localization.Extra_RAM_starts_at_0_and_ends_at_1_2_bytes, header.ExtraRamStart,
|
||||
header.ExtraRamEnd,
|
||||
(header.ExtraRamType & 0x10) == 0x10 ? (header.ExtraRamEnd - header.ExtraRamStart + 2) / 2
|
||||
(header.ExtraRamType & 0x10) == 0x10
|
||||
? (header.ExtraRamEnd - header.ExtraRamStart + 2) / 2
|
||||
: header.ExtraRamEnd - header.ExtraRamStart + 1).AppendLine();
|
||||
}
|
||||
else
|
||||
@@ -327,15 +336,15 @@ public class SegaMegaDrive : IByteAddressableImage
|
||||
_imageInfo.ImageSize = (ulong)stream.Length;
|
||||
_imageInfo.LastModificationTime = imageFilter.LastWriteTime;
|
||||
_imageInfo.CreationTime = imageFilter.CreationTime;
|
||||
_imageInfo.MediaPartNumber = StringHandlers.SpacePaddedToString(header.SerialNumber, encoding);
|
||||
_imageInfo.MediaPartNumber = StringHandlers.SpacePaddedToString(header.SerialNumber, encoding);
|
||||
_imageInfo.MediaTitle = StringHandlers.SpacePaddedToString(header.DomesticTitle, encoding);
|
||||
|
||||
_imageInfo.MediaType = StringHandlers.SpacePaddedToString(header.SystemType, encoding) switch
|
||||
{
|
||||
"SEGA 32X" => MediaType._32XCartridge,
|
||||
"SEGA PICO" => MediaType.SegaPicoCartridge,
|
||||
_ => MediaType.MegaDriveCartridge
|
||||
};
|
||||
{
|
||||
"SEGA 32X" => MediaType._32XCartridge,
|
||||
"SEGA PICO" => MediaType.SegaPicoCartridge,
|
||||
_ => MediaType.MegaDriveCartridge
|
||||
};
|
||||
|
||||
_imageInfo.Sectors = (ulong)_data.Length;
|
||||
_imageInfo.MetadataMediaType = MetadataMediaType.LinearMedia;
|
||||
@@ -348,29 +357,32 @@ public class SegaMegaDrive : IByteAddressableImage
|
||||
|
||||
/// <inheritdoc />
|
||||
public string ErrorMessage { get; private set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsWriting { get; private set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<string> KnownExtensions => new[]
|
||||
{
|
||||
".smd", ".md", ".32x"
|
||||
};
|
||||
public IEnumerable<string> KnownExtensions => new[] { ".smd", ".md", ".32x" };
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<MediaTagType> SupportedMediaTags => Array.Empty<MediaTagType>();
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<MediaType> SupportedMediaTypes => new[]
|
||||
{
|
||||
MediaType._32XCartridge, MediaType.MegaDriveCartridge, MediaType.SegaPicoCartridge
|
||||
};
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<(string name, Type type, string description, object @default)> SupportedOptions =>
|
||||
Array.Empty<(string name, Type type, string description, object @default)>();
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<SectorTagType> SupportedSectorTags => Array.Empty<SectorTagType>();
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Create(string path, MediaType mediaType, Dictionary<string, string> options, ulong sectors,
|
||||
uint sectorSize) => Create(path, mediaType, options, (long)sectors) == ErrorNumber.NoError;
|
||||
uint sectorSize) => Create(path, mediaType, options, (long)sectors) == ErrorNumber.NoError;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Close()
|
||||
@@ -391,13 +403,13 @@ public class SegaMegaDrive : IByteAddressableImage
|
||||
|
||||
if(_interleaved)
|
||||
{
|
||||
byte[] tmp = new byte[_data.Length];
|
||||
int half = _data.Length / 2;
|
||||
var tmp = new byte[_data.Length];
|
||||
int half = _data.Length / 2;
|
||||
|
||||
for(int i = 0; i < half; i++)
|
||||
for(var i = 0; i < half; i++)
|
||||
{
|
||||
tmp[i] = _data[i * 2];
|
||||
tmp[i + half] = _data[(i * 2) + 1];
|
||||
tmp[i + half] = _data[i * 2 + 1];
|
||||
}
|
||||
|
||||
_data = tmp;
|
||||
@@ -419,18 +431,18 @@ public class SegaMegaDrive : IByteAddressableImage
|
||||
|
||||
_dataStream.Write(smdHeader, 0, smdHeader.Length);
|
||||
|
||||
byte[] tmp = new byte[_data.Length];
|
||||
byte[] bankIn = new byte[16384];
|
||||
byte[] bankOut = new byte[16384];
|
||||
var tmp = new byte[_data.Length];
|
||||
var bankIn = new byte[16384];
|
||||
var bankOut = new byte[16384];
|
||||
|
||||
for(int b = 0; b < _data.Length / 16384; b++)
|
||||
for(var b = 0; b < _data.Length / 16384; b++)
|
||||
{
|
||||
Array.Copy(_data, b * 16384, bankIn, 0, 16384);
|
||||
|
||||
for(int i = 0; i < 8192; i++)
|
||||
for(var i = 0; i < 8192; i++)
|
||||
{
|
||||
bankOut[i] = bankIn[(i * 2) + 1];
|
||||
bankOut[i + 8192] = bankIn[i * 2];
|
||||
bankOut[i] = bankIn[i * 2 + 1];
|
||||
bankOut[i + 8192] = bankIn[i * 2];
|
||||
}
|
||||
|
||||
Array.Copy(bankOut, 0, tmp, b * 16384, 16384);
|
||||
@@ -723,11 +735,12 @@ public class SegaMegaDrive : IByteAddressableImage
|
||||
return ErrorNumber.ReadOnly;
|
||||
}
|
||||
|
||||
bool foundRom = false;
|
||||
bool foundSaveRam = false;
|
||||
var foundRom = false;
|
||||
var foundSaveRam = false;
|
||||
|
||||
// Sanitize
|
||||
foreach(LinearMemoryDevice map in mappings.Devices)
|
||||
{
|
||||
switch(map.Type)
|
||||
{
|
||||
case LinearMemoryType.ROM when !foundRom:
|
||||
@@ -738,8 +751,10 @@ public class SegaMegaDrive : IByteAddressableImage
|
||||
foundSaveRam = true;
|
||||
|
||||
break;
|
||||
default: return ErrorNumber.InvalidArgument;
|
||||
default:
|
||||
return ErrorNumber.InvalidArgument;
|
||||
}
|
||||
}
|
||||
|
||||
// Cannot save in this image format anyway
|
||||
return foundRom ? ErrorNumber.NoError : ErrorNumber.InvalidArgument;
|
||||
@@ -782,7 +797,7 @@ public class SegaMegaDrive : IByteAddressableImage
|
||||
|
||||
/// <inheritdoc />
|
||||
public ErrorNumber WriteBytes(byte[] buffer, int offset, int bytesToWrite, out int bytesWritten,
|
||||
bool advance = true) =>
|
||||
bool advance = true) =>
|
||||
WriteBytesAt(Position, buffer, offset, bytesToWrite, out bytesWritten, advance);
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -835,8 +850,13 @@ public class SegaMegaDrive : IByteAddressableImage
|
||||
return ErrorNumber.NoError;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1), SuppressMessage("ReSharper", "MemberCanBePrivate.Local"),
|
||||
SuppressMessage("ReSharper", "FieldCanBeMadeReadOnly.Local")]
|
||||
#endregion
|
||||
|
||||
#region Nested type: SegaHeader
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
[SuppressMessage("ReSharper", "MemberCanBePrivate.Local")]
|
||||
[SuppressMessage("ReSharper", "FieldCanBeMadeReadOnly.Local")]
|
||||
struct SegaHeader
|
||||
{
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 15)]
|
||||
@@ -873,8 +893,13 @@ public class SegaMegaDrive : IByteAddressableImage
|
||||
public byte[] Padding3;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1), SuppressMessage("ReSharper", "MemberCanBePrivate.Local"),
|
||||
SuppressMessage("ReSharper", "FieldCanBeMadeReadOnly.Local")]
|
||||
#endregion
|
||||
|
||||
#region Nested type: SuperMagicDriveHeader
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
[SuppressMessage("ReSharper", "MemberCanBePrivate.Local")]
|
||||
[SuppressMessage("ReSharper", "FieldCanBeMadeReadOnly.Local")]
|
||||
struct SuperMagicDriveHeader
|
||||
{
|
||||
/// <summary>16 KiB pages</summary>
|
||||
@@ -894,4 +919,6 @@ public class SegaMegaDrive : IByteAddressableImage
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 501)]
|
||||
public byte[] Empty;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user