diff --git a/Aaru.Images/CrunchDisk/Constants.cs b/Aaru.Images/CrunchDisk/Constants.cs new file mode 100644 index 000000000..216a945ba --- /dev/null +++ b/Aaru.Images/CrunchDisk/Constants.cs @@ -0,0 +1,47 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Constants.cs +// Author(s) : Natalia Portillo +// +// Component : Disk image plugins. +// +// --[ Description ] ---------------------------------------------------------- +// +// Contains constants for CrunchDisk disk images. +// +// --[ 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-2026 Natalia Portillo +// ****************************************************************************/ + +namespace Aaru.Images; + +public sealed partial class CrunchDisk +{ + /// "CDF0" file header magic number + const uint HEADER_MAGIC = 0x43444630; + /// "CYL0" uncompressed cylinder marker + const uint CYL_UNCOMPRESSED = 0x43594C30; + /// "CYL1" compressed/interleaved cylinder marker + const uint CYL_COMPRESSED = 0x43594C31; + /// Size of the file header in bytes + const int HEADER_SIZE = 52; + /// Size of the per-cylinder header in bytes + const int CYLINDER_HEADER_SIZE = 8; +} \ No newline at end of file diff --git a/Aaru.Images/CrunchDisk/CrunchDisk.cs b/Aaru.Images/CrunchDisk/CrunchDisk.cs new file mode 100644 index 000000000..94529c166 --- /dev/null +++ b/Aaru.Images/CrunchDisk/CrunchDisk.cs @@ -0,0 +1,71 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : CrunchDisk.cs +// Author(s) : Natalia Portillo +// +// Component : Disk image plugins. +// +// --[ Description ] ---------------------------------------------------------- +// +// Manages CrunchDisk disk images. +// +// --[ 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-2026 Natalia Portillo +// ****************************************************************************/ + +using Aaru.CommonTypes.Interfaces; +using Aaru.CommonTypes.Structs; + +namespace Aaru.Images; + +/// +/// Implements reading CrunchDisk disk images +public sealed partial class CrunchDisk : IMediaImage +{ + const string MODULE_NAME = "CrunchDisk plugin"; + byte[] _decompressedData; + + Header _header; + ImageInfo _imageInfo; + + public CrunchDisk() => _imageInfo = new ImageInfo + { + ReadableSectorTags = [], + ReadableMediaTags = [], + HasPartitions = false, + HasSessions = false, + Version = null, + Application = "CrunchDisk", + ApplicationVersion = null, + Creator = null, + Comments = null, + MediaManufacturer = null, + MediaModel = null, + MediaSerialNumber = null, + MediaBarcode = null, + MediaPartNumber = null, + MediaSequence = 0, + LastMediaSequence = 0, + DriveManufacturer = null, + DriveModel = null, + DriveSerialNumber = null, + DriveFirmwareRevision = null + }; +} \ No newline at end of file diff --git a/Aaru.Images/CrunchDisk/Enums.cs b/Aaru.Images/CrunchDisk/Enums.cs new file mode 100644 index 000000000..8ec30aabf --- /dev/null +++ b/Aaru.Images/CrunchDisk/Enums.cs @@ -0,0 +1,46 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Enums.cs +// Author(s) : Natalia Portillo +// +// Component : Disk image plugins. +// +// --[ Description ] ---------------------------------------------------------- +// +// Contains enumerations for CrunchDisk disk images. +// +// --[ 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-2026 Natalia Portillo +// ****************************************************************************/ + +namespace Aaru.Images; + +public sealed partial class CrunchDisk +{ + enum PackerType : ushort + { + /// No compression, stored data only + Stored = 0, + /// PowerPacker compression + PowerPacker = 1, + /// XPK compression (not supported) + Xpk = 2 + } +} \ No newline at end of file diff --git a/Aaru.Images/CrunchDisk/Helpers.cs b/Aaru.Images/CrunchDisk/Helpers.cs new file mode 100644 index 000000000..f037920ff --- /dev/null +++ b/Aaru.Images/CrunchDisk/Helpers.cs @@ -0,0 +1,216 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Helpers.cs +// Author(s) : Natalia Portillo +// +// Component : Disk image plugins. +// +// --[ Description ] ---------------------------------------------------------- +// +// Contains helper methods for CrunchDisk disk images. +// +// --[ 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-2026 Natalia Portillo +// ****************************************************************************/ + +using System; + +namespace Aaru.Images; + +public sealed partial class CrunchDisk +{ + /// Decompresses PowerPacker compressed data + /// Compressed data + /// Length of compressed data + /// Expected length of decompressed data + /// Bit widths for offset encoding per index (4 entries) + /// Decompressed data + static byte[] PowerPackerDecompress(byte[] source, int packedLength, int unpackedLength, byte[] offsetSizes) + { + var output = new byte[unpackedLength]; + int srcPos = packedLength - 4; + int dstPos = unpackedLength; + uint shiftReg = 1u << 8; + + // Skip the number of bits indicated by the last byte of compressed data + SkipBits(source, ref srcPos, ref shiftReg, source[packedLength - 1]); + + while(dstPos > 0) + { + // Determine whether we need to copy literal bytes + uint flag = ReadBits(source, ref srcPos, ref shiftReg, 1); + + if(flag == 0) + { + // Read run of literal bytes: at least 1, extended in groups of 3 + uint count = 1; + uint extra; + + do + { + extra = ReadBits(source, ref srcPos, ref shiftReg, 2); + count += extra; + } while(extra == 3); + + // Copy literal bytes from the bitstream + while(count-- > 0) + { + if(--dstPos < 0) return output; + + output[dstPos] = (byte)ReadBits(source, ref srcPos, ref shiftReg, 8); + } + } + + // Decode a back-reference from already-decompressed data + uint idx = ReadBits(source, ref srcPos, ref shiftReg, 2); + int nBits = offsetSizes[idx]; + uint length = idx + 2; + uint offset; + + if(idx == 3) + { + // Extended match: variable offset width and extended length + uint useFullBits = ReadBits(source, ref srcPos, ref shiftReg, 1); + offset = ReadBits(source, ref srcPos, ref shiftReg, useFullBits != 0 ? nBits : 7); + + // Read additional length in groups of 7 + uint lengthExtra; + + do + { + lengthExtra = ReadBits(source, ref srcPos, ref shiftReg, 3); + length += lengthExtra; + } while(lengthExtra == 7); + } + else + offset = ReadBits(source, ref srcPos, ref shiftReg, nBits); + + offset++; + + // Copy bytes from previous output + while(length-- > 0) + { + if(--dstPos < 0) return output; + + output[dstPos] = output[dstPos + offset]; + } + } + + return output; + } + + /// Reads a number of bits from the PowerPacker bitstream (backward, LSB-first) + static uint ReadBits(byte[] source, ref int srcPos, ref uint shiftReg, int count) + { + uint result = 0; + + for(var i = 0; i < count; i++) + { + if((shiftReg & 1u << 8) != 0) shiftReg = 1u << 16 | source[--srcPos]; + + result = result << 1 | shiftReg & 1; + shiftReg >>= 1; + } + + return result; + } + + /// Skips a number of bits in the PowerPacker bitstream + static void SkipBits(byte[] source, ref int srcPos, ref uint shiftReg, int count) + { + for(var i = 0; i < count; i++) + { + if((shiftReg & 1u << 8) != 0) shiftReg = 1u << 16 | source[--srcPos]; + + shiftReg >>= 1; + } + } + + /// + /// De-interleaves cylinder data from CrunchDisk's 4-pass byte ordering back to sequential sector data. + /// In CrunchDisk format, each sector's bytes are stored as all first bytes, then all second bytes, + /// then third bytes, then fourth bytes (interleaved in 4-byte strides). + /// + /// Interleaved source data + /// Output buffer for de-interleaved data + /// Size of each sector in bytes + /// Number of sectors in the cylinder + /// Actual size of source data available + static void ResortCylinderData(byte[] source, byte[] destination, uint blockSize, uint numBlocks, uint sourceSize) + { + var srcIdx = 0; + var dstBase = 0; + + for(uint block = 0; block < numBlocks; block++) + { + int blockEnd = dstBase + (int)blockSize; + + if(sourceSize >= blockSize) + { + for(var pass = 0; pass < 4; pass++) + { + for(int p = dstBase + pass; p < blockEnd; p += 4) destination[p] = source[srcIdx++]; + } + + sourceSize -= blockSize; + } + else + Array.Clear(destination, dstBase, (int)blockSize); + + dstBase = blockEnd; + } + } + + /// Computes PowerPacker offset bit widths from the efficiency parameter + /// Efficiency level 1-4 + /// Array of 4 bit widths for offset encoding + static byte[] ComputeOffsetSizes(ushort efficiency) + { + byte[] sizes = [9, 9, 9, 9]; + + // Each efficiency level progressively adds bits to the offset sizes + // Higher levels use wider offsets for better compression of larger data + switch(efficiency) + { + case >= 4: + sizes[3]++; + + goto case 3; + case 3: + sizes[3]++; + sizes[2]++; + + goto case 2; + case 2: + sizes[3]++; + sizes[2]++; + + goto case 1; + case 1: + sizes[3]++; + sizes[2]++; + sizes[1]++; + + break; + } + + return sizes; + } +} \ No newline at end of file diff --git a/Aaru.Images/CrunchDisk/Identify.cs b/Aaru.Images/CrunchDisk/Identify.cs new file mode 100644 index 000000000..6cea1f6f5 --- /dev/null +++ b/Aaru.Images/CrunchDisk/Identify.cs @@ -0,0 +1,73 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Identify.cs +// Author(s) : Natalia Portillo +// +// Component : Disk image plugins. +// +// --[ Description ] ---------------------------------------------------------- +// +// Identifies CrunchDisk disk images. +// +// --[ 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-2026 Natalia Portillo +// ****************************************************************************/ + +using System.IO; +using Aaru.CommonTypes.Interfaces; +using Aaru.Helpers; + +namespace Aaru.Images; + +public sealed partial class CrunchDisk +{ +#region IMediaImage Members + + /// + public bool Identify(IFilter imageFilter) + { + Stream stream = imageFilter.GetDataForkStream(); + + if(stream.Length < HEADER_SIZE) return false; + + stream.Seek(0, SeekOrigin.Begin); + + var buffer = new byte[HEADER_SIZE]; + stream.EnsureRead(buffer, 0, HEADER_SIZE); + + Header header = Marshal.ByteArrayToStructureBigEndian
(buffer); + + if(header.Id != HEADER_MAGIC) return false; + + if(header.BlockSize == 0) return false; + + if(header.Heads == 0) return false; + + if(header.BlocksPerTrack == 0) return false; + + if(header.HighCyl < header.LowCyl) return false; + + if(header.PackerType > 2) return false; + + return true; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Images/CrunchDisk/Properties.cs b/Aaru.Images/CrunchDisk/Properties.cs new file mode 100644 index 000000000..fd55b8e40 --- /dev/null +++ b/Aaru.Images/CrunchDisk/Properties.cs @@ -0,0 +1,68 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Properties.cs +// Author(s) : Natalia Portillo +// +// Component : Disk image plugins. +// +// --[ Description ] ---------------------------------------------------------- +// +// Contains properties for CrunchDisk disk images. +// +// --[ 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-2026 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Collections.Generic; +using Aaru.CommonTypes.AaruMetadata; +using Aaru.CommonTypes.Structs; + +namespace Aaru.Images; + +public sealed partial class CrunchDisk +{ +#region IMediaImage Members + + /// + public string Name => Localization.CrunchDisk_Name; + + /// + public Guid Id => new("A6D26D02-8D5A-4E4B-A542-E34E8F0052E9"); + + /// + public string Author => Authors.NataliaPortillo; + + /// + public string Format => "CrunchDisk"; + + /// + + // ReSharper disable once ConvertToAutoProperty + public ImageInfo Info => _imageInfo; + + /// + public List DumpHardware => null; + + /// + public Metadata AaruMetadata => null; + +#endregion +} \ No newline at end of file diff --git a/Aaru.Images/CrunchDisk/Read.cs b/Aaru.Images/CrunchDisk/Read.cs new file mode 100644 index 000000000..648ee5a12 --- /dev/null +++ b/Aaru.Images/CrunchDisk/Read.cs @@ -0,0 +1,241 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Read.cs +// Author(s) : Natalia Portillo +// +// Component : Disk image plugins. +// +// --[ Description ] ---------------------------------------------------------- +// +// Reads CrunchDisk disk images. +// +// --[ 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-2026 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.IO; +using Aaru.CommonTypes; +using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Interfaces; +using Aaru.Helpers; +using Aaru.Logging; + +namespace Aaru.Images; + +public sealed partial class CrunchDisk +{ +#region IMediaImage Members + + /// + public ErrorNumber Open(IFilter imageFilter) + { + Stream stream = imageFilter.GetDataForkStream(); + + if(stream.Length < HEADER_SIZE) return ErrorNumber.InvalidArgument; + + stream.Seek(0, SeekOrigin.Begin); + + var headerBytes = new byte[HEADER_SIZE]; + stream.EnsureRead(headerBytes, 0, HEADER_SIZE); + + _header = Marshal.ByteArrayToStructureBigEndian
(headerBytes); + + if(_header.Id != HEADER_MAGIC) return ErrorNumber.InvalidArgument; + + if(_header.IsPassword != 0) + { + AaruLogging.Debug(MODULE_NAME, Localization.CrunchDisk_image_is_password_protected); + + return ErrorNumber.NotSupported; + } + + if(_header.PackerType > (ushort)PackerType.PowerPacker) + { + AaruLogging.Debug(MODULE_NAME, Localization.CrunchDisk_unsupported_packer_type_0, _header.PackerType); + + return ErrorNumber.NotSupported; + } + + uint cylinders = _header.HighCyl - _header.LowCyl + 1; + uint sectorsPerCyl = _header.BlocksPerTrack * _header.Heads; + uint cylinderSize = sectorsPerCyl * _header.BlockSize; + uint totalSectors = cylinders * sectorsPerCyl; + + AaruLogging.Debug(MODULE_NAME, + Localization.CrunchDisk_0_cylinders_1_heads_2_sectors_per_track_3_bytes_per_sector, + cylinders, + _header.Heads, + _header.BlocksPerTrack, + _header.BlockSize); + + // Compute PowerPacker offset sizes if needed + byte[] offsetSizes = null; + + if(_header.PackerType == (ushort)PackerType.PowerPacker) offsetSizes = ComputeOffsetSizes(_header.Efficiency); + + // Allocate buffer for the full decompressed disk data + _decompressedData = new byte[totalSectors * _header.BlockSize]; + + var cylHeaderBytes = new byte[CYLINDER_HEADER_SIZE]; + var outputOffset = 0; + + for(uint cyl = _header.LowCyl; cyl <= _header.HighCyl; cyl++) + { + stream.EnsureRead(cylHeaderBytes, 0, CYLINDER_HEADER_SIZE); + + var cylMagic = BigEndianBitConverter.ToUInt32(cylHeaderBytes, 0); + var cylDataLen = BigEndianBitConverter.ToUInt32(cylHeaderBytes, 4); + + switch(cylMagic) + { + case CYL_UNCOMPRESSED: + { + // Raw cylinder data, read directly into output + stream.EnsureRead(_decompressedData, outputOffset, (int)cylDataLen); + + break; + } + + case CYL_COMPRESSED: + { + var packedData = new byte[cylDataLen]; + stream.EnsureRead(packedData, 0, (int)cylDataLen); + + switch((PackerType)_header.PackerType) + { + case PackerType.Stored: + { + // Data is byte-interleaved only, no compression + var resorted = new byte[cylinderSize]; + + ResortCylinderData(packedData, resorted, _header.BlockSize, sectorsPerCyl, cylDataLen); + + Buffer.BlockCopy(resorted, 0, _decompressedData, outputOffset, (int)cylinderSize); + + break; + } + + case PackerType.PowerPacker: + { + // Decompress with PowerPacker, then de-interleave + byte[] decompressed = + PowerPackerDecompress(packedData, (int)cylDataLen, (int)cylinderSize, offsetSizes); + + var resorted = new byte[cylinderSize]; + + ResortCylinderData(decompressed, resorted, _header.BlockSize, sectorsPerCyl, cylinderSize); + + Buffer.BlockCopy(resorted, 0, _decompressedData, outputOffset, (int)cylinderSize); + + break; + } + + default: + return ErrorNumber.NotSupported; + } + + break; + } + + default: + AaruLogging.Debug(MODULE_NAME, Localization.CrunchDisk_unexpected_cylinder_magic_0, cylMagic); + + return ErrorNumber.InvalidArgument; + } + + outputOffset += (int)cylinderSize; + } + + _imageInfo.Cylinders = cylinders; + _imageInfo.Heads = _header.Heads; + _imageInfo.SectorsPerTrack = _header.BlocksPerTrack; + _imageInfo.SectorSize = _header.BlockSize; + _imageInfo.Sectors = totalSectors; + _imageInfo.ImageSize = (ulong)_decompressedData.Length; + + _imageInfo.MetadataMediaType = MetadataMediaType.BlockMedia; + + _imageInfo.CreationTime = imageFilter.CreationTime; + _imageInfo.LastModificationTime = imageFilter.LastWriteTime; + _imageInfo.MediaTitle = Path.GetFileNameWithoutExtension(imageFilter.Filename); + + _imageInfo.MediaType = Geometry.GetMediaType(((ushort)_imageInfo.Cylinders, (byte)_imageInfo.Heads, + (ushort)_imageInfo.SectorsPerTrack, (ushort)_imageInfo.SectorSize, + MediaEncoding.MFM, false)); + + if(_imageInfo.MediaType == MediaType.Unknown) + AaruLogging.Debug(MODULE_NAME, Localization.CrunchDisk_unknown_media_type); + + return ErrorNumber.NoError; + } + + /// + public ErrorNumber ReadSector(ulong sectorAddress, bool negative, out byte[] buffer, out SectorStatus sectorStatus) + { + buffer = null; + sectorStatus = SectorStatus.NotDumped; + + if(negative) return ErrorNumber.NotSupported; + + if(sectorAddress >= _imageInfo.Sectors) return ErrorNumber.OutOfRange; + + buffer = new byte[_imageInfo.SectorSize]; + + Array.Copy(_decompressedData, (long)sectorAddress * _imageInfo.SectorSize, buffer, 0, _imageInfo.SectorSize); + + sectorStatus = SectorStatus.Dumped; + + return ErrorNumber.NoError; + } + + /// + public ErrorNumber ReadSectors(ulong sectorAddress, bool negative, uint length, out byte[] buffer, + out SectorStatus[] sectorStatus) + { + buffer = null; + sectorStatus = null; + + if(negative) return ErrorNumber.NotSupported; + + if(sectorAddress >= _imageInfo.Sectors) return ErrorNumber.OutOfRange; + + if(sectorAddress + length > _imageInfo.Sectors) return ErrorNumber.OutOfRange; + + var ms = new MemoryStream(); + sectorStatus = new SectorStatus[length]; + + for(uint i = 0; i < length; i++) + { + ErrorNumber errno = ReadSector(sectorAddress + i, false, out byte[] sector, out SectorStatus status); + + if(errno != ErrorNumber.NoError) return errno; + + ms.Write(sector, 0, sector.Length); + sectorStatus[i] = status; + } + + buffer = ms.ToArray(); + + return ErrorNumber.NoError; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Images/CrunchDisk/Structs.cs b/Aaru.Images/CrunchDisk/Structs.cs new file mode 100644 index 000000000..a88360c2a --- /dev/null +++ b/Aaru.Images/CrunchDisk/Structs.cs @@ -0,0 +1,68 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Structs.cs +// Author(s) : Natalia Portillo +// +// Component : Disk image plugins. +// +// --[ Description ] ---------------------------------------------------------- +// +// Contains structures for CrunchDisk disk images. +// +// --[ 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-2026 Natalia Portillo +// ****************************************************************************/ + +using System.Runtime.InteropServices; +using Aaru.CommonTypes.Attributes; + +namespace Aaru.Images; + +public sealed partial class CrunchDisk +{ + /// CrunchDisk file header, 52 bytes, big-endian + [StructLayout(LayoutKind.Sequential, Pack = 1)] + [SwapEndian] + partial struct Header + { + /// Magic number, "CDF0" (0x43444630) + public uint Id; + /// Bytes per sector + public uint BlockSize; + /// Sectors per track + public uint BlocksPerTrack; + /// Number of heads + public uint Heads; + /// First cylinder in image + public uint LowCyl; + /// Last cylinder in image + public uint HighCyl; + /// Non-zero if password protected + public byte IsPassword; + /// Padding byte + public byte Pad0; + /// PX20 password checksum + public ushort PasswordChecksum; + /// PowerPacker efficiency level (1-4) + public ushort Efficiency; + /// Compression type + public ushort PackerType; + } +} \ No newline at end of file diff --git a/Aaru.Images/CrunchDisk/Unsupported.cs b/Aaru.Images/CrunchDisk/Unsupported.cs new file mode 100644 index 000000000..016d18871 --- /dev/null +++ b/Aaru.Images/CrunchDisk/Unsupported.cs @@ -0,0 +1,87 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Unsupported.cs +// Author(s) : Natalia Portillo +// +// Component : Disk image plugins. +// +// --[ Description ] ---------------------------------------------------------- +// +// Contains unsupported features for CrunchDisk disk images. +// +// --[ 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-2026 Natalia Portillo +// ****************************************************************************/ + +using Aaru.CommonTypes.Enums; + +namespace Aaru.Images; + +public sealed partial class CrunchDisk +{ +#region IMediaImage Members + + /// + public ErrorNumber ReadMediaTag(MediaTagType tag, out byte[] buffer) + { + buffer = null; + + return ErrorNumber.NotSupported; + } + + /// + public ErrorNumber ReadSectorTag(ulong sectorAddress, bool negative, SectorTagType tag, out byte[] buffer) + { + buffer = null; + + return ErrorNumber.NotSupported; + } + + /// + public ErrorNumber ReadSectorsTag(ulong sectorAddress, bool negative, uint length, SectorTagType tag, + out byte[] buffer) + { + buffer = null; + + return ErrorNumber.NotSupported; + } + + /// + public ErrorNumber ReadSectorLong(ulong sectorAddress, bool negative, out byte[] buffer, + out SectorStatus sectorStatus) + { + buffer = null; + sectorStatus = SectorStatus.NotDumped; + + return ErrorNumber.NotSupported; + } + + /// + public ErrorNumber ReadSectorsLong(ulong sectorAddress, bool negative, uint length, out byte[] buffer, + out SectorStatus[] sectorStatus) + { + buffer = null; + sectorStatus = null; + + return ErrorNumber.NotSupported; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Images/Localization/Localization.Designer.cs b/Aaru.Images/Localization/Localization.Designer.cs index cec54f675..aba122dc0 100644 --- a/Aaru.Images/Localization/Localization.Designer.cs +++ b/Aaru.Images/Localization/Localization.Designer.cs @@ -3669,6 +3669,42 @@ namespace Aaru.Images { } } + internal static string CrunchDisk_Name { + get { + return ResourceManager.GetString("CrunchDisk_Name", resourceCulture); + } + } + + internal static string CrunchDisk_image_is_password_protected { + get { + return ResourceManager.GetString("CrunchDisk_image_is_password_protected", resourceCulture); + } + } + + internal static string CrunchDisk_unsupported_packer_type_0 { + get { + return ResourceManager.GetString("CrunchDisk_unsupported_packer_type_0", resourceCulture); + } + } + + internal static string CrunchDisk_0_cylinders_1_heads_2_sectors_per_track_3_bytes_per_sector { + get { + return ResourceManager.GetString("CrunchDisk_0_cylinders_1_heads_2_sectors_per_track_3_bytes_per_sector", resourceCulture); + } + } + + internal static string CrunchDisk_unexpected_cylinder_magic_0 { + get { + return ResourceManager.GetString("CrunchDisk_unexpected_cylinder_magic_0", resourceCulture); + } + } + + internal static string CrunchDisk_unknown_media_type { + get { + return ResourceManager.GetString("CrunchDisk_unknown_media_type", resourceCulture); + } + } + internal static string Incorrect_disk_type_0 { get { return ResourceManager.GetString("Incorrect_disk_type_0", resourceCulture); diff --git a/Aaru.Images/Localization/Localization.es.resx b/Aaru.Images/Localization/Localization.es.resx index 5b4c15805..889ee9dc3 100644 --- a/Aaru.Images/Localization/Localization.es.resx +++ b/Aaru.Images/Localization/Localization.es.resx @@ -364,6 +364,24 @@ Imagen de disco CisCopy (DC-File) + + + Imagen de disco CrunchDisk + + + La imagen CrunchDisk está protegida con contraseña. + + + La imagen CrunchDisk usa un tipo de compresión no soportado {0}. + + + Imagen CrunchDisk: {0} cilindros, {1} cabezas, {2} sectores por pista, {3} bytes por sector. + + + La imagen CrunchDisk tiene un valor mágico de cilindro inesperado 0x{0:X8}. + + + La geometría de la imagen CrunchDisk no corresponde a un tipo de medio conocido. CloneCD diff --git a/Aaru.Images/Localization/Localization.resx b/Aaru.Images/Localization/Localization.resx index 0f20d7b56..746d1c48b 100644 --- a/Aaru.Images/Localization/Localization.resx +++ b/Aaru.Images/Localization/Localization.resx @@ -1844,6 +1844,24 @@ CisCopy Disk Image (DC-File) + + + CrunchDisk disk image + + + CrunchDisk image is password protected. + + + CrunchDisk image uses unsupported packer type {0}. + + + CrunchDisk image: {0} cylinders, {1} heads, {2} sectors per track, {3} bytes per sector. + + + CrunchDisk image has unexpected cylinder magic 0x{0:X8}. + + + CrunchDisk image geometry does not correspond to a known media type. Incorrect disk type {0} diff --git a/README.md b/README.md index 3e81a72ab..1f441abd0 100644 --- a/README.md +++ b/README.md @@ -94,6 +94,7 @@ Media image formats we can read * BlindWrite 5/6 TOC files (.B5T/.B5I and .B6T/.B6I) * CopyQM * CPCEMU Disk file and Extended Disk File +* Crunchdisk * Dave Dunfield IMD * DiscJuggler images * Dreamcast GDI