// /*************************************************************************** // Aaru Data Preservation Suite // ---------------------------------------------------------------------------- // // Filename : Apricot.cs // Author(s) : Natalia Portillo // // Component : Partitioning scheme plugins. // // --[ Description ] ---------------------------------------------------------- // // Manages ACT Apricot partitions. // // --[ 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-2025 Natalia Portillo // ****************************************************************************/ using System; using System.Collections.Generic; using System.Runtime.InteropServices; using Aaru.CommonTypes; using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Interfaces; using Aaru.Helpers; using Aaru.Logging; using Marshal = Aaru.Helpers.Marshal; namespace Aaru.Partitions; /// /// Implements decoding of Apricot partitions public sealed class Apricot : IPartition { const string MODULE_NAME = "Apricot partitions plugin"; readonly int[] _baudRates = [50, 75, 110, 134, 150, 300, 600, 1200, 1800, 2400, 3600, 4800, 7200, 9600, 19200]; readonly string[] _bootTypeCodes = [ Localization.Non_bootable, Localization.Apricot_XI_RAM_BIOS, Localization.Generic_ROM_BIOS, Localization.Apricot_XI_ROM_BIOS, Localization.Apricot_Portable_ROM_BIOS, Localization.Apricot_F1_ROM_BIOS ]; readonly string[] _diskTypeCodes = [ Localization.MF1DD_70_track, "MF1DD", "MF2DD", "Winchester 5M", "Winchester 10M", "Winchester 20M" ]; readonly int[] _lineModes = [256, 200]; readonly int[] _lineWidths = [80, 40]; readonly string[] _operatingSystemCodes = [ Localization.Invalid_operating_system, "MS-DOS", "UCSD Pascal", Localization.CPM, "Concurrent CP/M" ]; readonly string[] _parityTypes = [ Localization.None_parity, Localization.Odd_parity, Localization.Even_parity, Localization.Mark_parity, Localization.Space_parity ]; readonly string[] _printDevices = [Localization.Parallel_print_device, Localization.Serial_print_device]; readonly double[] _stopBits = [1, 1.5, 2]; #region Nested type: Label /// Apricot Label. [StructLayout(LayoutKind.Sequential, Pack = 1)] readonly struct Label { /// Version of format which created disk [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public readonly byte[] version; /// Operating system. public readonly byte operatingSystem; /// Software write protection. [MarshalAs(UnmanagedType.U1)] public readonly bool writeProtected; /// Copy protected. [MarshalAs(UnmanagedType.U1)] public readonly bool copyProtected; /// Boot type. public readonly byte bootType; /// Partitions. public readonly byte partitionCount; /// Is hard disk?. [MarshalAs(UnmanagedType.U1)] public readonly bool winchester; /// Sector size. public readonly ushort sectorSize; /// Sectors per track. public readonly ushort spt; /// Tracks per side. public readonly uint cylinders; /// Sides. public readonly byte heads; /// Interleave factor. public readonly byte interleave; /// Skew factor. public readonly ushort skew; /// Sector where boot code starts. public readonly uint bootLocation; /// Size in sectors of boot code. public readonly ushort bootSize; /// Address at which to load boot code. public readonly uint bootAddress; /// Offset where to jump to boot. public readonly ushort bootOffset; /// Segment where to jump to boot. public readonly ushort bootSegment; /// First data sector. public readonly uint firstDataBlock; /// Generation. public readonly ushort generation; /// Copy count. public readonly ushort copyCount; /// Maximum number of copies. public readonly ushort maxCopies; /// Serial number. [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public readonly byte[] serialNumber; /// Part number. [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public readonly byte[] partNumber; /// Copyright. [MarshalAs(UnmanagedType.ByValArray, SizeConst = 14)] public readonly byte[] copyright; /// BPB for whole disk. public readonly ParameterBlock mainBPB; /// Name of FONT file. [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] public readonly byte[] fontName; /// Name of KEYBOARD file. [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] public readonly byte[] keyboardName; /// Minor BIOS version. public readonly byte biosMinorVersion; /// Major BIOS version. public readonly byte biosMajorVersion; /// Diagnostics enabled?. [MarshalAs(UnmanagedType.U1)] public readonly bool diagnosticsFlag; /// Printer device. public readonly byte prnDevice; /// Bell volume. public readonly byte bellVolume; /// Cache enabled?. [MarshalAs(UnmanagedType.U1)] public readonly bool enableCache; /// Graphics enabled?. [MarshalAs(UnmanagedType.U1)] public readonly bool enableGraphics; /// Length in sectors of DOS. public readonly byte dosLength; /// Length in sectors of FONT file. public readonly byte fontLength; /// Length in sectors of KEYBOARD file. public readonly byte keyboardLength; /// Starting sector of DOS. public readonly ushort dosStart; /// Starting sector of FONT file. public readonly ushort fontStart; /// Starting sector of KEYBOARD file. public readonly ushort keyboardStart; /// Keyboard click volume. public readonly byte keyboardVolume; /// Auto-repeat enabled?. [MarshalAs(UnmanagedType.U1)] public readonly bool autorepeat; /// Auto-repeat lead-in. public readonly byte autorepeatLeadIn; /// Auto-repeat interval. public readonly byte autorepeatInterval; /// Microscreen mode. public readonly byte microscreenMode; /// Spare area for keyboard values expansion. [MarshalAs(UnmanagedType.ByValArray, SizeConst = 11)] public readonly byte[] spareKeyboard; /// Screen line mode. public readonly byte lineMode; /// Screen line width. public readonly byte lineWidth; /// Screen disabled?. [MarshalAs(UnmanagedType.U1)] public readonly bool imageOff; /// Spare area for screen values expansion. [MarshalAs(UnmanagedType.ByValArray, SizeConst = 13)] public readonly byte[] spareScreen; /// TX baud rate. public readonly byte txBaudRate; /// RX baud rate. public readonly byte rxBaudRate; /// TX bits. public readonly byte txBits; /// RX bits. public readonly byte rxBits; /// Stop bits. public readonly byte stopBits; /// Parity enabled?. [MarshalAs(UnmanagedType.U1)] public readonly bool parityCheck; /// Parity type. public readonly byte parityType; /// Xon/Xoff enabled on TX. [MarshalAs(UnmanagedType.U1)] public readonly bool txXonXoff; /// Xon/Xoff enabled on RX. [MarshalAs(UnmanagedType.U1)] public readonly bool rxXonXoff; /// Xon character. public readonly byte xonCharacter; /// Xoff character. public readonly byte xoffCharacter; /// Xon/Xoff buffer on RX. public readonly ushort rxXonXoffBuffer; /// DTR/DSR enabled?. [MarshalAs(UnmanagedType.U1)] public readonly bool dtrDsr; /// CTS/RTS enabled?. [MarshalAs(UnmanagedType.U1)] public readonly bool ctsRts; /// NULLs after CR. public readonly byte nullsAfterCr; /// NULLs after 0xFF. public readonly byte nullsAfterFF; /// Send LF after CR in serial port. [MarshalAs(UnmanagedType.U1)] public readonly bool lfAfterCRSerial; /// BIOS error report in serial port. [MarshalAs(UnmanagedType.U1)] public readonly bool biosErrorReportSerial; /// Spare area for serial port values expansion. [MarshalAs(UnmanagedType.ByValArray, SizeConst = 13)] public readonly byte[] spareSerial; /// Send LF after CR in parallel port. [MarshalAs(UnmanagedType.U1)] public readonly bool lfAfterCrParallel; /// Select line supported?. [MarshalAs(UnmanagedType.U1)] public readonly bool selectLine; /// Paper empty supported?. [MarshalAs(UnmanagedType.U1)] public readonly bool paperEmpty; /// Fault line supported?. [MarshalAs(UnmanagedType.U1)] public readonly bool faultLine; /// BIOS error report in parallel port. [MarshalAs(UnmanagedType.U1)] public readonly bool biosErrorReportParallel; /// Spare area for parallel port values expansion. [MarshalAs(UnmanagedType.ByValArray, SizeConst = 11)] public readonly byte[] spareParallel; /// Spare area for Winchester values expansion. [MarshalAs(UnmanagedType.ByValArray, SizeConst = 14)] public readonly byte[] spareWinchester; /// Parking enabled?. [MarshalAs(UnmanagedType.U1)] public readonly bool parkingEnabled; /// Format protection?. [MarshalAs(UnmanagedType.U1)] public readonly bool formatProtection; /// Spare area for RAM disk values expansion. [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] public readonly byte[] spareRamDisk; /// List of bad blocks. [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] public readonly ushort[] badBlocks; /// Array of partition BPBs. [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public readonly ParameterBlock[] partitions; /// Spare area. [MarshalAs(UnmanagedType.ByValArray, SizeConst = 63)] public readonly byte[] spare; /// CP/M double side indicator?. public readonly bool cpmDoubleSided; } #endregion #region Nested type: ParameterBlock [StructLayout(LayoutKind.Sequential, Pack = 1)] struct ParameterBlock { /// Bytes per sector public readonly ushort bps; /// Sectors per cluster public readonly byte spc; /// Reserved sectors between BPB and FAT public readonly ushort rsectors; /// Number of FATs public readonly byte fats_no; /// Number of entries on root directory public readonly ushort root_ent; /// Sectors in volume public readonly ushort sectors; /// Media descriptor public readonly byte media; /// Sectors per FAT public readonly ushort spfat; /// Disk type public readonly byte diskType; /// Volume starting sector public readonly ushort startSector; } #endregion #region IPartition Members /// public string Name => Localization.Apricot_Name; /// public Guid Id => new("8CBF5864-7B5A-47A0-8CEB-199C74FA22DE"); /// public string Author => Authors.NATALIA_PORTILLO; /// public bool GetInformation(IMediaImage imagePlugin, out List partitions, ulong sectorOffset) { partitions = []; // I think Apricot can't chain partitions so. if(sectorOffset != 0) return false; ErrorNumber errno = imagePlugin.ReadSector(0, false, out byte[] sector, out _); if(errno != ErrorNumber.NoError || sector.Length < 512) return false; Label label = Marshal.ByteArrayToStructureLittleEndian