mirror of
https://github.com/aaru-dps/Aaru.git
synced 2025-12-16 19:24:25 +00:00
Added support for ADFS-S, ADFS-M, ADFS-L, ADFS-D, their
variants on hard disks and ADFS-E, ADFS-E+, ADFS-F, ADFS-F+ and ADFS-G boot blocks. Pending support for "big directory".
This commit is contained in:
@@ -35,12 +35,36 @@ using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using DiscImageChef.Console;
|
||||
using System.Security.Policy;
|
||||
|
||||
namespace DiscImageChef.Filesystems
|
||||
{
|
||||
public class AcornADFS : Filesystem
|
||||
{
|
||||
const ulong ADFS_SB_POS = 0xC00;
|
||||
/// <summary>
|
||||
/// Location for boot block, in bytes
|
||||
/// </summary>
|
||||
const ulong bootBlockLocation = 0xC00;
|
||||
/// <summary>
|
||||
/// Size of boot block, in bytes
|
||||
/// </summary>
|
||||
const uint bootBlockSize = 0x200;
|
||||
/// <summary>
|
||||
/// Location of new directory, in bytes
|
||||
/// </summary>
|
||||
const ulong newDirectoryLocation = 0x400;
|
||||
/// <summary>
|
||||
/// Location of old directory, in bytes
|
||||
/// </summary>
|
||||
const ulong oldDirectoryLocation = 0x200;
|
||||
/// <summary>
|
||||
/// Size of old directory
|
||||
/// </summary>
|
||||
const uint oldDirectorySize = 1280;
|
||||
/// <summary>
|
||||
/// Size of new directory
|
||||
/// </summary>
|
||||
const uint newDirectorySize = 2048;
|
||||
|
||||
public AcornADFS()
|
||||
{
|
||||
@@ -57,11 +81,26 @@ namespace DiscImageChef.Filesystems
|
||||
CurrentEncoding = Encoding.GetEncoding("iso-8859-1");
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
struct DiscRecord
|
||||
/// <summary>
|
||||
/// Boot block, used in hard disks and ADFS-F and higher.
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct BootBlock
|
||||
{
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x1C0)]
|
||||
public byte[] spare;
|
||||
public DiscRecord discRecord;
|
||||
public byte flags;
|
||||
public ushort startCylinder;
|
||||
public byte checksum;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disc record, used in hard disks and ADFS-E and higher.
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct DiscRecord
|
||||
{
|
||||
public byte log2secsize;
|
||||
public byte spt;
|
||||
public byte heads;
|
||||
@@ -88,31 +127,299 @@ namespace DiscImageChef.Filesystems
|
||||
public byte[] reserved;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Free block map, sector 0, used in ADFS-S, ADFS-L, ADFS-M and ADFS-D
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct OldMapSector0
|
||||
{
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 82 * 3)]
|
||||
public byte[] freeStart;
|
||||
public byte reserved;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)]
|
||||
public byte[] name;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
|
||||
public byte[] size;
|
||||
public byte checksum;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Free block map, sector 1, used in ADFS-S, ADFS-L, ADFS-M and ADFS-D
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct OldMapSector1
|
||||
{
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 82 * 3)]
|
||||
public byte[] freeStart;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)]
|
||||
public byte[] name;
|
||||
public ushort discId;
|
||||
public byte boot;
|
||||
public byte freeEnd;
|
||||
public byte checksum;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Free block map, sector 0, used in ADFS-E
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct NewMap
|
||||
{
|
||||
public byte zoneChecksum;
|
||||
public ushort freeLink;
|
||||
public byte crossChecksum;
|
||||
public DiscRecord discRecord;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Directory header, common to "old" and "new" directories
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct DirectoryHeader
|
||||
{
|
||||
public byte masterSequence;
|
||||
public uint magic;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// New directory format magic number, "Nick"
|
||||
/// </summary>
|
||||
const uint newDirMagic = 0x6B63694E;
|
||||
/// <summary>
|
||||
/// Old directory format magic number, "Hugo"
|
||||
/// </summary>
|
||||
const uint oldDirMagic = 0x6F677548;
|
||||
|
||||
/// <summary>
|
||||
/// Directory header, common to "old" and "new" directories
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct DirectoryEntry
|
||||
{
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
|
||||
public byte[] name;
|
||||
public uint load;
|
||||
public uint exec;
|
||||
public uint length;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
|
||||
public byte[] address;
|
||||
public byte atts;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Directory tail, new format
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct NewDirectoryTail
|
||||
{
|
||||
public byte lastMark;
|
||||
public ushort reserved;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
|
||||
public byte[] parent;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 19)]
|
||||
public byte[] title;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
|
||||
public byte[] name;
|
||||
public byte endMasSeq;
|
||||
public uint magic;
|
||||
public byte checkByte;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Directory tail, old format
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct OldDirectoryTail
|
||||
{
|
||||
public byte lastMark;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
|
||||
public byte[] name;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
|
||||
public byte[] parent;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 19)]
|
||||
public byte[] title;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 14)]
|
||||
public byte[] reserved;
|
||||
public byte endMasSeq;
|
||||
public uint magic;
|
||||
public byte checkByte;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Directory, old format
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct OldDirectory
|
||||
{
|
||||
public DirectoryHeader header;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 47)]
|
||||
public DirectoryEntry[] entries;
|
||||
public OldDirectoryTail tail;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Directory, new format
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct NewDirectory
|
||||
{
|
||||
public DirectoryHeader header;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 77)]
|
||||
public DirectoryEntry[] entries;
|
||||
public NewDirectoryTail tail;
|
||||
}
|
||||
|
||||
// TODO: BBC Master hard disks are untested...
|
||||
public override bool Identify(ImagePlugins.ImagePlugin imagePlugin, ulong partitionStart, ulong partitionEnd)
|
||||
{
|
||||
if(partitionStart >= partitionEnd)
|
||||
return false;
|
||||
|
||||
ulong sbSector;
|
||||
uint sectorsToRead;
|
||||
|
||||
if(imagePlugin.GetSectorSize() > ADFS_SB_POS)
|
||||
sbSector = 0;
|
||||
else
|
||||
sbSector = ADFS_SB_POS / imagePlugin.GetSectorSize();
|
||||
if(imagePlugin.ImageInfo.sectorSize < 256)
|
||||
return false;
|
||||
|
||||
byte[] sector = imagePlugin.ReadSector(sbSector + partitionStart);
|
||||
byte[] sector;
|
||||
GCHandle ptr;
|
||||
|
||||
// ADFS-S, ADFS-M, ADFS-L, ADFS-D without partitions
|
||||
if(partitionStart == 0)
|
||||
{
|
||||
OldMapSector0 oldMap0;
|
||||
OldMapSector1 oldMap1;
|
||||
OldDirectory oldRoot;
|
||||
byte oldChk0;
|
||||
byte oldChk1;
|
||||
byte dirChk;
|
||||
|
||||
sector = imagePlugin.ReadSector(0);
|
||||
oldChk0 = AcornMapChecksum(sector, 255);
|
||||
ptr = GCHandle.Alloc(sector, GCHandleType.Pinned);
|
||||
oldMap0 = (OldMapSector0)Marshal.PtrToStructure(ptr.AddrOfPinnedObject(), typeof(OldMapSector0));
|
||||
|
||||
sector = imagePlugin.ReadSector(1);
|
||||
oldChk1 = AcornMapChecksum(sector, 255);
|
||||
ptr = GCHandle.Alloc(sector, GCHandleType.Pinned);
|
||||
oldMap1 = (OldMapSector1)Marshal.PtrToStructure(ptr.AddrOfPinnedObject(), typeof(OldMapSector1));
|
||||
|
||||
DicConsole.DebugWriteLine("ADFS Plugin", "oldMap0.checksum = {0}", oldMap0.checksum);
|
||||
DicConsole.DebugWriteLine("ADFS Plugin", "oldChk0 = {0}", oldChk0);
|
||||
|
||||
// According to documentation map1 MUST start on sector 1. On ADFS-D it starts at 0x100, not on sector 1 (0x400)
|
||||
if(oldMap0.checksum == oldChk0 && oldMap1.checksum != oldChk1 && sector.Length >= 512)
|
||||
{
|
||||
sector = imagePlugin.ReadSector(0);
|
||||
byte[] tmp = new byte[256];
|
||||
Array.Copy(sector, 256, tmp, 0, 256);
|
||||
oldChk1 = AcornMapChecksum(tmp, 255);
|
||||
ptr = GCHandle.Alloc(tmp, GCHandleType.Pinned);
|
||||
oldMap1 = (OldMapSector1)Marshal.PtrToStructure(ptr.AddrOfPinnedObject(), typeof(OldMapSector1));
|
||||
}
|
||||
|
||||
DicConsole.DebugWriteLine("ADFS Plugin", "oldMap1.checksum = {0}", oldMap1.checksum);
|
||||
DicConsole.DebugWriteLine("ADFS Plugin", "oldChk1 = {0}", oldChk1);
|
||||
|
||||
if(oldMap0.checksum == oldChk0 && oldMap1.checksum == oldChk1 && oldMap0.checksum != 0 && oldMap1.checksum != 0)
|
||||
{
|
||||
sbSector = oldDirectoryLocation / imagePlugin.ImageInfo.sectorSize;
|
||||
sectorsToRead = oldDirectorySize / imagePlugin.ImageInfo.sectorSize;
|
||||
if(oldDirectorySize % imagePlugin.ImageInfo.sectorSize > 0)
|
||||
sectorsToRead++;
|
||||
|
||||
sector = imagePlugin.ReadSectors(sbSector, sectorsToRead);
|
||||
if(sector.Length > oldDirectorySize)
|
||||
{
|
||||
byte[] tmp = new byte[oldDirectorySize];
|
||||
Array.Copy(sector, 0, tmp, 0, oldDirectorySize - 53);
|
||||
Array.Copy(sector, sector.Length - 54, tmp, oldDirectorySize - 54, 53);
|
||||
sector = tmp;
|
||||
}
|
||||
ptr = GCHandle.Alloc(sector, GCHandleType.Pinned);
|
||||
oldRoot = (OldDirectory)Marshal.PtrToStructure(ptr.AddrOfPinnedObject(), typeof(OldDirectory));
|
||||
dirChk = AcornDirectoryChecksum(sector, (int)oldDirectorySize - 1);
|
||||
|
||||
DicConsole.DebugWriteLine("ADFS Plugin", "oldRoot.header.magic at 0x200 = {0}", oldRoot.header.magic);
|
||||
DicConsole.DebugWriteLine("ADFS Plugin", "oldRoot.tail.magic at 0x200 = {0}", oldRoot.tail.magic);
|
||||
DicConsole.DebugWriteLine("ADFS Plugin", "oldRoot.tail.checkByte at 0x200 = {0}", oldRoot.tail.checkByte);
|
||||
DicConsole.DebugWriteLine("ADFS Plugin", "dirChk at 0x200 = {0}", dirChk);
|
||||
|
||||
if((oldRoot.header.magic == oldDirMagic && oldRoot.tail.magic == oldDirMagic) ||
|
||||
(oldRoot.header.magic == newDirMagic && oldRoot.tail.magic == newDirMagic))
|
||||
return true;
|
||||
|
||||
// RISC OS says the old directory can't be in the new location, hard disks created by RISC OS 3.10 do that...
|
||||
sbSector = newDirectoryLocation / imagePlugin.ImageInfo.sectorSize;
|
||||
sectorsToRead = newDirectorySize / imagePlugin.ImageInfo.sectorSize;
|
||||
if(newDirectorySize % imagePlugin.ImageInfo.sectorSize > 0)
|
||||
sectorsToRead++;
|
||||
|
||||
sector = imagePlugin.ReadSectors(sbSector, sectorsToRead);
|
||||
if(sector.Length > oldDirectorySize)
|
||||
{
|
||||
byte[] tmp = new byte[oldDirectorySize];
|
||||
Array.Copy(sector, 0, tmp, 0, oldDirectorySize - 53);
|
||||
Array.Copy(sector, sector.Length - 54, tmp, oldDirectorySize - 54, 53);
|
||||
sector = tmp;
|
||||
}
|
||||
ptr = GCHandle.Alloc(sector, GCHandleType.Pinned);
|
||||
oldRoot = (OldDirectory)Marshal.PtrToStructure(ptr.AddrOfPinnedObject(), typeof(OldDirectory));
|
||||
dirChk = AcornDirectoryChecksum(sector, (int)oldDirectorySize - 1);
|
||||
|
||||
DicConsole.DebugWriteLine("ADFS Plugin", "oldRoot.header.magic at 0x400 = {0}", oldRoot.header.magic);
|
||||
DicConsole.DebugWriteLine("ADFS Plugin", "oldRoot.tail.magic at 0x400 = {0}", oldRoot.tail.magic);
|
||||
DicConsole.DebugWriteLine("ADFS Plugin", "oldRoot.tail.checkByte at 0x400 = {0}", oldRoot.tail.checkByte);
|
||||
DicConsole.DebugWriteLine("ADFS Plugin", "dirChk at 0x400 = {0}", dirChk);
|
||||
|
||||
if((oldRoot.header.magic == oldDirMagic && oldRoot.tail.magic == oldDirMagic) ||
|
||||
(oldRoot.header.magic == newDirMagic && oldRoot.tail.magic == newDirMagic))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Partitioning or not, new formats follow:
|
||||
DiscRecord drSb;
|
||||
|
||||
try
|
||||
sector = imagePlugin.ReadSector(partitionStart);
|
||||
byte newChk = NewMapChecksum(sector);
|
||||
DicConsole.DebugWriteLine("ADFS Plugin", "newChk = {0}", newChk);
|
||||
DicConsole.DebugWriteLine("ADFS Plugin", "map.zoneChecksum = {0}", sector[0]);
|
||||
|
||||
sbSector = bootBlockLocation / imagePlugin.ImageInfo.sectorSize;
|
||||
sectorsToRead = bootBlockSize / imagePlugin.ImageInfo.sectorSize;
|
||||
if(bootBlockSize % imagePlugin.ImageInfo.sectorSize > 0)
|
||||
sectorsToRead++;
|
||||
|
||||
byte[] bootSector = imagePlugin.ReadSectors(sbSector + partitionStart, sectorsToRead);
|
||||
int bootChk = 0;
|
||||
for(int i = 0; i < 0x1FF; i++)
|
||||
bootChk = ((bootChk & 0xFF) + (bootChk >> 8) + bootSector[i]);
|
||||
DicConsole.DebugWriteLine("ADFS Plugin", "bootChk = {0}", bootChk);
|
||||
DicConsole.DebugWriteLine("ADFS Plugin", "bBlock.checksum = {0}", bootSector[0x1FF]);
|
||||
|
||||
if(newChk == sector[0] && newChk != 0)
|
||||
{
|
||||
GCHandle handle = GCHandle.Alloc(sector, GCHandleType.Pinned);
|
||||
drSb = (DiscRecord)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(DiscRecord));
|
||||
handle.Free();
|
||||
ptr = GCHandle.Alloc(sector, GCHandleType.Pinned);
|
||||
NewMap nmap = (NewMap)Marshal.PtrToStructure(ptr.AddrOfPinnedObject(), typeof(NewMap));
|
||||
ptr.Free();
|
||||
drSb = nmap.discRecord;
|
||||
}
|
||||
catch
|
||||
else if(bootChk == bootSector[0x1FF])
|
||||
{
|
||||
ptr = GCHandle.Alloc(bootSector, GCHandleType.Pinned);
|
||||
BootBlock bBlock = (BootBlock)Marshal.PtrToStructure(ptr.AddrOfPinnedObject(), typeof(BootBlock));
|
||||
ptr.Free();
|
||||
drSb = bBlock.discRecord;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
DicConsole.DebugWriteLine("ADFS Plugin", "drSb.log2secsize = {0}", drSb.log2secsize);
|
||||
DicConsole.DebugWriteLine("ADFS Plugin", "drSb.idlen = {0}", drSb.idlen);
|
||||
DicConsole.DebugWriteLine("ADFS Plugin", "drSb.disc_size_high = {0}", drSb.disc_size_high);
|
||||
DicConsole.DebugWriteLine("ADFS Plugin", "drSb.disc_size = {0}", drSb.disc_size);
|
||||
DicConsole.DebugWriteLine("ADFS Plugin", "IsNullOrEmpty(drSb.reserved) = {0}", ArrayHelpers.ArrayIsNullOrEmpty(drSb.reserved));
|
||||
|
||||
if(drSb.log2secsize < 8 || drSb.log2secsize > 10)
|
||||
return false;
|
||||
@@ -135,6 +442,10 @@ namespace DiscImageChef.Filesystems
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO: Find root directory on volumes with DiscRecord
|
||||
// TODO: Support big directories (ADFS-G?)
|
||||
// TODO: Find the real freemap on volumes with DiscRecord, as DiscRecord's discid may be empty but this one isn't
|
||||
public override void GetInformation(ImagePlugins.ImagePlugin imagePlugin, ulong partitionStart, ulong partitionEnd, out string information)
|
||||
{
|
||||
StringBuilder sbInformation = new StringBuilder();
|
||||
@@ -142,17 +453,181 @@ namespace DiscImageChef.Filesystems
|
||||
information = "";
|
||||
|
||||
ulong sbSector;
|
||||
byte[] sector;
|
||||
uint sectorsToRead;
|
||||
GCHandle ptr;
|
||||
ulong bytes;
|
||||
string discname;
|
||||
|
||||
if(imagePlugin.GetSectorSize() > ADFS_SB_POS)
|
||||
sbSector = 0;
|
||||
// ADFS-S, ADFS-M, ADFS-L, ADFS-D without partitions
|
||||
if(partitionStart == 0)
|
||||
{
|
||||
OldMapSector0 oldMap0;
|
||||
OldMapSector1 oldMap1;
|
||||
OldDirectory oldRoot;
|
||||
NewDirectory newRoot;
|
||||
byte oldChk0;
|
||||
byte oldChk1;
|
||||
|
||||
sector = imagePlugin.ReadSector(0);
|
||||
oldChk0 = AcornMapChecksum(sector, 255);
|
||||
ptr = GCHandle.Alloc(sector, GCHandleType.Pinned);
|
||||
oldMap0 = (OldMapSector0)Marshal.PtrToStructure(ptr.AddrOfPinnedObject(), typeof(OldMapSector0));
|
||||
|
||||
sector = imagePlugin.ReadSector(1);
|
||||
oldChk1 = AcornMapChecksum(sector, 255);
|
||||
ptr = GCHandle.Alloc(sector, GCHandleType.Pinned);
|
||||
oldMap1 = (OldMapSector1)Marshal.PtrToStructure(ptr.AddrOfPinnedObject(), typeof(OldMapSector1));
|
||||
|
||||
// According to documentation map1 MUST start on sector 1. On ADFS-D it starts at 0x100, not on sector 1 (0x400)
|
||||
if(oldMap0.checksum == oldChk0 && oldMap1.checksum != oldChk1 && sector.Length >= 512)
|
||||
{
|
||||
sector = imagePlugin.ReadSector(0);
|
||||
byte[] tmp = new byte[256];
|
||||
Array.Copy(sector, 256, tmp, 0, 256);
|
||||
oldChk1 = AcornMapChecksum(tmp, 255);
|
||||
ptr = GCHandle.Alloc(tmp, GCHandleType.Pinned);
|
||||
oldMap1 = (OldMapSector1)Marshal.PtrToStructure(ptr.AddrOfPinnedObject(), typeof(OldMapSector1));
|
||||
}
|
||||
|
||||
if(oldMap0.checksum == oldChk0 && oldMap1.checksum == oldChk1 && oldMap0.checksum != 0 && oldMap1.checksum != 0)
|
||||
{
|
||||
bytes = (ulong)((oldMap0.size[2] << 16) + (oldMap0.size[1] << 8) + oldMap0.size[0]) * 256;
|
||||
byte[] namebytes = new byte[10];
|
||||
for(int i = 0; i < 5; i++)
|
||||
{
|
||||
namebytes[i * 2] = oldMap0.name[i];
|
||||
namebytes[i * 2 + 1] = oldMap1.name[i];
|
||||
}
|
||||
|
||||
xmlFSType = new Schemas.FileSystemType
|
||||
{
|
||||
Bootable = oldMap1.boot != 0, // Or not?
|
||||
Clusters = (long)(bytes / imagePlugin.ImageInfo.sectorSize),
|
||||
ClusterSize = (int)imagePlugin.ImageInfo.sectorSize,
|
||||
Type = "Acorn Advanced Disc Filing System",
|
||||
};
|
||||
|
||||
if(ArrayHelpers.ArrayIsNullOrEmpty(namebytes))
|
||||
{
|
||||
sbSector = oldDirectoryLocation / imagePlugin.ImageInfo.sectorSize;
|
||||
sectorsToRead = oldDirectorySize / imagePlugin.ImageInfo.sectorSize;
|
||||
if(oldDirectorySize % imagePlugin.ImageInfo.sectorSize > 0)
|
||||
sectorsToRead++;
|
||||
|
||||
sector = imagePlugin.ReadSectors(sbSector, sectorsToRead);
|
||||
if(sector.Length > oldDirectorySize)
|
||||
{
|
||||
byte[] tmp = new byte[oldDirectorySize];
|
||||
Array.Copy(sector, 0, tmp, 0, oldDirectorySize - 53);
|
||||
Array.Copy(sector, sector.Length - 54, tmp, oldDirectorySize - 54, 53);
|
||||
sector = tmp;
|
||||
}
|
||||
ptr = GCHandle.Alloc(sector, GCHandleType.Pinned);
|
||||
oldRoot = (OldDirectory)Marshal.PtrToStructure(ptr.AddrOfPinnedObject(), typeof(OldDirectory));
|
||||
|
||||
if(oldRoot.header.magic == oldDirMagic && oldRoot.tail.magic == oldDirMagic)
|
||||
{
|
||||
namebytes = oldRoot.tail.name;
|
||||
}
|
||||
else
|
||||
{
|
||||
// RISC OS says the old directory can't be in the new location, hard disks created by RISC OS 3.10 do that...
|
||||
sbSector = newDirectoryLocation / imagePlugin.ImageInfo.sectorSize;
|
||||
sectorsToRead = newDirectorySize / imagePlugin.ImageInfo.sectorSize;
|
||||
if(newDirectorySize % imagePlugin.ImageInfo.sectorSize > 0)
|
||||
sectorsToRead++;
|
||||
|
||||
sector = imagePlugin.ReadSectors(sbSector, sectorsToRead);
|
||||
if(sector.Length > oldDirectorySize)
|
||||
{
|
||||
byte[] tmp = new byte[oldDirectorySize];
|
||||
Array.Copy(sector, 0, tmp, 0, oldDirectorySize - 53);
|
||||
Array.Copy(sector, sector.Length - 54, tmp, oldDirectorySize - 54, 53);
|
||||
sector = tmp;
|
||||
}
|
||||
ptr = GCHandle.Alloc(sector, GCHandleType.Pinned);
|
||||
oldRoot = (OldDirectory)Marshal.PtrToStructure(ptr.AddrOfPinnedObject(), typeof(OldDirectory));
|
||||
|
||||
if(oldRoot.header.magic == oldDirMagic && oldRoot.tail.magic == oldDirMagic)
|
||||
{
|
||||
namebytes = oldRoot.tail.name;
|
||||
}
|
||||
else
|
||||
{
|
||||
sector = imagePlugin.ReadSectors(sbSector, sectorsToRead);
|
||||
if(sector.Length > newDirectorySize)
|
||||
{
|
||||
byte[] tmp = new byte[newDirectorySize];
|
||||
Array.Copy(sector, 0, tmp, 0, newDirectorySize - 41);
|
||||
Array.Copy(sector, sector.Length - 42, tmp, newDirectorySize - 42, 41);
|
||||
sector = tmp;
|
||||
}
|
||||
ptr = GCHandle.Alloc(sector, GCHandleType.Pinned);
|
||||
newRoot = (NewDirectory)Marshal.PtrToStructure(ptr.AddrOfPinnedObject(), typeof(NewDirectory));
|
||||
if(newRoot.header.magic == newDirMagic && newRoot.tail.magic == newDirMagic)
|
||||
{
|
||||
namebytes = newRoot.tail.title;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sbInformation.AppendLine("Acorn Advanced Disc Filing System");
|
||||
sbInformation.AppendLine();
|
||||
sbInformation.AppendFormat("{0} bytes per sector", imagePlugin.ImageInfo.sectorSize).AppendLine();
|
||||
sbInformation.AppendFormat("Volume has {0} bytes", bytes).AppendLine();
|
||||
sbInformation.AppendFormat("Volume name: {0}", StringHandlers.CToString(namebytes, CurrentEncoding)).AppendLine();
|
||||
if(oldMap1.discId > 0)
|
||||
{
|
||||
xmlFSType.VolumeSerial = string.Format("{0:X4}", oldMap1.discId);
|
||||
sbInformation.AppendFormat("Volume ID: {0:X4}", oldMap1.discId).AppendLine();
|
||||
}
|
||||
if(!ArrayHelpers.ArrayIsNullOrEmpty(namebytes))
|
||||
xmlFSType.VolumeName = StringHandlers.CToString(namebytes, CurrentEncoding);
|
||||
|
||||
information = sbInformation.ToString();
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Partitioning or not, new formats follow:
|
||||
DiscRecord drSb;
|
||||
|
||||
sector = imagePlugin.ReadSector(partitionStart);
|
||||
byte newChk = NewMapChecksum(sector);
|
||||
DicConsole.DebugWriteLine("ADFS Plugin", "newChk = {0}", newChk);
|
||||
DicConsole.DebugWriteLine("ADFS Plugin", "map.zoneChecksum = {0}", sector[0]);
|
||||
|
||||
sbSector = bootBlockLocation / imagePlugin.ImageInfo.sectorSize;
|
||||
sectorsToRead = bootBlockSize / imagePlugin.ImageInfo.sectorSize;
|
||||
if(bootBlockSize % imagePlugin.ImageInfo.sectorSize > 0)
|
||||
sectorsToRead++;
|
||||
|
||||
byte[] bootSector = imagePlugin.ReadSectors(sbSector + partitionStart, sectorsToRead);
|
||||
int bootChk = 0;
|
||||
for(int i = 0; i < 0x1FF; i++)
|
||||
bootChk = ((bootChk & 0xFF) + (bootChk >> 8) + bootSector[i]);
|
||||
DicConsole.DebugWriteLine("ADFS Plugin", "bootChk = {0}", bootChk);
|
||||
DicConsole.DebugWriteLine("ADFS Plugin", "bBlock.checksum = {0}", bootSector[0x1FF]);
|
||||
|
||||
if(newChk == sector[0] && newChk != 0)
|
||||
{
|
||||
ptr = GCHandle.Alloc(sector, GCHandleType.Pinned);
|
||||
NewMap nmap = (NewMap)Marshal.PtrToStructure(ptr.AddrOfPinnedObject(), typeof(NewMap));
|
||||
ptr.Free();
|
||||
drSb = nmap.discRecord;
|
||||
}
|
||||
else if(bootChk == bootSector[0x1FF])
|
||||
{
|
||||
ptr = GCHandle.Alloc(bootSector, GCHandleType.Pinned);
|
||||
BootBlock bBlock = (BootBlock)Marshal.PtrToStructure(ptr.AddrOfPinnedObject(), typeof(BootBlock));
|
||||
ptr.Free();
|
||||
drSb = bBlock.discRecord;
|
||||
}
|
||||
else
|
||||
sbSector = ADFS_SB_POS / imagePlugin.GetSectorSize();
|
||||
|
||||
byte[] sector = imagePlugin.ReadSector(sbSector + partitionStart);
|
||||
|
||||
GCHandle handle = GCHandle.Alloc(sector, GCHandleType.Pinned);
|
||||
DiscRecord drSb = (DiscRecord)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(DiscRecord));
|
||||
handle.Free();
|
||||
return;
|
||||
|
||||
DicConsole.DebugWriteLine("ADFS Plugin", "drSb.log2secsize = {0}", drSb.log2secsize);
|
||||
DicConsole.DebugWriteLine("ADFS Plugin", "drSb.spt = {0}", drSb.spt);
|
||||
@@ -188,7 +663,7 @@ namespace DiscImageChef.Filesystems
|
||||
if(!ArrayHelpers.ArrayIsNullOrEmpty(drSb.reserved))
|
||||
return;
|
||||
|
||||
ulong bytes = drSb.disc_size_high;
|
||||
bytes = drSb.disc_size_high;
|
||||
bytes *= 0x100000000;
|
||||
bytes += drSb.disc_size;
|
||||
|
||||
@@ -199,7 +674,7 @@ namespace DiscImageChef.Filesystems
|
||||
if(bytes > (imagePlugin.GetSectors() * imagePlugin.GetSectorSize()))
|
||||
return;
|
||||
|
||||
string discname = StringHandlers.CToString(drSb.disc_name, CurrentEncoding);
|
||||
xmlFSType = new Schemas.FileSystemType();
|
||||
|
||||
sbInformation.AppendLine("Acorn Advanced Disc Filing System");
|
||||
sbInformation.AppendLine();
|
||||
@@ -210,22 +685,29 @@ namespace DiscImageChef.Filesystems
|
||||
sbInformation.AppendFormat("Density code: {0}", drSb.density).AppendLine();
|
||||
sbInformation.AppendFormat("Skew: {0}", drSb.skew).AppendLine();
|
||||
sbInformation.AppendFormat("Boot option: {0}", drSb.bootoption).AppendLine();
|
||||
sbInformation.AppendFormat("Root starts at byte {0}", drSb.root).AppendLine();
|
||||
sbInformation.AppendFormat("Root is {0} bytes long", drSb.root_size).AppendLine();
|
||||
// TODO: What the hell is this field refering to?
|
||||
sbInformation.AppendFormat("Root starts at frag {0}", drSb.root).AppendLine();
|
||||
//sbInformation.AppendFormat("Root is {0} bytes long", drSb.root_size).AppendLine();
|
||||
sbInformation.AppendFormat("Volume has {0} bytes in {1} zones", bytes, zones).AppendLine();
|
||||
sbInformation.AppendFormat("Volume flags: 0x{0:X4}", drSb.flags).AppendLine();
|
||||
sbInformation.AppendFormat("Volume ID: {0}", drSb.disc_id).AppendLine();
|
||||
sbInformation.AppendFormat("Volume name: {0}", discname).AppendLine();
|
||||
if(drSb.disc_id > 0)
|
||||
{
|
||||
xmlFSType.VolumeSerial = string.Format("{0:X4}", drSb.disc_id);
|
||||
sbInformation.AppendFormat("Volume ID: {0:X4}", drSb.disc_id).AppendLine();
|
||||
}
|
||||
if(!ArrayHelpers.ArrayIsNullOrEmpty(drSb.disc_name))
|
||||
{
|
||||
discname = StringHandlers.CToString(drSb.disc_name, CurrentEncoding);
|
||||
xmlFSType.VolumeName = discname;
|
||||
sbInformation.AppendFormat("Volume name: {0}", discname).AppendLine();
|
||||
}
|
||||
|
||||
information = sbInformation.ToString();
|
||||
|
||||
xmlFSType = new Schemas.FileSystemType();
|
||||
xmlFSType.Bootable |= drSb.bootoption != 0; // Or not?
|
||||
xmlFSType.Clusters = (long)(bytes / (ulong)(1 << drSb.log2secsize));
|
||||
xmlFSType.ClusterSize = (1 << drSb.log2secsize);
|
||||
xmlFSType.Type = "Acorn Advanced Disc Filing System";
|
||||
xmlFSType.VolumeName = discname;
|
||||
xmlFSType.VolumeSerial = string.Format("{0}", drSb.disc_id);
|
||||
}
|
||||
|
||||
public override Errno Mount()
|
||||
@@ -287,6 +769,87 @@ namespace DiscImageChef.Filesystems
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
byte AcornMapChecksum(byte[] data, int length)
|
||||
{
|
||||
int sum = 0;
|
||||
int carry = 0;
|
||||
|
||||
if(length > data.Length)
|
||||
length = data.Length;
|
||||
|
||||
// ADC r0, r0, r1
|
||||
// MOVS r0, r0, LSL #24
|
||||
// MOV r0, r0, LSR #24
|
||||
for(int i = length - 1; i >= 0; i--)
|
||||
{
|
||||
sum += data[i] + carry;
|
||||
if(sum > 0xFF)
|
||||
{
|
||||
carry = 1;
|
||||
sum &= 0xFF;
|
||||
}
|
||||
else
|
||||
carry = 0;
|
||||
}
|
||||
|
||||
return (byte)(sum & 0xFF);
|
||||
}
|
||||
|
||||
byte NewMapChecksum(byte[] map_base)
|
||||
{
|
||||
uint sum_vector0;
|
||||
uint sum_vector1;
|
||||
uint sum_vector2;
|
||||
uint sum_vector3;
|
||||
uint rover;
|
||||
|
||||
sum_vector0 = 0;
|
||||
sum_vector1 = 0;
|
||||
sum_vector2 = 0;
|
||||
sum_vector3 = 0;
|
||||
|
||||
for(rover = (uint)(map_base.Length - 4); rover > 0; rover -= 4)
|
||||
{
|
||||
sum_vector0 += map_base[rover + 0] + (sum_vector3 >> 8);
|
||||
sum_vector3 &= 0xff;
|
||||
sum_vector1 += map_base[rover + 1] + (sum_vector0 >> 8);
|
||||
sum_vector0 &= 0xff;
|
||||
sum_vector2 += map_base[rover + 2] + (sum_vector1 >> 8);
|
||||
sum_vector1 &= 0xff;
|
||||
sum_vector3 += map_base[rover + 3] + (sum_vector2 >> 8);
|
||||
sum_vector2 &= 0xff;
|
||||
}
|
||||
|
||||
/*
|
||||
Don't add the check byte when calculating its value
|
||||
*/
|
||||
sum_vector0 += (sum_vector3 >> 8);
|
||||
sum_vector1 += map_base[rover + 1] + (sum_vector0 >> 8);
|
||||
sum_vector2 += map_base[rover + 2] + (sum_vector1 >> 8);
|
||||
sum_vector3 += map_base[rover + 3] + (sum_vector2 >> 8);
|
||||
|
||||
return (byte)((sum_vector0 ^ sum_vector1 ^ sum_vector2 ^ sum_vector3) & 0xff);
|
||||
}
|
||||
|
||||
// TODO: This is not correct...
|
||||
byte AcornDirectoryChecksum(byte[] data, int length)
|
||||
{
|
||||
uint sum = 0;
|
||||
|
||||
if(length > data.Length)
|
||||
length = data.Length;
|
||||
|
||||
// EOR r0, r1, r0, ROR #13
|
||||
for(int i = 0; i < length; i++)
|
||||
{
|
||||
uint carry = sum & 0x1FFF;
|
||||
sum >>= 13;
|
||||
sum ^= data[i];
|
||||
sum += (carry << 19);
|
||||
}
|
||||
|
||||
return (byte)(((sum & 0xFF000000) >> 24) ^ ((sum & 0xFF0000) >> 16) ^ ((sum & 0xFF00) >> 8) ^ (sum & 0xFF));
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user