mirror of
https://github.com/aaru-dps/Aaru.git
synced 2025-12-16 19:24:25 +00:00
[Acorn partitions] Implement detection of ICS partitions. Fixes #787
This commit is contained in:
@@ -32,6 +32,7 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using Aaru.CommonTypes;
|
using Aaru.CommonTypes;
|
||||||
@@ -46,14 +47,15 @@ namespace Aaru.Partitions;
|
|||||||
/// <summary>Implements decoding of Acorn partitions</summary>
|
/// <summary>Implements decoding of Acorn partitions</summary>
|
||||||
public sealed class Acorn : IPartition
|
public sealed class Acorn : IPartition
|
||||||
{
|
{
|
||||||
const ulong ADFS_SB_POS = 0xC00;
|
const ulong ADFS_SB_POS = 0xC00;
|
||||||
const uint LINUX_MAGIC = 0xDEAFA1DE;
|
const uint LINUX_MAGIC = 0xDEAFA1DE;
|
||||||
const uint SWAP_MAGIC = 0xDEAFAB1E;
|
const uint SWAP_MAGIC = 0xDEAFAB1E;
|
||||||
const uint RISCIX_MAGIC = 0x4A657320;
|
const uint RISCIX_MAGIC = 0x4A657320;
|
||||||
const uint TYPE_LINUX = 9;
|
const uint TYPE_LINUX = 9;
|
||||||
const uint TYPE_RISCIX_MFM = 1;
|
const uint TYPE_RISCIX_MFM = 1;
|
||||||
const uint TYPE_RISCIX_SCSI = 2;
|
const uint TYPE_RISCIX_SCSI = 2;
|
||||||
const uint TYPE_MASK = 15;
|
const uint TYPE_MASK = 15;
|
||||||
|
readonly byte[] _linuxIcsMagic = "LinuxPart"u8.ToArray();
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public string Name => Localization.Acorn_Name;
|
public string Name => Localization.Acorn_Name;
|
||||||
@@ -67,11 +69,22 @@ public sealed class Acorn : IPartition
|
|||||||
{
|
{
|
||||||
partitions = new List<Partition>();
|
partitions = new List<Partition>();
|
||||||
|
|
||||||
ulong sbSector;
|
ulong counter = 0;
|
||||||
|
|
||||||
|
GetFileCorePartitions(imagePlugin, partitions, sectorOffset, ref counter);
|
||||||
|
GetIcsPartitions(imagePlugin, partitions, sectorOffset, ref counter);
|
||||||
|
|
||||||
|
return partitions.Count != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void GetFileCorePartitions(IMediaImage imagePlugin, List<Partition> partitions, ulong sectorOffset,
|
||||||
|
ref ulong counter)
|
||||||
|
{
|
||||||
// RISC OS always checks for the partition on 0. Afaik no emulator chains it.
|
// RISC OS always checks for the partition on 0. Afaik no emulator chains it.
|
||||||
if(sectorOffset != 0)
|
if(sectorOffset != 0)
|
||||||
return false;
|
return;
|
||||||
|
|
||||||
|
ulong sbSector;
|
||||||
|
|
||||||
if(imagePlugin.Info.SectorSize > ADFS_SB_POS)
|
if(imagePlugin.Info.SectorSize > ADFS_SB_POS)
|
||||||
sbSector = 0;
|
sbSector = 0;
|
||||||
@@ -82,7 +95,7 @@ public sealed class Acorn : IPartition
|
|||||||
|
|
||||||
if(errno != ErrorNumber.NoError ||
|
if(errno != ErrorNumber.NoError ||
|
||||||
sector.Length < 512)
|
sector.Length < 512)
|
||||||
return false;
|
return;
|
||||||
|
|
||||||
AcornBootBlock bootBlock = Marshal.ByteArrayToStructureLittleEndian<AcornBootBlock>(sector);
|
AcornBootBlock bootBlock = Marshal.ByteArrayToStructureLittleEndian<AcornBootBlock>(sector);
|
||||||
|
|
||||||
@@ -96,14 +109,12 @@ public sealed class Acorn : IPartition
|
|||||||
int mapSector = bootBlock.startCylinder * secCyl;
|
int mapSector = bootBlock.startCylinder * secCyl;
|
||||||
|
|
||||||
if((ulong)mapSector >= imagePlugin.Info.Sectors)
|
if((ulong)mapSector >= imagePlugin.Info.Sectors)
|
||||||
return false;
|
return;
|
||||||
|
|
||||||
errno = imagePlugin.ReadSector((ulong)mapSector, out byte[] map);
|
errno = imagePlugin.ReadSector((ulong)mapSector, out byte[] map);
|
||||||
|
|
||||||
if(errno != ErrorNumber.NoError)
|
if(errno != ErrorNumber.NoError)
|
||||||
return false;
|
return;
|
||||||
|
|
||||||
ulong counter = 0;
|
|
||||||
|
|
||||||
if(checksum == bootBlock.checksum)
|
if(checksum == bootBlock.checksum)
|
||||||
{
|
{
|
||||||
@@ -112,7 +123,7 @@ public sealed class Acorn : IPartition
|
|||||||
Size = ((ulong)bootBlock.discRecord.disc_size_high * 0x100000000) + bootBlock.discRecord.disc_size,
|
Size = ((ulong)bootBlock.discRecord.disc_size_high * 0x100000000) + bootBlock.discRecord.disc_size,
|
||||||
Length = (((ulong)bootBlock.discRecord.disc_size_high * 0x100000000) + bootBlock.discRecord.disc_size) /
|
Length = (((ulong)bootBlock.discRecord.disc_size_high * 0x100000000) + bootBlock.discRecord.disc_size) /
|
||||||
imagePlugin.Info.SectorSize,
|
imagePlugin.Info.SectorSize,
|
||||||
Type = "ADFS",
|
Type = Localization.Filecore,
|
||||||
Name = StringHandlers.CToString(bootBlock.discRecord.disc_name, Encoding.GetEncoding("iso-8859-1"))
|
Name = StringHandlers.CToString(bootBlock.discRecord.disc_name, Encoding.GetEncoding("iso-8859-1"))
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -137,7 +148,13 @@ public sealed class Acorn : IPartition
|
|||||||
Size = entry.size,
|
Size = entry.size,
|
||||||
Length = (ulong)(entry.size * sector.Length),
|
Length = (ulong)(entry.size * sector.Length),
|
||||||
Sequence = counter,
|
Sequence = counter,
|
||||||
Scheme = Name
|
Scheme = "Filecore/Linux",
|
||||||
|
Type = entry.magic switch
|
||||||
|
{
|
||||||
|
LINUX_MAGIC => Localization.Linux,
|
||||||
|
SWAP_MAGIC => Localization.Linux_swap,
|
||||||
|
_ => Localization.Unknown_partition_type
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
part.Offset = part.Start * (ulong)sector.Length;
|
part.Offset = part.Start * (ulong)sector.Length;
|
||||||
@@ -167,7 +184,8 @@ public sealed class Acorn : IPartition
|
|||||||
Length = (ulong)(entry.length * sector.Length),
|
Length = (ulong)(entry.length * sector.Length),
|
||||||
Name = StringHandlers.CToString(entry.name, Encoding.GetEncoding("iso-8859-1")),
|
Name = StringHandlers.CToString(entry.name, Encoding.GetEncoding("iso-8859-1")),
|
||||||
Sequence = counter,
|
Sequence = counter,
|
||||||
Scheme = Name
|
Scheme = "Filecore/RISCiX",
|
||||||
|
Type = Localization.Unknown_partition_type
|
||||||
};
|
};
|
||||||
|
|
||||||
part.Offset = part.Start * (ulong)sector.Length;
|
part.Offset = part.Start * (ulong)sector.Length;
|
||||||
@@ -182,8 +200,85 @@ public sealed class Acorn : IPartition
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return partitions.Count != 0;
|
void GetIcsPartitions(IMediaImage imagePlugin, List<Partition> partitions, ulong sectorOffset, ref ulong counter)
|
||||||
|
{
|
||||||
|
// RISC OS always checks for the partition on 0. Afaik no emulator chains it.
|
||||||
|
if(sectorOffset != 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ErrorNumber errno = imagePlugin.ReadSector(0, out byte[] sector);
|
||||||
|
|
||||||
|
if(errno != ErrorNumber.NoError ||
|
||||||
|
sector.Length < 512)
|
||||||
|
return;
|
||||||
|
|
||||||
|
uint icsSum = 0x50617274;
|
||||||
|
|
||||||
|
for(int i = 0; i < 508; i++)
|
||||||
|
icsSum += sector[i];
|
||||||
|
|
||||||
|
uint discCheck = BitConverter.ToUInt32(sector, 508);
|
||||||
|
|
||||||
|
if(icsSum != discCheck)
|
||||||
|
return;
|
||||||
|
|
||||||
|
IcsTable table = Marshal.ByteArrayToStructureLittleEndian<IcsTable>(sector);
|
||||||
|
|
||||||
|
foreach(IcsEntry entry in table.entries.Where(entry => entry.size != 0))
|
||||||
|
{
|
||||||
|
// FileCore partition
|
||||||
|
Partition part;
|
||||||
|
|
||||||
|
if(entry.size > 0)
|
||||||
|
{
|
||||||
|
part = new Partition
|
||||||
|
{
|
||||||
|
Start = entry.start,
|
||||||
|
Length = (ulong)entry.size,
|
||||||
|
Size = (ulong)(entry.size * sector.Length),
|
||||||
|
Type = Localization.Filecore,
|
||||||
|
Sequence = counter,
|
||||||
|
Scheme = "ICS"
|
||||||
|
};
|
||||||
|
|
||||||
|
part.Offset = part.Start * (ulong)sector.Length;
|
||||||
|
counter++;
|
||||||
|
|
||||||
|
partitions.Add(part);
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Negative size means Linux partition, first sector needs to be read
|
||||||
|
errno = imagePlugin.ReadSector(entry.start, out sector);
|
||||||
|
|
||||||
|
if(errno != ErrorNumber.NoError)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if(_linuxIcsMagic.Where((t, i) => t != sector[i]).Any())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
part = new Partition
|
||||||
|
{
|
||||||
|
Start = entry.start,
|
||||||
|
Length = (ulong)(entry.size * -1),
|
||||||
|
Size = (ulong)(entry.size * -1 * sector.Length),
|
||||||
|
Type = sector[9] == 'N'
|
||||||
|
? Localization.Linux
|
||||||
|
: sector[9] == 'S'
|
||||||
|
? Localization.Linux_swap
|
||||||
|
: Localization.Unknown_partition_type,
|
||||||
|
Sequence = counter,
|
||||||
|
Scheme = "ICS"
|
||||||
|
};
|
||||||
|
|
||||||
|
part.Offset = part.Start * (ulong)sector.Length;
|
||||||
|
counter++;
|
||||||
|
|
||||||
|
partitions.Add(part);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
@@ -261,4 +356,18 @@ public sealed class Acorn : IPartition
|
|||||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
|
||||||
public readonly byte[] name;
|
public readonly byte[] name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||||
|
struct IcsTable
|
||||||
|
{
|
||||||
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
|
||||||
|
public readonly IcsEntry[] entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||||
|
struct IcsEntry
|
||||||
|
{
|
||||||
|
public readonly uint start;
|
||||||
|
public readonly int size;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
6692
Aaru.Partitions/Localization/Localization.Designer.cs
generated
6692
Aaru.Partitions/Localization/Localization.Designer.cs
generated
File diff suppressed because it is too large
Load Diff
@@ -1410,4 +1410,7 @@
|
|||||||
<data name="XENIX_Name" xml:space="preserve">
|
<data name="XENIX_Name" xml:space="preserve">
|
||||||
<value>XENIX</value>
|
<value>XENIX</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Filecore" xml:space="preserve">
|
||||||
|
<value>Filecore</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
Reference in New Issue
Block a user