Files
Aaru/Aaru.Images/CHD/Read.cs

2038 lines
86 KiB
C#
Raw Normal View History

// /***************************************************************************
2020-02-27 12:31:25 +00:00
// Aaru Data Preservation Suite
// ----------------------------------------------------------------------------
//
// Filename : Read.cs
// Author(s) : Natalia Portillo <claunia@claunia.com>
//
// Component : Disk image plugins.
//
// --[ Description ] ----------------------------------------------------------
//
// Reads MAME Compressed Hunks of Data disk images.
//
// --[ License ] --------------------------------------------------------------
//
// This library is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation; either version 2.1 of the
// License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
//
// ----------------------------------------------------------------------------
2024-05-01 04:17:32 +01:00
// Copyright © 2011-2024 Natalia Portillo
// ****************************************************************************/
using System;
using System.Collections.Generic;
using System.Diagnostics;
2020-07-20 07:47:12 +01:00
using System.Diagnostics.CodeAnalysis;
using System.IO;
2016-10-17 04:41:27 +01:00
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
2020-02-27 00:33:26 +00:00
using Aaru.CommonTypes;
using Aaru.CommonTypes.Enums;
using Aaru.CommonTypes.Interfaces;
using Aaru.CommonTypes.Structs;
using Aaru.CommonTypes.Structs.Devices.ATA;
using Aaru.Console;
using Aaru.Decoders.CD;
using Aaru.Helpers;
using Session = Aaru.CommonTypes.Structs.Session;
namespace Aaru.Images;
2022-03-06 13:29:38 +00:00
public sealed partial class Chd
{
2023-10-03 23:34:59 +01:00
#region IOpticalMediaImage Members
2022-03-06 13:29:38 +00:00
/// <inheritdoc />
[SuppressMessage("ReSharper", "UnusedVariable")]
public ErrorNumber Open(IFilter imageFilter)
2017-12-19 20:33:03 +00:00
{
2022-03-06 13:29:38 +00:00
Stream stream = imageFilter.GetDataForkStream();
stream.Seek(0, SeekOrigin.Begin);
2023-10-03 23:34:59 +01:00
var magic = new byte[8];
stream.EnsureRead(magic, 0, 8);
2024-05-01 04:05:22 +01:00
if(!_chdTag.SequenceEqual(magic)) return ErrorNumber.InvalidArgument;
2022-03-06 13:29:38 +00:00
// Read length
2023-10-03 23:34:59 +01:00
var buffer = new byte[4];
stream.EnsureRead(buffer, 0, 4);
2023-10-03 23:34:59 +01:00
var length = BitConverter.ToUInt32(buffer.Reverse().ToArray(), 0);
2022-03-06 13:29:38 +00:00
buffer = new byte[4];
stream.EnsureRead(buffer, 0, 4);
2023-10-03 23:34:59 +01:00
var version = BitConverter.ToUInt32(buffer.Reverse().ToArray(), 0);
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
buffer = new byte[length];
stream.Seek(0, SeekOrigin.Begin);
stream.EnsureRead(buffer, 0, (int)length);
2017-12-19 20:33:03 +00:00
ulong nextMetaOff = 0;
var hunkMapStopwatch = new Stopwatch();
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
switch(version)
{
case 1:
2017-12-19 20:33:03 +00:00
{
2022-03-06 13:29:38 +00:00
HeaderV1 hdrV1 = Marshal.ByteArrayToStructureBigEndian<HeaderV1>(buffer);
AaruConsole.DebugWriteLine(MODULE_NAME, "hdrV1.tag = \"{0}\"", Encoding.ASCII.GetString(hdrV1.tag));
2017-12-19 20:33:03 +00:00
AaruConsole.DebugWriteLine(MODULE_NAME, "hdrV1.length = {0} bytes", hdrV1.length);
2023-10-03 23:34:59 +01:00
AaruConsole.DebugWriteLine(MODULE_NAME, "hdrV1.version = {0}", hdrV1.version);
AaruConsole.DebugWriteLine(MODULE_NAME, "hdrV1.flags = {0}", (Flags)hdrV1.flags);
2017-12-19 20:33:03 +00:00
AaruConsole.DebugWriteLine(MODULE_NAME, "hdrV1.compression = {0}", (Compression)hdrV1.compression);
2017-12-19 20:33:03 +00:00
AaruConsole.DebugWriteLine(MODULE_NAME, "hdrV1.hunksize = {0}", hdrV1.hunksize);
AaruConsole.DebugWriteLine(MODULE_NAME, "hdrV1.totalhunks = {0}", hdrV1.totalhunks);
AaruConsole.DebugWriteLine(MODULE_NAME, "hdrV1.cylinders = {0}", hdrV1.cylinders);
AaruConsole.DebugWriteLine(MODULE_NAME, "hdrV1.heads = {0}", hdrV1.heads);
AaruConsole.DebugWriteLine(MODULE_NAME, "hdrV1.sectors = {0}", hdrV1.sectors);
AaruConsole.DebugWriteLine(MODULE_NAME, "hdrV1.md5 = {0}", ArrayHelpers.ByteArrayToHex(hdrV1.md5));
2017-12-19 20:33:03 +00:00
2024-05-01 04:05:22 +01:00
AaruConsole.DebugWriteLine(MODULE_NAME,
"hdrV1.parentmd5 = {0}",
2023-10-03 23:34:59 +01:00
ArrayHelpers.ArrayIsNullOrEmpty(hdrV1.parentmd5)
? "null"
2022-03-06 13:29:38 +00:00
: ArrayHelpers.ByteArrayToHex(hdrV1.parentmd5));
AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Reading_Hunk_map);
hunkMapStopwatch.Restart();
2022-03-06 13:29:38 +00:00
_hunkTable = new ulong[hdrV1.totalhunks];
2023-10-03 23:34:59 +01:00
var hunkSectorCount = (uint)Math.Ceiling((double)hdrV1.totalhunks * 8 / 512);
2017-12-19 20:33:03 +00:00
2023-10-03 23:34:59 +01:00
var hunkSectorBytes = new byte[512];
2017-12-19 20:33:03 +00:00
2023-10-03 23:34:59 +01:00
for(var i = 0; i < hunkSectorCount; i++)
2022-03-06 13:29:38 +00:00
{
stream.EnsureRead(hunkSectorBytes, 0, 512);
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
// This does the big-endian trick but reverses the order of elements also
Array.Reverse(hunkSectorBytes);
HunkSector hunkSector = Marshal.ByteArrayToStructureLittleEndian<HunkSector>(hunkSectorBytes);
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
// This restores the order of elements
Array.Reverse(hunkSector.hunkEntry);
2017-12-19 20:33:03 +00:00
2023-10-03 23:34:59 +01:00
if(_hunkTable.Length >= i * 512 / 8 + 512 / 8)
2022-03-06 13:29:38 +00:00
Array.Copy(hunkSector.hunkEntry, 0, _hunkTable, i * 512 / 8, 512 / 8);
else
2023-10-03 23:34:59 +01:00
Array.Copy(hunkSector.hunkEntry, 0, _hunkTable, i * 512 / 8, _hunkTable.Length - i * 512 / 8);
2017-12-19 20:33:03 +00:00
}
hunkMapStopwatch.Stop();
2024-05-01 04:05:22 +01:00
AaruConsole.DebugWriteLine(MODULE_NAME,
Localization.Took_0_seconds,
hunkMapStopwatch.Elapsed.TotalSeconds);
2017-12-19 20:33:03 +00:00
_imageInfo.MediaType = MediaType.GENERIC_HDD;
_imageInfo.Sectors = hdrV1.hunksize * hdrV1.totalhunks;
_imageInfo.MetadataMediaType = MetadataMediaType.BlockMedia;
_imageInfo.SectorSize = 512;
_imageInfo.Version = "1";
_imageInfo.ImageSize = _imageInfo.SectorSize * hdrV1.hunksize * hdrV1.totalhunks;
2020-02-29 18:03:35 +00:00
2022-03-06 13:29:38 +00:00
_totalHunks = hdrV1.totalhunks;
_sectorsPerHunk = hdrV1.hunksize;
_hdrCompression = hdrV1.compression;
_mapVersion = 1;
_isHdd = true;
2022-03-06 13:29:38 +00:00
_imageInfo.Cylinders = hdrV1.cylinders;
_imageInfo.Heads = hdrV1.heads;
_imageInfo.SectorsPerTrack = hdrV1.sectors;
2022-03-06 13:29:38 +00:00
break;
}
2022-03-06 13:29:38 +00:00
case 2:
{
HeaderV2 hdrV2 = Marshal.ByteArrayToStructureBigEndian<HeaderV2>(buffer);
AaruConsole.DebugWriteLine(MODULE_NAME, "hdrV2.tag = \"{0}\"", Encoding.ASCII.GetString(hdrV2.tag));
2017-12-19 20:33:03 +00:00
AaruConsole.DebugWriteLine(MODULE_NAME, "hdrV2.length = {0} bytes", hdrV2.length);
2023-10-03 23:34:59 +01:00
AaruConsole.DebugWriteLine(MODULE_NAME, "hdrV2.version = {0}", hdrV2.version);
AaruConsole.DebugWriteLine(MODULE_NAME, "hdrV2.flags = {0}", (Flags)hdrV2.flags);
2017-12-19 20:33:03 +00:00
AaruConsole.DebugWriteLine(MODULE_NAME, "hdrV2.compression = {0}", (Compression)hdrV2.compression);
2017-12-19 20:33:03 +00:00
AaruConsole.DebugWriteLine(MODULE_NAME, "hdrV2.hunksize = {0}", hdrV2.hunksize);
AaruConsole.DebugWriteLine(MODULE_NAME, "hdrV2.totalhunks = {0}", hdrV2.totalhunks);
AaruConsole.DebugWriteLine(MODULE_NAME, "hdrV2.cylinders = {0}", hdrV2.cylinders);
AaruConsole.DebugWriteLine(MODULE_NAME, "hdrV2.heads = {0}", hdrV2.heads);
AaruConsole.DebugWriteLine(MODULE_NAME, "hdrV2.sectors = {0}", hdrV2.sectors);
AaruConsole.DebugWriteLine(MODULE_NAME, "hdrV2.md5 = {0}", ArrayHelpers.ByteArrayToHex(hdrV2.md5));
2017-12-19 20:33:03 +00:00
2024-05-01 04:05:22 +01:00
AaruConsole.DebugWriteLine(MODULE_NAME,
"hdrV2.parentmd5 = {0}",
2023-10-03 23:34:59 +01:00
ArrayHelpers.ArrayIsNullOrEmpty(hdrV2.parentmd5)
? "null"
2022-03-06 13:29:38 +00:00
: ArrayHelpers.ByteArrayToHex(hdrV2.parentmd5));
2017-12-19 20:33:03 +00:00
AaruConsole.DebugWriteLine(MODULE_NAME, "hdrV2.seclen = {0}", hdrV2.seclen);
AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Reading_Hunk_map);
hunkMapStopwatch.Restart();
2022-03-06 13:29:38 +00:00
_hunkTable = new ulong[hdrV2.totalhunks];
2022-03-06 13:29:38 +00:00
// How many sectors uses the BAT
2023-10-03 23:34:59 +01:00
var hunkSectorCount = (uint)Math.Ceiling((double)hdrV2.totalhunks * 8 / 512);
2017-12-19 20:33:03 +00:00
2023-10-03 23:34:59 +01:00
var hunkSectorBytes = new byte[512];
2017-12-19 20:33:03 +00:00
2023-10-03 23:34:59 +01:00
for(var i = 0; i < hunkSectorCount; i++)
2022-03-06 13:29:38 +00:00
{
stream.EnsureRead(hunkSectorBytes, 0, 512);
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
// This does the big-endian trick but reverses the order of elements also
Array.Reverse(hunkSectorBytes);
HunkSector hunkSector = Marshal.ByteArrayToStructureLittleEndian<HunkSector>(hunkSectorBytes);
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
// This restores the order of elements
Array.Reverse(hunkSector.hunkEntry);
2017-12-19 20:33:03 +00:00
2023-10-03 23:34:59 +01:00
if(_hunkTable.Length >= i * 512 / 8 + 512 / 8)
2022-03-06 13:29:38 +00:00
Array.Copy(hunkSector.hunkEntry, 0, _hunkTable, i * 512 / 8, 512 / 8);
else
2023-10-03 23:34:59 +01:00
Array.Copy(hunkSector.hunkEntry, 0, _hunkTable, i * 512 / 8, _hunkTable.Length - i * 512 / 8);
2017-12-19 20:33:03 +00:00
}
hunkMapStopwatch.Stop();
2024-05-01 04:05:22 +01:00
AaruConsole.DebugWriteLine(MODULE_NAME,
Localization.Took_0_seconds,
hunkMapStopwatch.Elapsed.TotalSeconds);
2017-12-19 20:33:03 +00:00
_imageInfo.MediaType = MediaType.GENERIC_HDD;
_imageInfo.Sectors = hdrV2.hunksize * hdrV2.totalhunks;
_imageInfo.MetadataMediaType = MetadataMediaType.BlockMedia;
_imageInfo.SectorSize = hdrV2.seclen;
_imageInfo.Version = "2";
_imageInfo.ImageSize = _imageInfo.SectorSize * hdrV2.hunksize * hdrV2.totalhunks;
2020-02-29 18:03:35 +00:00
2022-03-06 13:29:38 +00:00
_totalHunks = hdrV2.totalhunks;
_sectorsPerHunk = hdrV2.hunksize;
_hdrCompression = hdrV2.compression;
_mapVersion = 1;
_isHdd = true;
2022-03-06 13:29:38 +00:00
_imageInfo.Cylinders = hdrV2.cylinders;
_imageInfo.Heads = hdrV2.heads;
_imageInfo.SectorsPerTrack = hdrV2.sectors;
2022-03-06 13:29:38 +00:00
break;
}
2022-03-06 13:29:38 +00:00
case 3:
{
HeaderV3 hdrV3 = Marshal.ByteArrayToStructureBigEndian<HeaderV3>(buffer);
AaruConsole.DebugWriteLine(MODULE_NAME, "hdrV3.tag = \"{0}\"", Encoding.ASCII.GetString(hdrV3.tag));
AaruConsole.DebugWriteLine(MODULE_NAME, "hdrV3.length = {0} bytes", hdrV3.length);
2023-10-03 23:34:59 +01:00
AaruConsole.DebugWriteLine(MODULE_NAME, "hdrV3.version = {0}", hdrV3.version);
AaruConsole.DebugWriteLine(MODULE_NAME, "hdrV3.flags = {0}", (Flags)hdrV3.flags);
AaruConsole.DebugWriteLine(MODULE_NAME, "hdrV3.compression = {0}", (Compression)hdrV3.compression);
2017-12-19 20:33:03 +00:00
AaruConsole.DebugWriteLine(MODULE_NAME, "hdrV3.totalhunks = {0}", hdrV3.totalhunks);
AaruConsole.DebugWriteLine(MODULE_NAME, "hdrV3.logicalbytes = {0}", hdrV3.logicalbytes);
AaruConsole.DebugWriteLine(MODULE_NAME, "hdrV3.metaoffset = {0}", hdrV3.metaoffset);
AaruConsole.DebugWriteLine(MODULE_NAME, "hdrV3.md5 = {0}", ArrayHelpers.ByteArrayToHex(hdrV3.md5));
2017-12-19 20:33:03 +00:00
2024-05-01 04:05:22 +01:00
AaruConsole.DebugWriteLine(MODULE_NAME,
"hdrV3.parentmd5 = {0}",
2023-10-03 23:34:59 +01:00
ArrayHelpers.ArrayIsNullOrEmpty(hdrV3.parentmd5)
? "null"
2022-03-06 13:29:38 +00:00
: ArrayHelpers.ByteArrayToHex(hdrV3.parentmd5));
2017-12-19 20:33:03 +00:00
AaruConsole.DebugWriteLine(MODULE_NAME, "hdrV3.hunkbytes = {0}", hdrV3.hunkbytes);
2017-12-19 20:33:03 +00:00
AaruConsole.DebugWriteLine(MODULE_NAME, "hdrV3.sha1 = {0}", ArrayHelpers.ByteArrayToHex(hdrV3.sha1));
2017-12-19 20:33:03 +00:00
2024-05-01 04:05:22 +01:00
AaruConsole.DebugWriteLine(MODULE_NAME,
"hdrV3.parentsha1 = {0}",
2023-10-03 23:34:59 +01:00
ArrayHelpers.ArrayIsNullOrEmpty(hdrV3.parentsha1)
? "null"
2022-03-06 13:29:38 +00:00
: ArrayHelpers.ByteArrayToHex(hdrV3.parentsha1));
2017-12-19 20:33:03 +00:00
AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Reading_Hunk_map);
hunkMapStopwatch.Restart();
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
_hunkMap = new byte[hdrV3.totalhunks * 16];
stream.EnsureRead(_hunkMap, 0, _hunkMap.Length);
hunkMapStopwatch.Stop();
2024-05-01 04:05:22 +01:00
AaruConsole.DebugWriteLine(MODULE_NAME,
Localization.Took_0_seconds,
hunkMapStopwatch.Elapsed.TotalSeconds);
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
nextMetaOff = hdrV3.metaoffset;
2020-02-29 18:03:35 +00:00
2022-03-06 13:29:38 +00:00
_imageInfo.ImageSize = hdrV3.logicalbytes;
_imageInfo.Version = "3";
2022-03-06 13:29:38 +00:00
_totalHunks = hdrV3.totalhunks;
_bytesPerHunk = hdrV3.hunkbytes;
_hdrCompression = hdrV3.compression;
_mapVersion = 3;
2022-03-06 13:29:38 +00:00
break;
}
2022-03-06 13:29:38 +00:00
case 4:
{
HeaderV4 hdrV4 = Marshal.ByteArrayToStructureBigEndian<HeaderV4>(buffer);
AaruConsole.DebugWriteLine(MODULE_NAME, "hdrV4.tag = \"{0}\"", Encoding.ASCII.GetString(hdrV4.tag));
AaruConsole.DebugWriteLine(MODULE_NAME, "hdrV4.length = {0} bytes", hdrV4.length);
2023-10-03 23:34:59 +01:00
AaruConsole.DebugWriteLine(MODULE_NAME, "hdrV4.version = {0}", hdrV4.version);
AaruConsole.DebugWriteLine(MODULE_NAME, "hdrV4.flags = {0}", (Flags)hdrV4.flags);
2017-12-19 20:33:03 +00:00
AaruConsole.DebugWriteLine(MODULE_NAME, "hdrV4.compression = {0}", (Compression)hdrV4.compression);
2017-12-19 20:33:03 +00:00
2023-10-03 23:34:59 +01:00
AaruConsole.DebugWriteLine(MODULE_NAME, "hdrV4.totalhunks = {0}", hdrV4.totalhunks);
AaruConsole.DebugWriteLine(MODULE_NAME, "hdrV4.logicalbytes = {0}", hdrV4.logicalbytes);
2023-10-03 23:34:59 +01:00
AaruConsole.DebugWriteLine(MODULE_NAME, "hdrV4.metaoffset = {0}", hdrV4.metaoffset);
AaruConsole.DebugWriteLine(MODULE_NAME, "hdrV4.hunkbytes = {0}", hdrV4.hunkbytes);
2017-12-19 20:33:03 +00:00
AaruConsole.DebugWriteLine(MODULE_NAME, "hdrV4.sha1 = {0}", ArrayHelpers.ByteArrayToHex(hdrV4.sha1));
2017-12-19 20:33:03 +00:00
2024-05-01 04:05:22 +01:00
AaruConsole.DebugWriteLine(MODULE_NAME,
"hdrV4.parentsha1 = {0}",
2023-10-03 23:34:59 +01:00
ArrayHelpers.ArrayIsNullOrEmpty(hdrV4.parentsha1)
? "null"
2022-03-06 13:29:38 +00:00
: ArrayHelpers.ByteArrayToHex(hdrV4.parentsha1));
2017-12-19 20:33:03 +00:00
2024-05-01 04:05:22 +01:00
AaruConsole.DebugWriteLine(MODULE_NAME,
"hdrV4.rawsha1 = {0}",
2022-03-06 13:29:38 +00:00
ArrayHelpers.ByteArrayToHex(hdrV4.rawsha1));
2017-12-19 20:33:03 +00:00
AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Reading_Hunk_map);
hunkMapStopwatch.Restart();
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
_hunkMap = new byte[hdrV4.totalhunks * 16];
stream.EnsureRead(_hunkMap, 0, _hunkMap.Length);
hunkMapStopwatch.Stop();
2024-05-01 04:05:22 +01:00
AaruConsole.DebugWriteLine(MODULE_NAME,
Localization.Took_0_seconds,
hunkMapStopwatch.Elapsed.TotalSeconds);
2022-03-06 13:29:38 +00:00
nextMetaOff = hdrV4.metaoffset;
2022-03-06 13:29:38 +00:00
_imageInfo.ImageSize = hdrV4.logicalbytes;
_imageInfo.Version = "4";
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
_totalHunks = hdrV4.totalhunks;
_bytesPerHunk = hdrV4.hunkbytes;
_hdrCompression = hdrV4.compression;
_mapVersion = 3;
2020-02-29 18:03:35 +00:00
2022-03-06 13:29:38 +00:00
break;
}
2022-03-06 13:29:38 +00:00
case 5:
{
// TODO: Check why reading is misaligned
AaruConsole.ErrorWriteLine(Localization.CHD_version_5_is_not_yet_supported);
2022-03-06 13:29:38 +00:00
return ErrorNumber.NotImplemented;
2022-03-06 13:29:38 +00:00
HeaderV5 hdrV5 = Marshal.ByteArrayToStructureBigEndian<HeaderV5>(buffer);
AaruConsole.DebugWriteLine(MODULE_NAME, "hdrV5.tag = \"{0}\"", Encoding.ASCII.GetString(hdrV5.tag));
AaruConsole.DebugWriteLine(MODULE_NAME, "hdrV5.length = {0} bytes", hdrV5.length);
2023-10-03 23:34:59 +01:00
AaruConsole.DebugWriteLine(MODULE_NAME, "hdrV5.version = {0}", hdrV5.version);
2024-05-01 04:05:22 +01:00
AaruConsole.DebugWriteLine(MODULE_NAME,
"hdrV5.compressor0 = \"{0}\"",
2022-03-07 07:36:44 +00:00
Encoding.ASCII.GetString(BigEndianBitConverter.GetBytes(hdrV5.compressor0)));
2024-05-01 04:05:22 +01:00
AaruConsole.DebugWriteLine(MODULE_NAME,
"hdrV5.compressor1 = \"{0}\"",
2022-03-07 07:36:44 +00:00
Encoding.ASCII.GetString(BigEndianBitConverter.GetBytes(hdrV5.compressor1)));
2024-05-01 04:05:22 +01:00
AaruConsole.DebugWriteLine(MODULE_NAME,
"hdrV5.compressor2 = \"{0}\"",
2022-03-07 07:36:44 +00:00
Encoding.ASCII.GetString(BigEndianBitConverter.GetBytes(hdrV5.compressor2)));
2017-12-19 20:33:03 +00:00
2024-05-01 04:05:22 +01:00
AaruConsole.DebugWriteLine(MODULE_NAME,
"hdrV5.compressor3 = \"{0}\"",
2022-03-07 07:36:44 +00:00
Encoding.ASCII.GetString(BigEndianBitConverter.GetBytes(hdrV5.compressor3)));
2017-12-19 20:33:03 +00:00
AaruConsole.DebugWriteLine(MODULE_NAME, "hdrV5.logicalbytes = {0}", hdrV5.logicalbytes);
2023-10-03 23:34:59 +01:00
AaruConsole.DebugWriteLine(MODULE_NAME, "hdrV5.mapoffset = {0}", hdrV5.mapoffset);
AaruConsole.DebugWriteLine(MODULE_NAME, "hdrV5.metaoffset = {0}", hdrV5.metaoffset);
AaruConsole.DebugWriteLine(MODULE_NAME, "hdrV5.hunkbytes = {0}", hdrV5.hunkbytes);
AaruConsole.DebugWriteLine(MODULE_NAME, "hdrV5.unitbytes = {0}", hdrV5.unitbytes);
2017-12-19 20:33:03 +00:00
AaruConsole.DebugWriteLine(MODULE_NAME, "hdrV5.sha1 = {0}", ArrayHelpers.ByteArrayToHex(hdrV5.sha1));
2017-12-19 20:33:03 +00:00
2024-05-01 04:05:22 +01:00
AaruConsole.DebugWriteLine(MODULE_NAME,
"hdrV5.parentsha1 = {0}",
2023-10-03 23:34:59 +01:00
ArrayHelpers.ArrayIsNullOrEmpty(hdrV5.parentsha1)
? "null"
2022-03-06 13:29:38 +00:00
: ArrayHelpers.ByteArrayToHex(hdrV5.parentsha1));
2017-12-19 20:33:03 +00:00
2024-05-01 04:05:22 +01:00
AaruConsole.DebugWriteLine(MODULE_NAME,
"hdrV5.rawsha1 = {0}",
2022-03-06 13:29:38 +00:00
ArrayHelpers.ByteArrayToHex(hdrV5.rawsha1));
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
// TODO: Implement compressed CHD v5
if(hdrV5.compressor0 == 0)
{
AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Reading_Hunk_map);
hunkMapStopwatch.Restart();
2022-03-06 13:29:38 +00:00
_hunkTableSmall = new uint[hdrV5.logicalbytes / hdrV5.hunkbytes];
2023-10-03 23:34:59 +01:00
var hunkSectorCount = (uint)Math.Ceiling((double)_hunkTableSmall.Length * 4 / 512);
2023-10-03 23:34:59 +01:00
var hunkSectorBytes = new byte[512];
2022-03-06 13:29:38 +00:00
stream.Seek((long)hdrV5.mapoffset, SeekOrigin.Begin);
2017-12-19 20:33:03 +00:00
2023-10-03 23:34:59 +01:00
for(var i = 0; i < hunkSectorCount; i++)
{
stream.EnsureRead(hunkSectorBytes, 0, 512);
2022-03-06 13:29:38 +00:00
// This does the big-endian trick but reverses the order of elements also
Array.Reverse(hunkSectorBytes);
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
HunkSectorSmall hunkSector =
Marshal.ByteArrayToStructureLittleEndian<HunkSectorSmall>(hunkSectorBytes);
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
// This restores the order of elements
Array.Reverse(hunkSector.hunkEntry);
2017-12-19 20:33:03 +00:00
2023-10-03 23:34:59 +01:00
if(_hunkTableSmall.Length >= i * 512 / 4 + 512 / 4)
2022-03-06 13:29:38 +00:00
Array.Copy(hunkSector.hunkEntry, 0, _hunkTableSmall, i * 512 / 4, 512 / 4);
else
2023-10-03 23:34:59 +01:00
{
2024-05-01 04:05:22 +01:00
Array.Copy(hunkSector.hunkEntry,
0,
_hunkTableSmall,
i * 512 / 4,
_hunkTableSmall.Length - i * 512 / 4);
2023-10-03 23:34:59 +01:00
}
2022-03-06 13:29:38 +00:00
}
2017-12-19 20:33:03 +00:00
hunkMapStopwatch.Stop();
2024-05-01 04:05:22 +01:00
AaruConsole.DebugWriteLine(MODULE_NAME,
Localization.Took_0_seconds,
hunkMapStopwatch.Elapsed.TotalSeconds);
2017-12-19 20:33:03 +00:00
}
2022-03-06 13:29:38 +00:00
else
{
AaruConsole.ErrorWriteLine(Localization.Cannot_read_compressed_CHD_version_5);
return ErrorNumber.NotSupported;
2022-03-06 13:29:38 +00:00
}
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
nextMetaOff = hdrV5.metaoffset;
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
_imageInfo.ImageSize = hdrV5.logicalbytes;
_imageInfo.Version = "5";
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
_totalHunks = (uint)(hdrV5.logicalbytes / hdrV5.hunkbytes);
_bytesPerHunk = hdrV5.hunkbytes;
_hdrCompression = hdrV5.compressor0;
_hdrCompression1 = hdrV5.compressor1;
_hdrCompression2 = hdrV5.compressor2;
_hdrCompression3 = hdrV5.compressor3;
_mapVersion = 5;
2022-03-06 13:29:38 +00:00
break;
}
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
default:
AaruConsole.ErrorWriteLine(string.Format(Localization.Unsupported_CHD_version_0, version));
2022-03-06 13:29:38 +00:00
return ErrorNumber.NotSupported;
}
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
if(_mapVersion >= 3)
{
_isCdrom = false;
_isHdd = false;
_isGdrom = false;
_swapAudio = false;
_tracks = new Dictionary<uint, Track>();
AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Reading_metadata);
2022-03-06 13:29:38 +00:00
ulong currentSector = 0;
uint currentTrack = 1;
2022-03-06 13:29:38 +00:00
while(nextMetaOff > 0)
{
2023-10-03 23:34:59 +01:00
var hdrBytes = new byte[16];
2022-03-06 13:29:38 +00:00
stream.Seek((long)nextMetaOff, SeekOrigin.Begin);
stream.EnsureRead(hdrBytes, 0, hdrBytes.Length);
2022-03-06 13:29:38 +00:00
MetadataHeader header = Marshal.ByteArrayToStructureBigEndian<MetadataHeader>(hdrBytes);
2023-10-03 23:34:59 +01:00
var meta = new byte[header.flagsAndLength & 0xFFFFFF];
stream.EnsureRead(meta, 0, meta.Length);
2024-05-01 04:05:22 +01:00
AaruConsole.DebugWriteLine(MODULE_NAME,
Localization.Found_metadata_0_,
2022-03-06 13:29:38 +00:00
Encoding.ASCII.GetString(BigEndianBitConverter.GetBytes(header.tag)));
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
switch(header.tag)
{
// "GDDD"
case HARD_DISK_METADATA:
if(_isCdrom || _isGdrom)
{
2024-05-01 04:05:22 +01:00
AaruConsole.ErrorWriteLine(Localization
.Image_cannot_be_a_hard_disk_and_a_CGD_ROM_at_the_same_time_aborting);
2022-03-06 13:29:38 +00:00
return ErrorNumber.NotSupported;
}
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
string gddd = StringHandlers.CToString(meta);
var gdddRegEx = new Regex(REGEX_METADATA_HDD);
Match gdddMatch = gdddRegEx.Match(gddd);
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
if(gdddMatch.Success)
{
_isHdd = true;
_imageInfo.SectorSize = uint.Parse(gdddMatch.Groups["bps"].Value);
_imageInfo.Cylinders = uint.Parse(gdddMatch.Groups["cylinders"].Value);
_imageInfo.Heads = uint.Parse(gdddMatch.Groups["heads"].Value);
_imageInfo.SectorsPerTrack = uint.Parse(gdddMatch.Groups["sectors"].Value);
}
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
break;
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
// "CHCD"
case CDROM_OLD_METADATA:
if(_isHdd)
{
2024-05-01 04:05:22 +01:00
AaruConsole.ErrorWriteLine(Localization
.Image_cannot_be_a_hard_disk_and_a_CD_ROM_at_the_same_time_aborting);
2022-03-06 13:29:38 +00:00
return ErrorNumber.NotSupported;
}
2022-03-06 13:29:38 +00:00
if(_isGdrom)
{
2024-05-01 04:05:22 +01:00
AaruConsole.ErrorWriteLine(Localization
.Image_cannot_be_a_GD_ROM_and_a_CD_ROM_at_the_same_time_aborting);
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
return ErrorNumber.NotSupported;
}
2017-12-19 20:33:03 +00:00
2023-10-03 23:34:59 +01:00
var chdTracksNumber = BigEndianBitConverter.ToUInt32(meta, 0);
2020-06-19 03:58:45 +01:00
2022-03-06 13:29:38 +00:00
// Byteswapped
2024-05-01 04:05:22 +01:00
if(chdTracksNumber > 99) chdTracksNumber = BigEndianBitConverter.ToUInt32(meta, 0);
2020-06-19 03:58:45 +01:00
2022-03-06 13:29:38 +00:00
currentSector = 0;
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
for(uint i = 0; i < chdTracksNumber; i++)
{
var chdTrack = new TrackOld
{
2023-10-03 23:34:59 +01:00
type = BigEndianBitConverter.ToUInt32(meta, (int)(4 + i * 24 + 0)),
subType = BigEndianBitConverter.ToUInt32(meta, (int)(4 + i * 24 + 4)),
dataSize = BigEndianBitConverter.ToUInt32(meta, (int)(4 + i * 24 + 8)),
subSize = BigEndianBitConverter.ToUInt32(meta, (int)(4 + i * 24 + 12)),
frames = BigEndianBitConverter.ToUInt32(meta, (int)(4 + i * 24 + 16)),
extraFrames = BigEndianBitConverter.ToUInt32(meta, (int)(4 + i * 24 + 20))
2022-03-06 13:29:38 +00:00
};
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
var aaruTrack = new Track();
2022-03-06 13:29:38 +00:00
switch((TrackTypeOld)chdTrack.type)
{
2022-03-06 13:29:38 +00:00
case TrackTypeOld.Audio:
aaruTrack.BytesPerSector = 2352;
aaruTrack.RawBytesPerSector = 2352;
aaruTrack.Type = TrackType.Audio;
2022-03-06 13:29:38 +00:00
break;
case TrackTypeOld.Mode1:
aaruTrack.BytesPerSector = 2048;
aaruTrack.RawBytesPerSector = 2048;
aaruTrack.Type = TrackType.CdMode1;
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
break;
case TrackTypeOld.Mode1Raw:
aaruTrack.BytesPerSector = 2048;
aaruTrack.RawBytesPerSector = 2352;
aaruTrack.Type = TrackType.CdMode1;
2022-03-06 13:29:38 +00:00
break;
case TrackTypeOld.Mode2:
case TrackTypeOld.Mode2FormMix:
aaruTrack.BytesPerSector = 2336;
aaruTrack.RawBytesPerSector = 2336;
aaruTrack.Type = TrackType.CdMode2Formless;
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
break;
case TrackTypeOld.Mode2Form1:
aaruTrack.BytesPerSector = 2048;
aaruTrack.RawBytesPerSector = 2048;
aaruTrack.Type = TrackType.CdMode2Form1;
2022-03-06 13:29:38 +00:00
break;
case TrackTypeOld.Mode2Form2:
aaruTrack.BytesPerSector = 2324;
aaruTrack.RawBytesPerSector = 2324;
aaruTrack.Type = TrackType.CdMode2Form2;
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
break;
case TrackTypeOld.Mode2Raw:
aaruTrack.BytesPerSector = 2336;
aaruTrack.RawBytesPerSector = 2352;
aaruTrack.Type = TrackType.CdMode2Formless;
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
break;
default:
{
AaruConsole.ErrorWriteLine(string.Format(Localization.Unsupported_track_type_0,
chdTrack.type));
return ErrorNumber.NotSupported;
}
2022-03-06 13:29:38 +00:00
}
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
switch((SubTypeOld)chdTrack.subType)
{
case SubTypeOld.Cooked:
aaruTrack.SubchannelFile = imageFilter.Filename;
aaruTrack.SubchannelType = TrackSubchannelType.PackedInterleaved;
aaruTrack.SubchannelFilter = imageFilter;
2022-03-06 13:29:38 +00:00
break;
case SubTypeOld.None:
aaruTrack.SubchannelType = TrackSubchannelType.None;
break;
case SubTypeOld.Raw:
aaruTrack.SubchannelFile = imageFilter.Filename;
aaruTrack.SubchannelType = TrackSubchannelType.RawInterleaved;
aaruTrack.SubchannelFilter = imageFilter;
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
break;
default:
2017-12-19 20:33:03 +00:00
{
AaruConsole.ErrorWriteLine(string.Format(Localization.Unsupported_subchannel_type_0,
chdTrack.type));
2022-03-06 13:29:38 +00:00
return ErrorNumber.NotSupported;
2017-12-19 20:33:03 +00:00
}
2022-03-06 13:29:38 +00:00
}
2017-12-19 20:33:03 +00:00
aaruTrack.Description = string.Format(Localization.Track_0, i + 1);
2022-03-06 13:29:38 +00:00
aaruTrack.EndSector = currentSector + chdTrack.frames - 1;
aaruTrack.File = imageFilter.Filename;
aaruTrack.FileType = "BINARY";
aaruTrack.Filter = imageFilter;
aaruTrack.StartSector = currentSector;
aaruTrack.Sequence = i + 1;
aaruTrack.Session = 1;
2024-05-01 04:05:22 +01:00
if(aaruTrack.Sequence == 1) aaruTrack.Indexes.Add(0, -150);
2022-03-06 13:29:38 +00:00
aaruTrack.Indexes.Add(1, (int)currentSector);
currentSector += chdTrack.frames + chdTrack.extraFrames;
_tracks.Add(aaruTrack.Sequence, aaruTrack);
}
2020-06-19 03:58:45 +01:00
2022-03-06 13:29:38 +00:00
_isCdrom = true;
2020-06-19 03:58:45 +01:00
2022-03-06 13:29:38 +00:00
break;
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
// "CHTR"
case CDROM_TRACK_METADATA:
if(_isHdd)
{
2024-05-01 04:05:22 +01:00
AaruConsole.ErrorWriteLine(Localization
.Image_cannot_be_a_hard_disk_and_a_CD_ROM_at_the_same_time_aborting);
2022-03-06 13:29:38 +00:00
return ErrorNumber.NotSupported;
}
2022-03-06 13:29:38 +00:00
if(_isGdrom)
{
2024-05-01 04:05:22 +01:00
AaruConsole.ErrorWriteLine(Localization
.Image_cannot_be_a_GD_ROM_and_a_CD_ROM_at_the_same_time_aborting);
2022-03-06 13:29:38 +00:00
return ErrorNumber.NotSupported;
}
string chtr = StringHandlers.CToString(meta);
var chtrRegEx = new Regex(REGEX_METADATA_CDROM);
Match chtrMatch = chtrRegEx.Match(chtr);
if(chtrMatch.Success)
{
_isCdrom = true;
2023-10-03 23:34:59 +01:00
var trackNo = uint.Parse(chtrMatch.Groups["track"].Value);
var frames = uint.Parse(chtrMatch.Groups["frames"].Value);
2022-03-06 13:29:38 +00:00
string subtype = chtrMatch.Groups["sub_type"].Value;
string tracktype = chtrMatch.Groups["track_type"].Value;
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
if(trackNo != currentTrack)
{
AaruConsole.ErrorWriteLine(Localization.Unsorted_tracks_cannot_proceed);
return ErrorNumber.NotSupported;
}
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
var aaruTrack = new Track();
2022-03-06 13:29:38 +00:00
switch(tracktype)
2017-12-19 20:33:03 +00:00
{
2022-03-06 13:29:38 +00:00
case TRACK_TYPE_AUDIO:
aaruTrack.BytesPerSector = 2352;
aaruTrack.RawBytesPerSector = 2352;
aaruTrack.Type = TrackType.Audio;
break;
case TRACK_TYPE_MODE1:
case TRACK_TYPE_MODE1_2K:
aaruTrack.BytesPerSector = 2048;
aaruTrack.RawBytesPerSector = 2048;
aaruTrack.Type = TrackType.CdMode1;
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
break;
case TRACK_TYPE_MODE1_RAW:
case TRACK_TYPE_MODE1_RAW_2K:
aaruTrack.BytesPerSector = 2048;
aaruTrack.RawBytesPerSector = 2352;
aaruTrack.Type = TrackType.CdMode1;
2022-03-06 13:29:38 +00:00
break;
case TRACK_TYPE_MODE2:
case TRACK_TYPE_MODE2_2K:
case TRACK_TYPE_MODE2_FM:
aaruTrack.BytesPerSector = 2336;
aaruTrack.RawBytesPerSector = 2336;
aaruTrack.Type = TrackType.CdMode2Formless;
2020-06-19 03:58:45 +01:00
2022-03-06 13:29:38 +00:00
break;
case TRACK_TYPE_MODE2_F1:
case TRACK_TYPE_MODE2_F1_2K:
aaruTrack.BytesPerSector = 2048;
aaruTrack.RawBytesPerSector = 2048;
aaruTrack.Type = TrackType.CdMode2Form1;
2020-06-19 03:58:45 +01:00
2022-03-06 13:29:38 +00:00
break;
case TRACK_TYPE_MODE2_F2:
case TRACK_TYPE_MODE2_F2_2K:
aaruTrack.BytesPerSector = 2324;
aaruTrack.RawBytesPerSector = 2324;
aaruTrack.Type = TrackType.CdMode2Form2;
2020-06-19 03:58:45 +01:00
2022-03-06 13:29:38 +00:00
break;
case TRACK_TYPE_MODE2_RAW:
case TRACK_TYPE_MODE2_RAW_2K:
aaruTrack.BytesPerSector = 2336;
aaruTrack.RawBytesPerSector = 2352;
aaruTrack.Type = TrackType.CdMode2Formless;
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
break;
default:
{
AaruConsole.ErrorWriteLine(string.Format(Localization.Unsupported_track_type_0,
tracktype));
return ErrorNumber.NotSupported;
}
2022-03-06 13:29:38 +00:00
}
switch(subtype)
{
case SUB_TYPE_COOKED:
aaruTrack.SubchannelFile = imageFilter.Filename;
aaruTrack.SubchannelType = TrackSubchannelType.PackedInterleaved;
aaruTrack.SubchannelFilter = imageFilter;
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
break;
case SUB_TYPE_NONE:
aaruTrack.SubchannelType = TrackSubchannelType.None;
2022-03-06 13:29:38 +00:00
break;
case SUB_TYPE_RAW:
aaruTrack.SubchannelFile = imageFilter.Filename;
aaruTrack.SubchannelType = TrackSubchannelType.RawInterleaved;
aaruTrack.SubchannelFilter = imageFilter;
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
break;
default:
2017-12-19 20:33:03 +00:00
{
AaruConsole.ErrorWriteLine(string.Format(Localization.Unsupported_subchannel_type_0,
subtype));
2022-03-06 13:29:38 +00:00
return ErrorNumber.NotSupported;
2017-12-19 20:33:03 +00:00
}
2022-03-06 13:29:38 +00:00
}
2017-12-19 20:33:03 +00:00
aaruTrack.Description = string.Format(Localization.Track_0, trackNo);
2022-03-06 13:29:38 +00:00
aaruTrack.EndSector = currentSector + frames - 1;
aaruTrack.File = imageFilter.Filename;
aaruTrack.FileType = "BINARY";
aaruTrack.Filter = imageFilter;
aaruTrack.StartSector = currentSector;
aaruTrack.Sequence = trackNo;
aaruTrack.Session = 1;
2024-05-01 04:05:22 +01:00
if(aaruTrack.Sequence == 1) aaruTrack.Indexes.Add(0, -150);
2022-03-06 13:29:38 +00:00
aaruTrack.Indexes.Add(1, (int)currentSector);
currentSector += frames;
currentTrack++;
_tracks.Add(aaruTrack.Sequence, aaruTrack);
}
2020-06-19 03:58:45 +01:00
2022-03-06 13:29:38 +00:00
break;
2020-06-19 03:58:45 +01:00
2022-03-06 13:29:38 +00:00
// "CHT2"
case CDROM_TRACK_METADATA2:
if(_isHdd)
{
2024-05-01 04:05:22 +01:00
AaruConsole.ErrorWriteLine(Localization
.Image_cannot_be_a_hard_disk_and_a_CD_ROM_at_the_same_time_aborting);
2022-03-06 13:29:38 +00:00
return ErrorNumber.NotSupported;
}
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
if(_isGdrom)
{
2024-05-01 04:05:22 +01:00
AaruConsole.ErrorWriteLine(Localization
.Image_cannot_be_a_GD_ROM_and_a_CD_ROM_at_the_same_time_aborting);
2022-03-06 13:29:38 +00:00
return ErrorNumber.NotSupported;
}
2022-03-06 13:29:38 +00:00
string cht2 = StringHandlers.CToString(meta);
var cht2RegEx = new Regex(REGEX_METADATA_CDROM2);
Match cht2Match = cht2RegEx.Match(cht2);
2022-03-06 13:29:38 +00:00
if(cht2Match.Success)
{
_isCdrom = true;
2017-12-19 20:33:03 +00:00
2023-10-03 23:34:59 +01:00
var trackNo = uint.Parse(cht2Match.Groups["track"].Value);
var frames = uint.Parse(cht2Match.Groups["frames"].Value);
2022-03-06 13:29:38 +00:00
string subtype = cht2Match.Groups["sub_type"].Value;
string trackType = cht2Match.Groups["track_type"].Value;
2023-10-03 23:34:59 +01:00
var pregap = uint.Parse(cht2Match.Groups["pregap"].Value);
2022-03-06 13:29:38 +00:00
// What is this, really? Same as track type?
string pregapType = cht2Match.Groups["pgtype"].Value;
// Read above, but for subchannel
string pregapSubType = cht2Match.Groups["pgsub"].Value;
// This is a recommendation (shall) of 150 sectors at the end of the last data track,
// or of any data track followed by an audio track, according to Yellow Book.
// It is indistinguishable from normal data.
// TODO: Does CHD store it, or like CDRWin, ignores it?
2023-10-03 23:34:59 +01:00
var postgap = uint.Parse(cht2Match.Groups["postgap"].Value);
2022-03-06 13:29:38 +00:00
if(trackNo != currentTrack)
{
AaruConsole.ErrorWriteLine(Localization.Unsorted_tracks_cannot_proceed);
return ErrorNumber.NotSupported;
}
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
var aaruTrack = new Track();
2022-03-06 13:29:38 +00:00
switch(trackType)
2017-12-19 20:33:03 +00:00
{
2022-03-06 13:29:38 +00:00
case TRACK_TYPE_AUDIO:
aaruTrack.BytesPerSector = 2352;
aaruTrack.RawBytesPerSector = 2352;
aaruTrack.Type = TrackType.Audio;
break;
case TRACK_TYPE_MODE1:
case TRACK_TYPE_MODE1_2K:
aaruTrack.BytesPerSector = 2048;
aaruTrack.RawBytesPerSector = 2048;
aaruTrack.Type = TrackType.CdMode1;
break;
case TRACK_TYPE_MODE1_RAW:
case TRACK_TYPE_MODE1_RAW_2K:
aaruTrack.BytesPerSector = 2048;
aaruTrack.RawBytesPerSector = 2352;
aaruTrack.Type = TrackType.CdMode1;
break;
case TRACK_TYPE_MODE2:
case TRACK_TYPE_MODE2_2K:
case TRACK_TYPE_MODE2_FM:
aaruTrack.BytesPerSector = 2336;
aaruTrack.RawBytesPerSector = 2336;
aaruTrack.Type = TrackType.CdMode2Formless;
break;
case TRACK_TYPE_MODE2_F1:
case TRACK_TYPE_MODE2_F1_2K:
aaruTrack.BytesPerSector = 2048;
aaruTrack.RawBytesPerSector = 2048;
aaruTrack.Type = TrackType.CdMode2Form1;
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
break;
case TRACK_TYPE_MODE2_F2:
case TRACK_TYPE_MODE2_F2_2K:
aaruTrack.BytesPerSector = 2324;
aaruTrack.RawBytesPerSector = 2324;
aaruTrack.Type = TrackType.CdMode2Form2;
2022-03-06 13:29:38 +00:00
break;
case TRACK_TYPE_MODE2_RAW:
case TRACK_TYPE_MODE2_RAW_2K:
aaruTrack.BytesPerSector = 2336;
aaruTrack.RawBytesPerSector = 2352;
aaruTrack.Type = TrackType.CdMode2Formless;
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
break;
default:
{
AaruConsole.ErrorWriteLine(string.Format(Localization.Unsupported_track_type_0,
trackType));
return ErrorNumber.NotSupported;
}
2022-03-06 13:29:38 +00:00
}
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
switch(subtype)
{
case SUB_TYPE_COOKED:
aaruTrack.SubchannelFile = imageFilter.Filename;
aaruTrack.SubchannelType = TrackSubchannelType.PackedInterleaved;
aaruTrack.SubchannelFilter = imageFilter;
2022-03-06 13:29:38 +00:00
break;
case SUB_TYPE_NONE:
aaruTrack.SubchannelType = TrackSubchannelType.None;
break;
case SUB_TYPE_RAW:
aaruTrack.SubchannelFile = imageFilter.Filename;
aaruTrack.SubchannelType = TrackSubchannelType.RawInterleaved;
aaruTrack.SubchannelFilter = imageFilter;
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
break;
default:
2017-12-19 20:33:03 +00:00
{
AaruConsole.ErrorWriteLine(string.Format(Localization.Unsupported_subchannel_type_0,
subtype));
2022-03-06 13:29:38 +00:00
return ErrorNumber.NotSupported;
2017-12-19 20:33:03 +00:00
}
2022-03-06 13:29:38 +00:00
}
2017-12-19 20:33:03 +00:00
aaruTrack.Description = string.Format(Localization.Track_0, trackNo);
2022-03-06 13:29:38 +00:00
aaruTrack.EndSector = currentSector + frames - 1;
aaruTrack.File = imageFilter.Filename;
aaruTrack.FileType = "BINARY";
aaruTrack.Filter = imageFilter;
aaruTrack.StartSector = currentSector;
aaruTrack.Sequence = trackNo;
aaruTrack.Session = 1;
2020-06-19 03:58:45 +01:00
2022-03-06 13:29:38 +00:00
if(aaruTrack.Sequence == 1)
{
if(pregap <= 150)
2020-06-19 03:58:45 +01:00
{
2022-03-06 13:29:38 +00:00
aaruTrack.Indexes.Add(0, -150);
aaruTrack.Pregap = 150;
2020-06-19 03:58:45 +01:00
}
2022-03-06 13:29:38 +00:00
else
2020-06-19 03:58:45 +01:00
{
2022-03-06 13:29:38 +00:00
aaruTrack.Indexes.Add(0, -1 * (int)pregap);
2021-09-14 21:18:28 +01:00
aaruTrack.Pregap = pregap;
2020-06-19 03:58:45 +01:00
}
2022-03-06 13:29:38 +00:00
aaruTrack.Indexes.Add(1, (int)currentSector);
2017-12-19 20:33:03 +00:00
}
2022-03-06 13:29:38 +00:00
else if(pregap > 0)
{
aaruTrack.Indexes.Add(0, (int)currentSector);
aaruTrack.Pregap = pregap;
aaruTrack.Indexes.Add(1, (int)(currentSector + pregap));
}
else
aaruTrack.Indexes.Add(1, (int)currentSector);
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
currentSector += frames;
currentTrack++;
_tracks.Add(aaruTrack.Sequence, aaruTrack);
}
2022-03-06 13:29:38 +00:00
break;
2022-03-06 13:29:38 +00:00
// "CHGT"
case GDROM_OLD_METADATA:
_swapAudio = true;
goto case GDROM_METADATA;
// "CHGD"
case GDROM_METADATA:
if(_isHdd)
{
2024-05-01 04:05:22 +01:00
AaruConsole.ErrorWriteLine(Localization
.Image_cannot_be_a_hard_disk_and_a_GD_ROM_at_the_same_time_aborting);
2022-03-06 13:29:38 +00:00
return ErrorNumber.NotSupported;
}
if(_isCdrom)
{
2024-05-01 04:05:22 +01:00
AaruConsole.ErrorWriteLine(Localization
.Image_cannot_be_a_CD_ROM_and_a_GD_ROM_at_the_same_time_aborting);
2022-03-06 13:29:38 +00:00
return ErrorNumber.NotSupported;
}
string chgd = StringHandlers.CToString(meta);
var chgdRegEx = new Regex(REGEX_METADATA_GDROM);
Match chgdMatch = chgdRegEx.Match(chgd);
if(chgdMatch.Success)
{
_isGdrom = true;
2023-10-03 23:34:59 +01:00
var trackNo = uint.Parse(chgdMatch.Groups["track"].Value);
var frames = uint.Parse(chgdMatch.Groups["frames"].Value);
2022-03-06 13:29:38 +00:00
string subtype = chgdMatch.Groups["sub_type"].Value;
string trackType = chgdMatch.Groups["track_type"].Value;
// TODO: Check pregap, postgap and pad behaviour
2023-10-03 23:34:59 +01:00
var pregap = uint.Parse(chgdMatch.Groups["pregap"].Value);
2022-03-06 13:29:38 +00:00
string pregapType = chgdMatch.Groups["pgtype"].Value;
string pregapSubType = chgdMatch.Groups["pgsub"].Value;
2023-10-03 23:34:59 +01:00
var postgap = uint.Parse(chgdMatch.Groups["postgap"].Value);
var pad = uint.Parse(chgdMatch.Groups["pad"].Value);
2022-03-06 13:29:38 +00:00
if(trackNo != currentTrack)
{
AaruConsole.ErrorWriteLine(Localization.Unsorted_tracks_cannot_proceed);
2022-03-06 13:29:38 +00:00
return ErrorNumber.NotSupported;
}
var aaruTrack = new Track();
switch(trackType)
{
case TRACK_TYPE_AUDIO:
aaruTrack.BytesPerSector = 2352;
aaruTrack.RawBytesPerSector = 2352;
aaruTrack.Type = TrackType.Audio;
break;
case TRACK_TYPE_MODE1:
case TRACK_TYPE_MODE1_2K:
aaruTrack.BytesPerSector = 2048;
aaruTrack.RawBytesPerSector = 2048;
aaruTrack.Type = TrackType.CdMode1;
break;
case TRACK_TYPE_MODE1_RAW:
case TRACK_TYPE_MODE1_RAW_2K:
aaruTrack.BytesPerSector = 2048;
aaruTrack.RawBytesPerSector = 2352;
aaruTrack.Type = TrackType.CdMode1;
break;
case TRACK_TYPE_MODE2:
case TRACK_TYPE_MODE2_2K:
case TRACK_TYPE_MODE2_FM:
aaruTrack.BytesPerSector = 2336;
aaruTrack.RawBytesPerSector = 2336;
aaruTrack.Type = TrackType.CdMode2Formless;
break;
case TRACK_TYPE_MODE2_F1:
case TRACK_TYPE_MODE2_F1_2K:
aaruTrack.BytesPerSector = 2048;
aaruTrack.RawBytesPerSector = 2048;
aaruTrack.Type = TrackType.CdMode2Form1;
break;
case TRACK_TYPE_MODE2_F2:
case TRACK_TYPE_MODE2_F2_2K:
aaruTrack.BytesPerSector = 2324;
aaruTrack.RawBytesPerSector = 2324;
aaruTrack.Type = TrackType.CdMode2Form2;
break;
case TRACK_TYPE_MODE2_RAW:
case TRACK_TYPE_MODE2_RAW_2K:
aaruTrack.BytesPerSector = 2336;
aaruTrack.RawBytesPerSector = 2352;
aaruTrack.Type = TrackType.CdMode2Formless;
break;
default:
{
AaruConsole.ErrorWriteLine(string.Format(Localization.Unsupported_track_type_0,
trackType));
2022-03-06 13:29:38 +00:00
return ErrorNumber.NotSupported;
}
}
switch(subtype)
{
case SUB_TYPE_COOKED:
aaruTrack.SubchannelFile = imageFilter.Filename;
aaruTrack.SubchannelType = TrackSubchannelType.PackedInterleaved;
aaruTrack.SubchannelFilter = imageFilter;
break;
case SUB_TYPE_NONE:
aaruTrack.SubchannelType = TrackSubchannelType.None;
break;
case SUB_TYPE_RAW:
aaruTrack.SubchannelFile = imageFilter.Filename;
aaruTrack.SubchannelType = TrackSubchannelType.RawInterleaved;
aaruTrack.SubchannelFilter = imageFilter;
break;
default:
{
AaruConsole.ErrorWriteLine(string.Format(Localization.Unsupported_subchannel_type_0,
subtype));
2022-03-06 13:29:38 +00:00
return ErrorNumber.NotSupported;
}
}
aaruTrack.Description = string.Format(Localization.Track_0, trackNo);
2022-03-06 13:29:38 +00:00
aaruTrack.EndSector = currentSector + frames - 1;
aaruTrack.File = imageFilter.Filename;
aaruTrack.FileType = "BINARY";
aaruTrack.Filter = imageFilter;
aaruTrack.StartSector = currentSector;
aaruTrack.Sequence = trackNo;
aaruTrack.Session = (ushort)(trackNo > 2 ? 2 : 1);
if(aaruTrack.Sequence == 1)
{
if(pregap <= 150)
{
aaruTrack.Indexes.Add(0, -150);
aaruTrack.Pregap = 150;
2017-12-19 20:33:03 +00:00
}
else
{
2022-03-06 13:29:38 +00:00
aaruTrack.Indexes.Add(0, -1 * (int)pregap);
aaruTrack.Pregap = pregap;
2017-12-19 20:33:03 +00:00
}
2022-03-06 13:29:38 +00:00
aaruTrack.Indexes.Add(1, (int)currentSector);
}
else if(pregap > 0)
{
aaruTrack.Indexes.Add(0, (int)currentSector);
aaruTrack.Pregap = pregap;
aaruTrack.Indexes.Add(1, (int)(currentSector + pregap));
2017-12-19 20:33:03 +00:00
}
2022-03-06 13:29:38 +00:00
else
aaruTrack.Indexes.Add(1, (int)currentSector);
2022-03-06 13:29:38 +00:00
currentSector += frames;
currentTrack++;
_tracks.Add(aaruTrack.Sequence, aaruTrack);
}
2022-03-06 13:29:38 +00:00
break;
2022-03-06 13:29:38 +00:00
// "IDNT"
case HARD_DISK_IDENT_METADATA:
Identify.IdentifyDevice? idnt = CommonTypes.Structs.Devices.ATA.Identify.Decode(meta);
2022-03-06 13:29:38 +00:00
if(idnt.HasValue)
{
_imageInfo.MediaManufacturer = idnt.Value.MediaManufacturer;
_imageInfo.MediaSerialNumber = idnt.Value.MediaSerial;
_imageInfo.DriveModel = idnt.Value.Model;
_imageInfo.DriveSerialNumber = idnt.Value.SerialNumber;
_imageInfo.DriveFirmwareRevision = idnt.Value.FirmwareRevision;
2023-10-04 09:38:17 +01:00
if(idnt is { CurrentCylinders: > 0, CurrentHeads: > 0, CurrentSectorsPerTrack: > 0 })
2022-03-06 13:29:38 +00:00
{
_imageInfo.Cylinders = idnt.Value.CurrentCylinders;
_imageInfo.Heads = idnt.Value.CurrentHeads;
_imageInfo.SectorsPerTrack = idnt.Value.CurrentSectorsPerTrack;
}
else
{
_imageInfo.Cylinders = idnt.Value.Cylinders;
_imageInfo.Heads = idnt.Value.Heads;
_imageInfo.SectorsPerTrack = idnt.Value.SectorsPerTrack;
}
}
2022-03-06 13:29:38 +00:00
_identify = meta;
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
if(!_imageInfo.ReadableMediaTags.Contains(MediaTagType.ATA_IDENTIFY))
_imageInfo.ReadableMediaTags.Add(MediaTagType.ATA_IDENTIFY);
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
break;
case PCMCIA_CIS_METADATA:
_cis = meta;
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
if(!_imageInfo.ReadableMediaTags.Contains(MediaTagType.PCMCIA_CIS))
_imageInfo.ReadableMediaTags.Add(MediaTagType.PCMCIA_CIS);
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
break;
2017-12-19 20:33:03 +00:00
}
2022-03-06 13:29:38 +00:00
nextMetaOff = header.next;
2017-12-19 20:33:03 +00:00
}
2022-03-06 13:29:38 +00:00
if(_isHdd)
{
_sectorsPerHunk = _bytesPerHunk / _imageInfo.SectorSize;
_imageInfo.Sectors = _imageInfo.ImageSize / _imageInfo.SectorSize;
_imageInfo.MediaType = MediaType.GENERIC_HDD;
_imageInfo.MetadataMediaType = MetadataMediaType.BlockMedia;
2022-03-06 13:29:38 +00:00
}
else if(_isCdrom)
2017-12-19 20:33:03 +00:00
{
2022-03-06 13:29:38 +00:00
// Hardcoded on MAME for CD-ROM
_sectorsPerHunk = 8;
_imageInfo.MediaType = MediaType.CDROM;
_imageInfo.MetadataMediaType = MetadataMediaType.OpticalDisc;
2020-07-20 21:11:32 +01:00
foreach(Track aaruTrack in _tracks.Values)
2022-03-06 13:29:38 +00:00
_imageInfo.Sectors += aaruTrack.EndSector - aaruTrack.StartSector + 1;
}
else if(_isGdrom)
{
// Hardcoded on MAME for GD-ROM
_sectorsPerHunk = 8;
_imageInfo.MediaType = MediaType.GDROM;
_imageInfo.MetadataMediaType = MetadataMediaType.OpticalDisc;
2022-03-06 13:29:38 +00:00
foreach(Track aaruTrack in _tracks.Values)
_imageInfo.Sectors += aaruTrack.EndSector - aaruTrack.StartSector + 1;
}
else
{
AaruConsole.ErrorWriteLine(Localization.Image_does_not_represent_a_known_media_aborting);
2022-03-06 13:29:38 +00:00
return ErrorNumber.NotSupported;
}
}
2022-03-06 13:29:38 +00:00
if(_isCdrom || _isGdrom)
{
_offsetmap = new Dictionary<ulong, uint>();
2024-05-01 04:39:38 +01:00
_partitions = [];
2022-03-06 13:29:38 +00:00
ulong partPos = 0;
2022-03-06 13:29:38 +00:00
foreach(Track aaruTrack in _tracks.Values)
{
var partition = new Partition
{
Description = aaruTrack.Description,
2022-03-07 07:36:44 +00:00
Size = (aaruTrack.EndSector - (ulong)aaruTrack.Indexes[1] + 1) * (ulong)aaruTrack.RawBytesPerSector,
Length = aaruTrack.EndSector - (ulong)aaruTrack.Indexes[1] + 1,
2022-03-06 13:29:38 +00:00
Sequence = aaruTrack.Sequence,
2022-03-07 07:36:44 +00:00
Offset = partPos,
Start = (ulong)aaruTrack.Indexes[1],
Type = aaruTrack.Type.ToString()
2022-03-06 13:29:38 +00:00
};
partPos += partition.Length;
_offsetmap.Add(aaruTrack.StartSector, aaruTrack.Sequence);
if(aaruTrack.SubchannelType != TrackSubchannelType.None)
2023-10-03 23:34:59 +01:00
{
2022-03-06 13:29:38 +00:00
if(!_imageInfo.ReadableSectorTags.Contains(SectorTagType.CdSectorSubchannel))
_imageInfo.ReadableSectorTags.Add(SectorTagType.CdSectorSubchannel);
2023-10-03 23:34:59 +01:00
}
2022-03-06 13:29:38 +00:00
switch(aaruTrack.Type)
{
case TrackType.CdMode1:
case TrackType.CdMode2Form1:
if(aaruTrack.RawBytesPerSector == 2352)
{
if(!_imageInfo.ReadableSectorTags.Contains(SectorTagType.CdSectorSync))
_imageInfo.ReadableSectorTags.Add(SectorTagType.CdSectorSync);
2022-03-06 13:29:38 +00:00
if(!_imageInfo.ReadableSectorTags.Contains(SectorTagType.CdSectorHeader))
_imageInfo.ReadableSectorTags.Add(SectorTagType.CdSectorHeader);
2022-03-06 13:29:38 +00:00
if(!_imageInfo.ReadableSectorTags.Contains(SectorTagType.CdSectorSubHeader))
_imageInfo.ReadableSectorTags.Add(SectorTagType.CdSectorSubHeader);
2022-03-06 13:29:38 +00:00
if(!_imageInfo.ReadableSectorTags.Contains(SectorTagType.CdSectorEcc))
_imageInfo.ReadableSectorTags.Add(SectorTagType.CdSectorEcc);
2022-03-06 13:29:38 +00:00
if(!_imageInfo.ReadableSectorTags.Contains(SectorTagType.CdSectorEccP))
_imageInfo.ReadableSectorTags.Add(SectorTagType.CdSectorEccP);
2022-03-06 13:29:38 +00:00
if(!_imageInfo.ReadableSectorTags.Contains(SectorTagType.CdSectorEccQ))
_imageInfo.ReadableSectorTags.Add(SectorTagType.CdSectorEccQ);
2022-03-06 13:29:38 +00:00
if(!_imageInfo.ReadableSectorTags.Contains(SectorTagType.CdSectorEdc))
_imageInfo.ReadableSectorTags.Add(SectorTagType.CdSectorEdc);
}
2022-03-06 13:29:38 +00:00
break;
case TrackType.CdMode2Form2:
if(aaruTrack.RawBytesPerSector == 2352)
{
if(!_imageInfo.ReadableSectorTags.Contains(SectorTagType.CdSectorSync))
_imageInfo.ReadableSectorTags.Add(SectorTagType.CdSectorSync);
2022-03-06 13:29:38 +00:00
if(!_imageInfo.ReadableSectorTags.Contains(SectorTagType.CdSectorHeader))
_imageInfo.ReadableSectorTags.Add(SectorTagType.CdSectorHeader);
2022-03-06 13:29:38 +00:00
if(!_imageInfo.ReadableSectorTags.Contains(SectorTagType.CdSectorSubHeader))
_imageInfo.ReadableSectorTags.Add(SectorTagType.CdSectorSubHeader);
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
if(!_imageInfo.ReadableSectorTags.Contains(SectorTagType.CdSectorEdc))
_imageInfo.ReadableSectorTags.Add(SectorTagType.CdSectorEdc);
}
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
break;
case TrackType.CdMode2Formless:
if(aaruTrack.RawBytesPerSector == 2352)
{
if(!_imageInfo.ReadableSectorTags.Contains(SectorTagType.CdSectorSync))
_imageInfo.ReadableSectorTags.Add(SectorTagType.CdSectorSync);
if(!_imageInfo.ReadableSectorTags.Contains(SectorTagType.CdSectorHeader))
_imageInfo.ReadableSectorTags.Add(SectorTagType.CdSectorHeader);
}
break;
2017-12-19 20:33:03 +00:00
}
2022-03-06 13:29:38 +00:00
if(aaruTrack.BytesPerSector > _imageInfo.SectorSize)
_imageInfo.SectorSize = (uint)aaruTrack.BytesPerSector;
_partitions.Add(partition);
2017-12-19 20:33:03 +00:00
}
2022-03-06 13:29:38 +00:00
_imageInfo.HasPartitions = true;
_imageInfo.HasSessions = true;
}
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
_maxBlockCache = (int)(MAX_CACHE_SIZE / (_imageInfo.SectorSize * _sectorsPerHunk));
_maxSectorCache = (int)(MAX_CACHE_SIZE / _imageInfo.SectorSize);
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
_imageStream = stream;
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
_sectorCache = new Dictionary<ulong, byte[]>();
_hunkCache = new Dictionary<ulong, byte[]>();
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
// TODO: Detect CompactFlash
// TODO: Get manufacturer and drive name from CIS if applicable
2024-05-01 04:05:22 +01:00
if(_cis != null) _imageInfo.MediaType = MediaType.PCCardTypeI;
2022-03-06 13:29:38 +00:00
_sectorBuilder = new SectorBuilder();
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
return ErrorNumber.NoError;
}
2022-03-06 13:29:38 +00:00
/// <inheritdoc />
public ErrorNumber ReadSector(ulong sectorAddress, out byte[] buffer)
{
buffer = null;
2017-12-19 20:33:03 +00:00
2024-05-01 04:05:22 +01:00
if(sectorAddress > _imageInfo.Sectors - 1) return ErrorNumber.OutOfRange;
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
var track = new Track();
uint sectorSize;
if(!_sectorCache.TryGetValue(sectorAddress, out byte[] sector))
{
if(_isHdd)
sectorSize = _imageInfo.SectorSize;
else
2017-12-19 20:33:03 +00:00
{
2022-03-06 13:29:38 +00:00
track = GetTrack(sectorAddress);
sectorSize = (uint)track.RawBytesPerSector;
}
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
ulong hunkNo = sectorAddress / _sectorsPerHunk;
ulong secOff = sectorAddress * sectorSize % (_sectorsPerHunk * sectorSize);
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
ErrorNumber errno = GetHunk(hunkNo, out byte[] hunk);
2021-09-21 04:55:28 +01:00
2024-05-01 04:05:22 +01:00
if(errno != ErrorNumber.NoError) return errno;
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
sector = new byte[_imageInfo.SectorSize];
Array.Copy(hunk, (int)secOff, sector, 0, sector.Length);
2017-12-19 20:33:03 +00:00
2024-05-01 04:05:22 +01:00
if(_sectorCache.Count >= _maxSectorCache) _sectorCache.Clear();
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
_sectorCache.Add(sectorAddress, sector);
}
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
if(_isHdd)
{
buffer = sector;
2022-03-06 13:29:38 +00:00
return ErrorNumber.NoError;
}
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
uint sectorOffset;
2023-10-03 23:34:59 +01:00
var mode2 = false;
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
switch(track.Type)
{
case TrackType.CdMode1:
2017-12-19 20:33:03 +00:00
{
2022-03-06 13:29:38 +00:00
if(track.RawBytesPerSector == 2352)
2017-12-19 20:33:03 +00:00
{
2022-03-06 13:29:38 +00:00
sectorOffset = 16;
sectorSize = 2048;
2017-12-19 20:33:03 +00:00
}
2022-03-06 13:29:38 +00:00
else
2017-12-19 20:33:03 +00:00
{
2022-03-06 13:29:38 +00:00
sectorOffset = 0;
sectorSize = 2048;
2017-12-19 20:33:03 +00:00
}
2022-03-06 13:29:38 +00:00
break;
}
case TrackType.CdMode2Form1:
{
if(track.RawBytesPerSector == 2352)
{
sectorOffset = 0;
2022-03-06 13:29:38 +00:00
sectorSize = 2352;
mode2 = true;
}
2022-03-06 13:29:38 +00:00
else
2017-12-19 20:33:03 +00:00
{
sectorOffset = 0;
2022-03-06 13:29:38 +00:00
sectorSize = 2048;
2017-12-19 20:33:03 +00:00
}
2022-03-06 13:29:38 +00:00
break;
2017-12-19 20:33:03 +00:00
}
2022-03-06 13:29:38 +00:00
case TrackType.CdMode2Form2:
{
if(track.RawBytesPerSector == 2352)
{
sectorOffset = 0;
sectorSize = 2352;
mode2 = true;
}
else
2017-12-19 20:33:03 +00:00
{
2022-03-06 13:29:38 +00:00
sectorOffset = 0;
sectorSize = 2324;
2017-12-19 20:33:03 +00:00
}
2022-03-06 13:29:38 +00:00
break;
}
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
case TrackType.CdMode2Formless:
{
sectorOffset = 0;
sectorSize = (uint)track.RawBytesPerSector;
mode2 = true;
2022-03-06 13:29:38 +00:00
break;
}
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
case TrackType.Audio:
{
sectorOffset = 0;
sectorSize = 2352;
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
break;
}
2023-10-03 23:34:59 +01:00
default:
return ErrorNumber.NotSupported;
2022-03-06 13:29:38 +00:00
}
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
buffer = new byte[sectorSize];
2022-03-06 13:29:38 +00:00
if(mode2)
buffer = Sector.GetUserDataFromMode2(sector);
else if(track.Type == TrackType.Audio && _swapAudio)
2023-10-03 23:34:59 +01:00
{
for(var i = 0; i < 2352; i += 2)
2017-12-19 20:33:03 +00:00
{
2022-03-06 13:29:38 +00:00
buffer[i + 1] = sector[i];
buffer[i] = sector[i + 1];
}
2023-10-03 23:34:59 +01:00
}
2022-03-06 13:29:38 +00:00
else
Array.Copy(sector, sectorOffset, buffer, 0, sectorSize);
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
return ErrorNumber.NoError;
}
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
/// <inheritdoc />
public ErrorNumber ReadSectorTag(ulong sectorAddress, SectorTagType tag, out byte[] buffer)
{
buffer = null;
2021-09-21 04:55:28 +01:00
2024-05-01 04:05:22 +01:00
if(_isHdd) return ErrorNumber.NotSupported;
2017-12-19 20:33:03 +00:00
2024-05-01 04:05:22 +01:00
if(sectorAddress > _imageInfo.Sectors - 1) return ErrorNumber.OutOfRange;
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
var track = new Track();
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
uint sectorSize;
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
if(!_sectorCache.TryGetValue(sectorAddress, out byte[] sector))
{
track = GetTrack(sectorAddress);
sectorSize = (uint)track.RawBytesPerSector;
2022-03-06 13:29:38 +00:00
ulong hunkNo = sectorAddress / _sectorsPerHunk;
ulong secOff = sectorAddress * sectorSize % (_sectorsPerHunk * sectorSize);
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
ErrorNumber errno = GetHunk(hunkNo, out byte[] hunk);
2017-12-19 20:33:03 +00:00
2024-05-01 04:05:22 +01:00
if(errno != ErrorNumber.NoError) return errno;
2022-03-06 13:29:38 +00:00
sector = new byte[_imageInfo.SectorSize];
Array.Copy(hunk, (int)secOff, sector, 0, sector.Length);
2024-05-01 04:05:22 +01:00
if(_sectorCache.Count >= _maxSectorCache) _sectorCache.Clear();
2022-03-06 13:29:38 +00:00
_sectorCache.Add(sectorAddress, sector);
}
2022-03-06 13:29:38 +00:00
if(_isHdd)
{
buffer = sector;
2022-03-06 13:29:38 +00:00
return ErrorNumber.NoError;
}
2022-03-06 13:29:38 +00:00
uint sectorOffset;
2022-03-06 13:29:38 +00:00
if(tag == SectorTagType.CdSectorSubchannel)
2023-10-03 23:34:59 +01:00
{
2022-03-06 13:29:38 +00:00
switch(track.SubchannelType)
{
2023-10-03 23:34:59 +01:00
case TrackSubchannelType.None:
return ErrorNumber.NoData;
2022-03-06 13:29:38 +00:00
case TrackSubchannelType.RawInterleaved:
sectorOffset = (uint)track.RawBytesPerSector;
sectorSize = 96;
2022-03-06 13:29:38 +00:00
break;
2023-10-03 23:34:59 +01:00
default:
return ErrorNumber.NotSupported;
2022-03-06 13:29:38 +00:00
}
2023-10-03 23:34:59 +01:00
}
2022-03-06 13:29:38 +00:00
else
2023-10-03 23:34:59 +01:00
{
2022-03-06 13:29:38 +00:00
switch(track.Type)
{
case TrackType.CdMode1:
case TrackType.CdMode2Form1:
{
if(track.RawBytesPerSector == 2352)
2023-10-03 23:34:59 +01:00
{
2022-03-06 13:29:38 +00:00
switch(tag)
{
case SectorTagType.CdSectorSync:
{
sectorOffset = 0;
sectorSize = 12;
2022-03-06 13:29:38 +00:00
break;
}
2022-03-06 13:29:38 +00:00
case SectorTagType.CdSectorHeader:
{
sectorOffset = 12;
sectorSize = 4;
2022-03-06 13:29:38 +00:00
break;
}
2023-10-03 23:34:59 +01:00
case SectorTagType.CdSectorSubHeader:
return ErrorNumber.NotSupported;
2022-03-06 13:29:38 +00:00
case SectorTagType.CdSectorEcc:
{
sectorOffset = 2076;
sectorSize = 276;
2022-03-06 13:29:38 +00:00
break;
2017-12-19 20:33:03 +00:00
}
2022-03-06 13:29:38 +00:00
case SectorTagType.CdSectorEccP:
2017-12-19 20:33:03 +00:00
{
2022-03-06 13:29:38 +00:00
sectorOffset = 2076;
sectorSize = 172;
2022-03-06 13:29:38 +00:00
break;
}
2022-03-06 13:29:38 +00:00
case SectorTagType.CdSectorEccQ:
{
sectorOffset = 2248;
sectorSize = 104;
2022-03-06 13:29:38 +00:00
break;
}
2022-03-06 13:29:38 +00:00
case SectorTagType.CdSectorEdc:
{
sectorOffset = 2064;
sectorSize = 4;
2022-03-06 13:29:38 +00:00
break;
}
2023-10-03 23:34:59 +01:00
default:
return ErrorNumber.NotSupported;
2022-03-06 13:29:38 +00:00
}
2023-10-03 23:34:59 +01:00
}
2022-03-06 13:29:38 +00:00
else
return ErrorNumber.NoData;
2022-03-06 13:29:38 +00:00
break;
}
2022-03-06 13:29:38 +00:00
case TrackType.CdMode2Form2:
{
if(track.RawBytesPerSector == 2352)
2023-10-03 23:34:59 +01:00
{
2022-03-06 13:29:38 +00:00
switch(tag)
{
case SectorTagType.CdSectorSync:
2017-12-19 20:33:03 +00:00
{
2022-03-06 13:29:38 +00:00
sectorOffset = 0;
sectorSize = 12;
2022-03-06 13:29:38 +00:00
break;
}
2022-03-06 13:29:38 +00:00
case SectorTagType.CdSectorHeader:
{
sectorOffset = 12;
sectorSize = 4;
2022-03-06 13:29:38 +00:00
break;
2017-12-19 20:33:03 +00:00
}
2022-03-06 13:29:38 +00:00
case SectorTagType.CdSectorSubHeader:
2017-12-19 20:33:03 +00:00
{
2022-03-06 13:29:38 +00:00
sectorOffset = 16;
sectorSize = 8;
2022-03-06 13:29:38 +00:00
break;
}
2022-03-06 13:29:38 +00:00
case SectorTagType.CdSectorEdc:
{
sectorOffset = 2348;
sectorSize = 4;
2022-03-06 13:29:38 +00:00
break;
}
2023-10-03 23:34:59 +01:00
default:
return ErrorNumber.NotSupported;
2022-03-06 13:29:38 +00:00
}
2023-10-03 23:34:59 +01:00
}
2022-03-06 13:29:38 +00:00
else
2023-10-03 23:34:59 +01:00
{
2022-03-06 13:29:38 +00:00
switch(tag)
{
case SectorTagType.CdSectorSync:
case SectorTagType.CdSectorHeader:
case SectorTagType.CdSectorEcc:
case SectorTagType.CdSectorEccP:
2023-10-03 23:34:59 +01:00
case SectorTagType.CdSectorEccQ:
return ErrorNumber.NotSupported;
2022-03-06 13:29:38 +00:00
case SectorTagType.CdSectorSubHeader:
{
sectorOffset = 0;
sectorSize = 8;
break;
2017-12-19 20:33:03 +00:00
}
2022-03-06 13:29:38 +00:00
case SectorTagType.CdSectorEdc:
{
sectorOffset = 2332;
sectorSize = 4;
2022-03-06 13:29:38 +00:00
break;
}
2017-12-19 20:33:03 +00:00
2023-10-03 23:34:59 +01:00
default:
return ErrorNumber.NotSupported;
2022-03-06 13:29:38 +00:00
}
2023-10-03 23:34:59 +01:00
}
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
break;
2017-12-19 20:33:03 +00:00
}
2022-03-06 13:29:38 +00:00
case TrackType.CdMode2Formless:
2017-12-19 20:33:03 +00:00
{
2022-03-06 13:29:38 +00:00
if(track.RawBytesPerSector == 2352)
2023-10-03 23:34:59 +01:00
{
2022-03-06 13:29:38 +00:00
switch(tag)
{
case SectorTagType.CdSectorSync:
case SectorTagType.CdSectorHeader:
case SectorTagType.CdSectorEcc:
case SectorTagType.CdSectorEccP:
2023-10-03 23:34:59 +01:00
case SectorTagType.CdSectorEccQ:
return ErrorNumber.NotSupported;
2022-03-06 13:29:38 +00:00
case SectorTagType.CdSectorSubHeader:
{
sectorOffset = 0;
sectorSize = 8;
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
break;
}
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
case SectorTagType.CdSectorEdc:
{
sectorOffset = 2332;
sectorSize = 4;
2022-03-06 13:29:38 +00:00
break;
}
2017-12-19 20:33:03 +00:00
2023-10-03 23:34:59 +01:00
default:
return ErrorNumber.NotSupported;
2022-03-06 13:29:38 +00:00
}
2023-10-03 23:34:59 +01:00
}
2022-03-06 13:29:38 +00:00
else
return ErrorNumber.NoData;
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
break;
}
2017-12-19 20:33:03 +00:00
2023-10-03 23:34:59 +01:00
case TrackType.Audio:
return ErrorNumber.NoData;
default:
return ErrorNumber.NotImplemented;
2022-03-06 13:29:38 +00:00
}
2023-10-03 23:34:59 +01:00
}
2022-03-06 13:29:38 +00:00
buffer = new byte[sectorSize];
2022-03-06 13:29:38 +00:00
if(track.Type == TrackType.Audio && _swapAudio)
2023-10-03 23:34:59 +01:00
{
for(var i = 0; i < 2352; i += 2)
2022-03-06 13:29:38 +00:00
{
buffer[i + 1] = sector[i];
buffer[i] = sector[i + 1];
2017-12-19 20:33:03 +00:00
}
2023-10-03 23:34:59 +01:00
}
2022-03-06 13:29:38 +00:00
else
Array.Copy(sector, sectorOffset, buffer, 0, sectorSize);
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
if(track.Type == TrackType.Audio && _swapAudio)
2023-10-03 23:34:59 +01:00
{
for(var i = 0; i < 2352; i += 2)
2022-03-06 13:29:38 +00:00
{
buffer[i + 1] = sector[i];
buffer[i] = sector[i + 1];
}
2023-10-03 23:34:59 +01:00
}
2022-03-06 13:29:38 +00:00
else
Array.Copy(sector, sectorOffset, buffer, 0, sectorSize);
2022-03-06 13:29:38 +00:00
return ErrorNumber.NoError;
}
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
/// <inheritdoc />
public ErrorNumber ReadSectors(ulong sectorAddress, uint length, out byte[] buffer)
{
buffer = null;
2024-05-01 04:05:22 +01:00
if(sectorAddress > _imageInfo.Sectors - 1) return ErrorNumber.OutOfRange;
2017-12-19 20:33:03 +00:00
2024-05-01 04:05:22 +01:00
if(sectorAddress + length > _imageInfo.Sectors) return ErrorNumber.OutOfRange;
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
var ms = new MemoryStream();
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
for(uint i = 0; i < length; i++)
{
ErrorNumber errno = ReadSector(sectorAddress + i, out byte[] sector);
2024-05-01 04:05:22 +01:00
if(errno != ErrorNumber.NoError) return errno;
2022-03-06 13:29:38 +00:00
ms.Write(sector, 0, sector.Length);
}
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
buffer = ms.ToArray();
2022-03-06 13:29:38 +00:00
return ErrorNumber.NoError;
}
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
/// <inheritdoc />
public ErrorNumber ReadSectorsTag(ulong sectorAddress, uint length, SectorTagType tag, out byte[] buffer)
{
buffer = null;
2024-05-01 04:05:22 +01:00
if(sectorAddress > _imageInfo.Sectors - 1) return ErrorNumber.OutOfRange;
2017-12-19 20:33:03 +00:00
2024-05-01 04:05:22 +01:00
if(sectorAddress + length > _imageInfo.Sectors) return ErrorNumber.OutOfRange;
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
var ms = new MemoryStream();
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
for(uint i = 0; i < length; i++)
{
ErrorNumber errno = ReadSectorTag(sectorAddress + i, tag, out byte[] sector);
2017-12-19 20:33:03 +00:00
2024-05-01 04:05:22 +01:00
if(errno != ErrorNumber.NoError) return errno;
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
ms.Write(sector, 0, sector.Length);
}
2021-09-21 04:55:28 +01:00
2022-03-06 13:29:38 +00:00
buffer = ms.ToArray();
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
return ErrorNumber.NoError;
}
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
/// <inheritdoc />
public ErrorNumber ReadSectorLong(ulong sectorAddress, out byte[] buffer)
{
buffer = null;
2017-12-19 20:33:03 +00:00
2024-05-01 04:05:22 +01:00
if(_isHdd) return ReadSector(sectorAddress, out buffer);
2017-12-19 20:33:03 +00:00
2024-05-01 04:05:22 +01:00
if(sectorAddress > _imageInfo.Sectors - 1) return ErrorNumber.OutOfRange;
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
var track = new Track();
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
if(!_sectorCache.TryGetValue(sectorAddress, out byte[] sector))
{
track = GetTrack(sectorAddress);
2023-10-03 23:34:59 +01:00
var sectorSize = (uint)track.RawBytesPerSector;
2022-03-06 13:29:38 +00:00
ulong hunkNo = sectorAddress / _sectorsPerHunk;
ulong secOff = sectorAddress * sectorSize % (_sectorsPerHunk * sectorSize);
2022-03-06 13:29:38 +00:00
ErrorNumber errno = GetHunk(hunkNo, out byte[] hunk);
2024-05-01 04:05:22 +01:00
if(errno != ErrorNumber.NoError) return errno;
2022-03-06 13:29:38 +00:00
sector = new byte[_imageInfo.SectorSize];
Array.Copy(hunk, (int)secOff, sector, 0, sector.Length);
2024-05-01 04:05:22 +01:00
if(_sectorCache.Count >= _maxSectorCache) _sectorCache.Clear();
2022-03-06 13:29:38 +00:00
_sectorCache.Add(sectorAddress, sector);
}
2022-03-06 13:29:38 +00:00
buffer = new byte[track.RawBytesPerSector];
2022-03-06 13:29:38 +00:00
if(track.Type == TrackType.Audio && _swapAudio)
2023-10-03 23:34:59 +01:00
{
for(var i = 0; i < 2352; i += 2)
2022-03-06 13:29:38 +00:00
{
buffer[i + 1] = sector[i];
buffer[i] = sector[i + 1];
}
2023-10-03 23:34:59 +01:00
}
2022-03-06 13:29:38 +00:00
else
Array.Copy(sector, 0, buffer, 0, track.RawBytesPerSector);
2022-03-06 13:29:38 +00:00
switch(track.Type)
{
case TrackType.CdMode1 when track.RawBytesPerSector == 2048:
{
2023-10-03 23:34:59 +01:00
var fullSector = new byte[2352];
2022-03-06 13:29:38 +00:00
Array.Copy(buffer, 0, fullSector, 16, 2048);
_sectorBuilder.ReconstructPrefix(ref fullSector, TrackType.CdMode1, (long)sectorAddress);
_sectorBuilder.ReconstructEcc(ref fullSector, TrackType.CdMode1);
2022-03-06 13:29:38 +00:00
buffer = fullSector;
2022-03-06 13:29:38 +00:00
break;
}
2022-03-06 13:29:38 +00:00
case TrackType.CdMode2Form1 when track.RawBytesPerSector == 2048:
{
2023-10-03 23:34:59 +01:00
var fullSector = new byte[2352];
2022-03-06 13:29:38 +00:00
Array.Copy(buffer, 0, fullSector, 24, 2048);
_sectorBuilder.ReconstructPrefix(ref fullSector, TrackType.CdMode2Form1, (long)sectorAddress);
_sectorBuilder.ReconstructEcc(ref fullSector, TrackType.CdMode2Form1);
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
buffer = fullSector;
2022-03-06 13:29:38 +00:00
break;
}
case TrackType.CdMode2Form1 when track.RawBytesPerSector == 2324:
{
2023-10-03 23:34:59 +01:00
var fullSector = new byte[2352];
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
Array.Copy(buffer, 0, fullSector, 24, 2324);
_sectorBuilder.ReconstructPrefix(ref fullSector, TrackType.CdMode2Form2, (long)sectorAddress);
_sectorBuilder.ReconstructEcc(ref fullSector, TrackType.CdMode2Form2);
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
buffer = fullSector;
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
break;
}
case TrackType.CdMode2Formless when track.RawBytesPerSector == 2336:
2017-12-19 20:33:03 +00:00
{
2023-10-03 23:34:59 +01:00
var fullSector = new byte[2352];
2022-03-06 13:29:38 +00:00
_sectorBuilder.ReconstructPrefix(ref fullSector, TrackType.CdMode2Formless, (long)sectorAddress);
Array.Copy(buffer, 0, fullSector, 16, 2336);
2022-03-06 13:29:38 +00:00
buffer = fullSector;
break;
2017-12-19 20:33:03 +00:00
}
2022-03-06 13:29:38 +00:00
}
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
return ErrorNumber.NoError;
}
2022-03-06 13:29:38 +00:00
/// <inheritdoc />
public ErrorNumber ReadSectorsLong(ulong sectorAddress, uint length, out byte[] buffer)
{
buffer = null;
2017-12-19 20:33:03 +00:00
2024-05-01 04:05:22 +01:00
if(sectorAddress > _imageInfo.Sectors - 1) return ErrorNumber.OutOfRange;
2017-12-19 20:33:03 +00:00
2024-05-01 04:05:22 +01:00
if(sectorAddress + length > _imageInfo.Sectors) return ErrorNumber.OutOfRange;
2022-03-06 13:29:38 +00:00
var ms = new MemoryStream();
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
for(uint i = 0; i < length; i++)
{
ErrorNumber errno = ReadSectorLong(sectorAddress + i, out byte[] sector);
2024-05-01 04:05:22 +01:00
if(errno != ErrorNumber.NoError) return errno;
2022-03-06 13:29:38 +00:00
ms.Write(sector, 0, sector.Length);
2017-12-19 20:33:03 +00:00
}
2022-03-06 13:29:38 +00:00
buffer = ms.ToArray();
return ErrorNumber.NoError;
}
2022-03-06 13:29:38 +00:00
/// <inheritdoc />
public ErrorNumber ReadMediaTag(MediaTagType tag, out byte[] buffer)
{
buffer = null;
2022-03-06 13:29:38 +00:00
switch(tag)
{
2022-03-06 13:29:38 +00:00
case MediaTagType.ATA_IDENTIFY:
if(_imageInfo.ReadableMediaTags.Contains(MediaTagType.ATA_IDENTIFY))
buffer = _identify?.Clone() as byte[];
2022-03-06 13:29:38 +00:00
return buffer == null ? ErrorNumber.NoData : ErrorNumber.NoError;
case MediaTagType.PCMCIA_CIS:
2024-05-01 04:05:22 +01:00
if(_imageInfo.ReadableMediaTags.Contains(MediaTagType.PCMCIA_CIS)) buffer = _cis?.Clone() as byte[];
2022-03-06 13:29:38 +00:00
return buffer == null ? ErrorNumber.NoData : ErrorNumber.NoError;
2023-10-03 23:34:59 +01:00
default:
return ErrorNumber.NotSupported;
}
2022-03-06 13:29:38 +00:00
}
2022-03-06 13:29:38 +00:00
/// <inheritdoc />
public List<Track> GetSessionTracks(Session session) => _isHdd ? null : GetSessionTracks(session.Sequence);
2022-03-06 13:29:38 +00:00
/// <inheritdoc />
public List<Track> GetSessionTracks(ushort session) =>
_isHdd ? null : _tracks.Values.Where(track => track.Session == session).ToList();
2022-03-06 13:29:38 +00:00
/// <inheritdoc />
public ErrorNumber ReadSector(ulong sectorAddress, uint track, out byte[] buffer)
{
buffer = null;
2022-03-06 13:29:38 +00:00
return _isHdd ? ErrorNumber.NotSupported : ReadSector(GetAbsoluteSector(sectorAddress, track), out buffer);
}
2022-03-06 13:29:38 +00:00
/// <inheritdoc />
public ErrorNumber ReadSectorTag(ulong sectorAddress, uint track, SectorTagType tag, out byte[] buffer)
{
buffer = null;
2023-10-03 23:34:59 +01:00
return _isHdd
? ErrorNumber.NotSupported
2022-03-06 13:29:38 +00:00
: ReadSectorTag(GetAbsoluteSector(sectorAddress, track), tag, out buffer);
}
2022-03-06 13:29:38 +00:00
/// <inheritdoc />
public ErrorNumber ReadSectors(ulong sectorAddress, uint length, uint track, out byte[] buffer)
{
buffer = null;
2023-10-03 23:34:59 +01:00
return _isHdd
? ErrorNumber.NotSupported
2022-03-06 13:29:38 +00:00
: ReadSectors(GetAbsoluteSector(sectorAddress, track), length, out buffer);
}
2022-03-06 13:29:38 +00:00
/// <inheritdoc />
2023-10-03 23:34:59 +01:00
public ErrorNumber ReadSectorsTag(ulong sectorAddress, uint length, uint track, SectorTagType tag,
2022-03-06 13:29:38 +00:00
out byte[] buffer)
{
buffer = null;
2023-10-03 23:34:59 +01:00
return _isHdd
? ErrorNumber.NotSupported
2022-03-06 13:29:38 +00:00
: ReadSectorsTag(GetAbsoluteSector(sectorAddress, track), length, tag, out buffer);
}
/// <inheritdoc />
public ErrorNumber ReadSectorLong(ulong sectorAddress, uint track, out byte[] buffer)
{
buffer = null;
2022-03-07 07:36:44 +00:00
return _isHdd ? ErrorNumber.NotSupported : ReadSectorLong(GetAbsoluteSector(sectorAddress, track), out buffer);
2022-03-06 13:29:38 +00:00
}
/// <inheritdoc />
public ErrorNumber ReadSectorsLong(ulong sectorAddress, uint length, uint track, out byte[] buffer)
{
buffer = null;
2023-10-03 23:34:59 +01:00
return _isHdd
? ErrorNumber.NotSupported
2022-03-06 13:29:38 +00:00
: ReadSectorLong(GetAbsoluteSector(sectorAddress, track), length, out buffer);
2017-12-19 20:33:03 +00:00
}
2023-10-03 23:34:59 +01:00
#endregion
2017-12-19 20:33:03 +00:00
}