// /***************************************************************************
// The Disc Image Chef
// ----------------------------------------------------------------------------
//
// Filename       : Structs.cs
// Author(s)      : Natalia Portillo <claunia@claunia.com>
//
// Component      : CP/M filesystem plugin.
//
// --[ Description ] ----------------------------------------------------------
//
//     CP/M filesystem structures.
//
// --[ 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/>.
//
// ----------------------------------------------------------------------------
// Copyright © 2011-2017 Natalia Portillo
// ****************************************************************************/

using System.Runtime.InteropServices;

namespace DiscImageChef.Filesystems.CPM
{
    partial class CPM : Filesystem
    {
        /// <summary>
        /// Most of the times this structure is hard wired or generated by CP/M, not stored on disk
        /// </summary>
        class DiscParameterBlock
        {
            /// <summary>
            /// Sectors per track
            /// </summary>
            public ushort spt;
            /// <summary>
            /// Block shift
            /// </summary>
            public byte bsh;
            /// <summary>
            /// Block mask
            /// </summary>
            public byte blm;
            /// <summary>
            /// Extent mask
            /// </summary>
            public byte exm;
            /// <summary>
            /// Blocks on disk - 1
            /// </summary>
            public ushort dsm;
            /// <summary>
            /// Directory entries - 1
            /// </summary>
            public ushort drm;
            /// <summary>
            /// First byte of allocation bitmap
            /// </summary>
            public byte al0;
            /// <summary>
            /// Second byte of allocation bitmap
            /// </summary>
            public byte al1;
            /// <summary>
            /// Checksum vector size
            /// </summary>
            public ushort cks;
            /// <summary>
            /// Reserved tracks
            /// </summary>
            public ushort off;
            /// <summary>
            /// Physical sector shift
            /// </summary>
            public byte psh;
            /// <summary>
            /// Physical sector mask
            /// </summary>
            public byte phm;
        }

        /// <summary>
        /// Amstrad superblock, for PCW
        /// </summary>
        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        struct AmstradSuperBlock
        {
            /// <summary>
            /// Format ID. 0 single-side, 3 double-side. 1 and 2 are for CPC but they don't use the superblock
            /// </summary>
            public byte format;
            /// <summary>
            /// Gives information about side ordering
            /// </summary>
            public byte sidedness;
            /// <summary>
            /// Tracks per side, aka, cylinders
            /// </summary>
            public byte tps;
            /// <summary>
            /// Sectors per track
            /// </summary>
            public byte spt;
            /// <summary>
            /// Physical sector shift
            /// </summary>
            public byte psh;
            /// <summary>
            /// Reserved tracks
            /// </summary>
            public byte off;
            /// <summary>
            /// Block size shift
            /// </summary>
            public byte bsh;
            /// <summary>
            /// How many blocks does the directory take
            /// </summary>
            public byte dirBlocks;
            /// <summary>
            /// GAP#3 length (intersector)
            /// </summary>
            public byte gapLen;
            /// <summary>
            /// GAP#4 length (end-of-track)
            /// </summary>
            public byte formatGap;
            /// <summary>
            /// Must be 0
            /// </summary>
            public byte zero1;
            /// <summary>
            /// Must be 0
            /// </summary>
            public byte zero2;
            /// <summary>
            /// Must be 0
            /// </summary>
            public byte zero3;
            /// <summary>
            /// Must be 0
            /// </summary>
            public byte zero4;
            /// <summary>
            /// Must be 0
            /// </summary>
            public byte zero5;
            /// <summary>
            /// Indicates machine the boot code following the superblock is designed to boot
            /// </summary>
            public byte fiddle;
        }

        /// <summary>
        /// Superblock found on CP/M-86 hard disk volumes
        /// </summary>
        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        struct HardDiskSuperBlock
        {
            /// <summary>
            /// Value so the sum of all the superblock's sector bytes taken as 16-bit values gives 0
            /// </summary>
            public ushort checksum;
            /// <summary>
            /// Copyright string
            /// </summary>
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x1F)]
            public byte[] copyright;
            /// <summary>
            /// First cylinder of disk where this volume resides
            /// </summary>
            public ushort firstCylinder;
            /// <summary>
            /// How many cylinders does this volume span
            /// </summary>
            public ushort cylinders;
            /// <summary>
            /// Heads on hard disk
            /// </summary>
            public byte heads;
            /// <summary>
            /// Sectors per track
            /// </summary>
            public byte sectorsPerTrack;
            /// <summary>
            /// Flags, only use by CCP/M where bit 0 equals verify on write
            /// </summary>
            public byte flags;
            /// <summary>
            /// Sector size / 128
            /// </summary>
            public byte recordsPerSector;
            /// <summary>
            /// <see cref="DiscParameterBlock.spt"/> 
            /// </summary>
            public ushort spt;
            /// <summary>
            /// <see cref="DiscParameterBlock.bsh"/> 
            /// </summary>
            public byte bsh;
            /// <summary>
            /// <see cref="DiscParameterBlock.blm"/> 
            /// </summary>
            public byte blm;
            /// <summary>
            /// <see cref="DiscParameterBlock.exm"/> 
            /// </summary>
            public byte exm;
            /// <summary>
            /// <see cref="DiscParameterBlock.dsm"/> 
            /// </summary>
            public ushort dsm;
            /// <summary>
            /// <see cref="DiscParameterBlock.drm"/> 
            /// </summary>
            public ushort drm;
            /// <summary>
            /// <see cref="DiscParameterBlock.al0"/> 
            /// </summary>
            public ushort al0;
            /// <summary>
            /// <see cref="DiscParameterBlock.al1"/> 
            /// </summary>
            public ushort al1;
            /// <summary>
            /// <see cref="DiscParameterBlock.cks"/> 
            /// </summary>
            public ushort cks;
            /// <summary>
            /// <see cref="DiscParameterBlock.off"/> 
            /// </summary>
            public ushort off;
            /// <summary>
            /// Must be zero
            /// </summary>
            public ushort zero1;
            /// <summary>
            /// Must be zero
            /// </summary>
            public ushort zero2;
            /// <summary>
            /// Must be zero
            /// </summary>
            public ushort zero3;
            /// <summary>
            /// Must be zero
            /// </summary>
            public ushort zero4;
            /// <summary>
            /// How many 128 bytes are in a block
            /// </summary>
            public ushort recordsPerBlock;
            /// <summary>
            /// Maximum number of bad blocks in the bad block list
            /// </summary>
            public ushort badBlockWordsMax;
            /// <summary>
            /// Used number of bad blocks in the bad block list
            /// </summary>
            public ushort badBlockWords;
            /// <summary>
            /// First block after the blocks reserved for bad block substitution
            /// </summary>
            public ushort firstSub;
        }

        /// <summary>
        /// Volume label entry
        /// </summary>
        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        struct LabelEntry
        {
            /// <summary>
            /// Must be 0x20
            /// </summary>
            public byte signature;
            /// <summary>
            /// Label in ASCII
            /// </summary>
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 11)]
            public byte[] label;
            /// <summary>
            /// Label flags. Bit 0 = label exists, bit 4 = creation timestamp, bit 5 = modification timestamp, bit 6 = access timestamp, bit 7 = password enabled
            /// </summary>
            public byte flags;
            /// <summary>
            /// Password decoder byte
            /// </summary>
            public byte passwordDecoder;
            /// <summary>
            /// Must be 0
            /// </summary>
            public ushort reserved;
            /// <summary>
            /// Password XOR'ed with <see cref="passwordDecoder"/> 
            /// </summary>
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
            public byte[] password;
            /// <summary>
            /// Label creation time
            /// </summary>
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
            public byte[] ctime;
            /// <summary>
            /// Label modification time
            /// </summary>
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
            public byte[] mtime;
        }

        /// <summary>
        /// CP/M 3 timestamp entry
        /// </summary>
        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        struct DateEntry
        {
            /// <summary>
            /// Must be 0x21
            /// </summary>
            public byte signature;
            /// <summary>
            /// File 1 create/access timestamp
            /// </summary>
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
            public byte[] date1;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
            /// <summary>
            /// File 1 modification timestamp
            /// </summary>
            public byte[] date2;
            /// <summary>
            /// File 1 password mode
            /// </summary>
            public byte mode1;
            public byte zero1;
            /// <summary>
            /// File 2 create/access timestamp
            /// </summary>
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
            public byte[] date3;
            /// <summary>
            /// File 2 modification timestamp
            /// </summary>
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
            public byte[] date4;
            /// <summary>
            /// File 2 password mode
            /// </summary>
            public byte mode2;
            public byte zero2;
            /// <summary>
            /// File 3 create/access timestamp
            /// </summary>
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
            public byte[] date5;
            /// <summary>
            /// File 3 modification timestamp
            /// </summary>
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
            public byte[] date6;
            /// <summary>
            /// File 3 password mode
            /// </summary>
            public byte mode3;
            public ushort zero3;
        }

        /// <summary>
        /// Password entry
        /// </summary>
        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        struct PasswordEntry
        {
            /// <summary>
            /// 16 + user number
            /// </summary>
            public byte userNumber;
            /// <summary>
            /// Filename
            /// </summary>
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
            public byte[] filename;
            /// <summary>
            /// Extension
            /// </summary>
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
            public byte[] extension;
            /// <summary>
            /// Password mode. Bit 7 = required for read, bit 6 = required for write, bit 5 = required for delete
            /// </summary>
            public byte mode;
            /// <summary>
            /// Password decoder byte
            /// </summary>
            public byte passwordDecoder;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
            public byte[] reserved;
            /// <summary>
            /// Password XOR'ed with <see cref="passwordDecoder"/> 
            /// </summary>
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
            public byte[] password;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
            public byte[] reserved2;
        }

        /// <summary>
        /// Timestamp for Z80DOS or DOS+
        /// </summary>
        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        struct TrdPartyDateEntry
        {
            /// <summary>
            /// Must be 0x21
            /// </summary>
            public byte signature;
            public byte zero;
            /// <summary>
            /// Creation year for file 1
            /// </summary>
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
            public byte[] create1;
            /// <summary>
            /// Modification time for file 1
            /// </summary>
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
            public byte[] modify1;
            /// <summary>
            /// Access time for file 1
            /// </summary>
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
            public byte[] access1;
            /// <summary>
            /// Creation year for file 2
            /// </summary>
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
            public byte[] create2;
            /// <summary>
            /// Modification time for file 2
            /// </summary>
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
            public byte[] modify2;
            /// <summary>
            /// Access time for file 2
            /// </summary>
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
            public byte[] access2;
            /// <summary>
            /// Creation year for file 3
            /// </summary>
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
            public byte[] create3;
            /// <summary>
            /// Modification time for file 3
            /// </summary>
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
            public byte[] modify3;
            /// <summary>
            /// Access time for file 3
            /// </summary>
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
            public byte[] access3;
        }

        /// <summary>
        /// Directory entry for &lt;256 allocation blocks 
        /// </summary>
        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        struct DirectoryEntry
        {
            /// <summary>
            /// User number. Bit 7 set in CP/M 1 means hidden
            /// </summary>
            public byte statusUser;
            /// <summary>
            /// Filename and bit 7 as flags
            /// </summary>
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
            public byte[] filename;
            /// <summary>
            /// Extension and bit 7 as flags
            /// </summary>
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
            public byte[] extension;
            /// <summary>
            /// Low byte of extent number
            /// </summary>
            public byte extentCounter;
            /// <summary>
            /// Last record bytes. In some implementations it means how many bytes are used in the last record, in others how many bytes are free.
            /// It always refer to 128 byte records even if blocks are way bigger, so it's mostly useless.
            /// </summary>
            public byte lastRecordBytes;
            /// <summary>
            /// High byte of extent number
            /// </summary>
            public byte extentCounterHigh;
            /// <summary>
            /// How many records are used in this entry. 0x80 if all are used.
            /// </summary>
            public byte records;
            /// <summary>
            /// Allocation blocks
            /// </summary>
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
            public byte[] allocations;
        }

        /// <summary>
        /// Directory entry for &bt;256 allocation blocks 
        /// </summary>
        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        struct DirectoryEntry16
        {
            /// <summary>
            /// User number. Bit 7 set in CP/M 1 means hidden
            /// </summary>
            public byte statusUser;
            /// <summary>
            /// Filename and bit 7 as flags
            /// </summary>
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
            public byte[] filename;
            /// <summary>
            /// Extension and bit 7 as flags
            /// </summary>
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
            public byte[] extension;
            /// <summary>
            /// Low byte of extent number
            /// </summary>
            public byte extentCounter;
            /// <summary>
            /// Last record bytes. In some implementations it means how many bytes are used in the last record, in others how many bytes are free.
            /// It always refer to 128 byte records even if blocks are way bigger, so it's mostly useless.
            /// </summary>
            public byte lastRecordBytes;
            /// <summary>
            /// High byte of extent number
            /// </summary>
            public byte extentCounterHigh;
            /// <summary>
            /// How many records are used in this entry. 0x80 if all are used.
            /// </summary>
            public byte records;
            /// <summary>
            /// Allocation blocks
            /// </summary>
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
            public ushort[] allocations;
        }
    }
}

