Files
Aaru/DiscImageChef.DiscImages/CHD/Read.cs

1580 lines
83 KiB
C#
Raw Normal View History

// /***************************************************************************
// The Disc Image Chef
// ----------------------------------------------------------------------------
//
// 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/>.
//
// ----------------------------------------------------------------------------
2020-01-03 17:51:30 +00:00
// Copyright © 2011-2020 Natalia Portillo
// ****************************************************************************/
using System;
using System.Collections.Generic;
using System.IO;
2016-10-17 04:41:27 +01:00
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using DiscImageChef.CommonTypes;
using DiscImageChef.CommonTypes.Enums;
using DiscImageChef.CommonTypes.Exceptions;
using DiscImageChef.CommonTypes.Interfaces;
using DiscImageChef.CommonTypes.Structs;
using DiscImageChef.Console;
2018-12-31 13:17:27 +00:00
using DiscImageChef.Decoders.ATA;
using DiscImageChef.Helpers;
namespace DiscImageChef.DiscImages
{
public partial class Chd
2017-12-19 20:33:03 +00:00
{
public bool Open(IFilter imageFilter)
2017-12-19 20:33:03 +00:00
{
Stream stream = imageFilter.GetDataForkStream();
stream.Seek(0, SeekOrigin.Begin);
byte[] magic = new byte[8];
stream.Read(magic, 0, 8);
if(!chdTag.SequenceEqual(magic)) return false;
2017-12-19 20:33:03 +00:00
// Read length
byte[] buffer = new byte[4];
2017-12-19 20:33:03 +00:00
stream.Read(buffer, 0, 4);
uint length = BitConverter.ToUInt32(buffer.Reverse().ToArray(), 0);
2018-06-22 08:08:38 +01:00
buffer = new byte[4];
2017-12-19 20:33:03 +00:00
stream.Read(buffer, 0, 4);
uint version = BitConverter.ToUInt32(buffer.Reverse().ToArray(), 0);
buffer = new byte[length];
stream.Seek(0, SeekOrigin.Begin);
stream.Read(buffer, 0, (int)length);
ulong nextMetaOff = 0;
switch(version)
{
case 1:
{
2019-02-27 08:49:42 +00:00
ChdHeaderV1 hdrV1 = Marshal.ByteArrayToStructureBigEndian<ChdHeaderV1>(buffer);
2017-12-19 20:33:03 +00:00
DicConsole.DebugWriteLine("CHD plugin", "hdrV1.tag = \"{0}\"",
Encoding.ASCII.GetString(hdrV1.tag));
2017-12-19 20:33:03 +00:00
DicConsole.DebugWriteLine("CHD plugin", "hdrV1.length = {0} bytes", hdrV1.length);
DicConsole.DebugWriteLine("CHD plugin", "hdrV1.version = {0}", hdrV1.version);
DicConsole.DebugWriteLine("CHD plugin", "hdrV1.flags = {0}", (ChdFlags)hdrV1.flags);
2017-12-19 20:33:03 +00:00
DicConsole.DebugWriteLine("CHD plugin", "hdrV1.compression = {0}",
(ChdCompression)hdrV1.compression);
DicConsole.DebugWriteLine("CHD plugin", "hdrV1.hunksize = {0}", hdrV1.hunksize);
2017-12-19 20:33:03 +00:00
DicConsole.DebugWriteLine("CHD plugin", "hdrV1.totalhunks = {0}", hdrV1.totalhunks);
DicConsole.DebugWriteLine("CHD plugin", "hdrV1.cylinders = {0}", hdrV1.cylinders);
DicConsole.DebugWriteLine("CHD plugin", "hdrV1.heads = {0}", hdrV1.heads);
DicConsole.DebugWriteLine("CHD plugin", "hdrV1.sectors = {0}", hdrV1.sectors);
DicConsole.DebugWriteLine("CHD plugin", "hdrV1.md5 = {0}",
ArrayHelpers.ByteArrayToHex(hdrV1.md5));
2017-12-19 20:33:03 +00:00
DicConsole.DebugWriteLine("CHD plugin", "hdrV1.parentmd5 = {0}",
ArrayHelpers.ArrayIsNullOrEmpty(hdrV1.parentmd5)
? "null"
: ArrayHelpers.ByteArrayToHex(hdrV1.parentmd5));
DicConsole.DebugWriteLine("CHD plugin", "Reading Hunk map.");
DateTime start = DateTime.UtcNow;
hunkTable = new ulong[hdrV1.totalhunks];
uint hunkSectorCount = (uint)Math.Ceiling((double)hdrV1.totalhunks * 8 / 512);
2017-12-19 20:33:03 +00:00
byte[] hunkSectorBytes = new byte[512];
for(int i = 0; i < hunkSectorCount; i++)
{
stream.Read(hunkSectorBytes, 0, 512);
// 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
// This restores the order of elements
Array.Reverse(hunkSector.hunkEntry);
2018-06-22 08:08:38 +01:00
if(hunkTable.Length >= i * 512 / 8 + 512 / 8)
Array.Copy(hunkSector.hunkEntry, 0, hunkTable, i * 512 / 8, 512 / 8);
2017-12-19 20:33:03 +00:00
else
Array.Copy(hunkSector.hunkEntry, 0, hunkTable, i * 512 / 8, hunkTable.Length - i * 512 / 8);
2017-12-19 20:33:03 +00:00
}
DateTime end = DateTime.UtcNow;
DicConsole.DebugWriteLine("CHD plugin", "Took {0} seconds", (end - start).TotalSeconds);
2017-12-19 20:33:03 +00:00
imageInfo.MediaType = MediaType.GENERIC_HDD;
imageInfo.Sectors = hdrV1.hunksize * hdrV1.totalhunks;
imageInfo.XmlMediaType = XmlMediaType.BlockMedia;
imageInfo.SectorSize = 512;
imageInfo.Version = "1";
imageInfo.ImageSize = imageInfo.SectorSize * hdrV1.hunksize * hdrV1.totalhunks;
2017-12-19 20:33:03 +00:00
totalHunks = hdrV1.totalhunks;
2017-12-19 20:33:03 +00:00
sectorsPerHunk = hdrV1.hunksize;
hdrCompression = hdrV1.compression;
mapVersion = 1;
isHdd = true;
2017-12-19 20:33:03 +00:00
imageInfo.Cylinders = hdrV1.cylinders;
imageInfo.Heads = hdrV1.heads;
imageInfo.SectorsPerTrack = hdrV1.sectors;
2017-12-19 20:33:03 +00:00
break;
}
2017-12-19 20:33:03 +00:00
case 2:
{
2019-02-27 08:49:42 +00:00
ChdHeaderV2 hdrV2 = Marshal.ByteArrayToStructureBigEndian<ChdHeaderV2>(buffer);
2017-12-19 20:33:03 +00:00
DicConsole.DebugWriteLine("CHD plugin", "hdrV2.tag = \"{0}\"",
Encoding.ASCII.GetString(hdrV2.tag));
2017-12-19 20:33:03 +00:00
DicConsole.DebugWriteLine("CHD plugin", "hdrV2.length = {0} bytes", hdrV2.length);
DicConsole.DebugWriteLine("CHD plugin", "hdrV2.version = {0}", hdrV2.version);
DicConsole.DebugWriteLine("CHD plugin", "hdrV2.flags = {0}", (ChdFlags)hdrV2.flags);
2017-12-19 20:33:03 +00:00
DicConsole.DebugWriteLine("CHD plugin", "hdrV2.compression = {0}",
(ChdCompression)hdrV2.compression);
DicConsole.DebugWriteLine("CHD plugin", "hdrV2.hunksize = {0}", hdrV2.hunksize);
2017-12-19 20:33:03 +00:00
DicConsole.DebugWriteLine("CHD plugin", "hdrV2.totalhunks = {0}", hdrV2.totalhunks);
DicConsole.DebugWriteLine("CHD plugin", "hdrV2.cylinders = {0}", hdrV2.cylinders);
DicConsole.DebugWriteLine("CHD plugin", "hdrV2.heads = {0}", hdrV2.heads);
DicConsole.DebugWriteLine("CHD plugin", "hdrV2.sectors = {0}", hdrV2.sectors);
DicConsole.DebugWriteLine("CHD plugin", "hdrV2.md5 = {0}",
ArrayHelpers.ByteArrayToHex(hdrV2.md5));
2017-12-19 20:33:03 +00:00
DicConsole.DebugWriteLine("CHD plugin", "hdrV2.parentmd5 = {0}",
ArrayHelpers.ArrayIsNullOrEmpty(hdrV2.parentmd5)
? "null"
: ArrayHelpers.ByteArrayToHex(hdrV2.parentmd5));
DicConsole.DebugWriteLine("CHD plugin", "hdrV2.seclen = {0}", hdrV2.seclen);
DicConsole.DebugWriteLine("CHD plugin", "Reading Hunk map.");
DateTime start = DateTime.UtcNow;
hunkTable = new ulong[hdrV2.totalhunks];
// How many sectors uses the BAT
uint hunkSectorCount = (uint)Math.Ceiling((double)hdrV2.totalhunks * 8 / 512);
2017-12-19 20:33:03 +00:00
byte[] hunkSectorBytes = new byte[512];
for(int i = 0; i < hunkSectorCount; i++)
{
stream.Read(hunkSectorBytes, 0, 512);
// 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
// This restores the order of elements
Array.Reverse(hunkSector.hunkEntry);
2018-06-22 08:08:38 +01:00
if(hunkTable.Length >= i * 512 / 8 + 512 / 8)
Array.Copy(hunkSector.hunkEntry, 0, hunkTable, i * 512 / 8, 512 / 8);
2017-12-19 20:33:03 +00:00
else
Array.Copy(hunkSector.hunkEntry, 0, hunkTable, i * 512 / 8, hunkTable.Length - i * 512 / 8);
2017-12-19 20:33:03 +00:00
}
DateTime end = DateTime.UtcNow;
DicConsole.DebugWriteLine("CHD plugin", "Took {0} seconds", (end - start).TotalSeconds);
2017-12-19 20:33:03 +00:00
imageInfo.MediaType = MediaType.GENERIC_HDD;
imageInfo.Sectors = hdrV2.hunksize * hdrV2.totalhunks;
imageInfo.XmlMediaType = XmlMediaType.BlockMedia;
imageInfo.SectorSize = hdrV2.seclen;
imageInfo.Version = "2";
imageInfo.ImageSize = imageInfo.SectorSize * hdrV2.hunksize * hdrV2.totalhunks;
2017-12-19 20:33:03 +00:00
totalHunks = hdrV2.totalhunks;
2017-12-19 20:33:03 +00:00
sectorsPerHunk = hdrV2.hunksize;
hdrCompression = hdrV2.compression;
mapVersion = 1;
isHdd = true;
2017-12-19 20:33:03 +00:00
imageInfo.Cylinders = hdrV2.cylinders;
imageInfo.Heads = hdrV2.heads;
imageInfo.SectorsPerTrack = hdrV2.sectors;
2017-12-19 20:33:03 +00:00
break;
}
2017-12-19 20:33:03 +00:00
case 3:
{
2019-02-27 08:49:42 +00:00
ChdHeaderV3 hdrV3 = Marshal.ByteArrayToStructureBigEndian<ChdHeaderV3>(buffer);
2017-12-19 20:33:03 +00:00
DicConsole.DebugWriteLine("CHD plugin", "hdrV3.tag = \"{0}\"",
Encoding.ASCII.GetString(hdrV3.tag));
2017-12-19 20:33:03 +00:00
DicConsole.DebugWriteLine("CHD plugin", "hdrV3.length = {0} bytes", hdrV3.length);
DicConsole.DebugWriteLine("CHD plugin", "hdrV3.version = {0}", hdrV3.version);
DicConsole.DebugWriteLine("CHD plugin", "hdrV3.flags = {0}", (ChdFlags)hdrV3.flags);
2017-12-19 20:33:03 +00:00
DicConsole.DebugWriteLine("CHD plugin", "hdrV3.compression = {0}",
(ChdCompression)hdrV3.compression);
DicConsole.DebugWriteLine("CHD plugin", "hdrV3.totalhunks = {0}", hdrV3.totalhunks);
2017-12-19 20:33:03 +00:00
DicConsole.DebugWriteLine("CHD plugin", "hdrV3.logicalbytes = {0}", hdrV3.logicalbytes);
DicConsole.DebugWriteLine("CHD plugin", "hdrV3.metaoffset = {0}", hdrV3.metaoffset);
DicConsole.DebugWriteLine("CHD plugin", "hdrV3.md5 = {0}",
ArrayHelpers.ByteArrayToHex(hdrV3.md5));
2017-12-19 20:33:03 +00:00
DicConsole.DebugWriteLine("CHD plugin", "hdrV3.parentmd5 = {0}",
ArrayHelpers.ArrayIsNullOrEmpty(hdrV3.parentmd5)
? "null"
: ArrayHelpers.ByteArrayToHex(hdrV3.parentmd5));
DicConsole.DebugWriteLine("CHD plugin", "hdrV3.hunkbytes = {0}", hdrV3.hunkbytes);
DicConsole.DebugWriteLine("CHD plugin", "hdrV3.sha1 = {0}",
ArrayHelpers.ByteArrayToHex(hdrV3.sha1));
DicConsole.DebugWriteLine("CHD plugin", "hdrV3.parentsha1 = {0}",
ArrayHelpers.ArrayIsNullOrEmpty(hdrV3.parentsha1)
? "null"
: ArrayHelpers.ByteArrayToHex(hdrV3.parentsha1));
DicConsole.DebugWriteLine("CHD plugin", "Reading Hunk map.");
DateTime start = DateTime.UtcNow;
hunkMap = new byte[hdrV3.totalhunks * 16];
stream.Read(hunkMap, 0, hunkMap.Length);
DateTime end = DateTime.UtcNow;
DicConsole.DebugWriteLine("CHD plugin", "Took {0} seconds", (end - start).TotalSeconds);
2017-12-19 20:33:03 +00:00
nextMetaOff = hdrV3.metaoffset;
imageInfo.ImageSize = hdrV3.logicalbytes;
imageInfo.Version = "3";
2017-12-19 20:33:03 +00:00
totalHunks = hdrV3.totalhunks;
bytesPerHunk = hdrV3.hunkbytes;
2017-12-19 20:33:03 +00:00
hdrCompression = hdrV3.compression;
mapVersion = 3;
2017-12-19 20:33:03 +00:00
break;
}
2017-12-19 20:33:03 +00:00
case 4:
{
2019-02-27 08:49:42 +00:00
ChdHeaderV4 hdrV4 = Marshal.ByteArrayToStructureBigEndian<ChdHeaderV4>(buffer);
2017-12-19 20:33:03 +00:00
DicConsole.DebugWriteLine("CHD plugin", "hdrV4.tag = \"{0}\"",
Encoding.ASCII.GetString(hdrV4.tag));
2017-12-19 20:33:03 +00:00
DicConsole.DebugWriteLine("CHD plugin", "hdrV4.length = {0} bytes", hdrV4.length);
DicConsole.DebugWriteLine("CHD plugin", "hdrV4.version = {0}", hdrV4.version);
DicConsole.DebugWriteLine("CHD plugin", "hdrV4.flags = {0}", (ChdFlags)hdrV4.flags);
2017-12-19 20:33:03 +00:00
DicConsole.DebugWriteLine("CHD plugin", "hdrV4.compression = {0}",
(ChdCompression)hdrV4.compression);
DicConsole.DebugWriteLine("CHD plugin", "hdrV4.totalhunks = {0}", hdrV4.totalhunks);
2017-12-19 20:33:03 +00:00
DicConsole.DebugWriteLine("CHD plugin", "hdrV4.logicalbytes = {0}", hdrV4.logicalbytes);
DicConsole.DebugWriteLine("CHD plugin", "hdrV4.metaoffset = {0}", hdrV4.metaoffset);
DicConsole.DebugWriteLine("CHD plugin", "hdrV4.hunkbytes = {0}", hdrV4.hunkbytes);
2017-12-19 20:33:03 +00:00
DicConsole.DebugWriteLine("CHD plugin", "hdrV4.sha1 = {0}",
ArrayHelpers.ByteArrayToHex(hdrV4.sha1));
DicConsole.DebugWriteLine("CHD plugin", "hdrV4.parentsha1 = {0}",
ArrayHelpers.ArrayIsNullOrEmpty(hdrV4.parentsha1)
? "null"
: ArrayHelpers.ByteArrayToHex(hdrV4.parentsha1));
DicConsole.DebugWriteLine("CHD plugin", "hdrV4.rawsha1 = {0}",
ArrayHelpers.ByteArrayToHex(hdrV4.rawsha1));
DicConsole.DebugWriteLine("CHD plugin", "Reading Hunk map.");
DateTime start = DateTime.UtcNow;
hunkMap = new byte[hdrV4.totalhunks * 16];
stream.Read(hunkMap, 0, hunkMap.Length);
DateTime end = DateTime.UtcNow;
DicConsole.DebugWriteLine("CHD plugin", "Took {0} seconds", (end - start).TotalSeconds);
2017-12-19 20:33:03 +00:00
nextMetaOff = hdrV4.metaoffset;
imageInfo.ImageSize = hdrV4.logicalbytes;
imageInfo.Version = "4";
2017-12-19 20:33:03 +00:00
totalHunks = hdrV4.totalhunks;
bytesPerHunk = hdrV4.hunkbytes;
2017-12-19 20:33:03 +00:00
hdrCompression = hdrV4.compression;
mapVersion = 3;
2017-12-19 20:33:03 +00:00
break;
}
2017-12-19 20:33:03 +00:00
case 5:
{
2019-02-27 08:49:42 +00:00
ChdHeaderV5 hdrV5 = Marshal.ByteArrayToStructureBigEndian<ChdHeaderV5>(buffer);
2017-12-19 20:33:03 +00:00
DicConsole.DebugWriteLine("CHD plugin", "hdrV5.tag = \"{0}\"",
Encoding.ASCII.GetString(hdrV5.tag));
2017-12-19 20:33:03 +00:00
DicConsole.DebugWriteLine("CHD plugin", "hdrV5.length = {0} bytes", hdrV5.length);
DicConsole.DebugWriteLine("CHD plugin", "hdrV5.version = {0}", hdrV5.version);
2017-12-19 20:33:03 +00:00
DicConsole.DebugWriteLine("CHD plugin", "hdrV5.compressor0 = \"{0}\"",
Encoding.ASCII.GetString(BigEndianBitConverter
.GetBytes(hdrV5.compressor0)));
2017-12-19 20:33:03 +00:00
DicConsole.DebugWriteLine("CHD plugin", "hdrV5.compressor1 = \"{0}\"",
Encoding.ASCII.GetString(BigEndianBitConverter
.GetBytes(hdrV5.compressor1)));
2017-12-19 20:33:03 +00:00
DicConsole.DebugWriteLine("CHD plugin", "hdrV5.compressor2 = \"{0}\"",
Encoding.ASCII.GetString(BigEndianBitConverter
.GetBytes(hdrV5.compressor2)));
2017-12-19 20:33:03 +00:00
DicConsole.DebugWriteLine("CHD plugin", "hdrV5.compressor3 = \"{0}\"",
Encoding.ASCII.GetString(BigEndianBitConverter
.GetBytes(hdrV5.compressor3)));
2017-12-19 20:33:03 +00:00
DicConsole.DebugWriteLine("CHD plugin", "hdrV5.logicalbytes = {0}", hdrV5.logicalbytes);
DicConsole.DebugWriteLine("CHD plugin", "hdrV5.mapoffset = {0}", hdrV5.mapoffset);
DicConsole.DebugWriteLine("CHD plugin", "hdrV5.metaoffset = {0}", hdrV5.metaoffset);
DicConsole.DebugWriteLine("CHD plugin", "hdrV5.hunkbytes = {0}", hdrV5.hunkbytes);
DicConsole.DebugWriteLine("CHD plugin", "hdrV5.unitbytes = {0}", hdrV5.unitbytes);
2017-12-19 20:33:03 +00:00
DicConsole.DebugWriteLine("CHD plugin", "hdrV5.sha1 = {0}",
ArrayHelpers.ByteArrayToHex(hdrV5.sha1));
DicConsole.DebugWriteLine("CHD plugin", "hdrV5.parentsha1 = {0}",
ArrayHelpers.ArrayIsNullOrEmpty(hdrV5.parentsha1)
? "null"
: ArrayHelpers.ByteArrayToHex(hdrV5.parentsha1));
DicConsole.DebugWriteLine("CHD plugin", "hdrV5.rawsha1 = {0}",
ArrayHelpers.ByteArrayToHex(hdrV5.rawsha1));
// TODO: Implement compressed CHD v5
if(hdrV5.compressor0 == 0)
{
DicConsole.DebugWriteLine("CHD plugin", "Reading Hunk map.");
DateTime start = DateTime.UtcNow;
hunkTableSmall = new uint[hdrV5.logicalbytes / hdrV5.hunkbytes];
uint hunkSectorCount = (uint)Math.Ceiling((double)hunkTableSmall.Length * 4 / 512);
2017-12-19 20:33:03 +00:00
byte[] hunkSectorBytes = new byte[512];
stream.Seek((long)hdrV5.mapoffset, SeekOrigin.Begin);
for(int i = 0; i < hunkSectorCount; i++)
{
stream.Read(hunkSectorBytes, 0, 512);
// This does the big-endian trick but reverses the order of elements also
Array.Reverse(hunkSectorBytes);
HunkSectorSmall hunkSector =
Marshal.ByteArrayToStructureLittleEndian<HunkSectorSmall>(hunkSectorBytes);
2017-12-19 20:33:03 +00:00
// This restores the order of elements
Array.Reverse(hunkSector.hunkEntry);
2018-06-22 08:08:38 +01:00
if(hunkTableSmall.Length >= i * 512 / 4 + 512 / 4)
Array.Copy(hunkSector.hunkEntry, 0, hunkTableSmall, i * 512 / 4, 512 / 4);
2017-12-19 20:33:03 +00:00
else
Array.Copy(hunkSector.hunkEntry, 0, hunkTableSmall, i * 512 / 4,
2018-06-22 08:08:38 +01:00
hunkTableSmall.Length - i * 512 / 4);
2017-12-19 20:33:03 +00:00
}
DateTime end = DateTime.UtcNow;
DicConsole.DebugWriteLine("CHD plugin", "Took {0} seconds", (end - start).TotalSeconds);
2017-12-19 20:33:03 +00:00
}
else throw new ImageNotSupportedException("Cannot read compressed CHD version 5");
nextMetaOff = hdrV5.metaoffset;
imageInfo.ImageSize = hdrV5.logicalbytes;
imageInfo.Version = "5";
2017-12-19 20:33:03 +00:00
totalHunks = (uint)(hdrV5.logicalbytes / hdrV5.hunkbytes);
bytesPerHunk = hdrV5.hunkbytes;
hdrCompression = hdrV5.compressor0;
2017-12-19 20:33:03 +00:00
hdrCompression1 = hdrV5.compressor1;
hdrCompression2 = hdrV5.compressor2;
hdrCompression3 = hdrV5.compressor3;
mapVersion = 5;
2017-12-19 20:33:03 +00:00
break;
}
default: throw new ImageNotSupportedException($"Unsupported CHD version {version}");
2017-12-19 20:33:03 +00:00
}
if(mapVersion >= 3)
{
isCdrom = false;
isHdd = false;
isGdrom = false;
2017-12-19 20:33:03 +00:00
swapAudio = false;
tracks = new Dictionary<uint, Track>();
2017-12-19 20:33:03 +00:00
DicConsole.DebugWriteLine("CHD plugin", "Reading metadata.");
ulong currentSector = 0;
uint currentTrack = 1;
2017-12-19 20:33:03 +00:00
while(nextMetaOff > 0)
{
byte[] hdrBytes = new byte[16];
stream.Seek((long)nextMetaOff, SeekOrigin.Begin);
stream.Read(hdrBytes, 0, hdrBytes.Length);
2019-02-27 08:49:42 +00:00
ChdMetadataHeader header = Marshal.ByteArrayToStructureBigEndian<ChdMetadataHeader>(hdrBytes);
byte[] meta = new byte[header.flagsAndLength & 0xFFFFFF];
2017-12-19 20:33:03 +00:00
stream.Read(meta, 0, meta.Length);
DicConsole.DebugWriteLine("CHD plugin", "Found metadata \"{0}\"",
Encoding.ASCII.GetString(BigEndianBitConverter.GetBytes(header.tag)));
switch(header.tag)
{
// "GDDD"
case HARD_DISK_METADATA:
2017-12-19 20:33:03 +00:00
if(isCdrom || isGdrom)
throw new
ImageNotSupportedException("Image cannot be a hard disk and a C/GD-ROM at the same time, aborting.");
string gddd = StringHandlers.CToString(meta);
Regex gdddRegEx = new Regex(REGEX_METADATA_HDD);
Match gdddMatch = gdddRegEx.Match(gddd);
2017-12-19 20:33:03 +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
}
2017-12-19 20:33:03 +00:00
break;
// "CHCD"
case CDROM_OLD_METADATA:
2017-12-19 20:33:03 +00:00
if(isHdd)
throw new
ImageNotSupportedException("Image cannot be a hard disk and a CD-ROM at the same time, aborting.");
if(isGdrom)
throw new
ImageNotSupportedException("Image cannot be a GD-ROM and a CD-ROM at the same time, aborting.");
uint chdTracksNumber = BigEndianBitConverter.ToUInt32(meta, 0);
2017-12-19 20:33:03 +00:00
// Byteswapped
if(chdTracksNumber > 99) chdTracksNumber = BigEndianBitConverter.ToUInt32(meta, 0);
2017-12-19 20:33:03 +00:00
currentSector = 0;
for(uint i = 0; i < chdTracksNumber; i++)
2017-12-19 20:33:03 +00:00
{
ChdTrackOld chdTrack = new ChdTrackOld
{
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))
};
Track dicTrack = new Track();
switch((ChdOldTrackType)chdTrack.type)
2017-12-19 20:33:03 +00:00
{
case ChdOldTrackType.Audio:
dicTrack.TrackBytesPerSector = 2352;
dicTrack.TrackRawBytesPerSector = 2352;
dicTrack.TrackType = TrackType.Audio;
2017-12-19 20:33:03 +00:00
break;
case ChdOldTrackType.Mode1:
dicTrack.TrackBytesPerSector = 2048;
dicTrack.TrackRawBytesPerSector = 2048;
dicTrack.TrackType = TrackType.CdMode1;
2017-12-19 20:33:03 +00:00
break;
case ChdOldTrackType.Mode1Raw:
dicTrack.TrackBytesPerSector = 2048;
dicTrack.TrackRawBytesPerSector = 2352;
dicTrack.TrackType = TrackType.CdMode1;
2017-12-19 20:33:03 +00:00
break;
case ChdOldTrackType.Mode2:
case ChdOldTrackType.Mode2FormMix:
dicTrack.TrackBytesPerSector = 2336;
dicTrack.TrackRawBytesPerSector = 2336;
dicTrack.TrackType = TrackType.CdMode2Formless;
2017-12-19 20:33:03 +00:00
break;
case ChdOldTrackType.Mode2Form1:
dicTrack.TrackBytesPerSector = 2048;
dicTrack.TrackRawBytesPerSector = 2048;
dicTrack.TrackType = TrackType.CdMode2Form1;
2017-12-19 20:33:03 +00:00
break;
case ChdOldTrackType.Mode2Form2:
dicTrack.TrackBytesPerSector = 2324;
dicTrack.TrackRawBytesPerSector = 2324;
dicTrack.TrackType = TrackType.CdMode2Form2;
2017-12-19 20:33:03 +00:00
break;
case ChdOldTrackType.Mode2Raw:
dicTrack.TrackBytesPerSector = 2336;
dicTrack.TrackRawBytesPerSector = 2352;
dicTrack.TrackType = TrackType.CdMode2Formless;
2017-12-19 20:33:03 +00:00
break;
default:
throw new ImageNotSupportedException($"Unsupported track type {chdTrack.type}");
2017-12-19 20:33:03 +00:00
}
switch((ChdOldSubType)chdTrack.subType)
2017-12-19 20:33:03 +00:00
{
case ChdOldSubType.Cooked:
dicTrack.TrackSubchannelFile = imageFilter.GetFilename();
dicTrack.TrackSubchannelType = TrackSubchannelType.PackedInterleaved;
dicTrack.TrackSubchannelFilter = imageFilter;
2017-12-19 20:33:03 +00:00
break;
case ChdOldSubType.None:
dicTrack.TrackSubchannelType = TrackSubchannelType.None;
2017-12-19 20:33:03 +00:00
break;
case ChdOldSubType.Raw:
dicTrack.TrackSubchannelFile = imageFilter.GetFilename();
dicTrack.TrackSubchannelType = TrackSubchannelType.RawInterleaved;
dicTrack.TrackSubchannelFilter = imageFilter;
2017-12-19 20:33:03 +00:00
break;
default:
throw new
ImageNotSupportedException($"Unsupported subchannel type {chdTrack.type}");
2017-12-19 20:33:03 +00:00
}
dicTrack.Indexes = new Dictionary<int, ulong>();
2018-06-22 08:08:38 +01:00
dicTrack.TrackDescription = $"Track {i + 1}";
dicTrack.TrackEndSector = currentSector + chdTrack.frames - 1;
dicTrack.TrackFile = imageFilter.GetFilename();
dicTrack.TrackFileType = "BINARY";
dicTrack.TrackFilter = imageFilter;
dicTrack.TrackStartSector = currentSector;
dicTrack.TrackSequence = i + 1;
dicTrack.TrackSession = 1;
currentSector += chdTrack.frames + chdTrack.extraFrames;
tracks.Add(dicTrack.TrackSequence, dicTrack);
2017-12-19 20:33:03 +00:00
}
isCdrom = true;
2017-12-19 20:33:03 +00:00
break;
// "CHTR"
case CDROM_TRACK_METADATA:
2017-12-19 20:33:03 +00:00
if(isHdd)
throw new
ImageNotSupportedException("Image cannot be a hard disk and a CD-ROM at the same time, aborting.");
if(isGdrom)
throw new
ImageNotSupportedException("Image cannot be a GD-ROM and a CD-ROM at the same time, aborting.");
string chtr = StringHandlers.CToString(meta);
Regex chtrRegEx = new Regex(REGEX_METADATA_CDROM);
Match chtrMatch = chtrRegEx.Match(chtr);
2017-12-19 20:33:03 +00:00
if(chtrMatch.Success)
{
isCdrom = true;
uint trackNo = uint.Parse(chtrMatch.Groups["track"].Value);
uint frames = uint.Parse(chtrMatch.Groups["frames"].Value);
string subtype = chtrMatch.Groups["sub_type"].Value;
2017-12-19 20:33:03 +00:00
string tracktype = chtrMatch.Groups["track_type"].Value;
if(trackNo != currentTrack)
throw new ImageNotSupportedException("Unsorted tracks, cannot proceed.");
Track dicTrack = new Track();
2017-12-19 20:33:03 +00:00
switch(tracktype)
{
case TRACK_TYPE_AUDIO:
dicTrack.TrackBytesPerSector = 2352;
dicTrack.TrackRawBytesPerSector = 2352;
dicTrack.TrackType = TrackType.Audio;
2017-12-19 20:33:03 +00:00
break;
case TRACK_TYPE_MODE1:
case TRACK_TYPE_MODE1_2K:
dicTrack.TrackBytesPerSector = 2048;
dicTrack.TrackRawBytesPerSector = 2048;
dicTrack.TrackType = TrackType.CdMode1;
2017-12-19 20:33:03 +00:00
break;
case TRACK_TYPE_MODE1_RAW:
case TRACK_TYPE_MODE1_RAW_2K:
dicTrack.TrackBytesPerSector = 2048;
dicTrack.TrackRawBytesPerSector = 2352;
dicTrack.TrackType = TrackType.CdMode1;
2017-12-19 20:33:03 +00:00
break;
case TRACK_TYPE_MODE2:
case TRACK_TYPE_MODE2_2K:
case TRACK_TYPE_MODE2_FM:
dicTrack.TrackBytesPerSector = 2336;
dicTrack.TrackRawBytesPerSector = 2336;
dicTrack.TrackType = TrackType.CdMode2Formless;
2017-12-19 20:33:03 +00:00
break;
case TRACK_TYPE_MODE2_F1:
case TRACK_TYPE_MODE2_F1_2K:
dicTrack.TrackBytesPerSector = 2048;
dicTrack.TrackRawBytesPerSector = 2048;
dicTrack.TrackType = TrackType.CdMode2Form1;
2017-12-19 20:33:03 +00:00
break;
case TRACK_TYPE_MODE2_F2:
case TRACK_TYPE_MODE2_F2_2K:
dicTrack.TrackBytesPerSector = 2324;
dicTrack.TrackRawBytesPerSector = 2324;
dicTrack.TrackType = TrackType.CdMode2Form2;
2017-12-19 20:33:03 +00:00
break;
case TRACK_TYPE_MODE2_RAW:
case TRACK_TYPE_MODE2_RAW_2K:
dicTrack.TrackBytesPerSector = 2336;
dicTrack.TrackRawBytesPerSector = 2352;
dicTrack.TrackType = TrackType.CdMode2Formless;
2017-12-19 20:33:03 +00:00
break;
default:
throw new ImageNotSupportedException($"Unsupported track type {tracktype}");
2017-12-19 20:33:03 +00:00
}
switch(subtype)
{
case SUB_TYPE_COOKED:
dicTrack.TrackSubchannelFile = imageFilter.GetFilename();
dicTrack.TrackSubchannelType = TrackSubchannelType.PackedInterleaved;
dicTrack.TrackSubchannelFilter = imageFilter;
2017-12-19 20:33:03 +00:00
break;
case SUB_TYPE_NONE:
dicTrack.TrackSubchannelType = TrackSubchannelType.None;
2017-12-19 20:33:03 +00:00
break;
case SUB_TYPE_RAW:
dicTrack.TrackSubchannelFile = imageFilter.GetFilename();
dicTrack.TrackSubchannelType = TrackSubchannelType.RawInterleaved;
dicTrack.TrackSubchannelFilter = imageFilter;
2017-12-19 20:33:03 +00:00
break;
default:
throw new ImageNotSupportedException($"Unsupported subchannel type {subtype}");
2017-12-19 20:33:03 +00:00
}
dicTrack.Indexes = new Dictionary<int, ulong>();
dicTrack.TrackDescription = $"Track {trackNo}";
dicTrack.TrackEndSector = currentSector + frames - 1;
dicTrack.TrackFile = imageFilter.GetFilename();
dicTrack.TrackFileType = "BINARY";
dicTrack.TrackFilter = imageFilter;
dicTrack.TrackStartSector = currentSector;
dicTrack.TrackSequence = trackNo;
dicTrack.TrackSession = 1;
currentSector += frames;
2017-12-19 20:33:03 +00:00
currentTrack++;
tracks.Add(dicTrack.TrackSequence, dicTrack);
2017-12-19 20:33:03 +00:00
}
break;
// "CHT2"
case CDROM_TRACK_METADATA2:
2017-12-19 20:33:03 +00:00
if(isHdd)
throw new
ImageNotSupportedException("Image cannot be a hard disk and a CD-ROM at the same time, aborting.");
if(isGdrom)
throw new
ImageNotSupportedException("Image cannot be a GD-ROM and a CD-ROM at the same time, aborting.");
string cht2 = StringHandlers.CToString(meta);
Regex cht2RegEx = new Regex(REGEX_METADATA_CDROM2);
Match cht2Match = cht2RegEx.Match(cht2);
2017-12-19 20:33:03 +00:00
if(cht2Match.Success)
{
isCdrom = true;
uint trackNo = uint.Parse(cht2Match.Groups["track"].Value);
uint frames = uint.Parse(cht2Match.Groups["frames"].Value);
string subtype = cht2Match.Groups["sub_type"].Value;
2017-12-19 20:33:03 +00:00
string tracktype = cht2Match.Groups["track_type"].Value;
// TODO: Check pregap and postgap behaviour
uint pregap = uint.Parse(cht2Match.Groups["pregap"].Value);
string pregapType = cht2Match.Groups["pgtype"].Value;
2017-12-19 20:33:03 +00:00
string pregapSubType = cht2Match.Groups["pgsub"].Value;
uint postgap = uint.Parse(cht2Match.Groups["postgap"].Value);
2017-12-19 20:33:03 +00:00
if(trackNo != currentTrack)
throw new ImageNotSupportedException("Unsorted tracks, cannot proceed.");
Track dicTrack = new Track();
2017-12-19 20:33:03 +00:00
switch(tracktype)
{
case TRACK_TYPE_AUDIO:
dicTrack.TrackBytesPerSector = 2352;
dicTrack.TrackRawBytesPerSector = 2352;
dicTrack.TrackType = TrackType.Audio;
2017-12-19 20:33:03 +00:00
break;
case TRACK_TYPE_MODE1:
case TRACK_TYPE_MODE1_2K:
dicTrack.TrackBytesPerSector = 2048;
dicTrack.TrackRawBytesPerSector = 2048;
dicTrack.TrackType = TrackType.CdMode1;
2017-12-19 20:33:03 +00:00
break;
case TRACK_TYPE_MODE1_RAW:
case TRACK_TYPE_MODE1_RAW_2K:
dicTrack.TrackBytesPerSector = 2048;
dicTrack.TrackRawBytesPerSector = 2352;
dicTrack.TrackType = TrackType.CdMode1;
2017-12-19 20:33:03 +00:00
break;
case TRACK_TYPE_MODE2:
case TRACK_TYPE_MODE2_2K:
case TRACK_TYPE_MODE2_FM:
dicTrack.TrackBytesPerSector = 2336;
dicTrack.TrackRawBytesPerSector = 2336;
dicTrack.TrackType = TrackType.CdMode2Formless;
2017-12-19 20:33:03 +00:00
break;
case TRACK_TYPE_MODE2_F1:
case TRACK_TYPE_MODE2_F1_2K:
dicTrack.TrackBytesPerSector = 2048;
dicTrack.TrackRawBytesPerSector = 2048;
dicTrack.TrackType = TrackType.CdMode2Form1;
2017-12-19 20:33:03 +00:00
break;
case TRACK_TYPE_MODE2_F2:
case TRACK_TYPE_MODE2_F2_2K:
dicTrack.TrackBytesPerSector = 2324;
dicTrack.TrackRawBytesPerSector = 2324;
dicTrack.TrackType = TrackType.CdMode2Form2;
2017-12-19 20:33:03 +00:00
break;
case TRACK_TYPE_MODE2_RAW:
case TRACK_TYPE_MODE2_RAW_2K:
dicTrack.TrackBytesPerSector = 2336;
dicTrack.TrackRawBytesPerSector = 2352;
dicTrack.TrackType = TrackType.CdMode2Formless;
2017-12-19 20:33:03 +00:00
break;
default:
throw new ImageNotSupportedException($"Unsupported track type {tracktype}");
2017-12-19 20:33:03 +00:00
}
switch(subtype)
{
case SUB_TYPE_COOKED:
dicTrack.TrackSubchannelFile = imageFilter.GetFilename();
dicTrack.TrackSubchannelType = TrackSubchannelType.PackedInterleaved;
dicTrack.TrackSubchannelFilter = imageFilter;
2017-12-19 20:33:03 +00:00
break;
case SUB_TYPE_NONE:
dicTrack.TrackSubchannelType = TrackSubchannelType.None;
2017-12-19 20:33:03 +00:00
break;
case SUB_TYPE_RAW:
dicTrack.TrackSubchannelFile = imageFilter.GetFilename();
dicTrack.TrackSubchannelType = TrackSubchannelType.RawInterleaved;
dicTrack.TrackSubchannelFilter = imageFilter;
2017-12-19 20:33:03 +00:00
break;
default:
throw new ImageNotSupportedException($"Unsupported subchannel type {subtype}");
2017-12-19 20:33:03 +00:00
}
dicTrack.Indexes = new Dictionary<int, ulong>();
dicTrack.TrackDescription = $"Track {trackNo}";
dicTrack.TrackEndSector = currentSector + frames - 1;
dicTrack.TrackFile = imageFilter.GetFilename();
dicTrack.TrackFileType = "BINARY";
dicTrack.TrackFilter = imageFilter;
dicTrack.TrackStartSector = currentSector;
dicTrack.TrackSequence = trackNo;
dicTrack.TrackSession = 1;
currentSector += frames;
2017-12-19 20:33:03 +00:00
currentTrack++;
tracks.Add(dicTrack.TrackSequence, dicTrack);
2017-12-19 20:33:03 +00:00
}
break;
// "CHGT"
case GDROM_OLD_METADATA:
2017-12-19 20:33:03 +00:00
swapAudio = true;
goto case GDROM_METADATA;
2017-12-19 20:33:03 +00:00
// "CHGD"
case GDROM_METADATA:
2017-12-19 20:33:03 +00:00
if(isHdd)
throw new
ImageNotSupportedException("Image cannot be a hard disk and a GD-ROM at the same time, aborting.");
if(isCdrom)
throw new
ImageNotSupportedException("Image cannot be a CD-ROM and a GD-ROM at the same time, aborting.");
string chgd = StringHandlers.CToString(meta);
Regex chgdRegEx = new Regex(REGEX_METADATA_GDROM);
Match chgdMatch = chgdRegEx.Match(chgd);
2017-12-19 20:33:03 +00:00
if(chgdMatch.Success)
{
isGdrom = true;
uint trackNo = uint.Parse(chgdMatch.Groups["track"].Value);
uint frames = uint.Parse(chgdMatch.Groups["frames"].Value);
string subtype = chgdMatch.Groups["sub_type"].Value;
2017-12-19 20:33:03 +00:00
string tracktype = chgdMatch.Groups["track_type"].Value;
// TODO: Check pregap, postgap and pad behaviour
uint pregap = uint.Parse(chgdMatch.Groups["pregap"].Value);
string pregapType = chgdMatch.Groups["pgtype"].Value;
2017-12-19 20:33:03 +00:00
string pregapSubType = chgdMatch.Groups["pgsub"].Value;
uint postgap = uint.Parse(chgdMatch.Groups["postgap"].Value);
uint pad = uint.Parse(chgdMatch.Groups["pad"].Value);
2017-12-19 20:33:03 +00:00
if(trackNo != currentTrack)
throw new ImageNotSupportedException("Unsorted tracks, cannot proceed.");
Track dicTrack = new Track();
2017-12-19 20:33:03 +00:00
switch(tracktype)
{
case TRACK_TYPE_AUDIO:
dicTrack.TrackBytesPerSector = 2352;
dicTrack.TrackRawBytesPerSector = 2352;
dicTrack.TrackType = TrackType.Audio;
2017-12-19 20:33:03 +00:00
break;
case TRACK_TYPE_MODE1:
case TRACK_TYPE_MODE1_2K:
dicTrack.TrackBytesPerSector = 2048;
dicTrack.TrackRawBytesPerSector = 2048;
dicTrack.TrackType = TrackType.CdMode1;
2017-12-19 20:33:03 +00:00
break;
case TRACK_TYPE_MODE1_RAW:
case TRACK_TYPE_MODE1_RAW_2K:
dicTrack.TrackBytesPerSector = 2048;
dicTrack.TrackRawBytesPerSector = 2352;
dicTrack.TrackType = TrackType.CdMode1;
2017-12-19 20:33:03 +00:00
break;
case TRACK_TYPE_MODE2:
case TRACK_TYPE_MODE2_2K:
case TRACK_TYPE_MODE2_FM:
dicTrack.TrackBytesPerSector = 2336;
dicTrack.TrackRawBytesPerSector = 2336;
dicTrack.TrackType = TrackType.CdMode2Formless;
2017-12-19 20:33:03 +00:00
break;
case TRACK_TYPE_MODE2_F1:
case TRACK_TYPE_MODE2_F1_2K:
dicTrack.TrackBytesPerSector = 2048;
dicTrack.TrackRawBytesPerSector = 2048;
dicTrack.TrackType = TrackType.CdMode2Form1;
2017-12-19 20:33:03 +00:00
break;
case TRACK_TYPE_MODE2_F2:
case TRACK_TYPE_MODE2_F2_2K:
dicTrack.TrackBytesPerSector = 2324;
dicTrack.TrackRawBytesPerSector = 2324;
dicTrack.TrackType = TrackType.CdMode2Form2;
2017-12-19 20:33:03 +00:00
break;
case TRACK_TYPE_MODE2_RAW:
case TRACK_TYPE_MODE2_RAW_2K:
dicTrack.TrackBytesPerSector = 2336;
dicTrack.TrackRawBytesPerSector = 2352;
dicTrack.TrackType = TrackType.CdMode2Formless;
2017-12-19 20:33:03 +00:00
break;
default:
throw new ImageNotSupportedException($"Unsupported track type {tracktype}");
2017-12-19 20:33:03 +00:00
}
switch(subtype)
{
case SUB_TYPE_COOKED:
dicTrack.TrackSubchannelFile = imageFilter.GetFilename();
dicTrack.TrackSubchannelType = TrackSubchannelType.PackedInterleaved;
dicTrack.TrackSubchannelFilter = imageFilter;
2017-12-19 20:33:03 +00:00
break;
case SUB_TYPE_NONE:
dicTrack.TrackSubchannelType = TrackSubchannelType.None;
2017-12-19 20:33:03 +00:00
break;
case SUB_TYPE_RAW:
dicTrack.TrackSubchannelFile = imageFilter.GetFilename();
dicTrack.TrackSubchannelType = TrackSubchannelType.RawInterleaved;
dicTrack.TrackSubchannelFilter = imageFilter;
2017-12-19 20:33:03 +00:00
break;
default:
throw new ImageNotSupportedException($"Unsupported subchannel type {subtype}");
2017-12-19 20:33:03 +00:00
}
dicTrack.Indexes = new Dictionary<int, ulong>();
dicTrack.TrackDescription = $"Track {trackNo}";
dicTrack.TrackEndSector = currentSector + frames - 1;
dicTrack.TrackFile = imageFilter.GetFilename();
dicTrack.TrackFileType = "BINARY";
dicTrack.TrackFilter = imageFilter;
dicTrack.TrackStartSector = currentSector;
dicTrack.TrackSequence = trackNo;
dicTrack.TrackSession = (ushort)(trackNo > 2 ? 2 : 1);
currentSector += frames;
2017-12-19 20:33:03 +00:00
currentTrack++;
tracks.Add(dicTrack.TrackSequence, dicTrack);
2017-12-19 20:33:03 +00:00
}
break;
// "IDNT"
case HARD_DISK_IDENT_METADATA:
2018-12-31 13:17:27 +00:00
Identify.IdentifyDevice? idnt = Decoders.ATA.Identify.Decode(meta);
2017-12-19 20:33:03 +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;
if(idnt.Value.CurrentCylinders > 0 && idnt.Value.CurrentHeads > 0 &&
2017-12-19 20:33:03 +00:00
idnt.Value.CurrentSectorsPerTrack > 0)
{
imageInfo.Cylinders = idnt.Value.CurrentCylinders;
imageInfo.Heads = idnt.Value.CurrentHeads;
imageInfo.SectorsPerTrack = idnt.Value.CurrentSectorsPerTrack;
2017-12-19 20:33:03 +00:00
}
else
{
imageInfo.Cylinders = idnt.Value.Cylinders;
imageInfo.Heads = idnt.Value.Heads;
imageInfo.SectorsPerTrack = idnt.Value.SectorsPerTrack;
2017-12-19 20:33:03 +00:00
}
}
2017-12-19 20:33:03 +00:00
identify = meta;
if(!imageInfo.ReadableMediaTags.Contains(MediaTagType.ATA_IDENTIFY))
imageInfo.ReadableMediaTags.Add(MediaTagType.ATA_IDENTIFY);
2017-12-19 20:33:03 +00:00
break;
case PCMCIA_CIS_METADATA:
2017-12-19 20:33:03 +00:00
cis = meta;
if(!imageInfo.ReadableMediaTags.Contains(MediaTagType.PCMCIA_CIS))
imageInfo.ReadableMediaTags.Add(MediaTagType.PCMCIA_CIS);
2017-12-19 20:33:03 +00:00
break;
}
nextMetaOff = header.next;
}
if(isHdd)
{
sectorsPerHunk = bytesPerHunk / imageInfo.SectorSize;
imageInfo.Sectors = imageInfo.ImageSize / imageInfo.SectorSize;
imageInfo.MediaType = MediaType.GENERIC_HDD;
imageInfo.XmlMediaType = XmlMediaType.BlockMedia;
2017-12-19 20:33:03 +00:00
}
else if(isCdrom)
{
// Hardcoded on MAME for CD-ROM
sectorsPerHunk = 8;
imageInfo.MediaType = MediaType.CDROM;
imageInfo.XmlMediaType = XmlMediaType.OpticalDisc;
2017-12-19 20:33:03 +00:00
foreach(Track dicTrack in tracks.Values)
imageInfo.Sectors += dicTrack.TrackEndSector - dicTrack.TrackStartSector + 1;
2017-12-19 20:33:03 +00:00
}
else if(isGdrom)
{
// Hardcoded on MAME for GD-ROM
sectorsPerHunk = 8;
imageInfo.MediaType = MediaType.GDROM;
imageInfo.XmlMediaType = XmlMediaType.OpticalDisc;
2017-12-19 20:33:03 +00:00
foreach(Track dicTrack in tracks.Values)
imageInfo.Sectors += dicTrack.TrackEndSector - dicTrack.TrackStartSector + 1;
2017-12-19 20:33:03 +00:00
}
2018-06-22 08:08:38 +01:00
else throw new ImageNotSupportedException("Image does not represent a known media, aborting");
2017-12-19 20:33:03 +00:00
}
if(isCdrom || isGdrom)
{
2018-06-22 08:08:38 +01:00
offsetmap = new Dictionary<ulong, uint>();
partitions = new List<Partition>();
2017-12-19 20:33:03 +00:00
ulong partPos = 0;
foreach(Track dicTrack in tracks.Values)
2017-12-19 20:33:03 +00:00
{
Partition partition = new Partition
{
Description = dicTrack.TrackDescription,
2018-06-22 08:08:38 +01:00
Size =
(dicTrack.TrackEndSector - dicTrack.TrackStartSector + 1) *
(ulong)dicTrack.TrackRawBytesPerSector,
Length = dicTrack.TrackEndSector - dicTrack.TrackStartSector + 1,
Sequence = dicTrack.TrackSequence,
Offset = partPos,
Start = dicTrack.TrackStartSector,
Type = dicTrack.TrackType.ToString()
};
2017-12-19 20:33:03 +00:00
partPos += partition.Length;
offsetmap.Add(dicTrack.TrackStartSector, dicTrack.TrackSequence);
2017-12-19 20:33:03 +00:00
if(dicTrack.TrackSubchannelType != TrackSubchannelType.None)
if(!imageInfo.ReadableSectorTags.Contains(SectorTagType.CdSectorSubchannel))
imageInfo.ReadableSectorTags.Add(SectorTagType.CdSectorSubchannel);
2017-12-19 20:33:03 +00:00
switch(dicTrack.TrackType)
2017-12-19 20:33:03 +00:00
{
case TrackType.CdMode1:
case TrackType.CdMode2Form1:
if(dicTrack.TrackRawBytesPerSector == 2352)
2017-12-19 20:33:03 +00:00
{
if(!imageInfo.ReadableSectorTags.Contains(SectorTagType.CdSectorSync))
imageInfo.ReadableSectorTags.Add(SectorTagType.CdSectorSync);
if(!imageInfo.ReadableSectorTags.Contains(SectorTagType.CdSectorHeader))
imageInfo.ReadableSectorTags.Add(SectorTagType.CdSectorHeader);
if(!imageInfo.ReadableSectorTags.Contains(SectorTagType.CdSectorSubHeader))
imageInfo.ReadableSectorTags.Add(SectorTagType.CdSectorSubHeader);
if(!imageInfo.ReadableSectorTags.Contains(SectorTagType.CdSectorEcc))
imageInfo.ReadableSectorTags.Add(SectorTagType.CdSectorEcc);
if(!imageInfo.ReadableSectorTags.Contains(SectorTagType.CdSectorEccP))
imageInfo.ReadableSectorTags.Add(SectorTagType.CdSectorEccP);
if(!imageInfo.ReadableSectorTags.Contains(SectorTagType.CdSectorEccQ))
imageInfo.ReadableSectorTags.Add(SectorTagType.CdSectorEccQ);
if(!imageInfo.ReadableSectorTags.Contains(SectorTagType.CdSectorEdc))
imageInfo.ReadableSectorTags.Add(SectorTagType.CdSectorEdc);
2017-12-19 20:33:03 +00:00
}
2017-12-19 20:33:03 +00:00
break;
case TrackType.CdMode2Form2:
if(dicTrack.TrackRawBytesPerSector == 2352)
2017-12-19 20:33:03 +00:00
{
if(!imageInfo.ReadableSectorTags.Contains(SectorTagType.CdSectorSync))
imageInfo.ReadableSectorTags.Add(SectorTagType.CdSectorSync);
if(!imageInfo.ReadableSectorTags.Contains(SectorTagType.CdSectorHeader))
imageInfo.ReadableSectorTags.Add(SectorTagType.CdSectorHeader);
if(!imageInfo.ReadableSectorTags.Contains(SectorTagType.CdSectorSubHeader))
imageInfo.ReadableSectorTags.Add(SectorTagType.CdSectorSubHeader);
if(!imageInfo.ReadableSectorTags.Contains(SectorTagType.CdSectorEdc))
imageInfo.ReadableSectorTags.Add(SectorTagType.CdSectorEdc);
2017-12-19 20:33:03 +00:00
}
2017-12-19 20:33:03 +00:00
break;
case TrackType.CdMode2Formless:
if(dicTrack.TrackRawBytesPerSector == 2352)
2017-12-19 20:33:03 +00:00
{
if(!imageInfo.ReadableSectorTags.Contains(SectorTagType.CdSectorSync))
imageInfo.ReadableSectorTags.Add(SectorTagType.CdSectorSync);
if(!imageInfo.ReadableSectorTags.Contains(SectorTagType.CdSectorHeader))
imageInfo.ReadableSectorTags.Add(SectorTagType.CdSectorHeader);
2017-12-19 20:33:03 +00:00
}
2017-12-19 20:33:03 +00:00
break;
}
if(dicTrack.TrackBytesPerSector > imageInfo.SectorSize)
imageInfo.SectorSize = (uint)dicTrack.TrackBytesPerSector;
2017-12-19 20:33:03 +00:00
partitions.Add(partition);
}
imageInfo.HasPartitions = true;
imageInfo.HasSessions = true;
2017-12-19 20:33:03 +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
imageStream = stream;
sectorCache = new Dictionary<ulong, byte[]>();
hunkCache = new Dictionary<ulong, byte[]>();
2017-12-19 20:33:03 +00:00
// TODO: Detect CompactFlash
// TODO: Get manufacturer and drive name from CIS if applicable
if(cis != null) imageInfo.MediaType = MediaType.PCCardTypeI;
2017-12-19 20:33:03 +00:00
return true;
}
public byte[] ReadSector(ulong sectorAddress)
2017-12-19 20:33:03 +00:00
{
if(sectorAddress > imageInfo.Sectors - 1)
2017-12-19 20:33:03 +00:00
throw new ArgumentOutOfRangeException(nameof(sectorAddress),
$"Sector address {sectorAddress} not found");
2017-12-19 20:33:03 +00:00
Track track = new Track();
uint sectorSize;
2017-12-19 20:33:03 +00:00
if(!sectorCache.TryGetValue(sectorAddress, out byte[] sector))
2017-12-19 20:33:03 +00:00
{
if(isHdd) sectorSize = imageInfo.SectorSize;
2017-12-19 20:33:03 +00:00
else
{
track = GetTrack(sectorAddress);
2017-12-19 20:33:03 +00:00
sectorSize = (uint)track.TrackRawBytesPerSector;
}
2018-06-22 08:08:38 +01:00
ulong hunkNo = sectorAddress / sectorsPerHunk;
ulong secOff = sectorAddress * sectorSize % (sectorsPerHunk * sectorSize);
2017-12-19 20:33:03 +00:00
byte[] hunk = GetHunk(hunkNo);
sector = new byte[imageInfo.SectorSize];
2017-12-19 20:33:03 +00:00
Array.Copy(hunk, (int)secOff, sector, 0, sector.Length);
if(sectorCache.Count >= maxSectorCache) sectorCache.Clear();
sectorCache.Add(sectorAddress, sector);
}
if(isHdd) return sector;
uint sectorOffset;
2017-12-19 20:33:03 +00:00
switch(track.TrackType)
{
case TrackType.CdMode1:
case TrackType.CdMode2Form1:
2017-12-19 20:33:03 +00:00
{
if(track.TrackRawBytesPerSector == 2352)
{
sectorOffset = 16;
sectorSize = 2048;
2017-12-19 20:33:03 +00:00
}
else
{
sectorOffset = 0;
sectorSize = 2048;
2017-12-19 20:33:03 +00:00
}
2017-12-19 20:33:03 +00:00
break;
}
case TrackType.CdMode2Form2:
2017-12-19 20:33:03 +00:00
{
if(track.TrackRawBytesPerSector == 2352)
{
sectorOffset = 16;
sectorSize = 2324;
2017-12-19 20:33:03 +00:00
}
else
{
sectorOffset = 0;
sectorSize = 2324;
2017-12-19 20:33:03 +00:00
}
2017-12-19 20:33:03 +00:00
break;
}
case TrackType.CdMode2Formless:
2017-12-19 20:33:03 +00:00
{
if(track.TrackRawBytesPerSector == 2352)
{
sectorOffset = 16;
sectorSize = 2336;
2017-12-19 20:33:03 +00:00
}
else
{
sectorOffset = 0;
sectorSize = 2336;
2017-12-19 20:33:03 +00:00
}
2017-12-19 20:33:03 +00:00
break;
}
2017-12-19 20:33:03 +00:00
case TrackType.Audio:
{
sectorOffset = 0;
sectorSize = 2352;
2017-12-19 20:33:03 +00:00
break;
}
2017-12-19 20:33:03 +00:00
default: throw new FeatureSupportedButNotImplementedImageException("Unsupported track type");
}
byte[] buffer = new byte[sectorSize];
2017-12-19 20:33:03 +00:00
2018-06-22 08:08:38 +01:00
if(track.TrackType == TrackType.Audio && swapAudio)
2017-12-19 20:33:03 +00:00
for(int i = 0; i < 2352; i += 2)
{
buffer[i + 1] = sector[i];
buffer[i] = sector[i + 1];
2017-12-19 20:33:03 +00:00
}
else Array.Copy(sector, sectorOffset, buffer, 0, sectorSize);
2017-12-19 20:33:03 +00:00
return buffer;
}
public byte[] ReadSectorTag(ulong sectorAddress, SectorTagType tag)
2017-12-19 20:33:03 +00:00
{
if(isHdd) throw new FeatureNotPresentImageException("Hard disk images do not have sector tags");
if(sectorAddress > imageInfo.Sectors - 1)
2017-12-19 20:33:03 +00:00
throw new ArgumentOutOfRangeException(nameof(sectorAddress),
$"Sector address {sectorAddress} not found");
2017-12-19 20:33:03 +00:00
Track track = new Track();
uint sectorSize;
if(!sectorCache.TryGetValue(sectorAddress, out byte[] sector))
2017-12-19 20:33:03 +00:00
{
track = GetTrack(sectorAddress);
2017-12-19 20:33:03 +00:00
sectorSize = (uint)track.TrackRawBytesPerSector;
2018-06-22 08:08:38 +01:00
ulong hunkNo = sectorAddress / sectorsPerHunk;
ulong secOff = sectorAddress * sectorSize % (sectorsPerHunk * sectorSize);
2017-12-19 20:33:03 +00:00
byte[] hunk = GetHunk(hunkNo);
sector = new byte[imageInfo.SectorSize];
2017-12-19 20:33:03 +00:00
Array.Copy(hunk, (int)secOff, sector, 0, sector.Length);
if(sectorCache.Count >= maxSectorCache) sectorCache.Clear();
sectorCache.Add(sectorAddress, sector);
}
if(isHdd) return sector;
uint sectorOffset;
2017-12-19 20:33:03 +00:00
if(tag == SectorTagType.CdSectorSubchannel)
switch(track.TrackSubchannelType)
{
case TrackSubchannelType.None:
throw new FeatureNotPresentImageException("Requested sector does not contain subchannel");
case TrackSubchannelType.RawInterleaved:
sectorOffset = (uint)track.TrackRawBytesPerSector;
sectorSize = 96;
break;
default:
throw new
FeatureSupportedButNotImplementedImageException($"Unsupported subchannel type {track.TrackSubchannelType}");
2017-12-19 20:33:03 +00:00
}
else
switch(track.TrackType)
{
case TrackType.CdMode1:
case TrackType.CdMode2Form1:
2017-12-19 20:33:03 +00:00
{
if(track.TrackRawBytesPerSector == 2352)
switch(tag)
{
case SectorTagType.CdSectorSync:
2017-12-19 20:33:03 +00:00
{
sectorOffset = 0;
sectorSize = 12;
2017-12-19 20:33:03 +00:00
break;
}
case SectorTagType.CdSectorHeader:
2017-12-19 20:33:03 +00:00
{
sectorOffset = 12;
sectorSize = 4;
2017-12-19 20:33:03 +00:00
break;
}
case SectorTagType.CdSectorSubHeader:
2017-12-19 20:33:03 +00:00
throw new ArgumentException("Unsupported tag requested for this track",
nameof(tag));
case SectorTagType.CdSectorEcc:
2017-12-19 20:33:03 +00:00
{
sectorOffset = 2076;
sectorSize = 276;
2017-12-19 20:33:03 +00:00
break;
}
case SectorTagType.CdSectorEccP:
2017-12-19 20:33:03 +00:00
{
sectorOffset = 2076;
sectorSize = 172;
2017-12-19 20:33:03 +00:00
break;
}
case SectorTagType.CdSectorEccQ:
2017-12-19 20:33:03 +00:00
{
sectorOffset = 2248;
sectorSize = 104;
2017-12-19 20:33:03 +00:00
break;
}
case SectorTagType.CdSectorEdc:
2017-12-19 20:33:03 +00:00
{
sectorOffset = 2064;
sectorSize = 4;
2017-12-19 20:33:03 +00:00
break;
}
2017-12-19 20:33:03 +00:00
default: throw new ArgumentException("Unsupported tag requested", nameof(tag));
}
else throw new FeatureNotPresentImageException("Requested sector does not contain tags");
break;
}
case TrackType.CdMode2Form2:
2017-12-19 20:33:03 +00:00
{
if(track.TrackRawBytesPerSector == 2352)
switch(tag)
{
case SectorTagType.CdSectorSync:
2017-12-19 20:33:03 +00:00
{
sectorOffset = 0;
sectorSize = 12;
2017-12-19 20:33:03 +00:00
break;
}
case SectorTagType.CdSectorHeader:
2017-12-19 20:33:03 +00:00
{
sectorOffset = 12;
sectorSize = 4;
2017-12-19 20:33:03 +00:00
break;
}
case SectorTagType.CdSectorSubHeader:
2017-12-19 20:33:03 +00:00
{
sectorOffset = 16;
sectorSize = 8;
2017-12-19 20:33:03 +00:00
break;
}
case SectorTagType.CdSectorEdc:
2017-12-19 20:33:03 +00:00
{
sectorOffset = 2348;
sectorSize = 4;
2017-12-19 20:33:03 +00:00
break;
}
2017-12-19 20:33:03 +00:00
default: throw new ArgumentException("Unsupported tag requested", nameof(tag));
}
else
switch(tag)
{
case SectorTagType.CdSectorSync:
case SectorTagType.CdSectorHeader:
case SectorTagType.CdSectorSubchannel:
case SectorTagType.CdSectorEcc:
case SectorTagType.CdSectorEccP:
case SectorTagType.CdSectorEccQ:
2017-12-19 20:33:03 +00:00
throw new ArgumentException("Unsupported tag requested for this track",
nameof(tag));
case SectorTagType.CdSectorSubHeader:
2017-12-19 20:33:03 +00:00
{
sectorOffset = 0;
sectorSize = 8;
2017-12-19 20:33:03 +00:00
break;
}
case SectorTagType.CdSectorEdc:
2017-12-19 20:33:03 +00:00
{
sectorOffset = 2332;
sectorSize = 4;
2017-12-19 20:33:03 +00:00
break;
}
2017-12-19 20:33:03 +00:00
default: throw new ArgumentException("Unsupported tag requested", nameof(tag));
}
break;
}
case TrackType.CdMode2Formless:
2017-12-19 20:33:03 +00:00
{
if(track.TrackRawBytesPerSector == 2352)
switch(tag)
{
case SectorTagType.CdSectorSync:
case SectorTagType.CdSectorHeader:
case SectorTagType.CdSectorEcc:
case SectorTagType.CdSectorEccP:
case SectorTagType.CdSectorEccQ:
2017-12-19 20:33:03 +00:00
throw new ArgumentException("Unsupported tag requested for this track",
nameof(tag));
case SectorTagType.CdSectorSubHeader:
2017-12-19 20:33:03 +00:00
{
sectorOffset = 0;
sectorSize = 8;
2017-12-19 20:33:03 +00:00
break;
}
case SectorTagType.CdSectorEdc:
2017-12-19 20:33:03 +00:00
{
sectorOffset = 2332;
sectorSize = 4;
2017-12-19 20:33:03 +00:00
break;
}
2017-12-19 20:33:03 +00:00
default: throw new ArgumentException("Unsupported tag requested", nameof(tag));
}
else throw new FeatureNotPresentImageException("Requested sector does not contain tags");
break;
}
2017-12-19 20:33:03 +00:00
case TrackType.Audio:
throw new FeatureNotPresentImageException("Requested sector does not contain tags");
default: throw new FeatureSupportedButNotImplementedImageException("Unsupported track type");
}
byte[] buffer = new byte[sectorSize];
2017-12-19 20:33:03 +00:00
2018-06-22 08:08:38 +01:00
if(track.TrackType == TrackType.Audio && swapAudio)
2017-12-19 20:33:03 +00:00
for(int i = 0; i < 2352; i += 2)
{
buffer[i + 1] = sector[i];
buffer[i] = sector[i + 1];
2017-12-19 20:33:03 +00:00
}
else Array.Copy(sector, sectorOffset, buffer, 0, sectorSize);
2017-12-19 20:33:03 +00:00
2018-06-22 08:08:38 +01:00
if(track.TrackType == TrackType.Audio && swapAudio)
2017-12-19 20:33:03 +00:00
for(int i = 0; i < 2352; i += 2)
{
buffer[i + 1] = sector[i];
buffer[i] = sector[i + 1];
2017-12-19 20:33:03 +00:00
}
else Array.Copy(sector, sectorOffset, buffer, 0, sectorSize);
2017-12-19 20:33:03 +00:00
return buffer;
}
public byte[] ReadSectors(ulong sectorAddress, uint length)
2017-12-19 20:33:03 +00:00
{
if(sectorAddress > imageInfo.Sectors - 1)
2017-12-19 20:33:03 +00:00
throw new ArgumentOutOfRangeException(nameof(sectorAddress),
$"Sector address {sectorAddress} not found");
2017-12-19 20:33:03 +00:00
if(sectorAddress + length > imageInfo.Sectors)
2017-12-19 20:33:03 +00:00
throw new ArgumentOutOfRangeException(nameof(length),
$"Requested more sectors ({sectorAddress + length}) than available ({imageInfo.Sectors})");
2017-12-19 20:33:03 +00:00
MemoryStream ms = new MemoryStream();
for(uint i = 0; i < length; i++)
{
byte[] sector = ReadSector(sectorAddress + i);
ms.Write(sector, 0, sector.Length);
}
return ms.ToArray();
}
public byte[] ReadSectorsTag(ulong sectorAddress, uint length, SectorTagType tag)
2017-12-19 20:33:03 +00:00
{
if(sectorAddress > imageInfo.Sectors - 1)
2017-12-19 20:33:03 +00:00
throw new ArgumentOutOfRangeException(nameof(sectorAddress),
$"Sector address {sectorAddress} not found");
2017-12-19 20:33:03 +00:00
if(sectorAddress + length > imageInfo.Sectors)
2017-12-19 20:33:03 +00:00
throw new ArgumentOutOfRangeException(nameof(length),
$"Requested more sectors ({sectorAddress + length}) than available ({imageInfo.Sectors})");
2017-12-19 20:33:03 +00:00
MemoryStream ms = new MemoryStream();
for(uint i = 0; i < length; i++)
{
byte[] sector = ReadSectorTag(sectorAddress + i, tag);
ms.Write(sector, 0, sector.Length);
}
return ms.ToArray();
}
public byte[] ReadSectorLong(ulong sectorAddress)
2017-12-19 20:33:03 +00:00
{
if(isHdd) return ReadSector(sectorAddress);
if(sectorAddress > imageInfo.Sectors - 1)
2017-12-19 20:33:03 +00:00
throw new ArgumentOutOfRangeException(nameof(sectorAddress),
$"Sector address {sectorAddress} not found");
2017-12-19 20:33:03 +00:00
Track track = new Track();
if(!sectorCache.TryGetValue(sectorAddress, out byte[] sector))
2017-12-19 20:33:03 +00:00
{
2018-06-22 08:08:38 +01:00
track = GetTrack(sectorAddress);
uint sectorSize = (uint)track.TrackRawBytesPerSector;
2017-12-19 20:33:03 +00:00
2018-06-22 08:08:38 +01:00
ulong hunkNo = sectorAddress / sectorsPerHunk;
ulong secOff = sectorAddress * sectorSize % (sectorsPerHunk * sectorSize);
2017-12-19 20:33:03 +00:00
byte[] hunk = GetHunk(hunkNo);
sector = new byte[imageInfo.SectorSize];
2017-12-19 20:33:03 +00:00
Array.Copy(hunk, (int)secOff, sector, 0, sector.Length);
if(sectorCache.Count >= maxSectorCache) sectorCache.Clear();
sectorCache.Add(sectorAddress, sector);
}
byte[] buffer = new byte[track.TrackRawBytesPerSector];
2018-06-22 08:08:38 +01:00
if(track.TrackType == TrackType.Audio && swapAudio)
2017-12-19 20:33:03 +00:00
for(int i = 0; i < 2352; i += 2)
{
buffer[i + 1] = sector[i];
buffer[i] = sector[i + 1];
2017-12-19 20:33:03 +00:00
}
else Array.Copy(sector, 0, buffer, 0, track.TrackRawBytesPerSector);
return buffer;
}
public byte[] ReadSectorsLong(ulong sectorAddress, uint length)
2017-12-19 20:33:03 +00:00
{
if(sectorAddress > imageInfo.Sectors - 1)
2017-12-19 20:33:03 +00:00
throw new ArgumentOutOfRangeException(nameof(sectorAddress),
$"Sector address {sectorAddress} not found");
2017-12-19 20:33:03 +00:00
if(sectorAddress + length > imageInfo.Sectors)
2017-12-19 20:33:03 +00:00
throw new ArgumentOutOfRangeException(nameof(length),
$"Requested more sectors ({sectorAddress + length}) than available ({imageInfo.Sectors})");
2017-12-19 20:33:03 +00:00
MemoryStream ms = new MemoryStream();
for(uint i = 0; i < length; i++)
{
byte[] sector = ReadSectorLong(sectorAddress + i);
ms.Write(sector, 0, sector.Length);
}
return ms.ToArray();
}
public byte[] ReadDiskTag(MediaTagType tag)
2017-12-19 20:33:03 +00:00
{
if(imageInfo.ReadableMediaTags.Contains(MediaTagType.ATA_IDENTIFY)) return identify;
2017-12-19 20:33:03 +00:00
if(imageInfo.ReadableMediaTags.Contains(MediaTagType.PCMCIA_CIS)) return cis;
2017-12-19 20:33:03 +00:00
throw new FeatureUnsupportedImageException("Feature not supported by image format");
}
public List<Track> GetSessionTracks(Session session)
{
if(isHdd)
throw new FeaturedNotSupportedByDiscImageException("Cannot access optical tracks on a hard disk image");
return GetSessionTracks(session.SessionSequence);
}
public List<Track> GetSessionTracks(ushort session)
{
if(isHdd)
throw new FeaturedNotSupportedByDiscImageException("Cannot access optical tracks on a hard disk image");
return tracks.Values.Where(track => track.TrackSession == session).ToList();
}
public byte[] ReadSector(ulong sectorAddress, uint track)
{
if(isHdd)
throw new FeaturedNotSupportedByDiscImageException("Cannot access optical tracks on a hard disk image");
return ReadSector(GetAbsoluteSector(sectorAddress, track));
}
public byte[] ReadSectorTag(ulong sectorAddress, uint track, SectorTagType tag)
{
if(isHdd)
throw new FeaturedNotSupportedByDiscImageException("Cannot access optical tracks on a hard disk image");
return ReadSectorTag(GetAbsoluteSector(sectorAddress, track), tag);
}
public byte[] ReadSectors(ulong sectorAddress, uint length, uint track)
{
if(isHdd)
throw new FeaturedNotSupportedByDiscImageException("Cannot access optical tracks on a hard disk image");
return ReadSectors(GetAbsoluteSector(sectorAddress, track), length);
}
public byte[] ReadSectorsTag(ulong sectorAddress, uint length, uint track, SectorTagType tag)
{
if(isHdd)
throw new FeaturedNotSupportedByDiscImageException("Cannot access optical tracks on a hard disk image");
return ReadSectorsTag(GetAbsoluteSector(sectorAddress, track), length, tag);
}
public byte[] ReadSectorLong(ulong sectorAddress, uint track)
{
if(isHdd)
throw new FeaturedNotSupportedByDiscImageException("Cannot access optical tracks on a hard disk image");
return ReadSectorLong(GetAbsoluteSector(sectorAddress, track));
}
public byte[] ReadSectorsLong(ulong sectorAddress, uint length, uint track)
{
if(isHdd)
throw new FeaturedNotSupportedByDiscImageException("Cannot access optical tracks on a hard disk image");
return ReadSectorLong(GetAbsoluteSector(sectorAddress, track), length);
}
2017-12-19 20:33:03 +00:00
}
}