From ad53e8e459efb9668e1d96c019125477be585204 Mon Sep 17 00:00:00 2001 From: Natalia Portillo Date: Sun, 21 Aug 2016 19:23:58 +0100 Subject: [PATCH] Separate Lisa tag decoding from Lisa filesystem and added Priam tags. --- ChangeLog | 6 + DiscImageChef.Decoders.csproj | 1 + LisaTag.cs | 360 ++++++++++++++++++++++++++++++++++ 3 files changed, 367 insertions(+) create mode 100644 LisaTag.cs diff --git a/ChangeLog b/ChangeLog index de8462e..92da95b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2016-08-21 Natalia Portillo + + * LisaTag.cs: + * DiscImageChef.Decoders.csproj: Separate Lisa tag decoding + from Lisa filesystem and added Priam tags. + 2016-08-18 Natalia Portillo * ATIP.cs: Make ATIP manufacturer resolver a public method. diff --git a/DiscImageChef.Decoders.csproj b/DiscImageChef.Decoders.csproj index f5b2d5b..63f28ca 100644 --- a/DiscImageChef.Decoders.csproj +++ b/DiscImageChef.Decoders.csproj @@ -91,6 +91,7 @@ + diff --git a/LisaTag.cs b/LisaTag.cs new file mode 100644 index 0000000..190f4b6 --- /dev/null +++ b/LisaTag.cs @@ -0,0 +1,360 @@ +// /*************************************************************************** +// The Disc Image Chef +// ---------------------------------------------------------------------------- +// +// Filename : LisaTag.cs +// Author(s) : Natalia Portillo +// +// Component : Component +// +// --[ Description ] ---------------------------------------------------------- +// +// Description +// +// --[ 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 . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2016 Natalia Portillo +// ****************************************************************************/ +using System; +namespace DiscImageChef.Decoders +{ + public static class LisaTag + { + /// + /// LisaOS tag as stored on Apple Profile and FileWare disks (20 bytes) + /// + public struct ProfileTag + { + /// 0x00, Lisa OS version number + public ushort version; + /// 0x02 bits 7 to 6, kind of info in this block + public byte kind; + /// 0x02 bits 5 to 0, reserved + public byte reserved; + /// 0x03, disk volume number + public byte volume; + /// 0x04, file ID + public short fileID; + /// + /// 0x06 bit 7, checksum valid? + /// + public bool validChk; + /// + /// 0x06 bits 6 to 0, used bytes in block + /// + public ushort usedBytes; + /// + /// 0x08, 3 bytes, absolute page number + /// + public uint absPage; + /// + /// 0x0B, checksum of data + /// + public byte checksum; + /// + /// 0x0C, relative page number + /// + public ushort relPage; + /// + /// 0x0E, 3 bytes, next block, 0xFFFFFF if it's last block + /// + public uint nextBlock; + /// + /// 0x11, 3 bytes, previous block, 0xFFFFFF if it's first block + /// + public uint prevBlock; + + /// On-memory value for easy first block search. + public bool isFirst; + /// On-memory value for easy last block search. + public bool isLast; +} + + /// + /// LisaOS tag as stored on Priam DataTower disks (24 bytes) + /// + public struct PriamTag + { + /// 0x00, Lisa OS version number + public ushort version; + /// 0x02 bits 7 to 6, kind of info in this block + public byte kind; + /// 0x02 bits 5 to 0, reserved + public byte reserved; + /// 0x03, disk volume number + public byte volume; + /// 0x04, file ID + public short fileID; + /// + /// 0x06 bit 7, checksum valid? + /// + public bool validChk; + /// + /// 0x06 bits 6 to 0, used bytes in block + /// + public ushort usedBytes; + /// + /// 0x08, 3 bytes, absolute page number + /// + public uint absPage; + /// + /// 0x0B, checksum of data + /// + public byte checksum; + /// + /// 0x0C, relative page number + /// + public ushort relPage; + /// + /// 0x0E, 3 bytes, next block, 0xFFFFFF if it's last block + /// + public uint nextBlock; + /// + /// 0x11, 3 bytes, previous block, 0xFFFFFF if it's first block + /// + public uint prevBlock; + /// + /// 0x14, disk size + /// + public uint diskSize; + + /// On-memory value for easy first block search. + public bool isFirst; + /// On-memory value for easy last block search. + public bool isLast; + } + + /// + /// LisaOS tag as stored on Apple Sony disks (12 bytes) + /// + public struct SonyTag + { + /// 0x00, Lisa OS version number + public ushort version; + /// 0x02 bits 7 to 6, kind of info in this block + public byte kind; + /// 0x02 bits 5 to 0, reserved + public byte reserved; + /// 0x03, disk volume number + public byte volume; + /// 0x04, file ID + public short fileID; + /// + /// 0x06, relative page number + /// + public ushort relPage; + /// + /// 0x08, 3 bytes, next block, 0x7FF if it's last block, 0x8000 set if block is valid + /// + public ushort nextBlock; + /// + /// 0x0A, 3 bytes, previous block, 0x7FF if it's first block + /// + public ushort prevBlock; + + /// On-memory value for easy first block search. + public bool isFirst; + /// On-memory value for easy last block search. + public bool isLast; + } + + public static SonyTag? DecodeSonyTag(byte[] tag) + { + if(tag == null || tag.Length != 12) + return null; + + SonyTag snTag = new SonyTag(); + + BigEndianBitConverter.IsLittleEndian = BitConverter.IsLittleEndian; + + byte[] tmp = new byte[4]; + + snTag.version = BigEndianBitConverter.ToUInt16(tag, 0); + snTag.kind = (byte)((tag[2] & 0xC0) >> 6); + snTag.reserved = (byte)(tag[2] & 0x3F); + snTag.volume = tag[3]; + snTag.fileID = BigEndianBitConverter.ToInt16(tag, 4); + snTag.relPage = BigEndianBitConverter.ToUInt16(tag, 6); + snTag.nextBlock = (ushort)(BigEndianBitConverter.ToUInt16(tag, 8) & 0x7FF); + snTag.prevBlock = (ushort)(BigEndianBitConverter.ToUInt16(tag, 10) & 0x7FF); + + snTag.isLast = snTag.nextBlock == 0x7FF; + snTag.isFirst = snTag.prevBlock == 0x7FF; + + return snTag; + } + + public static ProfileTag? DecodeProfileTag(byte[] tag) + { + if(tag == null || tag.Length != 20) + return null; + + ProfileTag phTag = new ProfileTag(); + + BigEndianBitConverter.IsLittleEndian = BitConverter.IsLittleEndian; + + byte[] tmp = new byte[4]; + + phTag.version = BigEndianBitConverter.ToUInt16(tag, 0); + phTag.kind = (byte)((tag[2] & 0xC0) >> 6); + phTag.reserved = (byte)(tag[2] & 0x3F); + phTag.volume = tag[3]; + phTag.fileID = BigEndianBitConverter.ToInt16(tag, 4); + phTag.validChk |= (tag[6] & 0x80) == 0x80; + phTag.usedBytes = (ushort)(BigEndianBitConverter.ToUInt16(tag, 6) & 0x7FFF); + + tmp[0] = 0x00; + tmp[1] = tag[8]; + tmp[2] = tag[9]; + tmp[3] = tag[10]; + phTag.absPage = BigEndianBitConverter.ToUInt32(tmp, 0); + + phTag.checksum = tag[11]; + phTag.relPage = BigEndianBitConverter.ToUInt16(tag, 12); + + tmp[0] = 0x00; + tmp[1] = tag[14]; + tmp[2] = tag[15]; + tmp[3] = tag[16]; + phTag.nextBlock = BigEndianBitConverter.ToUInt32(tmp, 0); + + tmp[0] = 0x00; + tmp[1] = tag[17]; + tmp[2] = tag[18]; + tmp[3] = tag[19]; + phTag.prevBlock = BigEndianBitConverter.ToUInt32(tmp, 0); + + phTag.isLast = phTag.nextBlock == 0xFFFFFF; + phTag.isFirst = phTag.prevBlock == 0xFFFFFF; + + return phTag; + } + + public static PriamTag? DecodePriamTag(byte[] tag) + { + if(tag == null || tag.Length != 24) + return null; + + PriamTag pmTag = new PriamTag(); + + BigEndianBitConverter.IsLittleEndian = BitConverter.IsLittleEndian; + + byte[] tmp = new byte[4]; + + pmTag.version = BigEndianBitConverter.ToUInt16(tag, 0); + pmTag.kind = (byte)((tag[2] & 0xC0) >> 6); + pmTag.reserved = (byte)(tag[2] & 0x3F); + pmTag.volume = tag[3]; + pmTag.fileID = BigEndianBitConverter.ToInt16(tag, 4); + pmTag.validChk |= (tag[6] & 0x80) == 0x80; + pmTag.usedBytes = (ushort)(BigEndianBitConverter.ToUInt16(tag, 6) & 0x7FFF); + + tmp[0] = 0x00; + tmp[1] = tag[8]; + tmp[2] = tag[9]; + tmp[3] = tag[10]; + pmTag.absPage = BigEndianBitConverter.ToUInt32(tmp, 0); + + pmTag.checksum = tag[11]; + pmTag.relPage = BigEndianBitConverter.ToUInt16(tag, 12); + + tmp[0] = 0x00; + tmp[1] = tag[14]; + tmp[2] = tag[15]; + tmp[3] = tag[16]; + pmTag.nextBlock = BigEndianBitConverter.ToUInt32(tmp, 0); + + tmp[0] = 0x00; + tmp[1] = tag[17]; + tmp[2] = tag[18]; + tmp[3] = tag[19]; + pmTag.prevBlock = BigEndianBitConverter.ToUInt32(tmp, 0); + + pmTag.diskSize = BigEndianBitConverter.ToUInt32(tag, 20); + + pmTag.isLast = pmTag.nextBlock == 0xFFFFFF; + pmTag.isFirst = pmTag.prevBlock == 0xFFFFFF; + + return pmTag; + } + + public static PriamTag? DecodeTag(byte[] tag) + { + if(tag == null) + return null; + + PriamTag pmTag = new PriamTag(); + + switch(tag.Length) + { + case 12: + SonyTag? snTag = DecodeSonyTag(tag); + + if(snTag == null) + return null; + + pmTag = new PriamTag(); + pmTag.absPage = 0; + pmTag.checksum = 0; + pmTag.diskSize = 0; + pmTag.fileID = snTag.Value.fileID; + pmTag.kind = snTag.Value.kind; + pmTag.nextBlock = snTag.Value.nextBlock; + pmTag.prevBlock = snTag.Value.prevBlock; + pmTag.relPage = snTag.Value.relPage; + pmTag.reserved = snTag.Value.reserved; + pmTag.usedBytes = 0; + pmTag.validChk = false; + pmTag.version = snTag.Value.version; + pmTag.volume = snTag.Value.volume; + pmTag.isFirst = snTag.Value.isFirst; + pmTag.isLast = snTag.Value.isLast; + + return pmTag; + case 20: + ProfileTag? phTag = DecodeProfileTag(tag); + + if(phTag == null) + return null; + + pmTag = new PriamTag(); + pmTag.absPage = phTag.Value.absPage; + pmTag.checksum = phTag.Value.checksum; + pmTag.diskSize = 0; + pmTag.fileID = phTag.Value.fileID; + pmTag.kind = phTag.Value.kind; + pmTag.nextBlock = phTag.Value.nextBlock; + pmTag.prevBlock = phTag.Value.prevBlock; + pmTag.relPage = phTag.Value.relPage; + pmTag.reserved = phTag.Value.reserved; + pmTag.usedBytes = phTag.Value.usedBytes; + pmTag.validChk = phTag.Value.validChk; + pmTag.version = phTag.Value.version; + pmTag.volume = phTag.Value.volume; + pmTag.isFirst = phTag.Value.isFirst; + pmTag.isLast = phTag.Value.isLast; + + return pmTag; + case 24: + return DecodePriamTag(tag); + default: + return null; + } + } + } +} +