// /*************************************************************************** // Aaru Data Preservation Suite // ---------------------------------------------------------------------------- // // Filename : Definitions.cs // Author(s) : Natalia Portillo // // Component : CP/M filesystem plugin. // // --[ Description ] ---------------------------------------------------------- // // Handles definitions of known CP/M disks. // // --[ 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-2023 Natalia Portillo // ****************************************************************************/ using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Reflection; using System.Text.Json; using System.Text.Json.Serialization; namespace Aaru.Filesystems; public sealed partial class CPM { /// Loads all the known CP/M disk definitions from an JSON stored as an embedded resource. /// The definitions. bool LoadDefinitions() { try { _definitions = JsonSerializer. Deserialize(Assembly.GetExecutingAssembly().GetManifestResourceStream("Aaru.Filesystems.CPM.cpmdefs.json") ?? new MemoryStream(), typeof(CpmDefinitions), CpmDefinitionsContext.Default) as CpmDefinitions; if(_definitions is null) return false; // Patch definitions foreach(CpmDefinition def in _definitions.definitions) { if(def.side1 == null) { def.side1 = new Side { sideId = 0, sectorIds = new int[def.sectorsPerTrack] }; for(int i = 0; i < def.sectorsPerTrack; i++) def.side1.sectorIds[i] = i + 1; } if(def.sides != 2 || def.side2 != null) continue; { def.side2 = new Side { sideId = 1, sectorIds = new int[def.sectorsPerTrack] }; for(int i = 0; i < def.sectorsPerTrack; i++) def.side2.sectorIds[i] = i + 1; } } return true; } catch { return false; } } } [JsonSourceGenerationOptions(WriteIndented = true, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, IncludeFields = true)] [JsonSerializable(typeof(CpmDefinitions))] // ReSharper disable once PartialTypeWithSinglePart public partial class CpmDefinitionsContext : JsonSerializerContext {} /// CP/M disk definitions [SuppressMessage("ReSharper", "InconsistentNaming")] public sealed class CpmDefinitions { /// Timestamp of creation of the CP/M disk definitions list public DateTime creation; /// List of all CP/M disk definitions public List definitions; } /// CP/M disk definition [SuppressMessage("ReSharper", "InconsistentNaming")] public sealed class CpmDefinition { /// Maps the first 16 allocation blocks for reservation, high byte public int al0; /// Maps the first 16 allocation blocks for reservation, low byte public int al1; /// Controller bitrate public string bitrate; /// Block mask for public int blm; /// Left shifts needed to translate allocation block number to lba public int bsh; /// Physical bytes per sector public int bytesPerSector; /// Comment and description public string comment; /// If true, all bytes written on disk are negated public bool complement; /// Total cylinders public int cylinders; /// Total number of available directory entries public int drm; /// Total number of 128 byte records on disk public int dsm; /// Encoding, "FM", "MFM", "GCR" public string encoding; /// Absolutely unknown? public bool evenOdd; /// Extent mask public int exm; /// Disk definition label public string label; /// Tracks at the beginning of disk reserved for BIOS/BDOS public int ofs; /// /// Cylinder/side ordering. SIDES = change side after each track, CYLINDERS = change side after whole side, EAGLE /// and COLUMBIA unknown /// public string order; /// Physical sectors per side public int sectorsPerTrack; /// Description of controller's side 0 (usually, upper side) public Side side1; /// Description of controller's side 1 (usually, lower side) public Side side2; /// Total sides public int sides; /// Physical sector interleaving public int skew; /// Sectors at the beginning of disk reserved for BIOS/BDOS public int sofs; } /// Side descriptions [SuppressMessage("ReSharper", "InconsistentNaming")] public sealed class Side { /// Software interleaving mask, [1,3,0,2] means CP/M LBA 0 is physical sector 1, LBA 1 = 3, so on public int[] sectorIds; /// Side ID as found in each sector address mark public int sideId; }